Plugin
VolumeBooster
Allows you to set the user and stream volume above the default maximum
1
import { definePluginSettings } from "@api/Settings";2
import { Devs } from "@utils/constants";3
import definePlugin, { makeRange, OptionType } from "@utils/types";4
5
const settings = definePluginSettings({6
multiplier: {7
description: "Volume Multiplier",8
type: OptionType.SLIDER,9
markers: makeRange(1, 5, 0.5),10
default: 2,11
stickToMarkers: true,12
}13
});14
15
interface StreamData {16
audioContext: AudioContext,17
audioElement: HTMLAudioElement,18
emitter: any,19
// added by this plugin20
gainNode?: GainNode,21
id: string,22
levelNode: AudioWorkletNode,23
sinkId: string | "default",24
stream: MediaStream,25
streamSourceNode?: MediaStreamAudioSourceNode,26
videoStreamId: string,27
_mute: boolean,28
_speakingFlags: number,29
_volume: number;30
}31
32
export default definePlugin({33
name: "VolumeBooster",34
authors: [Devs.Nuckyz, Devs.sadan],35
description: "Allows you to set the user and stream volume above the default maximum",36
tags: ["Voice", "Utility"],37
settings,38
39
patches: [40
// Change the max volume for sliders to allow for values above 20041
{42
find: "#{intl::USER_VOLUME}",43
replacement: {44
match: /(?<=maxValue:)\i\.isPlatformEmbedded\?(\i\.\i):\i\.\i(?=,)/,45
replace: (_, higherMaxVolume) => `${higherMaxVolume}*$self.settings.store.multiplier`46
}47
},48
// Change the max volume for sliders to allow for values above 20049
{50
find: "currentVolume:",51
replacement: {52
match: /(?<=maxValue:)\i\.\i\?(\d+?):\d+?(?=,)/,53
replace: (_, higherMaxVolume) => `${higherMaxVolume}*$self.settings.store.multiplier`54
}55
},56
// Patches needed for web/vesktop57
{58
find: "streamSourceNode",59
predicate: () => !IS_DISCORD_DESKTOP,60
group: true,61
replacement: [62
// Remove rounding algorithm63
{64
match: /Math\.max.{0,30}\)\)/,65
replace: "arguments[0]"66
},67
// Fix streams not playing audio until you update them68
{69
match: /\}return"video"/,70
replace: "this.updateAudioElement();$&"71
},72
// Patch the volume73
{74
match: /\.volume=this\._volume\/100;/,75
replace: ".volume=0.00;$self.patchVolume(this);"76
}77
]78
},79
// Prevent Audio Context Settings sync from trying to sync with values above 200, changing them to 200 before we send to Discord80
{81
find: "AudioContextSettingsMigrated",82
replacement: [83
{84
match: /(?<=isLocalMute\(\i,\i\),volume:(\i).+?\(0,\i\.\i\)\(\i,\i,\{volume:)\1(?=\}\))/,85
replace: "$&>200?200:$&"86
},87
{88
match: /(?<=Object\.entries\(\i\.localMutes\).+?volume:).+?(?=,)/,89
replace: "$&>200?200:$&"90
},91
{92
match: /(?<=Object\.entries\(\i\.localVolumes\).+?volume:).+?(?=})/,93
replace: "$&>200?200:$&"94
}95
]96
},97
// Prevent the MediaEngineStore from overwriting our LocalVolumes above 200 with the ones the Discord Audio Context Settings sync sends98
{99
find: 039;="MediaEngineStore",039;,100
replacement: [101
{102
match: /(\.settings\.audioContextSettings.+?)(\i\[\i\])=(\i\.volume)(.+?setLocalVolume\(\i,).+?\)/,103
replace: (_, rest1, localVolume, syncVolume, rest2) => rest1104
+ `(${localVolume}>200?void 0:${localVolume}=${syncVolume})`105
+ rest2106
+ `${localVolume}??${syncVolume})`107
}108
]109
}110
],111
112
patchVolume(data: StreamData) {113
if (data.stream.getAudioTracks().length === 0) return;114
115
data.streamSourceNode ??= data.audioContext.createMediaStreamSource(data.stream);116
117
if (!data.gainNode) {118
const gain = data.gainNode = data.audioContext.createGain();119
data.streamSourceNode.connect(gain);120
gain.connect(data.audioContext.destination);121
}122
123
// @ts-expect-error124
if (data.sinkId != null && data.sinkId !== data.audioContext.sinkId && "setSinkId" in AudioContext.prototype) {125
// @ts-expect-error https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/setSinkId126
data.audioContext.setSinkId(data.sinkId === "default" ? "" : data.sinkId);127
}128
129
data.gainNode.gain.value = data._mute130
? 0131
: data._volume / 100;132
}133
});134