mirror of
https://github.com/BluemediaDev/muse.git
synced 2025-06-27 09:12:43 +02:00
Merge pull request #1136 from museofficial/feature/lower-volume-when-talking
Feature/lower volume when talking
This commit is contained in:
commit
b2565a3a92
6 changed files with 162 additions and 10 deletions
|
@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
- New `/config set-reduce-vol-when-voice` command to automatically turn down the volume when people are speaking in the channel
|
||||
- New `/config set-reduce-vol-when-voice-target` command to set the target volume percentage (0-100) when people are speaking in the channel
|
||||
|
||||
|
||||
## [2.9.5] - 2024-10-29
|
||||
- Dependency update
|
||||
|
|
|
@ -143,3 +143,12 @@ In the default state, Muse has the status "Online" and the text "Listening to Mu
|
|||
### Bot-wide commands
|
||||
|
||||
If you have Muse running in a lot of guilds (10+) you may want to switch to registering commands bot-wide rather than for each guild. (The downside to this is that command updates can take up to an hour to propagate.) To do this, set the environment variable `REGISTER_COMMANDS_ON_BOT` to `true`.
|
||||
|
||||
### Automatically turn down volume when people speak
|
||||
|
||||
You can configure the bot to automatically turn down the volume when people are speaking in the channel using the following commands:
|
||||
|
||||
- `/config set-reduce-vol-when-voice true` - Enable automatic volume reduction
|
||||
- `/config set-reduce-vol-when-voice false` - Disable automatic volume reduction
|
||||
- `/config set-reduce-vol-when-voice-target <volume>` - Set the target volume percentage when people speak (0-100, default is 70)
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Setting" (
|
||||
"guildId" TEXT NOT NULL PRIMARY KEY,
|
||||
"playlistLimit" INTEGER NOT NULL DEFAULT 50,
|
||||
"secondsToWaitAfterQueueEmpties" INTEGER NOT NULL DEFAULT 30,
|
||||
"leaveIfNoListeners" BOOLEAN NOT NULL DEFAULT true,
|
||||
"queueAddResponseEphemeral" BOOLEAN NOT NULL DEFAULT false,
|
||||
"autoAnnounceNextSong" BOOLEAN NOT NULL DEFAULT false,
|
||||
"defaultVolume" INTEGER NOT NULL DEFAULT 100,
|
||||
"defaultQueuePageSize" INTEGER NOT NULL DEFAULT 10,
|
||||
"turnDownVolumeWhenPeopleSpeak" BOOLEAN NOT NULL DEFAULT false,
|
||||
"turnDownVolumeWhenPeopleSpeakTarget" INTEGER NOT NULL DEFAULT 20,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Setting" ("autoAnnounceNextSong", "createdAt", "defaultQueuePageSize", "defaultVolume", "guildId", "leaveIfNoListeners", "playlistLimit", "queueAddResponseEphemeral", "secondsToWaitAfterQueueEmpties", "updatedAt") SELECT "autoAnnounceNextSong", "createdAt", "defaultQueuePageSize", "defaultVolume", "guildId", "leaveIfNoListeners", "playlistLimit", "queueAddResponseEphemeral", "secondsToWaitAfterQueueEmpties", "updatedAt" FROM "Setting";
|
||||
DROP TABLE "Setting";
|
||||
ALTER TABLE "new_Setting" RENAME TO "Setting";
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
|
@ -32,6 +32,8 @@ model Setting {
|
|||
autoAnnounceNextSong Boolean @default(false)
|
||||
defaultVolume Int @default(100)
|
||||
defaultQueuePageSize Int @default(10)
|
||||
turnDownVolumeWhenPeopleSpeak Boolean @default(false)
|
||||
turnDownVolumeWhenPeopleSpeakTarget Int @default(20)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
|
|
@ -40,6 +40,22 @@ export default class implements Command {
|
|||
.setName('value')
|
||||
.setDescription('whether bot responses to queue additions are only displayed to the requester')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName('set-reduce-vol-when-voice')
|
||||
.setDescription('set whether to turn down the volume when people speak')
|
||||
.addBooleanOption(option => option
|
||||
.setName('value')
|
||||
.setDescription('whether to turn down the volume when people speak')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName('set-reduce-vol-when-voice-target')
|
||||
.setDescription('set the target volume when people speak')
|
||||
.addIntegerOption(option => option
|
||||
.setName('volume')
|
||||
.setDescription('volume percentage (0 is muted, 100 is max & default)')
|
||||
.setMinValue(0)
|
||||
.setMaxValue(100)
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName('set-auto-announce-next-song')
|
||||
.setDescription('set whether to announce the next song in the queue automatically')
|
||||
|
@ -197,6 +213,40 @@ export default class implements Command {
|
|||
break;
|
||||
}
|
||||
|
||||
case 'set-reduce-vol-when-voice': {
|
||||
const value = interaction.options.getBoolean('value')!;
|
||||
|
||||
await prisma.setting.update({
|
||||
where: {
|
||||
guildId: interaction.guild!.id,
|
||||
},
|
||||
data: {
|
||||
turnDownVolumeWhenPeopleSpeak: value,
|
||||
},
|
||||
});
|
||||
|
||||
await interaction.reply('👍 turn down volume setting updated');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'set-reduce-vol-when-voice-target': {
|
||||
const value = interaction.options.getInteger('volume')!;
|
||||
|
||||
await prisma.setting.update({
|
||||
where: {
|
||||
guildId: interaction.guild!.id,
|
||||
},
|
||||
data: {
|
||||
turnDownVolumeWhenPeopleSpeakTarget: value,
|
||||
},
|
||||
});
|
||||
|
||||
await interaction.reply('👍 turn down volume target setting updated');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'get': {
|
||||
const embed = new EmbedBuilder().setTitle('Config');
|
||||
|
||||
|
@ -212,6 +262,7 @@ export default class implements Command {
|
|||
'Add to queue reponses show for requester only': config.autoAnnounceNextSong ? 'yes' : 'no',
|
||||
'Default Volume': config.defaultVolume,
|
||||
'Default queue page size': config.defaultQueuePageSize,
|
||||
'Reduce volume when people speak': config.turnDownVolumeWhenPeopleSpeak ? 'yes' : 'no',
|
||||
};
|
||||
|
||||
let description = '';
|
||||
|
|
|
@ -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 {Setting} from '@prisma/client';
|
||||
|
||||
export enum MediaSource {
|
||||
Youtube,
|
||||
|
@ -82,6 +83,8 @@ export default class {
|
|||
private readonly fileCache: FileCacheProvider;
|
||||
private disconnectTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
private readonly channelToSpeakingUsers: Map<string, Set<string>> = new Map();
|
||||
|
||||
constructor(fileCache: FileCacheProvider, guildId: string) {
|
||||
this.fileCache = fileCache;
|
||||
this.guildId = guildId;
|
||||
|
@ -96,9 +99,12 @@ export default class {
|
|||
this.voiceConnection = joinVoiceChannel({
|
||||
channelId: channel.id,
|
||||
guildId: channel.guild.id,
|
||||
selfDeaf: false,
|
||||
adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator,
|
||||
});
|
||||
|
||||
const guildSettings = await getGuildSettings(this.guildId);
|
||||
|
||||
// Workaround to disable keepAlive
|
||||
this.voiceConnection.on('stateChange', (oldState, newState) => {
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
|
||||
|
@ -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(guildSettings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -302,6 +311,63 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
registerVoiceActivityListener(guildSettings: Setting) {
|
||||
const {turnDownVolumeWhenPeopleSpeak, turnDownVolumeWhenPeopleSpeakTarget} = guildSettings;
|
||||
if (!turnDownVolumeWhenPeopleSpeak || !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(turnDownVolumeWhenPeopleSpeakTarget);
|
||||
});
|
||||
|
||||
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(turnDownVolumeWhenPeopleSpeakTarget);
|
||||
});
|
||||
}
|
||||
|
||||
suppressVoiceWhenPeopleAreSpeaking(turnDownVolumeWhenPeopleSpeakTarget: number): void {
|
||||
if (!this.currentChannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const speakingUsers = this.channelToSpeakingUsers.get(this.currentChannel.id);
|
||||
if (speakingUsers && speakingUsers.size > 0) {
|
||||
this.setVolume(turnDownVolumeWhenPeopleSpeakTarget);
|
||||
} else {
|
||||
this.setVolume(this.defaultVolume);
|
||||
}
|
||||
}
|
||||
|
||||
canGoForward(skip: number) {
|
||||
return (this.queuePosition + skip - 1) < this.queue.length;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue