🔨 Auto inject smooth volume
This commit is contained in:
parent
6c46957f3f
commit
99b9cabdcf
9 changed files with 71 additions and 22 deletions
|
@ -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");
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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";
|
||||||
|
|
|
@ -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 */
|
||||||
|
}
|
||||||
|
|
|
@ -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==
|
||||||
|
|
Loading…
Reference in a new issue