mirror of
https://github.com/BluemediaDev/muse.git
synced 2025-06-27 01:02:41 +02:00
feat: automatically turn down volume when people talks
This commit is contained in:
parent
534d8fafaa
commit
aae98255b1
7 changed files with 90 additions and 4 deletions
|
@ -18,3 +18,4 @@ SPOTIFY_CLIENT_SECRET=
|
|||
# BOT_ACTIVITY_TYPE=
|
||||
# BOT_ACTIVITY_URL=
|
||||
# BOT_ACTIVITY=
|
||||
# TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK=
|
|
@ -5,6 +5,12 @@ 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]
|
||||
## [2.9.5] - 2024-09-15
|
||||
|
||||
### Added
|
||||
- An optional `TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK` config to automatically turn
|
||||
down the volume when people are speaking in the channel
|
||||
- An optional `TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET` config to set the target volume when people are speaking in the channel
|
||||
|
||||
## [2.9.4] - 2024-08-28
|
||||
|
||||
|
|
|
@ -141,3 +141,10 @@ 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 let the bot automatically turn down the volume when people are speaking
|
||||
in the channel though environment variable:
|
||||
- `TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK=true`
|
||||
- `TURN_DOWN_VOLUME_WHEN_PEOPLE_SPEAK_TARGET=70` (optional, default is 70%)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "muse",
|
||||
"version": "2.9.4",
|
||||
"version": "2.9.5",
|
||||
"description": "🎧 a self-hosted Discord music bot that doesn't suck ",
|
||||
"repository": "git@github.com:museofficial/muse.git",
|
||||
"author": "Max Isom <hi@maxisom.me>",
|
||||
|
|
|
@ -2,22 +2,25 @@ import {inject, injectable} from 'inversify';
|
|||
import {TYPES} from '../types.js';
|
||||
import Player from '../services/player.js';
|
||||
import FileCacheProvider from '../services/file-cache.js';
|
||||
import Config from '../services/config.js';
|
||||
|
||||
@injectable()
|
||||
export default class {
|
||||
private readonly guildPlayers: Map<string, Player>;
|
||||
private readonly fileCache: FileCacheProvider;
|
||||
private readonly config: Config;
|
||||
|
||||
constructor(@inject(TYPES.FileCache) fileCache: FileCacheProvider) {
|
||||
constructor(@inject(TYPES.FileCache) fileCache: FileCacheProvider, @inject(TYPES.Config) config: Config) {
|
||||
this.guildPlayers = new Map();
|
||||
this.fileCache = fileCache;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
get(guildId: string): Player {
|
||||
let player = this.guildPlayers.get(guildId);
|
||||
|
||||
if (!player) {
|
||||
player = new Player(this.fileCache, guildId);
|
||||
player = new Player(this.fileCache, guildId, this.config);
|
||||
|
||||
this.guildPlayers.set(guildId, player);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue