167 lines
7.6 KiB
C++
167 lines
7.6 KiB
C++
#pragma once
|
|
|
|
#include <sql/SqlQuery.h>
|
|
#include <Properties.h>
|
|
#include <shared_mutex>
|
|
#include <atomic>
|
|
#include <teaspeak/MusicPlayer.h>
|
|
#include <query/command3.h>
|
|
#include "MusicBotManager.h"
|
|
#include "PlaylistPermissions.h"
|
|
|
|
namespace ts {
|
|
namespace server {
|
|
class ConnectedClient;
|
|
}
|
|
|
|
namespace permission {
|
|
class PermissionManager;
|
|
}
|
|
|
|
namespace music {
|
|
class Playlist;
|
|
|
|
struct PlaylistEntryInfo {
|
|
typedef threads::Future<std::shared_ptr<::music::UrlInfo>> load_future_t;
|
|
SongId previous_song_id = 0;
|
|
|
|
ClientDbId invoker = 0;
|
|
SongId id = 0;
|
|
|
|
std::string url;
|
|
std::string url_loader;
|
|
std::string metadata; /* only present when loaded */
|
|
bool loaded = false;
|
|
|
|
std::chrono::system_clock::time_point load_start;
|
|
std::unique_ptr<load_future_t> load_future;
|
|
|
|
struct {
|
|
bool successfully_loaded;
|
|
} data;
|
|
};
|
|
|
|
class PlaylistEntry {
|
|
friend class Playlist;
|
|
public:
|
|
/* linking for the list */
|
|
std::shared_ptr<PlaylistEntry> previous_song;
|
|
std::shared_ptr<PlaylistEntry> next_song;
|
|
|
|
/* the entry */
|
|
std::shared_ptr<PlaylistEntryInfo> entry;
|
|
|
|
bool modified = false;
|
|
private:
|
|
inline void set_previous_song(const std::shared_ptr<PlaylistEntry>& song) {
|
|
assert(this->entry);
|
|
|
|
this->previous_song = song;
|
|
this->entry->previous_song_id = song ? song->entry->id : 0;
|
|
this->modified = true;
|
|
}
|
|
};
|
|
|
|
//TODO add some kind of play history?
|
|
class Playlist : public PlaylistPermissions {
|
|
friend class MusicBotManager;
|
|
public:
|
|
struct Type {
|
|
enum value {
|
|
BOT_BOUND,
|
|
GENERAL
|
|
};
|
|
};
|
|
|
|
Playlist(const std::shared_ptr<MusicBotManager>& /* manager */, const std::shared_ptr<Properties>& /* properties */, std::shared_ptr<permission::v2::PermissionManager> /* permissions */);
|
|
virtual ~Playlist();
|
|
|
|
virtual void load_songs();
|
|
inline bool loaded() { return this->_songs_loaded; };
|
|
|
|
virtual std::deque<std::shared_ptr<PlaylistEntryInfo>> list_songs();
|
|
virtual std::shared_ptr<PlaylistEntryInfo> find_song(SongId /* song */);
|
|
virtual std::shared_ptr<PlaylistEntryInfo> add_song(const std::shared_ptr<server::ConnectedClient>& /* invoker */, const std::string& /* url */, const std::string& /* url loader */, SongId /* previous */ = 0);
|
|
virtual std::shared_ptr<PlaylistEntryInfo> add_song(ClientDbId /* invoker */, const std::string& /* url */, const std::string& /* url loader */, SongId /* previous */ = 0);
|
|
virtual bool delete_song(SongId /* song */);
|
|
virtual bool reorder_song(SongId /* song */, SongId /* new id */);
|
|
|
|
inline Properties& properties() const { return *this->_properties; }
|
|
|
|
inline PlaylistId playlist_id() {
|
|
return this->properties()[property::PLAYLIST_ID].as<PlaylistId>();
|
|
}
|
|
|
|
inline Type::value playlist_type() {
|
|
return this->properties()[property::PLAYLIST_TYPE].as<Type::value>();
|
|
}
|
|
|
|
inline int32_t max_songs() {
|
|
return this->properties()[property::PLAYLIST_MAX_SONGS];
|
|
}
|
|
|
|
inline std::shared_ptr<MusicBotManager> ref_handle() { return this->manager.lock(); }
|
|
|
|
template <typename T = Playlist, typename std::enable_if<std::is_base_of<Playlist, T>::value, int>::type = 0>
|
|
inline std::shared_ptr<Playlist> ref() { return std::dynamic_pointer_cast<T>(this->_self.lock()); }
|
|
|
|
|
|
void add_subscriber(const std::shared_ptr<server::ConnectedClient>&);
|
|
void remove_subscriber(const std::shared_ptr<server::ConnectedClient>&);
|
|
bool is_subscriber(const std::shared_ptr<server::ConnectedClient>&);
|
|
protected:
|
|
virtual void set_self_ref(const std::shared_ptr<Playlist>& /* playlist */);
|
|
bool is_playlist_owner(ClientDbId database_id) const override { return this->properties()[property::PLAYLIST_OWNER_DBID].as_save<ClientDbId>() == database_id; }
|
|
|
|
std::atomic<SongId> current_id;
|
|
std::shared_ptr<Properties> _properties;
|
|
std::weak_ptr<MusicBotManager> manager;
|
|
std::weak_ptr<Playlist> _self;
|
|
bool _songs_loaded = false;
|
|
|
|
sql::SqlManager* get_sql();
|
|
std::shared_ptr<server::VirtualServer> get_server();
|
|
ServerId get_server_id();
|
|
|
|
std::shared_mutex playlist_lock{};
|
|
std::shared_ptr<PlaylistEntry> playlist_head{};
|
|
|
|
std::mutex subscriber_lock{};
|
|
std::deque<std::weak_ptr<server::ConnectedClient>> subscribers{};
|
|
|
|
virtual std::deque<std::shared_ptr<PlaylistEntryInfo>> _list_songs(const std::unique_lock<std::shared_mutex>& /* playlist lock */);
|
|
|
|
/* playlist functions are threadsave */
|
|
std::shared_ptr<PlaylistEntry> playlist_find(const std::unique_lock<std::shared_mutex>& /* playlist lock */, SongId /* song */);
|
|
std::shared_ptr<PlaylistEntry> playlist_end(const std::unique_lock<std::shared_mutex> &);
|
|
bool playlist_insert(
|
|
const std::unique_lock<std::shared_mutex>& /* playlist lock */,
|
|
const std::shared_ptr<PlaylistEntry>& /* song */,
|
|
std::shared_ptr<PlaylistEntry> /* previous */ = nullptr,
|
|
bool link_only = false
|
|
);
|
|
bool playlist_remove(const std::unique_lock<std::shared_mutex>& /* playlist lock */, const std::shared_ptr<PlaylistEntry>& /* song */);
|
|
bool playlist_reorder(const std::unique_lock<std::shared_mutex>& /* playlist lock */, const std::shared_ptr<PlaylistEntry>& /* song */, std::shared_ptr<PlaylistEntry> /* previous */ = nullptr);
|
|
|
|
std::deque<std::shared_ptr<PlaylistEntryInfo>> load_entries();
|
|
bool build_tree(std::deque<std::shared_ptr<PlaylistEntryInfo>> /* entries */);
|
|
void destroy_tree();
|
|
|
|
bool sql_remove(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
bool sql_add(const std::shared_ptr<PlaylistEntryInfo>& /* entry */); /* also assigns an ID */
|
|
bool sql_apply_changes(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
bool sql_flush_all_changes();
|
|
|
|
void broadcast_notify(const command_builder& /* command */);
|
|
bool notify_song_add(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
bool notify_song_remove(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
bool notify_song_reorder(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
bool notify_song_loaded(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
|
|
void enqueue_load(const std::shared_ptr<PlaylistEntryInfo>& /* entry */);
|
|
void execute_async_load(const std::shared_ptr<ts::music::PlaylistEntryInfo> &/* entry */);
|
|
};
|
|
}
|
|
}
|
|
|
|
DEFINE_TRANSFORMS(ts::music::Playlist::Type::value, uint8_t); |