distube 3.0.0-beta.9 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +64 -51
- package/dist/DisTube.d.ts +522 -0
- package/dist/DisTube.d.ts.map +1 -0
- package/dist/DisTube.js +794 -0
- package/dist/DisTube.js.map +1 -0
- package/dist/constant.d.ts +130 -0
- package/dist/constant.d.ts.map +1 -0
- package/dist/constant.js +150 -0
- package/dist/constant.js.map +1 -0
- package/dist/core/DisTubeBase.d.ts +55 -0
- package/dist/core/DisTubeBase.d.ts.map +1 -0
- package/dist/core/DisTubeBase.js +76 -0
- package/dist/core/DisTubeBase.js.map +1 -0
- package/dist/core/DisTubeHandler.d.ts +95 -0
- package/dist/core/DisTubeHandler.d.ts.map +1 -0
- package/dist/core/DisTubeHandler.js +337 -0
- package/dist/core/DisTubeHandler.js.map +1 -0
- package/dist/core/DisTubeOptions.d.ts +26 -0
- package/dist/core/DisTubeOptions.d.ts.map +1 -0
- package/dist/core/DisTubeOptions.js +93 -0
- package/dist/core/DisTubeOptions.js.map +1 -0
- package/dist/core/DisTubeStream.d.ts +52 -0
- package/dist/core/DisTubeStream.d.ts.map +1 -0
- package/dist/core/DisTubeStream.js +109 -0
- package/dist/core/DisTubeStream.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +19 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/manager/BaseManager.d.ts +18 -0
- package/dist/core/manager/BaseManager.d.ts.map +1 -0
- package/dist/core/manager/BaseManager.js +44 -0
- package/dist/core/manager/BaseManager.js.map +1 -0
- package/dist/core/manager/QueueManager.d.ts +60 -0
- package/dist/core/manager/QueueManager.d.ts.map +1 -0
- package/dist/core/manager/QueueManager.js +202 -0
- package/dist/core/manager/QueueManager.js.map +1 -0
- package/dist/core/manager/index.d.ts +3 -0
- package/dist/core/manager/index.d.ts.map +1 -0
- package/dist/core/manager/index.js +15 -0
- package/dist/core/manager/index.js.map +1 -0
- package/dist/core/voice/DJSAdapter.d.ts +4 -0
- package/dist/core/voice/DJSAdapter.d.ts.map +1 -0
- package/dist/core/voice/DJSAdapter.js +61 -0
- package/dist/core/voice/DJSAdapter.js.map +1 -0
- package/dist/core/voice/DisTubeVoice.d.ts +85 -0
- package/dist/core/voice/DisTubeVoice.d.ts.map +1 -0
- package/dist/core/voice/DisTubeVoice.js +246 -0
- package/dist/core/voice/DisTubeVoice.js.map +1 -0
- package/dist/core/voice/DisTubeVoiceManager.d.ts +41 -0
- package/dist/core/voice/DisTubeVoiceManager.d.ts.map +1 -0
- package/dist/core/voice/DisTubeVoiceManager.js +67 -0
- package/dist/core/voice/DisTubeVoiceManager.js.map +1 -0
- package/dist/core/voice/index.d.ts +4 -0
- package/dist/core/voice/index.d.ts.map +1 -0
- package/dist/core/voice/index.js +16 -0
- package/dist/core/voice/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/http.d.ts +8 -0
- package/dist/plugin/http.d.ts.map +1 -0
- package/dist/plugin/http.js +20 -0
- package/dist/plugin/http.js.map +1 -0
- package/dist/plugin/https.d.ts +14 -0
- package/dist/plugin/https.d.ts.map +1 -0
- package/dist/plugin/https.js +50 -0
- package/dist/plugin/https.js.map +1 -0
- package/dist/plugin/index.d.ts +4 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +16 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/youtube-dl.d.ts +11 -0
- package/dist/plugin/youtube-dl.d.ts.map +1 -0
- package/dist/plugin/youtube-dl.js +75 -0
- package/dist/plugin/youtube-dl.js.map +1 -0
- package/dist/struct/CustomPlugin.d.ts +27 -0
- package/dist/struct/CustomPlugin.d.ts.map +1 -0
- package/dist/struct/CustomPlugin.js +35 -0
- package/dist/struct/CustomPlugin.js.map +1 -0
- package/dist/struct/DisTubeError.d.ts +56 -0
- package/dist/struct/DisTubeError.d.ts.map +1 -0
- package/dist/struct/DisTubeError.js +75 -0
- package/dist/struct/DisTubeError.js.map +1 -0
- package/dist/struct/ExtractorPlugin.d.ts +29 -0
- package/dist/struct/ExtractorPlugin.d.ts.map +1 -0
- package/dist/struct/ExtractorPlugin.js +32 -0
- package/dist/struct/ExtractorPlugin.js.map +1 -0
- package/dist/struct/Playlist.d.ts +42 -0
- package/dist/struct/Playlist.d.ts.map +1 -0
- package/dist/struct/Playlist.js +104 -0
- package/dist/struct/Playlist.js.map +1 -0
- package/dist/struct/Plugin.d.ts +82 -0
- package/dist/struct/Plugin.d.ts.map +1 -0
- package/dist/struct/Plugin.js +108 -0
- package/dist/struct/Plugin.js.map +1 -0
- package/dist/struct/Queue.d.ts +217 -0
- package/dist/struct/Queue.d.ts.map +1 -0
- package/dist/struct/Queue.js +481 -0
- package/dist/struct/Queue.js.map +1 -0
- package/dist/struct/SearchResult.d.ts +28 -0
- package/dist/struct/SearchResult.d.ts.map +1 -0
- package/dist/struct/SearchResult.js +79 -0
- package/dist/struct/SearchResult.js.map +1 -0
- package/dist/struct/Song.d.ts +68 -0
- package/dist/struct/Song.d.ts.map +1 -0
- package/dist/struct/Song.js +229 -0
- package/dist/struct/Song.js.map +1 -0
- package/dist/struct/TaskQueue.d.ts +33 -0
- package/dist/struct/TaskQueue.d.ts.map +1 -0
- package/dist/struct/TaskQueue.js +58 -0
- package/dist/struct/TaskQueue.js.map +1 -0
- package/dist/struct/index.d.ts +10 -0
- package/dist/struct/index.d.ts.map +1 -0
- package/dist/struct/index.js +22 -0
- package/dist/struct/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/type.d.ts +159 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/type.js +3 -0
- package/dist/type.js.map +1 -0
- package/dist/util.d.ts +47 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +205 -0
- package/dist/util.js.map +1 -0
- package/package.json +88 -62
- package/src/DisTube.js +0 -851
- package/src/DisTubeBase.js +0 -39
- package/src/DisTubeHandler.js +0 -440
- package/src/DisTubeOptions.js +0 -82
- package/src/Filter.js +0 -36
- package/src/Playlist.js +0 -75
- package/src/Plugin/CustomPlugin.js +0 -26
- package/src/Plugin/ExtractorPlugin.js +0 -25
- package/src/Plugin/Plugin.js +0 -36
- package/src/Plugin/http.js +0 -27
- package/src/Plugin/https.js +0 -27
- package/src/Queue.js +0 -340
- package/src/SearchResult.js +0 -57
- package/src/Song.js +0 -169
- package/src/util.js +0 -65
- package/typings/DisTube.d.ts +0 -553
- package/typings/DisTubeBase.d.ts +0 -31
- package/typings/DisTubeHandler.d.ts +0 -130
- package/typings/DisTubeOptions.d.ts +0 -5
- package/typings/Filter.d.ts +0 -83
- package/typings/Playlist.d.ts +0 -58
- package/typings/Plugin/CustomPlugin.d.ts +0 -21
- package/typings/Plugin/ExtractorPlugin.d.ts +0 -20
- package/typings/Plugin/Plugin.d.ts +0 -31
- package/typings/Plugin/http.d.ts +0 -4
- package/typings/Plugin/https.d.ts +0 -4
- package/typings/Queue.d.ts +0 -227
- package/typings/SearchResult.d.ts +0 -51
- package/typings/Song.d.ts +0 -153
- package/typings/util.d.ts +0 -6
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
const Plugin = require("./Plugin");
|
|
3
|
-
const Discord = require("discord.js");
|
|
4
|
-
const Song = require("../Song");
|
|
5
|
-
const Playlist = require("../Playlist");
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Extractor Plugin
|
|
9
|
-
* @extends Plugin
|
|
10
|
-
*/
|
|
11
|
-
class ExtractorPlugin extends Plugin {
|
|
12
|
-
/** Create a extractor plugin */
|
|
13
|
-
constructor() {
|
|
14
|
-
super("extractor");
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Execute if the url is validated
|
|
18
|
-
* @param {string} url URL
|
|
19
|
-
* @param {Discord.GuildMember} member Requested user
|
|
20
|
-
* @returns {Promise<Song|Song[]|Playlist>}
|
|
21
|
-
*/
|
|
22
|
-
async resolve(url, member) { }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = ExtractorPlugin;
|
package/src/Plugin/Plugin.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
const DisTube = require("../DisTube");
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* DisTube Plugin
|
|
6
|
-
* @private
|
|
7
|
-
*/
|
|
8
|
-
class Plugin {
|
|
9
|
-
constructor(type) {
|
|
10
|
-
/**
|
|
11
|
-
* Type of plugin (`"custom"` | `"extractor"`)
|
|
12
|
-
* @type {string}
|
|
13
|
-
*/
|
|
14
|
-
this.type = type;
|
|
15
|
-
}
|
|
16
|
-
init(distube) {
|
|
17
|
-
/**
|
|
18
|
-
* DisTube
|
|
19
|
-
* @type {DisTube}
|
|
20
|
-
*/
|
|
21
|
-
this.distube = distube;
|
|
22
|
-
/**
|
|
23
|
-
* Handler
|
|
24
|
-
* @type {DisTubeHandler}
|
|
25
|
-
*/
|
|
26
|
-
this.handler = this.distube.handler;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Check if the url is working with this plugin
|
|
30
|
-
* @param {string} url Input url
|
|
31
|
-
* @returns {Promise<boolean>}
|
|
32
|
-
*/
|
|
33
|
-
async validate(url) { return false }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = Plugin;
|
package/src/Plugin/http.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const { ExtractorPlugin, Song } = require("../DisTube");
|
|
2
|
-
const http = require("http");
|
|
3
|
-
const { URL } = require("url");
|
|
4
|
-
const getResponseHeaders = url => new Promise((resolve, reject) => {
|
|
5
|
-
http.get(url)
|
|
6
|
-
.on("response", res => resolve(res.headers))
|
|
7
|
-
.on("error", reject);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
class HTTPPlugin extends ExtractorPlugin {
|
|
11
|
-
async validate(url) {
|
|
12
|
-
if (new URL(url).protocol.toLowerCase() !== "http:") return false;
|
|
13
|
-
const headers = await getResponseHeaders(url);
|
|
14
|
-
const type = headers["content-type"];
|
|
15
|
-
if (type.startsWith("audio")) return true;
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
resolve(url, member) {
|
|
19
|
-
url = url.replace(/\/+$/, "");
|
|
20
|
-
return new Song({
|
|
21
|
-
name: url.substring(url.lastIndexOf("/") + 1).replace(/((\?|#).*)?$/, ""),
|
|
22
|
-
url,
|
|
23
|
-
}, member, "http");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = HTTPPlugin;
|
package/src/Plugin/https.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const { ExtractorPlugin, Song } = require("../DisTube");
|
|
2
|
-
const https = require("https");
|
|
3
|
-
const { URL } = require("url");
|
|
4
|
-
const getResponseHeaders = url => new Promise((resolve, reject) => {
|
|
5
|
-
https.get(url)
|
|
6
|
-
.on("response", res => resolve(res.headers))
|
|
7
|
-
.on("error", reject);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
class HTTPSPlugin extends ExtractorPlugin {
|
|
11
|
-
async validate(url) {
|
|
12
|
-
if (new URL(url).protocol.toLowerCase() !== "https:") return false;
|
|
13
|
-
const headers = await getResponseHeaders(url);
|
|
14
|
-
const type = headers["content-type"];
|
|
15
|
-
if (type.startsWith("audio")) return true;
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
resolve(url, member) {
|
|
19
|
-
url = url.replace(/\/+$/, "");
|
|
20
|
-
return new Song({
|
|
21
|
-
name: url.substring(url.lastIndexOf("/") + 1).replace(/((\?|#).*)?$/, ""),
|
|
22
|
-
url,
|
|
23
|
-
}, member, "https");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = HTTPSPlugin;
|
package/src/Queue.js
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
const { formatDuration } = require("./util"),
|
|
2
|
-
Song = require("./Song"),
|
|
3
|
-
DisTubeBase = require("./DisTubeBase"),
|
|
4
|
-
// eslint-disable-next-line no-unused-vars
|
|
5
|
-
Discord = require("discord.js"),
|
|
6
|
-
// eslint-disable-next-line no-unused-vars
|
|
7
|
-
{ Readable } = require("stream"),
|
|
8
|
-
// eslint-disable-next-line no-unused-vars
|
|
9
|
-
DisTubeHandler = require("./DisTubeHandler");
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Represents a queue.
|
|
13
|
-
* @extends DisTubeBase
|
|
14
|
-
*/
|
|
15
|
-
class Queue extends DisTubeBase {
|
|
16
|
-
constructor(distube, message, song, textChannel = null) {
|
|
17
|
-
super(distube);
|
|
18
|
-
/**
|
|
19
|
-
* Queue id (Guild id)
|
|
20
|
-
* @type {Discord.Snowflake}
|
|
21
|
-
*/
|
|
22
|
-
this.id = message.guild.id;
|
|
23
|
-
/**
|
|
24
|
-
* Stream dispatcher.
|
|
25
|
-
* @type {Discord.StreamDispatcher?}
|
|
26
|
-
*/
|
|
27
|
-
this.dispatcher = null;
|
|
28
|
-
/**
|
|
29
|
-
* Voice connection.
|
|
30
|
-
* @type {Discord.VoiceConnection?}
|
|
31
|
-
*/
|
|
32
|
-
this.connection = null;
|
|
33
|
-
/**
|
|
34
|
-
* Stream volume. Default value: `50`.
|
|
35
|
-
* @type {number}
|
|
36
|
-
*/
|
|
37
|
-
this.volume = 50;
|
|
38
|
-
/**
|
|
39
|
-
* List of songs in the queue (The first one is the playing song)
|
|
40
|
-
* @type {Array<Song>}
|
|
41
|
-
*/
|
|
42
|
-
this.songs = Array.isArray(song) ? song : [song];
|
|
43
|
-
if (this.options.savePreviousSongs) {
|
|
44
|
-
/**
|
|
45
|
-
* List of the previous songs.
|
|
46
|
-
* @type {Array<Song>?}
|
|
47
|
-
*/
|
|
48
|
-
this.previousSongs = [];
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Whether stream is currently stopped.
|
|
52
|
-
* @type {boolean}
|
|
53
|
-
* @private
|
|
54
|
-
*/
|
|
55
|
-
this.stopped = false;
|
|
56
|
-
/**
|
|
57
|
-
* Whether or not the last song was skipped to next song.
|
|
58
|
-
* @type {boolean}
|
|
59
|
-
* @private
|
|
60
|
-
*/
|
|
61
|
-
this.next = false;
|
|
62
|
-
/**
|
|
63
|
-
* Whether or not the last song was skipped to previous song.
|
|
64
|
-
* @type {boolean}
|
|
65
|
-
* @private
|
|
66
|
-
*/
|
|
67
|
-
this.prev = false;
|
|
68
|
-
/**
|
|
69
|
-
* Whether or not the stream is currently playing.
|
|
70
|
-
* @type {boolean}
|
|
71
|
-
*/
|
|
72
|
-
this.playing = true;
|
|
73
|
-
/**
|
|
74
|
-
* Whether or not the stream is currently paused.
|
|
75
|
-
* @type {boolean}
|
|
76
|
-
*/
|
|
77
|
-
this.paused = false;
|
|
78
|
-
/**
|
|
79
|
-
* Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating all the queue).
|
|
80
|
-
* Default value: `0` (disabled)
|
|
81
|
-
* @type {number}
|
|
82
|
-
*/
|
|
83
|
-
this.repeatMode = 0;
|
|
84
|
-
/**
|
|
85
|
-
* Whether or not the autoplay mode is enabled.
|
|
86
|
-
* Default value: `false`
|
|
87
|
-
* @type {boolean}
|
|
88
|
-
*/
|
|
89
|
-
this.autoplay = false;
|
|
90
|
-
/**
|
|
91
|
-
* Enabled audio filters.
|
|
92
|
-
* Available filters: {@link Filters}
|
|
93
|
-
* @type {Array<string>}
|
|
94
|
-
*/
|
|
95
|
-
this.filters = [];
|
|
96
|
-
/**
|
|
97
|
-
* Should be an opus stream
|
|
98
|
-
* @type {Readable?}
|
|
99
|
-
* @private
|
|
100
|
-
*/
|
|
101
|
-
this.stream = null;
|
|
102
|
-
/**
|
|
103
|
-
* What time in the song to begin (in seconds).
|
|
104
|
-
* @type {number}
|
|
105
|
-
*/
|
|
106
|
-
this.beginTime = 0;
|
|
107
|
-
/**
|
|
108
|
-
* The text channel of the Queue. (Default: where the first command is called).
|
|
109
|
-
* @type {Discord.TextChannel?}
|
|
110
|
-
*/
|
|
111
|
-
this.textChannel = message?.channel || textChannel;
|
|
112
|
-
/**
|
|
113
|
-
* @type {DisTubeHandler}
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
this.handler = this.distube.handler;
|
|
117
|
-
/**
|
|
118
|
-
* Timeout for checking empty channel
|
|
119
|
-
* @type {NodeJS.Timeout?}
|
|
120
|
-
* @private
|
|
121
|
-
*/
|
|
122
|
-
this.emptyTimeout = null;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Formatted duration string.
|
|
126
|
-
* @type {string}
|
|
127
|
-
*/
|
|
128
|
-
get formattedDuration() {
|
|
129
|
-
return formatDuration(this.duration);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Queue's duration.
|
|
133
|
-
* @type {number}
|
|
134
|
-
*/
|
|
135
|
-
get duration() {
|
|
136
|
-
return this.songs.length ? this.songs.reduce((prev, next) => prev + next.duration, 0) : 0;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* What time in the song is playing (in seconds).
|
|
140
|
-
* @type {number}
|
|
141
|
-
*/
|
|
142
|
-
get currentTime() {
|
|
143
|
-
return this.dispatcher ? (this.dispatcher.streamTime / 1000) + this.beginTime : 0;
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Formatted {@link Queue#currentTime} string.
|
|
147
|
-
* @type {string}
|
|
148
|
-
*/
|
|
149
|
-
get formattedCurrentTime() {
|
|
150
|
-
return formatDuration(this.currentTime);
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* The voice channel playing in.
|
|
154
|
-
* @type {Discord.VoiceChannel|Discord.StageChannel}
|
|
155
|
-
*/
|
|
156
|
-
get voiceChannel() {
|
|
157
|
-
return this.connection?.voice?.channel;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Add a Song or an array of Song to the queue
|
|
161
|
-
* @param {Song|Array<Song>} song Song to add
|
|
162
|
-
* @param {boolean} [unshift=false] Unshift?
|
|
163
|
-
* @throws {Error}
|
|
164
|
-
* @returns {Queue}
|
|
165
|
-
*/
|
|
166
|
-
addToQueue(song, unshift = false) {
|
|
167
|
-
const isArray = Array.isArray(song);
|
|
168
|
-
if (!song || (isArray && !song.length)) throw new Error("No Song provided.");
|
|
169
|
-
if (unshift) {
|
|
170
|
-
const playing = this.songs.shift();
|
|
171
|
-
if (isArray) this.songs.unshift(playing, ...song);
|
|
172
|
-
else this.songs.unshift(playing, song);
|
|
173
|
-
} else if (isArray) this.songs.push(...song);
|
|
174
|
-
else this.songs.push(song);
|
|
175
|
-
return this;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Pause the guild stream
|
|
179
|
-
* @returns {Queue} The guild queue
|
|
180
|
-
*/
|
|
181
|
-
pause() {
|
|
182
|
-
this.playing = false;
|
|
183
|
-
this.paused = true;
|
|
184
|
-
this.dispatcher.pause();
|
|
185
|
-
return this;
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Resume the guild stream
|
|
189
|
-
* @returns {Queue} The guild queue
|
|
190
|
-
*/
|
|
191
|
-
resume() {
|
|
192
|
-
this.playing = true;
|
|
193
|
-
this.paused = false;
|
|
194
|
-
this.dispatcher.resume();
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Stop the guild stream
|
|
199
|
-
*/
|
|
200
|
-
stop() {
|
|
201
|
-
this.stopped = true;
|
|
202
|
-
try { this.dispatcher?.end() } catch { }
|
|
203
|
-
if (this.options.leaveOnStop) try { this.connection?.channel?.leave() } catch { }
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Set the guild stream's volume
|
|
207
|
-
* @param {number} percent The percentage of volume you want to set
|
|
208
|
-
* @returns {Queue} The guild queue
|
|
209
|
-
*/
|
|
210
|
-
setVolume(percent) {
|
|
211
|
-
if (typeof percent !== "number") throw new Error("Volume percent must be a number.");
|
|
212
|
-
this.volume = percent;
|
|
213
|
-
this.dispatcher.setVolume(this.volume / 100);
|
|
214
|
-
return this;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Skip the playing song
|
|
219
|
-
* @returns {Song} The song will skip to
|
|
220
|
-
* @throws {Error}
|
|
221
|
-
*/
|
|
222
|
-
skip() {
|
|
223
|
-
if (this.songs.length <= 1 && !this.autoplay) throw new Error("There is no song to skip.");
|
|
224
|
-
const song = this.songs[1];
|
|
225
|
-
this.next = true;
|
|
226
|
-
this.dispatcher.end();
|
|
227
|
-
return song;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Play the previous song
|
|
232
|
-
* @returns {Song} The guild queue
|
|
233
|
-
* @throws {Error}
|
|
234
|
-
*/
|
|
235
|
-
previous() {
|
|
236
|
-
if (!this.options.savePreviousSongs) throw new Error("savePreviousSongs is disabled.");
|
|
237
|
-
if (this.previousSongs?.length === 0 && this.repeatMode !== 2) throw new Error("There is no previous song.");
|
|
238
|
-
const song = this.repeatMode === 2 ? this.songs[this.songs.length - 1] : this.previousSongs[this.previousSongs.length - 1];
|
|
239
|
-
this.prev = true;
|
|
240
|
-
this.dispatcher.end();
|
|
241
|
-
return song;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Shuffle the queue's songs
|
|
245
|
-
* @returns {Queue} The guild queue
|
|
246
|
-
*/
|
|
247
|
-
shuffle() {
|
|
248
|
-
const playing = this.songs.shift();
|
|
249
|
-
for (let i = this.songs.length - 1; i > 0; i--) {
|
|
250
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
251
|
-
[this.songs[i], this.songs[j]] = [this.songs[j], this.songs[i]];
|
|
252
|
-
}
|
|
253
|
-
this.songs.unshift(playing);
|
|
254
|
-
return this;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Jump to the song number in the queue.
|
|
258
|
-
* The next one is 1, 2,...
|
|
259
|
-
* The previous one is -1, -2,...
|
|
260
|
-
* @param {number} num The song number to play
|
|
261
|
-
* @returns {Queue} The guild queue
|
|
262
|
-
* @throws {InvalidSong} if `num` is invalid number (0 < num < {@link Queue#songs}.length)
|
|
263
|
-
*/
|
|
264
|
-
jump(num) {
|
|
265
|
-
if (num > this.songs.length || -num > this.previousSongs.length || num === 0) throw new RangeError("InvalidSong");
|
|
266
|
-
if (num > 0) {
|
|
267
|
-
this.songs = this.songs.splice(num - 1);
|
|
268
|
-
this.next = true;
|
|
269
|
-
} else if (num === -1) this.prev = true;
|
|
270
|
-
else {
|
|
271
|
-
this.songs.unshift(...this.previousSongs.splice(num + 1));
|
|
272
|
-
this.prev = true;
|
|
273
|
-
}
|
|
274
|
-
if (this.dispatcher) this.dispatcher.end();
|
|
275
|
-
return this;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Set the repeat mode of the guild queue.
|
|
279
|
-
* Turn off if repeat mode is the same value as new mode.
|
|
280
|
-
* Toggle mode: `mode = null` `(0 -> 1 -> 2 -> 0...)`
|
|
281
|
-
* @param {number?} [mode] The repeat modes `(0: disabled, 1: Repeat a song, 2: Repeat all the queue)`
|
|
282
|
-
* @returns {number} The new repeat mode
|
|
283
|
-
*/
|
|
284
|
-
setRepeatMode(mode = null) {
|
|
285
|
-
mode = parseInt(mode, 10);
|
|
286
|
-
if (!mode && mode !== 0) this.repeatMode = (this.repeatMode + 1) % 3;
|
|
287
|
-
else if (this.repeatMode === mode) this.repeatMode = 0;
|
|
288
|
-
else this.repeatMode = mode;
|
|
289
|
-
return this.repeatMode;
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Enable or disable filter of the queue.
|
|
293
|
-
* Available filters: {@link Filters}
|
|
294
|
-
* @param {string|false} filter A filter name, `false` to clear all the filters
|
|
295
|
-
* @returns {Array<string>} Enabled filters.
|
|
296
|
-
* @throws {Error}
|
|
297
|
-
*/
|
|
298
|
-
setFilter(filter) {
|
|
299
|
-
if (filter === false) this.filters = [];
|
|
300
|
-
else if (!Object.prototype.hasOwnProperty.call(this.distube.filters, filter)) throw new TypeError(`${filter} is not a filter name.`);
|
|
301
|
-
else if (this.filters.includes(filter)) this.filters = this.filters.filter(f => f !== filter);
|
|
302
|
-
else this.filters.push(filter);
|
|
303
|
-
this.beginTime = this.currentTime;
|
|
304
|
-
this.handler.playSong(this);
|
|
305
|
-
return this.filters;
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Set the playing time to another position
|
|
309
|
-
* @param {number} time Time in seconds
|
|
310
|
-
* @returns {Queue}
|
|
311
|
-
*/
|
|
312
|
-
seek(time) {
|
|
313
|
-
this.beginTime = time;
|
|
314
|
-
this.handler.playSong(this);
|
|
315
|
-
return this;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Add a related song to the queue
|
|
319
|
-
* @param {Song} [song] A song to get the related one
|
|
320
|
-
* @returns {Promise<Queue>} The guild queue
|
|
321
|
-
* @throws {Error}
|
|
322
|
-
*/
|
|
323
|
-
async addRelatedVideo(song = this.songs[0]) {
|
|
324
|
-
const related = (await this.handler.getRelatedVideo(song))
|
|
325
|
-
.find(v => !this.previousSongs.map(s => s.id).includes(v.id));
|
|
326
|
-
if (!related) throw new Error("Cannot find any related songs.");
|
|
327
|
-
this.addToQueue(new Song(await this.handler.getYouTubeInfo(related.id), this.voiceChannel?.guild?.me));
|
|
328
|
-
return this;
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Toggle autoplay mode
|
|
332
|
-
* @returns {boolean} Autoplay mode state
|
|
333
|
-
*/
|
|
334
|
-
toggleAutoplay() {
|
|
335
|
-
this.autoplay = !this.autoplay;
|
|
336
|
-
return this.autoplay;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
module.exports = Queue;
|
package/src/SearchResult.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const { toSecond, formatDuration } = require("./util");
|
|
2
|
-
|
|
3
|
-
/** Class representing a search result. */
|
|
4
|
-
class SearchResult {
|
|
5
|
-
constructor(info) {
|
|
6
|
-
this.source = "youtube";
|
|
7
|
-
/**
|
|
8
|
-
* Type of SearchResult (video or playlist)
|
|
9
|
-
* @type {string}
|
|
10
|
-
*/
|
|
11
|
-
this.type = info.type;
|
|
12
|
-
/**
|
|
13
|
-
* YouTube video or playlist id
|
|
14
|
-
* @type {string}
|
|
15
|
-
*/
|
|
16
|
-
this.id = info.id;
|
|
17
|
-
/**
|
|
18
|
-
* Video or playlist title.
|
|
19
|
-
* @type {string}
|
|
20
|
-
*/
|
|
21
|
-
this.name = info.name;
|
|
22
|
-
/**
|
|
23
|
-
* Video or playlist URL.
|
|
24
|
-
* @type {string}
|
|
25
|
-
*/
|
|
26
|
-
this.url = info.url;
|
|
27
|
-
/**
|
|
28
|
-
* Video / Playlist views count
|
|
29
|
-
* @type {number}
|
|
30
|
-
*/
|
|
31
|
-
this.views = info.views;
|
|
32
|
-
if (this.type === "video") {
|
|
33
|
-
/**
|
|
34
|
-
* Indicates if the video is an active live.
|
|
35
|
-
* @type {boolean?}
|
|
36
|
-
*/
|
|
37
|
-
this.isLive = info.isLive;
|
|
38
|
-
/**
|
|
39
|
-
* Video duration.
|
|
40
|
-
* @type {number}
|
|
41
|
-
*/
|
|
42
|
-
this.duration = this.isLive ? 0 : toSecond(info.duration);
|
|
43
|
-
/**
|
|
44
|
-
* Formatted duration string `hh:mm:ss` or `mm:ss`.
|
|
45
|
-
* @type {string}
|
|
46
|
-
*/
|
|
47
|
-
this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
|
|
48
|
-
/**
|
|
49
|
-
* Video thumbnail.
|
|
50
|
-
* @type {string?}
|
|
51
|
-
*/
|
|
52
|
-
this.thumbnail = info.thumbnail;
|
|
53
|
-
} else if (this.type !== "playlist") throw new TypeError("Unsupported info");
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
module.exports = SearchResult;
|
package/src/Song.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
const { formatDuration, toSecond, parseNumber } = require("./util"),
|
|
2
|
-
ytdl = require("ytdl-core"),
|
|
3
|
-
Playlist = require("./Playlist"),
|
|
4
|
-
// eslint-disable-next-line no-unused-vars
|
|
5
|
-
Discord = require("discord.js");
|
|
6
|
-
|
|
7
|
-
/** Class representing a song. */
|
|
8
|
-
class Song {
|
|
9
|
-
/**
|
|
10
|
-
* Create a Song
|
|
11
|
-
* @param {ytdl.videoInfo|Object} info Raw info
|
|
12
|
-
* @param {Discord.GuildMember} member Requested user
|
|
13
|
-
* @param {string} src Song source
|
|
14
|
-
*/
|
|
15
|
-
constructor(info, member = null, src = "youtube") {
|
|
16
|
-
if (typeof src !== "string") throw new TypeError("Source must be a string");
|
|
17
|
-
/**
|
|
18
|
-
* The source of the song
|
|
19
|
-
* @type {string}
|
|
20
|
-
*/
|
|
21
|
-
this.source = src;
|
|
22
|
-
/**
|
|
23
|
-
* User requested
|
|
24
|
-
* @type {Discord.GuildMember?}
|
|
25
|
-
*/
|
|
26
|
-
this.member = member;
|
|
27
|
-
/**
|
|
28
|
-
* User requested
|
|
29
|
-
* @type {Discord.User?}
|
|
30
|
-
*/
|
|
31
|
-
this.user = this.member?.user;
|
|
32
|
-
if (this.source === "youtube" && info.full) {
|
|
33
|
-
/**
|
|
34
|
-
* `ytdl-core` raw info (If the song is from YouTube)
|
|
35
|
-
* @type {ytdl.videoInfo?}
|
|
36
|
-
* @private
|
|
37
|
-
*/
|
|
38
|
-
this.info = info;
|
|
39
|
-
info = info.videoDetails;
|
|
40
|
-
}
|
|
41
|
-
this._patch(info);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Patch data
|
|
46
|
-
* @param {ytdl.MoreVideoDetails|Object} info Video info
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
_patch(info) {
|
|
50
|
-
/**
|
|
51
|
-
* YouTube video id
|
|
52
|
-
* @type {string}
|
|
53
|
-
*/
|
|
54
|
-
this.id = info.videoId || info.id;
|
|
55
|
-
/**
|
|
56
|
-
* Song name aka video title.
|
|
57
|
-
* @type {string}
|
|
58
|
-
*/
|
|
59
|
-
this.name = info.title || info.name;
|
|
60
|
-
/**
|
|
61
|
-
* Indicates if the video is an active live.
|
|
62
|
-
* @type {boolean}
|
|
63
|
-
*/
|
|
64
|
-
this.isLive = info.isLive || info.is_live || false;
|
|
65
|
-
/**
|
|
66
|
-
* Song duration.
|
|
67
|
-
* @type {number}
|
|
68
|
-
*/
|
|
69
|
-
this.duration = this.isLive ? 0 : toSecond(info.lengthSeconds || info._duration_raw || info.duration);
|
|
70
|
-
/**
|
|
71
|
-
* Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).
|
|
72
|
-
* @type {string}
|
|
73
|
-
*/
|
|
74
|
-
this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
|
|
75
|
-
/**
|
|
76
|
-
* Song URL.
|
|
77
|
-
* @type {string}
|
|
78
|
-
*/
|
|
79
|
-
this.url = this.source === "youtube" ? `https://www.youtube.com/watch?v=${this.id}` : info.webpage_url || info.url;
|
|
80
|
-
/**
|
|
81
|
-
* Stream / Download URL.
|
|
82
|
-
* @type {string?}
|
|
83
|
-
*/
|
|
84
|
-
this.streamURL = this.info?.formats.length ? ytdl.chooseFormat(this.info.formats, {
|
|
85
|
-
filter: this.isLive ? "audioandvideo" : "audioonly",
|
|
86
|
-
quality: "highestaudio",
|
|
87
|
-
}).url : info.url;
|
|
88
|
-
/**
|
|
89
|
-
* Song thumbnail.
|
|
90
|
-
* @type {string?}
|
|
91
|
-
*/
|
|
92
|
-
this.thumbnail = info.thumbnails?.sort((a, b) => b.width - a.width)[0].url ||
|
|
93
|
-
info.thumbnail?.url || info.thumbnail || null;
|
|
94
|
-
/**
|
|
95
|
-
* Related videos (Only available with YouTube video)
|
|
96
|
-
* @type {Array<ytdl.relatedVideo>?}
|
|
97
|
-
*/
|
|
98
|
-
this.related = this.info?.related_videos;
|
|
99
|
-
/**
|
|
100
|
-
* Song views count
|
|
101
|
-
* @type {number}
|
|
102
|
-
*/
|
|
103
|
-
this.views = parseNumber(info.viewCount || info.view_count || info.views);
|
|
104
|
-
/**
|
|
105
|
-
* Song like count
|
|
106
|
-
* @type {number}
|
|
107
|
-
*/
|
|
108
|
-
this.likes = parseNumber(info.likes || info.like_count);
|
|
109
|
-
/**
|
|
110
|
-
* Song dislike count
|
|
111
|
-
* @type {number}
|
|
112
|
-
*/
|
|
113
|
-
this.dislikes = parseNumber(info.dislikes || info.dislike_count);
|
|
114
|
-
/**
|
|
115
|
-
* Song repost count
|
|
116
|
-
* @type {number}
|
|
117
|
-
*/
|
|
118
|
-
this.reposts = parseNumber(info.repost_count);
|
|
119
|
-
/**
|
|
120
|
-
* Song uploader
|
|
121
|
-
* @type {Object}
|
|
122
|
-
* @prop {string?} name Uploader name
|
|
123
|
-
* @prop {string?} url Uploader url
|
|
124
|
-
*/
|
|
125
|
-
this.uploader = {
|
|
126
|
-
name: info.author?.name || info.uploader || null,
|
|
127
|
-
url: info.author?.channel_url || info.uploader_url || null,
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* Whether or not an age-restricted content
|
|
131
|
-
* @type {boolean}
|
|
132
|
-
*/
|
|
133
|
-
this.age_restricted = info.age_restricted ||
|
|
134
|
-
(info.age_limit && parseNumber(info.age_limit) >= 18) ||
|
|
135
|
-
(typeof info.media?.notice === "string" && (
|
|
136
|
-
info.media.notice.includes("Age-restricted") || info.media.notice.includes("age-restricted")
|
|
137
|
-
)) || false;
|
|
138
|
-
/**
|
|
139
|
-
* @typedef {Object} Chapter
|
|
140
|
-
* @prop {string} title Chapter title
|
|
141
|
-
* @prop {number} start_time Chapter start time in seconds
|
|
142
|
-
*/
|
|
143
|
-
/**
|
|
144
|
-
* Chapters information (YouTube only)
|
|
145
|
-
* @type {Chapter[]}
|
|
146
|
-
*/
|
|
147
|
-
this.chapters = info.chapters || [];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* @param {Playlist} playlist Playlist
|
|
152
|
-
* @param {Discord.GuildMember} [member] User requested
|
|
153
|
-
* @private
|
|
154
|
-
* @returns {Song}
|
|
155
|
-
*/
|
|
156
|
-
_patchPlaylist(playlist, member = this.member) {
|
|
157
|
-
if (!(playlist instanceof Playlist)) throw new TypeError("playlist is not a valid Playlist");
|
|
158
|
-
/**
|
|
159
|
-
* The playlist added this song
|
|
160
|
-
* @type {Playlist?}
|
|
161
|
-
*/
|
|
162
|
-
this.playlist = playlist;
|
|
163
|
-
this.member = member;
|
|
164
|
-
this.user = this.member?.user;
|
|
165
|
-
return this;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
module.exports = Song;
|