diff --git a/approot/release.xml b/approot/release.xml index c2f9dcfc..3d6cc3ba 100644 --- a/approot/release.xml +++ b/approot/release.xml @@ -50,7 +50,21 @@ -

${disc-title}

+
+

${disc-title}

+
+ ${play-btn class="d-none d-sm-block btn btn-sm btn-outline-secondary border-0"} + +
+
${tracks class="d-grid gap-1 Lms-row-container"}
diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index 4a53b593..53fabd4e 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -142,6 +142,9 @@ namespace Database if (params.trackNumber) query.where("t.track_number = ?").bind(*params.trackNumber); + if (params.discNumber) + query.where("t.disc_number = ?").bind(*params.discNumber); + if (params.mediaLibrary.isValid()) query.where("t.media_library_id = ?").bind(params.mediaLibrary); diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp index 4a815323..a1cd4fd8 100644 --- a/src/libs/database/include/database/Track.hpp +++ b/src/libs/database/include/database/Track.hpp @@ -78,6 +78,7 @@ namespace Database { std::string releaseName; // matching this release name TrackListId trackList; // matching this trackList std::optional trackNumber; // matching this track number + std::optional discNumber; // matching this disc number MediaLibraryId mediaLibrary; // If set, tracks in this library FindParameters& setClusters(const std::vector& _clusters) { clusters = _clusters; return *this; } @@ -94,6 +95,7 @@ namespace Database { FindParameters& setReleaseName(std::string_view _releaseName) { releaseName = _releaseName; return *this; } FindParameters& setTrackList(TrackListId _trackList) { trackList = _trackList; return *this; } FindParameters& setTrackNumber(int _trackNumber) { trackNumber = _trackNumber; return *this; } + FindParameters& setDiscNumber(int _discNumber) { discNumber = _discNumber; return *this; } FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; } }; diff --git a/src/lms/ui/explore/PlayQueueController.cpp b/src/lms/ui/explore/PlayQueueController.cpp index bf800d19..87119aad 100644 --- a/src/lms/ui/explore/PlayQueueController.cpp +++ b/src/lms/ui/explore/PlayQueueController.cpp @@ -88,6 +88,36 @@ namespace UserInterface return res; } + std::vector getDiscTracks(Database::Session& session, const std::vector& discs, const std::vector& clusters, std::size_t maxTrackCount) + { + using namespace Database; + assert(maxTrackCount); + + std::vector res; + + auto transaction{ session.createReadTransaction() }; + + for (const PlayQueueController::Disc& disc : discs) + { + Database::Track::FindParameters params; + params.setRelease(disc.releaseId); + params.setSortMethod(Database::TrackSortMethod::Release); + params.setDiscNumber(disc.discNumber); + params.setClusters(clusters); + params.setRange(Database::Range{ 0, maxTrackCount - res.size() }); + + const auto tracks{ Database::Track::findIds(session, params) }; + + res.reserve(res.size() + tracks.results.size()); + res.insert(std::end(res), std::cbegin(tracks.results), std::cend(tracks.results)); + + if (res.size() == maxTrackCount) + break; + } + + return res; + } + std::vector getTrackListTracks(Database::Session& session, Database::TrackListId trackListId, const std::vector& clusters, std::size_t maxTrackCount) { using namespace Database; @@ -149,6 +179,12 @@ namespace UserInterface processCommand(command, tracks); } + void PlayQueueController::processCommand(Command command, const std::vector& discs) + { + const std::vector tracks{ getDiscTracks(LmsApp->getDbSession(), discs, _filters.getClusterIds(), _maxTrackCountToEnqueue) }; + processCommand(command, tracks); + } + void PlayQueueController::playTrackInRelease(Database::TrackId trackId) { Database::ReleaseId releaseId; diff --git a/src/lms/ui/explore/PlayQueueController.hpp b/src/lms/ui/explore/PlayQueueController.hpp index a7483f49..08b6106e 100644 --- a/src/lms/ui/explore/PlayQueueController.hpp +++ b/src/lms/ui/explore/PlayQueueController.hpp @@ -45,11 +45,18 @@ namespace UserInterface PlayShuffled, }; - void processCommand(Command command, const std::vector&); - void processCommand(Command command, const std::vector&); - void processCommand(Command command, const std::vector&); - void processCommand(Command command, Database::TrackListId); - void playTrackInRelease(Database::TrackId); + void processCommand(Command command, const std::vector& artists); + void processCommand(Command command, const std::vector& releases); + void processCommand(Command command, const std::vector& tracks); + + struct Disc + { + Database::ReleaseId releaseId; + size_t discNumber; + }; + void processCommand(Command command, const std::vector& discs); + void processCommand(Command command, Database::TrackListId trackList); + void playTrackInRelease(Database::TrackId track); void setMaxTrackCountToEnqueue(std::size_t maxTrackCount) { _maxTrackCountToEnqueue = maxTrackCount; } diff --git a/src/lms/ui/explore/ReleaseView.cpp b/src/lms/ui/explore/ReleaseView.cpp index 0d83012c..fdf49b4a 100644 --- a/src/lms/ui/explore/ReleaseView.cpp +++ b/src/lms/ui/explore/ReleaseView.cpp @@ -340,21 +340,47 @@ namespace UserInterface // Expect to be called in asc order std::map trackContainers; - auto getOrAddDiscContainer = [&](std::size_t discNumber, const std::string& discSubtitle) -> Wt::WContainerWidget* + auto getOrAddDiscContainer = [&, releaseId = _releaseId](std::size_t discNumber, const std::string& discSubtitle) -> Wt::WContainerWidget* { - { - auto it = trackContainers.find(discNumber); - if (it != std::cend(trackContainers)) - return it->second; - } + if (auto it{ trackContainers.find(discNumber) }; it != std::cend(trackContainers)) + return it->second; - Wt::WTemplate* disc{ rootContainer->addNew(Wt::WString::tr("Lms.Explore.Release.template.entry-disc")) }; + Template* disc{ rootContainer->addNew