Added an played tracklist
This commit is contained in:
@@ -8,11 +8,6 @@
|
|||||||
</div>
|
</div>
|
||||||
${most-played-artists}
|
${most-played-artists}
|
||||||
|
|
||||||
<div class="page-header">
|
|
||||||
<h2>${tr:Lms.Explore.recently-played-artists}</h2>
|
|
||||||
</div>
|
|
||||||
${recently-played-artists}
|
|
||||||
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h2>${tr:Lms.Explore.recently-added-artists}</h2>
|
<h2>${tr:Lms.Explore.recently-added-artists}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,11 +8,6 @@
|
|||||||
</div>
|
</div>
|
||||||
${most-played-releases}
|
${most-played-releases}
|
||||||
|
|
||||||
<div class="page-header">
|
|
||||||
<h2>${tr:Lms.Explore.recently-played-releases}</h2>
|
|
||||||
</div>
|
|
||||||
${recently-played-releases}
|
|
||||||
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h2>${tr:Lms.Explore.recently-added-releases}</h2>
|
<h2>${tr:Lms.Explore.recently-added-releases}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-2
@@ -8,12 +8,11 @@ lms_SOURCES = \
|
|||||||
$(srcdir)/database/Artist.cpp \
|
$(srcdir)/database/Artist.cpp \
|
||||||
$(srcdir)/database/Cluster.cpp \
|
$(srcdir)/database/Cluster.cpp \
|
||||||
$(srcdir)/database/DatabaseHandler.cpp \
|
$(srcdir)/database/DatabaseHandler.cpp \
|
||||||
$(srcdir)/database/Playlist.cpp \
|
$(srcdir)/database/TrackList.cpp \
|
||||||
$(srcdir)/database/Release.cpp \
|
$(srcdir)/database/Release.cpp \
|
||||||
$(srcdir)/database/ScanSettings.cpp \
|
$(srcdir)/database/ScanSettings.cpp \
|
||||||
$(srcdir)/database/SqlQuery.cpp \
|
$(srcdir)/database/SqlQuery.cpp \
|
||||||
$(srcdir)/database/Track.cpp \
|
$(srcdir)/database/Track.cpp \
|
||||||
$(srcdir)/database/TrackStats.cpp \
|
|
||||||
$(srcdir)/database/User.cpp \
|
$(srcdir)/database/User.cpp \
|
||||||
$(srcdir)/image/Image.cpp \
|
$(srcdir)/image/Image.cpp \
|
||||||
$(srcdir)/metadata/AvFormat.cpp \
|
$(srcdir)/metadata/AvFormat.cpp \
|
||||||
|
|||||||
@@ -31,17 +31,14 @@
|
|||||||
#include <Wt/Auth/PasswordStrengthValidator.h>
|
#include <Wt/Auth/PasswordStrengthValidator.h>
|
||||||
#include <Wt/Auth/PasswordVerifier.h>
|
#include <Wt/Auth/PasswordVerifier.h>
|
||||||
|
|
||||||
#include "Setting.hpp"
|
|
||||||
|
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
|
|
||||||
#include "Artist.hpp"
|
#include "Artist.hpp"
|
||||||
#include "Cluster.hpp"
|
#include "Cluster.hpp"
|
||||||
#include "Playlist.hpp"
|
#include "TrackList.hpp"
|
||||||
#include "Release.hpp"
|
#include "Release.hpp"
|
||||||
#include "ScanSettings.hpp"
|
#include "ScanSettings.hpp"
|
||||||
#include "Track.hpp"
|
#include "Track.hpp"
|
||||||
#include "TrackStats.hpp"
|
|
||||||
|
|
||||||
namespace Database {
|
namespace Database {
|
||||||
|
|
||||||
@@ -102,12 +99,10 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
|||||||
_session.mapClass<Artist>("artist");
|
_session.mapClass<Artist>("artist");
|
||||||
_session.mapClass<Cluster>("cluster");
|
_session.mapClass<Cluster>("cluster");
|
||||||
_session.mapClass<ClusterType>("cluster_type");
|
_session.mapClass<ClusterType>("cluster_type");
|
||||||
_session.mapClass<Playlist>("playlist");
|
_session.mapClass<TrackList>("tracklist");
|
||||||
_session.mapClass<PlaylistEntry>("playlist_entry");
|
_session.mapClass<TrackListEntry>("tracklist_entry");
|
||||||
_session.mapClass<Release>("release");
|
_session.mapClass<Release>("release");
|
||||||
_session.mapClass<Setting>("setting");
|
|
||||||
_session.mapClass<Track>("track");
|
_session.mapClass<Track>("track");
|
||||||
_session.mapClass<TrackStats>("track_stats");
|
|
||||||
|
|
||||||
_session.mapClass<ScanSettings>("scan_settings");
|
_session.mapClass<ScanSettings>("scan_settings");
|
||||||
|
|
||||||
@@ -139,7 +134,7 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
|||||||
_session.execute("CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)");
|
_session.execute("CREATE INDEX IF NOT EXISTS track_release_idx ON track(release_id)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS cluster_name_idx ON cluster(name)");
|
_session.execute("CREATE INDEX IF NOT EXISTS cluster_name_idx ON cluster(name)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS cluster_type_name_idx ON cluster_type(name)");
|
_session.execute("CREATE INDEX IF NOT EXISTS cluster_type_name_idx ON cluster_type(name)");
|
||||||
_session.execute("CREATE INDEX IF NOT EXISTS settings_name_idx ON setting(name)");
|
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name ON tracklist(name)");
|
||||||
}
|
}
|
||||||
|
|
||||||
_users = new UserDatabase(_session);
|
_users = new UserDatabase(_session);
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Emeric Poupon
|
|
||||||
*
|
|
||||||
* This file is part of LMS.
|
|
||||||
*
|
|
||||||
* LMS is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LMS is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include "Playlist.hpp"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
#include "Cluster.hpp"
|
|
||||||
#include "User.hpp"
|
|
||||||
#include "Track.hpp"
|
|
||||||
|
|
||||||
namespace Database {
|
|
||||||
|
|
||||||
Playlist::Playlist()
|
|
||||||
: _isPublic(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist::Playlist(std::string name, bool isPublic, Wt::Dbo::ptr<User> user)
|
|
||||||
: _name(name),
|
|
||||||
_isPublic(isPublic),
|
|
||||||
_user(user)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist::pointer
|
|
||||||
Playlist::create(Wt::Dbo::Session& session, std::string name, bool isPublic, Wt::Dbo::ptr<User> user)
|
|
||||||
{
|
|
||||||
return session.add( std::make_unique<Playlist>(name, isPublic, user) );
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaylistEntry::PlaylistEntry()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaylistEntry::pointer
|
|
||||||
PlaylistEntry::getById(Wt::Dbo::Session& session, IdType id)
|
|
||||||
{
|
|
||||||
return session.find<PlaylistEntry>().where("id = ?").bind(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist::pointer
|
|
||||||
Playlist::get(Wt::Dbo::Session& session, std::string name, Wt::Dbo::ptr<User> user)
|
|
||||||
{
|
|
||||||
return session.find<Playlist>().where("name = ? AND user_id = ?").bind(name).bind(user.id());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Playlist::pointer>
|
|
||||||
Playlist::getAll(Wt::Dbo::Session& session, Wt::Dbo::ptr<User> user)
|
|
||||||
{
|
|
||||||
Wt::Dbo::collection<Playlist::pointer> res = session.find<Playlist>().where("user_id = ?").bind(user.id()).orderBy("name");
|
|
||||||
|
|
||||||
return std::vector<Playlist::pointer>(res.begin(), res.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist::pointer
|
|
||||||
Playlist::getById(Wt::Dbo::Session& session, IdType id)
|
|
||||||
{
|
|
||||||
return session.find<Playlist>().where("id = ?").bind(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PlaylistEntry::PlaylistEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Playlist> playlist)
|
|
||||||
: _track(track),
|
|
||||||
_playlist(playlist)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaylistEntry::pointer
|
|
||||||
PlaylistEntry::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Playlist> playlist)
|
|
||||||
{
|
|
||||||
return session.add( std::make_unique<PlaylistEntry>( track, playlist) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<Wt::Dbo::ptr<PlaylistEntry>>
|
|
||||||
Playlist::getEntries(int offset, int size, bool& moreResults) const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
assert(IdIsValid(self()->id()));
|
|
||||||
|
|
||||||
moreResults = false;
|
|
||||||
|
|
||||||
Wt::Dbo::collection<Wt::Dbo::ptr<PlaylistEntry>> entries =
|
|
||||||
session()->find<PlaylistEntry>()
|
|
||||||
.where("playlist_id = ?").bind(self().id())
|
|
||||||
.orderBy("id")
|
|
||||||
.limit(size != -1 ? size + 1 : -1)
|
|
||||||
.offset(offset);
|
|
||||||
|
|
||||||
std::vector<Wt::Dbo::ptr<PlaylistEntry>> res;
|
|
||||||
|
|
||||||
for (auto entry : entries)
|
|
||||||
{
|
|
||||||
if (size != -1 && res.size() == static_cast<std::size_t>(size))
|
|
||||||
{
|
|
||||||
moreResults = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.push_back(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Wt::Dbo::ptr<PlaylistEntry>>
|
|
||||||
Playlist::getAllEntries() const
|
|
||||||
{
|
|
||||||
bool moreResults;
|
|
||||||
return getEntries(-1, -1, moreResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
Wt::Dbo::ptr<PlaylistEntry>
|
|
||||||
Playlist::getEntry(std::size_t pos) const
|
|
||||||
{
|
|
||||||
Wt::Dbo::ptr<PlaylistEntry> res;
|
|
||||||
|
|
||||||
bool moreResults;
|
|
||||||
auto entries = getEntries(pos, 1, moreResults);
|
|
||||||
if (!entries.empty())
|
|
||||||
res = entries.front();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
Playlist::getCount() const
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Wt::Dbo::ptr<Cluster>>
|
|
||||||
Playlist::getClusters() const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
assert(IdIsValid(self()->id()));
|
|
||||||
|
|
||||||
Wt::Dbo::collection<Cluster::pointer> res = session()->query<Cluster::pointer>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN playlist_entry p_e ON p_e.track_id = t.id INNER JOIN playlist p ON p.id = p_e.playlist_id")
|
|
||||||
.where("p.id = ?").bind(self()->id())
|
|
||||||
.groupBy("c.id")
|
|
||||||
.orderBy("COUNT(c.id) DESC");
|
|
||||||
|
|
||||||
return std::vector<Wt::Dbo::ptr<Cluster>>(res.begin(), res.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Playlist::hasTrack(IdType trackId) const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
assert(IdIsValid(self()->id()));
|
|
||||||
|
|
||||||
Wt::Dbo::collection<PlaylistEntry::pointer> res = session()->query<PlaylistEntry::pointer>("SELECT p_e from playlist_entry p_e INNER JOIN playlist p ON p_e.playlist_id = p.id")
|
|
||||||
.where("p_e.track_id = ?").bind(trackId)
|
|
||||||
.where("p.id = ?").bind(self()->id());
|
|
||||||
|
|
||||||
return res.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<IdType>
|
|
||||||
Playlist::getTrackIds() const
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
assert(IdIsValid(self()->id()));
|
|
||||||
|
|
||||||
Wt::Dbo::collection<IdType> res = session()->query<IdType>("SELECT p_e.track_id from playlist_entry p_e INNER JOIN playlist p ON p_e.playlist_id = p.id")
|
|
||||||
.where("p.id = ?").bind(self()->id());
|
|
||||||
|
|
||||||
return std::vector<IdType>(res.begin(), res.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Playlist::shuffle()
|
|
||||||
{
|
|
||||||
assert(session());
|
|
||||||
|
|
||||||
auto entries = getAllEntries();
|
|
||||||
|
|
||||||
auto now = std::chrono::system_clock::now();
|
|
||||||
std::mt19937 randGenerator(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
|
|
||||||
|
|
||||||
std::shuffle(entries.begin(), entries.end(), randGenerator);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
for (auto entry : entries)
|
|
||||||
PlaylistEntry::create(*session(), entry->getTrack(), self());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Database
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Emeric Poupon
|
|
||||||
*
|
|
||||||
* This file is part of LMS.
|
|
||||||
*
|
|
||||||
* LMS is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LMS is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Setting.hpp"
|
|
||||||
|
|
||||||
namespace Database {
|
|
||||||
|
|
||||||
bool
|
|
||||||
Setting::exists(Wt::Dbo::Session& session, std::string setting)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
return (getByName(session, setting) != Setting::pointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
Setting::getString(Wt::Dbo::Session& session, std::string setting, std::string defaultValue)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
|
|
||||||
pointer res = getByName(session, setting);
|
|
||||||
if (!res)
|
|
||||||
return defaultValue;
|
|
||||||
|
|
||||||
return res->_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Setting::getBool(Wt::Dbo::Session& session, std::string setting, bool defaultValue)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
|
|
||||||
pointer res = getByName(session, setting);
|
|
||||||
if (!res)
|
|
||||||
return defaultValue;
|
|
||||||
|
|
||||||
return (res->_value == "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
Wt::WTime
|
|
||||||
Setting::getTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime defaultValue)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
|
|
||||||
pointer res = getByName(session, setting);
|
|
||||||
if (!res)
|
|
||||||
return defaultValue;
|
|
||||||
|
|
||||||
return Wt::WTime::fromString(res->_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Setting::getInt(Wt::Dbo::Session& session, std::string setting, int defaultValue)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
|
|
||||||
pointer res = getByName(session, setting);
|
|
||||||
if (!res)
|
|
||||||
return defaultValue;
|
|
||||||
|
|
||||||
return std::stoi(res->_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Setting::pointer
|
|
||||||
Setting::create(Wt::Dbo::Session& session, std::string name)
|
|
||||||
{
|
|
||||||
return session.add<Setting>(std::make_unique<Setting>(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
Setting::pointer
|
|
||||||
Setting::getByName(Wt::Dbo::Session& session, std::string name)
|
|
||||||
{
|
|
||||||
return session.find<Setting>().where("name = ?").bind(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Setting::pointer
|
|
||||||
Setting::getOrCreateByName(Wt::Dbo::Session& session, std::string name)
|
|
||||||
{
|
|
||||||
pointer res = getByName(session, name);
|
|
||||||
if (!res)
|
|
||||||
res = create(session, name);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Setting::setString(Wt::Dbo::Session& session, std::string setting, std::string value)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
getOrCreateByName(session, setting).modify()->_value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Setting::setBool(Wt::Dbo::Session& session, std::string setting, bool value)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
getOrCreateByName(session, setting).modify()->_value = (value ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Setting::setTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime value)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
getOrCreateByName(session, setting).modify()->_value = value.toString().toUTF8();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Setting::setInt(Wt::Dbo::Session& session, std::string setting, int value)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
getOrCreateByName(session, setting).modify()->_value = std::to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Database
|
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 Emeric Poupon
|
|
||||||
*
|
|
||||||
* This file is part of LMS.
|
|
||||||
*
|
|
||||||
* LMS is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LMS is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Wt/Dbo/Dbo.h>
|
|
||||||
#include <Wt/WTime.h>
|
|
||||||
|
|
||||||
namespace Database {
|
|
||||||
|
|
||||||
// class meant to store general settings
|
|
||||||
class Setting
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using pointer = Wt::Dbo::ptr<Setting>;
|
|
||||||
|
|
||||||
Setting() {}
|
|
||||||
Setting(std::string name) : _name(name) {}
|
|
||||||
|
|
||||||
// check if a setting exists or not
|
|
||||||
static bool exists(Wt::Dbo::Session& session, std::string setting);
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
// Nested transactions
|
|
||||||
static std::string getString(Wt::Dbo::Session& session, std::string setting, std::string defaultValue = "");
|
|
||||||
static bool getBool(Wt::Dbo::Session& session, std::string setting, bool defaultValue = false);
|
|
||||||
static Wt::WTime getTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime defaultValue = Wt::WTime());
|
|
||||||
static int getInt(Wt::Dbo::Session& session, std::string setting, int defaultValue = 0);
|
|
||||||
|
|
||||||
// Setters
|
|
||||||
// Nested transactions
|
|
||||||
static void setString(Wt::Dbo::Session& session, std::string setting, std::string value);
|
|
||||||
static void setBool(Wt::Dbo::Session& session, std::string setting, bool value);
|
|
||||||
static void setTime(Wt::Dbo::Session& session, std::string setting, Wt::WTime value);
|
|
||||||
static void setInt(Wt::Dbo::Session& session, std::string setting, int value);
|
|
||||||
|
|
||||||
template<class Action>
|
|
||||||
void persist(Action& a)
|
|
||||||
{
|
|
||||||
Wt::Dbo::field(a, _name, "name");
|
|
||||||
Wt::Dbo::field(a, _value, "value");
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static pointer getByName(Wt::Dbo::Session& session, std::string name);
|
|
||||||
static pointer create(Wt::Dbo::Session& session, std::string name);
|
|
||||||
static pointer getOrCreateByName(Wt::Dbo::Session& session, std::string name);
|
|
||||||
|
|
||||||
std::string _name;
|
|
||||||
std::string _value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Database
|
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ namespace Database {
|
|||||||
class Artist;
|
class Artist;
|
||||||
class Cluster;
|
class Cluster;
|
||||||
class ClusterType;
|
class ClusterType;
|
||||||
class PlaylistEntry;
|
class TrackListEntry;
|
||||||
class Release;
|
class Release;
|
||||||
class TrackStats;
|
class TrackStats;
|
||||||
|
|
||||||
@@ -144,7 +144,6 @@ class Track : public Wt::Dbo::Dbo<Track>
|
|||||||
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||||
Wt::Dbo::hasMany(a, _stats, Wt::Dbo::ManyToOne, "track");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -173,8 +172,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
|||||||
Wt::Dbo::ptr<Artist> _artist;
|
Wt::Dbo::ptr<Artist> _artist;
|
||||||
Wt::Dbo::ptr<Release> _release;
|
Wt::Dbo::ptr<Release> _release;
|
||||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||||
Wt::Dbo::collection<Wt::Dbo::ptr<PlaylistEntry>> _playlistEntries;
|
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
|
||||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackStats>> _stats;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "TrackList.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include "utils/Logger.hpp"
|
||||||
|
|
||||||
|
#include "Artist.hpp"
|
||||||
|
#include "Cluster.hpp"
|
||||||
|
#include "Release.hpp"
|
||||||
|
#include "User.hpp"
|
||||||
|
#include "Track.hpp"
|
||||||
|
|
||||||
|
namespace Database {
|
||||||
|
|
||||||
|
TrackList::TrackList()
|
||||||
|
: _isPublic(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList::TrackList(std::string name, bool isPublic, Wt::Dbo::ptr<User> user)
|
||||||
|
: _name(name),
|
||||||
|
_isPublic(isPublic),
|
||||||
|
_user(user)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList::pointer
|
||||||
|
TrackList::create(Wt::Dbo::Session& session, std::string name, bool isPublic, Wt::Dbo::ptr<User> user)
|
||||||
|
{
|
||||||
|
assert(user);
|
||||||
|
|
||||||
|
auto res = session.add( std::make_unique<TrackList>(name, isPublic, user) );
|
||||||
|
session.flush();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackListEntry::pointer
|
||||||
|
TrackList::add(IdType trackId)
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(self());
|
||||||
|
|
||||||
|
return TrackListEntry::create(*session(), Database::Track::getById(*session(), trackId), self());
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList::pointer
|
||||||
|
TrackList::get(Wt::Dbo::Session& session, std::string name, Wt::Dbo::ptr<User> user)
|
||||||
|
{
|
||||||
|
return session.find<TrackList>().where("name = ? AND user_id = ?").bind(name).bind(user.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TrackList::pointer>
|
||||||
|
TrackList::getAll(Wt::Dbo::Session& session, Wt::Dbo::ptr<User> user)
|
||||||
|
{
|
||||||
|
Wt::Dbo::collection<TrackList::pointer> res = session.find<TrackList>().where("user_id = ?").bind(user.id()).orderBy("name");
|
||||||
|
|
||||||
|
return std::vector<TrackList::pointer>(res.begin(), res.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList::pointer
|
||||||
|
TrackList::getById(Wt::Dbo::Session& session, IdType id)
|
||||||
|
{
|
||||||
|
return session.find<TrackList>().where("id = ?").bind(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Wt::Dbo::ptr<TrackListEntry>>
|
||||||
|
TrackList::getEntries(int offset, int size) const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> entries =
|
||||||
|
session()->find<TrackListEntry>()
|
||||||
|
.where("tracklist_id = ?").bind(self().id())
|
||||||
|
.orderBy("id")
|
||||||
|
.limit(size)
|
||||||
|
.offset(offset);
|
||||||
|
|
||||||
|
return std::vector<Wt::Dbo::ptr<TrackListEntry>>(entries.begin(), entries.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::Dbo::ptr<TrackListEntry>
|
||||||
|
TrackList::getEntry(std::size_t pos) const
|
||||||
|
{
|
||||||
|
Wt::Dbo::ptr<TrackListEntry> res;
|
||||||
|
|
||||||
|
auto entries = getEntries(pos, 1);
|
||||||
|
if (!entries.empty())
|
||||||
|
res = entries.front();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
TrackList::getCount() const
|
||||||
|
{
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Wt::Dbo::ptr<Cluster>>
|
||||||
|
TrackList::getClusters() const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<Cluster::pointer> res = session()->query<Cluster::pointer>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
|
||||||
|
.where("p.id = ?").bind(self()->id())
|
||||||
|
.groupBy("c.id")
|
||||||
|
.orderBy("COUNT(c.id) DESC");
|
||||||
|
|
||||||
|
return std::vector<Wt::Dbo::ptr<Cluster>>(res.begin(), res.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TrackList::hasTrack(IdType trackId) const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<TrackListEntry::pointer> res = session()->query<TrackListEntry::pointer>("SELECT p_e from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
|
||||||
|
.where("p_e.track_id = ?").bind(trackId)
|
||||||
|
.where("p.id = ?").bind(self()->id());
|
||||||
|
|
||||||
|
return res.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IdType>
|
||||||
|
TrackList::getTrackIds() const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<IdType> res = session()->query<IdType>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
|
||||||
|
.where("p.id = ?").bind(self()->id());
|
||||||
|
|
||||||
|
return std::vector<IdType>(res.begin(), res.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrackList::shuffle()
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
|
||||||
|
auto entries = getEntries();
|
||||||
|
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::mt19937 randGenerator(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
|
||||||
|
|
||||||
|
std::shuffle(entries.begin(), entries.end(), randGenerator);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
for (auto entry : entries)
|
||||||
|
TrackListEntry::create(*session(), entry->getTrack(), self());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Artist::pointer>
|
||||||
|
TrackList::getTopArtists(int limit) const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<Artist::pointer> res = session()->query<Artist::pointer>("SELECT a from artist a INNER JOIN track t ON t.artist_id = a.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
|
||||||
|
.where("p.id = ?").bind(self()->id())
|
||||||
|
.groupBy("a.id")
|
||||||
|
.orderBy("COUNT(a.id) DESC")
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
|
return std::vector<Artist::pointer>(res.begin(), res.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Release::pointer>
|
||||||
|
TrackList::getTopReleases(int limit) const
|
||||||
|
{
|
||||||
|
assert(session());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
|
||||||
|
Wt::Dbo::collection<Release::pointer> res = session()->query<Release::pointer>("SELECT r from release r INNER JOIN track t ON t.release_id = r.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
|
||||||
|
.where("p.id = ?").bind(self()->id())
|
||||||
|
.groupBy("r.id")
|
||||||
|
.orderBy("COUNT(r.id) DESC")
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
|
return std::vector<Release::pointer>(res.begin(), res.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackListEntry::TrackListEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<TrackList> tracklist)
|
||||||
|
: _track(track),
|
||||||
|
_tracklist(tracklist)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackListEntry::TrackListEntry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackListEntry::pointer
|
||||||
|
TrackListEntry::create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<TrackList> tracklist)
|
||||||
|
{
|
||||||
|
assert(track);
|
||||||
|
assert(tracklist);
|
||||||
|
|
||||||
|
auto res = session.add( std::make_unique<TrackListEntry>( track, tracklist) );
|
||||||
|
session.flush();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackListEntry::pointer
|
||||||
|
TrackListEntry::getById(Wt::Dbo::Session& session, IdType id)
|
||||||
|
{
|
||||||
|
return session.find<TrackListEntry>().where("id = ?").bind(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Database
|
||||||
@@ -27,22 +27,28 @@
|
|||||||
|
|
||||||
namespace Database {
|
namespace Database {
|
||||||
|
|
||||||
class PlaylistEntry;
|
class Artist;
|
||||||
|
class Release;
|
||||||
class User;
|
class User;
|
||||||
class Track;
|
class Track;
|
||||||
|
class TrackListEntry;
|
||||||
class Cluster;
|
class Cluster;
|
||||||
|
|
||||||
class Playlist : public Wt::Dbo::Dbo<Playlist>
|
class TrackList : public Wt::Dbo::Dbo<TrackList>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using pointer = Wt::Dbo::ptr<Playlist>;
|
using pointer = Wt::Dbo::ptr<TrackList>;
|
||||||
|
|
||||||
Playlist();
|
TrackList();
|
||||||
Playlist(std::string name, bool isPublic, Wt::Dbo::ptr<User> user);
|
TrackList(std::string name, bool isPublic, Wt::Dbo::ptr<User> user);
|
||||||
|
|
||||||
|
// Stats utility
|
||||||
|
std::vector<Wt::Dbo::ptr<Artist>> getTopArtists(int limit = 1) const;
|
||||||
|
std::vector<Wt::Dbo::ptr<Release>> getTopReleases(int limit = 1) const;
|
||||||
|
|
||||||
// Search utility
|
// Search utility
|
||||||
static pointer get(Wt::Dbo::Session& session, std::string name, Wt::Dbo::ptr<User> user);
|
static pointer get(Wt::Dbo::Session& session, std::string name, Wt::Dbo::ptr<User> user);
|
||||||
static pointer getById(Wt::Dbo::Session& session, IdType playlistId);
|
static pointer getById(Wt::Dbo::Session& session, IdType tracklistId);
|
||||||
static std::vector<pointer> getAll(Wt::Dbo::Session& session, Wt::Dbo::ptr<User> user);
|
static std::vector<pointer> getAll(Wt::Dbo::Session& session, Wt::Dbo::ptr<User> user);
|
||||||
|
|
||||||
// Create utility
|
// Create utility
|
||||||
@@ -53,14 +59,14 @@ class Playlist : public Wt::Dbo::Dbo<Playlist>
|
|||||||
bool isPublic() const { return _isPublic; }
|
bool isPublic() const { return _isPublic; }
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
|
Wt::Dbo::ptr<TrackListEntry> add(IdType trackId);
|
||||||
void clear() { _entries.clear(); }
|
void clear() { _entries.clear(); }
|
||||||
void shuffle();
|
void shuffle();
|
||||||
|
|
||||||
// Get tracks, ordered by position
|
// Get tracks, ordered by position
|
||||||
std::size_t getCount() const;
|
std::size_t getCount() const;
|
||||||
Wt::Dbo::ptr<PlaylistEntry> getEntry(std::size_t pos) const;
|
Wt::Dbo::ptr<TrackListEntry> getEntry(std::size_t pos) const;
|
||||||
std::vector<Wt::Dbo::ptr<PlaylistEntry>> getEntries(int offset, int size, bool& moreResults) const;
|
std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntries(int offset = -1, int size = -1) const;
|
||||||
std::vector<Wt::Dbo::ptr<PlaylistEntry>> getAllEntries() const;
|
|
||||||
|
|
||||||
std::vector<IdType> getTrackIds() const;
|
std::vector<IdType> getTrackIds() const;
|
||||||
|
|
||||||
@@ -75,7 +81,7 @@ class Playlist : public Wt::Dbo::Dbo<Playlist>
|
|||||||
Wt::Dbo::field(a, _name, "name");
|
Wt::Dbo::field(a, _name, "name");
|
||||||
Wt::Dbo::field(a, _isPublic, "public");
|
Wt::Dbo::field(a, _isPublic, "public");
|
||||||
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::hasMany(a, _entries, Wt::Dbo::ManyToOne, "playlist");
|
Wt::Dbo::hasMany(a, _entries, Wt::Dbo::ManyToOne, "tracklist");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -83,23 +89,23 @@ class Playlist : public Wt::Dbo::Dbo<Playlist>
|
|||||||
std::string _name;
|
std::string _name;
|
||||||
bool _isPublic;
|
bool _isPublic;
|
||||||
Wt::Dbo::ptr<User> _user;
|
Wt::Dbo::ptr<User> _user;
|
||||||
Wt::Dbo::collection< Wt::Dbo::ptr<PlaylistEntry> > _entries;
|
Wt::Dbo::collection< Wt::Dbo::ptr<TrackListEntry> > _entries;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlaylistEntry
|
class TrackListEntry : public Wt::Dbo::Dbo<TrackListEntry>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using pointer = Wt::Dbo::ptr<PlaylistEntry>;
|
using pointer = Wt::Dbo::ptr<TrackListEntry>;
|
||||||
|
|
||||||
PlaylistEntry();
|
TrackListEntry();
|
||||||
PlaylistEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Playlist> playlist);
|
TrackListEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<TrackList> tracklist);
|
||||||
|
|
||||||
static pointer getById(Wt::Dbo::Session& session, IdType id);
|
static pointer getById(Wt::Dbo::Session& session, IdType id);
|
||||||
|
|
||||||
// Create utility
|
// Create utility
|
||||||
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Playlist> playlist);
|
static pointer create(Wt::Dbo::Session& session, Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<TrackList> tracklist);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
||||||
@@ -108,13 +114,13 @@ class PlaylistEntry
|
|||||||
void persist(Action& a)
|
void persist(Action& a)
|
||||||
{
|
{
|
||||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||||
Wt::Dbo::belongsTo(a, _playlist, "playlist", Wt::Dbo::OnDeleteCascade);
|
Wt::Dbo::belongsTo(a, _tracklist, "tracklist", Wt::Dbo::OnDeleteCascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Wt::Dbo::ptr<Track> _track;
|
Wt::Dbo::ptr<Track> _track;
|
||||||
Wt::Dbo::ptr<Playlist> _playlist;
|
Wt::Dbo::ptr<TrackList> _tracklist;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Database
|
} // namespace Database
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Emeric Poupon
|
|
||||||
*
|
|
||||||
* This file is part of LMS.
|
|
||||||
*
|
|
||||||
* LMS is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LMS is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "TrackStats.hpp"
|
|
||||||
|
|
||||||
#include "Artist.hpp"
|
|
||||||
#include "Release.hpp"
|
|
||||||
#include "Track.hpp"
|
|
||||||
#include "User.hpp"
|
|
||||||
|
|
||||||
namespace Database {
|
|
||||||
|
|
||||||
TrackStats::TrackStats(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<User> user)
|
|
||||||
: _track(track),
|
|
||||||
_user(user)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::vector<Artist::pointer>
|
|
||||||
TrackStats::getMostPlayedArtists(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("SUM(t_s.play_count) DESC")
|
|
||||||
.limit(limit);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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("SUM(t_s.play_count) DESC")
|
|
||||||
.limit(limit);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(session);
|
|
||||||
|
|
||||||
TrackStats::pointer res = session.find<TrackStats>()
|
|
||||||
.where("track_id = ?").bind(track.id())
|
|
||||||
.where("user_id = ?").bind(user.id());
|
|
||||||
if (!res)
|
|
||||||
res = session.add(std::make_unique<TrackStats>(track, user));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Database
|
|
||||||
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Emeric Poupon
|
|
||||||
*
|
|
||||||
* This file is part of LMS.
|
|
||||||
*
|
|
||||||
* LMS is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LMS is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Wt/Dbo/Dbo.h>
|
|
||||||
#include <Wt/WDateTime.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Types.hpp"
|
|
||||||
|
|
||||||
namespace Database {
|
|
||||||
|
|
||||||
class Artist;
|
|
||||||
class Release;
|
|
||||||
class Track;
|
|
||||||
class User;
|
|
||||||
|
|
||||||
class TrackStats
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using pointer = Wt::Dbo::ptr<TrackStats>;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
int _playCount = 0;
|
|
||||||
Wt::WDateTime _lastPlayed;
|
|
||||||
Wt::Dbo::ptr<Track> _track;
|
|
||||||
Wt::Dbo::ptr<User> _user;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Database
|
|
||||||
|
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "User.hpp"
|
#include "User.hpp"
|
||||||
|
|
||||||
|
#include "TrackList.hpp"
|
||||||
|
|
||||||
namespace Database {
|
namespace Database {
|
||||||
|
|
||||||
// must be ordered
|
// must be ordered
|
||||||
@@ -93,6 +95,38 @@ User::getMaxAudioBitrate(void) const
|
|||||||
return _maxAudioBitrate;
|
return _maxAudioBitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wt::Dbo::ptr<TrackList>
|
||||||
|
User::getPlayedTrackList() const
|
||||||
|
{
|
||||||
|
static const std::string listName = "__played_tracks__";
|
||||||
|
|
||||||
|
assert(self());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
assert(session());
|
||||||
|
|
||||||
|
auto res = TrackList::get(*session(), listName, self());
|
||||||
|
if (!res)
|
||||||
|
res = TrackList::create(*session(), listName, false, self());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::Dbo::ptr<TrackList>
|
||||||
|
User::getQueuedTrackList() const
|
||||||
|
{
|
||||||
|
static const std::string listName = "__queued_tracks__";
|
||||||
|
|
||||||
|
assert(self());
|
||||||
|
assert(IdIsValid(self()->id()));
|
||||||
|
assert(session());
|
||||||
|
|
||||||
|
auto res = TrackList::get(*session(), listName, self());
|
||||||
|
if (!res)
|
||||||
|
res = TrackList::create(*session(), listName, false, self());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Database
|
} // namespace Database
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Database {
|
|||||||
class User;
|
class User;
|
||||||
using AuthInfo = Wt::Auth::Dbo::AuthInfo<User>;
|
using AuthInfo = Wt::Auth::Dbo::AuthInfo<User>;
|
||||||
|
|
||||||
class Playlist;
|
class TrackList;
|
||||||
|
|
||||||
// User selectable audio formats
|
// User selectable audio formats
|
||||||
enum class AudioEncoding
|
enum class AudioEncoding
|
||||||
@@ -85,6 +85,9 @@ class User : public Wt::Dbo::Dbo<User>
|
|||||||
std::size_t getMaxAudioBitrate() const;
|
std::size_t getMaxAudioBitrate() const;
|
||||||
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
|
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
|
||||||
|
|
||||||
|
Wt::Dbo::ptr<TrackList> getQueuedTrackList() const;
|
||||||
|
Wt::Dbo::ptr<TrackList> getPlayedTrackList() const;
|
||||||
|
|
||||||
template<class Action>
|
template<class Action>
|
||||||
void persist(Action& a)
|
void persist(Action& a)
|
||||||
{
|
{
|
||||||
@@ -94,7 +97,7 @@ class User : public Wt::Dbo::Dbo<User>
|
|||||||
Wt::Dbo::field(a, _audioEncoding, "audio_encoding");
|
Wt::Dbo::field(a, _audioEncoding, "audio_encoding");
|
||||||
// User's dynamic data
|
// User's dynamic data
|
||||||
Wt::Dbo::field(a, _curPlayingTrackPos, "cur_playing_track_pos");
|
Wt::Dbo::field(a, _curPlayingTrackPos, "cur_playing_track_pos");
|
||||||
Wt::Dbo::hasMany(a, _playlists, Wt::Dbo::ManyToOne, "user");
|
Wt::Dbo::hasMany(a, _tracklists, Wt::Dbo::ManyToOne, "user");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -112,7 +115,7 @@ class User : public Wt::Dbo::Dbo<User>
|
|||||||
// User's dynamic data
|
// User's dynamic data
|
||||||
int _curPlayingTrackPos; // Current track position in queue
|
int _curPlayingTrackPos; // Current track position in queue
|
||||||
|
|
||||||
Wt::Dbo::collection< Wt::Dbo::ptr<Playlist> > _playlists;
|
Wt::Dbo::collection< Wt::Dbo::ptr<TrackList> > _tracklists;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -419,9 +419,15 @@ LmsApplication::createHome()
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Events from the PlayQueue
|
// Events from the PlayQueue
|
||||||
playqueue->playTrack.connect(explore, &Explore::handleTrackPlayed);
|
playqueue->playTrack.connect([=](Database::IdType trackId)
|
||||||
|
{
|
||||||
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
|
LmsApp->getUser()->getPlayedTrackList().modify()->add(trackId);
|
||||||
|
});
|
||||||
|
playqueue->playTrack.connect(explore, &Explore::handleTrackPlayed);
|
||||||
playqueue->playTrack.connect(player, &MediaPlayer::playTrack);
|
playqueue->playTrack.connect(player, &MediaPlayer::playTrack);
|
||||||
|
|
||||||
playqueue->playbackStop.connect(player, &MediaPlayer::stop);
|
playqueue->playbackStop.connect(player, &MediaPlayer::stop);
|
||||||
|
|
||||||
// Events from MediaScanner
|
// Events from MediaScanner
|
||||||
|
|||||||
+37
-48
@@ -28,8 +28,7 @@
|
|||||||
|
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
|
|
||||||
#include "database/Playlist.hpp"
|
#include "database/TrackList.hpp"
|
||||||
#include "database/TrackStats.hpp"
|
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
@@ -63,7 +62,7 @@ PlayQueue::PlayQueue()
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
getPlaylist().modify()->shuffle();
|
getTrackList().modify()->shuffle();
|
||||||
}
|
}
|
||||||
_entriesContainer->clear();
|
_entriesContainer->clear();
|
||||||
addSome();
|
addSome();
|
||||||
@@ -76,15 +75,15 @@ PlayQueue::PlayQueue()
|
|||||||
|
|
||||||
LmsApp->preQuit().connect([=]
|
LmsApp->preQuit().connect([=]
|
||||||
{
|
{
|
||||||
if (_playlistId)
|
if (_tracklistId)
|
||||||
{
|
{
|
||||||
LMS_LOG(UI, DEBUG) << "Removing playlist id " << *_playlistId;
|
LMS_LOG(UI, DEBUG) << "Removing tracklist id " << *_tracklistId;
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
auto playlist = Database::Playlist::getById(LmsApp->getDboSession(), *_playlistId);
|
auto tracklist = Database::TrackList::getById(LmsApp->getDboSession(), *_tracklistId);
|
||||||
if (playlist)
|
if (tracklist)
|
||||||
playlist.remove();
|
tracklist.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -92,30 +91,26 @@ PlayQueue::PlayQueue()
|
|||||||
addSome();
|
addSome();
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::Playlist::pointer
|
Database::TrackList::pointer
|
||||||
PlayQueue::getPlaylist()
|
PlayQueue::getTrackList()
|
||||||
{
|
{
|
||||||
static const std::string currentPlayQueueName = "__current__playqueue__";
|
static const std::string currentPlayQueueName = "__current__playqueue__";
|
||||||
Database::Playlist::pointer res;
|
Database::TrackList::pointer res;
|
||||||
|
|
||||||
if (LmsApp->getUser()->isDemo())
|
if (LmsApp->getUser()->isDemo())
|
||||||
{
|
{
|
||||||
if (!_playlistId)
|
if (!_tracklistId)
|
||||||
{
|
{
|
||||||
res = Database::Playlist::create(LmsApp->getDboSession(), currentPlayQueueName, false, LmsApp->getUser());
|
res = Database::TrackList::create(LmsApp->getDboSession(), currentPlayQueueName, false, LmsApp->getUser());
|
||||||
LmsApp->getDboSession().flush();
|
LmsApp->getDboSession().flush();
|
||||||
_playlistId = res.id();
|
_tracklistId = res.id();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Database::Playlist::getById(LmsApp->getDboSession(), *_playlistId);
|
return Database::TrackList::getById(LmsApp->getDboSession(), *_tracklistId);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = Database::Playlist::get(LmsApp->getDboSession(), currentPlayQueueName, LmsApp->getUser());
|
return LmsApp->getUser()->getQueuedTrackList();
|
||||||
if (!res)
|
|
||||||
res = Database::Playlist::create(LmsApp->getDboSession(), currentPlayQueueName, false, LmsApp->getUser());
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -123,7 +118,7 @@ PlayQueue::clearTracks()
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
getPlaylist().modify()->clear();
|
getTrackList().modify()->clear();
|
||||||
_showMore->setHidden(true);
|
_showMore->setHidden(true);
|
||||||
_entriesContainer->clear();
|
_entriesContainer->clear();
|
||||||
updateInfo();
|
updateInfo();
|
||||||
@@ -146,29 +141,24 @@ PlayQueue::play(std::size_t pos)
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
auto playlist = getPlaylist();
|
auto tracklist = getTrackList();
|
||||||
|
|
||||||
// If out of range, stop playing
|
// If out of range, stop playing
|
||||||
if (pos >= playlist->getCount())
|
if (pos >= tracklist->getCount())
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If last and radio mode, fill the next song
|
// If last and radio mode, fill the next song
|
||||||
if (_radioMode->checkState() == Wt::CheckState::Checked && pos == playlist->getCount() - 1)
|
if (_radioMode->checkState() == Wt::CheckState::Checked && pos == tracklist->getCount() - 1)
|
||||||
addRadioTrack();
|
addRadioTrack();
|
||||||
|
|
||||||
_trackPos = pos;
|
_trackPos = pos;
|
||||||
auto track = playlist->getEntry(*_trackPos)->getTrack();
|
auto track = tracklist->getEntry(*_trackPos)->getTrack();
|
||||||
|
|
||||||
trackId = track.id();
|
trackId = track.id();
|
||||||
|
|
||||||
auto stats = Database::TrackStats::get(LmsApp->getDboSession(), track, LmsApp->getUser());
|
|
||||||
|
|
||||||
stats.modify()->incPlayCount();
|
|
||||||
stats.modify()->setLastPlayed(Wt::WLocalDateTime::currentServerDateTime().toUTC());
|
|
||||||
|
|
||||||
updateCurrentTrack(true);
|
updateCurrentTrack(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +194,7 @@ PlayQueue::updateInfo()
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
_nbTracks->setText(Wt::WString::tr("Lms.PlayQueue.nb-tracks").arg(static_cast<unsigned>(getPlaylist()->getCount())));
|
_nbTracks->setText(Wt::WString::tr("Lms.PlayQueue.nb-tracks").arg(static_cast<unsigned>(getTrackList()->getCount())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -229,10 +219,10 @@ PlayQueue::enqueueTracks(const std::vector<Database::Track::pointer>& tracks)
|
|||||||
// Use a "session" playqueue in order to store the current playqueue
|
// Use a "session" playqueue in order to store the current playqueue
|
||||||
// so that the user can disconnect and get its playqueue back
|
// so that the user can disconnect and get its playqueue back
|
||||||
|
|
||||||
auto playlist = getPlaylist();
|
auto tracklist = getTrackList();
|
||||||
|
|
||||||
for (auto track : tracks)
|
for (auto track : tracks)
|
||||||
Database::PlaylistEntry::create(LmsApp->getDboSession(), track, playlist);
|
Database::TrackListEntry::create(LmsApp->getDboSession(), track, tracklist);
|
||||||
|
|
||||||
updateInfo();
|
updateInfo();
|
||||||
addSome();
|
addSome();
|
||||||
@@ -269,14 +259,13 @@ PlayQueue::addSome()
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
|
||||||
|
|
||||||
auto playlist = getPlaylist();
|
auto tracklist = getTrackList();
|
||||||
|
|
||||||
bool moreResults;
|
auto tracklistEntries = tracklist->getEntries(_entriesContainer->count(), 50);
|
||||||
auto playlistEntries = playlist->getEntries(_entriesContainer->count(), 50, moreResults);
|
for (auto tracklistEntry : tracklistEntries)
|
||||||
for (auto playlistEntry : playlistEntries)
|
|
||||||
{
|
{
|
||||||
auto playlistEntryId = playlistEntry.id();
|
auto tracklistEntryId = tracklistEntry.id();
|
||||||
auto track = playlistEntry->getTrack();
|
auto track = tracklistEntry->getTrack();
|
||||||
|
|
||||||
Wt::WTemplate* entry = _entriesContainer->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.PlayQueue.template.entry"));
|
Wt::WTemplate* entry = _entriesContainer->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.PlayQueue.template.entry"));
|
||||||
|
|
||||||
@@ -310,7 +299,7 @@ PlayQueue::addSome()
|
|||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction (LmsApp->getDboSession());
|
||||||
|
|
||||||
auto entryToRemove = Database::PlaylistEntry::getById(LmsApp->getDboSession(), playlistEntryId);
|
auto entryToRemove = Database::TrackListEntry::getById(LmsApp->getDboSession(), tracklistEntryId);
|
||||||
entryToRemove.remove();
|
entryToRemove.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +317,7 @@ PlayQueue::addSome()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_showMore->setHidden(!moreResults);
|
_showMore->setHidden(static_cast<std::size_t>(_entriesContainer->count()) >= tracklist->getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -337,17 +326,17 @@ PlayQueue::addRadioTrack()
|
|||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
std::mt19937 randGenerator(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
|
std::mt19937 randGenerator(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
|
||||||
|
|
||||||
auto playlist = getPlaylist();
|
auto tracklist = getTrackList();
|
||||||
|
|
||||||
std::set<Database::IdType> playlistTrackIds;
|
std::set<Database::IdType> trackIds;
|
||||||
{
|
{
|
||||||
auto ids = playlist->getTrackIds();
|
auto ids = tracklist->getTrackIds();
|
||||||
playlistTrackIds = std::set<Database::IdType>(ids.begin(), ids.end());
|
trackIds = std::set<Database::IdType>(ids.begin(), ids.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all the tracks of the playlist, get the cluster that is mostly used
|
// Get all the tracks of the tracklist, get the cluster that is mostly used
|
||||||
// and reuse it to get the next track
|
// and reuse it to get the next track
|
||||||
auto clusters = playlist->getClusters();
|
auto clusters = tracklist->getClusters();
|
||||||
if (clusters.empty())
|
if (clusters.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -357,7 +346,7 @@ PlayQueue::addRadioTrack()
|
|||||||
|
|
||||||
std::set<Database::IdType> candidateTrackIds;
|
std::set<Database::IdType> candidateTrackIds;
|
||||||
std::set_difference(clusterTrackIds.begin(), clusterTrackIds.end(),
|
std::set_difference(clusterTrackIds.begin(), clusterTrackIds.end(),
|
||||||
playlistTrackIds.begin(), playlistTrackIds.end(),
|
trackIds.begin(), trackIds.end(),
|
||||||
std::inserter(candidateTrackIds, candidateTrackIds.end()));
|
std::inserter(candidateTrackIds, candidateTrackIds.end()));
|
||||||
|
|
||||||
if (candidateTrackIds.empty())
|
if (candidateTrackIds.empty())
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "database/Playlist.hpp"
|
#include "database/TrackList.hpp"
|
||||||
#include "database/Track.hpp"
|
#include "database/Track.hpp"
|
||||||
|
|
||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
@@ -53,7 +53,7 @@ class PlayQueue : public Wt::WTemplate
|
|||||||
Wt::Signal<> playbackStop;
|
Wt::Signal<> playbackStop;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Database::Playlist::pointer getPlaylist();
|
Database::TrackList::pointer getTrackList();
|
||||||
|
|
||||||
void clearTracks();
|
void clearTracks();
|
||||||
void enqueueTracks(const std::vector<Database::Track::pointer>& tracks);
|
void enqueueTracks(const std::vector<Database::Track::pointer>& tracks);
|
||||||
@@ -66,7 +66,7 @@ class PlayQueue : public Wt::WTemplate
|
|||||||
void play(std::size_t pos);
|
void play(std::size_t pos);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
boost::optional<Database::IdType> _playlistId;
|
boost::optional<Database::IdType> _tracklistId;
|
||||||
Wt::WCheckBox* _radioMode;
|
Wt::WCheckBox* _radioMode;
|
||||||
Wt::WContainerWidget* _entriesContainer;
|
Wt::WContainerWidget* _entriesContainer;
|
||||||
Wt::WTemplate* _showMore;
|
Wt::WTemplate* _showMore;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <Wt/WText.h>
|
#include <Wt/WText.h>
|
||||||
|
|
||||||
#include "database/Artist.hpp"
|
#include "database/Artist.hpp"
|
||||||
#include "database/Setting.hpp"
|
|
||||||
|
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
#include "utils/Utils.hpp"
|
#include "utils/Utils.hpp"
|
||||||
|
|||||||
@@ -25,8 +25,7 @@
|
|||||||
#include <Wt/WTemplate.h>
|
#include <Wt/WTemplate.h>
|
||||||
|
|
||||||
#include "database/Artist.hpp"
|
#include "database/Artist.hpp"
|
||||||
#include "database/Setting.hpp"
|
#include "database/TrackList.hpp"
|
||||||
#include "database/TrackStats.hpp"
|
|
||||||
|
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
#include "utils/Utils.hpp"
|
#include "utils/Utils.hpp"
|
||||||
@@ -80,7 +79,6 @@ Artists::Artists(Filters* filters)
|
|||||||
refresh();
|
refresh();
|
||||||
refreshMostPlayed();
|
refreshMostPlayed();
|
||||||
refreshRecentlyAdded();
|
refreshRecentlyAdded();
|
||||||
refreshRecentlyPlayed();
|
|
||||||
|
|
||||||
filters->updated().connect(this, &Artists::refresh);
|
filters->updated().connect(this, &Artists::refresh);
|
||||||
}
|
}
|
||||||
@@ -97,22 +95,11 @@ Artists::refreshRecentlyAdded()
|
|||||||
addCompactEntries(_recentlyAddedContainer, artists);
|
addCompactEntries(_recentlyAddedContainer, artists);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Artists::refreshRecentlyPlayed()
|
|
||||||
{
|
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
|
||||||
auto artists = TrackStats::getLastPlayedArtists(LmsApp->getDboSession(), LmsApp->getUser(), 5);
|
|
||||||
|
|
||||||
_recentlyPlayedContainer->clear();
|
|
||||||
addCompactEntries(_recentlyPlayedContainer, artists);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Artists::refreshMostPlayed()
|
Artists::refreshMostPlayed()
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
auto artists = TrackStats::getMostPlayedArtists(LmsApp->getDboSession(), LmsApp->getUser(), 5);
|
auto artists = LmsApp->getUser()->getPlayedTrackList()->getTopArtists(5);
|
||||||
|
|
||||||
_mostPlayedContainer->clear();
|
_mostPlayedContainer->clear();
|
||||||
addCompactEntries(_mostPlayedContainer, artists);
|
addCompactEntries(_mostPlayedContainer, artists);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class Artists : public Wt::WTemplate
|
|||||||
Wt::Signal<Database::IdType> artistPlay;
|
Wt::Signal<Database::IdType> artistPlay;
|
||||||
|
|
||||||
void refreshRecentlyAdded();
|
void refreshRecentlyAdded();
|
||||||
void refreshRecentlyPlayed();
|
|
||||||
void refreshMostPlayed();
|
void refreshMostPlayed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -113,10 +113,7 @@ Explore::Explore()
|
|||||||
_trackPlayed.connect([=]
|
_trackPlayed.connect([=]
|
||||||
{
|
{
|
||||||
artists_raw->refreshMostPlayed();
|
artists_raw->refreshMostPlayed();
|
||||||
artists_raw->refreshRecentlyPlayed();
|
|
||||||
releases_raw->refreshMostPlayed();
|
releases_raw->refreshMostPlayed();
|
||||||
releases_raw->refreshRecentlyPlayed();
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto tracks = std::make_unique<Tracks>(_filters);
|
auto tracks = std::make_unique<Tracks>(_filters);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <Wt/WTemplate.h>
|
#include <Wt/WTemplate.h>
|
||||||
|
|
||||||
#include "database/Release.hpp"
|
#include "database/Release.hpp"
|
||||||
#include "database/TrackStats.hpp"
|
#include "database/TrackList.hpp"
|
||||||
|
|
||||||
#include "utils/Logger.hpp"
|
#include "utils/Logger.hpp"
|
||||||
#include "utils/Utils.hpp"
|
#include "utils/Utils.hpp"
|
||||||
@@ -96,7 +96,6 @@ _filters(filters)
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
refreshRecentlyAdded();
|
refreshRecentlyAdded();
|
||||||
refreshRecentlyPlayed();
|
|
||||||
refreshMostPlayed();
|
refreshMostPlayed();
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
@@ -106,8 +105,6 @@ _filters(filters)
|
|||||||
void
|
void
|
||||||
Releases::refreshRecentlyAdded()
|
Releases::refreshRecentlyAdded()
|
||||||
{
|
{
|
||||||
LMS_LOG(UI, DEBUG) << "Refreshing recently added releases";
|
|
||||||
|
|
||||||
auto after = Wt::WLocalDateTime::currentServerDateTime().toUTC().addMonths(-1);
|
auto after = Wt::WLocalDateTime::currentServerDateTime().toUTC().addMonths(-1);
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
@@ -118,27 +115,12 @@ Releases::refreshRecentlyAdded()
|
|||||||
addCompactEntries(_recentlyAddedContainer, releases);
|
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->getUser(), 5);
|
|
||||||
|
|
||||||
_recentlyPlayedContainer->clear();
|
|
||||||
addCompactEntries(_recentlyPlayedContainer, releases);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Releases::refreshMostPlayed()
|
Releases::refreshMostPlayed()
|
||||||
{
|
{
|
||||||
LMS_LOG(UI, DEBUG) << "Refreshing most played releases";
|
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
|
||||||
|
|
||||||
auto releases = TrackStats::getMostPlayedReleases(LmsApp->getDboSession(), LmsApp->getUser(), 5);
|
auto releases = LmsApp->getUser()->getPlayedTrackList()->getTopReleases(5);
|
||||||
|
|
||||||
_mostPlayedContainer->clear();
|
_mostPlayedContainer->clear();
|
||||||
addCompactEntries(_mostPlayedContainer, releases);
|
addCompactEntries(_mostPlayedContainer, releases);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class Releases : public Wt::WTemplate
|
|||||||
Wt::Signal<Database::IdType> releasePlay;
|
Wt::Signal<Database::IdType> releasePlay;
|
||||||
|
|
||||||
void refreshRecentlyAdded();
|
void refreshRecentlyAdded();
|
||||||
void refreshRecentlyPlayed();
|
|
||||||
void refreshMostPlayed();
|
void refreshMostPlayed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user