Added non album tracks in the artist view. ref #165
This commit is contained in:
@@ -8,9 +8,20 @@
|
|||||||
${clusters}
|
${clusters}
|
||||||
${play-btn class="Lms-explore-btn Lms-btn"}${more-btn class="Lms-explore-btn Lms-btn"}
|
${play-btn class="Lms-explore-btn Lms-btn"}${more-btn class="Lms-explore-btn Lms-btn"}
|
||||||
</div>
|
</div>
|
||||||
|
${<if-has-release>}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
${releases class="Lms-explore-artist-entries-container"}
|
${releases class="Lms-explore-artist-entries-container"}
|
||||||
</div>
|
</div>
|
||||||
|
${</if-has-release>}
|
||||||
|
${<if-has-non-release-track>}
|
||||||
|
<div class="Lms-explore-artist-tracks-container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
${tracks}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${</if-has-non-release-track>}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
${<if-has-similar-artists>}
|
${<if-has-similar-artists>}
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ a.Lms-artistname:hover, a.Lms-artistname:focus {
|
|||||||
.Lms-explore-entry-list {
|
.Lms-explore-entry-list {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
|
min-height: 76px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Lms-explore-entry-list-text-container {
|
.Lms-explore-entry-list-text-container {
|
||||||
@@ -229,6 +230,10 @@ a.Lms-artistname:hover, a.Lms-artistname:focus {
|
|||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Lms-explore-artist-tracks-container {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.Lms-explore-mode-container {
|
.Lms-explore-mode-container {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -465,15 +465,16 @@ Artist::getTracks(std::optional<TrackArtistLinkType> linkType) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Wt::Dbo::ptr<Track>>
|
std::vector<Wt::Dbo::ptr<Track>>
|
||||||
Artist::getTracksWithRelease(std::optional<TrackArtistLinkType> linkType) const
|
Artist::getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType) const
|
||||||
{
|
{
|
||||||
assert(self());
|
assert(self());
|
||||||
assert(IdIsValid(self()->id()));
|
assert(IdIsValid(self()->id()));
|
||||||
assert(session());
|
assert(session());
|
||||||
|
|
||||||
auto query {session()->query<Wt::Dbo::ptr<Track>>("SELECT t FROM track t 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 INNER JOIN release r ON r.id = t.release_id")
|
auto query {session()->query<Wt::Dbo::ptr<Track>>("SELECT t FROM track t 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 = ?").bind(self()->id())
|
.where("a.id = ?").bind(self()->id())
|
||||||
.orderBy("t.year,r.name,t.disc_number,t.track_number")};
|
.where("t.release_id is NULL")
|
||||||
|
.orderBy("t.name")};
|
||||||
|
|
||||||
if (linkType)
|
if (linkType)
|
||||||
query.where("t_a_l.type = ?").bind(*linkType);
|
query.where("t_a_l.type = ?").bind(*linkType);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
|||||||
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::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::size_t getReleaseCount() const;
|
||||||
std::vector<Wt::Dbo::ptr<Track>> getTracks(std::optional<TrackArtistLinkType> linkType = {}) const;
|
std::vector<Wt::Dbo::ptr<Track>> getTracks(std::optional<TrackArtistLinkType> linkType = {}) const;
|
||||||
std::vector<Wt::Dbo::ptr<Track>> getTracksWithRelease(std::optional<TrackArtistLinkType> linkType = {}) const;
|
std::vector<Wt::Dbo::ptr<Track>> getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType = {}) const;
|
||||||
std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(std::optional<std::size_t> count) const;
|
std::vector<Wt::Dbo::ptr<Track>> getRandomTracks(std::optional<std::size_t> count) const;
|
||||||
|
|
||||||
// No artistLinkTypes means get them all
|
// No artistLinkTypes means get them all
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "database/Release.hpp"
|
#include "database/Release.hpp"
|
||||||
#include "database/ScanSettings.hpp"
|
#include "database/ScanSettings.hpp"
|
||||||
#include "database/Session.hpp"
|
#include "database/Session.hpp"
|
||||||
|
#include "database/Track.hpp"
|
||||||
#include "database/User.hpp"
|
#include "database/User.hpp"
|
||||||
#include "recommendation/IEngine.hpp"
|
#include "recommendation/IEngine.hpp"
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
#include "LmsApplicationException.hpp"
|
#include "LmsApplicationException.hpp"
|
||||||
#include "ReleaseListHelpers.hpp"
|
#include "ReleaseListHelpers.hpp"
|
||||||
|
#include "TrackListHelpers.hpp"
|
||||||
|
|
||||||
using namespace Database;
|
using namespace Database;
|
||||||
|
|
||||||
@@ -107,6 +109,8 @@ Artist::refreshView()
|
|||||||
if (!artist)
|
if (!artist)
|
||||||
throw ArtistNotFoundException {};
|
throw ArtistNotFoundException {};
|
||||||
|
|
||||||
|
refreshReleases(artist);
|
||||||
|
refreshNonReleaseTracks(artist);
|
||||||
refreshLinks(artist);
|
refreshLinks(artist);
|
||||||
refreshSimilarArtists(similarArtistIds);
|
refreshSimilarArtists(similarArtistIds);
|
||||||
|
|
||||||
@@ -185,16 +189,40 @@ Artist::refreshView()
|
|||||||
popup->exec(moreBtn);
|
popup->exec(moreBtn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Artist::refreshReleases(const Wt::Dbo::ptr<Database::Artist>& artist)
|
||||||
|
{
|
||||||
|
const auto releases {artist->getReleases(_filters->getClusterIds())};
|
||||||
|
if (releases.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setCondition("if-has-release", true);
|
||||||
|
|
||||||
Wt::WContainerWidget* releasesContainer = bindNew<Wt::WContainerWidget>("releases");
|
Wt::WContainerWidget* releasesContainer = bindNew<Wt::WContainerWidget>("releases");
|
||||||
|
|
||||||
auto releases = artist->getReleases(_filters->getClusterIds());
|
|
||||||
for (const auto& release : releases)
|
for (const auto& release : releases)
|
||||||
{
|
{
|
||||||
releasesContainer->addWidget(ReleaseListHelpers::createEntryForArtist(release, artist));
|
releasesContainer->addWidget(ReleaseListHelpers::createEntryForArtist(release, artist));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Artist::refreshNonReleaseTracks(const Wt::Dbo::ptr<Database::Artist>& artist)
|
||||||
|
{
|
||||||
|
const auto tracks {artist->getNonReleaseTracks()};
|
||||||
|
if (tracks.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setCondition("if-has-non-release-track", true);
|
||||||
|
|
||||||
|
Wt::WContainerWidget* tracksContainer = bindNew<Wt::WContainerWidget>("tracks");
|
||||||
|
for (const Track::pointer& track : tracks)
|
||||||
|
{
|
||||||
|
tracksContainer->addWidget(TrackListHelpers::createEntry(track, tracksAction));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Artist::refreshSimilarArtists(const std::unordered_set<Database::IdType>& similarArtistsId)
|
Artist::refreshSimilarArtists(const std::unordered_set<Database::IdType>& similarArtistsId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ class Artist : public Wt::WTemplate
|
|||||||
Artist(Filters* filters);
|
Artist(Filters* filters);
|
||||||
|
|
||||||
PlayQueueActionSignal artistsAction;
|
PlayQueueActionSignal artistsAction;
|
||||||
|
PlayQueueActionSignal tracksAction;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshView();
|
void refreshView();
|
||||||
|
void refreshReleases(const Wt::Dbo::ptr<Database::Artist>& artist);
|
||||||
|
void refreshNonReleaseTracks(const Wt::Dbo::ptr<Database::Artist>& artist);
|
||||||
void refreshSimilarArtists(const std::unordered_set<Database::IdType>& similarArtistsId);
|
void refreshSimilarArtists(const std::unordered_set<Database::IdType>& similarArtistsId);
|
||||||
void refreshLinks(const Wt::Dbo::ptr<Database::Artist>& artist);
|
void refreshLinks(const Wt::Dbo::ptr<Database::Artist>& artist);
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ Explore::Explore(Filters* filters)
|
|||||||
|
|
||||||
auto artist = std::make_unique<Artist>(_filters);
|
auto artist = std::make_unique<Artist>(_filters);
|
||||||
artist->artistsAction.connect(this, &Explore::handleArtistsAction);
|
artist->artistsAction.connect(this, &Explore::handleArtistsAction);
|
||||||
|
artist->tracksAction.connect(this, &Explore::handleTracksAction);
|
||||||
contentsStack->addWidget(std::move(artist));
|
contentsStack->addWidget(std::move(artist));
|
||||||
|
|
||||||
auto releases = std::make_unique<Releases>(*_filters);
|
auto releases = std::make_unique<Releases>(*_filters);
|
||||||
|
|||||||
@@ -312,3 +312,27 @@ TEST_F(DatabaseFixture, MultiArtistsSortMethod)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DatabaseFixture, SingleArtistNonReleaseTracks)
|
||||||
|
{
|
||||||
|
ScopedArtist artist {session, "artist"};
|
||||||
|
ScopedTrack track1 {session, "MyTrack1"};
|
||||||
|
ScopedTrack track2 {session, "MyTrack2"};
|
||||||
|
ScopedRelease release{session, "MyRelease"};
|
||||||
|
{
|
||||||
|
auto transaction {session.createUniqueTransaction()};
|
||||||
|
|
||||||
|
TrackArtistLink::create(session, track1.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||||
|
TrackArtistLink::create(session, track2.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||||
|
|
||||||
|
track1.get().modify()->setRelease(release.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
|
const auto tracks {artist->getNonReleaseTracks()};
|
||||||
|
ASSERT_EQ(tracks.size(), 1);
|
||||||
|
EXPECT_EQ(tracks.front().id(), track2.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user