2018-02-27 17:20:49 +01:00
/// <reference path="channel.ts" />
2018-04-11 17:56:09 +02:00
/// <reference path="modal/ModalChangeVolume.ts" />
2018-11-04 00:39:29 +01:00
/// <reference path="client_move.ts" />
2018-02-27 17:20:49 +01:00
2018-04-30 23:57:21 +02:00
enum ClientType {
CLIENT_VOICE ,
CLIENT_QUERY ,
CLIENT_INTERNAL ,
CLIENT_WEB ,
CLIENT_MUSIC ,
CLIENT_UNDEFINED
}
2018-04-16 20:38:35 +02:00
class ClientProperties {
2018-04-30 23:57:21 +02:00
client_type : ClientType = ClientType . CLIENT_VOICE ; //TeamSpeaks type
client_type_exact : ClientType = ClientType . CLIENT_VOICE ;
2018-08-10 21:30:58 +02:00
client_database_id : number = 0 ;
2018-04-16 20:38:35 +02:00
client_version : string = "" ;
client_platform : string = "" ;
client_nickname : string = "unknown" ;
client_unique_identifier : string = "unknown" ;
client_description : string = "" ;
client_servergroups : string = "" ;
client_channel_group_id : number = 0 ;
client_lastconnected : number = 0 ;
2019-08-30 23:06:39 +02:00
client_created : number = 0 ;
client_totalconnections : number = 0 ;
2018-04-16 20:38:35 +02:00
client_flag_avatar : string = "" ;
2018-08-12 14:14:50 +02:00
client_icon_id : number = 0 ;
2018-04-16 20:38:35 +02:00
client_away_message : string = "" ;
client_away : boolean = false ;
2019-08-21 10:00:01 +02:00
client_country : string = "" ;
2018-04-16 20:38:35 +02:00
client_input_hardware : boolean = false ;
2018-04-30 23:57:21 +02:00
client_output_hardware : boolean = false ;
2018-04-16 20:38:35 +02:00
client_input_muted : boolean = false ;
2018-04-30 23:57:21 +02:00
client_output_muted : boolean = false ;
2018-04-16 20:38:35 +02:00
client_is_channel_commander : boolean = false ;
2018-04-30 23:57:21 +02:00
2019-08-21 10:00:01 +02:00
client_teaforo_id : number = 0 ;
client_teaforo_name : string = "" ;
client_teaforo_flags : number = 0 ; /* 0x01 := Banned | 0x02 := Stuff | 0x04 := Premium */
2018-08-12 13:26:56 +02:00
2019-08-30 23:06:39 +02:00
/* not updated in view! */
client_month_bytes_uploaded : number = 0 ;
client_month_bytes_downloaded : number = 0 ;
client_total_bytes_uploaded : number = 0 ;
client_total_bytes_downloaded : number = 0 ;
2018-08-12 13:26:56 +02:00
client_talk_power : number = 0 ;
2018-04-16 20:38:35 +02:00
}
2019-08-30 23:06:39 +02:00
class ClientConnectionInfo {
connection_bandwidth_received_last_minute_control : number = - 1 ;
connection_bandwidth_received_last_minute_keepalive : number = - 1 ;
connection_bandwidth_received_last_minute_speech : number = - 1 ;
connection_bandwidth_received_last_second_control : number = - 1 ;
connection_bandwidth_received_last_second_keepalive : number = - 1 ;
connection_bandwidth_received_last_second_speech : number = - 1 ;
connection_bandwidth_sent_last_minute_control : number = - 1 ;
connection_bandwidth_sent_last_minute_keepalive : number = - 1 ;
connection_bandwidth_sent_last_minute_speech : number = - 1 ;
connection_bandwidth_sent_last_second_control : number = - 1 ;
connection_bandwidth_sent_last_second_keepalive : number = - 1 ;
connection_bandwidth_sent_last_second_speech : number = - 1 ;
connection_bytes_received_control : number = - 1 ;
connection_bytes_received_keepalive : number = - 1 ;
connection_bytes_received_speech : number = - 1 ;
connection_bytes_sent_control : number = - 1 ;
connection_bytes_sent_keepalive : number = - 1 ;
connection_bytes_sent_speech : number = - 1 ;
connection_packets_received_control : number = - 1 ;
connection_packets_received_keepalive : number = - 1 ;
connection_packets_received_speech : number = - 1 ;
connection_packets_sent_control : number = - 1 ;
connection_packets_sent_keepalive : number = - 1 ;
connection_packets_sent_speech : number = - 1 ;
connection_ping : number = - 1 ;
connection_ping_deviation : number = - 1 ;
connection_server2client_packetloss_control : number = - 1 ;
connection_server2client_packetloss_keepalive : number = - 1 ;
connection_server2client_packetloss_speech : number = - 1 ;
connection_server2client_packetloss_total : number = - 1 ;
connection_client2server_packetloss_speech : number = - 1 ;
connection_client2server_packetloss_keepalive : number = - 1 ;
connection_client2server_packetloss_control : number = - 1 ;
connection_client2server_packetloss_total : number = - 1 ;
connection_filetransfer_bandwidth_sent : number = - 1 ;
connection_filetransfer_bandwidth_received : number = - 1 ;
connection_connected_time : number = - 1 ;
connection_idle_time : number = - 1 ;
connection_client_ip : string | undefined ;
connection_client_port : number = - 1 ;
}
2018-02-27 17:20:49 +01:00
class ClientEntry {
2018-04-30 23:57:21 +02:00
protected _clientId : number ;
protected _channel : ChannelEntry ;
protected _tag : JQuery < HTMLElement > ;
2018-04-16 20:38:35 +02:00
2018-04-30 23:57:21 +02:00
protected _properties : ClientProperties ;
protected lastVariableUpdate : number = 0 ;
2019-08-21 10:00:01 +02:00
protected _speaking : boolean ;
2019-04-04 21:47:52 +02:00
protected _listener_initialized : boolean ;
2019-08-21 10:00:01 +02:00
2019-04-04 21:47:52 +02:00
protected _audio_handle : connection.voice.VoiceClient ;
2019-08-21 10:00:01 +02:00
protected _audio_volume : number ;
protected _audio_muted : boolean ;
2018-02-27 17:20:49 +01:00
2019-08-30 23:06:39 +02:00
private _info_variables_promise : Promise < void > ;
private _info_variables_promise_timestamp : number ;
private _info_connection_promise : Promise < ClientConnectionInfo > ;
private _info_connection_promise_timestamp : number ;
private _info_connection_promise_resolve : any ;
private _info_connection_promise_reject : any ;
2018-02-27 17:20:49 +01:00
channelTree : ChannelTree ;
2019-04-04 21:47:52 +02:00
constructor ( clientId : number , clientName , properties : ClientProperties = new ClientProperties ( ) ) {
2018-04-30 23:57:21 +02:00
this . _properties = properties ;
this . _properties . client_nickname = clientName ;
2018-02-27 17:20:49 +01:00
this . _clientId = clientId ;
this . channelTree = null ;
this . _channel = null ;
2019-04-04 21:47:52 +02:00
}
2019-08-21 10:00:01 +02:00
destroy() {
if ( this . _tag ) {
this . _tag . remove ( ) ;
this . _tag = undefined ;
}
if ( this . _audio_handle ) {
2019-10-13 21:33:07 +02:00
log . warn ( LogCategory . AUDIO , tr ( "Destroying client with an active audio handle. This could cause memory leaks!" ) ) ;
2019-10-19 17:13:40 +02:00
try {
this . _audio_handle . abort_replay ( ) ;
} catch ( error ) {
log . warn ( LogCategory . AUDIO , tr ( "Failed to abort replay: %o" ) , error ) ;
}
2019-08-21 10:00:01 +02:00
this . _audio_handle . callback_playback = undefined ;
this . _audio_handle . callback_stopped = undefined ;
this . _audio_handle = undefined ;
}
this . _channel = undefined ;
}
tree_unregistered() {
this . channelTree = undefined ;
if ( this . _audio_handle ) {
2019-10-19 17:13:40 +02:00
try {
this . _audio_handle . abort_replay ( ) ;
} catch ( error ) {
log . warn ( LogCategory . AUDIO , tr ( "Failed to abort replay: %o" ) , error ) ;
}
2019-08-21 10:00:01 +02:00
this . _audio_handle . callback_playback = undefined ;
this . _audio_handle . callback_stopped = undefined ;
this . _audio_handle = undefined ;
}
this . _channel = undefined ;
}
2019-04-04 21:47:52 +02:00
set_audio_handle ( handle : connection.voice.VoiceClient ) {
if ( this . _audio_handle === handle )
return ;
2019-08-21 10:00:01 +02:00
if ( this . _audio_handle ) {
this . _audio_handle . callback_playback = undefined ;
this . _audio_handle . callback_stopped = undefined ;
}
2019-04-04 21:47:52 +02:00
//TODO may ensure that the id is the same?
this . _audio_handle = handle ;
if ( ! handle ) {
this . speaking = false ;
return ;
}
2018-02-27 17:20:49 +01:00
2019-04-04 21:47:52 +02:00
handle . callback_playback = ( ) = > this . speaking = true ;
handle . callback_stopped = ( ) = > this . speaking = false ;
}
2018-02-27 17:20:49 +01:00
2019-04-04 21:47:52 +02:00
get_audio_handle ( ) : connection . voice . VoiceClient {
return this . _audio_handle ;
2018-02-27 17:20:49 +01:00
}
2018-04-30 23:57:21 +02:00
get properties ( ) : ClientProperties {
return this . _properties ;
}
2018-11-04 00:39:29 +01:00
currentChannel ( ) : ChannelEntry { return this . _channel ; }
2018-02-27 17:20:49 +01:00
clientNickName ( ) { return this . properties . client_nickname ; }
clientUid ( ) { return this . properties . client_unique_identifier ; }
clientId ( ) { return this . _clientId ; }
2019-08-21 10:00:01 +02:00
is_muted() { return ! ! this . _audio_muted ; }
set_muted ( flag : boolean , update_icon : boolean , force? : boolean ) {
if ( this . _audio_muted === flag && ! force )
return ;
if ( flag ) {
this . channelTree . client . serverConnection . send_command ( 'clientmute' , {
clid : this.clientId ( )
} ) ;
} else if ( this . _audio_muted ) {
this . channelTree . client . serverConnection . send_command ( 'clientunmute' , {
clid : this.clientId ( )
} ) ;
}
this . _audio_muted = flag ;
this . channelTree . client . settings . changeServer ( "mute_client_" + this . clientUid ( ) , flag ) ;
if ( this . _audio_handle ) {
if ( flag ) {
this . _audio_handle . set_volume ( 0 ) ;
} else {
this . _audio_handle . set_volume ( this . _audio_volume ) ;
}
}
if ( update_icon )
this . updateClientSpeakIcon ( ) ;
for ( const client of this . channelTree . clients ) {
if ( client === this || client . properties . client_unique_identifier != this . properties . client_unique_identifier )
continue ;
client . set_muted ( flag , true ) ;
}
}
2019-10-13 21:33:07 +02:00
protected initializeListener() {
2018-11-04 13:54:18 +01:00
if ( this . _listener_initialized ) return ;
this . _listener_initialized = true ;
2019-01-19 15:21:37 +01:00
this . tag . on ( 'mouseup' , event = > {
if ( ! this . channelTree . client_mover . is_active ( ) ) {
this . channelTree . onSelect ( this ) ;
}
} ) ;
2019-04-04 21:47:52 +02:00
2018-11-04 15:59:54 +01:00
if ( ! ( this instanceof LocalClientEntry ) && ! ( this instanceof MusicClientEntry ) )
2018-11-04 00:39:29 +01:00
this . tag . dblclick ( event = > {
2018-11-04 13:54:18 +01:00
if ( $ . isArray ( this . channelTree . currently_selected ) ) { //Multiselect
return ;
}
2019-08-21 10:00:01 +02:00
this . open_text_chat ( ) ;
2018-11-04 00:39:29 +01:00
} ) ;
2018-04-16 20:38:35 +02:00
if ( ! settings . static ( Settings . KEY_DISABLE_CONTEXT_MENU , false ) ) {
2018-11-04 13:54:18 +01:00
this . tag . on ( "contextmenu" , ( event ) = > {
2018-04-16 20:38:35 +02:00
event . preventDefault ( ) ;
2018-11-04 13:54:18 +01:00
if ( $ . isArray ( this . channelTree . currently_selected ) ) { //Multiselect
( this . channelTree . currently_selected_context_callback || ( ( _ ) = > null ) ) ( event ) ;
return ;
}
this . channelTree . onSelect ( this , true ) ;
2019-01-19 15:21:37 +01:00
this . showContextMenu ( event . pageX , event . pageY , ( ) = > { } ) ;
2018-04-16 20:38:35 +02:00
return false ;
2018-02-27 17:20:49 +01:00
} ) ;
2018-04-16 20:38:35 +02:00
}
2018-11-04 00:39:29 +01:00
2019-04-04 21:47:52 +02:00
this . tag . on ( 'mousedown' , event = > {
2018-11-04 13:54:18 +01:00
if ( event . which != 1 ) return ; //Only the left button
2019-01-19 15:21:37 +01:00
let clients = this . channelTree . currently_selected as ( ClientEntry | ClientEntry [ ] ) ;
2019-01-20 18:43:14 +01:00
if ( ppt . key_pressed ( ppt . SpecialKey . SHIFT ) ) {
if ( clients != this && ! ( $ . isArray ( clients ) && clients . indexOf ( this ) != - 1 ) )
clients = $ . isArray ( clients ) ? [ . . . clients , this ] : [ clients , this ] ;
} else {
clients = this ;
}
2019-01-19 15:21:37 +01:00
this . channelTree . client_mover . activate ( clients , target = > {
2018-11-04 00:39:29 +01:00
if ( ! target ) return ;
2019-01-19 15:21:37 +01:00
for ( const client of $ . isArray ( clients ) ? clients : [ clients ] ) {
if ( target == client . _channel ) continue ;
const source = client . _channel ;
const self = this . channelTree . client . getClient ( ) ;
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientmove" , {
2019-01-19 15:21:37 +01:00
clid : client.clientId ( ) ,
cid : target.getChannelId ( )
} ) . then ( event = > {
if ( client . clientId ( ) == this . channelTree . client . clientId )
2019-04-04 21:47:52 +02:00
this . channelTree . client . sound . play ( Sound . CHANNEL_JOINED ) ;
2019-01-19 15:21:37 +01:00
else if ( target !== source && target != self . currentChannel ( ) )
2019-04-04 21:47:52 +02:00
this . channelTree . client . sound . play ( Sound . USER_MOVED ) ;
2019-01-19 15:21:37 +01:00
} ) ;
}
this . channelTree . onSelect ( ) ;
2018-11-04 00:39:29 +01:00
} , event ) ;
} ) ;
2018-02-27 17:20:49 +01:00
}
2019-08-21 10:00:01 +02:00
protected contextmenu_info ( ) : contextmenu . MenuEntry [ ] {
return [
{
type : contextmenu . MenuEntryType . ENTRY ,
name : this.properties.client_type_exact === ClientType . CLIENT_MUSIC ? tr ( "Show bot info" ) : tr ( "Show client info" ) ,
callback : ( ) = > {
this . channelTree . client . side_bar . show_client_info ( this ) ;
} ,
icon_class : "client-about" ,
visible : ! settings . static_global ( Settings . KEY_SWITCH_INSTANT_CLIENT )
} , {
callback : ( ) = > { } ,
type : contextmenu . MenuEntryType . HR ,
name : "" ,
visible : ! settings . static_global ( Settings . KEY_SWITCH_INSTANT_CLIENT )
}
]
}
2019-06-30 16:03:28 +02:00
protected assignment_context ( ) : contextmenu . MenuEntry [ ] {
let server_groups : contextmenu.MenuEntry [ ] = [ ] ;
2018-09-30 21:50:59 +02:00
for ( let group of this . channelTree . client . groups . serverGroups . sort ( GroupManager . sorter ( ) ) ) {
2018-09-30 22:47:41 +02:00
if ( group . type != GroupType . NORMAL ) continue ;
2018-09-30 21:50:59 +02:00
2019-06-30 16:03:28 +02:00
let entry : contextmenu.MenuEntry = { } as any ;
2018-09-30 21:50:59 +02:00
2019-06-30 16:03:28 +02:00
//TODO: May add the server group icon?
entry . checkbox_checked = this . groupAssigned ( group ) ;
2018-09-30 21:50:59 +02:00
entry . name = group . name + " [" + ( group . properties . savedb ? "perm" : "tmp" ) + "]" ;
if ( this . groupAssigned ( group ) ) {
entry . callback = ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "servergroupdelclient" , {
2018-09-30 21:50:59 +02:00
sgid : group.id ,
cldbid : this.properties.client_database_id
} ) ;
} ;
entry . disabled = ! this . channelTree . client . permissions . neededPermission ( PermissionType . I_GROUP_MEMBER_ADD_POWER ) . granted ( group . requiredMemberRemovePower ) ;
} else {
entry . callback = ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "servergroupaddclient" , {
2018-09-30 21:50:59 +02:00
sgid : group.id ,
cldbid : this.properties.client_database_id
} ) ;
} ;
entry . disabled = ! this . channelTree . client . permissions . neededPermission ( PermissionType . I_GROUP_MEMBER_REMOVE_POWER ) . granted ( group . requiredMemberAddPower ) ;
}
2019-06-30 16:03:28 +02:00
entry . type = contextmenu . MenuEntryType . CHECKBOX ;
2018-09-30 21:50:59 +02:00
server_groups . push ( entry ) ;
}
2019-06-30 16:03:28 +02:00
let channel_groups : contextmenu.MenuEntry [ ] = [ ] ;
2018-09-30 21:50:59 +02:00
for ( let group of this . channelTree . client . groups . channelGroups . sort ( GroupManager . sorter ( ) ) ) {
if ( group . type != GroupType . NORMAL ) continue ;
2019-06-30 16:03:28 +02:00
let entry : contextmenu.MenuEntry = { } as any ;
//TODO: May add the channel group icon?
entry . checkbox_checked = this . assignedChannelGroup ( ) == group . id ;
2018-09-30 21:50:59 +02:00
entry . name = group . name + " [" + ( group . properties . savedb ? "perm" : "tmp" ) + "]" ;
entry . callback = ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "setclientchannelgroup" , {
2018-09-30 21:50:59 +02:00
cldbid : this.properties.client_database_id ,
cgid : group.id ,
cid : this.currentChannel ( ) . channelId
} ) ;
} ;
entry . disabled = ! this . channelTree . client . permissions . neededPermission ( PermissionType . I_GROUP_MEMBER_ADD_POWER ) . granted ( group . requiredMemberRemovePower ) ;
2019-06-30 16:03:28 +02:00
entry . type = contextmenu . MenuEntryType . CHECKBOX ;
2018-09-30 21:50:59 +02:00
channel_groups . push ( entry ) ;
}
return [ {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . SUB_MENU ,
icon_class : "client-permission_server_groups" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Set server group" ) ,
2018-09-30 21:50:59 +02:00
sub_menu : [
{
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
2019-08-21 10:00:01 +02:00
icon_class : "client-permission_server_groups" ,
2018-09-30 21:50:59 +02:00
name : "Server groups dialog" ,
2019-09-19 01:25:57 +02:00
callback : ( ) = > this . open_assignment_modal ( )
2018-09-30 21:50:59 +02:00
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-09-30 21:50:59 +02:00
. . . server_groups
]
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . SUB_MENU ,
icon_class : "client-permission_channel" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Set channel group" ) ,
2018-09-30 21:50:59 +02:00
sub_menu : [
. . . channel_groups
]
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . SUB_MENU ,
icon_class : "client-permission_client" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Permissions" ) ,
2019-08-21 10:00:01 +02:00
sub_menu : [
{
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-permission_client" ,
name : tr ( "Client permissions" ) ,
callback : ( ) = > Modals . spawnPermissionEdit ( this . channelTree . client , "clp" , { unique_id : this.clientUid ( ) } ) . open ( )
} ,
{
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-permission_client" ,
name : tr ( "Client channel permissions" ) ,
callback : ( ) = > Modals . spawnPermissionEdit ( this . channelTree . client , "clchp" , { unique_id : this.clientUid ( ) , channel_id : this._channel ? this . _channel.channelId : undefined } ) . open ( )
}
]
2018-09-30 21:50:59 +02:00
} ] ;
}
2019-09-19 01:25:57 +02:00
open_assignment_modal() {
Modals . createServerGroupAssignmentModal ( this , ( groups , flag ) = > {
if ( groups . length == 0 ) return Promise . resolve ( true ) ;
if ( groups . length == 1 ) {
if ( flag ) {
return this . channelTree . client . serverConnection . send_command ( "servergroupaddclient" , {
sgid : groups [ 0 ] ,
cldbid : this.properties.client_database_id
} ) . then ( result = > true ) ;
} else
return this . channelTree . client . serverConnection . send_command ( "servergroupdelclient" , {
sgid : groups [ 0 ] ,
cldbid : this.properties.client_database_id
} ) . then ( result = > true ) ;
} else {
const data = groups . map ( e = > { return { sgid : e } ; } ) ;
data [ 0 ] [ "cldbid" ] = this . properties . client_database_id ;
if ( flag ) {
return this . channelTree . client . serverConnection . send_command ( "clientaddservergroup" , data , { flagset : [ "continueonerror" ] } ) . then ( result = > true ) ;
} else
return this . channelTree . client . serverConnection . send_command ( "clientdelservergroup" , data , { flagset : [ "continueonerror" ] } ) . then ( result = > true ) ;
}
} ) ;
}
2019-08-21 10:00:01 +02:00
open_text_chat() {
const chat = this . channelTree . client . side_bar ;
const conversation = chat . private_conversations ( ) . find_conversation ( {
name : this.clientNickName ( ) ,
client_id : this.clientId ( ) ,
unique_id : this.clientUid ( )
} , {
attach : true ,
create : true
} ) ;
chat . private_conversations ( ) . set_selected_conversation ( conversation ) ;
chat . show_private_conversations ( ) ;
chat . private_conversations ( ) . try_input_focus ( ) ;
}
2018-02-27 17:20:49 +01:00
showContextMenu ( x : number , y : number , on_close : ( ) = > void = undefined ) {
2019-03-07 15:30:53 +01:00
let trigger_close = true ;
2019-06-30 16:03:28 +02:00
contextmenu . spawn_context_menu ( x , y ,
2019-08-21 10:00:01 +02:00
. . . this . contextmenu_info ( ) , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-change_nickname" ,
name : ( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "<b>" : "" ) +
tr ( "Open text chat" ) +
( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "</b>" : "" ) ,
2019-03-07 15:30:53 +01:00
callback : ( ) = > {
2019-08-21 10:00:01 +02:00
this . open_text_chat ( ) ;
2018-02-27 17:20:49 +01:00
}
2019-09-19 01:25:57 +02:00
} ,
contextmenu . Entry . HR ( ) ,
{
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-about" ,
name : tr ( "Show client info" ) ,
callback : ( ) = > Modals . openClientInfo ( this )
} ,
contextmenu . Entry . HR ( ) ,
{
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-poke" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Poke client" ) ,
2019-03-07 15:30:53 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Poke client" ) , tr ( "Poke message:<br>" ) , text = > true , result = > {
2018-09-30 22:36:17 +02:00
if ( typeof ( result ) === "string" ) {
2018-12-05 20:46:33 +01:00
//TODO tr
2019-03-07 15:30:53 +01:00
console . log ( "Poking client " + this . clientNickName ( ) + " with message " + result ) ;
this . channelTree . client . serverConnection . send_command ( "clientpoke" , {
clid : this.clientId ( ) ,
2018-02-27 17:20:49 +01:00
msg : result
} ) ;
}
} , { width : 400 , maxLength : 512 } ) . open ( ) ;
}
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-edit" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Change description" ) ,
2019-03-07 15:30:53 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Change client description" ) , tr ( "New description:<br>" ) , text = > true , result = > {
2018-09-30 22:36:17 +02:00
if ( typeof ( result ) === "string" ) {
2018-12-05 20:46:33 +01:00
//TODO tr
2019-03-07 15:30:53 +01:00
console . log ( "Changing " + this . clientNickName ( ) + "'s description to " + result ) ;
this . channelTree . client . serverConnection . send_command ( "clientedit" , {
clid : this.clientId ( ) ,
2018-02-27 17:20:49 +01:00
client_description : result
} ) ;
}
} , { width : 400 , maxLength : 1024 } ) . open ( ) ;
}
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-09-30 21:50:59 +02:00
. . . this . assignment_context ( ) ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) , {
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-move_client_to_own_channel" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Move client to your channel" ) ,
2018-04-11 17:56:09 +02:00
callback : ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientmove" , {
2018-04-11 17:56:09 +02:00
clid : this.clientId ( ) ,
cid : this.channelTree.client.getClient ( ) . currentChannel ( ) . getChannelId ( )
} ) ;
}
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-kick_channel" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Kick client from channel" ) ,
2018-11-04 13:54:18 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Kick client from channel" ) , tr ( "Kick reason:<br>" ) , text = > true , result = > {
2019-03-17 12:39:21 +01:00
if ( typeof ( result ) !== 'boolean' || result ) {
2018-12-05 20:46:33 +01:00
//TODO tr
2019-03-07 15:30:53 +01:00
console . log ( "Kicking client " + this . clientNickName ( ) + " from channel with reason " + result ) ;
this . channelTree . client . serverConnection . send_command ( "clientkick" , {
clid : this.clientId ( ) ,
2018-02-27 17:20:49 +01:00
reasonid : ViewReasonId.VREASON_CHANNEL_KICK ,
reasonmsg : result
} ) ;
}
} , { width : 400 , maxLength : 255 } ) . open ( ) ;
}
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-kick_server" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Kick client fom server" ) ,
2018-11-04 13:54:18 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Kick client from server" ) , tr ( "Kick reason:<br>" ) , text = > true , result = > {
2019-03-17 12:39:21 +01:00
if ( typeof ( result ) !== 'boolean' || result ) {
2018-12-05 20:46:33 +01:00
//TODO tr
2019-03-07 15:30:53 +01:00
console . log ( "Kicking client " + this . clientNickName ( ) + " from server with reason " + result ) ;
this . channelTree . client . serverConnection . send_command ( "clientkick" , {
clid : this.clientId ( ) ,
2018-02-27 17:20:49 +01:00
reasonid : ViewReasonId.VREASON_SERVER_KICK ,
reasonmsg : result
} ) ;
}
} , { width : 400 , maxLength : 255 } ) . open ( ) ;
}
2018-04-11 17:56:09 +02:00
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-ban_client" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Ban client" ) ,
2018-04-30 23:57:21 +02:00
invalidPermission : ! this . channelTree . client . permissions . neededPermission ( PermissionType . I_CLIENT_BAN_MAX_BANTIME ) . granted ( 1 ) ,
callback : ( ) = > {
2019-09-19 01:25:57 +02:00
Modals . spawnBanClient ( this . channelTree . client , [ {
name : this.properties.client_nickname ,
unique_id : this.properties.client_unique_identifier
} ] , ( data ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "banclient" , {
2018-04-30 23:57:21 +02:00
uid : this.properties.client_unique_identifier ,
2018-10-20 19:58:06 +02:00
banreason : data.reason ,
time : data.length
2019-02-23 14:15:22 +01:00
} , {
flagset : [ data . no_ip ? "no-ip" : "" , data . no_hwid ? "no-hardware-id" : "" , data . no_name ? "no-nickname" : "" ]
} ) . then ( ( ) = > {
2019-04-04 21:47:52 +02:00
this . channelTree . client . sound . play ( Sound . USER_BANNED ) ;
2018-11-04 00:39:29 +01:00
} ) ;
2018-04-30 23:57:21 +02:00
} ) ;
}
2018-04-11 17:56:09 +02:00
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-09-26 15:04:56 +02:00
/ *
{
type : MenuEntryType . ENTRY ,
icon : "client-kick_server" ,
name : "Add group to client" ,
invalidPermission : true , //!this.channelTree.client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).granted(1),
callback : ( ) = > {
Modals . spawnBanClient ( this . properties . client_nickname , ( duration , reason ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "banclient" , {
2018-09-26 15:04:56 +02:00
uid : this.properties.client_unique_identifier ,
banreason : reason ,
time : duration
} ) ;
} ) ;
}
} ,
MenuEntry . HR ( ) ,
* /
2018-04-11 17:56:09 +02:00
{
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-volume" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Change Volume" ) ,
2018-04-11 17:56:09 +02:00
callback : ( ) = > {
2019-10-13 21:33:07 +02:00
Modals . spawnChangeVolume ( this , true , this . _audio_volume , undefined , volume = > {
2019-08-21 10:00:01 +02:00
this . _audio_volume = volume ;
2019-04-04 21:47:52 +02:00
this . channelTree . client . settings . changeServer ( "volume_client_" + this . clientUid ( ) , volume ) ;
2019-08-21 10:00:01 +02:00
if ( this . _audio_handle )
this . _audio_handle . set_volume ( volume ) ;
2019-08-30 23:06:39 +02:00
//TODO: Update in info
2018-04-11 17:56:09 +02:00
} ) ;
}
2019-08-21 10:00:01 +02:00
} , {
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-input_muted_local" ,
name : tr ( "Mute client" ) ,
visible : ! this . _audio_muted ,
callback : ( ) = > this . set_muted ( true , true )
} , {
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-input_muted_local" ,
name : tr ( "Unmute client" ) ,
visible : this._audio_muted ,
callback : ( ) = > this . set_muted ( false , true )
2018-02-27 17:20:49 +01:00
} ,
2019-09-01 17:24:06 +02:00
contextmenu . Entry . CLOSE ( ( ) = > trigger_close ? on_close ( ) : { } )
2018-02-27 17:20:49 +01:00
) ;
}
2018-04-16 20:38:35 +02:00
get tag ( ) : JQuery < HTMLElement > {
if ( this . _tag ) return this . _tag ;
2018-02-27 17:20:49 +01:00
2019-02-17 16:08:10 +01:00
let container_client = $ . spawn ( "div" )
. addClass ( "tree-entry client" )
. attr ( "client-id" , this . clientId ( ) ) ;
2018-02-27 17:20:49 +01:00
2019-09-19 01:25:57 +02:00
/* unread marker */
{
container_client . append (
$ . spawn ( "div" )
. addClass ( "marker-text-unread hidden" )
. attr ( "private-conversation" , this . _clientId )
) ;
}
2019-02-17 16:08:10 +01:00
container_client . append (
$ . spawn ( "div" )
. addClass ( "icon_client_state" )
. attr ( "title" , "Client state" )
) ;
container_client . append (
$ . spawn ( "div" )
. addClass ( "group-prefix" )
. attr ( "title" , "Server groups prefixes" )
. hide ( )
) ;
container_client . append (
$ . spawn ( "div" )
. addClass ( "client-name" )
. text ( this . clientNickName ( ) )
) ;
container_client . append (
$ . spawn ( "div" )
. addClass ( "group-suffix" )
. attr ( "title" , "Server groups suffix" )
. hide ( )
) ;
container_client . append (
$ . spawn ( "div" )
. addClass ( "client-away-message" )
. text ( this . clientNickName ( ) )
) ;
2018-02-27 17:20:49 +01:00
2019-02-17 16:08:10 +01:00
let container_icons = $ . spawn ( "div" ) . addClass ( "container-icons" ) ;
2018-02-27 17:20:49 +01:00
2019-02-17 16:08:10 +01:00
container_icons . append (
$ . spawn ( "div" )
. addClass ( "icon icon_talk_power client-input_muted" )
. hide ( )
) ;
container_icons . append (
$ . spawn ( "div" )
. addClass ( "container-icons-group" )
) ;
container_icons . append (
$ . spawn ( "div" )
. addClass ( "container-icon-client" )
) ;
container_client . append ( container_icons ) ;
2018-02-27 17:20:49 +01:00
2019-02-17 16:08:10 +01:00
this . _tag = container_client ;
2018-11-04 15:48:52 +01:00
this . initializeListener ( ) ;
return this . _tag ;
2018-02-27 17:20:49 +01:00
}
2019-01-20 18:43:14 +01:00
static bbcodeTag ( id : number , name : string , uid : string ) : string {
return "[url=client://" + id + "/" + uid + "~" + encodeURIComponent ( name ) + "]" + name + "[/url]" ;
}
2018-04-30 23:57:21 +02:00
2019-01-20 18:43:14 +01:00
static chatTag ( id : number , name : string , uid : string , braces : boolean = false ) : JQuery {
return $ ( htmltags . generate_client ( {
client_name : name ,
client_id : id ,
client_unique_id : uid ,
add_braces : braces
} ) ) ;
}
2018-04-30 23:57:21 +02:00
2019-01-20 18:43:14 +01:00
create_bbcode ( ) : string {
return ClientEntry . bbcodeTag ( this . clientId ( ) , this . clientNickName ( ) , this . clientUid ( ) ) ;
2018-02-27 17:20:49 +01:00
}
2018-04-11 17:56:09 +02:00
createChatTag ( braces : boolean = false ) : JQuery {
2018-02-27 17:20:49 +01:00
return ClientEntry . chatTag ( this . clientId ( ) , this . clientNickName ( ) , this . clientUid ( ) , braces ) ;
}
set speaking ( flag ) {
2019-08-21 10:00:01 +02:00
if ( flag === this . _speaking ) return ;
2018-02-27 17:20:49 +01:00
this . _speaking = flag ;
2018-08-12 13:26:56 +02:00
this . updateClientSpeakIcon ( ) ;
}
updateClientStatusIcons() {
let talk_power = this . properties . client_talk_power >= this . _channel . properties . channel_needed_talk_power ;
if ( talk_power )
2019-02-17 16:08:10 +01:00
this . tag . find ( ".icon_talk_power" ) . hide ( ) ;
2018-08-12 13:26:56 +02:00
else
2019-02-17 16:08:10 +01:00
this . tag . find ( ".icon_talk_power" ) . show ( ) ;
2018-02-27 17:20:49 +01:00
}
2018-08-12 13:26:56 +02:00
updateClientSpeakIcon() {
2018-02-27 17:20:49 +01:00
let icon : string = "" ;
let clicon : string = "" ;
2018-11-20 15:06:18 +01:00
if ( this . properties . client_type_exact == ClientType . CLIENT_QUERY ) {
icon = "client-server_query" ;
console . log ( "Server query!" ) ;
2018-02-27 17:20:49 +01:00
} else {
2019-08-21 10:00:01 +02:00
if ( this . properties . client_away ) {
2018-11-20 15:06:18 +01:00
icon = "client-away" ;
2019-08-21 10:00:01 +02:00
} else if ( this . _audio_muted && ! ( this instanceof LocalClientEntry ) ) {
icon = "client-input_muted_local" ;
2018-11-20 15:06:18 +01:00
} else if ( ! this . properties . client_output_hardware ) {
icon = "client-hardware_output_muted" ;
} else if ( this . properties . client_output_muted ) {
icon = "client-output_muted" ;
} else if ( ! this . properties . client_input_hardware ) {
icon = "client-hardware_input_muted" ;
} else if ( this . properties . client_input_muted ) {
icon = "client-input_muted" ;
2018-02-27 17:20:49 +01:00
} else {
2018-11-20 15:06:18 +01:00
if ( this . _speaking ) {
if ( this . properties . client_is_channel_commander )
clicon = "client_cc_talk" ;
else
clicon = "client_talk" ;
} else {
if ( this . properties . client_is_channel_commander )
clicon = "client_cc_idle" ;
else
clicon = "client_idle" ;
}
2018-02-27 17:20:49 +01:00
}
}
2018-11-20 15:06:18 +01:00
2018-02-27 17:20:49 +01:00
if ( clicon . length > 0 )
2018-04-16 20:38:35 +02:00
this . tag . find ( ".icon_client_state" ) . attr ( 'class' , 'icon_client_state clicon ' + clicon ) ;
2018-02-27 17:20:49 +01:00
else if ( icon . length > 0 )
2018-04-16 20:38:35 +02:00
this . tag . find ( ".icon_client_state" ) . attr ( 'class' , 'icon_client_state icon ' + icon ) ;
2018-02-27 17:20:49 +01:00
else
2018-04-16 20:38:35 +02:00
this . tag . find ( ".icon_client_state" ) . attr ( 'class' , 'icon_client_state icon_empty' ) ;
2018-02-27 17:20:49 +01:00
}
updateAwayMessage() {
2019-02-17 16:08:10 +01:00
let tag = this . tag . find ( ".client-away-message" ) ;
2018-04-16 20:38:35 +02:00
if ( this . properties . client_away == true && this . properties . client_away_message ) {
2018-02-27 17:20:49 +01:00
tag . text ( "[" + this . properties . client_away_message + "]" ) ;
tag . show ( ) ;
} else {
tag . hide ( ) ;
}
}
2018-04-16 20:38:35 +02:00
updateVariables ( . . . variables : { key : string , value : string } [ ] ) {
2018-12-05 20:46:33 +01:00
let group = log . group ( log . LogType . DEBUG , LogCategory . CLIENT , tr ( "Update properties (%i) of %s (%i)" ) , variables . length , this . clientNickName ( ) , this . clientId ( ) ) ;
2018-04-16 20:38:35 +02:00
2018-11-20 15:06:18 +01:00
let update_icon_status = false ;
let update_icon_speech = false ;
let update_away = false ;
let reorder_channel = false ;
2019-08-21 10:00:01 +02:00
let update_avatar = false ;
2018-11-20 15:06:18 +01:00
2019-03-25 20:04:04 +01:00
{
const entries = [ ] ;
for ( const variable of variables )
entries . push ( {
key : variable.key ,
value : variable.value ,
type : typeof ( this . properties [ variable . key ] )
} ) ;
2019-08-30 23:06:39 +02:00
log . table ( LogType . DEBUG , LogCategory . PERMISSIONS , "Client update properties" , entries ) ;
2019-03-25 20:04:04 +01:00
}
2019-04-04 21:47:52 +02:00
for ( const variable of variables ) {
2019-08-21 10:00:01 +02:00
const old_value = this . _properties [ variable . key ] ;
2018-08-10 21:30:58 +02:00
JSON . map_field_to ( this . _properties , variable . value , variable . key ) ;
2018-04-16 20:38:35 +02:00
if ( variable . key == "client_nickname" ) {
2019-08-21 10:00:01 +02:00
if ( variable . value !== old_value && typeof ( old_value ) === "string" ) {
if ( ! ( this instanceof LocalClientEntry ) ) { /* own changes will be logged somewhere else */
this . channelTree . client . log . log ( log . server . Type . CLIENT_NICKNAME_CHANGED , {
own_client : false ,
client : this.log_data ( ) ,
new_name : variable.value ,
old_name : old_value
} ) ;
}
}
2019-02-17 16:08:10 +01:00
this . tag . find ( ".client-name" ) . text ( variable . value ) ;
2018-11-20 15:06:18 +01:00
2019-08-21 10:00:01 +02:00
const chat = this . channelTree . client . side_bar ;
const conversation = chat . private_conversations ( ) . find_conversation ( {
name : this.clientNickName ( ) ,
client_id : this.clientId ( ) ,
unique_id : this.clientUid ( )
} , {
attach : false ,
create : false
} ) ;
if ( conversation )
conversation . set_client_name ( variable . value ) ;
2018-11-20 15:06:18 +01:00
reorder_channel = true ;
2018-04-16 20:38:35 +02:00
}
2019-04-04 21:47:52 +02:00
if (
variable . key == "client_away" ||
variable . key == "client_input_hardware" ||
variable . key == "client_output_hardware" ||
variable . key == "client_output_muted" ||
variable . key == "client_input_muted" ||
variable . key == "client_is_channel_commander" ) {
2018-11-20 15:06:18 +01:00
update_icon_speech = true ;
2018-04-16 20:38:35 +02:00
}
if ( variable . key == "client_away_message" || variable . key == "client_away" ) {
2018-11-20 15:06:18 +01:00
update_away = true ;
2018-04-16 20:38:35 +02:00
}
if ( variable . key == "client_unique_identifier" ) {
2019-08-21 10:00:01 +02:00
this . _audio_volume = parseFloat ( this . channelTree . client . settings . server ( "volume_client_" + this . clientUid ( ) , "1" ) ) ;
const mute_status = this . channelTree . client . settings . server ( "mute_client_" + this . clientUid ( ) , false ) ;
this . set_muted ( mute_status , false , mute_status ) ; /* force only needed when we want to mute the client */
if ( this . _audio_handle )
this . _audio_handle . set_volume ( this . _audio_muted ? 0 : this._audio_volume ) ;
update_icon_speech = true ;
log . debug ( LogCategory . CLIENT , tr ( "Loaded client (%s) server specific properties. Volume: %o Muted: %o." ) , this . clientUid ( ) , this . _audio_volume , this . _audio_muted ) ;
2018-04-16 20:38:35 +02:00
}
2018-08-12 13:26:56 +02:00
if ( variable . key == "client_talk_power" ) {
2018-11-20 15:06:18 +01:00
reorder_channel = true ;
update_icon_status = true ;
2018-08-12 13:26:56 +02:00
}
2019-04-25 20:21:50 +02:00
if ( variable . key == "client_icon_id" ) {
/ * y e a h w e l i k e j a v a s c r i p t . D u e t o J S w i e r e d i n t e g e r b e h a v i o u r p a r s i n g f o r e x a m p l e f a i l s f o r 1 8 4 4 6 7 4 4 0 7 3 4 0 9 8 2 9 8 6 3 .
* parseInt ( "18446744073409829863" ) evaluates to 18446744073409829000 .
* In opposite "18446744073409829863" >>> 0 evaluates to 3995244544 , which is the icon id : )
* /
this . properties . client_icon_id = variable . value as any >>> 0 ;
2018-08-12 14:14:50 +02:00
this . updateClientIcon ( ) ;
2019-04-25 20:21:50 +02:00
}
2018-09-30 22:36:17 +02:00
if ( variable . key == "client_channel_group_id" || variable . key == "client_servergroups" )
2018-12-17 21:21:52 +01:00
this . update_displayed_client_groups ( ) ;
2019-08-21 10:00:01 +02:00
else if ( variable . key == "client_flag_avatar" )
update_avatar = true ;
2018-04-11 17:56:09 +02:00
}
2018-04-16 20:38:35 +02:00
2018-11-20 15:06:18 +01:00
/* process updates after variables have been set */
if ( this . _channel && reorder_channel )
this . _channel . reorderClients ( ) ;
if ( update_icon_speech )
this . updateClientSpeakIcon ( ) ;
if ( update_icon_status )
this . updateClientStatusIcons ( ) ;
if ( update_away )
this . updateAwayMessage ( ) ;
2019-08-21 10:00:01 +02:00
const side_bar = this . channelTree . client . side_bar ;
{
const client_info = side_bar . client_info ( ) ;
if ( client_info . current_client ( ) === this )
client_info . set_current_client ( this , true ) ; /* force an update */
}
if ( update_avatar ) {
this . channelTree . client . fileManager . avatars . update_cache ( this . avatarId ( ) , this . properties . client_flag_avatar ) ;
const conversations = side_bar . private_conversations ( ) ;
const conversation = conversations . find_conversation ( { name : this.clientNickName ( ) , unique_id : this.clientUid ( ) , client_id : this.clientId ( ) } , { create : false , attach : false } ) ;
if ( conversation )
conversation . update_avatar ( ) ;
}
2018-04-16 20:38:35 +02:00
group . end ( ) ;
2018-02-27 17:20:49 +01:00
}
2018-12-17 21:21:52 +01:00
update_displayed_client_groups() {
2019-08-21 10:00:01 +02:00
this . tag . find ( ".container-icons-group" ) . children ( ) . remove ( ) ;
2018-12-17 21:21:52 +01:00
2018-09-30 22:36:17 +02:00
for ( let id of this . assignedServerGroupIds ( ) )
this . updateGroupIcon ( this . channelTree . client . groups . serverGroup ( id ) ) ;
2019-08-21 10:00:01 +02:00
this . update_group_icon_order ( ) ;
2018-09-30 22:36:17 +02:00
this . updateGroupIcon ( this . channelTree . client . groups . channelGroup ( this . properties . client_channel_group_id ) ) ;
2018-12-17 21:21:52 +01:00
let prefix_groups : string [ ] = [ ] ;
let suffix_groups : string [ ] = [ ] ;
for ( const group_id of this . assignedServerGroupIds ( ) ) {
const group = this . channelTree . client . groups . serverGroup ( group_id ) ;
if ( ! group ) continue ;
if ( group . properties . namemode == 1 )
prefix_groups . push ( group . name ) ;
else if ( group . properties . namemode == 2 )
suffix_groups . push ( group . name ) ;
}
2019-02-17 16:08:10 +01:00
const tag_group_prefix = this . tag . find ( ".group-prefix" ) ;
const tag_group_suffix = this . tag . find ( ".group-suffix" ) ;
2018-12-17 21:21:52 +01:00
if ( prefix_groups . length > 0 ) {
tag_group_prefix . text ( "[" + prefix_groups . join ( "][" ) + "]" ) . show ( ) ;
} else {
tag_group_prefix . hide ( )
}
if ( suffix_groups . length > 0 ) {
tag_group_suffix . text ( "[" + suffix_groups . join ( "][" ) + "]" ) . show ( ) ;
} else {
tag_group_suffix . hide ( )
}
2018-09-30 22:36:17 +02:00
}
2019-08-30 23:06:39 +02:00
updateClientVariables ( force_update? : boolean ) : Promise < void > {
if ( Date . now ( ) - 10 * 60 * 1000 < this . _info_variables_promise_timestamp && this . _info_variables_promise && ( typeof ( force_update ) !== "boolean" || force_update ) )
return this . _info_variables_promise ;
this . _info_variables_promise_timestamp = Date . now ( ) ;
return ( this . _info_variables_promise = new Promise < void > ( ( resolve , reject ) = > {
this . channelTree . client . serverConnection . send_command ( "clientgetvariables" , { clid : this.clientId ( ) } ) . then ( ( ) = > resolve ( ) ) . catch ( error = > {
this . _info_connection_promise_timestamp = 0 ; /* not succeeded */
reject ( error ) ;
} ) ;
} ) ) ;
2018-02-27 17:20:49 +01:00
}
2018-08-12 14:14:50 +02:00
updateClientIcon() {
2019-08-21 10:00:01 +02:00
this . tag . find ( ".container-icon-client" ) . children ( ) . remove ( ) ;
2018-08-12 14:14:50 +02:00
if ( this . properties . client_icon_id > 0 ) {
this . channelTree . client . fileManager . icons . generateTag ( this . properties . client_icon_id ) . attr ( "title" , "Client icon" )
2019-02-17 16:08:10 +01:00
. appendTo ( this . tag . find ( ".container-icon-client" ) ) ;
2018-08-12 14:14:50 +02:00
}
}
2018-04-16 20:38:35 +02:00
2018-02-27 17:20:49 +01:00
updateGroupIcon ( group : Group ) {
2018-09-30 22:47:41 +02:00
if ( ! group ) return ;
2019-08-21 10:00:01 +02:00
const container = this . tag . find ( ".container-icons-group" ) ;
container . find ( ".icon_group_" + group . id ) . remove ( ) ;
2018-02-27 17:20:49 +01:00
2018-08-12 14:14:50 +02:00
if ( group . properties . iconid > 0 ) {
2019-08-21 10:00:01 +02:00
container . append (
$ . spawn ( "div" ) . attr ( 'group-power' , group . properties . sortid )
2019-02-17 16:08:10 +01:00
. addClass ( "container-group-icon icon_group_" + group . id )
. append ( this . channelTree . client . fileManager . icons . generateTag ( group . properties . iconid ) ) . attr ( "title" , group . name )
2018-08-12 14:14:50 +02:00
) ;
}
2018-02-27 17:20:49 +01:00
}
2019-08-21 10:00:01 +02:00
update_group_icon_order() {
const container = this . tag . find ( ".container-icons-group" ) ;
container . append ( . . . [ . . . container . children ( ) ] . sort ( ( a , b ) = > parseInt ( a . getAttribute ( "group-power" ) ) - parseInt ( b . getAttribute ( "group-power" ) ) ) ) ;
}
2018-02-27 17:20:49 +01:00
assignedServerGroupIds ( ) : number [ ] {
let result = [ ] ;
for ( let id of this . properties . client_servergroups . split ( "," ) ) {
if ( id . length == 0 ) continue ;
result . push ( Number . parseInt ( id ) ) ;
}
return result ;
}
assignedChannelGroup ( ) : number {
2018-04-16 20:38:35 +02:00
return this . properties . client_channel_group_id ;
2018-02-27 17:20:49 +01:00
}
groupAssigned ( group : Group ) : boolean {
if ( group . target == GroupTarget . SERVER ) {
for ( let id of this . assignedServerGroupIds ( ) )
if ( id == group . id ) return true ;
return false ;
} else return group . id == this . assignedChannelGroup ( ) ;
}
2019-04-04 21:47:52 +02:00
onDelete() { }
2018-02-27 17:20:49 +01:00
calculateOnlineTime ( ) : number {
2018-04-30 23:57:21 +02:00
return Date . now ( ) / 1000 - this . properties . client_lastconnected ;
2018-04-16 20:38:35 +02:00
}
avatarId ? ( ) : string {
function str2ab ( str ) {
let buf = new ArrayBuffer ( str . length ) ; // 2 bytes for each char
let bufView = new Uint8Array ( buf ) ;
2018-08-12 16:38:38 +02:00
for ( let i = 0 , strLen = str . length ; i < strLen ; i + + ) {
2018-04-16 20:38:35 +02:00
bufView [ i ] = str . charCodeAt ( i ) ;
}
return buf ;
}
try {
let raw = atob ( this . properties . client_unique_identifier ) ;
let input = hex . encode ( str2ab ( raw ) ) ;
let result : string = "" ;
for ( let index = 0 ; index < input . length ; index ++ ) {
let c = input . charAt ( index ) ;
let offset : number = 0 ;
if ( c >= '0' && c <= '9' )
offset = c . charCodeAt ( 0 ) - '0' . charCodeAt ( 0 ) ;
else if ( c >= 'A' && c <= 'F' )
offset = c . charCodeAt ( 0 ) - 'A' . charCodeAt ( 0 ) + 0x0A ;
else if ( c >= 'a' && c <= 'f' )
offset = c . charCodeAt ( 0 ) - 'a' . charCodeAt ( 0 ) + 0x0A ;
result += String . fromCharCode ( 'a' . charCodeAt ( 0 ) + offset ) ;
}
return result ;
} catch ( e ) { //invalid base 64 (like music bot etc)
return undefined ;
}
2018-02-27 17:20:49 +01:00
}
2019-02-17 16:08:10 +01:00
update_family_index() {
if ( ! this . _channel ) return ;
const index = this . _channel . calculate_family_index ( ) ;
2019-07-10 00:52:08 +02:00
this . tag . css ( 'padding-left' , ( 5 + ( index + 2 ) * 16 ) + "px" ) ;
}
log_data ( ) : log . server . base . Client {
return {
client_unique_id : this.properties.client_unique_identifier ,
client_name : this.clientNickName ( ) ,
client_id : this._clientId
}
2019-02-17 16:08:10 +01:00
}
2019-08-30 23:06:39 +02:00
/* max 1s ago, so we could update every second */
request_connection_info ( ) : Promise < ClientConnectionInfo > {
if ( Date . now ( ) - 900 < this . _info_connection_promise_timestamp && this . _info_connection_promise )
return this . _info_connection_promise ;
if ( this . _info_connection_promise_reject )
this . _info_connection_promise_resolve ( "timeout" ) ;
let _local_reject ; /* to ensure we're using the right resolve! */
this . _info_connection_promise = new Promise < ClientConnectionInfo > ( ( resolve , reject ) = > {
this . _info_connection_promise_resolve = resolve ;
this . _info_connection_promise_reject = reject ;
_local_reject = reject ;
} ) ;
this . _info_connection_promise_timestamp = Date . now ( ) ;
this . channelTree . client . serverConnection . send_command ( "getconnectioninfo" , { clid : this._clientId } ) . catch ( error = > _local_reject ( error ) ) ;
return this . _info_connection_promise ;
}
set_connection_info ( info : ClientConnectionInfo ) {
if ( ! this . _info_connection_promise_resolve )
return ;
this . _info_connection_promise_resolve ( info ) ;
this . _info_connection_promise_resolve = undefined ;
this . _info_connection_promise_reject = undefined ;
}
2019-09-19 01:25:57 +02:00
set flag_text_unread ( flag : boolean ) {
this . _tag . find ( ".marker-text-unread" ) . toggleClass ( "hidden" , ! flag ) ;
}
2018-02-27 17:20:49 +01:00
}
class LocalClientEntry extends ClientEntry {
2019-04-04 21:47:52 +02:00
handle : ConnectionHandler ;
2018-02-27 17:20:49 +01:00
private renaming : boolean ;
2019-04-04 21:47:52 +02:00
constructor ( handle : ConnectionHandler ) {
2018-05-09 11:50:05 +02:00
super ( 0 , "local client" ) ;
2018-02-27 17:20:49 +01:00
this . handle = handle ;
}
showContextMenu ( x : number , y : number , on_close : ( ) = > void = undefined ) : void {
const _self = this ;
2019-06-30 16:03:28 +02:00
contextmenu . spawn_context_menu ( x , y ,
2019-08-21 10:00:01 +02:00
. . . this . contextmenu_info ( ) , {
2019-06-30 16:03:28 +02:00
name : ( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "<b>" : "" ) +
tr ( "Change name" ) +
( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "</b>" : "" ) ,
icon_class : "client-change_nickname" ,
2018-02-27 17:20:49 +01:00
callback : ( ) = > _self . openRename ( ) ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2018-02-27 17:20:49 +01:00
} , {
2018-12-05 20:46:33 +01:00
name : tr ( "Change description" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-edit" ,
2018-02-27 17:20:49 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Change own description" ) , tr ( "New description:<br>" ) , text = > true , result = > {
2018-02-27 17:20:49 +01:00
if ( result ) {
2018-12-05 20:46:33 +01:00
console . log ( tr ( "Changing own description to %s" ) , result ) ;
2019-02-23 14:15:22 +01:00
_self . channelTree . client . serverConnection . send_command ( "clientedit" , {
2018-02-27 17:20:49 +01:00
clid : _self.clientId ( ) ,
client_description : result
} ) ;
}
} , { width : 400 , maxLength : 1024 } ) . open ( ) ;
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2018-02-27 17:20:49 +01:00
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-09-30 22:58:53 +02:00
. . . this . assignment_context ( ) ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . CLOSE ( on_close )
2018-02-27 17:20:49 +01:00
) ;
}
initializeListener ( ) : void {
2019-10-13 21:33:07 +02:00
if ( this . _listener_initialized )
this . tag . off ( ) ;
2019-08-21 10:00:01 +02:00
this . _listener_initialized = false ; /* could there be a better system */
2018-02-27 17:20:49 +01:00
super . initializeListener ( ) ;
2019-02-17 16:08:10 +01:00
this . tag . find ( ".client-name" ) . addClass ( "client-name-own" ) ;
2018-02-27 17:20:49 +01:00
2019-10-13 21:33:07 +02:00
this . tag . on ( 'dblclick' , ( ) = > {
if ( Array . isArray ( this . channelTree . currently_selected ) ) { //Multiselect
2018-11-04 13:54:18 +01:00
return ;
}
this . openRename ( ) ;
2018-02-27 17:20:49 +01:00
} ) ;
}
openRename ( ) : void {
2019-04-26 00:32:19 +02:00
this . channelTree . client_mover . enabled = false ;
2019-02-17 16:08:10 +01:00
const elm = this . tag . find ( ".client-name" ) ;
2018-02-27 17:20:49 +01:00
elm . attr ( "contenteditable" , "true" ) ;
2019-02-17 16:08:10 +01:00
elm . removeClass ( "client-name-own" ) ;
2018-02-27 17:20:49 +01:00
elm . css ( "background-color" , "white" ) ;
elm . focus ( ) ;
2019-10-13 21:33:07 +02:00
this . renaming = true ;
2018-02-27 17:20:49 +01:00
2019-10-13 21:33:07 +02:00
elm . on ( 'keypress' , event = > {
if ( event . keyCode == KeyCode . KEY_RETURN ) {
$ ( event . target ) . trigger ( "focusout" ) ;
2018-02-27 17:20:49 +01:00
return false ;
}
} ) ;
2019-10-13 21:33:07 +02:00
elm . on ( 'focusout' , event = > {
2019-04-26 00:32:19 +02:00
this . channelTree . client_mover . enabled = true ;
2019-10-13 21:33:07 +02:00
if ( ! this . renaming ) return ;
this . renaming = false ;
2018-02-27 17:20:49 +01:00
elm . css ( "background-color" , "" ) ;
elm . removeAttr ( "contenteditable" ) ;
2019-02-17 16:08:10 +01:00
elm . addClass ( "client-name-own" ) ;
2018-02-27 17:20:49 +01:00
let text = elm . text ( ) . toString ( ) ;
2019-10-13 21:33:07 +02:00
if ( this . clientNickName ( ) == text ) return ;
2018-02-27 17:20:49 +01:00
2019-10-13 21:33:07 +02:00
elm . text ( this . clientNickName ( ) ) ;
const old_name = this . clientNickName ( ) ;
this . handle . serverConnection . command_helper . updateClient ( "client_nickname" , text ) . then ( ( e ) = > {
2019-06-19 11:08:46 +02:00
settings . changeGlobal ( Settings . KEY_CONNECT_USERNAME , text ) ;
2019-07-10 00:52:08 +02:00
this . channelTree . client . log . log ( log . server . Type . CLIENT_NICKNAME_CHANGED , {
client : this.log_data ( ) ,
2019-08-21 10:00:01 +02:00
old_name : old_name ,
new_name : text ,
own_client : true
2019-07-10 00:52:08 +02:00
} ) ;
2018-02-27 17:20:49 +01:00
} ) . catch ( ( e : CommandResult ) = > {
2019-07-10 00:52:08 +02:00
this . channelTree . client . log . log ( log . server . Type . CLIENT_NICKNAME_CHANGE_FAILED , {
reason : e.extra_message
} ) ;
2019-10-13 21:33:07 +02:00
this . openRename ( ) ;
2018-02-27 17:20:49 +01:00
} ) ;
} ) ;
}
2018-06-20 19:06:55 +02:00
}
class MusicClientProperties extends ClientProperties {
2018-08-10 21:30:58 +02:00
player_state : number = 0 ;
player_volume : number = 0 ;
2019-01-20 18:43:14 +01:00
client_playlist_id : number = 0 ;
client_disabled : boolean = false ;
2018-08-10 21:30:58 +02:00
}
class MusicClientPlayerInfo {
2018-11-26 20:52:56 +01:00
bot_id : number = 0 ;
2018-08-10 21:30:58 +02:00
player_state : number = 0 ;
player_buffered_index : number = 0 ;
player_replay_index : number = 0 ;
player_max_index : number = 0 ;
player_seekable : boolean = false ;
player_title : string = "" ;
player_description : string = "" ;
song_id : number = 0 ;
song_url : string = "" ;
song_invoker : number = 0 ;
song_loaded : boolean = false ;
song_title : string = "" ;
song_thumbnail : string = "" ;
song_length : number = 0 ;
2018-06-20 19:06:55 +02:00
}
class MusicClientEntry extends ClientEntry {
2018-08-10 21:30:58 +02:00
private _info_promise : Promise < MusicClientPlayerInfo > ;
private _info_promise_age : number = 0 ;
private _info_promise_resolve : any ;
private _info_promise_reject : any ;
2018-06-20 19:06:55 +02:00
constructor ( clientId , clientName ) {
super ( clientId , clientName , new MusicClientProperties ( ) ) ;
}
2019-08-21 10:00:01 +02:00
destroy() {
super . destroy ( ) ;
this . _info_promise = undefined ;
this . _info_promise_reject = undefined ;
this . _info_promise_resolve = undefined ;
}
2018-06-20 19:06:55 +02:00
get properties ( ) : MusicClientProperties {
return this . _properties as MusicClientProperties ;
}
showContextMenu ( x : number , y : number , on_close : ( ) = > void = undefined ) : void {
2019-03-07 15:30:53 +01:00
let trigger_close = true ;
2019-06-30 16:03:28 +02:00
contextmenu . spawn_context_menu ( x , y ,
2019-08-21 10:00:01 +02:00
. . . this . contextmenu_info ( ) , {
2019-10-13 21:33:07 +02:00
name : ( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "<b>" : "" ) +
tr ( "Change bot name" ) +
( contextmenu . get_provider ( ) . html_format_enabled ( ) ? "</b>" : "" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-change_nickname" ,
2018-11-04 13:54:18 +01:00
disabled : false ,
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Change music bots nickname" ) , tr ( "New nickname:<br>" ) , text = > text . length >= 3 && text . length <= 31 , result = > {
2018-11-04 13:54:18 +01:00
if ( result ) {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientedit" , {
2018-11-04 13:54:18 +01:00
clid : this.clientId ( ) ,
client_nickname : result
} ) ;
}
2019-10-13 21:33:07 +02:00
} , { width : "40em" , min_width : "10em" , maxLength : 255 } ) . open ( ) ;
2018-11-04 13:54:18 +01:00
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2018-06-20 19:06:55 +02:00
} , {
2018-12-05 20:46:33 +01:00
name : tr ( "Change bot description" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-edit" ,
2018-11-04 13:54:18 +01:00
disabled : false ,
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Change music bots description" ) , tr ( "New description:<br>" ) , text = > true , result = > {
2018-11-04 13:54:18 +01:00
if ( typeof ( result ) === 'string' ) {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientedit" , {
2018-11-04 13:54:18 +01:00
clid : this.clientId ( ) ,
client_description : result
} ) ;
}
2019-10-13 21:33:07 +02:00
} , { width : "60em" , min_width : "10em" , maxLength : 255 } ) . open ( ) ;
2018-11-04 13:54:18 +01:00
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2019-01-20 18:43:14 +01:00
} ,
/ *
{
2018-12-05 20:46:33 +01:00
name : tr ( "Open music panel" ) ,
2018-06-20 19:06:55 +02:00
icon : "client-edit" ,
disabled : true ,
callback : ( ) = > { } ,
type : MenuEntryType . ENTRY
2019-01-20 18:43:14 +01:00
} ,
* /
{
name : tr ( "Open bot's playlist" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-edit" ,
2019-01-20 18:43:14 +01:00
disabled : false ,
callback : ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . command_helper . request_playlist_list ( ) . then ( lists = > {
2019-01-20 18:43:14 +01:00
for ( const entry of lists ) {
if ( entry . playlist_id == this . properties . client_playlist_id ) {
Modals . spawnPlaylistEdit ( this . channelTree . client , entry ) ;
return ;
}
}
createErrorModal ( tr ( "Invalid permissions" ) , tr ( "You dont have to see the bots playlist." ) ) . open ( ) ;
} ) . catch ( error = > {
createErrorModal ( tr ( "Failed to query playlist." ) , tr ( "Failed to query playlist info." ) ) . open ( ) ;
} ) ;
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2019-01-20 18:43:14 +01:00
} ,
{
2018-12-05 20:46:33 +01:00
name : tr ( "Quick url replay" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-edit" ,
2018-11-04 13:54:18 +01:00
disabled : false ,
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Please enter the URL" ) , tr ( "URL:" ) , text = > true , result = > {
2018-11-04 13:54:18 +01:00
if ( result ) {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "musicbotqueueadd" , {
2018-11-26 20:52:56 +01:00
bot_id : this.properties.client_database_id ,
2018-11-04 13:54:18 +01:00
type : "yt" , //Its a hint not a force!
url : result
} ) . catch ( error = > {
if ( error instanceof CommandResult ) {
error = error . extra_message || error . message ;
}
2018-12-05 20:46:33 +01:00
//TODO tr
createErrorModal ( tr ( "Failed to replay url" ) , "Failed to enqueue url:<br>" + error ) . open ( ) ;
2018-11-04 13:54:18 +01:00
} ) ;
}
} , { width : 400 , maxLength : 255 } ) . open ( ) ;
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2018-06-20 19:06:55 +02:00
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-09-30 21:50:59 +02:00
. . . super . assignment_context ( ) ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) , {
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-move_client_to_own_channel" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Move client to your channel" ) ,
2018-11-04 00:39:29 +01:00
callback : ( ) = > {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientmove" , {
2018-11-04 00:39:29 +01:00
clid : this.clientId ( ) ,
cid : this.channelTree.client.getClient ( ) . currentChannel ( ) . getChannelId ( )
} ) ;
}
} , {
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-kick_channel" ,
2018-12-05 20:46:33 +01:00
name : tr ( "Kick client from channel" ) ,
2018-11-04 00:39:29 +01:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
createInputModal ( tr ( "Kick client from channel" ) , tr ( "Kick reason:<br>" ) , text = > true , result = > {
2019-03-17 12:39:21 +01:00
if ( typeof ( result ) !== 'boolean' || result ) {
2018-12-05 20:46:33 +01:00
console . log ( tr ( "Kicking client %o from channel with reason %o" ) , this . clientNickName ( ) , result ) ;
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientkick" , {
2018-11-04 00:39:29 +01:00
clid : this.clientId ( ) ,
reasonid : ViewReasonId.VREASON_CHANNEL_KICK ,
reasonmsg : result
} ) ;
}
} , { width : 400 , maxLength : 255 } ) . open ( ) ;
}
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-11-04 00:39:29 +01:00
{
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-volume" ,
2019-01-20 18:43:14 +01:00
name : tr ( "Change local volume" ) ,
2018-11-04 00:39:29 +01:00
callback : ( ) = > {
2019-10-13 21:33:07 +02:00
Modals . spawnChangeVolume ( this , true , this . _audio_handle . get_volume ( ) , undefined , volume = > {
2019-04-04 21:47:52 +02:00
this . channelTree . client . settings . changeServer ( "volume_client_" + this . clientUid ( ) , volume ) ;
this . _audio_handle . set_volume ( volume ) ;
2019-01-20 18:43:14 +01:00
} ) ;
}
} ,
{
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY ,
icon_class : "client-volume" ,
2019-01-20 18:43:14 +01:00
name : tr ( "Change remote volume" ) ,
callback : ( ) = > {
let max_volume = this . channelTree . client . permissions . neededPermission ( PermissionType . I_CLIENT_MUSIC_CREATE_MODIFY_MAX_VOLUME ) . value ;
if ( max_volume < 0 )
max_volume = 100 ;
2019-10-13 21:33:07 +02:00
Modals . spawnChangeVolume ( this , false , this . properties . player_volume , max_volume / 100 , value = > {
2019-06-29 21:27:29 +02:00
if ( typeof ( value ) !== "number" )
return ;
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "clientedit" , {
2019-01-20 18:43:14 +01:00
clid : this.clientId ( ) ,
player_volume : value ,
} ) . then ( ( ) = > {
2019-08-30 23:06:39 +02:00
//TODO: Update in info
2019-01-20 18:43:14 +01:00
} ) ;
2018-11-04 00:39:29 +01:00
} ) ;
}
} ,
2019-06-30 16:03:28 +02:00
contextmenu . Entry . HR ( ) ,
2018-06-20 19:06:55 +02:00
{
2018-12-05 20:46:33 +01:00
name : tr ( "Delete bot" ) ,
2019-06-30 16:03:28 +02:00
icon_class : "client-delete" ,
2018-11-04 13:54:18 +01:00
disabled : false ,
2018-06-20 19:06:55 +02:00
callback : ( ) = > {
2018-12-05 20:46:33 +01:00
const tag = $ . spawn ( "div" ) . append ( MessageHelper . formatMessage ( tr ( "Do you really want to delete {0}" ) , this . createChatTag ( false ) ) ) ;
Modals . spawnYesNo ( tr ( "Are you sure?" ) , $ . spawn ( "div" ) . append ( tag ) , result = > {
2018-11-04 13:54:18 +01:00
if ( result ) {
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "musicbotdelete" , {
2018-11-26 20:52:56 +01:00
bot_id : this.properties.client_database_id
2018-11-04 13:54:18 +01:00
} ) ;
}
} ) ;
2018-06-20 19:06:55 +02:00
} ,
2019-06-30 16:03:28 +02:00
type : contextmenu . MenuEntryType . ENTRY
2018-06-20 19:06:55 +02:00
} ,
2019-09-19 01:25:57 +02:00
contextmenu . Entry . CLOSE ( ( ) = > trigger_close && on_close ( ) )
2018-06-20 19:06:55 +02:00
) ;
}
initializeListener ( ) : void {
super . initializeListener ( ) ;
}
2018-08-10 21:30:58 +02:00
handlePlayerInfo ( json ) {
if ( json ) {
2019-09-12 23:59:35 +02:00
const info = new MusicClientPlayerInfo ( ) ;
JSON . map_to ( info , json ) ;
2018-08-10 21:30:58 +02:00
if ( this . _info_promise_resolve )
this . _info_promise_resolve ( info ) ;
this . _info_promise_reject = undefined ;
}
if ( this . _info_promise ) {
if ( this . _info_promise_reject )
this . _info_promise_reject ( "timeout" ) ;
this . _info_promise = undefined ;
this . _info_promise_age = undefined ;
this . _info_promise_reject = undefined ;
this . _info_promise_resolve = undefined ;
}
}
requestPlayerInfo ( max_age : number = 1000 ) : Promise < MusicClientPlayerInfo > {
if ( this . _info_promise && this . _info_promise_age && Date . now ( ) - max_age <= this . _info_promise_age ) return this . _info_promise ;
this . _info_promise_age = Date . now ( ) ;
this . _info_promise = new Promise < MusicClientPlayerInfo > ( ( resolve , reject ) = > {
this . _info_promise_reject = reject ;
this . _info_promise_resolve = resolve ;
} ) ;
2019-02-23 14:15:22 +01:00
this . channelTree . client . serverConnection . send_command ( "musicbotplayerinfo" , { bot_id : this.properties.client_database_id } ) ;
2018-08-10 21:30:58 +02:00
return this . _info_promise ;
}
2018-02-27 17:20:49 +01:00
}