feat: documentation
This commit is contained in:
parent
c172af0fbf
commit
fcd8a8e186
19 changed files with 364 additions and 70 deletions
|
@ -32,9 +32,6 @@ Your extractor should have 2 methods (required):
|
|||
url: "Some Link"
|
||||
}
|
||||
```
|
||||
- `important: boolean`
|
||||
|
||||
You can mark your Extractor as `important` by adding `important: true` to your extractor object. Doing this will disable rest of the extractors that comes after your extractor and use your extractor to get data. By default, it is set to `false`.
|
||||
|
||||
- `version: string`
|
||||
|
||||
|
|
|
@ -8,5 +8,5 @@ const { AudioFilters } = require("discord-player");
|
|||
AudioFilters.define("3D", "apulsator=hz=0.128");
|
||||
|
||||
// later, it can be used like this
|
||||
player.setFilters(message, { "3D": true });
|
||||
queue.setFilters(message, { "3D": true });
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
# How to play live videos?
|
||||
|
||||
You cannot play live videos by default. If you need to play the live video, just add this option:
|
||||
|
||||
```js
|
||||
const player = new Player(client, {
|
||||
enableLive: true // enables livestream
|
||||
});
|
||||
```
|
||||
|
||||
However, you cannot use audio filters with livestreams using this library!
|
|
@ -1,15 +0,0 @@
|
|||
# Pause and Resume is not working properly
|
||||
|
||||
This is a bug in **[discord.js#5300](https://github.com/discordjs/discord.js/issues/5300)**.
|
||||
|
||||
# Fix
|
||||
|
||||
You have to update your command something like this:
|
||||
|
||||
```diff
|
||||
- client.player.resume(message);
|
||||
|
||||
+ client.player.resume(message);
|
||||
+ client.player.pause(message);
|
||||
+ client.player.resume(message);
|
||||
```
|
|
@ -3,6 +3,10 @@ Complete framework to facilitate music commands using **[discord.js](https://dis
|
|||
|
||||
[![downloadsBadge](https://img.shields.io/npm/dt/discord-player?style=for-the-badge)](https://npmjs.com/discord-player)
|
||||
[![versionBadge](https://img.shields.io/npm/v/discord-player?style=for-the-badge)](https://npmjs.com/discord-player)
|
||||
[![discordBadge](https://img.shields.io/discord/558328638911545423?style=for-the-badge&color=7289da)](https://androz2091.fr/discord)
|
||||
[![wakatime](https://wakatime.com/badge/github/Androz2091/discord-player.svg)](https://wakatime.com/badge/github/Androz2091/discord-player)
|
||||
|
||||
> V5 WIP
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -43,13 +47,13 @@ Here is the code you will need to get started with discord-player. Then, you wil
|
|||
|
||||
```js
|
||||
const Discord = require("discord.js"),
|
||||
client = new Discord.Client,
|
||||
client = new Discord.Client({ intents: ["GUILD_VOICE_STATES", "GUILD_MESSAGES", "GUILDS"] }),
|
||||
settings = {
|
||||
prefix: "!",
|
||||
token: "Your Discord Token"
|
||||
};
|
||||
|
||||
const { Player } = require("discord-player");
|
||||
const { Player, QueryType } = require("discord-player");
|
||||
|
||||
// Create a new Player (you don't need any API Key)
|
||||
const player = new Player(client);
|
||||
|
@ -58,7 +62,7 @@ const player = new Player(client);
|
|||
client.player = player;
|
||||
|
||||
// add the trackStart event so when a song will be played this message will be sent
|
||||
client.player.on("trackStart", (message, track) => message.channel.send(`Now playing ${track.title}...`))
|
||||
client.player.on("trackStart", (queue, track) => queue.metadata.channel.send(`Now playing ${track.title}...`))
|
||||
|
||||
client.once("ready", () => {
|
||||
console.log("I'm ready !");
|
||||
|
@ -70,10 +74,29 @@ client.on("message", async (message) => {
|
|||
const command = args.shift().toLowerCase();
|
||||
|
||||
// !play Despacito
|
||||
// will play the song "Despacito" in the voice channel
|
||||
if(command === "play"){
|
||||
client.player.play(message, args[0]);
|
||||
// as we registered the event above, no need to send a success message here
|
||||
// will play "Despacito" in the voice channel
|
||||
if (command === "play") {
|
||||
if (!message.member.voice.channel) return void message.reply("You are not in a voice channel!");
|
||||
if (message.guild.me.voice.channel && message.member.voice.channelID !== message.guild.me.voice.channelID) return void message.reply("You are not in my voice channel!");
|
||||
|
||||
const queue = client.player.createQueue(message.guild, {
|
||||
metadata: message
|
||||
});
|
||||
|
||||
// verify vc connection
|
||||
try {
|
||||
if (!queue.connection) await queue.connect(message.member.voice.channel);
|
||||
} catch {
|
||||
queue.destroy();
|
||||
return void message.reply("Could not join your voice channel!");
|
||||
}
|
||||
|
||||
const track = await client.player.search(args[0], {
|
||||
searchEngine: QueryType.YOUTUBE_SEARCH
|
||||
}).then(x => x.tracks[1]);
|
||||
if (!track) return void message.reply("Track not found!");
|
||||
|
||||
queue.play(track);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -106,13 +129,13 @@ These bots are made by the community, they can help you build your own!
|
|||
* [Discord-Music](https://github.com/inhydrox/discord-music) by [inhydrox](https://github.com/inhydrox)
|
||||
* [Music-bot](https://github.com/ZerioDev/Music-bot) by [ZerioDev](https://github.com/ZerioDev)
|
||||
|
||||
## FAQ
|
||||
## Advanced
|
||||
|
||||
### How to use cookies
|
||||
### Use cookies
|
||||
|
||||
```js
|
||||
const player = new Player(client, {
|
||||
ytdlDownloadOptions: {
|
||||
ytdlOptions: {
|
||||
requestOptions: {
|
||||
headers: {
|
||||
cookie: "YOUR_YOUTUBE_COOKIE"
|
||||
|
@ -122,7 +145,7 @@ const player = new Player(client, {
|
|||
});
|
||||
```
|
||||
|
||||
### How to use custom proxies
|
||||
### Use custom proxies
|
||||
|
||||
```js
|
||||
const HttpsProxyAgent = require("https-proxy-agent");
|
||||
|
@ -132,7 +155,7 @@ const proxy = "http://user:pass@111.111.111.111:8080";
|
|||
const agent = HttpsProxyAgent(proxy);
|
||||
|
||||
const player = new Player(client, {
|
||||
ytdlDownloadOptions: {
|
||||
ytdlOptions: {
|
||||
requestOptions: { agent }
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
files:
|
||||
- name: Custom Filters
|
||||
path: custom_filters.md
|
||||
- name: Livestreams
|
||||
path: live_video.md
|
||||
- name: Pause & Resume
|
||||
path: pause_resume.md
|
||||
- name: YouTube
|
||||
files:
|
||||
- name: Using Cookies
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
const { Player } = require("discord-player");
|
||||
|
||||
const player = new Player(client, {
|
||||
ytdlDownloadOptions: {
|
||||
ytdlOptions: {
|
||||
requestOptions: {
|
||||
headers: {
|
||||
cookie: "YOUR_YOUTUBE_COOKIE"
|
||||
|
|
|
@ -9,7 +9,7 @@ const proxy = "http://user:pass@111.111.111.111:8080";
|
|||
const agent = HttpsProxyAgent(proxy);
|
||||
|
||||
const player = new Player(client, {
|
||||
ytdlDownloadOptions: {
|
||||
ytdlOptions: {
|
||||
requestOptions: { agent }
|
||||
}
|
||||
});
|
||||
|
|
|
@ -56,6 +56,13 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles voice state update
|
||||
* @param {VoiceState} oldState The old voice state
|
||||
* @param {VoiceState} newState The new voice state
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
private _handleVoiceState(oldState: VoiceState, newState: VoiceState): void {
|
||||
const queue = this.getQueue(oldState.guild.id);
|
||||
if (!queue) return;
|
||||
|
@ -141,7 +148,7 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
|
|||
* Search tracks
|
||||
* @param {string|Track} query The search query
|
||||
* @param {UserResolvable} requestedBy The person who requested track search
|
||||
* @returns {Promise<{playlist?: Playlist; tracks: Track[]}>}
|
||||
* @returns {Promise<object>}
|
||||
*/
|
||||
async search(query: string | Track, options: SearchOptions) {
|
||||
if (query instanceof Track) return { playlist: null, tracks: [query] };
|
||||
|
@ -400,6 +407,12 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} extractorName The extractor name
|
||||
* @param {ExtractorModel|any} extractor The extractor object
|
||||
* @param {boolean} [force=false]
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
use(extractorName: string, extractor: ExtractorModel | any, force = false): ExtractorModel {
|
||||
if (!extractorName) throw new Error("Cannot use unknown extractor!");
|
||||
if (this.extractors.has(extractorName) && !force) return this.extractors.get(extractorName);
|
||||
|
@ -418,6 +431,11 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
|
|||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes registered extractor
|
||||
* @param {string} extractorName The extractor name
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
unuse(extractorName: string) {
|
||||
if (!this.extractors.has(extractorName)) throw new Error(`Cannot find extractor "${extractorName}"`);
|
||||
const prev = this.extractors.get(extractorName);
|
||||
|
@ -425,6 +443,10 @@ class DiscordPlayer extends EventEmitter<PlayerEvents> {
|
|||
return prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report of the dependencies used by the `@discordjs/voice` module. Useful for debugging.
|
||||
* @returns {string}
|
||||
*/
|
||||
scanDeps() {
|
||||
return generateDependencyReport();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,12 @@ class ExtractorModel {
|
|||
*/
|
||||
this.name = extractorName;
|
||||
|
||||
/**
|
||||
* The raw model
|
||||
* @name ExtractorModel#_raw
|
||||
* @type {any}
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
|
||||
}
|
||||
|
||||
|
|
|
@ -16,25 +16,106 @@ class Playlist {
|
|||
};
|
||||
public id: string;
|
||||
public url: string;
|
||||
public rawPlaylist?: any;
|
||||
public readonly rawPlaylist?: any;
|
||||
|
||||
/**
|
||||
* Playlist constructor
|
||||
* @param {Player} player The player
|
||||
* @param {PlaylistInitData} data The data
|
||||
*/
|
||||
constructor(player: Player, data: PlaylistInitData) {
|
||||
/**
|
||||
* The player
|
||||
* @name Playlist#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
|
||||
/**
|
||||
* The tracks in this playlist
|
||||
* @name Playlist#tracks
|
||||
* @type {Track[]}
|
||||
*/
|
||||
this.tracks = data.tracks ?? [];
|
||||
|
||||
/**
|
||||
* The author of this playlist
|
||||
* @name Playlist#author
|
||||
* @type {object}
|
||||
*/
|
||||
this.author = data.author;
|
||||
|
||||
/**
|
||||
* The description
|
||||
* @name Playlist#description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
|
||||
/**
|
||||
* The thumbnail of this playlist
|
||||
* @name Playlist#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
this.thumbnail = data.thumbnail;
|
||||
|
||||
/**
|
||||
* The playlist type:
|
||||
* - `album`
|
||||
* - `playlist`
|
||||
* @name Playlist#type
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = data.type;
|
||||
|
||||
/**
|
||||
* The source of this playlist:
|
||||
* - `youtube`
|
||||
* - `soundcloud`
|
||||
* - `spotify`
|
||||
* - `arbitrary`
|
||||
* @name Playlist#source
|
||||
* @type {string}
|
||||
*/
|
||||
this.source = data.source;
|
||||
|
||||
/**
|
||||
* The playlist id
|
||||
* @name Playlist#id
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* The playlist url
|
||||
* @name Playlist#url
|
||||
* @type {string}
|
||||
*/
|
||||
this.url = data.url;
|
||||
|
||||
/**
|
||||
* The playlist title
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = data.title;
|
||||
|
||||
/**
|
||||
* @name Playlist#rawPlaylist
|
||||
* @type {any}
|
||||
* @readonly
|
||||
*/
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
yield* this.tracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON representation of this playlist
|
||||
* @param {boolean} [withTracks=true] If it should build json with tracks
|
||||
* @returns {PlaylistJSON}
|
||||
*/
|
||||
toJSON(withTracks = true) {
|
||||
const payload = {
|
||||
id: this.id,
|
||||
|
|
|
@ -27,18 +27,20 @@ class Queue<T = unknown> {
|
|||
* Queue constructor
|
||||
* @param {Player} player The player that instantiated this queue
|
||||
* @param {Guild} guild The guild that instantiated this queue
|
||||
* @param {PlayerOptions={}} options Player options for the queue
|
||||
* @param {PlayerOptions} [options={}] Player options for the queue
|
||||
*/
|
||||
constructor(player: Player, guild: Guild, options: PlayerOptions = {}) {
|
||||
/**
|
||||
* The player that instantiated this queue
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
|
||||
/**
|
||||
* The guild that instantiated this queue
|
||||
* @type {Guild}
|
||||
* @readonly
|
||||
*/
|
||||
this.guild = guild;
|
||||
|
||||
|
@ -69,7 +71,7 @@ class Queue<T = unknown> {
|
|||
|
||||
/**
|
||||
* Returns current track
|
||||
* @returns {Track}
|
||||
* @type {Track}
|
||||
*/
|
||||
get current() {
|
||||
return this.connection.audioResource?.metadata ?? this.tracks[0];
|
||||
|
@ -85,7 +87,7 @@ class Queue<T = unknown> {
|
|||
|
||||
/**
|
||||
* Connects to a voice channel
|
||||
* @param {StageChannel|VoiceChannel} channel
|
||||
* @param {StageChannel|VoiceChannel} channel The voice/stage channel
|
||||
* @returns {Promise<Queue>}
|
||||
*/
|
||||
async connect(channel: StageChannel | VoiceChannel) {
|
||||
|
@ -110,6 +112,8 @@ class Queue<T = unknown> {
|
|||
|
||||
/**
|
||||
* Destroys this queue
|
||||
* @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy
|
||||
* @returns {void}
|
||||
*/
|
||||
destroy(disconnect = this.options.leaveOnStop) {
|
||||
this.connection.end();
|
||||
|
@ -159,6 +163,7 @@ class Queue<T = unknown> {
|
|||
/**
|
||||
* Sets bitrate
|
||||
* @param {number|"auto"} bitrate bitrate to set
|
||||
* @returns {void}
|
||||
*/
|
||||
setBitrate(bitrate: number | "auto") {
|
||||
if (!this.connection?.audioResource?.encoder) return;
|
||||
|
@ -189,20 +194,22 @@ class Queue<T = unknown> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns current volume amount
|
||||
* The current volume amount
|
||||
* @type {number}
|
||||
*/
|
||||
get volume() {
|
||||
if (!this.connection) return 100;
|
||||
return this.connection.volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative volume setter
|
||||
*/
|
||||
set volume(amount: number) {
|
||||
this.setVolume(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stream time of this queue
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime() {
|
||||
if (!this.connection) return 0;
|
||||
const playbackTime = this._streamTime + this.connection.streamTime;
|
||||
|
@ -213,14 +220,27 @@ class Queue<T = unknown> {
|
|||
return NC ? playbackTime * NC : VW ? playbackTime * VW : playbackTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersEnabled() {
|
||||
return AudioFilters.names.filter((x) => this._activeFilters.includes(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns disabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersDisabled() {
|
||||
return AudioFilters.names.filter((x) => !this._activeFilters.includes(x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets filters
|
||||
* @param {QueueFilters} filters Queue filters
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setFilters(filters?: QueueFilters) {
|
||||
if (!filters || !Object.keys(filters).length) {
|
||||
// reset filters
|
||||
|
@ -254,6 +274,11 @@ class Queue<T = unknown> {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to the given time
|
||||
* @param {number} position The position
|
||||
* @returns {boolean}
|
||||
*/
|
||||
async seek(position: number) {
|
||||
if (!this.playing || !this.current) return false;
|
||||
if (position < 1) position = 0;
|
||||
|
@ -277,8 +302,8 @@ class Queue<T = unknown> {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Track} [src] The track to play (if empty, uses first track from the queue)
|
||||
* @param {PlayOptions={}} options The options
|
||||
* @param {Track} [src] The track to play (if empty, uses first track from the queue)
|
||||
* @param {PlayOptions} [options={}] The options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async play(src?: Track, options: PlayOptions = {}): Promise<void> {
|
||||
|
|
|
@ -92,6 +92,13 @@ class Track {
|
|||
* @type {RawTrackData}
|
||||
*/
|
||||
|
||||
/**
|
||||
* The track id
|
||||
* @name Track#_trackID
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
|
||||
void this._patch(data);
|
||||
}
|
||||
|
||||
|
@ -153,7 +160,7 @@ class Track {
|
|||
|
||||
/**
|
||||
* Raw JSON representation of this track
|
||||
* @returns {object}
|
||||
* @returns {TrackJSON}
|
||||
*/
|
||||
toJSON(hidePlaylist?: boolean) {
|
||||
return {
|
||||
|
|
|
@ -24,18 +24,37 @@ export interface VoiceEvents {
|
|||
finish: () => any;
|
||||
}
|
||||
|
||||
class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
||||
class StreamDispatcher extends EventEmitter<VoiceEvents> {
|
||||
public readonly voiceConnection: VoiceConnection;
|
||||
public readonly audioPlayer: AudioPlayer;
|
||||
public readonly channel: VoiceChannel | StageChannel;
|
||||
public audioResource?: AudioResource<Track>;
|
||||
private readyLock: boolean = false;
|
||||
|
||||
/**
|
||||
* Creates new connection object
|
||||
* @param {VoiceConnection} connection The connection
|
||||
* @param {VoiceChannel|StageChannel} channel The connected channel
|
||||
*/
|
||||
constructor(connection: VoiceConnection, channel: VoiceChannel | StageChannel) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* The voice connection
|
||||
* @type {VoiceConnection}
|
||||
*/
|
||||
this.voiceConnection = connection;
|
||||
|
||||
/**
|
||||
* The audio player
|
||||
* @type {AudioPlayer}
|
||||
*/
|
||||
this.audioPlayer = createAudioPlayer();
|
||||
|
||||
/**
|
||||
* The voice channel
|
||||
* @type {VoiceChannel|StageChannel}
|
||||
*/
|
||||
this.channel = channel;
|
||||
|
||||
this.voiceConnection.on("stateChange", async (_, newState) => {
|
||||
|
@ -85,7 +104,7 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
/**
|
||||
* Creates stream
|
||||
* @param {Readable|Duplex|string} src The stream source
|
||||
* @param {({type?:StreamType;data?:any;})} [ops] Options
|
||||
* @param {object} [ops={}] Options
|
||||
* @returns {AudioResource}
|
||||
*/
|
||||
createStream(src: Readable | Duplex | string, ops?: { type?: StreamType; data?: any }) {
|
||||
|
@ -100,6 +119,7 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
|
||||
/**
|
||||
* The player status
|
||||
* @type {AudioPlayerStatus}
|
||||
*/
|
||||
get status() {
|
||||
return this.audioPlayer.state.status;
|
||||
|
@ -107,6 +127,7 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
|
||||
/**
|
||||
* Disconnects from voice
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnect() {
|
||||
try {
|
||||
|
@ -116,16 +137,26 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
|
||||
/**
|
||||
* Stops the player
|
||||
* @returns {void}
|
||||
*/
|
||||
end() {
|
||||
this.audioPlayer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the stream playback
|
||||
* @param {boolean} [interpolateSilence=false] If true, the player will play 5 packets of silence after pausing to prevent audio glitches.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
pause(interpolateSilence?: boolean) {
|
||||
const success = this.audioPlayer.pause(interpolateSilence);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the stream playback
|
||||
* @returns {boolean}
|
||||
*/
|
||||
resume() {
|
||||
const success = this.audioPlayer.unpause();
|
||||
return success;
|
||||
|
@ -133,7 +164,8 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
|
||||
/**
|
||||
* Play stream
|
||||
* @param {AudioResource} resource The audio resource to play
|
||||
* @param {AudioResource<Track>} [resource=this.audioResource] The audio resource to play
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
async playStream(resource: AudioResource<Track> = this.audioResource) {
|
||||
if (!resource) throw new Error("Audio resource is not available!");
|
||||
|
@ -144,6 +176,11 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets playback volume
|
||||
* @param {number} value The volume amount
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setVolume(value: number) {
|
||||
if (!this.audioResource || isNaN(value) || value < 0 || value > Infinity) return false;
|
||||
|
||||
|
@ -152,20 +189,32 @@ class BasicStreamDispatcher extends EventEmitter<VoiceEvents> {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current volume
|
||||
* @type {number}
|
||||
*/
|
||||
get volume() {
|
||||
if (!this.audioResource || !this.audioResource.volume) return 100;
|
||||
const currentVol = this.audioResource.volume.volume;
|
||||
return Math.round(Math.pow(currentVol, 1 / 1.660964) * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* The playback time
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime() {
|
||||
if (!this.audioResource) return 0;
|
||||
return this.audioResource.playbackDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* The paused state
|
||||
* @type {boolean}
|
||||
*/
|
||||
get paused() {
|
||||
return [AudioPlayerStatus.AutoPaused, AudioPlayerStatus.Paused].includes(this.audioPlayer.state.status);
|
||||
}
|
||||
}
|
||||
|
||||
export { BasicStreamDispatcher as StreamDispatcher };
|
||||
export { StreamDispatcher as StreamDispatcher };
|
||||
|
|
|
@ -3,13 +3,24 @@ import { entersState, joinVoiceChannel, VoiceConnection, VoiceConnectionStatus }
|
|||
import { StreamDispatcher } from "./BasicStreamDispatcher";
|
||||
|
||||
class VoiceUtils {
|
||||
public cache = new Collection<Snowflake, StreamDispatcher>();
|
||||
public cache: Collection<Snowflake, StreamDispatcher>;
|
||||
|
||||
/**
|
||||
* Joins a voice channel
|
||||
* The voice utils
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
* The cache where voice utils stores stream managers
|
||||
* @type {Collection<Snowflake, StreamDispatcher>}
|
||||
*/
|
||||
this.cache = new Collection<Snowflake, StreamDispatcher>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a voice channel, creating basic stream dispatch manager
|
||||
* @param {StageChannel|VoiceChannel} channel The voice channel
|
||||
* @param {({deaf?: boolean;maxTime?: number;})} [options] Join options
|
||||
* @returns {Promise<BasicStreamDispatcher>}
|
||||
* @param {object} [options={}] Join options
|
||||
* @returns {Promise<StreamDispatcher>}
|
||||
*/
|
||||
public async connect(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
|
@ -24,6 +35,12 @@ class VoiceUtils {
|
|||
return sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a voice channel
|
||||
* @param {StageChannel|VoiceChannel} [channel] The voice/stage channel to join
|
||||
* @param {object} [options={}] Join options
|
||||
* @returns {VoiceConnection}
|
||||
*/
|
||||
public async join(
|
||||
channel: VoiceChannel | StageChannel,
|
||||
options?: {
|
||||
|
@ -50,12 +67,18 @@ class VoiceUtils {
|
|||
/**
|
||||
* Disconnects voice connection
|
||||
* @param {VoiceConnection} connection The voice connection
|
||||
* @returns {void}
|
||||
*/
|
||||
public disconnect(connection: VoiceConnection | StreamDispatcher) {
|
||||
if (connection instanceof StreamDispatcher) return connection.voiceConnection.destroy();
|
||||
return connection.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Discord Player voice connection
|
||||
* @param {Snowflake} guild The guild id
|
||||
* @returns {StreamDispatcher}
|
||||
*/
|
||||
public getConnection(guild: Snowflake) {
|
||||
return this.cache.get(guild);
|
||||
}
|
||||
|
|
|
@ -140,38 +140,71 @@ export enum QueryType {
|
|||
export interface PlayerEvents {
|
||||
/**
|
||||
* Emitted when bot gets disconnected from a voice channel
|
||||
* @event Player#botDisconnect
|
||||
* @param {Queue} queue The queue
|
||||
*/
|
||||
botDisconnect: (queue: Queue) => any;
|
||||
|
||||
/**
|
||||
* Emitted when the voice channel is empty
|
||||
* @event Player#channelEmpty
|
||||
* @param {Queue} queue The queue
|
||||
*/
|
||||
channelEmpty: (queue: Queue) => any;
|
||||
|
||||
/**
|
||||
* Emitted when bot connects to a voice channel
|
||||
* @event Player#connectionCreate
|
||||
* @param {Queue} queue The queue
|
||||
* @param {StreamDispatcher} connection The discord player connection object
|
||||
*/
|
||||
connectionCreate: (queue: Queue, connection: StreamDispatcher) => any;
|
||||
|
||||
/**
|
||||
* Debug information
|
||||
* @event Player#debug
|
||||
* @param {Queue} queue The queue
|
||||
* @param {string} message The message
|
||||
*/
|
||||
debug: (queue: Queue, message: string) => any;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
error: (queue: Queue, error: Error) => any;
|
||||
|
||||
/**
|
||||
* Emitted when queue ends
|
||||
* @event Player#queueEnd
|
||||
* @param {Queue} queue The queue
|
||||
*/
|
||||
queueEnd: (queue: Queue) => any;
|
||||
|
||||
/**
|
||||
* Emitted when a single track is added
|
||||
* @event Player#trackAdd
|
||||
* @param {Queue} queue The queue
|
||||
* @param {Track} track The track
|
||||
*/
|
||||
trackAdd: (queue: Queue, track: Track) => any;
|
||||
|
||||
/**
|
||||
* Emitted when multiple tracks are added
|
||||
* @event Player#tracksAdd
|
||||
* @param {Queue} queue The queue
|
||||
* @param {Track[]} tracks The tracks
|
||||
*/
|
||||
tracksAdd: (queue: Queue, track: Track[]) => any;
|
||||
|
||||
/**
|
||||
* Emitted when a track starts playing
|
||||
* @event Player#trackStart
|
||||
* @param {Queue} queue The queue
|
||||
* @param {Track} track The track
|
||||
*/
|
||||
trackStart: (queue: Queue, track: Track) => any;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,18 @@ const attachmentRegex =
|
|||
// scary things above *sigh*
|
||||
|
||||
class QueryResolver {
|
||||
/**
|
||||
* Query resolver
|
||||
*/
|
||||
constructor() {
|
||||
throw new Error("Cannot instantiate static class!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given search query
|
||||
* @param {string} query The query
|
||||
* @returns {QueryType}
|
||||
*/
|
||||
static resolve(query: string): QueryType {
|
||||
if (SoundcloudValidateURL(query, "track")) return QueryType.SOUNDCLOUD_TRACK;
|
||||
if (SoundcloudValidateURL(query, "playlist") || query.includes("/sets/")) return QueryType.SOUNDCLOUD_PLAYLIST;
|
||||
|
@ -32,6 +44,11 @@ class QueryResolver {
|
|||
return QueryType.YOUTUBE_SEARCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses vimeo id from url
|
||||
* @param {string} query The query
|
||||
* @returns {string}
|
||||
*/
|
||||
static getVimeoID(query: string): string {
|
||||
return QueryResolver.resolve(query) === QueryType.VIMEO
|
||||
? query
|
||||
|
|
|
@ -2,12 +2,29 @@ import { StageChannel, VoiceChannel } from "discord.js";
|
|||
import { TimeData } from "../types/types";
|
||||
|
||||
class Util {
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
constructor() {
|
||||
throw new Error("Cannot instantiate static class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates duration string
|
||||
* @param {object} durObj The duration object
|
||||
* @returns {string}
|
||||
*/
|
||||
static durationString(durObj: object) {
|
||||
return Object.values(durObj)
|
||||
.map((m) => (isNaN(m) ? 0 : m))
|
||||
.join(":");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses milliseconds to consumable time object
|
||||
* @param {number} milliseconds The time in ms
|
||||
* @returns {TimeData}
|
||||
*/
|
||||
static parseMS(milliseconds: number) {
|
||||
const round = milliseconds > 0 ? Math.floor : Math.ceil;
|
||||
|
||||
|
@ -19,6 +36,11 @@ class Util {
|
|||
} as TimeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds time code
|
||||
* @param {TimeData} duration The duration object
|
||||
* @returns {string}
|
||||
*/
|
||||
static buildTimeCode(duration: TimeData) {
|
||||
const items = Object.keys(duration);
|
||||
const required = ["days", "hours", "minutes", "seconds"];
|
||||
|
@ -31,15 +53,30 @@ class Util {
|
|||
return final.length <= 3 ? `0:${final.padStart(2, "0") || 0}` : final;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks last item of the given array
|
||||
* @param {any[]} arr The array
|
||||
* @returns {any}
|
||||
*/
|
||||
static last<T = any>(arr: T[]): T {
|
||||
if (!Array.isArray(arr)) return;
|
||||
return arr[arr.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the voice channel is empty
|
||||
* @param {VoiceChannel|StageChannel} channel The voice channel
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isVoiceEmpty(channel: VoiceChannel | StageChannel) {
|
||||
return channel.members.filter((member) => !member.user.bot).size === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safer require
|
||||
* @param {string} id Node require id
|
||||
* @returns {any}
|
||||
*/
|
||||
static require(id: string) {
|
||||
try {
|
||||
return require(id);
|
||||
|
@ -48,6 +85,11 @@ class Util {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous timeout
|
||||
* @param {number} time The time in ms to wait
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
static wait(time: number) {
|
||||
return new Promise((r) => setTimeout(r, time).unref());
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"strictNullChecks": false,
|
||||
"esModuleInterop": true,
|
||||
"removeComments": true
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
|
|
Loading…
Reference in a new issue