Raised artist/album/track limits when explorin the collection. fixes #237
This commit is contained in:
@@ -370,6 +370,7 @@ CoverService::getFromTrack(Database::Session& dbSession, Database::TrackId track
|
|||||||
std::shared_ptr<IEncodedImage>
|
std::shared_ptr<IEncodedImage>
|
||||||
CoverService::getFromRelease(Database::ReleaseId releaseId, ImageSize width)
|
CoverService::getFromRelease(Database::ReleaseId releaseId, ImageSize width)
|
||||||
{
|
{
|
||||||
|
using namespace Database;
|
||||||
const CacheEntryDesc cacheEntryDesc {releaseId, width};
|
const CacheEntryDesc cacheEntryDesc {releaseId, width};
|
||||||
|
|
||||||
std::shared_ptr<IEncodedImage> cover {loadFromCache(cacheEntryDesc)};
|
std::shared_ptr<IEncodedImage> cover {loadFromCache(cacheEntryDesc)};
|
||||||
@@ -378,11 +379,11 @@ CoverService::getFromRelease(Database::ReleaseId releaseId, ImageSize width)
|
|||||||
|
|
||||||
struct ReleaseInfo
|
struct ReleaseInfo
|
||||||
{
|
{
|
||||||
Database::TrackId firstTrackId;
|
TrackId firstTrackId;
|
||||||
std::filesystem::path releaseDirectory;
|
std::filesystem::path releaseDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
Database::Session& session {_db.getTLSSession()};
|
Session& session {_db.getTLSSession()};
|
||||||
|
|
||||||
auto getReleaseInfo {[&]
|
auto getReleaseInfo {[&]
|
||||||
{
|
{
|
||||||
@@ -390,13 +391,15 @@ CoverService::getFromRelease(Database::ReleaseId releaseId, ImageSize width)
|
|||||||
|
|
||||||
auto transaction {session.createSharedTransaction()};
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
if (const Database::Release::pointer release {Database::Release::find(session, releaseId)})
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(releaseId).setRange({0, 1}).setSortMethod(TrackSortMethod::Release))};
|
||||||
|
|
||||||
|
if (!tracks.results.empty())
|
||||||
{
|
{
|
||||||
if (const auto firstTrack {release->getFirstTrack()})
|
if (const Track::pointer track {Track::find(session, tracks.results.front())})
|
||||||
{
|
{
|
||||||
res = ReleaseInfo {};
|
res = ReleaseInfo {};
|
||||||
res->firstTrackId = firstTrack->getId();
|
res->firstTrackId = track->getId();
|
||||||
res->releaseDirectory = firstTrack->getPath().parent_path();
|
res->releaseDirectory = track->getPath().parent_path();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -405,64 +405,12 @@ Release::hasVariousArtists() const
|
|||||||
return getArtists().size() > 1;
|
return getArtists().size() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Track::pointer>
|
|
||||||
Release::getTracks(const std::vector<ClusterId>& clusterIds) const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
|
|
||||||
WhereClause where;
|
|
||||||
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "SELECT t FROM track t INNER JOIN release r ON t.release_id = r.id";
|
|
||||||
|
|
||||||
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(id.toString());
|
|
||||||
|
|
||||||
where.And(clusterClause);
|
|
||||||
}
|
|
||||||
|
|
||||||
where.And(WhereClause("r.id = ?")).bind(getId().toString());
|
|
||||||
|
|
||||||
oss << " " << where.get();
|
|
||||||
|
|
||||||
if (!clusterIds.empty())
|
|
||||||
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
|
|
||||||
|
|
||||||
oss << " ORDER BY t.disc_number,t.track_number";
|
|
||||||
|
|
||||||
auto query {session()->query<Wt::Dbo::ptr<Track>>(oss.str())};
|
|
||||||
for (const std::string& bindArg : where.getBindArgs())
|
|
||||||
query.bind(bindArg);
|
|
||||||
|
|
||||||
auto res {query.resultList()};
|
|
||||||
return std::vector<Track::pointer> (res.begin(), res.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
Release::getTracksCount() const
|
Release::getTracksCount() const
|
||||||
{
|
{
|
||||||
return _tracks.size();
|
return _tracks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::pointer
|
|
||||||
Release::getFirstTrack() const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
|
|
||||||
return session()->query<Wt::Dbo::ptr<Track>>("SELECT t from track t")
|
|
||||||
.join("release r ON t.release_id = r.id")
|
|
||||||
.where("r.id = ?").bind(getId())
|
|
||||||
.orderBy("t.disc_number,t.track_number")
|
|
||||||
.limit(1)
|
|
||||||
.resultValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::milliseconds
|
std::chrono::milliseconds
|
||||||
Release::getDuration() const
|
Release::getDuration() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -103,8 +103,11 @@ createQuery(Session& session, const Track::FindParameters& params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(!(params.nonRelease && params.release.isValid()));
|
||||||
if (params.nonRelease)
|
if (params.nonRelease)
|
||||||
query.where("t.release_id IS NULL");
|
query.where("t.release_id IS NULL");
|
||||||
|
else if (params.release.isValid())
|
||||||
|
query.where("t.release_id = ?").bind(params.release);
|
||||||
|
|
||||||
switch (params.sortMethod)
|
switch (params.sortMethod)
|
||||||
{
|
{
|
||||||
@@ -126,6 +129,9 @@ createQuery(Session& session, const Track::FindParameters& params)
|
|||||||
case TrackSortMethod::DateDescAndRelease:
|
case TrackSortMethod::DateDescAndRelease:
|
||||||
query.orderBy("t.date DESC,t.release_id,t.disc_number,t.track_number");
|
query.orderBy("t.date DESC,t.release_id,t.disc_number,t.track_number");
|
||||||
break;
|
break;
|
||||||
|
case TrackSortMethod::Release:
|
||||||
|
query.orderBy("t.disc_number,t.track_number");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
|||||||
@@ -91,9 +91,7 @@ class Release : public Object<Release, ReleaseId>
|
|||||||
static RangeResults<ReleaseId> findOrphans(Session& session, Range range); // no track related
|
static RangeResults<ReleaseId> findOrphans(Session& session, Range range); // no track related
|
||||||
static RangeResults<ReleaseId> findOrderedByArtist(Session& session, Range range);
|
static RangeResults<ReleaseId> findOrderedByArtist(Session& session, Range range);
|
||||||
|
|
||||||
std::vector<ObjectPtr<Track>> getTracks(const std::vector<ClusterId>& clusters = {}) const;
|
|
||||||
std::size_t getTracksCount() const;
|
std::size_t getTracksCount() const;
|
||||||
ObjectPtr<Track> getFirstTrack() const;
|
|
||||||
|
|
||||||
// Get the cluster of the tracks that belong to this release
|
// Get the cluster of the tracks that belong to this release
|
||||||
// Each clusters are grouped by cluster type, sorted by the number of occurence (max to min)
|
// Each clusters are grouped by cluster type, sorted by the number of occurence (max to min)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "services/database/ArtistId.hpp"
|
#include "services/database/ArtistId.hpp"
|
||||||
#include "services/database/ClusterId.hpp"
|
#include "services/database/ClusterId.hpp"
|
||||||
#include "services/database/Object.hpp"
|
#include "services/database/Object.hpp"
|
||||||
|
#include "services/database/ReleaseId.hpp"
|
||||||
#include "services/database/TrackId.hpp"
|
#include "services/database/TrackId.hpp"
|
||||||
#include "services/database/Types.hpp"
|
#include "services/database/Types.hpp"
|
||||||
#include "services/database/UserId.hpp"
|
#include "services/database/UserId.hpp"
|
||||||
@@ -67,6 +68,7 @@ class Track : public Object<Track, TrackId>
|
|||||||
ArtistId artist; // only tracks that involve this user
|
ArtistId artist; // only tracks that involve this user
|
||||||
EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
|
EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
|
||||||
bool nonRelease {}; // only tracks that do not belong to a release
|
bool nonRelease {}; // only tracks that do not belong to a release
|
||||||
|
ReleaseId release; // matching this release
|
||||||
|
|
||||||
FindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; }
|
FindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; }
|
||||||
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
|
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
|
||||||
@@ -76,6 +78,7 @@ class Track : public Object<Track, TrackId>
|
|||||||
FindParameters& setStarringUser(UserId _user, Scrobbler _scrobbler) { starringUser = _user; scrobbler = _scrobbler; return *this; }
|
FindParameters& setStarringUser(UserId _user, Scrobbler _scrobbler) { starringUser = _user; scrobbler = _scrobbler; return *this; }
|
||||||
FindParameters& setArtist(ArtistId _artist, EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artist = _artist; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; }
|
FindParameters& setArtist(ArtistId _artist, EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artist = _artist; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; }
|
||||||
FindParameters& setNonRelease(bool _nonRelease) { nonRelease = _nonRelease; return *this; }
|
FindParameters& setNonRelease(bool _nonRelease) { nonRelease = _nonRelease; return *this; }
|
||||||
|
FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PathResult
|
struct PathResult
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ namespace Database
|
|||||||
StarredDateDesc,
|
StarredDateDesc,
|
||||||
Name,
|
Name,
|
||||||
DateDescAndRelease,
|
DateDescAndRelease,
|
||||||
|
Release, // order by disc/track number
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TrackArtistLinkType
|
enum class TrackArtistLinkType
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease)
|
|||||||
ASSERT_EQ(releases.results.size(), 1);
|
ASSERT_EQ(releases.results.size(), 1);
|
||||||
EXPECT_EQ(releases.results.front(), release.getId());
|
EXPECT_EQ(releases.results.front(), release.getId());
|
||||||
|
|
||||||
EXPECT_EQ(release->getTracks().size(), nbTracks);
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(release.getId()))};
|
||||||
|
EXPECT_EQ(tracks.results.size(), nbTracks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ TEST_F(DatabaseFixture, Release_singleTrack)
|
|||||||
auto transaction {session.createSharedTransaction()};
|
auto transaction {session.createSharedTransaction()};
|
||||||
EXPECT_TRUE(Release::findOrphans(session, Range {}).results.empty());
|
EXPECT_TRUE(Release::findOrphans(session, Range {}).results.empty());
|
||||||
|
|
||||||
EXPECT_EQ(release->getTracksCount(), 1);
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(release.getId()))};
|
||||||
ASSERT_EQ(release->getTracks().size(), 1);
|
ASSERT_EQ(tracks.results.size(), 1);
|
||||||
EXPECT_EQ(release->getTracks().front()->getId(), track.getId());
|
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -103,7 +103,8 @@ TEST_F(DatabaseFixture, Release_singleTrack)
|
|||||||
{
|
{
|
||||||
auto transaction {session.createUniqueTransaction()};
|
auto transaction {session.createUniqueTransaction()};
|
||||||
|
|
||||||
EXPECT_TRUE(release->getTracks().empty());
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(release.getId()))};
|
||||||
|
EXPECT_TRUE(tracks.results.empty());
|
||||||
|
|
||||||
auto releases {Release::findOrphans(session, Range {})};
|
auto releases {Release::findOrphans(session, Range {})};
|
||||||
ASSERT_EQ(releases.results.size(), 1);
|
ASSERT_EQ(releases.results.size(), 1);
|
||||||
@@ -279,8 +280,8 @@ TEST_F(DatabaseFixture, MultiTracksSingleReleaseFirstTrack)
|
|||||||
{
|
{
|
||||||
auto transaction {session.createSharedTransaction()};
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
EXPECT_FALSE(release1->getFirstTrack());
|
EXPECT_TRUE(Track::find(session, Track::FindParameters {}.setRelease(release1.getId())).results.empty());
|
||||||
EXPECT_FALSE(release2->getFirstTrack());
|
EXPECT_TRUE(Track::find(session, Track::FindParameters {}.setRelease(release2.getId())).results.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -303,11 +304,17 @@ TEST_F(DatabaseFixture, MultiTracksSingleReleaseFirstTrack)
|
|||||||
{
|
{
|
||||||
auto transaction {session.createSharedTransaction()};
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
EXPECT_TRUE(release1->getFirstTrack());
|
{
|
||||||
EXPECT_TRUE(release2->getFirstTrack());
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release))};
|
||||||
|
ASSERT_FALSE(tracks.results.empty());
|
||||||
|
EXPECT_EQ(tracks.results.front(), track1A.getId());
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_EQ(release1->getFirstTrack()->getId(), track1A.getId());
|
{
|
||||||
EXPECT_EQ(release2->getFirstTrack()->getId(), track2B.getId());
|
const auto tracks {Track::find(session, Track::FindParameters {}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release))};
|
||||||
|
ASSERT_FALSE(tracks.results.empty());
|
||||||
|
EXPECT_EQ(tracks.results.front(), track2B.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -860,9 +860,12 @@ handleGetAlbumRequest(RequestContext& context)
|
|||||||
Response response {Response::createOkResponse(context.serverProtocolVersion)};
|
Response response {Response::createOkResponse(context.serverProtocolVersion)};
|
||||||
Response::Node releaseNode {releaseToResponseNode(release, context.dbSession, user, true /* id3 */)};
|
Response::Node releaseNode {releaseToResponseNode(release, context.dbSession, user, true /* id3 */)};
|
||||||
|
|
||||||
auto tracks {release->getTracks()};
|
const auto tracks {Track::find(context.dbSession, Track::FindParameters {}.setRelease(id).setSortMethod(TrackSortMethod::Release))};
|
||||||
for (const Track::pointer& track : tracks)
|
for (const TrackId trackId : tracks.results)
|
||||||
|
{
|
||||||
|
const Track::pointer track {Track::find(context.dbSession, trackId)};
|
||||||
releaseNode.addArrayChild("song", trackToResponseNode(track, context.dbSession, user));
|
releaseNode.addArrayChild("song", trackToResponseNode(track, context.dbSession, user));
|
||||||
|
}
|
||||||
|
|
||||||
response.addNode("album", std::move(releaseNode));
|
response.addNode("album", std::move(releaseNode));
|
||||||
|
|
||||||
@@ -1021,9 +1024,12 @@ handleGetMusicDirectoryRequest(RequestContext& context)
|
|||||||
|
|
||||||
directoryNode.setAttribute("name", makeNameFilesystemCompatible(release->getName()));
|
directoryNode.setAttribute("name", makeNameFilesystemCompatible(release->getName()));
|
||||||
|
|
||||||
auto tracks {release->getTracks()};
|
const auto tracks {Track::find(context.dbSession, Track::FindParameters {}.setRelease(*releaseId).setSortMethod(TrackSortMethod::Release))};
|
||||||
for (const Track::pointer& track : tracks)
|
for (const TrackId trackId : tracks.results)
|
||||||
|
{
|
||||||
|
const Track::pointer track {Track::find(context.dbSession, trackId)};
|
||||||
directoryNode.addArrayChild("child", trackToResponseNode(track, context.dbSession, user));
|
directoryNode.addArrayChild("child", trackToResponseNode(track, context.dbSession, user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw BadParameterGenericError {"id"};
|
throw BadParameterGenericError {"id"};
|
||||||
|
|||||||
@@ -481,6 +481,7 @@ LmsApplication::createHome()
|
|||||||
mainStack->addNew<UserView>();
|
mainStack->addNew<UserView>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explore->setMaxTrackCountForAction(_playQueue->getCapacity());
|
||||||
explore->tracksAction.connect([this] (PlayQueueAction action, const std::vector<Database::TrackId>& trackIds)
|
explore->tracksAction.connect([this] (PlayQueueAction action, const std::vector<Database::TrackId>& trackIds)
|
||||||
{
|
{
|
||||||
_playQueue->processTracks(action, trackIds);
|
_playQueue->processTracks(action, trackIds);
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ bool
|
|||||||
PlayQueue::isFull() const
|
PlayQueue::isFull() const
|
||||||
{
|
{
|
||||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||||
return getTrackList()->getCount() == _nbMaxEntries;
|
return getTrackList()->getCount() == getCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -313,7 +313,7 @@ PlayQueue::enqueueTracks(const std::vector<Database::TrackId>& trackIds)
|
|||||||
|
|
||||||
auto tracklist {getTrackList()};
|
auto tracklist {getTrackList()};
|
||||||
|
|
||||||
std::size_t nbTracksToEnqueue {tracklist->getCount() + trackIds.size() > _nbMaxEntries ? _nbMaxEntries - tracklist->getCount() : trackIds.size()};
|
std::size_t nbTracksToEnqueue {tracklist->getCount() + trackIds.size() > getCapacity() ? getCapacity() - tracklist->getCount() : trackIds.size()};
|
||||||
for (const Database::TrackId trackId : trackIds)
|
for (const Database::TrackId trackId : trackIds)
|
||||||
{
|
{
|
||||||
Database::Track::pointer track {Database::Track::find(LmsApp->getDbSession(), trackId)};
|
Database::Track::pointer track {Database::Track::find(LmsApp->getDbSession(), trackId)};
|
||||||
@@ -368,10 +368,10 @@ PlayQueue::processTracks(PlayQueueAction action, const std::vector<Database::Tra
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nbAddedTracks > 0)
|
if (nbAddedTracks > 0)
|
||||||
LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.PlayQueue.playqueue"), Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", nbAddedTracks).arg(nbAddedTracks), std::chrono::milliseconds(2000));
|
LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.PlayQueue.playqueue"), Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", nbAddedTracks).arg(nbAddedTracks), std::chrono::seconds {2});
|
||||||
|
|
||||||
if (isFull())
|
if (isFull())
|
||||||
LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.PlayQueue.playqueue"), Wt::WString::tr("Lms.PlayQueue.playqueue-full"), std::chrono::milliseconds(2000));
|
LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.PlayQueue.playqueue"), Wt::WString::tr("Lms.PlayQueue.playqueue-full"), std::chrono::seconds {2});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ class PlayQueue : public Template
|
|||||||
// Signal emitted when track is unselected (has to be stopped)
|
// Signal emitted when track is unselected (has to be stopped)
|
||||||
Wt::Signal<> trackUnselected;
|
Wt::Signal<> trackUnselected;
|
||||||
|
|
||||||
|
constexpr std::size_t getCapacity() const { return _capacity; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Database::ObjectPtr<Database::TrackList> getTrackList() const;
|
Database::ObjectPtr<Database::TrackList> getTrackList() const;
|
||||||
bool isFull() const;
|
bool isFull() const;
|
||||||
@@ -88,7 +90,7 @@ class PlayQueue : public Template
|
|||||||
void addRadioTrackFromClusters();
|
void addRadioTrackFromClusters();
|
||||||
std::optional<float> getReplayGain(std::size_t pos, const Database::ObjectPtr<Database::Track>& track) const;
|
std::optional<float> getReplayGain(std::size_t pos, const Database::ObjectPtr<Database::Track>& track) const;
|
||||||
|
|
||||||
static inline constexpr std::size_t _nbMaxEntries {1000};
|
static inline constexpr std::size_t _capacity {1000};
|
||||||
static inline constexpr std::size_t _batchSize {12};
|
static inline constexpr std::size_t _batchSize {12};
|
||||||
|
|
||||||
bool _mediaPlayerSettingsLoaded {};
|
bool _mediaPlayerSettingsLoaded {};
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace UserInterface
|
|||||||
void addSome();
|
void addSome();
|
||||||
|
|
||||||
static constexpr std::size_t _batchSize {30};
|
static constexpr std::size_t _batchSize {30};
|
||||||
static constexpr std::size_t _maxCount {512};
|
static constexpr std::size_t _maxCount {8000};
|
||||||
|
|
||||||
Wt::WWidget* _currentActiveItem {};
|
Wt::WWidget* _currentActiveItem {};
|
||||||
InfiniteScrollingContainer* _container {};
|
InfiniteScrollingContainer* _container {};
|
||||||
|
|||||||
@@ -130,18 +130,29 @@ Explore::search(const Wt::WString& searchText)
|
|||||||
|
|
||||||
static
|
static
|
||||||
std::vector<Database::TrackId>
|
std::vector<Database::TrackId>
|
||||||
getArtistsTracks(Database::Session& session, const std::vector<Database::ArtistId>& artistsId, const std::vector<Database::ClusterId>& clusters)
|
getArtistsTracks(Database::Session& session, const std::vector<Database::ArtistId>& artistsId, const std::vector<Database::ClusterId>& clusters, std::size_t maxTrackCount)
|
||||||
{
|
{
|
||||||
|
assert(maxTrackCount);
|
||||||
|
|
||||||
std::vector<Database::TrackId> res;
|
std::vector<Database::TrackId> res;
|
||||||
|
|
||||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
for (const Database::ArtistId artistId : artistsId)
|
for (const Database::ArtistId artistId : artistsId)
|
||||||
{
|
{
|
||||||
const auto tracks {Database::Track::find(LmsApp->getDbSession(), Database::Track::FindParameters {}.setArtist(artistId).setClusters(clusters).setSortMethod(Database::TrackSortMethod::DateDescAndRelease))};
|
Database::Track::FindParameters params;
|
||||||
|
params.setArtist(artistId);
|
||||||
|
params.setSortMethod(Database::TrackSortMethod::DateDescAndRelease);
|
||||||
|
params.setClusters(clusters);
|
||||||
|
params.setRange({0, maxTrackCount - res.size()});
|
||||||
|
|
||||||
|
const auto tracks {Database::Track::find(session, params)};
|
||||||
|
|
||||||
res.reserve(res.size() + tracks.results.size());
|
res.reserve(res.size() + tracks.results.size());
|
||||||
res.insert(std::end(res), std::cbegin(tracks.results), std::cend(tracks.results));
|
res.insert(std::end(res), std::cbegin(tracks.results), std::cend(tracks.results));
|
||||||
|
|
||||||
|
if (res.size() == maxTrackCount)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -149,23 +160,31 @@ getArtistsTracks(Database::Session& session, const std::vector<Database::ArtistI
|
|||||||
|
|
||||||
static
|
static
|
||||||
std::vector<Database::TrackId>
|
std::vector<Database::TrackId>
|
||||||
getReleasesTracks(Database::Session& session, const std::vector<Database::ReleaseId>& releasesId, const std::vector<Database::ClusterId>& clusters)
|
getReleasesTracks(Database::Session& session, const std::vector<Database::ReleaseId>& releasesId, const std::vector<Database::ClusterId>& clusters, std::size_t maxTrackCount)
|
||||||
{
|
{
|
||||||
std::vector<Database::TrackId> res;
|
using namespace Database;
|
||||||
|
|
||||||
// TODO optimize this
|
assert(maxTrackCount);
|
||||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
|
||||||
|
|
||||||
for (const Database::ReleaseId releaseId : releasesId)
|
std::vector<TrackId> res;
|
||||||
|
|
||||||
|
auto transaction {session.createSharedTransaction()};
|
||||||
|
|
||||||
|
for (const ReleaseId releaseId : releasesId)
|
||||||
{
|
{
|
||||||
const Database::Release::pointer release {Database::Release::find(session, releaseId)};
|
Database::Track::FindParameters params;
|
||||||
if (!release)
|
params.setRelease(releaseId);
|
||||||
continue;
|
params.setSortMethod(Database::TrackSortMethod::Release);
|
||||||
|
params.setClusters(clusters);
|
||||||
|
params.setRange({0, maxTrackCount - res.size()});
|
||||||
|
|
||||||
const std::vector<Database::Track::pointer> tracks {release->getTracks(clusters)};
|
const auto tracks {Database::Track::find(session, params)};
|
||||||
|
|
||||||
res.reserve(res.size() + tracks.size());
|
res.reserve(res.size() + tracks.results.size());
|
||||||
std::transform(std::cbegin(tracks), std::cend(tracks), std::back_inserter(res), [](const Database::Track::pointer& track) { return track->getId(); });
|
res.insert(std::end(res), std::cbegin(tracks.results), std::cend(tracks.results));
|
||||||
|
|
||||||
|
if (res.size() == maxTrackCount)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -174,13 +193,13 @@ getReleasesTracks(Database::Session& session, const std::vector<Database::Releas
|
|||||||
void
|
void
|
||||||
Explore::handleArtistsAction(PlayQueueAction action, const std::vector<Database::ArtistId>& artistsId)
|
Explore::handleArtistsAction(PlayQueueAction action, const std::vector<Database::ArtistId>& artistsId)
|
||||||
{
|
{
|
||||||
tracksAction.emit(action, getArtistsTracks(LmsApp->getDbSession(), artistsId, _filters->getClusterIds()));
|
tracksAction.emit(action, getArtistsTracks(LmsApp->getDbSession(), artistsId, _filters->getClusterIds(), _maxTrackCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Explore::handleReleasesAction(PlayQueueAction action, const std::vector<Database::ReleaseId>& releasesId)
|
Explore::handleReleasesAction(PlayQueueAction action, const std::vector<Database::ReleaseId>& releasesId)
|
||||||
{
|
{
|
||||||
tracksAction.emit(action, getReleasesTracks(LmsApp->getDbSession(), releasesId, _filters->getClusterIds()));
|
tracksAction.emit(action, getReleasesTracks(LmsApp->getDbSession(), releasesId, _filters->getClusterIds(), _maxTrackCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ namespace UserInterface
|
|||||||
void search(const Wt::WString& searchText);
|
void search(const Wt::WString& searchText);
|
||||||
|
|
||||||
PlayQueueActionTrackSignal tracksAction;
|
PlayQueueActionTrackSignal tracksAction;
|
||||||
|
void setMaxTrackCountForAction(std::size_t maxTrackCount) { _maxTrackCount = maxTrackCount; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleArtistsAction(PlayQueueAction action, const std::vector<Database::ArtistId>& artistsId);
|
void handleArtistsAction(PlayQueueAction action, const std::vector<Database::ArtistId>& artistsId);
|
||||||
@@ -45,6 +46,7 @@ namespace UserInterface
|
|||||||
|
|
||||||
Filters* _filters {};
|
Filters* _filters {};
|
||||||
SearchView* _search {};
|
SearchView* _search {};
|
||||||
|
std::size_t _maxTrackCount {};
|
||||||
};
|
};
|
||||||
} // namespace UserInterface
|
} // namespace UserInterface
|
||||||
|
|
||||||
|
|||||||
@@ -232,12 +232,15 @@ Release::refreshView()
|
|||||||
return noDiscTracksContainer;
|
return noDiscTracksContainer;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto clusterIds {_filters->getClusterIds()};
|
Database::Track::FindParameters params;
|
||||||
const auto tracks {release->getTracks(clusterIds)};
|
params.setRelease(*releaseId);
|
||||||
|
params.setSortMethod(Database::TrackSortMethod::Release);
|
||||||
|
params.setClusters(_filters->getClusterIds());
|
||||||
|
|
||||||
for (const auto& track : tracks)
|
const auto tracks {Database::Track::find(LmsApp->getDbSession(), params)};
|
||||||
|
for (const Database::TrackId trackId : tracks.results)
|
||||||
{
|
{
|
||||||
auto trackId {track->getId()};
|
const Database::Track::pointer track {Database::Track::find(LmsApp->getDbSession(), trackId)};
|
||||||
|
|
||||||
const auto discNumber {track->getDiscNumber()};
|
const auto discNumber {track->getDiscNumber()};
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ std::vector<ReleaseId>
|
|||||||
Releases::getAllReleases()
|
Releases::getAllReleases()
|
||||||
{
|
{
|
||||||
RangeResults<ReleaseId> releaseIds {_releaseCollector.get(Range {})};
|
RangeResults<ReleaseId> releaseIds {_releaseCollector.get(Range {})};
|
||||||
|
|
||||||
return std::move(releaseIds.results);
|
return std::move(releaseIds.results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace UserInterface
|
|||||||
|
|
||||||
static constexpr std::size_t _maxItemsPerLine {6};
|
static constexpr std::size_t _maxItemsPerLine {6};
|
||||||
static constexpr std::size_t _batchSize {_maxItemsPerLine};
|
static constexpr std::size_t _batchSize {_maxItemsPerLine};
|
||||||
static constexpr std::size_t _maxCount {_maxItemsPerLine * 32};
|
static constexpr std::size_t _maxCount {_maxItemsPerLine * 500};
|
||||||
|
|
||||||
Wt::WWidget* _currentActiveItem {};
|
Wt::WWidget* _currentActiveItem {};
|
||||||
InfiniteScrollingContainer* _container {};
|
InfiniteScrollingContainer* _container {};
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ namespace UserInterface
|
|||||||
};
|
};
|
||||||
static inline std::unordered_map<Mode, std::size_t> _maxCounts
|
static inline std::unordered_map<Mode, std::size_t> _maxCounts
|
||||||
{
|
{
|
||||||
{Mode::Artist, 512},
|
{Mode::Artist, 8000},
|
||||||
{Mode::Release, 60},
|
{Mode::Release, 4000},
|
||||||
{Mode::Track, 64},
|
{Mode::Track, 4000},
|
||||||
};
|
};
|
||||||
std::size_t getBatchSize(Mode mode) const;
|
std::size_t getBatchSize(Mode mode) const;
|
||||||
std::size_t getMaxCount(Mode mode) const;
|
std::size_t getMaxCount(Mode mode) const;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace UserInterface
|
|||||||
|
|
||||||
static constexpr TrackCollector::Mode _defaultMode {TrackCollector::Mode::Random};
|
static constexpr TrackCollector::Mode _defaultMode {TrackCollector::Mode::Random};
|
||||||
static constexpr std::size_t _batchSize {6};
|
static constexpr std::size_t _batchSize {6};
|
||||||
static constexpr std::size_t _maxCount {160};
|
static constexpr std::size_t _maxCount {8000};
|
||||||
|
|
||||||
Wt::WWidget* _currentActiveItem {};
|
Wt::WWidget* _currentActiveItem {};
|
||||||
InfiniteScrollingContainer* _container {};
|
InfiniteScrollingContainer* _container {};
|
||||||
|
|||||||
@@ -212,16 +212,17 @@ DownloadReleaseResource::DownloadReleaseResource(Database::ReleaseId releaseId)
|
|||||||
std::unique_ptr<Zip::Zipper>
|
std::unique_ptr<Zip::Zipper>
|
||||||
DownloadReleaseResource::createZipper()
|
DownloadReleaseResource::createZipper()
|
||||||
{
|
{
|
||||||
|
using namespace Database;
|
||||||
|
|
||||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||||
|
|
||||||
const Database::Release::pointer release {Database::Release::find(LmsApp->getDbSession(), _releaseId)};
|
auto trackResults {Track::find(LmsApp->getDbSession(), Track::FindParameters {}.setRelease(_releaseId).setSortMethod(TrackSortMethod::Release))};
|
||||||
if (!release)
|
|
||||||
{
|
|
||||||
LOG(DEBUG) << "Cannot find release";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return UserInterface::createZipper(release->getTracks());
|
std::vector<Track::pointer> tracks;
|
||||||
|
tracks.reserve(trackResults.results.size());
|
||||||
|
std::transform(std::cbegin(trackResults.results), std::cend(trackResults.results), std::back_inserter(tracks), [](TrackId trackId){ return Track::find(LmsApp->getDbSession(), trackId); });
|
||||||
|
|
||||||
|
return UserInterface::createZipper(tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadTrackResource::DownloadTrackResource(Database::TrackId trackId)
|
DownloadTrackResource::DownloadTrackResource(Database::TrackId trackId)
|
||||||
|
|||||||
Reference in New Issue
Block a user