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