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 +24 -24
- package/dist/structures/Manager.js +18 -19
- package/dist/structures/Node.js +21 -201
- package/dist/structures/Player.js +0 -110
- package/dist/structures/Rest.js +1 -1
- package/dist/utils/managerCheck.js +17 -17
- package/dist/utils/nodeCheck.js +25 -25
- package/package.json +1 -1
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 `
|
|
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
|
-
|
|
480
|
+
useSSL?: boolean;
|
|
481
481
|
/** The identifier for the node. */
|
|
482
482
|
identifier?: string;
|
|
483
|
-
/** The
|
|
484
|
-
|
|
485
|
-
/** The
|
|
486
|
-
|
|
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
|
-
|
|
488
|
+
enableSessionResumeOption?: boolean;
|
|
489
489
|
/** The time the lavalink server will wait before it removes the player. */
|
|
490
|
-
|
|
490
|
+
sessionTimeoutMs?: number;
|
|
491
491
|
/** The timeout used for api calls. */
|
|
492
|
-
|
|
492
|
+
apiRequestTimeoutMs?: number;
|
|
493
493
|
/** Priority of the node. */
|
|
494
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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 `
|
|
1001
|
-
* If `
|
|
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 `
|
|
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
|
-
/**
|
|
1118
|
-
|
|
1119
|
-
/**
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
51
|
+
enabledPlugins: [],
|
|
52
52
|
nodes: [
|
|
53
53
|
{
|
|
54
54
|
identifier: "default",
|
|
55
55
|
host: "localhost",
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
enableSessionResumeOption: false,
|
|
57
|
+
sessionTimeoutMs: 1000,
|
|
58
58
|
},
|
|
59
59
|
],
|
|
60
|
-
|
|
61
|
-
|
|
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.
|
|
129
|
-
for (const [index, plugin] of this.options.
|
|
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.
|
|
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 `
|
|
534
|
-
* If `
|
|
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 `
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
858
|
+
weight: node.options.nodePriority / totalWeight,
|
|
860
859
|
}));
|
|
861
860
|
// Generate a random number between 0 and 1
|
|
862
861
|
const randomNumber = Math.random();
|
package/dist/structures/Node.js
CHANGED
|
@@ -61,13 +61,13 @@ class Node {
|
|
|
61
61
|
this.options = {
|
|
62
62
|
port: 2333,
|
|
63
63
|
password: "youshallnotpass",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
useSSL: false,
|
|
65
|
+
maxRetryAttempts: 30,
|
|
66
|
+
retryDelayMs: 60000,
|
|
67
|
+
nodePriority: 0,
|
|
68
68
|
...options,
|
|
69
69
|
};
|
|
70
|
-
if (this.options.
|
|
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 `
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
283
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
434
|
+
if (this.options.enableSessionResumeOption) {
|
|
435
435
|
await this.rest.patch(`/v4/sessions/${this.sessionId}`, {
|
|
436
|
-
resuming: this.options.
|
|
437
|
-
timeout: this.options.
|
|
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.
|
|
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 {
|
|
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 (
|
|
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.
|
|
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.
|
package/dist/structures/Rest.js
CHANGED
|
@@ -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.
|
|
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 {
|
|
14
|
-
// Validate
|
|
15
|
-
if (typeof
|
|
16
|
-
throw new TypeError('Manager option "
|
|
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
|
|
41
|
-
if (typeof
|
|
42
|
-
throw new TypeError('Manager option "
|
|
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
|
|
58
|
-
if (typeof
|
|
59
|
-
throw new TypeError('Manager option "
|
|
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
|
|
62
|
-
if (
|
|
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].
|
|
65
|
-
throw new TypeError(`Missing or invalid node option "
|
|
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
|
|
79
|
-
if (typeof
|
|
80
|
-
throw new TypeError('Manager option "
|
|
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)) {
|
package/dist/utils/nodeCheck.js
CHANGED
|
@@ -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,
|
|
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
|
|
35
|
-
// The
|
|
36
|
-
if (typeof
|
|
37
|
-
throw new TypeError('Node option "
|
|
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
|
|
40
|
-
// The
|
|
41
|
-
if (typeof
|
|
42
|
-
throw new TypeError('Node option "
|
|
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
|
|
45
|
-
// The
|
|
46
|
-
if (typeof
|
|
47
|
-
throw new TypeError('Node option "
|
|
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
|
|
50
|
-
// The
|
|
51
|
-
if (typeof
|
|
52
|
-
throw new TypeError('Node option "
|
|
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
|
|
55
|
-
// The
|
|
56
|
-
if (typeof
|
|
57
|
-
throw new TypeError('Node option "
|
|
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
|
|
60
|
-
// The
|
|
61
|
-
if (typeof
|
|
62
|
-
throw new TypeError('Node option "
|
|
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
|
}
|