134 lines
3.3 KiB
TypeScript
134 lines
3.3 KiB
TypeScript
import { Queue } from "../../utils/mod.ts";
|
|
import { AudioSource, LoadSource } from "../audio-source/mod.ts";
|
|
import { ConnectionData } from "../connection-data.ts";
|
|
import { PlayerEventSource, AllEventTypes, PlayerListener } from "./events.ts";
|
|
import { RawPlayer } from "./raw-player.ts";
|
|
import { Player } from "./types.ts";
|
|
|
|
import { nowPlayingCallback } from "../../../commands/np.ts";
|
|
|
|
export class QueuePlayer
|
|
extends Queue<AudioSource>
|
|
implements Player<AudioSource>
|
|
{
|
|
playing = true;
|
|
looping = false;
|
|
playingSince?: number;
|
|
nowPlaying?: AudioSource;
|
|
#rawPlayer: RawPlayer;
|
|
#loadSource: LoadSource;
|
|
#events = new PlayerEventSource<AudioSource, AllEventTypes>();
|
|
|
|
constructor(conn: ConnectionData, loadSource: LoadSource) {
|
|
super();
|
|
this.#loadSource = loadSource;
|
|
this.#rawPlayer = new RawPlayer(conn);
|
|
this.playNext();
|
|
this.#rawPlayer.on("done", async () => {
|
|
const current = this.current();
|
|
if (current) {
|
|
this.#events.trigger("done", current);
|
|
}
|
|
await this.playNext();
|
|
if (!this.playing) {
|
|
this.pause();
|
|
}
|
|
});
|
|
}
|
|
|
|
async playNext() {
|
|
let song;
|
|
const current = this.current();
|
|
if (this.looping && current !== undefined) {
|
|
song = current;
|
|
this.#events.trigger("loop", song);
|
|
} else {
|
|
song = await super.next();
|
|
this.#events.trigger("next", song);
|
|
}
|
|
this.playingSince = Date.now();
|
|
this.nowPlaying = song;
|
|
this.#rawPlayer.setAudio(await song.data());
|
|
await nowPlayingCallback(this.#rawPlayer.conn);
|
|
}
|
|
|
|
clear() {
|
|
return super.clear();
|
|
}
|
|
|
|
play() {
|
|
this.playing = true;
|
|
this.#rawPlayer.play();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
pause() {
|
|
this.playing = false;
|
|
this.#rawPlayer.pause();
|
|
}
|
|
|
|
stop() {
|
|
this.skip();
|
|
this.pause();
|
|
}
|
|
|
|
skip() {
|
|
this.looping = false;
|
|
this.#rawPlayer.clear();
|
|
}
|
|
|
|
loop(value: boolean) {
|
|
this.looping = value;
|
|
}
|
|
|
|
stopInterrupt() {
|
|
this.#rawPlayer.interrupt(undefined);
|
|
}
|
|
|
|
/**
|
|
* Listen to events:
|
|
*
|
|
* `next`: New sound started playing
|
|
*
|
|
* `done`: Last sound is done playing
|
|
*
|
|
* `loop`: New loop iteration was started
|
|
* @param event Event to listen to
|
|
* @param listener Triggered on event
|
|
* @returns Function that disconnects the listener
|
|
*/
|
|
on<J extends AllEventTypes>(
|
|
event: J,
|
|
listener: PlayerListener<AudioSource, J>
|
|
) {
|
|
return this.#events.on(event, listener);
|
|
}
|
|
|
|
/**
|
|
* Interrupts the current song, resumes when finished
|
|
* @param query Loads a universal song (local file or youtube search)
|
|
*/
|
|
async interruptQuery(guildId: bigint, query: string) {
|
|
const sources = await this.#loadSource(query as string, guildId);
|
|
this.#rawPlayer.interrupt(await sources[0].data());
|
|
}
|
|
|
|
async pushQuery(guildId: bigint, added_by?: string, ...queries: string[]) {
|
|
const sources = [];
|
|
for (const query of queries) {
|
|
sources.push(...(await this.#loadSource(query as string, guildId, String(added_by))));
|
|
this.push(...sources);
|
|
}
|
|
return sources;
|
|
}
|
|
|
|
async unshiftQuery(guildId: bigint, ...queries: string[]) {
|
|
const sources = [];
|
|
for (const query of queries) {
|
|
sources.push(...(await this.#loadSource(query as string, guildId)));
|
|
this.unshift(...sources);
|
|
}
|
|
return sources;
|
|
}
|
|
}
|