magmastream 2.5.8 → 2.5.10
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/index.d.ts +32 -2
- package/dist/structures/Manager.js +5 -0
- package/dist/structures/Node.js +54 -1
- package/dist/structures/Player.js +84 -0
- package/dist/structures/Utils.js +3 -1
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -265,6 +265,11 @@ declare class Player {
|
|
|
265
265
|
* @param botUser
|
|
266
266
|
*/
|
|
267
267
|
setAutoplay(autoplayState: boolean, botUser: object): this;
|
|
268
|
+
/**
|
|
269
|
+
* Gets recommended tracks and returns an array of tracks.
|
|
270
|
+
* @param track
|
|
271
|
+
*/
|
|
272
|
+
getRecommended(track: Track): Promise<any[]>;
|
|
268
273
|
/**
|
|
269
274
|
* Sets the player volume.
|
|
270
275
|
* @param volume
|
|
@@ -483,6 +488,8 @@ declare class Node {
|
|
|
483
488
|
protected handleEvent(payload: PlayerEvent & PlayerEvents): Promise<void>;
|
|
484
489
|
protected trackStart(player: Player, track: Track, payload: TrackStartEvent): void;
|
|
485
490
|
protected trackEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>;
|
|
491
|
+
extractSpotifyTrackID(url: string): string | null;
|
|
492
|
+
extractSpotifyArtistID(url: string): string | null;
|
|
486
493
|
private handleAutoplay;
|
|
487
494
|
private handleFailedTrack;
|
|
488
495
|
private handleRepeatedTrack;
|
|
@@ -556,6 +563,29 @@ interface FrameStats {
|
|
|
556
563
|
/** The amount of deficit frames. */
|
|
557
564
|
deficit?: number;
|
|
558
565
|
}
|
|
566
|
+
interface LavalinkInfo {
|
|
567
|
+
version: {
|
|
568
|
+
semver: string;
|
|
569
|
+
major: number;
|
|
570
|
+
minor: number;
|
|
571
|
+
patch: number;
|
|
572
|
+
preRelease: string;
|
|
573
|
+
};
|
|
574
|
+
buildTime: number;
|
|
575
|
+
git: {
|
|
576
|
+
branch: string;
|
|
577
|
+
commit: string;
|
|
578
|
+
commitTime: number;
|
|
579
|
+
};
|
|
580
|
+
jvm: string;
|
|
581
|
+
lavaplayer: string;
|
|
582
|
+
sourceManagers: string[];
|
|
583
|
+
filters: string[];
|
|
584
|
+
plugins: {
|
|
585
|
+
name: string;
|
|
586
|
+
version: string;
|
|
587
|
+
}[];
|
|
588
|
+
}
|
|
559
589
|
|
|
560
590
|
declare abstract class TrackUtils {
|
|
561
591
|
static trackPartial: string[] | null;
|
|
@@ -846,7 +876,7 @@ interface ManagerOptions {
|
|
|
846
876
|
*/
|
|
847
877
|
send(id: string, payload: Payload): void;
|
|
848
878
|
}
|
|
849
|
-
type SearchPlatform = "deezer" | "soundcloud" | "youtube music" | "youtube";
|
|
879
|
+
type SearchPlatform = "deezer" | "soundcloud" | "youtube music" | "youtube" | "spotify" | "jiosaavn" | "tidal" | "applemusic" | "bandcamp";
|
|
850
880
|
interface SearchQuery {
|
|
851
881
|
/** The source to search from. */
|
|
852
882
|
source?: SearchPlatform | string;
|
|
@@ -907,4 +937,4 @@ interface ManagerEvents {
|
|
|
907
937
|
trackError: [player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent];
|
|
908
938
|
}
|
|
909
939
|
|
|
910
|
-
export { type CPUStats, type EqualizerBand, type Exception, type Extendable, type FrameStats, type LavalinkResponse, type LoadType, Manager, type ManagerEvents, type ManagerOptions, type MemoryStats, Node, type NodeMessage, type NodeOptions, type NodeStats, type Payload, type PlayOptions, Player, type PlayerEvent, type PlayerEventType, type PlayerEvents, type PlayerOptions, type PlayerUpdate, type PlaylistData, type PlaylistRawData, Plugin, Queue, type SearchPlatform, type SearchQuery, type SearchResult, type Severity, type Sizes, type State, Structure, type Track, type TrackData, type TrackDataInfo, type TrackEndEvent, type TrackEndReason, type TrackExceptionEvent, type TrackPluginInfo, type TrackSourceName, type TrackStartEvent, type TrackStuckEvent, TrackUtils, type UnresolvedQuery, type UnresolvedTrack, type VoicePacket, type VoiceServer, type VoiceState, type WebSocketClosedEvent };
|
|
940
|
+
export { type CPUStats, type EqualizerBand, type Exception, type Extendable, type FrameStats, type LavalinkInfo, type LavalinkResponse, type LoadType, Manager, type ManagerEvents, type ManagerOptions, type MemoryStats, Node, type NodeMessage, type NodeOptions, type NodeStats, type Payload, type PlayOptions, Player, type PlayerEvent, type PlayerEventType, type PlayerEvents, type PlayerOptions, type PlayerUpdate, type PlaylistData, type PlaylistRawData, Plugin, Queue, type SearchPlatform, type SearchQuery, type SearchResult, type Severity, type Sizes, type State, Structure, type Track, type TrackData, type TrackDataInfo, type TrackEndEvent, type TrackEndReason, type TrackExceptionEvent, type TrackPluginInfo, type TrackSourceName, type TrackStartEvent, type TrackStuckEvent, TrackUtils, type UnresolvedQuery, type UnresolvedTrack, type VoicePacket, type VoiceServer, type VoiceState, type WebSocketClosedEvent };
|
|
@@ -17,8 +17,13 @@ class Manager extends events_1.EventEmitter {
|
|
|
17
17
|
static DEFAULT_SOURCES = {
|
|
18
18
|
"youtube music": "ytmsearch",
|
|
19
19
|
youtube: "ytsearch",
|
|
20
|
+
spotify: "spsearch",
|
|
21
|
+
jiosaavn: "jssearch",
|
|
20
22
|
soundcloud: "scsearch",
|
|
21
23
|
deezer: "dzsearch",
|
|
24
|
+
tidal: "tdsearch",
|
|
25
|
+
applemusic: "amsearch",
|
|
26
|
+
bandcamp: "bcsearch",
|
|
22
27
|
};
|
|
23
28
|
/** The map of players. */
|
|
24
29
|
players = new collection_1.Collection();
|
package/dist/structures/Node.js
CHANGED
|
@@ -247,15 +247,59 @@ class Node {
|
|
|
247
247
|
await this.queueEnd(player, track, payload);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
+
extractSpotifyTrackID(url) {
|
|
251
|
+
const regex = /https:\/\/open\.spotify\.com\/track\/([a-zA-Z0-9]+)/;
|
|
252
|
+
const match = url.match(regex);
|
|
253
|
+
return match ? match[1] : null;
|
|
254
|
+
}
|
|
255
|
+
extractSpotifyArtistID(url) {
|
|
256
|
+
const regex = /https:\/\/open\.spotify\.com\/artist\/([a-zA-Z0-9]+)/;
|
|
257
|
+
const match = url.match(regex);
|
|
258
|
+
return match ? match[1] : null;
|
|
259
|
+
}
|
|
250
260
|
// Handle autoplay
|
|
251
261
|
async handleAutoplay(player, track) {
|
|
252
262
|
const previousTrack = player.queue.previous;
|
|
253
263
|
if (!player.isAutoplay || !previousTrack)
|
|
254
264
|
return;
|
|
265
|
+
const hasSpotifyURL = ["spotify.com", "open.spotify.com"].some((url) => previousTrack.uri.includes(url));
|
|
266
|
+
if (hasSpotifyURL) {
|
|
267
|
+
const node = this.manager.useableNodes;
|
|
268
|
+
const res = await node.rest.get(`/v4/info`);
|
|
269
|
+
const info = res;
|
|
270
|
+
const isSpotifyPluginEnabled = info.plugins.some((plugin) => plugin.name === "lavasrc-plugin");
|
|
271
|
+
const isSpotifySourceManagerEnabled = info.sourceManagers.includes("spotify");
|
|
272
|
+
if (isSpotifyPluginEnabled && isSpotifySourceManagerEnabled) {
|
|
273
|
+
const trackID = this.extractSpotifyTrackID(previousTrack.uri);
|
|
274
|
+
const artistID = this.extractSpotifyArtistID(previousTrack.pluginInfo.artistUrl);
|
|
275
|
+
let identifier = "";
|
|
276
|
+
if (trackID && artistID) {
|
|
277
|
+
identifier = `sprec:seed_artists=${artistID}&seed_tracks=${trackID}`;
|
|
278
|
+
}
|
|
279
|
+
else if (trackID) {
|
|
280
|
+
identifier = `sprec:seed_tracks=${trackID}`;
|
|
281
|
+
}
|
|
282
|
+
else if (artistID) {
|
|
283
|
+
identifier = `sprec:seed_artists=${artistID}`;
|
|
284
|
+
}
|
|
285
|
+
if (identifier) {
|
|
286
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
287
|
+
if (recommendedResult.loadType === "playlist") {
|
|
288
|
+
const playlistData = recommendedResult.data;
|
|
289
|
+
const recommendedTrack = playlistData.tracks[0];
|
|
290
|
+
if (recommendedTrack) {
|
|
291
|
+
player.queue.add(Utils_1.TrackUtils.build(recommendedTrack, player.get("Internal_BotUser")));
|
|
292
|
+
player.play();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
255
299
|
const hasYouTubeURL = ["youtube.com", "youtu.be"].some((url) => previousTrack.uri.includes(url));
|
|
256
300
|
let videoID = previousTrack.uri.substring(previousTrack.uri.indexOf("=") + 1);
|
|
257
301
|
if (!hasYouTubeURL) {
|
|
258
|
-
const res = await player.search(`${previousTrack.author} - ${previousTrack.title}
|
|
302
|
+
const res = await player.search(`${previousTrack.author} - ${previousTrack.title}`, player.get("Internal_BotUser"));
|
|
259
303
|
videoID = res.tracks[0].uri.substring(res.tracks[0].uri.indexOf("=") + 1);
|
|
260
304
|
}
|
|
261
305
|
let randomIndex;
|
|
@@ -273,6 +317,15 @@ class Node {
|
|
|
273
317
|
}
|
|
274
318
|
const foundTrack = tracks.sort(() => Math.random() - 0.5).find((shuffledTrack) => shuffledTrack.uri !== track.uri);
|
|
275
319
|
if (foundTrack) {
|
|
320
|
+
if (this.manager.options.replaceYouTubeCredentials) {
|
|
321
|
+
foundTrack.author = foundTrack.author.replace("- Topic", "");
|
|
322
|
+
foundTrack.title = foundTrack.title.replace("Topic -", "");
|
|
323
|
+
if (foundTrack.title.includes("-")) {
|
|
324
|
+
const [author, title] = foundTrack.title.split("-").map((str) => str.trim());
|
|
325
|
+
foundTrack.author = author;
|
|
326
|
+
foundTrack.title = title;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
276
329
|
player.queue.add(foundTrack);
|
|
277
330
|
player.play();
|
|
278
331
|
}
|
|
@@ -231,6 +231,90 @@ class Player {
|
|
|
231
231
|
this.set("Internal_BotUser", botUser);
|
|
232
232
|
return this;
|
|
233
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Gets recommended tracks and returns an array of tracks.
|
|
236
|
+
* @param track
|
|
237
|
+
*/
|
|
238
|
+
async getRecommended(track) {
|
|
239
|
+
const node = this.manager.useableNodes;
|
|
240
|
+
if (!node) {
|
|
241
|
+
throw new Error("No available nodes.");
|
|
242
|
+
}
|
|
243
|
+
const hasSpotifyURL = ["spotify.com", "open.spotify.com"].some((url) => track.uri.includes(url));
|
|
244
|
+
const hasYouTubeURL = ["youtube.com", "youtu.be"].some((url) => track.uri.includes(url));
|
|
245
|
+
if (hasSpotifyURL) {
|
|
246
|
+
const res = await node.rest.get(`/v4/info`);
|
|
247
|
+
const info = res;
|
|
248
|
+
const isSpotifyPluginEnabled = info.plugins.some((plugin) => plugin.name === "lavasrc-plugin");
|
|
249
|
+
const isSpotifySourceManagerEnabled = info.sourceManagers.includes("spotify");
|
|
250
|
+
if (isSpotifyPluginEnabled && isSpotifySourceManagerEnabled) {
|
|
251
|
+
const trackID = node.extractSpotifyTrackID(track.uri);
|
|
252
|
+
const artistID = node.extractSpotifyArtistID(track.pluginInfo.artistUrl);
|
|
253
|
+
let identifier = "";
|
|
254
|
+
if (trackID && artistID) {
|
|
255
|
+
identifier = `sprec:seed_artists=${artistID}&seed_tracks=${trackID}`;
|
|
256
|
+
}
|
|
257
|
+
else if (trackID) {
|
|
258
|
+
identifier = `sprec:seed_tracks=${trackID}`;
|
|
259
|
+
}
|
|
260
|
+
else if (artistID) {
|
|
261
|
+
identifier = `sprec:seed_artists=${artistID}`;
|
|
262
|
+
}
|
|
263
|
+
if (identifier) {
|
|
264
|
+
const recommendedResult = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(identifier)}`));
|
|
265
|
+
if (recommendedResult.loadType === "playlist") {
|
|
266
|
+
const playlistData = recommendedResult.data;
|
|
267
|
+
const recommendedTracks = playlistData.tracks;
|
|
268
|
+
if (recommendedTracks) {
|
|
269
|
+
const spotifyArray = [];
|
|
270
|
+
recommendedTracks.forEach((song) => {
|
|
271
|
+
const track = {
|
|
272
|
+
track: song.encoded,
|
|
273
|
+
title: song.info.title,
|
|
274
|
+
identifier: song.info.title,
|
|
275
|
+
author: song.info.author,
|
|
276
|
+
duration: song.info.length,
|
|
277
|
+
uri: song.info.uri,
|
|
278
|
+
artworkUrl: song.info.artworkUrl,
|
|
279
|
+
sourceName: song.info.sourceName,
|
|
280
|
+
requester: undefined,
|
|
281
|
+
plugininfo: song.pluginInfo,
|
|
282
|
+
};
|
|
283
|
+
spotifyArray.push(track);
|
|
284
|
+
});
|
|
285
|
+
return spotifyArray;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
let videoID = track.uri.substring(track.uri.indexOf("=") + 1);
|
|
292
|
+
if (!hasYouTubeURL) {
|
|
293
|
+
const res = await this.manager.search(`${track.author} - ${track.title}`);
|
|
294
|
+
videoID = res.tracks[0].uri.substring(res.tracks[0].uri.indexOf("=") + 1);
|
|
295
|
+
}
|
|
296
|
+
const searchURI = `https://www.youtube.com/watch?v=${videoID}&list=RD${videoID}`;
|
|
297
|
+
const res = await this.manager.search(searchURI);
|
|
298
|
+
if (res.loadType === "empty" || res.loadType === "error")
|
|
299
|
+
return;
|
|
300
|
+
let tracks = res.tracks;
|
|
301
|
+
if (res.loadType === "playlist") {
|
|
302
|
+
tracks = res.playlist.tracks;
|
|
303
|
+
}
|
|
304
|
+
const filteredTracks = tracks.filter((track) => track.uri !== `https://www.youtube.com/watch?v=${videoID}`);
|
|
305
|
+
if (this.manager.options.replaceYouTubeCredentials) {
|
|
306
|
+
for (const track of filteredTracks) {
|
|
307
|
+
track.author = track.author.replace("- Topic", "");
|
|
308
|
+
track.title = track.title.replace("Topic -", "");
|
|
309
|
+
if (track.title.includes("-")) {
|
|
310
|
+
const [author, title] = track.title.split("-").map((str) => str.trim());
|
|
311
|
+
track.author = author;
|
|
312
|
+
track.title = title;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return filteredTracks;
|
|
317
|
+
}
|
|
234
318
|
/**
|
|
235
319
|
* Sets the player volume.
|
|
236
320
|
* @param volume
|
package/dist/structures/Utils.js
CHANGED
|
@@ -157,7 +157,9 @@ class TrackUtils {
|
|
|
157
157
|
if (sameDuration)
|
|
158
158
|
return sameDuration;
|
|
159
159
|
}
|
|
160
|
-
|
|
160
|
+
const finalTrack = res.tracks[0];
|
|
161
|
+
finalTrack.customData = unresolvedTrack.customData;
|
|
162
|
+
return finalTrack;
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
exports.TrackUtils = TrackUtils;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magmastream",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.10",
|
|
4
4
|
"description": "A user-friendly Lavalink client designed for NodeJS.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@favware/rollup-type-bundler": "^3.3.0",
|
|
18
|
-
"@types/lodash": "^4.17.
|
|
19
|
-
"@types/node": "^20.14.
|
|
20
|
-
"@types/ws": "^8.5.
|
|
21
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
22
|
-
"@typescript-eslint/parser": "^7.
|
|
18
|
+
"@types/lodash": "^4.17.7",
|
|
19
|
+
"@types/node": "^20.14.14",
|
|
20
|
+
"@types/ws": "^8.5.12",
|
|
21
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
22
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
23
23
|
"eslint": "^8.57.0",
|
|
24
24
|
"npm-run-all": "^4.1.5",
|
|
25
25
|
"typedoc": "^0.25.13",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@discordjs/collection": "^2.1.0",
|
|
31
|
-
"axios": "^1.7.
|
|
31
|
+
"axios": "^1.7.3",
|
|
32
32
|
"events": "^3.3.0",
|
|
33
33
|
"lodash": "^4.17.21",
|
|
34
34
|
"tslib": "^2.6.3",
|