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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TrackListType>
|
||||||
static bool appendToPlaylist(
|
static bool appendToPlaylist(
|
||||||
ILibraryPtr library,
|
ILibraryPtr library,
|
||||||
const int64_t playlistId,
|
const int64_t playlistId,
|
||||||
std::shared_ptr<TrackList> trackList,
|
TrackListType trackList,
|
||||||
int offset)
|
int offset)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<AppendPlaylistQuery> query =
|
std::shared_ptr<AppendPlaylistQuery> query =
|
||||||
std::make_shared<AppendPlaylistQuery>(
|
std::make_shared<AppendPlaylistQuery>(
|
||||||
playlistId,
|
library, playlistId, trackList, offset);
|
||||||
trackList,
|
|
||||||
offset);
|
|
||||||
|
|
||||||
library->Enqueue(query, ILibrary::QuerySynchronous);
|
library->Enqueue(query, ILibrary::QuerySynchronous);
|
||||||
|
|
||||||
@ -447,3 +446,14 @@ bool LocalSimpleDataProvider::AppendToPlaylistWithExternalIds(
|
|||||||
return 0;
|
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,
|
size_t externalIdCount,
|
||||||
int offset = -1) override;
|
int offset = -1) override;
|
||||||
|
|
||||||
|
virtual bool AppendToPlaylistWithTrackList(
|
||||||
|
const int64_t playlistId,
|
||||||
|
musik::core::sdk::ITrackList* trackList,
|
||||||
|
int offset = -1) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
musik::core::ILibraryPtr library;
|
musik::core::ILibraryPtr library;
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,8 @@
|
|||||||
|
|
||||||
#include "pch.hpp"
|
#include "pch.hpp"
|
||||||
#include "AppendPlaylistQuery.h"
|
#include "AppendPlaylistQuery.h"
|
||||||
|
#include <core/library/track/LibraryTrack.h>
|
||||||
|
#include <core/library/query/local/TrackMetadataQuery.h>
|
||||||
#include <core/library/LocalLibraryConstants.h>
|
#include <core/library/LocalLibraryConstants.h>
|
||||||
#include <core/db/Statement.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 = ?";
|
"SELECT MAX(sort_order) from playlist_tracks where playlist_id = ?";
|
||||||
|
|
||||||
AppendPlaylistQuery::AppendPlaylistQuery(
|
AppendPlaylistQuery::AppendPlaylistQuery(
|
||||||
|
musik::core::ILibraryPtr library,
|
||||||
const int64_t playlistId,
|
const int64_t playlistId,
|
||||||
std::shared_ptr<musik::core::TrackList> tracks,
|
std::shared_ptr<musik::core::TrackList> tracks,
|
||||||
const int offset)
|
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)
|
, playlistId(playlistId)
|
||||||
, offset(offset) {
|
, offset(offset) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendPlaylistQuery::OnRun(musik::core::db::Connection &db) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,20 +117,33 @@ bool AppendPlaylistQuery::OnRun(musik::core::db::Connection &db) {
|
|||||||
|
|
||||||
Statement insertTrack(INSERT_PLAYLIST_TRACK_QUERY.c_str(), db);
|
Statement insertTrack(INSERT_PLAYLIST_TRACK_QUERY.c_str(), db);
|
||||||
|
|
||||||
for (size_t i = 0; i < this->tracks->Count(); i++) {
|
for (size_t i = 0; i < tracks->Count(); i++) {
|
||||||
auto track = this->tracks->Get(i);
|
auto id = tracks->GetId(i);
|
||||||
insertTrack.Reset();
|
auto target = TrackPtr(new LibraryTrack(id, this->library));
|
||||||
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) {
|
std::shared_ptr<TrackMetadataQuery> query(
|
||||||
return false;
|
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();
|
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 {
|
class AppendPlaylistQuery : public musik::core::db::LocalQueryBase {
|
||||||
public:
|
public:
|
||||||
AppendPlaylistQuery(
|
AppendPlaylistQuery(
|
||||||
|
musik::core::ILibraryPtr library,
|
||||||
const int64_t playlistId,
|
const int64_t playlistId,
|
||||||
std::shared_ptr<musik::core::TrackList> tracks,
|
std::shared_ptr<musik::core::TrackList> tracks,
|
||||||
const int offset = -1);
|
const int offset = -1);
|
||||||
|
|
||||||
|
AppendPlaylistQuery(
|
||||||
|
musik::core::ILibraryPtr library,
|
||||||
|
const int64_t playlistId,
|
||||||
|
musik::core::sdk::ITrackList *tracks,
|
||||||
|
const int offset = -1);
|
||||||
|
|
||||||
virtual ~AppendPlaylistQuery() { }
|
virtual ~AppendPlaylistQuery() { }
|
||||||
|
|
||||||
std::string Name() { return "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);
|
virtual bool OnRun(musik::core::db::Connection &db);
|
||||||
|
|
||||||
int64_t playlistId;
|
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;
|
int offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,17 +55,33 @@ static const std::string ALL_METADATA_QUERY_BY_EXTERNAL_ID =
|
|||||||
"FROM " + TABLES + " " +
|
"FROM " + TABLES + " " +
|
||||||
"WHERE t.external_id=? AND " + PREDICATE;
|
"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->result = target;
|
||||||
this->library = library;
|
this->library = library;
|
||||||
|
this->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackMetadataQuery::OnRun(Connection& db) {
|
bool TrackMetadataQuery::OnRun(Connection& db) {
|
||||||
bool queryById = this->result->GetId() != 0;
|
bool queryById = this->result->GetId() != 0;
|
||||||
|
|
||||||
const std::string& query = queryById
|
std::string query;
|
||||||
? ALL_METADATA_QUERY_BY_ID
|
|
||||||
: ALL_METADATA_QUERY_BY_EXTERNAL_ID;
|
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);
|
Statement trackQuery(query.c_str(), db);
|
||||||
|
|
||||||
@ -82,26 +98,33 @@ bool TrackMetadataQuery::OnRun(Connection& db) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (trackQuery.Step() == Row) {
|
if (trackQuery.Step() == Row) {
|
||||||
result->SetValue(constants::Track::TRACK_NUM, trackQuery.ColumnText(0));
|
if (this->type == Full) {
|
||||||
result->SetValue(constants::Track::DISC_NUM, trackQuery.ColumnText(1));
|
result->SetValue(constants::Track::TRACK_NUM, trackQuery.ColumnText(0));
|
||||||
result->SetValue(constants::Track::BPM, trackQuery.ColumnText(2));
|
result->SetValue(constants::Track::DISC_NUM, trackQuery.ColumnText(1));
|
||||||
result->SetValue(constants::Track::DURATION, trackQuery.ColumnText(3));
|
result->SetValue(constants::Track::BPM, trackQuery.ColumnText(2));
|
||||||
result->SetValue(constants::Track::FILESIZE, trackQuery.ColumnText(4));
|
result->SetValue(constants::Track::DURATION, trackQuery.ColumnText(3));
|
||||||
result->SetValue(constants::Track::YEAR, trackQuery.ColumnText(5));
|
result->SetValue(constants::Track::FILESIZE, trackQuery.ColumnText(4));
|
||||||
result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(6));
|
result->SetValue(constants::Track::YEAR, trackQuery.ColumnText(5));
|
||||||
result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(7));
|
result->SetValue(constants::Track::TITLE, trackQuery.ColumnText(6));
|
||||||
result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(8));
|
result->SetValue(constants::Track::FILENAME, trackQuery.ColumnText(7));
|
||||||
result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(9));
|
result->SetValue(constants::Track::THUMBNAIL_ID, trackQuery.ColumnText(8));
|
||||||
result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(10));
|
result->SetValue(constants::Track::ALBUM, trackQuery.ColumnText(9));
|
||||||
result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(11));
|
result->SetValue(constants::Track::ALBUM_ARTIST, trackQuery.ColumnText(10));
|
||||||
result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(12));
|
result->SetValue(constants::Track::GENRE, trackQuery.ColumnText(11));
|
||||||
result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(13));
|
result->SetValue(constants::Track::ARTIST, trackQuery.ColumnText(12));
|
||||||
result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(14));
|
result->SetValue(constants::Track::FILETIME, trackQuery.ColumnText(13));
|
||||||
result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(15));
|
result->SetValue(constants::Track::GENRE_ID, trackQuery.ColumnText(14));
|
||||||
result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(16));
|
result->SetValue(constants::Track::ARTIST_ID, trackQuery.ColumnText(15));
|
||||||
result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(17));
|
result->SetValue(constants::Track::ALBUM_ARTIST_ID, trackQuery.ColumnText(16));
|
||||||
result->SetValue(constants::Track::SOURCE_ID, trackQuery.ColumnText(18));
|
result->SetValue(constants::Track::ALBUM_ID, trackQuery.ColumnText(17));
|
||||||
result->SetValue(constants::Track::EXTERNAL_ID, trackQuery.ColumnText(19));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +41,12 @@ namespace musik { namespace core { namespace db { namespace local {
|
|||||||
|
|
||||||
class TrackMetadataQuery : public LocalQueryBase {
|
class TrackMetadataQuery : public LocalQueryBase {
|
||||||
public:
|
public:
|
||||||
|
enum Type { Full, IdsOnly };
|
||||||
|
|
||||||
TrackMetadataQuery(
|
TrackMetadataQuery(
|
||||||
musik::core::TrackPtr target,
|
musik::core::TrackPtr target,
|
||||||
musik::core::ILibraryPtr library);
|
musik::core::ILibraryPtr library,
|
||||||
|
Type type = Full);
|
||||||
|
|
||||||
virtual ~TrackMetadataQuery() { }
|
virtual ~TrackMetadataQuery() { }
|
||||||
|
|
||||||
@ -56,6 +59,7 @@ class TrackMetadataQuery : public LocalQueryBase {
|
|||||||
virtual std::string Name() { return "TrackMetadataQuery"; }
|
virtual std::string Name() { return "TrackMetadataQuery"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Type type;
|
||||||
ILibraryPtr library;
|
ILibraryPtr library;
|
||||||
TrackPtr result;
|
TrackPtr result;
|
||||||
};
|
};
|
||||||
|
@ -99,6 +99,11 @@ namespace musik { namespace core { namespace sdk {
|
|||||||
const char** externalTrackIds,
|
const char** externalTrackIds,
|
||||||
size_t externalTrackIdCount,
|
size_t externalTrackIdCount,
|
||||||
int offset = -1) = 0;
|
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 authenticated = "authenticated";
|
||||||
static const std::string playlist_id = "playlist_id";
|
static const std::string playlist_id = "playlist_id";
|
||||||
static const std::string playlist_name = "playlist_name";
|
static const std::string playlist_name = "playlist_name";
|
||||||
|
static const std::string subquery = "subquery";
|
||||||
|
static const std::string type = "type";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace value {
|
namespace value {
|
||||||
|
@ -419,7 +419,7 @@ void WebSocketServer::RespondWithSuccess(connection_hdl connection, const std::s
|
|||||||
{ message::name, name },
|
{ message::name, name },
|
||||||
{ message::id, id },
|
{ message::id, id },
|
||||||
{ message::type, type::response },
|
{ 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);
|
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::name, request[message::name] },
|
||||||
{ message::id, request[message::id] },
|
{ message::id, request[message::id] },
|
||||||
{ message::type, type::response },
|
{ 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);
|
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()) {
|
if (request.find(message::options) != request.end()) {
|
||||||
json& options = request[message::options];
|
json& options = request[message::options];
|
||||||
|
|
||||||
std::string filter = options.value(key::filter, "");
|
std::string filter = options.value(key::filter, "");
|
||||||
|
|
||||||
int limit = -1, offset = 0;
|
|
||||||
this->GetLimitAndOffset(options, limit, offset);
|
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)) {
|
if (this->RespondWithTracks(connection, request, tracks, limit, offset)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -788,84 +791,87 @@ void WebSocketServer::RespondWithCurrentTime(connection_hdl connection, json& re
|
|||||||
|
|
||||||
void WebSocketServer::RespondWithSavePlaylist(connection_hdl connection, json& request) {
|
void WebSocketServer::RespondWithSavePlaylist(connection_hdl connection, json& request) {
|
||||||
auto& options = request[message::options];
|
auto& options = request[message::options];
|
||||||
|
int64_t id = options.value(key::playlist_id, 0);
|
||||||
|
|
||||||
/* by int64 id (faster, but less reliable) */
|
if (id) {
|
||||||
if (options.find(key::ids) != options.end()) {
|
/* by int64 id (faster, but less reliable) */
|
||||||
json& ids = options[key::ids];
|
if (options.find(key::ids) != options.end()) {
|
||||||
|
json& ids = options[key::ids];
|
||||||
|
|
||||||
if (ids.is_array()) {
|
if (ids.is_array()) {
|
||||||
int64_t id = options.value(key::playlist_id, 0);
|
std::string name = options.value(key::playlist_name, "");
|
||||||
std::string name = options.value(key::playlist_name, "");
|
|
||||||
|
|
||||||
size_t count = ids.size();
|
size_t count = ids.size();
|
||||||
int64_t* idArray = new int64_t[count];
|
int64_t* idArray = new int64_t[count];
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
std::copy(ids.begin(), ids.end(), idArray);
|
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
|
if (externalIds.is_array()) {
|
||||||
->SavePlaylistWithIds(idArray, count, name.c_str(), id);
|
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) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
this->RespondWithOptions(connection, request, {
|
std::string externalId = externalIds[i];
|
||||||
{ key::playlist_id, newPlaylistId }
|
size_t size = externalId.size();
|
||||||
});
|
externalIdArray[i] = (char*)malloc(size + 1);
|
||||||
}
|
strncpy(externalIdArray[i], externalId.c_str(), size);
|
||||||
else {
|
externalIdArray[i][size] = 0;
|
||||||
this->RespondWithFailure(connection, request);
|
}
|
||||||
|
|
||||||
|
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()) {
|
this->RespondWithInvalidRequest(
|
||||||
int64_t id = options.value(key::playlist_id, 0);
|
connection, request[message::name], request[message::id]);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketServer::RespondWithRenamePlaylist(connection_hdl connection, json& request) {
|
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) {
|
void WebSocketServer::RespondWithAppendToPlaylist(connection_hdl connection, json& request) {
|
||||||
auto& options = request[message::options];
|
auto& options = request[message::options];
|
||||||
int offset = options.value(key::offset, -1);
|
int offset = options.value(key::offset, -1);
|
||||||
|
int64_t id = options.value(key::playlist_id, 0);
|
||||||
|
|
||||||
/* by int64 id (faster, but less reliable) */
|
if (id) {
|
||||||
if (options.find(key::ids) != options.end()) {
|
/* by int64 id (faster, but less reliable) */
|
||||||
json& ids = options[key::ids];
|
if (options.find(key::ids) != options.end()) {
|
||||||
|
json& ids = options[key::ids];
|
||||||
|
|
||||||
if (ids.is_array()) {
|
if (ids.is_array()) {
|
||||||
int64_t id = options.value(key::playlist_id, 0);
|
size_t count = ids.size();
|
||||||
size_t count = ids.size();
|
int64_t* idArray = new int64_t[count];
|
||||||
int64_t* idArray = new int64_t[count];
|
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
std::copy(ids.begin(), ids.end(), idArray);
|
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) */
|
||||||
/* by external id (slower, more reliable) */
|
else if (options.find(key::external_ids) != options.end()) {
|
||||||
else if (options.find(key::external_ids) != options.end()) {
|
json& externalIds = options[key::external_ids];
|
||||||
json& externalIds = options[key::external_ids];
|
|
||||||
|
|
||||||
if (externalIds.is_array()) {
|
if (externalIds.is_array()) {
|
||||||
int64_t id = options.value(key::playlist_id, 0);
|
size_t count = externalIds.size();
|
||||||
size_t count = externalIds.size();
|
char** externalIdArray = (char**)malloc(count * sizeof(char*));
|
||||||
char** externalIdArray = (char**)malloc(count * sizeof(char*));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
std::string externalId = externalIds[i];
|
std::string externalId = externalIds[i];
|
||||||
size_t size = externalId.size();
|
size_t size = externalId.size();
|
||||||
externalIdArray[i] = (char*)malloc(size + 1);
|
externalIdArray[i] = (char*)malloc(size + 1);
|
||||||
strncpy(externalIdArray[i], externalId.c_str(), size);
|
strncpy(externalIdArray[i], externalId.c_str(), size);
|
||||||
externalIdArray[i][size] = 0;
|
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
|
if (subquery.find(message::options) != subquery.end()) {
|
||||||
->AppendToPlaylistWithExternalIds(
|
ITrackList* tracks = nullptr;
|
||||||
id, (const char**)externalIdArray, count, offset);
|
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++) {
|
if (tracks) {
|
||||||
free(externalIdArray[i]);
|
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 */
|
/* no id list or external id list */
|
||||||
else {
|
this->RespondWithInvalidRequest(
|
||||||
this->RespondWithInvalidRequest(
|
connection, request[message::name], request[message::id]);
|
||||||
connection, request[message::name], request[message::id]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketServer::BroadcastPlaybackOverview() {
|
void WebSocketServer::BroadcastPlaybackOverview() {
|
||||||
|
@ -156,6 +156,7 @@ class WebSocketServer {
|
|||||||
|
|
||||||
void GetLimitAndOffset(json& options, int& limit, int& offset);
|
void GetLimitAndOffset(json& options, int& limit, int& offset);
|
||||||
ITrackList* QueryTracksByCategory(json& request, int& limit, int& offset);
|
ITrackList* QueryTracksByCategory(json& request, int& limit, int& offset);
|
||||||
|
ITrackList* QueryTracks(json& request, int& limit, int& offset);
|
||||||
json ReadTrackMetadata(ITrack* track);
|
json ReadTrackMetadata(ITrack* track);
|
||||||
void BuildPlaybackOverview(json& options);
|
void BuildPlaybackOverview(json& options);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user