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