From 1cdcf045adbbef0941b287ac13d0dddb74d86a23 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Fri, 26 Mar 2021 20:33:21 +0900 Subject: [PATCH 01/15] :bug: Temporary remove quote grouping --- deps.ts | 1 - src/models/command.ts | 4 ++-- src/test/cmd.ts | 2 +- src/test/cmds/ping.ts | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deps.ts b/deps.ts index 91097fc..e20a610 100644 --- a/deps.ts +++ b/deps.ts @@ -1,7 +1,6 @@ export { EventEmitter } from 'https://deno.land/x/event@0.2.1/mod.ts' export { unzlib } from 'https://denopkg.com/DjDeveloperr/denoflate@1.2/mod.ts' export { fetchAuto } from 'https://deno.land/x/fetchbase64@1.0.0/mod.ts' -export { parse } from 'https://deno.land/x/mutil@0.1.2/mod.ts' export { connect } from 'https://deno.land/x/redis@v0.14.1/mod.ts' export type { Redis, diff --git a/src/models/command.ts b/src/models/command.ts index 4040449..ee24145 100644 --- a/src/models/command.ts +++ b/src/models/command.ts @@ -5,7 +5,7 @@ import { User } from '../structures/user.ts' import { Collection } from '../utils/collection.ts' import { CommandClient } from './commandClient.ts' import { Extension } from './extensions.ts' -import { join, parse, walk } from '../../deps.ts' +import { join, walk } from '../../deps.ts' export interface CommandContext { /** The Client object */ @@ -599,7 +599,7 @@ export const parseCommand = ( ): ParsedCommand | undefined => { let content = msg.content.slice(prefix.length) if (client.spacesAfterPrefix === true) content = content.trim() - const args = parse(content)._.map((e) => e.toString()) + const args = content.split(' ') const name = args.shift() if (name === undefined) return diff --git a/src/test/cmd.ts b/src/test/cmd.ts index 5063198..4798c36 100644 --- a/src/test/cmd.ts +++ b/src/test/cmd.ts @@ -139,7 +139,7 @@ client.on('messageReactionRemoveAll', (message) => { // client.on('raw', (evt: string) => console.log(`EVENT: ${evt}`)) -const files = Deno.readDirSync('./src/test/cmds') +const files = Deno.readDirSync('cmds') for (const file of files) { const module = await import(`./cmds/${file.name}`) diff --git a/src/test/cmds/ping.ts b/src/test/cmds/ping.ts index 61981ae..3f0c381 100644 --- a/src/test/cmds/ping.ts +++ b/src/test/cmds/ping.ts @@ -5,6 +5,7 @@ export default class PingCommand extends Command { name = 'ping' execute(ctx: CommandContext): void { + console.log(ctx.args, ctx.argString) ctx.message.reply(`Pong! Latency: ${ctx.client.ping}ms`) } } From 37de39daa7a1c06c541e906200acb768f533fc55 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Fri, 26 Mar 2021 21:54:15 +0900 Subject: [PATCH 02/15] :wrench: Edit linter config (disable no-non-null-assertion) --- .eslintrc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 200257b..d9d64f0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,6 +17,7 @@ module.exports = { }, plugins: ['@typescript-eslint'], rules: { - '@typescript-eslint/restrict-template-expressions': 'off' + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/no-non-null-assertion': 'off' } } From 4dc18f7266d7138566014b04f78c4ecd650f1df9 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 29 Mar 2021 10:10:26 +0530 Subject: [PATCH 03/15] fix typo --- src/structures/channel.ts | 24 ++++++++++++------------ src/test/index.ts | 14 +++++++------- src/types/channel.ts | 14 +++++++------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 65caf4d..36e60e9 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -74,7 +74,7 @@ export class GuildChannel extends Channel { const stringToObject = typeof target === 'string' ? (await this.guild.members.get(target)) ?? - (await this.guild.roles.get(target)) + (await this.guild.roles.get(target)) : target if (stringToObject === undefined) { @@ -121,7 +121,7 @@ export class GuildChannel extends Channel { const stringToObject = typeof target === 'string' ? (await this.guild.members.get(target)) ?? - (await this.guild.roles.get(target)) + (await this.guild.roles.get(target)) : target if (stringToObject === undefined) { @@ -193,8 +193,8 @@ export class GuildChannel extends Channel { overwrite.id instanceof Role ? 0 : overwrite.id instanceof Member - ? 1 - : overwrite.type + ? 1 + : overwrite.type if (type === undefined) { throw new Error('Overwrite type is undefined.') } @@ -226,8 +226,8 @@ export class GuildChannel extends Channel { overwrite.id instanceof Role ? 0 : overwrite.id instanceof Member - ? 1 - : overwrite.type + ? 1 + : overwrite.type if (type === undefined) { throw new Error('Overwrite type is undefined.') } @@ -257,11 +257,11 @@ export class GuildChannel extends Channel { async editOverwrite( overwrite: OverwriteAsArg, { - overriteAllow = OverrideType.ADD, - overriteDeny = OverrideType.ADD + overwriteAllow = OverrideType.ADD, + overwriteDeny = OverrideType.ADD }: { - overriteAllow?: OverrideType - overriteDeny?: OverrideType + overwriteAllow?: OverrideType + overwriteDeny?: OverrideType } ): Promise { const id = typeof overwrite.id === 'string' ? overwrite.id : overwrite.id.id @@ -327,8 +327,8 @@ export class GuildChannel extends Channel { overwrite.id instanceof Role ? 0 : overwrite.id instanceof Member - ? 1 - : overwrite.type + ? 1 + : overwrite.type if (type === undefined) { throw new Error('Overwrite type is undefined.') } diff --git a/src/test/index.ts b/src/test/index.ts index 992efb5..22096c7 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -74,12 +74,12 @@ client.on('messageCreate', async (msg: Message) => { const guilds = await msg.client.guilds.collection() msg.channel.send( 'Guild List:\n' + - (guilds - .array() - .map((c: Guild, i: number) => { - return `${i + 1}. ${c.name} - ${c.memberCount} members` - }) - .join('\n') as string) + (guilds + .array() + .map((c: Guild, i: number) => { + return `${i + 1}. ${c.name} - ${c.memberCount} members` + }) + .join('\n') as string) ) } else if (msg.content === '!roles') { const col = await msg.guild?.roles.collection() @@ -246,7 +246,7 @@ client.on('messageCreate', async (msg: Message) => { allow: Permissions.DEFAULT.toString() }, { - overriteAllow: OverrideType.REMOVE + overwriteAllow: OverrideType.REMOVE } ) msg.channel.send(`Done!`) diff --git a/src/types/channel.ts b/src/types/channel.ts index 80bf065..26cd456 100644 --- a/src/types/channel.ts +++ b/src/types/channel.ts @@ -28,7 +28,7 @@ export interface GuildChannelPayload extends ChannelPayload { export interface GuildTextBasedChannelPayload extends TextChannelPayload, - GuildChannelPayload { + GuildChannelPayload { topic?: string } @@ -36,7 +36,7 @@ export interface GuildTextChannelPayload extends GuildTextBasedChannelPayload { rate_limit_per_user: number } -export interface GuildNewsChannelPayload extends GuildTextBasedChannelPayload {} +export interface GuildNewsChannelPayload extends GuildTextBasedChannelPayload { } export interface GuildVoiceChannelPayload extends GuildChannelPayload { bitrate: string @@ -55,7 +55,7 @@ export interface GroupDMChannelPayload extends DMChannelPayload { export interface GuildCategoryChannelPayload extends ChannelPayload, - GuildChannelPayload {} + GuildChannelPayload { } export interface ModifyChannelPayload { name?: string @@ -66,7 +66,7 @@ export interface ModifyChannelPayload { } export interface ModifyGuildCategoryChannelPayload - extends ModifyChannelPayload {} + extends ModifyChannelPayload { } export interface ModifyGuildTextBasedChannelPayload extends ModifyChannelPayload { @@ -80,7 +80,7 @@ export interface ModifyGuildTextChannelPayload } export interface ModifyGuildNewsChannelPayload - extends ModifyGuildTextBasedChannelPayload {} + extends ModifyGuildTextBasedChannelPayload { } export interface ModifyVoiceChannelPayload extends ModifyChannelPayload { bitrate?: number | null @@ -95,7 +95,7 @@ export interface ModifyChannelOption { nsfw?: boolean | null } -export interface ModifyGuildCategoryChannelOption extends ModifyChannelOption {} +export interface ModifyGuildCategoryChannelOption extends ModifyChannelOption { } export interface ModifyGuildTextBasedChannelOption extends ModifyChannelOption { type?: number @@ -108,7 +108,7 @@ export interface ModifyGuildTextChannelOption } export interface ModifyGuildNewsChannelOption - extends ModifyGuildTextBasedChannelOption {} + extends ModifyGuildTextBasedChannelOption { } export interface ModifyVoiceChannelOption extends ModifyChannelOption { bitrate?: number | null From 004bf22126cc8a16d571656a7ea2ae26eb6b6903 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 29 Mar 2021 10:15:09 +0530 Subject: [PATCH 04/15] lol i forgot to save --- src/structures/channel.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/structures/channel.ts b/src/structures/channel.ts index 36e60e9..d993825 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -274,9 +274,9 @@ export class GuildChannel extends Channel { if ( overwrite.allow !== undefined && - overriteAllow !== OverrideType.REPLACE + overwriteAllow !== OverrideType.REPLACE ) { - switch (overriteAllow) { + switch (overwriteAllow) { case OverrideType.ADD: { const originalAllow = new Permissions(overwrites[index].allow) const newAllow = new Permissions(overwrite.allow) @@ -299,8 +299,8 @@ export class GuildChannel extends Channel { : overwrite.allow?.toJSON() ?? overwrites[index].allow } - if (overwrite.deny !== undefined && overriteDeny !== OverrideType.REPLACE) { - switch (overriteDeny) { + if (overwrite.deny !== undefined && overwriteDeny !== OverrideType.REPLACE) { + switch (overwriteDeny) { case OverrideType.ADD: { const originalDeny = new Permissions(overwrites[index].deny) const newDeny = new Permissions(overwrite.deny) From 0692276f3a53777687e91f2ffc0d6a44502a416a Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 29 Mar 2021 10:22:52 +0530 Subject: [PATCH 05/15] x --- mod.ts | 3 ++- src/structures/channel.ts | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mod.ts b/mod.ts index 8b22bfa..3faff80 100644 --- a/mod.ts +++ b/mod.ts @@ -46,7 +46,8 @@ export { UsersManager } from './src/managers/users.ts' export { InviteManager } from './src/managers/invites.ts' export { Application } from './src/structures/application.ts' // export { ImageURL } from './src/structures/cdn.ts' -export { Channel } from './src/structures/channel.ts' +export { Channel, GuildChannel } from './src/structures/channel.ts' +export type { EditOverwriteOptions } from './src/structures/channel.ts' export { DMChannel } from './src/structures/dmChannel.ts' export { Embed } from './src/structures/embed.ts' export { Emoji } from './src/structures/emoji.ts' diff --git a/src/structures/channel.ts b/src/structures/channel.ts index d993825..9aad184 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -38,6 +38,13 @@ export class Channel extends SnowflakeBase { } } +export interface EditOverwriteOptions { + /** Allow Override Type */ + allow?: OverrideType + /** Deny Override Type */ + deny?: OverrideType +} + export class GuildChannel extends Channel { guildID: string name: string @@ -257,12 +264,9 @@ export class GuildChannel extends Channel { async editOverwrite( overwrite: OverwriteAsArg, { - overwriteAllow = OverrideType.ADD, - overwriteDeny = OverrideType.ADD - }: { - overwriteAllow?: OverrideType - overwriteDeny?: OverrideType - } + allow: overwriteAllow = OverrideType.ADD, + deny: overwriteDeny = OverrideType.ADD + }: EditOverwriteOptions ): Promise { const id = typeof overwrite.id === 'string' ? overwrite.id : overwrite.id.id const index = this.permissionOverwrites.findIndex((e) => e.id === id) From 0e57401a6bc19e448e73c1613bd94da1523c5b2e Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 29 Mar 2021 10:24:18 +0530 Subject: [PATCH 06/15] fix --- src/test/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/index.ts b/src/test/index.ts index 22096c7..bb9a439 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -246,7 +246,7 @@ client.on('messageCreate', async (msg: Message) => { allow: Permissions.DEFAULT.toString() }, { - overwriteAllow: OverrideType.REMOVE + allow: OverrideType.REMOVE } ) msg.channel.send(`Done!`) From b4a1ae389d35d950a7c954cb26c5a332ad4ac129 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 01:43:01 +0900 Subject: [PATCH 07/15] :sparkles: Add some few things that are useful to voiceState --- src/structures/member.ts | 39 +++++++++++++++++-- src/structures/voiceState.ts | 74 +++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/structures/member.ts b/src/structures/member.ts index fe491d4..ee60bf7 100644 --- a/src/structures/member.ts +++ b/src/structures/member.ts @@ -5,6 +5,7 @@ import { MemberPayload } from '../types/guild.ts' import { Permissions } from '../utils/permissions.ts' import { SnowflakeBase } from './base.ts' import { Guild } from './guild.ts' +import { VoiceChannel } from './guildVoiceChannel.ts' import { Role } from './role.ts' import { User } from './user.ts' @@ -13,6 +14,7 @@ export interface MemberData { roles?: Array deaf?: boolean mute?: boolean + channel?: string | VoiceChannel | null } export class Member extends SnowflakeBase { @@ -84,8 +86,11 @@ export class Member extends SnowflakeBase { nick: data.nick, roles: data.roles?.map((e) => (typeof e === 'string' ? e : e.id)), deaf: data.deaf, - mute: data.mute + mute: data.mute, + channel_id: + typeof data.channel === 'string' ? data.channel : data.channel?.id } + const res = await this.client.rest.patch( GUILD_MEMBER(this.guild.id, this.id), payload, @@ -125,7 +130,7 @@ export class Member extends SnowflakeBase { */ async setMute(mute?: boolean): Promise { return await this.edit({ - mute: mute === undefined ? false : mute + mute: mute ?? false }) } @@ -135,7 +140,28 @@ export class Member extends SnowflakeBase { */ async setDeaf(deaf?: boolean): Promise { return await this.edit({ - deaf: deaf === undefined ? false : deaf + deaf: deaf ?? false + }) + } + + /** + * Moves a Member to another VC + * @param channel Channel to move(null or undefined to disconnect) + */ + async moveVoiceChannel( + channel?: string | VoiceChannel | null + ): Promise { + return await this.edit({ + channel: channel ?? null + }) + } + + /** + * Disconnects a Member from connected VC + */ + async disconnectVoice(): Promise { + return await this.edit({ + channel: null }) } @@ -146,6 +172,13 @@ export class Member extends SnowflakeBase { return await this.setMute(false) } + /** + * Undeafs the Member from VC. + */ + async undeaf(): Promise { + return await this.setDeaf(false) + } + /** * Kicks the member. */ diff --git a/src/structures/voiceState.ts b/src/structures/voiceState.ts index cd3cc7f..45c2a4b 100644 --- a/src/structures/voiceState.ts +++ b/src/structures/voiceState.ts @@ -1,4 +1,5 @@ import { Client } from '../models/client.ts' +import { ChannelTypes } from '../types/channel.ts' import { VoiceStatePayload } from '../types/voice.ts' import { Base } from './base.ts' import { Guild } from './guild.ts' @@ -52,12 +53,81 @@ export class VoiceState extends Base { this.deaf = data.deaf ?? this.deaf this.channelID = data.channel_id ?? this.channelID this.mute = data.mute ?? this.mute - this.deaf = data.self_deaf ?? this.deaf - this.mute = data.self_mute ?? this.mute this.selfDeaf = data.self_deaf ?? this.selfDeaf this.selfMute = data.self_mute ?? this.selfMute this.stream = data.self_stream ?? this.stream this.video = data.self_video ?? this.video this.suppress = data.suppress ?? this.suppress } + + /** + * Disconnects a Member from connected VC + */ + async disconnect(): Promise { + const result = this.member?.disconnectVoice() + if (result !== undefined) { + this.channelID = null + this.channel = null + } + return result + } + + /** + * Moves a Member to another VC + * @param channel Channel to move(null or undefined to disconnect) + */ + async moveChannel( + channel?: string | VoiceChannel | null + ): Promise { + const result = this.member?.moveVoiceChannel(channel) + if (result !== undefined) { + let channelFetched: VoiceChannel | null + let channelID: string | null + if (typeof channel === 'string') { + channelID = channel + const channelCached = await this.guild?.channels.fetch(channel) + if (channelCached?.type === ChannelTypes.GUILD_VOICE) { + channelFetched = channelCached as VoiceChannel + } else { + throw new Error(`Channel ${channel} is not a VoiceChannel.`) + } + } else { + channelID = channel?.id ?? null + channelFetched = channel ?? null + } + this.channelID = channelID + this.channel = channelFetched + } + return result + } + + /** + * Sets a Member mute in VC + * @param mute Value to set + */ + async setMute(mute?: boolean): Promise { + return this.member?.setMute(mute) + } + + /** + * Sets a Member deaf in VC + * @param deaf Value to set + */ + async setDeaf(deaf?: boolean): Promise { + return this.member?.setDeaf(deaf) + } + + /** + * Unmutes the Member from VC. + */ + async unmute(): Promise { + return await this.setMute(false) + } + + /** + * Undeafs the Member from VC. + */ + async undeaf(): Promise { + return await this.setDeaf(false) + } } From 9c5aea1ef8544eeeca8d90bd1388401941c1c541 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 01:54:21 +0900 Subject: [PATCH 08/15] :bug: Replace the guild as the manager's guild if it's undefined --- src/managers/guildVoiceStates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/guildVoiceStates.ts b/src/managers/guildVoiceStates.ts index 4b1c5bd..baefcf7 100644 --- a/src/managers/guildVoiceStates.ts +++ b/src/managers/guildVoiceStates.ts @@ -30,7 +30,7 @@ export class GuildVoiceStatesManager extends BaseManager< const guild = raw.guild_id === undefined - ? undefined + ? this.guild : await this.client.guilds.get(raw.guild_id) return new VoiceState(this.client, raw, { @@ -57,7 +57,7 @@ export class GuildVoiceStatesManager extends BaseManager< arr.map(async (raw) => { const guild = raw.guild_id === undefined - ? undefined + ? this.guild : await this.client.guilds.get(raw.guild_id) return new VoiceState(this.client, raw, { From 064c3a6d765adf223ad3d42f844f7a9853ebd6a9 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 02:00:25 +0900 Subject: [PATCH 09/15] :bug: Make .edit check channel type more precisely --- src/structures/member.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/member.ts b/src/structures/member.ts index ee60bf7..eb2593a 100644 --- a/src/structures/member.ts +++ b/src/structures/member.ts @@ -88,7 +88,7 @@ export class Member extends SnowflakeBase { deaf: data.deaf, mute: data.mute, channel_id: - typeof data.channel === 'string' ? data.channel : data.channel?.id + data.channel instanceof VoiceChannel ? data.channel.id : data.channel } const res = await this.client.rest.patch( From d2cedeceb13ded109f4a17f5725a89662ce5dd6b Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 02:01:19 +0900 Subject: [PATCH 10/15] :white_check_mark: Add voice kick test --- src/test/cmds/kickFromVoice.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/cmds/kickFromVoice.ts diff --git a/src/test/cmds/kickFromVoice.ts b/src/test/cmds/kickFromVoice.ts new file mode 100644 index 0000000..5730703 --- /dev/null +++ b/src/test/cmds/kickFromVoice.ts @@ -0,0 +1,20 @@ +import { Command } from '../../../mod.ts' +import { CommandContext } from '../../models/command.ts' + +export default class KickFromVoiceCommand extends Command { + name = 'kickFromVoice' + + async execute(ctx: CommandContext): Promise { + if (ctx.guild !== undefined) { + const voiceStates = await ctx.guild.voiceStates.array() + if (voiceStates !== undefined) { + voiceStates.forEach(async (voiceState) => { + const member = await voiceState.disconnect() + if (member !== undefined) { + ctx.channel.send(`Kicked member ${member.id}`) + } + }) + } + } + } +} From 51b1d71e9a9053372191a0751017c0ca13eea8e2 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 02:18:24 +0900 Subject: [PATCH 11/15] :sparkles: Add guild channel voice states manager --- src/managers/guildChannelVoiceStates.ts | 39 +++++++++++++++++++++++++ src/structures/guildVoiceChannel.ts | 6 ++++ src/test/cmds/kickFromSpecificVoice.ts | 28 ++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/managers/guildChannelVoiceStates.ts create mode 100644 src/test/cmds/kickFromSpecificVoice.ts diff --git a/src/managers/guildChannelVoiceStates.ts b/src/managers/guildChannelVoiceStates.ts new file mode 100644 index 0000000..2dc9ac5 --- /dev/null +++ b/src/managers/guildChannelVoiceStates.ts @@ -0,0 +1,39 @@ +import { Client } from '../models/client.ts' +import { BaseChildManager } from './baseChild.ts' +import { VoiceStatePayload } from '../types/voice.ts' +import { VoiceState } from '../structures/voiceState.ts' +import { GuildVoiceStatesManager } from './guildVoiceStates.ts' +import { VoiceChannel } from '../structures/guildVoiceChannel.ts' + +export class GuildChannelVoiceStatesManager extends BaseChildManager< + VoiceStatePayload, + VoiceState +> { + channel: VoiceChannel + + constructor( + client: Client, + parent: GuildVoiceStatesManager, + channel: VoiceChannel + ) { + super(client, parent as any) + this.channel = channel + } + + async get(id: string): Promise { + const res = await this.parent.get(id) + if (res !== undefined && res.channel?.id === this.channel.id) return res + else return undefined + } + + async array(): Promise { + const arr = (await this.parent.array()) as VoiceState[] + return arr.filter((c: any) => c.channel?.id === this.channel.id) as any + } + + async fromPayload(d: VoiceStatePayload[]): Promise { + for (const data of d) { + await this.set(data.user_id, data) + } + } +} diff --git a/src/structures/guildVoiceChannel.ts b/src/structures/guildVoiceChannel.ts index d1dc287..0f2764a 100644 --- a/src/structures/guildVoiceChannel.ts +++ b/src/structures/guildVoiceChannel.ts @@ -10,6 +10,7 @@ import { CHANNEL } from '../types/endpoint.ts' import { GuildChannel } from './channel.ts' import { Guild } from './guild.ts' import { VoiceState } from './voiceState.ts' +import { GuildChannelVoiceStatesManager } from '../managers/guildChannelVoiceStates.ts' export interface VoiceServerData extends VoiceServerUpdateData { sessionID: string @@ -18,6 +19,11 @@ export interface VoiceServerData extends VoiceServerUpdateData { export class VoiceChannel extends GuildChannel { bitrate: string userLimit: number + voiceStates = new GuildChannelVoiceStatesManager( + this.client, + this.guild.voiceStates, + this + ) constructor(client: Client, data: GuildVoiceChannelPayload, guild: Guild) { super(client, data, guild) diff --git a/src/test/cmds/kickFromSpecificVoice.ts b/src/test/cmds/kickFromSpecificVoice.ts new file mode 100644 index 0000000..5fb8499 --- /dev/null +++ b/src/test/cmds/kickFromSpecificVoice.ts @@ -0,0 +1,28 @@ +import { Command, VoiceChannel } from '../../../mod.ts' +import { CommandContext } from '../../models/command.ts' +import { ChannelTypes } from '../../types/channel.ts' + +export default class KickFromSpecificVoiceCommand extends Command { + name = 'kickFromSpecificVoice' + + async execute(ctx: CommandContext): Promise { + if (ctx.guild !== undefined) { + const channel = await ctx.guild.channels.get('YOUR VOICE CHANNEL ID') + if (channel === undefined || channel.type !== ChannelTypes.GUILD_VOICE) { + ctx.channel.send('The channel is either not a voice or not available.') + return + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const voiceStates = await (channel as VoiceChannel).voiceStates.array() + if (voiceStates !== undefined) { + voiceStates.forEach(async (voiceState) => { + const member = await voiceState.disconnect() + if (member !== undefined) { + ctx.channel.send(`Kicked member ${member.id}`) + } + }) + } + } + } +} From 96b273ed047a77e92627b8711ca0d19e248f4c6c Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 11:05:21 +0900 Subject: [PATCH 12/15] :sparkles: Add disconnection functions to voice channel --- src/structures/guildVoiceChannel.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/structures/guildVoiceChannel.ts b/src/structures/guildVoiceChannel.ts index 0f2764a..759fb71 100644 --- a/src/structures/guildVoiceChannel.ts +++ b/src/structures/guildVoiceChannel.ts @@ -11,6 +11,8 @@ import { GuildChannel } from './channel.ts' import { Guild } from './guild.ts' import { VoiceState } from './voiceState.ts' import { GuildChannelVoiceStatesManager } from '../managers/guildChannelVoiceStates.ts' +import { User } from './user.ts' +import { Member } from './member.ts' export interface VoiceServerData extends VoiceServerUpdateData { sessionID: string @@ -113,4 +115,25 @@ export class VoiceChannel extends GuildChannel { return new VoiceChannel(this.client, resp, this.guild) } + + async disconnectMember( + member: User | Member | string + ): Promise { + const memberID = typeof member === 'string' ? member : member.id + const memberVoiceState = await this.voiceStates.get(memberID) + + return memberVoiceState?.disconnect() + } + + async disconnectAll(): Promise { + const members: Member[] = [] + for await (const memberVoiceState of this.voiceStates) { + const member = await memberVoiceState.disconnect() + if (member !== undefined) { + members.push(member) + } + } + + return members + } } From 3fe5ce3063e31d29cab8e2d1d7cd9aa92ec74112 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Wed, 31 Mar 2021 11:29:07 +0900 Subject: [PATCH 13/15] :white_check_mark: Add voice channel disconnect test --- src/test/cmds/kickFromSpecificVoice.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/test/cmds/kickFromSpecificVoice.ts b/src/test/cmds/kickFromSpecificVoice.ts index 5fb8499..f60089b 100644 --- a/src/test/cmds/kickFromSpecificVoice.ts +++ b/src/test/cmds/kickFromSpecificVoice.ts @@ -14,15 +14,10 @@ export default class KickFromSpecificVoiceCommand extends Command { } // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - const voiceStates = await (channel as VoiceChannel).voiceStates.array() - if (voiceStates !== undefined) { - voiceStates.forEach(async (voiceState) => { - const member = await voiceState.disconnect() - if (member !== undefined) { - ctx.channel.send(`Kicked member ${member.id}`) - } - }) - } + const members = await (channel as VoiceChannel).disconnectAll() + members.forEach((member) => { + ctx.channel.send(`Kicked member ${member.id}`) + }) } } } From 5e89e3b8e41f723cb6fe507829f387ae8b1d4a64 Mon Sep 17 00:00:00 2001 From: MegaPixel Date: Sat, 3 Apr 2021 10:13:25 +0545 Subject: [PATCH 14/15] export colorutil --- mod.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/mod.ts b/mod.ts index 3faff80..fa941d4 100644 --- a/mod.ts +++ b/mod.ts @@ -146,3 +146,4 @@ export { UserFlags } from './src/types/userFlags.ts' export type { VoiceStatePayload } from './src/types/voice.ts' export type { WebhookPayload } from './src/types/webhook.ts' export * from './src/models/collectors.ts' +export * from './src/utils/colorutil.ts' From 5a8514949c238ec42e0a30ce10796d79b7a9eded Mon Sep 17 00:00:00 2001 From: MegaPixel Date: Sat, 3 Apr 2021 10:24:43 +0545 Subject: [PATCH 15/15] make it happy I guess --- mod.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod.ts b/mod.ts index fa941d4..2382784 100644 --- a/mod.ts +++ b/mod.ts @@ -146,4 +146,5 @@ export { UserFlags } from './src/types/userFlags.ts' export type { VoiceStatePayload } from './src/types/voice.ts' export type { WebhookPayload } from './src/types/webhook.ts' export * from './src/models/collectors.ts' -export * from './src/utils/colorutil.ts' +export { ColorUtil } from './src/utils/colorutil.ts' +export type { Colors } from './src/utils/colorutil.ts'