src/functions/myqueue.ts (view raw)
1import { createAudioResource, createAudioPlayer, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnection, AudioPlayer, AudioResource } from '@discordjs/voice';
2import play, { YouTubeVideo } from 'play-dl';
3
4async function resourceFromYTUrl(url: string): Promise<AudioResource<null>> {
5 try {
6 const stream = await play.stream(url);
7 return createAudioResource(stream.stream, { inputType: stream.type })
8 } catch (error) {
9 return null;
10 }
11
12}
13
14export default class MyQueue {
15 #nowPlaying: YouTubeVideo;
16 #queue: Array<YouTubeVideo>;
17 connection: VoiceConnection;
18 player: AudioPlayer;
19 static _instance: MyQueue;
20 get queue() {
21 if (this.#nowPlaying)
22 return [this.#nowPlaying].concat(this.#queue);
23 return null
24 }
25
26 constructor() {
27 if (MyQueue._instance) {
28 return MyQueue._instance
29 }
30 MyQueue._instance = this;
31
32 this.#nowPlaying = null;
33 this.connection = null;
34 this.#queue = Array<YouTubeVideo>();
35 this.player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Stop } });
36 this.player.on(AudioPlayerStatus.Idle, () => {
37 if (this.#queue.length > 0)
38 return this.next();
39 this.connection.disconnect();
40 });
41 }
42
43 clear() {
44 this.#queue = Array<YouTubeVideo>();
45 }
46
47 stop(): boolean {
48 this.clear();
49 this.#nowPlaying = null;
50 if (this.player) {
51 const p = this.player.stop();
52 const c = this.connection.disconnect();
53 return p && c;
54 }
55 return false;
56 }
57
58 async next() {
59 if (this.#queue.length == 0)
60 return this.stop();
61 this.#nowPlaying = this.#queue.shift();
62 const resource = await resourceFromYTUrl(this.#nowPlaying.url);
63 if (!resource) {
64 return await this.next();
65 }
66 this.player.play(resource);
67 this.connection.subscribe(this.player);
68 }
69
70 add(video: YouTubeVideo, position=this.#queue.length) {
71 const l = this.#queue.length;
72 const normalizedPosition = position % (l + 1);
73 this.#queue.splice(normalizedPosition, 0, video);
74 if (l == 0) this.next();
75 }
76
77 async addArray(urls: YouTubeVideo[]) {
78 const l = this.#queue.length;
79 this.#queue.push(...urls);
80 if (l == 0 && this.player.state.status == AudioPlayerStatus.Idle) this.next();
81 return urls;
82 }
83
84 pause() {
85 this.player.pause();
86 }
87
88 resume() {
89 this.player.unpause();
90 this.connection.subscribe(this.player);
91 }
92
93 async outro(url: string) {
94 this.player.pause();
95 const resource = await resourceFromYTUrl(url);
96
97 const p = createAudioPlayer();
98 p.on(AudioPlayerStatus.Idle, () => {
99 if (this.player.state.status == AudioPlayerStatus.Paused) {
100 this.resume();
101 return
102 }
103 this.connection.disconnect();
104 });
105
106 p.play(resource);
107 this.connection.subscribe(p);
108 }
109}
110
111(module).exports = MyQueue;