diff options
Diffstat (limited to 'src/services')
| -rw-r--r-- | src/services/config.ts | 4 | ||||
| -rw-r--r-- | src/services/player.ts | 67 |
2 files changed, 70 insertions, 1 deletions
diff --git a/src/services/config.ts b/src/services/config.ts index b6b9aea..ef2a7c9 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -14,6 +14,8 @@ const CONFIG_MAP = { YOUTUBE_API_KEY: process.env.YOUTUBE_API_KEY, SPOTIFY_CLIENT_ID: process.env.SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET: process.env.SPOTIFY_CLIENT_SECRET, + TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK: process.env.TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK === 'true', + TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET: process.env.TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET ?? 20, REGISTER_COMMANDS_ON_BOT: process.env.REGISTER_COMMANDS_ON_BOT === 'true', DATA_DIR, CACHE_DIR: path.join(DATA_DIR, 'cache'), @@ -43,6 +45,8 @@ export default class Config { readonly DATA_DIR!: string; readonly CACHE_DIR!: string; readonly CACHE_LIMIT_IN_BYTES!: number; + readonly TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK!: boolean; + readonly TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET!: number; readonly BOT_STATUS!: PresenceStatusData; readonly BOT_ACTIVITY_TYPE!: Exclude<ActivityType, ActivityType.Custom>; readonly BOT_ACTIVITY_URL!: string; diff --git a/src/services/player.ts b/src/services/player.ts index 5e284a6..00081ca 100644 --- a/src/services/player.ts +++ b/src/services/player.ts @@ -20,6 +20,7 @@ import FileCacheProvider from './file-cache.js'; import debug from '../utils/debug.js'; import {getGuildSettings} from '../utils/get-guild-settings.js'; import {buildPlayingMessageEmbed} from '../utils/build-embed.js'; +import Config from './config.js'; export enum MediaSource { Youtube, @@ -82,9 +83,13 @@ export default class { private readonly fileCache: FileCacheProvider; private disconnectTimer: NodeJS.Timeout | null = null; - constructor(fileCache: FileCacheProvider, guildId: string) { + private readonly channelToSpeakingUsers: Map<string, Set<string>> = new Map(); + private readonly config: Config; + + constructor(fileCache: FileCacheProvider, guildId: string, config: Config) { this.fileCache = fileCache; this.guildId = guildId; + this.config = config; } async connect(channel: VoiceChannel): Promise<void> { @@ -96,6 +101,7 @@ export default class { this.voiceConnection = joinVoiceChannel({ channelId: channel.id, guildId: channel.guild.id, + selfDeaf: false, adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator, }); @@ -115,6 +121,9 @@ export default class { /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */ this.currentChannel = channel; + if (newState.status === VoiceConnectionStatus.Ready) { + this.registerVoiceActivityListener(); + } }); } @@ -302,6 +311,62 @@ export default class { } } + registerVoiceActivityListener(): void { + if (!this.config.TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK || !this.voiceConnection) { + return; + } + + this.voiceConnection.receiver.speaking.on('start', (userId: string) => { + if (!this.currentChannel) { + return; + } + + const member = this.currentChannel.members.get(userId); + const channelId = this.currentChannel?.id; + + if (member) { + if (!this.channelToSpeakingUsers.has(channelId)) { + this.channelToSpeakingUsers.set(channelId, new Set()); + } + + this.channelToSpeakingUsers.get(channelId)?.add(member.id); + } + + this.suppressVoiceWhenPeopleAreSpeaking(); + }); + + this.voiceConnection.receiver.speaking.on('end', (userId: string) => { + if (!this.currentChannel) { + return; + } + + const member = this.currentChannel.members.get(userId); + const channelId = this.currentChannel.id; + if (member) { + if (!this.channelToSpeakingUsers.has(channelId)) { + this.channelToSpeakingUsers.set(channelId, new Set()); + } + + this.channelToSpeakingUsers.get(channelId)?.delete(member.id); + } + + this.suppressVoiceWhenPeopleAreSpeaking(); + }); + } + + suppressVoiceWhenPeopleAreSpeaking(): void { + if (!this.currentChannel) { + return; + } + + const speakingUsers = this.channelToSpeakingUsers.get(this.currentChannel.id); + if (speakingUsers && speakingUsers.size > 0) { + this.setVolume(this.config.TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET); + } else { + this.setVolume(this.defaultVolume); + } + } + canGoForward(skip: number) { return (this.queuePosition + skip - 1) < this.queue.length; } |
