Files
Teaspeak-Server/server/src/music/PlayablePlaylist.cpp
T
WolverinDEV e5f7b3bd32 Some changes
2020-03-20 00:56:36 +01:00

213 lines
8.2 KiB
C++

#include "PlayablePlaylist.h"
#include "src/VirtualServer.h"
#include "src/client/music/MusicClient.h"
#include "src/client/ConnectedClient.h"
#include "MusicPlaylist.h"
#include <log/LogUtils.h>
using namespace ts;
using namespace ts::server;
using namespace ts::music;
using namespace std;
using namespace std::chrono;
PlayablePlaylist::PlayablePlaylist(const std::shared_ptr<MusicBotManager> &handle, const std::shared_ptr<Properties> &props, const std::shared_ptr<permission::v2::PermissionManager>& perms) : Playlist(handle, props, perms) { }
PlayablePlaylist::~PlayablePlaylist() {}
void PlayablePlaylist::load_songs() {
Playlist::load_songs();
unique_lock playlist_lock(this->playlist_lock);
auto song_id = this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as_save<SongId>();
auto current_song = this->playlist_find(playlist_lock, song_id);
if(!current_song && song_id != 0) {
logWarning(this->get_server_id(), "[Playlist] Failed to reinitialize current song index for playlist {}. Song {} is missing.", this->playlist_id(), song_id);
this->properties()[property::PLAYLIST_CURRENT_SONG_ID] = 0;
}
if(current_song) {
this->current_loading_entry = current_song->entry;
this->enqueue_load(current_song->entry);
}
}
void PlayablePlaylist::set_self_ref(const std::shared_ptr<Playlist> &ptr) {
Playlist::set_self_ref(ptr);
}
void PlayablePlaylist::previous() {
unique_lock lock(this->currently_playing_lock);
auto entry = this->playlist_previous_entry();
if(entry) this->enqueue_load(entry);
this->properties()[property::PLAYLIST_CURRENT_SONG_ID] = entry ? entry->song_id : 0;
this->current_loading_entry = entry;
}
void PlayablePlaylist::next() {
unique_lock lock(this->currently_playing_lock);
auto entry = this->playlist_next_entry();
if(entry) this->enqueue_load(entry);
this->properties()[property::PLAYLIST_CURRENT_SONG_ID] = entry ? entry->song_id : 0;
this->current_loading_entry = entry;
}
std::shared_ptr<ts::music::PlayableSong> PlayablePlaylist::current_song(bool& await_load) {
await_load = false;
unique_lock lock(this->currently_playing_lock);
auto entry = this->current_loading_entry.lock();
auto id = entry ? entry->song_id : 0;
if(this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as<SongId>() != id) /* should not happen */
this->properties()[property::PLAYLIST_CURRENT_SONG_ID] = id;
if(!entry)
return nullptr;
if(entry->metadata.is_loading()) {
if(entry->metadata.load_begin + seconds(30) < system_clock::now()) {
this->delete_song(entry->song_id); /* delete song because we cant load it */
return PlayableSong::create({
entry->song_id,
entry->original_url,
entry->invoker
}, MusicClient::failedLoader("Song failed to load"));
}
await_load = true;
return nullptr;
}
if(!entry->metadata.is_loaded()) {
assert(entry->metadata.has_failed_to_load());
this->delete_song(entry->song_id); /* acquired playlist */
/* return promise */
return PlayableSong::create({
entry->song_id,
entry->original_url,
entry->invoker
}, MusicClient::failedLoader(entry->metadata.load_error));
}
auto result = entry->metadata.loaded_data;
assert(result); /* previous tested */
if(result->type != ::music::UrlType::TYPE_VIDEO && result->type != ::music::UrlType::TYPE_STREAM) {
/* we cant replay that kind of entry. Skipping it */
debugMessage(this->get_server_id(), "[PlayList] Tried to replay an invalid entry type (SongID: {}, Type: {})! Skipping song", entry->song_id, result->type);
return nullptr;
}
return PlayableSong::create({
entry->song_id,
result->url,
entry->invoker
}, MusicClient::providerLoader(entry->url_loader));
}
std::shared_ptr<PlaylistEntryInfo> PlayablePlaylist::playlist_next_entry() {
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>();
unique_lock playlist_lock(this->playlist_lock);
auto old_song = this->playlist_find(playlist_lock, this->currently_playing());
if(replay_mode == ReplayMode::SINGLE_LOOPED) {
if(old_song) return old_song->entry;
if(this->playlist_head) return this->playlist_head->entry;
this->properties()[property::PLAYLIST_FLAG_FINISHED] = true;
return nullptr;
}
std::shared_ptr<PlaylistEntryInfo> result;
if(replay_mode == ReplayMode::LINEAR || replay_mode == ReplayMode::LINEAR_LOOPED) {
if(old_song) {
if(old_song->next_song)
result = old_song->next_song->entry;
else if(replay_mode == ReplayMode::LINEAR_LOOPED && this->playlist_head)
result = this->playlist_head->entry;
else {
this->properties()[property::PLAYLIST_FLAG_FINISHED] = true;
result = nullptr;
}
} else if(replay_mode == ReplayMode::LINEAR_LOOPED || !this->properties()[property::PLAYLIST_FLAG_FINISHED]) {
result = this->playlist_head ? this->playlist_head->entry : nullptr;
}
} else if(replay_mode == ReplayMode::SHUFFLE) {
auto songs = this->_list_songs(playlist_lock);
//TODO may add a already played list?
if(songs.size() == 0) {
this->properties()[property::PLAYLIST_FLAG_FINISHED] = true;
result = nullptr;
} else if(songs.size() == 1) {
result = songs.front();
} else {
size_t index;
while(songs[index = (rand() % songs.size())] == (!old_song ? nullptr : old_song->entry)) { }
result = songs[index];
}
}
playlist_lock.unlock();
if(old_song && this->properties()[property::PLAYLIST_FLAG_DELETE_PLAYED].as<bool>()) {
this->delete_song(old_song->entry->song_id);
}
return result;
}
std::shared_ptr<PlaylistEntryInfo> PlayablePlaylist::playlist_previous_entry() {
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>();
unique_lock playlist_lock(this->playlist_lock);
this->properties()[property::PLAYLIST_FLAG_FINISHED] = false;
auto current_song = this->playlist_find(playlist_lock, this->currently_playing());
if(current_song) {
if(replay_mode == ReplayMode::LINEAR || replay_mode == ReplayMode::LINEAR_LOOPED) {
if(current_song->previous_song) return current_song->previous_song->entry;
if(!this->playlist_head) return nullptr;
if(replay_mode == ReplayMode::LINEAR)
return this->playlist_head->entry;
auto tail = this->playlist_head;
while(tail->next_song) tail = tail->next_song;
return tail->entry;
} else if(replay_mode == ReplayMode::SINGLE_LOOPED) {
return current_song ? current_song->entry : this->playlist_head ? this->playlist_head->entry : nullptr;
} else {
return current_song ? current_song->entry : nullptr; /* not possible to rewind shuffle mode */
}
} else {
return this->playlist_head ? this->playlist_head->entry : nullptr;
}
}
bool PlayablePlaylist::set_current_song(SongId song_id) {
{
unique_lock playlist_lock(this->playlist_lock);
auto current_song = this->playlist_find(playlist_lock, song_id);
if(!current_song && song_id != 0) return false;
this->current_loading_entry = current_song->entry;
if(current_song) {
this->enqueue_load(current_song->entry);
auto id = current_song ? current_song->entry->song_id : 0;
if(this->properties()[property::PLAYLIST_CURRENT_SONG_ID].as<SongId>() != id)
this->properties()[property::PLAYLIST_CURRENT_SONG_ID] = id;
}
}
{
auto bot = this->current_bot();
bot->resetSong(); /* reset the song and use the song which is supposed to be the "current" */
}
return true;
}