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 {