mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 13:02:35 +00:00
A handful of additions, speed-ups, and new features:
1. Optimized AppendPlaylistQuery and TrackMetadataQuery to not query extraneous metadata -- only the required IDs. 2. Updated the `append_to_playlist` command in the remote server to allow for track subqueries -- `query_tracks` and `query_tracks_by_category` are both supported. 3. Fixed bugs in `WebSocketServer::RespondWithSuccess` and `WebSocketServer::RespondWithFailure` where the `success` flag was not being properly returned.
This commit is contained in:
parent
47c2fa3f82
commit
d73178ed4e
@ -389,18 +389,17 @@ bool LocalSimpleDataProvider::DeletePlaylist(const int64_t playlistId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TrackListType>
|
||||
static bool appendToPlaylist(
|
||||
ILibraryPtr library,
|
||||
const int64_t playlistId,
|
||||
std::shared_ptr<TrackList> trackList,
|
||||
TrackListType trackList,
|
||||
int offset)
|
||||
{
|
||||
try {
|
||||
std::shared_ptr<AppendPlaylistQuery> query =
|
||||
std::make_shared<AppendPlaylistQuery>(
|
||||
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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -34,7 +34,8 @@
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "AppendPlaylistQuery.h"
|
||||
|
||||
#include <core/library/track/LibraryTrack.h>
|
||||
#include <core/library/query/local/TrackMetadataQuery.h>
|
||||
#include <core/library/LocalLibraryConstants.h>
|
||||
#include <core/db/Statement.h>
|
||||
|
||||
@ -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<musik::core::TrackList> 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<TrackMetadataQuery> 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;
|
||||
}
|
@ -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<musik::core::TrackList> 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<musik::core::TrackList> tracks;
|
||||
|
||||
musik::core::ILibraryPtr library;
|
||||
std::shared_ptr<musik::core::TrackList> sharedTracks;
|
||||
musik::core::sdk::ITrackList* rawTracks;
|
||||
int offset;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user