Make recetnly played/most played info update
This commit is contained in:
@@ -8,6 +8,11 @@
|
||||
</div>
|
||||
${most-played-artists}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>${tr:Lms.Explore.recently-played-artists}</h2>
|
||||
</div>
|
||||
${recently-played-artists}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>${tr:Lms.Explore.recently-added-artists}</h2>
|
||||
</div>
|
||||
|
||||
@@ -57,9 +57,11 @@
|
||||
<message id="Lms.Explore.add-filter">Add filter</message>
|
||||
<message id="Lms.Explore.artists">Artists</message>
|
||||
<message id="Lms.Explore.most-played-artists">Most played artists</message>
|
||||
<message id="Lms.Explore.most-played-releases">Most played releases</message>
|
||||
<message id="Lms.Explore.most-played-releases">Most played albums</message>
|
||||
<message id="Lms.Explore.recently-added-artists">Recently added artists</message>
|
||||
<message id="Lms.Explore.recently-added-releases">Recently added releases</message>
|
||||
<message id="Lms.Explore.recently-added-releases">Recently added albums</message>
|
||||
<message id="Lms.Explore.recently-played-artists">Recently played artists</message>
|
||||
<message id="Lms.Explore.recently-played-releases">Recently played albums</message>
|
||||
<message id="Lms.Explore.releases">Albums</message>
|
||||
<message id="Lms.Explore.search-placeholder">Search...</message>
|
||||
<message id="Lms.Explore.show-more">Show more</message>
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
</div>
|
||||
${most-played-releases}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>${tr:Lms.Explore.recently-played-releases}</h2>
|
||||
</div>
|
||||
${recently-played-releases}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>${tr:Lms.Explore.recently-added-releases}</h2>
|
||||
</div>
|
||||
|
||||
@@ -44,6 +44,19 @@ TrackStats::getMostPlayedArtists(Wt::Dbo::Session& session, User::pointer user,
|
||||
return std::vector<Artist::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer>
|
||||
TrackStats::getLastPlayedArtists(Wt::Dbo::Session& session, User::pointer user, int limit)
|
||||
{
|
||||
Wt::Dbo::collection<Artist::pointer> res = session.query<Artist::pointer>
|
||||
("SELECT a FROM artist a INNER JOIN track t ON a.id = t.artist_id INNER JOIN track_stats t_s ON t.id = t_s.track_id")
|
||||
.where("t_s.user_id = ?").bind(user.id())
|
||||
.groupBy("a.id")
|
||||
.orderBy("t_s.last_played DESC")
|
||||
.limit(limit);
|
||||
|
||||
return std::vector<Artist::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
std::vector<Release::pointer>
|
||||
TrackStats::getMostPlayedReleases(Wt::Dbo::Session& session, User::pointer user, int limit)
|
||||
{
|
||||
@@ -57,6 +70,19 @@ TrackStats::getMostPlayedReleases(Wt::Dbo::Session& session, User::pointer user,
|
||||
return std::vector<Release::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
std::vector<Release::pointer>
|
||||
TrackStats::getLastPlayedReleases(Wt::Dbo::Session& session, User::pointer user, int limit)
|
||||
{
|
||||
Wt::Dbo::collection<Release::pointer> res = session.query<Release::pointer>
|
||||
("SELECT r FROM release r INNER JOIN track t ON r.id = t.release_id INNER JOIN track_stats t_s ON t.id = t_s.track_id")
|
||||
.where("t_s.user_id = ?").bind(user.id())
|
||||
.groupBy("r.id")
|
||||
.orderBy("t_s.last_played DESC")
|
||||
.limit(limit);
|
||||
|
||||
return std::vector<Release::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
TrackStats::pointer
|
||||
TrackStats::get(Wt::Dbo::Session& session, Track::pointer track, User::pointer user)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -41,17 +42,22 @@ class TrackStats
|
||||
TrackStats(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<User> user);
|
||||
|
||||
static std::vector<Wt::Dbo::ptr<Artist>> getMostPlayedArtists(Wt::Dbo::Session& session, Wt::Dbo::ptr<User>, int limit = 1);
|
||||
static std::vector<Wt::Dbo::ptr<Artist>> getLastPlayedArtists(Wt::Dbo::Session& session, Wt::Dbo::ptr<User>, int limit = 1);
|
||||
|
||||
static std::vector<Wt::Dbo::ptr<Release>> getMostPlayedReleases(Wt::Dbo::Session& session, Wt::Dbo::ptr<User>, int limit = 1);
|
||||
static std::vector<Wt::Dbo::ptr<Release>> getLastPlayedReleases(Wt::Dbo::Session& session, Wt::Dbo::ptr<User>, int limit = 1);
|
||||
|
||||
// Get utility (will create if does not exist)
|
||||
static pointer get(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<User> user);
|
||||
|
||||
void incPlayCount() { _playCount++; }
|
||||
void setLastPlayed(Wt::WDateTime lastPlayed) { _lastPlayed = lastPlayed; }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _playCount, "play_count");
|
||||
Wt::Dbo::field(a, _lastPlayed, "last_played");
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
@@ -59,6 +65,7 @@ class TrackStats
|
||||
private:
|
||||
|
||||
int _playCount = 0;
|
||||
Wt::WDateTime _lastPlayed;
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
};
|
||||
|
||||
@@ -384,16 +384,20 @@ LmsApplication::handleAuthEvent(void)
|
||||
}));
|
||||
|
||||
// Events from the PlayQueue
|
||||
playqueue->playTrack.connect(explore, &Explore::handleTrackPlayed);
|
||||
|
||||
playqueue->playTrack.connect(player, &MediaPlayer::playTrack);
|
||||
playqueue->playbackStop.connect(player, &MediaPlayer::stop);
|
||||
|
||||
// Events from MediaScanner
|
||||
if (_isAdmin)
|
||||
{
|
||||
std::string sessionId = this->sessionId();
|
||||
_scanner.scanComplete().connect(std::bind([=] (Scanner::MediaScanner::Stats stats)
|
||||
_scanner.scanComplete().connect([=] (Scanner::MediaScanner::Stats stats)
|
||||
{
|
||||
Wt::WServer::instance()->post(sessionId, [=]
|
||||
{
|
||||
bool changes = false;
|
||||
|
||||
if (_isAdmin)
|
||||
{
|
||||
notifyMsg(Wt::WString::tr("Lms.Admin.Database.scan-complete")
|
||||
.arg(static_cast<unsigned>(stats.nbFiles()))
|
||||
@@ -402,10 +406,19 @@ LmsApplication::handleAuthEvent(void)
|
||||
.arg(static_cast<unsigned>(stats.deletions))
|
||||
.arg(static_cast<unsigned>(stats.nbDuplicates()))
|
||||
.arg(static_cast<unsigned>(stats.nbErrors())));
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (stats.nbChanges() > 0)
|
||||
{
|
||||
explore->handleDbChanged();
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (changes)
|
||||
triggerUpdate();
|
||||
});
|
||||
}, std::placeholders::_1));
|
||||
}
|
||||
});
|
||||
|
||||
internalPathChanged().connect(std::bind([=]
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WImage.h>
|
||||
#include <Wt/WLocalDateTime.h>
|
||||
#include <Wt/WText.h>
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
@@ -121,7 +122,10 @@ PlayQueue::play(std::size_t pos)
|
||||
|
||||
trackId = track.id();
|
||||
|
||||
Database::TrackStats::get(LmsApp->getDboSession(), track, LmsApp->getCurrentUser()).modify()->incPlayCount();
|
||||
auto stats = Database::TrackStats::get(LmsApp->getDboSession(), track, LmsApp->getCurrentUser());
|
||||
|
||||
stats.modify()->incPlayCount();
|
||||
stats.modify()->setLastPlayed(Wt::WLocalDateTime::currentServerDateTime().toUTC());
|
||||
|
||||
updateCurrentTrack(true);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WLineEdit.h>
|
||||
#include <Wt/WLocalDateTime.h>
|
||||
#include <Wt/WServer.h>
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
@@ -68,6 +67,7 @@ Artists::Artists(Filters* filters)
|
||||
_container = bindNew<Wt::WContainerWidget>("artists");
|
||||
_mostPlayedContainer = bindNew<Wt::WContainerWidget>("most-played-artists");
|
||||
_recentlyAddedContainer = bindNew<Wt::WContainerWidget>("recently-added-artists");
|
||||
_recentlyPlayedContainer = bindNew<Wt::WContainerWidget>("recently-played-artists");
|
||||
|
||||
_showMore = bindNew<Wt::WTemplate>("show-more", Wt::WString::tr("Lms.Explore.template.show-more"));
|
||||
_showMore->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
@@ -80,21 +80,9 @@ Artists::Artists(Filters* filters)
|
||||
refresh();
|
||||
refreshMostPlayed();
|
||||
refreshRecentlyAdded();
|
||||
refreshRecentlyPlayed();
|
||||
|
||||
filters->updated().connect(this, &Artists::refresh);
|
||||
|
||||
std::string sessionId = LmsApp->sessionId();
|
||||
LmsApp->getMediaScanner().scanComplete().connect([=] (Scanner::MediaScanner::Stats stats)
|
||||
{
|
||||
if (stats.nbChanges() > 0)
|
||||
{
|
||||
Wt::WServer::instance()->post(sessionId, [=]
|
||||
{
|
||||
refreshRecentlyAdded();
|
||||
LmsApp->triggerUpdate();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -109,6 +97,17 @@ Artists::refreshRecentlyAdded()
|
||||
addCompactEntries(_recentlyAddedContainer, artists);
|
||||
}
|
||||
|
||||
void
|
||||
Artists::refreshRecentlyPlayed()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||
auto artists = TrackStats::getLastPlayedArtists(LmsApp->getDboSession(), LmsApp->getCurrentUser(), 5);
|
||||
|
||||
_recentlyPlayedContainer->clear();
|
||||
addCompactEntries(_recentlyPlayedContainer, artists);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Artists::refreshMostPlayed()
|
||||
{
|
||||
|
||||
@@ -38,9 +38,11 @@ class Artists : public Wt::WTemplate
|
||||
Wt::Signal<Database::IdType> artistAdd;
|
||||
Wt::Signal<Database::IdType> artistPlay;
|
||||
|
||||
private:
|
||||
void refreshRecentlyAdded();
|
||||
void refreshRecentlyPlayed();
|
||||
void refreshMostPlayed();
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
void addSome();
|
||||
|
||||
@@ -50,6 +52,7 @@ class Artists : public Wt::WTemplate
|
||||
Wt::WContainerWidget* _container;
|
||||
Wt::WContainerWidget* _mostPlayedContainer;
|
||||
Wt::WContainerWidget* _recentlyAddedContainer;
|
||||
Wt::WContainerWidget* _recentlyPlayedContainer;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -79,6 +79,7 @@ Explore::Explore()
|
||||
Wt::WStackedWidget* stack = bindNew<Wt::WStackedWidget>("contents");
|
||||
|
||||
auto artists = std::make_unique<Artists>(_filters);
|
||||
auto artists_raw = artists.get();
|
||||
artists->artistAdd.connect(this, &Explore::handleArtistAdd);
|
||||
artists->artistPlay.connect(this, &Explore::handleArtistPlay);
|
||||
stack->addWidget(std::move(artists));
|
||||
@@ -91,6 +92,7 @@ Explore::Explore()
|
||||
stack->addWidget(std::move(artist));
|
||||
|
||||
auto releases = std::make_unique<Releases>(_filters);
|
||||
auto releases_raw = releases.get();
|
||||
releases->releaseAdd.connect(this, &Explore::handleReleaseAdd);
|
||||
releases->releasePlay.connect(this, &Explore::handleReleasePlay);
|
||||
stack->addWidget(std::move(releases));
|
||||
@@ -102,6 +104,21 @@ Explore::Explore()
|
||||
release->trackPlay.connect(this, &Explore::handleTrackPlay);
|
||||
stack->addWidget(std::move(release));
|
||||
|
||||
_dbChanged.connect([=]
|
||||
{
|
||||
artists_raw->refreshRecentlyAdded();
|
||||
releases_raw->refreshRecentlyAdded();
|
||||
});
|
||||
|
||||
_trackPlayed.connect([=]
|
||||
{
|
||||
artists_raw->refreshMostPlayed();
|
||||
artists_raw->refreshRecentlyPlayed();
|
||||
releases_raw->refreshMostPlayed();
|
||||
releases_raw->refreshRecentlyPlayed();
|
||||
|
||||
});
|
||||
|
||||
auto tracks = std::make_unique<Tracks>(_filters);
|
||||
tracks->trackAdd.connect(this, &Explore::handleTrackAdd);
|
||||
tracks->trackPlay.connect(this, &Explore::handleTrackPlay);
|
||||
|
||||
@@ -36,6 +36,9 @@ class Explore : public Wt::WTemplate
|
||||
Wt::Signal<std::vector<Database::Track::pointer>> tracksAdd;
|
||||
Wt::Signal<std::vector<Database::Track::pointer>> tracksPlay;
|
||||
|
||||
void handleDbChanged() { _dbChanged.emit(); };
|
||||
void handleTrackPlayed(Database::IdType trackId) { _trackPlayed.emit(); }
|
||||
|
||||
private:
|
||||
|
||||
void handleArtistAdd(Database::IdType id);
|
||||
@@ -48,6 +51,9 @@ class Explore : public Wt::WTemplate
|
||||
void handleTracksPlay(std::vector<Database::Track::pointer> tracks);
|
||||
|
||||
Filters* _filters;
|
||||
|
||||
Wt::Signal<> _dbChanged;
|
||||
Wt::Signal<> _trackPlayed;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "ReleasesView.hpp"
|
||||
|
||||
#include <Wt/WServer.h>
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WImage.h>
|
||||
@@ -87,6 +86,7 @@ _filters(filters)
|
||||
_container = bindNew<Wt::WContainerWidget>("releases");
|
||||
_mostPlayedContainer = bindNew<Wt::WContainerWidget>("most-played-releases");
|
||||
_recentlyAddedContainer = bindNew<Wt::WContainerWidget>("recently-added-releases");
|
||||
_recentlyPlayedContainer = bindNew<Wt::WContainerWidget>("recently-played-releases");
|
||||
|
||||
_showMore = bindNew<Wt::WTemplate>("show-more", Wt::WString::tr("Lms.Explore.show-more"));
|
||||
_showMore->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
@@ -96,28 +96,18 @@ _filters(filters)
|
||||
}));
|
||||
|
||||
refreshRecentlyAdded();
|
||||
refreshRecentlyPlayed();
|
||||
refreshMostPlayed();
|
||||
refresh();
|
||||
|
||||
filters->updated().connect(this, &Releases::refresh);
|
||||
|
||||
std::string sessionId = LmsApp->sessionId();
|
||||
LmsApp->getMediaScanner().scanComplete().connect([=] (Scanner::MediaScanner::Stats stats)
|
||||
{
|
||||
if (stats.nbChanges() > 0)
|
||||
{
|
||||
Wt::WServer::instance()->post(sessionId, [=]
|
||||
{
|
||||
refreshRecentlyAdded();
|
||||
LmsApp->triggerUpdate();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Releases::refreshRecentlyAdded()
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Refreshing recently added releases";
|
||||
|
||||
auto after = Wt::WLocalDateTime::currentServerDateTime().toUTC().addMonths(-1);
|
||||
|
||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||
@@ -128,9 +118,23 @@ Releases::refreshRecentlyAdded()
|
||||
addCompactEntries(_recentlyAddedContainer, releases);
|
||||
}
|
||||
|
||||
void
|
||||
Releases::refreshRecentlyPlayed()
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Refreshing recently played releases";
|
||||
|
||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||
|
||||
auto releases = TrackStats::getLastPlayedReleases(LmsApp->getDboSession(), LmsApp->getCurrentUser(), 5);
|
||||
|
||||
_recentlyPlayedContainer->clear();
|
||||
addCompactEntries(_recentlyPlayedContainer, releases);
|
||||
}
|
||||
|
||||
void
|
||||
Releases::refreshMostPlayed()
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Refreshing most played releases";
|
||||
|
||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@ class Releases : public Wt::WTemplate
|
||||
Wt::Signal<Database::IdType> releaseAdd;
|
||||
Wt::Signal<Database::IdType> releasePlay;
|
||||
|
||||
private:
|
||||
void refreshRecentlyAdded();
|
||||
void refreshRecentlyPlayed();
|
||||
void refreshMostPlayed();
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
void addSome();
|
||||
|
||||
@@ -50,6 +52,7 @@ class Releases : public Wt::WTemplate
|
||||
Wt::WContainerWidget* _container;
|
||||
Wt::WContainerWidget* _mostPlayedContainer;
|
||||
Wt::WContainerWidget* _recentlyAddedContainer;
|
||||
Wt::WContainerWidget* _recentlyPlayedContainer;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
Reference in New Issue
Block a user