diff --git a/src/libs/scrobbling/impl/Scrobbling.cpp b/src/libs/scrobbling/impl/Scrobbling.cpp index add4cf2e..b1a91936 100644 --- a/src/libs/scrobbling/impl/Scrobbling.cpp +++ b/src/libs/scrobbling/impl/Scrobbling.cpp @@ -19,8 +19,11 @@ #include "Scrobbling.hpp" +#include "database/Artist.hpp" #include "database/Db.hpp" +#include "database/Release.hpp" #include "database/Session.hpp" +#include "database/Track.hpp" #include "database/TrackList.hpp" #include "database/User.hpp" @@ -29,13 +32,15 @@ namespace Scrobbling { + using namespace Database; + std::unique_ptr - createScrobbling(boost::asio::io_context& ioContext, Database::Db& db) + createScrobbling(boost::asio::io_context& ioContext, Db& db) { return std::make_unique(ioContext, db); } - Scrobbling::Scrobbling(boost::asio::io_context& ioContext, Database::Db& db) + Scrobbling::Scrobbling(boost::asio::io_context& ioContext, Db& db) : _db {db} { _scrobblers.emplace(Database::Scrobbler::Internal, std::make_unique(_db)); @@ -68,116 +73,169 @@ namespace Scrobbling { std::optional scrobbler; - Database::Session& session {_db.getTLSSession()}; + Session& session {_db.getTLSSession()}; auto transaction {session.createSharedTransaction()}; - if (const Database::User::pointer user {Database::User::getById(session, userId)}) + if (const User::pointer user {User::getById(session, userId)}) scrobbler = user->getScrobbler(); return scrobbler; } - std::vector> - Scrobbling::getRecentArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) + Scrobbling::ArtistContainer + Scrobbling::getRecentArtists(UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + ArtistContainer res; - std::vector> res; + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + const ObjectPtr history {getListensTrackList(session, user)}; if (history) - res = history->getArtistsReverse(clusterIds, linkType, range, moreResults); + { + for (const Artist::pointer& artist : history->getArtistsReverse(clusterIds, linkType, range, moreResults)) + res.push_back(artist->getId()); + } return res; } - std::vector> - Scrobbling::getRecentReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) + Scrobbling::ReleaseContainer + Scrobbling::getRecentReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + ReleaseContainer res; - std::vector> res; + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + const ObjectPtr history {getListensTrackList(session, user)}; if (history) - res = history->getReleasesReverse(clusterIds, range, moreResults); + { + for (const Release::pointer& release : history->getReleasesReverse(clusterIds, range, moreResults)) + res.push_back(release->getId()); + } return res; } - std::vector> - Scrobbling::getRecentTracks(Database::Session& session, - Database::ObjectPtr user, + Scrobbling::TrackContainer + Scrobbling::getRecentTracks(Database::UserId userId, const std::vector& clusterIds, std::optional range, bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + TrackContainer res; - std::vector> res; + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + const ObjectPtr history {getListensTrackList(session, user)}; if (history) - res = history->getTracksReverse(clusterIds, range, moreResults); + { + for (const Track::pointer& track : history->getTracksReverse(clusterIds, range, moreResults)) + res.push_back(track->getId()); + } return res; } // Top - std::vector> - Scrobbling::getTopArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) + Scrobbling::ArtistContainer + Scrobbling::getTopArtists(UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + ArtistContainer res; - std::vector> res; + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + const ObjectPtr history {getListensTrackList(session, user)}; if (history) - res = history->getTopArtists(clusterIds, linkType, range, moreResults); + { + for (const Artist::pointer& artist : history->getTopArtists(clusterIds, linkType, range, moreResults)) + res.push_back(artist->getId()); + } return res; } - std::vector> - Scrobbling::getTopReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) + Scrobbling::ReleaseContainer + Scrobbling::getTopReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + ReleaseContainer res; - std::vector> res; + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + const ObjectPtr history {getListensTrackList(session, user)}; if (history) - res = history->getTopReleases(clusterIds, range, moreResults); + { + for (const Release::pointer& release : history->getTopReleases(clusterIds, range, moreResults)) + res.push_back(release->getId()); + } return res; } - std::vector> - Scrobbling::getTopTracks(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) + Scrobbling::TrackContainer + Scrobbling::getTopTracks(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) { - const Database::ObjectPtr history {getListensTrackList(session, user)}; + TrackContainer res; - std::vector> res; - if (history) - res = history->getTopTracks(clusterIds, range, moreResults); + Session& session {_db.getTLSSession()}; + auto transaction {session.createSharedTransaction()}; + + const User::pointer user {User::getById(session, userId)}; + if (!user) + return res; + + if (const ObjectPtr history {getListensTrackList(session, user)}) + { + for (const Track::pointer& track : history->getTopTracks(clusterIds, range, moreResults)) + res.push_back(track->getId()); + } return res; } Database::ObjectPtr - Scrobbling::getListensTrackList(Database::Session& session, Database::ObjectPtr user) + Scrobbling::getListensTrackList(Session& session, Database::ObjectPtr user) { return _scrobblers[user->getScrobbler()]->getListensTrackList(session, user); } diff --git a/src/libs/scrobbling/impl/Scrobbling.hpp b/src/libs/scrobbling/impl/Scrobbling.hpp index 6aa2ed2f..dd338dd3 100644 --- a/src/libs/scrobbling/impl/Scrobbling.hpp +++ b/src/libs/scrobbling/impl/Scrobbling.hpp @@ -38,43 +38,37 @@ namespace Scrobbling void listenFinished(const Listen& listen, std::optional duration) override; void addTimedListen(const TimedListen& listen) override; - std::vector> getRecentArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) override; + ArtistContainer getRecentArtists(Database::UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) override; - std::vector> getRecentReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) override; + ReleaseContainer getRecentReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) override; - std::vector> getRecentTracks(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) override; + TrackContainer getRecentTracks(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) override; - std::vector> getTopArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) override; + ArtistContainer getTopArtists(Database::UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) override; - std::vector> getTopReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) override; + ReleaseContainer getTopReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) override; - std::vector> getTopTracks(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) override; + TrackContainer getTopTracks(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) override; Database::ObjectPtr getListensTrackList(Database::Session& session, Database::ObjectPtr user); diff --git a/src/libs/scrobbling/include/scrobbling/IScrobbling.hpp b/src/libs/scrobbling/include/scrobbling/IScrobbling.hpp index 6f4436c7..cda27ca1 100644 --- a/src/libs/scrobbling/include/scrobbling/IScrobbling.hpp +++ b/src/libs/scrobbling/include/scrobbling/IScrobbling.hpp @@ -56,45 +56,45 @@ namespace Scrobbling virtual void addTimedListen(const TimedListen& listen) = 0; // Stats + template + using ResultContainer = std::vector; + + using ArtistContainer = ResultContainer; + using ReleaseContainer = ResultContainer; + using TrackContainer = ResultContainer; // From most recent to oldest - virtual std::vector> getRecentArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) = 0; + virtual ArtistContainer getRecentArtists(Database::UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) = 0; - virtual std::vector> getRecentReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) = 0; + virtual ReleaseContainer getRecentReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) = 0; - virtual std::vector> getRecentTracks(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) = 0; + virtual TrackContainer getRecentTracks(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) = 0; // Top - virtual std::vector> getTopArtists(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional linkType, - std::optional range, - bool& moreResults) = 0; + virtual ArtistContainer getTopArtists(Database::UserId userId, + const std::vector& clusterIds, + std::optional linkType, + std::optional range, + bool& moreResults) = 0; - virtual std::vector> getTopReleases(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) = 0; + virtual ReleaseContainer getTopReleases(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) = 0; - virtual std::vector> getTopTracks(Database::Session& session, - Database::ObjectPtr user, - const std::vector& clusterIds, - std::optional range, - bool& moreResults) = 0; + virtual TrackContainer getTopTracks(Database::UserId userId, + const std::vector& clusterIds, + std::optional range, + bool& moreResults) = 0; }; std::unique_ptr createScrobbling(boost::asio::io_service& ioService, Database::Db& db); diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 3fc97965..3f6e9ec8 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -724,6 +724,7 @@ handleGetAlbumListRequestCommon(const RequestContext& context, bool id3) const Range range {offset, size}; std::vector releases; + Scrobbling::IScrobbling& scrobbling {*Service::get()}; auto transaction {context.dbSession.createSharedTransaction()}; @@ -765,7 +766,11 @@ handleGetAlbumListRequestCommon(const RequestContext& context, bool id3) else if (type == "frequent") { bool moreResults {}; - releases = Service::get()->getTopReleases(context.dbSession, user, {}, range, moreResults); + for (ReleaseId releaseId : scrobbling.getTopReleases(context.userId, {}, range, moreResults)) + { + if (Release::pointer release {Release::getById(context.dbSession, releaseId)}) + releases.push_back(release ); + } } else if (type == "newest") { @@ -780,7 +785,11 @@ handleGetAlbumListRequestCommon(const RequestContext& context, bool id3) else if (type == "recent") { bool moreResults {}; - releases = Service::get()->getRecentReleases(context.dbSession, user, {}, range, moreResults); + for (ReleaseId releaseId : scrobbling.getRecentReleases(context.userId, {}, range, moreResults)) + { + if (Release::pointer release {Release::getById(context.dbSession, releaseId)}) + releases.push_back(release ); + } } else if (type == "starred") { diff --git a/src/lms/ui/explore/ArtistCollector.cpp b/src/lms/ui/explore/ArtistCollector.cpp index 49e19731..0c73aa3e 100644 --- a/src/lms/ui/explore/ArtistCollector.cpp +++ b/src/lms/ui/explore/ArtistCollector.cpp @@ -34,6 +34,8 @@ namespace UserInterface std::vector> ArtistCollector::get(std::optional range, bool& moreResults) { + Scrobbling::IScrobbling& scrobbling {*Service::get()}; + range = getActualRange(range); std::vector artists; @@ -53,17 +55,19 @@ namespace UserInterface break; case Mode::RecentlyPlayed: - artists = Service::get()->getRecentArtists(LmsApp->getDbSession(), LmsApp->getUser(), - getFilters().getClusterIds(), - _linkType, - range, moreResults); + for (const ArtistId artistId : scrobbling.getRecentArtists(LmsApp->getUserId(), getFilters().getClusterIds(), _linkType, range, moreResults)) + { + if (Artist::pointer artist {Artist::getById(LmsApp->getDbSession(), artistId)}) + artists.push_back(artist); + } break; case Mode::MostPlayed: - artists = Service::get()->getTopArtists(LmsApp->getDbSession(), LmsApp->getUser(), - getFilters().getClusterIds(), - _linkType, - range, moreResults); + for (const ArtistId artistId : scrobbling.getTopArtists(LmsApp->getUserId(), getFilters().getClusterIds(), _linkType, range, moreResults)) + { + if (Artist::pointer artist {Artist::getById(LmsApp->getDbSession(), artistId)}) + artists.push_back(artist); + } break; case Mode::RecentlyAdded: diff --git a/src/lms/ui/explore/ReleaseCollector.cpp b/src/lms/ui/explore/ReleaseCollector.cpp index 473278df..c5671f54 100644 --- a/src/lms/ui/explore/ReleaseCollector.cpp +++ b/src/lms/ui/explore/ReleaseCollector.cpp @@ -37,6 +37,8 @@ namespace UserInterface std::vector ReleaseCollector::get(std::optional range, bool& moreResults) { + Scrobbling::IScrobbling& scrobbling {*Service::get()}; + range = getActualRange(range); std::vector releases; @@ -51,11 +53,19 @@ namespace UserInterface break; case ReleaseCollector::Mode::RecentlyPlayed: - releases = Service::get()->getRecentReleases(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); + for (const ReleaseId releaseId : scrobbling.getRecentReleases(LmsApp->getUserId(), getFilters().getClusterIds(), range, moreResults)) + { + if (const Release::pointer release {Release::getById(LmsApp->getDbSession(), releaseId)}) + releases.push_back(release); + } break; case Mode::MostPlayed: - releases = Service::get()->getTopReleases(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); + for (const ReleaseId releaseId : scrobbling.getTopReleases(LmsApp->getUserId(), getFilters().getClusterIds(), range, moreResults)) + { + if (const Release::pointer release {Release::getById(LmsApp->getDbSession(), releaseId)}) + releases.push_back(release); + } break; case Mode::RecentlyAdded: diff --git a/src/lms/ui/explore/TrackCollector.cpp b/src/lms/ui/explore/TrackCollector.cpp index 26495626..77106931 100644 --- a/src/lms/ui/explore/TrackCollector.cpp +++ b/src/lms/ui/explore/TrackCollector.cpp @@ -37,44 +37,53 @@ namespace UserInterface std::vector TrackCollector::get(std::optional range, bool& moreResults) { + Scrobbling::IScrobbling& scrobbling {*Service::get()}; range = getActualRange(range); - std::vector releases; + std::vector tracks; switch (getMode()) { case Mode::Random: - releases = getRandomTracks(range, moreResults); + tracks = getRandomTracks(range, moreResults); break; case Mode::Starred: - releases = Track::getStarred(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); + tracks = Track::getStarred(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); break; case TrackCollector::Mode::RecentlyPlayed: - releases = Service::get()->getRecentTracks(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); + for (const TrackId trackId : scrobbling.getRecentTracks(LmsApp->getUserId(), getFilters().getClusterIds(), range, moreResults)) + { + if (const Track::pointer track {Track::getById(LmsApp->getDbSession(), trackId)}) + tracks.push_back(track); + } break; case Mode::MostPlayed: - releases = Service::get()->getTopTracks(LmsApp->getDbSession(), LmsApp->getUser(), getFilters().getClusterIds(), range, moreResults); + for (const TrackId trackId : scrobbling.getTopTracks(LmsApp->getUserId(), getFilters().getClusterIds(), range, moreResults)) + { + if (const Track::pointer track {Track::getById(LmsApp->getDbSession(), trackId)}) + tracks.push_back(track); + } break; case Mode::RecentlyAdded: - releases = Track::getLastWritten(LmsApp->getDbSession(), std::nullopt, getFilters().getClusterIds(), range, moreResults); + tracks = Track::getLastWritten(LmsApp->getDbSession(), std::nullopt, getFilters().getClusterIds(), range, moreResults); break; case Mode::Search: - releases = Track::getByFilter(LmsApp->getDbSession(), getFilters().getClusterIds(), getSearchKeywords(), range, moreResults); + tracks = Track::getByFilter(LmsApp->getDbSession(), getFilters().getClusterIds(), getSearchKeywords(), range, moreResults); break; case Mode::All: - releases = Track::getByFilter(LmsApp->getDbSession(), getFilters().getClusterIds(), {}, range, moreResults); + tracks = Track::getByFilter(LmsApp->getDbSession(), getFilters().getClusterIds(), {}, range, moreResults); break; } if (range && getMaxCount() && (range->offset + range->limit == *getMaxCount())) moreResults = false; - return releases; + return tracks; } std::vector @@ -95,7 +104,7 @@ namespace UserInterface std::vector TrackCollector::getRandomTracks(std::optional range, bool& moreResults) { - std::vector releases; + std::vector tracks; assert(getMode() == Mode::Random); @@ -108,15 +117,15 @@ namespace UserInterface for (auto it {itBegin}; it != itEnd; ++it) { - Track::pointer release {Track::getById(LmsApp->getDbSession(), *it)}; - if (release) - releases.push_back(release); + Track::pointer track {Track::getById(LmsApp->getDbSession(), *it)}; + if (track) + tracks.push_back(track); } moreResults = (itEnd != std::cend(_randomTracks)); } - return releases; + return tracks; } } // ns UserInterface