magmastream 2.10.3-dev.2 → 2.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/structures/Enums.d.ts +145 -1
- package/dist/structures/Enums.js +148 -1
- package/dist/structures/Filters.d.ts +120 -1
- package/dist/structures/Filters.js +348 -11
- package/dist/structures/Manager.d.ts +9 -0
- package/dist/structures/Manager.js +169 -30
- package/dist/structures/Node.d.ts +89 -2
- package/dist/structures/Node.js +504 -53
- package/dist/structures/Player.d.ts +85 -2
- package/dist/structures/Player.js +300 -12
- package/dist/structures/Rest.d.ts +61 -2
- package/dist/structures/Rest.js +210 -1
- package/dist/structures/Types.d.ts +645 -90
- package/dist/structures/Utils.d.ts +1 -1
- package/dist/structures/Utils.js +60 -18
- package/dist/utils/managerCheck.js +3 -2
- package/package.json +1 -1
|
@@ -83,7 +83,7 @@ export declare abstract class AutoPlayUtils {
|
|
|
83
83
|
* @param platform The source to get recommended tracks from.
|
|
84
84
|
* @returns An array of recommended tracks.
|
|
85
85
|
*/
|
|
86
|
-
static getRecommendedTracksFromSource(track: Track, platform: AutoPlayPlatform): Promise<Track[]>;
|
|
86
|
+
static getRecommendedTracksFromSource(track: Track, platform: AutoPlayPlatform, node?: import("./Node").Node): Promise<Track[]>;
|
|
87
87
|
/**
|
|
88
88
|
* Searches for a track using the manager and returns resolved tracks.
|
|
89
89
|
* @param query The search query (artist - title).
|
package/dist/structures/Utils.js
CHANGED
|
@@ -63,7 +63,7 @@ class TrackUtils {
|
|
|
63
63
|
if (typeof track !== "object" || track === null)
|
|
64
64
|
return false;
|
|
65
65
|
const trackRecord = track;
|
|
66
|
-
return REQUIRED_TRACK_KEYS.every((key) => typeof trackRecord[key] === "string");
|
|
66
|
+
return REQUIRED_TRACK_KEYS.every((key) => (key === "uri" ? typeof trackRecord[key] === "string" || trackRecord[key] === null : typeof trackRecord[key] === "string"));
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Checks if the provided argument is a valid Track array.
|
|
@@ -97,17 +97,32 @@ class TrackUtils {
|
|
|
97
97
|
}
|
|
98
98
|
try {
|
|
99
99
|
const sourceNameMap = {
|
|
100
|
+
amazonmusic: "AmazonMusic",
|
|
101
|
+
anghami: "Anghami",
|
|
100
102
|
applemusic: "AppleMusic",
|
|
103
|
+
audiomack: "Audiomack",
|
|
101
104
|
audius: "Audius",
|
|
102
105
|
bandcamp: "Bandcamp",
|
|
106
|
+
bilibili: "Bilibili",
|
|
103
107
|
deezer: "Deezer",
|
|
108
|
+
eternalbox: "EternalBox",
|
|
109
|
+
flowery: "Flowery",
|
|
110
|
+
gaana: "Gaana",
|
|
111
|
+
googledrive: "GoogleDrive",
|
|
112
|
+
googletts: "GoogleTTS",
|
|
113
|
+
iheartradio: "IHeartRadio",
|
|
104
114
|
jiosaavn: "Jiosaavn",
|
|
115
|
+
lastfm: "LastFM",
|
|
116
|
+
netease: "Netease",
|
|
105
117
|
soundcloud: "SoundCloud",
|
|
106
118
|
spotify: "Spotify",
|
|
107
119
|
tidal: "Tidal",
|
|
108
120
|
youtube: "YouTube",
|
|
109
121
|
vkmusic: "VKMusic",
|
|
122
|
+
nicovideo: "NicoVideo",
|
|
123
|
+
pandora: "Pandora",
|
|
110
124
|
qobuz: "Qobuz",
|
|
125
|
+
shazam: "Shazam",
|
|
111
126
|
http: "Http",
|
|
112
127
|
tts: "Tts",
|
|
113
128
|
clypit: "Clypit",
|
|
@@ -131,14 +146,14 @@ class TrackUtils {
|
|
|
131
146
|
uri: data.info.uri,
|
|
132
147
|
artworkUrl: data.info?.artworkUrl ?? null,
|
|
133
148
|
sourceName: sourceNameMap[data.info?.sourceName?.toLowerCase() ?? ""] ?? data.info?.sourceName,
|
|
134
|
-
thumbnail: data.info.uri
|
|
149
|
+
thumbnail: data.info.uri?.includes("youtube") ? `https://img.youtube.com/vi/${data.info.identifier}/default.jpg` : null,
|
|
135
150
|
displayThumbnail(size = "default") {
|
|
136
151
|
const finalSize = SIZES.find((s) => s === size) ?? "default";
|
|
137
|
-
return this.uri
|
|
152
|
+
return this.uri?.includes("youtube") ? `https://img.youtube.com/vi/${data.info.identifier}/${finalSize}.jpg` : null;
|
|
138
153
|
},
|
|
139
154
|
requester: requester,
|
|
140
155
|
pluginInfo: data.pluginInfo,
|
|
141
|
-
customData: {},
|
|
156
|
+
customData: data.userData ?? {},
|
|
142
157
|
isAutoplay: isAutoplay,
|
|
143
158
|
};
|
|
144
159
|
track.displayThumbnail = track.displayThumbnail.bind(track);
|
|
@@ -180,7 +195,7 @@ class TrackUtils {
|
|
|
180
195
|
return track;
|
|
181
196
|
track.displayThumbnail = function (size = "default") {
|
|
182
197
|
const finalSize = SIZES.find((s) => s === size) ?? "default";
|
|
183
|
-
return this.uri
|
|
198
|
+
return this.uri?.includes("youtube") ? `https://img.youtube.com/vi/${this.identifier}/${finalSize}.jpg` : null;
|
|
184
199
|
}.bind(track);
|
|
185
200
|
return track;
|
|
186
201
|
}
|
|
@@ -228,7 +243,14 @@ class AutoPlayUtils {
|
|
|
228
243
|
// Iterate over autoplay platforms in order of priority
|
|
229
244
|
for (const platform of autoPlaySearchPlatforms) {
|
|
230
245
|
if (enabledSources.includes(platform)) {
|
|
231
|
-
|
|
246
|
+
let recommendedTracks;
|
|
247
|
+
try {
|
|
248
|
+
recommendedTracks = await this.getRecommendedTracksFromSource(track, platform, node);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[AUTOPLAY] Failed to fetch recommendations from ${platform}: ${error instanceof Error ? error.message : String(error)}`);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
232
254
|
// If tracks are found, return them immediately
|
|
233
255
|
if (recommendedTracks.length > 0) {
|
|
234
256
|
return recommendedTracks;
|
|
@@ -316,8 +338,12 @@ class AutoPlayUtils {
|
|
|
316
338
|
* @param platform The source to get recommended tracks from.
|
|
317
339
|
* @returns An array of recommended tracks.
|
|
318
340
|
*/
|
|
319
|
-
static async getRecommendedTracksFromSource(track, platform) {
|
|
341
|
+
static async getRecommendedTracksFromSource(track, platform, node = this.manager.useableNode) {
|
|
320
342
|
const requester = track.requester;
|
|
343
|
+
if (!track.uri)
|
|
344
|
+
return [];
|
|
345
|
+
if (!node)
|
|
346
|
+
return [];
|
|
321
347
|
const parsedURL = new URL(track.uri);
|
|
322
348
|
switch (platform) {
|
|
323
349
|
case Enums_1.AutoPlayPlatform.Spotify: {
|
|
@@ -334,8 +360,8 @@ class AutoPlayUtils {
|
|
|
334
360
|
// return match ? match[1] : null;
|
|
335
361
|
// };
|
|
336
362
|
// const identifier = `sprec:seed_artists=${extractSpotifyArtistID(track.pluginInfo.artistUrl)}&seed_tracks=${track.identifier}`;
|
|
337
|
-
const identifier = `sprec:mix:track:${track.identifier}`;
|
|
338
|
-
const recommendedResult = (await
|
|
363
|
+
const identifier = node.isNodeLink ? `sprec:seed_tracks=${track.identifier}` : `sprec:mix:track:${track.identifier}`;
|
|
364
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
339
365
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
340
366
|
return tracks;
|
|
341
367
|
}
|
|
@@ -348,7 +374,7 @@ class AutoPlayUtils {
|
|
|
348
374
|
track = resolvedTrack;
|
|
349
375
|
}
|
|
350
376
|
const identifier = `dzrec:${track.identifier}`;
|
|
351
|
-
const recommendedResult = (await
|
|
377
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
352
378
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
353
379
|
return tracks;
|
|
354
380
|
}
|
|
@@ -412,14 +438,14 @@ class AutoPlayUtils {
|
|
|
412
438
|
}
|
|
413
439
|
case Enums_1.AutoPlayPlatform.YouTube: {
|
|
414
440
|
const allowedYouTubeHosts = ["youtube.com", "youtu.be"];
|
|
415
|
-
const hasYouTubeURL = allowedYouTubeHosts.some((url) => track.uri
|
|
441
|
+
const hasYouTubeURL = allowedYouTubeHosts.some((url) => track.uri?.includes(url));
|
|
416
442
|
let videoID = null;
|
|
417
443
|
if (hasYouTubeURL) {
|
|
418
|
-
videoID = track.uri
|
|
444
|
+
videoID = track.uri?.split("=").pop() ?? null;
|
|
419
445
|
}
|
|
420
446
|
else {
|
|
421
447
|
const resolvedTrack = await this.resolveFirstTrackFromQuery(`${track.author} - ${track.title}`, Enums_1.SearchPlatform.YouTube, requester);
|
|
422
|
-
if (!resolvedTrack)
|
|
448
|
+
if (!resolvedTrack?.uri)
|
|
423
449
|
return [];
|
|
424
450
|
videoID = resolvedTrack.uri.split("=").pop();
|
|
425
451
|
}
|
|
@@ -431,7 +457,7 @@ class AutoPlayUtils {
|
|
|
431
457
|
do {
|
|
432
458
|
randomIndex = Math.floor(Math.random() * 23) + 2;
|
|
433
459
|
searchURI = `https://www.youtube.com/watch?v=${videoID}&list=RD${videoID}&index=${randomIndex}`;
|
|
434
|
-
} while (track.uri
|
|
460
|
+
} while (track.uri?.includes(searchURI));
|
|
435
461
|
const resolvedTracks = await this.resolveTracksFromQuery(searchURI, Enums_1.SearchPlatform.YouTube, requester);
|
|
436
462
|
const filteredTracks = resolvedTracks.filter((resolvedTrack) => resolvedTrack.uri !== track.uri);
|
|
437
463
|
return filteredTracks;
|
|
@@ -445,7 +471,7 @@ class AutoPlayUtils {
|
|
|
445
471
|
track = resolvedTrack;
|
|
446
472
|
}
|
|
447
473
|
const identifier = `tdrec:${track.identifier}`;
|
|
448
|
-
const recommendedResult = (await
|
|
474
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
449
475
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
450
476
|
return tracks;
|
|
451
477
|
}
|
|
@@ -458,7 +484,7 @@ class AutoPlayUtils {
|
|
|
458
484
|
track = resolvedTrack;
|
|
459
485
|
}
|
|
460
486
|
const identifier = `vkrec:${track.identifier}`;
|
|
461
|
-
const recommendedResult = (await
|
|
487
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
462
488
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
463
489
|
return tracks;
|
|
464
490
|
}
|
|
@@ -471,7 +497,7 @@ class AutoPlayUtils {
|
|
|
471
497
|
track = resolvedTrack;
|
|
472
498
|
}
|
|
473
499
|
const identifier = `qbrec:${track.identifier}`;
|
|
474
|
-
const recommendedResult = (await
|
|
500
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
475
501
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
476
502
|
return tracks;
|
|
477
503
|
}
|
|
@@ -484,7 +510,7 @@ class AutoPlayUtils {
|
|
|
484
510
|
track = resolvedTrack;
|
|
485
511
|
}
|
|
486
512
|
const identifier = `ymrec:${track.identifier}`;
|
|
487
|
-
const recommendedResult = (await
|
|
513
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
488
514
|
const tracks = this.buildTracksFromResponse(recommendedResult, requester);
|
|
489
515
|
return tracks;
|
|
490
516
|
}
|
|
@@ -513,6 +539,7 @@ class AutoPlayUtils {
|
|
|
513
539
|
case Enums_1.LoadTypes.Playlist:
|
|
514
540
|
return searchResult.playlist.tracks;
|
|
515
541
|
case Enums_1.LoadTypes.Track:
|
|
542
|
+
case Enums_1.LoadTypes.Episode:
|
|
516
543
|
case Enums_1.LoadTypes.Search:
|
|
517
544
|
case Enums_1.LoadTypes.Short:
|
|
518
545
|
return searchResult.tracks;
|
|
@@ -548,6 +575,7 @@ class AutoPlayUtils {
|
|
|
548
575
|
case Enums_1.LoadTypes.Playlist:
|
|
549
576
|
return searchResult.playlist.tracks[0] || null;
|
|
550
577
|
case Enums_1.LoadTypes.Track:
|
|
578
|
+
case Enums_1.LoadTypes.Episode:
|
|
551
579
|
case Enums_1.LoadTypes.Search:
|
|
552
580
|
case Enums_1.LoadTypes.Short:
|
|
553
581
|
return searchResult.tracks[0] || null;
|
|
@@ -575,6 +603,7 @@ class AutoPlayUtils {
|
|
|
575
603
|
if (TrackUtils.isErrorOrEmptySearchResult(recommendedResult))
|
|
576
604
|
return [];
|
|
577
605
|
switch (recommendedResult.loadType) {
|
|
606
|
+
case Enums_1.LoadTypes.Episode:
|
|
578
607
|
case Enums_1.LoadTypes.Track: {
|
|
579
608
|
const data = recommendedResult.data;
|
|
580
609
|
if (!this.isTrackData(data)) {
|
|
@@ -739,7 +768,20 @@ class PlayerUtils {
|
|
|
739
768
|
karaoke: player.filters.karaoke ?? null,
|
|
740
769
|
rotation: player.filters.rotation ?? null,
|
|
741
770
|
timescale: player.filters.timescale ?? null,
|
|
771
|
+
tremolo: player.filters.tremoloOptions ?? null,
|
|
742
772
|
vibrato: player.filters.vibrato ?? null,
|
|
773
|
+
channelMix: player.filters.channelMix ?? null,
|
|
774
|
+
lowPass: player.filters.lowPass ?? null,
|
|
775
|
+
highpass: player.filters.highpass ?? null,
|
|
776
|
+
echo: player.filters.echo ?? null,
|
|
777
|
+
chorus: player.filters.chorus ?? null,
|
|
778
|
+
compressor: player.filters.compressor ?? null,
|
|
779
|
+
flanger: player.filters.flanger ?? null,
|
|
780
|
+
phaser: player.filters.phaser ?? null,
|
|
781
|
+
phonograph: player.filters.phonograph ?? null,
|
|
782
|
+
spatial: player.filters.spatial ?? null,
|
|
783
|
+
tape: player.filters.tape ?? null,
|
|
784
|
+
pluginFilters: player.filters.pluginFilters ?? {},
|
|
743
785
|
reverb: player.filters.reverb ?? null,
|
|
744
786
|
volume: player.filters.volume ?? 1.0,
|
|
745
787
|
bassBoostlevel: player.filters.bassBoostlevel ?? null,
|
|
@@ -37,10 +37,11 @@ function managerCheck(options, isWrapper = false) {
|
|
|
37
37
|
}
|
|
38
38
|
// Validate defaultSearchPlatform option
|
|
39
39
|
if (typeof defaultSearchPlatform !== "undefined") {
|
|
40
|
-
|
|
40
|
+
const validSearchPlatforms = [...Object.values(Enums_1.SearchPlatform), ...Object.values(Enums_1.NodeLinkSearchPlatform), ...Object.values(Enums_1.NodeLinkRecommendationPlatform)];
|
|
41
|
+
if (!validSearchPlatforms.includes(defaultSearchPlatform)) {
|
|
41
42
|
throw new MagmastreamError_1.MagmaStreamError({
|
|
42
43
|
code: Enums_1.MagmaStreamErrorCode.MANAGER_INVALID_CONFIG,
|
|
43
|
-
message: `Manager option "defaultSearchPlatform" must be one of: ${
|
|
44
|
+
message: `Manager option "defaultSearchPlatform" must be one of: ${validSearchPlatforms.join(", ")}.`,
|
|
44
45
|
context: { option: "defaultSearchPlatform", value: defaultSearchPlatform },
|
|
45
46
|
});
|
|
46
47
|
}
|