From 472a5907adca35d5ce0c912cf503d57cdddad05a Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 31 Oct 2024 18:49:57 +0100 Subject: [PATCH] Subsonci API: added savePlayQueue / getPlayQueue support --- src/libs/database/CMakeLists.txt | 1 + src/libs/database/impl/Migration.cpp | 28 +++++- src/libs/database/impl/PlayQueue.cpp | 97 +++++++++++++++++++ src/libs/database/impl/Session.cpp | 2 + .../database/include/database/PlayQueue.hpp | 97 +++++++++++++++++++ src/libs/database/test/Migration.cpp | 2 + src/libs/subsonic/impl/SubsonicResource.cpp | 4 +- .../subsonic/impl/entrypoints/Bookmarks.cpp | 80 +++++++++++++++ .../subsonic/impl/entrypoints/Bookmarks.hpp | 2 + .../subsonic/impl/entrypoints/Browsing.cpp | 11 +-- 10 files changed, 315 insertions(+), 9 deletions(-) create mode 100644 src/libs/database/impl/PlayQueue.cpp create mode 100644 src/libs/database/include/database/PlayQueue.hpp diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt index 3b2bf1d2..af4a6a1b 100644 --- a/src/libs/database/CMakeLists.txt +++ b/src/libs/database/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(lmsdatabase SHARED impl/Listen.cpp impl/MediaLibrary.cpp impl/Migration.cpp + impl/PlayQueue.cpp impl/TrackArtistLink.cpp impl/TrackFeatures.cpp impl/TrackList.cpp diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index d1a0a1ce..179ca438 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -35,7 +35,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 71 }; + static constexpr Version LMS_DATABASE_VERSION{ 72 }; } VersionInfo::VersionInfo() @@ -907,6 +907,31 @@ SELECT utils::executeCommand(*session.getDboSession(), "UPDATE scan_settings SET scan_version = scan_version + 1"); } + void migrateFromV71(Session& session) + { + // Add a file name/stem in tracks + utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "playqueue" ( + "id" integer primary key autoincrement, + "version" integer not null, + "name" text not null, + "current_index" integer not null, + "current_position_in_track" integer, + "last_modified_date_time" text, + "user_id" bigint, + constraint "fk_playqueue_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred +))"); + + utils::executeCommand(*session.getDboSession(), R"(CREATE TABLE IF NOT EXISTS "playqueue_track" ( + "playqueue_id" bigint, + "track_id" bigint not null, + primary key ("playqueue_id", "track_id"), + constraint "fk_playqueue_track_key1" foreign key ("playqueue_id") references "playqueue" ("id") on delete cascade deferrable initially deferred, + constraint "fk_playqueue_track_key2" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred +))"); + utils::executeCommand(*session.getDboSession(), R"(CREATE INDEX "playqueue_track_playqueue" on "playqueue_track" ("playqueue_id"))"); + utils::executeCommand(*session.getDboSession(), R"(CREATE INDEX "playqueue_track_track" on "playqueue_track" ("track_id"))"); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -954,6 +979,7 @@ SELECT { 68, migrateFromV68 }, { 69, migrateFromV69 }, { 70, migrateFromV70 }, + { 71, migrateFromV71 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/PlayQueue.cpp b/src/libs/database/impl/PlayQueue.cpp new file mode 100644 index 00000000..e08efbab --- /dev/null +++ b/src/libs/database/impl/PlayQueue.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 Emeric Poupon + * + * This file is part of LMS. + * + * LMS 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. + * + * LMS 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 LMS. If not, see . + */ + +#include "database/PlayQueue.hpp" + +#include + +#include "database/Directory.hpp" +#include "database/MediaLibrary.hpp" +#include "database/Release.hpp" +#include "database/Session.hpp" +#include "database/Track.hpp" +#include "database/User.hpp" + +#include "IdTypeTraits.hpp" +#include "StringViewTraits.hpp" +#include "Utils.hpp" + +namespace lms::db +{ + PlayQueue::PlayQueue(const ObjectPtr& user, std::string_view name) + : _name{ name } + , _user{ getDboPtr(user) } + { + } + + PlayQueue::pointer PlayQueue::create(Session& session, const ObjectPtr& user, std::string_view name) + { + return session.getDboSession()->add(std::unique_ptr{ new PlayQueue{ user, name } }); + } + + std::size_t PlayQueue::getCount(Session& session) + { + session.checkReadTransaction(); + + return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(*) FROM playqueue")); + } + + PlayQueue::pointer PlayQueue::find(Session& session, PlayQueueId id) + { + session.checkReadTransaction(); + + return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT p from playqueue p").where("p.id = ?").bind(id)); + } + + PlayQueue::pointer PlayQueue::find(Session& session, UserId userId, std::string_view name) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->query>("SELECT p from playqueue p") }; + query.where("p.user_id = ?").bind(userId); + query.where("p.name = ?").bind(name); + + return utils::fetchQuerySingleResult(query); + } + + void PlayQueue::clear() + { + _tracks.clear(); + } + + void PlayQueue::addTrack(const ObjectPtr& track) + { + _tracks.insert(getDboPtr(track)); + } + + Track::pointer PlayQueue::getTrackAtCurrentIndex() const + { + auto query{ _tracks.find() }; + query.offset(_currentIndex); + query.limit(1); + + return utils::fetchQuerySingleResult(query); + } + + void PlayQueue::visitTracks(const std::function& track)>& visitor) const + { + utils::forEachQueryResult(_tracks.find(), visitor); + } + +} // namespace lms::db diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 23f6d637..afd1b89a 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -30,6 +30,7 @@ #include "database/Image.hpp" #include "database/Listen.hpp" #include "database/MediaLibrary.hpp" +#include "database/PlayQueue.hpp" #include "database/RatedArtist.hpp" #include "database/RatedRelease.hpp" #include "database/RatedTrack.hpp" @@ -104,6 +105,7 @@ namespace lms::db _session.mapClass