Added clusters for track list
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>${name}</h2>
|
<h2>${name}</h2>
|
||||||
<div class="small text-muted">${track-count} · ${duration}</div>
|
<div class="small text-muted">${track-count} · ${duration}</div>
|
||||||
|
${clusters class="mb-2"}
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
${play-btn class="btn btn-primary"}
|
${play-btn class="btn btn-primary"}
|
||||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
||||||
|
|||||||
@@ -466,6 +466,57 @@ TrackList::getClusters() const
|
|||||||
return std::vector<Cluster::pointer>(res.begin(), res.end());
|
return std::vector<Cluster::pointer>(res.begin(), res.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<Cluster::pointer>>
|
||||||
|
TrackList::getClusterGroups(const std::vector<ClusterType::pointer>& clusterTypes, std::size_t size) const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
std::vector<std::vector<Cluster::pointer>> res;
|
||||||
|
|
||||||
|
if (clusterTypes.empty())
|
||||||
|
return res;
|
||||||
|
|
||||||
|
auto query {session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c")};
|
||||||
|
|
||||||
|
query.join("track t ON c.id = t_c.cluster_id")
|
||||||
|
.join("track_cluster t_c ON t_c.track_id = t.id")
|
||||||
|
.join("cluster_type c_type ON c.cluster_type_id = c_type.id")
|
||||||
|
.join("tracklist_entry t_l_e ON t_l_e.track_id = t.id")
|
||||||
|
.join("tracklist t_l ON t_l.id = t_l_e.tracklist_id")
|
||||||
|
.where("t_l.id = ?").bind(getId());
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "c_type.id IN (";
|
||||||
|
bool first {true};
|
||||||
|
for (auto clusterType : clusterTypes)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
oss << ", ";
|
||||||
|
oss << "?";
|
||||||
|
query.bind(clusterType ->getId());
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
oss << ")";
|
||||||
|
query.where(oss.str());
|
||||||
|
}
|
||||||
|
query.groupBy("c.id");
|
||||||
|
query.orderBy("COUNT(c.id) DESC");
|
||||||
|
|
||||||
|
auto queryRes {query.resultList()};
|
||||||
|
|
||||||
|
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
|
||||||
|
for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes)
|
||||||
|
{
|
||||||
|
if (clustersByType[cluster->getType()->getId()].size() < size)
|
||||||
|
clustersByType[cluster->getType()->getId()].push_back(cluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& [clusterTypeId, clusters] : clustersByType)
|
||||||
|
res.push_back(clusters);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TrackList::hasTrack(TrackId trackId) const
|
TrackList::hasTrack(TrackId trackId) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace Database {
|
|||||||
|
|
||||||
class Artist;
|
class Artist;
|
||||||
class Cluster;
|
class Cluster;
|
||||||
|
class ClusterType;
|
||||||
class Release;
|
class Release;
|
||||||
class Session;
|
class Session;
|
||||||
class Track;
|
class Track;
|
||||||
@@ -107,6 +108,7 @@ class TrackList : public Object<TrackList, TrackListId>
|
|||||||
|
|
||||||
// Get clusters, order by occurence
|
// Get clusters, order by occurence
|
||||||
std::vector<ObjectPtr<Cluster>> getClusters() const;
|
std::vector<ObjectPtr<Cluster>> getClusters() const;
|
||||||
|
std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(const std::vector<ObjectPtr<ClusterType>>& clusterTypes, std::size_t size) const;
|
||||||
|
|
||||||
bool hasTrack(TrackId trackId) const;
|
bool hasTrack(TrackId trackId) const;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include <Wt/WPushButton.h>
|
#include <Wt/WPushButton.h>
|
||||||
|
|
||||||
|
#include "services/database/Cluster.hpp"
|
||||||
|
#include "services/database/ScanSettings.hpp"
|
||||||
#include "services/database/Session.hpp"
|
#include "services/database/Session.hpp"
|
||||||
#include "services/database/Track.hpp"
|
#include "services/database/Track.hpp"
|
||||||
#include "services/database/TrackList.hpp"
|
#include "services/database/TrackList.hpp"
|
||||||
@@ -51,7 +53,8 @@ namespace
|
|||||||
namespace UserInterface
|
namespace UserInterface
|
||||||
{
|
{
|
||||||
TrackList::TrackList(Filters& filters)
|
TrackList::TrackList(Filters& filters)
|
||||||
: Template {Wt::WString::tr("Lms.Explore.TrackList.template")}
|
: Template {Wt::WString::tr("Lms.Explore.TrackList.template")}
|
||||||
|
, _filters {filters}
|
||||||
{
|
{
|
||||||
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||||
addFunction("id", &Wt::WTemplate::Functions::id);
|
addFunction("id", &Wt::WTemplate::Functions::id);
|
||||||
@@ -61,7 +64,7 @@ namespace UserInterface
|
|||||||
refreshView();
|
refreshView();
|
||||||
});
|
});
|
||||||
|
|
||||||
filters.updated().connect([this]
|
_filters.updated().connect([this]
|
||||||
{
|
{
|
||||||
refreshView();
|
refreshView();
|
||||||
});
|
});
|
||||||
@@ -93,6 +96,25 @@ namespace UserInterface
|
|||||||
bindString("duration", Utils::durationToString(trackList->getDuration()));
|
bindString("duration", Utils::durationToString(trackList->getDuration()));
|
||||||
bindString("track-count", Wt::WString::trn("Lms.Explore.TrackList.track-count", trackList->getCount()).arg(trackList->getCount()));
|
bindString("track-count", Wt::WString::trn("Lms.Explore.TrackList.track-count", trackList->getCount()).arg(trackList->getCount()));
|
||||||
|
|
||||||
|
Wt::WContainerWidget* clusterContainers {bindNew<Wt::WContainerWidget>("clusters")};
|
||||||
|
{
|
||||||
|
const auto clusterTypes {ScanSettings::get(LmsApp->getDbSession())->getClusterTypes()};
|
||||||
|
const auto clusterGroups {trackList->getClusterGroups(clusterTypes, 3)};
|
||||||
|
|
||||||
|
for (const auto& clusters : clusterGroups)
|
||||||
|
{
|
||||||
|
for (const Database::Cluster::pointer& cluster : clusters)
|
||||||
|
{
|
||||||
|
const ClusterId clusterId {cluster->getId()};
|
||||||
|
Wt::WInteractWidget* entry {clusterContainers->addWidget(Utils::createCluster(clusterId))};
|
||||||
|
entry->clicked().connect([=]
|
||||||
|
{
|
||||||
|
_filters.add(clusterId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML)
|
bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML)
|
||||||
->clicked().connect([=]
|
->clicked().connect([=]
|
||||||
{
|
{
|
||||||
@@ -163,6 +185,7 @@ namespace UserInterface
|
|||||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||||
|
|
||||||
Database::Track::FindParameters params;
|
Database::Track::FindParameters params;
|
||||||
|
params.setClusters(_filters.getClusterIds());
|
||||||
params.setTrackList(_trackListId);
|
params.setTrackList(_trackListId);
|
||||||
params.setSortMethod(Database::TrackSortMethod::TrackList);
|
params.setSortMethod(Database::TrackSortMethod::TrackList);
|
||||||
params.setRange({static_cast<std::size_t>(_container->getCount()), _batchSize});
|
params.setRange({static_cast<std::size_t>(_container->getCount()), _batchSize});
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ namespace UserInterface
|
|||||||
static constexpr std::size_t _batchSize {6};
|
static constexpr std::size_t _batchSize {6};
|
||||||
static constexpr std::size_t _maxCount {8000};
|
static constexpr std::size_t _maxCount {8000};
|
||||||
|
|
||||||
|
Filters& _filters;
|
||||||
Database::TrackListId _trackListId;
|
Database::TrackListId _trackListId;
|
||||||
InfiniteScrollingContainer* _container {};
|
InfiniteScrollingContainer* _container {};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user