Skip to content

Commit

Permalink
Merge branch 'develop' for release v3.46.0
Browse files Browse the repository at this point in the history
  • Loading branch information
epoupon committed Dec 18, 2023
2 parents e5e60d0 + c016efa commit d9307fb
Show file tree
Hide file tree
Showing 59 changed files with 1,196 additions and 841 deletions.
9 changes: 5 additions & 4 deletions approot/messages.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,12 @@
<plural case="1">Producers</plural>
</message>
<message id="Lms.Explore.Artists.linktype-releaseartist">
<plural case="0">Album artists</plural>
<plural case="1">Album artist</plural>
<plural case="0">Album artist</plural>
<plural case="1">Album artists</plural>
</message>
<message id="Lms.Explore.Artists.linktype-remixer">
<plural case="0">Remixers</plural>
<plural case="1">Remixer</plural>
<plural case="0">Remixer</plural>
<plural case="1">Remixers</plural>
</message>

<!--Explore:Release-->
Expand All @@ -213,6 +213,7 @@
<message id="Lms.Explore.Release.type-secondary-compilation">Compilation</message>
<message id="Lms.Explore.Release.type-secondary-demo">Demo</message>
<message id="Lms.Explore.Release.type-secondary-djmix">DJ-mix</message>
<message id="Lms.Explore.Release.type-secondary-field-recording">Field recording</message>
<message id="Lms.Explore.Release.type-secondary-interview">Interview</message>
<message id="Lms.Explore.Release.type-secondary-live">Live</message>
<message id="Lms.Explore.Release.type-secondary-mixtape-street">Mixtape/Street</message>
Expand Down
13 changes: 7 additions & 6 deletions approot/messages_fr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 +204,22 @@
<message id="Lms.Explore.Release.disc">Disque {1}</message>
<message id="Lms.Explore.Release.type">Type</message>
<message id="Lms.Explore.Release.type-primary-album">Album</message>
<message id="Lms.Explore.Release.type-primary-broadcast">Broadcast</message>
<message id="Lms.Explore.Release.type-primary-broadcast">Diffusion</message>
<message id="Lms.Explore.Release.type-primary-ep">EP</message>
<message id="Lms.Explore.Release.type-primary-other">Other</message>
<message id="Lms.Explore.Release.type-primary-single">Single</message>
<message id="Lms.Explore.Release.type-secondary-audiobook">Audiobook</message>
<message id="Lms.Explore.Release.type-secondary-audiodrama">Audio drama</message>
<message id="Lms.Explore.Release.type-secondary-audiobook">Livre audio</message>
<message id="Lms.Explore.Release.type-secondary-audiodrama">Drame audio</message>
<message id="Lms.Explore.Release.type-secondary-compilation">Compilation</message>
<message id="Lms.Explore.Release.type-secondary-demo">Demo</message>
<message id="Lms.Explore.Release.type-secondary-demo">Démo</message>
<message id="Lms.Explore.Release.type-secondary-djmix">DJ-mix</message>
<message id="Lms.Explore.Release.type-secondary-field-recording">Enregistrement sur le terrain</message>
<message id="Lms.Explore.Release.type-secondary-interview">Interview</message>
<message id="Lms.Explore.Release.type-secondary-live">Live</message>
<message id="Lms.Explore.Release.type-secondary-mixtape-street">Mixtape/Street</message>
<message id="Lms.Explore.Release.type-secondary-remix">Remix</message>
<message id="Lms.Explore.Release.type-secondary-soundtrack">Soundtrack</message>
<message id="Lms.Explore.Release.type-secondary-spokenword">Spokenword</message>
<message id="Lms.Explore.Release.type-secondary-soundtrack">Bande son</message>
<message id="Lms.Explore.Release.type-secondary-spokenword">Création parlée</message>

