diff --git a/approot/artist.xml b/approot/artist.xml
index 2b3f5730..24045219 100644
--- a/approot/artist.xml
+++ b/approot/artist.xml
@@ -4,7 +4,7 @@
-
${name}
+
${name}
${clusters class="mb-2"}
${play-btn class="btn btn-primary"}
@@ -20,17 +20,21 @@
- ${}
+ ${}
+ ${}${tr:Lms.Explore.releases}
${}
${releases class="mb-3"}
- ${}
- ${}
+ ${}
+ ${}
+ ${}${tr:Lms.Explore.Artist.appears-on}
${}
+ ${appears-on-releases class="mb-3"}
+ ${}
+ ${}
+ ${}${tr:Lms.Explore.tracks}
${}
${tracks class="mb-3"}
- ${}
+ ${}
${}
-
-
${tr:Lms.Explore.Artist.similar-artists}
- ${similar-artists class="d-grid gap-3"}
-
+ ${tr:Lms.Explore.Artist.similar-artists}
+ ${similar-artists class="d-grid gap-3"}
${}
diff --git a/approot/messages.xml b/approot/messages.xml
index 0acf1da1..93d68433 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -137,6 +137,7 @@
Various artists
+Appears on
Similar artists
diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml
index b4572718..7a9c708a 100644
--- a/approot/messages_fr.xml
+++ b/approot/messages_fr.xml
@@ -137,6 +137,7 @@
Artistes divers
+Apparitions
Artistes similaires
diff --git a/approot/messages_it.xml b/approot/messages_it.xml
index b8648405..7fd6fdfd 100644
--- a/approot/messages_it.xml
+++ b/approot/messages_it.xml
@@ -136,6 +136,7 @@
Vari artisti
+
Artisti simili
diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml
index fca04e46..094fffa0 100644
--- a/approot/messages_zh.xml
+++ b/approot/messages_zh.xml
@@ -137,6 +137,7 @@
群星
+
相似歌手
diff --git a/approot/release.xml b/approot/release.xml
index d964b8c2..715c2d3d 100644
--- a/approot/release.xml
+++ b/approot/release.xml
@@ -12,7 +12,7 @@
${cover}
-
${name}
+
${name}
${
}${artists}${}
${
}${tr:Lms.Explore.various-artists}
${}
${}${year}${} (${orig-year})${} · ${}${duration}
diff --git a/src/libs/services/database/impl/Release.cpp b/src/libs/services/database/impl/Release.cpp
index c268ef7c..4513f9cd 100644
--- a/src/libs/services/database/impl/Release.cpp
+++ b/src/libs/services/database/impl/Release.cpp
@@ -41,7 +41,8 @@ createQuery(Session& session, const Release::FindParameters& params)
if (params.sortMethod == ReleaseSortMethod::LastWritten
|| params.writtenAfter.isValid()
- || params.dateRange)
+ || params.dateRange
+ || params.artist.isValid())
{
query.join("track t ON t.release_id = r.id");
}
@@ -66,6 +67,55 @@ createQuery(Session& session, const Release::FindParameters& params)
.where("s_r.scrobbler = ?").bind(*params.scrobbler);
}
+ if (params.artist.isValid())
+ {
+ query.join("artist a ON a.id = t_a_l.artist_id")
+ .join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
+ .where("a.id = ?").bind(params.artist);
+
+ if (!params.trackArtistLinkTypes.empty())
+ {
+ std::ostringstream oss;
+
+ bool first {true};
+ for (TrackArtistLinkType linkType : params.trackArtistLinkTypes)
+ {
+ if (!first)
+ oss << " OR ";
+ oss << "t_a_l.type = ?";
+ query.bind(linkType);
+
+ first = false;
+ }
+ query.where(oss.str());
+ }
+
+ if (!params.excludedTrackArtistLinkTypes.empty())
+ {
+ std::ostringstream oss;
+ oss << "r.id NOT IN (SELECT DISTINCT r.id FROM release r"
+ " INNER JOIN artist a ON a.id = t_a_l.artist_id"
+ " INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
+ " INNER JOIN track t ON t.release_id = r.id"
+ " WHERE (a.id = ? AND (";
+
+ query.bind(params.artist);
+
+ bool first {true};
+ for (const TrackArtistLinkType linkType : params.excludedTrackArtistLinkTypes)
+ {
+ if (!first)
+ oss << " OR ";
+ oss << "t_a_l.type = ?";
+ query.bind(linkType);
+
+ first = false;
+ }
+ oss << ")))";
+ query.where(oss.str());
+ }
+ }
+
if (!params.clusters.empty())
{
std::ostringstream oss;
@@ -103,6 +153,9 @@ createQuery(Session& session, const Release::FindParameters& params)
case ReleaseSortMethod::Date:
query.orderBy("t.date, r.name COLLATE NOCASE");
break;
+ case ReleaseSortMethod::DateDesc:
+ query.orderBy("t.date DESC, r.name COLLATE NOCASE");
+ break;
case ReleaseSortMethod::StarredDateDesc:
assert(params.starringUser.isValid());
query.orderBy("s_r.date_time DESC");
diff --git a/src/libs/services/database/impl/Session.cpp b/src/libs/services/database/impl/Session.cpp
index 660e7082..ec41e43c 100644
--- a/src/libs/services/database/impl/Session.cpp
+++ b/src/libs/services/database/impl/Session.cpp
@@ -151,9 +151,9 @@ Session::prepareTables()
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_user_idx ON tracklist(user_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_features_track_idx ON track_features(track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_artist_idx ON track_artist_link(artist_id)");
- _session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_name_idx ON track_artist_link(name)");
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_track_idx ON track_artist_link(track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_type_idx ON track_artist_link(type)");
+ _session.execute("CREATE INDEX IF NOT EXISTS track_artist_link_artist_type_idx ON track_artist_link(artist_id,type)");
_session.execute("CREATE INDEX IF NOT EXISTS track_bookmark_user_idx ON track_bookmark(user_id)");
_session.execute("CREATE INDEX IF NOT EXISTS track_bookmark_user_track_idx ON track_bookmark(user_id,track_id)");
_session.execute("CREATE INDEX IF NOT EXISTS listen_scrobbler_idx ON listen(scrobbler)");
diff --git a/src/libs/services/database/include/services/database/Release.hpp b/src/libs/services/database/include/services/database/Release.hpp
index 999899a6..ed11e694 100644
--- a/src/libs/services/database/include/services/database/Release.hpp
+++ b/src/libs/services/database/include/services/database/Release.hpp
@@ -25,11 +25,13 @@
#include
#include
+#include "services/database/ArtistId.hpp"
#include "services/database/ClusterId.hpp"
#include "services/database/Object.hpp"
#include "services/database/ReleaseId.hpp"
#include "services/database/Types.hpp"
#include "services/database/UserId.hpp"
+#include "utils/EnumSet.hpp"
#include "utils/UUID.hpp"
namespace Database
@@ -54,8 +56,11 @@ class Release : public Object
Range range;
Wt::WDateTime writtenAfter;
std::optional dateRange;
- UserId starringUser; // only releases starred by this user
- std::optional scrobbler; // and for this scrobbler
+ UserId starringUser; // only releases starred by this user
+ std::optional scrobbler; // and for this scrobbler
+ ArtistId artist; // only releases that involved this user
+ EnumSet trackArtistLinkTypes; // and for these link types
+ EnumSet excludedTrackArtistLinkTypes; // but not for these link types
FindParameters& setClusters(const std::vector& _clusters) { clusters = _clusters; return *this; }
FindParameters& setKeywords(const std::vector& _keywords) { keywords = _keywords; return *this; }
@@ -64,6 +69,13 @@ class Release : public Object
FindParameters& setWrittenAfter(const Wt::WDateTime& _after) {writtenAfter = _after; return *this; }
FindParameters& setDateRange(const std::optional& _dateRange) {dateRange = _dateRange; return *this; }
FindParameters& setStarringUser(UserId _user, Scrobbler _scrobbler) { starringUser = _user; scrobbler = _scrobbler; return *this; }
+ FindParameters& setArtist(ArtistId _artist, EnumSet _trackArtistLinkTypes = {}, EnumSet _excludedTrackArtistLinkTypes = {})
+ {
+ artist = _artist;
+ trackArtistLinkTypes = _trackArtistLinkTypes;
+ excludedTrackArtistLinkTypes = _excludedTrackArtistLinkTypes;
+ return *this;
+ }
};
Release() = default;
diff --git a/src/libs/services/database/include/services/database/TrackArtistLink.hpp b/src/libs/services/database/include/services/database/TrackArtistLink.hpp
index 8a1ba0b2..5d565da5 100644
--- a/src/libs/services/database/include/services/database/TrackArtistLink.hpp
+++ b/src/libs/services/database/include/services/database/TrackArtistLink.hpp
@@ -54,7 +54,6 @@ namespace Database
void persist(Action& a)
{
Wt::Dbo::field(a, _type, "type");
- Wt::Dbo::field(a, _type, "name");
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
@@ -62,7 +61,6 @@ namespace Database
private:
TrackArtistLinkType _type;
- std::string _name;
Wt::Dbo::ptr