fix docs
This commit is contained in:
parent
e1cc416c84
commit
9d5f065582
14 changed files with 3427 additions and 106 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -9,3 +9,6 @@ lib/
|
||||||
|
|
||||||
# error logs
|
# error logs
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
|
||||||
|
# demo
|
||||||
|
demo/
|
|
@ -3,3 +3,4 @@ tslint.json
|
||||||
tsconfig.json
|
tsconfig.json
|
||||||
.prettierrc
|
.prettierrc
|
||||||
test/
|
test/
|
||||||
|
demo/
|
2
docs/extractors/extractor.md
Normal file
2
docs/extractors/extractor.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Discord Player Extractor API
|
||||||
|
The extractor API
|
139
docs/general/Welcome.md
Normal file
139
docs/general/Welcome.md
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
# Discord Player
|
||||||
|
Complete framework to facilitate music commands using **[discord.js](https://discord.js.org)**.
|
||||||
|
|
||||||
|
[![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)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Install **[discord-player](https://npmjs.com/package/discord-player)**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install --save discord-player
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install **[@discordjs/opus](https://npmjs.com/package/@discordjs/opus)**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install --save @discordjs/opus
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install FFmpeg or Avconv
|
||||||
|
- Official FFMPEG Website: **[https://www.ffmpeg.org/download.html](https://www.ffmpeg.org/download.html)**
|
||||||
|
|
||||||
|
- Node Module (FFMPEG): **[https://npmjs.com/package/ffmpeg-static](https://npmjs.com/package/ffmpeg-static)**
|
||||||
|
|
||||||
|
- Avconv: **[https://libav.org/download](https://libav.org/download)**
|
||||||
|
|
||||||
|
# Features
|
||||||
|
- Simple & easy to use 🤘
|
||||||
|
- Beginner friendly 😱
|
||||||
|
- Audio filters 🎸
|
||||||
|
- Lightweight 🛬
|
||||||
|
- Custom extractors support 🌌
|
||||||
|
- Lyrics 📃
|
||||||
|
- Multiple sources support ✌
|
||||||
|
- Play in multiple servers at the same time 🚗
|
||||||
|
|
||||||
|
## [Documentation](https://discord-player.js.org)
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Here is the code you will need to get started with discord-player. Then, you will be able to use `client.player` everywhere in your code!
|
||||||
|
|
||||||
|
```js
|
||||||
|
const Discord = require("discord.js"),
|
||||||
|
client = new Discord.Client,
|
||||||
|
settings = {
|
||||||
|
prefix: "!",
|
||||||
|
token: "Your Discord Token"
|
||||||
|
};
|
||||||
|
|
||||||
|
const { Player } = require("discord-player");
|
||||||
|
|
||||||
|
// Create a new Player (you don't need any API Key)
|
||||||
|
const player = new Player(client);
|
||||||
|
|
||||||
|
// To easily access the player
|
||||||
|
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.once("ready", () => {
|
||||||
|
console.log("I'm ready !");
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("message", async (message) => {
|
||||||
|
|
||||||
|
const args = message.content.slice(settings.prefix.length).trim().split(/ +/g);
|
||||||
|
const command = args.shift().toLowerCase();
|
||||||
|
|
||||||
|
// !play Despacito
|
||||||
|
// will play "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
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login(settings.token);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported websites
|
||||||
|
|
||||||
|
By default, discord-player supports **YouTube**, **Spotify** and **SoundCloud** streams only.
|
||||||
|
|
||||||
|
### Optional dependencies
|
||||||
|
|
||||||
|
Discord Player provides an **Extractor API** that enables you to use your custom stream extractor with it. Some packages have been made by the community to add new features using this API.
|
||||||
|
|
||||||
|
#### [@discord-player/extractor](https://github.com/Snowflake107/discord-player-extractors) (optional)
|
||||||
|
|
||||||
|
Optional package that adds support for `vimeo`, `reverbnation`, `facebook`, `attachment links` and `lyrics`.
|
||||||
|
You just need to install it using `npm i --save @discord-player/extractor` (discord-player will automatically detect and use it).
|
||||||
|
|
||||||
|
#### [@discord-player/downloader](https://github.com/DevSnowflake/discord-player-downloader) (optional)
|
||||||
|
|
||||||
|
`@discord-player/downloader` is an optional package that brings support for +700 websites. The documentation is available [here](https://github.com/DevSnowflake/discord-player-downloader).
|
||||||
|
|
||||||
|
## Examples of bots made with Discord Player
|
||||||
|
|
||||||
|
These bots are made by the community, they can help you build your own!
|
||||||
|
|
||||||
|
* [AtlantaBot](https://github.com/Androz2091/AtlantaBot) by [Androz2091](https://github.com/Androz2091)
|
||||||
|
* [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
|
||||||
|
|
||||||
|
### How to use cookies?
|
||||||
|
|
||||||
|
```js
|
||||||
|
const player = new Player(client, {
|
||||||
|
ytdlDownloadOptions: {
|
||||||
|
requestOptions: {
|
||||||
|
headers: {
|
||||||
|
cookie: "YOUR_YOUTUBE_COOKIE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### How to use custom proxies?
|
||||||
|
|
||||||
|
```js
|
||||||
|
const HttpsProxyAgent = require("https-proxy-agent");
|
||||||
|
|
||||||
|
// Remove "user:pass@" if you don't need to authenticate to your proxy.
|
||||||
|
const proxy = "http://user:pass@111.111.111.111:8080";
|
||||||
|
const agent = HttpsProxyAgent(proxy);
|
||||||
|
|
||||||
|
const player = new Player(client, {
|
||||||
|
ytdlDownloadOptions: {
|
||||||
|
requestOptions: { agent }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
8
docs/index.yml
Normal file
8
docs/index.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
- name: General
|
||||||
|
files:
|
||||||
|
- name: Welcome
|
||||||
|
path: welcome.md
|
||||||
|
- name: Extractors
|
||||||
|
files:
|
||||||
|
- name: Extractors
|
||||||
|
path: extractor.md
|
17
jsdoc.json
Normal file
17
jsdoc.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"includePattern": ".+\\.ts(doc|x)?$"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"plugins/markdown",
|
||||||
|
"node_modules/jsdoc-babel"
|
||||||
|
],
|
||||||
|
"babel": {
|
||||||
|
"extensions": ["ts"],
|
||||||
|
"babelrc": false,
|
||||||
|
"presets": [
|
||||||
|
["@babel/preset-env", { "targets": { "node": true } }],
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
10
package.json
10
package.json
|
@ -11,7 +11,9 @@
|
||||||
"test": "yarn build && cd test && node index.js",
|
"test": "yarn build && cd test && node index.js",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"format": "prettier --write \"src/**/*.ts\"",
|
"format": "prettier --write \"src/**/*.ts\"",
|
||||||
"lint": "tslint -p tsconfig.json"
|
"lint": "tslint -p tsconfig.json",
|
||||||
|
"docs": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml --output demo/docs.json",
|
||||||
|
"docs:test": "docgen --jsdoc jsdoc.json --source src/*.ts src/**/*.ts --custom docs/index.yml"
|
||||||
},
|
},
|
||||||
"funding": "https://github.com/Androz2091/discord-player?sponsor=1",
|
"funding": "https://github.com/Androz2091/discord-player?sponsor=1",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
@ -45,11 +47,17 @@
|
||||||
"ytdl-core": "^4.5.0"
|
"ytdl-core": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.13.16",
|
||||||
|
"@babel/core": "^7.13.16",
|
||||||
|
"@babel/preset-env": "^7.13.15",
|
||||||
|
"@babel/preset-typescript": "^7.13.0",
|
||||||
"@discord-player/extractor": "^2.0.0",
|
"@discord-player/extractor": "^2.0.0",
|
||||||
"@discordjs/opus": "^0.5.0",
|
"@discordjs/opus": "^0.5.0",
|
||||||
"@types/node": "^14.14.41",
|
"@types/node": "^14.14.41",
|
||||||
"@types/ws": "^7.4.1",
|
"@types/ws": "^7.4.1",
|
||||||
"discord.js": "^12.5.3",
|
"discord.js": "^12.5.3",
|
||||||
|
"discord.js-docgen": "discordjs/docgen#ts-patch",
|
||||||
|
"jsdoc-babel": "^0.5.0",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"tslint": "^6.1.3",
|
"tslint": "^6.1.3",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
|
|
103
src/Player.ts
103
src/Player.ts
|
@ -28,13 +28,23 @@ const SoundCloud = new SoundCloudClient();
|
||||||
export class Player extends EventEmitter {
|
export class Player extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* The discord client that instantiated this player
|
* The discord client that instantiated this player
|
||||||
|
* @type {Discord.Client}
|
||||||
*/
|
*/
|
||||||
public client!: Client;
|
public client!: Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The player options
|
||||||
|
*/
|
||||||
public options: PlayerOptionsType;
|
public options: PlayerOptionsType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The audio filters
|
||||||
|
*/
|
||||||
public filters: typeof AudioFilters;
|
public filters: typeof AudioFilters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection of queues in this player
|
* The collection of queues in this player
|
||||||
|
* @type {Discord.Collection}
|
||||||
*/
|
*/
|
||||||
public queues = new Collection<Snowflake, Queue>();
|
public queues = new Collection<Snowflake, Queue>();
|
||||||
private _resultsCollectors = new Collection<string, Collector<Snowflake, Message>>();
|
private _resultsCollectors = new Collection<string, Collector<Snowflake, Message>>();
|
||||||
|
@ -42,13 +52,14 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The extractor model collection
|
* The extractor model collection
|
||||||
|
* @type {Discord.Collection}
|
||||||
*/
|
*/
|
||||||
public Extractors = new Collection<string, ExtractorModel>();
|
public Extractors = new Collection<string, ExtractorModel>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new Player instance
|
* Creates new Player instance
|
||||||
* @param client The discord.js client
|
* @param {Discord.Client} client The discord.js client
|
||||||
* @param options Player options
|
* @param {PlayerOptionsType} options Player options
|
||||||
*/
|
*/
|
||||||
constructor(client: Client, options?: PlayerOptionsType) {
|
constructor(client: Client, options?: PlayerOptionsType) {
|
||||||
super();
|
super();
|
||||||
|
@ -58,17 +69,11 @@ export class Player extends EventEmitter {
|
||||||
enumerable: false
|
enumerable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* The player options
|
|
||||||
*/
|
|
||||||
this.options = Object.assign({}, PlayerOptions, options ?? {});
|
this.options = Object.assign({}, PlayerOptions, options ?? {});
|
||||||
|
|
||||||
// check FFmpeg
|
// check FFmpeg
|
||||||
void Util.alertFFmpeg();
|
void Util.alertFFmpeg();
|
||||||
|
|
||||||
/**
|
|
||||||
* The audio filters
|
|
||||||
*/
|
|
||||||
this.filters = AudioFilters;
|
this.filters = AudioFilters;
|
||||||
|
|
||||||
this.client.on('voiceStateUpdate', (o, n) => void this._handleVoiceStateUpdate(o, n));
|
this.client.on('voiceStateUpdate', (o, n) => void this._handleVoiceStateUpdate(o, n));
|
||||||
|
@ -86,8 +91,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define custom extractor in this player
|
* Define custom extractor in this player
|
||||||
* @param extractorName The extractor name
|
* @param {string} extractorName The extractor name
|
||||||
* @param extractor The extractor itself
|
* @param {any} extractor The extractor itself
|
||||||
*/
|
*/
|
||||||
use(extractorName: string, extractor: any): Player {
|
use(extractorName: string, extractor: any): Player {
|
||||||
if (!extractorName) throw new PlayerError('Missing extractor name!', 'PlayerExtractorError');
|
if (!extractorName) throw new PlayerError('Missing extractor name!', 'PlayerExtractorError');
|
||||||
|
@ -106,7 +111,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove existing extractor from this player
|
* Remove existing extractor from this player
|
||||||
* @param extractorName The extractor name
|
* @param {string} extractorName The extractor name
|
||||||
*/
|
*/
|
||||||
unuse(extractorName: string): boolean {
|
unuse(extractorName: string): boolean {
|
||||||
if (!extractorName) throw new PlayerError('Missing extractor name!', 'PlayerExtractorError');
|
if (!extractorName) throw new PlayerError('Missing extractor name!', 'PlayerExtractorError');
|
||||||
|
@ -359,9 +364,9 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a song
|
* Play a song
|
||||||
* @param message The discord.js message object
|
* @param {Discord.Message} message The discord.js message object
|
||||||
* @param query Search query, can be `Player.Track` instance
|
* @param {string|Track} query Search query, can be `Player.Track` instance
|
||||||
* @param firstResult If it should play the first result
|
* @param {boolean} [firstResult] If it should play the first result
|
||||||
* @example await player.play(message, "never gonna give you up", true)
|
* @example await player.play(message, "never gonna give you up", true)
|
||||||
*/
|
*/
|
||||||
async play(message: Message, query: string | Track, firstResult?: boolean): Promise<void> {
|
async play(message: Message, query: string | Track, firstResult?: boolean): Promise<void> {
|
||||||
|
@ -444,7 +449,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this player is playing in a server
|
* Checks if this player is playing in a server
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
isPlaying(message: Message): boolean {
|
isPlaying(message: Message): boolean {
|
||||||
return this.queues.some((g) => g.guildID === message.guild.id);
|
return this.queues.some((g) => g.guildID === message.guild.id);
|
||||||
|
@ -452,7 +457,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns guild queue object
|
* Returns guild queue object
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
getQueue(message: Message): Queue {
|
getQueue(message: Message): Queue {
|
||||||
return this.queues.find((g) => g.guildID === message.guild.id);
|
return this.queues.find((g) => g.guildID === message.guild.id);
|
||||||
|
@ -460,8 +465,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets audio filters in this player
|
* Sets audio filters in this player
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param newFilters Audio filters object
|
* @param {QueueFilters} newFilters Audio filters object
|
||||||
*/
|
*/
|
||||||
setFilters(message: Message, newFilters: QueueFilters): Promise<void> {
|
setFilters(message: Message, newFilters: QueueFilters): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
@ -495,9 +500,9 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets track position
|
* Sets track position
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param time Time in ms to set
|
* @param {number} time Time in ms to set
|
||||||
* @alias seek
|
* @alias Player.seek
|
||||||
*/
|
*/
|
||||||
setPosition(message: Message, time: number): Promise<void> {
|
setPosition(message: Message, time: number): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
@ -519,9 +524,9 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets track position
|
* Sets track position
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param time Time in ms to set
|
* @param {number} time Time in ms to set
|
||||||
* @alias setPosition
|
* @alias Player.setPosition
|
||||||
*/
|
*/
|
||||||
seek(message: Message, time: number): Promise<void> {
|
seek(message: Message, time: number): Promise<void> {
|
||||||
return this.setPosition(message, time);
|
return this.setPosition(message, time);
|
||||||
|
@ -529,7 +534,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skips current track
|
* Skips current track
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
skip(message: Message): boolean {
|
skip(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -550,8 +555,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to a new voice channel
|
* Moves to a new voice channel
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param channel New voice channel to move to
|
* @param {Discord.VoiceChannel} channel New voice channel to move to
|
||||||
*/
|
*/
|
||||||
moveTo(message: Message, channel?: VoiceChannel): boolean {
|
moveTo(message: Message, channel?: VoiceChannel): boolean {
|
||||||
if (!channel || channel.type !== 'voice') return;
|
if (!channel || channel.type !== 'voice') return;
|
||||||
|
@ -577,7 +582,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause the playback
|
* Pause the playback
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
pause(message: Message): boolean {
|
pause(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -597,7 +602,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume the playback
|
* Resume the playback
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
resume(message: Message): boolean {
|
resume(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -617,7 +622,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the player
|
* Stops the player
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
stop(message: Message): boolean {
|
stop(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -641,8 +646,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets music volume
|
* Sets music volume
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param percent The volume percentage/amount to set
|
* @param {number} percent The volume percentage/amount to set
|
||||||
*/
|
*/
|
||||||
setVolume(message: Message, percent: number): boolean {
|
setVolume(message: Message, percent: number): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -663,7 +668,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the queue
|
* Clears the queue
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
clearQueue(message: Message): boolean {
|
clearQueue(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -679,7 +684,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays previous track
|
* Plays previous track
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
back(message: Message): boolean {
|
back(message: Message): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -701,8 +706,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets repeat mode
|
* Sets repeat mode
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param enabled If it should enable the repeat mode
|
* @param {boolean} enabled If it should enable the repeat mode
|
||||||
*/
|
*/
|
||||||
setRepeatMode(message: Message, enabled: boolean): boolean {
|
setRepeatMode(message: Message, enabled: boolean): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -718,8 +723,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets loop mode
|
* Sets loop mode
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param enabled If it should enable the loop mode
|
* @param {boolean} enabled If it should enable the loop mode
|
||||||
*/
|
*/
|
||||||
setLoopMode(message: Message, enabled: boolean): boolean {
|
setLoopMode(message: Message, enabled: boolean): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -735,7 +740,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns currently playing track
|
* Returns currently playing track
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
nowPlaying(message: Message): Track {
|
nowPlaying(message: Message): Track {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -749,7 +754,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuffles the queue
|
* Shuffles the queue
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
shuffle(message: Message): Queue {
|
shuffle(message: Message): Queue {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -772,8 +777,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes specified track
|
* Removes specified track
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param track The track object/id to remove
|
* @param {Track|number} track The track object/id to remove
|
||||||
*/
|
*/
|
||||||
remove(message: Message, track: Track | number): Track {
|
remove(message: Message, track: Track | number): Track {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -800,8 +805,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns time code of currently playing song
|
* Returns time code of currently playing song
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param queueTime If it should make the time code of the whole queue
|
* @param {boolean} [queueTime] If it should make the time code of the whole queue
|
||||||
*/
|
*/
|
||||||
getTimeCode(message: Message, queueTime?: boolean): { current: string; end: string } {
|
getTimeCode(message: Message, queueTime?: boolean): { current: string; end: string } {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -824,8 +829,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates progressbar
|
* Creates progressbar
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param options Progressbar options
|
* @param {PlayerProgressbarOptions} [options] Progressbar options
|
||||||
*/
|
*/
|
||||||
createProgressBar(message: Message, options?: PlayerProgressbarOptions): string {
|
createProgressBar(message: Message, options?: PlayerProgressbarOptions): string {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
@ -872,7 +877,7 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets lyrics of a song
|
* Gets lyrics of a song
|
||||||
* @param query Search query
|
* @param {string} query Search query
|
||||||
* @example const lyrics = await player.lyrics("alan walker faded")
|
* @example const lyrics = await player.lyrics("alan walker faded")
|
||||||
* message.channel.send(lyrics.lyrics);
|
* message.channel.send(lyrics.lyrics);
|
||||||
*/
|
*/
|
||||||
|
@ -888,8 +893,8 @@ export class Player extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle autoplay for youtube streams
|
* Toggle autoplay for youtube streams
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
* @param enable Enable/Disable autoplay
|
* @param {boolean} enable Enable/Disable autoplay
|
||||||
*/
|
*/
|
||||||
setAutoPlay(message: Message, enable: boolean): boolean {
|
setAutoPlay(message: Message, enable: boolean): boolean {
|
||||||
const queue = this.getQueue(message);
|
const queue = this.getQueue(message);
|
||||||
|
|
|
@ -6,12 +6,13 @@ class ExtractorModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for raw Discord Player extractors
|
* Model for raw Discord Player extractors
|
||||||
* @param extractorName Name of the extractor
|
* @param {string} extractorName Name of the extractor
|
||||||
* @param data Extractor object
|
* @param {Object} data Extractor object
|
||||||
*/
|
*/
|
||||||
constructor(extractorName: string, data: any) {
|
constructor(extractorName: string, data: any) {
|
||||||
/**
|
/**
|
||||||
* The extractor name
|
* The extractor name
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
this.name = extractorName;
|
this.name = extractorName;
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ class ExtractorModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to handle requests from `Player.play()`
|
* Method to handle requests from `Player.play()`
|
||||||
* @param query Query to handle
|
* @param {string} query Query to handle
|
||||||
*/
|
*/
|
||||||
async handle(query: string): Promise<ExtractorModelData> {
|
async handle(query: string): Promise<ExtractorModelData> {
|
||||||
const data = await this._raw.getInfo(query);
|
const data = await this._raw.getInfo(query);
|
||||||
|
@ -40,7 +41,7 @@ class ExtractorModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method used by Discord Player to validate query with this extractor
|
* Method used by Discord Player to validate query with this extractor
|
||||||
* @param query The query to validate
|
* @param {string} query The query to validate
|
||||||
*/
|
*/
|
||||||
validate(query: string): boolean {
|
validate(query: string): boolean {
|
||||||
return Boolean(this._raw.validate(query));
|
return Boolean(this._raw.validate(query));
|
||||||
|
@ -48,6 +49,7 @@ class ExtractorModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The extractor version
|
* The extractor version
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
get version(): string {
|
get version(): string {
|
||||||
return this._raw.version ?? '0.0.0';
|
return this._raw.version ?? '0.0.0';
|
||||||
|
@ -55,6 +57,7 @@ class ExtractorModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If player should mark this extractor as important
|
* If player should mark this extractor as important
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get important(): boolean {
|
get important(): boolean {
|
||||||
return Boolean(this._raw.important);
|
return Boolean(this._raw.important);
|
||||||
|
|
|
@ -24,12 +24,16 @@ export class Queue extends EventEmitter {
|
||||||
public filters: QueueFilters;
|
public filters: QueueFilters;
|
||||||
public additionalStreamTime: number;
|
public additionalStreamTime: number;
|
||||||
public firstMessage: Message;
|
public firstMessage: Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
public autoPlay = false;
|
public autoPlay = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue constructor
|
* Queue constructor
|
||||||
* @param player The player that instantiated this Queue
|
* @param {Player} player The player that instantiated this Queue
|
||||||
* @param message The message object
|
* @param {Discord.Message} message The message object
|
||||||
*/
|
*/
|
||||||
constructor(player: Player, message: Message) {
|
constructor(player: Player, message: Message) {
|
||||||
super();
|
super();
|
||||||
|
@ -38,66 +42,79 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID of the guild assigned to this queue
|
* ID of the guild assigned to this queue
|
||||||
|
* @type {Discord.Snowflake}
|
||||||
*/
|
*/
|
||||||
this.guildID = message.guild.id;
|
this.guildID = message.guild.id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The voice connection of this queue
|
* The voice connection of this queue
|
||||||
|
* @type {Discord.VoiceConnection}
|
||||||
*/
|
*/
|
||||||
this.voiceConnection = null;
|
this.voiceConnection = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks of this queue
|
* Tracks of this queue
|
||||||
|
* @type {Track[]}
|
||||||
*/
|
*/
|
||||||
this.tracks = [];
|
this.tracks = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Previous tracks of this queue
|
* Previous tracks of this queue
|
||||||
|
* @type {Track[]}
|
||||||
*/
|
*/
|
||||||
this.previousTracks = [];
|
this.previousTracks = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the player of this queue is stopped
|
* If the player of this queue is stopped
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.stopped = false;
|
this.stopped = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If last track was skipped
|
* If last track was skipped
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.lastSkipped = false;
|
this.lastSkipped = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue volume
|
* Queue volume
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.volume = 100;
|
this.volume = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the player of this queue is paused
|
* If the player of this queue is paused
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.paused = Boolean(this.voiceConnection?.dispatcher?.paused);
|
this.paused = Boolean(this.voiceConnection?.dispatcher?.paused);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If repeat mode is enabled in this queue
|
* If repeat mode is enabled in this queue
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.repeatMode = false;
|
this.repeatMode = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If loop mode is enabled in this queue
|
* If loop mode is enabled in this queue
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.loopMode = false;
|
this.loopMode = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The additional calculated stream time
|
* The additional calculated stream time
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.additionalStreamTime = 0;
|
this.additionalStreamTime = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The initial message object
|
* The initial message object
|
||||||
|
* @type {Discord.Message}
|
||||||
*/
|
*/
|
||||||
this.firstMessage = message;
|
this.firstMessage = message;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The audio filters in this queue
|
* The audio filters in this queue
|
||||||
|
* @type {QueueFilters}
|
||||||
*/
|
*/
|
||||||
this.filters = {};
|
this.filters = {};
|
||||||
|
|
||||||
|
@ -108,6 +125,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently playing track
|
* Currently playing track
|
||||||
|
* @type {Track}
|
||||||
*/
|
*/
|
||||||
get playing(): Track {
|
get playing(): Track {
|
||||||
return this.tracks[0];
|
return this.tracks[0];
|
||||||
|
@ -115,6 +133,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculated volume of this queue
|
* Calculated volume of this queue
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get calculatedVolume(): number {
|
get calculatedVolume(): number {
|
||||||
return this.filters.normalizer ? this.volume + 70 : this.volume;
|
return this.filters.normalizer ? this.volume + 70 : this.volume;
|
||||||
|
@ -122,6 +141,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total duration
|
* Total duration
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get totalTime(): number {
|
get totalTime(): number {
|
||||||
return this.tracks.length > 0 ? this.tracks.map((t) => t.durationMS).reduce((p, c) => p + c) : 0;
|
return this.tracks.length > 0 ? this.tracks.map((t) => t.durationMS).reduce((p, c) => p + c) : 0;
|
||||||
|
@ -129,6 +149,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current stream time
|
* Current stream time
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get currentStreamTime(): number {
|
get currentStreamTime(): number {
|
||||||
return this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0;
|
return this.voiceConnection?.dispatcher?.streamTime + this.additionalStreamTime || 0;
|
||||||
|
@ -136,7 +157,8 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets audio filters in this player
|
* Sets audio filters in this player
|
||||||
* @param filters Audio filters to set
|
* @param {QueueFilters} filters Audio filters to set
|
||||||
|
* @type {Promise<void>}
|
||||||
*/
|
*/
|
||||||
setFilters(filters: QueueFilters): Promise<void> {
|
setFilters(filters: QueueFilters): Promise<void> {
|
||||||
return this.player.setFilters(this.firstMessage, filters);
|
return this.player.setFilters(this.firstMessage, filters);
|
||||||
|
@ -144,6 +166,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns array of all enabled filters
|
* Returns array of all enabled filters
|
||||||
|
* @type {string[]}
|
||||||
*/
|
*/
|
||||||
getFiltersEnabled(): string[] {
|
getFiltersEnabled(): string[] {
|
||||||
const filters: string[] = [];
|
const filters: string[] = [];
|
||||||
|
@ -157,6 +180,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all disabled filters
|
* Returns all disabled filters
|
||||||
|
* @type {string[]}
|
||||||
*/
|
*/
|
||||||
getFiltersDisabled(): string[] {
|
getFiltersDisabled(): string[] {
|
||||||
const enabled = this.getFiltersEnabled();
|
const enabled = this.getFiltersEnabled();
|
||||||
|
@ -166,6 +190,7 @@ export class Queue extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String representation of this Queue
|
* String representation of this Queue
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `<Queue ${this.guildID}>`;
|
return `<Queue ${this.guildID}>`;
|
||||||
|
|
|
@ -6,63 +6,74 @@ import Queue from './Queue';
|
||||||
export class Track {
|
export class Track {
|
||||||
/**
|
/**
|
||||||
* The player that instantiated this Track
|
* The player that instantiated this Track
|
||||||
|
* @type {Player}
|
||||||
*/
|
*/
|
||||||
public player!: Player;
|
public player!: Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of this track
|
* Title of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public title!: string;
|
public title!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description of this track
|
* Description of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public description!: string;
|
public description!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author of this track
|
* Author of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public author!: string;
|
public author!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link of this track
|
* Link of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public url!: string;
|
public url!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thumbnail of this track
|
* Thumbnail of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public thumbnail!: string;
|
public thumbnail!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duration of this track
|
* Duration of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
public duration!: string;
|
public duration!: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View count of this track
|
* View count of this track
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
public views!: number;
|
public views!: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Person who requested this track
|
* Person who requested this track
|
||||||
|
* @type {Discord.User}
|
||||||
*/
|
*/
|
||||||
public requestedBy!: User;
|
public requestedBy!: User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this track belongs to a playlist
|
* If this track belongs to a playlist
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
public fromPlaylist!: boolean;
|
public fromPlaylist!: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw data of this track
|
* Raw data of this track
|
||||||
|
* @type {TrackData}
|
||||||
*/
|
*/
|
||||||
public raw!: TrackData;
|
public raw!: TrackData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Track constructor
|
* Track constructor
|
||||||
* @param player The player that instantiated this Track
|
* @param {Player} player The player that instantiated this Track
|
||||||
* @param data Track data
|
* @param {TrackData} data Track data
|
||||||
*/
|
*/
|
||||||
constructor(player: Player, data: TrackData) {
|
constructor(player: Player, data: TrackData) {
|
||||||
Object.defineProperty(this, 'player', { value: player, enumerable: false });
|
Object.defineProperty(this, 'player', { value: player, enumerable: false });
|
||||||
|
@ -87,6 +98,7 @@ export class Track {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The queue in which this track is located
|
* The queue in which this track is located
|
||||||
|
* @type {Queue}
|
||||||
*/
|
*/
|
||||||
get queue(): Queue {
|
get queue(): Queue {
|
||||||
return this.player.queues.find((q) => q.tracks.includes(this));
|
return this.player.queues.find((q) => q.tracks.includes(this));
|
||||||
|
@ -94,6 +106,7 @@ export class Track {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The track duration in millisecond
|
* The track duration in millisecond
|
||||||
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get durationMS(): number {
|
get durationMS(): number {
|
||||||
const times = (n: number, t: number) => {
|
const times = (n: number, t: number) => {
|
||||||
|
@ -111,6 +124,7 @@ export class Track {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String representation of this track
|
* String representation of this track
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `${this.title} by ${this.author}`;
|
return `${this.title} by ${this.author}`;
|
||||||
|
|
|
@ -47,11 +47,7 @@ const FilterList = {
|
||||||
return `${Object.values(this).join(',')}`;
|
return `${Object.values(this).join(',')}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
create(filter?: FiltersName[]): string {
|
||||||
* Creates single string of audio filters
|
|
||||||
* @param filter Array of AudioFilters name
|
|
||||||
*/
|
|
||||||
create(filter?: FiltersName[]) {
|
|
||||||
if (!filter || !Array.isArray(filter)) return this.toString();
|
if (!filter || !Array.isArray(filter)) return this.toString();
|
||||||
return filter
|
return filter
|
||||||
.filter((predicate) => typeof predicate === 'string')
|
.filter((predicate) => typeof predicate === 'string')
|
||||||
|
@ -59,27 +55,13 @@ const FilterList = {
|
||||||
.join(',');
|
.join(',');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
define(filterName: string, value: string): void {
|
||||||
* Defines custom filter
|
if (typeof this[filterName as FiltersName] && typeof this[filterName as FiltersName] === 'function') return;
|
||||||
* @param filterName The filter name
|
|
||||||
* @param value FFmpeg args to use with -af
|
|
||||||
* @example Player.AudioFilters.define("3D", "apulsator=hz=0.125")
|
|
||||||
*
|
|
||||||
* player.setFilters(message, { "3D": true })
|
|
||||||
*/
|
|
||||||
define(filterName: string, value: string) {
|
|
||||||
/* @ts-ignore */
|
|
||||||
if (typeof this[filterName] && typeof this[filterName] === 'function') return;
|
|
||||||
|
|
||||||
/* @ts-ignore */
|
this[filterName as FiltersName] = value;
|
||||||
this[filterName] = value;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
defineBulk(filterArray: { name: string; value: string }[]): void {
|
||||||
* Defines filters in bulk
|
|
||||||
* @param filterArray Array of filters containing object with `name` and `value` prop
|
|
||||||
*/
|
|
||||||
defineBulk(filterArray: { name: string; value: string }[]) {
|
|
||||||
filterArray.forEach((arr) => this.define(arr.name, arr.value));
|
filterArray.forEach((arr) => this.define(arr.name, arr.value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,10 +15,17 @@ const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/;
|
||||||
const attachmentRegex = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
|
const attachmentRegex = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
|
||||||
|
|
||||||
export class Util {
|
export class Util {
|
||||||
|
/**
|
||||||
|
* Static Player Util class
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
throw new Error(`The ${this.constructor.name} class is static and cannot be instantiated!`);
|
throw new Error(`The ${this.constructor.name} class is static and cannot be instantiated!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks FFmpeg Version
|
||||||
|
* @param {boolean} [force] If it should forcefully get the version
|
||||||
|
*/
|
||||||
static getFFmpegVersion(force?: boolean): string {
|
static getFFmpegVersion(force?: boolean): string {
|
||||||
try {
|
try {
|
||||||
const info = FFmpeg.getInfo(Boolean(force));
|
const info = FFmpeg.getInfo(Boolean(force));
|
||||||
|
@ -29,11 +36,18 @@ export class Util {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks FFmpeg
|
||||||
|
* @param {boolean} [force] If it should forcefully get the version
|
||||||
|
*/
|
||||||
static checkFFmpeg(force?: boolean): boolean {
|
static checkFFmpeg(force?: boolean): boolean {
|
||||||
const version = Util.getFFmpegVersion(force);
|
const version = Util.getFFmpegVersion(force);
|
||||||
return version === null ? false : true;
|
return version === null ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alerts if FFmpeg is not available
|
||||||
|
*/
|
||||||
static alertFFmpeg(): void {
|
static alertFFmpeg(): void {
|
||||||
const hasFFmpeg = Util.checkFFmpeg();
|
const hasFFmpeg = Util.checkFFmpeg();
|
||||||
|
|
||||||
|
@ -43,6 +57,10 @@ export class Util {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves query type
|
||||||
|
* @param {string} query The query
|
||||||
|
*/
|
||||||
static getQueryType(query: string): QueryType {
|
static getQueryType(query: string): QueryType {
|
||||||
if (SoundcloudValidateURL(query) && !query.includes('/sets/')) return 'soundcloud_track';
|
if (SoundcloudValidateURL(query) && !query.includes('/sets/')) return 'soundcloud_track';
|
||||||
if (SoundcloudValidateURL(query) && query.includes('/sets/')) return 'soundcloud_playlist';
|
if (SoundcloudValidateURL(query) && query.includes('/sets/')) return 'soundcloud_playlist';
|
||||||
|
@ -59,10 +77,18 @@ export class Util {
|
||||||
return 'youtube_search';
|
return 'youtube_search';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given string is url
|
||||||
|
* @param {string} str URL to check
|
||||||
|
*/
|
||||||
static isURL(str: string): boolean {
|
static isURL(str: string): boolean {
|
||||||
return str.length < 2083 && attachmentRegex.test(str);
|
return str.length < 2083 && attachmentRegex.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Vimeo ID
|
||||||
|
* @param {string} query Vimeo link
|
||||||
|
*/
|
||||||
static getVimeoID(query: string): string {
|
static getVimeoID(query: string): string {
|
||||||
return Util.getQueryType(query) === 'vimeo'
|
return Util.getQueryType(query) === 'vimeo'
|
||||||
? query
|
? query
|
||||||
|
@ -72,6 +98,10 @@ export class Util {
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses ms time
|
||||||
|
* @param {number} milliseconds Time to parse
|
||||||
|
*/
|
||||||
static parseMS(milliseconds: number): TimeData {
|
static parseMS(milliseconds: number): TimeData {
|
||||||
const roundTowardsZero = milliseconds > 0 ? Math.floor : Math.ceil;
|
const roundTowardsZero = milliseconds > 0 ? Math.floor : Math.ceil;
|
||||||
|
|
||||||
|
@ -83,12 +113,22 @@ export class Util {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates simple duration string
|
||||||
|
* @param {object} durObj Duration object
|
||||||
|
*/
|
||||||
static durationString(durObj: object): string {
|
static durationString(durObj: object): string {
|
||||||
return Object.values(durObj)
|
return Object.values(durObj)
|
||||||
.map((m) => (isNaN(m) ? 0 : m))
|
.map((m) => (isNaN(m) ? 0 : m))
|
||||||
.join(':');
|
.join(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes youtube searches
|
||||||
|
* @param {string} query The query
|
||||||
|
* @param {any} options Options
|
||||||
|
* @returns {Promise<Track[]>}
|
||||||
|
*/
|
||||||
static ytSearch(query: string, options?: any): Promise<Track[]> {
|
static ytSearch(query: string, options?: any): Promise<Track[]> {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
await YouTube.search(query, {
|
await YouTube.search(query, {
|
||||||
|
@ -119,6 +159,9 @@ export class Util {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this system is running in replit.com
|
||||||
|
*/
|
||||||
static isRepl(): boolean {
|
static isRepl(): boolean {
|
||||||
if ('DP_REPL_NOCHECK' in process.env) return false;
|
if ('DP_REPL_NOCHECK' in process.env) return false;
|
||||||
|
|
||||||
|
@ -137,10 +180,18 @@ export class Util {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given voice channel is empty
|
||||||
|
* @param {Discord.VoiceChannel} channel The voice channel
|
||||||
|
*/
|
||||||
static isVoiceEmpty(channel: VoiceChannel): boolean {
|
static isVoiceEmpty(channel: VoiceChannel): boolean {
|
||||||
return channel.members.filter((member) => !member.user.bot).size === 0;
|
return channel.members.filter((member) => !member.user.bot).size === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds time code
|
||||||
|
* @param {object} data The data to build time code from
|
||||||
|
*/
|
||||||
static buildTimeCode(data: any): string {
|
static buildTimeCode(data: any): string {
|
||||||
const items = Object.keys(data);
|
const items = Object.keys(data);
|
||||||
const required = ['days', 'hours', 'minutes', 'seconds'];
|
const required = ['days', 'hours', 'minutes', 'seconds'];
|
||||||
|
@ -155,7 +206,7 @@ export class Util {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage CJS require
|
* Manage CJS require
|
||||||
* @param id id to require
|
* @param {string} id id to require
|
||||||
*/
|
*/
|
||||||
static require(id: string): any {
|
static require(id: string): any {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue