2020-01-26 14:21:34 +01:00
//
// Created by wolverindev on 26.01.20.
//
# include <memory>
# include <spdlog/sinks/rotating_file_sink.h>
# include <iostream>
# include <bitset>
# include <algorithm>
# include <openssl/sha.h>
# include "../../build.h"
# include "../ConnectedClient.h"
# include "../InternalClient.h"
2020-05-03 14:06:34 +02:00
# include "src/server/file/LocalFileServer.h"
2020-01-26 14:21:34 +01:00
# include "../../server/VoiceServer.h"
# include "../voice/VoiceClient.h"
# include "PermissionManager.h"
# include "../../InstanceHandler.h"
# include "../../server/QueryServer.h"
# include "../file/FileClient.h"
# include "../music/MusicClient.h"
# include "../query/QueryClient.h"
# include "../../weblist/WebListManager.h"
# include "../../manager/ConversationManager.h"
# include "../../manager/PermissionNameMapper.h"
# include <experimental/filesystem>
# include <cstdint>
# include <StringVariable.h>
# include "helpers.h"
# include <Properties.h>
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/base64.h>
# include <misc/hex.h>
# include <misc/digest.h>
# include <misc/rnd.h>
# include <misc/timer.h>
# include <misc/strobf.h>
# include <misc/scope_guard.h>
# include <bbcode/bbcodes.h>
2020-03-01 15:46:03 +01:00
# include <src/music/MusicPlaylist.h>
2020-01-26 14:21:34 +01:00
namespace fs = std : : experimental : : filesystem ;
using namespace std : : chrono ;
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : token ;
command_result ConnectedClient : : handleCommandMusicBotCreate ( Command & cmd ) {
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
if ( this - > server - > musicManager - > max_bots ( ) ! = - 1 & & this - > server - > musicManager - > max_bots ( ) < = this - > server - > musicManager - > current_bot_count ( ) ) {
if ( config : : license - > isPremium ( ) )
return command_result { error : : music_limit_reached } ;
else
return command_result { error : : music_limit_reached , strobf ( " You reached the server music bot limit. You could increase this limit by extend your server with a premium license. " ) . string ( ) } ;
}
auto permissions_list = this - > calculate_permissions ( {
permission : : i_client_music_limit ,
permission : : b_client_music_create_permanent ,
permission : : b_client_music_create_semi_permanent ,
permission : : b_client_music_create_temporary ,
permission : : i_channel_join_power ,
permission : : i_client_music_delete_power ,
permission : : i_client_music_create_modify_max_volume
} , this - > getChannelId ( ) ) ;
auto permissions = map < permission : : PermissionType , permission : : v2 : : PermissionFlaggedValue > ( permissions_list . begin ( ) , permissions_list . end ( ) ) ;
auto max_bots = permissions [ permission : : i_client_music_limit ] ;
if ( max_bots . has_value ) {
auto ownBots = this - > server - > musicManager - > listBots ( this - > getClientDatabaseId ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( ownBots . size ( ) + 1 , max_bots ) )
return command_result { error : : music_client_limit_reached } ;
}
MusicClient : : Type : : value create_type ;
if ( cmd [ 0 ] . has ( " type " ) ) {
create_type = cmd [ " type " ] . as < MusicClient : : Type : : value > ( ) ;
switch ( create_type ) {
case MusicClient : : Type : : PERMANENT :
if ( ! permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_permanent ] ) )
return command_result { permission : : b_client_music_create_permanent } ;
break ;
case MusicClient : : Type : : SEMI_PERMANENT :
if ( ! permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_semi_permanent ] ) )
return command_result { permission : : b_client_music_create_semi_permanent } ;
break ;
case MusicClient : : Type : : TEMPORARY :
if ( ! permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_temporary ] ) )
return command_result { permission : : b_client_music_create_temporary } ;
break ;
default :
return command_result { error : : vs_critical } ;
}
} else {
if ( permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_permanent ] ) )
create_type = MusicClient : : Type : : PERMANENT ;
else if ( permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_semi_permanent ] ) )
create_type = MusicClient : : Type : : SEMI_PERMANENT ;
else if ( permission : : v2 : : permission_granted ( 1 , permissions [ permission : : b_client_music_create_temporary ] ) )
create_type = MusicClient : : Type : : TEMPORARY ;
else
return command_result { permission : : b_client_music_create_temporary } ;
}
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
auto channel = cmd [ 0 ] . has ( " cid " ) ? this - > server - > channelTree - > findChannel ( cmd [ " cid " ] ) : this - > currentChannel ;
if ( ! channel ) {
if ( cmd [ 0 ] . has ( " cid " ) ) return command_result { error : : channel_invalid_id } ;
} else {
2020-02-16 19:02:06 +01:00
if ( this - > calculate_and_get_join_state ( channel ) ! = permission : : ok )
2020-01-26 14:21:34 +01:00
channel = nullptr ;
}
if ( ! channel )
channel = this - > server - > channelTree - > getDefaultChannel ( ) ;
auto bot = this - > server - > musicManager - > createBot ( this - > getClientDatabaseId ( ) ) ;
if ( ! bot ) return command_result { error : : vs_critical } ;
bot - > set_bot_type ( create_type ) ;
if ( permissions [ permission : : i_client_music_create_modify_max_volume ] . has_value ) {
auto max_volume = min ( 100 , max ( 0 , permissions [ permission : : i_client_music_create_modify_max_volume ] . value ) ) ;
if ( max_volume > = 0 )
bot - > volume_modifier ( max_volume / 100.f ) ;
}
this - > selectedBot = bot ;
{
server_channel_lock . unlock ( ) ;
unique_lock server_channel_w_lock ( this - > server - > channel_tree_lock ) ;
this - > server - > client_move (
bot ,
channel ,
nullptr ,
" music bot created " ,
ViewReasonId : : VREASON_USER_ACTION ,
false ,
server_channel_w_lock
) ;
}
bot - > properties ( ) [ property : : CLIENT_LAST_CHANNEL ] = channel ? channel - > channelId ( ) : 0 ;
bot - > properties ( ) [ property : : CLIENT_COUNTRY ] = config : : geo : : countryFlag ;
if ( permissions [ permission : : i_client_music_delete_power ] . has_value & & permissions [ permission : : i_client_music_delete_power ] . value > = 0 ) {
bot - > clientPermissions - > set_permission ( permission : : i_client_music_needed_delete_power , { permissions [ permission : : i_client_music_delete_power ] . value , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
}
Command notify ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifymusiccreated " : " " ) ;
notify [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandMusicBotDelete ( Command & cmd ) {
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
if ( bot - > getOwner ( ) ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_delete_power , bot - > calculate_permission ( permission : : i_client_music_needed_delete_power , bot - > getChannelId ( ) ) , this - > getChannelId ( ) ) ;
}
this - > server - > musicManager - > deleteBot ( bot ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandMusicBotSetSubscription ( ts : : Command & cmd ) {
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot & & cmd [ " bot_id " ] . as < ClientDbId > ( ) ! = 0 ) return command_result { error : : music_invalid_id } ;
{
auto old_bot = this - > subscribed_bot . lock ( ) ;
if ( old_bot )
old_bot - > remove_subscriber ( _this . lock ( ) ) ;
}
if ( bot ) {
bot - > add_subscriber ( _this . lock ( ) ) ;
this - > subscribed_bot = bot ;
}
return command_result { error : : ok } ;
}
void apply_song ( Command & command , const std : : shared_ptr < ts : : music : : SongInfo > & element , int index = 0 ) {
if ( ! element ) return ;
command [ index ] [ " song_id " ] = element ? element - > getSongId ( ) : 0 ;
command [ index ] [ " song_url " ] = element ? element - > getUrl ( ) : " " ;
command [ index ] [ " song_invoker " ] = element ? element - > getInvoker ( ) : 0 ;
command [ index ] [ " song_loaded " ] = false ;
auto entry = dynamic_pointer_cast < ts : : music : : PlayableSong > ( element ) ;
if ( entry ) {
auto data = entry - > song_loaded_data ( ) ;
command [ index ] [ " song_loaded " ] = entry - > song_loaded ( ) & & data ;
if ( entry - > song_loaded ( ) & & data ) {
command [ index ] [ " song_title " ] = data - > title ;
command [ index ] [ " song_description " ] = data - > description ;
command [ index ] [ " song_thumbnail " ] = data - > thumbnail ;
command [ index ] [ " song_length " ] = data - > length . count ( ) ;
}
}
}
command_result ConnectedClient : : handleCommandMusicBotPlayerInfo ( Command & cmd ) {
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifymusicplayerinfo " : " " ) ;
result [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
result [ " player_state " ] = ( int ) bot - > player_state ( ) ;
2020-02-01 22:40:23 +01:00
auto player = bot - > current_player ( ) ;
if ( player ) {
result [ " player_buffered_index " ] = player - > bufferedUntil ( ) . count ( ) ;
result [ " player_replay_index " ] = player - > currentIndex ( ) . count ( ) ;
result [ " player_max_index " ] = player - > length ( ) . count ( ) ;
result [ " player_seekable " ] = player - > seek_supported ( ) ;
result [ " player_title " ] = player - > songTitle ( ) ;
result [ " player_description " ] = player - > songDescription ( ) ;
2020-01-26 14:21:34 +01:00
} else {
result [ " player_buffered_index " ] = 0 ;
result [ " player_replay_index " ] = 0 ;
result [ " player_max_index " ] = 0 ;
result [ " player_seekable " ] = 0 ;
result [ " player_title " ] = " " ;
result [ " player_description " ] = " " ;
}
apply_song ( result , bot - > current_song ( ) ) ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandMusicBotPlayerAction ( Command & cmd ) {
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_play_power , bot - > calculate_permission ( permission : : i_client_music_needed_play_power , bot - > getChannelId ( ) ) , this - > getChannelId ( ) ) ;
2020-02-01 22:40:23 +01:00
auto player = bot - > current_player ( ) ;
2020-01-26 14:21:34 +01:00
if ( cmd [ " action " ] = = 0 ) {
bot - > stopMusic ( ) ;
} else if ( cmd [ " action " ] = = 1 ) {
bot - > playMusic ( ) ;
} else if ( cmd [ " action " ] = = 2 ) {
bot - > player_pause ( ) ;
} else if ( cmd [ " action " ] = = 3 ) {
bot - > forwardSong ( ) ;
} else if ( cmd [ " action " ] = = 4 ) {
bot - > rewindSong ( ) ;
} else if ( cmd [ " action " ] = = 5 ) {
2020-02-01 22:40:23 +01:00
if ( ! player ) return command_result { error : : music_no_player } ;
player - > forward ( : : music : : PlayerUnits ( cmd [ " units " ] . as < int64_t > ( ) ) ) ;
2020-01-26 14:21:34 +01:00
} else if ( cmd [ " action " ] = = 6 ) {
2020-02-01 22:40:23 +01:00
if ( ! player ) return command_result { error : : music_no_player } ;
player - > rewind ( : : music : : PlayerUnits ( cmd [ " units " ] . as < int64_t > ( ) ) ) ;
2020-01-26 14:21:34 +01:00
} else return command_result { error : : music_invalid_action } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistList ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
2020-02-01 14:32:16 +01:00
auto self_ref = this - > ref ( ) ;
2020-01-26 14:21:34 +01:00
auto playlists = this - > server - > musicManager - > playlists ( ) ;
playlists . erase ( find_if ( playlists . begin ( ) , playlists . end ( ) , [ & ] ( const shared_ptr < music : : PlayablePlaylist > & playlist ) {
2020-02-01 14:32:16 +01:00
return playlist - > client_has_permissions ( self_ref , permission : : i_playlist_needed_view_power , permission : : i_playlist_view_power , music : : PlaylistPermissions : : do_no_require_granted ) ! = permission : : ok ;
2020-01-26 14:21:34 +01:00
} ) , playlists . end ( ) ) ;
if ( playlists . empty ( ) )
return command_result { error : : database_empty_result } ;
Command notify ( this - > notify_response_command ( " notifyplaylistlist " ) ) ;
size_t index = 0 ;
for ( const auto & entry : playlists ) {
notify [ index ] [ " playlist_id " ] = entry - > playlist_id ( ) ;
auto bot = entry - > current_bot ( ) ;
notify [ index ] [ " playlist_bot_id " ] = bot ? bot - > getClientDatabaseId ( ) : 0 ;
notify [ index ] [ " playlist_title " ] = entry - > properties ( ) [ property : : PLAYLIST_TITLE ] . value ( ) ;
notify [ index ] [ " playlist_type " ] = entry - > properties ( ) [ property : : PLAYLIST_TYPE ] . value ( ) ;
notify [ index ] [ " playlist_owner_dbid " ] = entry - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] . value ( ) ;
notify [ index ] [ " playlist_owner_name " ] = entry - > properties ( ) [ property : : PLAYLIST_OWNER_NAME ] . value ( ) ;
2020-02-01 14:32:16 +01:00
auto permissions = entry - > permission_manager ( ) ;
auto permission = permissions - > permission_value_flagged ( permission : : i_playlist_needed_modify_power ) ;
notify [ index ] [ " needed_power_modify " ] = permission . has_value ? permission . value : 0 ;
permission = permissions - > permission_value_flagged ( permission : : i_playlist_needed_permission_modify_power ) ;
notify [ index ] [ " needed_power_permission_modify " ] = permission . has_value ? permission . value : 0 ;
permission = permissions - > permission_value_flagged ( permission : : i_playlist_needed_delete_power ) ;
notify [ index ] [ " needed_power_delete " ] = permission . has_value ? permission . value : 0 ;
permission = permissions - > permission_value_flagged ( permission : : i_playlist_song_needed_add_power ) ;
notify [ index ] [ " needed_power_song_add " ] = permission . has_value ? permission . value : 0 ;
permission = permissions - > permission_value_flagged ( permission : : i_playlist_song_needed_move_power ) ;
notify [ index ] [ " needed_power_song_move " ] = permission . has_value ? permission . value : 0 ;
permission = permissions - > permission_value_flagged ( permission : : i_playlist_song_needed_remove_power ) ;
notify [ index ] [ " needed_power_song_remove " ] = permission . has_value ? permission . value : 0 ;
2020-01-26 14:21:34 +01:00
index + + ;
}
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistCreate ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_playlist_create , 1 ) ;
{
auto max_playlists = this - > calculate_permission ( permission : : i_max_playlists , 0 ) ;
if ( max_playlists . has_value ) {
auto playlists = ref_server - > musicManager - > find_playlists_by_client ( this - > getClientDatabaseId ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( playlists . size ( ) , max_playlists ) )
return command_result { permission : : i_max_playlists } ;
}
}
auto playlist = ref_server - > musicManager - > create_playlist ( this - > getClientDatabaseId ( ) , this - > getDisplayName ( ) ) ;
if ( ! playlist ) return command_result { error : : vs_critical } ;
playlist - > properties ( ) [ property : : PLAYLIST_TYPE ] = music : : Playlist : : Type : : GENERAL ;
{
auto max_songs = this - > calculate_permission ( permission : : i_max_playlist_size , 0 ) ;
if ( max_songs . has_value & & max_songs . value > = 0 )
playlist - > properties ( ) [ property : : PLAYLIST_MAX_SONGS ] = max_songs . value ;
}
auto power = this - > calculate_permission ( permission : : i_playlist_song_remove_power , 0 ) ;
if ( power . has_value & & power . value > = 0 )
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permission : : i_playlist_song_needed_remove_power , { power . value , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
power = this - > calculate_permission ( permission : : i_playlist_delete_power , 0 ) ;
if ( power . has_value & & power . value > = 0 )
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permission : : i_playlist_needed_delete_power , { power . value , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
power = this - > calculate_permission ( permission : : i_playlist_modify_power , 0 ) ;
if ( power . has_value & & power . value > = 0 )
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permission : : i_playlist_needed_modify_power , { power . value , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
power = this - > calculate_permission ( permission : : i_playlist_permission_modify_power , 0 ) ;
if ( power . has_value & & power . value > = 0 )
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permission : : i_playlist_needed_permission_modify_power , { power . value , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
Command notify ( this - > notify_response_command ( " notifyplaylistcreated " ) ) ;
notify [ " playlist_id " ] = playlist - > playlist_id ( ) ;
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistDelete ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_delete_power , permission : : i_playlist_delete_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
string error ;
if ( ! ref_server - > musicManager - > delete_playlist ( playlist - > playlist_id ( ) , error ) ) {
logError ( this - > getServerId ( ) , " Failed to delete playlist with id {}. Error: {} " , playlist - > playlist_id ( ) , error ) ;
return command_result { error : : vs_critical } ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistInfo ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_view_power , permission : : i_playlist_view_power , music : : PlaylistPermissions : : do_no_require_granted ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
Command notify ( this - > notify_response_command ( " notifyplaylistinfo " ) ) ;
for ( const auto & property : playlist - > properties ( ) . list_properties ( property : : FLAG_PLAYLIST_VARIABLE ) ) {
notify [ property . type ( ) . name ] = property . value ( ) ;
}
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistEdit ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_modify_power , permission : : i_playlist_modify_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
2020-04-08 13:01:41 +02:00
deque < pair < const property : : PropertyDescription * , string > > properties ;
2020-01-26 14:21:34 +01:00
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " playlist_id " ) continue ;
if ( key = = " return_code " ) continue ;
2020-04-08 13:01:41 +02:00
const auto & property = property : : find < property : : PlaylistProperties > ( key ) ;
if ( property = = property : : PLAYLIST_UNDEFINED ) {
2020-01-26 14:21:34 +01:00
logError ( this - > getServerId ( ) , R " ([{}] Tried to edit a not existing playlist property " { } " to " { } " ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2020-04-08 13:01:41 +02:00
if ( ( property . flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
2020-01-26 14:21:34 +01:00
logError ( this - > getServerId ( ) , " [{}] Tried to change a playlist property which is not changeable. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2020-04-08 13:01:41 +02:00
if ( ! property . validate_input ( cmd [ key ] . as < string > ( ) ) ) {
2020-01-26 14:21:34 +01:00
logError ( this - > getServerId ( ) , " [{}] Tried to change a playlist property to an invalid value. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2020-04-08 13:01:41 +02:00
if ( property = = property : : PLAYLIST_CURRENT_SONG_ID ) {
2020-01-26 14:21:34 +01:00
auto song_id = cmd [ key ] . as < SongId > ( ) ;
auto song = song_id > 0 ? playlist - > find_song ( song_id ) : nullptr ;
if ( song_id ! = 0 & & ! song )
return command_result { error : : playlist_invalid_song_id } ;
2020-04-08 13:01:41 +02:00
} else if ( property = = property : : PLAYLIST_MAX_SONGS ) {
2020-01-26 14:21:34 +01:00
auto value = cmd [ key ] . as < int32_t > ( ) ;
auto max_value = this - > calculate_permission ( permission : : i_max_playlist_size , this - > getChannelId ( ) ) ;
if ( max_value . has_value & & ! permission : : v2 : : permission_granted ( value , max_value ) )
return command_result { permission : : i_max_playlist_size } ;
}
2020-04-08 13:01:41 +02:00
properties . emplace_back ( & property , key ) ;
2020-01-26 14:21:34 +01:00
}
for ( const auto & property : properties ) {
if ( * property . first = = property : : PLAYLIST_CURRENT_SONG_ID ) {
playlist - > set_current_song ( cmd [ property . second ] ) ;
continue ;
}
playlist - > properties ( ) [ property . first ] = cmd [ property . second ] . string ( ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistPermList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
{
auto value = playlist - > calculate_client_specific_permissions ( permission : : b_virtualserver_playlist_permission_list , this - > ref ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( 1 , value ) )
return command_result { permission : : b_virtualserver_playlist_permission_list } ;
}
2020-01-26 14:21:34 +01:00
2020-02-01 14:32:16 +01:00
auto permissions = playlist - > permission_manager ( ) - > permissions ( ) ;
2020-01-26 14:21:34 +01:00
if ( permissions . empty ( ) )
2020-02-01 14:32:16 +01:00
return command_result { error : : database_empty_result } ;
2020-01-26 14:21:34 +01:00
Command result ( this - > notify_response_command ( " notifyplaylistpermlist " ) ) ;
2020-02-01 14:32:16 +01:00
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
auto perm_sid = cmd . hasParm ( " permsid " ) | | cmd . hasParm ( " names " ) ;
2020-01-26 14:21:34 +01:00
int index = 0 ;
result [ " playlist_id " ] = playlist - > playlist_id ( ) ;
2020-02-01 14:32:16 +01:00
for ( const auto & [ perm , value ] : permissions ) {
if ( value . flags . value_set ) {
if ( perm_sid )
result [ index ] [ " permsid " ] = permission_mapper - > permission_name ( this - > getType ( ) , perm ) ;
else
result [ index ] [ " permid " ] = perm ;
2020-01-26 14:21:34 +01:00
2020-02-01 14:32:16 +01:00
result [ index ] [ " permvalue " ] = value . values . value ;
result [ index ] [ " permnegated " ] = value . flags . negate ;
result [ index ] [ " permskip " ] = value . flags . skip ;
2020-01-26 14:21:34 +01:00
index + + ;
}
2020-02-01 14:32:16 +01:00
if ( value . flags . grant_set ) {
if ( perm_sid )
result [ index ] [ " permsid " ] = permission_mapper - > permission_name_grant ( this - > getType ( ) , perm ) ;
else
result [ index ] [ " permid " ] = perm | PERM_ID_GRANT ;
result [ index ] [ " permvalue " ] = value . values . grant ;
2020-01-26 14:21:34 +01:00
result [ index ] [ " permnegated " ] = 0 ;
result [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistAddPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_permission_modify_power , permission : : i_playlist_permission_modify_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
auto max_value = this - > calculate_permission ( permission : : i_permission_modify_power , 0 , true ) ;
if ( ! max_value . has_value ) return command_result { permission : : i_permission_modify_power } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & ! permission : : v2 : : permission_granted ( val , max_value ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-03 19:41:18 +01:00
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permType , 0 , true ) ) ) {
2020-01-26 14:21:34 +01:00
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : do_nothing , permission : : v2 : : set_value ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permType , { cmd [ index ] [ " permvalue " ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , cmd [ index ] [ " permskip " ] . as < bool > ( ) , cmd [ index ] [ " permnegated " ] . as < bool > ( ) ) ;
2020-01-26 14:21:34 +01:00
}
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistDelPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_permission_modify_power , permission : : i_playlist_permission_modify_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 0 , this - > calculate_permission ( permType , 0 , true ) ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-01 14:32:16 +01:00
2020-01-26 14:21:34 +01:00
if ( grant ) {
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permType , { 0 , 0 } , permission : : v2 : : do_nothing , permission : : v2 : : delete_value ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-02-01 14:32:16 +01:00
playlist - > permission_manager ( ) - > set_permission ( permType , { 0 , 0 } , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
}
}
return command_result { error : : ok } ;
}
2020-02-21 20:32:25 +01:00
command_result ConnectedClient : : handleCommandPlaylistClientList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
{
auto value = playlist - > calculate_client_specific_permissions ( permission : : b_virtualserver_playlist_permission_list , this - > ref ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( 1 , value ) )
return command_result { permission : : b_virtualserver_playlist_permission_list } ;
}
auto permissions = playlist - > permission_manager ( ) - > channel_permissions ( ) ;
if ( permissions . empty ( ) )
return command_result { error : : database_empty_result } ;
Command result ( this - > notify_response_command ( " notifyplaylistclientlist " ) ) ;
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
int index = 0 ;
ClientDbId last_client_id { 0 } ;
result [ " playlist_id " ] = playlist - > playlist_id ( ) ;
for ( const auto & [ perm , client , value ] : permissions ) {
if ( last_client_id ! = client )
result [ index + + ] [ " cldbid " ] = client ;
}
if ( index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
2020-02-01 14:32:16 +01:00
command_result ConnectedClient : : handleCommandPlaylistClientPermList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
{
auto value = playlist - > calculate_client_specific_permissions ( permission : : b_virtualserver_playlist_permission_list , this - > ref ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( 1 , value ) )
return command_result { permission : : b_virtualserver_playlist_permission_list } ;
}
auto permissions = playlist - > permission_manager ( ) - > channel_permissions ( ) ;
if ( permissions . empty ( ) )
return command_result { error : : database_empty_result } ;
Command result ( this - > notify_response_command ( " notifyplaylistclientpermlist " ) ) ;
auto client_id = cmd . hasParm ( " cldbid " ) ? cmd [ 0 ] [ " cldbid " ] . as < ClientDbId > ( ) : 0 ;
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
auto perm_sid = cmd . hasParm ( " permsid " ) | | cmd . hasParm ( " names " ) ;
int index = 0 ;
ClientDbId last_client_id { 0 } ;
result [ " playlist_id " ] = playlist - > playlist_id ( ) ;
result [ " cldbid " ] = client_id ;
for ( const auto & [ perm , client , value ] : permissions ) {
if ( client_id > 0 & & client ! = client_id ) continue ;
if ( last_client_id ! = client )
result [ index ] [ " cldbid " ] = client ;
if ( value . flags . value_set ) {
if ( perm_sid )
result [ index ] [ " permsid " ] = permission_mapper - > permission_name ( this - > getType ( ) , perm ) ;
else
result [ index ] [ " permid " ] = perm ;
result [ index ] [ " permvalue " ] = value . values . value ;
result [ index ] [ " permnegated " ] = value . flags . negate ;
result [ index ] [ " permskip " ] = value . flags . skip ;
index + + ;
}
if ( value . flags . grant_set ) {
if ( perm_sid )
result [ index ] [ " permsid " ] = permission_mapper - > permission_name_grant ( this - > getType ( ) , perm ) ;
else
result [ index ] [ " permid " ] = perm | PERM_ID_GRANT ;
result [ index ] [ " permvalue " ] = value . values . grant ;
result [ index ] [ " permnegated " ] = 0 ;
result [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
if ( index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistClientAddPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
auto client_id = cmd [ 0 ] [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( client_id = = 0 ) return command_result { error : : client_invalid_id } ;
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_permission_modify_power , permission : : i_playlist_permission_modify_power ) ; perr )
return command_result { perr } ;
auto max_value = this - > calculate_permission ( permission : : i_permission_modify_power , 0 , true ) ;
if ( ! max_value . has_value ) return command_result { permission : : i_permission_modify_power } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & ! permission : : v2 : : permission_granted ( val , max_value ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-03 19:41:18 +01:00
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permType , 0 , true ) ) ) {
2020-02-01 14:32:16 +01:00
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
playlist - > permission_manager ( ) - > set_channel_permission ( permType , client_id , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : do_nothing , permission : : v2 : : set_value ) ;
} else {
playlist - > permission_manager ( ) - > set_channel_permission ( permType , client_id , { cmd [ index ] [ " permvalue " ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , cmd [ index ] [ " permskip " ] . as < bool > ( ) , cmd [ index ] [ " permnegated " ] . as < bool > ( ) ) ;
}
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistClientDelPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
auto client_id = cmd [ 0 ] [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( client_id = = 0 ) return command_result { error : : client_invalid_id } ;
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_needed_permission_modify_power , permission : : i_playlist_permission_modify_power ) ; perr )
return command_result { perr } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 0 , this - > calculate_permission ( permType , 0 , true ) ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
playlist - > permission_manager ( ) - > set_channel_permission ( permType , client_id , { 0 , 0 } , permission : : v2 : : do_nothing , permission : : v2 : : delete_value ) ;
} else {
playlist - > permission_manager ( ) - > set_channel_permission ( permType , client_id , { 0 , 0 } , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
}
}
return command_result { error : : ok } ;
}
2020-04-04 01:38:37 +02:00
constexpr auto max_song_meta_info = 1024 * 512 ;
inline size_t estimated_song_info_size ( const std : : shared_ptr < ts : : music : : PlaylistEntryInfo > & song , bool extract_metadata ) {
return 128 + std : : min ( song - > metadata . json_string . length ( ) , ( size_t ) max_song_meta_info ) + extract_metadata * 256 ;
}
inline void fill_song_info ( ts : : command_builder_bulk bulk , const std : : shared_ptr < ts : : music : : PlaylistEntryInfo > & song , bool extract_metadata ) {
bulk . reserve ( estimated_song_info_size ( song , extract_metadata ) ) ;
bulk . put ( " song_id " , song - > song_id ) ;
bulk . put ( " song_invoker " , song - > invoker ) ;
bulk . put ( " song_previous_song_id " , song - > previous_song_id ) ;
bulk . put ( " song_url " , song - > original_url ) ;
bulk . put ( " song_url_loader " , song - > url_loader ) ;
bulk . put ( " song_loaded " , song - > metadata . is_loaded ( ) ) ;
if ( song - > metadata . json_string . length ( ) > 1024 * 1024 * 512 ) {
logWarning ( LOG_GENERAL , " Dropping song metadata because its way to big. ({}bytes) " , song - > metadata . json_string . size ( ) ) ;
} else {
bulk . put ( " song_metadata " , song - > metadata . json_string ) ;
}
if ( extract_metadata ) {
bulk . reserve ( 256 , true ) ;
auto metadata = song - > metadata . loaded_data ;
if ( extract_metadata & & song - > metadata . is_loaded ( ) & & metadata ) {
bulk . put ( " song_metadata_title " , metadata - > title ) ;
bulk . put ( " song_metadata_description " , metadata - > description ) ;
bulk . put ( " song_metadata_url " , metadata - > url ) ;
bulk . put ( " song_metadata_length " , metadata - > length . count ( ) ) ;
if ( auto thumbnail = static_pointer_cast < : : music : : ThumbnailUrl > ( metadata - > thumbnail ) ; thumbnail & & thumbnail - > type ( ) = = : : music : : THUMBNAIL_URL ) {
bulk . put ( " song_metadata_thumbnail_url " , thumbnail - > url ( ) ) ;
} else {
bulk . put ( " song_metadata_thumbnail_url " , " none " ) ;
}
}
}
}
2020-01-26 14:21:34 +01:00
command_result ConnectedClient : : handleCommandPlaylistSongList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
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 } ;
2020-01-26 14:21:34 +01:00
auto songs = playlist - > list_songs ( ) ;
if ( songs . empty ( ) )
return command_result { error : : database_empty_result } ;
2020-04-04 01:38:37 +02:00
ts : : command_builder result { this - > notify_response_command ( " notifyplaylistsonglist " ) } ;
result . put ( 0 , " version " , 2 ) ; /* to signalize that we're sending the response bulked */
2020-03-01 15:46:03 +01:00
auto extract_metadata = cmd . hasParm ( " extract-metadata " ) ;
2020-04-04 01:38:37 +02:00
size_t index { 0 } ;
2020-01-26 14:21:34 +01:00
for ( const auto & song : songs ) {
2020-04-04 01:38:37 +02:00
if ( index = = 0 ) {
result . put ( 0 , " playlist_id " , playlist - > playlist_id ( ) ) ;
2020-03-01 15:46:03 +01:00
}
2020-04-04 01:38:37 +02:00
fill_song_info ( result . bulk ( index ) , song , extract_metadata ) ;
2020-03-01 15:46:03 +01:00
2020-04-04 01:38:37 +02:00
if ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & result . current_size ( ) + estimated_song_info_size ( song , extract_metadata ) > 128 * 1024 ) {
this - > sendCommand ( result ) ;
result . reset ( ) ;
index = 0 ;
} else {
index + + ;
}
2020-01-26 14:21:34 +01:00
}
2020-04-04 01:38:37 +02:00
if ( index > 0 )
this - > sendCommand ( result ) ;
2020-04-04 11:59:33 +02:00
if ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ) {
ts : : command_builder finish { " notifyplaylistsonglistfinished " } ;
finish . put ( 0 , " playlist_id " , playlist - > playlist_id ( ) ) ;
this - > sendCommand ( finish ) ;
}
2020-01-26 14:21:34 +01:00
return command_result { error : : ok } ;
}
2020-02-02 14:58:46 +01:00
command_result ConnectedClient : : handleCommandPlaylistSongSetCurrent ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_song_needed_move_power , permission : : i_playlist_song_move_power ) ; perr )
return command_result { perr } ;
if ( ! playlist - > set_current_song ( cmd [ " song_id " ] ) )
return command_result { error : : playlist_invalid_song_id } ;
return command_result { error : : ok } ;
}
2020-01-26 14:21:34 +01:00
command_result ConnectedClient : : handleCommandPlaylistSongAdd ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_song_needed_add_power , permission : : i_playlist_song_add_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
2020-03-01 15:46:03 +01:00
if ( cmd [ 0 ] . has ( " invoker " ) )
cmd [ " type " ] = " " ;
else if ( ! cmd [ 0 ] . has ( " type " ) )
cmd [ " type " ] = " " ;
2020-01-26 14:21:34 +01:00
if ( ! cmd [ 0 ] . has ( " previous " ) ) {
auto songs = playlist - > list_songs ( ) ;
if ( songs . empty ( ) )
cmd [ " previous " ] = " 0 " ;
else
2020-03-01 15:46:03 +01:00
cmd [ " previous " ] = songs . back ( ) - > song_id ;
2020-01-26 14:21:34 +01:00
}
2020-03-01 15:46:03 +01:00
auto & type = cmd [ 0 ] [ " type " ] ;
std : : string loader_string { " " } ;
if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 0 ) | | type . as < string > ( ) = = " yt " ) {
loader_string = " YouTube " ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 1 ) | | type . as < string > ( ) = = " ffmpeg " ) {
loader_string = " FFMpeg " ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 2 ) | | type . as < string > ( ) = = " channel " ) {
loader_string = " ChannelProvider " ;
}
2020-01-26 14:21:34 +01:00
2020-03-01 15:46:03 +01:00
auto song = playlist - > add_song ( _this . lock ( ) , cmd [ " url " ] , loader_string , cmd [ " previous " ] ) ;
2020-01-26 14:21:34 +01:00
if ( ! song ) return command_result { error : : vs_critical } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistSongReorder ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_song_needed_move_power , permission : : i_playlist_song_move_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
SongId song_id = cmd [ " song_id " ] ;
SongId previous_id = cmd [ " song_previous_song_id " ] ;
auto song = playlist - > find_song ( song_id ) ;
if ( ! song ) return command_result { error : : playlist_invalid_song_id } ;
if ( ! playlist - > reorder_song ( song_id , previous_id ) )
return command_result { error : : vs_critical } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPlaylistSongRemove ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return command_result { error : : playlist_invalid_id } ;
2020-02-01 14:32:16 +01:00
if ( auto perr = playlist - > client_has_permissions ( this - > ref ( ) , permission : : i_playlist_song_needed_remove_power , permission : : i_playlist_song_remove_power ) ; perr )
return command_result { perr } ;
2020-01-26 14:21:34 +01:00
SongId song_id = cmd [ " song_id " ] ;
auto song = playlist - > find_song ( song_id ) ;
if ( ! song ) return command_result { error : : playlist_invalid_song_id } ;
if ( ! playlist - > delete_song ( song_id ) )
return command_result { error : : vs_critical } ;
return command_result { error : : ok } ;
}
2020-02-01 14:32:16 +01:00
/****** legacy ******/
command_result ConnectedClient : : handleCommandMusicBotQueueList ( Command & cmd ) {
2020-03-01 15:46:03 +01:00
# if false
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
2020-02-01 14:32:16 +01:00
auto playlist = dynamic_pointer_cast < music : : PlayablePlaylist > ( bot - > playlist ( ) ) ;
if ( ! playlist ) return command_result { error : : vs_critical } ;
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 } ;
2020-01-26 14:21:34 +01:00
bool bulked = cmd . hasParm ( " bulk " ) | | cmd . hasParm ( " balk " ) | | cmd . hasParm ( " pipe " ) | | cmd . hasParm ( " bar " ) | | cmd . hasParm ( " paypal " ) ;
int command_index = 0 ;
2020-02-01 14:32:16 +01:00
Command notify ( this - > notify_response_command ( " notifymusicqueueentry " ) ) ;
auto songs = playlist - > list_songs ( ) ;
int begin_index { 0 } ;
for ( auto it = songs . begin ( ) ; it ! = songs . end ( ) ; it + + )
2020-03-01 15:46:03 +01:00
if ( ( * it ) - > song_id = = playlist - > currently_playing ( ) )
2020-02-01 14:32:16 +01:00
break ;
else
begin_index - - ;
2020-01-26 14:21:34 +01:00
2020-02-01 14:32:16 +01:00
for ( auto it = songs . begin ( ) ; it ! = songs . end ( ) ; it + + ) {
2020-01-26 14:21:34 +01:00
if ( ! bulked )
2020-02-01 14:32:16 +01:00
notify = Command ( this - > notify_response_command ( " notifymusicqueueentry " ) ) ;
2020-01-26 14:21:34 +01:00
2020-03-01 10:28:29 +01:00
auto song = * it ;
2020-03-01 15:46:03 +01:00
notify [ command_index ] [ " song_id " ] = song - > song_id ;
notify [ command_index ] [ " song_url " ] = song - > original_url ;
2020-03-01 10:28:29 +01:00
notify [ command_index ] [ " song_invoker " ] = song - > invoker ;
2020-03-01 15:46:03 +01:00
notify [ command_index ] [ " song_loaded " ] = song - > metadata . is_loaded ( ) ;
2020-03-01 10:28:29 +01:00
2020-03-01 15:46:03 +01:00
auto entry = song - > load_future & & song - > load_future - > succeeded ( ) ? song - > load_future - > getValue ( { } ) : nullptr ;
2020-03-01 10:28:29 +01:00
if ( entry ) {
notify [ command_index ] [ " song_loaded " ] = true ;
if ( entry - > type ! = : : music : : TYPE_STREAM & & entry - > type ! = : : music : : TYPE_VIDEO )
continue ;
auto info = reinterpret_pointer_cast < : : music : : UrlSongInfo > ( entry ) ;
if ( info ) {
notify [ command_index ] [ " song_title " ] = info - > title ;
notify [ command_index ] [ " song_description " ] = info - > description ;
if ( auto thumbnail = reinterpret_pointer_cast < : : music : : ThumbnailUrl > ( info - > thumbnail ) ; thumbnail & & thumbnail - > type ( ) = = : : music : : THUMBNAIL_URL )
notify [ command_index ] [ " song_thumbnail " ] = thumbnail - > url ( ) ;
else
notify [ command_index ] [ " song_thumbnail " ] = " " ;
notify [ command_index ] [ " song_length " ] = info - > length . count ( ) ;
}
}
2020-02-01 14:32:16 +01:00
notify [ command_index ] [ " queue_index " ] = begin_index + + ;
2020-01-26 14:21:34 +01:00
if ( ! bulked )
this - > sendCommand ( notify ) ;
2020-02-01 14:32:16 +01:00
else
2020-01-26 14:21:34 +01:00
command_index + + ;
}
if ( bulked ) {
if ( command_index > 0 ) {
this - > sendCommand ( notify ) ;
2020-02-01 14:32:16 +01:00
} else
return command_result { error : : database_empty_result } ;
2020-01-26 14:21:34 +01:00
}
2020-02-01 14:32:16 +01:00
if ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ) {
2020-01-26 14:21:34 +01:00
Command notify ( " notifymusicqueuefinish " ) ;
notify [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
this - > sendCommand ( notify ) ;
}
return command_result { error : : ok } ;
2020-03-01 15:46:03 +01:00
# endif
return command_result { error : : not_implemented } ; //FIXME
2020-01-26 14:21:34 +01:00
}
command_result ConnectedClient : : handleCommandMusicBotQueueAdd ( Command & cmd ) {
return command_result { error : : not_implemented } ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
MusicClient : : loader_t loader ;
auto & type = cmd [ 0 ] [ " type " ] ;
if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 0 ) | | type . as < string > ( ) = = " yt " ) {
loader = bot - > ytLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 1 ) | | type . as < string > ( ) = = " ffmpeg " ) {
loader = bot - > ffmpegLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 2 ) | | type . as < string > ( ) = = " channel " ) {
loader = bot - > channelLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = - 1 ) | | type . as < string > ( ) = = " any " ) {
loader = bot - > providerLoader ( this - > getServer ( ) , " " ) ;
}
if ( ! loader ) return command_result { error : : music_invalid_action } ;
auto entry = bot - > queue ( ) - > insertEntry ( cmd [ " url " ] , _this . lock ( ) , loader ) ;
if ( ! entry ) return command_result { error : : vs_critical } ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueAdd ( bot , entry , bot - > queue ( ) - > queueEntries ( ) . size ( ) - 1 , _this . lock ( ) ) ;
} ) ;
return command_result { error : : ok } ;
*/
}
command_result ConnectedClient : : handleCommandMusicBotQueueRemove ( Command & cmd ) {
return command_result { error : : not_implemented } ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
std : : deque < std : : shared_ptr < music : : SongInfo > > songs ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto entry = bot - > queue ( ) - > find_queue ( cmd [ " song_id " ] ) ;
if ( ! entry ) {
if ( cmd . hasParm ( " skip_error " ) ) continue ;
return command_result { error : : database_empty_result } ;
}
songs . push_back ( move ( entry ) ) ;
}
for ( const auto & entry : songs )
bot - > queue ( ) - > deleteEntry ( dynamic_pointer_cast < music : : PlayableSong > ( entry ) ) ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueRemove ( bot , songs , _this . lock ( ) ) ;
} ) ;
return command_result { error : : ok } ;
*/
}
command_result ConnectedClient : : handleCommandMusicBotQueueReorder ( Command & cmd ) {
return command_result { error : : not_implemented } ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
auto entry = bot - > queue ( ) - > find_queue ( cmd [ " song_id " ] ) ;
if ( ! entry ) return command_result { error : : database_empty_result } ;
auto order = bot - > queue ( ) - > changeOrder ( entry , cmd [ " index " ] ) ;
if ( order < 0 ) return command_result { error : : vs_critical } ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueOrderChange ( bot , entry , order , _this . lock ( ) ) ;
} ) ;
return command_result { error : : ok } ;
*/
}
command_result ConnectedClient : : handleCommandMusicBotPlaylistAssign ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = ref_server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return command_result { error : : music_invalid_id } ;
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 ) ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist & & cmd [ " playlist_id " ] ! = 0 ) return command_result { error : : playlist_invalid_id } ;
if ( ref_server - > musicManager - > find_bot_by_playlist ( playlist ) )
return command_result { error : : playlist_already_in_use } ;
2020-02-01 14:32:16 +01:00
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 } ;
2020-01-26 14:21:34 +01:00
if ( ! ref_server - > musicManager - > assign_playlist ( bot , playlist ) )
return command_result { error : : vs_critical } ;
return command_result { error : : ok } ;
}
2020-02-02 14:58:46 +01:00
command_result ConnectedClient : : handleCommandPlaylistSetSubscription ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( ! config : : music : : enabled ) return command_result { error : : music_disabled } ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist & & cmd [ " playlist_id " ] ! = 0 ) return command_result { error : : playlist_invalid_id } ;
{
auto old_playlist = this - > _subscribed_playlist . lock ( ) ;
if ( old_playlist )
old_playlist - > remove_subscriber ( _this . lock ( ) ) ;
}
if ( playlist ) {
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 } ;
playlist - > add_subscriber ( _this . lock ( ) ) ;
this - > _subscribed_playlist = playlist ;
}
return command_result { error : : ok } ;
}
2020-01-26 14:21:34 +01:00