style: run format:apply

This commit is contained in:
2026-01-13 17:50:33 -03:00
parent 02949e8b16
commit 83569a27e7
+154 -142
View File
@@ -1,182 +1,194 @@
import { AudioPlayer, createAudioPlayer, createAudioResource, StreamType, VoiceConnection } from "@discordjs/voice";
import { AudioMixer } from "node-audio-mixer";
import { PassThrough, Readable } from "stream";
import {
AudioPlayer,
createAudioPlayer,
createAudioResource,
StreamType,
VoiceConnection
} from '@discordjs/voice';
import { AudioMixer } from 'node-audio-mixer';
import { PassThrough, Readable } from 'stream';
import prism from "prism-media";
import prism from 'prism-media';
export class StreamQueue {
private queue: Readable[] = [];
private isPlaying = false;
private mixer: MixedStream;
private queue: Readable[] = [];
private isPlaying = false;
private mixer: MixedStream;
constructor(mixer: MixedStream) {
this.mixer = mixer;
}
constructor(mixer: MixedStream) {
this.mixer = mixer;
}
public enqueue(resource: Readable) {
this.queue.push(resource);
this.processQueue();
}
public enqueue(resource: Readable) {
this.queue.push(resource);
this.processQueue();
}
private async processQueue() {
if (this.isPlaying || this.queue.length === 0) return;
private async processQueue() {
if (this.isPlaying || this.queue.length === 0) return;
this.isPlaying = true;
const nextStream = this.queue.shift();
this.isPlaying = true;
const nextStream = this.queue.shift();
try {
if (nextStream) {
await this.mixer.playStream(nextStream);
}
} catch (e) {
console.error("Queue error:", e);
} finally {
this.isPlaying = false;
this.processQueue();
}
}
try {
if (nextStream) {
await this.mixer.playStream(nextStream);
}
} catch (e) {
console.error('Queue error:', e);
} finally {
this.isPlaying = false;
this.processQueue();
}
}
public clear() {
this.queue = [];
}
public clear() {
this.queue = [];
}
}
export class MixedStream {
public readonly player: AudioPlayer;
private mixer: AudioMixer;
private output: PassThrough;
private silenceInterval: NodeJS.Timeout;
public readonly player: AudioPlayer;
private mixer: AudioMixer;
private output: PassThrough;
private silenceInterval: NodeJS.Timeout;
private queues: Map<string, StreamQueue> = new Map();
private queues: Map<string, StreamQueue> = new Map();
public constructor() {
this.player = createAudioPlayer();
public constructor() {
this.player = createAudioPlayer();
this.mixer = new AudioMixer({
channels: 2,
bitDepth: 16,
sampleRate: 48000,
autoClose: false,
generateSilence: false // does not work :<
});
this.mixer = new AudioMixer({
channels: 2,
bitDepth: 16,
sampleRate: 48000,
autoClose: false,
generateSilence: false // does not work :<
});
const silenceInput = this.mixer.createAudioInput({
channels: 2,
sampleRate: 48000,
bitDepth: 16,
volume: 100
})
const silenceInput = this.mixer.createAudioInput({
channels: 2,
sampleRate: 48000,
bitDepth: 16,
volume: 100
});
const chunk = Buffer.alloc(3840);
this.silenceInterval = setInterval(() => {
if (silenceInput.writable && silenceInput.writableLength < 3840 * 10) {
silenceInput.write(chunk);
}
}, 20);
const chunk = Buffer.alloc(3840);
this.silenceInterval = setInterval(() => {
if (silenceInput.writable && silenceInput.writableLength < 3840 * 10) {
silenceInput.write(chunk);
}
}, 20);
this.output = new PassThrough({ highWaterMark: 1024 * 16 });
this.mixer.pipe(this.output);
this.output = new PassThrough({ highWaterMark: 1024 * 16 });
this.mixer.pipe(this.output);
const resource = createAudioResource(this.output, {
inputType: StreamType.Raw
});
const resource = createAudioResource(this.output, {
inputType: StreamType.Raw
});
this.player.play(resource);
this.player.on('error', error => {
console.error('Error: ', error.message);
});
}
this.player.play(resource);
this.player.on('error', (error) => {
console.error('Error: ', error.message);
});
}
public getQueue(name: string): StreamQueue {
let queue = this.queues.get(name);
if (!queue) {
queue = new StreamQueue(this);
this.queues.set(name, queue);
}
return queue;
}
public getQueue(name: string): StreamQueue {
let queue = this.queues.get(name);
if (!queue) {
queue = new StreamQueue(this);
this.queues.set(name, queue);
}
return queue;
}
public playStream(source: Readable): Promise<void> {
return new Promise((resolve) => {
const mixerInput = this.mixer.createAudioInput({
channels: 2,
sampleRate: 48000,
bitDepth: 16,
volume: 100,
});
public playStream(source: Readable): Promise<void> {
return new Promise((resolve) => {
const mixerInput = this.mixer.createAudioInput({
channels: 2,
sampleRate: 48000,
bitDepth: 16,
volume: 100
});
const transcoder = new prism.FFmpeg({
args: [
'-analyzeduration', '0',
'-loglevel', '0',
'-f', 's16le',
'-ar', '48000',
'-ac', '2',
],
});
let totalBytes = 0;
const transcoder = new prism.FFmpeg({
args: [
'-analyzeduration',
'0',
'-loglevel',
'0',
'-f',
's16le',
'-ar',
'48000',
'-ac',
'2'
]
});
let totalBytes = 0;
transcoder.on('data', (chunk: Buffer) => {
totalBytes += chunk.length;
});
transcoder.on('data', (chunk: Buffer) => {
totalBytes += chunk.length;
});
transcoder.on('end', () => {
const durationMs = (totalBytes / 192000) * 1000;
transcoder.on('end', () => {
const durationMs = (totalBytes / 192000) * 1000;
setTimeout(() => {
source.unpipe(transcoder);
transcoder.unpipe(mixerInput);
this.mixer.removeAudioinput(mixerInput);
transcoder.destroy();
resolve();
}, durationMs);
})
setTimeout(() => {
source.unpipe(transcoder);
transcoder.unpipe(mixerInput);
this.mixer.removeAudioinput(mixerInput);
transcoder.destroy();
resolve();
}, durationMs);
});
transcoder.on('error', () => {
this.mixer.removeAudioinput(mixerInput);
resolve();
});
transcoder.on('error', () => {
this.mixer.removeAudioinput(mixerInput);
resolve();
});
source.pipe(transcoder).pipe(mixerInput);
});
}
source.pipe(transcoder).pipe(mixerInput);
});
}
public destroy(): void {
this.player.stop();
this.output.destroy();
this.mixer.destroy();
clearInterval(this.silenceInterval);
}
public destroy(): void {
this.player.stop();
this.output.destroy();
this.mixer.destroy();
clearInterval(this.silenceInterval);
}
}
export class AudioStreamManager {
private streams = new WeakMap<VoiceConnection, MixedStream>();
private streams = new WeakMap<VoiceConnection, MixedStream>();
public getOrCreateStream(conn: VoiceConnection): MixedStream {
let stream = this.streams.get(conn);
if (stream) return stream;
public getOrCreateStream(conn: VoiceConnection): MixedStream {
let stream = this.streams.get(conn);
if (stream) return stream;
stream = new MixedStream();
this.streams.set(conn, stream);
conn.subscribe(stream.player);
return stream;
}
stream = new MixedStream();
this.streams.set(conn, stream);
conn.subscribe(stream.player);
return stream;
}
public destroyStream(conn: VoiceConnection): void {
const stream = this.streams.get(conn);
if (stream) {
stream.destroy();
this.streams.delete(conn);
}
}
public destroyStream(conn: VoiceConnection): void {
const stream = this.streams.get(conn);
if (stream) {
stream.destroy();
this.streams.delete(conn);
}
}
/*
/*
singleton logic
*/
static #instance: AudioStreamManager | null = null;
static #instance: AudioStreamManager | null = null;
public static get get(): AudioStreamManager {
if (!AudioStreamManager.#instance) AudioStreamManager.#instance = new AudioStreamManager();
return AudioStreamManager.#instance;
}
public static get get(): AudioStreamManager {
if (!AudioStreamManager.#instance)
AudioStreamManager.#instance = new AudioStreamManager();
return AudioStreamManager.#instance;
}
}