From 639629fbb376151d09f05476fdce36e75acc0845 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 9 Feb 2025 21:11:45 +0100 Subject: [PATCH] Added a way to filter by release type --- approot/messages.xml | 1 + approot/messages_fr.xml | 1 + approot/messages_it.xml | 1 + approot/messages_pl.xml | 1 + approot/messages_zh.xml | 1 + src/libs/database/impl/Artist.cpp | 12 +++- src/libs/database/impl/Listen.cpp | 36 ++++++++--- src/libs/database/impl/Release.cpp | 24 ++++++++ src/libs/database/impl/Session.cpp | 4 +- src/libs/database/impl/Track.cpp | 6 ++ src/libs/database/impl/TrackList.cpp | 9 ++- .../database/include/database/Filters.hpp | 7 +++ .../database/include/database/Release.hpp | 1 + src/libs/database/include/database/Types.hpp | 6 ++ src/lms/ui/explore/Filters.cpp | 60 +++++++++++++++++-- src/lms/ui/explore/Filters.hpp | 5 +- 16 files changed, 156 insertions(+), 19 deletions(-) diff --git a/approot/messages.xml b/approot/messages.xml index 9673b06a..04bc9e86 100644 --- a/approot/messages.xml +++ b/approot/messages.xml @@ -192,6 +192,7 @@ Recently modified Recently played Release information +Release type Albums Search Star diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml index 54920f49..6b082834 100644 --- a/approot/messages_fr.xml +++ b/approot/messages_fr.xml @@ -192,6 +192,7 @@ Modifiés récemment Joués récemment Informations sur l'album +Type de publication Albums Rechercher Ajouter aux favoris diff --git a/approot/messages_it.xml b/approot/messages_it.xml index c7ee2ebd..63fdce7e 100644 --- a/approot/messages_it.xml +++ b/approot/messages_it.xml @@ -192,6 +192,7 @@ Modificati di recente Riprodotti di recente Informazioni sull'album +Tipo di pubblicazione Album Ricerca Aggiungi ai preferiti diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml index 6bb2b14d..305e4a30 100644 --- a/approot/messages_pl.xml +++ b/approot/messages_pl.xml @@ -209,6 +209,7 @@ Ostatnio zmienione Ostatnio odtwarzane Informacje o wydaniu +Typ wydania Albumy Szukaj Wyróżnij diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml index 8f0640fc..5193f55f 100644 --- a/approot/messages_zh.xml +++ b/approot/messages_zh.xml @@ -192,6 +192,7 @@ 最近更改 最近播放 + 专辑 搜索 收藏 diff --git a/src/libs/database/impl/Artist.cpp b/src/libs/database/impl/Artist.cpp index 7bec17cf..7a61591a 100644 --- a/src/libs/database/impl/Artist.cpp +++ b/src/libs/database/impl/Artist.cpp @@ -51,7 +51,8 @@ namespace lms::db || params.release.isValid() || params.filters.clusters.size() == 1 || params.filters.mediaLibrary.isValid() - || params.filters.label.isValid()) + || params.filters.label.isValid() + || params.filters.releaseType.isValid()) { query.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id"); } @@ -61,7 +62,8 @@ namespace lms::db || params.writtenAfter.isValid() || params.release.isValid() || params.filters.mediaLibrary.isValid() - || params.filters.label.isValid()) + || params.filters.label.isValid() + || params.filters.releaseType.isValid()) { query.join("track t ON t.id = t_a_l.track_id"); @@ -79,6 +81,12 @@ namespace lms::db query.join("release_label r_l ON r_l.release_id = t.release_id"); query.where("r_l.label_id = ?").bind(params.filters.label); } + + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } } if (params.linkType) diff --git a/src/libs/database/impl/Listen.cpp b/src/libs/database/impl/Listen.cpp index 6704496f..be05082a 100644 --- a/src/libs/database/impl/Listen.cpp +++ b/src/libs/database/impl/Listen.cpp @@ -42,18 +42,26 @@ namespace lms::db assert(!params.artist.isValid()); // poor check - if (params.filters.mediaLibrary.isValid() || params.filters.label.isValid()) + if (params.filters.mediaLibrary.isValid() + || params.filters.label.isValid() + || params.filters.releaseType.isValid()) { query.join("track t ON t.id = t_a_l.track_id"); - } - if (params.filters.mediaLibrary.isValid()) - query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary); + if (params.filters.mediaLibrary.isValid()) + query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary); - if (params.filters.label.isValid()) - { - query.join("release_label r_l ON t.release_id = r_l.release_id"); - query.where("r_l.label_id = ?").bind(params.filters.label); + if (params.filters.label.isValid()) + { + query.join("release_label r_l ON r_l.release_id = t.release_id"); + query.where("r_l.label_id = ?").bind(params.filters.label); + } + + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } } if (params.linkType) @@ -127,6 +135,12 @@ namespace lms::db query.where("r_l.label_id = ?").bind(params.filters.label); } + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = r.id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } + if (!params.filters.clusters.empty()) { std::ostringstream oss; @@ -180,6 +194,12 @@ namespace lms::db query.where("r_l.label_id = ?").bind(params.filters.label); } + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } + if (!params.filters.clusters.empty()) { std::ostringstream oss; diff --git a/src/libs/database/impl/Release.cpp b/src/libs/database/impl/Release.cpp index 37648cf5..add8377a 100644 --- a/src/libs/database/impl/Release.cpp +++ b/src/libs/database/impl/Release.cpp @@ -83,6 +83,12 @@ namespace lms::db query.where("r_l.label_id = ?").bind(params.filters.label); } + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = r.id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } + if (params.directory.isValid()) query.where("t.directory_id = ?").bind(params.directory); @@ -401,6 +407,24 @@ namespace lms::db return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT r_t from release_type r_t").where("r_t.name = ?").bind(name)); } + void ReleaseType::find(Session& session, ReleaseTypeSortMethod sortMethod, std::function func) + { + session.checkReadTransaction(); + + auto query{ session.getDboSession()->find() }; + switch (sortMethod) + { + case ReleaseTypeSortMethod::None: + break; + case ReleaseTypeSortMethod::Name: + query.orderBy("name COLLATE NOCASE"); + } + + utils::forEachQueryResult(query, [&](const ReleaseType::pointer& releaseType) { + func(releaseType); + }); + } + RangeResults ReleaseType::findOrphanIds(Session& session, std::optional range) { session.checkReadTransaction(); diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index 39d3dd0a..0340736b 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -238,7 +238,9 @@ namespace lms::db utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_mbid_idx ON release(mbid)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_name_idx ON release(name)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_name_nocase_idx ON release(name COLLATE NOCASE)"); - utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_type_name_idx ON release_type(name)"); + + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_type_id_idx ON release_type(id)"); + utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS release_type_name_idx ON release_type(name COLLATE NOCASE)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_id_idx ON track(id)"); utils::executeCommand(_session, "CREATE INDEX IF NOT EXISTS track_absolute_path_idx ON track(absolute_file_path)"); diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp index 251dbef9..fae4863a 100644 --- a/src/libs/database/impl/Track.cpp +++ b/src/libs/database/impl/Track.cpp @@ -168,6 +168,12 @@ namespace lms::db query.where("r_l.label_id = ?").bind(params.filters.label); } + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } + if (params.directory.isValid()) query.where("t.directory_id = ?").bind(params.directory); diff --git a/src/libs/database/impl/TrackList.cpp b/src/libs/database/impl/TrackList.cpp index e76bc7bb..9892d93c 100644 --- a/src/libs/database/impl/TrackList.cpp +++ b/src/libs/database/impl/TrackList.cpp @@ -54,7 +54,8 @@ namespace lms::db query.where("t_l.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%"); if (params.filters.mediaLibrary.isValid() - || params.filters.label.isValid()) + || params.filters.label.isValid() + || params.filters.releaseType.isValid()) { query.join("track t ON t.id = t_l_e.track_id"); @@ -66,6 +67,12 @@ namespace lms::db query.join("release_label r_l ON r_l.release_id = t.release_id"); query.where("r_l.label_id = ?").bind(params.filters.label); } + + if (params.filters.releaseType.isValid()) + { + query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id"); + query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType); + } } if (params.user.isValid()) diff --git a/src/libs/database/include/database/Filters.hpp b/src/libs/database/include/database/Filters.hpp index ba4301af..84108568 100644 --- a/src/libs/database/include/database/Filters.hpp +++ b/src/libs/database/include/database/Filters.hpp @@ -24,6 +24,7 @@ #include "database/ClusterId.hpp" #include "database/LabelId.hpp" #include "database/MediaLibraryId.hpp" +#include "database/ReleaseTypeId.hpp" namespace lms::db { @@ -32,6 +33,7 @@ namespace lms::db MediaLibraryId mediaLibrary; // tracks that belongs to this library std::vector clusters; // tracks that belong to all these clusters LabelId label; // tracks which release has this label + ReleaseTypeId releaseType; // tracks which release has this type Filters& setClusters(std::span _clusters) { @@ -48,5 +50,10 @@ namespace lms::db label = _label; return *this; } + Filters& setReleaseType(ReleaseTypeId _releaseType) + { + releaseType = _releaseType; + return *this; + } }; } // namespace lms::db \ No newline at end of file diff --git a/src/libs/database/include/database/Release.hpp b/src/libs/database/include/database/Release.hpp index 028c384d..9b28fcfc 100644 --- a/src/libs/database/include/database/Release.hpp +++ b/src/libs/database/include/database/Release.hpp @@ -124,6 +124,7 @@ namespace lms::db static std::size_t getCount(Session& session); static pointer find(Session& session, ReleaseTypeId id); static pointer find(Session& session, std::string_view name); + static void find(Session& session, ReleaseTypeSortMethod sortMethod, std::function func); static RangeResults findOrphanIds(Session& session, std::optional range = std::nullopt); // Accessors diff --git a/src/libs/database/include/database/Types.hpp b/src/libs/database/include/database/Types.hpp index 9bde8def..e139062f 100644 --- a/src/libs/database/include/database/Types.hpp +++ b/src/libs/database/include/database/Types.hpp @@ -158,6 +158,12 @@ namespace lms::db StarredDateDesc, }; + enum class ReleaseTypeSortMethod + { + None, + Name, + }; + enum class TrackListSortMethod { None, diff --git a/src/lms/ui/explore/Filters.cpp b/src/lms/ui/explore/Filters.cpp index 78cb14b7..1f565c7e 100644 --- a/src/lms/ui/explore/Filters.cpp +++ b/src/lms/ui/explore/Filters.cpp @@ -30,6 +30,7 @@ #include "database/LabelId.hpp" #include "database/MediaLibrary.hpp" #include "database/Release.hpp" +#include "database/ReleaseTypeId.hpp" #include "database/Session.hpp" #include "LmsApplication.hpp" @@ -50,7 +51,11 @@ namespace lms::ui { }; - using TypeVariant = std::variant; + struct ReleaseTypeTag + { + }; + + using TypeVariant = std::variant; using TypeModel = ValueStringModel; std::unique_ptr createTypeModel() @@ -66,11 +71,12 @@ namespace lms::ui typeModel->add(Wt::WString::tr("Lms.Explore.media-library"), MediaLibraryTag{}); typeModel->add(Wt::WString::tr("Lms.Explore.label"), LabelTag{}); + typeModel->add(Wt::WString::tr("Lms.Explore.release-type"), ReleaseTypeTag{}); return typeModel; } - using ValueVariant = std::variant; + using ValueVariant = std::variant; using ValueModel = ValueStringModel; std::unique_ptr createValueModel(TypeVariant type) @@ -93,6 +99,12 @@ namespace lms::ui valueModel->add(Wt::WString::fromUTF8(std::string{ label->getName() }), label->getId()); }); } + else if (std::holds_alternative(type)) + { + db::ReleaseType::find(session, db::ReleaseTypeSortMethod::Name, [&](const db::ReleaseType::pointer& releaseType) { + valueModel->add(Wt::WString::fromUTF8(std::string{ releaseType->getName() }), releaseType->getId()); + }); + } else if (const db::ClusterTypeId * clusterTypeId{ std::get_if(&type) }) { db::Cluster::FindParameters params; @@ -136,6 +148,11 @@ namespace lms::ui set(*labelId); state::writeValue("filters_label_id", labelId->getValue()); } + else if (const db::ReleaseTypeId * releaseTypeId{ std::get_if(&value) }) + { + set(*releaseTypeId); + state::writeValue("filters_release_type_id", releaseTypeId->getValue()); + } else if (const db::ClusterId * clusterId{ std::get_if(&value) }) { add(*clusterId); @@ -176,8 +193,10 @@ namespace lms::ui if (const std::optional mediaLibraryId{ state::readValue("filters_media_library_id") }) set(db::MediaLibraryId{ *mediaLibraryId }); - if (const std::optional mediaLibraryId{ state::readValue("filters_label_id") }) - set(db::LabelId{ *mediaLibraryId }); + if (const std::optional labelId{ state::readValue("filters_label_id") }) + set(db::LabelId{ *labelId }); + if (const std::optional releaseTypeId{ state::readValue("filters_release_type_id") }) + set(db::ReleaseTypeId{ *releaseTypeId }); } void Filters::add(db::ClusterId clusterId) @@ -272,6 +291,39 @@ namespace lms::ui emitFilterAddedNotification(); } + void Filters::set(db::ReleaseTypeId releaseTypeId) + { + if (_releaseTypeFilter) + { + _filters->removeWidget(_releaseTypeFilter); + _releaseTypeFilter = nullptr; + _dbFilters.releaseType = db::ReleaseTypeId{}; + } + + std::string name; + { + auto transaction{ LmsApp->getDbSession().createReadTransaction() }; + + const auto releaseType{ db::ReleaseType::find(LmsApp->getDbSession(), releaseTypeId) }; + if (!releaseType) + return; + + name = releaseType->getName(); + } + + _dbFilters.releaseType = releaseTypeId; + _releaseTypeFilter = _filters->addWidget(utils::createFilter(Wt::WString::fromUTF8(name), Wt::WString::tr("Lms.Explore.release-type"), "bg-dark", true)); + _releaseTypeFilter->clicked().connect(_releaseTypeFilter, [this] { + _filters->removeWidget(_releaseTypeFilter); + _dbFilters.releaseType = db::ReleaseTypeId{}; + _releaseTypeFilter = nullptr; + _sigUpdated.emit(); + state::writeValue("filters_release_type_id", std::nullopt); + }); + + emitFilterAddedNotification(); + } + void Filters::emitFilterAddedNotification() { LmsApp->notifyMsg(Notification::Type::Info, diff --git a/src/lms/ui/explore/Filters.hpp b/src/lms/ui/explore/Filters.hpp index 98e9931b..1407c847 100644 --- a/src/lms/ui/explore/Filters.hpp +++ b/src/lms/ui/explore/Filters.hpp @@ -19,9 +19,6 @@ #pragma once -#include -#include - #include #include #include @@ -45,11 +42,13 @@ namespace lms::ui void showDialog(); void set(db::LabelId labelId); void set(db::MediaLibraryId mediaLibraryId); + void set(db::ReleaseTypeId releaseTypeId); void emitFilterAddedNotification(); Wt::WContainerWidget* _filters{}; Wt::WInteractWidget* _mediaLibraryFilter{}; Wt::WInteractWidget* _labelFilter{}; + Wt::WInteractWidget* _releaseTypeFilter{}; Wt::Signal<> _sigUpdated;