implement looping system

This commit is contained in:
Snowflake107 2021-06-13 18:28:36 +05:45
parent dac08c1d3f
commit fec70a25a1
6 changed files with 66 additions and 5 deletions

View file

@ -1,6 +1,6 @@
import { Client, GuildMember, Message, TextChannel } from "discord.js";
import { Player, Queue, Track } from "../src/index";
import { QueryType } from "../src/types/types";
import { QueryType, QueueRepeatMode } from "../src/types/types";
import { config } from "./config";
// use this in prod.
// import { Player, Queue } from "discord-player";
@ -76,6 +76,32 @@ client.on("message", async (message) => {
}
]
},
{
name: "loop",
description: "Sets loop mode",
options: [
{
name: "mode",
type: "INTEGER",
description: "Loop type",
required: true,
choices: [
{
name: "Off",
value: 0
},
{
name: "Track",
value: 1
},
{
name: "Queue",
value: 2
}
]
}
]
},
{
name: "skip",
description: "Skip to the current song"
@ -130,7 +156,7 @@ client.on("interaction", async (interaction) => {
if (!searchResult.length) return void interaction.followUp({ content: "No results were found!" });
const queue = await player.createQueue(interaction.guild, {
metadata: interaction.channel
metadata: interaction.channel as TextChannel
});
try {
@ -208,6 +234,14 @@ client.on("interaction", async (interaction) => {
const queue = player.getQueue(interaction.guildID);
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
return void interaction.followUp({ content: `🎶 | Current song: **${queue.current.title}**!` });
} else if (interaction.commandName === "loop") {
await interaction.defer();
const queue = player.getQueue(interaction.guildID);
if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | No music is being played!" });
const loopMode = interaction.options.get("mode")!.value as QueueRepeatMode;
const success = queue.setRepeatMode(loopMode);
const mode = loopMode === QueueRepeatMode.TRACK ? "🔂" : loopMode === QueueRepeatMode.QUEUE ? "🔁" : "▶";
return void interaction.followUp({ content: success ? `${mode} | Updated loop mode!` : "❌ | Could not update loop mode!" });
} else {
interaction.reply({
content: "Unknown command!",

View file

@ -37,7 +37,7 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
* @param {PlayerOptions} queueInitOptions Queue init options
* @returns {Queue}
*/
createQueue<T = unknown>(guild: Guild, queueInitOptions?: PlayerOptions & { metadata?: any }) {
createQueue<T = unknown>(guild: Guild, queueInitOptions?: PlayerOptions & { metadata?: T }): Queue<T> {
if (this.queues.has(guild.id)) return this.queues.get(guild.id) as Queue<T>;
const _meta = queueInitOptions.metadata;

View file

@ -2,18 +2,21 @@ import { Guild, StageChannel, VoiceChannel } from "discord.js";
import { Player } from "../Player";
import { StreamDispatcher } from "../VoiceInterface/BasicStreamDispatcher";
import Track from "./Track";
import { PlayerOptions, PlayOptions } from "../types/types";
import { PlayerOptions, PlayOptions, QueueRepeatMode } from "../types/types";
import ytdl from "discord-ytdl-core";
import { AudioResource, StreamType } from "@discordjs/voice";
import { Util } from "../utils/Util";
class Queue<T = unknown> {
public readonly guild: Guild;
public readonly player: Player;
public connection: StreamDispatcher;
public tracks: Track[] = [];
public previousTracks: Track[] = [];
public options: PlayerOptions;
public playing = false;
public metadata?: T = null;
public repeatMode: QueueRepeatMode = 0;
constructor(player: Player, guild: Guild, options: PlayerOptions = {}) {
this.player = player;
@ -99,6 +102,14 @@ class Queue<T = unknown> {
return this.connection.setVolume(amount);
}
setRepeatMode(mode: QueueRepeatMode) {
if (![QueueRepeatMode.OFF, QueueRepeatMode.QUEUE, QueueRepeatMode.TRACK].includes(mode)) throw new Error(`Unknown repeat mode "${mode}"!`);
const prev = this.repeatMode;
if (mode === prev) return false;
this.repeatMode = mode;
return true;
}
get volume() {
if (!this.connection) return 100;
return this.connection.volume;
@ -109,6 +120,8 @@ class Queue<T = unknown> {
if (src && (this.playing || this.tracks.length) && !options.immediate) return this.addTrack(src);
const track = options.filtersUpdate ? this.current : src ?? this.tracks.shift();
if (!track) return;
this.previousTracks = this.previousTracks.filter((x) => x._trackID !== track._trackID);
this.previousTracks.push(track);
let stream;
if (["youtube", "spotify"].includes(track.raw.source)) {
stream = ytdl(track.raw.source === "spotify" ? track.raw.engine : track.url, {
@ -145,10 +158,12 @@ class Queue<T = unknown> {
this.playing = false;
if (options.filtersUpdate) return;
if (!this.tracks.length) {
if (!this.tracks.length && this.repeatMode === QueueRepeatMode.OFF) {
this.destroy();
this.player.emit("queueEnd", this);
} else {
if (this.repeatMode === QueueRepeatMode.TRACK) return void this.play(Util.last(this.previousTracks), { immediate: true });
if (this.repeatMode === QueueRepeatMode.QUEUE) this.tracks.push(Util.last(this.previousTracks));
const nextTrack = this.tracks.shift();
this.play(nextTrack, { immediate: true });
}

View file

@ -15,6 +15,7 @@ class Track {
public requestedBy!: User;
public fromPlaylist!: boolean;
public readonly raw!: RawTrackData;
public readonly _trackID = Date.now();
/**
* Track constructor

View file

@ -156,3 +156,9 @@ export interface SearchOptions {
requestedBy: User;
searchEngine?: QueryType;
}
export enum QueueRepeatMode {
OFF = 0,
TRACK = 1,
QUEUE = 2
}

View file

@ -29,6 +29,11 @@ class Util {
.join(":");
return final.length <= 3 ? `0:${final.padStart(2, "0") || 0}` : final;
}
static last<T = any>(arr: T[]): T {
if (!Array.isArray(arr)) return;
return arr[arr.length - 1];
}
}
export { Util };