distube 4.0.2 → 4.0.4
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 +10 -10
- package/dist/index.d.ts +90 -65
- package/dist/index.js +712 -629
- package/dist/index.js.map +1 -1
- package/package.json +10 -14
- package/dist/index.mjs +0 -2360
- package/dist/index.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
22
22
|
}
|
|
23
23
|
return to;
|
|
24
24
|
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
26
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
30
|
var __publicField = (obj, key, value) => {
|
|
28
31
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -56,15 +59,11 @@ var require_package = __commonJS({
|
|
|
56
59
|
"package.json"(exports, module2) {
|
|
57
60
|
module2.exports = {
|
|
58
61
|
name: "distube",
|
|
59
|
-
version: "4.0.
|
|
62
|
+
version: "4.0.4",
|
|
60
63
|
description: "A Discord.js module to simplify your music commands and play songs with audio filters on Discord without any API key.",
|
|
61
64
|
main: "./dist/index.js",
|
|
62
|
-
module: "./dist/index.mjs",
|
|
63
65
|
types: "./dist/index.d.ts",
|
|
64
|
-
exports:
|
|
65
|
-
import: "./dist/index.mjs",
|
|
66
|
-
require: "./dist/index.js"
|
|
67
|
-
},
|
|
66
|
+
exports: "./dist/index.js",
|
|
68
67
|
directories: {
|
|
69
68
|
lib: "src",
|
|
70
69
|
test: "tests"
|
|
@@ -74,7 +73,7 @@ var require_package = __commonJS({
|
|
|
74
73
|
],
|
|
75
74
|
scripts: {
|
|
76
75
|
test: "jest",
|
|
77
|
-
docs: "docgen -s src
|
|
76
|
+
docs: "docgen -s src/**/*.ts -o docs.json -c pages/index.yml -g -j jsdoc.config.json",
|
|
78
77
|
lint: "prettier --check . && eslint .",
|
|
79
78
|
"lint:fix": "eslint . --fix",
|
|
80
79
|
prettier: 'prettier --write "**/*.{ts,json,yml,yaml,md}"',
|
|
@@ -137,13 +136,13 @@ var require_package = __commonJS({
|
|
|
137
136
|
"@commitlint/cli": "^17.0.3",
|
|
138
137
|
"@commitlint/config-conventional": "^17.0.3",
|
|
139
138
|
"@discordjs/voice": "^0.11.0",
|
|
140
|
-
"@
|
|
139
|
+
"@distubejs/docgen": "distubejs/docgen",
|
|
141
140
|
"@types/jest": "^28.1.6",
|
|
142
|
-
"@types/node": "^18.
|
|
143
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
144
|
-
"@typescript-eslint/parser": "^5.
|
|
141
|
+
"@types/node": "^18.6.1",
|
|
142
|
+
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
|
143
|
+
"@typescript-eslint/parser": "^5.31.0",
|
|
145
144
|
"babel-jest": "^28.1.3",
|
|
146
|
-
"discord.js": "^14.0.
|
|
145
|
+
"discord.js": "^14.0.3",
|
|
147
146
|
eslint: "^8.20.0",
|
|
148
147
|
"eslint-config-distube": "^1.6.4",
|
|
149
148
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -153,10 +152,10 @@ var require_package = __commonJS({
|
|
|
153
152
|
jest: "^28.1.3",
|
|
154
153
|
"jsdoc-babel": "^0.5.0",
|
|
155
154
|
"nano-staged": "^0.8.0",
|
|
156
|
-
"npm-check-updates": "^
|
|
155
|
+
"npm-check-updates": "^16.0.0",
|
|
157
156
|
pinst: "^3.0.0",
|
|
158
157
|
prettier: "^2.7.1",
|
|
159
|
-
tsup: "^6.
|
|
158
|
+
tsup: "^6.2.0",
|
|
160
159
|
typescript: "^4.7.4"
|
|
161
160
|
},
|
|
162
161
|
peerDependencies: {
|
|
@@ -199,6 +198,7 @@ __export(src_exports, {
|
|
|
199
198
|
DisTubeStream: () => DisTubeStream,
|
|
200
199
|
DisTubeVoice: () => DisTubeVoice,
|
|
201
200
|
DisTubeVoiceManager: () => DisTubeVoiceManager,
|
|
201
|
+
Events: () => Events,
|
|
202
202
|
ExtractorPlugin: () => ExtractorPlugin,
|
|
203
203
|
FilterManager: () => FilterManager,
|
|
204
204
|
GuildIdManager: () => GuildIdManager,
|
|
@@ -233,6 +233,7 @@ __export(src_exports, {
|
|
|
233
233
|
isTextChannelInstance: () => isTextChannelInstance,
|
|
234
234
|
isURL: () => isURL,
|
|
235
235
|
isVoiceChannelEmpty: () => isVoiceChannelEmpty,
|
|
236
|
+
objectKeys: () => objectKeys,
|
|
236
237
|
parseNumber: () => parseNumber,
|
|
237
238
|
resolveGuildId: () => resolveGuildId,
|
|
238
239
|
toSecond: () => toSecond,
|
|
@@ -262,6 +263,25 @@ var StreamType = /* @__PURE__ */ ((StreamType2) => {
|
|
|
262
263
|
StreamType2[StreamType2["RAW"] = 1] = "RAW";
|
|
263
264
|
return StreamType2;
|
|
264
265
|
})(StreamType || {});
|
|
266
|
+
var Events = /* @__PURE__ */ ((Events2) => {
|
|
267
|
+
Events2["ERROR"] = "error";
|
|
268
|
+
Events2["ADD_LIST"] = "addList";
|
|
269
|
+
Events2["ADD_SONG"] = "addSong";
|
|
270
|
+
Events2["PLAY_SONG"] = "playSong";
|
|
271
|
+
Events2["FINISH_SONG"] = "finishSong";
|
|
272
|
+
Events2["EMPTY"] = "empty";
|
|
273
|
+
Events2["FINISH"] = "finish";
|
|
274
|
+
Events2["INIT_QUEUE"] = "initQueue";
|
|
275
|
+
Events2["NO_RELATED"] = "noRelated";
|
|
276
|
+
Events2["DISCONNECT"] = "disconnect";
|
|
277
|
+
Events2["DELETE_QUEUE"] = "deleteQueue";
|
|
278
|
+
Events2["SEARCH_CANCEL"] = "searchCancel";
|
|
279
|
+
Events2["SEARCH_NO_RESULT"] = "searchNoResult";
|
|
280
|
+
Events2["SEARCH_DONE"] = "searchDone";
|
|
281
|
+
Events2["SEARCH_INVALID_ANSWER"] = "searchInvalidAnswer";
|
|
282
|
+
Events2["SEARCH_RESULT"] = "searchResult";
|
|
283
|
+
return Events2;
|
|
284
|
+
})(Events || {});
|
|
265
285
|
|
|
266
286
|
// src/constant.ts
|
|
267
287
|
var defaultFilters = {
|
|
@@ -698,6 +718,7 @@ var DisTubeBase = class {
|
|
|
698
718
|
__name(DisTubeBase, "DisTubeBase");
|
|
699
719
|
|
|
700
720
|
// src/core/DisTubeVoice.ts
|
|
721
|
+
var import_discord = require("discord.js");
|
|
701
722
|
var import_tiny_typed_emitter = require("tiny-typed-emitter");
|
|
702
723
|
var import_voice = require("@discordjs/voice");
|
|
703
724
|
var _channel, _volume, _br, br_fn, _join, join_fn;
|
|
@@ -751,7 +772,23 @@ var DisTubeVoice = class extends import_tiny_typed_emitter.TypedEmitter {
|
|
|
751
772
|
}).on("error", () => void 0);
|
|
752
773
|
this.connection.subscribe(this.audioPlayer);
|
|
753
774
|
}
|
|
775
|
+
get channelId() {
|
|
776
|
+
return this.connection?.joinConfig?.channelId ?? void 0;
|
|
777
|
+
}
|
|
754
778
|
get channel() {
|
|
779
|
+
if (!this.channelId)
|
|
780
|
+
return __privateGet(this, _channel);
|
|
781
|
+
if (__privateGet(this, _channel)?.id === this.channelId)
|
|
782
|
+
return __privateGet(this, _channel);
|
|
783
|
+
const channel = this.voices.client.channels.cache.get(this.channelId);
|
|
784
|
+
if (!channel)
|
|
785
|
+
return __privateGet(this, _channel);
|
|
786
|
+
for (const type of import_discord.Constants.VoiceBasedChannelTypes) {
|
|
787
|
+
if (channel.type === type) {
|
|
788
|
+
__privateSet(this, _channel, channel);
|
|
789
|
+
return channel;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
755
792
|
return __privateGet(this, _channel);
|
|
756
793
|
}
|
|
757
794
|
set channel(channel) {
|
|
@@ -762,7 +799,7 @@ var DisTubeVoice = class extends import_tiny_typed_emitter.TypedEmitter {
|
|
|
762
799
|
throw new DisTubeError("VOICE_DIFFERENT_GUILD");
|
|
763
800
|
if (channel.client.user?.id !== this.voices.client.user?.id)
|
|
764
801
|
throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
|
|
765
|
-
if (channel.id ===
|
|
802
|
+
if (channel.id === this.channelId)
|
|
766
803
|
return;
|
|
767
804
|
if (!channel.joinable) {
|
|
768
805
|
if (channel.full)
|
|
@@ -886,538 +923,222 @@ join_fn = /* @__PURE__ */ __name(function(channel) {
|
|
|
886
923
|
});
|
|
887
924
|
}, "#join");
|
|
888
925
|
|
|
889
|
-
// src/core/
|
|
890
|
-
var
|
|
891
|
-
var
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
926
|
+
// src/core/DisTubeHandler.ts
|
|
927
|
+
var import_ytpl = __toESM(require("@distube/ytpl"));
|
|
928
|
+
var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
|
|
929
|
+
var DisTubeHandler = class extends DisTubeBase {
|
|
930
|
+
constructor(distube) {
|
|
931
|
+
super(distube);
|
|
932
|
+
const client = this.client;
|
|
933
|
+
if (this.options.leaveOnEmpty) {
|
|
934
|
+
client.on("voiceStateUpdate", (oldState) => {
|
|
935
|
+
if (!oldState?.channel)
|
|
936
|
+
return;
|
|
937
|
+
const queue = this.queues.get(oldState);
|
|
938
|
+
if (!queue) {
|
|
939
|
+
if (isVoiceChannelEmpty(oldState)) {
|
|
940
|
+
setTimeout(() => {
|
|
941
|
+
if (!this.queues.get(oldState) && isVoiceChannelEmpty(oldState))
|
|
942
|
+
this.voices.leave(oldState);
|
|
943
|
+
}, this.options.emptyCooldown * 1e3).unref();
|
|
944
|
+
}
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
if (queue._emptyTimeout) {
|
|
948
|
+
clearTimeout(queue._emptyTimeout);
|
|
949
|
+
delete queue._emptyTimeout;
|
|
950
|
+
}
|
|
951
|
+
if (isVoiceChannelEmpty(oldState)) {
|
|
952
|
+
queue._emptyTimeout = setTimeout(() => {
|
|
953
|
+
delete queue._emptyTimeout;
|
|
954
|
+
if (isVoiceChannelEmpty(oldState)) {
|
|
955
|
+
queue.voice.leave();
|
|
956
|
+
this.emit("empty", queue);
|
|
957
|
+
if (queue.stopped)
|
|
958
|
+
queue.remove();
|
|
959
|
+
}
|
|
960
|
+
}, this.options.emptyCooldown * 1e3).unref();
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}
|
|
895
964
|
}
|
|
896
|
-
get
|
|
897
|
-
|
|
965
|
+
get ytdlOptions() {
|
|
966
|
+
const options = this.options.ytdlOptions;
|
|
967
|
+
if (this.options.youtubeCookie) {
|
|
968
|
+
if (!options.requestOptions)
|
|
969
|
+
options.requestOptions = {};
|
|
970
|
+
if (!options.requestOptions.headers)
|
|
971
|
+
options.requestOptions.headers = {};
|
|
972
|
+
options.requestOptions.headers.cookie = this.options.youtubeCookie;
|
|
973
|
+
if (this.options.youtubeIdentityToken) {
|
|
974
|
+
options.requestOptions.headers["x-youtube-identity-token"] = this.options.youtubeIdentityToken;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return options;
|
|
898
978
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
var GuildIdManager = class extends BaseManager {
|
|
904
|
-
add(idOrInstance, data) {
|
|
905
|
-
const id = resolveGuildId(idOrInstance);
|
|
906
|
-
const existing = this.get(id);
|
|
907
|
-
if (existing)
|
|
908
|
-
return this;
|
|
909
|
-
return this.collection.set(id, data);
|
|
979
|
+
getYouTubeInfo(url, basic = false) {
|
|
980
|
+
if (basic)
|
|
981
|
+
return import_ytdl_core.default.getBasicInfo(url, this.ytdlOptions);
|
|
982
|
+
return import_ytdl_core.default.getInfo(url, this.ytdlOptions);
|
|
910
983
|
}
|
|
911
|
-
|
|
912
|
-
|
|
984
|
+
async resolve(song, options = {}) {
|
|
985
|
+
if (song instanceof Song || song instanceof Playlist) {
|
|
986
|
+
if ("metadata" in options)
|
|
987
|
+
song.metadata = options.metadata;
|
|
988
|
+
if ("member" in options)
|
|
989
|
+
song.member = options.member;
|
|
990
|
+
return song;
|
|
991
|
+
}
|
|
992
|
+
if (song instanceof SearchResultVideo)
|
|
993
|
+
return new Song(song, options);
|
|
994
|
+
if (song instanceof SearchResultPlaylist)
|
|
995
|
+
return this.resolvePlaylist(song.url, options);
|
|
996
|
+
if (isObject(song)) {
|
|
997
|
+
if (!("url" in song) && !("id" in song))
|
|
998
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", song);
|
|
999
|
+
return new Song(song, options);
|
|
1000
|
+
}
|
|
1001
|
+
if (import_ytpl.default.validateID(song))
|
|
1002
|
+
return this.resolvePlaylist(song, options);
|
|
1003
|
+
if (import_ytdl_core.default.validateURL(song))
|
|
1004
|
+
return new Song(await this.getYouTubeInfo(song, true), options);
|
|
1005
|
+
if (isURL(song)) {
|
|
1006
|
+
for (const plugin of this.distube.extractorPlugins) {
|
|
1007
|
+
if (await plugin.validate(song))
|
|
1008
|
+
return plugin.resolve(song, options);
|
|
1009
|
+
}
|
|
1010
|
+
throw new DisTubeError("NOT_SUPPORTED_URL");
|
|
1011
|
+
}
|
|
1012
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", song);
|
|
913
1013
|
}
|
|
914
|
-
|
|
915
|
-
|
|
1014
|
+
async resolvePlaylist(playlist, options = {}) {
|
|
1015
|
+
const { member, source, metadata } = { source: "youtube", ...options };
|
|
1016
|
+
if (playlist instanceof Playlist) {
|
|
1017
|
+
if ("metadata" in options)
|
|
1018
|
+
playlist.metadata = metadata;
|
|
1019
|
+
if ("member" in options)
|
|
1020
|
+
playlist.member = member;
|
|
1021
|
+
return playlist;
|
|
1022
|
+
}
|
|
1023
|
+
if (typeof playlist === "string") {
|
|
1024
|
+
const info = await (0, import_ytpl.default)(playlist, { limit: Infinity });
|
|
1025
|
+
const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
|
|
1026
|
+
return new Playlist(
|
|
1027
|
+
{
|
|
1028
|
+
source,
|
|
1029
|
+
songs,
|
|
1030
|
+
member,
|
|
1031
|
+
name: info.title,
|
|
1032
|
+
url: info.url,
|
|
1033
|
+
thumbnail: songs[0].thumbnail
|
|
1034
|
+
},
|
|
1035
|
+
{ metadata }
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
return new Playlist(playlist, { member, properties: { source }, metadata });
|
|
916
1039
|
}
|
|
917
|
-
|
|
918
|
-
|
|
1040
|
+
async searchSong(message, query) {
|
|
1041
|
+
if (!isMessageInstance(message))
|
|
1042
|
+
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1043
|
+
if (typeof query !== "string")
|
|
1044
|
+
throw new DisTubeError("INVALID_TYPE", "string", query, "query");
|
|
1045
|
+
if (query.length === 0)
|
|
1046
|
+
throw new DisTubeError("EMPTY_STRING", "query");
|
|
1047
|
+
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1048
|
+
const results = await this.distube.search(query, {
|
|
1049
|
+
limit,
|
|
1050
|
+
safeSearch: this.options.nsfw ? false : !message.channel?.nsfw
|
|
1051
|
+
}).catch(() => {
|
|
1052
|
+
if (!this.emit("searchNoResult", message, query)) {
|
|
1053
|
+
console.warn("searchNoResult event does not have any listeners! Emits `error` event instead.");
|
|
1054
|
+
throw new DisTubeError("NO_RESULT");
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
if (!results)
|
|
1058
|
+
return null;
|
|
1059
|
+
return this.createSearchMessageCollector(message, results, query);
|
|
919
1060
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
var DisTubeVoiceManager = class extends GuildIdManager {
|
|
926
|
-
create(channel) {
|
|
927
|
-
const existing = this.get(channel.guildId);
|
|
928
|
-
if (existing) {
|
|
929
|
-
existing.channel = channel;
|
|
930
|
-
return existing;
|
|
1061
|
+
async createSearchMessageCollector(message, results, query) {
|
|
1062
|
+
if (!isMessageInstance(message))
|
|
1063
|
+
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1064
|
+
if (!Array.isArray(results) || results.length == 0) {
|
|
1065
|
+
throw new DisTubeError("INVALID_TYPE", "Array<SearchResult|Song|Playlist>", results, "results");
|
|
931
1066
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1067
|
+
if (this.options.searchSongs > 1) {
|
|
1068
|
+
const searchEvents = [
|
|
1069
|
+
"searchNoResult",
|
|
1070
|
+
"searchResult",
|
|
1071
|
+
"searchCancel",
|
|
1072
|
+
"searchInvalidAnswer",
|
|
1073
|
+
"searchDone"
|
|
1074
|
+
];
|
|
1075
|
+
for (const evn of searchEvents) {
|
|
1076
|
+
if (this.distube.listenerCount(evn) === 0) {
|
|
1077
|
+
console.warn(`"searchSongs" option is disabled due to missing "${evn}" listener.`);
|
|
1078
|
+
console.warn(
|
|
1079
|
+
`If you don't want to use "${evn}" event, simply add an empty listener (not recommended):
|
|
1080
|
+
<DisTube>.on("${evn}", () => {})`
|
|
1081
|
+
);
|
|
1082
|
+
this.options.searchSongs = 0;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1087
|
+
let result = results[0];
|
|
1088
|
+
if (limit > 1) {
|
|
1089
|
+
results.splice(limit);
|
|
1090
|
+
this.emit("searchResult", message, results, query);
|
|
1091
|
+
const c = message.channel;
|
|
1092
|
+
const answers = await c.awaitMessages({
|
|
1093
|
+
filter: (m) => m.author.id === message.author.id,
|
|
1094
|
+
max: 1,
|
|
1095
|
+
time: this.options.searchCooldown * 1e3,
|
|
1096
|
+
errors: ["time"]
|
|
1097
|
+
}).catch(() => void 0);
|
|
1098
|
+
const ans = answers?.first();
|
|
1099
|
+
if (!ans) {
|
|
1100
|
+
this.emit("searchCancel", message, query);
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
const index = parseInt(ans.content, 10);
|
|
1104
|
+
if (isNaN(index) || index > results.length || index < 1) {
|
|
1105
|
+
this.emit("searchInvalidAnswer", message, ans, query);
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
this.emit("searchDone", message, ans, query);
|
|
1109
|
+
result = results[index - 1];
|
|
1110
|
+
}
|
|
1111
|
+
return result;
|
|
939
1112
|
}
|
|
940
|
-
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
1113
|
+
async playPlaylist(voiceChannel, playlist, options = {}) {
|
|
1114
|
+
const { textChannel, skip } = { skip: false, ...options };
|
|
1115
|
+
const position = Number(options.position) || (skip ? 1 : 0);
|
|
1116
|
+
if (!(playlist instanceof Playlist))
|
|
1117
|
+
throw new DisTubeError("INVALID_TYPE", "Playlist", playlist, "playlist");
|
|
1118
|
+
const queue = this.queues.get(voiceChannel);
|
|
1119
|
+
if (!this.options.nsfw && !(queue?.textChannel || textChannel)?.nsfw) {
|
|
1120
|
+
playlist.songs = playlist.songs.filter((s) => !s.age_restricted);
|
|
1121
|
+
}
|
|
1122
|
+
if (!playlist.songs.length) {
|
|
1123
|
+
if (!this.options.nsfw && !textChannel?.nsfw) {
|
|
1124
|
+
throw new DisTubeError("EMPTY_FILTERED_PLAYLIST");
|
|
1125
|
+
}
|
|
1126
|
+
throw new DisTubeError("EMPTY_PLAYLIST");
|
|
1127
|
+
}
|
|
1128
|
+
if (queue) {
|
|
1129
|
+
if (this.options.joinNewVoiceChannel)
|
|
1130
|
+
queue.voice.channel = voiceChannel;
|
|
1131
|
+
queue.addToQueue(playlist.songs, position);
|
|
1132
|
+
if (skip)
|
|
1133
|
+
queue.skip();
|
|
1134
|
+
else
|
|
1135
|
+
this.emit("addList", queue, playlist);
|
|
944
1136
|
} else {
|
|
945
|
-
const
|
|
946
|
-
if (
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
__name(DisTubeVoiceManager, "DisTubeVoiceManager");
|
|
953
|
-
|
|
954
|
-
// src/core/manager/FilterManager.ts
|
|
955
|
-
var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
|
|
956
|
-
var FilterManager = class extends BaseManager {
|
|
957
|
-
constructor(queue) {
|
|
958
|
-
super(queue.distube);
|
|
959
|
-
__privateAdd(this, _validate);
|
|
960
|
-
__privateAdd(this, _resolveName);
|
|
961
|
-
__privateAdd(this, _resolveValue);
|
|
962
|
-
__privateAdd(this, _apply);
|
|
963
|
-
__publicField(this, "queue");
|
|
964
|
-
this.queue = queue;
|
|
965
|
-
}
|
|
966
|
-
add(filterOrFilters, override = false) {
|
|
967
|
-
if (Array.isArray(filterOrFilters)) {
|
|
968
|
-
const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
|
|
969
|
-
const newFilters = resolvedFilters.reduceRight((unique, o) => {
|
|
970
|
-
if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
|
|
971
|
-
if (!this.has(o))
|
|
972
|
-
unique.push(o);
|
|
973
|
-
if (this.has(o) && override) {
|
|
974
|
-
this.remove(o);
|
|
975
|
-
unique.push(o);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return unique;
|
|
979
|
-
}, []).reverse();
|
|
980
|
-
return this.set([...this.collection.values(), ...newFilters]);
|
|
981
|
-
}
|
|
982
|
-
return this.set([...this.collection.values(), filterOrFilters]);
|
|
983
|
-
}
|
|
984
|
-
clear() {
|
|
985
|
-
return this.set([]);
|
|
986
|
-
}
|
|
987
|
-
set(filters) {
|
|
988
|
-
this.collection.clear();
|
|
989
|
-
for (const filter of filters) {
|
|
990
|
-
const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
|
|
991
|
-
this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
|
|
992
|
-
}
|
|
993
|
-
__privateMethod(this, _apply, apply_fn).call(this);
|
|
994
|
-
return this;
|
|
995
|
-
}
|
|
996
|
-
remove(filterOrFilters) {
|
|
997
|
-
const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
|
|
998
|
-
if (Array.isArray(filterOrFilters))
|
|
999
|
-
filterOrFilters.map(remove);
|
|
1000
|
-
else
|
|
1001
|
-
remove(filterOrFilters);
|
|
1002
|
-
__privateMethod(this, _apply, apply_fn).call(this);
|
|
1003
|
-
return this;
|
|
1004
|
-
}
|
|
1005
|
-
has(filter) {
|
|
1006
|
-
return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
|
|
1007
|
-
}
|
|
1008
|
-
get names() {
|
|
1009
|
-
return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
|
|
1010
|
-
}
|
|
1011
|
-
get values() {
|
|
1012
|
-
return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
|
|
1013
|
-
}
|
|
1014
|
-
toString() {
|
|
1015
|
-
return this.names.toString();
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
__name(FilterManager, "FilterManager");
|
|
1019
|
-
_validate = new WeakSet();
|
|
1020
|
-
validate_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1021
|
-
if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
|
|
1022
|
-
return filter;
|
|
1023
|
-
}
|
|
1024
|
-
throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
|
|
1025
|
-
}, "#validate");
|
|
1026
|
-
_resolveName = new WeakSet();
|
|
1027
|
-
resolveName_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1028
|
-
return typeof filter === "string" ? filter : filter.name;
|
|
1029
|
-
}, "#resolveName");
|
|
1030
|
-
_resolveValue = new WeakSet();
|
|
1031
|
-
resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1032
|
-
return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
|
|
1033
|
-
}, "#resolveValue");
|
|
1034
|
-
_apply = new WeakSet();
|
|
1035
|
-
apply_fn = /* @__PURE__ */ __name(function() {
|
|
1036
|
-
this.queue.beginTime = this.queue.currentTime;
|
|
1037
|
-
this.queues.playSong(this.queue);
|
|
1038
|
-
}, "#apply");
|
|
1039
|
-
|
|
1040
|
-
// src/core/manager/QueueManager.ts
|
|
1041
|
-
var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
|
|
1042
|
-
var QueueManager = class extends GuildIdManager {
|
|
1043
|
-
constructor() {
|
|
1044
|
-
super(...arguments);
|
|
1045
|
-
__privateAdd(this, _voiceEventHandler);
|
|
1046
|
-
__privateAdd(this, _handleSongFinish);
|
|
1047
|
-
__privateAdd(this, _handlePlayingError);
|
|
1048
|
-
__privateAdd(this, _emitPlaySong);
|
|
1049
|
-
}
|
|
1050
|
-
async create(channel, song, textChannel) {
|
|
1051
|
-
if (this.has(channel.guildId))
|
|
1052
|
-
throw new DisTubeError("QUEUE_EXIST");
|
|
1053
|
-
const voice = this.voices.create(channel);
|
|
1054
|
-
const queue = new Queue(this.distube, voice, song, textChannel);
|
|
1055
|
-
await queue._taskQueue.queuing();
|
|
1056
|
-
try {
|
|
1057
|
-
await voice.join();
|
|
1058
|
-
__privateMethod(this, _voiceEventHandler, voiceEventHandler_fn).call(this, queue);
|
|
1059
|
-
this.add(queue.id, queue);
|
|
1060
|
-
this.emit("initQueue", queue);
|
|
1061
|
-
const err = await this.playSong(queue);
|
|
1062
|
-
return err || queue;
|
|
1063
|
-
} finally {
|
|
1064
|
-
queue._taskQueue.resolve();
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
createStream(queue) {
|
|
1068
|
-
const { duration, formats, isLive, source, streamURL } = queue.songs[0];
|
|
1069
|
-
const ffmpegArgs = queue.filters.size ? ["-af", queue.filters.values.join(",")] : void 0;
|
|
1070
|
-
const seek = duration ? queue.beginTime : void 0;
|
|
1071
|
-
const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };
|
|
1072
|
-
if (source === "youtube")
|
|
1073
|
-
return DisTubeStream.YouTube(formats, streamOptions);
|
|
1074
|
-
return DisTubeStream.DirectLink(streamURL, streamOptions);
|
|
1075
|
-
}
|
|
1076
|
-
async playSong(queue) {
|
|
1077
|
-
if (!queue)
|
|
1078
|
-
return true;
|
|
1079
|
-
if (!queue.songs.length) {
|
|
1080
|
-
queue.stop();
|
|
1081
|
-
return true;
|
|
1082
|
-
}
|
|
1083
|
-
if (queue.stopped)
|
|
1084
|
-
return false;
|
|
1085
|
-
try {
|
|
1086
|
-
const song = queue.songs[0];
|
|
1087
|
-
const { url, source, formats, streamURL } = song;
|
|
1088
|
-
if (source === "youtube" && !formats)
|
|
1089
|
-
song._patchYouTube(await this.handler.getYouTubeInfo(url));
|
|
1090
|
-
if (source !== "youtube" && !streamURL) {
|
|
1091
|
-
for (const plugin of [...this.distube.extractorPlugins, ...this.distube.customPlugins]) {
|
|
1092
|
-
if (await plugin.validate(url)) {
|
|
1093
|
-
const info = [plugin.getStreamURL(url), plugin.getRelatedSongs(url)];
|
|
1094
|
-
const result = await Promise.all(info);
|
|
1095
|
-
song.streamURL = result[0];
|
|
1096
|
-
song.related = result[1];
|
|
1097
|
-
break;
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
const stream = this.createStream(queue);
|
|
1102
|
-
queue.voice.play(stream);
|
|
1103
|
-
song.streamURL = stream.url;
|
|
1104
|
-
if (queue.stopped)
|
|
1105
|
-
queue.stop();
|
|
1106
|
-
else if (queue.paused)
|
|
1107
|
-
queue.voice.pause();
|
|
1108
|
-
return false;
|
|
1109
|
-
} catch (e) {
|
|
1110
|
-
__privateMethod(this, _handlePlayingError, handlePlayingError_fn).call(this, queue, e);
|
|
1111
|
-
return true;
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
};
|
|
1115
|
-
__name(QueueManager, "QueueManager");
|
|
1116
|
-
_voiceEventHandler = new WeakSet();
|
|
1117
|
-
voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
|
|
1118
|
-
queue._listeners = {
|
|
1119
|
-
disconnect: (error) => {
|
|
1120
|
-
queue.remove();
|
|
1121
|
-
this.emit("disconnect", queue);
|
|
1122
|
-
if (error)
|
|
1123
|
-
this.emitError(error, queue.textChannel);
|
|
1124
|
-
},
|
|
1125
|
-
error: (error) => __privateMethod(this, _handlePlayingError, handlePlayingError_fn).call(this, queue, error),
|
|
1126
|
-
finish: () => __privateMethod(this, _handleSongFinish, handleSongFinish_fn).call(this, queue)
|
|
1127
|
-
};
|
|
1128
|
-
for (const event of Object.keys(queue._listeners)) {
|
|
1129
|
-
queue.voice.on(event, queue._listeners[event]);
|
|
1130
|
-
}
|
|
1131
|
-
}, "#voiceEventHandler");
|
|
1132
|
-
_handleSongFinish = new WeakSet();
|
|
1133
|
-
handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
|
|
1134
|
-
this.emit("finishSong", queue, queue.songs[0]);
|
|
1135
|
-
await queue._taskQueue.queuing();
|
|
1136
|
-
try {
|
|
1137
|
-
if (queue.stopped)
|
|
1138
|
-
return;
|
|
1139
|
-
if (queue.repeatMode === 2 /* QUEUE */ && !queue._prev)
|
|
1140
|
-
queue.songs.push(queue.songs[0]);
|
|
1141
|
-
if (queue._prev) {
|
|
1142
|
-
if (queue.repeatMode === 2 /* QUEUE */)
|
|
1143
|
-
queue.songs.unshift(queue.songs.pop());
|
|
1144
|
-
else
|
|
1145
|
-
queue.songs.unshift(queue.previousSongs.pop());
|
|
1146
|
-
}
|
|
1147
|
-
if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
|
|
1148
|
-
if (queue.autoplay) {
|
|
1149
|
-
try {
|
|
1150
|
-
await queue.addRelatedSong();
|
|
1151
|
-
} catch {
|
|
1152
|
-
this.emit("noRelated", queue);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
if (queue.songs.length <= 1) {
|
|
1156
|
-
if (this.options.leaveOnFinish)
|
|
1157
|
-
queue.voice.leave();
|
|
1158
|
-
if (!queue.autoplay)
|
|
1159
|
-
this.emit("finish", queue);
|
|
1160
|
-
queue.remove();
|
|
1161
|
-
return;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
|
|
1165
|
-
if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
|
|
1166
|
-
const prev = queue.songs.shift();
|
|
1167
|
-
delete prev.formats;
|
|
1168
|
-
delete prev.streamURL;
|
|
1169
|
-
if (this.options.savePreviousSongs)
|
|
1170
|
-
queue.previousSongs.push(prev);
|
|
1171
|
-
else
|
|
1172
|
-
queue.previousSongs.push({ id: prev.id });
|
|
1173
|
-
}
|
|
1174
|
-
queue._next = queue._prev = false;
|
|
1175
|
-
queue.beginTime = 0;
|
|
1176
|
-
const err = await this.playSong(queue);
|
|
1177
|
-
if (!err && emitPlaySong)
|
|
1178
|
-
this.emit("playSong", queue, queue.songs[0]);
|
|
1179
|
-
} finally {
|
|
1180
|
-
queue._taskQueue.resolve();
|
|
1181
|
-
}
|
|
1182
|
-
}, "#handleSongFinish");
|
|
1183
|
-
_handlePlayingError = new WeakSet();
|
|
1184
|
-
handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
|
|
1185
|
-
const song = queue.songs.shift();
|
|
1186
|
-
try {
|
|
1187
|
-
error.name = "PlayingError";
|
|
1188
|
-
error.message = `${error.message}
|
|
1189
|
-
Id: ${song.id}
|
|
1190
|
-
Name: ${song.name}`;
|
|
1191
|
-
} catch {
|
|
1192
|
-
}
|
|
1193
|
-
this.emitError(error, queue.textChannel);
|
|
1194
|
-
if (queue.songs.length > 0) {
|
|
1195
|
-
queue._next = queue._prev = false;
|
|
1196
|
-
queue.beginTime = 0;
|
|
1197
|
-
this.playSong(queue).then((e) => {
|
|
1198
|
-
if (!e)
|
|
1199
|
-
this.emit("playSong", queue, queue.songs[0]);
|
|
1200
|
-
});
|
|
1201
|
-
} else {
|
|
1202
|
-
queue.stop();
|
|
1203
|
-
}
|
|
1204
|
-
}, "#handlePlayingError");
|
|
1205
|
-
_emitPlaySong = new WeakSet();
|
|
1206
|
-
emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
|
|
1207
|
-
return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
|
|
1208
|
-
}, "#emitPlaySong");
|
|
1209
|
-
|
|
1210
|
-
// src/core/DisTubeHandler.ts
|
|
1211
|
-
var import_ytpl = __toESM(require("@distube/ytpl"));
|
|
1212
|
-
var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
|
|
1213
|
-
var DisTubeHandler = class extends DisTubeBase {
|
|
1214
|
-
constructor(distube) {
|
|
1215
|
-
super(distube);
|
|
1216
|
-
const client = this.client;
|
|
1217
|
-
if (this.options.leaveOnEmpty) {
|
|
1218
|
-
client.on("voiceStateUpdate", (oldState) => {
|
|
1219
|
-
if (!oldState?.channel)
|
|
1220
|
-
return;
|
|
1221
|
-
const queue = this.queues.get(oldState);
|
|
1222
|
-
if (!queue) {
|
|
1223
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1224
|
-
setTimeout(() => {
|
|
1225
|
-
if (!this.queues.get(oldState) && isVoiceChannelEmpty(oldState))
|
|
1226
|
-
this.voices.leave(oldState);
|
|
1227
|
-
}, this.options.emptyCooldown * 1e3).unref();
|
|
1228
|
-
}
|
|
1229
|
-
return;
|
|
1230
|
-
}
|
|
1231
|
-
if (queue._emptyTimeout) {
|
|
1232
|
-
clearTimeout(queue._emptyTimeout);
|
|
1233
|
-
delete queue._emptyTimeout;
|
|
1234
|
-
}
|
|
1235
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1236
|
-
queue._emptyTimeout = setTimeout(() => {
|
|
1237
|
-
delete queue._emptyTimeout;
|
|
1238
|
-
if (isVoiceChannelEmpty(oldState)) {
|
|
1239
|
-
queue.voice.leave();
|
|
1240
|
-
this.emit("empty", queue);
|
|
1241
|
-
if (queue.stopped)
|
|
1242
|
-
queue.remove();
|
|
1243
|
-
}
|
|
1244
|
-
}, this.options.emptyCooldown * 1e3).unref();
|
|
1245
|
-
}
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
get ytdlOptions() {
|
|
1250
|
-
const options = this.options.ytdlOptions;
|
|
1251
|
-
if (this.options.youtubeCookie) {
|
|
1252
|
-
if (!options.requestOptions)
|
|
1253
|
-
options.requestOptions = {};
|
|
1254
|
-
if (!options.requestOptions.headers)
|
|
1255
|
-
options.requestOptions.headers = {};
|
|
1256
|
-
options.requestOptions.headers.cookie = this.options.youtubeCookie;
|
|
1257
|
-
if (this.options.youtubeIdentityToken) {
|
|
1258
|
-
options.requestOptions.headers["x-youtube-identity-token"] = this.options.youtubeIdentityToken;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
return options;
|
|
1262
|
-
}
|
|
1263
|
-
getYouTubeInfo(url, basic = false) {
|
|
1264
|
-
if (basic)
|
|
1265
|
-
return import_ytdl_core.default.getBasicInfo(url, this.ytdlOptions);
|
|
1266
|
-
return import_ytdl_core.default.getInfo(url, this.ytdlOptions);
|
|
1267
|
-
}
|
|
1268
|
-
async resolve(song, options = {}) {
|
|
1269
|
-
if (song instanceof Song || song instanceof Playlist) {
|
|
1270
|
-
if ("metadata" in options)
|
|
1271
|
-
song.metadata = options.metadata;
|
|
1272
|
-
if ("member" in options)
|
|
1273
|
-
song.member = options.member;
|
|
1274
|
-
return song;
|
|
1275
|
-
}
|
|
1276
|
-
if (song instanceof SearchResultVideo)
|
|
1277
|
-
return new Song(song, options);
|
|
1278
|
-
if (song instanceof SearchResultPlaylist)
|
|
1279
|
-
return this.resolvePlaylist(song.url, options);
|
|
1280
|
-
if (isObject(song)) {
|
|
1281
|
-
if (!("url" in song) && !("id" in song))
|
|
1282
|
-
throw new DisTubeError("CANNOT_RESOLVE_SONG", song);
|
|
1283
|
-
return new Song(song, options);
|
|
1284
|
-
}
|
|
1285
|
-
if (import_ytpl.default.validateID(song))
|
|
1286
|
-
return this.resolvePlaylist(song, options);
|
|
1287
|
-
if (import_ytdl_core.default.validateURL(song))
|
|
1288
|
-
return new Song(await this.getYouTubeInfo(song), options);
|
|
1289
|
-
if (isURL(song)) {
|
|
1290
|
-
for (const plugin of this.distube.extractorPlugins) {
|
|
1291
|
-
if (await plugin.validate(song))
|
|
1292
|
-
return plugin.resolve(song, options);
|
|
1293
|
-
}
|
|
1294
|
-
throw new DisTubeError("NOT_SUPPORTED_URL");
|
|
1295
|
-
}
|
|
1296
|
-
throw new DisTubeError("CANNOT_RESOLVE_SONG", song);
|
|
1297
|
-
}
|
|
1298
|
-
async resolvePlaylist(playlist, options = {}) {
|
|
1299
|
-
const { member, source, metadata } = { source: "youtube", ...options };
|
|
1300
|
-
if (playlist instanceof Playlist) {
|
|
1301
|
-
if ("metadata" in options)
|
|
1302
|
-
playlist.metadata = metadata;
|
|
1303
|
-
if ("member" in options)
|
|
1304
|
-
playlist.member = member;
|
|
1305
|
-
return playlist;
|
|
1306
|
-
}
|
|
1307
|
-
if (typeof playlist === "string") {
|
|
1308
|
-
const info = await (0, import_ytpl.default)(playlist, { limit: Infinity });
|
|
1309
|
-
const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
|
|
1310
|
-
return new Playlist({
|
|
1311
|
-
source,
|
|
1312
|
-
songs,
|
|
1313
|
-
member,
|
|
1314
|
-
name: info.title,
|
|
1315
|
-
url: info.url,
|
|
1316
|
-
thumbnail: songs[0].thumbnail
|
|
1317
|
-
}, { metadata });
|
|
1318
|
-
}
|
|
1319
|
-
return new Playlist(playlist, { member, properties: { source }, metadata });
|
|
1320
|
-
}
|
|
1321
|
-
async searchSong(message, query) {
|
|
1322
|
-
if (!isMessageInstance(message))
|
|
1323
|
-
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1324
|
-
if (typeof query !== "string")
|
|
1325
|
-
throw new DisTubeError("INVALID_TYPE", "string", query, "query");
|
|
1326
|
-
if (query.length === 0)
|
|
1327
|
-
throw new DisTubeError("EMPTY_STRING", "query");
|
|
1328
|
-
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1329
|
-
const results = await this.distube.search(query, {
|
|
1330
|
-
limit,
|
|
1331
|
-
safeSearch: this.options.nsfw ? false : !message.channel?.nsfw
|
|
1332
|
-
}).catch(() => {
|
|
1333
|
-
if (!this.emit("searchNoResult", message, query)) {
|
|
1334
|
-
console.warn("searchNoResult event does not have any listeners! Emits `error` event instead.");
|
|
1335
|
-
throw new DisTubeError("NO_RESULT");
|
|
1336
|
-
}
|
|
1337
|
-
});
|
|
1338
|
-
if (!results)
|
|
1339
|
-
return null;
|
|
1340
|
-
return this.createSearchMessageCollector(message, results, query);
|
|
1341
|
-
}
|
|
1342
|
-
async createSearchMessageCollector(message, results, query) {
|
|
1343
|
-
if (!isMessageInstance(message))
|
|
1344
|
-
throw new DisTubeError("INVALID_TYPE", "Discord.Message", message, "message");
|
|
1345
|
-
if (!Array.isArray(results) || results.length == 0) {
|
|
1346
|
-
throw new DisTubeError("INVALID_TYPE", "Array<SearchResult|Song|Playlist>", results, "results");
|
|
1347
|
-
}
|
|
1348
|
-
if (this.options.searchSongs > 1) {
|
|
1349
|
-
const searchEvents = [
|
|
1350
|
-
"searchNoResult",
|
|
1351
|
-
"searchResult",
|
|
1352
|
-
"searchCancel",
|
|
1353
|
-
"searchInvalidAnswer",
|
|
1354
|
-
"searchDone"
|
|
1355
|
-
];
|
|
1356
|
-
for (const evn of searchEvents) {
|
|
1357
|
-
if (this.distube.listenerCount(evn) === 0) {
|
|
1358
|
-
console.warn(`"searchSongs" option is disabled due to missing "${evn}" listener.`);
|
|
1359
|
-
console.warn(`If you don't want to use "${evn}" event, simply add an empty listener (not recommended):
|
|
1360
|
-
<DisTube>.on("${evn}", () => {})`);
|
|
1361
|
-
this.options.searchSongs = 0;
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;
|
|
1366
|
-
let result = results[0];
|
|
1367
|
-
if (limit > 1) {
|
|
1368
|
-
results.splice(limit);
|
|
1369
|
-
this.emit("searchResult", message, results, query);
|
|
1370
|
-
const c = message.channel;
|
|
1371
|
-
const answers = await c.awaitMessages({
|
|
1372
|
-
filter: (m) => m.author.id === message.author.id,
|
|
1373
|
-
max: 1,
|
|
1374
|
-
time: this.options.searchCooldown * 1e3,
|
|
1375
|
-
errors: ["time"]
|
|
1376
|
-
}).catch(() => void 0);
|
|
1377
|
-
const ans = answers?.first();
|
|
1378
|
-
if (!ans) {
|
|
1379
|
-
this.emit("searchCancel", message, query);
|
|
1380
|
-
return null;
|
|
1381
|
-
}
|
|
1382
|
-
const index = parseInt(ans.content, 10);
|
|
1383
|
-
if (isNaN(index) || index > results.length || index < 1) {
|
|
1384
|
-
this.emit("searchInvalidAnswer", message, ans, query);
|
|
1385
|
-
return null;
|
|
1386
|
-
}
|
|
1387
|
-
this.emit("searchDone", message, ans, query);
|
|
1388
|
-
result = results[index - 1];
|
|
1389
|
-
}
|
|
1390
|
-
return result;
|
|
1391
|
-
}
|
|
1392
|
-
async playPlaylist(voiceChannel, playlist, options = {}) {
|
|
1393
|
-
const { textChannel, skip } = { skip: false, ...options };
|
|
1394
|
-
const position = Number(options.position) || (skip ? 1 : 0);
|
|
1395
|
-
if (!(playlist instanceof Playlist))
|
|
1396
|
-
throw new DisTubeError("INVALID_TYPE", "Playlist", playlist, "playlist");
|
|
1397
|
-
const queue = this.queues.get(voiceChannel);
|
|
1398
|
-
if (!this.options.nsfw && !(queue?.textChannel || textChannel)?.nsfw) {
|
|
1399
|
-
playlist.songs = playlist.songs.filter((s) => !s.age_restricted);
|
|
1400
|
-
}
|
|
1401
|
-
if (!playlist.songs.length) {
|
|
1402
|
-
if (!this.options.nsfw && !textChannel?.nsfw) {
|
|
1403
|
-
throw new DisTubeError("EMPTY_FILTERED_PLAYLIST");
|
|
1404
|
-
}
|
|
1405
|
-
throw new DisTubeError("EMPTY_PLAYLIST");
|
|
1406
|
-
}
|
|
1407
|
-
if (queue) {
|
|
1408
|
-
if (this.options.joinNewVoiceChannel)
|
|
1409
|
-
queue.voice.channel = voiceChannel;
|
|
1410
|
-
queue.addToQueue(playlist.songs, position);
|
|
1411
|
-
if (skip)
|
|
1412
|
-
queue.skip();
|
|
1413
|
-
else
|
|
1414
|
-
this.emit("addList", queue, playlist);
|
|
1415
|
-
} else {
|
|
1416
|
-
const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);
|
|
1417
|
-
if (newQueue instanceof Queue) {
|
|
1418
|
-
if (this.options.emitAddListWhenCreatingQueue)
|
|
1419
|
-
this.emit("addList", newQueue, playlist);
|
|
1420
|
-
this.emit("playSong", newQueue, newQueue.songs[0]);
|
|
1137
|
+
const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);
|
|
1138
|
+
if (newQueue instanceof Queue) {
|
|
1139
|
+
if (this.options.emitAddListWhenCreatingQueue)
|
|
1140
|
+
this.emit("addList", newQueue, playlist);
|
|
1141
|
+
this.emit("playSong", newQueue, newQueue.songs[0]);
|
|
1421
1142
|
}
|
|
1422
1143
|
}
|
|
1423
1144
|
}
|
|
@@ -1520,13 +1241,23 @@ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
|
|
|
1520
1241
|
throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
|
|
1521
1242
|
}
|
|
1522
1243
|
if (typeof options.joinNewVoiceChannel !== "boolean") {
|
|
1523
|
-
throw new DisTubeError(
|
|
1244
|
+
throw new DisTubeError(
|
|
1245
|
+
"INVALID_TYPE",
|
|
1246
|
+
"boolean",
|
|
1247
|
+
options.joinNewVoiceChannel,
|
|
1248
|
+
"DisTubeOptions.joinNewVoiceChannel"
|
|
1249
|
+
);
|
|
1524
1250
|
}
|
|
1525
1251
|
if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
|
|
1526
1252
|
throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
|
|
1527
1253
|
}
|
|
1528
1254
|
if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
|
|
1529
|
-
throw new DisTubeError(
|
|
1255
|
+
throw new DisTubeError(
|
|
1256
|
+
"INVALID_TYPE",
|
|
1257
|
+
"string",
|
|
1258
|
+
options.youtubeIdentityToken,
|
|
1259
|
+
"DisTubeOptions.youtubeIdentityToken"
|
|
1260
|
+
);
|
|
1530
1261
|
}
|
|
1531
1262
|
if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
|
|
1532
1263
|
throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
|
|
@@ -1550,90 +1281,424 @@ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
|
|
|
1550
1281
|
throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
|
|
1551
1282
|
}
|
|
1552
1283
|
if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
|
|
1553
|
-
throw new DisTubeError(
|
|
1284
|
+
throw new DisTubeError(
|
|
1285
|
+
"INVALID_TYPE",
|
|
1286
|
+
"boolean",
|
|
1287
|
+
options.emitAddSongWhenCreatingQueue,
|
|
1288
|
+
"DisTubeOptions.emitAddSongWhenCreatingQueue"
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
|
|
1292
|
+
throw new DisTubeError(
|
|
1293
|
+
"INVALID_TYPE",
|
|
1294
|
+
"boolean",
|
|
1295
|
+
options.emitAddListWhenCreatingQueue,
|
|
1296
|
+
"DisTubeOptions.emitAddListWhenCreatingQueue"
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
|
|
1300
|
+
throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
|
|
1301
|
+
}
|
|
1302
|
+
if (typeof options.directLink !== "boolean") {
|
|
1303
|
+
throw new DisTubeError("INVALID_TYPE", "boolean", options.directLink, "DisTubeOptions.directLink");
|
|
1304
|
+
}
|
|
1305
|
+
}, "#validateOptions");
|
|
1306
|
+
|
|
1307
|
+
// src/core/DisTubeStream.ts
|
|
1308
|
+
var import_prism_media = require("prism-media");
|
|
1309
|
+
var import_voice2 = require("@discordjs/voice");
|
|
1310
|
+
var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
|
|
1311
|
+
let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
|
|
1312
|
+
if (isLive)
|
|
1313
|
+
filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
|
|
1314
|
+
formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
|
|
1315
|
+
return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
|
|
1316
|
+
}, "chooseBestVideoFormat");
|
|
1317
|
+
var DisTubeStream = class {
|
|
1318
|
+
constructor(url, options) {
|
|
1319
|
+
__publicField(this, "type");
|
|
1320
|
+
__publicField(this, "stream");
|
|
1321
|
+
__publicField(this, "url");
|
|
1322
|
+
this.url = url;
|
|
1323
|
+
this.type = !options.type ? import_voice2.StreamType.OggOpus : import_voice2.StreamType.Raw;
|
|
1324
|
+
const args = [
|
|
1325
|
+
"-reconnect",
|
|
1326
|
+
"1",
|
|
1327
|
+
"-reconnect_streamed",
|
|
1328
|
+
"1",
|
|
1329
|
+
"-reconnect_delay_max",
|
|
1330
|
+
"5",
|
|
1331
|
+
"-i",
|
|
1332
|
+
url,
|
|
1333
|
+
"-analyzeduration",
|
|
1334
|
+
"0",
|
|
1335
|
+
"-loglevel",
|
|
1336
|
+
"0",
|
|
1337
|
+
"-ar",
|
|
1338
|
+
"48000",
|
|
1339
|
+
"-ac",
|
|
1340
|
+
"2",
|
|
1341
|
+
"-f"
|
|
1342
|
+
];
|
|
1343
|
+
if (!options.type) {
|
|
1344
|
+
args.push("opus", "-acodec", "libopus");
|
|
1345
|
+
} else {
|
|
1346
|
+
args.push("s16le");
|
|
1347
|
+
}
|
|
1348
|
+
if (typeof options.seek === "number" && options.seek > 0) {
|
|
1349
|
+
args.unshift("-ss", options.seek.toString());
|
|
1350
|
+
}
|
|
1351
|
+
if (Array.isArray(options.ffmpegArgs)) {
|
|
1352
|
+
args.push(...options.ffmpegArgs);
|
|
1353
|
+
}
|
|
1354
|
+
this.stream = new import_prism_media.FFmpeg({ args, shell: false });
|
|
1355
|
+
this.stream._readableState && (this.stream._readableState.highWaterMark = 1 << 25);
|
|
1356
|
+
}
|
|
1357
|
+
static YouTube(formats, options = {}) {
|
|
1358
|
+
if (!formats || !formats.length)
|
|
1359
|
+
throw new DisTubeError("UNAVAILABLE_VIDEO");
|
|
1360
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1361
|
+
throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
1362
|
+
}
|
|
1363
|
+
const bestFormat = chooseBestVideoFormat(formats, options.isLive);
|
|
1364
|
+
if (!bestFormat)
|
|
1365
|
+
throw new DisTubeError("UNPLAYABLE_FORMATS");
|
|
1366
|
+
return new DisTubeStream(bestFormat.url, options);
|
|
1367
|
+
}
|
|
1368
|
+
static DirectLink(url, options = {}) {
|
|
1369
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1370
|
+
throw new DisTubeError("INVALID_TYPE", "object", options, "options");
|
|
1371
|
+
}
|
|
1372
|
+
if (typeof url !== "string" || !isURL(url)) {
|
|
1373
|
+
throw new DisTubeError("INVALID_TYPE", "an URL", url);
|
|
1374
|
+
}
|
|
1375
|
+
return new DisTubeStream(url, options);
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
__name(DisTubeStream, "DisTubeStream");
|
|
1379
|
+
|
|
1380
|
+
// src/core/manager/BaseManager.ts
|
|
1381
|
+
var import_discord2 = require("discord.js");
|
|
1382
|
+
var BaseManager = class extends DisTubeBase {
|
|
1383
|
+
constructor() {
|
|
1384
|
+
super(...arguments);
|
|
1385
|
+
__publicField(this, "collection", new import_discord2.Collection());
|
|
1386
|
+
}
|
|
1387
|
+
get size() {
|
|
1388
|
+
return this.collection.size;
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1391
|
+
__name(BaseManager, "BaseManager");
|
|
1392
|
+
|
|
1393
|
+
// src/core/manager/GuildIdManager.ts
|
|
1394
|
+
var GuildIdManager = class extends BaseManager {
|
|
1395
|
+
add(idOrInstance, data) {
|
|
1396
|
+
const id = resolveGuildId(idOrInstance);
|
|
1397
|
+
const existing = this.get(id);
|
|
1398
|
+
if (existing)
|
|
1399
|
+
return this;
|
|
1400
|
+
return this.collection.set(id, data);
|
|
1401
|
+
}
|
|
1402
|
+
get(idOrInstance) {
|
|
1403
|
+
return this.collection.get(resolveGuildId(idOrInstance));
|
|
1404
|
+
}
|
|
1405
|
+
remove(idOrInstance) {
|
|
1406
|
+
return this.collection.delete(resolveGuildId(idOrInstance));
|
|
1407
|
+
}
|
|
1408
|
+
has(idOrInstance) {
|
|
1409
|
+
return this.collection.has(resolveGuildId(idOrInstance));
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
__name(GuildIdManager, "GuildIdManager");
|
|
1413
|
+
|
|
1414
|
+
// src/core/manager/DisTubeVoiceManager.ts
|
|
1415
|
+
var import_voice3 = require("@discordjs/voice");
|
|
1416
|
+
var DisTubeVoiceManager = class extends GuildIdManager {
|
|
1417
|
+
create(channel) {
|
|
1418
|
+
const existing = this.get(channel.guildId);
|
|
1419
|
+
if (existing) {
|
|
1420
|
+
existing.channel = channel;
|
|
1421
|
+
return existing;
|
|
1422
|
+
}
|
|
1423
|
+
return new DisTubeVoice(this, channel);
|
|
1424
|
+
}
|
|
1425
|
+
join(channel) {
|
|
1426
|
+
const existing = this.get(channel.guildId);
|
|
1427
|
+
if (existing)
|
|
1428
|
+
return existing.join(channel);
|
|
1429
|
+
return this.create(channel).join();
|
|
1430
|
+
}
|
|
1431
|
+
leave(guild) {
|
|
1432
|
+
const voice = this.get(guild);
|
|
1433
|
+
if (voice) {
|
|
1434
|
+
voice.leave();
|
|
1435
|
+
} else {
|
|
1436
|
+
const connection = (0, import_voice3.getVoiceConnection)(resolveGuildId(guild), this.client.user?.id) ?? (0, import_voice3.getVoiceConnection)(resolveGuildId(guild));
|
|
1437
|
+
if (connection && connection.state.status !== import_voice3.VoiceConnectionStatus.Destroyed) {
|
|
1438
|
+
connection.destroy();
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
__name(DisTubeVoiceManager, "DisTubeVoiceManager");
|
|
1444
|
+
|
|
1445
|
+
// src/core/manager/FilterManager.ts
|
|
1446
|
+
var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
|
|
1447
|
+
var FilterManager = class extends BaseManager {
|
|
1448
|
+
constructor(queue) {
|
|
1449
|
+
super(queue.distube);
|
|
1450
|
+
__privateAdd(this, _validate);
|
|
1451
|
+
__privateAdd(this, _resolveName);
|
|
1452
|
+
__privateAdd(this, _resolveValue);
|
|
1453
|
+
__privateAdd(this, _apply);
|
|
1454
|
+
__publicField(this, "queue");
|
|
1455
|
+
this.queue = queue;
|
|
1456
|
+
}
|
|
1457
|
+
add(filterOrFilters, override = false) {
|
|
1458
|
+
if (Array.isArray(filterOrFilters)) {
|
|
1459
|
+
const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
|
|
1460
|
+
const newFilters = resolvedFilters.reduceRight((unique, o) => {
|
|
1461
|
+
if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
|
|
1462
|
+
if (!this.has(o))
|
|
1463
|
+
unique.push(o);
|
|
1464
|
+
if (this.has(o) && override) {
|
|
1465
|
+
this.remove(o);
|
|
1466
|
+
unique.push(o);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return unique;
|
|
1470
|
+
}, []).reverse();
|
|
1471
|
+
return this.set([...this.collection.values(), ...newFilters]);
|
|
1472
|
+
}
|
|
1473
|
+
return this.set([...this.collection.values(), filterOrFilters]);
|
|
1474
|
+
}
|
|
1475
|
+
clear() {
|
|
1476
|
+
return this.set([]);
|
|
1477
|
+
}
|
|
1478
|
+
set(filters) {
|
|
1479
|
+
this.collection.clear();
|
|
1480
|
+
for (const filter of filters) {
|
|
1481
|
+
const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
|
|
1482
|
+
this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
|
|
1483
|
+
}
|
|
1484
|
+
__privateMethod(this, _apply, apply_fn).call(this);
|
|
1485
|
+
return this;
|
|
1486
|
+
}
|
|
1487
|
+
remove(filterOrFilters) {
|
|
1488
|
+
const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
|
|
1489
|
+
if (Array.isArray(filterOrFilters))
|
|
1490
|
+
filterOrFilters.map(remove);
|
|
1491
|
+
else
|
|
1492
|
+
remove(filterOrFilters);
|
|
1493
|
+
__privateMethod(this, _apply, apply_fn).call(this);
|
|
1494
|
+
return this;
|
|
1495
|
+
}
|
|
1496
|
+
has(filter) {
|
|
1497
|
+
return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
|
|
1498
|
+
}
|
|
1499
|
+
get names() {
|
|
1500
|
+
return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
|
|
1554
1501
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1502
|
+
get values() {
|
|
1503
|
+
return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
|
|
1557
1504
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1505
|
+
toString() {
|
|
1506
|
+
return this.names.toString();
|
|
1560
1507
|
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1508
|
+
};
|
|
1509
|
+
__name(FilterManager, "FilterManager");
|
|
1510
|
+
_validate = new WeakSet();
|
|
1511
|
+
validate_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1512
|
+
if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
|
|
1513
|
+
return filter;
|
|
1563
1514
|
}
|
|
1564
|
-
|
|
1515
|
+
throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
|
|
1516
|
+
}, "#validate");
|
|
1517
|
+
_resolveName = new WeakSet();
|
|
1518
|
+
resolveName_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1519
|
+
return typeof filter === "string" ? filter : filter.name;
|
|
1520
|
+
}, "#resolveName");
|
|
1521
|
+
_resolveValue = new WeakSet();
|
|
1522
|
+
resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
|
|
1523
|
+
return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
|
|
1524
|
+
}, "#resolveValue");
|
|
1525
|
+
_apply = new WeakSet();
|
|
1526
|
+
apply_fn = /* @__PURE__ */ __name(function() {
|
|
1527
|
+
this.queue.beginTime = this.queue.currentTime;
|
|
1528
|
+
this.queues.playSong(this.queue);
|
|
1529
|
+
}, "#apply");
|
|
1565
1530
|
|
|
1566
|
-
// src/core/
|
|
1567
|
-
var
|
|
1568
|
-
var
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
"
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
url,
|
|
1592
|
-
"-analyzeduration",
|
|
1593
|
-
"0",
|
|
1594
|
-
"-loglevel",
|
|
1595
|
-
"0",
|
|
1596
|
-
"-ar",
|
|
1597
|
-
"48000",
|
|
1598
|
-
"-ac",
|
|
1599
|
-
"2",
|
|
1600
|
-
"-f"
|
|
1601
|
-
];
|
|
1602
|
-
if (!options.type) {
|
|
1603
|
-
args.push("opus", "-acodec", "libopus");
|
|
1604
|
-
} else {
|
|
1605
|
-
args.push("s16le");
|
|
1531
|
+
// src/core/manager/QueueManager.ts
|
|
1532
|
+
var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
|
|
1533
|
+
var QueueManager = class extends GuildIdManager {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
super(...arguments);
|
|
1536
|
+
__privateAdd(this, _voiceEventHandler);
|
|
1537
|
+
__privateAdd(this, _handleSongFinish);
|
|
1538
|
+
__privateAdd(this, _handlePlayingError);
|
|
1539
|
+
__privateAdd(this, _emitPlaySong);
|
|
1540
|
+
}
|
|
1541
|
+
async create(channel, song, textChannel) {
|
|
1542
|
+
if (this.has(channel.guildId))
|
|
1543
|
+
throw new DisTubeError("QUEUE_EXIST");
|
|
1544
|
+
const voice = this.voices.create(channel);
|
|
1545
|
+
const queue = new Queue(this.distube, voice, song, textChannel);
|
|
1546
|
+
await queue._taskQueue.queuing();
|
|
1547
|
+
try {
|
|
1548
|
+
await voice.join();
|
|
1549
|
+
__privateMethod(this, _voiceEventHandler, voiceEventHandler_fn).call(this, queue);
|
|
1550
|
+
this.add(queue.id, queue);
|
|
1551
|
+
this.emit("initQueue", queue);
|
|
1552
|
+
const err = await this.playSong(queue);
|
|
1553
|
+
return err || queue;
|
|
1554
|
+
} finally {
|
|
1555
|
+
queue._taskQueue.resolve();
|
|
1606
1556
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1557
|
+
}
|
|
1558
|
+
createStream(queue) {
|
|
1559
|
+
const { duration, formats, isLive, source, streamURL } = queue.songs[0];
|
|
1560
|
+
const ffmpegArgs = queue.filters.size ? ["-af", queue.filters.values.join(",")] : void 0;
|
|
1561
|
+
const seek = duration ? queue.beginTime : void 0;
|
|
1562
|
+
const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };
|
|
1563
|
+
if (source === "youtube")
|
|
1564
|
+
return DisTubeStream.YouTube(formats, streamOptions);
|
|
1565
|
+
return DisTubeStream.DirectLink(streamURL, streamOptions);
|
|
1566
|
+
}
|
|
1567
|
+
async playSong(queue) {
|
|
1568
|
+
if (!queue)
|
|
1569
|
+
return true;
|
|
1570
|
+
if (!queue.songs.length) {
|
|
1571
|
+
queue.stop();
|
|
1572
|
+
return true;
|
|
1609
1573
|
}
|
|
1610
|
-
if (
|
|
1611
|
-
|
|
1574
|
+
if (queue.stopped)
|
|
1575
|
+
return false;
|
|
1576
|
+
try {
|
|
1577
|
+
const song = queue.songs[0];
|
|
1578
|
+
const { url, source, formats, streamURL, isLive } = song;
|
|
1579
|
+
if (source === "youtube") {
|
|
1580
|
+
if (!formats || !chooseBestVideoFormat(formats, isLive)) {
|
|
1581
|
+
song._patchYouTube(await this.handler.getYouTubeInfo(url));
|
|
1582
|
+
}
|
|
1583
|
+
} else if (!streamURL) {
|
|
1584
|
+
for (const plugin of [...this.distube.extractorPlugins, ...this.distube.customPlugins]) {
|
|
1585
|
+
if (await plugin.validate(url)) {
|
|
1586
|
+
const info = [plugin.getStreamURL(url), plugin.getRelatedSongs(url)];
|
|
1587
|
+
const result = await Promise.all(info);
|
|
1588
|
+
song.streamURL = result[0];
|
|
1589
|
+
song.related = result[1];
|
|
1590
|
+
break;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
const stream = this.createStream(queue);
|
|
1595
|
+
queue.voice.play(stream);
|
|
1596
|
+
song.streamURL = stream.url;
|
|
1597
|
+
if (queue.stopped)
|
|
1598
|
+
queue.stop();
|
|
1599
|
+
else if (queue.paused)
|
|
1600
|
+
queue.voice.pause();
|
|
1601
|
+
return false;
|
|
1602
|
+
} catch (e) {
|
|
1603
|
+
__privateMethod(this, _handlePlayingError, handlePlayingError_fn).call(this, queue, e);
|
|
1604
|
+
return true;
|
|
1612
1605
|
}
|
|
1613
|
-
this.stream = new import_prism_media.FFmpeg({ args, shell: false });
|
|
1614
1606
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1607
|
+
};
|
|
1608
|
+
__name(QueueManager, "QueueManager");
|
|
1609
|
+
_voiceEventHandler = new WeakSet();
|
|
1610
|
+
voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
|
|
1611
|
+
queue._listeners = {
|
|
1612
|
+
disconnect: (error) => {
|
|
1613
|
+
queue.remove();
|
|
1614
|
+
this.emit("disconnect", queue);
|
|
1615
|
+
if (error)
|
|
1616
|
+
this.emitError(error, queue.textChannel);
|
|
1617
|
+
},
|
|
1618
|
+
error: (error) => __privateMethod(this, _handlePlayingError, handlePlayingError_fn).call(this, queue, error),
|
|
1619
|
+
finish: () => __privateMethod(this, _handleSongFinish, handleSongFinish_fn).call(this, queue)
|
|
1620
|
+
};
|
|
1621
|
+
for (const event of objectKeys(queue._listeners)) {
|
|
1622
|
+
queue.voice.on(event, queue._listeners[event]);
|
|
1625
1623
|
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1624
|
+
}, "#voiceEventHandler");
|
|
1625
|
+
_handleSongFinish = new WeakSet();
|
|
1626
|
+
handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
|
|
1627
|
+
this.emit("finishSong", queue, queue.songs[0]);
|
|
1628
|
+
await queue._taskQueue.queuing();
|
|
1629
|
+
try {
|
|
1630
|
+
if (queue.stopped)
|
|
1631
|
+
return;
|
|
1632
|
+
if (queue.repeatMode === 2 /* QUEUE */ && !queue._prev)
|
|
1633
|
+
queue.songs.push(queue.songs[0]);
|
|
1634
|
+
if (queue._prev) {
|
|
1635
|
+
if (queue.repeatMode === 2 /* QUEUE */)
|
|
1636
|
+
queue.songs.unshift(queue.songs.pop());
|
|
1637
|
+
else
|
|
1638
|
+
queue.songs.unshift(queue.previousSongs.pop());
|
|
1629
1639
|
}
|
|
1630
|
-
if (
|
|
1631
|
-
|
|
1640
|
+
if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
|
|
1641
|
+
if (queue.autoplay) {
|
|
1642
|
+
try {
|
|
1643
|
+
await queue.addRelatedSong();
|
|
1644
|
+
} catch {
|
|
1645
|
+
this.emit("noRelated", queue);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
if (queue.songs.length <= 1) {
|
|
1649
|
+
if (this.options.leaveOnFinish)
|
|
1650
|
+
queue.voice.leave();
|
|
1651
|
+
if (!queue.autoplay)
|
|
1652
|
+
this.emit("finish", queue);
|
|
1653
|
+
queue.remove();
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1632
1656
|
}
|
|
1633
|
-
|
|
1657
|
+
const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
|
|
1658
|
+
if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
|
|
1659
|
+
const prev = queue.songs.shift();
|
|
1660
|
+
delete prev.formats;
|
|
1661
|
+
delete prev.streamURL;
|
|
1662
|
+
if (this.options.savePreviousSongs)
|
|
1663
|
+
queue.previousSongs.push(prev);
|
|
1664
|
+
else
|
|
1665
|
+
queue.previousSongs.push({ id: prev.id });
|
|
1666
|
+
}
|
|
1667
|
+
queue._next = queue._prev = false;
|
|
1668
|
+
queue.beginTime = 0;
|
|
1669
|
+
const err = await this.playSong(queue);
|
|
1670
|
+
if (!err && emitPlaySong)
|
|
1671
|
+
this.emit("playSong", queue, queue.songs[0]);
|
|
1672
|
+
} finally {
|
|
1673
|
+
queue._taskQueue.resolve();
|
|
1634
1674
|
}
|
|
1635
|
-
};
|
|
1636
|
-
|
|
1675
|
+
}, "#handleSongFinish");
|
|
1676
|
+
_handlePlayingError = new WeakSet();
|
|
1677
|
+
handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
|
|
1678
|
+
const song = queue.songs.shift();
|
|
1679
|
+
try {
|
|
1680
|
+
error.name = "PlayingError";
|
|
1681
|
+
error.message = `${error.message}
|
|
1682
|
+
Id: ${song.id}
|
|
1683
|
+
Name: ${song.name}`;
|
|
1684
|
+
} catch {
|
|
1685
|
+
}
|
|
1686
|
+
this.emitError(error, queue.textChannel);
|
|
1687
|
+
if (queue.songs.length > 0) {
|
|
1688
|
+
queue._next = queue._prev = false;
|
|
1689
|
+
queue.beginTime = 0;
|
|
1690
|
+
this.playSong(queue).then((e) => {
|
|
1691
|
+
if (!e)
|
|
1692
|
+
this.emit("playSong", queue, queue.songs[0]);
|
|
1693
|
+
});
|
|
1694
|
+
} else {
|
|
1695
|
+
queue.stop();
|
|
1696
|
+
}
|
|
1697
|
+
}, "#handlePlayingError");
|
|
1698
|
+
_emitPlaySong = new WeakSet();
|
|
1699
|
+
emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
|
|
1700
|
+
return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
|
|
1701
|
+
}, "#emitPlaySong");
|
|
1637
1702
|
|
|
1638
1703
|
// src/struct/Queue.ts
|
|
1639
1704
|
var _filters;
|
|
@@ -1881,7 +1946,7 @@ var Queue = class extends DisTubeBase {
|
|
|
1881
1946
|
this.songs = [];
|
|
1882
1947
|
this.previousSongs = [];
|
|
1883
1948
|
if (this._listeners) {
|
|
1884
|
-
for (const event of
|
|
1949
|
+
for (const event of objectKeys(this._listeners)) {
|
|
1885
1950
|
this.voice.removeListener(event, this._listeners[event]);
|
|
1886
1951
|
}
|
|
1887
1952
|
}
|
|
@@ -1957,7 +2022,7 @@ __name(ExtractorPlugin, "ExtractorPlugin");
|
|
|
1957
2022
|
|
|
1958
2023
|
// src/util.ts
|
|
1959
2024
|
var import_url = require("url");
|
|
1960
|
-
var
|
|
2025
|
+
var import_discord3 = require("discord.js");
|
|
1961
2026
|
var formatInt = /* @__PURE__ */ __name((int) => int < 10 ? `0${int}` : int, "formatInt");
|
|
1962
2027
|
function formatDuration(sec) {
|
|
1963
2028
|
if (!sec || !Number(sec))
|
|
@@ -2011,8 +2076,8 @@ function isURL(input) {
|
|
|
2011
2076
|
}
|
|
2012
2077
|
__name(isURL, "isURL");
|
|
2013
2078
|
function checkIntents(options) {
|
|
2014
|
-
const intents = new
|
|
2015
|
-
if (!intents.has(
|
|
2079
|
+
const intents = new import_discord3.IntentsBitField(options.intents);
|
|
2080
|
+
if (!intents.has(import_discord3.GatewayIntentBits.GuildVoiceStates))
|
|
2016
2081
|
throw new DisTubeError("MISSING_INTENTS", "GuildVoiceStates");
|
|
2017
2082
|
}
|
|
2018
2083
|
__name(checkIntents, "checkIntents");
|
|
@@ -2030,7 +2095,7 @@ function isVoiceChannelEmpty(voiceState) {
|
|
|
2030
2095
|
__name(isVoiceChannelEmpty, "isVoiceChannelEmpty");
|
|
2031
2096
|
function isSnowflake(id) {
|
|
2032
2097
|
try {
|
|
2033
|
-
return
|
|
2098
|
+
return import_discord3.SnowflakeUtil.deconstruct(id).timestamp > import_discord3.SnowflakeUtil.epoch;
|
|
2034
2099
|
} catch {
|
|
2035
2100
|
return false;
|
|
2036
2101
|
}
|
|
@@ -2041,15 +2106,15 @@ function isMemberInstance(member) {
|
|
|
2041
2106
|
}
|
|
2042
2107
|
__name(isMemberInstance, "isMemberInstance");
|
|
2043
2108
|
function isTextChannelInstance(channel) {
|
|
2044
|
-
return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" &&
|
|
2109
|
+
return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && import_discord3.Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.nsfw === "boolean" && "messages" in channel && typeof channel.send === "function";
|
|
2045
2110
|
}
|
|
2046
2111
|
__name(isTextChannelInstance, "isTextChannelInstance");
|
|
2047
2112
|
function isMessageInstance(message) {
|
|
2048
|
-
return !!message && isSnowflake(message.id) && isSnowflake(message.guildId) && isMemberInstance(message.member) && isTextChannelInstance(message.channel) &&
|
|
2113
|
+
return !!message && isSnowflake(message.id) && isSnowflake(message.guildId) && isMemberInstance(message.member) && isTextChannelInstance(message.channel) && import_discord3.Constants.NonSystemMessageTypes.includes(message.type) && message.member.id === message.author?.id;
|
|
2049
2114
|
}
|
|
2050
2115
|
__name(isMessageInstance, "isMessageInstance");
|
|
2051
2116
|
function isSupportedVoiceChannel(channel) {
|
|
2052
|
-
return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) &&
|
|
2117
|
+
return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && import_discord3.Constants.VoiceBasedChannelTypes.includes(channel.type);
|
|
2053
2118
|
}
|
|
2054
2119
|
__name(isSupportedVoiceChannel, "isSupportedVoiceChannel");
|
|
2055
2120
|
function isGuildInstance(guild) {
|
|
@@ -2081,8 +2146,8 @@ __name(isClientInstance, "isClientInstance");
|
|
|
2081
2146
|
function checkInvalidKey(target, source, sourceName) {
|
|
2082
2147
|
if (!isObject(target))
|
|
2083
2148
|
throw new DisTubeError("INVALID_TYPE", "object", target, sourceName);
|
|
2084
|
-
const sourceKeys = Array.isArray(source) ? source :
|
|
2085
|
-
const invalidKey =
|
|
2149
|
+
const sourceKeys = Array.isArray(source) ? source : objectKeys(source);
|
|
2150
|
+
const invalidKey = objectKeys(target).find((key) => !sourceKeys.includes(key));
|
|
2086
2151
|
if (invalidKey)
|
|
2087
2152
|
throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
|
|
2088
2153
|
}
|
|
@@ -2095,6 +2160,12 @@ function isRecord(obj) {
|
|
|
2095
2160
|
return isObject(obj);
|
|
2096
2161
|
}
|
|
2097
2162
|
__name(isRecord, "isRecord");
|
|
2163
|
+
function objectKeys(obj) {
|
|
2164
|
+
if (!isObject(obj))
|
|
2165
|
+
return [];
|
|
2166
|
+
return Object.keys(obj);
|
|
2167
|
+
}
|
|
2168
|
+
__name(objectKeys, "objectKeys");
|
|
2098
2169
|
|
|
2099
2170
|
// src/plugin/DirectLink.ts
|
|
2100
2171
|
var import_undici = require("undici");
|
|
@@ -2111,10 +2182,14 @@ var DirectLinkPlugin = class extends ExtractorPlugin {
|
|
|
2111
2182
|
}
|
|
2112
2183
|
async resolve(url, options = {}) {
|
|
2113
2184
|
url = url.replace(/\/+$/, "");
|
|
2114
|
-
return new Song(
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2185
|
+
return new Song(
|
|
2186
|
+
{
|
|
2187
|
+
name: url.substring(url.lastIndexOf("/") + 1).replace(/((\?|#).*)?$/, "") || url,
|
|
2188
|
+
url,
|
|
2189
|
+
src: "direct_link"
|
|
2190
|
+
},
|
|
2191
|
+
options
|
|
2192
|
+
);
|
|
2118
2193
|
}
|
|
2119
2194
|
};
|
|
2120
2195
|
__name(DirectLinkPlugin, "DirectLinkPlugin");
|
|
@@ -2228,7 +2303,9 @@ ${e.message}`;
|
|
|
2228
2303
|
throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
|
|
2229
2304
|
if (!songs.length)
|
|
2230
2305
|
throw new DisTubeError("EMPTY_ARRAY", "songs");
|
|
2231
|
-
const filteredSongs = songs.filter(
|
|
2306
|
+
const filteredSongs = songs.filter(
|
|
2307
|
+
(song) => song instanceof Song || isURL(song) || typeof song !== "string" && song.type === "video" /* VIDEO */
|
|
2308
|
+
);
|
|
2232
2309
|
if (!filteredSongs.length)
|
|
2233
2310
|
throw new DisTubeError("NO_VALID_SONG");
|
|
2234
2311
|
if (member && !isMemberInstance(member)) {
|
|
@@ -2238,7 +2315,9 @@ ${e.message}`;
|
|
|
2238
2315
|
throw new DisTubeError("NO_VALID_SONG");
|
|
2239
2316
|
let resolvedSongs;
|
|
2240
2317
|
if (parallel) {
|
|
2241
|
-
const promises = filteredSongs.map(
|
|
2318
|
+
const promises = filteredSongs.map(
|
|
2319
|
+
(song) => this.handler.resolve(song, { member, metadata }).catch(() => void 0)
|
|
2320
|
+
);
|
|
2242
2321
|
resolvedSongs = (await Promise.all(promises)).filter((s) => !!s);
|
|
2243
2322
|
} else {
|
|
2244
2323
|
const resolved = [];
|
|
@@ -2360,7 +2439,9 @@ ${e.message}`;
|
|
|
2360
2439
|
} else {
|
|
2361
2440
|
console.error(error);
|
|
2362
2441
|
console.warn("Unhandled 'error' event.");
|
|
2363
|
-
console.warn(
|
|
2442
|
+
console.warn(
|
|
2443
|
+
"See: https://distube.js.org/#/docs/DisTube/stable/class/DisTube?scrollTo=e-error and https://nodejs.org/api/events.html#events_error_events"
|
|
2444
|
+
);
|
|
2364
2445
|
}
|
|
2365
2446
|
}
|
|
2366
2447
|
};
|
|
@@ -2377,6 +2458,7 @@ __name(DisTube, "DisTube");
|
|
|
2377
2458
|
DisTubeStream,
|
|
2378
2459
|
DisTubeVoice,
|
|
2379
2460
|
DisTubeVoiceManager,
|
|
2461
|
+
Events,
|
|
2380
2462
|
ExtractorPlugin,
|
|
2381
2463
|
FilterManager,
|
|
2382
2464
|
GuildIdManager,
|
|
@@ -2410,6 +2492,7 @@ __name(DisTube, "DisTube");
|
|
|
2410
2492
|
isTextChannelInstance,
|
|
2411
2493
|
isURL,
|
|
2412
2494
|
isVoiceChannelEmpty,
|
|
2495
|
+
objectKeys,
|
|
2413
2496
|
parseNumber,
|
|
2414
2497
|
resolveGuildId,
|
|
2415
2498
|
toSecond,
|