🔨 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({ require("dotenv").config({
path: __dirname+"/.env" path: __dirname+"/.env"
}); });
require("discord-player/smoothVolume");
const { Client, GuildMember, Intents } = require("discord.js"); const { Client, GuildMember, Intents } = require("discord.js");
const config = require("./config"); const config = require("./config");
const { Player, QueryType, QueueRepeatMode } = require("discord-player"); const { Player, QueryType, QueueRepeatMode } = require("discord-player");

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,7 @@ export class VolumeTransformer extends Transform {
private _chunk: Buffer; private _chunk: Buffer;
public volume: number; public volume: number;
private _targetVolume: number; private _targetVolume: number;
public type: "s16le" | "s32le" | "s16be" | "s32be";
constructor(options: VolumeTransformerOptions = {}) { constructor(options: VolumeTransformerOptions = {}) {
super(options); super(options);
switch (options.type) { switch (options.type) {
@ -42,9 +43,11 @@ export class VolumeTransformer extends Transform {
default: default:
throw new Error("VolumeTransformer type should be one of s16le, s16be, s32le, s32be"); throw new Error("VolumeTransformer type should be one of s16le, s16be, s32le, s32be");
} }
this.type = options.type;
this._bytes = this._bits / 8; this._bytes = this._bits / 8;
this._extremum = Math.pow(2, this._bits - 1); 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._targetVolume = this.volume;
this._chunk = Buffer.alloc(0); this._chunk = Buffer.alloc(0);
this._smoothing = options.smoothness || 0; this._smoothing = options.smoothness || 0;
@ -57,14 +60,16 @@ export class VolumeTransformer extends Transform {
return index; return index;
} }
_transform(chunk: Buffer, encoding: BufferEncoding, done: () => unknown) { _applySmoothness() {
if (this._smoothing > 0 && this.volume !== this._targetVolume) { if (this.volume < this._targetVolume) {
if (this.volume < this._targetVolume) { this.volume = this.volume + this._smoothing >= this._targetVolume ? this._targetVolume : this.volume + this._smoothing;
this.volume = this.volume + this._smoothing >= this._targetVolume ? this._targetVolume : this.volume + this._smoothing; } else if (this.volume > this._targetVolume) {
} else if (this.volume > this._targetVolume) { this.volume = this.volume - this._smoothing <= this._targetVolume ? this._targetVolume : this.volume - this._smoothing;
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) { if (this.volume === 1) {
this.push(chunk); this.push(chunk);
@ -94,6 +99,9 @@ export class VolumeTransformer extends Transform {
} }
setVolume(volume: number) { 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; this._targetVolume = volume;
if (this._smoothing <= 0) this.volume = volume; if (this._smoothing <= 0) this.volume = volume;
} }
@ -113,4 +121,24 @@ export class VolumeTransformer extends Transform {
get volumeLogarithmic() { get volumeLogarithmic() {
return Math.pow(this.volume, 1 / 1.660964); 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 { AudioFilters } from "./utils/AudioFilters";
export { ExtractorModel } from "./Structures/ExtractorModel"; export { ExtractorModel } from "./Structures/ExtractorModel";
export { Playlist } from "./Structures/Playlist"; 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 try {
(require("prism-media") as typeof import("prism-media")).VolumeTransformer = VolumeTransformer; // 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: dependencies:
prism-media "^1.2.9" prism-media "^1.2.9"
discord.js@^13.3.1: discord.js@^13.6.0:
version "13.6.0" version "13.6.0"
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-13.6.0.tgz#d8a8a591dbf25cbcf9c783d5ddf22c4694860475" resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-13.6.0.tgz#d8a8a591dbf25cbcf9c783d5ddf22c4694860475"
integrity sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g== integrity sha512-tXNR8zgsEPxPBvGk3AQjJ9ljIIC6/LOPjzKwpwz8Y1Q2X66Vi3ZqFgRHYwnHKC0jC0F+l4LzxlhmOJsBZDNg9g==