distube 4.2.1 → 5.0.0
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/README.md +8 -6
- package/dist/index.d.ts +464 -987
- package/dist/index.js +905 -1664
- package/dist/index.js.map +1 -1
- package/package.json +21 -26
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __typeError = (msg) => {
|
|
7
|
+
throw TypeError(msg);
|
|
8
|
+
};
|
|
8
9
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
10
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
11
|
var __commonJS = (cb, mod) => function __require() {
|
|
@@ -22,49 +23,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
22
23
|
}
|
|
23
24
|
return to;
|
|
24
25
|
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
-
mod
|
|
32
|
-
));
|
|
33
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
|
-
var __publicField = (obj, key, value) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
throw TypeError("Cannot " + msg);
|
|
41
|
-
};
|
|
42
|
-
var __privateGet = (obj, member, getter) => {
|
|
43
|
-
__accessCheck(obj, member, "read from private field");
|
|
44
|
-
return getter ? getter.call(obj) : member.get(obj);
|
|
45
|
-
};
|
|
46
|
-
var __privateAdd = (obj, member, value) => {
|
|
47
|
-
if (member.has(obj))
|
|
48
|
-
throw TypeError("Cannot add the same private member more than once");
|
|
49
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
50
|
-
};
|
|
51
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
52
|
-
__accessCheck(obj, member, "write to private field");
|
|
53
|
-
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
54
|
-
return value;
|
|
55
|
-
};
|
|
56
|
-
var __privateMethod = (obj, member, method) => {
|
|
57
|
-
__accessCheck(obj, member, "access private method");
|
|
58
|
-
return method;
|
|
59
|
-
};
|
|
27
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
28
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
29
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
30
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
31
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
32
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
60
33
|
|
|
61
34
|
// package.json
|
|
62
35
|
var require_package = __commonJS({
|
|
63
36
|
"package.json"(exports2, module2) {
|
|
64
37
|
module2.exports = {
|
|
65
38
|
name: "distube",
|
|
66
|
-
version: "
|
|
67
|
-
description: "A Discord.js module
|
|
39
|
+
version: "5.0.0",
|
|
40
|
+
description: "A powerful Discord.js module for simplifying music commands and effortless playback of various sources with integrated audio filters.",
|
|
68
41
|
main: "./dist/index.js",
|
|
69
42
|
types: "./dist/index.d.ts",
|
|
70
43
|
exports: "./dist/index.js",
|
|
@@ -83,11 +56,10 @@ var require_package = __commonJS({
|
|
|
83
56
|
prettier: 'prettier --write "**/*.{ts,json,yml,yaml,md}"',
|
|
84
57
|
build: "tsup",
|
|
85
58
|
"build:check": "tsc --noEmit",
|
|
86
|
-
update:
|
|
87
|
-
|
|
59
|
+
update: 'pnpm up -L "!eslint"',
|
|
60
|
+
prepare: "husky",
|
|
88
61
|
prepublishOnly: "pnpm run lint && pnpm run test",
|
|
89
|
-
prepack: "pnpm run build
|
|
90
|
-
postpack: "pinst --enable",
|
|
62
|
+
prepack: "pnpm run build",
|
|
91
63
|
"dev:add-docs-to-worktree": "git worktree add --track -b docs docs origin/docs"
|
|
92
64
|
},
|
|
93
65
|
repository: {
|
|
@@ -112,42 +84,38 @@ var require_package = __commonJS({
|
|
|
112
84
|
bugs: {
|
|
113
85
|
url: "https://github.com/skick1234/DisTube/issues"
|
|
114
86
|
},
|
|
115
|
-
funding: "https://github.com/skick1234/DisTube?sponsor
|
|
87
|
+
funding: "https://github.com/skick1234/DisTube?sponsor",
|
|
116
88
|
homepage: "https://distube.js.org/",
|
|
117
89
|
dependencies: {
|
|
118
|
-
"@distube/ytdl-core": "^4.13.3",
|
|
119
|
-
"@distube/ytpl": "^1.2.1",
|
|
120
|
-
"@distube/ytsr": "^2.0.0",
|
|
121
90
|
"tiny-typed-emitter": "^2.1.0",
|
|
122
|
-
|
|
123
|
-
tslib: "^2.6.2",
|
|
124
|
-
undici: "^6.13.0"
|
|
91
|
+
undici: "^6.18.2"
|
|
125
92
|
},
|
|
126
93
|
devDependencies: {
|
|
127
|
-
"@babel/core": "^7.24.
|
|
128
|
-
"@babel/plugin-transform-class-properties": "^7.24.
|
|
129
|
-
"@babel/plugin-transform-object-rest-spread": "^7.24.
|
|
130
|
-
"@babel/plugin-transform-private-methods": "^7.24.
|
|
131
|
-
"@babel/preset-env": "^7.24.
|
|
132
|
-
"@babel/preset-typescript": "^7.24.
|
|
133
|
-
"@commitlint/cli": "^19.
|
|
94
|
+
"@babel/core": "^7.24.6",
|
|
95
|
+
"@babel/plugin-transform-class-properties": "^7.24.6",
|
|
96
|
+
"@babel/plugin-transform-object-rest-spread": "^7.24.6",
|
|
97
|
+
"@babel/plugin-transform-private-methods": "^7.24.6",
|
|
98
|
+
"@babel/preset-env": "^7.24.6",
|
|
99
|
+
"@babel/preset-typescript": "^7.24.6",
|
|
100
|
+
"@commitlint/cli": "^19.3.0",
|
|
134
101
|
"@commitlint/config-conventional": "^19.2.2",
|
|
135
|
-
"@discordjs/voice": "^0.
|
|
102
|
+
"@discordjs/voice": "^0.17.0",
|
|
136
103
|
"@types/jest": "^29.5.12",
|
|
137
|
-
"@types/node": "^20.
|
|
104
|
+
"@types/node": "^20.14.1",
|
|
138
105
|
"@types/tough-cookie": "^4.0.5",
|
|
139
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
140
|
-
"@typescript-eslint/parser": "^7.
|
|
106
|
+
"@typescript-eslint/eslint-plugin": "^7.12.0",
|
|
107
|
+
"@typescript-eslint/parser": "^7.12.0",
|
|
141
108
|
"babel-jest": "^29.7.0",
|
|
142
|
-
"discord.js": "^14.
|
|
109
|
+
"discord.js": "^14.15.3",
|
|
143
110
|
eslint: "^8.57.0",
|
|
144
111
|
"eslint-config-distube": "^1.7.0",
|
|
145
112
|
husky: "^9.0.11",
|
|
146
113
|
jest: "^29.7.0",
|
|
147
114
|
"nano-staged": "^0.8.0",
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
115
|
+
prettier: "^3.3.0",
|
|
116
|
+
"sodium-native": "^4.1.1",
|
|
117
|
+
"ts-node": "^10.9.2",
|
|
118
|
+
tsup: "^8.1.0",
|
|
151
119
|
typedoc: "^0.25.13",
|
|
152
120
|
"typedoc-material-theme": "^1.0.2",
|
|
153
121
|
typescript: "^5.4.5"
|
|
@@ -176,8 +144,6 @@ var require_package = __commonJS({
|
|
|
176
144
|
var src_exports = {};
|
|
177
145
|
__export(src_exports, {
|
|
178
146
|
BaseManager: () => BaseManager,
|
|
179
|
-
CustomPlugin: () => CustomPlugin,
|
|
180
|
-
DirectLinkPlugin: () => DirectLinkPlugin,
|
|
181
147
|
DisTube: () => DisTube,
|
|
182
148
|
DisTubeBase: () => DisTubeBase,
|
|
183
149
|
DisTubeError: () => DisTubeError,
|
|
@@ -189,23 +155,20 @@ __export(src_exports, {
|
|
|
189
155
|
ExtractorPlugin: () => ExtractorPlugin,
|
|
190
156
|
FilterManager: () => FilterManager,
|
|
191
157
|
GuildIdManager: () => GuildIdManager,
|
|
158
|
+
InfoExtractorPlugin: () => InfoExtractorPlugin,
|
|
192
159
|
Options: () => Options,
|
|
160
|
+
PlayableExtractorPlugin: () => PlayableExtractorPlugin,
|
|
193
161
|
Playlist: () => Playlist,
|
|
194
162
|
Plugin: () => Plugin,
|
|
195
163
|
PluginType: () => PluginType,
|
|
196
164
|
Queue: () => Queue,
|
|
197
165
|
QueueManager: () => QueueManager,
|
|
198
166
|
RepeatMode: () => RepeatMode,
|
|
199
|
-
SearchResultPlaylist: () => SearchResultPlaylist,
|
|
200
|
-
SearchResultType: () => SearchResultType,
|
|
201
|
-
SearchResultVideo: () => SearchResultVideo,
|
|
202
167
|
Song: () => Song,
|
|
203
|
-
StreamType: () => StreamType,
|
|
204
168
|
TaskQueue: () => TaskQueue,
|
|
205
169
|
checkFFmpeg: () => checkFFmpeg,
|
|
206
170
|
checkIntents: () => checkIntents,
|
|
207
171
|
checkInvalidKey: () => checkInvalidKey,
|
|
208
|
-
chooseBestVideoFormat: () => chooseBestVideoFormat,
|
|
209
172
|
default: () => DisTube,
|
|
210
173
|
defaultFilters: () => defaultFilters,
|
|
211
174
|
defaultOptions: () => defaultOptions,
|
|
@@ -216,7 +179,6 @@ __export(src_exports, {
|
|
|
216
179
|
isMessageInstance: () => isMessageInstance,
|
|
217
180
|
isNsfwChannel: () => isNsfwChannel,
|
|
218
181
|
isObject: () => isObject,
|
|
219
|
-
isRecord: () => isRecord,
|
|
220
182
|
isSnowflake: () => isSnowflake,
|
|
221
183
|
isSupportedVoiceChannel: () => isSupportedVoiceChannel,
|
|
222
184
|
isTextChannelInstance: () => isTextChannelInstance,
|
|
@@ -224,35 +186,12 @@ __export(src_exports, {
|
|
|
224
186
|
isURL: () => isURL,
|
|
225
187
|
isVoiceChannelEmpty: () => isVoiceChannelEmpty,
|
|
226
188
|
objectKeys: () => objectKeys,
|
|
227
|
-
parseNumber: () => parseNumber,
|
|
228
189
|
resolveGuildId: () => resolveGuildId,
|
|
229
|
-
toSecond: () => toSecond,
|
|
230
190
|
version: () => version
|
|
231
191
|
});
|
|
232
192
|
module.exports = __toCommonJS(src_exports);
|
|
233
193
|
|
|
234
194
|
// src/type.ts
|
|
235
|
-
var RepeatMode = /* @__PURE__ */ ((RepeatMode2) => {
|
|
236
|
-
RepeatMode2[RepeatMode2["DISABLED"] = 0] = "DISABLED";
|
|
237
|
-
RepeatMode2[RepeatMode2["SONG"] = 1] = "SONG";
|
|
238
|
-
RepeatMode2[RepeatMode2["QUEUE"] = 2] = "QUEUE";
|
|
239
|
-
return RepeatMode2;
|
|
240
|
-
})(RepeatMode || {});
|
|
241
|
-
var PluginType = /* @__PURE__ */ ((PluginType2) => {
|
|
242
|
-
PluginType2["CUSTOM"] = "custom";
|
|
243
|
-
PluginType2["EXTRACTOR"] = "extractor";
|
|
244
|
-
return PluginType2;
|
|
245
|
-
})(PluginType || {});
|
|
246
|
-
var SearchResultType = /* @__PURE__ */ ((SearchResultType2) => {
|
|
247
|
-
SearchResultType2["VIDEO"] = "video";
|
|
248
|
-
SearchResultType2["PLAYLIST"] = "playlist";
|
|
249
|
-
return SearchResultType2;
|
|
250
|
-
})(SearchResultType || {});
|
|
251
|
-
var StreamType = /* @__PURE__ */ ((StreamType2) => {
|
|
252
|
-
StreamType2[StreamType2["OPUS"] = 0] = "OPUS";
|
|
253
|
-
StreamType2[StreamType2["RAW"] = 1] = "RAW";
|
|
254
|
-
return StreamType2;
|
|
255
|
-
})(StreamType || {});
|
|
256
195
|
var Events = /* @__PURE__ */ ((Events2) => {
|
|
257
196
|
Events2["ERROR"] = "error";
|
|
258
197
|
Events2["ADD_LIST"] = "addList";
|
|
@@ -265,14 +204,22 @@ var Events = /* @__PURE__ */ ((Events2) => {
|
|
|
265
204
|
Events2["NO_RELATED"] = "noRelated";
|
|
266
205
|
Events2["DISCONNECT"] = "disconnect";
|
|
267
206
|
Events2["DELETE_QUEUE"] = "deleteQueue";
|
|
268
|
-
Events2["SEARCH_CANCEL"] = "searchCancel";
|
|
269
|
-
Events2["SEARCH_NO_RESULT"] = "searchNoResult";
|
|
270
|
-
Events2["SEARCH_DONE"] = "searchDone";
|
|
271
|
-
Events2["SEARCH_INVALID_ANSWER"] = "searchInvalidAnswer";
|
|
272
|
-
Events2["SEARCH_RESULT"] = "searchResult";
|
|
273
207
|
Events2["FFMPEG_DEBUG"] = "ffmpegDebug";
|
|
208
|
+
Events2["DEBUG"] = "debug";
|
|
274
209
|
return Events2;
|
|
275
210
|
})(Events || {});
|
|
211
|
+
var RepeatMode = /* @__PURE__ */ ((RepeatMode2) => {
|
|
212
|
+
RepeatMode2[RepeatMode2["DISABLED"] = 0] = "DISABLED";
|
|
213
|
+
RepeatMode2[RepeatMode2["SONG"] = 1] = "SONG";
|
|
214
|
+
RepeatMode2[RepeatMode2["QUEUE"] = 2] = "QUEUE";
|
|
215
|
+
return RepeatMode2;
|
|
216
|
+
})(RepeatMode || {});
|
|
217
|
+
var PluginType = /* @__PURE__ */ ((PluginType2) => {
|
|
218
|
+
PluginType2["EXTRACTOR"] = "extractor";
|
|
219
|
+
PluginType2["INFO_EXTRACTOR"] = "info-extractor";
|
|
220
|
+
PluginType2["PLAYABLE_EXTRACTOR"] = "playable-extractor";
|
|
221
|
+
return PluginType2;
|
|
222
|
+
})(PluginType || {});
|
|
276
223
|
|
|
277
224
|
// src/constant.ts
|
|
278
225
|
var defaultFilters = {
|
|
@@ -295,62 +242,59 @@ var defaultFilters = {
|
|
|
295
242
|
var defaultOptions = {
|
|
296
243
|
plugins: [],
|
|
297
244
|
emitNewSongOnly: false,
|
|
298
|
-
leaveOnEmpty: true,
|
|
299
|
-
leaveOnFinish: false,
|
|
300
|
-
leaveOnStop: true,
|
|
301
245
|
savePreviousSongs: true,
|
|
302
|
-
searchSongs: 0,
|
|
303
|
-
ytdlOptions: {},
|
|
304
|
-
searchCooldown: 60,
|
|
305
|
-
emptyCooldown: 60,
|
|
306
246
|
nsfw: false,
|
|
307
247
|
emitAddSongWhenCreatingQueue: true,
|
|
308
248
|
emitAddListWhenCreatingQueue: true,
|
|
309
|
-
joinNewVoiceChannel: true
|
|
310
|
-
streamType: 0 /* OPUS */,
|
|
311
|
-
directLink: true
|
|
249
|
+
joinNewVoiceChannel: true
|
|
312
250
|
};
|
|
313
251
|
|
|
314
252
|
// src/struct/DisTubeError.ts
|
|
315
253
|
var import_node_util = require("util");
|
|
316
254
|
var ERROR_MESSAGES = {
|
|
317
|
-
INVALID_TYPE: (expected, got, name) => `Expected ${Array.isArray(expected) ? expected.map((e) => typeof e === "number" ? e : `'${e}'`).join(" or ") : `'${expected}'`}${name ? ` for '${name}'` : ""}, but got ${(0, import_node_util.inspect)(got)} (${typeof got})`,
|
|
318
|
-
NUMBER_COMPARE: (name, expected, value) => `'${name}' must be ${expected} ${value}`,
|
|
319
|
-
EMPTY_ARRAY: (name) => `'${name}' is an empty array`,
|
|
320
|
-
EMPTY_FILTERED_ARRAY: (name, type) => `There is no valid '${type}' in the '${name}' array`,
|
|
321
|
-
EMPTY_STRING: (name) => `'${name}' string must not be empty`,
|
|
322
|
-
INVALID_KEY: (obj, key) => `'${key}' does not need to be provided in ${obj}`,
|
|
323
|
-
MISSING_KEY: (obj, key) => `'${key}' needs to be provided in ${obj}`,
|
|
324
|
-
MISSING_KEYS: (obj, key, all) => `${key.map((k) => `'${k}'`).join(all ? " and " : " or ")} need to be provided in ${obj}`,
|
|
325
|
-
MISSING_INTENTS: (i) => `${i} intent must be provided for the Client`,
|
|
326
|
-
DISABLED_OPTION: (o) => `DisTubeOptions.${o} is disabled`,
|
|
327
|
-
ENABLED_OPTION: (o) => `DisTubeOptions.${o} is enabled`,
|
|
255
|
+
INVALID_TYPE: /* @__PURE__ */ __name((expected, got, name) => `Expected ${Array.isArray(expected) ? expected.map((e) => typeof e === "number" ? e : `'${e}'`).join(" or ") : `'${expected}'`}${name ? ` for '${name}'` : ""}, but got ${(0, import_node_util.inspect)(got)} (${typeof got})`, "INVALID_TYPE"),
|
|
256
|
+
NUMBER_COMPARE: /* @__PURE__ */ __name((name, expected, value) => `'${name}' must be ${expected} ${value}`, "NUMBER_COMPARE"),
|
|
257
|
+
EMPTY_ARRAY: /* @__PURE__ */ __name((name) => `'${name}' is an empty array`, "EMPTY_ARRAY"),
|
|
258
|
+
EMPTY_FILTERED_ARRAY: /* @__PURE__ */ __name((name, type) => `There is no valid '${type}' in the '${name}' array`, "EMPTY_FILTERED_ARRAY"),
|
|
259
|
+
EMPTY_STRING: /* @__PURE__ */ __name((name) => `'${name}' string must not be empty`, "EMPTY_STRING"),
|
|
260
|
+
INVALID_KEY: /* @__PURE__ */ __name((obj, key) => `'${key}' does not need to be provided in ${obj}`, "INVALID_KEY"),
|
|
261
|
+
MISSING_KEY: /* @__PURE__ */ __name((obj, key) => `'${key}' needs to be provided in ${obj}`, "MISSING_KEY"),
|
|
262
|
+
MISSING_KEYS: /* @__PURE__ */ __name((obj, key, all) => `${key.map((k) => `'${k}'`).join(all ? " and " : " or ")} need to be provided in ${obj}`, "MISSING_KEYS"),
|
|
263
|
+
MISSING_INTENTS: /* @__PURE__ */ __name((i) => `${i} intent must be provided for the Client`, "MISSING_INTENTS"),
|
|
264
|
+
DISABLED_OPTION: /* @__PURE__ */ __name((o) => `DisTubeOptions.${o} is disabled`, "DISABLED_OPTION"),
|
|
265
|
+
ENABLED_OPTION: /* @__PURE__ */ __name((o) => `DisTubeOptions.${o} is enabled`, "ENABLED_OPTION"),
|
|
328
266
|
NOT_IN_VOICE: "User is not in any voice channel",
|
|
329
267
|
VOICE_FULL: "The voice channel is full",
|
|
330
|
-
|
|
268
|
+
VOICE_ALREADY_CREATED: "This guild already has a voice connection which is not managed by DisTube",
|
|
269
|
+
VOICE_CONNECT_FAILED: /* @__PURE__ */ __name((s) => `Cannot connect to the voice channel after ${s} seconds`, "VOICE_CONNECT_FAILED"),
|
|
331
270
|
VOICE_MISSING_PERMS: "I do not have permission to join this voice channel",
|
|
332
271
|
VOICE_RECONNECT_FAILED: "Cannot reconnect to the voice channel",
|
|
333
272
|
VOICE_DIFFERENT_GUILD: "Cannot join a voice channel in a different guild",
|
|
334
273
|
VOICE_DIFFERENT_CLIENT: "Cannot join a voice channel created by a different client",
|
|
335
|
-
FFMPEG_EXITED: (code) => `ffmpeg exited with code ${code}`,
|
|
336
|
-
FFMPEG_NOT_INSTALLED: (path) => `ffmpeg is not installed at '${path}' path`,
|
|
274
|
+
FFMPEG_EXITED: /* @__PURE__ */ __name((code) => `ffmpeg exited with code ${code}`, "FFMPEG_EXITED"),
|
|
275
|
+
FFMPEG_NOT_INSTALLED: /* @__PURE__ */ __name((path) => `ffmpeg is not installed at '${path}' path`, "FFMPEG_NOT_INSTALLED"),
|
|
337
276
|
NO_QUEUE: "There is no playing queue in this guild",
|
|
338
277
|
QUEUE_EXIST: "This guild has a Queue already",
|
|
278
|
+
QUEUE_STOPPED: "The queue has been stopped already",
|
|
339
279
|
PAUSED: "The queue has been paused already",
|
|
340
280
|
RESUMED: "The queue has been playing already",
|
|
341
281
|
NO_PREVIOUS: "There is no previous song in this queue",
|
|
342
282
|
NO_UP_NEXT: "There is no up next song",
|
|
343
283
|
NO_SONG_POSITION: "Does not have any song at this position",
|
|
344
|
-
|
|
345
|
-
NO_RESULT: "No result found",
|
|
284
|
+
NO_PLAYING_SONG: "There is no playing song in the queue",
|
|
346
285
|
NO_RELATED: "Cannot find any related songs",
|
|
347
286
|
CANNOT_PLAY_RELATED: "Cannot play the related song",
|
|
348
287
|
UNAVAILABLE_VIDEO: "This video is unavailable",
|
|
349
288
|
UNPLAYABLE_FORMATS: "No playable format found",
|
|
350
289
|
NON_NSFW: "Cannot play age-restricted content in non-NSFW channel",
|
|
351
290
|
NOT_SUPPORTED_URL: "This url is not supported",
|
|
352
|
-
|
|
353
|
-
NO_VALID_SONG: "'songs' array does not have any valid Song
|
|
291
|
+
NOT_SUPPORTED_SONG: /* @__PURE__ */ __name((song) => `There is no plugin supporting this song (${song})`, "NOT_SUPPORTED_SONG"),
|
|
292
|
+
NO_VALID_SONG: "'songs' array does not have any valid Song or url",
|
|
293
|
+
CANNOT_RESOLVE_SONG: /* @__PURE__ */ __name((t) => `Cannot resolve ${(0, import_node_util.inspect)(t)} to a Song`, "CANNOT_RESOLVE_SONG"),
|
|
294
|
+
CANNOT_GET_STREAM_URL: /* @__PURE__ */ __name((song) => `Cannot get stream url from this song (${song})`, "CANNOT_GET_STREAM_URL"),
|
|
295
|
+
CANNOT_GET_SEARCH_QUERY: /* @__PURE__ */ __name((song) => `Cannot get search query from this song (${song})`, "CANNOT_GET_SEARCH_QUERY"),
|
|
296
|
+
NO_RESULT: /* @__PURE__ */ __name((query) => `Cannot get song stream from this query (${query})`, "NO_RESULT"),
|
|
297
|
+
NO_STREAM_URL: /* @__PURE__ */ __name((song) => `No stream url attached (${song})`, "NO_STREAM_URL"),
|
|
354
298
|
EMPTY_FILTERED_PLAYLIST: "There is no valid video in the playlist\nMaybe age-restricted contents is filtered because you are in non-NSFW channel",
|
|
355
299
|
EMPTY_PLAYLIST: "There is no valid video in the playlist"
|
|
356
300
|
};
|
|
@@ -362,8 +306,7 @@ var _DisTubeError = class _DisTubeError extends Error {
|
|
|
362
306
|
super(getErrorMessage(code, ...args));
|
|
363
307
|
__publicField(this, "errorCode");
|
|
364
308
|
this.errorCode = code;
|
|
365
|
-
if (Error.captureStackTrace)
|
|
366
|
-
Error.captureStackTrace(this, _DisTubeError);
|
|
309
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, _DisTubeError);
|
|
367
310
|
}
|
|
368
311
|
get name() {
|
|
369
312
|
return `DisTubeError [${this.errorCode}]`;
|
|
@@ -377,11 +320,9 @@ var DisTubeError = _DisTubeError;
|
|
|
377
320
|
|
|
378
321
|
// src/struct/TaskQueue.ts
|
|
379
322
|
var _Task = class _Task {
|
|
380
|
-
constructor(
|
|
323
|
+
constructor() {
|
|
381
324
|
__publicField(this, "resolve");
|
|
382
325
|
__publicField(this, "promise");
|
|
383
|
-
__publicField(this, "resolveInfo");
|
|
384
|
-
this.resolveInfo = resolveInfo;
|
|
385
326
|
this.promise = new Promise((res) => {
|
|
386
327
|
this.resolve = res;
|
|
387
328
|
});
|
|
@@ -399,12 +340,10 @@ var _TaskQueue = class _TaskQueue {
|
|
|
399
340
|
}
|
|
400
341
|
/**
|
|
401
342
|
* Waits for last task finished and queues a new task
|
|
402
|
-
*
|
|
403
|
-
* @param resolveInfo - Whether the task is a resolving info task
|
|
404
343
|
*/
|
|
405
|
-
queuing(
|
|
344
|
+
queuing() {
|
|
406
345
|
const next = this.remaining ? __privateGet(this, _tasks)[__privateGet(this, _tasks).length - 1].promise : Promise.resolve();
|
|
407
|
-
__privateGet(this, _tasks).push(new Task(
|
|
346
|
+
__privateGet(this, _tasks).push(new Task());
|
|
408
347
|
return next;
|
|
409
348
|
}
|
|
410
349
|
/**
|
|
@@ -419,12 +358,6 @@ var _TaskQueue = class _TaskQueue {
|
|
|
419
358
|
get remaining() {
|
|
420
359
|
return __privateGet(this, _tasks).length;
|
|
421
360
|
}
|
|
422
|
-
/**
|
|
423
|
-
* Whether or not having a resolving info task
|
|
424
|
-
*/
|
|
425
|
-
get hasResolveTask() {
|
|
426
|
-
return __privateGet(this, _tasks).some((t) => t.resolveInfo);
|
|
427
|
-
}
|
|
428
361
|
};
|
|
429
362
|
_tasks = new WeakMap();
|
|
430
363
|
__name(_TaskQueue, "TaskQueue");
|
|
@@ -434,49 +367,46 @@ var TaskQueue = _TaskQueue;
|
|
|
434
367
|
var _metadata, _member;
|
|
435
368
|
var _Playlist = class _Playlist {
|
|
436
369
|
/**
|
|
437
|
-
* Create a
|
|
438
|
-
*
|
|
439
|
-
* @param
|
|
440
|
-
* @param options - Optional options
|
|
370
|
+
* Create a Playlist
|
|
371
|
+
* @param playlist - Raw playlist info
|
|
372
|
+
* @param options - Optional data
|
|
441
373
|
*/
|
|
442
|
-
constructor(playlist,
|
|
374
|
+
constructor(playlist, { member, metadata } = {}) {
|
|
375
|
+
/**
|
|
376
|
+
* Playlist source.
|
|
377
|
+
*/
|
|
443
378
|
__publicField(this, "source");
|
|
379
|
+
/**
|
|
380
|
+
* Songs in the playlist.
|
|
381
|
+
*/
|
|
444
382
|
__publicField(this, "songs");
|
|
383
|
+
/**
|
|
384
|
+
* Playlist ID.
|
|
385
|
+
*/
|
|
386
|
+
__publicField(this, "id");
|
|
387
|
+
/**
|
|
388
|
+
* Playlist name.
|
|
389
|
+
*/
|
|
445
390
|
__publicField(this, "name");
|
|
446
|
-
|
|
447
|
-
|
|
391
|
+
/**
|
|
392
|
+
* Playlist URL.
|
|
393
|
+
*/
|
|
448
394
|
__publicField(this, "url");
|
|
395
|
+
/**
|
|
396
|
+
* Playlist thumbnail.
|
|
397
|
+
*/
|
|
449
398
|
__publicField(this, "thumbnail");
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
this.songs = playlist;
|
|
462
|
-
this.name = this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`;
|
|
463
|
-
this.thumbnail = this.songs[0].thumbnail;
|
|
464
|
-
this.member = member;
|
|
465
|
-
} else {
|
|
466
|
-
this.source = playlist.source.toLowerCase();
|
|
467
|
-
if (!Array.isArray(playlist.songs) || !playlist.songs.length)
|
|
468
|
-
throw new DisTubeError("EMPTY_PLAYLIST");
|
|
469
|
-
this.songs = playlist.songs;
|
|
470
|
-
this.name = playlist.name || // eslint-disable-next-line deprecation/deprecation
|
|
471
|
-
playlist.title || (this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`);
|
|
472
|
-
this.url = playlist.url || playlist.webpage_url;
|
|
473
|
-
this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;
|
|
474
|
-
this.member = member || playlist.member;
|
|
475
|
-
}
|
|
476
|
-
this.songs.forEach((s) => s.constructor.name === "Song" && (s.playlist = this));
|
|
477
|
-
if (properties)
|
|
478
|
-
for (const [key, value] of Object.entries(properties))
|
|
479
|
-
this[key] = value;
|
|
399
|
+
__privateAdd(this, _metadata);
|
|
400
|
+
__privateAdd(this, _member);
|
|
401
|
+
if (!Array.isArray(playlist.songs) || !playlist.songs.length) throw new DisTubeError("EMPTY_PLAYLIST");
|
|
402
|
+
this.source = playlist.source.toLowerCase();
|
|
403
|
+
this.songs = playlist.songs;
|
|
404
|
+
this.name = playlist.name;
|
|
405
|
+
this.id = playlist.id;
|
|
406
|
+
this.url = playlist.url;
|
|
407
|
+
this.thumbnail = playlist.thumbnail;
|
|
408
|
+
this.member = member;
|
|
409
|
+
this.songs.forEach((s) => s.playlist = this);
|
|
480
410
|
this.metadata = metadata;
|
|
481
411
|
}
|
|
482
412
|
/**
|
|
@@ -498,10 +428,9 @@ var _Playlist = class _Playlist {
|
|
|
498
428
|
return __privateGet(this, _member);
|
|
499
429
|
}
|
|
500
430
|
set member(member) {
|
|
501
|
-
if (!isMemberInstance(member))
|
|
502
|
-
return;
|
|
431
|
+
if (!isMemberInstance(member)) return;
|
|
503
432
|
__privateSet(this, _member, member);
|
|
504
|
-
this.songs.forEach((s) => s.
|
|
433
|
+
this.songs.forEach((s) => s.member = this.member);
|
|
505
434
|
}
|
|
506
435
|
/**
|
|
507
436
|
* User requested.
|
|
@@ -509,12 +438,15 @@ var _Playlist = class _Playlist {
|
|
|
509
438
|
get user() {
|
|
510
439
|
return this.member?.user;
|
|
511
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Optional metadata that can be used to identify the playlist.
|
|
443
|
+
*/
|
|
512
444
|
get metadata() {
|
|
513
445
|
return __privateGet(this, _metadata);
|
|
514
446
|
}
|
|
515
447
|
set metadata(metadata) {
|
|
516
448
|
__privateSet(this, _metadata, metadata);
|
|
517
|
-
this.songs.forEach((s) => s.
|
|
449
|
+
this.songs.forEach((s) => s.metadata = metadata);
|
|
518
450
|
}
|
|
519
451
|
};
|
|
520
452
|
_metadata = new WeakMap();
|
|
@@ -522,225 +454,144 @@ _member = new WeakMap();
|
|
|
522
454
|
__name(_Playlist, "Playlist");
|
|
523
455
|
var Playlist = _Playlist;
|
|
524
456
|
|
|
525
|
-
// src/struct/SearchResult.ts
|
|
526
|
-
var _ISearchResult = class _ISearchResult {
|
|
527
|
-
/**
|
|
528
|
-
* Create a search result
|
|
529
|
-
*
|
|
530
|
-
* @param info - ytsr result
|
|
531
|
-
*/
|
|
532
|
-
constructor(info) {
|
|
533
|
-
__publicField(this, "source");
|
|
534
|
-
__publicField(this, "id");
|
|
535
|
-
__publicField(this, "name");
|
|
536
|
-
__publicField(this, "url");
|
|
537
|
-
__publicField(this, "uploader");
|
|
538
|
-
this.source = "youtube";
|
|
539
|
-
this.id = info.id;
|
|
540
|
-
this.name = info.name;
|
|
541
|
-
this.url = info.url;
|
|
542
|
-
this.uploader = {
|
|
543
|
-
name: void 0,
|
|
544
|
-
url: void 0
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
|
-
__name(_ISearchResult, "ISearchResult");
|
|
549
|
-
var ISearchResult = _ISearchResult;
|
|
550
|
-
var _SearchResultVideo = class _SearchResultVideo extends ISearchResult {
|
|
551
|
-
constructor(info) {
|
|
552
|
-
super(info);
|
|
553
|
-
__publicField(this, "type");
|
|
554
|
-
__publicField(this, "views");
|
|
555
|
-
__publicField(this, "isLive");
|
|
556
|
-
__publicField(this, "duration");
|
|
557
|
-
__publicField(this, "formattedDuration");
|
|
558
|
-
__publicField(this, "thumbnail");
|
|
559
|
-
if (info.type !== "video")
|
|
560
|
-
throw new DisTubeError("INVALID_TYPE", "video", info.type, "type");
|
|
561
|
-
this.type = "video" /* VIDEO */;
|
|
562
|
-
this.views = info.views;
|
|
563
|
-
this.isLive = info.isLive;
|
|
564
|
-
this.duration = this.isLive ? 0 : toSecond(info.duration);
|
|
565
|
-
this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
|
|
566
|
-
this.thumbnail = info.thumbnail;
|
|
567
|
-
this.uploader = {
|
|
568
|
-
name: info.author?.name,
|
|
569
|
-
url: info.author?.url
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
__name(_SearchResultVideo, "SearchResultVideo");
|
|
574
|
-
var SearchResultVideo = _SearchResultVideo;
|
|
575
|
-
var _SearchResultPlaylist = class _SearchResultPlaylist extends ISearchResult {
|
|
576
|
-
constructor(info) {
|
|
577
|
-
super(info);
|
|
578
|
-
__publicField(this, "type");
|
|
579
|
-
__publicField(this, "length");
|
|
580
|
-
if (info.type !== "playlist")
|
|
581
|
-
throw new DisTubeError("INVALID_TYPE", "playlist", info.type, "type");
|
|
582
|
-
this.type = "playlist" /* PLAYLIST */;
|
|
583
|
-
this.length = info.length;
|
|
584
|
-
this.uploader = {
|
|
585
|
-
name: info.owner?.name,
|
|
586
|
-
url: info.owner?.url
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
__name(_SearchResultPlaylist, "SearchResultPlaylist");
|
|
591
|
-
var SearchResultPlaylist = _SearchResultPlaylist;
|
|
592
|
-
|
|
593
457
|
// src/struct/Song.ts
|
|
594
458
|
var _metadata2, _member2, _playlist;
|
|
595
459
|
var _Song = class _Song {
|
|
596
460
|
/**
|
|
597
461
|
* Create a Song
|
|
598
462
|
*
|
|
599
|
-
* @param info
|
|
600
|
-
* @param options
|
|
463
|
+
* @param info - Raw song info
|
|
464
|
+
* @param options - Optional data
|
|
601
465
|
*/
|
|
602
|
-
constructor(info,
|
|
466
|
+
constructor(info, { member, metadata } = {}) {
|
|
467
|
+
/**
|
|
468
|
+
* The source of this song info
|
|
469
|
+
*/
|
|
603
470
|
__publicField(this, "source");
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
471
|
+
/**
|
|
472
|
+
* Song ID.
|
|
473
|
+
*/
|
|
607
474
|
__publicField(this, "id");
|
|
475
|
+
/**
|
|
476
|
+
* Song name.
|
|
477
|
+
*/
|
|
608
478
|
__publicField(this, "name");
|
|
479
|
+
/**
|
|
480
|
+
* Indicates if the song is an active live.
|
|
481
|
+
*/
|
|
609
482
|
__publicField(this, "isLive");
|
|
483
|
+
/**
|
|
484
|
+
* Song duration.
|
|
485
|
+
*/
|
|
610
486
|
__publicField(this, "duration");
|
|
487
|
+
/**
|
|
488
|
+
* Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).
|
|
489
|
+
*/
|
|
611
490
|
__publicField(this, "formattedDuration");
|
|
491
|
+
/**
|
|
492
|
+
* Song URL.
|
|
493
|
+
*/
|
|
612
494
|
__publicField(this, "url");
|
|
613
|
-
|
|
495
|
+
/**
|
|
496
|
+
* Song thumbnail.
|
|
497
|
+
*/
|
|
614
498
|
__publicField(this, "thumbnail");
|
|
615
|
-
|
|
499
|
+
/**
|
|
500
|
+
* Song view count
|
|
501
|
+
*/
|
|
616
502
|
__publicField(this, "views");
|
|
503
|
+
/**
|
|
504
|
+
* Song like count
|
|
505
|
+
*/
|
|
617
506
|
__publicField(this, "likes");
|
|
507
|
+
/**
|
|
508
|
+
* Song dislike count
|
|
509
|
+
*/
|
|
618
510
|
__publicField(this, "dislikes");
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
511
|
+
/**
|
|
512
|
+
* Song repost (share) count
|
|
513
|
+
*/
|
|
622
514
|
__publicField(this, "reposts");
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
515
|
+
/**
|
|
516
|
+
* Song uploader
|
|
517
|
+
*/
|
|
518
|
+
__publicField(this, "uploader");
|
|
519
|
+
/**
|
|
520
|
+
* Whether or not an age-restricted content
|
|
521
|
+
*/
|
|
522
|
+
__publicField(this, "ageRestricted");
|
|
523
|
+
/**
|
|
524
|
+
* Stream info
|
|
525
|
+
*/
|
|
526
|
+
__publicField(this, "stream");
|
|
527
|
+
/**
|
|
528
|
+
* The plugin that created this song
|
|
529
|
+
*/
|
|
530
|
+
__publicField(this, "plugin");
|
|
531
|
+
__privateAdd(this, _metadata2);
|
|
532
|
+
__privateAdd(this, _member2);
|
|
533
|
+
__privateAdd(this, _playlist);
|
|
534
|
+
this.source = info.source.toLowerCase();
|
|
629
535
|
this.metadata = metadata;
|
|
630
536
|
this.member = member;
|
|
631
|
-
if (this.source === "youtube") {
|
|
632
|
-
this._patchYouTube(info);
|
|
633
|
-
} else {
|
|
634
|
-
this._patchOther(info);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
_patchYouTube(i) {
|
|
638
|
-
const info = i;
|
|
639
|
-
if (info.full === true) {
|
|
640
|
-
this.formats = info.formats;
|
|
641
|
-
const err = require("@distube/ytdl-core/lib/utils").playError(info.player_response, [
|
|
642
|
-
"UNPLAYABLE",
|
|
643
|
-
"LIVE_STREAM_OFFLINE",
|
|
644
|
-
"LOGIN_REQUIRED"
|
|
645
|
-
]);
|
|
646
|
-
if (err)
|
|
647
|
-
throw err;
|
|
648
|
-
if (!info.formats?.length)
|
|
649
|
-
throw new DisTubeError("UNAVAILABLE_VIDEO");
|
|
650
|
-
}
|
|
651
|
-
const details = info.videoDetails || info;
|
|
652
|
-
this.id = details.videoId || details.id;
|
|
653
|
-
this.name = details.title || details.name;
|
|
654
|
-
this.isLive = Boolean(details.isLive);
|
|
655
|
-
this.duration = this.isLive ? 0 : toSecond(details.lengthSeconds || details.length_seconds || details.duration);
|
|
656
|
-
this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
|
|
657
|
-
this.url = `https://www.youtube.com/watch?v=${this.id}`;
|
|
658
|
-
this.streamURL = void 0;
|
|
659
|
-
this.thumbnail = details.thumbnails?.sort((a, b) => b.width - a.width)?.[0]?.url || details.thumbnail?.url || details.thumbnail;
|
|
660
|
-
this.related = info?.related_videos || details.related || [];
|
|
661
|
-
if (!Array.isArray(this.related))
|
|
662
|
-
throw new DisTubeError("INVALID_TYPE", "Array", this.related, "Song#related");
|
|
663
|
-
this.related = this.related.map((v) => new _Song(v, { source: this.source, metadata: this.metadata }));
|
|
664
|
-
this.views = parseNumber(details.viewCount || details.view_count || details.views);
|
|
665
|
-
this.likes = parseNumber(details.likes);
|
|
666
|
-
this.dislikes = parseNumber(details.dislikes);
|
|
667
|
-
this.uploader = {
|
|
668
|
-
name: info.uploader?.name || details.author?.name,
|
|
669
|
-
url: info.uploader?.url || details.author?.channel_url || details.author?.url
|
|
670
|
-
};
|
|
671
|
-
this.age_restricted = Boolean(details.age_restricted);
|
|
672
|
-
this.chapters = details.chapters || [];
|
|
673
|
-
this.reposts = 0;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Patch data from other source
|
|
677
|
-
*
|
|
678
|
-
* @param info - Video info
|
|
679
|
-
*/
|
|
680
|
-
_patchOther(info) {
|
|
681
537
|
this.id = info.id;
|
|
682
|
-
this.name = info.
|
|
683
|
-
this.isLive =
|
|
684
|
-
this.duration = this.isLive ? 0 :
|
|
538
|
+
this.name = info.name;
|
|
539
|
+
this.isLive = info.isLive;
|
|
540
|
+
this.duration = this.isLive || !info.duration ? 0 : info.duration;
|
|
685
541
|
this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
|
|
686
|
-
this.url = info.
|
|
542
|
+
this.url = info.url;
|
|
687
543
|
this.thumbnail = info.thumbnail;
|
|
688
|
-
this.
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
this.
|
|
692
|
-
this.
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
url: info.uploader_url
|
|
700
|
-
};
|
|
701
|
-
} else {
|
|
702
|
-
this.uploader = {
|
|
703
|
-
name: info.uploader?.name,
|
|
704
|
-
url: info.uploader?.url
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
this.age_restricted = info.age_restricted || Boolean(info.age_limit) && parseNumber(info.age_limit) >= 18;
|
|
708
|
-
this.chapters = info.chapters || [];
|
|
544
|
+
this.views = info.views;
|
|
545
|
+
this.likes = info.likes;
|
|
546
|
+
this.dislikes = info.dislikes;
|
|
547
|
+
this.reposts = info.reposts;
|
|
548
|
+
this.uploader = {
|
|
549
|
+
name: info.uploader?.name,
|
|
550
|
+
url: info.uploader?.url
|
|
551
|
+
};
|
|
552
|
+
this.ageRestricted = info.ageRestricted;
|
|
553
|
+
this.stream = { playFromSource: info.playFromSource };
|
|
554
|
+
this.plugin = info.plugin;
|
|
709
555
|
}
|
|
710
556
|
/**
|
|
711
|
-
* The playlist
|
|
557
|
+
* The playlist this song belongs to
|
|
712
558
|
*/
|
|
713
559
|
get playlist() {
|
|
714
560
|
return __privateGet(this, _playlist);
|
|
715
561
|
}
|
|
716
562
|
set playlist(playlist) {
|
|
717
|
-
if (!(playlist instanceof Playlist))
|
|
718
|
-
throw new DisTubeError("INVALID_TYPE", "Playlist", playlist, "Song#playlist");
|
|
563
|
+
if (!(playlist instanceof Playlist)) throw new DisTubeError("INVALID_TYPE", "Playlist", playlist, "Song#playlist");
|
|
719
564
|
__privateSet(this, _playlist, playlist);
|
|
720
565
|
this.member = playlist.member;
|
|
721
566
|
}
|
|
722
567
|
/**
|
|
723
|
-
* User requested.
|
|
568
|
+
* User requested to play this song.
|
|
724
569
|
*/
|
|
725
570
|
get member() {
|
|
726
571
|
return __privateGet(this, _member2);
|
|
727
572
|
}
|
|
728
573
|
set member(member) {
|
|
729
|
-
if (isMemberInstance(member))
|
|
730
|
-
__privateSet(this, _member2, member);
|
|
574
|
+
if (isMemberInstance(member)) __privateSet(this, _member2, member);
|
|
731
575
|
}
|
|
732
576
|
/**
|
|
733
|
-
* User requested.
|
|
577
|
+
* User requested to play this song.
|
|
734
578
|
*/
|
|
735
579
|
get user() {
|
|
736
580
|
return this.member?.user;
|
|
737
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Optional metadata that can be used to identify the song. This is attached by the
|
|
584
|
+
* {@link DisTube#play} method.
|
|
585
|
+
*/
|
|
738
586
|
get metadata() {
|
|
739
587
|
return __privateGet(this, _metadata2);
|
|
740
588
|
}
|
|
741
589
|
set metadata(metadata) {
|
|
742
590
|
__privateSet(this, _metadata2, metadata);
|
|
743
591
|
}
|
|
592
|
+
toString() {
|
|
593
|
+
return this.name || this.url || this.id || "Unknown";
|
|
594
|
+
}
|
|
744
595
|
};
|
|
745
596
|
_metadata2 = new WeakMap();
|
|
746
597
|
_member2 = new WeakMap();
|
|
@@ -756,7 +607,6 @@ var _DisTubeBase = class _DisTubeBase {
|
|
|
756
607
|
}
|
|
757
608
|
/**
|
|
758
609
|
* Emit the {@link DisTube} of this base
|
|
759
|
-
*
|
|
760
610
|
* @param eventName - Event name
|
|
761
611
|
* @param args - arguments
|
|
762
612
|
*/
|
|
@@ -765,12 +615,19 @@ var _DisTubeBase = class _DisTubeBase {
|
|
|
765
615
|
}
|
|
766
616
|
/**
|
|
767
617
|
* Emit error event
|
|
768
|
-
*
|
|
769
618
|
* @param error - error
|
|
770
|
-
* @param
|
|
619
|
+
* @param queue - The queue encountered the error
|
|
620
|
+
* @param song - The playing song when encountered the error
|
|
771
621
|
*/
|
|
772
|
-
emitError(error,
|
|
773
|
-
this.distube.emitError(error,
|
|
622
|
+
emitError(error, queue, song) {
|
|
623
|
+
this.distube.emitError(error, queue, song);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Emit debug event
|
|
627
|
+
* @param message - debug message
|
|
628
|
+
*/
|
|
629
|
+
debug(message) {
|
|
630
|
+
this.distube.debug(message);
|
|
774
631
|
}
|
|
775
632
|
/**
|
|
776
633
|
* The queue manager
|
|
@@ -802,6 +659,12 @@ var _DisTubeBase = class _DisTubeBase {
|
|
|
802
659
|
get handler() {
|
|
803
660
|
return this.distube.handler;
|
|
804
661
|
}
|
|
662
|
+
/**
|
|
663
|
+
* DisTube plugins
|
|
664
|
+
*/
|
|
665
|
+
get plugins() {
|
|
666
|
+
return this.distube.plugins;
|
|
667
|
+
}
|
|
805
668
|
};
|
|
806
669
|
__name(_DisTubeBase, "DisTubeBase");
|
|
807
670
|
var DisTubeBase = _DisTubeBase;
|
|
@@ -810,34 +673,28 @@ var DisTubeBase = _DisTubeBase;
|
|
|
810
673
|
var import_discord = require("discord.js");
|
|
811
674
|
var import_tiny_typed_emitter = require("tiny-typed-emitter");
|
|
812
675
|
var import_voice = require("@discordjs/voice");
|
|
813
|
-
var _channel, _volume,
|
|
676
|
+
var _channel, _volume, _DisTubeVoice_instances, join_fn;
|
|
814
677
|
var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedEmitter {
|
|
815
678
|
constructor(voiceManager, channel) {
|
|
816
679
|
super();
|
|
817
|
-
__privateAdd(this,
|
|
818
|
-
__privateAdd(this, _join);
|
|
680
|
+
__privateAdd(this, _DisTubeVoice_instances);
|
|
819
681
|
__publicField(this, "id");
|
|
820
682
|
__publicField(this, "voices");
|
|
821
683
|
__publicField(this, "audioPlayer");
|
|
822
684
|
__publicField(this, "connection");
|
|
823
|
-
__publicField(this, "audioResource");
|
|
824
685
|
__publicField(this, "emittedError");
|
|
825
686
|
__publicField(this, "isDisconnected", false);
|
|
826
687
|
__publicField(this, "stream");
|
|
827
|
-
__privateAdd(this, _channel
|
|
688
|
+
__privateAdd(this, _channel);
|
|
828
689
|
__privateAdd(this, _volume, 100);
|
|
829
690
|
this.voices = voiceManager;
|
|
830
691
|
this.id = channel.guildId;
|
|
831
692
|
this.channel = channel;
|
|
832
693
|
this.voices.add(this.id, this);
|
|
833
694
|
this.audioPlayer = (0, import_voice.createAudioPlayer)().on(import_voice.AudioPlayerStatus.Idle, (oldState) => {
|
|
834
|
-
if (oldState.status !== import_voice.AudioPlayerStatus.Idle)
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
}
|
|
838
|
-
}).on(import_voice.AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
|
|
839
|
-
if (this.emittedError)
|
|
840
|
-
return;
|
|
695
|
+
if (oldState.status !== import_voice.AudioPlayerStatus.Idle) this.emit("finish");
|
|
696
|
+
}).on("error", (error) => {
|
|
697
|
+
if (this.emittedError) return;
|
|
841
698
|
this.emittedError = true;
|
|
842
699
|
this.emit("error", error);
|
|
843
700
|
});
|
|
@@ -872,13 +729,10 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
872
729
|
return this.connection?.joinConfig?.channelId ?? void 0;
|
|
873
730
|
}
|
|
874
731
|
get channel() {
|
|
875
|
-
if (!this.channelId)
|
|
876
|
-
|
|
877
|
-
if (__privateGet(this, _channel)?.id === this.channelId)
|
|
878
|
-
return __privateGet(this, _channel);
|
|
732
|
+
if (!this.channelId) return __privateGet(this, _channel);
|
|
733
|
+
if (__privateGet(this, _channel)?.id === this.channelId) return __privateGet(this, _channel);
|
|
879
734
|
const channel = this.voices.client.channels.cache.get(this.channelId);
|
|
880
|
-
if (!channel)
|
|
881
|
-
return __privateGet(this, _channel);
|
|
735
|
+
if (!channel) return __privateGet(this, _channel);
|
|
882
736
|
for (const type of import_discord.Constants.VoiceBasedChannelTypes) {
|
|
883
737
|
if (channel.type === type) {
|
|
884
738
|
__privateSet(this, _channel, channel);
|
|
@@ -891,38 +745,28 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
891
745
|
if (!isSupportedVoiceChannel(channel)) {
|
|
892
746
|
throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
|
|
893
747
|
}
|
|
894
|
-
if (channel.guildId !== this.id)
|
|
895
|
-
|
|
896
|
-
if (channel.
|
|
897
|
-
throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
|
|
898
|
-
if (channel.id === this.channelId)
|
|
899
|
-
return;
|
|
748
|
+
if (channel.guildId !== this.id) throw new DisTubeError("VOICE_DIFFERENT_GUILD");
|
|
749
|
+
if (channel.client.user?.id !== this.voices.client.user?.id) throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
|
|
750
|
+
if (channel.id === this.channelId) return;
|
|
900
751
|
if (!channel.joinable) {
|
|
901
|
-
if (channel.full)
|
|
902
|
-
|
|
903
|
-
else
|
|
904
|
-
throw new DisTubeError("VOICE_MISSING_PERMS");
|
|
752
|
+
if (channel.full) throw new DisTubeError("VOICE_FULL");
|
|
753
|
+
else throw new DisTubeError("VOICE_MISSING_PERMS");
|
|
905
754
|
}
|
|
906
|
-
this.connection = __privateMethod(this,
|
|
755
|
+
this.connection = __privateMethod(this, _DisTubeVoice_instances, join_fn).call(this, channel);
|
|
907
756
|
__privateSet(this, _channel, channel);
|
|
908
|
-
__privateMethod(this, _br, br_fn).call(this);
|
|
909
757
|
}
|
|
910
758
|
/**
|
|
911
759
|
* Join a voice channel with this connection
|
|
912
|
-
*
|
|
913
760
|
* @param channel - A voice channel
|
|
914
761
|
*/
|
|
915
762
|
async join(channel) {
|
|
916
763
|
const TIMEOUT = 3e4;
|
|
917
|
-
if (channel)
|
|
918
|
-
this.channel = channel;
|
|
764
|
+
if (channel) this.channel = channel;
|
|
919
765
|
try {
|
|
920
766
|
await (0, import_voice.entersState)(this.connection, import_voice.VoiceConnectionStatus.Ready, TIMEOUT);
|
|
921
767
|
} catch {
|
|
922
|
-
if (this.connection.state.status === import_voice.VoiceConnectionStatus.Ready)
|
|
923
|
-
|
|
924
|
-
if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed)
|
|
925
|
-
this.connection.destroy();
|
|
768
|
+
if (this.connection.state.status === import_voice.VoiceConnectionStatus.Ready) return this;
|
|
769
|
+
if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed) this.connection.destroy();
|
|
926
770
|
this.voices.remove(this.id);
|
|
927
771
|
throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
|
|
928
772
|
}
|
|
@@ -930,7 +774,6 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
930
774
|
}
|
|
931
775
|
/**
|
|
932
776
|
* Leave the voice channel of this connection
|
|
933
|
-
*
|
|
934
777
|
* @param error - Optional, an error to emit with 'error' event.
|
|
935
778
|
*/
|
|
936
779
|
leave(error) {
|
|
@@ -939,42 +782,33 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
939
782
|
this.emit("disconnect", error);
|
|
940
783
|
this.isDisconnected = true;
|
|
941
784
|
}
|
|
942
|
-
if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed)
|
|
943
|
-
this.connection.destroy();
|
|
785
|
+
if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed) this.connection.destroy();
|
|
944
786
|
this.voices.remove(this.id);
|
|
945
787
|
}
|
|
946
788
|
/**
|
|
947
789
|
* Stop the playing stream
|
|
948
|
-
*
|
|
949
790
|
* @param force - If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state even
|
|
950
|
-
* if the {@link
|
|
791
|
+
* if the {@link DisTubeStream#audioResource} has silence padding frames.
|
|
951
792
|
*/
|
|
952
793
|
stop(force = false) {
|
|
953
794
|
this.audioPlayer.stop(force);
|
|
954
|
-
this.stream?.kill?.();
|
|
955
795
|
}
|
|
956
796
|
/**
|
|
957
797
|
* Play a {@link DisTubeStream}
|
|
958
|
-
*
|
|
959
798
|
* @param dtStream - DisTubeStream
|
|
960
799
|
*/
|
|
961
800
|
play(dtStream) {
|
|
962
801
|
this.emittedError = false;
|
|
963
802
|
dtStream.on("error", (error) => {
|
|
964
|
-
if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
|
|
965
|
-
return;
|
|
803
|
+
if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE") return;
|
|
966
804
|
this.emittedError = true;
|
|
967
805
|
this.emit("error", error);
|
|
968
806
|
});
|
|
969
|
-
this.
|
|
970
|
-
|
|
971
|
-
inlineVolume: true
|
|
972
|
-
});
|
|
973
|
-
this.volume = __privateGet(this, _volume);
|
|
974
|
-
if (this.audioPlayer.state.status !== import_voice.AudioPlayerStatus.Paused)
|
|
975
|
-
this.audioPlayer.play(this.audioResource);
|
|
976
|
-
this.stream?.kill?.();
|
|
807
|
+
if (this.audioPlayer.state.status !== import_voice.AudioPlayerStatus.Paused) this.audioPlayer.play(dtStream.audioResource);
|
|
808
|
+
this.stream?.kill();
|
|
977
809
|
this.stream = dtStream;
|
|
810
|
+
this.volume = __privateGet(this, _volume);
|
|
811
|
+
dtStream.spawn();
|
|
978
812
|
}
|
|
979
813
|
set volume(volume) {
|
|
980
814
|
if (typeof volume !== "number" || isNaN(volume)) {
|
|
@@ -984,8 +818,11 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
984
818
|
throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
|
|
985
819
|
}
|
|
986
820
|
__privateSet(this, _volume, volume);
|
|
987
|
-
this.
|
|
821
|
+
this.stream?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
|
|
988
822
|
}
|
|
823
|
+
/**
|
|
824
|
+
* Get or set the volume percentage
|
|
825
|
+
*/
|
|
989
826
|
get volume() {
|
|
990
827
|
return __privateGet(this, _volume);
|
|
991
828
|
}
|
|
@@ -993,19 +830,19 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
993
830
|
* Playback duration of the audio resource in seconds
|
|
994
831
|
*/
|
|
995
832
|
get playbackDuration() {
|
|
996
|
-
return (this.audioResource?.playbackDuration ?? 0) / 1e3;
|
|
833
|
+
return (this.stream?.audioResource?.playbackDuration ?? 0) / 1e3;
|
|
997
834
|
}
|
|
998
835
|
pause() {
|
|
999
836
|
this.audioPlayer.pause();
|
|
1000
837
|
}
|
|
1001
838
|
unpause() {
|
|
1002
839
|
const state = this.audioPlayer.state;
|
|
1003
|
-
if (state.status !== import_voice.AudioPlayerStatus.Paused)
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
else
|
|
840
|
+
if (state.status !== import_voice.AudioPlayerStatus.Paused) return;
|
|
841
|
+
if (this.stream?.audioResource && state.resource !== this.stream.audioResource) {
|
|
842
|
+
this.audioPlayer.play(this.stream.audioResource);
|
|
843
|
+
} else {
|
|
1008
844
|
this.audioPlayer.unpause();
|
|
845
|
+
}
|
|
1009
846
|
}
|
|
1010
847
|
/**
|
|
1011
848
|
* Whether the bot is self-deafened
|
|
@@ -1021,9 +858,7 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
1021
858
|
}
|
|
1022
859
|
/**
|
|
1023
860
|
* Self-deafens/undeafens the bot.
|
|
1024
|
-
*
|
|
1025
861
|
* @param selfDeaf - Whether or not the bot should be self-deafened
|
|
1026
|
-
*
|
|
1027
862
|
* @returns true if the voice state was successfully updated, otherwise false
|
|
1028
863
|
*/
|
|
1029
864
|
setSelfDeaf(selfDeaf) {
|
|
@@ -1037,9 +872,7 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
1037
872
|
}
|
|
1038
873
|
/**
|
|
1039
874
|
* Self-mutes/unmutes the bot.
|
|
1040
|
-
*
|
|
1041
875
|
* @param selfMute - Whether or not the bot should be self-muted
|
|
1042
|
-
*
|
|
1043
876
|
* @returns true if the voice state was successfully updated, otherwise false
|
|
1044
877
|
*/
|
|
1045
878
|
setSelfMute(selfMute) {
|
|
@@ -1060,12 +893,7 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
|
|
|
1060
893
|
};
|
|
1061
894
|
_channel = new WeakMap();
|
|
1062
895
|
_volume = new WeakMap();
|
|
1063
|
-
|
|
1064
|
-
br_fn = /* @__PURE__ */ __name(function() {
|
|
1065
|
-
if (this.audioResource?.encoder?.encoder)
|
|
1066
|
-
this.audioResource.encoder.setBitrate(this.channel.bitrate);
|
|
1067
|
-
}, "#br");
|
|
1068
|
-
_join = new WeakSet();
|
|
896
|
+
_DisTubeVoice_instances = new WeakSet();
|
|
1069
897
|
join_fn = /* @__PURE__ */ __name(function(channel) {
|
|
1070
898
|
return (0, import_voice.joinVoiceChannel)({
|
|
1071
899
|
channelId: channel.id,
|
|
@@ -1078,57 +906,51 @@ __name(_DisTubeVoice, "DisTubeVoice");
|
|
|
1078
906
|
var DisTubeVoice = _DisTubeVoice;
|
|
1079
907
|
|
|
1080
908
|
// src/core/DisTubeStream.ts
|
|
1081
|
-
var
|
|
909
|
+
var import_stream = require("stream");
|
|
1082
910
|
var import_child_process = require("child_process");
|
|
1083
911
|
var import_tiny_typed_emitter2 = require("tiny-typed-emitter");
|
|
1084
912
|
var import_voice2 = require("@discordjs/voice");
|
|
1085
|
-
var chooseBestVideoFormat = /* @__PURE__ */ __name(({ duration, formats, isLive }) => formats && formats.filter((f) => f.hasAudio && (duration < 10 * 60 || f.hasVideo) && (!isLive || f.isHLS)).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate))[0], "chooseBestVideoFormat");
|
|
1086
913
|
var checked = process.env.NODE_ENV === "test";
|
|
1087
914
|
var checkFFmpeg = /* @__PURE__ */ __name((distube) => {
|
|
1088
|
-
if (checked)
|
|
1089
|
-
return;
|
|
915
|
+
if (checked) return;
|
|
1090
916
|
const path = distube.options.ffmpeg.path;
|
|
1091
917
|
const debug = /* @__PURE__ */ __name((str) => distube.emit("ffmpegDebug" /* FFMPEG_DEBUG */, str), "debug");
|
|
1092
918
|
try {
|
|
1093
919
|
debug(`[test] spawn ffmpeg at '${path}' path`);
|
|
1094
920
|
const process2 = (0, import_child_process.spawnSync)(path, ["-h"], { windowsHide: true, shell: true, encoding: "utf-8" });
|
|
1095
|
-
if (process2.error)
|
|
1096
|
-
|
|
1097
|
-
if (process2.stderr && !process2.stdout)
|
|
1098
|
-
throw new Error(process2.stderr);
|
|
921
|
+
if (process2.error) throw process2.error;
|
|
922
|
+
if (process2.stderr && !process2.stdout) throw new Error(process2.stderr);
|
|
1099
923
|
const result = process2.output.join("\n");
|
|
1100
924
|
const version2 = /ffmpeg version (\S+)/iu.exec(result)?.[1];
|
|
1101
|
-
if (!version2)
|
|
1102
|
-
throw new Error("Invalid FFmpeg version");
|
|
925
|
+
if (!version2) throw new Error("Invalid FFmpeg version");
|
|
1103
926
|
debug(`[test] ffmpeg version: ${version2}`);
|
|
1104
|
-
if (result.includes("--enable-libopus")) {
|
|
1105
|
-
debug("[test] ffmpeg supports libopus");
|
|
1106
|
-
} else {
|
|
1107
|
-
debug("[test] ffmpeg does not support libopus");
|
|
1108
|
-
distube.options.streamType = 1 /* RAW */;
|
|
1109
|
-
}
|
|
1110
927
|
} catch (e) {
|
|
1111
928
|
debug(`[test] failed to spawn ffmpeg at '${path}': ${e?.stack ?? e}`);
|
|
1112
929
|
throw new DisTubeError("FFMPEG_NOT_INSTALLED", path);
|
|
1113
930
|
}
|
|
1114
931
|
checked = true;
|
|
1115
932
|
}, "checkFFmpeg");
|
|
933
|
+
var _ffmpegPath, _opts;
|
|
1116
934
|
var _DisTubeStream = class _DisTubeStream extends import_tiny_typed_emitter2.TypedEmitter {
|
|
1117
935
|
/**
|
|
1118
936
|
* Create a DisTubeStream to play with {@link DisTubeVoice}
|
|
1119
|
-
*
|
|
1120
937
|
* @param url - Stream URL
|
|
1121
938
|
* @param options - Stream options
|
|
1122
939
|
*/
|
|
1123
|
-
constructor(url,
|
|
940
|
+
constructor(url, options) {
|
|
941
|
+
if (typeof url !== "string" || !isURL(url)) {
|
|
942
|
+
throw new DisTubeError("INVALID_TYPE", "an URL", url);
|
|
943
|
+
}
|
|
944
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
945
|
+
throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
946
|
+
}
|
|
1124
947
|
super();
|
|
1125
|
-
|
|
948
|
+
__privateAdd(this, _ffmpegPath);
|
|
949
|
+
__privateAdd(this, _opts);
|
|
1126
950
|
__publicField(this, "process");
|
|
1127
951
|
__publicField(this, "stream");
|
|
1128
|
-
__publicField(this, "
|
|
1129
|
-
|
|
1130
|
-
this.url = url;
|
|
1131
|
-
this.type = !type ? import_voice2.StreamType.OggOpus : import_voice2.StreamType.Raw;
|
|
952
|
+
__publicField(this, "audioResource");
|
|
953
|
+
const { ffmpeg, seek } = options;
|
|
1132
954
|
const opts = {
|
|
1133
955
|
reconnect: 1,
|
|
1134
956
|
reconnect_streamed: 1,
|
|
@@ -1140,34 +962,36 @@ var _DisTubeStream = class _DisTubeStream extends import_tiny_typed_emitter2.Typ
|
|
|
1140
962
|
i: url,
|
|
1141
963
|
ar: 48e3,
|
|
1142
964
|
ac: 2,
|
|
1143
|
-
...ffmpeg.args.output
|
|
965
|
+
...ffmpeg.args.output,
|
|
966
|
+
f: "s16le"
|
|
1144
967
|
};
|
|
1145
|
-
if (
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
968
|
+
if (typeof seek === "number" && seek > 0) opts.ss = seek.toString();
|
|
969
|
+
__privateSet(this, _ffmpegPath, ffmpeg.path);
|
|
970
|
+
__privateSet(this, _opts, [
|
|
971
|
+
...Object.entries(opts).flatMap(
|
|
972
|
+
([key, value]) => Array.isArray(value) ? value.filter(Boolean).map((v) => [`-${key}`, String(v)]) : value == null || value === false ? [] : [value === true ? `-${key}` : [`-${key}`, String(value)]]
|
|
973
|
+
).flat(),
|
|
974
|
+
"pipe:1"
|
|
975
|
+
]);
|
|
976
|
+
this.stream = new VolumeTransformer();
|
|
977
|
+
this.stream.on("close", () => this.kill()).on("error", (err) => {
|
|
978
|
+
this.debug(`[stream] error: ${err.message}`);
|
|
979
|
+
this.emit("error", err);
|
|
980
|
+
}).on("finish", () => this.debug("[stream] log: stream finished"));
|
|
981
|
+
this.audioResource = (0, import_voice2.createAudioResource)(this.stream, { inputType: import_voice2.StreamType.Raw, inlineVolume: false });
|
|
982
|
+
}
|
|
983
|
+
spawn() {
|
|
984
|
+
this.debug(`[process] spawn: ${__privateGet(this, _ffmpegPath)} ${__privateGet(this, _opts).join(" ")}`);
|
|
985
|
+
this.process = (0, import_child_process.spawn)(__privateGet(this, _ffmpegPath), __privateGet(this, _opts), {
|
|
986
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
987
|
+
shell: false,
|
|
988
|
+
windowsHide: true
|
|
989
|
+
}).on("error", (err) => {
|
|
1165
990
|
this.debug(`[process] error: ${err.message}`);
|
|
1166
991
|
this.emit("error", err);
|
|
1167
992
|
}).on("exit", (code, signal) => {
|
|
1168
993
|
this.debug(`[process] exit: code=${code ?? "unknown"} signal=${signal ?? "unknown"}`);
|
|
1169
|
-
if (!code || [0, 255].includes(code))
|
|
1170
|
-
return;
|
|
994
|
+
if (!code || [0, 255].includes(code)) return;
|
|
1171
995
|
this.debug(`[process] error: ffmpeg exited with code ${code}`);
|
|
1172
996
|
this.emit("error", new DisTubeError("FFMPEG_EXITED", code));
|
|
1173
997
|
});
|
|
@@ -1175,17 +999,11 @@ var _DisTubeStream = class _DisTubeStream extends import_tiny_typed_emitter2.Typ
|
|
|
1175
999
|
this.kill();
|
|
1176
1000
|
throw new Error("Failed to create ffmpeg process");
|
|
1177
1001
|
}
|
|
1178
|
-
this.stream = new import_node_stream.PassThrough();
|
|
1179
|
-
this.stream.on("close", () => this.kill()).on("error", (err) => {
|
|
1180
|
-
this.debug(`[stream] error: ${err.message}`);
|
|
1181
|
-
this.emit("error", err);
|
|
1182
|
-
}).on("finish", () => this.debug("[stream] log: stream finished"));
|
|
1183
1002
|
this.process.stdout.pipe(this.stream);
|
|
1184
1003
|
this.process.stderr.setEncoding("utf8")?.on("data", (data) => {
|
|
1185
1004
|
const lines = data.split(/\r\n|\r|\n/u);
|
|
1186
1005
|
for (const line of lines) {
|
|
1187
|
-
if (/^\s*$/.test(line))
|
|
1188
|
-
continue;
|
|
1006
|
+
if (/^\s*$/.test(line)) continue;
|
|
1189
1007
|
this.debug(`[ffmpeg] log: ${line}`);
|
|
1190
1008
|
}
|
|
1191
1009
|
});
|
|
@@ -1193,422 +1011,171 @@ var _DisTubeStream = class _DisTubeStream extends import_tiny_typed_emitter2.Typ
|
|
|
1193
1011
|
debug(debug) {
|
|
1194
1012
|
this.emit("debug", debug);
|
|
1195
1013
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
return;
|
|
1199
|
-
this.process.kill("SIGKILL");
|
|
1200
|
-
this.killed = true;
|
|
1014
|
+
setVolume(volume) {
|
|
1015
|
+
this.stream.vol = volume;
|
|
1201
1016
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
* @param song - A YouTube Song
|
|
1206
|
-
* @param options - options
|
|
1207
|
-
*/
|
|
1208
|
-
static YouTube(song, options) {
|
|
1209
|
-
if (song.source !== "youtube")
|
|
1210
|
-
throw new DisTubeError("INVALID_TYPE", "youtube", song.source, "Song#source");
|
|
1211
|
-
if (!song.formats?.length)
|
|
1212
|
-
throw new DisTubeError("UNAVAILABLE_VIDEO");
|
|
1213
|
-
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1214
|
-
throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
1215
|
-
}
|
|
1216
|
-
const bestFormat = chooseBestVideoFormat(song);
|
|
1217
|
-
if (!bestFormat)
|
|
1218
|
-
throw new DisTubeError("UNPLAYABLE_FORMATS");
|
|
1219
|
-
return new _DisTubeStream(bestFormat.url, options);
|
|
1017
|
+
kill() {
|
|
1018
|
+
if (!this.stream.destroyed) this.stream.destroy();
|
|
1019
|
+
if (this.process && !this.process.killed) this.process.kill("SIGKILL");
|
|
1220
1020
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1021
|
+
};
|
|
1022
|
+
_ffmpegPath = new WeakMap();
|
|
1023
|
+
_opts = new WeakMap();
|
|
1024
|
+
__name(_DisTubeStream, "DisTubeStream");
|
|
1025
|
+
var DisTubeStream = _DisTubeStream;
|
|
1026
|
+
var _VolumeTransformer = class _VolumeTransformer extends import_stream.Transform {
|
|
1027
|
+
constructor() {
|
|
1028
|
+
super(...arguments);
|
|
1029
|
+
__publicField(this, "buffer", Buffer.allocUnsafe(0));
|
|
1030
|
+
__publicField(this, "extrema", [-Math.pow(2, 16 - 1), Math.pow(2, 16 - 1) - 1]);
|
|
1031
|
+
__publicField(this, "vol", 1);
|
|
1032
|
+
}
|
|
1033
|
+
_transform(newChunk, _encoding, done) {
|
|
1034
|
+
const { vol } = this;
|
|
1035
|
+
if (vol === 1) {
|
|
1036
|
+
this.push(newChunk);
|
|
1037
|
+
done();
|
|
1038
|
+
return;
|
|
1230
1039
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1040
|
+
const bytes = 2;
|
|
1041
|
+
const chunk = Buffer.concat([this.buffer, newChunk]);
|
|
1042
|
+
const readableLength = Math.floor(chunk.length / bytes) * bytes;
|
|
1043
|
+
for (let i = 0; i < readableLength; i += bytes) {
|
|
1044
|
+
const value = chunk.readInt16LE(i);
|
|
1045
|
+
const clampedValue = Math.min(this.extrema[1], Math.max(this.extrema[0], value * vol));
|
|
1046
|
+
chunk.writeInt16LE(clampedValue, i);
|
|
1233
1047
|
}
|
|
1234
|
-
|
|
1048
|
+
this.buffer = chunk.subarray(readableLength);
|
|
1049
|
+
this.push(chunk.subarray(0, readableLength));
|
|
1050
|
+
done();
|
|
1235
1051
|
}
|
|
1236
1052
|
};
|
|
1237
|
-
__name(
|
|
1238
|
-
var
|
|
1053
|
+
__name(_VolumeTransformer, "VolumeTransformer");
|
|
1054
|
+
var VolumeTransformer = _VolumeTransformer;
|
|
1239
1055
|
|
|
1240
1056
|
// src/core/DisTubeHandler.ts
|
|
1241
|
-
var
|
|
1242
|
-
var
|
|
1243
|
-
var
|
|
1244
|
-
var _cookie;
|
|
1057
|
+
var import_undici = require("undici");
|
|
1058
|
+
var REDIRECT_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
1059
|
+
var _DisTubeHandler_instances, searchSong_fn;
|
|
1245
1060
|
var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
|
|
1246
|
-
constructor(
|
|
1247
|
-
super(
|
|
1248
|
-
__privateAdd(this,
|
|
1249
|
-
const client = this.client;
|
|
1250
|
-
if (this.options.leaveOnEmpty) {
|
|
1251
|
-
client.on("voiceStateUpdate", (oldState) => {
|
|
1252
|
-
if (!oldState?.channel)
|
|
1253
|
-
return;
|
|
1254
|
-
const queue = this.queues.get(oldState);
|
|
1255
|
-
if (!queue) {
|
|
1256
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1257
|
-
setTimeout(() => {
|
|
1258
|
-
if (!this.queues.get(oldState) && isVoiceChannelEmpty(oldState))
|
|
1259
|
-
this.voices.leave(oldState);
|
|
1260
|
-
}, this.options.emptyCooldown * 1e3).unref();
|
|
1261
|
-
}
|
|
1262
|
-
return;
|
|
1263
|
-
}
|
|
1264
|
-
if (queue._emptyTimeout) {
|
|
1265
|
-
clearTimeout(queue._emptyTimeout);
|
|
1266
|
-
delete queue._emptyTimeout;
|
|
1267
|
-
}
|
|
1268
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1269
|
-
queue._emptyTimeout = setTimeout(() => {
|
|
1270
|
-
delete queue._emptyTimeout;
|
|
1271
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1272
|
-
queue.voice.leave();
|
|
1273
|
-
this.emit("empty" /* EMPTY */, queue);
|
|
1274
|
-
if (queue.stopped)
|
|
1275
|
-
queue.remove();
|
|
1276
|
-
}
|
|
1277
|
-
}, this.options.emptyCooldown * 1e3).unref();
|
|
1278
|
-
}
|
|
1279
|
-
});
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
get ytdlOptions() {
|
|
1283
|
-
const options = this.options.ytdlOptions;
|
|
1284
|
-
if (this.options.youtubeCookie && this.options.youtubeCookie !== __privateGet(this, _cookie)) {
|
|
1285
|
-
const cookies = __privateSet(this, _cookie, this.options.youtubeCookie);
|
|
1286
|
-
if (typeof cookies === "string") {
|
|
1287
|
-
console.warn(
|
|
1288
|
-
"\x1B[33mWARNING:\x1B[0m You are using the old YouTube cookie format, please use the new one instead. (https://github.com/skick1234/DisTube/wiki/YouTube-Cookies)"
|
|
1289
|
-
);
|
|
1290
|
-
options.agent = import_ytdl_core.default.createAgent(
|
|
1291
|
-
cookies.split(";").map((c) => import_tough_cookie.Cookie.parse(c)).filter(isTruthy)
|
|
1292
|
-
);
|
|
1293
|
-
} else {
|
|
1294
|
-
options.agent = import_ytdl_core.default.createAgent(cookies);
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
return options;
|
|
1298
|
-
}
|
|
1299
|
-
get ytCookie() {
|
|
1300
|
-
const agent = this.ytdlOptions.agent;
|
|
1301
|
-
if (!agent)
|
|
1302
|
-
return "";
|
|
1303
|
-
const { jar } = agent;
|
|
1304
|
-
return jar.getCookieStringSync("https://www.youtube.com");
|
|
1305
|
-
}
|
|
1306
|
-
/**
|
|
1307
|
-
* @param url - url
|
|
1308
|
-
* @param basic - getBasicInfo?
|
|
1309
|
-
*/
|
|
1310
|
-
getYouTubeInfo(url, basic = false) {
|
|
1311
|
-
if (basic)
|
|
1312
|
-
return import_ytdl_core.default.getBasicInfo(url, this.ytdlOptions);
|
|
1313
|
-
return import_ytdl_core.default.getInfo(url, this.ytdlOptions);
|
|
1061
|
+
constructor() {
|
|
1062
|
+
super(...arguments);
|
|
1063
|
+
__privateAdd(this, _DisTubeHandler_instances);
|
|
1314
1064
|
}
|
|
1315
1065
|
/**
|
|
1316
1066
|
* Resolve a url or a supported object to a {@link Song} or {@link Playlist}
|
|
1317
|
-
*
|
|
1318
1067
|
* @throws {@link DisTubeError}
|
|
1319
|
-
*
|
|
1320
|
-
* @param song - URL | {@link Song}| {@link SearchResult} | {@link Playlist}
|
|
1068
|
+
* @param input - Resolvable input
|
|
1321
1069
|
* @param options - Optional options
|
|
1322
|
-
*
|
|
1323
1070
|
* @returns Resolved
|
|
1324
1071
|
*/
|
|
1325
|
-
async resolve(
|
|
1326
|
-
if (
|
|
1327
|
-
if ("metadata" in options)
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1072
|
+
async resolve(input, options = {}) {
|
|
1073
|
+
if (input instanceof Song || input instanceof Playlist) {
|
|
1074
|
+
if ("metadata" in options) input.metadata = options.metadata;
|
|
1075
|
+
if ("member" in options) input.member = options.member;
|
|
1076
|
+
return input;
|
|
1077
|
+
}
|
|
1078
|
+
if (typeof input === "string") {
|
|
1079
|
+
if (isURL(input)) {
|
|
1080
|
+
const plugin = await this._getPluginFromURL(input) || await this._getPluginFromURL(await this.followRedirectLink(input));
|
|
1081
|
+
if (!plugin) throw new DisTubeError("NOT_SUPPORTED_URL");
|
|
1082
|
+
this.debug(`[${plugin.constructor.name}] Resolving song from url: ${input}`);
|
|
1083
|
+
return plugin.resolve(input, options);
|
|
1084
|
+
}
|
|
1085
|
+
try {
|
|
1086
|
+
const song = await __privateMethod(this, _DisTubeHandler_instances, searchSong_fn).call(this, input, options);
|
|
1087
|
+
if (song) return song;
|
|
1088
|
+
} catch {
|
|
1089
|
+
}
|
|
1341
1090
|
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
}
|
|
1355
|
-
/**
|
|
1356
|
-
* Resolve Song[] or YouTube playlist url to a Playlist
|
|
1357
|
-
*
|
|
1358
|
-
* @param playlist - Resolvable playlist
|
|
1359
|
-
* @param options - Optional options
|
|
1360
|
-
*/
|
|
1361
|
-
async resolvePlaylist(playlist, options = {}) {
|
|
1362
|
-
const { member, source, metadata } = { source: "youtube", ...options };
|
|
1363
|
-
if (playlist instanceof Playlist) {
|
|
1364
|
-
if ("metadata" in options)
|
|
1365
|
-
playlist.metadata = metadata;
|
|
1366
|
-
if ("member" in options)
|
|
1367
|
-
playlist.member = member;
|
|
1368
|
-
return playlist;
|
|
1369
|
-
}
|
|
1370
|
-
if (typeof playlist === "string") {
|
|
1371
|
-
const info = await (0, import_ytpl.default)(playlist, { limit: Infinity, requestOptions: { headers: { cookie: this.ytCookie } } });
|
|
1372
|
-
const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
|
|
1373
|
-
return new Playlist(
|
|
1374
|
-
{
|
|
1375
|
-
source,
|
|
1376
|
-
songs,
|
|
1377
|
-
member,
|
|
1378
|
-
name: info.title,
|
|
1379
|
-
url: info.url,
|
|
1380
|
-
thumbnail: songs[0].thumbnail
|
|
1381
|
-
},
|
|
1382
|
-
{ metadata }
|
|
1383
|
-
);
|
|
1384
|
-
}
|
|
1385
|
-
return new Playlist(playlist, { member, properties: { source }, metadata });
|
|
1386
|
-
}
|
|
1387
|
-
/**
|
|
1388
|
-
* Search for a song, fire {@link DisTube#error} if not found.
|
|
1389
|
-
*
|
|
1390
|
-
* @throws {@link DisTubeError}
|
|
1391
|
-
*
|
|
1392
|
-
* @param message - The original message from an user
|
|
1393
|
-
* @param query - The query string
|
|
1394
|
-
*
|
|
1395
|
-
* @returns Song info
|
|
1396
|
-
*/
|
|
1397
|
-
async searchSong(message, query) {
|
|
1398
|
-
if (!isMessageInstance(message))
|
|
1399
|
-
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1400
|
-
if (typeof query !== "string")
|
|
1401
|
-
throw new DisTubeError("INVALID_TYPE", "string", query, "query");
|
|
1402
|
-
if (query.length === 0)
|
|
1403
|
-
throw new DisTubeError("EMPTY_STRING", "query");
|
|
1404
|
-
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1405
|
-
const results = await this.distube.search(query, {
|
|
1406
|
-
limit,
|
|
1407
|
-
safeSearch: this.options.nsfw ? false : !isNsfwChannel(message.channel)
|
|
1408
|
-
}).catch(() => {
|
|
1409
|
-
if (!this.emit("searchNoResult" /* SEARCH_NO_RESULT */, message, query)) {
|
|
1410
|
-
console.warn("searchNoResult event does not have any listeners! Emits `error` event instead.");
|
|
1411
|
-
throw new DisTubeError("NO_RESULT");
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1414
|
-
if (!results)
|
|
1415
|
-
return null;
|
|
1416
|
-
return this.createSearchMessageCollector(message, results, query);
|
|
1417
|
-
}
|
|
1418
|
-
/**
|
|
1419
|
-
* Create a message collector for selecting search results.
|
|
1420
|
-
*
|
|
1421
|
-
* Needed events: {@link DisTube#searchResult}, {@link DisTube#searchCancel},
|
|
1422
|
-
* {@link DisTube#searchInvalidAnswer}, {@link DisTube#searchDone}.
|
|
1423
|
-
*
|
|
1424
|
-
* @throws {@link DisTubeError}
|
|
1425
|
-
*
|
|
1426
|
-
* @param message - The original message from an user
|
|
1427
|
-
* @param results - The search results
|
|
1428
|
-
* @param query - The query string
|
|
1429
|
-
*
|
|
1430
|
-
* @returns Selected result
|
|
1431
|
-
*/
|
|
1432
|
-
async createSearchMessageCollector(message, results, query) {
|
|
1433
|
-
if (!isMessageInstance(message))
|
|
1434
|
-
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1435
|
-
if (!Array.isArray(results) || results.length === 0) {
|
|
1436
|
-
throw new DisTubeError("INVALID_TYPE", "Array<SearchResult|Song|Playlist>", results, "results");
|
|
1437
|
-
}
|
|
1438
|
-
if (this.options.searchSongs > 1) {
|
|
1439
|
-
const searchEvents = [
|
|
1440
|
-
"searchNoResult" /* SEARCH_NO_RESULT */,
|
|
1441
|
-
"searchResult" /* SEARCH_RESULT */,
|
|
1442
|
-
"searchCancel" /* SEARCH_CANCEL */,
|
|
1443
|
-
"searchInvalidAnswer" /* SEARCH_INVALID_ANSWER */,
|
|
1444
|
-
"searchDone" /* SEARCH_DONE */
|
|
1445
|
-
];
|
|
1446
|
-
for (const evn of searchEvents) {
|
|
1447
|
-
if (this.distube.listenerCount(evn) === 0) {
|
|
1448
|
-
console.warn(`"searchSongs" option is disabled due to missing "${evn}" listener.`);
|
|
1449
|
-
console.warn(
|
|
1450
|
-
`If you don't want to use "${evn}" event, simply add an empty listener (not recommended):
|
|
1451
|
-
<DisTube>.on("${evn}", () => {})`
|
|
1452
|
-
);
|
|
1453
|
-
this.options.searchSongs = 0;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1458
|
-
let result = results[0];
|
|
1459
|
-
if (limit > 1) {
|
|
1460
|
-
results.splice(limit);
|
|
1461
|
-
this.emit("searchResult" /* SEARCH_RESULT */, message, results, query);
|
|
1462
|
-
const answers = await message.channel.awaitMessages({
|
|
1463
|
-
filter: (m) => m.author.id === message.author.id,
|
|
1464
|
-
max: 1,
|
|
1465
|
-
time: this.options.searchCooldown * 1e3,
|
|
1466
|
-
errors: ["time"]
|
|
1467
|
-
}).catch(() => void 0);
|
|
1468
|
-
const ans = answers?.first();
|
|
1469
|
-
if (!ans) {
|
|
1470
|
-
this.emit("searchCancel" /* SEARCH_CANCEL */, message, query);
|
|
1471
|
-
return null;
|
|
1472
|
-
}
|
|
1473
|
-
const index = parseInt(ans.content, 10);
|
|
1474
|
-
if (isNaN(index) || index > results.length || index < 1) {
|
|
1475
|
-
this.emit("searchInvalidAnswer" /* SEARCH_INVALID_ANSWER */, message, ans, query);
|
|
1476
|
-
return null;
|
|
1477
|
-
}
|
|
1478
|
-
this.emit("searchDone" /* SEARCH_DONE */, message, ans, query);
|
|
1479
|
-
result = results[index - 1];
|
|
1480
|
-
}
|
|
1481
|
-
return result;
|
|
1482
|
-
}
|
|
1483
|
-
/**
|
|
1484
|
-
* Play or add a {@link Playlist} to the queue.
|
|
1485
|
-
*
|
|
1486
|
-
* @throws {@link DisTubeError}
|
|
1487
|
-
*
|
|
1488
|
-
* @param voiceChannel - A voice channel
|
|
1489
|
-
* @param playlist - A YouTube playlist url | a Playlist
|
|
1490
|
-
* @param options - Optional options
|
|
1491
|
-
*/
|
|
1492
|
-
async playPlaylist(voiceChannel, playlist, options = {}) {
|
|
1493
|
-
const { textChannel, skip } = { skip: false, ...options };
|
|
1494
|
-
const position = Number(options.position) || (skip ? 1 : 0);
|
|
1495
|
-
if (!(playlist instanceof Playlist))
|
|
1496
|
-
throw new DisTubeError("INVALID_TYPE", "Playlist", playlist, "playlist");
|
|
1497
|
-
const queue = this.queues.get(voiceChannel);
|
|
1498
|
-
const isNsfw = isNsfwChannel(queue?.textChannel || textChannel);
|
|
1499
|
-
if (!this.options.nsfw && !isNsfw)
|
|
1500
|
-
playlist.songs = playlist.songs.filter((s) => !s.age_restricted);
|
|
1501
|
-
if (!playlist.songs.length) {
|
|
1502
|
-
if (!this.options.nsfw && !isNsfw)
|
|
1503
|
-
throw new DisTubeError("EMPTY_FILTERED_PLAYLIST");
|
|
1504
|
-
throw new DisTubeError("EMPTY_PLAYLIST");
|
|
1505
|
-
}
|
|
1506
|
-
if (queue) {
|
|
1507
|
-
if (this.options.joinNewVoiceChannel)
|
|
1508
|
-
queue.voice.channel = voiceChannel;
|
|
1509
|
-
queue.addToQueue(playlist.songs, position);
|
|
1510
|
-
if (skip)
|
|
1511
|
-
queue.skip();
|
|
1512
|
-
else
|
|
1513
|
-
this.emit("addList" /* ADD_LIST */, queue, playlist);
|
|
1514
|
-
} else {
|
|
1515
|
-
const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);
|
|
1516
|
-
if (newQueue instanceof Queue) {
|
|
1517
|
-
if (this.options.emitAddListWhenCreatingQueue)
|
|
1518
|
-
this.emit("addList" /* ADD_LIST */, newQueue, playlist);
|
|
1519
|
-
this.emit("playSong" /* PLAY_SONG */, newQueue, newQueue.songs[0]);
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
/**
|
|
1524
|
-
* Play or add a {@link Song} to the queue.
|
|
1525
|
-
*
|
|
1526
|
-
* @throws {@link DisTubeError}
|
|
1527
|
-
*
|
|
1528
|
-
* @param voiceChannel - A voice channel
|
|
1529
|
-
* @param song - A YouTube playlist url | a Playlist
|
|
1530
|
-
* @param options - Optional options
|
|
1531
|
-
*/
|
|
1532
|
-
async playSong(voiceChannel, song, options = {}) {
|
|
1533
|
-
if (!(song instanceof Song))
|
|
1534
|
-
throw new DisTubeError("INVALID_TYPE", "Song", song, "song");
|
|
1535
|
-
const { textChannel, skip } = { skip: false, ...options };
|
|
1536
|
-
const position = Number(options.position) || (skip ? 1 : 0);
|
|
1537
|
-
const queue = this.queues.get(voiceChannel);
|
|
1538
|
-
if (!this.options.nsfw && song.age_restricted && !isNsfwChannel(queue?.textChannel || textChannel)) {
|
|
1539
|
-
throw new DisTubeError("NON_NSFW");
|
|
1540
|
-
}
|
|
1541
|
-
if (queue) {
|
|
1542
|
-
if (this.options.joinNewVoiceChannel)
|
|
1543
|
-
queue.voice.channel = voiceChannel;
|
|
1544
|
-
queue.addToQueue(song, position);
|
|
1545
|
-
if (skip)
|
|
1546
|
-
queue.skip();
|
|
1547
|
-
else
|
|
1548
|
-
this.emit("addSong" /* ADD_SONG */, queue, song);
|
|
1549
|
-
} else {
|
|
1550
|
-
const newQueue = await this.queues.create(voiceChannel, song, textChannel);
|
|
1551
|
-
if (newQueue instanceof Queue) {
|
|
1552
|
-
if (this.options.emitAddSongWhenCreatingQueue)
|
|
1553
|
-
this.emit("addSong" /* ADD_SONG */, newQueue, song);
|
|
1554
|
-
this.emit("playSong" /* PLAY_SONG */, newQueue, song);
|
|
1091
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", input);
|
|
1092
|
+
}
|
|
1093
|
+
async _getPluginFromURL(url) {
|
|
1094
|
+
for (const plugin of this.plugins) if (await plugin.validate(url)) return plugin;
|
|
1095
|
+
return null;
|
|
1096
|
+
}
|
|
1097
|
+
async _getPluginFromSong(song, types, validate = true) {
|
|
1098
|
+
if (!types || types.includes(song.plugin?.type)) return song.plugin;
|
|
1099
|
+
if (!song.url) return null;
|
|
1100
|
+
for (const plugin of this.plugins) {
|
|
1101
|
+
if ((!types || types.includes(plugin?.type)) && (!validate || await plugin.validate(song.url))) {
|
|
1102
|
+
return plugin;
|
|
1555
1103
|
}
|
|
1556
1104
|
}
|
|
1105
|
+
return null;
|
|
1557
1106
|
}
|
|
1558
1107
|
/**
|
|
1559
1108
|
* Get {@link Song}'s stream info and attach it to the song.
|
|
1560
|
-
*
|
|
1561
1109
|
* @param song - A Song
|
|
1562
1110
|
*/
|
|
1563
1111
|
async attachStreamInfo(song) {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1112
|
+
if (song.stream.playFromSource) {
|
|
1113
|
+
if (song.stream.url) return;
|
|
1114
|
+
this.debug(`[DisTubeHandler] Getting stream info: ${song}`);
|
|
1115
|
+
const plugin = await this._getPluginFromSong(song, ["extractor" /* EXTRACTOR */, "playable-extractor" /* PLAYABLE_EXTRACTOR */]);
|
|
1116
|
+
if (!plugin) throw new DisTubeError("NOT_SUPPORTED_SONG", song.toString());
|
|
1117
|
+
this.debug(`[${plugin.constructor.name}] Getting stream URL: ${song}`);
|
|
1118
|
+
song.stream.url = await plugin.getStreamURL(song);
|
|
1119
|
+
if (!song.stream.url) throw new DisTubeError("CANNOT_GET_STREAM_URL", song.toString());
|
|
1567
1120
|
} else {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1121
|
+
if (song.stream.song?.stream?.playFromSource && song.stream.song.stream.url) return;
|
|
1122
|
+
this.debug(`[DisTubeHandler] Getting stream info: ${song}`);
|
|
1123
|
+
const plugin = await this._getPluginFromSong(song, ["info-extractor" /* INFO_EXTRACTOR */]);
|
|
1124
|
+
if (!plugin) throw new DisTubeError("NOT_SUPPORTED_SONG", song.toString());
|
|
1125
|
+
this.debug(`[${plugin.constructor.name}] Creating search query for: ${song}`);
|
|
1126
|
+
const query = await plugin.createSearchQuery(song);
|
|
1127
|
+
if (!query) throw new DisTubeError("CANNOT_GET_SEARCH_QUERY", song.toString());
|
|
1128
|
+
const altSong = await __privateMethod(this, _DisTubeHandler_instances, searchSong_fn).call(this, query, { metadata: song.metadata, member: song.member }, true);
|
|
1129
|
+
if (!altSong || !altSong.stream.playFromSource) throw new DisTubeError("NO_RESULT", query || song.toString());
|
|
1130
|
+
song.stream.song = altSong;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async followRedirectLink(url, maxRedirect = 5) {
|
|
1134
|
+
if (maxRedirect === 0) return url;
|
|
1135
|
+
const res = await (0, import_undici.request)(url, {
|
|
1136
|
+
method: "HEAD",
|
|
1137
|
+
headers: {
|
|
1138
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
|
|
1576
1139
|
}
|
|
1140
|
+
});
|
|
1141
|
+
if (REDIRECT_CODES.has(res.statusCode ?? 200)) {
|
|
1142
|
+
let location = res.headers.location;
|
|
1143
|
+
if (typeof location !== "string") location = location?.[0] ?? url;
|
|
1144
|
+
return this.followRedirectLink(location, --maxRedirect);
|
|
1577
1145
|
}
|
|
1146
|
+
return url;
|
|
1578
1147
|
}
|
|
1579
1148
|
};
|
|
1580
|
-
|
|
1149
|
+
_DisTubeHandler_instances = new WeakSet();
|
|
1150
|
+
searchSong_fn = /* @__PURE__ */ __name(async function(query, options = {}, getStreamURL = false) {
|
|
1151
|
+
for (const plugin of this.plugins) {
|
|
1152
|
+
if (plugin.type === "extractor" /* EXTRACTOR */) {
|
|
1153
|
+
this.debug(`[${plugin.constructor.name}] Searching for song: ${query}`);
|
|
1154
|
+
const result = await plugin.searchSong(query, options);
|
|
1155
|
+
if (result) {
|
|
1156
|
+
if (getStreamURL && result.stream.playFromSource) result.stream.url = await plugin.getStreamURL(result);
|
|
1157
|
+
return result;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return null;
|
|
1162
|
+
}, "#searchSong");
|
|
1581
1163
|
__name(_DisTubeHandler, "DisTubeHandler");
|
|
1582
1164
|
var DisTubeHandler = _DisTubeHandler;
|
|
1583
1165
|
|
|
1584
1166
|
// src/core/DisTubeOptions.ts
|
|
1585
|
-
var
|
|
1167
|
+
var _Options_instances, validateOptions_fn, ffmpegOption_fn;
|
|
1586
1168
|
var _Options = class _Options {
|
|
1587
1169
|
constructor(options) {
|
|
1588
|
-
__privateAdd(this,
|
|
1589
|
-
__privateAdd(this, _ffmpegOption);
|
|
1170
|
+
__privateAdd(this, _Options_instances);
|
|
1590
1171
|
__publicField(this, "plugins");
|
|
1591
1172
|
__publicField(this, "emitNewSongOnly");
|
|
1592
|
-
__publicField(this, "leaveOnFinish");
|
|
1593
|
-
__publicField(this, "leaveOnStop");
|
|
1594
|
-
__publicField(this, "leaveOnEmpty");
|
|
1595
|
-
__publicField(this, "emptyCooldown");
|
|
1596
1173
|
__publicField(this, "savePreviousSongs");
|
|
1597
|
-
__publicField(this, "searchSongs");
|
|
1598
|
-
__publicField(this, "searchCooldown");
|
|
1599
|
-
__publicField(this, "youtubeCookie");
|
|
1600
1174
|
__publicField(this, "customFilters");
|
|
1601
|
-
__publicField(this, "ytdlOptions");
|
|
1602
1175
|
__publicField(this, "nsfw");
|
|
1603
1176
|
__publicField(this, "emitAddSongWhenCreatingQueue");
|
|
1604
1177
|
__publicField(this, "emitAddListWhenCreatingQueue");
|
|
1605
1178
|
__publicField(this, "joinNewVoiceChannel");
|
|
1606
|
-
__publicField(this, "streamType");
|
|
1607
|
-
__publicField(this, "directLink");
|
|
1608
|
-
/** @deprecated */
|
|
1609
|
-
__publicField(this, "ffmpegPath");
|
|
1610
|
-
/** @deprecated */
|
|
1611
|
-
__publicField(this, "ffmpegDefaultArgs");
|
|
1612
1179
|
__publicField(this, "ffmpeg");
|
|
1613
1180
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
1614
1181
|
throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
|
|
@@ -1616,53 +1183,34 @@ var _Options = class _Options {
|
|
|
1616
1183
|
const opts = { ...defaultOptions, ...options };
|
|
1617
1184
|
this.plugins = opts.plugins;
|
|
1618
1185
|
this.emitNewSongOnly = opts.emitNewSongOnly;
|
|
1619
|
-
this.leaveOnEmpty = opts.leaveOnEmpty;
|
|
1620
|
-
this.leaveOnFinish = opts.leaveOnFinish;
|
|
1621
|
-
this.leaveOnStop = opts.leaveOnStop;
|
|
1622
1186
|
this.savePreviousSongs = opts.savePreviousSongs;
|
|
1623
|
-
this.searchSongs = opts.searchSongs;
|
|
1624
|
-
this.youtubeCookie = opts.youtubeCookie;
|
|
1625
1187
|
this.customFilters = opts.customFilters;
|
|
1626
|
-
this.ytdlOptions = opts.ytdlOptions;
|
|
1627
|
-
this.searchCooldown = opts.searchCooldown;
|
|
1628
|
-
this.emptyCooldown = opts.emptyCooldown;
|
|
1629
1188
|
this.nsfw = opts.nsfw;
|
|
1630
1189
|
this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
|
|
1631
1190
|
this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
|
|
1632
1191
|
this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
|
|
1633
|
-
this.
|
|
1634
|
-
this.directLink = opts.directLink;
|
|
1635
|
-
this.ffmpeg = __privateMethod(this, _ffmpegOption, ffmpegOption_fn).call(this, options);
|
|
1192
|
+
this.ffmpeg = __privateMethod(this, _Options_instances, ffmpegOption_fn).call(this, options);
|
|
1636
1193
|
checkInvalidKey(opts, this, "DisTubeOptions");
|
|
1637
|
-
__privateMethod(this,
|
|
1194
|
+
__privateMethod(this, _Options_instances, validateOptions_fn).call(this);
|
|
1638
1195
|
}
|
|
1639
1196
|
};
|
|
1640
|
-
|
|
1197
|
+
_Options_instances = new WeakSet();
|
|
1641
1198
|
validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
|
|
1642
1199
|
const booleanOptions = /* @__PURE__ */ new Set([
|
|
1643
1200
|
"emitNewSongOnly",
|
|
1644
|
-
"leaveOnEmpty",
|
|
1645
|
-
"leaveOnFinish",
|
|
1646
|
-
"leaveOnStop",
|
|
1647
1201
|
"savePreviousSongs",
|
|
1648
1202
|
"joinNewVoiceChannel",
|
|
1649
1203
|
"nsfw",
|
|
1650
1204
|
"emitAddSongWhenCreatingQueue",
|
|
1651
|
-
"emitAddListWhenCreatingQueue"
|
|
1652
|
-
"directLink"
|
|
1205
|
+
"emitAddListWhenCreatingQueue"
|
|
1653
1206
|
]);
|
|
1654
|
-
const numberOptions = /* @__PURE__ */ new Set(
|
|
1207
|
+
const numberOptions = /* @__PURE__ */ new Set();
|
|
1655
1208
|
const stringOptions = /* @__PURE__ */ new Set();
|
|
1656
|
-
const objectOptions = /* @__PURE__ */ new Set(["customFilters", "
|
|
1657
|
-
const optionalOptions = /* @__PURE__ */ new Set(["
|
|
1209
|
+
const objectOptions = /* @__PURE__ */ new Set(["customFilters", "ffmpeg"]);
|
|
1210
|
+
const optionalOptions = /* @__PURE__ */ new Set(["customFilters"]);
|
|
1658
1211
|
for (const [key, value] of Object.entries(options)) {
|
|
1659
|
-
if (value === void 0 && optionalOptions.has(key))
|
|
1660
|
-
|
|
1661
|
-
if (key === "youtubeCookie" && !Array.isArray(value) && typeof value !== "string") {
|
|
1662
|
-
throw new DisTubeError("INVALID_TYPE", ["Array<Cookie>", "string"], value, `DisTubeOptions.${key}`);
|
|
1663
|
-
} else if (key === "streamType" && (typeof value !== "number" || isNaN(value) || !StreamType[value])) {
|
|
1664
|
-
throw new DisTubeError("INVALID_TYPE", "StreamType", value, `DisTubeOptions.${key}`);
|
|
1665
|
-
} else if (key === "plugins" && !Array.isArray(value)) {
|
|
1212
|
+
if (value === void 0 && optionalOptions.has(key)) continue;
|
|
1213
|
+
if (key === "plugins" && !Array.isArray(value)) {
|
|
1666
1214
|
throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", value, `DisTubeOptions.${key}`);
|
|
1667
1215
|
} else if (booleanOptions.has(key)) {
|
|
1668
1216
|
if (typeof value !== "boolean") {
|
|
@@ -1683,26 +1231,31 @@ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
|
|
|
1683
1231
|
}
|
|
1684
1232
|
}
|
|
1685
1233
|
}, "#validateOptions");
|
|
1686
|
-
_ffmpegOption = new WeakSet();
|
|
1687
1234
|
ffmpegOption_fn = /* @__PURE__ */ __name(function(opts) {
|
|
1688
|
-
let path;
|
|
1689
1235
|
const args = { global: {}, input: {}, output: {} };
|
|
1690
|
-
if (opts.ffmpegPath) {
|
|
1691
|
-
console.warn("`DisTubeOptions.ffmpegPath` is deprecated. Use `ffmpeg.path` instead.");
|
|
1692
|
-
path = opts.ffmpegPath;
|
|
1693
|
-
}
|
|
1694
|
-
if (opts.ffmpegDefaultArgs) {
|
|
1695
|
-
console.warn("`DisTubeOptions.ffmpegDefaultArgs` is deprecated. Use `ffmpeg.args` instead.");
|
|
1696
|
-
args.global = opts.ffmpegDefaultArgs;
|
|
1697
|
-
}
|
|
1698
|
-
path ??= opts.ffmpeg?.path ?? `ffmpeg${process.platform === "win32" ? ".exe" : ""}`;
|
|
1699
1236
|
if (opts.ffmpeg?.args) {
|
|
1700
|
-
if (opts.ffmpeg.args.global)
|
|
1701
|
-
|
|
1702
|
-
if (opts.ffmpeg.args.
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1237
|
+
if (opts.ffmpeg.args.global) args.global = opts.ffmpeg.args.global;
|
|
1238
|
+
if (opts.ffmpeg.args.input) args.input = opts.ffmpeg.args.input;
|
|
1239
|
+
if (opts.ffmpeg.args.output) args.output = opts.ffmpeg.args.output;
|
|
1240
|
+
}
|
|
1241
|
+
const path = opts.ffmpeg?.path ?? "ffmpeg";
|
|
1242
|
+
if (typeof path !== "string") {
|
|
1243
|
+
throw new DisTubeError("INVALID_TYPE", "string", path, "DisTubeOptions.ffmpeg.path");
|
|
1244
|
+
}
|
|
1245
|
+
for (const [key, value] of Object.entries(args)) {
|
|
1246
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
1247
|
+
throw new DisTubeError("INVALID_TYPE", "object", value, `DisTubeOptions.ffmpeg.${key}`);
|
|
1248
|
+
}
|
|
1249
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1250
|
+
if (typeof v !== "string" && typeof v !== "number" && typeof v !== "boolean" && !Array.isArray(v) && v !== null && v !== void 0) {
|
|
1251
|
+
throw new DisTubeError(
|
|
1252
|
+
"INVALID_TYPE",
|
|
1253
|
+
["string", "number", "boolean", "Array<string | null | undefined>", "null", "undefined"],
|
|
1254
|
+
v,
|
|
1255
|
+
`DisTubeOptions.ffmpeg.${key}.${k}`
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1706
1259
|
}
|
|
1707
1260
|
return { path, args };
|
|
1708
1261
|
}, "#ffmpegOption");
|
|
@@ -1734,8 +1287,7 @@ var _GuildIdManager = class _GuildIdManager extends BaseManager {
|
|
|
1734
1287
|
add(idOrInstance, data) {
|
|
1735
1288
|
const id = resolveGuildId(idOrInstance);
|
|
1736
1289
|
const existing = this.get(id);
|
|
1737
|
-
if (existing)
|
|
1738
|
-
return this;
|
|
1290
|
+
if (existing) return this;
|
|
1739
1291
|
this.collection.set(id, data);
|
|
1740
1292
|
return this;
|
|
1741
1293
|
}
|
|
@@ -1756,16 +1308,7 @@ var GuildIdManager = _GuildIdManager;
|
|
|
1756
1308
|
var import_voice3 = require("@discordjs/voice");
|
|
1757
1309
|
var _DisTubeVoiceManager = class _DisTubeVoiceManager extends GuildIdManager {
|
|
1758
1310
|
/**
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1761
|
-
* @param guild - The queue resolvable to resolve
|
|
1762
|
-
*/
|
|
1763
|
-
/**
|
|
1764
|
-
* Collection of {@link DisTubeVoice}.
|
|
1765
|
-
*/
|
|
1766
|
-
/**
|
|
1767
|
-
* Create a {@link DisTubeVoice}
|
|
1768
|
-
*
|
|
1311
|
+
* Create a {@link DisTubeVoice} instance
|
|
1769
1312
|
* @param channel - A voice channel to join
|
|
1770
1313
|
*/
|
|
1771
1314
|
create(channel) {
|
|
@@ -1774,22 +1317,22 @@ var _DisTubeVoiceManager = class _DisTubeVoiceManager extends GuildIdManager {
|
|
|
1774
1317
|
existing.channel = channel;
|
|
1775
1318
|
return existing;
|
|
1776
1319
|
}
|
|
1320
|
+
if ((0, import_voice3.getVoiceConnection)(resolveGuildId(channel), this.client.user?.id) || (0, import_voice3.getVoiceConnection)(resolveGuildId(channel))) {
|
|
1321
|
+
throw new DisTubeError("VOICE_ALREADY_CREATED");
|
|
1322
|
+
}
|
|
1777
1323
|
return new DisTubeVoice(this, channel);
|
|
1778
1324
|
}
|
|
1779
1325
|
/**
|
|
1780
|
-
* Join a voice channel
|
|
1781
|
-
*
|
|
1326
|
+
* Join a voice channel and wait until the connection is ready
|
|
1782
1327
|
* @param channel - A voice channel to join
|
|
1783
1328
|
*/
|
|
1784
1329
|
join(channel) {
|
|
1785
1330
|
const existing = this.get(channel.guildId);
|
|
1786
|
-
if (existing)
|
|
1787
|
-
return existing.join(channel);
|
|
1331
|
+
if (existing) return existing.join(channel);
|
|
1788
1332
|
return this.create(channel).join();
|
|
1789
1333
|
}
|
|
1790
1334
|
/**
|
|
1791
1335
|
* Leave the connected voice channel in a guild
|
|
1792
|
-
*
|
|
1793
1336
|
* @param guild - Queue Resolvable
|
|
1794
1337
|
*/
|
|
1795
1338
|
leave(guild) {
|
|
@@ -1808,38 +1351,33 @@ __name(_DisTubeVoiceManager, "DisTubeVoiceManager");
|
|
|
1808
1351
|
var DisTubeVoiceManager = _DisTubeVoiceManager;
|
|
1809
1352
|
|
|
1810
1353
|
// src/core/manager/FilterManager.ts
|
|
1811
|
-
var
|
|
1354
|
+
var _FilterManager_instances, resolve_fn, apply_fn, removeFn_fn;
|
|
1812
1355
|
var _FilterManager = class _FilterManager extends BaseManager {
|
|
1813
1356
|
constructor(queue) {
|
|
1814
1357
|
super(queue.distube);
|
|
1815
|
-
__privateAdd(this,
|
|
1816
|
-
__privateAdd(this, _apply);
|
|
1817
|
-
__privateAdd(this, _removeFn);
|
|
1358
|
+
__privateAdd(this, _FilterManager_instances);
|
|
1818
1359
|
/**
|
|
1819
|
-
*
|
|
1360
|
+
* The queue to manage
|
|
1820
1361
|
*/
|
|
1821
1362
|
__publicField(this, "queue");
|
|
1822
1363
|
this.queue = queue;
|
|
1823
1364
|
}
|
|
1824
1365
|
/**
|
|
1825
1366
|
* Enable a filter or multiple filters to the manager
|
|
1826
|
-
*
|
|
1827
1367
|
* @param filterOrFilters - The filter or filters to enable
|
|
1828
1368
|
* @param override - Wether or not override the applied filter with new filter value
|
|
1829
1369
|
*/
|
|
1830
1370
|
add(filterOrFilters, override = false) {
|
|
1831
1371
|
if (Array.isArray(filterOrFilters)) {
|
|
1832
1372
|
for (const filter of filterOrFilters) {
|
|
1833
|
-
const ft = __privateMethod(this,
|
|
1834
|
-
if (override || !this.has(ft))
|
|
1835
|
-
this.collection.set(ft.name, ft);
|
|
1373
|
+
const ft = __privateMethod(this, _FilterManager_instances, resolve_fn).call(this, filter);
|
|
1374
|
+
if (override || !this.has(ft)) this.collection.set(ft.name, ft);
|
|
1836
1375
|
}
|
|
1837
1376
|
} else {
|
|
1838
|
-
const ft = __privateMethod(this,
|
|
1839
|
-
if (override || !this.has(ft))
|
|
1840
|
-
this.collection.set(ft.name, ft);
|
|
1377
|
+
const ft = __privateMethod(this, _FilterManager_instances, resolve_fn).call(this, filterOrFilters);
|
|
1378
|
+
if (override || !this.has(ft)) this.collection.set(ft.name, ft);
|
|
1841
1379
|
}
|
|
1842
|
-
__privateMethod(this,
|
|
1380
|
+
__privateMethod(this, _FilterManager_instances, apply_fn).call(this);
|
|
1843
1381
|
return this;
|
|
1844
1382
|
}
|
|
1845
1383
|
/**
|
|
@@ -1850,40 +1388,34 @@ var _FilterManager = class _FilterManager extends BaseManager {
|
|
|
1850
1388
|
}
|
|
1851
1389
|
/**
|
|
1852
1390
|
* Set the filters applied to the manager
|
|
1853
|
-
*
|
|
1854
1391
|
* @param filters - The filters to apply
|
|
1855
1392
|
*/
|
|
1856
1393
|
set(filters) {
|
|
1857
|
-
if (!Array.isArray(filters))
|
|
1858
|
-
throw new DisTubeError("INVALID_TYPE", "Array<FilterResolvable>", filters, "filters");
|
|
1394
|
+
if (!Array.isArray(filters)) throw new DisTubeError("INVALID_TYPE", "Array<FilterResolvable>", filters, "filters");
|
|
1859
1395
|
this.collection.clear();
|
|
1860
1396
|
for (const f of filters) {
|
|
1861
|
-
const filter = __privateMethod(this,
|
|
1397
|
+
const filter = __privateMethod(this, _FilterManager_instances, resolve_fn).call(this, f);
|
|
1862
1398
|
this.collection.set(filter.name, filter);
|
|
1863
1399
|
}
|
|
1864
|
-
__privateMethod(this,
|
|
1400
|
+
__privateMethod(this, _FilterManager_instances, apply_fn).call(this);
|
|
1865
1401
|
return this;
|
|
1866
1402
|
}
|
|
1867
1403
|
/**
|
|
1868
1404
|
* Disable a filter or multiple filters
|
|
1869
|
-
*
|
|
1870
1405
|
* @param filterOrFilters - The filter or filters to disable
|
|
1871
1406
|
*/
|
|
1872
1407
|
remove(filterOrFilters) {
|
|
1873
|
-
if (Array.isArray(filterOrFilters))
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
__privateMethod(this, _removeFn, removeFn_fn).call(this, filterOrFilters);
|
|
1877
|
-
__privateMethod(this, _apply, apply_fn).call(this);
|
|
1408
|
+
if (Array.isArray(filterOrFilters)) filterOrFilters.forEach((f) => __privateMethod(this, _FilterManager_instances, removeFn_fn).call(this, f));
|
|
1409
|
+
else __privateMethod(this, _FilterManager_instances, removeFn_fn).call(this, filterOrFilters);
|
|
1410
|
+
__privateMethod(this, _FilterManager_instances, apply_fn).call(this);
|
|
1878
1411
|
return this;
|
|
1879
1412
|
}
|
|
1880
1413
|
/**
|
|
1881
1414
|
* Check whether a filter enabled or not
|
|
1882
|
-
*
|
|
1883
1415
|
* @param filter - The filter to check
|
|
1884
1416
|
*/
|
|
1885
1417
|
has(filter) {
|
|
1886
|
-
return this.collection.has(typeof filter === "string" ? filter : __privateMethod(this,
|
|
1418
|
+
return this.collection.has(typeof filter === "string" ? filter : __privateMethod(this, _FilterManager_instances, resolve_fn).call(this, filter).name);
|
|
1887
1419
|
}
|
|
1888
1420
|
/**
|
|
1889
1421
|
* Array of enabled filter names
|
|
@@ -1904,7 +1436,7 @@ var _FilterManager = class _FilterManager extends BaseManager {
|
|
|
1904
1436
|
return this.names.toString();
|
|
1905
1437
|
}
|
|
1906
1438
|
};
|
|
1907
|
-
|
|
1439
|
+
_FilterManager_instances = new WeakSet();
|
|
1908
1440
|
resolve_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1909
1441
|
if (typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
|
|
1910
1442
|
return filter;
|
|
@@ -1917,232 +1449,179 @@ resolve_fn = /* @__PURE__ */ __name(function(filter) {
|
|
|
1917
1449
|
}
|
|
1918
1450
|
throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
|
|
1919
1451
|
}, "#resolve");
|
|
1920
|
-
_apply = new WeakSet();
|
|
1921
1452
|
apply_fn = /* @__PURE__ */ __name(function() {
|
|
1922
|
-
this.queue.
|
|
1923
|
-
this.
|
|
1453
|
+
this.queue._beginTime = this.queue.currentTime;
|
|
1454
|
+
this.queue.play(false);
|
|
1924
1455
|
}, "#apply");
|
|
1925
|
-
_removeFn = new WeakSet();
|
|
1926
1456
|
removeFn_fn = /* @__PURE__ */ __name(function(f) {
|
|
1927
|
-
return this.collection.delete(__privateMethod(this,
|
|
1457
|
+
return this.collection.delete(__privateMethod(this, _FilterManager_instances, resolve_fn).call(this, f).name);
|
|
1928
1458
|
}, "#removeFn");
|
|
1929
1459
|
__name(_FilterManager, "FilterManager");
|
|
1930
1460
|
var FilterManager = _FilterManager;
|
|
1931
1461
|
|
|
1932
1462
|
// src/core/manager/QueueManager.ts
|
|
1933
|
-
var
|
|
1463
|
+
var _QueueManager_instances, voiceEventHandler_fn, emitPlaySong_fn, handleSongFinish_fn, handlePlayingError_fn;
|
|
1934
1464
|
var _QueueManager = class _QueueManager extends GuildIdManager {
|
|
1935
1465
|
constructor() {
|
|
1936
1466
|
super(...arguments);
|
|
1937
|
-
|
|
1938
|
-
* Get a Queue from this QueueManager.
|
|
1939
|
-
*
|
|
1940
|
-
* @param guild - Resolvable thing from a guild
|
|
1941
|
-
*/
|
|
1942
|
-
/**
|
|
1943
|
-
* Listen to DisTubeVoice events and handle the Queue
|
|
1944
|
-
*
|
|
1945
|
-
* @param queue - Queue
|
|
1946
|
-
*/
|
|
1947
|
-
__privateAdd(this, _voiceEventHandler);
|
|
1948
|
-
/**
|
|
1949
|
-
* Whether or not emit playSong event
|
|
1950
|
-
*
|
|
1951
|
-
* @param queue - Queue
|
|
1952
|
-
*/
|
|
1953
|
-
__privateAdd(this, _emitPlaySong);
|
|
1954
|
-
/**
|
|
1955
|
-
* Handle the queue when a Song finish
|
|
1956
|
-
*
|
|
1957
|
-
* @param queue - queue
|
|
1958
|
-
*/
|
|
1959
|
-
__privateAdd(this, _handleSongFinish);
|
|
1960
|
-
/**
|
|
1961
|
-
* Handle error while playing
|
|
1962
|
-
*
|
|
1963
|
-
* @param queue - queue
|
|
1964
|
-
* @param error - error
|
|
1965
|
-
*/
|
|
1966
|
-
__privateAdd(this, _handlePlayingError);
|
|
1467
|
+
__privateAdd(this, _QueueManager_instances);
|
|
1967
1468
|
}
|
|
1968
|
-
/**
|
|
1969
|
-
* Collection of {@link Queue}.
|
|
1970
|
-
*/
|
|
1971
1469
|
/**
|
|
1972
1470
|
* Create a {@link Queue}
|
|
1973
|
-
*
|
|
1974
1471
|
* @param channel - A voice channel
|
|
1975
|
-
* @param song - First song
|
|
1976
1472
|
* @param textChannel - Default text channel
|
|
1977
|
-
*
|
|
1978
1473
|
* @returns Returns `true` if encounter an error
|
|
1979
1474
|
*/
|
|
1980
|
-
async create(channel,
|
|
1981
|
-
if (this.has(channel.guildId))
|
|
1982
|
-
|
|
1475
|
+
async create(channel, textChannel) {
|
|
1476
|
+
if (this.has(channel.guildId)) throw new DisTubeError("QUEUE_EXIST");
|
|
1477
|
+
this.debug(`[QueueManager] Creating queue for guild: ${channel.guildId}`);
|
|
1983
1478
|
const voice = this.voices.create(channel);
|
|
1984
|
-
const queue = new Queue(this.distube, voice,
|
|
1479
|
+
const queue = new Queue(this.distube, voice, textChannel);
|
|
1985
1480
|
await queue._taskQueue.queuing();
|
|
1986
1481
|
try {
|
|
1987
1482
|
checkFFmpeg(this.distube);
|
|
1483
|
+
this.debug(`[QueueManager] Joining voice channel: ${channel.id}`);
|
|
1988
1484
|
await voice.join();
|
|
1989
|
-
__privateMethod(this,
|
|
1485
|
+
__privateMethod(this, _QueueManager_instances, voiceEventHandler_fn).call(this, queue);
|
|
1990
1486
|
this.add(queue.id, queue);
|
|
1991
1487
|
this.emit("initQueue" /* INIT_QUEUE */, queue);
|
|
1992
|
-
|
|
1993
|
-
return err || queue;
|
|
1488
|
+
return queue;
|
|
1994
1489
|
} finally {
|
|
1995
1490
|
queue._taskQueue.resolve();
|
|
1996
1491
|
}
|
|
1997
1492
|
}
|
|
1998
1493
|
/**
|
|
1999
|
-
*
|
|
2000
|
-
*
|
|
2001
|
-
* @param
|
|
2002
|
-
*/
|
|
2003
|
-
createStream(queue) {
|
|
2004
|
-
const song = queue.songs[0];
|
|
2005
|
-
const { duration, source, streamURL } = song;
|
|
2006
|
-
const streamOptions = {
|
|
2007
|
-
ffmpeg: {
|
|
2008
|
-
path: this.options.ffmpeg.path,
|
|
2009
|
-
args: {
|
|
2010
|
-
global: { ...this.options.ffmpeg.args.global },
|
|
2011
|
-
input: { ...this.options.ffmpeg.args.input },
|
|
2012
|
-
output: { ...this.options.ffmpeg.args.output, ...queue.filters.ffmpegArgs }
|
|
2013
|
-
}
|
|
2014
|
-
},
|
|
2015
|
-
seek: duration ? queue.beginTime : void 0,
|
|
2016
|
-
type: this.options.streamType
|
|
2017
|
-
};
|
|
2018
|
-
if (source === "youtube")
|
|
2019
|
-
return DisTubeStream.YouTube(song, streamOptions);
|
|
2020
|
-
if (!streamURL)
|
|
2021
|
-
throw new Error("No streamURL, something went wrong");
|
|
2022
|
-
return DisTubeStream.DirectLink(streamURL, streamOptions);
|
|
2023
|
-
}
|
|
2024
|
-
/**
|
|
2025
|
-
* Play a song on voice connection
|
|
2026
|
-
*
|
|
2027
|
-
* @param queue - The guild queue
|
|
2028
|
-
*
|
|
2029
|
-
* @returns error?
|
|
1494
|
+
* Play a song on voice connection with queue properties
|
|
1495
|
+
* @param queue - The guild queue to play
|
|
1496
|
+
* @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event
|
|
2030
1497
|
*/
|
|
2031
|
-
async playSong(queue) {
|
|
2032
|
-
if (!queue)
|
|
2033
|
-
return true;
|
|
1498
|
+
async playSong(queue, emitPlaySong = true) {
|
|
1499
|
+
if (!queue) return;
|
|
2034
1500
|
if (queue.stopped || !queue.songs.length) {
|
|
2035
1501
|
queue.stop();
|
|
2036
|
-
return
|
|
1502
|
+
return;
|
|
2037
1503
|
}
|
|
2038
1504
|
try {
|
|
2039
1505
|
const song = queue.songs[0];
|
|
1506
|
+
this.debug(`[${queue.id}] Getting stream from: ${song}`);
|
|
2040
1507
|
await this.handler.attachStreamInfo(song);
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
}
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
1508
|
+
const willPlaySong = song.stream.playFromSource ? song : song.stream.song;
|
|
1509
|
+
const stream = willPlaySong?.stream;
|
|
1510
|
+
if (!willPlaySong || !stream?.playFromSource || !stream.url) throw new DisTubeError("NO_STREAM_URL", `${song}`);
|
|
1511
|
+
this.debug(`[${queue.id}] Creating DisTubeStream for: ${willPlaySong}`);
|
|
1512
|
+
const streamOptions = {
|
|
1513
|
+
ffmpeg: {
|
|
1514
|
+
path: this.options.ffmpeg.path,
|
|
1515
|
+
args: {
|
|
1516
|
+
global: { ...queue.ffmpegArgs.global },
|
|
1517
|
+
input: { ...queue.ffmpegArgs.input },
|
|
1518
|
+
output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs }
|
|
1519
|
+
}
|
|
1520
|
+
},
|
|
1521
|
+
seek: willPlaySong.duration ? queue._beginTime : void 0
|
|
1522
|
+
};
|
|
1523
|
+
const dtStream = new DisTubeStream(stream.url, streamOptions);
|
|
1524
|
+
dtStream.on("debug", (data) => this.emit("ffmpegDebug" /* FFMPEG_DEBUG */, `[${queue.id}] ${data}`));
|
|
1525
|
+
this.debug(`[${queue.id}] Started playing: ${willPlaySong}`);
|
|
1526
|
+
queue.voice.play(dtStream);
|
|
1527
|
+
if (emitPlaySong) this.emit("playSong" /* PLAY_SONG */, queue, song);
|
|
2050
1528
|
} catch (e) {
|
|
2051
|
-
__privateMethod(this,
|
|
2052
|
-
return true;
|
|
1529
|
+
__privateMethod(this, _QueueManager_instances, handlePlayingError_fn).call(this, queue, e);
|
|
2053
1530
|
}
|
|
2054
1531
|
}
|
|
2055
1532
|
};
|
|
2056
|
-
|
|
1533
|
+
_QueueManager_instances = new WeakSet();
|
|
1534
|
+
/**
|
|
1535
|
+
* Listen to DisTubeVoice events and handle the Queue
|
|
1536
|
+
* @param queue - Queue
|
|
1537
|
+
*/
|
|
2057
1538
|
voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
|
|
2058
1539
|
queue._listeners = {
|
|
2059
|
-
disconnect: (error) => {
|
|
1540
|
+
disconnect: /* @__PURE__ */ __name((error) => {
|
|
2060
1541
|
queue.remove();
|
|
2061
1542
|
this.emit("disconnect" /* DISCONNECT */, queue);
|
|
2062
|
-
if (error)
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
finish: () => __privateMethod(this, _handleSongFinish, handleSongFinish_fn).call(this, queue)
|
|
1543
|
+
if (error) this.emitError(error, queue, queue.songs?.[0]);
|
|
1544
|
+
}, "disconnect"),
|
|
1545
|
+
error: /* @__PURE__ */ __name((error) => __privateMethod(this, _QueueManager_instances, handlePlayingError_fn).call(this, queue, error), "error"),
|
|
1546
|
+
finish: /* @__PURE__ */ __name(() => __privateMethod(this, _QueueManager_instances, handleSongFinish_fn).call(this, queue), "finish")
|
|
2067
1547
|
};
|
|
2068
1548
|
for (const event of objectKeys(queue._listeners)) {
|
|
2069
1549
|
queue.voice.on(event, queue._listeners[event]);
|
|
2070
1550
|
}
|
|
2071
1551
|
}, "#voiceEventHandler");
|
|
2072
|
-
|
|
1552
|
+
/**
|
|
1553
|
+
* Whether or not emit playSong event
|
|
1554
|
+
* @param queue - Queue
|
|
1555
|
+
*/
|
|
2073
1556
|
emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
|
|
2074
1557
|
return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
|
|
2075
1558
|
}, "#emitPlaySong");
|
|
2076
|
-
_handleSongFinish = new WeakSet();
|
|
2077
1559
|
handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
|
|
1560
|
+
this.debug(`[QueueManager] Handling song finish: ${queue.id}`);
|
|
1561
|
+
const song = queue.songs[0];
|
|
2078
1562
|
this.emit("finishSong" /* FINISH_SONG */, queue, queue.songs[0]);
|
|
2079
1563
|
await queue._taskQueue.queuing();
|
|
2080
1564
|
try {
|
|
2081
|
-
if (queue.stopped)
|
|
2082
|
-
|
|
2083
|
-
if (queue.repeatMode === 2 /* QUEUE */ && !queue._prev)
|
|
2084
|
-
queue.songs.push(queue.songs[0]);
|
|
1565
|
+
if (queue.stopped) return;
|
|
1566
|
+
if (queue.repeatMode === 2 /* QUEUE */ && !queue._prev) queue.songs.push(song);
|
|
2085
1567
|
if (queue._prev) {
|
|
2086
|
-
if (queue.repeatMode === 2 /* QUEUE */)
|
|
2087
|
-
|
|
2088
|
-
else
|
|
2089
|
-
queue.songs.unshift(queue.previousSongs.pop());
|
|
1568
|
+
if (queue.repeatMode === 2 /* QUEUE */) queue.songs.unshift(queue.songs.pop());
|
|
1569
|
+
else queue.songs.unshift(queue.previousSongs.pop());
|
|
2090
1570
|
}
|
|
2091
1571
|
if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
|
|
2092
1572
|
if (queue.autoplay) {
|
|
2093
1573
|
try {
|
|
1574
|
+
this.debug(`[QueueManager] Adding related song: ${queue.id}`);
|
|
2094
1575
|
await queue.addRelatedSong();
|
|
2095
|
-
} catch {
|
|
2096
|
-
this.
|
|
1576
|
+
} catch (e) {
|
|
1577
|
+
this.debug(`[${queue.id}] Add related song error: ${e.message}`);
|
|
1578
|
+
this.emit("noRelated" /* NO_RELATED */, queue, e);
|
|
2097
1579
|
}
|
|
2098
1580
|
}
|
|
2099
1581
|
if (queue.songs.length <= 1) {
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
if (!queue.autoplay)
|
|
2103
|
-
this.emit("finish" /* FINISH */, queue);
|
|
1582
|
+
this.debug(`[${queue.id}] Queue is empty, stopping...`);
|
|
1583
|
+
if (!queue.autoplay) this.emit("finish" /* FINISH */, queue);
|
|
2104
1584
|
queue.remove();
|
|
2105
1585
|
return;
|
|
2106
1586
|
}
|
|
2107
1587
|
}
|
|
2108
|
-
const emitPlaySong = __privateMethod(this,
|
|
1588
|
+
const emitPlaySong = __privateMethod(this, _QueueManager_instances, emitPlaySong_fn).call(this, queue);
|
|
2109
1589
|
if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
|
|
2110
1590
|
const prev = queue.songs.shift();
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
if (this.options.savePreviousSongs)
|
|
2114
|
-
queue.previousSongs.push(prev);
|
|
2115
|
-
else
|
|
2116
|
-
queue.previousSongs.push({ id: prev.id });
|
|
1591
|
+
if (this.options.savePreviousSongs) queue.previousSongs.push(prev);
|
|
1592
|
+
else queue.previousSongs.push({ id: prev.id });
|
|
2117
1593
|
}
|
|
2118
1594
|
queue._next = queue._prev = false;
|
|
2119
|
-
queue.
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
1595
|
+
queue._beginTime = 0;
|
|
1596
|
+
if (song !== queue.songs[0]) {
|
|
1597
|
+
const playedSong = song.stream.playFromSource ? song : song.stream.song;
|
|
1598
|
+
if (playedSong?.stream.playFromSource) delete playedSong.stream.url;
|
|
1599
|
+
}
|
|
1600
|
+
await this.playSong(queue, emitPlaySong);
|
|
2123
1601
|
} finally {
|
|
2124
1602
|
queue._taskQueue.resolve();
|
|
2125
1603
|
}
|
|
2126
1604
|
}, "#handleSongFinish");
|
|
2127
|
-
|
|
1605
|
+
/**
|
|
1606
|
+
* Handle error while playing
|
|
1607
|
+
* @param queue - queue
|
|
1608
|
+
* @param error - error
|
|
1609
|
+
*/
|
|
2128
1610
|
handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
|
|
2129
1611
|
const song = queue.songs.shift();
|
|
2130
1612
|
try {
|
|
2131
1613
|
error.name = "PlayingError";
|
|
2132
|
-
error.message = `${error.message}
|
|
2133
|
-
Id: ${song.id}
|
|
2134
|
-
Name: ${song.name}`;
|
|
2135
1614
|
} catch {
|
|
2136
1615
|
}
|
|
2137
|
-
this.
|
|
1616
|
+
this.debug(`[${queue.id}] Error while playing: ${error.stack || error.message}`);
|
|
1617
|
+
this.emitError(error, queue, song);
|
|
2138
1618
|
if (queue.songs.length > 0) {
|
|
1619
|
+
this.debug(`[${queue.id}] Playing next song: ${queue.songs[0]}`);
|
|
2139
1620
|
queue._next = queue._prev = false;
|
|
2140
|
-
queue.
|
|
2141
|
-
this.playSong(queue)
|
|
2142
|
-
if (!e)
|
|
2143
|
-
this.emit("playSong" /* PLAY_SONG */, queue, queue.songs[0]);
|
|
2144
|
-
});
|
|
1621
|
+
queue._beginTime = 0;
|
|
1622
|
+
this.playSong(queue);
|
|
2145
1623
|
} else {
|
|
1624
|
+
this.debug(`[${queue.id}] Queue is empty, stopping...`);
|
|
2146
1625
|
queue.stop();
|
|
2147
1626
|
}
|
|
2148
1627
|
}, "#handlePlayingError");
|
|
@@ -2150,53 +1629,106 @@ __name(_QueueManager, "QueueManager");
|
|
|
2150
1629
|
var QueueManager = _QueueManager;
|
|
2151
1630
|
|
|
2152
1631
|
// src/struct/Queue.ts
|
|
2153
|
-
var _filters;
|
|
1632
|
+
var _filters, _Queue_instances, getRelatedSong_fn;
|
|
2154
1633
|
var _Queue = class _Queue extends DisTubeBase {
|
|
2155
1634
|
/**
|
|
2156
1635
|
* Create a queue for the guild
|
|
2157
|
-
*
|
|
2158
1636
|
* @param distube - DisTube
|
|
2159
1637
|
* @param voice - Voice connection
|
|
2160
|
-
* @param song - First song(s)
|
|
2161
1638
|
* @param textChannel - Default text channel
|
|
2162
1639
|
*/
|
|
2163
|
-
constructor(distube, voice,
|
|
1640
|
+
constructor(distube, voice, textChannel) {
|
|
2164
1641
|
super(distube);
|
|
1642
|
+
__privateAdd(this, _Queue_instances);
|
|
1643
|
+
/**
|
|
1644
|
+
* Queue id (Guild id)
|
|
1645
|
+
*/
|
|
2165
1646
|
__publicField(this, "id");
|
|
1647
|
+
/**
|
|
1648
|
+
* Voice connection of this queue.
|
|
1649
|
+
*/
|
|
2166
1650
|
__publicField(this, "voice");
|
|
1651
|
+
/**
|
|
1652
|
+
* List of songs in the queue (The first one is the playing song)
|
|
1653
|
+
*/
|
|
2167
1654
|
__publicField(this, "songs");
|
|
1655
|
+
/**
|
|
1656
|
+
* List of the previous songs.
|
|
1657
|
+
*/
|
|
2168
1658
|
__publicField(this, "previousSongs");
|
|
1659
|
+
/**
|
|
1660
|
+
* Whether stream is currently stopped.
|
|
1661
|
+
*/
|
|
2169
1662
|
__publicField(this, "stopped");
|
|
2170
|
-
|
|
2171
|
-
|
|
1663
|
+
/**
|
|
1664
|
+
* Whether or not the stream is currently playing.
|
|
1665
|
+
*/
|
|
2172
1666
|
__publicField(this, "playing");
|
|
1667
|
+
/**
|
|
1668
|
+
* Whether or not the stream is currently paused.
|
|
1669
|
+
*/
|
|
2173
1670
|
__publicField(this, "paused");
|
|
1671
|
+
/**
|
|
1672
|
+
* Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating
|
|
1673
|
+
* all the queue). Default value: `0` (disabled)
|
|
1674
|
+
*/
|
|
2174
1675
|
__publicField(this, "repeatMode");
|
|
1676
|
+
/**
|
|
1677
|
+
* Whether or not the autoplay mode is enabled. Default value: `false`
|
|
1678
|
+
*/
|
|
2175
1679
|
__publicField(this, "autoplay");
|
|
2176
|
-
|
|
2177
|
-
|
|
1680
|
+
/**
|
|
1681
|
+
* FFmpeg arguments for the current queue. Default value is defined with {@link DisTubeOptions}.ffmpeg.args.
|
|
1682
|
+
* `af` output argument will be replaced with {@link Queue#filters} manager
|
|
1683
|
+
*/
|
|
1684
|
+
__publicField(this, "ffmpegArgs");
|
|
1685
|
+
/**
|
|
1686
|
+
* The text channel of the Queue. (Default: where the first command is called).
|
|
1687
|
+
*/
|
|
2178
1688
|
__publicField(this, "textChannel");
|
|
2179
|
-
|
|
1689
|
+
__privateAdd(this, _filters);
|
|
1690
|
+
/**
|
|
1691
|
+
* What time in the song to begin (in seconds).
|
|
1692
|
+
*/
|
|
1693
|
+
__publicField(this, "_beginTime");
|
|
1694
|
+
/**
|
|
1695
|
+
* Whether or not the last song was skipped to next song.
|
|
1696
|
+
*/
|
|
1697
|
+
__publicField(this, "_next");
|
|
1698
|
+
/**
|
|
1699
|
+
* Whether or not the last song was skipped to previous song.
|
|
1700
|
+
*/
|
|
1701
|
+
__publicField(this, "_prev");
|
|
1702
|
+
/**
|
|
1703
|
+
* Task queuing system
|
|
1704
|
+
*/
|
|
2180
1705
|
__publicField(this, "_taskQueue");
|
|
1706
|
+
/**
|
|
1707
|
+
* {@link DisTubeVoice} listener
|
|
1708
|
+
*/
|
|
2181
1709
|
__publicField(this, "_listeners");
|
|
2182
1710
|
this.voice = voice;
|
|
2183
1711
|
this.id = voice.id;
|
|
2184
1712
|
this.volume = 50;
|
|
2185
|
-
this.songs =
|
|
1713
|
+
this.songs = [];
|
|
2186
1714
|
this.previousSongs = [];
|
|
2187
1715
|
this.stopped = false;
|
|
2188
1716
|
this._next = false;
|
|
2189
1717
|
this._prev = false;
|
|
2190
|
-
this.playing =
|
|
1718
|
+
this.playing = false;
|
|
2191
1719
|
this.paused = false;
|
|
2192
1720
|
this.repeatMode = 0 /* DISABLED */;
|
|
2193
1721
|
this.autoplay = false;
|
|
2194
1722
|
__privateSet(this, _filters, new FilterManager(this));
|
|
2195
|
-
this.
|
|
1723
|
+
this._beginTime = 0;
|
|
2196
1724
|
this.textChannel = textChannel;
|
|
2197
|
-
this._emptyTimeout = void 0;
|
|
2198
1725
|
this._taskQueue = new TaskQueue();
|
|
2199
1726
|
this._listeners = void 0;
|
|
1727
|
+
this.ffmpegArgs = {
|
|
1728
|
+
global: { ...this.options.ffmpeg.args.global },
|
|
1729
|
+
input: { ...this.options.ffmpeg.args.input },
|
|
1730
|
+
output: { ...this.options.ffmpeg.args.output }
|
|
1731
|
+
};
|
|
2200
1732
|
}
|
|
2201
1733
|
/**
|
|
2202
1734
|
* The client user as a `GuildMember` of this queue's guild
|
|
@@ -2226,7 +1758,7 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2226
1758
|
* What time in the song is playing (in seconds).
|
|
2227
1759
|
*/
|
|
2228
1760
|
get currentTime() {
|
|
2229
|
-
return this.voice.playbackDuration + this.
|
|
1761
|
+
return this.voice.playbackDuration + this._beginTime;
|
|
2230
1762
|
}
|
|
2231
1763
|
/**
|
|
2232
1764
|
* Formatted {@link Queue#currentTime} string.
|
|
@@ -2240,6 +1772,9 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2240
1772
|
get voiceChannel() {
|
|
2241
1773
|
return this.clientMember?.voice?.channel ?? null;
|
|
2242
1774
|
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Get or set the stream volume. Default value: `50`.
|
|
1777
|
+
*/
|
|
2243
1778
|
get volume() {
|
|
2244
1779
|
return this.voice.volume;
|
|
2245
1780
|
}
|
|
@@ -2248,13 +1783,12 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2248
1783
|
}
|
|
2249
1784
|
/**
|
|
2250
1785
|
* @throws {DisTubeError}
|
|
2251
|
-
*
|
|
2252
1786
|
* @param song - Song to add
|
|
2253
1787
|
* @param position - Position to add, \<= 0 to add to the end of the queue
|
|
2254
|
-
*
|
|
2255
1788
|
* @returns The guild queue
|
|
2256
1789
|
*/
|
|
2257
1790
|
addToQueue(song, position = 0) {
|
|
1791
|
+
if (this.stopped) throw new DisTubeError("QUEUE_STOPPED");
|
|
2258
1792
|
if (!song || Array.isArray(song) && !song.length) {
|
|
2259
1793
|
throw new DisTubeError("INVALID_TYPE", ["Song", "Array<Song>"], song, "song");
|
|
2260
1794
|
}
|
|
@@ -2262,52 +1796,38 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2262
1796
|
throw new DisTubeError("INVALID_TYPE", "integer", position, "position");
|
|
2263
1797
|
}
|
|
2264
1798
|
if (position <= 0) {
|
|
2265
|
-
if (Array.isArray(song))
|
|
2266
|
-
|
|
2267
|
-
else
|
|
2268
|
-
this.songs.push(song);
|
|
1799
|
+
if (Array.isArray(song)) this.songs.push(...song);
|
|
1800
|
+
else this.songs.push(song);
|
|
2269
1801
|
} else if (Array.isArray(song)) {
|
|
2270
1802
|
this.songs.splice(position, 0, ...song);
|
|
2271
1803
|
} else {
|
|
2272
1804
|
this.songs.splice(position, 0, song);
|
|
2273
1805
|
}
|
|
2274
|
-
if (Array.isArray(song))
|
|
2275
|
-
song.forEach((s) => delete s.formats);
|
|
2276
|
-
else
|
|
2277
|
-
delete song.formats;
|
|
2278
1806
|
return this;
|
|
2279
1807
|
}
|
|
2280
1808
|
/**
|
|
2281
1809
|
* Pause the guild stream
|
|
2282
|
-
*
|
|
2283
1810
|
* @returns The guild queue
|
|
2284
1811
|
*/
|
|
2285
1812
|
pause() {
|
|
2286
|
-
if (this.paused)
|
|
2287
|
-
throw new DisTubeError("PAUSED");
|
|
2288
|
-
this.playing = false;
|
|
1813
|
+
if (this.paused) throw new DisTubeError("PAUSED");
|
|
2289
1814
|
this.paused = true;
|
|
2290
1815
|
this.voice.pause();
|
|
2291
1816
|
return this;
|
|
2292
1817
|
}
|
|
2293
1818
|
/**
|
|
2294
1819
|
* Resume the guild stream
|
|
2295
|
-
*
|
|
2296
1820
|
* @returns The guild queue
|
|
2297
1821
|
*/
|
|
2298
1822
|
resume() {
|
|
2299
|
-
if (this.
|
|
2300
|
-
throw new DisTubeError("RESUMED");
|
|
2301
|
-
this.playing = true;
|
|
1823
|
+
if (!this.paused) throw new DisTubeError("RESUMED");
|
|
2302
1824
|
this.paused = false;
|
|
2303
1825
|
this.voice.unpause();
|
|
2304
1826
|
return this;
|
|
2305
1827
|
}
|
|
2306
1828
|
/**
|
|
2307
1829
|
* Set the guild stream's volume
|
|
2308
|
-
*
|
|
2309
1830
|
* @param percent - The percentage of volume you want to set
|
|
2310
|
-
*
|
|
2311
1831
|
* @returns The guild queue
|
|
2312
1832
|
*/
|
|
2313
1833
|
setVolume(percent) {
|
|
@@ -2318,17 +1838,14 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2318
1838
|
* Skip the playing song if there is a next song in the queue. <info>If {@link
|
|
2319
1839
|
* Queue#autoplay} is `true` and there is no up next song, DisTube will add and
|
|
2320
1840
|
* play a related song.</info>
|
|
2321
|
-
*
|
|
2322
1841
|
* @returns The song will skip to
|
|
2323
1842
|
*/
|
|
2324
1843
|
async skip() {
|
|
2325
1844
|
await this._taskQueue.queuing();
|
|
2326
1845
|
try {
|
|
2327
1846
|
if (this.songs.length <= 1) {
|
|
2328
|
-
if (this.autoplay)
|
|
2329
|
-
|
|
2330
|
-
else
|
|
2331
|
-
throw new DisTubeError("NO_UP_NEXT");
|
|
1847
|
+
if (this.autoplay) await this.addRelatedSong();
|
|
1848
|
+
else throw new DisTubeError("NO_UP_NEXT");
|
|
2332
1849
|
}
|
|
2333
1850
|
const song = this.songs[1];
|
|
2334
1851
|
this._next = true;
|
|
@@ -2340,14 +1857,12 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2340
1857
|
}
|
|
2341
1858
|
/**
|
|
2342
1859
|
* Play the previous song if exists
|
|
2343
|
-
*
|
|
2344
1860
|
* @returns The guild queue
|
|
2345
1861
|
*/
|
|
2346
1862
|
async previous() {
|
|
2347
1863
|
await this._taskQueue.queuing();
|
|
2348
1864
|
try {
|
|
2349
|
-
if (!this.options.savePreviousSongs)
|
|
2350
|
-
throw new DisTubeError("DISABLED_OPTION", "savePreviousSongs");
|
|
1865
|
+
if (!this.options.savePreviousSongs) throw new DisTubeError("DISABLED_OPTION", "savePreviousSongs");
|
|
2351
1866
|
if (this.previousSongs?.length === 0 && this.repeatMode !== 2 /* QUEUE */) {
|
|
2352
1867
|
throw new DisTubeError("NO_PREVIOUS");
|
|
2353
1868
|
}
|
|
@@ -2361,15 +1876,13 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2361
1876
|
}
|
|
2362
1877
|
/**
|
|
2363
1878
|
* Shuffle the queue's songs
|
|
2364
|
-
*
|
|
2365
1879
|
* @returns The guild queue
|
|
2366
1880
|
*/
|
|
2367
1881
|
async shuffle() {
|
|
2368
1882
|
await this._taskQueue.queuing();
|
|
2369
1883
|
try {
|
|
2370
1884
|
const playing = this.songs.shift();
|
|
2371
|
-
if (playing === void 0)
|
|
2372
|
-
return this;
|
|
1885
|
+
if (playing === void 0) return this;
|
|
2373
1886
|
for (let i = this.songs.length - 1; i > 0; i--) {
|
|
2374
1887
|
const j = Math.floor(Math.random() * (i + 1));
|
|
2375
1888
|
[this.songs[i], this.songs[j]] = [this.songs[j], this.songs[i]];
|
|
@@ -2384,16 +1897,13 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2384
1897
|
* Jump to the song position in the queue. The next one is 1, 2,... The previous
|
|
2385
1898
|
* one is -1, -2,...
|
|
2386
1899
|
* if `num` is invalid number
|
|
2387
|
-
*
|
|
2388
1900
|
* @param position - The song position to play
|
|
2389
|
-
*
|
|
2390
1901
|
* @returns The new Song will be played
|
|
2391
1902
|
*/
|
|
2392
1903
|
async jump(position) {
|
|
2393
1904
|
await this._taskQueue.queuing();
|
|
2394
1905
|
try {
|
|
2395
|
-
if (typeof position !== "number")
|
|
2396
|
-
throw new DisTubeError("INVALID_TYPE", "number", position, "position");
|
|
1906
|
+
if (typeof position !== "number") throw new DisTubeError("INVALID_TYPE", "number", position, "position");
|
|
2397
1907
|
if (!position || position > this.songs.length || -position > this.previousSongs.length) {
|
|
2398
1908
|
throw new DisTubeError("NO_SONG_POSITION");
|
|
2399
1909
|
}
|
|
@@ -2412,8 +1922,7 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2412
1922
|
throw new DisTubeError("DISABLED_OPTION", "savePreviousSongs");
|
|
2413
1923
|
} else {
|
|
2414
1924
|
this._prev = true;
|
|
2415
|
-
if (position !== -1)
|
|
2416
|
-
this.songs.unshift(...this.previousSongs.splice(position + 1));
|
|
1925
|
+
if (position !== -1) this.songs.unshift(...this.previousSongs.splice(position + 1));
|
|
2417
1926
|
nextSong = this.previousSongs[this.previousSongs.length - 1];
|
|
2418
1927
|
}
|
|
2419
1928
|
this.voice.stop();
|
|
@@ -2425,53 +1934,49 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2425
1934
|
/**
|
|
2426
1935
|
* Set the repeat mode of the guild queue.
|
|
2427
1936
|
* Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
|
|
2428
|
-
*
|
|
2429
1937
|
* @param mode - The repeat modes (toggle if `undefined`)
|
|
2430
|
-
*
|
|
2431
1938
|
* @returns The new repeat mode
|
|
2432
1939
|
*/
|
|
2433
1940
|
setRepeatMode(mode) {
|
|
2434
1941
|
if (mode !== void 0 && !Object.values(RepeatMode).includes(mode)) {
|
|
2435
1942
|
throw new DisTubeError("INVALID_TYPE", ["RepeatMode", "undefined"], mode, "mode");
|
|
2436
1943
|
}
|
|
2437
|
-
if (mode === void 0)
|
|
2438
|
-
|
|
2439
|
-
else
|
|
2440
|
-
this.repeatMode = 0 /* DISABLED */;
|
|
2441
|
-
else
|
|
2442
|
-
this.repeatMode = mode;
|
|
1944
|
+
if (mode === void 0) this.repeatMode = (this.repeatMode + 1) % 3;
|
|
1945
|
+
else if (this.repeatMode === mode) this.repeatMode = 0 /* DISABLED */;
|
|
1946
|
+
else this.repeatMode = mode;
|
|
2443
1947
|
return this.repeatMode;
|
|
2444
1948
|
}
|
|
2445
1949
|
/**
|
|
2446
1950
|
* Set the playing time to another position
|
|
2447
|
-
*
|
|
2448
1951
|
* @param time - Time in seconds
|
|
2449
|
-
*
|
|
2450
1952
|
* @returns The guild queue
|
|
2451
1953
|
*/
|
|
2452
1954
|
seek(time) {
|
|
2453
|
-
if (typeof time !== "number")
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
this.beginTime = time;
|
|
2458
|
-
this.queues.playSong(this);
|
|
1955
|
+
if (typeof time !== "number") throw new DisTubeError("INVALID_TYPE", "number", time, "time");
|
|
1956
|
+
if (isNaN(time) || time < 0) throw new DisTubeError("NUMBER_COMPARE", "time", "bigger or equal to", 0);
|
|
1957
|
+
this._beginTime = time;
|
|
1958
|
+
this.play(false);
|
|
2459
1959
|
return this;
|
|
2460
1960
|
}
|
|
2461
1961
|
/**
|
|
2462
1962
|
* Add a related song of the playing song to the queue
|
|
2463
|
-
*
|
|
2464
1963
|
* @returns The added song
|
|
2465
1964
|
*/
|
|
2466
1965
|
async addRelatedSong() {
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
const
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
1966
|
+
const current = this.songs?.[0];
|
|
1967
|
+
if (!current) throw new DisTubeError("NO_PLAYING_SONG");
|
|
1968
|
+
const prevIds = this.previousSongs.map((p) => p.id);
|
|
1969
|
+
const relatedSongs = (await __privateMethod(this, _Queue_instances, getRelatedSong_fn).call(this, current)).filter((s) => !prevIds.includes(s.id));
|
|
1970
|
+
this.debug(`[${this.id}] Getting related songs from: ${current}`);
|
|
1971
|
+
if (!relatedSongs.length && !current.stream.playFromSource) {
|
|
1972
|
+
const altSong = current.stream.song;
|
|
1973
|
+
if (altSong) relatedSongs.push(...(await __privateMethod(this, _Queue_instances, getRelatedSong_fn).call(this, altSong)).filter((s) => !prevIds.includes(s.id)));
|
|
1974
|
+
this.debug(`[${this.id}] Getting related songs from streamed song: ${altSong}`);
|
|
1975
|
+
}
|
|
1976
|
+
const song = relatedSongs[0];
|
|
1977
|
+
if (!song) throw new DisTubeError("NO_RELATED");
|
|
1978
|
+
song.metadata = current.metadata;
|
|
1979
|
+
song.member = this.clientMember;
|
|
2475
1980
|
this.addToQueue(song);
|
|
2476
1981
|
return song;
|
|
2477
1982
|
}
|
|
@@ -2484,18 +1989,14 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2484
1989
|
this.playing = false;
|
|
2485
1990
|
this.paused = false;
|
|
2486
1991
|
this.stopped = true;
|
|
2487
|
-
|
|
2488
|
-
this.voice.leave();
|
|
2489
|
-
else
|
|
2490
|
-
this.voice.stop();
|
|
1992
|
+
this.voice.stop();
|
|
2491
1993
|
this.remove();
|
|
2492
1994
|
} finally {
|
|
2493
1995
|
this._taskQueue.resolve();
|
|
2494
1996
|
}
|
|
2495
1997
|
}
|
|
2496
1998
|
/**
|
|
2497
|
-
* Remove the queue from the manager
|
|
2498
|
-
* {@link DisTubeOptions | DisTubeOptions.leaveOnStop} is enabled)
|
|
1999
|
+
* Remove the queue from the manager
|
|
2499
2000
|
*/
|
|
2500
2001
|
remove() {
|
|
2501
2002
|
this.stopped = true;
|
|
@@ -2503,7 +2004,7 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2503
2004
|
this.previousSongs = [];
|
|
2504
2005
|
if (this._listeners) {
|
|
2505
2006
|
for (const event of objectKeys(this._listeners)) {
|
|
2506
|
-
this.voice.
|
|
2007
|
+
this.voice.off(event, this._listeners[event]);
|
|
2507
2008
|
}
|
|
2508
2009
|
}
|
|
2509
2010
|
this.queues.remove(this.id);
|
|
@@ -2511,118 +2012,47 @@ var _Queue = class _Queue extends DisTubeBase {
|
|
|
2511
2012
|
}
|
|
2512
2013
|
/**
|
|
2513
2014
|
* Toggle autoplay mode
|
|
2514
|
-
*
|
|
2515
2015
|
* @returns Autoplay mode state
|
|
2516
2016
|
*/
|
|
2517
2017
|
toggleAutoplay() {
|
|
2518
2018
|
this.autoplay = !this.autoplay;
|
|
2519
2019
|
return this.autoplay;
|
|
2520
2020
|
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Play the queue
|
|
2023
|
+
* @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event
|
|
2024
|
+
*/
|
|
2025
|
+
play(emitPlaySong = true) {
|
|
2026
|
+
if (this.stopped) throw new DisTubeError("QUEUE_STOPPED");
|
|
2027
|
+
this.playing = true;
|
|
2028
|
+
return this.queues.playSong(this, emitPlaySong);
|
|
2029
|
+
}
|
|
2521
2030
|
};
|
|
2522
2031
|
_filters = new WeakMap();
|
|
2032
|
+
_Queue_instances = new WeakSet();
|
|
2033
|
+
getRelatedSong_fn = /* @__PURE__ */ __name(async function(current) {
|
|
2034
|
+
const plugin = await this.handler._getPluginFromSong(current);
|
|
2035
|
+
if (plugin) return plugin.getRelatedSongs(current);
|
|
2036
|
+
return [];
|
|
2037
|
+
}, "#getRelatedSong");
|
|
2523
2038
|
__name(_Queue, "Queue");
|
|
2524
2039
|
var Queue = _Queue;
|
|
2525
2040
|
|
|
2526
2041
|
// src/struct/Plugin.ts
|
|
2527
2042
|
var _Plugin = class _Plugin {
|
|
2528
2043
|
constructor() {
|
|
2044
|
+
/**
|
|
2045
|
+
* DisTube
|
|
2046
|
+
*/
|
|
2529
2047
|
__publicField(this, "distube");
|
|
2530
2048
|
}
|
|
2531
2049
|
init(distube) {
|
|
2532
2050
|
this.distube = distube;
|
|
2533
2051
|
}
|
|
2534
|
-
/**
|
|
2535
|
-
* Type of the plugin
|
|
2536
|
-
*/
|
|
2537
|
-
/**
|
|
2538
|
-
* Emit an event to the {@link DisTube} class
|
|
2539
|
-
*
|
|
2540
|
-
* @param eventName - Event name
|
|
2541
|
-
* @param args - arguments
|
|
2542
|
-
*/
|
|
2543
|
-
emit(eventName, ...args) {
|
|
2544
|
-
return this.distube.emit(eventName, ...args);
|
|
2545
|
-
}
|
|
2546
|
-
/**
|
|
2547
|
-
* Emit error event to the {@link DisTube} class
|
|
2548
|
-
*
|
|
2549
|
-
* @param error - error
|
|
2550
|
-
* @param channel - Text channel where the error is encountered.
|
|
2551
|
-
*/
|
|
2552
|
-
emitError(error, channel) {
|
|
2553
|
-
this.distube.emitError(error, channel);
|
|
2554
|
-
}
|
|
2555
|
-
/**
|
|
2556
|
-
* The queue manager
|
|
2557
|
-
*/
|
|
2558
|
-
get queues() {
|
|
2559
|
-
return this.distube.queues;
|
|
2560
|
-
}
|
|
2561
|
-
/**
|
|
2562
|
-
* The voice manager
|
|
2563
|
-
*/
|
|
2564
|
-
get voices() {
|
|
2565
|
-
return this.distube.voices;
|
|
2566
|
-
}
|
|
2567
|
-
/**
|
|
2568
|
-
* Discord.js client
|
|
2569
|
-
*/
|
|
2570
|
-
get client() {
|
|
2571
|
-
return this.distube.client;
|
|
2572
|
-
}
|
|
2573
|
-
/**
|
|
2574
|
-
* DisTube options
|
|
2575
|
-
*/
|
|
2576
|
-
get options() {
|
|
2577
|
-
return this.distube.options;
|
|
2578
|
-
}
|
|
2579
|
-
/**
|
|
2580
|
-
* DisTube handler
|
|
2581
|
-
*/
|
|
2582
|
-
get handler() {
|
|
2583
|
-
return this.distube.handler;
|
|
2584
|
-
}
|
|
2585
|
-
/**
|
|
2586
|
-
* Check if the string is working with this plugin
|
|
2587
|
-
*
|
|
2588
|
-
* @param _string - Input string
|
|
2589
|
-
*/
|
|
2590
|
-
validate(_string) {
|
|
2591
|
-
return false;
|
|
2592
|
-
}
|
|
2593
|
-
/**
|
|
2594
|
-
* Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.
|
|
2595
|
-
* Not needed if the plugin plays song from YouTube.
|
|
2596
|
-
*
|
|
2597
|
-
* @param url - Input url
|
|
2598
|
-
*/
|
|
2599
|
-
getStreamURL(url) {
|
|
2600
|
-
return url;
|
|
2601
|
-
}
|
|
2602
|
-
/**
|
|
2603
|
-
* Get related songs from a supported url. {@link Song#member} should be
|
|
2604
|
-
* `undefined`. Not needed to add {@link Song#related} because it will be added
|
|
2605
|
-
* with this function later.
|
|
2606
|
-
*
|
|
2607
|
-
* @param _url - Input url
|
|
2608
|
-
*/
|
|
2609
|
-
getRelatedSongs(_url) {
|
|
2610
|
-
return [];
|
|
2611
|
-
}
|
|
2612
2052
|
};
|
|
2613
2053
|
__name(_Plugin, "Plugin");
|
|
2614
2054
|
var Plugin = _Plugin;
|
|
2615
2055
|
|
|
2616
|
-
// src/struct/CustomPlugin.ts
|
|
2617
|
-
var _CustomPlugin = class _CustomPlugin extends Plugin {
|
|
2618
|
-
constructor() {
|
|
2619
|
-
super(...arguments);
|
|
2620
|
-
__publicField(this, "type", "custom" /* CUSTOM */);
|
|
2621
|
-
}
|
|
2622
|
-
};
|
|
2623
|
-
__name(_CustomPlugin, "CustomPlugin");
|
|
2624
|
-
var CustomPlugin = _CustomPlugin;
|
|
2625
|
-
|
|
2626
2056
|
// src/struct/ExtractorPlugin.ts
|
|
2627
2057
|
var _ExtractorPlugin = class _ExtractorPlugin extends Plugin {
|
|
2628
2058
|
constructor() {
|
|
@@ -2633,56 +2063,46 @@ var _ExtractorPlugin = class _ExtractorPlugin extends Plugin {
|
|
|
2633
2063
|
__name(_ExtractorPlugin, "ExtractorPlugin");
|
|
2634
2064
|
var ExtractorPlugin = _ExtractorPlugin;
|
|
2635
2065
|
|
|
2066
|
+
// src/struct/InfoExtratorPlugin.ts
|
|
2067
|
+
var _InfoExtractorPlugin = class _InfoExtractorPlugin extends Plugin {
|
|
2068
|
+
constructor() {
|
|
2069
|
+
super(...arguments);
|
|
2070
|
+
__publicField(this, "type", "info-extractor" /* INFO_EXTRACTOR */);
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
__name(_InfoExtractorPlugin, "InfoExtractorPlugin");
|
|
2074
|
+
var InfoExtractorPlugin = _InfoExtractorPlugin;
|
|
2075
|
+
|
|
2076
|
+
// src/struct/PlayableExtratorPlugin.ts
|
|
2077
|
+
var _PlayableExtractorPlugin = class _PlayableExtractorPlugin extends Plugin {
|
|
2078
|
+
constructor() {
|
|
2079
|
+
super(...arguments);
|
|
2080
|
+
__publicField(this, "type", "playable-extractor" /* PLAYABLE_EXTRACTOR */);
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
__name(_PlayableExtractorPlugin, "PlayableExtractorPlugin");
|
|
2084
|
+
var PlayableExtractorPlugin = _PlayableExtractorPlugin;
|
|
2085
|
+
|
|
2636
2086
|
// src/util.ts
|
|
2637
2087
|
var import_url = require("url");
|
|
2638
2088
|
var import_discord3 = require("discord.js");
|
|
2639
2089
|
var formatInt = /* @__PURE__ */ __name((int) => int < 10 ? `0${int}` : int, "formatInt");
|
|
2640
2090
|
function formatDuration(sec) {
|
|
2641
|
-
if (!sec || !Number(sec))
|
|
2642
|
-
return "00:00";
|
|
2091
|
+
if (!sec || !Number(sec)) return "00:00";
|
|
2643
2092
|
const seconds = Math.floor(sec % 60);
|
|
2644
2093
|
const minutes = Math.floor(sec % 3600 / 60);
|
|
2645
2094
|
const hours = Math.floor(sec / 3600);
|
|
2646
|
-
if (hours > 0)
|
|
2647
|
-
|
|
2648
|
-
if (minutes > 0)
|
|
2649
|
-
return `${formatInt(minutes)}:${formatInt(seconds)}`;
|
|
2095
|
+
if (hours > 0) return `${formatInt(hours)}:${formatInt(minutes)}:${formatInt(seconds)}`;
|
|
2096
|
+
if (minutes > 0) return `${formatInt(minutes)}:${formatInt(seconds)}`;
|
|
2650
2097
|
return `00:${formatInt(seconds)}`;
|
|
2651
2098
|
}
|
|
2652
2099
|
__name(formatDuration, "formatDuration");
|
|
2653
|
-
function toSecond(input) {
|
|
2654
|
-
if (!input)
|
|
2655
|
-
return 0;
|
|
2656
|
-
if (typeof input !== "string")
|
|
2657
|
-
return Number(input) || 0;
|
|
2658
|
-
if (input.includes(":")) {
|
|
2659
|
-
const time = input.split(":").reverse();
|
|
2660
|
-
let seconds = 0;
|
|
2661
|
-
for (let i = 0; i < 3; i++)
|
|
2662
|
-
if (time[i])
|
|
2663
|
-
seconds += Number(time[i].replace(/[^\d.]+/g, "")) * Math.pow(60, i);
|
|
2664
|
-
if (time.length > 3)
|
|
2665
|
-
seconds += Number(time[3].replace(/[^\d.]+/g, "")) * 24 * 60 * 60;
|
|
2666
|
-
return seconds;
|
|
2667
|
-
} else {
|
|
2668
|
-
return Number(input.replace(/[^\d.]+/g, "")) || 0;
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
__name(toSecond, "toSecond");
|
|
2672
|
-
function parseNumber(input) {
|
|
2673
|
-
if (typeof input === "string")
|
|
2674
|
-
return Number(input.replace(/[^\d.]+/g, "")) || 0;
|
|
2675
|
-
return Number(input) || 0;
|
|
2676
|
-
}
|
|
2677
|
-
__name(parseNumber, "parseNumber");
|
|
2678
2100
|
var SUPPORTED_PROTOCOL = ["https:", "http:", "file:"];
|
|
2679
2101
|
function isURL(input) {
|
|
2680
|
-
if (typeof input !== "string" || input.includes(" "))
|
|
2681
|
-
return false;
|
|
2102
|
+
if (typeof input !== "string" || input.includes(" ")) return false;
|
|
2682
2103
|
try {
|
|
2683
2104
|
const url = new import_url.URL(input);
|
|
2684
|
-
if (!SUPPORTED_PROTOCOL.some((p) => p === url.protocol))
|
|
2685
|
-
return false;
|
|
2105
|
+
if (!SUPPORTED_PROTOCOL.some((p) => p === url.protocol)) return false;
|
|
2686
2106
|
} catch {
|
|
2687
2107
|
return false;
|
|
2688
2108
|
}
|
|
@@ -2690,19 +2110,16 @@ function isURL(input) {
|
|
|
2690
2110
|
}
|
|
2691
2111
|
__name(isURL, "isURL");
|
|
2692
2112
|
function checkIntents(options) {
|
|
2693
|
-
const intents = new import_discord3.IntentsBitField(options.intents);
|
|
2694
|
-
if (!intents.has(import_discord3.GatewayIntentBits.GuildVoiceStates))
|
|
2695
|
-
throw new DisTubeError("MISSING_INTENTS", "GuildVoiceStates");
|
|
2113
|
+
const intents = options.intents instanceof import_discord3.IntentsBitField ? options.intents : new import_discord3.IntentsBitField(options.intents);
|
|
2114
|
+
if (!intents.has(import_discord3.GatewayIntentBits.GuildVoiceStates)) throw new DisTubeError("MISSING_INTENTS", "GuildVoiceStates");
|
|
2696
2115
|
}
|
|
2697
2116
|
__name(checkIntents, "checkIntents");
|
|
2698
2117
|
function isVoiceChannelEmpty(voiceState) {
|
|
2699
2118
|
const guild = voiceState.guild;
|
|
2700
2119
|
const clientId = voiceState.client.user?.id;
|
|
2701
|
-
if (!guild || !clientId)
|
|
2702
|
-
return false;
|
|
2120
|
+
if (!guild || !clientId) return false;
|
|
2703
2121
|
const voiceChannel = guild.members.me?.voice?.channel;
|
|
2704
|
-
if (!voiceChannel)
|
|
2705
|
-
return false;
|
|
2122
|
+
if (!voiceChannel) return false;
|
|
2706
2123
|
const members = voiceChannel.members.filter((m) => !m.user.bot);
|
|
2707
2124
|
return !members.size;
|
|
2708
2125
|
}
|
|
@@ -2748,8 +2165,7 @@ function resolveGuildId(resolvable) {
|
|
|
2748
2165
|
guildId = resolvable.guild.id;
|
|
2749
2166
|
}
|
|
2750
2167
|
}
|
|
2751
|
-
if (!isSnowflake(guildId))
|
|
2752
|
-
throw new DisTubeError("INVALID_TYPE", "GuildIdResolvable", resolvable);
|
|
2168
|
+
if (!isSnowflake(guildId)) throw new DisTubeError("INVALID_TYPE", "GuildIdResolvable", resolvable);
|
|
2753
2169
|
return guildId;
|
|
2754
2170
|
}
|
|
2755
2171
|
__name(resolveGuildId, "resolveGuildId");
|
|
@@ -2758,81 +2174,73 @@ function isClientInstance(client) {
|
|
|
2758
2174
|
}
|
|
2759
2175
|
__name(isClientInstance, "isClientInstance");
|
|
2760
2176
|
function checkInvalidKey(target, source, sourceName) {
|
|
2761
|
-
if (!isObject(target))
|
|
2762
|
-
throw new DisTubeError("INVALID_TYPE", "object", target, sourceName);
|
|
2177
|
+
if (!isObject(target)) throw new DisTubeError("INVALID_TYPE", "object", target, sourceName);
|
|
2763
2178
|
const sourceKeys = Array.isArray(source) ? source : objectKeys(source);
|
|
2764
2179
|
const invalidKey = objectKeys(target).find((key) => !sourceKeys.includes(key));
|
|
2765
|
-
if (invalidKey)
|
|
2766
|
-
throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
|
|
2180
|
+
if (invalidKey) throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
|
|
2767
2181
|
}
|
|
2768
2182
|
__name(checkInvalidKey, "checkInvalidKey");
|
|
2769
2183
|
function isObject(obj) {
|
|
2770
2184
|
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
|
2771
2185
|
}
|
|
2772
2186
|
__name(isObject, "isObject");
|
|
2773
|
-
function isRecord(obj) {
|
|
2774
|
-
return isObject(obj);
|
|
2775
|
-
}
|
|
2776
|
-
__name(isRecord, "isRecord");
|
|
2777
2187
|
function objectKeys(obj) {
|
|
2778
|
-
if (!isObject(obj))
|
|
2779
|
-
return [];
|
|
2188
|
+
if (!isObject(obj)) return [];
|
|
2780
2189
|
return Object.keys(obj);
|
|
2781
2190
|
}
|
|
2782
2191
|
__name(objectKeys, "objectKeys");
|
|
2783
2192
|
function isNsfwChannel(channel) {
|
|
2784
|
-
if (!isTextChannelInstance(channel))
|
|
2785
|
-
|
|
2786
|
-
if (channel.isThread())
|
|
2787
|
-
return channel.parent?.nsfw ?? false;
|
|
2193
|
+
if (!isTextChannelInstance(channel)) return false;
|
|
2194
|
+
if (channel.isThread()) return channel.parent?.nsfw ?? false;
|
|
2788
2195
|
return channel.nsfw;
|
|
2789
2196
|
}
|
|
2790
2197
|
__name(isNsfwChannel, "isNsfwChannel");
|
|
2791
2198
|
var isTruthy = /* @__PURE__ */ __name((x) => Boolean(x), "isTruthy");
|
|
2792
2199
|
|
|
2793
|
-
// src/plugin/DirectLink.ts
|
|
2794
|
-
var import_undici = require("undici");
|
|
2795
|
-
var _DirectLinkPlugin = class _DirectLinkPlugin extends ExtractorPlugin {
|
|
2796
|
-
async validate(url) {
|
|
2797
|
-
try {
|
|
2798
|
-
const headers = await (0, import_undici.request)(url, { method: "HEAD" }).then((res) => res.headers);
|
|
2799
|
-
const types = headers["content-type"];
|
|
2800
|
-
const type = Array.isArray(types) ? types[0] : types;
|
|
2801
|
-
if (["audio/", "video/", "application/ogg"].some((s) => type?.startsWith(s)))
|
|
2802
|
-
return true;
|
|
2803
|
-
} catch {
|
|
2804
|
-
}
|
|
2805
|
-
return false;
|
|
2806
|
-
}
|
|
2807
|
-
resolve(url, options = {}) {
|
|
2808
|
-
const u = new URL(url);
|
|
2809
|
-
const name = u.pathname.split("/").pop() || u.href;
|
|
2810
|
-
return new Song({ name, url, src: "direct_link" }, options);
|
|
2811
|
-
}
|
|
2812
|
-
};
|
|
2813
|
-
__name(_DirectLinkPlugin, "DirectLinkPlugin");
|
|
2814
|
-
var DirectLinkPlugin = _DirectLinkPlugin;
|
|
2815
|
-
|
|
2816
2200
|
// src/DisTube.ts
|
|
2817
|
-
var import_ytsr = __toESM(require("@distube/ytsr"));
|
|
2818
2201
|
var import_tiny_typed_emitter3 = require("tiny-typed-emitter");
|
|
2819
2202
|
var { version } = require_package();
|
|
2820
|
-
var
|
|
2821
|
-
var _DisTube = class _DisTube extends import_tiny_typed_emitter3.TypedEmitter {
|
|
2203
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _DisTube_instances, getQueue_fn;
|
|
2204
|
+
var _DisTube = class _DisTube extends (_m = import_tiny_typed_emitter3.TypedEmitter, _l = "addList" /* ADD_LIST */, _k = "addSong" /* ADD_SONG */, _j = "deleteQueue" /* DELETE_QUEUE */, _i = "disconnect" /* DISCONNECT */, _h = "error" /* ERROR */, _g = "ffmpegDebug" /* FFMPEG_DEBUG */, _f = "debug" /* DEBUG */, _e = "finish" /* FINISH */, _d = "finishSong" /* FINISH_SONG */, _c = "initQueue" /* INIT_QUEUE */, _b = "noRelated" /* NO_RELATED */, _a = "playSong" /* PLAY_SONG */, _m) {
|
|
2205
|
+
/**
|
|
2206
|
+
* Create a new DisTube class.
|
|
2207
|
+
* @throws {@link DisTubeError}
|
|
2208
|
+
* @param client - Discord.JS client
|
|
2209
|
+
* @param opts - Custom DisTube options
|
|
2210
|
+
*/
|
|
2822
2211
|
constructor(client, opts = {}) {
|
|
2823
2212
|
super();
|
|
2824
|
-
__privateAdd(this,
|
|
2213
|
+
__privateAdd(this, _DisTube_instances);
|
|
2214
|
+
/**
|
|
2215
|
+
* DisTube internal handler
|
|
2216
|
+
*/
|
|
2825
2217
|
__publicField(this, "handler");
|
|
2218
|
+
/**
|
|
2219
|
+
* DisTube options
|
|
2220
|
+
*/
|
|
2826
2221
|
__publicField(this, "options");
|
|
2222
|
+
/**
|
|
2223
|
+
* Discord.js v14 client
|
|
2224
|
+
*/
|
|
2827
2225
|
__publicField(this, "client");
|
|
2226
|
+
/**
|
|
2227
|
+
* Queues manager
|
|
2228
|
+
*/
|
|
2828
2229
|
__publicField(this, "queues");
|
|
2230
|
+
/**
|
|
2231
|
+
* DisTube voice connections manager
|
|
2232
|
+
*/
|
|
2829
2233
|
__publicField(this, "voices");
|
|
2830
|
-
|
|
2831
|
-
|
|
2234
|
+
/**
|
|
2235
|
+
* DisTube plugins
|
|
2236
|
+
*/
|
|
2237
|
+
__publicField(this, "plugins");
|
|
2238
|
+
/**
|
|
2239
|
+
* DisTube ffmpeg audio filters
|
|
2240
|
+
*/
|
|
2832
2241
|
__publicField(this, "filters");
|
|
2833
2242
|
this.setMaxListeners(1);
|
|
2834
|
-
if (!isClientInstance(client))
|
|
2835
|
-
throw new DisTubeError("INVALID_TYPE", "Discord.Client", client, "client");
|
|
2243
|
+
if (!isClientInstance(client)) throw new DisTubeError("INVALID_TYPE", "Discord.Client", client, "client");
|
|
2836
2244
|
this.client = client;
|
|
2837
2245
|
checkIntents(client.options);
|
|
2838
2246
|
this.options = new Options(opts);
|
|
@@ -2840,11 +2248,8 @@ var _DisTube = class _DisTube extends import_tiny_typed_emitter3.TypedEmitter {
|
|
|
2840
2248
|
this.handler = new DisTubeHandler(this);
|
|
2841
2249
|
this.queues = new QueueManager(this);
|
|
2842
2250
|
this.filters = { ...defaultFilters, ...this.options.customFilters };
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
this.options.plugins.forEach((p) => p.init(this));
|
|
2846
|
-
this.extractorPlugins = this.options.plugins.filter((p) => p.type === "extractor");
|
|
2847
|
-
this.customPlugins = this.options.plugins.filter((p) => p.type === "custom");
|
|
2251
|
+
this.plugins = [...this.options.plugins];
|
|
2252
|
+
this.plugins.forEach((p) => p.init(this));
|
|
2848
2253
|
}
|
|
2849
2254
|
static get version() {
|
|
2850
2255
|
return version;
|
|
@@ -2856,37 +2261,19 @@ var _DisTube = class _DisTube extends import_tiny_typed_emitter3.TypedEmitter {
|
|
|
2856
2261
|
return version;
|
|
2857
2262
|
}
|
|
2858
2263
|
/**
|
|
2859
|
-
* Play / add a song or playlist from url.
|
|
2860
|
-
* valid url.
|
|
2861
|
-
*
|
|
2862
|
-
* @example
|
|
2863
|
-
* ```ts
|
|
2864
|
-
* client.on('message', (message) => {
|
|
2865
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
2866
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
2867
|
-
* const command = args.shift();
|
|
2868
|
-
* if (command == "play")
|
|
2869
|
-
* distube.play(message.member.voice.channel, args.join(" "), {
|
|
2870
|
-
* member: message.member,
|
|
2871
|
-
* textChannel: message.channel,
|
|
2872
|
-
* message
|
|
2873
|
-
* });
|
|
2874
|
-
* });
|
|
2875
|
-
* ```ts
|
|
2876
|
-
*
|
|
2264
|
+
* Play / add a song or playlist from url.
|
|
2265
|
+
* Search and play a song (with {@link ExtractorPlugin}) if it is not a valid url.
|
|
2877
2266
|
* @throws {@link DisTubeError}
|
|
2878
|
-
*
|
|
2879
2267
|
* @param voiceChannel - The channel will be joined if the bot isn't in any channels, the bot will be
|
|
2880
2268
|
* moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`
|
|
2881
|
-
* @param song - URL | Search string | {@link Song} | {@link
|
|
2269
|
+
* @param song - URL | Search string | {@link Song} | {@link Playlist}
|
|
2882
2270
|
* @param options - Optional options
|
|
2883
2271
|
*/
|
|
2884
2272
|
async play(voiceChannel, song, options = {}) {
|
|
2885
2273
|
if (!isSupportedVoiceChannel(voiceChannel)) {
|
|
2886
2274
|
throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", voiceChannel, "voiceChannel");
|
|
2887
2275
|
}
|
|
2888
|
-
if (!isObject(options))
|
|
2889
|
-
throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
2276
|
+
if (!isObject(options)) throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
2890
2277
|
const { textChannel, member, skip, message, metadata } = {
|
|
2891
2278
|
member: voiceChannel.guild.members.me ?? void 0,
|
|
2892
2279
|
textChannel: options?.message?.channel,
|
|
@@ -2903,37 +2290,33 @@ var _DisTube = class _DisTube extends import_tiny_typed_emitter3.TypedEmitter {
|
|
|
2903
2290
|
if (member && !isMemberInstance(member)) {
|
|
2904
2291
|
throw new DisTubeError("INVALID_TYPE", "Discord.GuildMember", member, "options.member");
|
|
2905
2292
|
}
|
|
2906
|
-
const queue = this.getQueue(voiceChannel);
|
|
2907
|
-
|
|
2908
|
-
if (queuing)
|
|
2909
|
-
await queue?._taskQueue.queuing(true);
|
|
2293
|
+
const queue = this.getQueue(voiceChannel) || await this.queues.create(voiceChannel, textChannel);
|
|
2294
|
+
await queue._taskQueue.queuing();
|
|
2910
2295
|
try {
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2296
|
+
this.debug(`[${queue.id}] Resolving song: ${typeof song === "string" ? song : JSON.stringify(song)}`);
|
|
2297
|
+
const resolved = await this.handler.resolve(song, { member, metadata });
|
|
2298
|
+
const isNsfw = isNsfwChannel(queue?.textChannel || textChannel);
|
|
2299
|
+
if (resolved instanceof Playlist) {
|
|
2300
|
+
if (!this.options.nsfw && !isNsfw) {
|
|
2301
|
+
resolved.songs = resolved.songs.filter((s) => !s.ageRestricted);
|
|
2302
|
+
if (!resolved.songs.length) throw new DisTubeError("EMPTY_FILTERED_PLAYLIST");
|
|
2917
2303
|
}
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
} else {
|
|
2923
|
-
const result = await this.handler.searchSong(message, song);
|
|
2924
|
-
if (!result)
|
|
2925
|
-
return;
|
|
2926
|
-
song = result;
|
|
2927
|
-
}
|
|
2928
|
-
}
|
|
2929
|
-
song = await this.handler.resolve(song, { member, metadata });
|
|
2930
|
-
if (song instanceof Playlist) {
|
|
2931
|
-
await this.handler.playPlaylist(voiceChannel, song, { textChannel, skip, position });
|
|
2304
|
+
if (!resolved.songs.length) throw new DisTubeError("EMPTY_PLAYLIST");
|
|
2305
|
+
this.debug(`[${queue.id}] Adding playlist to queue: ${resolved.songs.length} songs`);
|
|
2306
|
+
queue.addToQueue(resolved.songs, position);
|
|
2307
|
+
if (queue.playing || this.options.emitAddListWhenCreatingQueue) this.emit("addList" /* ADD_LIST */, queue, resolved);
|
|
2932
2308
|
} else {
|
|
2933
|
-
|
|
2309
|
+
if (!this.options.nsfw && resolved.ageRestricted && !isNsfwChannel(queue?.textChannel || textChannel)) {
|
|
2310
|
+
throw new DisTubeError("NON_NSFW");
|
|
2311
|
+
}
|
|
2312
|
+
this.debug(`[${queue.id}] Adding song to queue: ${resolved.name || resolved.url || resolved.id || resolved}`);
|
|
2313
|
+
queue.addToQueue(resolved, position);
|
|
2314
|
+
if (queue.playing || this.options.emitAddSongWhenCreatingQueue) this.emit("addSong" /* ADD_SONG */, queue, resolved);
|
|
2934
2315
|
}
|
|
2316
|
+
if (!queue.playing) await queue.play();
|
|
2935
2317
|
} catch (e) {
|
|
2936
2318
|
if (!(e instanceof DisTubeError)) {
|
|
2319
|
+
this.debug(`[${queue.id}] Unexpected error while playing song: ${e.stack || e.message}`);
|
|
2937
2320
|
try {
|
|
2938
2321
|
e.name = "PlayError";
|
|
2939
2322
|
e.message = `${typeof song === "string" ? song : song.url}
|
|
@@ -2943,43 +2326,24 @@ ${e.message}`;
|
|
|
2943
2326
|
}
|
|
2944
2327
|
throw e;
|
|
2945
2328
|
} finally {
|
|
2946
|
-
|
|
2947
|
-
queue?._taskQueue.resolve();
|
|
2329
|
+
queue._taskQueue.resolve();
|
|
2948
2330
|
}
|
|
2949
2331
|
}
|
|
2950
2332
|
/**
|
|
2951
2333
|
* Create a custom playlist
|
|
2952
|
-
*
|
|
2953
|
-
* @example
|
|
2954
|
-
* ```ts
|
|
2955
|
-
* const songs = ["https://www.youtube.com/watch?v=xxx", "https://www.youtube.com/watch?v=yyy"];
|
|
2956
|
-
* const playlist = await distube.createCustomPlaylist(songs, {
|
|
2957
|
-
* member: message.member,
|
|
2958
|
-
* properties: { name: "My playlist name", source: "custom" },
|
|
2959
|
-
* parallel: true
|
|
2960
|
-
* });
|
|
2961
|
-
* distube.play(voiceChannel, playlist, { ... });
|
|
2962
|
-
* ```ts
|
|
2963
|
-
*
|
|
2964
|
-
* @param songs - Array of url, Song or SearchResult
|
|
2334
|
+
* @param songs - Array of url or Song
|
|
2965
2335
|
* @param options - Optional options
|
|
2966
2336
|
*/
|
|
2967
|
-
async createCustomPlaylist(songs,
|
|
2968
|
-
|
|
2969
|
-
if (!
|
|
2970
|
-
|
|
2971
|
-
if (!
|
|
2972
|
-
throw new DisTubeError("EMPTY_ARRAY", "songs");
|
|
2973
|
-
const filteredSongs = songs.filter(
|
|
2974
|
-
(song) => song instanceof Song || isURL(song) || typeof song !== "string" && song.type === "video" /* VIDEO */
|
|
2975
|
-
);
|
|
2976
|
-
if (!filteredSongs.length)
|
|
2977
|
-
throw new DisTubeError("NO_VALID_SONG");
|
|
2337
|
+
async createCustomPlaylist(songs, { member, parallel, metadata, name, source, url, thumbnail } = {}) {
|
|
2338
|
+
if (!Array.isArray(songs)) throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
|
|
2339
|
+
if (!songs.length) throw new DisTubeError("EMPTY_ARRAY", "songs");
|
|
2340
|
+
const filteredSongs = songs.filter((song) => song instanceof Song || isURL(song));
|
|
2341
|
+
if (!filteredSongs.length) throw new DisTubeError("NO_VALID_SONG");
|
|
2978
2342
|
if (member && !isMemberInstance(member)) {
|
|
2979
2343
|
throw new DisTubeError("INVALID_TYPE", "Discord.Member", member, "options.member");
|
|
2980
2344
|
}
|
|
2981
2345
|
let resolvedSongs;
|
|
2982
|
-
if (parallel) {
|
|
2346
|
+
if (parallel !== false) {
|
|
2983
2347
|
const promises = filteredSongs.map(
|
|
2984
2348
|
(song) => this.handler.resolve(song, { member, metadata }).catch(() => void 0)
|
|
2985
2349
|
);
|
|
@@ -2988,71 +2352,22 @@ ${e.message}`;
|
|
|
2988
2352
|
resolvedSongs = [];
|
|
2989
2353
|
for (const song of filteredSongs) {
|
|
2990
2354
|
const resolved = await this.handler.resolve(song, { member, metadata }).catch(() => void 0);
|
|
2991
|
-
if (resolved instanceof Song)
|
|
2992
|
-
resolvedSongs.push(resolved);
|
|
2355
|
+
if (resolved instanceof Song) resolvedSongs.push(resolved);
|
|
2993
2356
|
}
|
|
2994
2357
|
}
|
|
2995
|
-
return new Playlist(
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
* @param options.safeSearch - Whether or not use safe search (YouTube restricted mode)
|
|
3006
|
-
*
|
|
3007
|
-
* @returns Array of results
|
|
3008
|
-
*/
|
|
3009
|
-
async search(string, options = {}) {
|
|
3010
|
-
const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
|
|
3011
|
-
if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
|
|
3012
|
-
throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
|
|
3013
|
-
}
|
|
3014
|
-
if (typeof opts.limit !== "number")
|
|
3015
|
-
throw new DisTubeError("INVALID_TYPE", "number", opts.limit, "options.limit");
|
|
3016
|
-
if (opts.limit < 1)
|
|
3017
|
-
throw new DisTubeError("NUMBER_COMPARE", "option.limit", "bigger or equal to", 1);
|
|
3018
|
-
if (typeof opts.safeSearch !== "boolean") {
|
|
3019
|
-
throw new DisTubeError("INVALID_TYPE", "boolean", opts.safeSearch, "options.safeSearch");
|
|
3020
|
-
}
|
|
3021
|
-
try {
|
|
3022
|
-
const search = await (0, import_ytsr.default)(string, { ...opts, requestOptions: { headers: { cookie: this.handler.ytCookie } } });
|
|
3023
|
-
const results = search.items.map((i) => {
|
|
3024
|
-
if (i.type === "video")
|
|
3025
|
-
return new SearchResultVideo(i);
|
|
3026
|
-
return new SearchResultPlaylist(i);
|
|
3027
|
-
});
|
|
3028
|
-
if (results.length === 0)
|
|
3029
|
-
throw new DisTubeError("NO_RESULT");
|
|
3030
|
-
return results;
|
|
3031
|
-
} catch (e) {
|
|
3032
|
-
if (options.retried)
|
|
3033
|
-
throw e;
|
|
3034
|
-
options.retried = true;
|
|
3035
|
-
return this.search(string, options);
|
|
3036
|
-
}
|
|
2358
|
+
return new Playlist(
|
|
2359
|
+
{
|
|
2360
|
+
source: source || "custom",
|
|
2361
|
+
name,
|
|
2362
|
+
url,
|
|
2363
|
+
thumbnail: thumbnail || resolvedSongs.find((s) => s.thumbnail)?.thumbnail,
|
|
2364
|
+
songs: resolvedSongs
|
|
2365
|
+
},
|
|
2366
|
+
{ member, metadata }
|
|
2367
|
+
);
|
|
3037
2368
|
}
|
|
3038
2369
|
/**
|
|
3039
2370
|
* Get the guild queue
|
|
3040
|
-
*
|
|
3041
|
-
* @example
|
|
3042
|
-
* ```ts
|
|
3043
|
-
* client.on('message', (message) => {
|
|
3044
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3045
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3046
|
-
* const command = args.shift();
|
|
3047
|
-
* if (command == "queue") {
|
|
3048
|
-
* const queue = distube.getQueue(message);
|
|
3049
|
-
* message.channel.send('Current queue:\n' + queue.songs.map((song, id) =>
|
|
3050
|
-
* `**${id+1}**. [${song.name}](${song.url}) - \`${song.formattedDuration}\``
|
|
3051
|
-
* ).join("\n"));
|
|
3052
|
-
* }
|
|
3053
|
-
* });
|
|
3054
|
-
* ```ts
|
|
3055
|
-
*
|
|
3056
2371
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3057
2372
|
*/
|
|
3058
2373
|
getQueue(guild) {
|
|
@@ -3060,288 +2375,220 @@ ${e.message}`;
|
|
|
3060
2375
|
}
|
|
3061
2376
|
/**
|
|
3062
2377
|
* Pause the guild stream
|
|
3063
|
-
*
|
|
3064
2378
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3065
|
-
*
|
|
3066
2379
|
* @returns The guild queue
|
|
3067
2380
|
*/
|
|
3068
2381
|
pause(guild) {
|
|
3069
|
-
return __privateMethod(this,
|
|
2382
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).pause();
|
|
3070
2383
|
}
|
|
3071
2384
|
/**
|
|
3072
2385
|
* Resume the guild stream
|
|
3073
|
-
*
|
|
3074
2386
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3075
|
-
*
|
|
3076
2387
|
* @returns The guild queue
|
|
3077
2388
|
*/
|
|
3078
2389
|
resume(guild) {
|
|
3079
|
-
return __privateMethod(this,
|
|
2390
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).resume();
|
|
3080
2391
|
}
|
|
3081
2392
|
/**
|
|
3082
2393
|
* Stop the guild stream
|
|
3083
|
-
*
|
|
3084
|
-
* @example
|
|
3085
|
-
* ```ts
|
|
3086
|
-
* client.on('message', (message) => {
|
|
3087
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3088
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3089
|
-
* const command = args.shift();
|
|
3090
|
-
* if (command == "stop") {
|
|
3091
|
-
* distube.stop(message);
|
|
3092
|
-
* message.channel.send("Stopped the queue!");
|
|
3093
|
-
* }
|
|
3094
|
-
* });
|
|
3095
|
-
* ```ts
|
|
3096
|
-
*
|
|
3097
2394
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3098
2395
|
*/
|
|
3099
2396
|
stop(guild) {
|
|
3100
|
-
return __privateMethod(this,
|
|
2397
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).stop();
|
|
3101
2398
|
}
|
|
3102
2399
|
/**
|
|
3103
2400
|
* Set the guild stream's volume
|
|
3104
|
-
*
|
|
3105
|
-
* @example
|
|
3106
|
-
* ```ts
|
|
3107
|
-
* client.on('message', (message) => {
|
|
3108
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3109
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3110
|
-
* const command = args.shift();
|
|
3111
|
-
* if (command == "volume")
|
|
3112
|
-
* distube.setVolume(message, Number(args[0]));
|
|
3113
|
-
* });
|
|
3114
|
-
* ```ts
|
|
3115
|
-
*
|
|
3116
2401
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3117
2402
|
* @param percent - The percentage of volume you want to set
|
|
3118
|
-
*
|
|
3119
2403
|
* @returns The guild queue
|
|
3120
2404
|
*/
|
|
3121
2405
|
setVolume(guild, percent) {
|
|
3122
|
-
return __privateMethod(this,
|
|
2406
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).setVolume(percent);
|
|
3123
2407
|
}
|
|
3124
2408
|
/**
|
|
3125
2409
|
* Skip the playing song if there is a next song in the queue. <info>If {@link
|
|
3126
2410
|
* Queue#autoplay} is `true` and there is no up next song, DisTube will add and
|
|
3127
2411
|
* play a related song.</info>
|
|
3128
|
-
*
|
|
3129
|
-
* @example
|
|
3130
|
-
* ```ts
|
|
3131
|
-
* client.on('message', (message) => {
|
|
3132
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3133
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3134
|
-
* const command = args.shift();
|
|
3135
|
-
* if (command == "skip")
|
|
3136
|
-
* distube.skip(message);
|
|
3137
|
-
* });
|
|
3138
|
-
* ```ts
|
|
3139
|
-
*
|
|
3140
2412
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3141
|
-
*
|
|
3142
2413
|
* @returns The new Song will be played
|
|
3143
2414
|
*/
|
|
3144
2415
|
skip(guild) {
|
|
3145
|
-
return __privateMethod(this,
|
|
2416
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).skip();
|
|
3146
2417
|
}
|
|
3147
2418
|
/**
|
|
3148
2419
|
* Play the previous song
|
|
3149
|
-
*
|
|
3150
|
-
* @example
|
|
3151
|
-
* ```ts
|
|
3152
|
-
* client.on('message', (message) => {
|
|
3153
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3154
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3155
|
-
* const command = args.shift();
|
|
3156
|
-
* if (command == "previous")
|
|
3157
|
-
* distube.previous(message);
|
|
3158
|
-
* });
|
|
3159
|
-
* ```ts
|
|
3160
|
-
*
|
|
3161
2420
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3162
|
-
*
|
|
3163
2421
|
* @returns The new Song will be played
|
|
3164
2422
|
*/
|
|
3165
2423
|
previous(guild) {
|
|
3166
|
-
return __privateMethod(this,
|
|
2424
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).previous();
|
|
3167
2425
|
}
|
|
3168
2426
|
/**
|
|
3169
2427
|
* Shuffle the guild queue songs
|
|
3170
|
-
*
|
|
3171
|
-
* @example
|
|
3172
|
-
* ```ts
|
|
3173
|
-
* client.on('message', (message) => {
|
|
3174
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3175
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3176
|
-
* const command = args.shift();
|
|
3177
|
-
* if (command == "shuffle")
|
|
3178
|
-
* distube.shuffle(message);
|
|
3179
|
-
* });
|
|
3180
|
-
* ```ts
|
|
3181
|
-
*
|
|
3182
2428
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3183
|
-
*
|
|
3184
2429
|
* @returns The guild queue
|
|
3185
2430
|
*/
|
|
3186
2431
|
shuffle(guild) {
|
|
3187
|
-
return __privateMethod(this,
|
|
2432
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).shuffle();
|
|
3188
2433
|
}
|
|
3189
2434
|
/**
|
|
3190
2435
|
* Jump to the song number in the queue. The next one is 1, 2,... The previous one
|
|
3191
2436
|
* is -1, -2,...
|
|
3192
|
-
*
|
|
3193
|
-
* @example
|
|
3194
|
-
* ```ts
|
|
3195
|
-
* client.on('message', (message) => {
|
|
3196
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3197
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3198
|
-
* const command = args.shift();
|
|
3199
|
-
* if (command == "jump")
|
|
3200
|
-
* distube.jump(message, parseInt(args[0]))
|
|
3201
|
-
* .catch(err => message.channel.send("Invalid song number."));
|
|
3202
|
-
* });
|
|
3203
|
-
* ```ts
|
|
3204
|
-
*
|
|
3205
2437
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3206
2438
|
* @param num - The song number to play
|
|
3207
|
-
*
|
|
3208
2439
|
* @returns The new Song will be played
|
|
3209
2440
|
*/
|
|
3210
2441
|
jump(guild, num) {
|
|
3211
|
-
return __privateMethod(this,
|
|
2442
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).jump(num);
|
|
3212
2443
|
}
|
|
3213
2444
|
/**
|
|
3214
2445
|
* Set the repeat mode of the guild queue.
|
|
3215
2446
|
* Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
|
|
3216
|
-
*
|
|
3217
|
-
* @example
|
|
3218
|
-
* ```ts
|
|
3219
|
-
* client.on('message', (message) => {
|
|
3220
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3221
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3222
|
-
* const command = args.shift();
|
|
3223
|
-
* if (command == "repeat") {
|
|
3224
|
-
* let mode = distube.setRepeatMode(message, parseInt(args[0]));
|
|
3225
|
-
* mode = mode ? mode == 2 ? "Repeat queue" : "Repeat song" : "Off";
|
|
3226
|
-
* message.channel.send("Set repeat mode to `" + mode + "`");
|
|
3227
|
-
* }
|
|
3228
|
-
* });
|
|
3229
|
-
* ```ts
|
|
3230
|
-
* @example
|
|
3231
|
-
* ```ts
|
|
3232
|
-
* const { RepeatMode } = require("distube");
|
|
3233
|
-
* let mode;
|
|
3234
|
-
* switch(distube.setRepeatMode(message, parseInt(args[0]))) {
|
|
3235
|
-
* case RepeatMode.DISABLED:
|
|
3236
|
-
* mode = "Off";
|
|
3237
|
-
* break;
|
|
3238
|
-
* case RepeatMode.SONG:
|
|
3239
|
-
* mode = "Repeat a song";
|
|
3240
|
-
* break;
|
|
3241
|
-
* case RepeatMode.QUEUE:
|
|
3242
|
-
* mode = "Repeat all queue";
|
|
3243
|
-
* break;
|
|
3244
|
-
* }
|
|
3245
|
-
* message.channel.send("Set repeat mode to `" + mode + "`");
|
|
3246
|
-
* ```ts
|
|
3247
|
-
*
|
|
3248
2447
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3249
2448
|
* @param mode - The repeat modes (toggle if `undefined`)
|
|
3250
|
-
*
|
|
3251
2449
|
* @returns The new repeat mode
|
|
3252
2450
|
*/
|
|
3253
2451
|
setRepeatMode(guild, mode) {
|
|
3254
|
-
return __privateMethod(this,
|
|
2452
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).setRepeatMode(mode);
|
|
3255
2453
|
}
|
|
3256
2454
|
/**
|
|
3257
2455
|
* Toggle autoplay mode
|
|
3258
|
-
*
|
|
3259
|
-
* @example
|
|
3260
|
-
* ```ts
|
|
3261
|
-
* client.on('message', (message) => {
|
|
3262
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3263
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3264
|
-
* const command = args.shift();
|
|
3265
|
-
* if (command == "autoplay") {
|
|
3266
|
-
* const mode = distube.toggleAutoplay(message);
|
|
3267
|
-
* message.channel.send("Set autoplay mode to `" + (mode ? "On" : "Off") + "`");
|
|
3268
|
-
* }
|
|
3269
|
-
* });
|
|
3270
|
-
* ```ts
|
|
3271
|
-
*
|
|
3272
2456
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3273
|
-
*
|
|
3274
2457
|
* @returns Autoplay mode state
|
|
3275
2458
|
*/
|
|
3276
2459
|
toggleAutoplay(guild) {
|
|
3277
|
-
const queue = __privateMethod(this,
|
|
2460
|
+
const queue = __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild);
|
|
3278
2461
|
queue.autoplay = !queue.autoplay;
|
|
3279
2462
|
return queue.autoplay;
|
|
3280
2463
|
}
|
|
3281
2464
|
/**
|
|
3282
2465
|
* Add related song to the queue
|
|
3283
|
-
*
|
|
3284
2466
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3285
|
-
*
|
|
3286
2467
|
* @returns The guild queue
|
|
3287
2468
|
*/
|
|
3288
2469
|
addRelatedSong(guild) {
|
|
3289
|
-
return __privateMethod(this,
|
|
2470
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).addRelatedSong();
|
|
3290
2471
|
}
|
|
3291
2472
|
/**
|
|
3292
2473
|
* Set the playing time to another position
|
|
3293
|
-
*
|
|
3294
|
-
* @example
|
|
3295
|
-
* ```ts
|
|
3296
|
-
* client.on('message', message => {
|
|
3297
|
-
* if (!message.content.startsWith(config.prefix)) return;
|
|
3298
|
-
* const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
|
3299
|
-
* const command = args.shift();
|
|
3300
|
-
* if (command = 'seek')
|
|
3301
|
-
* distube.seek(message, Number(args[0]));
|
|
3302
|
-
* });
|
|
3303
|
-
* ```ts
|
|
3304
|
-
*
|
|
3305
2474
|
* @param guild - The type can be resolved to give a {@link Queue}
|
|
3306
2475
|
* @param time - Time in seconds
|
|
3307
|
-
*
|
|
3308
2476
|
* @returns Seeked queue
|
|
3309
2477
|
*/
|
|
3310
2478
|
seek(guild, time) {
|
|
3311
|
-
return __privateMethod(this,
|
|
2479
|
+
return __privateMethod(this, _DisTube_instances, getQueue_fn).call(this, guild).seek(time);
|
|
3312
2480
|
}
|
|
3313
2481
|
/**
|
|
3314
2482
|
* Emit error event
|
|
3315
|
-
*
|
|
3316
2483
|
* @param error - error
|
|
3317
|
-
* @param
|
|
2484
|
+
* @param queue - The queue encountered the error
|
|
2485
|
+
* @param song - The playing song when encountered the error
|
|
3318
2486
|
*/
|
|
3319
|
-
emitError(error,
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
}
|
|
2487
|
+
emitError(error, queue, song) {
|
|
2488
|
+
this.emit("error" /* ERROR */, error, queue, song);
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* Emit debug event
|
|
2492
|
+
* @param message - debug message
|
|
2493
|
+
*/
|
|
2494
|
+
debug(message) {
|
|
2495
|
+
this.emit("debug" /* DEBUG */, message);
|
|
3329
2496
|
}
|
|
3330
2497
|
};
|
|
3331
|
-
|
|
2498
|
+
_DisTube_instances = new WeakSet();
|
|
3332
2499
|
getQueue_fn = /* @__PURE__ */ __name(function(guild) {
|
|
3333
2500
|
const queue = this.getQueue(guild);
|
|
3334
|
-
if (!queue)
|
|
3335
|
-
throw new DisTubeError("NO_QUEUE");
|
|
2501
|
+
if (!queue) throw new DisTubeError("NO_QUEUE");
|
|
3336
2502
|
return queue;
|
|
3337
2503
|
}, "#getQueue");
|
|
3338
2504
|
__name(_DisTube, "DisTube");
|
|
2505
|
+
/**
|
|
2506
|
+
* @event
|
|
2507
|
+
* Emitted after DisTube add a new playlist to the playing {@link Queue}.
|
|
2508
|
+
* @param queue - The guild queue
|
|
2509
|
+
* @param playlist - Playlist info
|
|
2510
|
+
*/
|
|
2511
|
+
__publicField(_DisTube, _l);
|
|
2512
|
+
/**
|
|
2513
|
+
* @event
|
|
2514
|
+
* Emitted after DisTube add a new song to the playing {@link Queue}.
|
|
2515
|
+
* @param queue - The guild queue
|
|
2516
|
+
* @param song - Added song
|
|
2517
|
+
*/
|
|
2518
|
+
__publicField(_DisTube, _k);
|
|
2519
|
+
/**
|
|
2520
|
+
* @event
|
|
2521
|
+
* Emitted when a {@link Queue} is deleted with any reasons.
|
|
2522
|
+
* @param queue - The guild queue
|
|
2523
|
+
*/
|
|
2524
|
+
__publicField(_DisTube, _j);
|
|
2525
|
+
/**
|
|
2526
|
+
* @event
|
|
2527
|
+
* Emitted when the bot is disconnected to a voice channel.
|
|
2528
|
+
* @param queue - The guild queue
|
|
2529
|
+
*/
|
|
2530
|
+
__publicField(_DisTube, _i);
|
|
2531
|
+
/**
|
|
2532
|
+
* @event
|
|
2533
|
+
* Emitted when DisTube encounters an error while playing songs.
|
|
2534
|
+
* @param error - error
|
|
2535
|
+
* @param queue - The queue encountered the error
|
|
2536
|
+
* @param song - The playing song when encountered the error
|
|
2537
|
+
*/
|
|
2538
|
+
__publicField(_DisTube, _h);
|
|
2539
|
+
/**
|
|
2540
|
+
* @event
|
|
2541
|
+
* Emitted for logging FFmpeg debug information.
|
|
2542
|
+
* @param debug - Debug message string.
|
|
2543
|
+
*/
|
|
2544
|
+
__publicField(_DisTube, _g);
|
|
2545
|
+
/**
|
|
2546
|
+
* @event
|
|
2547
|
+
* Emitted to provide debug information from DisTube's operation.
|
|
2548
|
+
* Useful for troubleshooting or logging purposes.
|
|
2549
|
+
*
|
|
2550
|
+
* @param debug - Debug message string.
|
|
2551
|
+
*/
|
|
2552
|
+
__publicField(_DisTube, _f);
|
|
2553
|
+
/**
|
|
2554
|
+
* @event
|
|
2555
|
+
* Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.
|
|
2556
|
+
* @param queue - The guild queue
|
|
2557
|
+
*/
|
|
2558
|
+
__publicField(_DisTube, _e);
|
|
2559
|
+
/**
|
|
2560
|
+
* @event
|
|
2561
|
+
* Emitted when DisTube finished a song.
|
|
2562
|
+
* @param queue - The guild queue
|
|
2563
|
+
* @param song - Finished song
|
|
2564
|
+
*/
|
|
2565
|
+
__publicField(_DisTube, _d);
|
|
2566
|
+
/**
|
|
2567
|
+
* @event
|
|
2568
|
+
* Emitted when DisTube initialize a queue to change queue default properties.
|
|
2569
|
+
* @param queue - The guild queue
|
|
2570
|
+
*/
|
|
2571
|
+
__publicField(_DisTube, _c);
|
|
2572
|
+
/**
|
|
2573
|
+
* @event
|
|
2574
|
+
* Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty, and
|
|
2575
|
+
* DisTube cannot find related songs to play.
|
|
2576
|
+
* @param queue - The guild queue
|
|
2577
|
+
*/
|
|
2578
|
+
__publicField(_DisTube, _b);
|
|
2579
|
+
/**
|
|
2580
|
+
* @event
|
|
2581
|
+
* Emitted when DisTube play a song.
|
|
2582
|
+
* If {@link DisTubeOptions}.emitNewSongOnly is `true`, this event is not emitted
|
|
2583
|
+
* when looping a song or next song is the previous one.
|
|
2584
|
+
* @param queue - The guild queue
|
|
2585
|
+
* @param song - Playing song
|
|
2586
|
+
*/
|
|
2587
|
+
__publicField(_DisTube, _a);
|
|
3339
2588
|
var DisTube = _DisTube;
|
|
3340
2589
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3341
2590
|
0 && (module.exports = {
|
|
3342
2591
|
BaseManager,
|
|
3343
|
-
CustomPlugin,
|
|
3344
|
-
DirectLinkPlugin,
|
|
3345
2592
|
DisTube,
|
|
3346
2593
|
DisTubeBase,
|
|
3347
2594
|
DisTubeError,
|
|
@@ -3353,23 +2600,20 @@ var DisTube = _DisTube;
|
|
|
3353
2600
|
ExtractorPlugin,
|
|
3354
2601
|
FilterManager,
|
|
3355
2602
|
GuildIdManager,
|
|
2603
|
+
InfoExtractorPlugin,
|
|
3356
2604
|
Options,
|
|
2605
|
+
PlayableExtractorPlugin,
|
|
3357
2606
|
Playlist,
|
|
3358
2607
|
Plugin,
|
|
3359
2608
|
PluginType,
|
|
3360
2609
|
Queue,
|
|
3361
2610
|
QueueManager,
|
|
3362
2611
|
RepeatMode,
|
|
3363
|
-
SearchResultPlaylist,
|
|
3364
|
-
SearchResultType,
|
|
3365
|
-
SearchResultVideo,
|
|
3366
2612
|
Song,
|
|
3367
|
-
StreamType,
|
|
3368
2613
|
TaskQueue,
|
|
3369
2614
|
checkFFmpeg,
|
|
3370
2615
|
checkIntents,
|
|
3371
2616
|
checkInvalidKey,
|
|
3372
|
-
chooseBestVideoFormat,
|
|
3373
2617
|
defaultFilters,
|
|
3374
2618
|
defaultOptions,
|
|
3375
2619
|
formatDuration,
|
|
@@ -3379,7 +2623,6 @@ var DisTube = _DisTube;
|
|
|
3379
2623
|
isMessageInstance,
|
|
3380
2624
|
isNsfwChannel,
|
|
3381
2625
|
isObject,
|
|
3382
|
-
isRecord,
|
|
3383
2626
|
isSnowflake,
|
|
3384
2627
|
isSupportedVoiceChannel,
|
|
3385
2628
|
isTextChannelInstance,
|
|
@@ -3387,9 +2630,7 @@ var DisTube = _DisTube;
|
|
|
3387
2630
|
isURL,
|
|
3388
2631
|
isVoiceChannelEmpty,
|
|
3389
2632
|
objectKeys,
|
|
3390
|
-
parseNumber,
|
|
3391
2633
|
resolveGuildId,
|
|
3392
|
-
toSecond,
|
|
3393
2634
|
version
|
|
3394
2635
|
});
|
|
3395
2636
|
//# sourceMappingURL=index.js.map
|