🔨 Auto inject smooth volume

This commit is contained in:
DevAndromeda 2022-01-31 17:29:00 +05:45
parent 6c46957f3f
commit 99b9cabdcf
9 changed files with 71 additions and 22 deletions

View file

@ -1,7 +1,6 @@
require("dotenv").config({
path: __dirname+"/.env"
});
require("discord-player/smoothVolume");
const { Client, GuildMember, Intents } = require("discord.js");
const config = require("./config");
const { Player, QueryType, QueueRepeatMode } = require("discord-player");

View file

@ -13,7 +13,9 @@
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./smoothVolume": "./dist/smoothVolume.js"
"./smoothVolume": "./dist/smoothVolume.js",
"./src/*": "./dist/*",
"./dist/*": "./dist/*"
},
"scripts": {
"dev": "cd example/test && ts-node index.ts",
@ -86,7 +88,7 @@
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"discord-api-types": "^0.24.0",
"discord.js": "^13.3.1",
"discord.js": "^13.6.0",
"eslint": "^8.3.0",
"gen-esm-wrapper": "^1.1.3",
"husky": "^7.0.4",

View file

@ -45,7 +45,7 @@ class Player extends EventEmitter<PlayerEvents> {
*/
this.client = client;
if (!new Intents(this.client.options.intents).has(Intents.FLAGS.GUILD_VOICE_STATES)) {
if (this.client?.options?.intents && !new Intents(this.client?.options?.intents).has(Intents.FLAGS.GUILD_VOICE_STATES)) {
throw new PlayerError('client is missing "GUILD_VOICE_STATES" intent');
}
@ -153,7 +153,7 @@ class Player extends EventEmitter<PlayerEvents> {
const _meta = queueInitOptions.metadata;
delete queueInitOptions["metadata"];
queueInitOptions.volumeSmoothness ??= 0.1;
queueInitOptions.volumeSmoothness ??= 0.08;
queueInitOptions.ytdlOptions ??= this.options.ytdlOptions;
const queue = new Queue(this, guild, queueInitOptions);
queue.metadata = _meta;

View file

@ -10,6 +10,7 @@ import YouTube from "youtube-sr";
import AudioFilters from "../utils/AudioFilters";
import { PlayerError, ErrorStatusCode } from "./PlayerError";
import type { Readable } from "stream";
import { VolumeTransformer } from "../VoiceInterface/VolumeTransformer";
class Queue<T = unknown> {
public readonly guild: Guild;
@ -154,8 +155,7 @@ class Queue<T = unknown> {
if (!["GUILD_STAGE_VOICE", "GUILD_VOICE"].includes(_channel?.type))
throw new PlayerError(`Channel type must be GUILD_VOICE or GUILD_STAGE_VOICE, got ${_channel?.type}!`, ErrorStatusCode.INVALID_ARG_TYPE);
const connection = await this.player.voiceUtils.connect(_channel, {
deaf: this.options.autoSelfDeaf,
maxTime: this.player.options.connectionTimeout || 20000
deaf: this.options.autoSelfDeaf
});
this.connection = connection;
@ -206,6 +206,10 @@ class Queue<T = unknown> {
}
});
await this.player.voiceUtils.enterReady(this.connection.voiceConnection, {
maxTime: this.player.options.connectionTimeout || 30_000
});
return this;
}
@ -703,8 +707,9 @@ class Queue<T = unknown> {
if (options.seek) this._streamTime = options.seek;
this._filtersUpdate = options.filtersUpdate;
if (resource.volume && typeof this.options.volumeSmoothness === "number") {
Reflect.set(resource.volume, "_smoothing", this.options.volumeSmoothness || 0);
const volumeTransformer = resource.volume as VolumeTransformer;
if (volumeTransformer?.hasSmoothness && typeof this.options.volumeSmoothness === "number") {
if (typeof volumeTransformer.setSmoothness === "function") volumeTransformer.setSmoothness(this.options.volumeSmoothness || 0);
}
this.setVolume(this.options.initialVolume);

View file

@ -49,13 +49,17 @@ class VoiceUtils {
maxTime?: number;
}
) {
let conn = joinVoiceChannel({
const conn = joinVoiceChannel({
guildId: channel.guild.id,
channelId: channel.id,
adapterCreator: channel.guild.voiceAdapterCreator as unknown as DiscordGatewayAdapterCreator,
selfDeaf: Boolean(options.deaf)
});
return conn;
}
public async enterReady(conn: VoiceConnection, options: { maxTime?: number } = {}) {
try {
conn = await entersState(conn, VoiceConnectionStatus.Ready, options?.maxTime ?? 20000);
return conn;

View file

@ -16,6 +16,7 @@ export class VolumeTransformer extends Transform {
private _chunk: Buffer;
public volume: number;
private _targetVolume: number;
public type: "s16le" | "s32le" | "s16be" | "s32be";
constructor(options: VolumeTransformerOptions = {}) {
super(options);
switch (options.type) {
@ -42,9 +43,11 @@ export class VolumeTransformer extends Transform {
default:
throw new Error("VolumeTransformer type should be one of s16le, s16be, s32le, s32be");
}
this.type = options.type;
this._bytes = this._bits / 8;
this._extremum = Math.pow(2, this._bits - 1);
this.volume = typeof options.volume === "undefined" ? 1 : options.volume;
this.volume = Number.isNaN(options.volume) ? 1 : Number(options.volume);
if (!Number.isFinite(this.volume)) this.volume = 1;
this._targetVolume = this.volume;
this._chunk = Buffer.alloc(0);
this._smoothing = options.smoothness || 0;
@ -57,14 +60,16 @@ export class VolumeTransformer extends Transform {
return index;
}
_transform(chunk: Buffer, encoding: BufferEncoding, done: () => unknown) {
if (this._smoothing > 0 && this.volume !== this._targetVolume) {
if (this.volume < this._targetVolume) {
this.volume = this.volume + this._smoothing >= this._targetVolume ? this._targetVolume : this.volume + this._smoothing;
} else if (this.volume > this._targetVolume) {
this.volume = this.volume - this._smoothing <= this._targetVolume ? this._targetVolume : this.volume - this._smoothing;
}
_applySmoothness() {
if (this.volume < this._targetVolume) {
this.volume = this.volume + this._smoothing >= this._targetVolume ? this._targetVolume : this.volume + this._smoothing;
} else if (this.volume > this._targetVolume) {
this.volume = this.volume - this._smoothing <= this._targetVolume ? this._targetVolume : this.volume - this._smoothing;
}
}
_transform(chunk: Buffer, encoding: BufferEncoding, done: () => unknown) {
if (this.smoothingEnabled() && this.volume !== this._targetVolume) this._applySmoothness();
if (this.volume === 1) {
this.push(chunk);
@ -94,6 +99,9 @@ export class VolumeTransformer extends Transform {
}
setVolume(volume: number) {
if (Number.isNaN(volume)) volume = 1;
if (typeof volume !== "number") volume = Number(volume);
if (!Number.isFinite(volume)) volume = volume < 0 ? 0 : 1;
this._targetVolume = volume;
if (this._smoothing <= 0) this.volume = volume;
}
@ -113,4 +121,24 @@ export class VolumeTransformer extends Transform {
get volumeLogarithmic() {
return Math.pow(this.volume, 1 / 1.660964);
}
get smoothness() {
return this._smoothing;
}
setSmoothness(smoothness: number) {
this._smoothing = smoothness;
}
smoothingEnabled() {
return Number.isFinite(this._smoothing) && this._smoothing > 0;
}
get hasSmoothness() {
return true;
}
static get hasSmoothing() {
return true;
}
}

View file

@ -1,3 +1,6 @@
// try applying smooth volume patch on load
import "./smoothVolume";
export { AudioFilters } from "./utils/AudioFilters";
export { ExtractorModel } from "./Structures/ExtractorModel";
export { Playlist } from "./Structures/Playlist";

View file

@ -1,4 +1,12 @@
import { VolumeTransformer } from "./VolumeTransformer";
import { VolumeTransformer as VolumeTransformerMock } from "./VoiceInterface/VolumeTransformer";
// eslint-disable-next-line
(require("prism-media") as typeof import("prism-media")).VolumeTransformer = VolumeTransformer;
try {
// eslint-disable-next-line
const mod = require("prism-media") as typeof import("prism-media") & { VolumeTransformer: typeof VolumeTransformerMock };
if (typeof mod.VolumeTransformer.hasSmoothing !== "boolean") {
Reflect.set(mod, "VolumeTransformer", VolumeTransformerMock);
}
} catch {
/* do nothing */
}

View file

@ -1990,7 +1990,7 @@ discord-ytdl-core@^5.0.4:
dependencies:
prism-media "^1.2.9"
discord.js@^13.3.1:
discord.js@^13.6.0:
version "13.6.0"
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-13.6.0.tgz#d8a8a591dbf25cbcf9c783d5ddf22c4694860475"
integrity sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==