discord-player
Advanced tools
Comparing version 5.0.0-dev.8e2f50cfb5cf1b077f98cb2c7d6d6a5dfddd2609 to 5.0.0-dev.92a3409.1625911434
@@ -5,6 +5,9 @@ export { AudioFilters } from "./utils/AudioFilters"; | ||
export { Player } from "./Player"; | ||
export { QueryResolver } from "./utils/QueryResolver"; | ||
export { Queue } from "./Structures/Queue"; | ||
export { Track } from "./Structures/Track"; | ||
export { Util } from "./utils/Util"; | ||
export { VoiceUtils } from "./VoiceInterface/VoiceUtils"; | ||
export { VoiceEvents, StreamDispatcher } from "./VoiceInterface/BasicStreamDispatcher"; | ||
export { VoiceEvents, StreamDispatcher } from "./VoiceInterface/StreamDispatcher"; | ||
export { VoiceAdapterCreator } from "./VoiceInterface/AdapterCreator"; | ||
export * from "./types/types"; |
@@ -13,3 +13,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.StreamDispatcher = exports.VoiceUtils = exports.Track = exports.Queue = exports.Player = exports.Playlist = exports.ExtractorModel = exports.AudioFilters = void 0; | ||
exports.VoiceAdapterCreator = exports.StreamDispatcher = exports.VoiceUtils = exports.Util = exports.Track = exports.Queue = exports.QueryResolver = exports.Player = exports.Playlist = exports.ExtractorModel = exports.AudioFilters = void 0; | ||
var AudioFilters_1 = require("./utils/AudioFilters"); | ||
@@ -23,2 +23,4 @@ Object.defineProperty(exports, "AudioFilters", { enumerable: true, get: function () { return AudioFilters_1.AudioFilters; } }); | ||
Object.defineProperty(exports, "Player", { enumerable: true, get: function () { return Player_1.Player; } }); | ||
var QueryResolver_1 = require("./utils/QueryResolver"); | ||
Object.defineProperty(exports, "QueryResolver", { enumerable: true, get: function () { return QueryResolver_1.QueryResolver; } }); | ||
var Queue_1 = require("./Structures/Queue"); | ||
@@ -28,6 +30,10 @@ Object.defineProperty(exports, "Queue", { enumerable: true, get: function () { return Queue_1.Queue; } }); | ||
Object.defineProperty(exports, "Track", { enumerable: true, get: function () { return Track_1.Track; } }); | ||
var Util_1 = require("./utils/Util"); | ||
Object.defineProperty(exports, "Util", { enumerable: true, get: function () { return Util_1.Util; } }); | ||
var VoiceUtils_1 = require("./VoiceInterface/VoiceUtils"); | ||
Object.defineProperty(exports, "VoiceUtils", { enumerable: true, get: function () { return VoiceUtils_1.VoiceUtils; } }); | ||
var BasicStreamDispatcher_1 = require("./VoiceInterface/BasicStreamDispatcher"); | ||
Object.defineProperty(exports, "StreamDispatcher", { enumerable: true, get: function () { return BasicStreamDispatcher_1.StreamDispatcher; } }); | ||
var StreamDispatcher_1 = require("./VoiceInterface/StreamDispatcher"); | ||
Object.defineProperty(exports, "StreamDispatcher", { enumerable: true, get: function () { return StreamDispatcher_1.StreamDispatcher; } }); | ||
var AdapterCreator_1 = require("./VoiceInterface/AdapterCreator"); | ||
Object.defineProperty(exports, "VoiceAdapterCreator", { enumerable: true, get: function () { return AdapterCreator_1.VoiceAdapterCreator; } }); | ||
__exportStar(require("./types/types"), exports); |
@@ -5,3 +5,3 @@ import { Client, Collection, GuildResolvable } from "discord.js"; | ||
import { VoiceUtils } from "./VoiceInterface/VoiceUtils"; | ||
import { PlayerEvents, PlayerOptions, SearchOptions, DiscordPlayerInitOptions } from "./types/types"; | ||
import { PlayerEvents, PlayerOptions, SearchOptions, PlayerInitOptions } from "./types/types"; | ||
import Track from "./Structures/Track"; | ||
@@ -12,3 +12,3 @@ import { Playlist } from "./Structures/Playlist"; | ||
readonly client: Client; | ||
readonly options: DiscordPlayerInitOptions; | ||
readonly options: PlayerInitOptions; | ||
readonly queues: Collection<`${bigint}`, Queue<unknown>>; | ||
@@ -20,4 +20,5 @@ readonly voiceUtils: VoiceUtils; | ||
* @param {Client} client The Discord Client | ||
* @param {PlayerInitOptions} [options={}] The player init options | ||
*/ | ||
constructor(client: Client, options?: DiscordPlayerInitOptions); | ||
constructor(client: Client, options?: PlayerInitOptions); | ||
/** | ||
@@ -53,6 +54,11 @@ * Handles voice state update | ||
/** | ||
* @typedef {object} SearchResult | ||
* @property {Playlist} [playlist] The playlist (if any) | ||
* @property {Track[]} tracks The tracks | ||
*/ | ||
/** | ||
* Search tracks | ||
* @param {string|Track} query The search query | ||
* @param {UserResolvable} requestedBy The person who requested track search | ||
* @returns {Promise<object>} | ||
* @param {SearchOptions} options The search options | ||
* @returns {Promise<SearchResult>} | ||
*/ | ||
@@ -64,2 +70,3 @@ search(query: string | Track, options: SearchOptions): Promise<{ | ||
/** | ||
* Registers extractor | ||
* @param {string} extractorName The extractor name | ||
@@ -82,56 +89,10 @@ * @param {ExtractorModel|any} extractor The extractor object | ||
scanDeps(): string; | ||
/** | ||
* Resolves qeuue | ||
* @param {GuildResolvable|Queue} queueLike Queue like object | ||
* @returns {Queue} | ||
*/ | ||
resolveQueue<T>(queueLike: GuildResolvable | Queue): Queue<T>; | ||
[Symbol.iterator](): Generator<Queue<unknown>, void, undefined>; | ||
} | ||
/** | ||
* Emitted when bot gets disconnected from a voice channel | ||
* @event Player#botDisconnect | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when the voice channel is empty | ||
* @event Player#channelEmpty | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when bot connects to a voice channel | ||
* @event Player#connectionCreate | ||
* @param {Queue} queue The queue | ||
* @param {StreamDispatcher} connection The discord player connection object | ||
*/ | ||
/** | ||
* Debug information | ||
* @event Player#debug | ||
* @param {Queue} queue The queue | ||
* @param {string} message The message | ||
*/ | ||
/** | ||
* Emitted on error | ||
* <warn>This event should handled properly otherwise it may crash your process!</warn> | ||
* @event Player#error | ||
* @param {Queue} queue The queue | ||
* @param {Error} error The error | ||
*/ | ||
/** | ||
* Emitted when queue ends | ||
* @event Player#queueEnd | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when a single track is added | ||
* @event Player#trackAdd | ||
* @param {Queue} queue The queue | ||
* @param {Track} track The track | ||
*/ | ||
/** | ||
* Emitted when multiple tracks are added | ||
* @event Player#tracksAdd | ||
* @param {Queue} queue The queue | ||
* @param {Track[]} tracks The tracks | ||
*/ | ||
/** | ||
* Emitted when a track starts playing | ||
* @event Player#trackStart | ||
* @param {Queue} queue The queue | ||
* @param {Track} track The track | ||
*/ | ||
export { Player }; |
@@ -26,2 +26,3 @@ "use strict"; | ||
const spotify_url_info_1 = __importDefault(require("spotify-url-info")); | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore | ||
@@ -37,2 +38,3 @@ const soundcloud_scraper_1 = require("soundcloud-scraper"); | ||
* @param {Client} client The Discord Client | ||
* @param {PlayerInitOptions} [options={}] The player init options | ||
*/ | ||
@@ -61,3 +63,3 @@ constructor(client, options = {}) { | ||
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.autoRegisterExtractor) { | ||
let nv; | ||
let nv; // eslint-disable-line @typescript-eslint/no-explicit-any | ||
if ((nv = Util_1.Util.require("@discord-player/extractor"))) { | ||
@@ -79,3 +81,26 @@ ["Attachment", "Facebook", "Reverbnation", "Vimeo"].forEach((ext) => void this.use(ext, nv[ext])); | ||
return; | ||
if (oldState.member.id === this.client.user.id && !newState.channelID) { | ||
if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId) { | ||
queue.connection.channel = newState.channel; | ||
} | ||
if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.me.id) { | ||
if (newState.serverMute || !newState.serverMute) { | ||
queue.setPaused(newState.serverMute); | ||
} | ||
else if (newState.suppress || !newState.suppress) { | ||
if (newState.suppress) | ||
newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop); | ||
queue.setPaused(newState.suppress); | ||
} | ||
} | ||
if (oldState.channelId === newState.channelId && oldState.member.id === newState.guild.me.id) { | ||
if (oldState.serverMute !== newState.serverMute) { | ||
queue.setPaused(newState.serverMute); | ||
} | ||
else if (oldState.suppress !== newState.suppress) { | ||
if (newState.suppress) | ||
newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop); | ||
queue.setPaused(newState.suppress); | ||
} | ||
} | ||
if (oldState.member.id === this.client.user.id && !newState.channelId) { | ||
queue.destroy(); | ||
@@ -86,3 +111,3 @@ return void this.emit("botDisconnect", queue); | ||
return; | ||
if (!oldState.channelID || newState.channelID) { | ||
if (!oldState.channelId || newState.channelId) { | ||
const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`); | ||
@@ -115,3 +140,3 @@ const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel); | ||
*/ | ||
createQueue(guild, queueInitOptions) { | ||
createQueue(guild, queueInitOptions = {}) { | ||
var _a; | ||
@@ -155,3 +180,3 @@ guild = this.client.guilds.resolve(guild); | ||
} | ||
catch (_a) { } | ||
catch (_a) { } // eslint-disable-line no-empty | ||
this.queues.delete(guild.id); | ||
@@ -161,6 +186,11 @@ return prev; | ||
/** | ||
* @typedef {object} SearchResult | ||
* @property {Playlist} [playlist] The playlist (if any) | ||
* @property {Track[]} tracks The tracks | ||
*/ | ||
/** | ||
* Search tracks | ||
* @param {string|Track} query The search query | ||
* @param {UserResolvable} requestedBy The person who requested track search | ||
* @returns {Promise<object>} | ||
* @param {SearchOptions} options The search options | ||
* @returns {Promise<SearchResult>} | ||
*/ | ||
@@ -177,3 +207,6 @@ search(query, options) { | ||
options.searchEngine = types_1.QueryType.AUTO; | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for (const [_, extractor] of this.extractors) { | ||
if (options.blockExtractor) | ||
break; | ||
if (!extractor.validate(query)) | ||
@@ -197,3 +230,3 @@ continue; | ||
type: "video" | ||
}).catch(() => { }); | ||
}).catch(Util_1.Util.noop); | ||
if (!videos) | ||
@@ -203,3 +236,3 @@ return { playlist: null, tracks: [] }; | ||
var _a, _b; | ||
m.source = "youtube"; | ||
m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any | ||
return new Track_1.default(this, { | ||
@@ -221,3 +254,4 @@ title: m.title, | ||
case types_1.QueryType.SOUNDCLOUD_SEARCH: { | ||
const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : yield soundcloud.search(query, "track").catch(() => { }); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-function | ||
const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : yield soundcloud.search(query, "track").catch(Util_1.Util.noop); | ||
if (!result || !result.length) | ||
@@ -227,3 +261,3 @@ return { playlist: null, tracks: [] }; | ||
for (const r of result) { | ||
const trackInfo = yield soundcloud.getSongInfo(r.url).catch(() => { }); | ||
const trackInfo = yield soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop); | ||
if (!trackInfo) | ||
@@ -248,3 +282,3 @@ continue; | ||
case types_1.QueryType.SPOTIFY_SONG: { | ||
const spotifyData = yield spotify_url_info_1.default.getData(query).catch(() => { }); | ||
const spotifyData = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop); | ||
if (!spotifyData) | ||
@@ -269,3 +303,3 @@ return { playlist: null, tracks: [] }; | ||
case types_1.QueryType.SPOTIFY_ALBUM: { | ||
const spotifyPlaylist = yield spotify_url_info_1.default.getData(query).catch(() => { }); | ||
const spotifyPlaylist = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop); | ||
if (!spotifyPlaylist) | ||
@@ -294,2 +328,3 @@ return { playlist: null, tracks: [] }; | ||
if (spotifyPlaylist.type !== "playlist") { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
playlist.tracks = spotifyPlaylist.tracks.items.map((m) => { | ||
@@ -313,2 +348,3 @@ var _a, _b, _c, _d, _e, _f, _g, _h; | ||
else { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
playlist.tracks = spotifyPlaylist.tracks.items.map((m) => { | ||
@@ -334,3 +370,3 @@ var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
case types_1.QueryType.SOUNDCLOUD_PLAYLIST: { | ||
const data = yield soundcloud_scraper_1.Client.getPlaylist(query).catch(() => { }); | ||
const data = yield soundcloud_scraper_1.Client.getPlaylist(query).catch(Util_1.Util.noop); | ||
if (!data) | ||
@@ -372,7 +408,6 @@ return { playlist: null, tracks: [] }; | ||
case types_1.QueryType.YOUTUBE_PLAYLIST: { | ||
const ytpl = yield youtube_sr_1.default.getPlaylist(query).catch(() => { }); | ||
const ytpl = yield youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop); | ||
if (!ytpl) | ||
return { playlist: null, tracks: [] }; | ||
// @todo: better way of handling large playlists | ||
yield ytpl.fetch().catch(() => { }); | ||
yield ytpl.fetch().catch(Util_1.Util.noop); | ||
const playlist = new Playlist_1.Playlist(this, { | ||
@@ -417,2 +452,3 @@ title: ytpl.title, | ||
/** | ||
* Registers extractor | ||
* @param {string} extractorName The extractor name | ||
@@ -423,2 +459,3 @@ * @param {ExtractorModel|any} extractor The extractor object | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
use(extractorName, extractor, force = false) { | ||
@@ -460,2 +497,10 @@ if (!extractorName) | ||
} | ||
/** | ||
* Resolves qeuue | ||
* @param {GuildResolvable|Queue} queueLike Queue like object | ||
* @returns {Queue} | ||
*/ | ||
resolveQueue(queueLike) { | ||
return this.getQueue(queueLike instanceof Queue_1.Queue ? queueLike.guild : queueLike); | ||
} | ||
*[Symbol.iterator]() { | ||
@@ -462,0 +507,0 @@ yield* Array.from(this.queues.values()); |
@@ -19,2 +19,3 @@ "use strict"; | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
constructor(extractorName, data) { | ||
@@ -47,3 +48,5 @@ /** | ||
playlist: (_a = data.playlist) !== null && _a !== void 0 ? _a : null, | ||
data: (_c = (_b = data.info) === null || _b === void 0 ? void 0 : _b.map((m) => ({ | ||
data: | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(_c = (_b = data.info) === null || _b === void 0 ? void 0 : _b.map((m) => ({ | ||
title: m.title, | ||
@@ -50,0 +53,0 @@ duration: m.duration, |
/// <reference types="node" /> | ||
import { Collection, Guild, StageChannel, VoiceChannel } from "discord.js"; | ||
import { Collection, Guild, Snowflake, GuildChannelResolvable } from "discord.js"; | ||
import { Player } from "../Player"; | ||
import { StreamDispatcher } from "../VoiceInterface/BasicStreamDispatcher"; | ||
import { StreamDispatcher } from "../VoiceInterface/StreamDispatcher"; | ||
import Track from "./Track"; | ||
import { PlayerOptions, PlayOptions, QueueFilters, QueueRepeatMode } from "../types/types"; | ||
import { PlayerOptions, PlayerProgressbarOptions, PlayOptions, QueueFilters, QueueRepeatMode } from "../types/types"; | ||
declare class Queue<T = unknown> { | ||
#private; | ||
readonly guild: Guild; | ||
@@ -17,5 +18,7 @@ readonly player: Player; | ||
repeatMode: QueueRepeatMode; | ||
readonly id: Snowflake; | ||
private _streamTime; | ||
_cooldownsTimeout: Collection<string, NodeJS.Timeout>; | ||
private _activeFilters; | ||
private _filtersUpdate; | ||
/** | ||
@@ -34,2 +37,7 @@ * Queue constructor | ||
/** | ||
* If this queue is destroyed | ||
* @type {boolean} | ||
*/ | ||
get destroyed(): boolean; | ||
/** | ||
* Returns current track | ||
@@ -41,6 +49,6 @@ * @returns {Track} | ||
* Connects to a voice channel | ||
* @param {StageChannel|VoiceChannel} channel The voice/stage channel | ||
* @param {GuildChannelResolvable} channel The voice/stage channel | ||
* @returns {Promise<Queue>} | ||
*/ | ||
connect(channel: StageChannel | VoiceChannel): Promise<this>; | ||
connect(channel: GuildChannelResolvable): Promise<this>; | ||
/** | ||
@@ -76,3 +84,3 @@ * Destroys this queue | ||
* Sets bitrate | ||
* @param {number|"auto"} bitrate bitrate to set | ||
* @param {number|auto} bitrate bitrate to set | ||
* @returns {void} | ||
@@ -100,2 +108,12 @@ */ | ||
/** | ||
* Mutes the playback | ||
* @returns {void} | ||
*/ | ||
mute(): void; | ||
/** | ||
* Unmutes the playback. If the last volume was set to 0, unmute will produce no effect. | ||
* @returns {void} | ||
*/ | ||
unmute(): void; | ||
/** | ||
* The stream time of this queue | ||
@@ -105,2 +123,3 @@ * @type {number} | ||
get streamTime(): number; | ||
set streamTime(time: number); | ||
/** | ||
@@ -110,3 +129,3 @@ * Returns enabled filters | ||
*/ | ||
getFiltersEnabled(): string[]; | ||
getFiltersEnabled(): (keyof QueueFilters)[]; | ||
/** | ||
@@ -116,3 +135,3 @@ * Returns disabled filters | ||
*/ | ||
getFiltersDisabled(): string[]; | ||
getFiltersDisabled(): (keyof QueueFilters)[]; | ||
/** | ||
@@ -136,2 +155,60 @@ * Sets filters | ||
/** | ||
* Clear this queue | ||
*/ | ||
clear(): void; | ||
/** | ||
* Stops the player | ||
* @returns {void} | ||
*/ | ||
stop(): void; | ||
/** | ||
* Shuffles this queue | ||
* @returns {boolean} | ||
*/ | ||
shuffle(): boolean; | ||
/** | ||
* Removes a track from the queue | ||
* @param {Track|Snowflake|number} track The track to remove | ||
* @returns {Track} | ||
*/ | ||
remove(track: Track | Snowflake | number): Track; | ||
/** | ||
* Jumps to particular track | ||
* @param {Track|number} track The track | ||
* @returns {void} | ||
*/ | ||
jump(track: Track | number): void; | ||
/** | ||
* Inserts the given track to specified index | ||
* @param {Track} track The track to insert | ||
* @param {number} [index=0] The index where this track should be | ||
*/ | ||
insert(track: Track, index?: number): void; | ||
/** | ||
* @typedef {object} PlayerTimestamp | ||
* @property {string} current The current progress | ||
* @property {string} end The total time | ||
* @property {number} progress Progress in % | ||
*/ | ||
/** | ||
* Returns player stream timestamp | ||
* @returns {PlayerTimestamp} | ||
*/ | ||
getPlayerTimestamp(): { | ||
current: string; | ||
end: string; | ||
progress: number; | ||
}; | ||
/** | ||
* Creates progress bar string | ||
* @param {PlayerProgressbarOptions} options The progress bar options | ||
* @returns {string} | ||
*/ | ||
createProgressBar(options?: PlayerProgressbarOptions): string; | ||
/** | ||
* Total duration | ||
* @type {Number} | ||
*/ | ||
get totalTime(): number; | ||
/** | ||
* Play stream in a voice/stage channel | ||
@@ -143,2 +220,9 @@ * @param {Track} [src] The track to play (if empty, uses first track from the queue) | ||
play(src?: Track, options?: PlayOptions): Promise<void>; | ||
/** | ||
* Private method to handle autoplay | ||
* @param {Track} track The source track to find its similar track for autoplay | ||
* @returns {Promise<void>} | ||
* @private | ||
*/ | ||
private _handleAutoplay; | ||
[Symbol.iterator](): Generator<Track, void, undefined>; | ||
@@ -150,2 +234,3 @@ /** | ||
toJSON(): { | ||
id: `${bigint}`; | ||
guild: `${bigint}`; | ||
@@ -152,0 +237,0 @@ voiceChannel: `${bigint}`; |
@@ -11,5 +11,17 @@ "use strict"; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var _Queue_instances, _Queue_lastVolume, _Queue_destroyed, _Queue_watchDestroyed; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -33,2 +45,3 @@ exports.Queue = void 0; | ||
constructor(player, guild, options = {}) { | ||
_Queue_instances.add(this); | ||
this.tracks = []; | ||
@@ -39,5 +52,9 @@ this.previousTracks = []; | ||
this.repeatMode = 0; | ||
this.id = discord_js_1.SnowflakeUtil.generate(); | ||
this._streamTime = 0; | ||
this._cooldownsTimeout = new discord_js_1.Collection(); | ||
this._activeFilters = []; | ||
this._activeFilters = []; // eslint-disable-line @typescript-eslint/no-explicit-any | ||
this._filtersUpdate = false; | ||
_Queue_lastVolume.set(this, 0); | ||
_Queue_destroyed.set(this, false); | ||
/** | ||
@@ -60,2 +77,32 @@ * The player that instantiated this queue | ||
this.options = {}; | ||
/** | ||
* Queue repeat mode | ||
* @type {QueueRepeatMode} | ||
* @name Queue#repeatMode | ||
*/ | ||
/** | ||
* Queue metadata | ||
* @type {any} | ||
* @name Queue#metadata | ||
*/ | ||
/** | ||
* Previous tracks | ||
* @type {Track[]} | ||
* @name Queue#previousTracks | ||
*/ | ||
/** | ||
* Regular tracks | ||
* @type {Track[]} | ||
* @name Queue#tracks | ||
*/ | ||
/** | ||
* The connection | ||
* @type {StreamDispatcher} | ||
* @name Queue#connection | ||
*/ | ||
/** | ||
* The ID of this queue | ||
* @type {Snowflake} | ||
* @name Queue#id | ||
*/ | ||
Object.assign(this.options, { | ||
@@ -67,7 +114,3 @@ leaveOnEnd: true, | ||
autoSelfDeaf: true, | ||
enableLive: false, | ||
ytdlOptions: {}, | ||
useSafeSearch: false, | ||
disableAutoRegister: false, | ||
fetchBeforeQueued: false, | ||
initialVolume: 100 | ||
@@ -82,5 +125,13 @@ }, options); | ||
var _a, _b; | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return (_b = (_a = this.connection.audioResource) === null || _a === void 0 ? void 0 : _a.metadata) !== null && _b !== void 0 ? _b : this.tracks[0]; | ||
} | ||
/** | ||
* If this queue is destroyed | ||
* @type {boolean} | ||
*/ | ||
get destroyed() { | ||
return __classPrivateFieldGet(this, _Queue_destroyed, "f"); | ||
} | ||
/** | ||
* Returns current track | ||
@@ -90,2 +141,3 @@ * @returns {Track} | ||
nowPlaying() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return this.current; | ||
@@ -95,3 +147,3 @@ } | ||
* Connects to a voice channel | ||
* @param {StageChannel|VoiceChannel} channel The voice/stage channel | ||
* @param {GuildChannelResolvable} channel The voice/stage channel | ||
* @returns {Promise<Queue>} | ||
@@ -101,15 +153,52 @@ */ | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!["stage", "voice"].includes(channel === null || channel === void 0 ? void 0 : channel.type)) | ||
throw new TypeError(`Channel type must be voice or stage, got ${channel === null || channel === void 0 ? void 0 : channel.type}!`); | ||
const connection = yield this.player.voiceUtils.connect(channel, { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
const _channel = this.guild.channels.resolve(channel); | ||
if (!["GUILD_STAGE_VOICE", "GUILD_VOICE"].includes(_channel === null || _channel === void 0 ? void 0 : _channel.type)) | ||
throw new TypeError(`Channel type must be GUILD_VOICE or GUILD_STAGE_VOICE, got ${_channel === null || _channel === void 0 ? void 0 : _channel.type}!`); | ||
const connection = yield this.player.voiceUtils.connect(_channel, { | ||
deaf: this.options.autoSelfDeaf | ||
}); | ||
this.connection = connection; | ||
// it's ok to use this here since Queue listens to the events 1 time per play and destroys the listener | ||
this.connection.setMaxListeners(Infinity); | ||
if (channel.type === "stage") | ||
yield channel.guild.me.voice.setRequestToSpeak(true).catch(() => { }); | ||
this.connection.on("error", (err) => this.player.emit("error", this, err)); | ||
if (_channel.type === "GUILD_STAGE_VOICE") { | ||
yield _channel.guild.me.voice.setSuppressed(false).catch(() => __awaiter(this, void 0, void 0, function* () { | ||
return yield _channel.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop); | ||
})); | ||
} | ||
this.connection.on("error", (err) => this.player.emit("connectionError", this, err)); | ||
this.connection.on("debug", (msg) => this.player.emit("debug", this, msg)); | ||
this.player.emit("connectionCreate", this, this.connection); | ||
this.connection.on("start", (resource) => { | ||
var _a; | ||
this.playing = true; | ||
if (!this._filtersUpdate && (resource === null || resource === void 0 ? void 0 : resource.metadata)) | ||
this.player.emit("trackStart", this, (_a = resource === null || resource === void 0 ? void 0 : resource.metadata) !== null && _a !== void 0 ? _a : this.current); | ||
this._filtersUpdate = false; | ||
}); | ||
this.connection.on("finish", (resource) => __awaiter(this, void 0, void 0, function* () { | ||
this.playing = false; | ||
if (this._filtersUpdate) | ||
return; | ||
this._streamTime = 0; | ||
if (resource && resource.metadata) | ||
this.previousTracks.push(resource.metadata); | ||
if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.OFF) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
this.player.emit("queueEnd", this); | ||
} | ||
else { | ||
if (this.repeatMode !== types_1.QueueRepeatMode.AUTOPLAY) { | ||
if (this.repeatMode === types_1.QueueRepeatMode.TRACK) | ||
return void this.play(Util_1.Util.last(this.previousTracks), { immediate: true }); | ||
if (this.repeatMode === types_1.QueueRepeatMode.QUEUE) | ||
this.tracks.push(Util_1.Util.last(this.previousTracks)); | ||
const nextTrack = this.tracks.shift(); | ||
this.play(nextTrack, { immediate: true }); | ||
return; | ||
} | ||
else { | ||
this._handleAutoplay(Util_1.Util.last(this.previousTracks)); | ||
} | ||
} | ||
})); | ||
return this; | ||
@@ -124,6 +213,11 @@ }); | ||
destroy(disconnect = this.options.leaveOnStop) { | ||
this.connection.end(); | ||
var _a; | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (this.connection) | ||
this.connection.end(); | ||
if (disconnect) | ||
this.connection.disconnect(); | ||
(_a = this.connection) === null || _a === void 0 ? void 0 : _a.disconnect(); | ||
this.player.queues.delete(this.guild.id); | ||
this.player.voiceUtils.cache.delete(this.guild.id); | ||
__classPrivateFieldSet(this, _Queue_destroyed, true, "f"); | ||
} | ||
@@ -135,4 +229,6 @@ /** | ||
skip() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection) | ||
return false; | ||
this._filtersUpdate = false; | ||
this.connection.end(); | ||
@@ -147,2 +243,5 @@ return true; | ||
addTrack(track) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!(track instanceof Track_1.default)) | ||
throw new Error("invalid track"); | ||
this.tracks.push(track); | ||
@@ -156,2 +255,5 @@ this.player.emit("trackAdd", this, track); | ||
addTracks(tracks) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!tracks.every((y) => y instanceof Track_1.default)) | ||
throw new Error("invalid track"); | ||
this.tracks.push(...tracks); | ||
@@ -166,2 +268,3 @@ this.player.emit("tracksAdd", this, tracks); | ||
setPaused(paused) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection) | ||
@@ -173,3 +276,3 @@ return false; | ||
* Sets bitrate | ||
* @param {number|"auto"} bitrate bitrate to set | ||
* @param {number|auto} bitrate bitrate to set | ||
* @returns {void} | ||
@@ -179,2 +282,3 @@ */ | ||
var _a, _b, _c, _d; | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!((_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.audioResource) === null || _b === void 0 ? void 0 : _b.encoder)) | ||
@@ -192,4 +296,6 @@ return; | ||
setVolume(amount) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection) | ||
return false; | ||
__classPrivateFieldSet(this, _Queue_lastVolume, amount, "f"); | ||
this.options.initialVolume = amount; | ||
@@ -204,2 +310,3 @@ return this.connection.setVolume(amount); | ||
setRepeatMode(mode) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (![types_1.QueueRepeatMode.OFF, types_1.QueueRepeatMode.QUEUE, types_1.QueueRepeatMode.TRACK, types_1.QueueRepeatMode.AUTOPLAY].includes(mode)) | ||
@@ -217,2 +324,3 @@ throw new Error(`Unknown repeat mode "${mode}"!`); | ||
get volume() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection) | ||
@@ -226,2 +334,18 @@ return 100; | ||
/** | ||
* Mutes the playback | ||
* @returns {void} | ||
*/ | ||
mute() { | ||
const lv = __classPrivateFieldGet(this, _Queue_lastVolume, "f"); | ||
this.volume = 0; | ||
__classPrivateFieldSet(this, _Queue_lastVolume, lv, "f"); | ||
} | ||
/** | ||
* Unmutes the playback. If the last volume was set to 0, unmute will produce no effect. | ||
* @returns {void} | ||
*/ | ||
unmute() { | ||
this.volume = __classPrivateFieldGet(this, _Queue_lastVolume, "f"); | ||
} | ||
/** | ||
* The stream time of this queue | ||
@@ -231,2 +355,3 @@ * @type {number} | ||
get streamTime() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection) | ||
@@ -241,2 +366,6 @@ return 0; | ||
} | ||
set streamTime(time) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
this.seek(time); | ||
} | ||
/** | ||
@@ -247,2 +376,3 @@ * Returns enabled filters | ||
getFiltersEnabled() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return AudioFilters_1.default.names.filter((x) => this._activeFilters.includes(x)); | ||
@@ -255,2 +385,3 @@ } | ||
getFiltersDisabled() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return AudioFilters_1.default.names.filter((x) => !this._activeFilters.includes(x)); | ||
@@ -265,2 +396,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!filters || !Object.keys(filters).length) { | ||
@@ -277,3 +409,3 @@ // reset filters | ||
} | ||
const _filters = []; | ||
const _filters = []; // eslint-disable-line @typescript-eslint/no-explicit-any | ||
for (const filter in filters) { | ||
@@ -303,2 +435,3 @@ if (filters[filter] === true) | ||
return __awaiter(this, void 0, void 0, function* () { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.playing || !this.current) | ||
@@ -324,6 +457,152 @@ return false; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return yield this.play(Util_1.Util.last(this.previousTracks), { immediate: true }); | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
const prev = this.previousTracks[this.previousTracks.length - 2]; // because last item is the current track | ||
if (!prev) | ||
throw new Error("Could not find previous track"); | ||
return yield this.play(prev, { immediate: true }); | ||
}); | ||
} | ||
/** | ||
* Clear this queue | ||
*/ | ||
clear() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
this.tracks = []; | ||
this.previousTracks = []; | ||
} | ||
/** | ||
* Stops the player | ||
* @returns {void} | ||
*/ | ||
stop() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return this.destroy(); | ||
} | ||
/** | ||
* Shuffles this queue | ||
* @returns {boolean} | ||
*/ | ||
shuffle() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.tracks.length || this.tracks.length < 3) | ||
return false; | ||
const currentTrack = this.tracks.shift(); | ||
for (let i = this.tracks.length - 1; i > 0; i--) { | ||
const j = Math.floor(Math.random() * (i + 1)); | ||
[this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]]; | ||
} | ||
this.tracks.unshift(currentTrack); | ||
return true; | ||
} | ||
/** | ||
* Removes a track from the queue | ||
* @param {Track|Snowflake|number} track The track to remove | ||
* @returns {Track} | ||
*/ | ||
remove(track) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
let trackFound = null; | ||
if (typeof track === "number") { | ||
trackFound = this.tracks[track]; | ||
if (trackFound) { | ||
this.tracks = this.tracks.filter((t) => t.id !== trackFound.id); | ||
} | ||
} | ||
else { | ||
trackFound = this.tracks.find((s) => s.id === (track instanceof Track_1.default ? track.id : track)); | ||
if (trackFound) { | ||
this.tracks = this.tracks.filter((s) => s.id !== trackFound.id); | ||
} | ||
} | ||
return trackFound; | ||
} | ||
/** | ||
* Jumps to particular track | ||
* @param {Track|number} track The track | ||
* @returns {void} | ||
*/ | ||
jump(track) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
const foundTrack = this.remove(track); | ||
if (!foundTrack) | ||
throw new Error("Track not found"); | ||
this.tracks.splice(1, 0, foundTrack); | ||
return void this.skip(); | ||
} | ||
/** | ||
* Inserts the given track to specified index | ||
* @param {Track} track The track to insert | ||
* @param {number} [index=0] The index where this track should be | ||
*/ | ||
insert(track, index = 0) { | ||
if (!track || !(track instanceof Track_1.default)) | ||
throw new TypeError("track must be the instance of Track"); | ||
if (typeof index !== "number" || index < 0 || !Number.isFinite(index)) | ||
throw new Error(`Invalid index "${index}"`); | ||
this.tracks.splice(index, 0, track); | ||
this.player.emit("trackAdd", this, track); | ||
} | ||
/** | ||
* @typedef {object} PlayerTimestamp | ||
* @property {string} current The current progress | ||
* @property {string} end The total time | ||
* @property {number} progress Progress in % | ||
*/ | ||
/** | ||
* Returns player stream timestamp | ||
* @returns {PlayerTimestamp} | ||
*/ | ||
getPlayerTimestamp() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
const currentStreamTime = this.streamTime; | ||
const totalTime = this.current.durationMS; | ||
const currentTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(currentStreamTime)); | ||
const endTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(totalTime)); | ||
return { | ||
current: currentTimecode, | ||
end: endTimecode, | ||
progress: Math.round((currentStreamTime / totalTime) * 100) | ||
}; | ||
} | ||
/** | ||
* Creates progress bar string | ||
* @param {PlayerProgressbarOptions} options The progress bar options | ||
* @returns {string} | ||
*/ | ||
createProgressBar(options = { timecodes: true }) { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
const length = typeof options.length === "number" ? (options.length <= 0 || options.length === Infinity ? 15 : options.length) : 15; | ||
const index = Math.round((this.streamTime / this.current.durationMS) * length); | ||
const indicator = typeof options.indicator === "string" && options.indicator.length > 0 ? options.indicator : "🔘"; | ||
const line = typeof options.line === "string" && options.line.length > 0 ? options.line : "▬"; | ||
if (index >= 1 && index <= length) { | ||
const bar = line.repeat(length - 1).split(""); | ||
bar.splice(index, 0, indicator); | ||
if (options.timecodes) { | ||
const timestamp = this.getPlayerTimestamp(); | ||
return `${timestamp.current} ┃ ${bar.join("")} ┃ ${timestamp.end}`; | ||
} | ||
else { | ||
return `${bar.join("")}`; | ||
} | ||
} | ||
else { | ||
if (options.timecodes) { | ||
const timestamp = this.getPlayerTimestamp(); | ||
return `${timestamp.current} ┃ ${indicator}${line.repeat(length - 1)} ┃ ${timestamp.end}`; | ||
} | ||
else { | ||
return `${indicator}${line.repeat(length - 1)}`; | ||
} | ||
} | ||
} | ||
/** | ||
* Total duration | ||
* @type {Number} | ||
*/ | ||
get totalTime() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return this.tracks.length > 0 ? this.tracks.map((t) => t.durationMS).reduce((p, c) => p + c) : 0; | ||
} | ||
/** | ||
* Play stream in a voice/stage channel | ||
@@ -337,2 +616,4 @@ * @param {Track} [src] The track to play (if empty, uses first track from the queue) | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!this.destroyed) | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.connection || !this.connection.voiceConnection) | ||
@@ -345,7 +626,8 @@ throw new Error("Voice connection is not available, use <Queue>.connect()!"); | ||
return; | ||
this.player.emit("debug", this, "Received play request"); | ||
if (!options.filtersUpdate) { | ||
this.previousTracks = this.previousTracks.filter((x) => x._trackID !== track._trackID); | ||
this.previousTracks = this.previousTracks.filter((x) => x.id !== track.id); | ||
this.previousTracks.push(track); | ||
} | ||
let stream, pauseEvent = false; | ||
let stream; | ||
if (["youtube", "spotify"].includes(track.raw.source)) { | ||
@@ -363,3 +645,2 @@ if (track.raw.source === "spotify" && !track.raw.engine) { | ||
opusEncoded: false, fmt: "s16le", encoderArgs: ((_a = options.encoderArgs) !== null && _a !== void 0 ? _a : this._activeFilters.length) ? ["-af", AudioFilters_1.default.create(this._activeFilters)] : [], seek: options.seek ? options.seek / 1000 : 0 })).on("error", (err) => { | ||
pauseEvent = true; | ||
return err.message.toLowerCase().includes("premature close") ? null : this.player.emit("error", this, err); | ||
@@ -377,3 +658,2 @@ }); | ||
.on("error", (err) => { | ||
pauseEvent = true; | ||
return err.message.toLowerCase().includes("premature close") ? null : this.player.emit("error", this, err); | ||
@@ -388,65 +668,47 @@ }); | ||
this._streamTime = options.seek; | ||
const dispatcher = yield this.connection.playStream(resource); | ||
dispatcher.setVolume(this.options.initialVolume); | ||
// need to use these events here | ||
dispatcher.once("start", () => { | ||
this.playing = true; | ||
if (options.filtersUpdate || pauseEvent) | ||
return; | ||
this.player.emit("trackStart", this, this.current); | ||
this._filtersUpdate = options.filtersUpdate; | ||
this.connection.playStream(resource).then(() => { | ||
this.setVolume(this.options.initialVolume); | ||
}); | ||
dispatcher.once("finish", () => __awaiter(this, void 0, void 0, function* () { | ||
var _c; | ||
this.playing = false; | ||
if (options.filtersUpdate || pauseEvent) | ||
return; | ||
this._streamTime = 0; | ||
if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.OFF) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
this.player.emit("queueEnd", this); | ||
} | ||
else { | ||
if (this.repeatMode !== types_1.QueueRepeatMode.AUTOPLAY) { | ||
if (this.repeatMode === types_1.QueueRepeatMode.TRACK) | ||
return void this.play(Util_1.Util.last(this.previousTracks), { immediate: true }); | ||
if (this.repeatMode === types_1.QueueRepeatMode.QUEUE) | ||
this.tracks.push(Util_1.Util.last(this.previousTracks)); | ||
const nextTrack = this.tracks.shift(); | ||
this.play(nextTrack, { immediate: true }); | ||
return; | ||
} | ||
else { | ||
if (![track.source, (_c = track.raw) === null || _c === void 0 ? void 0 : _c.source].includes("youtube")) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
return void this.player.emit("queueEnd", this); | ||
} | ||
const info = yield discord_ytdl_core_1.default | ||
.getInfo(track.url) | ||
.then((x) => x.related_videos[0]) | ||
.catch(() => { }); | ||
if (!info) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
return void this.player.emit("queueEnd", this); | ||
} | ||
const nextTrack = new Track_1.default(this.player, { | ||
title: info.title, | ||
url: `https://www.youtube.com/watch?v=${info.id}`, | ||
duration: info.length_seconds ? Util_1.Util.buildTimeCode(Util_1.Util.parseMS(info.length_seconds * 1000)) : "0:00", | ||
description: "", | ||
thumbnail: Util_1.Util.last(info.thumbnails).url, | ||
views: parseInt(info.view_count.replace(/[^0-9]/g, "")), | ||
author: typeof info.author === "string" ? info.author : info.author.name, | ||
requestedBy: track.requestedBy, | ||
source: "youtube" | ||
}); | ||
this.play(nextTrack, { immediate: true }); | ||
} | ||
} | ||
})); | ||
}); | ||
} | ||
*[Symbol.iterator]() { | ||
/** | ||
* Private method to handle autoplay | ||
* @param {Track} track The source track to find its similar track for autoplay | ||
* @returns {Promise<void>} | ||
* @private | ||
*/ | ||
_handleAutoplay(track) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!track || ![track.source, (_a = track.raw) === null || _a === void 0 ? void 0 : _a.source].includes("youtube")) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
return void this.player.emit("queueEnd", this); | ||
} | ||
const info = yield youtube_sr_1.default.getVideo(track.url) | ||
.then((x) => x.videos[0]) | ||
.catch(Util_1.Util.noop); | ||
if (!info) { | ||
if (this.options.leaveOnEnd) | ||
this.destroy(); | ||
return void this.player.emit("queueEnd", this); | ||
} | ||
const nextTrack = new Track_1.default(this.player, { | ||
title: info.title, | ||
url: `https://www.youtube.com/watch?v=${info.id}`, | ||
duration: info.durationFormatted ? Util_1.Util.buildTimeCode(Util_1.Util.parseMS(info.duration * 1000)) : "0:00", | ||
description: "", | ||
thumbnail: typeof info.thumbnail === "string" ? info.thumbnail : info.thumbnail.url, | ||
views: info.views, | ||
author: info.channel.name, | ||
requestedBy: track.requestedBy, | ||
source: "youtube" | ||
}); | ||
this.play(nextTrack, { immediate: true }); | ||
}); | ||
} | ||
*[(_Queue_lastVolume = new WeakMap(), _Queue_destroyed = new WeakMap(), _Queue_instances = new WeakSet(), Symbol.iterator)]() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
yield* this.tracks; | ||
@@ -460,3 +722,5 @@ } | ||
var _a, _b; | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
return { | ||
id: this.id, | ||
guild: this.guild.id, | ||
@@ -473,2 +737,3 @@ voiceChannel: (_b = (_a = this.connection) === null || _a === void 0 ? void 0 : _a.channel) === null || _b === void 0 ? void 0 : _b.id, | ||
toString() { | ||
__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this); | ||
if (!this.tracks.length) | ||
@@ -480,1 +745,5 @@ return "No songs available to display!"; | ||
exports.Queue = Queue; | ||
_Queue_watchDestroyed = function _Queue_watchDestroyed() { | ||
if (__classPrivateFieldGet(this, _Queue_destroyed, "f")) | ||
throw new Error("Cannot use destroyed queue"); | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { User } from "discord.js"; | ||
import { User, Snowflake } from "discord.js"; | ||
import { Player } from "../Player"; | ||
@@ -18,3 +18,3 @@ import { RawTrackData, TrackJSON } from "../types/types"; | ||
readonly raw: RawTrackData; | ||
readonly _trackID: number; | ||
readonly id: Snowflake; | ||
/** | ||
@@ -21,0 +21,0 @@ * Track constructor |
@@ -13,3 +13,3 @@ "use strict"; | ||
this.raw = {}; | ||
this._trackID = Date.now(); | ||
this.id = discord_js_1.SnowflakeUtil.generate(); | ||
/** | ||
@@ -74,4 +74,4 @@ * The player that instantiated this Track | ||
* The track id | ||
* @name Track#_trackID | ||
* @type {number} | ||
* @name Track#id | ||
* @type {Snowflake} | ||
* @readonly | ||
@@ -140,2 +140,3 @@ */ | ||
return { | ||
id: this.id, | ||
title: this.title, | ||
@@ -142,0 +143,0 @@ description: this.description, |
@@ -7,7 +7,12 @@ /// <reference types="node" /> | ||
import { Playlist } from "../Structures/Playlist"; | ||
import { StreamDispatcher } from "../VoiceInterface/BasicStreamDispatcher"; | ||
import { StreamDispatcher } from "../VoiceInterface/StreamDispatcher"; | ||
import { downloadOptions } from "ytdl-core"; | ||
export declare type FiltersName = keyof QueueFilters; | ||
export declare type QueueFilters = { | ||
/** | ||
* @typedef {AudioFilters} QueueFilters | ||
*/ | ||
export interface QueueFilters { | ||
bassboost_low?: boolean; | ||
bassboost?: boolean; | ||
bassboost_high?: boolean; | ||
"8D"?: boolean; | ||
@@ -43,4 +48,28 @@ vaporwave?: boolean; | ||
earrape?: boolean; | ||
}; | ||
} | ||
/** | ||
* The track source: | ||
* - soundcloud | ||
* - youtube | ||
* - spotify | ||
* - arbitrary | ||
* @typedef {string} TrackSource | ||
*/ | ||
export declare type TrackSource = "soundcloud" | "youtube" | "spotify" | "arbitrary"; | ||
/** | ||
* @typedef {object} RawTrackData | ||
* @property {string} title The title | ||
* @property {string} description The description | ||
* @property {string} author The author | ||
* @property {string} url The url | ||
* @property {string} thumbnail The thumbnail | ||
* @property {string} duration The duration | ||
* @property {number} views The views | ||
* @property {User} requestedBy The user who requested this track | ||
* @property {Playlist} [playlist] The playlist | ||
* @property {TrackSource} [source="arbitrary"] The source | ||
* @property {any} [engine] The engine | ||
* @property {boolean} [live] If this track is live | ||
* @property {any} [raw] The raw data | ||
*/ | ||
export interface RawTrackData { | ||
@@ -61,2 +90,9 @@ title: string; | ||
} | ||
/** | ||
* @typedef {object} TimeData | ||
* @property {number} days Time in days | ||
* @property {number} hours Time in hours | ||
* @property {number} minutes Time in minutes | ||
* @property {number} seconds Time in seconds | ||
*/ | ||
export interface TimeData { | ||
@@ -68,5 +104,12 @@ days: number; | ||
} | ||
/** | ||
* @typedef {object} PlayerProgressbarOptions | ||
* @property {boolean} [timecodes] If it should render time codes | ||
* @property {boolean} [queue] If it should create progress bar for the whole queue | ||
* @property {number} [length] The bar length | ||
* @property {string} [line] The bar track | ||
* @property {string} [indicator] The indicator | ||
*/ | ||
export interface PlayerProgressbarOptions { | ||
timecodes?: boolean; | ||
queue?: boolean; | ||
length?: number; | ||
@@ -76,2 +119,12 @@ line?: string; | ||
} | ||
/** | ||
* @typedef {object} PlayerOptions | ||
* @property {boolean} [leaveOnEnd=true] If it should leave on end | ||
* @property {boolean} [leaveOnStop=true] If it should leave on stop | ||
* @property {boolean} [leaveOnEmpty=true] If it should leave on empty | ||
* @property {number} [leaveOnEmptyCooldown=1000] The cooldown in ms | ||
* @property {boolean} [autoSelfDeaf=true] If it should set the bot in deaf mode | ||
* @property {YTDLDownloadOptions} [ytdlOptions={}] The youtube download options | ||
* @property {number} [initialVolume=100] The initial player volume | ||
*/ | ||
export interface PlayerOptions { | ||
@@ -83,9 +136,34 @@ leaveOnEnd?: boolean; | ||
autoSelfDeaf?: boolean; | ||
enableLive?: boolean; | ||
ytdlOptions?: downloadOptions; | ||
useSafeSearch?: boolean; | ||
disableAutoRegister?: boolean; | ||
fetchBeforeQueued?: boolean; | ||
initialVolume?: number; | ||
} | ||
/** | ||
* @typedef {object} ExtractorModelData | ||
* @property {object} [playlist] The playlist info (if any) | ||
* @property {string} [playlist.title] The playlist title | ||
* @property {string} [playlist.description] The playlist description | ||
* @property {string} [playlist.thumbnail] The playlist thumbnail | ||
* @property {album|playlist} [playlist.type] The playlist type: `album` | `playlist` | ||
* @property {TrackSource} [playlist.source] The playlist source | ||
* @property {object} [playlist.author] The playlist author | ||
* @property {string} [playlist.author.name] The author name | ||
* @property {string} [playlist.author.url] The author url | ||
* @property {string} [playlist.id] The playlist id | ||
* @property {string} [playlist.url] The playlist url | ||
* @property {any} [playlist.rawPlaylist] The raw data | ||
* @property {ExtractorData[]} data The data | ||
*/ | ||
/** | ||
* @typedef {object} ExtractorData | ||
* @property {string} title The title | ||
* @property {number} duration The duration | ||
* @property {string} thumbnail The thumbnail | ||
* @property {string|Readable|Duplex} engine The stream engine | ||
* @property {number} views The views count | ||
* @property {string} author The author | ||
* @property {string} description The description | ||
* @property {string} url The url | ||
* @property {string} [version] The extractor version | ||
* @property {TrackSource} [source="arbitrary"] The source | ||
*/ | ||
export interface ExtractorModelData { | ||
@@ -116,6 +194,25 @@ playlist?: { | ||
version?: string; | ||
important?: boolean; | ||
source?: TrackSource; | ||
}[]; | ||
} | ||
/** | ||
* The search query type | ||
* This can be one of: | ||
* - AUTO | ||
* - YOUTUBE | ||
* - YOUTUBE_PLAYLIST | ||
* - SOUNDCLOUD_TRACK | ||
* - SOUNDCLOUD_PLAYLIST | ||
* - SOUNDCLOUD | ||
* - SPOTIFY_SONG | ||
* - SPOTIFY_ALBUM | ||
* - SPOTIFY_PLAYLIST | ||
* - VIMEO | ||
* - ARBITRARY | ||
* - REVERBNATION | ||
* - YOUTUBE_SEARCH | ||
* - SOUNDCLOUD_SEARCH | ||
* @typedef {string} QueryType | ||
*/ | ||
export declare enum QueryType { | ||
@@ -138,2 +235,60 @@ AUTO = "auto", | ||
} | ||
/** | ||
* Emitted when bot gets disconnected from a voice channel | ||
* @event Player#botDisconnect | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when the voice channel is empty | ||
* @event Player#channelEmpty | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when bot connects to a voice channel | ||
* @event Player#connectionCreate | ||
* @param {Queue} queue The queue | ||
* @param {StreamDispatcher} connection The discord player connection object | ||
*/ | ||
/** | ||
* Debug information | ||
* @event Player#debug | ||
* @param {Queue} queue The queue | ||
* @param {string} message The message | ||
*/ | ||
/** | ||
* Emitted on error | ||
* <warn>This event should handled properly otherwise it may crash your process!</warn> | ||
* @event Player#error | ||
* @param {Queue} queue The queue | ||
* @param {Error} error The error | ||
*/ | ||
/** | ||
* Emitted on connection error. Sometimes stream errors are emitted here as well. | ||
* @event Player#connectionError | ||
* @param {Queue} queue The queue | ||
* @param {Error} error The error | ||
*/ | ||
/** | ||
* Emitted when queue ends | ||
* @event Player#queueEnd | ||
* @param {Queue} queue The queue | ||
*/ | ||
/** | ||
* Emitted when a single track is added | ||
* @event Player#trackAdd | ||
* @param {Queue} queue The queue | ||
* @param {Track} track The track | ||
*/ | ||
/** | ||
* Emitted when multiple tracks are added | ||
* @event Player#tracksAdd | ||
* @param {Queue} queue The queue | ||
* @param {Track[]} tracks The tracks | ||
*/ | ||
/** | ||
* Emitted when a track starts playing | ||
* @event Player#trackStart | ||
* @param {Queue} queue The queue | ||
* @param {Track} track The track | ||
*/ | ||
export interface PlayerEvents { | ||
@@ -145,2 +300,3 @@ botDisconnect: (queue: Queue) => any; | ||
error: (queue: Queue, error: Error) => any; | ||
connectionError: (queue: Queue, error: Error) => any; | ||
queueEnd: (queue: Queue) => any; | ||
@@ -151,16 +307,34 @@ trackAdd: (queue: Queue, track: Track) => any; | ||
} | ||
/** | ||
* @typedef {object} PlayOptions | ||
* @property {boolean} [filtersUpdate=false] If this play was triggered for filters update | ||
* @property {string[]} [encoderArgs=[]] FFmpeg args passed to encoder | ||
* @property {number} [seek] Time to seek to before playing | ||
* @property {boolean} [immediate=false] If it should start playing the provided track immediately | ||
*/ | ||
export interface PlayOptions { | ||
/** If this play is triggered for filters update */ | ||
filtersUpdate?: boolean; | ||
/** ffmpeg args passed to encoder */ | ||
encoderArgs?: string[]; | ||
/** Time to seek to before playing */ | ||
seek?: number; | ||
/** If it should start playing provided track immediately */ | ||
immediate?: boolean; | ||
} | ||
/** | ||
* @typedef {object} SearchOptions | ||
* @property {UserResolvable} requestedBy The user who requested this search | ||
* @property {QueryType} [searchEngine=QueryType.AUTO] The query search engine | ||
* @property {boolean} [blockExtractor=false] If it should block custom extractors | ||
*/ | ||
export interface SearchOptions { | ||
requestedBy: UserResolvable; | ||
searchEngine?: QueryType; | ||
blockExtractor?: boolean; | ||
} | ||
/** | ||
* The queue repeat mode. This can be one of: | ||
* - OFF | ||
* - TRACK | ||
* - QUEUE | ||
* - AUTOPLAY | ||
* @typedef {number} QueueRepeatMode | ||
*/ | ||
export declare enum QueueRepeatMode { | ||
@@ -172,2 +346,17 @@ OFF = 0, | ||
} | ||
/** | ||
* @typedef {object} PlaylistInitData | ||
* @property {Track[]} tracks The tracks of this playlist | ||
* @property {string} title The playlist title | ||
* @property {string} description The description | ||
* @property {string} thumbnail The thumbnail | ||
* @property {album|playlist} type The playlist type: `album` | `playlist` | ||
* @property {TrackSource} source The playlist source | ||
* @property {object} author The playlist author | ||
* @property {string} [author.name] The author name | ||
* @property {string} [author.url] The author url | ||
* @property {string} id The playlist id | ||
* @property {string} url The playlist url | ||
* @property {any} [rawPlaylist] The raw playlist data | ||
*/ | ||
export interface PlaylistInitData { | ||
@@ -188,3 +377,17 @@ tracks: Track[]; | ||
} | ||
/** | ||
* @typedef {object} TrackJSON | ||
* @property {string} title The track title | ||
* @property {string} description The track description | ||
* @property {string} author The author | ||
* @property {string} url The url | ||
* @property {string} thumbnail The thumbnail | ||
* @property {string} duration The duration | ||
* @property {number} durationMS The duration in ms | ||
* @property {number} views The views count | ||
* @property {Snowflake} requestedBy The id of the user who requested this track | ||
* @property {PlaylistJSON} [playlist] The playlist info (if any) | ||
*/ | ||
export interface TrackJSON { | ||
id: Snowflake; | ||
title: string; | ||
@@ -201,2 +404,16 @@ description: string; | ||
} | ||
/** | ||
* @typedef {object} PlaylistJSON | ||
* @property {string} id The playlist id | ||
* @property {string} url The playlist url | ||
* @property {string} title The playlist title | ||
* @property {string} description The playlist description | ||
* @property {string} thumbnail The thumbnail | ||
* @property {album|playlist} type The playlist type: `album` | `playlist` | ||
* @property {TrackSource} source The track source | ||
* @property {object} author The playlist author | ||
* @property {string} [author.name] The author name | ||
* @property {string} [author.url] The author url | ||
* @property {TrackJSON[]} tracks The tracks data (if any) | ||
*/ | ||
export interface PlaylistJSON { | ||
@@ -216,5 +433,10 @@ id: string; | ||
} | ||
export interface DiscordPlayerInitOptions { | ||
/** | ||
* @typedef {object} PlayerInitOptions | ||
* @property {boolean} [autoRegisterExtractor=true] If it should automatically register `@discord-player/extractor` | ||
* @property {YTDLDownloadOptions} [ytdlOptions={}] The options passed to `ytdl-core` | ||
*/ | ||
export interface PlayerInitOptions { | ||
autoRegisterExtractor?: boolean; | ||
ytdlOptions?: downloadOptions; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.QueueRepeatMode = exports.QueryType = void 0; | ||
/** | ||
* The search query type | ||
* This can be one of: | ||
* - AUTO | ||
* - YOUTUBE | ||
* - YOUTUBE_PLAYLIST | ||
* - SOUNDCLOUD_TRACK | ||
* - SOUNDCLOUD_PLAYLIST | ||
* - SOUNDCLOUD | ||
* - SPOTIFY_SONG | ||
* - SPOTIFY_ALBUM | ||
* - SPOTIFY_PLAYLIST | ||
* - VIMEO | ||
* - ARBITRARY | ||
* - REVERBNATION | ||
* - YOUTUBE_SEARCH | ||
* - SOUNDCLOUD_SEARCH | ||
* @typedef {string} QueryType | ||
*/ | ||
var QueryType; | ||
@@ -22,2 +42,10 @@ (function (QueryType) { | ||
})(QueryType = exports.QueryType || (exports.QueryType = {})); | ||
/** | ||
* The queue repeat mode. This can be one of: | ||
* - OFF | ||
* - TRACK | ||
* - QUEUE | ||
* - AUTOPLAY | ||
* @typedef {number} QueueRepeatMode | ||
*/ | ||
var QueueRepeatMode; | ||
@@ -24,0 +52,0 @@ (function (QueueRepeatMode) { |
@@ -5,3 +5,5 @@ import { FiltersName } from "../types/types"; | ||
* @typedef {object} AudioFilters | ||
* @property {string} bassboost The bassboost filter | ||
* @property {string} bassboost_low The bassboost filter (+15dB) | ||
* @property {string} bassboost The bassboost filter (+20dB) | ||
* @property {string} bassboost_high The bassboost filter (+30dB) | ||
* @property {string} 8D The 8D filter | ||
@@ -39,3 +41,5 @@ * @property {string} vaporwave The vaporwave filter | ||
declare const FilterList: { | ||
bassboost_low: string; | ||
bassboost: string; | ||
bassboost_high: string; | ||
"8D": string; | ||
@@ -75,3 +79,3 @@ vaporwave: string; | ||
}>; | ||
readonly names: string[]; | ||
readonly names: (keyof import("../types/types").QueueFilters)[]; | ||
readonly length: number; | ||
@@ -78,0 +82,0 @@ toString(): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.AudioFilters = void 0; | ||
const bass = (g) => `bass=g=${g}:f=110:w=0.3`; | ||
/** | ||
* The available audio filters | ||
* @typedef {object} AudioFilters | ||
* @property {string} bassboost The bassboost filter | ||
* @property {string} bassboost_low The bassboost filter (+15dB) | ||
* @property {string} bassboost The bassboost filter (+20dB) | ||
* @property {string} bassboost_high The bassboost filter (+30dB) | ||
* @property {string} 8D The 8D filter | ||
@@ -40,3 +43,5 @@ * @property {string} vaporwave The vaporwave filter | ||
const FilterList = { | ||
bassboost: "bass=g=20:f=110:w=0.3", | ||
bassboost_low: bass(15), | ||
bassboost: bass(20), | ||
bassboost_high: bass(30), | ||
"8D": "apulsator=hz=0.09", | ||
@@ -85,3 +90,3 @@ vaporwave: "aresample=48000,asetrate=48000*0.8", | ||
toString() { | ||
return this.names.map((m) => this[m]).join(","); | ||
return this.names.map((m) => this[m]).join(","); // eslint-disable-line @typescript-eslint/no-explicit-any | ||
}, | ||
@@ -88,0 +93,0 @@ create(filter) { |
import { QueryType } from "../types/types"; | ||
declare class QueryResolver { | ||
declare class QueryResolver extends null { | ||
/** | ||
* Query resolver | ||
*/ | ||
constructor(); | ||
private constructor(); | ||
/** | ||
@@ -8,0 +8,0 @@ * Resolves the given search query |
@@ -7,2 +7,3 @@ "use strict"; | ||
const types_1 = require("../types/types"); | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore | ||
@@ -19,9 +20,7 @@ const soundcloud_scraper_1 = require("soundcloud-scraper"); | ||
// scary things above *sigh* | ||
class QueryResolver { | ||
class QueryResolver extends null { | ||
/** | ||
* Query resolver | ||
*/ | ||
constructor() { | ||
throw new Error("Cannot instantiate static class!"); | ||
} | ||
constructor() { } // eslint-disable-line @typescript-eslint/no-empty-function | ||
/** | ||
@@ -28,0 +27,0 @@ * Resolves the given search query |
import { StageChannel, VoiceChannel } from "discord.js"; | ||
import { TimeData } from "../types/types"; | ||
declare class Util { | ||
declare class Util extends null { | ||
/** | ||
* Utils | ||
*/ | ||
constructor(); | ||
private constructor(); | ||
/** | ||
@@ -13,3 +13,3 @@ * Creates duration string | ||
*/ | ||
static durationString(durObj: object): string; | ||
static durationString(durObj: Record<string, number>): string; | ||
/** | ||
@@ -51,3 +51,4 @@ * Parses milliseconds to consumable time object | ||
static wait(time: number): Promise<unknown>; | ||
static get noop(): () => void; | ||
} | ||
export { Util }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Util = void 0; | ||
class Util { | ||
class Util extends null { | ||
/** | ||
* Utils | ||
*/ | ||
constructor() { | ||
throw new Error("Cannot instantiate static class"); | ||
} | ||
constructor() { } // eslint-disable-line @typescript-eslint/no-empty-function | ||
/** | ||
@@ -55,2 +53,3 @@ * Creates duration string | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
static last(arr) { | ||
@@ -88,5 +87,8 @@ if (!Array.isArray(arr)) | ||
static wait(time) { | ||
return new Promise((r) => setTimeout(r, time).unref()); | ||
return new Promise((r) => setTimeout(r, time)); | ||
} | ||
static get noop() { | ||
return () => { }; // eslint-disable-line @typescript-eslint/no-empty-function | ||
} | ||
} | ||
exports.Util = Util; |
import { VoiceChannel, StageChannel, Collection, Snowflake } from "discord.js"; | ||
import { VoiceConnection } from "@discordjs/voice"; | ||
import { StreamDispatcher } from "./BasicStreamDispatcher"; | ||
import { DiscordGatewayAdapterCreator, VoiceConnection } from "@discordjs/voice"; | ||
import { StreamDispatcher } from "./StreamDispatcher"; | ||
declare class VoiceUtils { | ||
@@ -8,2 +8,3 @@ cache: Collection<Snowflake, StreamDispatcher>; | ||
* The voice utils | ||
* @private | ||
*/ | ||
@@ -30,2 +31,3 @@ constructor(); | ||
maxTime?: number; | ||
adapter?: DiscordGatewayAdapterCreator; | ||
}): Promise<VoiceConnection>; | ||
@@ -32,0 +34,0 @@ /** |
@@ -15,6 +15,8 @@ "use strict"; | ||
const voice_1 = require("@discordjs/voice"); | ||
const BasicStreamDispatcher_1 = require("./BasicStreamDispatcher"); | ||
const StreamDispatcher_1 = require("./StreamDispatcher"); | ||
const AdapterCreator_1 = require("./AdapterCreator"); | ||
class VoiceUtils { | ||
/** | ||
* The voice utils | ||
* @private | ||
*/ | ||
@@ -37,3 +39,3 @@ constructor() { | ||
const conn = yield this.join(channel, options); | ||
const sub = new BasicStreamDispatcher_1.StreamDispatcher(conn, channel); | ||
const sub = new StreamDispatcher_1.StreamDispatcher(conn, channel); | ||
this.cache.set(channel.guild.id, sub); | ||
@@ -50,3 +52,3 @@ return sub; | ||
join(channel, options) { | ||
var _a; | ||
var _a, _b, _c; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -56,7 +58,7 @@ let conn = voice_1.joinVoiceChannel({ | ||
channelId: channel.id, | ||
adapterCreator: channel.guild.voiceAdapterCreator, | ||
adapterCreator: (_b = (_a = options.adapter) !== null && _a !== void 0 ? _a : channel.guild.voiceAdapterCreator) !== null && _b !== void 0 ? _b : AdapterCreator_1.VoiceAdapterCreator(channel), | ||
selfDeaf: Boolean(options.deaf) | ||
}); | ||
try { | ||
conn = yield voice_1.entersState(conn, voice_1.VoiceConnectionStatus.Ready, (_a = options === null || options === void 0 ? void 0 : options.maxTime) !== null && _a !== void 0 ? _a : 20000); | ||
conn = yield voice_1.entersState(conn, voice_1.VoiceConnectionStatus.Ready, (_c = options === null || options === void 0 ? void 0 : options.maxTime) !== null && _c !== void 0 ? _c : 20000); | ||
return conn; | ||
@@ -76,3 +78,3 @@ } | ||
disconnect(connection) { | ||
if (connection instanceof BasicStreamDispatcher_1.StreamDispatcher) | ||
if (connection instanceof StreamDispatcher_1.StreamDispatcher) | ||
return connection.voiceConnection.destroy(); | ||
@@ -79,0 +81,0 @@ return connection.destroy(); |
{ | ||
"name": "discord-player", | ||
"version": "5.0.0-dev.8e2f50cfb5cf1b077f98cb2c7d6d6a5dfddd2609", | ||
"version": "5.0.0-dev.92a3409.1625911434", | ||
"description": "Complete framework to facilitate music commands using discord.js", | ||
@@ -13,6 +13,8 @@ "main": "lib/index.js", | ||
"build": "rimraf lib && tsc", | ||
"build:check": "tsc --noEmit --incremental false", | ||
"format": "prettier --write \"src/**/*.ts\" \"example/**/*.ts\"", | ||
"lint": "tslint -p tsconfig.json", | ||
"docs": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml --output docs/docs.json", | ||
"docs:test": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml" | ||
"docs:test": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml", | ||
"lint": "eslint src --ext .ts", | ||
"lint:fix": "eslint src --ext .ts --fix" | ||
}, | ||
@@ -54,3 +56,3 @@ "funding": "https://github.com/Androz2091/discord-player?sponsor=1", | ||
"dependencies": { | ||
"@discordjs/voice": "^0.5.0", | ||
"@discordjs/voice": "^0.5.3", | ||
"discord-ytdl-core": "^5.0.4", | ||
@@ -61,25 +63,26 @@ "libsodium-wrappers": "^0.7.9", | ||
"tiny-typed-emitter": "^2.0.3", | ||
"youtube-sr": "^4.1.4", | ||
"ytdl-core": "^4.8.2" | ||
"youtube-sr": "^4.1.7", | ||
"ytdl-core": "^4.8.3" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.14.5", | ||
"@babel/core": "^7.14.5", | ||
"@babel/preset-env": "^7.14.5", | ||
"@babel/core": "^7.14.6", | ||
"@babel/preset-env": "^7.14.7", | ||
"@babel/preset-typescript": "^7.14.5", | ||
"@devsnowflake/docgen": "devsnowflake/docgen#ts-patch", | ||
"@discord-player/extractor": "^3.0.2", | ||
"@discordjs/opus": "^0.5.3", | ||
"@types/node": "^15.12.2", | ||
"@types/ws": "^7.4.4", | ||
"@types/node": "^16.0.0", | ||
"@types/ws": "^7.4.6", | ||
"@typescript-eslint/eslint-plugin": "^4.28.1", | ||
"@typescript-eslint/parser": "^4.28.1", | ||
"discord-api-types": "^0.18.1", | ||
"discord.js": "^13.0.0-dev.1f8f3ab0f8dbd346154bbfa14a98726b8df25d57", | ||
"discord.js-docgen": "discordjs/docgen#ts-patch", | ||
"discord.js": "^13.0.0-dev.d6c43a5.1625875428", | ||
"eslint": "^7.30.0", | ||
"jsdoc-babel": "^0.5.0", | ||
"prettier": "^2.3.1", | ||
"prettier": "^2.3.2", | ||
"rimraf": "^3.0.2", | ||
"ts-node": "^10.0.0", | ||
"tslint": "^6.1.3", | ||
"tslint-config-prettier": "^1.18.0", | ||
"typescript": "^4.3.2" | ||
"typescript": "^4.3.5" | ||
} | ||
} |
@@ -8,5 +8,4 @@ # Discord Player | ||
[](https://wakatime.com/badge/github/Androz2091/discord-player) | ||
[](https://www.codefactor.io/repository/github/androz2091/discord-player/overview/v5) | ||
> V5 WIP | ||
## Installation | ||
@@ -96,3 +95,3 @@ | ||
const track = await client.player.search(args[0], { | ||
searchEngine: QueryType.YOUTUBE_SEARCH | ||
requestedBy: message.author | ||
}).then(x => x.tracks[1]); | ||
@@ -99,0 +98,0 @@ if (!track) return void message.reply("Track not found!"); |
142660
29
3436
19
162
Updated@discordjs/voice@^0.5.3
Updatedyoutube-sr@^4.1.7
Updatedytdl-core@^4.8.3