Added non album tracks in the artist view. closes #165

This commit is contained in:
emeric
2021-09-15 14:03:21 +02:00
parent f24ef27d2a
commit 598f01069e
6 changed files with 114 additions and 40 deletions
-4
View File
@@ -15,12 +15,8 @@
${</if-has-release>} ${</if-has-release>}
${<if-has-non-release-track>} ${<if-has-non-release-track>}
<div class="Lms-explore-artist-tracks-container"> <div class="Lms-explore-artist-tracks-container">
<div class="row">
<div class="col-lg-8">
${tracks} ${tracks}
</div> </div>
</div>
</div>
${</if-has-non-release-track>} ${</if-has-non-release-track>}
<div class="row"> <div class="row">
${<if-has-similar-artists>} ${<if-has-similar-artists>}
+30 -5
View File
@@ -465,12 +465,39 @@ Artist::getTracks(std::optional<TrackArtistLinkType> linkType) const
} }
std::vector<Wt::Dbo::ptr<Track>> std::vector<Wt::Dbo::ptr<Track>>
Artist::getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType) const Artist::getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType, std::optional<Range> range, bool& moreResults) 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")
.where("a.id = ?").bind(self()->id())
.where("t.release_id is NULL")
.orderBy("t.name")
.limit(range ? static_cast<int>(range->limit) + 1 : -1)
.offset(range ? static_cast<int>(range->offset) : -1)};
if (linkType)
query.where("t_a_l.type = ?").bind(*linkType);
Wt::Dbo::collection<Track::pointer> tracks {query.resultList()};
auto res {std::vector<Track::pointer>(tracks.begin(), tracks.end())};
if (range && res.size() == static_cast<std::size_t>(range->limit) + 1)
{
moreResults = true;
res.pop_back();
}
else
moreResults = false;
return res;
}
bool
Artist::hasNonReleaseTracks(std::optional<TrackArtistLinkType> linkType) const
{
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") 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())
.where("t.release_id is NULL") .where("t.release_id is NULL")
@@ -479,12 +506,10 @@ Artist::getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType) const
if (linkType) if (linkType)
query.where("t_a_l.type = ?").bind(*linkType); query.where("t_a_l.type = ?").bind(*linkType);
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> tracks {query.resultList()}; Wt::Dbo::collection<Track::pointer> tracks {query.resultList()};
return !tracks.empty();
return std::vector<Wt::Dbo::ptr<Track>>(tracks.begin(), tracks.end());
} }
std::vector<Wt::Dbo::ptr<Track>> std::vector<Wt::Dbo::ptr<Track>>
Artist::getRandomTracks(std::optional<std::size_t> count) const Artist::getRandomTracks(std::optional<std::size_t> count) const
{ {
@@ -104,7 +104,8 @@ 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>> getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType = {}) const; bool hasNonReleaseTracks(std::optional<TrackArtistLinkType> linkType = std::nullopt) const;
std::vector<Wt::Dbo::ptr<Track>> getNonReleaseTracks(std::optional<TrackArtistLinkType> linkType, std::optional<Range> range, bool& moreResults) 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
+44 -10
View File
@@ -35,6 +35,7 @@
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/String.hpp" #include "utils/String.hpp"
#include "common/InfiniteScrollingContainer.hpp"
#include "resource/DownloadResource.hpp" #include "resource/DownloadResource.hpp"
#include "ArtistListHelpers.hpp" #include "ArtistListHelpers.hpp"
#include "Filters.hpp" #include "Filters.hpp"
@@ -93,6 +94,8 @@ Artist::refreshView()
return; return;
clear(); clear();
_artistId = {};
_trackContainer = nullptr;
const auto artistId {extractArtistIdFromInternalPath()}; const auto artistId {extractArtistIdFromInternalPath()};
if (!artistId) if (!artistId)
@@ -109,6 +112,8 @@ Artist::refreshView()
if (!artist) if (!artist)
throw ArtistNotFoundException {}; throw ArtistNotFoundException {};
_artistId = *artistId;
refreshReleases(artist); refreshReleases(artist);
refreshNonReleaseTracks(artist); refreshNonReleaseTracks(artist);
refreshLinks(artist); refreshLinks(artist);
@@ -140,7 +145,7 @@ Artist::refreshView()
playBtn->clicked().connect([=] playBtn->clicked().connect([=]
{ {
artistsAction.emit(PlayQueueAction::Play, {*artistId}); artistsAction.emit(PlayQueueAction::Play, {_artistId});
}); });
} }
@@ -154,12 +159,12 @@ Artist::refreshView()
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled")) popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
->triggered().connect(this, [=] ->triggered().connect(this, [=]
{ {
artistsAction.emit(PlayQueueAction::PlayShuffled, {*artistId}); artistsAction.emit(PlayQueueAction::PlayShuffled, {_artistId});
}); });
popup->addItem(Wt::WString::tr("Lms.Explore.play-last")) popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
->triggered().connect(this, [=] ->triggered().connect(this, [=]
{ {
artistsAction.emit(PlayQueueAction::PlayLast, {*artistId}); artistsAction.emit(PlayQueueAction::PlayLast, {_artistId});
}); });
bool isStarred {}; bool isStarred {};
@@ -210,17 +215,17 @@ Artist::refreshReleases(const Wt::Dbo::ptr<Database::Artist>& artist)
void void
Artist::refreshNonReleaseTracks(const Wt::Dbo::ptr<Database::Artist>& artist) Artist::refreshNonReleaseTracks(const Wt::Dbo::ptr<Database::Artist>& artist)
{ {
const auto tracks {artist->getNonReleaseTracks()}; if (!artist->hasNonReleaseTracks())
if (tracks.empty())
return; return;
setCondition("if-has-non-release-track", true); setCondition("if-has-non-release-track", true);
_trackContainer = bindNew<InfiniteScrollingContainer>("tracks", Wt::WString::tr("Lms.Explore.Tracks.template.container"));
Wt::WContainerWidget* tracksContainer = bindNew<Wt::WContainerWidget>("tracks"); _trackContainer->onRequestElements.connect(this, [this]
for (const Track::pointer& track : tracks)
{ {
tracksContainer->addWidget(TrackListHelpers::createEntry(track, tracksAction)); addSomeNonReleaseTracks();
} });
addSomeNonReleaseTracks();
} }
void void
@@ -257,5 +262,34 @@ Artist::refreshLinks(const Database::Artist::pointer& artist)
} }
} }
void
Artist::addSomeNonReleaseTracks()
{
bool moreResults {};
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
const Database::Artist::pointer artist {Database::Artist::getById(LmsApp->getDbSession(), _artistId)};
if (!artist)
return;
const auto tracks {artist->getNonReleaseTracks(std::nullopt, Database::Range {static_cast<std::size_t>(_trackContainer->getCount()), _tracksBatchSize}, moreResults)};
for (const auto& track : tracks)
{
if (_trackContainer->getCount() == _tracksMaxCount)
{
moreResults = false;
break;
}
_trackContainer->add(TrackListHelpers::createEntry(track, tracksAction));
}
}
_trackContainer->setHasMore(moreResults);
}
} // namespace UserInterface } // namespace UserInterface
+13 -8
View File
@@ -34,12 +34,14 @@ namespace Database
class Release; class Release;
} }
namespace UserInterface { namespace UserInterface
class Filters;
class Artist : public Wt::WTemplate
{ {
class Filters;
class InfiniteScrollingContainer;
class Artist : public Wt::WTemplate
{
public: public:
Artist(Filters* filters); Artist(Filters* filters);
@@ -53,10 +55,13 @@ class Artist : public Wt::WTemplate
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);
std::unique_ptr<Wt::WTemplate> createRelease(const Wt::Dbo::ptr<Database::Artist>& artist, const Wt::Dbo::ptr<Database::Release>& release); void addSomeNonReleaseTracks();
static constexpr std::size_t _tracksBatchSize {6};
static constexpr std::size_t _tracksMaxCount {160};
Filters* _filters {}; Filters* _filters {};
}; InfiniteScrollingContainer* _trackContainer {};
Database::IdType _artistId {};
};
} // namespace UserInterface } // namespace UserInterface
+14 -1
View File
@@ -318,6 +318,16 @@ TEST_F(DatabaseFixture, SingleArtistNonReleaseTracks)
ScopedTrack track1 {session, "MyTrack1"}; ScopedTrack track1 {session, "MyTrack1"};
ScopedTrack track2 {session, "MyTrack2"}; ScopedTrack track2 {session, "MyTrack2"};
ScopedRelease release{session, "MyRelease"}; ScopedRelease release{session, "MyRelease"};
{
auto transaction {session.createSharedTransaction()};
EXPECT_EQ(artist->hasNonReleaseTracks(std::nullopt), false);
bool moreResults;
const auto tracks {artist->getNonReleaseTracks(std::nullopt, std::nullopt, moreResults )};
EXPECT_EQ(tracks.size(), 0);
}
{ {
auto transaction {session.createUniqueTransaction()}; auto transaction {session.createUniqueTransaction()};
@@ -331,7 +341,10 @@ TEST_F(DatabaseFixture, SingleArtistNonReleaseTracks)
{ {
auto transaction {session.createSharedTransaction()}; auto transaction {session.createSharedTransaction()};
const auto tracks {artist->getNonReleaseTracks()}; bool moreResults;
const auto tracks {artist->getNonReleaseTracks(std::nullopt, std::nullopt, moreResults )};
EXPECT_EQ(artist->hasNonReleaseTracks(std::nullopt), true);
EXPECT_EQ(moreResults, false);
ASSERT_EQ(tracks.size(), 1); ASSERT_EQ(tracks.size(), 1);
EXPECT_EQ(tracks.front().id(), track2.getId()); EXPECT_EQ(tracks.front().id(), track2.getId());
} }