Merge pull request #119 from Helloyunho/voiceState-updates
Add things to `<VoiceState>` and Add `<GuildChannelVoiceStatesManager>`
This commit is contained in:
commit
01f92b35bf
7 changed files with 221 additions and 7 deletions
39
src/managers/guildChannelVoiceStates.ts
Normal file
39
src/managers/guildChannelVoiceStates.ts
Normal file
|
@ -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<VoiceState | undefined> {
|
||||
const res = await this.parent.get(id)
|
||||
if (res !== undefined && res.channel?.id === this.channel.id) return res
|
||||
else return undefined
|
||||
}
|
||||
|
||||
async array(): Promise<VoiceState[]> {
|
||||
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<void> {
|
||||
for (const data of d) {
|
||||
await this.set(data.user_id, data)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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, {
|
||||
|
|
|
@ -10,6 +10,9 @@ 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'
|
||||
import { User } from './user.ts'
|
||||
import { Member } from './member.ts'
|
||||
|
||||
export interface VoiceServerData extends VoiceServerUpdateData {
|
||||
sessionID: string
|
||||
|
@ -18,6 +21,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)
|
||||
|
@ -107,4 +115,25 @@ export class VoiceChannel extends GuildChannel {
|
|||
|
||||
return new VoiceChannel(this.client, resp, this.guild)
|
||||
}
|
||||
|
||||
async disconnectMember(
|
||||
member: User | Member | string
|
||||
): Promise<Member | undefined> {
|
||||
const memberID = typeof member === 'string' ? member : member.id
|
||||
const memberVoiceState = await this.voiceStates.get(memberID)
|
||||
|
||||
return memberVoiceState?.disconnect()
|
||||
}
|
||||
|
||||
async disconnectAll(): Promise<Member[]> {
|
||||
const members: Member[] = []
|
||||
for await (const memberVoiceState of this.voiceStates) {
|
||||
const member = await memberVoiceState.disconnect()
|
||||
if (member !== undefined) {
|
||||
members.push(member)
|
||||
}
|
||||
}
|
||||
|
||||
return members
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Role | string>
|
||||
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:
|
||||
data.channel instanceof VoiceChannel ? data.channel.id : data.channel
|
||||
}
|
||||
|
||||
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<Member> {
|
||||
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<Member> {
|
||||
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<Member> {
|
||||
return await this.edit({
|
||||
channel: channel ?? null
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects a Member from connected VC
|
||||
*/
|
||||
async disconnectVoice(): Promise<Member> {
|
||||
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<Member> {
|
||||
return await this.setDeaf(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks the member.
|
||||
*/
|
||||
|
|
|
@ -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<Member | undefined> {
|
||||
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<Member | undefined> {
|
||||
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<Member | undefined> {
|
||||
return this.member?.setMute(mute)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Member deaf in VC
|
||||
* @param deaf Value to set
|
||||
*/
|
||||
async setDeaf(deaf?: boolean): Promise<Member | undefined> {
|
||||
return this.member?.setDeaf(deaf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes the Member from VC.
|
||||
*/
|
||||
async unmute(): Promise<Member | undefined> {
|
||||
return await this.setMute(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Undeafs the Member from VC.
|
||||
*/
|
||||
async undeaf(): Promise<Member | undefined> {
|
||||
return await this.setDeaf(false)
|
||||
}
|
||||
}
|
||||
|
|
23
src/test/cmds/kickFromSpecificVoice.ts
Normal file
23
src/test/cmds/kickFromSpecificVoice.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
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<void> {
|
||||
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 members = await (channel as VoiceChannel).disconnectAll()
|
||||
members.forEach((member) => {
|
||||
ctx.channel.send(`Kicked member ${member.id}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
20
src/test/cmds/kickFromVoice.ts
Normal file
20
src/test/cmds/kickFromVoice.ts
Normal file
|
@ -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<void> {
|
||||
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}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue