Added the ability to create playlists via ISimpleDataProvider using both

stable (external) ids, and non-stable ids.
This commit is contained in:
casey langen 2017-10-01 00:38:11 -07:00
parent acd5a94c10
commit 41c4f9bbf1
5 changed files with 187 additions and 42 deletions

View File

@ -49,7 +49,6 @@
#include <core/library/track/RetainedTrack.h>
#include <core/library/LocalLibraryConstants.h>
#define TAG "LocalSimpleDataProvider"
using namespace musik::core;
@ -58,6 +57,59 @@ using namespace musik::core::db::local;
using namespace musik::core::library;
using namespace musik::core::sdk;
class ExternalIdListToTrackListQuery : public LocalQueryBase {
public:
ExternalIdListToTrackListQuery(
ILibraryPtr library,
const char** externalIds,
size_t externalIdCount)
{
this->library = library;
this->externalIds = externalIds;
this->externalIdCount = externalIdCount;
}
virtual ~ExternalIdListToTrackListQuery() {
}
std::shared_ptr<TrackList> Result() {
return this->result;
}
protected:
virtual bool OnRun(musik::core::db::Connection& db) {
std::string sql = "SELECT id FROM tracks WHERE external_id IN(";
for (size_t i = 0; i < externalIdCount; i++) {
sql += (i == 0) ? "?" : ",?";
}
sql += ");";
Statement query(sql.c_str(), db);
for (size_t i = 0; i < externalIdCount; i++) {
query.BindText(i, externalIds[i]);
}
this->result = std::make_shared<TrackList>(this->library);
while (query.Step() == Row) {
result->Add(query.ColumnInt64(0));
}
return true;
}
virtual std::string Name() {
return "ExternalIdListToTrackListQuery";
}
private:
ILibraryPtr library;
const char** externalIds;
size_t externalIdCount;
std::shared_ptr<TrackList> result;
};
LocalSimpleDataProvider::LocalSimpleDataProvider(musik::core::ILibraryPtr library)
: library(library) {
@ -213,32 +265,25 @@ IMetadataMapList* LocalSimpleDataProvider::QueryAlbums(const char* filter) {
return this->QueryAlbums(nullptr, -1, filter);
}
uint64_t LocalSimpleDataProvider::SavePlaylist(
int64_t trackIds[],
size_t trackIdCount,
const char* name,
static uint64_t savePlaylist(
ILibraryPtr library,
std::shared_ptr<TrackList> trackList,
const char* playlistName,
const uint64_t playlistId)
{
if (playlistId == 0 && (!name || !strlen(name))) {
return 0;
}
try {
std::shared_ptr<TrackList> sharedTrackList =
std::make_shared<TrackList>(this->library, trackIds, trackIdCount);
/* replacing (and optionally renaming) an existing playlist */
if (playlistId != 0) {
std::shared_ptr<SavePlaylistQuery> query =
SavePlaylistQuery::Replace(playlistId, sharedTrackList);
SavePlaylistQuery::Replace(playlistId, trackList);
this->library->Enqueue(query, ILibrary::QuerySynchronous);
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
if (strlen(name)) {
query = SavePlaylistQuery::Rename(playlistId, name);
if (strlen(playlistName)) {
query = SavePlaylistQuery::Rename(playlistId, playlistName);
this->library->Enqueue(query, ILibrary::QuerySynchronous);
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
return playlistId;
@ -251,9 +296,9 @@ uint64_t LocalSimpleDataProvider::SavePlaylist(
}
else {
std::shared_ptr<SavePlaylistQuery> query =
SavePlaylistQuery::Save(name, sharedTrackList);
SavePlaylistQuery::Save(playlistName, trackList);
this->library->Enqueue(query, ILibrary::QuerySynchronous);
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
return query->GetPlaylistId();
@ -267,6 +312,46 @@ uint64_t LocalSimpleDataProvider::SavePlaylist(
return 0;
}
uint64_t LocalSimpleDataProvider::SavePlaylistWithIds(
int64_t* trackIds,
size_t trackIdCount,
const char* playlistName,
const uint64_t playlistId)
{
if (playlistId == 0 && (!playlistName || !strlen(playlistName))) {
return 0;
}
std::shared_ptr<TrackList> trackList =
std::make_shared<TrackList>(this->library, trackIds, trackIdCount);
return savePlaylist(this->library, trackList, playlistName, playlistId);
}
uint64_t LocalSimpleDataProvider::SavePlaylistWithExternalIds(
const char** externalIds,
size_t externalIdCount,
const char* playlistName,
const uint64_t playlistId)
{
if (playlistId == 0 && (!playlistName || !strlen(playlistName))) {
return 0;
}
using Query = ExternalIdListToTrackListQuery;
std::shared_ptr<Query> query =
std::make_shared<Query> (this->library, externalIds, externalIdCount);
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
return savePlaylist(this->library, query->Result(), playlistName, playlistId);
}
return 0;
}
bool LocalSimpleDataProvider::RenamePlaylist(const uint64_t playlistId, const char* name)
{
try {

View File

@ -78,12 +78,18 @@ namespace musik { namespace core { namespace db { namespace local {
int64_t categoryIdValue,
const char* filter = "") override;
virtual uint64_t SavePlaylist(
int64_t trackIds[],
virtual uint64_t SavePlaylistWithIds(
int64_t* trackIds,
size_t trackIdCount,
const char* name,
const uint64_t playlistId = 0) override;
virtual uint64_t SavePlaylistWithExternalIds(
const char** externalIds,
size_t externalIdCount,
const char* playlistName,
const uint64_t playlistId = 0) override;
virtual bool RenamePlaylist(
const uint64_t playlistId,
const char* name) override;

View File

@ -70,12 +70,18 @@ namespace musik { namespace core { namespace sdk {
int64_t categoryIdValue,
const char* filter = "") = 0;
virtual uint64_t SavePlaylist(
int64_t trackIds[],
virtual uint64_t SavePlaylistWithIds(
int64_t* trackIds,
size_t trackIdCount,
const char* playlistName,
const uint64_t playlistId = 0) = 0;
virtual uint64_t SavePlaylistWithExternalIds(
const char** externalIds,
size_t externalIdCount,
const char* playlistName,
const uint64_t playlistId = 0) = 0;
virtual bool RenamePlaylist(
const uint64_t playlistId,
const char* playlistName) = 0;

View File

@ -80,6 +80,7 @@ namespace key {
static const std::string playing_track = "playing_track";
static const std::string title = "title";
static const std::string external_id = "external_id";
static const std::string external_ids = "external_ids";
static const std::string filename = "filename";
static const std::string duration = "duration";
static const std::string artist = "artist";

View File

@ -785,32 +785,79 @@ void WebSocketServer::RespondWithCurrentTime(connection_hdl connection, json& re
void WebSocketServer::RespondWithSavePlaylist(connection_hdl connection, json& request) {
auto& options = request[message::options];
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, "");
/* by int64 id (faster, but less reliable) */
if (options.find(key::ids) != options.end()) {
json& ids = options[key::ids];
size_t count = ids.size();
int64_t* idArray = new int64_t[count];
if (ids.is_array()) {
int64_t id = options.value(key::playlist_id, 0);
std::string name = options.value(key::playlist_name, "");
if (count > 0) {
std::copy(ids.begin(), ids.end(), idArray);
}
size_t count = ids.size();
int64_t* idArray = new int64_t[count];
uint64_t newPlaylistId = this->context.dataProvider
->SavePlaylist(idArray, count, name.c_str(), id);
if (count > 0) {
std::copy(ids.begin(), ids.end(), idArray);
}
delete[] idArray;
uint64_t newPlaylistId = this->context.dataProvider
->SavePlaylistWithIds(idArray, count, name.c_str(), id);
if (newPlaylistId != 0) {
this->RespondWithOptions(connection, request, {
{ key::playlist_id, newPlaylistId }
});
}
else {
this->RespondWithFailure(connection, request);
delete[] idArray;
if (newPlaylistId != 0) {
this->RespondWithOptions(connection, request, {
{ key::playlist_id, newPlaylistId }
});
}
else {
this->RespondWithFailure(connection, request);
}
}
}
/* 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;
}
uint64_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]);