diff --git a/src/core/library/LocalSimpleDataProvider.cpp b/src/core/library/LocalSimpleDataProvider.cpp index 387351fa0..7bfb672f9 100644 --- a/src/core/library/LocalSimpleDataProvider.cpp +++ b/src/core/library/LocalSimpleDataProvider.cpp @@ -389,18 +389,17 @@ bool LocalSimpleDataProvider::DeletePlaylist(const int64_t playlistId) { return false; } +template static bool appendToPlaylist( ILibraryPtr library, const int64_t playlistId, - std::shared_ptr trackList, + TrackListType trackList, int offset) { try { std::shared_ptr query = std::make_shared( - playlistId, - trackList, - offset); + library, playlistId, trackList, offset); library->Enqueue(query, ILibrary::QuerySynchronous); @@ -447,3 +446,14 @@ bool LocalSimpleDataProvider::AppendToPlaylistWithExternalIds( return 0; } + +bool LocalSimpleDataProvider::AppendToPlaylistWithTrackList( + const int64_t playlistId, ITrackList* trackList, int offset) +{ + static auto deleter = [](musik::core::sdk::ITrackList* trackList) {}; + + bool result = appendToPlaylist( + this->library, playlistId, trackList, offset); + + return result; +} \ No newline at end of file diff --git a/src/core/library/LocalSimpleDataProvider.h b/src/core/library/LocalSimpleDataProvider.h index a3d6e6b8c..c1316cb44 100644 --- a/src/core/library/LocalSimpleDataProvider.h +++ b/src/core/library/LocalSimpleDataProvider.h @@ -108,6 +108,11 @@ namespace musik { namespace core { namespace db { namespace local { size_t externalIdCount, int offset = -1) override; + virtual bool AppendToPlaylistWithTrackList( + const int64_t playlistId, + musik::core::sdk::ITrackList* trackList, + int offset = -1) override; + private: musik::core::ILibraryPtr library; }; diff --git a/src/core/library/query/local/AppendPlaylistQuery.cpp b/src/core/library/query/local/AppendPlaylistQuery.cpp index 8eaec340c..1252ecb46 100644 --- a/src/core/library/query/local/AppendPlaylistQuery.cpp +++ b/src/core/library/query/local/AppendPlaylistQuery.cpp @@ -34,7 +34,8 @@ #include "pch.hpp" #include "AppendPlaylistQuery.h" - +#include +#include #include #include @@ -58,17 +59,34 @@ static std::string GET_MAX_SORT_ORDER_QUERY = "SELECT MAX(sort_order) from playlist_tracks where playlist_id = ?"; AppendPlaylistQuery::AppendPlaylistQuery( + musik::core::ILibraryPtr library, const int64_t playlistId, std::shared_ptr tracks, const int offset) -: tracks(tracks) +: library(library) +, sharedTracks(tracks) +, rawTracks(nullptr) +, playlistId(playlistId) +, offset(offset) { + +} + +AppendPlaylistQuery::AppendPlaylistQuery( + musik::core::ILibraryPtr library, + const int64_t playlistId, + musik::core::sdk::ITrackList *tracks, + const int offset) +: library(library) +, rawTracks(tracks) , playlistId(playlistId) , offset(offset) { } bool AppendPlaylistQuery::OnRun(musik::core::db::Connection &db) { - if (!tracks->Count() || playlistId == 0) { + ITrackList* tracks = sharedTracks ? sharedTracks.get() : rawTracks; + + if (!tracks || !tracks->Count() || playlistId == 0) { return true; } @@ -99,20 +117,33 @@ bool AppendPlaylistQuery::OnRun(musik::core::db::Connection &db) { Statement insertTrack(INSERT_PLAYLIST_TRACK_QUERY.c_str(), db); - for (size_t i = 0; i < this->tracks->Count(); i++) { - auto track = this->tracks->Get(i); - insertTrack.Reset(); - insertTrack.BindText(0, track->GetString("external_id")); - insertTrack.BindText(1, track->GetString("source_id")); - insertTrack.BindInt64(2, playlistId); - insertTrack.BindInt32(3, offset++); + for (size_t i = 0; i < tracks->Count(); i++) { + auto id = tracks->GetId(i); + auto target = TrackPtr(new LibraryTrack(id, this->library)); - if (insertTrack.Step() == db::Error) { - return false; + std::shared_ptr query( + new TrackMetadataQuery( + target, + this->library, + TrackMetadataQuery::IdsOnly)); + + this->library->Enqueue(query, ILibrary::QuerySynchronous); + + if (query->GetStatus() == IQuery::Finished) { + auto track = query->Result(); + insertTrack.Reset(); + insertTrack.BindText(0, track->GetString("external_id")); + insertTrack.BindText(1, track->GetString("source_id")); + insertTrack.BindInt64(2, playlistId); + insertTrack.BindInt32(3, offset++); + + if (insertTrack.Step() == db::Error) { + return false; + } } } transaction.CommitAndRestart(); - return false; + return true; } \ No newline at end of file diff --git a/src/core/library/query/local/AppendPlaylistQuery.h b/src/core/library/query/local/AppendPlaylistQuery.h index fe5b98d6b..a703eb85c 100644 --- a/src/core/library/query/local/AppendPlaylistQuery.h +++ b/src/core/library/query/local/AppendPlaylistQuery.h @@ -44,10 +44,17 @@ namespace musik { namespace core { namespace db { namespace local { class AppendPlaylistQuery : public musik::core::db::LocalQueryBase { public: AppendPlaylistQuery( + musik::core::ILibraryPtr library, const int64_t playlistId, std::shared_ptr tracks, const int offset = -1); + AppendPlaylistQuery( + musik::core::ILibraryPtr library, + const int64_t playlistId, + musik::core::sdk::ITrackList *tracks, + const int offset = -1); + virtual ~AppendPlaylistQuery() { } std::string Name() { return "AppendPlaylistQuery"; } @@ -56,7 +63,10 @@ namespace musik { namespace core { namespace db { namespace local { virtual bool OnRun(musik::core::db::Connection &db); int64_t playlistId; - std::shared_ptr tracks; + + musik::core::ILibraryPtr library; + std::shared_ptr sharedTracks; + musik::core::sdk::ITrackList* rawTracks; int offset; }; diff --git a/src/core/library/query/local/TrackMetadataQuery.cpp b/src/core/library/query/local/TrackMetadataQuery.cpp index 1d9c05b09..fa2f85cc8 100644 --- a/src/core/library/query/local/TrackMetadataQuery.cpp +++ b/src/core/library/query/local/TrackMetadataQuery.cpp @@ -55,17 +55,33 @@ static const std::string ALL_METADATA_QUERY_BY_EXTERNAL_ID = "FROM " + TABLES + " " + "WHERE t.external_id=? AND " + PREDICATE; -TrackMetadataQuery::TrackMetadataQuery(TrackPtr target, ILibraryPtr library) { +static const std::string IDS_ONLY_QUERY_BY_ID = + "SELECT DISTINCT external_id, source_id FROM tracks WHERE tracks.id=?"; + +static const std::string IDS_ONLY_QUERY_BY_EXTERNAL_ID = + "SELECT DISTINCT external_id, source_id FROM tracks WHERE tracks.external_id=?"; + +TrackMetadataQuery::TrackMetadataQuery(TrackPtr target, ILibraryPtr library, Type type) { this->result = target; this->library = library; + this->type = type; } bool TrackMetadataQuery::OnRun(Connection& db) { bool queryById = this->result->GetId() != 0; - const std::string& query = queryById - ? ALL_METADATA_QUERY_BY_ID - : ALL_METADATA_QUERY_BY_EXTERNAL_ID; + std::string query; + + if (this->type == Full) { + query = queryById + ? ALL_METADATA_QUERY_BY_ID + : ALL_METADATA_QUERY_BY_EXTERNAL_ID; + } + else { + query = queryById + ? IDS_ONLY_QUERY_BY_ID + : IDS_ONLY_QUERY_BY_EXTERNAL_ID; + } Statement trackQuery(query.c_str(), db); @@ -82,26 +98,33 @@ bool TrackMetadataQuery::OnRun(Connection& db) { } if (trackQuery.Step() == Row) { - result->SetValue(constants::Track::TRACK_NUM, trackQuery.ColumnText(0)); - result->SetValue(constants::Track::DISC_NUM, trackQuery.ColumnText(1)); - result->SetValue(constants::Track::BPM, trackQuery.ColumnText(2)); - result->SetValue(constants::Track::DURATION, trackQuery.ColumnText(3)); - result->SetValue(constants::Track::FILESIZE, trackQuery.ColumnText(4)); - result->SetValue(constants::Track::YEAR, trackQuery.ColumnText(5)); - result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(6)); - result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(7)); - result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(8)); - result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(9)); - result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(10)); - result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(11)); - result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(12)); - result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(13)); - result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(14)); - result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(15)); - result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(16)); - result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(17)); - result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(18)); - result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(19)); + if (this->type == Full) { + result->SetValue(constants::Track::TRACK_NUM, trackQuery.ColumnText(0)); + result->SetValue(constants::Track::DISC_NUM, trackQuery.ColumnText(1)); + result->SetValue(constants::Track::BPM, trackQuery.ColumnText(2)); + result->SetValue(constants::Track::DURATION, trackQuery.ColumnText(3)); + result->SetValue(constants::Track::FILESIZE, trackQuery.ColumnText(4)); + result->SetValue(constants::Track::YEAR, trackQuery.ColumnText(5)); + result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(6)); + result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(7)); + result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(8)); + result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(9)); + result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(10)); + result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(11)); + result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(12)); + result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(13)); + result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(14)); + result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(15)); + result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(16)); + result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(17)); + result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(18)); + result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(19)); + } + else { + result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(0)); + result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(1)); + } + return true; } diff --git a/src/core/library/query/local/TrackMetadataQuery.h b/src/core/library/query/local/TrackMetadataQuery.h index 2a9154872..00bc955f9 100644 --- a/src/core/library/query/local/TrackMetadataQuery.h +++ b/src/core/library/query/local/TrackMetadataQuery.h @@ -41,9 +41,12 @@ namespace musik { namespace core { namespace db { namespace local { class TrackMetadataQuery : public LocalQueryBase { public: + enum Type { Full, IdsOnly }; + TrackMetadataQuery( musik::core::TrackPtr target, - musik::core::ILibraryPtr library); + musik::core::ILibraryPtr library, + Type type = Full); virtual ~TrackMetadataQuery() { } @@ -56,6 +59,7 @@ class TrackMetadataQuery : public LocalQueryBase { virtual std::string Name() { return "TrackMetadataQuery"; } private: + Type type; ILibraryPtr library; TrackPtr result; }; diff --git a/src/core/sdk/ISimpleDataProvider.h b/src/core/sdk/ISimpleDataProvider.h index 72706c9e9..3f46efdb4 100644 --- a/src/core/sdk/ISimpleDataProvider.h +++ b/src/core/sdk/ISimpleDataProvider.h @@ -99,6 +99,11 @@ namespace musik { namespace core { namespace sdk { const char** externalTrackIds, size_t externalTrackIdCount, int offset = -1) = 0; + + virtual bool AppendToPlaylistWithTrackList( + const int64_t playlistId, + ITrackList* trackList, + int offset = -1) = 0; }; } } } diff --git a/src/plugins/websocket_remote/Constants.h b/src/plugins/websocket_remote/Constants.h index 5fca90c06..b0388297f 100644 --- a/src/plugins/websocket_remote/Constants.h +++ b/src/plugins/websocket_remote/Constants.h @@ -113,6 +113,8 @@ namespace key { static const std::string authenticated = "authenticated"; static const std::string playlist_id = "playlist_id"; static const std::string playlist_name = "playlist_name"; + static const std::string subquery = "subquery"; + static const std::string type = "type"; } namespace value { diff --git a/src/plugins/websocket_remote/WebSocketServer.cpp b/src/plugins/websocket_remote/WebSocketServer.cpp index 2b6cd54f9..36023f5ea 100644 --- a/src/plugins/websocket_remote/WebSocketServer.cpp +++ b/src/plugins/websocket_remote/WebSocketServer.cpp @@ -419,7 +419,7 @@ void WebSocketServer::RespondWithSuccess(connection_hdl connection, const std::s { message::name, name }, { message::id, id }, { message::type, type::response }, - { message::options,{ key::success, true } } + { message::options, {{ key::success, true }} } }; wss->send(connection, success.dump().c_str(), websocketpp::frame::opcode::text); @@ -430,7 +430,7 @@ void WebSocketServer::RespondWithFailure(connection_hdl connection, json& reques { message::name, request[message::name] }, { message::id, request[message::id] }, { message::type, type::response }, - { message::options,{ key::success, false } } + { message::options, {{ key::success, false }} } }; wss->send(connection, error.dump().c_str(), websocketpp::frame::opcode::text); @@ -526,17 +526,20 @@ void WebSocketServer::GetLimitAndOffset(json& options, int& limit, int& offset) } } -void WebSocketServer::RespondWithQueryTracks(connection_hdl connection, json& request) { +ITrackList* WebSocketServer::QueryTracks(json& request, int& limit, int& offset) { if (request.find(message::options) != request.end()) { json& options = request[message::options]; - std::string filter = options.value(key::filter, ""); - - int limit = -1, offset = 0; this->GetLimitAndOffset(options, limit, offset); + return context.dataProvider->QueryTracks(filter.c_str(), limit, offset); + } + return nullptr; +} - ITrackList* tracks = context.dataProvider->QueryTracks(filter.c_str(), limit, offset); - +void WebSocketServer::RespondWithQueryTracks(connection_hdl connection, json& request) { + if (request.find(message::options) != request.end()) { + int limit = -1, offset = 0; + ITrackList* tracks = this->QueryTracks(request, limit, offset); if (this->RespondWithTracks(connection, request, tracks, limit, offset)) { return; } @@ -788,84 +791,87 @@ void WebSocketServer::RespondWithCurrentTime(connection_hdl connection, json& re void WebSocketServer::RespondWithSavePlaylist(connection_hdl connection, json& request) { auto& options = request[message::options]; + int64_t id = options.value(key::playlist_id, 0); - /* by int64 id (faster, but less reliable) */ - if (options.find(key::ids) != options.end()) { - json& ids = options[key::ids]; + if (id) { + /* by int64 id (faster, but less reliable) */ + if (options.find(key::ids) != options.end()) { + json& ids = options[key::ids]; - if (ids.is_array()) { - int64_t id = options.value(key::playlist_id, 0); - std::string name = options.value(key::playlist_name, ""); + if (ids.is_array()) { + std::string name = options.value(key::playlist_name, ""); - size_t count = ids.size(); - int64_t* idArray = new int64_t[count]; + size_t count = ids.size(); + int64_t* idArray = new int64_t[count]; - if (count > 0) { - std::copy(ids.begin(), ids.end(), idArray); + if (count > 0) { + std::copy(ids.begin(), ids.end(), idArray); + } + + int64_t newPlaylistId = this->context.dataProvider + ->SavePlaylistWithIds(idArray, count, name.c_str(), id); + + delete[] idArray; + + if (newPlaylistId != 0) { + this->RespondWithOptions(connection, request, { + { key::playlist_id, newPlaylistId } + }); + return; + } + else { + this->RespondWithFailure(connection, request); + return; + } } + } + /* by external id (slower, more reliable) */ + else if (options.find(key::external_ids) != options.end()) { + json& externalIds = options[key::external_ids]; - int64_t newPlaylistId = this->context.dataProvider - ->SavePlaylistWithIds(idArray, count, name.c_str(), id); + if (externalIds.is_array()) { + std::string name = options.value(key::playlist_name, ""); - delete[] idArray; + size_t count = externalIds.size(); + char** externalIdArray = (char**)malloc(count * sizeof(char*)); - if (newPlaylistId != 0) { - this->RespondWithOptions(connection, request, { - { key::playlist_id, newPlaylistId } - }); - } - else { - this->RespondWithFailure(connection, request); + for (size_t i = 0; i < count; i++) { + std::string externalId = externalIds[i]; + size_t size = externalId.size(); + externalIdArray[i] = (char*)malloc(size + 1); + strncpy(externalIdArray[i], externalId.c_str(), size); + externalIdArray[i][size] = 0; + } + + int64_t newPlaylistId = this->context.dataProvider + ->SavePlaylistWithExternalIds( + (const char**)externalIdArray, + count, + name.c_str(), + id); + + for (size_t i = 0; i < count; i++) { + free(externalIdArray[i]); + } + + free(externalIdArray); + + if (newPlaylistId != 0) { + this->RespondWithOptions(connection, request, { + { key::playlist_id, newPlaylistId } + }); + return; + } + else { + this->RespondWithFailure(connection, request); + return; + } } } } - /* by external id (slower, more reliable) */ - else if (options.find(key::external_ids) != options.end()) { - json& externalIds = options[key::external_ids]; - if (externalIds.is_array()) { - int64_t id = options.value(key::playlist_id, 0); - std::string name = options.value(key::playlist_name, ""); - - size_t count = externalIds.size(); - char** externalIdArray = (char**) malloc(count * sizeof(char*)); - - for (size_t i = 0; i < count; i++) { - std::string externalId = externalIds[i]; - size_t size = externalId.size(); - externalIdArray[i] = (char*) malloc(size + 1); - strncpy(externalIdArray[i], externalId.c_str(), size); - externalIdArray[i][size] = 0; - } - - int64_t newPlaylistId = this->context.dataProvider - ->SavePlaylistWithExternalIds( - (const char**) externalIdArray, - count, - name.c_str(), - id); - - for (size_t i = 0; i < count; i++) { - free(externalIdArray[i]); - } - - free(externalIdArray); - - if (newPlaylistId != 0) { - this->RespondWithOptions(connection, request, { - { key::playlist_id, newPlaylistId } - }); - } - else { - this->RespondWithFailure(connection, request); - } - } - } - /* no id list or external id list */ - else { - this->RespondWithInvalidRequest( - connection, request[message::name], request[message::id]); - } + this->RespondWithInvalidRequest( + connection, request[message::name], request[message::id]); } void WebSocketServer::RespondWithRenamePlaylist(connection_hdl connection, json& request) { @@ -890,69 +896,99 @@ void WebSocketServer::RespondWithDeletePlaylist(connection_hdl connection, json& void WebSocketServer::RespondWithAppendToPlaylist(connection_hdl connection, json& request) { auto& options = request[message::options]; int offset = options.value(key::offset, -1); + int64_t id = options.value(key::playlist_id, 0); - /* by int64 id (faster, but less reliable) */ - if (options.find(key::ids) != options.end()) { - json& ids = options[key::ids]; + if (id) { + /* by int64 id (faster, but less reliable) */ + if (options.find(key::ids) != options.end()) { + json& ids = options[key::ids]; - if (ids.is_array()) { - int64_t id = options.value(key::playlist_id, 0); - size_t count = ids.size(); - int64_t* idArray = new int64_t[count]; + if (ids.is_array()) { + size_t count = ids.size(); + int64_t* idArray = new int64_t[count]; - if (count > 0) { - std::copy(ids.begin(), ids.end(), idArray); + if (count > 0) { + std::copy(ids.begin(), ids.end(), idArray); + } + + bool result = this->context.dataProvider + ->AppendToPlaylistWithIds(id, idArray, count, offset); + + delete[] idArray; + + result + ? this->RespondWithSuccess(connection, request) + : this->RespondWithFailure(connection, request); + + return; } - - bool result = this->context.dataProvider - ->AppendToPlaylistWithIds(id, idArray, count, offset); - - delete[] idArray; - - result - ? this->RespondWithSuccess(connection, request) - : this->RespondWithFailure(connection, request); - - return; } - } - /* by external id (slower, more reliable) */ - else if (options.find(key::external_ids) != options.end()) { - json& externalIds = options[key::external_ids]; + /* by external id (slower, more reliable) */ + else if (options.find(key::external_ids) != options.end()) { + json& externalIds = options[key::external_ids]; - if (externalIds.is_array()) { - int64_t id = options.value(key::playlist_id, 0); - size_t count = externalIds.size(); - char** externalIdArray = (char**)malloc(count * sizeof(char*)); + if (externalIds.is_array()) { + size_t count = externalIds.size(); + char** externalIdArray = (char**)malloc(count * sizeof(char*)); - for (size_t i = 0; i < count; i++) { - std::string externalId = externalIds[i]; - size_t size = externalId.size(); - externalIdArray[i] = (char*)malloc(size + 1); - strncpy(externalIdArray[i], externalId.c_str(), size); - externalIdArray[i][size] = 0; + for (size_t i = 0; i < count; i++) { + std::string externalId = externalIds[i]; + size_t size = externalId.size(); + externalIdArray[i] = (char*)malloc(size + 1); + strncpy(externalIdArray[i], externalId.c_str(), size); + externalIdArray[i][size] = 0; + } + + bool result = this->context.dataProvider + ->AppendToPlaylistWithExternalIds( + id, (const char**)externalIdArray, count, offset); + + for (size_t i = 0; i < count; i++) { + free(externalIdArray[i]); + } + + free(externalIdArray); + + result + ? this->RespondWithSuccess(connection, request) + : this->RespondWithFailure(connection, request); + + return; } + } + /* by subquery (query_tracks or query_tracks_by_category) */ + else if (options.find(key::subquery) != options.end()) { + auto& subquery = options[key::subquery]; + std::string type = subquery.value(key::type, ""); - bool result = this->context.dataProvider - ->AppendToPlaylistWithExternalIds( - id, (const char**)externalIdArray, count, offset); + if (subquery.find(message::options) != subquery.end()) { + ITrackList* tracks = nullptr; + int queryLimit, queryOffset; + if (type == request::query_tracks) { + tracks = this->QueryTracks(subquery, queryLimit, queryOffset); + } + else if (type == request::query_tracks_by_category) { + tracks = this->QueryTracksByCategory(subquery, queryLimit, queryOffset); + } - for (size_t i = 0; i < count; i++) { - free(externalIdArray[i]); + if (tracks) { + bool result = this->context.dataProvider + ->AppendToPlaylistWithTrackList(id, tracks, offset); + + tracks->Release(); + + result + ? this->RespondWithSuccess(connection, request) + : this->RespondWithFailure(connection, request); + + return; + } } - - free(externalIdArray); - - result - ? this->RespondWithSuccess(connection, request) - : this->RespondWithFailure(connection, request); } } /* no id list or external id list */ - else { - this->RespondWithInvalidRequest( - connection, request[message::name], request[message::id]); - } + this->RespondWithInvalidRequest( + connection, request[message::name], request[message::id]); } void WebSocketServer::BroadcastPlaybackOverview() { diff --git a/src/plugins/websocket_remote/WebSocketServer.h b/src/plugins/websocket_remote/WebSocketServer.h index 93034fc2f..24cfd5815 100644 --- a/src/plugins/websocket_remote/WebSocketServer.h +++ b/src/plugins/websocket_remote/WebSocketServer.h @@ -156,6 +156,7 @@ class WebSocketServer { void GetLimitAndOffset(json& options, int& limit, int& offset); ITrackList* QueryTracksByCategory(json& request, int& limit, int& offset); + ITrackList* QueryTracks(json& request, int& limit, int& offset); json ReadTrackMetadata(ITrack* track); void BuildPlaybackOverview(json& options);