Subsonic API: added playCount
This commit is contained in:
@@ -140,6 +140,7 @@ namespace Database
|
|||||||
|
|
||||||
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
|
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
|
||||||
{
|
{
|
||||||
|
session.checkUniqueLocked();
|
||||||
return session.getDboSession().add(std::unique_ptr<Listen> {new Listen{ user, track, backend, dateTime }});
|
return session.getDboSession().add(std::unique_ptr<Listen> {new Listen{ user, track, backend, dateTime }});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +189,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<ArtistId> Listen::getTopArtists(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType, Range range)
|
RangeResults<ArtistId> Listen::getTopArtists(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createArtistsQuery(session.getDboSession(), userId, backend, clusterIds, linkType) };
|
auto query{ createArtistsQuery(session.getDboSession(), userId, backend, clusterIds, linkType) };
|
||||||
|
|
||||||
auto collection{ query
|
auto collection{ query
|
||||||
@@ -199,6 +201,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<ReleaseId> Listen::getTopReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
RangeResults<ReleaseId> Listen::getTopReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createReleasesQuery(session.getDboSession(), userId, backend, clusterIds)
|
auto query{ createReleasesQuery(session.getDboSession(), userId, backend, clusterIds)
|
||||||
.orderBy("COUNT(r.id) DESC")
|
.orderBy("COUNT(r.id) DESC")
|
||||||
.groupBy("r.id") };
|
.groupBy("r.id") };
|
||||||
@@ -208,6 +211,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<TrackId> Listen::getTopTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
RangeResults<TrackId> Listen::getTopTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
|
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
|
||||||
.orderBy("COUNT(t.id) DESC")
|
.orderBy("COUNT(t.id) DESC")
|
||||||
.groupBy("t.id") };
|
.groupBy("t.id") };
|
||||||
@@ -217,6 +221,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<ArtistId> Listen::getRecentArtists(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType, Range range)
|
RangeResults<ArtistId> Listen::getRecentArtists(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, std::optional<TrackArtistLinkType> linkType, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createArtistsQuery(session.getDboSession(), userId, backend, clusterIds, linkType)
|
auto query{ createArtistsQuery(session.getDboSession(), userId, backend, clusterIds, linkType)
|
||||||
.groupBy("a.id").having("l.date_time = MAX(l.date_time)")
|
.groupBy("a.id").having("l.date_time = MAX(l.date_time)")
|
||||||
.orderBy("l.date_time DESC") };
|
.orderBy("l.date_time DESC") };
|
||||||
@@ -226,6 +231,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<ReleaseId> Listen::getRecentReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
RangeResults<ReleaseId> Listen::getRecentReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createReleasesQuery(session.getDboSession(), userId, backend, clusterIds)
|
auto query{ createReleasesQuery(session.getDboSession(), userId, backend, clusterIds)
|
||||||
.groupBy("r.id").having("l.date_time = MAX(l.date_time)")
|
.groupBy("r.id").having("l.date_time = MAX(l.date_time)")
|
||||||
.orderBy("l.date_time DESC") };
|
.orderBy("l.date_time DESC") };
|
||||||
@@ -235,6 +241,7 @@ namespace Database
|
|||||||
|
|
||||||
RangeResults<TrackId> Listen::getRecentTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
RangeResults<TrackId> Listen::getRecentTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
|
auto query{ createTracksQuery(session.getDboSession(), userId, backend, clusterIds)
|
||||||
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
|
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
|
||||||
.orderBy("l.date_time DESC") };
|
.orderBy("l.date_time DESC") };
|
||||||
@@ -242,8 +249,38 @@ namespace Database
|
|||||||
return Utils::execQuery(query, range);
|
return Utils::execQuery(query, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t Listen::getCount(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
|
||||||
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
|
|
||||||
|
return session.getDboSession().query<int>("SELECT COUNT(*) from listen l")
|
||||||
|
.where("l.track_id = ?").bind(trackId)
|
||||||
|
.where("l.user_id = ?").bind(userId)
|
||||||
|
.where("l.backend = ?").bind(backend)
|
||||||
|
.resultValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Listen::getCount(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
|
||||||
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
|
|
||||||
|
return session.getDboSession().query<int>("SELECT IFNULL(MIN(count_result), 0)"
|
||||||
|
" FROM ("
|
||||||
|
" SELECT COUNT(l.track_id) AS count_result"
|
||||||
|
" FROM track t"
|
||||||
|
" LEFT JOIN listen l ON t.id = l.track_id AND l.backend = ? AND l.user_id = ?"
|
||||||
|
" WHERE t.release_id = ?"
|
||||||
|
" GROUP BY t.id)")
|
||||||
|
.bind(backend)
|
||||||
|
.bind(userId)
|
||||||
|
.bind(releaseId)
|
||||||
|
.resultValue();
|
||||||
|
}
|
||||||
|
|
||||||
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
|
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
|
|
||||||
// TODO not pending remove?
|
// TODO not pending remove?
|
||||||
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
|
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
|
||||||
.join("track t ON l.track_id = t.id")
|
.join("track t ON l.track_id = t.id")
|
||||||
@@ -257,10 +294,10 @@ namespace Database
|
|||||||
|
|
||||||
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
|
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
|
||||||
{
|
{
|
||||||
|
session.checkSharedLocked();
|
||||||
// TODO not pending remove?
|
// TODO not pending remove?
|
||||||
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
|
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
|
||||||
.join("track t ON track_id = t.id")
|
.where("l.track_id = ?").bind(trackId)
|
||||||
.where("t.id = ?").bind(trackId)
|
|
||||||
.where("l.user_id = ?").bind(userId)
|
.where("l.user_id = ?").bind(userId)
|
||||||
.where("l.backend = ?").bind(backend)
|
.where("l.backend = ?").bind(backend)
|
||||||
.orderBy("l.date_time DESC")
|
.orderBy("l.date_time DESC")
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ namespace Database
|
|||||||
_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 track_bookmark_user_track_idx ON track_bookmark(user_id,track_id)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS listen_backend_idx ON listen(backend)");
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_backend_idx ON listen(backend)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_backend_idx ON listen(user_id,backend)");
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_backend_idx ON listen(user_id,backend)");
|
||||||
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_track_user_backend_idx ON listen(track_id,user_id,backend)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_track_backend_date_time_idx ON listen(user_id,track_id,backend,date_time)");
|
_session.execute("CREATE INDEX IF NOT EXISTS listen_user_track_backend_date_time_idx ON listen(user_id,track_id,backend,date_time)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_user_backend_idx ON starred_artist(user_id,backend)");
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_user_backend_idx ON starred_artist(user_id,backend)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_artist_user_backend_idx ON starred_artist(artist_id,user_id,backend)");
|
_session.execute("CREATE INDEX IF NOT EXISTS starred_artist_artist_user_backend_idx ON starred_artist(artist_id,user_id,backend)");
|
||||||
|
|||||||
@@ -71,10 +71,13 @@ namespace Database
|
|||||||
static RangeResults<ReleaseId> getRecentReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range = {});
|
static RangeResults<ReleaseId> getRecentReleases(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range = {});
|
||||||
static RangeResults<TrackId> getRecentTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range = {});
|
static RangeResults<TrackId> getRecentTracks(Session& session, UserId userId, ScrobblingBackend backend, const std::vector<ClusterId>& clusterIds, Range range = {});
|
||||||
|
|
||||||
|
static std::size_t getCount(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId);
|
||||||
|
static std::size_t getCount(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId trackId);
|
||||||
|
|
||||||
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId);
|
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId);
|
||||||
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId);
|
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId);
|
||||||
|
|
||||||
SyncState getSyncState() const { return _syncState; }
|
SyncState getSyncState() const { return _syncState; }
|
||||||
ObjectPtr<User> getUser() const { return _user; }
|
ObjectPtr<User> getUser() const { return _user; }
|
||||||
ObjectPtr<Track> getTrack() const { return _track; }
|
ObjectPtr<Track> getTrack() const { return _track; }
|
||||||
const Wt::WDateTime& getDateTime() const { return _dateTime; }
|
const Wt::WDateTime& getDateTime() const { return _dateTime; }
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ TEST_F(DatabaseFixture, Listen_getTopReleases)
|
|||||||
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
|
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
|
||||||
ScopedRelease release{ session, "MyRelease" };
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track.get().modify()->setRelease(release.get());
|
track.get().modify()->setRelease(release.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ TEST_F(DatabaseFixture, Listen_getTopReleases_multi)
|
|||||||
ScopedRelease release2{ session, "MyRelease2" };
|
ScopedRelease release2{ session, "MyRelease2" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track1.get().modify()->setRelease(release1.get());
|
track1.get().modify()->setRelease(release1.get());
|
||||||
track2.get().modify()->setRelease(release2.get());
|
track2.get().modify()->setRelease(release2.get());
|
||||||
}
|
}
|
||||||
@@ -381,7 +381,7 @@ TEST_F(DatabaseFixture, Listen_getTopReleases_cluster)
|
|||||||
ScopedRelease release{ session, "MyRelease" };
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track.get().modify()->setRelease(release.get());
|
track.get().modify()->setRelease(release.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +652,7 @@ TEST_F(DatabaseFixture, Listen_getRecentReleases)
|
|||||||
ScopedRelease release{ session, "MyRelease" };
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track.get().modify()->setRelease(release.get());
|
track.get().modify()->setRelease(release.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +692,7 @@ TEST_F(DatabaseFixture, Listen_getMostRecentRelease)
|
|||||||
ScopedRelease release{ session, "MyRelease" };
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track.get().modify()->setRelease(release.get());
|
track.get().modify()->setRelease(release.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,7 +746,7 @@ TEST_F(DatabaseFixture, Listen_getRecentReleases_multi)
|
|||||||
ScopedRelease release2{ session, "MyRelease2" };
|
ScopedRelease release2{ session, "MyRelease2" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track1.get().modify()->setRelease(release1.get());
|
track1.get().modify()->setRelease(release1.get());
|
||||||
track2.get().modify()->setRelease(release2.get());
|
track2.get().modify()->setRelease(release2.get());
|
||||||
}
|
}
|
||||||
@@ -806,7 +806,7 @@ TEST_F(DatabaseFixture, Listen_getRecentReleases_cluster)
|
|||||||
ScopedRelease release{ session, "MyRelease" };
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
|
|
||||||
{
|
{
|
||||||
auto transaction{ session.createSharedTransaction() };
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
track.get().modify()->setRelease(release.get());
|
track.get().modify()->setRelease(release.get());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -873,6 +873,71 @@ TEST_F(DatabaseFixture, Listen_getRecentTracks)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DatabaseFixture, Listen_getCount_track)
|
||||||
|
{
|
||||||
|
ScopedTrack track{ session, "MyTrack" };
|
||||||
|
ScopedUser user{ session, "MyUser" };
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createSharedTransaction() };
|
||||||
|
|
||||||
|
const std::size_t count{ Listen::getCount(session, user->getId(), ScrobblingBackend::Internal, track.getId()) };
|
||||||
|
EXPECT_EQ(count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
|
||||||
|
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createSharedTransaction() };
|
||||||
|
|
||||||
|
const std::size_t count{ Listen::getCount(session, user->getId(), ScrobblingBackend::Internal, track.getId()) };
|
||||||
|
EXPECT_EQ(count, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DatabaseFixture, Listen_getCount_release)
|
||||||
|
{
|
||||||
|
ScopedTrack track1{ session, "MyTrack" };
|
||||||
|
ScopedTrack track2{ session, "MyTrack" };
|
||||||
|
ScopedUser user{ session, "MyUser" };
|
||||||
|
ScopedRelease release{ session, "MyRelease" };
|
||||||
|
|
||||||
|
auto getReleaseListenCount{ [&]
|
||||||
|
{
|
||||||
|
auto transaction{ session.createSharedTransaction() };
|
||||||
|
return Listen::getCount(session, user->getId(), ScrobblingBackend::Internal, release.getId());
|
||||||
|
} };
|
||||||
|
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 0);
|
||||||
|
|
||||||
|
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
|
||||||
|
ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
|
||||||
|
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
|
track1.get().modify()->setRelease(release.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createUniqueTransaction() };
|
||||||
|
track2.get().modify()->setRelease(release.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 0);
|
||||||
|
ScopedListen listen2{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 1);
|
||||||
|
ScopedListen listen3{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 1);
|
||||||
|
|
||||||
|
ScopedListen listen4{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
|
||||||
|
EXPECT_EQ(getReleaseListenCount(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseFixture, Listen_getMostRecentTrack)
|
TEST_F(DatabaseFixture, Listen_getMostRecentTrack)
|
||||||
{
|
{
|
||||||
ScopedTrack track{ session, "MyTrack" };
|
ScopedTrack track{ session, "MyTrack" };
|
||||||
|
|||||||
@@ -19,8 +19,9 @@
|
|||||||
|
|
||||||
#include "responses/Album.hpp"
|
#include "responses/Album.hpp"
|
||||||
|
|
||||||
#include "services/database/Cluster.hpp"
|
|
||||||
#include "services/database/Artist.hpp"
|
#include "services/database/Artist.hpp"
|
||||||
|
#include "services/database/Cluster.hpp"
|
||||||
|
#include "services/database/Listen.hpp"
|
||||||
#include "services/database/Release.hpp"
|
#include "services/database/Release.hpp"
|
||||||
#include "services/database/User.hpp"
|
#include "services/database/User.hpp"
|
||||||
#include "services/feedback/IFeedbackService.hpp"
|
#include "services/feedback/IFeedbackService.hpp"
|
||||||
@@ -124,6 +125,8 @@ namespace API::Subsonic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
albumNode.setAttribute("playCount", Listen::getCount(context.dbSession, user->getId(), user->getScrobblingBackend(), release->getId()));
|
||||||
|
|
||||||
// Report the first GENRE for this track
|
// Report the first GENRE for this track
|
||||||
const ClusterType::pointer genreClusterType{ ClusterType::find(context.dbSession, "GENRE") };
|
const ClusterType::pointer genreClusterType{ ClusterType::find(context.dbSession, "GENRE") };
|
||||||
if (genreClusterType)
|
if (genreClusterType)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "services/database/Artist.hpp"
|
#include "services/database/Artist.hpp"
|
||||||
#include "services/database/Cluster.hpp"
|
#include "services/database/Cluster.hpp"
|
||||||
|
#include "services/database/Listen.hpp"
|
||||||
#include "services/database/Release.hpp"
|
#include "services/database/Release.hpp"
|
||||||
#include "services/database/Track.hpp"
|
#include "services/database/Track.hpp"
|
||||||
#include "services/database/TrackArtistLink.hpp"
|
#include "services/database/TrackArtistLink.hpp"
|
||||||
@@ -106,7 +107,7 @@ namespace API::Subsonic
|
|||||||
trackResponse.setAttribute("discNumber", *track->getDiscNumber());
|
trackResponse.setAttribute("discNumber", *track->getDiscNumber());
|
||||||
if (track->getYear())
|
if (track->getYear())
|
||||||
trackResponse.setAttribute("year", *track->getYear());
|
trackResponse.setAttribute("year", *track->getYear());
|
||||||
|
trackResponse.setAttribute("playCount", Listen::getCount(context.dbSession, user->getId(), user->getScrobblingBackend(), track->getId()));
|
||||||
trackResponse.setAttribute("path", getTrackPath(track));
|
trackResponse.setAttribute("path", getTrackPath(track));
|
||||||
{
|
{
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|||||||
Reference in New Issue
Block a user