Added an played tracklist

This commit is contained in:
emeric
2018-08-03 14:01:56 +02:00
parent 5c182f2868
commit a7e279ce42
23 changed files with 360 additions and 727 deletions
+4 -9
View File
@@ -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);
-208
View File
@@ -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
-133
View File
@@ -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
-71
View File
@@ -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
+2 -4
View File
@@ -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;
};
+238
View File
@@ -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
-101
View File
@@ -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
-75
View File
@@ -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
+34
View File
@@ -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
+6 -3
View File
@@ -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;
};