Added a way to filter artist by type (album artist, track artist, all artits). Fixes #19
This commit is contained in:
+11
-4
@@ -6,10 +6,17 @@
|
||||
<div class="page-header">
|
||||
<h2>${tr:Lms.Explore.artists}</h2>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
${search}
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-3">
|
||||
<div class="Lms-explore-artists-input">
|
||||
${link-type}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-9">
|
||||
<div class="input-group Lms-explore-artists-input">
|
||||
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||
${search}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${artists}
|
||||
|
||||
@@ -115,6 +115,9 @@
|
||||
<message id="Lms.Explore.ArtistInfo.similar-artists">Similar artists</message>
|
||||
|
||||
<!--Explore:Artists-->
|
||||
<message id="Lms.Explore.Artists.linktype-all">All artists</message>
|
||||
<message id="Lms.Explore.Artists.linktype-artist">Track artists</message>
|
||||
<message id="Lms.Explore.Artists.linktype-releaseartist">Album artists</message>
|
||||
<message id="Lms.Explore.ArtistsInfo.recently-added">Recently added</message>
|
||||
<message id="Lms.Explore.ArtistsInfo.most-played">Top artists</message>
|
||||
|
||||
|
||||
@@ -115,6 +115,9 @@
|
||||
<message id="Lms.Explore.ArtistInfo.similar-artists">Artistes similaires</message>
|
||||
|
||||
<!--Explore:Artists-->
|
||||
<message id="Lms.Explore.Artists.linktype-all">Tous les artistes</message>
|
||||
<message id="Lms.Explore.Artists.linktype-artist">Artiste de piste</message>
|
||||
<message id="Lms.Explore.Artists.linktype-releaseartist">Artiste d'album</message>
|
||||
<message id="Lms.Explore.ArtistsInfo.recently-added">Ajouts récents</message>
|
||||
<message id="Lms.Explore.ArtistsInfo.most-played">Artistes populaires</message>
|
||||
|
||||
|
||||
@@ -232,6 +232,10 @@ a:hover {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.Lms-explore-artists-input {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.Lms-explore-artist-entry {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
@@ -1387,7 +1387,7 @@ handleSearchRequestCommon(RequestContext& context, bool id3)
|
||||
|
||||
bool more;
|
||||
{
|
||||
auto artists {Artist::getByFilter(context.dbSession, {}, keywords, artistOffset, artistCount, more)};
|
||||
auto artists {Artist::getByFilter(context.dbSession, {}, keywords, {}, artistOffset, artistCount, more)};
|
||||
for (const Artist::pointer& artist : artists)
|
||||
searchResult2Node.addArrayChild("artist", artistToResponseNode(user, artist, id3));
|
||||
}
|
||||
|
||||
+17
-9
@@ -108,7 +108,8 @@ static
|
||||
Wt::Dbo::Query<Artist::pointer>
|
||||
getQuery(Session& session,
|
||||
const std::set<IdType>& clusterIds,
|
||||
const std::vector<std::string>& keywords)
|
||||
const std::vector<std::string>& keywords,
|
||||
std::optional<TrackArtistLink::Type> linkType)
|
||||
{
|
||||
session.checkSharedLocked();
|
||||
|
||||
@@ -120,16 +121,22 @@ getQuery(Session& session,
|
||||
for (auto keyword : keywords)
|
||||
where.And(WhereClause("a.name LIKE ?")).bind("%%" + keyword + "%%");
|
||||
|
||||
if (!clusterIds.empty())
|
||||
if (!clusterIds.empty() || linkType)
|
||||
{
|
||||
oss << " INNER JOIN track t ON t.id = t_a_l.track_id INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
|
||||
oss << " INNER JOIN track t ON t.id = t_a_l.track_id INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id";
|
||||
|
||||
WhereClause clusterClause;
|
||||
if (!clusterIds.empty())
|
||||
{
|
||||
oss << " INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
|
||||
WhereClause clusterClause;
|
||||
|
||||
for (auto id : clusterIds)
|
||||
clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id));
|
||||
for (auto id : clusterIds)
|
||||
clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id));
|
||||
|
||||
where.And(clusterClause);
|
||||
where.And(clusterClause);
|
||||
}
|
||||
if (linkType)
|
||||
where.And(WhereClause {"t_a_l.type = ?"}.bind(std::to_string(static_cast<int>(*linkType))));
|
||||
}
|
||||
oss << " " << where.get();
|
||||
|
||||
@@ -155,19 +162,20 @@ Artist::getByClusters(Session& session, const std::set<IdType>& clusters)
|
||||
|
||||
session.checkSharedLocked();
|
||||
bool more;
|
||||
return getByFilter(session, clusters, {}, {}, {}, more);
|
||||
return getByFilter(session, clusters, {}, {}, {}, {}, more);
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer>
|
||||
Artist::getByFilter(Session& session,
|
||||
const std::set<IdType>& clusters,
|
||||
const std::vector<std::string>& keywords,
|
||||
std::optional<TrackArtistLink::Type> linkType,
|
||||
std::optional<std::size_t> offset,
|
||||
std::optional<std::size_t> size,
|
||||
bool& moreResults)
|
||||
{
|
||||
session.checkSharedLocked();
|
||||
Wt::Dbo::collection<Artist::pointer> collection = getQuery(session, clusters, keywords)
|
||||
Wt::Dbo::collection<Artist::pointer> collection = getQuery(session, clusters, keywords, linkType)
|
||||
.limit(size ? static_cast<int>(*size) + 1 : -1)
|
||||
.offset(offset ? static_cast<int>(*offset) : -1);
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
static std::vector<pointer> getByFilter(Session& session,
|
||||
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<TrackArtistLink::Type> linkType, // if set, only artists that have produced at least one track with this link type
|
||||
std::optional<std::size_t> offset,
|
||||
std::optional<std::size_t> size,
|
||||
bool& moreExpected);
|
||||
|
||||
@@ -19,13 +19,15 @@
|
||||
|
||||
#include "ArtistsView.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WLineEdit.h>
|
||||
#include <Wt/WLocalDateTime.h>
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
#include "common/ValueStringModel.hpp"
|
||||
#include "database/Artist.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
@@ -36,6 +38,8 @@ using namespace Database;
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
using ArtistLinkModel = ValueStringModel<std::optional<TrackArtistLink::Type>>;
|
||||
|
||||
Artists::Artists(Filters* filters)
|
||||
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Artists.template")),
|
||||
_filters(filters)
|
||||
@@ -46,6 +50,16 @@ Artists::Artists(Filters* filters)
|
||||
_search->setPlaceholderText(Wt::WString::tr("Lms.Explore.search-placeholder"));
|
||||
_search->textInput().connect(this, &Artists::refresh);
|
||||
|
||||
_linkType = bindNew<Wt::WComboBox>("link-type");
|
||||
{
|
||||
auto linkTypeModel {std::make_shared<ArtistLinkModel>()};
|
||||
linkTypeModel->add(Wt::WString::tr("Lms.Explore.Artists.linktype-all"), {});
|
||||
linkTypeModel->add(Wt::WString::tr("Lms.Explore.Artists.linktype-artist"), TrackArtistLink::Type::Artist);
|
||||
linkTypeModel->add(Wt::WString::tr("Lms.Explore.Artists.linktype-releaseartist"), TrackArtistLink::Type::ReleaseArtist);
|
||||
_linkType->setModel(linkTypeModel);
|
||||
}
|
||||
_linkType->changed().connect(this, &Artists::refresh);
|
||||
|
||||
_container = bindNew<Wt::WContainerWidget>("artists");
|
||||
|
||||
_showMore = bindNew<Wt::WPushButton>("show-more", Wt::WString::tr("Lms.Explore.show-more"));
|
||||
@@ -72,6 +86,7 @@ Artists::addSome()
|
||||
auto searchKeywords = splitString(_search->text().toUTF8(), " ");
|
||||
|
||||
auto clusterIds = _filters->getClusterIds();
|
||||
auto linkModel = static_cast<ArtistLinkModel*>(_linkType->model().get());
|
||||
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
|
||||
@@ -79,6 +94,7 @@ Artists::addSome()
|
||||
const std::vector<Artist::pointer> artists {Artist::getByFilter(LmsApp->getDbSession(),
|
||||
clusterIds,
|
||||
searchKeywords,
|
||||
linkModel->getValue(_linkType->currentIndex()),
|
||||
_container->count(), 20, moreResults)};
|
||||
|
||||
for (const auto& artist : artists)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WComboBox.h>
|
||||
#include <Wt/WContainerWidget.h>
|
||||
#include <Wt/WLineEdit.h>
|
||||
#include <Wt/WPushButton.h>
|
||||
@@ -46,6 +47,7 @@ class Artists : public Wt::WTemplate
|
||||
Filters* _filters;
|
||||
Wt::WPushButton* _showMore;
|
||||
Wt::WLineEdit* _search;
|
||||
Wt::WComboBox* _linkType;
|
||||
Wt::WContainerWidget* _container;
|
||||
};
|
||||
|
||||
|
||||
@@ -306,6 +306,16 @@ testSingleTrackSingleArtistMultiRoles(Session& session)
|
||||
CHECK(Artist::getAllOrphans(session).empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
bool hasMore{};
|
||||
CHECK(Artist::getByFilter(session, {}, {}, {}, {}, {}, hasMore).size() == 1);
|
||||
CHECK(Artist::getByFilter(session, {}, {}, TrackArtistLink::Type::Artist, {}, {}, hasMore).size() == 1);
|
||||
CHECK(Artist::getByFilter(session, {}, {}, TrackArtistLink::Type::ReleaseArtist, {}, {}, hasMore).size() == 1);
|
||||
CHECK(Artist::getByFilter(session, {}, {}, TrackArtistLink::Type::Writer, {}, {}, hasMore).size() == 1);
|
||||
CHECK(Artist::getByFilter(session, {}, {}, TrackArtistLink::Type::Composer, {}, {}, hasMore).empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user