magmastream 2.9.0-dev.0 → 2.9.0-dev.2

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 CHANGED
@@ -200,7 +200,7 @@ declare class Node {
200
200
  * @remarks
201
201
  * If the node is already connected, this method will do nothing.
202
202
  * If the node has a session ID, it will be sent in the headers of the WebSocket connection.
203
- * If the node has no session ID but the `resumeStatus` option is true, it will use the session ID
203
+ * If the node has no session ID but the `enableSessionResumeOption` option is true, it will use the session ID
204
204
  * stored in the sessionIds.json file if it exists.
205
205
  */
206
206
  connect(): void;
@@ -477,21 +477,21 @@ interface NodeOptions {
477
477
  /** The password for the node. */
478
478
  password?: string;
479
479
  /** Whether the host uses SSL. */
480
- secure?: boolean;
480
+ useSSL?: boolean;
481
481
  /** The identifier for the node. */
482
482
  identifier?: string;
483
- /** The retryAmount for the node. */
484
- retryAmount?: number;
485
- /** The retryDelay for the node. */
486
- retryDelay?: number;
483
+ /** The maxRetryAttempts for the node. */
484
+ maxRetryAttempts?: number;
485
+ /** The retryDelayMs for the node. */
486
+ retryDelayMs?: number;
487
487
  /** Whether to resume the previous session. */
488
- resumeStatus?: boolean;
488
+ enableSessionResumeOption?: boolean;
489
489
  /** The time the lavalink server will wait before it removes the player. */
490
- resumeTimeout?: number;
490
+ sessionTimeoutMs?: number;
491
491
  /** The timeout used for api calls. */
492
- requestTimeout?: number;
492
+ apiRequestTimeoutMs?: number;
493
493
  /** Priority of the node. */
494
- priority?: number;
494
+ nodePriority?: number;
495
495
  }
496
496
  interface NodeStats {
497
497
  /** The amount of players on the node. */
@@ -898,11 +898,11 @@ declare class Manager extends EventEmitter {
898
898
  /**
899
899
  * Initiates the Manager class.
900
900
  * @param options
901
- * @param options.plugins - An array of plugins to load.
901
+ * @param options.enabledPlugins - An array of enabledPlugins to load.
902
902
  * @param options.nodes - An array of node options to create nodes from.
903
- * @param options.autoPlay - Whether to automatically play the first track in the queue when the player is created.
903
+ * @param options.playNextOnEnd - Whether to automatically play the first track in the queue when the player is created.
904
904
  * @param options.autoPlaySearchPlatform - The search platform autoplay will use. Fallback to Youtube if not found.
905
- * @param options.usePriority - Whether to use the priority when selecting a node to play on.
905
+ * @param options.enablePriorityMode - Whether to use the priority when selecting a node to play on.
906
906
  * @param options.clientName - The name of the client to send to Lavalink.
907
907
  * @param options.defaultSearchPlatform - The default search platform to use when searching for tracks.
908
908
  * @param options.useNode - The strategy to use when selecting a node to play on.
@@ -997,10 +997,10 @@ declare class Manager extends EventEmitter {
997
997
  */
998
998
  loadPlayerStates(nodeId: string): Promise<void>;
999
999
  /**
1000
- * Returns the node to use based on the configured `useNode` and `usePriority` options.
1001
- * If `usePriority` is true, the node is chosen based on priority, otherwise it is chosen based on the `useNode` option.
1000
+ * Returns the node to use based on the configured `useNode` and `enablePriorityMode` options.
1001
+ * If `enablePriorityMode` is true, the node is chosen based on priority, otherwise it is chosen based on the `useNode` option.
1002
1002
  * If `useNode` is "leastLoad", the node with the lowest load is chosen, if it is "leastPlayers", the node with the fewest players is chosen.
1003
- * If `usePriority` is false and `useNode` is not set, the node with the lowest load is chosen.
1003
+ * If `enablePriorityMode` is false and `useNode` is not set, the node with the lowest load is chosen.
1004
1004
  * @returns {Node} The node to use.
1005
1005
  */
1006
1006
  get useableNode(): Node;
@@ -1114,9 +1114,11 @@ interface Payload {
1114
1114
  };
1115
1115
  }
1116
1116
  interface ManagerOptions {
1117
- /** Whether players should automatically play the next song. */
1118
- autoPlay?: boolean;
1119
- /** The search platform autoplay should use. Fallback to YouTube if not found.
1117
+ /** Enable priority mode over least player count or load balancing? */
1118
+ enablePriorityMode?: boolean;
1119
+ /** Automatically play the next track when the current one ends. */
1120
+ playNextOnEnd?: boolean;
1121
+ /** The search platform autoplay should use
1120
1122
  * Use enum `SearchPlatform`. */
1121
1123
  autoPlaySearchPlatform?: SearchPlatform;
1122
1124
  /** The client ID to use. */
@@ -1125,6 +1127,8 @@ interface ManagerOptions {
1125
1127
  clientName?: string;
1126
1128
  /** The array of shard IDs connected to this manager instance. */
1127
1129
  clusterId?: number;
1130
+ /** List of plugins to load. */
1131
+ enabledPlugins?: Plugin[];
1128
1132
  /** The default search platform to use.
1129
1133
  * Use enum `SearchPlatform`. */
1130
1134
  defaultSearchPlatform?: SearchPlatform;
@@ -1136,16 +1140,12 @@ interface ManagerOptions {
1136
1140
  maxPreviousTracks?: number;
1137
1141
  /** The array of nodes to connect to. */
1138
1142
  nodes?: NodeOptions[];
1139
- /** A array of plugins to use. */
1140
- plugins?: Plugin[];
1141
1143
  /** Whether the YouTube video titles should be replaced if the Author does not exactly match. */
1142
- replaceYouTubeCredentials?: boolean;
1144
+ normalizeYouTubeTitles?: boolean;
1143
1145
  /** An array of track properties to keep. `track` will always be present. */
1144
1146
  trackPartial?: TrackPartial[];
1145
1147
  /** Use the least amount of players or least load? */
1146
1148
  useNode?: UseNodeOptions.LeastLoad | UseNodeOptions.LeastPlayers;
1147
- /** Use priority mode over least amount of player or load? */
1148
- usePriority?: boolean;
1149
1149
  /**
1150
1150
  * Function to send data to the websocket.
1151
1151
  * @param id The ID of the node to send the data to.
@@ -24,11 +24,11 @@ class Manager extends events_1.EventEmitter {
24
24
  /**
25
25
  * Initiates the Manager class.
26
26
  * @param options
27
- * @param options.plugins - An array of plugins to load.
27
+ * @param options.enabledPlugins - An array of enabledPlugins to load.
28
28
  * @param options.nodes - An array of node options to create nodes from.
29
- * @param options.autoPlay - Whether to automatically play the first track in the queue when the player is created.
29
+ * @param options.playNextOnEnd - Whether to automatically play the first track in the queue when the player is created.
30
30
  * @param options.autoPlaySearchPlatform - The search platform autoplay will use. Fallback to Youtube if not found.
31
- * @param options.usePriority - Whether to use the priority when selecting a node to play on.
31
+ * @param options.enablePriorityMode - Whether to use the priority when selecting a node to play on.
32
32
  * @param options.clientName - The name of the client to send to Lavalink.
33
33
  * @param options.defaultSearchPlatform - The default search platform to use when searching for tracks.
34
34
  * @param options.useNode - The strategy to use when selecting a node to play on.
@@ -48,17 +48,17 @@ class Manager extends events_1.EventEmitter {
48
48
  delete options.trackPartial;
49
49
  }
50
50
  this.options = {
51
- plugins: [],
51
+ enabledPlugins: [],
52
52
  nodes: [
53
53
  {
54
54
  identifier: "default",
55
55
  host: "localhost",
56
- resumeStatus: false,
57
- resumeTimeout: 1000,
56
+ enableSessionResumeOption: false,
57
+ sessionTimeoutMs: 1000,
58
58
  },
59
59
  ],
60
- autoPlay: true,
61
- usePriority: false,
60
+ playNextOnEnd: true,
61
+ enablePriorityMode: false,
62
62
  clientName: "Magmastream",
63
63
  defaultSearchPlatform: SearchPlatform.YouTube,
64
64
  // autoPlaySearchPlatform: SearchPlatform.YouTube,
@@ -125,8 +125,8 @@ class Manager extends events_1.EventEmitter {
125
125
  this.emit(ManagerEventTypes.NodeError, node, err);
126
126
  }
127
127
  }
128
- if (this.options.plugins) {
129
- for (const [index, plugin] of this.options.plugins.entries()) {
128
+ if (this.options.enabledPlugins) {
129
+ for (const [index, plugin] of this.options.enabledPlugins.entries()) {
130
130
  if (!(plugin instanceof __1.Plugin))
131
131
  throw new RangeError(`Plugin at index ${index} does not extend Plugin.`);
132
132
  plugin.load(this);
@@ -175,7 +175,7 @@ class Manager extends events_1.EventEmitter {
175
175
  break;
176
176
  }
177
177
  }
178
- if (this.options.replaceYouTubeCredentials) {
178
+ if (this.options.normalizeYouTubeTitles) {
179
179
  const processTrack = (track) => {
180
180
  if (!/(youtube\.com|youtu\.be)/.test(track.uri))
181
181
  return track;
@@ -447,7 +447,6 @@ class Manager extends events_1.EventEmitter {
447
447
  }
448
448
  else {
449
449
  player.paused = false;
450
- player.playing = true;
451
450
  }
452
451
  if (state.trackRepeat)
453
452
  player.setTrackRepeat(true);
@@ -530,14 +529,14 @@ class Manager extends events_1.EventEmitter {
530
529
  this.emit(ManagerEventTypes.Debug, "[MANAGER] Finished loading saved players.");
531
530
  }
532
531
  /**
533
- * Returns the node to use based on the configured `useNode` and `usePriority` options.
534
- * If `usePriority` is true, the node is chosen based on priority, otherwise it is chosen based on the `useNode` option.
532
+ * Returns the node to use based on the configured `useNode` and `enablePriorityMode` options.
533
+ * If `enablePriorityMode` is true, the node is chosen based on priority, otherwise it is chosen based on the `useNode` option.
535
534
  * If `useNode` is "leastLoad", the node with the lowest load is chosen, if it is "leastPlayers", the node with the fewest players is chosen.
536
- * If `usePriority` is false and `useNode` is not set, the node with the lowest load is chosen.
535
+ * If `enablePriorityMode` is false and `useNode` is not set, the node with the lowest load is chosen.
537
536
  * @returns {Node} The node to use.
538
537
  */
539
538
  get useableNode() {
540
- return this.options.usePriority
539
+ return this.options.enablePriorityMode
541
540
  ? this.priorityNode
542
541
  : this.options.useNode === UseNodeOptions.LeastLoad
543
542
  ? this.leastLoadNode.first()
@@ -850,13 +849,13 @@ class Manager extends events_1.EventEmitter {
850
849
  */
851
850
  get priorityNode() {
852
851
  // Filter out nodes that are not connected or have a priority of 0
853
- const filteredNodes = this.nodes.filter((node) => node.connected && node.options.priority > 0);
852
+ const filteredNodes = this.nodes.filter((node) => node.connected && node.options.nodePriority > 0);
854
853
  // Calculate the total weight
855
- const totalWeight = filteredNodes.reduce((total, node) => total + node.options.priority, 0);
854
+ const totalWeight = filteredNodes.reduce((total, node) => total + node.options.nodePriority, 0);
856
855
  // Map the nodes to their weights
857
856
  const weightedNodes = filteredNodes.map((node) => ({
858
857
  node,
859
- weight: node.options.priority / totalWeight,
858
+ weight: node.options.nodePriority / totalWeight,
860
859
  }));
861
860
  // Generate a random number between 0 and 1
862
861
  const randomNumber = Math.random();
@@ -61,13 +61,13 @@ class Node {
61
61
  this.options = {
62
62
  port: 2333,
63
63
  password: "youshallnotpass",
64
- secure: false,
65
- retryAmount: 30,
66
- retryDelay: 60000,
67
- priority: 0,
64
+ useSSL: false,
65
+ maxRetryAttempts: 30,
66
+ retryDelayMs: 60000,
67
+ nodePriority: 0,
68
68
  ...options,
69
69
  };
70
- if (this.options.secure) {
70
+ if (this.options.useSSL) {
71
71
  this.options.port = 443;
72
72
  }
73
73
  this.options.identifier = options.identifier || options.host;
@@ -179,7 +179,7 @@ class Node {
179
179
  * @remarks
180
180
  * If the node is already connected, this method will do nothing.
181
181
  * If the node has a session ID, it will be sent in the headers of the WebSocket connection.
182
- * If the node has no session ID but the `resumeStatus` option is true, it will use the session ID
182
+ * If the node has no session ID but the `enableSessionResumeOption` option is true, it will use the session ID
183
183
  * stored in the sessionIds.json file if it exists.
184
184
  */
185
185
  connect() {
@@ -194,11 +194,11 @@ class Node {
194
194
  if (this.sessionId) {
195
195
  headers["Session-Id"] = this.sessionId;
196
196
  }
197
- else if (this.options.resumeStatus && sessionIdsMap.has(compositeKey)) {
197
+ else if (this.options.enableSessionResumeOption && sessionIdsMap.has(compositeKey)) {
198
198
  this.sessionId = sessionIdsMap.get(compositeKey) || null;
199
199
  headers["Session-Id"] = this.sessionId;
200
200
  }
201
- this.socket = new ws_1.default(`ws${this.options.secure ? "s" : ""}://${this.address}/v4/websocket`, { headers });
201
+ this.socket = new ws_1.default(`ws${this.options.useSSL ? "s" : ""}://${this.address}/v4/websocket`, { headers });
202
202
  this.socket.on("open", this.open.bind(this));
203
203
  this.socket.on("close", this.close.bind(this));
204
204
  this.socket.on("message", this.message.bind(this));
@@ -210,7 +210,7 @@ class Node {
210
210
  options: {
211
211
  clientId: this.manager.options.clientId,
212
212
  clientName: this.manager.options.clientName,
213
- secure: this.options.secure,
213
+ useSSL: this.options.useSSL,
214
214
  identifier: this.options.identifier,
215
215
  },
216
216
  };
@@ -279,17 +279,17 @@ class Node {
279
279
  identifier: this.options.identifier,
280
280
  connected: this.connected,
281
281
  reconnectAttempts: this.reconnectAttempts,
282
- retryAmount: this.options.retryAmount,
283
- retryDelay: this.options.retryDelay,
282
+ maxRetryAttempts: this.options.maxRetryAttempts,
283
+ retryDelayMs: this.options.retryDelayMs,
284
284
  };
285
285
  // Emit a debug event indicating the node is attempting to reconnect
286
286
  this.manager.emit(Manager_1.ManagerEventTypes.Debug, `[NODE] Reconnecting node: ${JSON.stringify(debugInfo)}`);
287
287
  // Schedule the reconnection attempt after the specified retry delay
288
288
  this.reconnectTimeout = setTimeout(async () => {
289
289
  // Check if the maximum number of retry attempts has been reached
290
- if (this.reconnectAttempts >= this.options.retryAmount) {
290
+ if (this.reconnectAttempts >= this.options.maxRetryAttempts) {
291
291
  // Emit an error event and destroy the node if retries are exhausted
292
- const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);
292
+ const error = new Error(`Unable to connect after ${this.options.maxRetryAttempts} attempts.`);
293
293
  this.manager.emit(Manager_1.ManagerEventTypes.NodeError, this, error);
294
294
  return await this.destroy();
295
295
  }
@@ -301,7 +301,7 @@ class Node {
301
301
  this.connect();
302
302
  // Increment the reconnect attempts counter
303
303
  this.reconnectAttempts++;
304
- }, this.options.retryDelay);
304
+ }, this.options.retryDelayMs);
305
305
  }
306
306
  /**
307
307
  * Handles the "open" event emitted by the WebSocket connection.
@@ -431,10 +431,10 @@ class Node {
431
431
  // Load player states from the JSON file
432
432
  await this.manager.loadPlayerStates(this.options.identifier);
433
433
  }
434
- if (this.options.resumeStatus) {
434
+ if (this.options.enableSessionResumeOption) {
435
435
  await this.rest.patch(`/v4/sessions/${this.sessionId}`, {
436
- resuming: this.options.resumeStatus,
437
- timeout: this.options.resumeTimeout,
436
+ resuming: this.options.enableSessionResumeOption,
437
+ timeout: this.options.sessionTimeoutMs,
438
438
  });
439
439
  }
440
440
  break;
@@ -615,187 +615,7 @@ class Node {
615
615
  else {
616
616
  return false;
617
617
  }
618
- // // Determine if YouTube should be used
619
- // // If Last.fm is not available, use YouTube as a fallback
620
- // // If YouTube is available and this is the last attempt, use YouTube
621
- // const shouldUseYouTube =
622
- // (!apiKey && enabledSources.includes("youtube")) || // Fallback to YouTube if Last.fm is not available
623
- // (attempt === player.autoplayTries - 1 && player.autoplayTries > 1 && enabledSources.includes("youtube")); // Use YouTube on the last attempt
624
- // if (shouldUseYouTube) {
625
- // // Use YouTube-based autoplay
626
- // return await this.handleYouTubeAutoplay(player, lastTrack);
627
- // }
628
- // // Handle Last.fm-based autoplay (or other platforms)
629
- // const selectedSource = this.selectPlatform(enabledSources);
630
- // if (selectedSource) {
631
- // // Use the selected source to handle autoplay
632
- // return await this.handlePlatformAutoplay(player, lastTrack, selectedSource, apiKey);
633
- // }
634
- // // If no source is available, return false
635
- // return false;
636
- return false;
637
618
  }
638
- // return response.data.similartracks.track.filter((t: { uri: string }) => t.uri !== track.uri);
639
- // /**
640
- // * Selects a platform from the given enabled sources.
641
- // * @param {string[]} enabledSources - The enabled sources to select from.
642
- // * @returns {SearchPlatform | null} - The selected platform or null if none was found.
643
- // */
644
- // public selectPlatform(enabledSources: string[]): SearchPlatform | null {
645
- // const { autoPlaySearchPlatform } = this.manager.options;
646
- // const platformMapping: { [key in SearchPlatform]: string } = {
647
- // [SearchPlatform.AppleMusic]: "applemusic",
648
- // [SearchPlatform.Bandcamp]: "bandcamp",
649
- // [SearchPlatform.Deezer]: "deezer",
650
- // [SearchPlatform.Jiosaavn]: "jiosaavn",
651
- // [SearchPlatform.SoundCloud]: "soundcloud",
652
- // [SearchPlatform.Spotify]: "spotify",
653
- // [SearchPlatform.Tidal]: "tidal",
654
- // [SearchPlatform.VKMusic]: "vkmusic",
655
- // [SearchPlatform.YouTube]: "youtube",
656
- // [SearchPlatform.YouTubeMusic]: "youtube",
657
- // };
658
- // // Try the autoPlaySearchPlatform first
659
- // if (enabledSources.includes(platformMapping[autoPlaySearchPlatform])) {
660
- // return autoPlaySearchPlatform;
661
- // }
662
- // // Fallback to other platforms in a predefined order
663
- // const fallbackPlatforms = [
664
- // SearchPlatform.Spotify,
665
- // SearchPlatform.Deezer,
666
- // SearchPlatform.SoundCloud,
667
- // SearchPlatform.AppleMusic,
668
- // SearchPlatform.Bandcamp,
669
- // SearchPlatform.Jiosaavn,
670
- // SearchPlatform.Tidal,
671
- // SearchPlatform.VKMusic,
672
- // SearchPlatform.YouTubeMusic,
673
- // SearchPlatform.YouTube,
674
- // ];
675
- // for (const platform of fallbackPlatforms) {
676
- // if (enabledSources.includes(platformMapping[platform])) {
677
- // return platform;
678
- // }
679
- // }
680
- // return null;
681
- // }
682
- // /**
683
- // * Handles Last.fm-based autoplay.
684
- // * @param {Player} player - The player instance.
685
- // * @param {Track} previousTrack - The previous track.
686
- // * @param {SearchPlatform} platform - The selected platform.
687
- // * @param {string} apiKey - The Last.fm API key.
688
- // * @returns {Promise<boolean>} - Whether the autoplay was successful.
689
- // */
690
- // private async handlePlatformAutoplay(player: Player, previousTrack: Track, platform: SearchPlatform, apiKey: string): Promise<boolean> {
691
- // let { author: artist } = previousTrack;
692
- // const { title } = previousTrack;
693
- // if (!artist || !title) {
694
- // if (!title) {
695
- // // No title provided, search for the artist's top tracks
696
- // const noTitleUrl = `https://ws.audioscrobbler.com/2.0/?method=artist.getTopTracks&artist=${artist}&autocorrect=1&api_key=${apiKey}&format=json`;
697
- // const response = await axios.get(noTitleUrl);
698
- // if (response.data.error || !response.data.toptracks?.track?.length) return false;
699
- // const randomTrack = response.data.toptracks.track[Math.floor(Math.random() * response.data.toptracks.track.length)];
700
- // const res = await player.search(
701
- // { query: `${randomTrack.artist.name} - ${randomTrack.name}`, source: platform },
702
- // player.get("Internal_BotUser") as User | ClientUser
703
- // );
704
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return false;
705
- // const foundTrack = res.tracks.find((t) => t.uri !== previousTrack.uri);
706
- // if (!foundTrack) return false;
707
- // player.queue.add(foundTrack);
708
- // await player.play();
709
- // return true;
710
- // }
711
- // if (!artist) {
712
- // // No artist provided, search for the track title
713
- // const noArtistUrl = `https://ws.audioscrobbler.com/2.0/?method=track.search&track=${title}&api_key=${apiKey}&format=json`;
714
- // const response = await axios.get(noArtistUrl);
715
- // artist = response.data.results.trackmatches?.track?.[0]?.artist;
716
- // if (!artist) return false;
717
- // }
718
- // }
719
- // // Search for similar tracks to the current track
720
- // const url = `https://ws.audioscrobbler.com/2.0/?method=track.getSimilar&artist=${artist}&track=${title}&limit=10&autocorrect=1&api_key=${apiKey}&format=json`;
721
- // let response: axios.AxiosResponse;
722
- // try {
723
- // response = await axios.get(url);
724
- // } catch (error) {
725
- // if (error) return false;
726
- // }
727
- // if (response.data.error || !response.data.similartracks?.track?.length) {
728
- // // Retry the request if the first attempt fails
729
- // const retryUrl = `https://ws.audioscrobbler.com/2.0/?method=artist.getTopTracks&artist=${artist}&autocorrect=1&api_key=${apiKey}&format=json`;
730
- // const retryResponse = await axios.get(retryUrl);
731
- // if (retryResponse.data.error || !retryResponse.data.toptracks?.track?.length) return false;
732
- // const randomTrack = retryResponse.data.toptracks.track[Math.floor(Math.random() * retryResponse.data.toptracks.track.length)];
733
- // const res = await player.search(
734
- // { query: `${randomTrack.artist.name} - ${randomTrack.name}`, source: platform },
735
- // player.get("Internal_BotUser") as User | ClientUser
736
- // );
737
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return false;
738
- // const foundTrack = res.tracks.find((t) => t.uri !== previousTrack.uri);
739
- // if (!foundTrack) return false;
740
- // player.queue.add(foundTrack);
741
- // await player.play();
742
- // return true;
743
- // }
744
- // const randomTrack = response.data.similartracks.track[Math.floor(Math.random() * response.data.similartracks.track.length)];
745
- // const res = await player.search(
746
- // { query: `${randomTrack.artist.name} - ${randomTrack.name}`, source: platform },
747
- // player.get("Internal_BotUser") as User | ClientUser
748
- // );
749
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return false;
750
- // const foundTrack = res.tracks.find((t) => t.uri !== previousTrack.uri);
751
- // if (!foundTrack) return false;
752
- // player.queue.add(foundTrack);
753
- // await player.play();
754
- // return true;
755
- // }
756
- // /**
757
- // * Handles YouTube-based autoplay.
758
- // * @param {Player} player - The player instance.
759
- // * @param {Track} previousTrack - The previous track.
760
- // * @returns {Promise<boolean>} - Whether the autoplay was successful.
761
- // */
762
- // private async handleYouTubeAutoplay(player: Player, previousTrack: Track): Promise<boolean> {
763
- // // Check if the previous track has a YouTube URL
764
- // const hasYouTubeURL = ["youtube.com", "youtu.be"].some((url) => previousTrack.uri.includes(url));
765
- // // Get the video ID from the previous track's URL
766
- // const videoID = hasYouTubeURL
767
- // ? previousTrack.uri.split("=").pop()
768
- // : (
769
- // await this.manager.search(
770
- // { query: `${previousTrack.author} - ${previousTrack.title}`, source: SearchPlatform.YouTube },
771
- // player.get("Internal_BotUser") as User | ClientUser
772
- // )
773
- // ).tracks[0]?.uri
774
- // .split("=")
775
- // .pop();
776
- // // If the video ID is not found, return false
777
- // if (!videoID) return false;
778
- // // Get a random video index between 2 and 24
779
- // let randomIndex: number;
780
- // let searchURI: string;
781
- // do {
782
- // // Generate a random index between 2 and 24
783
- // randomIndex = Math.floor(Math.random() * 23) + 2;
784
- // // Build the search URI
785
- // searchURI = `https://www.youtube.com/watch?v=${videoID}&list=RD${videoID}&index=${randomIndex}`;
786
- // } while (previousTrack.uri.includes(searchURI));
787
- // // Search for the video and return false if the search fails
788
- // const res = await this.manager.search({ query: searchURI, source: SearchPlatform.YouTube }, player.get("Internal_BotUser") as User | ClientUser);
789
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return false;
790
- // // Find a track that is not the same as the current track
791
- // const foundTrack = res.tracks.find((t) => t.uri !== previousTrack.uri && t.author !== previousTrack.author && t.title !== previousTrack.title);
792
- // // If no track is found, return false
793
- // if (!foundTrack) return false;
794
- // // Add the found track to the queue and play it
795
- // player.queue.add(foundTrack);
796
- // await player.play();
797
- // return true;
798
- // }
799
619
  /**
800
620
  * Handles the scenario when a track fails to play or load.
801
621
  * Shifts the queue to the next track and emits a track end event.
@@ -815,7 +635,7 @@ class Node {
815
635
  return;
816
636
  }
817
637
  this.manager.emit(Manager_1.ManagerEventTypes.TrackEnd, player, track, payload);
818
- if (this.manager.options.autoPlay)
638
+ if (this.manager.options.playNextOnEnd)
819
639
  await player.play();
820
640
  }
821
641
  /**
@@ -832,7 +652,7 @@ class Node {
832
652
  */
833
653
  async handleRepeatedTrack(player, track, payload) {
834
654
  const { queue, trackRepeat, queueRepeat } = player;
835
- const { autoPlay } = this.manager.options;
655
+ const { playNextOnEnd } = this.manager.options;
836
656
  if (trackRepeat) {
837
657
  // Prevent duplicate repeat insertion
838
658
  if (queue[0] !== queue.current) {
@@ -855,7 +675,7 @@ class Node {
855
675
  return;
856
676
  }
857
677
  // If autoplay is enabled, play the next track
858
- if (autoPlay)
678
+ if (playNextOnEnd)
859
679
  await player.play();
860
680
  }
861
681
  /**
@@ -875,7 +695,7 @@ class Node {
875
695
  // Emit the track end event
876
696
  this.manager.emit(Manager_1.ManagerEventTypes.TrackEnd, player, track, payload);
877
697
  // If autoplay is enabled, play the next track
878
- if (this.manager.options.autoPlay)
698
+ if (this.manager.options.playNextOnEnd)
879
699
  await player.play();
880
700
  }
881
701
  /**
@@ -377,117 +377,7 @@ class Player {
377
377
  async getRecommendedTracks(track) {
378
378
  const tracks = await Utils_1.AutoPlayUtils.getRecommendedTracks(this, track);
379
379
  return tracks;
380
- // const node = this.manager.useableNode;
381
- // if (!node) {
382
- // throw new Error("No available nodes.");
383
- // }
384
- // if (!TrackUtils.validate(track)) {
385
- // throw new RangeError('"Track must be a "Track" or "Track[]');
386
- // }
387
- // // Get the Last.fm API key and the available source managers
388
- // const apiKey = this.manager.options.lastFmApiKey;
389
- // const enabledSources = node.info.sourceManagers;
390
- // // Determine if YouTube should be used
391
- // if (!apiKey && enabledSources.includes("youtube")) {
392
- // // Use YouTube-based autoplay
393
- // return await this.handleYouTubeRecommendations(track);
394
- // }
395
- // if (!apiKey) return [];
396
- // // Handle Last.fm-based autoplay (or other platforms)
397
- // const selectedSource = node.selectPlatform(enabledSources);
398
- // if (selectedSource) {
399
- // // Use the selected source to handle autoplay
400
- // return await this.handlePlatformAutoplay(track, selectedSource, apiKey);
401
- // }
402
- // // If no source is available, return false
403
- // return [];
404
380
  }
405
- // /**
406
- // * Handles YouTube-based recommendations.
407
- // * @param {Track} track - The track to find recommendations for.
408
- // * @returns {Promise<Track[]>} - Array of recommended tracks.
409
- // */
410
- // private async handleYouTubeRecommendations(track: Track): Promise<Track[]> {
411
- // // Check if the previous track has a YouTube URL
412
- // const hasYouTubeURL = ["youtube.com", "youtu.be"].some((url) => track.uri.includes(url));
413
- // // Get the video ID from the previous track's URL
414
- // let videoID: string | null = null;
415
- // if (hasYouTubeURL) {
416
- // videoID = track.uri.split("=").pop();
417
- // } else {
418
- // const searchResult = await this.manager.search({ query: `${track.author} - ${track.title}`, source: SearchPlatform.YouTube }, track.requester);
419
- // videoID = searchResult.tracks[0]?.uri.split("=").pop();
420
- // }
421
- // // If the video ID is not found, return false
422
- // if (!videoID) return [];
423
- // // Get a random video index between 2 and 24
424
- // let randomIndex: number;
425
- // let searchURI: string;
426
- // do {
427
- // // Generate a random index between 2 and 24
428
- // randomIndex = Math.floor(Math.random() * 23) + 2;
429
- // // Build the search URI
430
- // searchURI = `https://www.youtube.com/watch?v=${videoID}&list=RD${videoID}&index=${randomIndex}`;
431
- // } while (track.uri.includes(searchURI));
432
- // // Search for the video and return false if the search fails
433
- // const res = await this.manager.search({ query: searchURI, source: SearchPlatform.YouTube }, track.requester);
434
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return [];
435
- // // Return all track titles that do not have the same URI as the track.uri from before
436
- // return res.tracks.filter((t) => t.uri !== track.uri);
437
- // }
438
- // /**
439
- // * Handles Last.fm-based autoplay (or other platforms).
440
- // * @param {Track} track - The track to find recommendations for.
441
- // * @param {SearchPlatform} source - The selected search platform.
442
- // * @param {string} apiKey - The Last.fm API key.
443
- // * @returns {Promise<Track[]>} - Array of recommended tracks.
444
- // */
445
- // private async handlePlatformAutoplay(track: Track, source: SearchPlatform, apiKey: string): Promise<Track[]> {
446
- // let { author: artist } = track;
447
- // const { title } = track;
448
- // if (!artist || !title) {
449
- // if (!title) {
450
- // // No title provided, search for the artist's top tracks
451
- // const noTitleUrl = `https://ws.audioscrobbler.com/2.0/?method=artist.getTopTracks&artist=${artist}&autocorrect=1&api_key=${apiKey}&format=json`;
452
- // const response = await axios.get(noTitleUrl);
453
- // if (response.data.error || !response.data.toptracks?.track?.length) return [];
454
- // const randomTrack = response.data.toptracks.track[Math.floor(Math.random() * response.data.toptracks.track.length)];
455
- // const res = await this.manager.search({ query: `${randomTrack.artist.name} - ${randomTrack.name}`, source: source }, track.requester);
456
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return [];
457
- // const filteredTracks = res.tracks.filter((t) => t.uri !== track.uri);
458
- // if (!filteredTracks) return [];
459
- // return filteredTracks;
460
- // }
461
- // if (!artist) {
462
- // // No artist provided, search for the track title
463
- // const noArtistUrl = `https://ws.audioscrobbler.com/2.0/?method=track.search&track=${title}&api_key=${apiKey}&format=json`;
464
- // const response = await axios.get(noArtistUrl);
465
- // artist = response.data.results.trackmatches?.track?.[0]?.artist;
466
- // if (!artist) return [];
467
- // }
468
- // }
469
- // // Search for similar tracks to the current track
470
- // const url = `https://ws.audioscrobbler.com/2.0/?method=track.getSimilar&artist=${artist}&track=${title}&limit=10&autocorrect=1&api_key=${apiKey}&format=json`;
471
- // let response: axios.AxiosResponse;
472
- // try {
473
- // response = await axios.get(url);
474
- // } catch (error) {
475
- // if (error) return [];
476
- // }
477
- // if (response.data.error || !response.data.similartracks?.track?.length) {
478
- // // Retry the request if the first attempt fails
479
- // const retryUrl = `https://ws.audioscrobbler.com/2.0/?method=artist.getTopTracks&artist=${artist}&autocorrect=1&api_key=${apiKey}&format=json`;
480
- // const retryResponse = await axios.get(retryUrl);
481
- // if (retryResponse.data.error || !retryResponse.data.toptracks?.track?.length) return [];
482
- // const randomTrack = retryResponse.data.toptracks.track[Math.floor(Math.random() * retryResponse.data.toptracks.track.length)];
483
- // const res = await this.manager.search({ query: `${randomTrack.artist.name} - ${randomTrack.name}`, source: source }, track.requester);
484
- // if (res.loadType === LoadTypes.Empty || res.loadType === LoadTypes.Error) return [];
485
- // const filteredTracks = res.tracks.filter((t) => t.uri !== track.uri);
486
- // if (!filteredTracks) return [];
487
- // return filteredTracks;
488
- // }
489
- // return response.data.similartracks.track.filter((t: { uri: string }) => t.uri !== track.uri);
490
- // }
491
381
  /**
492
382
  * Sets the volume of the player.
493
383
  * @param {number} volume - The new volume. Must be between 0 and 1000.
@@ -18,7 +18,7 @@ class Rest {
18
18
  manager;
19
19
  constructor(node, manager) {
20
20
  this.node = node;
21
- this.url = `http${node.options.secure ? "s" : ""}://${node.options.host}:${node.options.port}`;
21
+ this.url = `http${node.options.useSSL ? "s" : ""}://${node.options.host}:${node.options.port}`;
22
22
  this.sessionId = node.sessionId;
23
23
  this.password = node.options.password;
24
24
  this.manager = manager;
@@ -10,10 +10,10 @@ const Manager_1 = require("../structures/Manager");
10
10
  function managerCheck(options) {
11
11
  if (!options)
12
12
  throw new TypeError("ManagerOptions must not be empty.");
13
- const { autoPlay, clientName, defaultSearchPlatform, autoPlaySearchPlatform, nodes, plugins, send, trackPartial, usePriority, useNode, replaceYouTubeCredentials, lastFmApiKey, maxPreviousTracks, } = options;
14
- // Validate autoPlay option
15
- if (typeof autoPlay !== "boolean") {
16
- throw new TypeError('Manager option "autoPlay" must be a boolean.');
13
+ const { playNextOnEnd, clientName, defaultSearchPlatform, autoPlaySearchPlatform, nodes, enabledPlugins, send, trackPartial, enablePriorityMode, useNode, normalizeYouTubeTitles, lastFmApiKey, maxPreviousTracks, } = options;
14
+ // Validate playNextOnEnd option
15
+ if (typeof playNextOnEnd !== "boolean") {
16
+ throw new TypeError('Manager option "playNextOnEnd" must be a boolean.');
17
17
  }
18
18
  // Validate clientName option
19
19
  if (typeof clientName !== "undefined") {
@@ -37,9 +37,9 @@ function managerCheck(options) {
37
37
  if (typeof nodes === "undefined" || !Array.isArray(nodes)) {
38
38
  throw new TypeError('Manager option "nodes" must be an array.');
39
39
  }
40
- // Validate plugins option
41
- if (typeof plugins !== "undefined" && !Array.isArray(plugins)) {
42
- throw new TypeError('Manager option "plugins" must be a Plugin array.');
40
+ // Validate enabledPlugins option
41
+ if (typeof enabledPlugins !== "undefined" && !Array.isArray(enabledPlugins)) {
42
+ throw new TypeError('Manager option "enabledPlugins" must be a Plugin array.');
43
43
  }
44
44
  // Validate send option
45
45
  if (typeof send !== "function") {
@@ -54,15 +54,15 @@ function managerCheck(options) {
54
54
  throw new TypeError('Manager option "trackPartial" must be an array of valid TrackPartial values.');
55
55
  }
56
56
  }
57
- // Validate usePriority option
58
- if (typeof usePriority !== "undefined" && typeof usePriority !== "boolean") {
59
- throw new TypeError('Manager option "usePriority" must be a boolean.');
57
+ // Validate enablePriorityMode option
58
+ if (typeof enablePriorityMode !== "undefined" && typeof enablePriorityMode !== "boolean") {
59
+ throw new TypeError('Manager option "enablePriorityMode" must be a boolean.');
60
60
  }
61
- // Validate node priority if usePriority is enabled
62
- if (usePriority) {
61
+ // Validate node priority if enablePriorityMode is enabled
62
+ if (enablePriorityMode) {
63
63
  for (let index = 0; index < nodes.length; index++) {
64
- if (typeof nodes[index].priority !== "number" || isNaN(nodes[index].priority)) {
65
- throw new TypeError(`Missing or invalid node option "priority" at position ${index}`);
64
+ if (typeof nodes[index].nodePriority !== "number" || isNaN(nodes[index].nodePriority)) {
65
+ throw new TypeError(`Missing or invalid node option "nodePriority" at position ${index}`);
66
66
  }
67
67
  }
68
68
  }
@@ -75,9 +75,9 @@ function managerCheck(options) {
75
75
  throw new TypeError('Manager option "useNode" must be either "leastLoad" or "leastPlayers".');
76
76
  }
77
77
  }
78
- // Validate replaceYouTubeCredentials option
79
- if (typeof replaceYouTubeCredentials !== "undefined" && typeof replaceYouTubeCredentials !== "boolean") {
80
- throw new TypeError('Manager option "replaceYouTubeCredentials" must be a boolean.');
78
+ // Validate normalizeYouTubeTitles option
79
+ if (typeof normalizeYouTubeTitles !== "undefined" && typeof normalizeYouTubeTitles !== "boolean") {
80
+ throw new TypeError('Manager option "normalizeYouTubeTitles" must be a boolean.');
81
81
  }
82
82
  // Validate lastFmApiKey option
83
83
  if (typeof lastFmApiKey !== "undefined" && (typeof lastFmApiKey !== "string" || lastFmApiKey.trim().length === 0)) {
@@ -12,7 +12,7 @@ function nodeCheck(options) {
12
12
  throw new TypeError("NodeOptions must not be empty.");
13
13
  // Validate the host option
14
14
  // The host option must be present and be a non-empty string.
15
- const { host, identifier, password, port, resumeStatus, resumeTimeout, retryAmount, retryDelay, secure, priority } = options;
15
+ const { host, identifier, password, port, enableSessionResumeOption, sessionTimeoutMs, maxRetryAttempts, retryDelayMs, useSSL, nodePriority } = options;
16
16
  if (typeof host !== "string" || !/.+/.test(host)) {
17
17
  throw new TypeError('Node option "host" must be present and be a non-empty string.');
18
18
  }
@@ -31,34 +31,34 @@ function nodeCheck(options) {
31
31
  if (typeof port !== "undefined" && typeof port !== "number") {
32
32
  throw new TypeError('Node option "port" must be a number.');
33
33
  }
34
- // Validate the resumeStatus option
35
- // The resumeStatus option must be a boolean or undefined.
36
- if (typeof resumeStatus !== "undefined" && typeof resumeStatus !== "boolean") {
37
- throw new TypeError('Node option "resumeStatus" must be a boolean.');
34
+ // Validate the enableSessionResumeOption option
35
+ // The enableSessionResumeOption option must be a boolean or undefined.
36
+ if (typeof enableSessionResumeOption !== "undefined" && typeof enableSessionResumeOption !== "boolean") {
37
+ throw new TypeError('Node option "enableSessionResumeOption" must be a boolean.');
38
38
  }
39
- // Validate the resumeTimeout option
40
- // The resumeTimeout option must be a number or undefined.
41
- if (typeof resumeTimeout !== "undefined" && typeof resumeTimeout !== "number") {
42
- throw new TypeError('Node option "resumeTimeout" must be a number.');
39
+ // Validate the sessionTimeoutMs option
40
+ // The sessionTimeoutMs option must be a number or undefined.
41
+ if (typeof sessionTimeoutMs !== "undefined" && typeof sessionTimeoutMs !== "number") {
42
+ throw new TypeError('Node option "sessionTimeoutMs" must be a number.');
43
43
  }
44
- // Validate the retryAmount option
45
- // The retryAmount option must be a number or undefined.
46
- if (typeof retryAmount !== "undefined" && typeof retryAmount !== "number") {
47
- throw new TypeError('Node option "retryAmount" must be a number.');
44
+ // Validate the maxRetryAttempts option
45
+ // The maxRetryAttempts option must be a number or undefined.
46
+ if (typeof maxRetryAttempts !== "undefined" && typeof maxRetryAttempts !== "number") {
47
+ throw new TypeError('Node option "maxRetryAttempts" must be a number.');
48
48
  }
49
- // Validate the retryDelay option
50
- // The retryDelay option must be a number or undefined.
51
- if (typeof retryDelay !== "undefined" && typeof retryDelay !== "number") {
52
- throw new TypeError('Node option "retryDelay" must be a number.');
49
+ // Validate the retryDelayMs option
50
+ // The retryDelayMs option must be a number or undefined.
51
+ if (typeof retryDelayMs !== "undefined" && typeof retryDelayMs !== "number") {
52
+ throw new TypeError('Node option "retryDelayMs" must be a number.');
53
53
  }
54
- // Validate the secure option
55
- // The secure option must be a boolean or undefined.
56
- if (typeof secure !== "undefined" && typeof secure !== "boolean") {
57
- throw new TypeError('Node option "secure" must be a boolean.');
54
+ // Validate the useSSL option
55
+ // The useSSL option must be a boolean or undefined.
56
+ if (typeof useSSL !== "undefined" && typeof useSSL !== "boolean") {
57
+ throw new TypeError('Node option "useSSL" must be a boolean.');
58
58
  }
59
- // Validate the priority option
60
- // The priority option must be a number or undefined.
61
- if (typeof priority !== "undefined" && typeof priority !== "number") {
62
- throw new TypeError('Node option "priority" must be a number.');
59
+ // Validate the nodePriority option
60
+ // The nodePriority option must be a number or undefined.
61
+ if (typeof nodePriority !== "undefined" && typeof nodePriority !== "number") {
62
+ throw new TypeError('Node option "nodePriority" must be a number.');
63
63
  }
64
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magmastream",
3
- "version": "2.9.0-dev.0",
3
+ "version": "2.9.0-dev.2",
4
4
  "description": "A user-friendly Lavalink client designed for NodeJS.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",