2022-03-19 10:37:45 +00:00
'use strict' ;
2022-04-16 10:44:43 +00:00
const { Collection } = require ( '@discordjs/collection' ) ;
2022-05-21 13:58:33 +00:00
const { joinVoiceChannel , entersState , VoiceConnectionStatus } = require ( '@discordjs/voice' ) ;
2022-03-19 10:37:45 +00:00
const { Channel } = require ( './Channel' ) ;
2022-04-16 10:44:43 +00:00
const Invite = require ( './Invite' ) ;
const TextBasedChannel = require ( './interfaces/TextBasedChannel' ) ;
2022-03-19 10:37:45 +00:00
const { Error } = require ( '../errors' ) ;
2022-04-03 04:53:09 +00:00
const MessageManager = require ( '../managers/MessageManager' ) ;
2022-08-14 10:16:51 +00:00
const { Status , Opcodes } = require ( '../util/Constants' ) ;
2022-04-03 04:53:09 +00:00
const DataResolver = require ( '../util/DataResolver' ) ;
2022-03-19 10:37:45 +00:00
/ * *
* Represents a Partial Group DM Channel on Discord .
* @ extends { Channel }
* /
class PartialGroupDMChannel extends Channel {
constructor ( client , data ) {
super ( client , data ) ;
/ * *
* The name of this Group DM Channel
* @ type { ? string }
* /
2022-08-19 11:16:11 +00:00
this . name = null ;
2022-03-19 10:37:45 +00:00
/ * *
* The hash of the channel icon
* @ type { ? string }
* /
2022-08-19 11:16:11 +00:00
this . icon = null ;
2022-03-19 10:37:45 +00:00
/ * *
* The recipients of this Group DM Channel .
2022-08-19 11:16:11 +00:00
* @ type { Collection < Snowflake , User > }
2022-03-19 10:37:45 +00:00
* /
2022-08-19 11:16:11 +00:00
this . recipients = null ;
2022-04-03 04:53:09 +00:00
/ * *
* Messages data
* @ type { Collection }
* /
this . messages = new MessageManager ( this ) ;
/ * *
* Last Message ID
2022-08-19 11:16:11 +00:00
* @ type { ? Snowflake }
2022-04-03 04:53:09 +00:00
* /
this . lastMessageId = null ;
/ * *
* Last Pin Timestamp
* @ type { UnixTimestamp }
* /
this . lastPinTimestamp = null ;
/ * *
2022-08-19 11:16:11 +00:00
* Owner ID
* @ type { ? Snowflake }
2022-04-03 04:53:09 +00:00
* /
2022-08-19 11:16:11 +00:00
this . ownerId = null ;
2022-04-03 04:53:09 +00:00
/ * *
* Invites fetch
2022-05-06 14:17:20 +00:00
* @ type { Collection < string , Invite > }
2022-04-03 04:53:09 +00:00
* /
this . invites = new Collection ( ) ;
2022-08-19 11:16:11 +00:00
this . _patch ( data ) ;
}
/ * *
* The owner of this Group DM Channel
* @ type { ? User }
* @ readonly
* /
get owner ( ) {
return this . client . users . cache . get ( this . ownerId ) ;
2022-04-03 04:53:09 +00:00
}
/ * *
2022-04-16 10:44:43 +00:00
*
2022-04-16 12:01:05 +00:00
* @ param { Object } data Channel Data
2022-04-03 04:53:09 +00:00
* @ private
* /
2022-08-19 11:16:11 +00:00
_patch ( data ) {
super . _patch ( data ) ;
2022-04-03 04:53:09 +00:00
if ( 'recipients' in data ) {
2022-08-19 11:16:11 +00:00
this . recipients = new Collection ( ) ;
data . recipients . map ( recipient => this . recipients . set ( recipient . id , this . client . users . _add ( recipient ) ) ) ;
2022-04-03 04:53:09 +00:00
}
if ( 'last_pin_timestamp' in data ) {
const date = new Date ( data . last _pin _timestamp ) ;
this . lastPinTimestamp = date . getTime ( ) ;
}
if ( 'last_message_id' in data ) {
this . lastMessageId = data . last _message _id ;
}
2022-08-19 11:16:11 +00:00
if ( 'owner_id' in data ) {
this . ownerId = data . owner _id ;
}
if ( 'name' in data ) {
this . name = data . name ;
}
if ( 'icon' in data ) {
this . icon = data . icon ;
}
2022-04-03 04:53:09 +00:00
}
/ * *
2022-08-19 11:16:11 +00:00
* Edit channel data
* @ param { Object } data name , icon owner
* @ returns { Promise < undefined > }
2022-04-03 04:53:09 +00:00
* @ private
* /
async edit ( data ) {
const _data = { } ;
if ( 'name' in data ) _data . name = data . name ? . trim ( ) ? ? null ;
2022-04-16 10:44:43 +00:00
if ( typeof data . icon !== 'undefined' ) {
2022-04-03 04:53:09 +00:00
_data . icon = await DataResolver . resolveImage ( data . icon ) ;
2022-04-16 10:44:43 +00:00
}
2022-08-19 11:16:11 +00:00
if ( 'owner' in data ) {
_data . owner = data . owner ;
}
2022-04-03 04:53:09 +00:00
const newData = await this . client . api . channels ( this . id ) . patch ( {
data : _data ,
} ) ;
return this . client . actions . ChannelUpdate . handle ( newData ) . updated ;
2022-03-19 10:37:45 +00:00
}
/ * *
* The URL to this channel ' s icon .
2022-03-24 10:55:32 +00:00
* @ param { StaticImageURLOptions } [ options = { } ] Options for the Image URL
2022-03-19 10:37:45 +00:00
* @ returns { ? string }
* /
2022-03-24 10:55:32 +00:00
iconURL ( { format , size } = { } ) {
2022-04-16 10:44:43 +00:00
return this . icon && this . client . rest . cdn . GDMIcon ( this . id , this . icon , format , size ) ;
2022-03-19 10:37:45 +00:00
}
2022-07-15 10:26:25 +00:00
/ * *
* Adds a user to this Group DM Channel .
* @ param { UserResolvable } user User to add to the group
* @ returns { Promise < PartialGroupDMChannel > }
* /
2022-04-03 04:53:09 +00:00
async addMember ( user ) {
2022-07-15 10:26:25 +00:00
user = this . client . users . resolveId ( user ) ;
if ( ! user ) {
return Promise . reject ( new TypeError ( 'User is not a User or User ID' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-08-18 20:19:45 +00:00
if ( this . recipients . get ( user ) ) return Promise . reject ( new Error ( 'USER_ALREADY_IN_GROUP_DM_CHANNEL' ) ) ; // Fails sometimes if member leaves recently (ex. user leave msg's channel used for adding)
2022-07-15 10:26:25 +00:00
await this . client . api . channels [ this . id ] . recipients [ user ] . put ( ) ;
this . recipients . set ( user , this . client . users . cache . get ( user ) ) ;
2022-04-03 04:53:09 +00:00
return this ;
2022-03-19 10:37:45 +00:00
}
2022-07-15 10:26:25 +00:00
/ * *
* Removes a user from this Group DM Channel .
* @ param { UserResolvable } user User to remove from the group
* @ returns { Promise < PartialGroupDMChannel > }
* /
2022-04-03 04:53:09 +00:00
async removeMember ( user ) {
2022-04-16 10:44:43 +00:00
if ( this . ownerId !== this . client . user . id ) {
2022-04-03 04:53:09 +00:00
return Promise . reject ( new Error ( 'NOT_OWNER_GROUP_DM_CHANNEL' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-07-15 10:26:25 +00:00
user = this . client . users . resolveId ( user ) ;
if ( ! user ) {
return Promise . reject ( new TypeError ( 'User is not a User or User ID' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-07-15 10:26:25 +00:00
if ( ! this . recipients . get ( user ) ) return Promise . reject ( new Error ( 'USER_NOT_IN_GROUP_DM_CHANNEL' ) ) ;
await this . client . api . channels [ this . id ] . recipients [ user ] . delete ( ) ;
this . recipients . delete ( user ) ;
2022-04-03 04:53:09 +00:00
return this ;
2022-03-19 10:37:45 +00:00
}
2022-04-03 04:53:09 +00:00
2022-07-15 10:26:25 +00:00
/ * *
* Renames this Group DM Channel .
* @ param { ? string } name Name of the channel
* @ returns { Promise < PartialGroupDMChannel > }
* /
2022-04-03 04:53:09 +00:00
setName ( name ) {
return this . edit ( { name } ) ;
}
2022-07-15 10:26:25 +00:00
/ * *
* Sets the icon of this Group DM Channel .
* @ param { ? ( Base64Resolvable | BufferResolvable ) } icon Icon of the channel
* @ returns { Promise < PartialGroupDMChannel > }
* /
2022-04-03 04:53:09 +00:00
setIcon ( icon ) {
return this . edit ( { icon } ) ;
}
2022-08-19 11:16:11 +00:00
/ * *
* Changes the owner of this Group DM Channel .
* @ param { UserResolvable } user User to transfer ownership to
* @ returns { Promise < PartialGroupDMChannel > }
* /
setOwner ( user ) {
const id = this . client . users . resolveId ( user ) ;
if ( ! id ) {
throw new TypeError ( 'User is not a User or User ID' ) ;
}
if ( this . ownerId !== this . client . user . id ) {
throw new Error ( 'NOT_OWNER_GROUP_DM_CHANNEL' ) ;
}
if ( this . ownerId === id ) {
return this ;
}
return this . edit ( { owner : id } ) ;
}
2022-07-15 10:26:25 +00:00
/ * *
* Gets the invite for this Group DM Channel .
* @ returns { Promise < Invite > }
* /
2022-04-03 04:53:09 +00:00
async getInvite ( ) {
const inviteCode = await this . client . api . channels ( this . id ) . invites . post ( {
2022-04-16 10:44:43 +00:00
data : {
max _age : 86400 ,
} ,
} ) ;
2022-04-03 04:53:09 +00:00
const invite = new Invite ( this . client , inviteCode ) ;
this . invites . set ( invite . code , invite ) ;
return invite ;
}
2022-07-15 10:26:25 +00:00
/ * *
* Get all the invites for this Group DM Channel .
* @ param { boolean } force Using API to fetch invites or cache
* @ returns { Promise < Collection < string , Invite >> }
* /
2022-04-03 04:53:09 +00:00
async fetchInvite ( force = false ) {
2022-04-16 10:44:43 +00:00
if ( this . ownerId !== this . client . user . id ) {
2022-04-03 04:53:09 +00:00
return Promise . reject ( new Error ( 'NOT_OWNER_GROUP_DM_CHANNEL' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-04-03 04:53:09 +00:00
if ( ! force && this . invites . size ) return this . invites ;
const invites = await this . client . api . channels ( this . id ) . invites . get ( ) ;
await Promise . all ( invites . map ( invite => this . invites . set ( invite . code , new Invite ( this . client , invite ) ) ) ) ;
return this . invites ;
}
2022-07-15 10:26:25 +00:00
/ * *
* Delete invites from this Group DM Channel .
* @ param { Invite } invite Invite to add to the channel
* @ returns { Promise < PartialGroupDMChannel > }
* /
2022-04-03 04:53:09 +00:00
async removeInvite ( invite ) {
2022-04-16 10:44:43 +00:00
if ( this . ownerId !== this . client . user . id ) {
2022-04-03 04:53:09 +00:00
return Promise . reject ( new Error ( 'NOT_OWNER_GROUP_DM_CHANNEL' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-04-16 12:01:05 +00:00
if ( ! ( invite instanceof Invite ) ) {
2022-04-03 04:53:09 +00:00
return Promise . reject ( new TypeError ( 'Invite is not an instance of Discord.Invite' ) ) ;
2022-04-16 10:44:43 +00:00
}
2022-04-03 04:53:09 +00:00
await this . client . api . channels ( this . id ) . invites [ invite . code ] . delete ( ) ;
this . invites . delete ( invite . code ) ;
return this ;
}
2022-08-19 11:16:11 +00:00
/ * *
* Leave this Group DM Channel .
* @ param { ? boolean } slient Leave without notifying other members
* @ returns { Promise < Channel > }
* @ example
* // Delete the channel
* channel . delete ( )
* . then ( console . log )
* . catch ( console . error ) ;
* /
async delete ( slient = false ) {
if ( typeof slient === 'boolean' && slient ) {
await this . client . api . channels ( this . id ) . delete ( {
query : {
silent : true ,
} ,
} ) ;
} else {
await this . client . api . channels ( this . id ) . delete ( ) ;
}
return this ;
}
2022-04-03 04:53:09 +00:00
// These are here only for documentation purposes - they are implemented by TextBasedChannel
/* eslint-disable no-empty-function */
2022-04-16 10:44:43 +00:00
get lastMessage ( ) { }
get lastPinAt ( ) { }
send ( ) { }
sendTyping ( ) { }
2022-04-27 13:58:06 +00:00
2022-07-15 10:26:25 +00:00
/ * *
* @ typedef { Object } CallOptions
* @ property { boolean } [ selfDeaf ] Whether to deafen yourself
* @ property { boolean } [ selfMute ] Whether to mute yourself
* /
2022-04-27 13:58:06 +00:00
// Testing feature: Call
// URL: https://discord.com/api/v9/channels/DMchannelId/call/ring
/ * *
2022-05-21 13:58:33 +00:00
* Call this Group DMChannel . Return discordjs / voice VoiceConnection
2022-07-15 10:26:25 +00:00
* @ param { CallOptions } options Options for the call
2022-05-21 13:58:33 +00:00
* @ returns { Promise < VoiceConnection > }
2022-04-27 13:58:06 +00:00
* /
2022-05-21 13:58:33 +00:00
call ( options = { } ) {
return new Promise ( ( resolve , reject ) => {
2022-05-21 14:36:31 +00:00
this . client . api
. channels ( this . id )
. call . ring . post ( {
2022-06-13 12:13:03 +00:00
body : {
2022-05-21 14:36:31 +00:00
recipients : null ,
} ,
} )
. catch ( e => {
console . error ( 'Emit ring error:' , e . message ) ;
} ) ;
2022-05-21 13:58:33 +00:00
const connection = joinVoiceChannel ( {
channelId : this . id ,
guildId : null ,
adapterCreator : this . voiceAdapterCreator ,
selfDeaf : options . selfDeaf ? ? false ,
selfMute : options . selfMute ? ? false ,
} ) ;
entersState ( connection , VoiceConnectionStatus . Ready , 30000 )
. then ( connection => {
resolve ( connection ) ;
} )
. catch ( err => {
connection . destroy ( ) ;
reject ( err ) ;
} ) ;
2022-04-27 13:58:06 +00:00
} ) ;
}
2022-08-14 10:16:51 +00:00
/ * *
* Sync VoiceState of this Group DMChannel .
* @ returns { undefined }
* /
sync ( ) {
this . client . ws . broadcast ( {
op : Opcodes . DM _UPDATE ,
d : {
channel _id : this . id ,
} ,
} ) ;
}
/ * *
* The user in this voice - based channel
* @ type { Collection < Snowflake , User > }
* @ readonly
* /
get voiceUsers ( ) {
const coll = new Collection ( ) ;
for ( const state of this . client . voiceStates . cache . values ( ) ) {
if ( state . channelId === this . id && state . user ) {
coll . set ( state . id , state . user ) ;
}
}
return coll ;
}
/ * *
* Get connection to current call
* @ type { ? VoiceConnection }
* @ readonly
* /
get voiceConnection ( ) {
const check = this . client . callVoice ? . joinConfig ? . channelId == this . id ;
if ( check ) {
return this . client . callVoice ;
}
return null ;
}
/ * *
* Get current shard
* @ type { WebSocketShard }
* @ readonly
* /
2022-05-21 13:58:33 +00:00
get shard ( ) {
return this . client . ws . shards . first ( ) ;
}
2022-08-14 10:16:51 +00:00
/ * *
* The voice state adapter for this client that can be used with @ discordjs / voice to play audio in DM / Group DM channels .
* @ type { ? Function }
* @ readonly
* /
2022-05-21 13:58:33 +00:00
get voiceAdapterCreator ( ) {
return methods => {
this . client . voice . adapters . set ( this . id , methods ) ;
return {
sendPayload : data => {
data . d = {
... data . d ,
self _video : false ,
} ;
if ( this . shard . status !== Status . READY ) return false ;
this . shard . send ( data ) ;
return true ;
} ,
destroy : ( ) => {
this . client . voice . adapters . delete ( this . id ) ;
} ,
} ;
} ;
}
2022-03-19 10:37:45 +00:00
}
2022-06-06 04:21:36 +00:00
TextBasedChannel . applyToClass ( PartialGroupDMChannel , true , [
'bulkDelete' ,
'fetchWebhooks' ,
'createWebhook' ,
'setRateLimitPerUser' ,
'setNSFW' ,
] ) ;
2022-04-03 04:53:09 +00:00
2022-03-19 10:37:45 +00:00
module . exports = PartialGroupDMChannel ;