Some minor changes
This commit is contained in:
parent
c6ed584d97
commit
25504abe7e
@ -9,7 +9,7 @@ set(TEASPEAK_SERVER ON)
|
|||||||
#end now
|
#end now
|
||||||
#set(MEMORY_DEBUG_FLAGS " -fsanitize=leak -fsanitize=address -fstack-protector-all ")
|
#set(MEMORY_DEBUG_FLAGS " -fsanitize=leak -fsanitize=address -fstack-protector-all ")
|
||||||
#set(MEMORY_DEBUG_FLAGS "-fsanitize=address -fstack-protector-all")
|
#set(MEMORY_DEBUG_FLAGS "-fsanitize=address -fstack-protector-all")
|
||||||
set(MEMORY_DEBUG_FLAGS "-fstack-protector-all")
|
#set(MEMORY_DEBUG_FLAGS "-fstack-protector-all")
|
||||||
|
|
||||||
if (NOT BUILD_OS_ARCH)
|
if (NOT BUILD_OS_ARCH)
|
||||||
set(BUILD_OS_ARCH $ENV{build_os_arch})
|
set(BUILD_OS_ARCH $ENV{build_os_arch})
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 3a9c5359719d893a35646191389c17338460535a
|
Subproject commit 8e90036a3759183ee4d620a5ec294167dec8eece
|
@ -309,7 +309,7 @@ namespace ts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool playlist_subscribed(const std::shared_ptr<ts::music::Playlist>& playlist) const {
|
inline bool playlist_subscribed(const std::shared_ptr<ts::music::Playlist>& playlist) const {
|
||||||
return this->_subscribed_playlist.lock() == playlist;
|
return this->subscribed_playlist_.lock() == playlist;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
std::weak_ptr<ConnectedClient> _this;
|
std::weak_ptr<ConnectedClient> _this;
|
||||||
@ -378,7 +378,7 @@ namespace ts {
|
|||||||
|
|
||||||
std::weak_ptr<MusicClient> selectedBot;
|
std::weak_ptr<MusicClient> selectedBot;
|
||||||
std::weak_ptr<MusicClient> subscribed_bot;
|
std::weak_ptr<MusicClient> subscribed_bot;
|
||||||
std::weak_ptr<ts::music::Playlist> _subscribed_playlist{};
|
std::weak_ptr<ts::music::Playlist> subscribed_playlist_{};
|
||||||
|
|
||||||
bool loadDataForCurrentServer() override;
|
bool loadDataForCurrentServer() override;
|
||||||
|
|
||||||
@ -541,7 +541,7 @@ namespace ts {
|
|||||||
|
|
||||||
command_result handleCommandMusicBotQueueList(Command&);
|
command_result handleCommandMusicBotQueueList(Command&);
|
||||||
command_result handleCommandMusicBotQueueAdd(Command&);
|
command_result handleCommandMusicBotQueueAdd(Command&);
|
||||||
command_result handleCommandMusicBotQueueRemove(Command&);
|
command_result handleCommandMusicBotQcueueRemove(Command&);
|
||||||
command_result handleCommandMusicBotQueueReorder(Command&);
|
command_result handleCommandMusicBotQueueReorder(Command&);
|
||||||
|
|
||||||
command_result handleCommandMusicBotPlaylistAssign(Command&);
|
command_result handleCommandMusicBotPlaylistAssign(Command&);
|
||||||
|
@ -2866,6 +2866,7 @@ command_result ConnectedClient::handleCommandListFeatureSupport(ts::Command &cmd
|
|||||||
REGISTER_FEATURE("log-query", FeatureSupportMode::FULL, 1);
|
REGISTER_FEATURE("log-query", FeatureSupportMode::FULL, 1);
|
||||||
REGISTER_FEATURE("whisper-echo", FeatureSupportMode::FULL, 1);
|
REGISTER_FEATURE("whisper-echo", FeatureSupportMode::FULL, 1);
|
||||||
REGISTER_FEATURE("video", FeatureSupportMode::EXPERIMENTAL, 1);
|
REGISTER_FEATURE("video", FeatureSupportMode::EXPERIMENTAL, 1);
|
||||||
|
REGISTER_FEATURE("sidebar-mode", FeatureSupportMode::FULL, 1);
|
||||||
|
|
||||||
this->sendCommand(notify);
|
this->sendCommand(notify);
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
|
@ -284,11 +284,13 @@ command_result ConnectedClient::handleCommandMusicBotPlayerAction(Command& cmd)
|
|||||||
bot->rewindSong();
|
bot->rewindSong();
|
||||||
} else if(cmd["action"] == 5) {
|
} else if(cmd["action"] == 5) {
|
||||||
if(!player) return command_result{error::music_no_player};
|
if(!player) return command_result{error::music_no_player};
|
||||||
player->forward(::music::PlayerUnits(cmd["units"].as<int64_t>()));
|
player->forward(::music::PlayerUnits{(int64_t) cmd["units"].as<uint64_t>()});
|
||||||
} else if(cmd["action"] == 6) {
|
} else if(cmd["action"] == 6) {
|
||||||
if(!player) return command_result{error::music_no_player};
|
if(!player) return command_result{error::music_no_player};
|
||||||
player->rewind(::music::PlayerUnits(cmd["units"].as<int64_t>()));
|
player->rewind(::music::PlayerUnits{(int64_t) cmd["units"].as<uint64_t>()});
|
||||||
} else return command_result{error::music_invalid_action};
|
} else {
|
||||||
|
return command_result{error::music_invalid_action};
|
||||||
|
}
|
||||||
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
}
|
}
|
||||||
@ -799,7 +801,7 @@ inline void fill_song_info(ts::command_builder_bulk bulk, const std::shared_ptr<
|
|||||||
if(extract_metadata && song->metadata.is_loaded() && metadata) {
|
if(extract_metadata && song->metadata.is_loaded() && metadata) {
|
||||||
bulk.put("song_metadata_title", metadata->title);
|
bulk.put("song_metadata_title", metadata->title);
|
||||||
bulk.put("song_metadata_description", metadata->description);
|
bulk.put("song_metadata_description", metadata->description);
|
||||||
bulk.put("song_metadata_url", metadata->url);
|
bulk.put("song_metadata_url", metadata->url); /* Internally resolved URL. Should not be externally used */
|
||||||
bulk.put("song_metadata_length", metadata->length.count());
|
bulk.put("song_metadata_length", metadata->length.count());
|
||||||
if(auto thumbnail = static_pointer_cast<::music::ThumbnailUrl>(metadata->thumbnail); thumbnail && thumbnail->type() == ::music::THUMBNAIL_URL) {
|
if(auto thumbnail = static_pointer_cast<::music::ThumbnailUrl>(metadata->thumbnail); thumbnail && thumbnail->type() == ::music::THUMBNAIL_URL) {
|
||||||
bulk.put("song_metadata_thumbnail_url", thumbnail->url());
|
bulk.put("song_metadata_thumbnail_url", thumbnail->url());
|
||||||
@ -836,7 +838,7 @@ command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd)
|
|||||||
}
|
}
|
||||||
fill_song_info(result.bulk(index), song, extract_metadata);
|
fill_song_info(result.bulk(index), song, extract_metadata);
|
||||||
|
|
||||||
if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK && result.current_size() + estimated_song_info_size(song, extract_metadata) > 128 * 1024) {
|
if(this->getType() != ClientType::CLIENT_QUERY && result.current_size() + estimated_song_info_size(song, extract_metadata) > 64 * 1024) {
|
||||||
this->sendCommand(result);
|
this->sendCommand(result);
|
||||||
result.reset();
|
result.reset();
|
||||||
index = 0;
|
index = 0;
|
||||||
@ -844,9 +846,13 @@ command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd)
|
|||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(index > 0)
|
|
||||||
|
if(index > 0) {
|
||||||
this->sendCommand(result);
|
this->sendCommand(result);
|
||||||
if(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK) {
|
}
|
||||||
|
|
||||||
|
/* This step is actiually not really needed... */
|
||||||
|
if(this->getType() != ClientType::CLIENT_QUERY) {
|
||||||
ts::command_builder finish{"notifyplaylistsonglistfinished"};
|
ts::command_builder finish{"notifyplaylistsonglistfinished"};
|
||||||
finish.put(0, "playlist_id", playlist->playlist_id());
|
finish.put(0, "playlist_id", playlist->playlist_id());
|
||||||
this->sendCommand(finish);
|
this->sendCommand(finish);
|
||||||
@ -1137,8 +1143,9 @@ command_result ConnectedClient::handleCommandMusicBotPlaylistAssign(ts::Command
|
|||||||
|
|
||||||
auto bot = ref_server->music_manager_->findBotById(cmd["bot_id"]);
|
auto bot = ref_server->music_manager_->findBotById(cmd["bot_id"]);
|
||||||
if(!bot) return command_result{error::music_invalid_id};
|
if(!bot) return command_result{error::music_invalid_id};
|
||||||
if(bot->getOwner() != this->getClientDatabaseId())
|
if(bot->getOwner() != this->getClientDatabaseId()) {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_music_play_power, bot->calculate_permission(permission::i_client_music_needed_play_power, 0));
|
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_music_play_power, bot->calculate_permission(permission::i_client_music_needed_play_power, 0));
|
||||||
|
}
|
||||||
|
|
||||||
auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]);
|
auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]);
|
||||||
if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id};
|
if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id};
|
||||||
@ -1163,20 +1170,24 @@ command_result ConnectedClient::handleCommandPlaylistSetSubscription(ts::Command
|
|||||||
if(!config::music::enabled) return command_result{error::music_disabled};
|
if(!config::music::enabled) return command_result{error::music_disabled};
|
||||||
|
|
||||||
auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]);
|
auto playlist = ref_server->music_manager_->find_playlist(cmd["playlist_id"]);
|
||||||
if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id};
|
if(!playlist && cmd["playlist_id"] != 0) {
|
||||||
|
return command_result{error::playlist_invalid_id};
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto old_playlist = this->_subscribed_playlist.lock();
|
auto old_playlist = this->subscribed_playlist_.lock();
|
||||||
if(old_playlist)
|
if(old_playlist) {
|
||||||
old_playlist->remove_subscriber(_this.lock());
|
old_playlist->remove_subscriber(_this.lock());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(playlist) {
|
if(playlist) {
|
||||||
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr)
|
if(auto perr = playlist->client_has_permissions(this->ref(), permission::i_playlist_needed_view_power, permission::i_playlist_view_power); perr) {
|
||||||
return command_result{perr};
|
return command_result{perr};
|
||||||
|
}
|
||||||
|
|
||||||
playlist->add_subscriber(_this.lock());
|
playlist->add_subscriber(_this.lock());
|
||||||
this->_subscribed_playlist = playlist;
|
this->subscribed_playlist_ = playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
return command_result{error::ok};
|
return command_result{error::ok};
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include "MusicQueue.h"
|
|
||||||
#include "MusicClient.h"
|
|
||||||
|
|
||||||
using namespace ts;
|
|
||||||
using namespace ts::server;
|
|
||||||
using namespace ts::music;
|
|
||||||
using namespace ::music;
|
|
||||||
using namespace std;
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
MusicQueue::MusicQueue(ts::server::MusicClient* self) {
|
|
||||||
this->handle = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
MusicQueue::~MusicQueue() {}
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> MusicQueue::currentSong() {
|
|
||||||
return this->current;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MusicQueue::notifySongEnded() {
|
|
||||||
if(this->currentSong()) {
|
|
||||||
this->getNextSong();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MusicQueue::notifySongAbort() {
|
|
||||||
this->getNextSong(); //TODO retry count!
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> MusicQueue::rewind() {
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
|
|
||||||
if(this->current)
|
|
||||||
this->queue.push_front(std::move(this->current));
|
|
||||||
if(!this->_history.empty()) {
|
|
||||||
this->current = dynamic_pointer_cast<PlayableSong>(this->_history.front());
|
|
||||||
this->_history.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->current;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> MusicQueue::getNextSong() {
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
if(this->current) {
|
|
||||||
this->_history.push_front(this->current);
|
|
||||||
for(int index = 10; index < this->_history.size(); index++) { //Last ten songs full cache!
|
|
||||||
if(!dynamic_pointer_cast<PlayableSong>(this->_history[index])) break;
|
|
||||||
|
|
||||||
auto element = this->_history[index];
|
|
||||||
this->_history[index] = make_shared<MusicHistoryEntry>(element->getUrl(), element->getInvoker(), element->getSongId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this->queue.empty()) this->current = nullptr;
|
|
||||||
else {
|
|
||||||
this->current = this->queue.front();
|
|
||||||
this->queue.pop_front();
|
|
||||||
}
|
|
||||||
return this->current;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> MusicQueue::find_queue(ts::SongId id) {
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
for(const auto& element : this->queue)
|
|
||||||
if(element->getSongId() == id)
|
|
||||||
return element;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SongInfo> MusicQueue::find(ts::SongId id) {
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
for(const auto& element : this->queue)
|
|
||||||
if(element->getSongId() == id)
|
|
||||||
return element;
|
|
||||||
for(const auto& element : this->_history)
|
|
||||||
if(element->getSongId() == id)
|
|
||||||
return element;
|
|
||||||
if(this->current && this->current->getSongId() == id)
|
|
||||||
return this->current;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<std::shared_ptr<PlayableSong>> MusicQueue::queueEntries() {
|
|
||||||
return this->queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<std::shared_ptr<SongInfo>> MusicQueue::history() {
|
|
||||||
return this->_history;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MusicQueue::deleteEntry(const std::shared_ptr<PlayableSong>& entry) {
|
|
||||||
if(!entry) return false;
|
|
||||||
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
auto found = std::find(this->queue.begin(), this->queue.end(), entry);
|
|
||||||
if(found == this->queue.end()) return false;
|
|
||||||
this->queue.erase(found);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MusicQueue::changeOrder(const std::shared_ptr<PlayableSong>& entry, int position) {
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
auto found = std::find(this->queue.begin(), this->queue.end(), entry);
|
|
||||||
if(found == this->queue.end()) return -1;
|
|
||||||
this->queue.erase(found);
|
|
||||||
|
|
||||||
if(position < 0) position = (int) this->queue.size();
|
|
||||||
if(position > this->queue.size()) position = (int) this->queue.size();
|
|
||||||
this->queue.insert(this->queue.begin(), entry);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> MusicQueue::insertEntry(const std::string &url, const tsclient &invoker, const std::shared_ptr<PlayableSong::song_loader_t> &loader) {
|
|
||||||
auto entry = PlayableSong::create({
|
|
||||||
0,
|
|
||||||
url,
|
|
||||||
invoker ? invoker->getClientDatabaseId() : 0
|
|
||||||
}, loader);
|
|
||||||
{
|
|
||||||
entry->set_song_id(this->song_id_index++);
|
|
||||||
threads::MutexLock lock(this->lock);
|
|
||||||
this->queue.push_back(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->get_loader(this->handle->getServer(), true);
|
|
||||||
return entry;
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../ConnectedClient.h"
|
|
||||||
#include "Song.h"
|
|
||||||
#include <teaspeak/MusicPlayer.h>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace ts {
|
|
||||||
namespace server {
|
|
||||||
class MusicClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace music {
|
|
||||||
class MusicHistoryEntry : public SongInfo {
|
|
||||||
public:
|
|
||||||
MusicHistoryEntry(std::string url, ClientDbId invoker, ts::SongId songId) : url(std::move(url)), invoker(invoker), id(songId) {}
|
|
||||||
|
|
||||||
std::string getUrl() const override { return this->url; }
|
|
||||||
ts::ClientDbId getInvoker() const override { return this->invoker; }
|
|
||||||
ts::SongId getSongId() const override { return this->id; }
|
|
||||||
private:
|
|
||||||
ts::SongId id;
|
|
||||||
std::string url;
|
|
||||||
ts::ClientDbId invoker;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MusicQueue {
|
|
||||||
public:
|
|
||||||
MusicQueue(server::MusicClient*);
|
|
||||||
~MusicQueue();
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> currentSong();
|
|
||||||
std::deque<std::shared_ptr<PlayableSong>> queueEntries();
|
|
||||||
std::deque<std::shared_ptr<SongInfo>> history(); //near to past
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> rewind();
|
|
||||||
std::shared_ptr<PlayableSong> getNextSong();
|
|
||||||
std::shared_ptr<PlayableSong> find_queue(ts::SongId);
|
|
||||||
std::shared_ptr<SongInfo> find(ts::SongId);
|
|
||||||
|
|
||||||
bool deleteEntry(const std::shared_ptr<PlayableSong>&);
|
|
||||||
int changeOrder(const std::shared_ptr<PlayableSong>&, int position);
|
|
||||||
|
|
||||||
std::shared_ptr<PlayableSong> insertEntry(const std::string& url, const tsclient& invoker, const std::shared_ptr<PlayableSong::song_loader_t>& loader = nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
void notifySongEnded();
|
|
||||||
void notifySongAbort();
|
|
||||||
private:
|
|
||||||
server::MusicClient* handle;
|
|
||||||
|
|
||||||
threads::Mutex lock;
|
|
||||||
std::shared_ptr<PlayableSong> current;
|
|
||||||
std::deque<std::shared_ptr<PlayableSong>> queue;
|
|
||||||
uint32_t song_id_index = 1;
|
|
||||||
|
|
||||||
std::deque<std::shared_ptr<SongInfo>> _history;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -61,8 +61,9 @@ std::shared_ptr<PlaylistEntry> Playlist::playlist_find(const std::unique_lock<st
|
|||||||
while(current) {
|
while(current) {
|
||||||
assert(current->entry);
|
assert(current->entry);
|
||||||
|
|
||||||
if(current->entry->song_id == id)
|
if(current->entry->song_id == id) {
|
||||||
return current;
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
current = current->next_song;
|
current = current->next_song;
|
||||||
}
|
}
|
||||||
@ -186,8 +187,8 @@ bool Playlist::sql_apply_changes(const std::shared_ptr<ts::music::PlaylistEntryI
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Playlist::sql_flush_all_changes() {
|
bool Playlist::sql_flush_all_changes() {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
std::unique_lock list_lock{this->playlist_mutex};
|
||||||
deque<shared_ptr<PlaylistEntryInfo>> changed_entries;
|
std::deque<std::shared_ptr<PlaylistEntryInfo>> changed_entries;
|
||||||
auto head = this->playlist_head;
|
auto head = this->playlist_head;
|
||||||
while(head) {
|
while(head) {
|
||||||
if(head->modified) {
|
if(head->modified) {
|
||||||
@ -290,10 +291,11 @@ std::deque<std::shared_ptr<PlaylistEntryInfo>> Playlist::load_entries() {
|
|||||||
bool Playlist::build_tree(deque<shared_ptr<PlaylistEntryInfo>> entries) {
|
bool Playlist::build_tree(deque<shared_ptr<PlaylistEntryInfo>> entries) {
|
||||||
this->playlist_head = nullptr;
|
this->playlist_head = nullptr;
|
||||||
|
|
||||||
if(entries.empty())
|
if(entries.empty()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unique_lock list_lock(this->playlist_lock);
|
std::unique_lock list_lock{this->playlist_mutex};
|
||||||
auto find_entry = [&](SongId id) -> shared_ptr<PlaylistEntryInfo> {
|
auto find_entry = [&](SongId id) -> shared_ptr<PlaylistEntryInfo> {
|
||||||
for(const auto& entry : entries)
|
for(const auto& entry : entries)
|
||||||
if(entry->song_id == id)
|
if(entry->song_id == id)
|
||||||
@ -322,14 +324,16 @@ bool Playlist::build_tree(deque<shared_ptr<PlaylistEntryInfo>> entries) {
|
|||||||
|
|
||||||
this->playlist_head = entry;
|
this->playlist_head = entry;
|
||||||
} else {
|
} else {
|
||||||
if(head->modified)
|
if(head->modified) {
|
||||||
entry->set_previous_song(current_tail);
|
entry->set_previous_song(current_tail);
|
||||||
else
|
} else {
|
||||||
entry->previous_song = current_tail;
|
entry->previous_song = current_tail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(current_tail)
|
if(current_tail) {
|
||||||
current_tail->next_song = entry;
|
current_tail->next_song = entry;
|
||||||
|
}
|
||||||
current_tail = entry;
|
current_tail = entry;
|
||||||
|
|
||||||
head = head->next;
|
head = head->next;
|
||||||
@ -339,7 +343,7 @@ bool Playlist::build_tree(deque<shared_ptr<PlaylistEntryInfo>> entries) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::destroy_tree() {
|
void Playlist::destroy_tree() {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
auto element = this->playlist_head;
|
auto element = this->playlist_head;
|
||||||
while(element) {
|
while(element) {
|
||||||
element->entry = nullptr;
|
element->entry = nullptr;
|
||||||
@ -352,7 +356,7 @@ void Playlist::destroy_tree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::shared_ptr<PlaylistEntryInfo>> Playlist::list_songs() {
|
std::deque<std::shared_ptr<PlaylistEntryInfo>> Playlist::list_songs() {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
return this->_list_songs(list_lock);
|
return this->_list_songs(list_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +375,7 @@ std::deque<std::shared_ptr<PlaylistEntryInfo>> Playlist::_list_songs(const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PlaylistEntryInfo> Playlist::find_song(ts::SongId id) {
|
std::shared_ptr<PlaylistEntryInfo> Playlist::find_song(ts::SongId id) {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
auto head = this->playlist_head;
|
auto head = this->playlist_head;
|
||||||
while(head) {
|
while(head) {
|
||||||
if(head->entry->song_id == id)
|
if(head->entry->song_id == id)
|
||||||
@ -389,7 +393,7 @@ std::shared_ptr<PlaylistEntryInfo> Playlist::add_song(const std::shared_ptr<ts::
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PlaylistEntryInfo> Playlist::add_song(ClientDbId client, const std::string &url, const std::string& url_loader, ts::SongId order) {
|
std::shared_ptr<PlaylistEntryInfo> Playlist::add_song(ClientDbId client, const std::string &url, const std::string& url_loader, ts::SongId order) {
|
||||||
auto entry = make_shared<PlaylistEntryInfo>();
|
auto entry = std::make_shared<PlaylistEntryInfo>();
|
||||||
|
|
||||||
entry->previous_song_id = order;
|
entry->previous_song_id = order;
|
||||||
entry->invoker = client;
|
entry->invoker = client;
|
||||||
@ -401,7 +405,7 @@ std::shared_ptr<PlaylistEntryInfo> Playlist::add_song(ClientDbId client, const s
|
|||||||
auto list_entry = make_shared<PlaylistEntry>();
|
auto list_entry = make_shared<PlaylistEntry>();
|
||||||
list_entry->entry = entry;
|
list_entry->entry = entry;
|
||||||
|
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
if(order == 0) {
|
if(order == 0) {
|
||||||
auto end = playlist_end(list_lock);
|
auto end = playlist_end(list_lock);
|
||||||
entry->previous_song_id = end ? end->entry->song_id : 0;
|
entry->previous_song_id = end ? end->entry->song_id : 0;
|
||||||
@ -427,7 +431,7 @@ std::shared_ptr<PlaylistEntryInfo> Playlist::add_song(ClientDbId client, const s
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Playlist::delete_song(ts::SongId id) {
|
bool Playlist::delete_song(ts::SongId id) {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
auto song = this->playlist_find(list_lock, id);
|
auto song = this->playlist_find(list_lock, id);
|
||||||
if(!song) return false;
|
if(!song) return false;
|
||||||
|
|
||||||
@ -440,7 +444,7 @@ bool Playlist::delete_song(ts::SongId id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Playlist::reorder_song(ts::SongId song_id, ts::SongId order_id) {
|
bool Playlist::reorder_song(ts::SongId song_id, ts::SongId order_id) {
|
||||||
unique_lock list_lock(this->playlist_lock);
|
unique_lock list_lock(this->playlist_mutex);
|
||||||
auto song = this->playlist_find(list_lock, song_id);
|
auto song = this->playlist_find(list_lock, song_id);
|
||||||
auto order = this->playlist_find(list_lock, order_id);
|
auto order = this->playlist_find(list_lock, order_id);
|
||||||
if(!song) return false;
|
if(!song) return false;
|
||||||
|
@ -128,7 +128,7 @@ namespace ts {
|
|||||||
bool is_subscriber(const std::shared_ptr<server::ConnectedClient>&);
|
bool is_subscriber(const std::shared_ptr<server::ConnectedClient>&);
|
||||||
protected:
|
protected:
|
||||||
virtual void set_self_ref(const std::shared_ptr<Playlist>& /* playlist */);
|
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; }
|
[[nodiscard]] 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::atomic<SongId> current_id;
|
||||||
std::shared_ptr<Properties> _properties;
|
std::shared_ptr<Properties> _properties;
|
||||||
@ -140,7 +140,7 @@ namespace ts {
|
|||||||
std::shared_ptr<server::VirtualServer> get_server();
|
std::shared_ptr<server::VirtualServer> get_server();
|
||||||
ServerId get_server_id();
|
ServerId get_server_id();
|
||||||
|
|
||||||
std::shared_mutex playlist_lock{};
|
std::shared_mutex playlist_mutex{};
|
||||||
std::shared_ptr<PlaylistEntry> playlist_head{};
|
std::shared_ptr<PlaylistEntry> playlist_head{};
|
||||||
|
|
||||||
std::mutex subscriber_lock{};
|
std::mutex subscriber_lock{};
|
||||||
@ -148,7 +148,7 @@ namespace ts {
|
|||||||
|
|
||||||
virtual std::deque<std::shared_ptr<PlaylistEntryInfo>> _list_songs(const std::unique_lock<std::shared_mutex>& /* playlist lock */);
|
virtual std::deque<std::shared_ptr<PlaylistEntryInfo>> _list_songs(const std::unique_lock<std::shared_mutex>& /* playlist lock */);
|
||||||
|
|
||||||
/* playlist functions are threadsave */
|
/* playlist functions are thread safe */
|
||||||
std::shared_ptr<PlaylistEntry> playlist_find(const std::unique_lock<std::shared_mutex>& /* playlist lock */, SongId /* song */);
|
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> &);
|
std::shared_ptr<PlaylistEntry> playlist_end(const std::unique_lock<std::shared_mutex> &);
|
||||||
bool playlist_insert(
|
bool playlist_insert(
|
||||||
|
@ -18,7 +18,7 @@ PlayablePlaylist::~PlayablePlaylist() {}
|
|||||||
void PlayablePlaylist::load_songs() {
|
void PlayablePlaylist::load_songs() {
|
||||||
Playlist::load_songs();
|
Playlist::load_songs();
|
||||||
|
|
||||||
unique_lock playlist_lock(this->playlist_lock);
|
unique_lock playlist_lock(this->playlist_mutex);
|
||||||
auto song_id = this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as_save<SongId>();
|
auto song_id = this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as_save<SongId>();
|
||||||
auto current_song = this->playlist_find(playlist_lock, song_id);
|
auto current_song = this->playlist_find(playlist_lock, song_id);
|
||||||
if(!current_song && song_id != 0) {
|
if(!current_song && song_id != 0) {
|
||||||
@ -113,7 +113,7 @@ std::shared_ptr<PlaylistEntryInfo> PlayablePlaylist::playlist_next_entry() {
|
|||||||
if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */
|
if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */
|
||||||
auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as<ReplayMode::value>();
|
auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as<ReplayMode::value>();
|
||||||
|
|
||||||
unique_lock playlist_lock(this->playlist_lock);
|
unique_lock playlist_lock(this->playlist_mutex);
|
||||||
auto old_song = this->playlist_find(playlist_lock, this->currently_playing());
|
auto old_song = this->playlist_find(playlist_lock, this->currently_playing());
|
||||||
|
|
||||||
if(replay_mode == ReplayMode::SINGLE_LOOPED) {
|
if(replay_mode == ReplayMode::SINGLE_LOOPED) {
|
||||||
@ -165,7 +165,7 @@ std::shared_ptr<PlaylistEntryInfo> PlayablePlaylist::playlist_previous_entry() {
|
|||||||
if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */
|
if(!this->playlist_head) return nullptr; /* fuzzy check if we're not empty */
|
||||||
auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as<ReplayMode::value>();
|
auto replay_mode = this->properties()[property::PLAYLIST_REPLAY_MODE].as<ReplayMode::value>();
|
||||||
|
|
||||||
unique_lock playlist_lock(this->playlist_lock);
|
unique_lock playlist_lock(this->playlist_mutex);
|
||||||
this->properties()[property::PLAYLIST_FLAG_FINISHED] = false;
|
this->properties()[property::PLAYLIST_FLAG_FINISHED] = false;
|
||||||
|
|
||||||
auto current_song = this->playlist_find(playlist_lock, this->currently_playing());
|
auto current_song = this->playlist_find(playlist_lock, this->currently_playing());
|
||||||
@ -192,7 +192,7 @@ std::shared_ptr<PlaylistEntryInfo> PlayablePlaylist::playlist_previous_entry() {
|
|||||||
|
|
||||||
bool PlayablePlaylist::set_current_song(SongId song_id) {
|
bool PlayablePlaylist::set_current_song(SongId song_id) {
|
||||||
{
|
{
|
||||||
unique_lock playlist_lock(this->playlist_lock);
|
unique_lock playlist_lock(this->playlist_mutex);
|
||||||
auto current_song = this->playlist_find(playlist_lock, song_id);
|
auto current_song = this->playlist_find(playlist_lock, song_id);
|
||||||
if(!current_song && song_id != 0) return false;
|
if(!current_song && song_id != 0) return false;
|
||||||
|
|
||||||
|
@ -14,17 +14,26 @@ namespace ts::music {
|
|||||||
ignore_playlist_owner,
|
ignore_playlist_owner,
|
||||||
do_no_require_granted
|
do_no_require_granted
|
||||||
};
|
};
|
||||||
PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> permissions);
|
explicit PlaylistPermissions(std::shared_ptr<permission::v2::PermissionManager> permissions);
|
||||||
|
|
||||||
inline const std::shared_ptr<permission::v2::PermissionManager>& permission_manager() const { return this->_permissions; }
|
[[nodiscard]] inline const std::shared_ptr<permission::v2::PermissionManager>& permission_manager() const { return this->_permissions; }
|
||||||
|
|
||||||
/* returns permission::ok if client has permissions */
|
/* returns permission::ok if client has permissions */
|
||||||
permission::PermissionType client_has_permissions(const std::shared_ptr<server::ConnectedClient>& client, permission::PermissionType needed_permission, permission::PermissionType granted_permission, uint8_t /* ignore playlist owner */ = 0);
|
permission::PermissionType client_has_permissions(
|
||||||
permission::v2::PermissionFlaggedValue calculate_client_specific_permissions(permission::PermissionType /* permission */, const std::shared_ptr<server::ConnectedClient>& /* client */);
|
const std::shared_ptr<server::ConnectedClient>& /* client */,
|
||||||
|
permission::PermissionType /* needed_permission */,
|
||||||
|
permission::PermissionType /* granted_permission */,
|
||||||
|
uint8_t /* ignore playlist owner */ = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
permission::v2::PermissionFlaggedValue calculate_client_specific_permissions(
|
||||||
|
permission::PermissionType /* permission */,
|
||||||
|
const std::shared_ptr<server::ConnectedClient>& /* client */
|
||||||
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const std::shared_ptr<permission::v2::PermissionManager> _permissions;
|
const std::shared_ptr<permission::v2::PermissionManager> _permissions;
|
||||||
|
|
||||||
virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0;
|
[[nodiscard]] virtual bool is_playlist_owner(ClientDbId /* database id */) const = 0;
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
}
|
}
|
2
shared
2
shared
@ -1 +1 @@
|
|||||||
Subproject commit 12c2a1592d86fa8b10c9d56919222de3891bd4a7
|
Subproject commit eb77a7fefb454469ed4f0b495959923048a2b768
|
Loading…
Reference in New Issue
Block a user