all repos — simple-discord-music-bot @ master

A Discord bot making use of discord.js and play-yt.

src/functions/myqueue.ts (view raw)

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