diff --git a/.gitignore b/.gitignore index 8ffeab8fe5..ed1fb7ce70 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ /dist/scripts/maketarball.sh /debian/changelog _codeql_detected_source_root +.qtcreator/ +obj-x86_64-linux-gnu/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 55d8b73231..e39da3d3ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,11 @@ if(UNIX AND NOT APPLE) endif() find_package(X11 COMPONENTS X11_xcb) endif() +find_package(Qt6 REQUIRED COMPONENTS Protobuf) +if(NOT Protobuf_FOUND) + message(STATUS "Missing Protobuf compiler.") +endif() + pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GOBJECT REQUIRED IMPORTED_TARGET gobject-2.0) if(NOT APPLE) @@ -352,6 +357,10 @@ optional_component(EBUR128 ON "EBU R 128 loudness normalization" DEPENDS "libebur128" LIBEBUR128_FOUND ) +optional_component(NETWORKREMOTE ON "Network Remote" + DEPENDS "Protobuf" Protobuf_FOUND +) + if(APPLE) optional_component(SPARKLE ON "Sparkle integration" DEPENDS "Sparkle" SPARKLE @@ -1485,6 +1494,31 @@ optional_source(HAVE_QOBUZ src/settings/qobuzsettingspage.ui ) +optional_source(HAVE_NETWORKREMOTE + SOURCES + src/networkremote/networkremote.cpp + src/networkremote/networkremotetcpserver.cpp + src/networkremote/networkremotesettings.cpp + src/networkremote/networkremoteclient.cpp + src/networkremote/networkremoteclientmanager.cpp + src/networkremote/networkremoteincomingmsg.cpp + src/networkremote/networkremoteoutgoingmsg.cpp + src/networkremote/RemoteMessages.proto + src/settings/networkremotesettingspage.cpp + HEADERS + src/networkremote/networkremote.h + src/networkremote/networkremotetcpserver.h + src/networkremote/networkremotesettings.h + src/networkremote/networkremoteclient.h + src/networkremote/networkremoteclientmanager.h + src/networkremote/networkremoteincomingmsg.h + src/networkremote/networkremoteoutgoingmsg.h + src/settings/networkremotesettingspage.h + UI + src/settings/networkremotesettingspage.ui + ) + + qt_wrap_cpp(SOURCES ${HEADERS}) qt_wrap_ui(SOURCES ${UI}) qt_add_resources(SOURCES data/data.qrc data/icons.qrc) @@ -1586,6 +1620,12 @@ if(APPLE) endif() endif() +if(HAVE_NETWORKREMOTE) + add_subdirectory(src/networkremote) + target_link_libraries(strawberry_lib PRIVATE Qt6::Protobuf) + target_link_libraries(strawberry PUBLIC strawberry_lib lib-networkremote) +endif() + target_link_libraries(strawberry PUBLIC strawberry_lib) if(NOT APPLE) diff --git a/data/icons.qrc b/data/icons.qrc index ebbfe2f3b2..80b8ba1f8e 100644 --- a/data/icons.qrc +++ b/data/icons.qrc @@ -506,5 +506,9 @@ icons/22x22/somafm.png icons/22x22/radioparadise.png icons/22x22/musicbrainz.png + icons/22x22/network-remote.png + icons/32x32/network-remote.png + icons/64x64/network-remote.png + icons/128x128/network-remote.png diff --git a/data/icons/128x128/network-remote.png b/data/icons/128x128/network-remote.png new file mode 100644 index 0000000000..56da71d2cb Binary files /dev/null and b/data/icons/128x128/network-remote.png differ diff --git a/data/icons/22x22/network-remote.png b/data/icons/22x22/network-remote.png new file mode 100644 index 0000000000..26632867ca Binary files /dev/null and b/data/icons/22x22/network-remote.png differ diff --git a/data/icons/32x32/network-remote.png b/data/icons/32x32/network-remote.png new file mode 100644 index 0000000000..2f50cb413a Binary files /dev/null and b/data/icons/32x32/network-remote.png differ diff --git a/data/icons/48x28 b/data/icons/48x28 new file mode 100644 index 0000000000..8ce116bd9a Binary files /dev/null and b/data/icons/48x28 differ diff --git a/data/icons/64x64/network-remote.png b/data/icons/64x64/network-remote.png new file mode 100644 index 0000000000..a6192db62c Binary files /dev/null and b/data/icons/64x64/network-remote.png differ diff --git a/data/icons/full/network-remote.png b/data/icons/full/network-remote.png new file mode 100644 index 0000000000..d9ba730ab9 Binary files /dev/null and b/data/icons/full/network-remote.png differ diff --git a/src/config.h.in b/src/config.h.in index 72f7bdc498..f96ace9b0b 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -34,6 +34,7 @@ #cmakedefine HAVE_SPOTIFY #cmakedefine HAVE_QOBUZ #cmakedefine HAVE_DISCORD_RPC +#cmakedefine HAVE_NETWORKREMOTE #cmakedefine HAVE_TAGLIB_DSFFILE #cmakedefine HAVE_TAGLIB_DSDIFFFILE diff --git a/src/core/application.cpp b/src/core/application.cpp index c08eed78d5..7ddbd17b0d 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -4,6 +4,7 @@ * Copyright 2012, David Sansome * Copyright 2012, 2014, John Maguire * Copyright 2018-2025, Jonas Kvinge + * Copyright 2025, Leopold List * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,6 +111,10 @@ # include "moodbar/moodbarloader.h" #endif +#ifdef HAVE_NETWORKREMOTE +# include "networkremote/networkremote.h" +#endif + #include "radios/radioservices.h" #include "radios/radiobackend.h" @@ -216,6 +221,13 @@ class ApplicationImpl { #ifdef HAVE_MOODBAR moodbar_loader_([app]() { return new MoodbarLoader(app); }), moodbar_controller_([app]() { return new MoodbarController(app->player(), app->moodbar_loader()); }), +#endif +#ifdef HAVE_NETWORKREMOTE + network_remote_([app]() { + qLog(Debug) << "Moving to new thread"; + NetworkRemote *remote = new NetworkRemote(app->player(), app); + app->MoveToNewThread(remote); + return remote;}), #endif lastfm_import_([app]() { return new LastFMImport(app->network()); }) {} @@ -241,6 +253,9 @@ class ApplicationImpl { #ifdef HAVE_MOODBAR Lazy moodbar_loader_; Lazy moodbar_controller_; +#endif +#ifdef HAVE_NETWORKREMOTE + Lazy network_remote_; #endif Lazy lastfm_import_; @@ -261,7 +276,7 @@ Application::Application(QObject *parent) device_finders()->Init(); collection()->Init(); tagreader_client(); - + network_remote()->Init(); } Application::~Application() { @@ -324,6 +339,9 @@ void Application::Exit() { << &*albumcover_loader() << &*device_manager() << &*streaming_services() +#ifdef HAVE_NETWORKREMOTE + << &*network_remote() +#endif << &*radio_services()->radio_backend(); QObject::connect(&*tagreader_client(), &TagReaderClient::ExitFinished, this, &Application::ExitReceived); @@ -390,3 +408,6 @@ SharedPtr Application::lastfm_import() const { return p_->lastfm_i SharedPtr Application::moodbar_controller() const { return p_->moodbar_controller_.ptr(); } SharedPtr Application::moodbar_loader() const { return p_->moodbar_loader_.ptr(); } #endif +#ifdef HAVE_NETWORKREMOTE +SharedPtr Application::network_remote() const { return p_->network_remote_.ptr();} +#endif diff --git a/src/core/application.h b/src/core/application.h index 38185fa730..dde41da9d0 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -4,6 +4,7 @@ * Copyright 2012, David Sansome * Copyright 2012, 2014, John Maguire * Copyright 2018-2024, Jonas Kvinge + * Copyright 2025, Leopold List * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,6 +64,9 @@ class RadioServices; class MoodbarController; class MoodbarLoader; #endif +#ifdef HAVE_NETWORKREMOTE +class NetworkRemote; +#endif class Application : public QObject { Q_OBJECT @@ -103,6 +107,9 @@ class Application : public QObject { SharedPtr moodbar_loader() const; #endif +#ifdef HAVE_NETWORKREMOTE + SharedPtr network_remote() const; +#endif SharedPtr lastfm_import() const; void Exit(); diff --git a/src/networkremote/CMakeLists.txt b/src/networkremote/CMakeLists.txt new file mode 100644 index 0000000000..1c34dd9f09 --- /dev/null +++ b/src/networkremote/CMakeLists.txt @@ -0,0 +1,25 @@ +add_library(lib-networkremote STATIC) + +qt_add_protobuf(lib-networkremote + PROTO_FILES RemoteMessages.proto +) + +target_include_directories(lib-networkremote SYSTEM PRIVATE + ${GLIB_INCLUDE_DIRS} + ${PROTOBUF_INCLUDE_DIRS} +) + +target_include_directories(lib-networkremote PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_BINARY_DIR}/src +) + +target_link_libraries(lib-networkremote PRIVATE + ${GLIB_LIBRARIES} + ${Protobuf_LIBRARIES} + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Gui +) diff --git a/src/networkremote/RemoteMessages.proto b/src/networkremote/RemoteMessages.proto new file mode 100644 index 0000000000..57d46e4e1d --- /dev/null +++ b/src/networkremote/RemoteMessages.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; + +package nw.remote; + +option java_multiple_files = true; + +enum MsgType { + MSG_TYPE_UNSPECIFIED = 0; + + // Client message + MSG_TYPE_REQUEST_SONG_INFO = 1; + MSG_TYPE_REQUEST_PLAY = 2; + MSG_TYPE_REQUEST_NEXT = 3; + MSG_TYPE_REQUEST_PREVIOUS = 4; + MSG_TYPE_REQUEST_PAUSE = 5; + MSG_TYPE_REQUEST_STOP = 6; + MSG_TYPE_REQUEST_FINISH = 7; + + + // Server messages + MSG_TYPE_REPLY_SONG_INFO = 8; + MSG_TYPE_REPLY_PLAY = 9; + MSG_TYPE_REPLY_NEXT = 10; + MSG_TYPE_REPLY_PREVIOUS = 11; + MSG_TYPE_REPLY_PAUSE = 12; + MSG_TYPE_REPLY_STOP = 13; + MSG_TYPE_REPLY_FINISH = 14; + MSG_TYPE_ENGINE_STATE_CHANGE = 15; + + // Bidirectional messages + MSG_TYPE_DISCONNECT = 16; +} + +enum PlayerState{ + PLAYER_STATUS_UNSPECIFIED = 0; + PLAYER_STATUS_PLAYING = 1; +} + +enum EngineState { + ENGINE_STATE_EMPTY = 0; + ENGINE_STATE_IDELE = 1; + ENGINE_STATE_PLAYING = 2; + ENGINE_STATE_PAUSED = 3; +} + +enum ReasonDisconnect { + REASON_DISCONNECT_SERVER_SHUTDOWN = 0; + REASON_DISCONNECT_CLIENT_SHUTDOWN = 1; +} + +message RequestDisconnect { + ReasonDisconnect reason_disconnect = 1; +} + +message SongMetadata{ + uint32 id = 1; + string title = 2; + string album = 3; + string artist = 4; + string albumartist = 5; + uint32 track = 6; + string stryear = 7; + string genre = 8; + uint32 playcount = 9; + string songlength = 10; +} +message RequestSongMetadata { + bool send = 1; +} + +message ResponseSongMetadata { + SongMetadata song_metadata = 1; + PlayerState player_state = 2; +} + +message RequestNextTrack { + bool next = 1; +} + +message ResponseNextTrack { + bool next = 1; +} + +message RequestPreviousTrack { + bool previous = 1; +} + +message ResponsePreviousTrack { + bool previous = 1; +} + +message RequestPlay { + bool play = 1; +} + +message ResponsePlay { + bool play = 1; +} + +message RequestPause { + bool pause = 1; +} + +message ResponsePause { + bool pause = 1; +} + +message RequestStop { + bool stop = 1; +} + +message EngineStateChange { + EngineState state = 1; +} +message Message { + MsgType type = 1; + RequestSongMetadata request_song_metadata = 2; + ResponseSongMetadata response_song_metadata = 3; + RequestNextTrack request_next_track = 4; + RequestPreviousTrack request_previous_track = 5; + RequestPlay request_play = 6; + RequestPause request_pause = 7; + RequestStop request_stop = 8; + EngineStateChange engine_state_change = 9; + RequestDisconnect request_disconnect = 10; + ResponseNextTrack response_next_track = 11; + ResponsePreviousTrack response_previous_track = 12; + ResponsePlay response_play = 13; + ResponsePause response_pause = 14; +} + diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp new file mode 100644 index 0000000000..c2bf6eb163 --- /dev/null +++ b/src/networkremote/networkremote.cpp @@ -0,0 +1,81 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include "networkremote/networkremote.h" +#include "core/application.h" +#include "core/logging.h" + +NetworkRemote::NetworkRemote(const SharedPtr player, QObject *parent) + : QObject(parent), + player_(player), + enabled_(false), + local_only_(false), + remote_port_(5050), + server_(nullptr), + settings_(new NetworkRemoteSettings()) { + setObjectName("NetworkRemote"); +} + +NetworkRemote::~NetworkRemote() { + stopTcpServer(); +} + +void NetworkRemote::Init() { + qLog(Debug) << "NetworkRemote Init() "; + LoadSettings(); + if (enabled_) { + startTcpServer(); + } + else { + stopTcpServer(); + } +} + +void NetworkRemote::Update() { + LoadSettings(); + if (enabled_) { + stopTcpServer(); + startTcpServer(); + } + else { + stopTcpServer(); + } + qLog(Debug) << "NetworkRemote Updated ==== "; +} + +void NetworkRemote::LoadSettings() { + settings_->Load(); + enabled_ = settings_->UserRemote(); + local_only_ = settings_->LocalOnly(); + remote_port_ = settings_->GetPort(); + ipAddr_.setAddress(settings_->GetIpAddress()); +} + +void NetworkRemote::startTcpServer() { + server_ = new NetworkRemoteTcpServer(player_, this); + server_->StartServer(ipAddr_, remote_port_); +} + +void NetworkRemote::stopTcpServer() { + if (server_ && server_->ServerUp()) { + qLog(Debug) << "TcpServer stopped "; + server_->StopServer(); + } +} diff --git a/src/networkremote/networkremote.h b/src/networkremote/networkremote.h new file mode 100644 index 0000000000..d079d58872 --- /dev/null +++ b/src/networkremote/networkremote.h @@ -0,0 +1,54 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTE_H +#define NETWORKREMOTE_H + +#include +#include + +#include "networkremotetcpserver.h" +#include "networkremote/networkremotesettings.h" + +class QThread; + +class NetworkRemote : public QObject { + Q_OBJECT + public: + explicit NetworkRemote(const SharedPtr player, QObject *parent = nullptr); + ~NetworkRemote() override; + + public Q_SLOTS: + void Init(); + void Update(); + void LoadSettings(); + void startTcpServer(); + void stopTcpServer(); + + private: + const SharedPtr player_; + bool enabled_; + bool local_only_; + int remote_port_; + QHostAddress ipAddr_; + NetworkRemoteTcpServer *server_; + NetworkRemoteSettings *settings_; +}; + +#endif // NETWORKREMOTE_H diff --git a/src/networkremote/networkremoteclient.cpp b/src/networkremote/networkremoteclient.cpp new file mode 100644 index 0000000000..31c2a4c293 --- /dev/null +++ b/src/networkremote/networkremoteclient.cpp @@ -0,0 +1,75 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "core/logging.h" +#include "networkremoteclient.h" +#include "core/player.h" + +NetworkRemoteClient::NetworkRemoteClient(const SharedPtr player, QObject *parent) + : QObject(parent), + player_(player), + incoming_msg_(new NetworkRemoteIncomingMsg(this)), + outgoing_msg_(new NetworkRemoteOutgoingMsg(player, this)) {} + +NetworkRemoteClient::~NetworkRemoteClient(){} + +void NetworkRemoteClient::Init(QTcpSocket *socket){ + socket_ = socket; + QObject::connect(incoming_msg_, &NetworkRemoteIncomingMsg::InMsgParsed, this, &NetworkRemoteClient::ProcessIncoming); + incoming_msg_->Init(socket_); + outgoing_msg_->Init(socket_); +} + +QTcpSocket *NetworkRemoteClient::GetSocket() { + return socket_; +} + +void NetworkRemoteClient::ProcessIncoming() { + switch (incoming_msg_->GetMsgType()) { + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_SONG_INFO: + outgoing_msg_->SendCurrentTrackInfo(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_PLAY: + player_->Play(); + // In case the player was paused when the client started send the song info again + outgoing_msg_->SendCurrentTrackInfo(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_NEXT: + player_->Next(); + outgoing_msg_->SendCurrentTrackInfo(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_PREVIOUS: + player_->Previous(); + outgoing_msg_->SendCurrentTrackInfo(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_PAUSE: + player_->Pause(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_STOP: + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REQUEST_FINISH: + Q_EMIT ClientIsLeaving(); + break; + case nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_DISCONNECT: + break; + default: + qLog(Debug) << "Unknown message type"; + break; + } +} diff --git a/src/networkremote/networkremoteclient.h b/src/networkremote/networkremoteclient.h new file mode 100644 index 0000000000..5095f0b059 --- /dev/null +++ b/src/networkremote/networkremoteclient.h @@ -0,0 +1,52 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTECLIENT_H +#define NETWORKREMOTECLIENT_H + +#include +#include +#include "networkremoteincomingmsg.h" +#include "networkremoteoutgoingmsg.h" +#include "includes/shared_ptr.h" + +class Player; + +class NetworkRemoteClient : public QObject{ + Q_OBJECT + public: + explicit NetworkRemoteClient(const SharedPtr player, QObject *parent = nullptr); + ~NetworkRemoteClient(); + void Init(QTcpSocket *); + QTcpSocket *GetSocket(); + void ProcessIncoming(); + + Q_SIGNALS: + void ReceiveMsg(); + void PrepareResponse(); + void ClientIsLeaving(); + + private: + const SharedPtr player_; + QTcpSocket *socket_; + NetworkRemoteIncomingMsg *incoming_msg_; + NetworkRemoteOutgoingMsg *outgoing_msg_; +}; + +#endif diff --git a/src/networkremote/networkremoteclientmanager.cpp b/src/networkremote/networkremoteclientmanager.cpp new file mode 100644 index 0000000000..e952205bfe --- /dev/null +++ b/src/networkremote/networkremoteclientmanager.cpp @@ -0,0 +1,86 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "networkremoteclientmanager.h" +#include "networkremoteclient.h" +#include "core/application.h" +#include "core/logging.h" + + +NetworkRemoteClientManager::NetworkRemoteClientManager(const SharedPtr player, QObject *parent) + : QObject(parent), + player_(player), + clients_() {} + +NetworkRemoteClientManager::~NetworkRemoteClientManager() {} + +void NetworkRemoteClientManager::AddClient(QTcpSocket *socket) { + qLog(Debug) << "New Client connection +++++++++++++++"; + QObject::connect(socket, &QAbstractSocket::errorOccurred, this, &NetworkRemoteClientManager::Error); + QObject::connect(socket, &QAbstractSocket::stateChanged, this, &NetworkRemoteClientManager::StateChanged); + + QSharedPointer client = QSharedPointer::create(player_); + client->Init(socket); + clients_.append(client); + + QObject::connect(client.data(), &NetworkRemoteClient::ClientIsLeaving, this, [this, client](){ + RemoveClient(client); + }); + qLog(Debug) << "Socket State is " << socket->state(); + qLog(Debug) << "There are now +++++++++++++++" << clients_.count() << "clients connected"; +} + +void NetworkRemoteClientManager::RemoveClient(const QSharedPointer& client) { + clients_.removeOne(client); + qLog(Debug) << "There are now +++++++++++++++" << clients_.count() << "clients connected"; +} + +void NetworkRemoteClientManager::Error(QAbstractSocket::SocketError socketError) { + QTcpSocket *socket = qobject_cast(sender()); + if (!socket) return; + switch (socketError) { + case QAbstractSocket::RemoteHostClosedError: + qLog(Debug) << "Remote Host closed"; + break; + case QAbstractSocket::HostNotFoundError: + qLog(Debug) << "The host was not found. Please check the host name and port settings."; + break; + case QAbstractSocket::ConnectionRefusedError: + qLog(Debug) << "The connection was refused by the peer."; + break; + default: + qLog(Debug) << "The following error occurred:" << socket->errorString(); + } +} + +void NetworkRemoteClientManager::StateChanged() { + QTcpSocket *socket = qobject_cast(sender()); + if (!socket) return; + qLog(Debug) << socket->state(); + qLog(Debug) << "State Changed"; + if (socket->state() == QAbstractSocket::UnconnectedState) { + for (const QSharedPointer &client : std::as_const(clients_)) { + if (client->GetSocket() == socket) { + RemoveClient(client); + break; + } + } + } +} + diff --git a/src/networkremote/networkremoteclientmanager.h b/src/networkremote/networkremoteclientmanager.h new file mode 100644 index 0000000000..1b24889f7a --- /dev/null +++ b/src/networkremote/networkremoteclientmanager.h @@ -0,0 +1,49 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTECLIENTMANAGER_H +#define NETWORKREMOTECLIENTMANAGER_H + +#include +#include +#include +#include "includes/shared_ptr.h" + +class Player; + +class NetworkRemoteClient; + +class NetworkRemoteClientManager : public QObject{ + Q_OBJECT + public: + explicit NetworkRemoteClientManager(const SharedPtr player, QObject *parent = nullptr); + ~NetworkRemoteClientManager(); + void AddClient(QTcpSocket *socket); + + private Q_SLOTS: + void RemoveClient(const QSharedPointer& client); + void Error(QAbstractSocket::SocketError socketError); + void StateChanged(); + + private: + const SharedPtr player_; + QList> clients_; +}; + +#endif diff --git a/src/networkremote/networkremoteincomingmsg.cpp b/src/networkremote/networkremoteincomingmsg.cpp new file mode 100644 index 0000000000..c251c0a1a3 --- /dev/null +++ b/src/networkremote/networkremoteincomingmsg.cpp @@ -0,0 +1,60 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include + +#include "networkremoteincomingmsg.h" +#include "core/logging.h" + +NetworkRemoteIncomingMsg::NetworkRemoteIncomingMsg(QObject *parent) + : QObject(parent), + socket_(nullptr), + bytes_in_(0) {} + +NetworkRemoteIncomingMsg::~NetworkRemoteIncomingMsg() = default; + +void NetworkRemoteIncomingMsg::Init(QTcpSocket *socket) { + socket_ = socket; + QObject::connect(socket_, &QIODevice::readyRead, this, &NetworkRemoteIncomingMsg::ReadyRead); +} + +void NetworkRemoteIncomingMsg::SetMsgType() { + QProtobufSerializer serializer; + msg_.deserialize(&serializer, msg_stream_.constData()); + if (serializer.lastError() == QAbstractProtobufSerializer::Error::None) { + msg_type_ = msg_.type(); + Q_EMIT InMsgParsed(); + } else { + qLog(Debug) << "Failed to deserialize message: (" + << qToUnderlying(serializer.lastError()) << ") "<< serializer.lastErrorString(); + } +} + +nw::remote::MsgTypeGadget::MsgType NetworkRemoteIncomingMsg::GetMsgType() { + return msg_type_; +} + +void NetworkRemoteIncomingMsg::ReadyRead() { + qLog(Debug) << "Ready To Read"; + msg_stream_ = socket_->readAll(); + if (!msg_stream_.isEmpty()) { + SetMsgType(); + } +} diff --git a/src/networkremote/networkremoteincomingmsg.h b/src/networkremote/networkremoteincomingmsg.h new file mode 100644 index 0000000000..54c114fa2d --- /dev/null +++ b/src/networkremote/networkremoteincomingmsg.h @@ -0,0 +1,54 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTEINCOMINGMSG_H +#define NETWORKREMOTEINCOMINGMSG_H + +#include +#include +#include +#include "networkremote/RemoteMessages.qpb.h" + +class QTcpSocket; + +class NetworkRemoteIncomingMsg : public QObject{ + Q_OBJECT + public: + explicit NetworkRemoteIncomingMsg(QObject *parent = nullptr); + ~NetworkRemoteIncomingMsg(); + void Init(QTcpSocket* socket); + void SetMsgType(); + nw::remote::MsgTypeGadget::MsgType GetMsgType(); + + private Q_SLOTS: + void ReadyRead(); + + Q_SIGNALS: + void InMsgParsed(); + + private: + nw::remote::Message msg_; + nw::remote::MsgTypeGadget::MsgType msg_type_; + QTcpSocket *socket_; + long bytes_in_; + QByteArray msg_stream_; + std::string msg_string_; +}; + +#endif diff --git a/src/networkremote/networkremoteoutgoingmsg.cpp b/src/networkremote/networkremoteoutgoingmsg.cpp new file mode 100644 index 0000000000..b2420e75fd --- /dev/null +++ b/src/networkremote/networkremoteoutgoingmsg.cpp @@ -0,0 +1,84 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include +#include "networkremoteoutgoingmsg.h" +#include "core/application.h" +#include "core/logging.h" +#include "core/player.h" + +NetworkRemoteOutgoingMsg::NetworkRemoteOutgoingMsg(const SharedPtr player, QObject *parent) + : QObject(parent), + player_(player), + bytes_out_(0), + msg_type_(0), + playlist_(nullptr), + socket_(nullptr) {} + +void NetworkRemoteOutgoingMsg::Init(QTcpSocket *socket) { + socket_ = socket; +} + +void NetworkRemoteOutgoingMsg::SendCurrentTrackInfo() { + msg_ = nw::remote::Message(); + response_song_ = nw::remote::ResponseSongMetadata(); + current_item_ = player_->GetCurrentItem(); + + if (current_item_ != nullptr) { + song_ = nw::remote::SongMetadata(); + song_.setTitle(current_item_->EffectiveMetadata().PrettyTitle()); + song_.setAlbum(current_item_->EffectiveMetadata().album()); + song_.setArtist(current_item_->EffectiveMetadata().artist()); + song_.setAlbumartist(current_item_->EffectiveMetadata().albumartist()); + song_.setTrack(current_item_->EffectiveMetadata().track()); + song_.setStryear(current_item_->EffectiveMetadata().PrettyYear()); + song_.setGenre(current_item_->EffectiveMetadata().genre()); + song_.setPlaycount(current_item_->EffectiveMetadata().playcount()); + song_.setSonglength(current_item_->EffectiveMetadata().PrettyLength()); + + response_song_.setPlayerState(nw::remote::PlayerStateGadget::PlayerState::PLAYER_STATUS_PLAYING); + response_song_.setSongMetadata(song_); + + msg_.setType(nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REPLY_SONG_INFO); + msg_.setResponseSongMetadata(response_song_); + } + else { + response_song_.setPlayerState(nw::remote::PlayerStateGadget::PlayerState::PLAYER_STATUS_UNSPECIFIED); + msg_.setType(nw::remote::MsgTypeGadget::MsgType::MSG_TYPE_REPLY_SONG_INFO); + msg_.setResponseSongMetadata(response_song_); + } + SendMsg(); +} + +void NetworkRemoteOutgoingMsg::SendMsg() { + QProtobufSerializer serializer; + QByteArray data = serializer.serialize(&msg_); + if (serializer.lastError() != QAbstractProtobufSerializer::Error::None) { + qLog(Debug) << "Failed to serialize message:" << serializer.lastErrorString(); + return; + } + bytes_out_ = data.size(); + if (socket_ && socket_->isWritable()) { + socket_->write(data); + qLog(Debug) << bytes_out_ << "bytes written to socket" << socket_->socketDescriptor(); + } else { + qWarning() << "Socket is not writable."; + } +} diff --git a/src/networkremote/networkremoteoutgoingmsg.h b/src/networkremote/networkremoteoutgoingmsg.h new file mode 100644 index 0000000000..ca5d49b75b --- /dev/null +++ b/src/networkremote/networkremoteoutgoingmsg.h @@ -0,0 +1,56 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTEOUTGOINGMSG_H +#define NETWORKREMOTEOUTGOINGMSG_H + +#include +#include +#include "playlist/playlistitem.h" +#include "includes/shared_ptr.h" +#include "networkremote/RemoteMessages.qpb.h" + +class Playlist; +class Player; +class QTcpSocket; + +class NetworkRemoteOutgoingMsg : public QObject{ + Q_OBJECT + public: + explicit NetworkRemoteOutgoingMsg(const SharedPtr player, QObject *parent = nullptr); + void Init(QTcpSocket *); + void SendCurrentTrackInfo(); + void SendMsg(); + + private: + SharedPtr player_ ; + long bytes_out_; + qint32 msg_type_; + Playlist *playlist_; + QTcpSocket *socket_; + PlaylistItemPtr current_item_; + QByteArray msg_stream_; + std::string msg_string_; + nw::remote::Message msg_; + nw::remote::SongMetadata song_; + nw::remote::ResponseSongMetadata response_song_; + +}; + +#endif diff --git a/src/networkremote/networkremotesettings.cpp b/src/networkremote/networkremotesettings.cpp new file mode 100644 index 0000000000..54b3b6b04c --- /dev/null +++ b/src/networkremote/networkremotesettings.cpp @@ -0,0 +1,109 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include +#include "networkremotesettings.h" +#include "core/logging.h" +#include "core/settings.h" + +const char *NetworkRemoteSettings::kSettingsGroup = "NetworkRemote"; + +NetworkRemoteSettings::NetworkRemoteSettings() + : enabled_(false), + local_only_(false), + remote_port_(5050) {} + +NetworkRemoteSettings::~NetworkRemoteSettings() {} + +void NetworkRemoteSettings::Load() { + SetIpAdress(); + Settings s_; + s_.beginGroup(NetworkRemoteSettings::kSettingsGroup); + if (!s_.contains("useRemote")) { + qLog(Debug) << "First time run the Network Remote"; + s_.setValue("useRemote", false); + s_.setValue("localOnly", false); + s_.setValue("remotePort", 5050); + s_.setValue("ipAddress", ip_addr_); + } + else { + enabled_ = s_.value("useRemote").toBool(); + local_only_ = s_.value("localOnly").toBool(); + remote_port_ = s_.value("remotePort").toInt(); + s_.setValue("ipAddress", ip_addr_); + } + s_.endGroup(); + qLog(Debug) << "QSettings Loaded ++++++++++++++++"; +} + +void NetworkRemoteSettings::Save() { + Settings s_; + s_.beginGroup(NetworkRemoteSettings::kSettingsGroup); + s_.setValue("useRemote", enabled_); + s_.setValue("localOnly", local_only_); + s_.setValue("remotePort", remote_port_); + s_.setValue("ipAddress", ip_addr_); + s_.endGroup(); + s_.sync(); + qLog(Debug) << "Saving QSettings ++++++++++++++++"; +} + +bool NetworkRemoteSettings::UserRemote() { + return enabled_; +} + +bool NetworkRemoteSettings::LocalOnly() { + return local_only_; +} + +QString NetworkRemoteSettings::GetIpAddress() { + return ip_addr_; +} + +int NetworkRemoteSettings::GetPort() { + return remote_port_; +} + +void NetworkRemoteSettings::SetUseRemote(bool useRemote) { + enabled_ = useRemote; + Save(); +} + +void NetworkRemoteSettings::SetLocalOnly(bool localOnly) { + local_only_ = localOnly; + Save(); +} + +void NetworkRemoteSettings::SetIpAdress() { + bool found = false; + const QList host_list = QNetworkInterface::allAddresses(); + for (const QHostAddress &address : host_list) { + if (address.protocol() == QAbstractSocket::IPv4Protocol && address.isLoopback() == false && !found) { + qInfo( "Warning: The code only picks the first IPv4 address"); + found = true; + ip_addr_ = address.toString(); + } + } +} + +void NetworkRemoteSettings::SetPort(int port) { + remote_port_ = port; + Save(); +} diff --git a/src/networkremote/networkremotesettings.h b/src/networkremote/networkremotesettings.h new file mode 100644 index 0000000000..9008f9c228 --- /dev/null +++ b/src/networkremote/networkremotesettings.h @@ -0,0 +1,48 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTESETTINGS_H +#define NETWORKREMOTESETTINGS_H + +#include + +class NetworkRemoteSettings{ + public: + static const char *kSettingsGroup; + explicit NetworkRemoteSettings(); + ~NetworkRemoteSettings(); + void Load(); + void Save(); + bool UserRemote(); + bool LocalOnly(); + QString GetIpAddress(); + int GetPort(); + void SetUseRemote(bool); + void SetLocalOnly(bool); + void SetIpAdress (); + void SetPort(int); + + private: + bool enabled_; + bool local_only_; + int remote_port_; + QString ip_addr_; +}; + +#endif diff --git a/src/networkremote/networkremotetcpserver.cpp b/src/networkremote/networkremotetcpserver.cpp new file mode 100644 index 0000000000..3886a26943 --- /dev/null +++ b/src/networkremote/networkremotetcpserver.cpp @@ -0,0 +1,55 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include "networkremotetcpserver.h" +#include "core/logging.h" +#include "networkremote/networkremoteclientmanager.h" + +NetworkRemoteTcpServer::NetworkRemoteTcpServer(const SharedPtr player, QObject *parent) + : QObject(parent), + player_(player), + server_(new QTcpServer(this)), + client_mgr_(new NetworkRemoteClientManager(player_, this)){ + connect(server_, &QTcpServer::newConnection, this, &NetworkRemoteTcpServer::NewTcpConnection); +} + +void NetworkRemoteTcpServer::StartServer(const QHostAddress ipAddr, int port) { + server_->setProxy(QNetworkProxy::NoProxy); + if (server_->listen(ipAddr, port)) { + qLog(Debug) << "TCP Server Started on --- " << ipAddr.toString() << " and port -- " << port; + } +} + +void NetworkRemoteTcpServer::NewTcpConnection() { + socket_ = server_->nextPendingConnection(); + client_mgr_->AddClient(socket_); + qLog(Debug) << "New Socket -------------------"; +} + +void NetworkRemoteTcpServer::StopServer() { + if(server_ && server_->isListening()){ + server_->close(); + qLog(Debug) << "TCP Server Stopped ----------------------"; + } +} + +bool NetworkRemoteTcpServer::ServerUp() { + return server_->isListening(); +} diff --git a/src/networkremote/networkremotetcpserver.h b/src/networkremote/networkremotetcpserver.h new file mode 100644 index 0000000000..f86dc69667 --- /dev/null +++ b/src/networkremote/networkremotetcpserver.h @@ -0,0 +1,46 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTETCPSERVER_H +#define NETWORKREMOTETCPSERVER_H + +#include +#include +#include +#include "networkremote/networkremoteclientmanager.h" + +class NetworkRemoteTcpServer : public QObject{ + Q_OBJECT + public: + explicit NetworkRemoteTcpServer(const SharedPtr player, QObject *parent = nullptr); + bool ServerUp(); + + public Q_SLOTS: + void NewTcpConnection(); + void StartServer(QHostAddress ipAddr, int port); + void StopServer(); + + private: + const SharedPtr player_; + QTcpServer *server_; + QTcpSocket *socket_; + NetworkRemoteClientManager *client_mgr_; +}; + +#endif diff --git a/src/settings/networkremotesettingspage.cpp b/src/settings/networkremotesettingspage.cpp new file mode 100644 index 0000000000..6a66466998 --- /dev/null +++ b/src/settings/networkremotesettingspage.cpp @@ -0,0 +1,95 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include "core/iconloader.h" +#include "core/logging.h" +#include "settings/settingsdialog.h" +#include "settings/networkremotesettingspage.h" +#include "ui_networkremotesettingspage.h" + +//using namespace Qt::Literals::StringLiterals; + +NetworkRemoteSettingsPage::NetworkRemoteSettingsPage(SettingsDialog *dialog, QWidget *parent) : + SettingsPage(dialog,parent), + ui_(new Ui_NetworkRemoteSettingsPage), + settings_(new NetworkRemoteSettings) { + ui_->setupUi(this); + const int iconSize = style()->pixelMetric(QStyle::PM_TabBarIconSize); + setWindowIcon(IconLoader::Load(QStringLiteral("network-remote"), true, 0,iconSize)); + QObject::connect(ui_->useRemoteClient,&QAbstractButton::clicked, this, &NetworkRemoteSettingsPage::RemoteButtonClicked); + QObject::connect(ui_->localConnectionsOnly, &QAbstractButton::clicked, this, &NetworkRemoteSettingsPage::LocalConnectButtonClicked); + QObject::connect(ui_->portSelected, &QAbstractSpinBox::editingFinished, this, &NetworkRemoteSettingsPage::PortChanged); +} + +NetworkRemoteSettingsPage::~NetworkRemoteSettingsPage() { + delete ui_; +} + +void NetworkRemoteSettingsPage::Load() { + ui_->portSelected->setRange(5050, 65535); + ui_->ip_address->setText(QStringLiteral("0.0.0.0")); + settings_->Load(); + + ui_->useRemoteClient->setCheckable(true); + ui_->useRemoteClient->setChecked(settings_->UserRemote()); + if (settings_->UserRemote()) { + ui_->localConnectionsOnly->setCheckable(true); + ui_->localConnectionsOnly->setChecked(settings_->LocalOnly()); + ui_->portSelected->setReadOnly(false); + ui_->portSelected->setValue(settings_->GetPort()); + } + else { + ui_->localConnectionsOnly->setCheckable(false); + ui_->portSelected->setReadOnly(true); + } + DisplayIP(); + qLog(Debug) << "SettingsPage Loaded QSettings ++++++++++++++++"; + Init(ui_->layout_networkremotesettingspage->parentWidget()); +} + +void NetworkRemoteSettingsPage::Save() { + qLog(Debug) << "Saving QSettings ++++++++++++++++"; +} + +void NetworkRemoteSettingsPage::DisplayIP() { + ui_->ip_address->setText(settings_->GetIpAddress()); +} + +void NetworkRemoteSettingsPage::RemoteButtonClicked() { + settings_->SetUseRemote(ui_->useRemoteClient->isChecked()); + ui_->useRemoteClient->setChecked(settings_->UserRemote()); + if (ui_->useRemoteClient->isChecked()) { + ui_->localConnectionsOnly->setCheckable(true); + ui_->portSelected->setReadOnly(false); + } + else { + ui_->localConnectionsOnly->setCheckable(false); + ui_->portSelected->setReadOnly(true); + } +} + +void NetworkRemoteSettingsPage::LocalConnectButtonClicked() { + settings_->SetLocalOnly(ui_->localConnectionsOnly->isChecked()); +} + +void NetworkRemoteSettingsPage::PortChanged() { + settings_->SetPort(ui_->portSelected->value()); +} + diff --git a/src/settings/networkremotesettingspage.h b/src/settings/networkremotesettingspage.h new file mode 100644 index 0000000000..08e9992513 --- /dev/null +++ b/src/settings/networkremotesettingspage.h @@ -0,0 +1,52 @@ +/* + * Strawberry Music Player + * Copyright 2025, Leopold List + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef NETWORKREMOTESETTINGSPAGE_H +#define NETWORKREMOTESETTINGSPAGE_H + +#include "settingspage.h" +#include "networkremote/networkremotesettings.h" + +class SettingsDialog; +class Ui_NetworkRemoteSettingsPage; +class NetworkRemote; + +class NetworkRemoteSettingsPage : public SettingsPage{ + Q_OBJECT + public: + explicit NetworkRemoteSettingsPage(SettingsDialog *dialog, QWidget *parent = nullptr); + ~NetworkRemoteSettingsPage() override; + void Load() override; + void Save() override; + + Q_SIGNALS: + void remoteSettingsChanged(); + + private: + Ui_NetworkRemoteSettingsPage *ui_; + NetworkRemoteSettings *settings_; + + private Q_SLOTS: + void RemoteButtonClicked(); + void LocalConnectButtonClicked(); + void PortChanged(); + void DisplayIP(); +}; + +#endif // NETWORKREMOTESETTINGSPAGE_H diff --git a/src/settings/networkremotesettingspage.ui b/src/settings/networkremotesettingspage.ui new file mode 100644 index 0000000000..8a2e31814c --- /dev/null +++ b/src/settings/networkremotesettingspage.ui @@ -0,0 +1,101 @@ + + + NetworkRemoteSettingsPage + + + + 0 + 0 + 496 + 195 + + + + Remote + + + + + + + + Use Remote Network Client + + + + + + + + + + + + 20 + 20 + 101 + 17 + + + + Remote Port + + + + + + 160 + 10 + 71 + 26 + + + + + + + 20 + 60 + 231 + 23 + + + + Only allow local connections + + + + + + 30 + 110 + 141 + 17 + + + + Your IP Address is + + + + + + 240 + 110 + 191 + 17 + + + + + + + + + + + + + + + diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp index 6eaf5587ad..8f7e176e86 100644 --- a/src/settings/settingsdialog.cpp +++ b/src/settings/settingsdialog.cpp @@ -3,6 +3,7 @@ * This file was part of Clementine. * Copyright 2010, David Sansome * Copyright 2019-2024, Jonas Kvinge + * Copyright 2025, Leopold List * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -90,6 +91,9 @@ # include "qobuz/qobuzservice.h" # include "qobuzsettingspage.h" #endif +#ifdef HAVE_NETWORKREMOTE +# include "networkremotesettingspage.h" +#endif #include "ui_settingsdialog.h" @@ -130,6 +134,9 @@ SettingsDialog::SettingsDialog(const SharedPtr player, AddPage(Page::Lyrics, new LyricsSettingsPage(this, lyrics_providers, this), general); AddPage(Page::Transcoding, new TranscoderSettingsPage(this, this), general); AddPage(Page::Proxy, new NetworkProxySettingsPage(this, this), general); +#ifdef HAVE_NETWORKREMOTE + AddPage(Page::NetworkRemote, new NetworkRemoteSettingsPage(this, this), general); +#endif QTreeWidgetItem *iface = AddCategory(tr("User interface")); AddPage(Page::Appearance, new AppearanceSettingsPage(this, this), iface); diff --git a/src/settings/settingsdialog.h b/src/settings/settingsdialog.h index 8723ca193c..da260a3e48 100644 --- a/src/settings/settingsdialog.h +++ b/src/settings/settingsdialog.h @@ -3,6 +3,7 @@ * This file was part of Clementine. * Copyright 2010, David Sansome * Copyright 2019-2021, Jonas Kvinge + * Copyright 2025, Leopold List * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -93,6 +94,9 @@ class SettingsDialog : public QDialog { Tidal, Qobuz, Spotify, +#ifdef HAVE_NETWORKREMOTE + NetworkRemote +#endif }; enum Role {