<!--Explore:TrackLists-->
<message id="Lms.Explore.TrackLists.del-tracklist-confirm">Supprimer la liste de lecture ?</message>
Expand Down
1 change: 1 addition & 0 deletions approot/messages_it.xml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@




<!--Explore:TrackLists-->


Expand Down
1 change: 1 addition & 0 deletions approot/messages_zh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@




<!--Explore:TrackLists-->
<message id="Lms.Explore.TrackLists.del-tracklist-confirm">删除播放列表?</message>

Expand Down
5 changes: 4 additions & 1 deletion conf/lms.conf
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ cover-max-cache-size = 30;
cover-jpeg-quality = 75;

# Preferred file names for covers (order is important)
cover-preferred-file-names = ("cover", "front" );
cover-preferred-file-names = ("cover", "front");

# File names for artist images (order is important)
artist-image-file-names = ("artist");

# Playqueue max entry count
playqueue-max-entry-count = 1000;
Expand Down
2 changes: 1 addition & 1 deletion src/libs/database/impl/Artist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ namespace Database
return session.getDboSession().query<int>("SELECT COUNT(*) FROM artist");
}

std::vector<Artist::pointer> Artist::find(Session& session, const std::string& name)
std::vector<Artist::pointer> Artist::find(Session& session, std::string_view name)
{
session.checkReadTransaction();

Expand Down
59 changes: 29 additions & 30 deletions src/libs/database/impl/IdTypeTraits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,34 @@

namespace Wt::Dbo
{

template<typename T>
struct sql_value_traits<T, typename std::enable_if<std::is_base_of<Database::IdType, T>::value>::type>
{
static_assert(!std::is_same_v<Database::IdType, T>, "Cannot use IdType, use derived types");
static const bool specialized = true;

static std::string type(SqlConnection *conn, int size)
{
return sql_value_traits<typename T::ValueType, void>::type(conn, size);
}

static void bind(const T& v, SqlStatement *statement, int column, int size)
{
sql_value_traits<typename T::ValueType>::bind(v.getValue(), statement, column, size);
}

static bool read(T& v, SqlStatement *statement, int column, int size)
{
typename T::ValueType value;
if (sql_value_traits<typename T::ValueType>::read(value, statement, column, size))
{
v = value;
return true;
}

v = {};
return false;
}
};
template<typename T>
struct sql_value_traits<T, typename std::enable_if<std::is_base_of<Database::IdType, T>::value>::type>
{
static_assert(!std::is_same_v<Database::IdType, T>, "Cannot use IdType, use derived types");
static const bool specialized = true;

static std::string type(SqlConnection* conn, int size)
{
return sql_value_traits<typename T::ValueType, void>::type(conn, size);
}

static void bind(const T& v, SqlStatement* statement, int column, int size)
{
sql_value_traits<typename T::ValueType>::bind(v.getValue(), statement, column, size);
}

static bool read(T& v, SqlStatement* statement, int column, int size)
{
typename T::ValueType value;
if (sql_value_traits<typename T::ValueType>::read(value, statement, column, size))
{
v = value;
return true;
}

v = {};
return false;
}
};
}

182 changes: 96 additions & 86 deletions src/libs/database/impl/Listen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,112 +25,113 @@
#include "SqlQuery.hpp"
#include "Utils.hpp"

namespace
namespace Database
{
using namespace Database;

Wt::Dbo::Query<ArtistId> createArtistsQuery(Wt::Dbo::Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType)
namespace
{
auto query{ session.query<ArtistId>("SELECT a.id from artist a")
.join("track t ON t.id = t_a_l.track_id")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };
Wt::Dbo::Query<ArtistId> createArtistsQuery(Wt::Dbo::Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType)
{
auto query{ session.query<ArtistId>("SELECT a.id from artist a")
.join("track t ON t.id = t_a_l.track_id")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };

if (linkType)
query.where("t_a_l.type = ?").bind(*linkType);
if (linkType)
query.where("t_a_l.type = ?").bind(*linkType);

if (!clusterIds.empty())
{
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT a.id FROM artist a"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";

WhereClause clusterClause;
for (auto id : clusterIds)
if (!clusterIds.empty())
{
clusterClause.Or(WhereClause("c.id = ?"));
query.bind(id);
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT a.id FROM artist a"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";

WhereClause clusterClause;
for (auto id : clusterIds)
{
clusterClause.Or(WhereClause("c.id = ?"));
query.bind(id);
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id,a.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size() << ")";

query.where(oss.str());
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id,a.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size() << ")";

query.where(oss.str());
return query;
}

return query;
}

Wt::Dbo::Query<ReleaseId> createReleasesQuery(Wt::Dbo::Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds)
{
auto query{ session.query<ReleaseId>("SELECT r.id from release r")
.join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };

if (!clusterIds.empty())
Wt::Dbo::Query<ReleaseId> createReleasesQuery(Wt::Dbo::Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds)
{
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";

WhereClause clusterClause;
for (ClusterId id : clusterIds)
auto query{ session.query<ReleaseId>("SELECT r.id from release r")
.join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };

if (!clusterIds.empty())
{
clusterClause.Or(WhereClause("c.id = ?"));
query.bind(id);
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";

WhereClause clusterClause;
for (ClusterId id : clusterIds)
{
clusterClause.Or(WhereClause("c.id = ?"));
query.bind(id);
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size() << ")";

query.where(oss.str());
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size() << ")";

query.where(oss.str());
return query;
}

return query;
}

Wt::Dbo::Query<TrackId> createTracksQuery(Wt::Dbo::Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds)
{
auto query{ session.query<TrackId>("SELECT t.id from track t")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };

if (!clusterIds.empty())
Wt::Dbo::Query<TrackId> createTracksQuery(Wt::Dbo::Session& session, UserId userId, ArtistId artistId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds)
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
auto query{ session.query<TrackId>("SELECT t.id from track t")
.join("listen l ON l.track_id = t.id")
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) };

WhereClause clusterClause;
for (auto id : clusterIds)
if (artistId.isValid())
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id").where("t_a_l.artist_id = ?").bind(artistId);

if (!clusterIds.empty())
{
clusterClause.Or(WhereClause("c.id = ?")).bind(id.toString());
query.bind(id);
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";

WhereClause clusterClause;
for (auto id : clusterIds)
{
clusterClause.Or(WhereClause("c.id = ?")).bind(id.toString());
query.bind(id);
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size() << ")";

query.where(oss.str());
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size() << ")";

query.where(oss.str());
return query;
}

return query;
}
}

namespace Database
{
Listen::Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
: _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) }
, _backend{ backend }
Expand Down Expand Up @@ -212,7 +213,17 @@ namespace Database
RangeResults<TrackId> Listen::getTopTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<Range> range)
{
session.checkReadTransaction();
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
auto query{ createTracksQuery(session.getDboSession(), userId, ArtistId{}, backend, clusterIds)
.orderBy("COUNT(t.id) DESC")
.groupBy("t.id") };

return Utils::execQuery<TrackId>(query, range);
}

RangeResults<TrackId> Listen::getTopTracks(Session& session, UserId userId, ArtistId artistId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<Range> range)
{
session.checkReadTransaction();
auto query{ createTracksQuery(session.getDboSession(), userId, artistId, backend, clusterIds)
.orderBy("COUNT(t.id) DESC")
.groupBy("t.id") };

Expand Down Expand Up @@ -242,7 +253,7 @@ namespace Database
RangeResults<TrackId> Listen::getRecentTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<Range> range)
{
session.checkReadTransaction();
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
auto query{ createTracksQuery(session.getDboSession(), userId, ArtistId{}, backend, clusterIds)
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };

Expand Down Expand Up @@ -307,4 +318,3 @@ namespace Database
.resultValue();
}
} // namespace Database

Loading

0 comments on commit d9307fb

Please sign in to comment.