Improved the tag based similarity results

This commit is contained in:
emeric
2019-10-22 12:47:25 +02:00
parent cdcc84ab03
commit 4ab91aea44
16 changed files with 924 additions and 827 deletions
+30 -1
View File
@@ -140,8 +140,10 @@ getQuery(Session& session,
}
std::vector<Artist::pointer>
Artist::getByFilter(Session& session, const std::set<IdType>& clusters)
Artist::getByClusters(Session& session, const std::set<IdType>& clusters)
{
assert(!clusters.empty());
session.checkSharedLocked();
bool more;
return getByFilter(session, clusters, {}, {}, {}, more);
@@ -296,6 +298,33 @@ Artist::getRandomTracks(std::optional<std::size_t> count) const
return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end());
}
std::vector<Wt::Dbo::ptr<Artist>>
Artist::getSimilarArtists(std::optional<std::size_t> offset, std::optional<std::size_t> count) const
{
assert(self());
assert(IdIsValid(self()->id()));
assert(session());
Wt::Dbo::Query<pointer> query {session()->query<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"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT c.id 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 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 = ?)"
" AND a.id <> ?"
)
.bind(self()->id())
.bind(self()->id())
.groupBy("a.id")
.orderBy("COUNT(*) DESC")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1)};
Wt::Dbo::collection<pointer> res = query;
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>>
Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
{
+5 -4
View File
@@ -52,11 +52,11 @@ class Artist : public Wt::Dbo::Dbo<Artist>
static pointer getByMBID(Session& session, const std::string& MBID);
static pointer getById(Session& session, IdType id);
static std::vector<pointer> getByName(Session& session, const std::string& name);
static std::vector<pointer> getByFilter(Session& session,
static std::vector<pointer> getByClusters(Session& session,
const std::set<IdType>& clusters); // at least one track that belongs to these clusters
static std::vector<pointer> getByFilter(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
const std::set<IdType>& clusters, // if non empty, at least one artist that belongs to these clusters
const std::vector<std::string>& keywords, // if non empty, name must match all of these keywords
std::optional<std::size_t> offset,
std::optional<std::size_t> size,
bool& moreExpected);
@@ -69,11 +69,12 @@ class Artist : public Wt::Dbo::Dbo<Artist>
const std::string& getName(void) const { return _name; }
const std::string& getMBID(void) const { return _MBID; }
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = std::set<IdType>()) const;
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = {}) const; // if non empty, get the releases that match all these clusters
std::size_t getReleaseCount() const;
std::vector<Wt::Dbo::ptr<Track>> getTracks(std::optional<TrackArtistLink::Type> linkType = {}) const;
std::vector<Wt::Dbo::ptr<Track>> getTracksWithRelease(std::optional<TrackArtistLink::Type> linkType = {}) const;
std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(std::optional<std::size_t> count) const;
std::vector<pointer> getSimilarArtists(std::optional<std::size_t> offset = {}, std::optional<std::size_t> count = {}) const;
// Get the cluster of the tracks made by this artist
// Each clusters are grouped by cluster type, sorted by the number of occurence
+7 -7
View File
@@ -63,8 +63,7 @@ std::vector<Cluster::pointer>
Cluster::getAllOrphans(Session& session)
{
session.checkSharedLocked();
Wt::Dbo::collection<Cluster::pointer> res {session.getDboSession().query<Cluster::pointer>("SELECT DISTINCT c FROM cluster c WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_cluster t_c ON t.id = t_c.track_id)")};
Wt::Dbo::collection<Cluster::pointer> res {session.getDboSession().query<Cluster::pointer>("SELECT DISTINCT c FROM cluster c WHERE NOT EXISTS(SELECT 1 FROM track_cluster t_c WHERE t_c.cluster_id = c.id)")};
return std::vector<Cluster::pointer>(res.begin(), res.end());
}
@@ -84,15 +83,16 @@ Cluster::addTrack(Wt::Dbo::ptr<Track> track)
}
std::vector<Wt::Dbo::ptr<Track>>
Cluster::getTracks(int offset, int limit) const
Cluster::getTracks(std::optional<std::size_t> offset, std::optional<std::size_t> limit) const
{
assert(session());
assert(IdIsValid(self()->id()));
Wt::Dbo::collection<Track::pointer> res = session()->query<Track::pointer>("SELECT t FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("c.id = ?").bind(self()->id())
.offset(offset)
.limit(limit);
Wt::Dbo::collection<Track::pointer> res
{session()->query<Track::pointer>("SELECT t FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("c.id = ?").bind(self()->id())
.offset(offset ? static_cast<int>(*offset) : -1)
.limit(limit ? static_cast<int>(*limit) : -1)};
return std::vector<Wt::Dbo::ptr<Track>>(res.begin(), res.end());
}
+1 -1
View File
@@ -55,7 +55,7 @@ class Cluster : public Wt::Dbo::Dbo<Cluster>
const std::string& getName() const { return _name; }
Wt::Dbo::ptr<ClusterType> getType() const { return _clusterType; }
std::size_t getTracksCount() const { return _tracks.size(); }
std::vector<Wt::Dbo::ptr<Track>> getTracks(int offset, int limit) const;
std::vector<Wt::Dbo::ptr<Track>> getTracks(std::optional<std::size_t> offset = {}, std::optional<std::size_t> limit = {}) const;
std::set<IdType> getTrackIds() const;
std::size_t getReleasesCount() const;
+34 -2
View File
@@ -206,10 +206,14 @@ getQuery(Session& session,
}
std::vector<Release::pointer>
Release::getByFilter(Session& session, const std::set<IdType>& clusterIds)
Release::getByClusters(Session& session, const std::set<IdType>& clusters)
{
assert(!clusters.empty());
session.checkSharedLocked();
bool moreResults;
return getByFilter(session, clusterIds, {}, {}, {}, moreResults);
return getByFilter(session, clusters, {}, {}, {}, moreResults);
}
std::vector<Release::pointer>
@@ -220,6 +224,8 @@ Release::getByFilter(Session& session,
std::optional<std::size_t> size,
bool& moreResults)
{
session.checkSharedLocked();
Wt::Dbo::collection<pointer> collection = getQuery(session, clusterIds, keywords)
.limit(size ? static_cast<int>(*size) + 1 : -1)
.offset(offset ? static_cast<int>(*offset) : -1);
@@ -332,6 +338,32 @@ Release::getArtists(TrackArtistLink::Type linkType) const
return std::vector<Wt::Dbo::ptr<Artist>>(res.begin(), res.end());
}
std::vector<Release::pointer>
Release::getSimilarReleases(std::optional<std::size_t> offset, std::optional<std::size_t> count) const
{
assert(self());
assert(IdIsValid(self()->id()));
assert(session());
Wt::Dbo::Query<pointer> query {session()->query<pointer>(
"SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT c.id 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 release r ON r.id = t.release_id WHERE r.id = ?)"
" AND r.id <> ?"
)
.bind(self()->id())
.bind(self()->id())
.groupBy("r.id")
.orderBy("COUNT(*) DESC")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1)};
Wt::Dbo::collection<pointer> res = query;
return std::vector<pointer>(res.begin(), res.end());
}
bool
Release::hasVariousArtists() const
{
+4 -3
View File
@@ -57,10 +57,10 @@ class Release : public Wt::Dbo::Dbo<Release>
static std::vector<pointer> getLastAdded(Session& session, const Wt::WDateTime& after, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getByYear(Session& session, int yearFrom, int yearTo, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
static std::vector<pointer> getByFilter(Session& session, const std::set<IdType>& clusters);
static std::vector<pointer> getByClusters(Session& session, const std::set<IdType>& clusters);
static std::vector<pointer> getByFilter(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
const std::set<IdType>& clusters, // if non empty, at least one release that belongs to these clusters
const std::vector<std::string>& keywords, // if non empty, name must match all of these keywords
std::optional<std::size_t> offset,
std::optional<std::size_t> size,
bool& moreExpected);
@@ -96,6 +96,7 @@ class Release : public Wt::Dbo::Dbo<Release>
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;
std::vector<pointer> getSimilarReleases(std::optional<std::size_t> offset = {}, std::optional<std::size_t> count = {}) const;
void setMBID(std::string mbid) { _MBID = mbid; }
+39 -1
View File
@@ -248,9 +248,47 @@ Track::getByFilter(Session& session,
}
std::vector<Track::pointer>
Track::getByFilter(Session& session,
Track::getSimilarTracks(Session& session,
const std::set<IdType>& tracks,
std::optional<std::size_t> offset,
std::optional<std::size_t> size)
{
assert(!tracks.empty());
session.checkSharedLocked();
std::ostringstream oss;
for (std::size_t i {}; i < tracks.size(); ++i)
{
if (!oss.str().empty())
oss << ", ";
oss << "?";
}
Wt::Dbo::Query<pointer> query {session.getDboSession().query<pointer>(
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + oss.str() + "))"
" AND t.id NOT IN (" + oss.str() + ")")
.groupBy("t.id")
.orderBy("COUNT(*) DESC")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1)};
for (IdType trackId : tracks)
query.bind(trackId );
for (IdType trackId : tracks)
query.bind(trackId );
Wt::Dbo::collection<pointer> res = query;
return std::vector<pointer>(res.begin(), res.end());
}
std::vector<Track::pointer>
Track::getByClusters(Session& session,
const std::set<IdType>& clusters)
{
assert(!clusters.empty());
session.checkSharedLocked();
bool moreResults;
+7 -3
View File
@@ -55,11 +55,15 @@ class Track : public Wt::Dbo::Dbo<Track>
static pointer getByPath(Session& session, const std::filesystem::path& p);
static pointer getById(Session& session, IdType id);
static pointer getByMBID(Session& session, const std::string& MBID);
static std::vector<pointer> getByFilter(Session& session,
static std::vector<pointer> getSimilarTracks(Session& session,
const std::set<IdType>& trackIds,
std::optional<std::size_t> offset = {},
std::optional<std::size_t> size = {});
static std::vector<pointer> getByClusters(Session& session,
const std::set<IdType>& clusters); // tracks that belong to these clusters
static std::vector<pointer> getByFilter(Session& session,
const std::set<IdType>& clusters, // tracks that belong to these clusters
const std::vector<std::string>& keywords, // name must match all of these keywords
const std::set<IdType>& clusters, // if non empty, tracks that belong to these clusters
const std::vector<std::string>& keywords, // if non empty, name must match all of these keywords
std::optional<std::size_t> offset,
std::optional<std::size_t> size,
bool& moreExpected);
+33
View File
@@ -65,6 +65,15 @@ TrackList::get(Session& session, const std::string& name, Type type, Wt::Dbo::pt
.where("user_id = ?").bind(user.id());
}
std::vector<TrackList::pointer>
TrackList::getAll(Session& session)
{
session.checkSharedLocked();
Wt::Dbo::collection<TrackList::pointer> res = session.getDboSession().find<TrackList>();
return std::vector<TrackList::pointer>(res.begin(), res.end());
}
std::vector<TrackList::pointer>
TrackList::getAll(Session& session, Wt::Dbo::ptr<User> user)
{
@@ -176,6 +185,30 @@ TrackList::hasTrack(IdType trackId) const
return res.size() > 0;
}
std::vector<Track::pointer>
TrackList::getSimilarTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size) const
{
assert(session());
assert(IdIsValid(self()->id()));
Wt::Dbo::Query<Track::pointer> query {session()->query<Track::pointer>(
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" (t_c.cluster_id IN (SELECT c.id 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 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 = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))"
)
.bind(self()->id())
.bind(self()->id())
.groupBy("t.id")
.orderBy("COUNT(*) DESC")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1)};
Wt::Dbo::collection<Track::pointer> tracks = query;
return std::vector<Track::pointer>(tracks.begin(), tracks.end());
}
std::vector<IdType>
TrackList::getTrackIds() const
{
+4
View File
@@ -58,6 +58,7 @@ class TrackList : public Wt::Dbo::Dbo<TrackList>
// Search utility
static pointer get(Session& session, const std::string& name, Type type, Wt::Dbo::ptr<User> user);
static pointer getById(Session& session, IdType tracklistId);
static std::vector<pointer> getAll(Session& session);
static std::vector<pointer> getAll(Session& session, Wt::Dbo::ptr<User> user);
static std::vector<pointer> getAll(Session& session, Wt::Dbo::ptr<User> user, Type type);
@@ -90,6 +91,9 @@ class TrackList : public Wt::Dbo::Dbo<TrackList>
bool hasTrack(IdType trackId) const;
// Ordered from most clusters in common
std::vector<Wt::Dbo::ptr<Track>> getSimilarTracks(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
template<class Action>
void persist(Action& a)
{
+31
View File
@@ -23,6 +23,7 @@
#include "cluster/SimilarityClusterSearcher.hpp"
#include "database/SimilaritySettings.hpp"
#include "database/TrackList.hpp"
namespace Similarity {
@@ -37,6 +38,36 @@ Database::SimilaritySettings::EngineType getEngineType(Database::Session& dbSess
return Database::SimilaritySettings::get(dbSession)->getEngineType();
}
std::vector<Database::IdType>
Searcher::getSimilarTracksFromTrackList(Database::Session& session, Database::IdType trackListId, std::size_t maxCount)
{
auto engineType {getEngineType(session)};
auto somSearcher {_somAddon.getSearcher()};
std::set<Database::IdType> trackIds;
{
auto transaction {session.createSharedTransaction()};
Database::TrackList::pointer trackList {Database::TrackList::getById(session, trackListId)};
if (trackList)
{
const std::vector<Database::IdType> orderedTrackIds {trackList->getTrackIds()};
trackIds = std::set<Database::IdType> {std::cbegin(orderedTrackIds), std::cend(orderedTrackIds)};
}
}
if (trackIds.empty())
return {};
if (engineType == Database::SimilaritySettings::EngineType::Features
&& somSearcher
&& std::any_of(std::cbegin(trackIds), std::cend(trackIds), [&](Database::IdType trackId) { return somSearcher->isTrackClassified(trackId); } ))
{
return somSearcher->getSimilarTracks(trackIds, maxCount);
}
else
return ClusterSearcher::getSimilarTracksFromTrackList(session, trackListId, maxCount);
}
std::vector<Database::IdType>
Searcher::getSimilarTracks(Database::Session& dbSession, const std::set<Database::IdType>& trackIds, std::size_t maxCount)
{
+1
View File
@@ -39,6 +39,7 @@ class Searcher
Searcher(FeaturesScannerAddon& somAddon);
// Closest results first
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::set<Database::IdType>& tracksId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount);
@@ -27,71 +27,42 @@
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/TrackList.hpp"
#include "utils/Utils.hpp"
namespace Similarity {
namespace ClusterSearcher {
static
std::vector<Database::IdType>
getSimilarTracksLocked(Database::Session& dbSession, const std::set<Database::IdType>& trackIds, std::size_t maxCount)
{
std::vector<Database::IdType> clusterIds;
for (auto trackId : trackIds)
{
auto track {Database::Track::getById(dbSession, trackId)};
if (!track)
continue;
auto clusters = track->getClusters();
if (clusters.empty())
continue;
for (const auto& cluster : clusters)
clusterIds.push_back(cluster.id());
}
std::vector<Database::IdType> sortedClusterIds;
uniqueAndSortedByOccurence(clusterIds.begin(), clusterIds.end(), std::back_inserter(sortedClusterIds));
std::vector<Database::IdType> res;
for (auto clusterId : clusterIds)
{
auto cluster {Database::Cluster::getById(dbSession, clusterId)};
if (!cluster)
continue;
std::set<Database::IdType> clusterTrackIds = cluster->getTrackIds();
std::set<Database::IdType> candidateTrackIds;
std::set_difference(clusterTrackIds.begin(), clusterTrackIds.end(),
trackIds.begin(), trackIds.end(),
std::inserter(candidateTrackIds, candidateTrackIds.end()));
if (candidateTrackIds.empty())
continue;
for (auto trackId : candidateTrackIds)
{
if (res.size() >= maxCount)
break;
res.push_back(trackId);
}
if (res.size() >= maxCount)
break;
}
return res;
}
std::vector<Database::IdType>
getSimilarTracks(Database::Session& dbSession, const std::set<Database::IdType>& trackIds, std::size_t maxCount)
{
auto transaction {dbSession.createSharedTransaction()};
return getSimilarTracksLocked(dbSession, trackIds, maxCount);
auto tracks {Database::Track::getSimilarTracks(dbSession, trackIds, 0, maxCount)};
std::vector<Database::IdType> res;
res.reserve(tracks.size());
std::transform(std::cbegin(tracks), std::cend(tracks), std::back_inserter(res), [](const auto& track) { return track.id(); });
return res;
}
std::vector<Database::IdType>
getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount)
{
std::vector<Database::IdType> res;
auto transaction {session.createSharedTransaction()};
const Database::TrackList::pointer trackList {Database::TrackList::getById(session, tracklistId)};
if (!trackList)
return res;
const std::vector<Database::Track::pointer> tracks {trackList->getSimilarTracks(0, maxCount)};
res.reserve(tracks.size());
std::transform(std::cbegin(tracks), std::cend(tracks), std::back_inserter(res),
[](const Database::Track::pointer& track) { return track.id(); });
return res;
}
std::vector<Database::IdType>
@@ -105,31 +76,9 @@ getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std
if (!release)
return res;
auto releaseTracks = release->getTracks();
std::set<Database::IdType> releaseTrackIds;
for (const auto& releaseTrack : releaseTracks)
releaseTrackIds.insert(releaseTrack.id());
auto trackIds {getSimilarTracksLocked(dbSession, releaseTrackIds, maxCount * 5)};
for (auto trackId : trackIds)
{
auto track {Database::Track::getById(dbSession, trackId)};
if (!track)
continue;
auto trackRelease = track->getRelease();
if (!trackRelease || trackRelease.id() == releaseId)
continue;
if (std::find(res.begin(), res.end(), trackRelease.id()) != res.end())
continue;
res.push_back(trackRelease.id());
if (res.size() == maxCount)
break;
}
const auto releases {release->getSimilarReleases(0, maxCount)};
res.reserve(releases.size());
std::transform(std::cbegin(releases), std::cend(releases), std::back_inserter(res), [](const auto& release) { return release.id(); });
return res;
}
@@ -145,36 +94,9 @@ getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::
if (!artist)
return res;
auto artistTracks {artist->getTracks()};
std::set<Database::IdType> artistTrackIds;
for (const auto& artistTrack : artistTracks)
artistTrackIds.insert(artistTrack.id());
auto trackIds {getSimilarTracksLocked(dbSession, artistTrackIds, maxCount * 5)};
for (auto trackId : trackIds)
{
auto track {Database::Track::getById(dbSession, trackId)};
if (!track)
continue;
for (const auto& trackArtist : track->getArtists())
{
if (!trackArtist || trackArtist.id() == artistId)
continue;
if (std::find(res.begin(), res.end(), trackArtist.id()) != res.end())
continue;
res.push_back(trackArtist.id());
if (res.size() == maxCount)
break;
}
if (res.size() == maxCount)
break;
}
const auto artists {artist->getSimilarArtists(0, maxCount)};
res.reserve(artists.size());
std::transform(std::cbegin(artists), std::cend(artists), std::back_inserter(res), [](const auto& artist) { return artist.id(); });
return res;
}
@@ -31,6 +31,7 @@ namespace Similarity {
namespace ClusterSearcher
{
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::set<Database::IdType>& tracksId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount);
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount);
+2 -13
View File
@@ -22,6 +22,7 @@
#include <Wt/WText.h>
#include <Wt/WText.h>
#include "database/Cluster.hpp"
#include "database/Track.hpp"
#include "database/TrackList.hpp"
#include "database/User.hpp"
@@ -411,19 +412,7 @@ PlayQueue::addSome()
void
PlayQueue::enqueueRadioTrack()
{
std::vector<Database::IdType> trackIds;
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
Database::TrackList::pointer tracklist {getTrackList()};
trackIds = getTrackList()->getTrackIds();
}
if (trackIds.empty())
return;
const std::vector<Database::IdType> trackToAddIds {getService<Similarity::Searcher>()->getSimilarTracks(LmsApp->getDbSession(), std::set<Database::IdType>(std::cbegin(trackIds), std::cend(trackIds)), 1)};
const std::vector<Database::IdType> trackToAddIds {getService<Similarity::Searcher>()->getSimilarTracksFromTrackList(LmsApp->getDbSession(), _tracklistId, 1)};
enqueueTracks(trackToAddIds);
}