1 /* 2 * Copyright (C) 2021 Emeric Poupon 3 * 4 * This file is part of LMS. 5 * 6 * LMS is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * LMS is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with LMS. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "Scrobbling.hpp" 21 22 #include "database/Db.hpp" 23 #include "database/Session.hpp" 24 #include "database/TrackList.hpp" 25 #include "database/User.hpp" 26 27 #include "internal/InternalScrobbler.hpp" 28 #include "listenbrainz/ListenBrainzScrobbler.hpp" 29 30 namespace Scrobbling 31 { 32 std::unique_ptr<IScrobbling> createScrobbling(Database::Db & db)33 createScrobbling(Database::Db& db) 34 { 35 return std::make_unique<Scrobbling>(db); 36 } 37 Scrobbling(Database::Db & db)38 Scrobbling::Scrobbling(Database::Db& db) 39 : _db {db} 40 { 41 _scrobblers.emplace(Database::Scrobbler::Internal, std::make_unique<InternalScrobbler>(_db)); 42 _scrobblers.emplace(Database::Scrobbler::ListenBrainz, std::make_unique<ListenBrainzScrobbler>(_db)); 43 } 44 45 void listenStarted(const Listen & listen)46 Scrobbling::listenStarted(const Listen& listen) 47 { 48 if (auto scrobbler {getUserScrobbler(listen.userId)}) 49 _scrobblers[*scrobbler]->listenStarted(listen); 50 } 51 52 void listenFinished(const Listen & listen,std::optional<std::chrono::seconds> duration)53 Scrobbling::listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration) 54 { 55 if (auto scrobbler {getUserScrobbler(listen.userId)}) 56 _scrobblers[*scrobbler]->listenFinished(listen, duration); 57 } 58 59 void addListen(const Listen & listen,Wt::WDateTime timePoint)60 Scrobbling::addListen(const Listen& listen, Wt::WDateTime timePoint) 61 { 62 if (auto scrobbler {getUserScrobbler(listen.userId)}) 63 _scrobblers[*scrobbler]->addListen(listen, timePoint); 64 } 65 66 std::optional<Database::Scrobbler> getUserScrobbler(Database::IdType userId)67 Scrobbling::getUserScrobbler(Database::IdType userId) 68 { 69 std::optional<Database::Scrobbler> scrobbler; 70 71 Database::Session& session {_db.getTLSSession()}; 72 auto transaction {session.createSharedTransaction()}; 73 if (const Database::User::pointer user {Database::User::getById(session, userId)}) 74 scrobbler = user->getScrobbler(); 75 76 return scrobbler; 77 } 78 79 std::vector<Wt::Dbo::ptr<Database::Artist>> getRecentArtists(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::TrackArtistLinkType> linkType,std::optional<Database::Range> range,bool & moreResults)80 Scrobbling::getRecentArtists(Database::Session& session, 81 Wt::Dbo::ptr<Database::User> user, 82 const std::set<Database::IdType>& clusterIds, 83 std::optional<Database::TrackArtistLinkType> linkType, 84 std::optional<Database::Range> range, 85 bool& moreResults) 86 { 87 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 88 89 std::vector<Wt::Dbo::ptr<Database::Artist>> res; 90 if (history) 91 res = history->getArtistsReverse(clusterIds, linkType, range, moreResults); 92 93 return res; 94 } 95 96 std::vector<Wt::Dbo::ptr<Database::Release>> getRecentReleases(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::Range> range,bool & moreResults)97 Scrobbling::getRecentReleases(Database::Session& session, 98 Wt::Dbo::ptr<Database::User> user, 99 const std::set<Database::IdType>& clusterIds, 100 std::optional<Database::Range> range, 101 bool& moreResults) 102 { 103 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 104 105 std::vector<Wt::Dbo::ptr<Database::Release>> res; 106 if (history) 107 res = history->getReleasesReverse(clusterIds, range, moreResults); 108 109 return res; 110 } 111 112 std::vector<Wt::Dbo::ptr<Database::Track>> getRecentTracks(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::Range> range,bool & moreResults)113 Scrobbling::getRecentTracks(Database::Session& session, 114 Wt::Dbo::ptr<Database::User> user, 115 const std::set<Database::IdType>& clusterIds, 116 std::optional<Database::Range> range, 117 bool& moreResults) 118 { 119 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 120 121 std::vector<Wt::Dbo::ptr<Database::Track>> res; 122 if (history) 123 res = history->getTracksReverse(clusterIds, range, moreResults); 124 125 return res; 126 } 127 128 129 // Top 130 std::vector<Wt::Dbo::ptr<Database::Artist>> getTopArtists(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::TrackArtistLinkType> linkType,std::optional<Database::Range> range,bool & moreResults)131 Scrobbling::getTopArtists(Database::Session& session, 132 Wt::Dbo::ptr<Database::User> user, 133 const std::set<Database::IdType>& clusterIds, 134 std::optional<Database::TrackArtistLinkType> linkType, 135 std::optional<Database::Range> range, 136 bool& moreResults) 137 { 138 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 139 140 std::vector<Wt::Dbo::ptr<Database::Artist>> res; 141 if (history) 142 res = history->getTopArtists(clusterIds, linkType, range, moreResults); 143 144 return res; 145 } 146 147 std::vector<Wt::Dbo::ptr<Database::Release>> getTopReleases(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::Range> range,bool & moreResults)148 Scrobbling::getTopReleases(Database::Session& session, 149 Wt::Dbo::ptr<Database::User> user, 150 const std::set<Database::IdType>& clusterIds, 151 std::optional<Database::Range> range, 152 bool& moreResults) 153 { 154 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 155 156 std::vector<Wt::Dbo::ptr<Database::Release>> res; 157 if (history) 158 res = history->getTopReleases(clusterIds, range, moreResults); 159 160 return res; 161 } 162 163 std::vector<Wt::Dbo::ptr<Database::Track>> getTopTracks(Database::Session & session,Wt::Dbo::ptr<Database::User> user,const std::set<Database::IdType> & clusterIds,std::optional<Database::Range> range,bool & moreResults)164 Scrobbling::getTopTracks(Database::Session& session, 165 Wt::Dbo::ptr<Database::User> user, 166 const std::set<Database::IdType>& clusterIds, 167 std::optional<Database::Range> range, 168 bool& moreResults) 169 { 170 const Wt::Dbo::ptr<Database::TrackList> history {getListensTrackList(session, user)}; 171 172 std::vector<Wt::Dbo::ptr<Database::Track>> res; 173 if (history) 174 res = history->getTopTracks(clusterIds, range, moreResults); 175 176 return res; 177 } 178 179 Wt::Dbo::ptr<Database::TrackList> getListensTrackList(Database::Session & session,Wt::Dbo::ptr<Database::User> user)180 Scrobbling::getListensTrackList(Database::Session& session, Wt::Dbo::ptr<Database::User> user) 181 { 182 return _scrobblers[user->getScrobbler()]->getListensTrackList(session, user); 183 } 184 185 } // ns Scrobbling 186 187