diff --git a/src/database/Cluster.cpp b/src/database/Cluster.cpp index 136c48e9..102e6f5e 100644 --- a/src/database/Cluster.cpp +++ b/src/database/Cluster.cpp @@ -74,6 +74,19 @@ Cluster::getTracks(int offset, int limit) const return std::vector>(res.begin(), res.end()); } +std::set +Cluster::getTrackIds() const +{ + assert(session()); + assert(IdIsValid(self()->id())); + + Wt::Dbo::collection res = session()->query("SELECT t_c.track_id from track_cluster t_c INNER JOIN cluster c ON c.id = t_c.cluster_id") + .where("c.id = ?").bind(self()->id()); + + return std::set(res.begin(), res.end()); + +} + ClusterType::ClusterType(std::string name) : _name(name) diff --git a/src/database/Cluster.hpp b/src/database/Cluster.hpp index ba7965a3..04b96279 100644 --- a/src/database/Cluster.hpp +++ b/src/database/Cluster.hpp @@ -52,9 +52,9 @@ class Cluster : public Wt::Dbo::Dbo // Accessors const std::string& getName(void) const { return _name; } Wt::Dbo::ptr getType() const { return _clusterType; } - const Wt::Dbo::collection>& getTracks() const { return _tracks; } - std::size_t getTrackCount() const { return _tracks.size(); } + std::size_t getCount() const { return _tracks.size(); } std::vector> getTracks(int offset, int limit) const; + std::set getTrackIds() const; void addTrack(Wt::Dbo::ptr track); diff --git a/src/database/Playlist.cpp b/src/database/Playlist.cpp index 17d55eab..341bc368 100644 --- a/src/database/Playlist.cpp +++ b/src/database/Playlist.cpp @@ -155,10 +155,24 @@ Playlist::hasTrack(IdType trackId) const assert(IdIsValid(self()->id())); Wt::Dbo::collection res = session()->query("SELECT p_e from playlist_entry p_e INNER JOIN playlist p ON p_e.playlist_id = p.id") - .where("p_e.track_id = ?").bind(trackId); + .where("p_e.track_id = ?").bind(trackId) + .where("p.id = ?").bind(self()->id()); return res.size() > 0; } +std::vector +Playlist::getTrackIds() const +{ + assert(session()); + assert(IdIsValid(self()->id())); + + Wt::Dbo::collection res = session()->query("SELECT p_e.track_id from playlist_entry p_e INNER JOIN playlist p ON p_e.playlist_id = p.id") + .where("p.id = ?").bind(self()->id()); + + return std::vector(res.begin(), res.end()); + +} + } // namespace Database diff --git a/src/database/Playlist.hpp b/src/database/Playlist.hpp index 27135c9d..904f3ae3 100644 --- a/src/database/Playlist.hpp +++ b/src/database/Playlist.hpp @@ -58,6 +58,7 @@ class Playlist : public Wt::Dbo::Dbo std::size_t getCount() const; Wt::Dbo::ptr getEntry(std::size_t pos) const; std::vector> getEntries(int offset, int size, bool& moreResults) const; + std::vector getTrackIds() const; // Get clusters, order by occurence std::vector> getClusters() const; diff --git a/src/scanner/MediaScanner.cpp b/src/scanner/MediaScanner.cpp index f2bcf716..a7ed1094 100644 --- a/src/scanner/MediaScanner.cpp +++ b/src/scanner/MediaScanner.cpp @@ -668,7 +668,7 @@ MediaScanner::checkAudioFiles( Stats& stats ) auto clusters = Cluster::getAll(_db.getSession()); for (auto cluster : clusters) { - if (cluster->getTracks().size() == 0) + if (cluster->getCount() == 0) { LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan cluster '" << cluster->getName() << "'"; cluster.remove(); diff --git a/src/ui/PlayQueueView.cpp b/src/ui/PlayQueueView.cpp index 824a2e9e..6721805a 100644 --- a/src/ui/PlayQueueView.cpp +++ b/src/ui/PlayQueueView.cpp @@ -178,8 +178,6 @@ PlayQueue::enqueueTracks(const std::vector& tracks) // Use a "session" playqueue in order to store the current playqueue // so that the user can disconnect and get its playqueue back - LMS_LOG(UI, DEBUG) << "Adding tracks to the current queue"; - auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); for (auto track : tracks) @@ -205,8 +203,6 @@ PlayQueue::addTracks(const std::vector& tracks) void PlayQueue::playTracks(const std::vector& tracks) { - LMS_LOG(UI, DEBUG) << "Emptying current queue to play new tracks"; - Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); auto playqueue = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); @@ -294,10 +290,14 @@ PlayQueue::addRadioTrack() auto now = std::chrono::system_clock::now(); std::mt19937 randGenerator(std::chrono::duration_cast(now.time_since_epoch()).count()); - LMS_LOG(UI, INFO) << "Radio mode: adding track"; - auto playlist = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getCurrentUser()); + std::set playlistTrackIds; + { + auto ids = playlist->getTrackIds(); + playlistTrackIds = std::set(ids.begin(), ids.end()); + } + // Get all the tracks of the playlist, get the cluster that is mostly used // and reuse it to get the next track auto clusters = playlist->getClusters(); @@ -306,21 +306,22 @@ PlayQueue::addRadioTrack() for (auto cluster : clusters) { - LMS_LOG(UI, DEBUG) << "Processing cluster '" << cluster->getName() << "'"; + std::set clusterTrackIds = cluster->getTrackIds(); - auto nbTracks = cluster->getTrackCount(); - if (nbTracks == 0) + std::set candidateTrackIds; + std::set_difference(clusterTrackIds.begin(), clusterTrackIds.end(), + playlistTrackIds.begin(), playlistTrackIds.end(), + std::inserter(candidateTrackIds, candidateTrackIds.end())); + + if (candidateTrackIds.empty()) continue; - std::uniform_int_distribution dist(0, nbTracks - 1); + std::uniform_int_distribution dist(0, candidateTrackIds.size() - 1); - auto trackToAdd = cluster->getTracks(dist(randGenerator), 1).front(); + auto trackToAdd = Database::Track::getById(LmsApp->getDboSession(), *std::next(candidateTrackIds.begin(), dist(randGenerator))); + enqueueTrack(trackToAdd); - if (!playlist->hasTrack(trackToAdd.id())) - { - enqueueTrack(trackToAdd); - return; - } + return; } LMS_LOG(UI, INFO) << "No more track to be added!";