Added Album Artist support
This commit is contained in:
@@ -21,6 +21,8 @@ lms_SOURCES = \
|
||||
$(srcdir)/database/Cluster.hpp \
|
||||
$(srcdir)/database/DatabaseHandler.cpp \
|
||||
$(srcdir)/database/DatabaseHandler.hpp \
|
||||
$(srcdir)/database/TrackArtistLink.cpp \
|
||||
$(srcdir)/database/TrackArtistLink.hpp \
|
||||
$(srcdir)/database/TrackFeatures.cpp \
|
||||
$(srcdir)/database/TrackFeatures.hpp \
|
||||
$(srcdir)/database/TrackList.cpp \
|
||||
|
||||
+45
-15
@@ -77,7 +77,7 @@ Artist::getAll(Wt::Dbo::Session& session, boost::optional<std::size_t> offset, b
|
||||
std::vector<Artist::pointer>
|
||||
Artist::getAllOrphans(Wt::Dbo::Session& session)
|
||||
{
|
||||
Wt::Dbo::collection<Artist::pointer> res = session.query< Wt::Dbo::ptr<Artist> >("SELECT DISTINCT a FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist t_a ON t_a.artist_id = a.id WHERE t.id = t_a.track_id)");
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res {session.query<Wt::Dbo::ptr<Artist>>("SELECT DISTINCT a FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)")};
|
||||
|
||||
return std::vector<pointer>(res.begin(), res.end());
|
||||
}
|
||||
@@ -98,7 +98,7 @@ getQuery(Wt::Dbo::Session& session,
|
||||
|
||||
if (!clusterIds.empty())
|
||||
{
|
||||
oss << " INNER JOIN track t ON t_a.track_id = t.id INNER JOIN track_artist t_a ON t_a.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";
|
||||
oss << " 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;
|
||||
|
||||
@@ -110,7 +110,7 @@ getQuery(Wt::Dbo::Session& session,
|
||||
oss << " " << where.get();
|
||||
|
||||
if (!clusterIds.empty())
|
||||
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
|
||||
oss << " GROUP BY t.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size();
|
||||
|
||||
oss << " ORDER BY a.sort_name COLLATE NOCASE";
|
||||
|
||||
@@ -124,6 +124,13 @@ getQuery(Wt::Dbo::Session& session,
|
||||
return query;
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer>
|
||||
Artist::getByFilter(Wt::Dbo::Session& session, const std::set<IdType>& clusters)
|
||||
{
|
||||
bool more;
|
||||
return getByFilter(session, clusters, {}, {}, {}, more);
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer>
|
||||
Artist::getByFilter(Wt::Dbo::Session& session,
|
||||
const std::set<IdType>& clusters,
|
||||
@@ -152,7 +159,7 @@ Artist::getByFilter(Wt::Dbo::Session& session,
|
||||
std::vector<Artist::pointer>
|
||||
Artist::getLastAdded(Wt::Dbo::Session& session, Wt::WDateTime after, boost::optional<std::size_t> limit)
|
||||
{
|
||||
Wt::Dbo::collection<Artist::pointer> res = session.query<Artist::pointer>("SELECT a from artist a INNER JOIN track_artist t_a ON t_a.artist_id = a.id INNER JOIN track t ON t.id = t_a.track_id")
|
||||
Wt::Dbo::collection<Artist::pointer> res = session.query<Artist::pointer>("SELECT a from artist a INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id INNER JOIN track t ON t.id = t_a_l.track_id")
|
||||
.where("t.file_added > ?").bind(after)
|
||||
.groupBy("a.id")
|
||||
.orderBy("t.file_added DESC")
|
||||
@@ -171,7 +178,8 @@ Artist::getReleases(const std::set<IdType>& clusterIds) const
|
||||
WhereClause where;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "SELECT DISTINCT r FROM release r INNER JOIN artist a ON t_a.artist_id = a.id INNER JOIN track_artist t_a ON t_a.track_id = t.id INNER JOIN track t ON t.release_id = r.id";
|
||||
|
||||
oss << "SELECT DISTINCT r 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";
|
||||
|
||||
if (!clusterIds.empty())
|
||||
{
|
||||
@@ -190,32 +198,54 @@ Artist::getReleases(const std::set<IdType>& clusterIds) const
|
||||
oss << " " << where.get();
|
||||
|
||||
if (!clusterIds.empty())
|
||||
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
|
||||
oss << " GROUP BY t.id HAVING COUNT(DISTINCT c.id) = " << clusterIds.size();
|
||||
|
||||
oss << " ORDER BY t.year,r.name";
|
||||
|
||||
Wt::Dbo::Query<Release::pointer> query = session()->query<Release::pointer>( oss.str() );
|
||||
|
||||
for (const std::string& bindArg : where.getBindArgs())
|
||||
{
|
||||
query.bind(bindArg);
|
||||
}
|
||||
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Release> > res = query;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Release>> res = query;
|
||||
|
||||
return std::vector< Wt::Dbo::ptr<Release> > (res.begin(), res.end());
|
||||
return std::vector<Wt::Dbo::ptr<Release>>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Track>>
|
||||
Artist::getTracks() const
|
||||
Artist::getTracks(boost::optional<TrackArtistLink::Type> linkType) const
|
||||
{
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {session()->query<Wt::Dbo::ptr<Track>>("SELECT t from Track t INNER JOIN artist a ON t_a.artist_id = a.id INNER JOIN track_artist t_a ON t_a.track_id = t.id INNER JOIN release r ON r.id = t.release_id")
|
||||
assert(self());
|
||||
assert(IdIsValid(self()->id()));
|
||||
assert(session());
|
||||
|
||||
auto query {session()->query<Wt::Dbo::ptr<Track>>("SELECT DISTINCT t FROM track t 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")
|
||||
.where("a.id = ?").bind(self()->id())
|
||||
.orderBy("t.year,t.release_id,t.disc_number,t.track_number")};
|
||||
|
||||
if (linkType)
|
||||
query.where("t_a_l.type = ?").bind(*linkType);
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {query.resultList()};
|
||||
|
||||
return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end());
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Track>>
|
||||
Artist::getTracksWithRelease(boost::optional<TrackArtistLink::Type> linkType) const
|
||||
{
|
||||
assert(self());
|
||||
assert(IdIsValid(self()->id()));
|
||||
assert(session());
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {session()->query<Wt::Dbo::ptr<Track>>("SELECT t FROM track t 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 release r ON r.id = t.release_id")
|
||||
.where("a.id = ?").bind(self()->id())
|
||||
.orderBy("t.year,r.name,t.disc_number,t.track_number")};
|
||||
|
||||
return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end());
|
||||
}
|
||||
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Track>>
|
||||
Artist::getRandomTracks(boost::optional<std::size_t> count) const
|
||||
{
|
||||
@@ -223,7 +253,7 @@ Artist::getRandomTracks(boost::optional<std::size_t> count) const
|
||||
assert(IdIsValid(self()->id()));
|
||||
assert(session());
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {session()->query<Wt::Dbo::ptr<Track>>("SELECT t from Track t INNER JOIN artist a ON t_a.artist_id = a.id INNER JOIN track_artist t_a ON t_a.track_id = t.id")
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {session()->query<Wt::Dbo::ptr<Track>>("SELECT t from track t 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")
|
||||
.where("a.id = ?").bind(self()->id())
|
||||
.orderBy("RANDOM()")
|
||||
.limit(count ? static_cast<int>(*count) : -1)};
|
||||
@@ -241,7 +271,7 @@ Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::si
|
||||
WhereClause where;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN cluster_type c_type ON c.cluster_type_id = c_type.id INNER JOIN artist a ON t_a.artist_id = a.id INNER JOIN track_artist t_a ON t_a.track_id = t.id";
|
||||
oss << "SELECT c FROM cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN cluster_type c_type ON c.cluster_type_id = c_type.id INNER JOIN artist a ON t_a_l.artist_id = a.id INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id";
|
||||
|
||||
where.And(WhereClause("a.id = ?")).bind(std::to_string(self()->id()));
|
||||
{
|
||||
@@ -252,7 +282,7 @@ Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::si
|
||||
where.And(clusterClause);
|
||||
}
|
||||
oss << " " << where.get();
|
||||
oss << "GROUP BY c.id ORDER BY COUNT(c.id) DESC";
|
||||
oss << "GROUP BY c.id ORDER BY COUNT(DISTINCT c.id) DESC";
|
||||
|
||||
Wt::Dbo::Query<Cluster::pointer> query = session()->query<Cluster::pointer>( oss.str() );
|
||||
|
||||
|
||||
@@ -27,15 +27,16 @@
|
||||
#include <Wt/WDateTime.h>
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "TrackArtistLink.hpp"
|
||||
#include "Types.hpp"
|
||||
|
||||
namespace Database
|
||||
{
|
||||
|
||||
class Track;
|
||||
class Cluster;
|
||||
class ClusterType;
|
||||
class Release;
|
||||
class Track;
|
||||
|
||||
class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
{
|
||||
@@ -50,6 +51,8 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
static pointer getByMBID(Wt::Dbo::Session& session, const std::string& MBID);
|
||||
static pointer getById(Wt::Dbo::Session& session, IdType id);
|
||||
static std::vector<pointer> getByName(Wt::Dbo::Session& session, const std::string& name);
|
||||
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session,
|
||||
const std::set<IdType>& clusters); // at least one track that belongs to these clusters
|
||||
static std::vector<pointer> getByFilter(Wt::Dbo::Session& session,
|
||||
const std::set<IdType>& clusters, // at least one track that belongs to these clusters
|
||||
const std::vector<std::string>& keywords, // name must match all of these keywords
|
||||
@@ -65,9 +68,9 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
const std::string& getName(void) const { return _name; }
|
||||
const std::string& getMBID(void) const { return _MBID; }
|
||||
|
||||
// Get the releases that have at least one track for this artist that belongs to optional cluster filters
|
||||
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = std::set<IdType>()) const;
|
||||
std::vector<Wt::Dbo::ptr<Track>> getTracks() const;
|
||||
std::vector<Wt::Dbo::ptr<Track>> getTracks(boost::optional<TrackArtistLink::Type> linkType = {}) const;
|
||||
std::vector<Wt::Dbo::ptr<Track>> getTracksWithRelease(boost::optional<TrackArtistLink::Type> linkType = {}) const;
|
||||
std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(boost::optional<std::size_t> count) const;
|
||||
|
||||
// Get the cluster of the tracks made by this artist
|
||||
@@ -89,7 +92,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
Wt::Dbo::field(a, _name, "sort_name");
|
||||
Wt::Dbo::field(a, _MBID, "mbid");
|
||||
|
||||
Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToMany, "track_artist", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _trackArtistLinks, Wt::Dbo::ManyToOne, "artist");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -100,7 +103,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
std::string _sortName;
|
||||
std::string _MBID; // Musicbrainz Identifier
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks; // Tracks of this artist
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks; // Tracks involving this artist
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
|
||||
@@ -108,6 +108,12 @@ ClusterType::getByName(Wt::Dbo::Session& session, std::string name)
|
||||
return session.find<ClusterType>().where("name = ?").bind(name);
|
||||
}
|
||||
|
||||
ClusterType::pointer
|
||||
ClusterType::getById(Wt::Dbo::Session& session, IdType id)
|
||||
{
|
||||
return session.find<ClusterType>().where("id= ?").bind(id);
|
||||
}
|
||||
|
||||
std::vector<ClusterType::pointer>
|
||||
ClusterType::getAll(Wt::Dbo::Session& session)
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ class ClusterType : public Wt::Dbo::Dbo<ClusterType>
|
||||
|
||||
static std::vector<pointer> getAllOrphans(Wt::Dbo::Session& session);
|
||||
static pointer getByName(Wt::Dbo::Session& session, std::string name);
|
||||
static pointer getById(Wt::Dbo::Session& session, IdType id);
|
||||
static std::vector<pointer> getAll(Wt::Dbo::Session& session);
|
||||
|
||||
static pointer create(Wt::Dbo::Session& session, std::string name);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "ScanSettings.hpp"
|
||||
#include "SimilaritySettings.hpp"
|
||||
#include "Track.hpp"
|
||||
#include "TrackArtistLink.hpp"
|
||||
#include "TrackList.hpp"
|
||||
#include "TrackFeatures.hpp"
|
||||
|
||||
@@ -106,6 +107,7 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||
_session.mapClass<TrackListEntry>("tracklist_entry");
|
||||
_session.mapClass<Release>("release");
|
||||
_session.mapClass<Track>("track");
|
||||
_session.mapClass<TrackArtistLink>("track_artist_link");
|
||||
_session.mapClass<TrackFeatures>("track_features");
|
||||
|
||||
_session.mapClass<ScanSettings>("scan_settings");
|
||||
|
||||
@@ -73,7 +73,7 @@ Release::getAll(Wt::Dbo::Session& session, boost::optional<std::size_t> offset,
|
||||
{
|
||||
Wt::Dbo::collection<pointer> res = session.find<Release>()
|
||||
.offset(offset ? static_cast<int>(*offset) : -1)
|
||||
.limit(size ? static_cast<int>(*size) : - 1)
|
||||
.limit(size ? static_cast<int>(*size) : -1)
|
||||
.orderBy("name COLLATE NOCASE");
|
||||
|
||||
return std::vector<pointer>(res.begin(), res.end());
|
||||
@@ -83,7 +83,7 @@ std::vector<Release::pointer>
|
||||
Release::getAllRandom(Wt::Dbo::Session& session, boost::optional<std::size_t> size)
|
||||
{
|
||||
Wt::Dbo::collection<pointer> res = session.find<Release>()
|
||||
.limit(size ? static_cast<int>(*size) : - 1)
|
||||
.limit(size ? static_cast<int>(*size) : -1)
|
||||
.orderBy("RANDOM()");
|
||||
|
||||
return std::vector<pointer>(res.begin(), res.end());
|
||||
@@ -183,6 +183,18 @@ Release::getByFilter(Wt::Dbo::Session& session,
|
||||
return res;
|
||||
}
|
||||
|
||||
boost::optional<std::size_t>
|
||||
Release::getTotalTrackNumber(void) const
|
||||
{
|
||||
return (_totalTrackNumber > 0) ? boost::make_optional<std::size_t>(_totalTrackNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::size_t>
|
||||
Release::getTotalDiscNumber(void) const
|
||||
{
|
||||
return (_totalDiscNumber > 0) ? boost::make_optional<std::size_t>(_totalDiscNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<int>
|
||||
Release::getReleaseYear(bool original) const
|
||||
{
|
||||
@@ -249,16 +261,16 @@ Release::getCopyrightURL() const
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Artist>>
|
||||
Release::getArtists() const
|
||||
Release::getArtists(TrackArtistLink::Type linkType) const
|
||||
{
|
||||
assert(self());
|
||||
assert(IdIsValid(self()->id()));
|
||||
assert(session());
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res = session()->query<Wt::Dbo::ptr<Artist>>(
|
||||
"SELECT DISTINCT a FROM artist a INNER JOIN release r ON t.id = t_a.track_id INNER JOIN track_artist t_a ON t_a.artist_id = a.id INNER JOIN track t ON t.release_id = r.id")
|
||||
.where("r.id = ?")
|
||||
.bind(id());
|
||||
"SELECT DISTINCT a FROM artist a INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id INNER JOIN track t ON t.id = t_a_l.track_id INNER JOIN release r ON r.id = t.release_id")
|
||||
.where("r.id = ?").bind(self()->id())
|
||||
.where("t_a_l.type = ?").bind(linkType);
|
||||
|
||||
return std::vector<Wt::Dbo::ptr<Artist>>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <Wt/Dbo/WtSqlTraits.h>
|
||||
|
||||
#include "TrackArtistLink.hpp"
|
||||
#include "Types.hpp"
|
||||
|
||||
namespace Database
|
||||
@@ -76,13 +77,20 @@ class Release : public Wt::Dbo::Dbo<Release>
|
||||
boost::optional<std::string> getCopyright() const;
|
||||
boost::optional<std::string> getCopyrightURL() const;
|
||||
|
||||
// Modifiers
|
||||
void setTotalDiscNumber(std::size_t num) { _totalDiscNumber = static_cast<int>(num); }
|
||||
void setTotalTrackNumber(std::size_t num) { _totalTrackNumber = static_cast<int>(num); }
|
||||
|
||||
// Accessors
|
||||
std::string getName() const { return _name; }
|
||||
std::string getMBID() const { return _MBID; }
|
||||
std::string getName() const { return _name; }
|
||||
std::string getMBID() const { return _MBID; }
|
||||
boost::optional<std::size_t> getTotalTrackNumber() const;
|
||||
boost::optional<std::size_t> getTotalDiscNumber() const;
|
||||
std::chrono::milliseconds getDuration() const;
|
||||
|
||||
// Get the artists of this release
|
||||
std::vector<Wt::Dbo::ptr<Artist> > getArtists() const;
|
||||
std::vector<Wt::Dbo::ptr<Artist> > getArtists(TrackArtistLink::Type type = TrackArtistLink::Type::Artist) const;
|
||||
std::vector<Wt::Dbo::ptr<Artist> > getReleaseArtists() const { return getArtists(TrackArtistLink::Type::ReleaseArtist); }
|
||||
bool hasVariousArtists() const;
|
||||
|
||||
void setMBID(std::string mbid) { _MBID = mbid; }
|
||||
@@ -92,17 +100,21 @@ class Release : public Wt::Dbo::Dbo<Release>
|
||||
{
|
||||
Wt::Dbo::field(a, _name, "name");
|
||||
Wt::Dbo::field(a, _MBID, "mbid");
|
||||
Wt::Dbo::field(a, _totalDiscNumber, "total_disc_number");
|
||||
Wt::Dbo::field(a, _totalTrackNumber, "total_track_number");
|
||||
|
||||
Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToOne, "release");
|
||||
}
|
||||
|
||||
private:
|
||||
static const std::size_t _maxNameLength = 128;
|
||||
static const std::size_t _maxNameLength {128};
|
||||
|
||||
std::string _name;
|
||||
std::string _MBID;
|
||||
std::string _name;
|
||||
std::string _MBID;
|
||||
int _totalDiscNumber {};
|
||||
int _totalTrackNumber {};
|
||||
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Track> > _tracks; // Tracks in the release
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks; // Tracks in the release
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
|
||||
+34
-22
@@ -37,12 +37,13 @@ _filePath( p.string() )
|
||||
{
|
||||
}
|
||||
|
||||
Wt::Dbo::collection< Track::pointer >
|
||||
std::vector<Track::pointer>
|
||||
Track::getAll(Wt::Dbo::Session& session, boost::optional<std::size_t> limit)
|
||||
{
|
||||
int size {limit ? static_cast<int>(*limit) : -1};
|
||||
Wt::Dbo::collection<Track::pointer> res {session.find<Track>()
|
||||
.limit(limit ? static_cast<int>(*limit) : -1)};
|
||||
|
||||
return session.find<Track>().limit(size);
|
||||
return std::vector<Track::pointer>(std::cbegin(res), std::cend(res));
|
||||
}
|
||||
|
||||
std::vector<Track::pointer>
|
||||
@@ -229,15 +230,24 @@ Track::getByFilter(Wt::Dbo::Session& session,
|
||||
{
|
||||
bool moreResults;
|
||||
|
||||
return getByFilter(session, clusters, std::vector<std::string>{}, -1, -1, moreResults);
|
||||
return getByFilter(session,
|
||||
clusters,
|
||||
std::vector<std::string> {},
|
||||
boost::optional<std::size_t> {},
|
||||
boost::optional<std::size_t> {},
|
||||
moreResults);
|
||||
}
|
||||
|
||||
void
|
||||
Track::setArtists(const std::vector<Wt::Dbo::ptr<Artist>>& artists)
|
||||
Track::clearArtistLinks()
|
||||
{
|
||||
_artists.clear();
|
||||
for (const Wt::Dbo::ptr<Artist>& artist : artists)
|
||||
_artists.insert(artist);
|
||||
_trackArtistLinks.clear();
|
||||
}
|
||||
|
||||
void
|
||||
Track::addArtistLink(const Wt::Dbo::ptr<TrackArtistLink>& artistLink)
|
||||
{
|
||||
_trackArtistLinks.insert(artistLink);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -260,24 +270,12 @@ Track::getTrackNumber(void) const
|
||||
return (_trackNumber > 0) ? boost::make_optional<std::size_t>(_trackNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::size_t>
|
||||
Track::getTotalTrackNumber(void) const
|
||||
{
|
||||
return (_totalTrackNumber > 0) ? boost::make_optional<std::size_t>(_totalTrackNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::size_t>
|
||||
Track::getDiscNumber(void) const
|
||||
{
|
||||
return (_discNumber > 0) ? boost::make_optional<std::size_t>(_discNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<std::size_t>
|
||||
Track::getTotalDiscNumber(void) const
|
||||
{
|
||||
return (_totalDiscNumber > 0) ? boost::make_optional<std::size_t>(_totalDiscNumber) : boost::none;
|
||||
}
|
||||
|
||||
boost::optional<int>
|
||||
Track::getYear() const
|
||||
{
|
||||
@@ -303,9 +301,23 @@ Track::getCopyrightURL() const
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Artist>>
|
||||
Track::getArtists() const
|
||||
Track::getArtists(TrackArtistLink::Type type) const
|
||||
{
|
||||
return std::vector<Wt::Dbo::ptr<Artist>>(_artists.begin(), _artists.end());
|
||||
assert(self());
|
||||
assert(IdIsValid(self()->id()));
|
||||
assert(session());
|
||||
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> artists {session()->query<Artist::pointer>("SELECT a from artist a INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id INNER JOIN track t ON t.id = t_a_l.track_id")
|
||||
.where("t.id = ?").bind(self()->id())
|
||||
.where("t_a_l.type = ?").bind(type)};
|
||||
|
||||
return std::vector<Wt::Dbo::ptr<Artist>>(artists.begin(), artists.end());
|
||||
}
|
||||
|
||||
std::vector<Wt::Dbo::ptr<TrackArtistLink>>
|
||||
Track::getArtistLinks() const
|
||||
{
|
||||
return std::vector<Wt::Dbo::ptr<TrackArtistLink>>(_trackArtistLinks.begin(), _trackArtistLinks.end());
|
||||
}
|
||||
|
||||
Wt::Dbo::ptr<TrackFeatures>
|
||||
|
||||
+8
-13
@@ -29,6 +29,7 @@
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include "TrackArtistLink.hpp"
|
||||
#include "Types.hpp"
|
||||
|
||||
namespace Database {
|
||||
@@ -63,7 +64,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
boost::optional<std::size_t> size,
|
||||
bool& moreExpected);
|
||||
|
||||
static Wt::Dbo::collection< pointer > getAll(Wt::Dbo::Session& session, boost::optional<std::size_t> limit = {});
|
||||
static std::vector<pointer> getAll(Wt::Dbo::Session& session, boost::optional<std::size_t> limit = {});
|
||||
static std::vector<pointer> getAllRandom(Wt::Dbo::Session& session, boost::optional<std::size_t> limit = {});
|
||||
static std::vector<IdType> getAllIds(Wt::Dbo::Session& session); // nested transaction
|
||||
static std::vector<boost::filesystem::path> getAllPaths(Wt::Dbo::Session& session); // nested transaction
|
||||
@@ -79,9 +80,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
// Accessors
|
||||
void setScanVersion(std::size_t version) { _scanVersion = version; }
|
||||
void setTrackNumber(int num) { _trackNumber = num; }
|
||||
void setTotalTrackNumber(int num) { _totalTrackNumber = num; }
|
||||
void setDiscNumber(int num) { _discNumber = num; }
|
||||
void setTotalDiscNumber(int num) { _totalDiscNumber = num; }
|
||||
void setName(const std::string& name) { _name = std::string(name, 0, _maxNameLength); }
|
||||
void setDuration(std::chrono::milliseconds duration) { _duration = duration; }
|
||||
void setLastWriteTime(Wt::WDateTime time) { _fileLastWrite = time; }
|
||||
@@ -93,16 +92,15 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
void setMBID(const std::string& MBID) { _MBID = MBID; }
|
||||
void setCopyright(const std::string& copyright) { _copyright = std::string(copyright, 0, _maxCopyrightLength); }
|
||||
void setCopyrightURL(const std::string& copyrightURL) { _copyrightURL = std::string(copyrightURL, 0, _maxCopyrightURLLength); }
|
||||
void setArtists(const std::vector<Wt::Dbo::ptr<Artist>>& artists);
|
||||
void clearArtistLinks();
|
||||
void addArtistLink(const Wt::Dbo::ptr<TrackArtistLink>& artistLink);
|
||||
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
|
||||
void setClusters(const std::vector<Wt::Dbo::ptr<Cluster>>& clusters );
|
||||
void setFeatures(const Wt::Dbo::ptr<TrackFeatures>& features);
|
||||
|
||||
std::size_t getScanVersion() const { return _scanVersion; }
|
||||
boost::optional<std::size_t> getTrackNumber() const;
|
||||
boost::optional<std::size_t> getTotalTrackNumber() const;
|
||||
boost::optional<std::size_t> getDiscNumber() const;
|
||||
boost::optional<std::size_t> getTotalDiscNumber() const;
|
||||
std::string getName() const { return _name; }
|
||||
boost::filesystem::path getPath() const { return _filePath; }
|
||||
std::chrono::milliseconds getDuration() const { return _duration; }
|
||||
@@ -115,7 +113,8 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
const std::string& getMBID() const { return _MBID; }
|
||||
boost::optional<std::string> getCopyright() const;
|
||||
boost::optional<std::string> getCopyrightURL() const;
|
||||
std::vector<Wt::Dbo::ptr<Artist>> getArtists() const;
|
||||
std::vector<Wt::Dbo::ptr<Artist>> getArtists(TrackArtistLink::Type type = {TrackArtistLink::Type::Artist}) const;
|
||||
std::vector<Wt::Dbo::ptr<TrackArtistLink>> getArtistLinks() const;
|
||||
Wt::Dbo::ptr<Release> getRelease() const { return _release; }
|
||||
std::vector<Wt::Dbo::ptr<Cluster>> getClusters() const;
|
||||
bool hasTrackFeatures() const;
|
||||
@@ -128,9 +127,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
{
|
||||
Wt::Dbo::field(a, _scanVersion, "scan_version");
|
||||
Wt::Dbo::field(a, _trackNumber, "track_number");
|
||||
Wt::Dbo::field(a, _totalTrackNumber, "total_track_number");
|
||||
Wt::Dbo::field(a, _discNumber, "disc_number");
|
||||
Wt::Dbo::field(a, _totalDiscNumber, "total_disc_number");
|
||||
Wt::Dbo::field(a, _name, "name");
|
||||
Wt::Dbo::field(a, _duration, "duration");
|
||||
Wt::Dbo::field(a, _year, "year");
|
||||
@@ -144,7 +141,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
Wt::Dbo::field(a, _copyright, "copyright");
|
||||
Wt::Dbo::field(a, _copyrightURL, "copyright_url");
|
||||
Wt::Dbo::belongsTo(a, _release, "release", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _artists, Wt::Dbo::ManyToMany, "track_artist", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _trackArtistLinks, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasOne(a, _trackFeatures);
|
||||
@@ -158,9 +155,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
|
||||
int _scanVersion = 0;
|
||||
int _trackNumber = 0;
|
||||
int _totalTrackNumber = 0;
|
||||
int _discNumber = 0;
|
||||
int _totalDiscNumber = 0;
|
||||
std::string _name;
|
||||
std::string _artistName;
|
||||
std::string _releaseName;
|
||||
@@ -177,7 +172,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
std::string _copyrightURL;
|
||||
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> _artists;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
|
||||
Wt::Dbo::weak_ptr<TrackFeatures> _trackFeatures;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TrackArtistLink.hpp"
|
||||
|
||||
#include "Artist.hpp"
|
||||
#include "Track.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
TrackArtistLink::TrackArtistLink(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Artist> artist, Type type)
|
||||
: _type {type},
|
||||
_track {track},
|
||||
_artist {artist}
|
||||
{
|
||||
}
|
||||
|
||||
TrackArtistLink::pointer
|
||||
TrackArtistLink::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Artist> artist,Type type)
|
||||
{
|
||||
return session.add(std::make_unique<TrackArtistLink>(track, artist, type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "Types.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
class Artist;
|
||||
class Track;
|
||||
|
||||
class TrackArtistLink
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Artist, // regular artist
|
||||
Arranger,
|
||||
Composer,
|
||||
Conductor,
|
||||
Lyricist,
|
||||
Mixer,
|
||||
Performer,
|
||||
Producer,
|
||||
ReleaseArtist,
|
||||
Remixer,
|
||||
Writer,
|
||||
};
|
||||
|
||||
using pointer = Wt::Dbo::ptr<TrackArtistLink>;
|
||||
|
||||
TrackArtistLink() = default;
|
||||
TrackArtistLink(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Artist> artist, Type type);
|
||||
|
||||
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Artist> artist,Type type);
|
||||
|
||||
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
||||
Wt::Dbo::ptr<Artist> getArtist() const { return _artist; }
|
||||
Type getType() const { return _type; }
|
||||
|
||||
template<class Action>
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Type _type;
|
||||
std::string _name;
|
||||
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
Wt::Dbo::ptr<Artist> _artist;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ TrackList::getTopArtists(std::size_t limit) const
|
||||
assert(session());
|
||||
assert(IdIsValid(self()->id()));
|
||||
|
||||
Wt::Dbo::collection<Artist::pointer> res = session()->query<Artist::pointer>("SELECT a from artist a INNER JOIN track t ON t.id = t_a.track_id INNER JOIN track_artist t_a ON t_a.artist_id = a.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
|
||||
Wt::Dbo::collection<Artist::pointer> res = session()->query<Artist::pointer>("SELECT a 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 tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
|
||||
.where("p.id = ?").bind(self()->id())
|
||||
.groupBy("a.id")
|
||||
.orderBy("COUNT(a.id) DESC")
|
||||
|
||||
@@ -63,6 +63,8 @@ std::vector<std::string> generateWtConfig(std::string execPath)
|
||||
args.push_back("--http-address=" + Config::instance().getString("listen-addr", "0.0.0.0"));
|
||||
}
|
||||
|
||||
args.push_back("--gdb");
|
||||
|
||||
// Generate the wt_config.xml file
|
||||
boost::property_tree::ptree pt;
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem:
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer>
|
||||
getArtists(Wt::Dbo::Session& session, const std::vector<MetaData::Artist>& artistsInfo)
|
||||
getOrCreateArtists(Wt::Dbo::Session& session, const std::vector<MetaData::Artist>& artistsInfo)
|
||||
{
|
||||
std::vector<Artist::pointer> artists;
|
||||
|
||||
@@ -129,7 +129,7 @@ getArtists(Wt::Dbo::Session& session, const std::vector<MetaData::Artist>& artis
|
||||
}
|
||||
|
||||
Release::pointer
|
||||
getRelease(Wt::Dbo::Session& session, const MetaData::Album& album)
|
||||
getOrCreateRelease(Wt::Dbo::Session& session, const MetaData::Album& album)
|
||||
{
|
||||
Release::pointer release;
|
||||
|
||||
@@ -166,7 +166,7 @@ getRelease(Wt::Dbo::Session& session, const MetaData::Album& album)
|
||||
}
|
||||
|
||||
std::vector<Cluster::pointer>
|
||||
getClusters(Wt::Dbo::Session& session, const MetaData::Clusters& clustersNames)
|
||||
getOrCreateClusters(Wt::Dbo::Session& session, const MetaData::Clusters& clustersNames)
|
||||
{
|
||||
std::vector< Cluster::pointer > clusters;
|
||||
|
||||
@@ -465,15 +465,18 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
|
||||
}
|
||||
|
||||
// ***** Clusters
|
||||
std::vector<Cluster::pointer> clusters {getClusters(_db.getSession(), trackInfo->clusters)};
|
||||
std::vector<Cluster::pointer> clusters {getOrCreateClusters(_db.getSession(), trackInfo->clusters)};
|
||||
|
||||
// ***** Artists
|
||||
std::vector<Artist::pointer> artists {getArtists(_db.getSession(), trackInfo->artists)};
|
||||
std::vector<Artist::pointer> artists {getOrCreateArtists(_db.getSession(), trackInfo->artists)};
|
||||
|
||||
// ***** Release artists
|
||||
std::vector<Artist::pointer> releaseArtists {getOrCreateArtists(_db.getSession(), trackInfo->albumArtists)};
|
||||
|
||||
// ***** Release
|
||||
Release::pointer release;
|
||||
if (trackInfo->album)
|
||||
release = getRelease(_db.getSession(), *trackInfo->album);
|
||||
release = getOrCreateRelease(_db.getSession(), *trackInfo->album);
|
||||
|
||||
// If file already exist, update data
|
||||
// Otherwise, create it
|
||||
@@ -493,11 +496,25 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
|
||||
stats.updates++;
|
||||
}
|
||||
|
||||
// Release related data
|
||||
if (release)
|
||||
{
|
||||
release.modify()->setTotalTrackNumber(trackInfo->totalTrack ? *trackInfo->totalTrack : 0);
|
||||
release.modify()->setTotalDiscNumber(trackInfo->totalDisc ? *trackInfo->totalDisc : 0);
|
||||
}
|
||||
|
||||
// Track related data
|
||||
assert(track);
|
||||
|
||||
track.modify()->clearArtistLinks();
|
||||
for (const auto& artist : artists)
|
||||
track.modify()->addArtistLink(Database::TrackArtistLink::create(_db.getSession(), track, artist, Database::TrackArtistLink::Type::Artist));
|
||||
|
||||
for (const auto& releaseArtist : releaseArtists)
|
||||
track.modify()->addArtistLink(Database::TrackArtistLink::create(_db.getSession(), track, releaseArtist, Database::TrackArtistLink::Type::ReleaseArtist));
|
||||
|
||||
track.modify()->setScanVersion(_scanVersion);
|
||||
track.modify()->setChecksum(checksum);
|
||||
track.modify()->setArtists(artists);
|
||||
track.modify()->setRelease(release);
|
||||
track.modify()->setClusters(clusters);
|
||||
track.modify()->setLastWriteTime(lastWriteTime);
|
||||
@@ -505,9 +522,7 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
|
||||
track.modify()->setDuration(trackInfo->duration);
|
||||
track.modify()->setAddedTime(Wt::WLocalDateTime::currentServerDateTime().toUTC());
|
||||
track.modify()->setTrackNumber(trackInfo->trackNumber ? *trackInfo->trackNumber : 0);
|
||||
track.modify()->setTotalTrackNumber(trackInfo->totalTrack ? *trackInfo->totalTrack : 0);
|
||||
track.modify()->setDiscNumber(trackInfo->discNumber ? *trackInfo->discNumber : 0);
|
||||
track.modify()->setTotalDiscNumber(trackInfo->totalDisc ? *trackInfo->totalDisc : 0);
|
||||
track.modify()->setYear(trackInfo->year ? *trackInfo->year : 0);
|
||||
track.modify()->setOriginalYear(trackInfo->originalYear ? *trackInfo->originalYear : 0);
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ Artist::refresh()
|
||||
Wt::WContainerWidget* releasesContainer = t->bindNew<Wt::WContainerWidget>("releases");
|
||||
|
||||
auto releases = artist->getReleases(_filters->getClusterIds());
|
||||
|
||||
for (auto release : releases)
|
||||
{
|
||||
auto releaseId = release.id();
|
||||
@@ -139,8 +140,27 @@ Artist::refresh()
|
||||
|
||||
entry->bindWidget("name", LmsApplication::createReleaseAnchor(release));
|
||||
|
||||
if (release->hasVariousArtists())
|
||||
entry->setCondition("if-has-various-artists", true);
|
||||
auto artists {release->getReleaseArtists()};
|
||||
LMS_LOG(UI, DEBUG) << "Found " << artists.size() << " release artists";
|
||||
|
||||
for (auto artist : artists)
|
||||
LMS_LOG(UI, DEBUG) << "\tArtist = '" << artist->getName() << "'";
|
||||
|
||||
if (artists.empty())
|
||||
artists = release->getArtists();
|
||||
|
||||
bool isSameArtist {(std::find(std::cbegin(artists), std::cend(artists), artist) != artists.end())};
|
||||
|
||||
if (artists.size() > 1)
|
||||
{
|
||||
entry->setCondition("if-has-artist", true);
|
||||
entry->bindNew<Wt::WText>("artist", Wt::WString::tr("Lms.Explore.various-artists"));
|
||||
}
|
||||
else if (artists.size() == 1 && !isSameArtist)
|
||||
{
|
||||
entry->setCondition("if-has-artist", true);
|
||||
entry->bindWidget("artist", LmsApplication::createArtistAnchor(artists.front()));
|
||||
}
|
||||
|
||||
boost::optional<int> year = release->getReleaseYear();
|
||||
if (year)
|
||||
|
||||
@@ -44,7 +44,10 @@ ReleaseLink::ReleaseLink(Database::Release::pointer release)
|
||||
cover->setWidth(48);
|
||||
anchor->setImage(std::move(cover));
|
||||
|
||||
auto artists = release->getArtists();
|
||||
auto artists = release->getReleaseArtists();
|
||||
if (artists.empty())
|
||||
artists = release->getArtists();
|
||||
|
||||
if (artists.size() > 1)
|
||||
{
|
||||
setCondition("if-has-artist", true);
|
||||
|
||||
@@ -96,16 +96,21 @@ Release::refresh()
|
||||
}
|
||||
|
||||
{
|
||||
auto artists {release->getArtists()};
|
||||
std::vector<Wt::Dbo::ptr<Database::Artist>> artists;
|
||||
|
||||
artists = release->getReleaseArtists();
|
||||
if (artists.empty())
|
||||
artists = release->getArtists();
|
||||
|
||||
if (artists.size() > 1)
|
||||
{
|
||||
t->setCondition("if-has-artist", true);
|
||||
t->bindNew<Wt::WText>("artist-name", Wt::WString::tr("Lms.Explore.various-artists"));
|
||||
t->bindNew<Wt::WText>("artist", Wt::WString::tr("Lms.Explore.various-artists"));
|
||||
}
|
||||
else if (artists.size() == 1)
|
||||
{
|
||||
t->setCondition("if-has-artist", true);
|
||||
t->bindWidget("artist-name", LmsApplication::createArtistAnchor(artists.front()));
|
||||
t->bindWidget("artist", LmsApplication::createArtistAnchor(artists.front()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +186,7 @@ Release::refresh()
|
||||
}
|
||||
|
||||
auto discNumber {track->getDiscNumber()};
|
||||
auto totalDiscNumber {track->getTotalDiscNumber()};
|
||||
auto totalDiscNumber {release->getTotalDiscNumber()};
|
||||
if (discNumber && totalDiscNumber && *totalDiscNumber > 1)
|
||||
{
|
||||
entry->setCondition("if-has-disc-number", true);
|
||||
|
||||
@@ -96,7 +96,10 @@ Releases::addSome()
|
||||
|
||||
entry->bindWidget("release-name", LmsApplication::createReleaseAnchor(release));
|
||||
|
||||
auto artists = release->getArtists();
|
||||
auto artists = release->getReleaseArtists();
|
||||
if (artists.empty())
|
||||
artists = release->getArtists();
|
||||
|
||||
if (artists.size() > 1)
|
||||
{
|
||||
entry->setCondition("if-has-artist", true);
|
||||
|
||||
Reference in New Issue
Block a user