Added an played tracklist
This commit is contained in:
@@ -31,17 +31,14 @@
|
||||
#include <Wt/Auth/PasswordStrengthValidator.h>
|
||||
#include <Wt/Auth/PasswordVerifier.h>
|
||||
|
||||
#include "Setting.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
#include "Artist.hpp"
|
||||
#include "Cluster.hpp"
|
||||
#include "Playlist.hpp"
|
||||
#include "TrackList.hpp"
|
||||
#include "Release.hpp"
|
||||
#include "ScanSettings.hpp"
|
||||
#include "Track.hpp"
|
||||
#include "TrackStats.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
@@ -102,12 +99,10 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||
_session.mapClass<Artist>("artist");
|
||||
_session.mapClass<Cluster>("cluster");
|
||||
_session.mapClass<ClusterType>("cluster_type");
|
||||
_session.mapClass<Playlist>("playlist");
|
||||
_session.mapClass<PlaylistEntry>("playlist_entry");
|
||||
_session.mapClass<TrackList>("tracklist");
|
||||
_session.mapClass<TrackListEntry>("tracklist_entry");
|
||||
_session.mapClass<Release>("release");
|
||||
_session.mapClass<Setting>("setting");
|
||||
_session.mapClass<Track>("track");
|
||||
_session.mapClass<TrackStats>("track_stats");
|
||||
|
||||
_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 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 settings_name_idx ON setting(name)");
|
||||
_session.execute("CREATE INDEX IF NOT EXISTS tracklist_name ON tracklist(name)");
|
||||
}
|
||||
|
||||
_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 Cluster;
|
||||
class ClusterType;
|
||||
class PlaylistEntry;
|
||||
class TrackListEntry;
|
||||
class Release;
|
||||
class TrackStats;
|
||||
|
||||
@@ -144,7 +144,6 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
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, _playlistEntries, Wt::Dbo::ManyToOne, "track");
|
||||
Wt::Dbo::hasMany(a, _stats, Wt::Dbo::ManyToOne, "track");
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -173,8 +172,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
Wt::Dbo::ptr<Artist> _artist;
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<PlaylistEntry>> _playlistEntries;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackStats>> _stats;
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _playlistEntries;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
class PlaylistEntry;
|
||||
class Artist;
|
||||
class Release;
|
||||
class User;
|
||||
class Track;
|
||||
class TrackListEntry;
|
||||
class Cluster;
|
||||
|
||||
class Playlist : public Wt::Dbo::Dbo<Playlist>
|
||||
class TrackList : public Wt::Dbo::Dbo<TrackList>
|
||||
{
|
||||
public:
|
||||
using pointer = Wt::Dbo::ptr<Playlist>;
|
||||
using pointer = Wt::Dbo::ptr<TrackList>;
|
||||
|
||||
Playlist();
|
||||
Playlist(std::string name, bool isPublic, Wt::Dbo::ptr<User> user);
|
||||
TrackList();
|
||||
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
|
||||
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);
|
||||
|
||||
// Create utility
|
||||
@@ -53,14 +59,14 @@ class Playlist : public Wt::Dbo::Dbo<Playlist>
|
||||
bool isPublic() const { return _isPublic; }
|
||||
|
||||
// Modifiers
|
||||
Wt::Dbo::ptr<TrackListEntry> add(IdType trackId);
|
||||
void clear() { _entries.clear(); }
|
||||
void shuffle();
|
||||
|
||||
// Get tracks, ordered by position
|
||||
std::size_t getCount() const;
|
||||
Wt::Dbo::ptr<PlaylistEntry> 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<PlaylistEntry>> getAllEntries() const;
|
||||
Wt::Dbo::ptr<TrackListEntry> getEntry(std::size_t pos) const;
|
||||
std::vector<Wt::Dbo::ptr<TrackListEntry>> getEntries(int offset = -1, int size = -1) 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, _isPublic, "public");
|
||||
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:
|
||||
@@ -83,23 +89,23 @@ class Playlist : public Wt::Dbo::Dbo<Playlist>
|
||||
std::string _name;
|
||||
bool _isPublic;
|
||||
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:
|
||||
|
||||
using pointer = Wt::Dbo::ptr<PlaylistEntry>;
|
||||
using pointer = Wt::Dbo::ptr<TrackListEntry>;
|
||||
|
||||
PlaylistEntry();
|
||||
PlaylistEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<Playlist> playlist);
|
||||
TrackListEntry();
|
||||
TrackListEntry(Wt::Dbo::ptr<Track> track, Wt::Dbo::ptr<TrackList> tracklist);
|
||||
|
||||
static pointer getById(Wt::Dbo::Session& session, IdType id);
|
||||
|
||||
// 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
|
||||
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
||||
@@ -108,13 +114,13 @@ class PlaylistEntry
|
||||
void persist(Action& a)
|
||||
{
|
||||
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:
|
||||
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
Wt::Dbo::ptr<Playlist> _playlist;
|
||||
Wt::Dbo::ptr<TrackList> _tracklist;
|
||||
};
|
||||
|
||||
} // 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 "TrackList.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
// must be ordered
|
||||
@@ -93,6 +95,38 @@ User::getMaxAudioBitrate(void) const
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Database {
|
||||
class User;
|
||||
using AuthInfo = Wt::Auth::Dbo::AuthInfo<User>;
|
||||
|
||||
class Playlist;
|
||||
class TrackList;
|
||||
|
||||
// User selectable audio formats
|
||||
enum class AudioEncoding
|
||||
@@ -85,6 +85,9 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
std::size_t getMaxAudioBitrate() const;
|
||||
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
|
||||
|
||||
Wt::Dbo::ptr<TrackList> getQueuedTrackList() const;
|
||||
Wt::Dbo::ptr<TrackList> getPlayedTrackList() const;
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
@@ -94,7 +97,7 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
Wt::Dbo::field(a, _audioEncoding, "audio_encoding");
|
||||
// User's dynamic data
|
||||
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:
|
||||
@@ -112,7 +115,7 @@ class User : public Wt::Dbo::Dbo<User>
|
||||
// User's dynamic data
|
||||
int _curPlayingTrackPos; // Current track position in queue
|
||||
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Playlist> > _playlists;
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<TrackList> > _tracklists;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user