lavalink-client 1.0.4 → 1.0.6

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.
Files changed (35) hide show
  1. package/README.md +33 -98
  2. package/dist/cjs/structures/LavalinkManager.d.ts +19 -14
  3. package/dist/cjs/structures/LavalinkManager.js +3 -14
  4. package/dist/cjs/structures/Node.d.ts +3 -3
  5. package/dist/cjs/structures/Node.js +16 -11
  6. package/dist/cjs/structures/NodeManager.d.ts +1 -12
  7. package/dist/cjs/structures/NodeManager.js +53 -60
  8. package/dist/cjs/structures/Player.d.ts +4 -4
  9. package/dist/cjs/structures/Player.js +20 -7
  10. package/dist/cjs/structures/Queue.d.ts +9 -9
  11. package/dist/cjs/structures/Queue.js +24 -23
  12. package/dist/cjs/structures/Track.d.ts +14 -3
  13. package/dist/cjs/structures/Utils.d.ts +20 -5
  14. package/dist/cjs/structures/Utils.js +135 -15
  15. package/dist/esm/structures/LavalinkManager.d.ts +19 -14
  16. package/dist/esm/structures/LavalinkManager.js +3 -14
  17. package/dist/esm/structures/Node.d.ts +3 -3
  18. package/dist/esm/structures/Node.js +16 -11
  19. package/dist/esm/structures/NodeManager.d.ts +1 -12
  20. package/dist/esm/structures/NodeManager.js +53 -60
  21. package/dist/esm/structures/Player.d.ts +4 -4
  22. package/dist/esm/structures/Player.js +20 -7
  23. package/dist/esm/structures/Queue.d.ts +9 -9
  24. package/dist/esm/structures/Queue.js +25 -24
  25. package/dist/esm/structures/Track.d.ts +14 -3
  26. package/dist/esm/structures/Utils.d.ts +20 -5
  27. package/dist/esm/structures/Utils.js +135 -15
  28. package/dist/types/structures/LavalinkManager.d.ts +19 -14
  29. package/dist/types/structures/Node.d.ts +3 -3
  30. package/dist/types/structures/NodeManager.d.ts +1 -12
  31. package/dist/types/structures/Player.d.ts +4 -4
  32. package/dist/types/structures/Queue.d.ts +9 -9
  33. package/dist/types/structures/Track.d.ts +14 -3
  34. package/dist/types/structures/Utils.d.ts +20 -5
  35. package/package.json +1 -1
@@ -42,10 +42,6 @@ export class LavalinkManager extends EventEmitter {
42
42
  };
43
43
  if (!this.options.autoSkip)
44
44
  this.options.autoSkip = true;
45
- if (!this.options.defaultLeastLoadNodeSortType)
46
- this.options.defaultLeastLoadNodeSortType = "memory";
47
- if (!this.options.defaultLeastUsedNodeSortType)
48
- this.options.defaultLeastUsedNodeSortType = "players";
49
45
  if (!this.options.playerOptions.defaultSearchPlatform)
50
46
  this.options.playerOptions.defaultSearchPlatform = "ytsearch";
51
47
  // default queue options
@@ -63,13 +59,9 @@ export class LavalinkManager extends EventEmitter {
63
59
  if (typeof options.sendToShard !== "function")
64
60
  throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
65
61
  // only check in .init()
66
- // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string, shards?: 'auto'|number } was not provided, which is required");
62
+ // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
67
63
  if (options.autoSkip && typeof options.autoSkip !== "boolean")
68
64
  throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
69
- if (options.defaultLeastLoadNodeSortType && !["memory", "cpu"].includes(options.defaultLeastLoadNodeSortType))
70
- throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'cpu'");
71
- if (options.defaultLeastUsedNodeSortType && !["memory", "players", "calls"].includes(options.defaultLeastUsedNodeSortType))
72
- throw new SyntaxError("ManagerOption.defaultLeastLoadNodeSortType must be 'memory' | 'calls' | 'players'");
73
65
  if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
74
66
  throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
75
67
  /* QUEUE STORE */
@@ -154,9 +146,7 @@ export class LavalinkManager extends EventEmitter {
154
146
  * @param data
155
147
  */
156
148
  async sendRawData(data) {
157
- if (!this.initiated)
158
- return;
159
- if (!("t" in data))
149
+ if (!this.initiated || !("t" in data))
160
150
  return;
161
151
  // for channel Delete
162
152
  if ("CHANNEL_DELETE" === data.t) {
@@ -164,9 +154,8 @@ export class LavalinkManager extends EventEmitter {
164
154
  if (!update.guild_id)
165
155
  return;
166
156
  const player = this.getPlayer(update.guild_id);
167
- if (player.voiceChannelId === update.id) {
157
+ if (player && player.voiceChannelId === update.id)
168
158
  return player.destroy(DestroyReasons.ChannelDeleted);
169
- }
170
159
  }
171
160
  // for voice updates
172
161
  if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
@@ -4,7 +4,7 @@ import { NodeManager } from "./NodeManager";
4
4
  import internal from "stream";
5
5
  import { InvalidLavalinkRestRequest, LavalinkPlayer, PlayerUpdateInfo, RoutePlanner, Session, Base64 } from "./Utils";
6
6
  import { DestroyReasonsType } from "./Player";
7
- import { TrackInfo } from "./Track";
7
+ import { Track } from "./Track";
8
8
  /** Modifies any outgoing REST requests. */
9
9
  export type ModifyRequest = (options: Dispatcher.RequestOptions) => void;
10
10
  export interface LavalinkNodeOptions {
@@ -185,13 +185,13 @@ export declare class LavalinkNode {
185
185
  * @param encoded
186
186
  * @returns
187
187
  */
188
- singleTrack: (encoded: Base64) => Promise<TrackInfo>;
188
+ singleTrack: (encoded: Base64, requester: unknown) => Promise<Track>;
189
189
  /**
190
190
  *
191
191
  * @param encodeds Decodes multiple tracks into their info
192
192
  * @returns
193
193
  */
194
- multipleTracks: (encodeds: Base64[]) => Promise<TrackInfo[]>;
194
+ multipleTracks: (encodeds: Base64[], requester: unknown) => Promise<Track[]>;
195
195
  };
196
196
  /**
197
197
  * Request Lavalink statistics.
@@ -133,9 +133,8 @@ export class LavalinkNode {
133
133
  return;
134
134
  const headers = {
135
135
  Authorization: this.options.authorization,
136
- "Num-Shards": String(this.NodeManager.LavalinkManager.options.client.shards || "auto"),
137
136
  "User-Id": this.NodeManager.LavalinkManager.options.client.id,
138
- "User-Name": this.NodeManager.LavalinkManager.options.client.username || "Lavalink-Client",
137
+ "Client-Name": this.NodeManager.LavalinkManager.options.client.username || "Lavalink-Client",
139
138
  };
140
139
  if (typeof this.options.sessionId === "string" || typeof sessionId === "string") {
141
140
  headers["Session-Id"] = this.options.sessionId || sessionId;
@@ -224,25 +223,27 @@ export class LavalinkNode {
224
223
  * @param encoded
225
224
  * @returns
226
225
  */
227
- singleTrack: async (encoded) => {
226
+ singleTrack: async (encoded, requester) => {
228
227
  if (!encoded)
229
228
  throw new SyntaxError("No encoded (Base64 string) was provided");
230
- return await this.request(`/decodetrack?encodedTrack=${encoded}`);
229
+ // return the decoded + builded track
230
+ return this.NodeManager.LavalinkManager.utils.buildTrack(await this.request(`/decodetrack?encodedTrack=${encoded}`), requester);
231
231
  },
232
232
  /**
233
233
  *
234
234
  * @param encodeds Decodes multiple tracks into their info
235
235
  * @returns
236
236
  */
237
- multipleTracks: async (encodeds) => {
237
+ multipleTracks: async (encodeds, requester) => {
238
238
  if (!Array.isArray(encodeds) || !encodeds.every(v => typeof v === "string" && v.length > 1))
239
239
  throw new SyntaxError("You need to provide encodeds, which is an array of base64 strings");
240
+ // return the decoded + builded tracks
240
241
  return await this.request(`/decodetracks`, r => {
241
242
  r.method = "POST";
242
243
  r.body = JSON.stringify(encodeds);
243
244
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
244
245
  r.headers["Content-Type"] = "application/json";
245
- });
246
+ }).then((r) => r.map(track => this.NodeManager.LavalinkManager.utils.buildTrack(track, requester)));
246
247
  }
247
248
  };
248
249
  /**
@@ -473,6 +474,7 @@ export class LavalinkNode {
473
474
  player.filterManager.filterUpdatedState = 0;
474
475
  }
475
476
  }
477
+ this.NodeManager.LavalinkManager.emit("playerUpdate", player);
476
478
  break;
477
479
  case "event":
478
480
  this.handleEvent(payload);
@@ -519,6 +521,7 @@ export class LavalinkNode {
519
521
  return this.NodeManager.LavalinkManager.emit("trackStart", player, track, payload);
520
522
  }
521
523
  async trackEnd(player, track, payload) {
524
+ console.log(payload.reason);
522
525
  // If there are no songs in the queue
523
526
  if (!player.queue.tracks.length && player.repeatMode === "off")
524
527
  return this.queueEnd(player, track, payload);
@@ -527,7 +530,7 @@ export class LavalinkNode {
527
530
  return this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload);
528
531
  // If a track had an error while starting
529
532
  if (["loadFailed", "cleanup"].includes(payload.reason)) {
530
- await queueTrackEnd(player.queue, false);
533
+ await queueTrackEnd(player);
531
534
  // if no track available, end queue
532
535
  if (!player.queue.current)
533
536
  return this.queueEnd(player, track, payload);
@@ -538,7 +541,7 @@ export class LavalinkNode {
538
541
  }
539
542
  // remove tracks from the queue
540
543
  if (player.repeatMode !== "track")
541
- await queueTrackEnd(player.queue, player.repeatMode === "queue");
544
+ await queueTrackEnd(player);
542
545
  // if no track available, end queue
543
546
  if (!player.queue.current)
544
547
  return this.queueEnd(player, track, payload);
@@ -548,15 +551,17 @@ export class LavalinkNode {
548
551
  return this.NodeManager.LavalinkManager.options.autoSkip && player.play({ noReplace: true });
549
552
  }
550
553
  async queueEnd(player, track, payload) {
554
+ // add previous track to the queue!
551
555
  player.queue.current = null;
552
556
  player.playing = false;
553
557
  if (typeof this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function") {
554
558
  await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track);
555
559
  if (player.queue.tracks.length > 0)
556
- await queueTrackEnd(player.queue, player.repeatMode === "queue");
560
+ await queueTrackEnd(player);
557
561
  if (player.queue.current)
558
562
  return player.play({ noReplace: true, paused: false });
559
563
  }
564
+ player.queue.previous.unshift(track);
560
565
  if (payload?.reason !== "stopped") {
561
566
  await player.queue.utils.save();
562
567
  }
@@ -581,7 +586,7 @@ export class LavalinkNode {
581
586
  if (!player.queue.tracks.length && player.repeatMode === "off")
582
587
  return;
583
588
  // remove the current track, and enqueue the next one
584
- await queueTrackEnd(player.queue, player.repeatMode === "queue");
589
+ await queueTrackEnd(player);
585
590
  // if no track available, end queue
586
591
  if (!player.queue.current)
587
592
  return this.queueEnd(player, track, payload);
@@ -591,7 +596,7 @@ export class LavalinkNode {
591
596
  async trackError(player, track, payload) {
592
597
  this.NodeManager.LavalinkManager.emit("trackError", player, track, payload);
593
598
  // remove the current track, and enqueue the next one
594
- await queueTrackEnd(player.queue, player.repeatMode === "queue");
599
+ await queueTrackEnd(player);
595
600
  // if no track available, end queue
596
601
  if (!player.queue.current)
597
602
  return this.queueEnd(player, track, payload);
@@ -55,18 +55,7 @@ export declare class NodeManager extends EventEmitter {
55
55
  nodes: MiniMap<string, LavalinkNode>;
56
56
  constructor(LavalinkManager: LavalinkManager);
57
57
  createNode(options: LavalinkNodeOptions): LavalinkNode;
58
- get leastUsedNodes(): LavalinkNode[];
59
- /** Returns the least used Nodes sorted by amount of calls. */
60
- private get leastUsedNodesCalls();
61
- /** Returns the least used Nodes sorted by amount of players. */
62
- private get leastUsedNodesPlayers();
63
- /** Returns the least used Nodes sorted by amount of memory usage. */
64
- private get leastUsedNodesMemory();
65
- /** Returns the least system load Nodes. */
66
- get leastLoadNodes(): LavalinkNode[];
67
- get leastLoadNodesMemory(): LavalinkNode[];
68
- /** Returns the least system load Nodes. */
69
- get leastLoadNodesCpu(): LavalinkNode[];
58
+ leastUsedNodes(sortType?: "memory" | "cpuLavalink" | "cpuSystem" | "calls" | "playingPlayers" | "players"): LavalinkNode[];
70
59
  deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
71
60
  }
72
61
  export {};
@@ -17,68 +17,61 @@ export class NodeManager extends EventEmitter {
17
17
  this.nodes.set(newNode.id, newNode);
18
18
  return newNode;
19
19
  }
20
- get leastUsedNodes() {
21
- if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "memory")
22
- return this.leastUsedNodesMemory;
23
- else if (this.LavalinkManager.options.defaultLeastUsedNodeSortType === "calls")
24
- return this.leastUsedNodesCalls;
25
- else
26
- return this.leastUsedNodesPlayers; // this.options.defaultLeastUsedNodeSortType === "players"
27
- }
28
- /** Returns the least used Nodes sorted by amount of calls. */
29
- get leastUsedNodesCalls() {
30
- return [...this.nodes.values()]
31
- .filter((node) => node.connected)
32
- .sort((a, b) => b.calls - a.calls); // client sided sorting
33
- }
34
- /** Returns the least used Nodes sorted by amount of players. */
35
- get leastUsedNodesPlayers() {
36
- return [...this.nodes.values()]
37
- .filter((node) => node.connected)
38
- .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
39
- }
40
- /** Returns the least used Nodes sorted by amount of memory usage. */
41
- get leastUsedNodesMemory() {
42
- return [...this.nodes.values()]
43
- .filter((node) => node.connected)
44
- .sort((a, b) => (b.stats?.memory?.used || 0) - (a.stats?.memory?.used || 0)); // sort after memory
45
- }
46
- /** Returns the least system load Nodes. */
47
- get leastLoadNodes() {
48
- if (this.LavalinkManager.options.defaultLeastLoadNodeSortType === "cpu")
49
- return this.leastLoadNodesCpu;
50
- else
51
- return this.leastLoadNodesMemory; // this.options.defaultLeastLoadNodeSortType === "memory"
52
- }
53
- get leastLoadNodesMemory() {
54
- return [...this.nodes.values()]
55
- .filter((node) => node.connected)
56
- .sort((a, b) => {
57
- const aload = a.stats.memory?.used
58
- ? a.stats.memory.used
59
- : 0;
60
- const bload = b.stats.memory?.used
61
- ? b.stats.memory.used
62
- : 0;
63
- return aload - bload;
64
- });
65
- }
66
- /** Returns the least system load Nodes. */
67
- get leastLoadNodesCpu() {
68
- return [...this.nodes.values()]
69
- .filter((node) => node.connected)
70
- .sort((a, b) => {
71
- const aload = a.stats.cpu
72
- ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100
73
- : 0;
74
- const bload = b.stats.cpu
75
- ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100
76
- : 0;
77
- return aload - bload;
78
- });
20
+ leastUsedNodes(sortType = "players") {
21
+ switch (sortType) {
22
+ case "memory":
23
+ {
24
+ return [...this.nodes.values()]
25
+ .filter((node) => node.connected)
26
+ .sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0)); // sort after memor
27
+ }
28
+ break;
29
+ case "cpuLavalink":
30
+ {
31
+ return [...this.nodes.values()]
32
+ .filter((node) => node.connected)
33
+ .sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)); // sort after memor
34
+ }
35
+ break;
36
+ case "cpuSystem":
37
+ {
38
+ return [...this.nodes.values()]
39
+ .filter((node) => node.connected)
40
+ .sort((a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)); // sort after memor
41
+ }
42
+ break;
43
+ case "calls":
44
+ {
45
+ return [...this.nodes.values()]
46
+ .filter((node) => node.connected)
47
+ .sort((a, b) => a.calls - b.calls); // client sided sorting
48
+ }
49
+ break;
50
+ case "playingPlayers":
51
+ {
52
+ return [...this.nodes.values()]
53
+ .filter((node) => node.connected)
54
+ .sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
55
+ }
56
+ break;
57
+ case "players":
58
+ {
59
+ return [...this.nodes.values()]
60
+ .filter((node) => node.connected)
61
+ .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
62
+ }
63
+ break;
64
+ default:
65
+ {
66
+ return [...this.nodes.values()]
67
+ .filter((node) => node.connected)
68
+ .sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
69
+ }
70
+ break;
71
+ }
79
72
  }
80
73
  deleteNode(node) {
81
- const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes[0];
74
+ const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
82
75
  if (!decodeNode)
83
76
  throw new Error("Node was not found");
84
77
  decodeNode.destroy(DestroyReasons.NodeDeleted);
@@ -110,7 +110,7 @@ export declare class Player {
110
110
  * Play the next track from the queue / a specific track, with playoptions for Lavalink
111
111
  * @param options
112
112
  */
113
- play(options?: Partial<PlayOptions>): Promise<void>;
113
+ play(options?: Partial<PlayOptions>): any;
114
114
  /**
115
115
  * Set the Volume for the Player
116
116
  * @param volume The Volume in percent
@@ -143,12 +143,12 @@ export declare class Player {
143
143
  * Set the Repeatmode of the Player
144
144
  * @param repeatMode
145
145
  */
146
- setRepeatMode(repeatMode: RepeatMode): Promise<void>;
146
+ setRepeatMode(repeatMode: RepeatMode): Promise<RepeatMode>;
147
147
  /**
148
148
  * Skip the current song, or a specific amount of songs
149
149
  * @param amount provide the index of the next track to skip to
150
150
  */
151
- skip(skipTo?: number): Promise<true | void>;
151
+ skip(skipTo?: number): Promise<any>;
152
152
  /**
153
153
  * Connects the Player to the Voice Channel
154
154
  * @returns
@@ -172,6 +172,7 @@ export declare class Player {
172
172
  /** Converts the Player including Queue to a Json state */
173
173
  toJSON(): {
174
174
  guildId: string;
175
+ options: PlayerOptions;
175
176
  voiceChannelId: string;
176
177
  textChannelId: string;
177
178
  position: number;
@@ -184,7 +185,6 @@ export declare class Player {
184
185
  createdTimeStamp: number;
185
186
  filters: {};
186
187
  equalizer: import("./Filters").EQBand[];
187
- queue: import("./Queue").StoredQueue;
188
188
  nodeId: string;
189
189
  };
190
190
  }
@@ -64,8 +64,10 @@ export class Player {
64
64
  this.voiceChannelId = this.options.voiceChannelId;
65
65
  this.textChannelId = this.options.textChannelId || null;
66
66
  this.node = typeof this.options.node === "string" ? this.LavalinkManager.nodeManager.nodes.get(this.options.node) : this.options.node;
67
- if (!this.node || typeof this.node?.request !== "function")
68
- this.node = this.LavalinkManager.nodeManager.leastUsedNodes.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || this.LavalinkManager.nodeManager.leastUsedNodes[0] || null;
67
+ if (!this.node || typeof this.node.request !== "function") {
68
+ const least = this.LavalinkManager.nodeManager.leastUsedNodes();
69
+ this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
70
+ }
69
71
  if (!this.node)
70
72
  throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
71
73
  if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
@@ -120,10 +122,22 @@ export class Player {
120
122
  }
121
123
  if (options?.track && this.LavalinkManager.utils.isTrack(options?.track)) {
122
124
  await this.queue.add(options?.track, 0);
123
- await queueTrackEnd(this.queue, this.repeatMode === "queue");
125
+ await queueTrackEnd(this);
124
126
  }
125
127
  if (!this.queue.current && this.queue.tracks.length)
126
- await queueTrackEnd(this.queue, this.repeatMode === "queue");
128
+ await queueTrackEnd(this);
129
+ // @ts-ignore
130
+ if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
131
+ try {
132
+ this.queue.current = await this.LavalinkManager.utils.getClosestTrack({ ...(this.queue.current || {}) }, this);
133
+ }
134
+ catch (error) {
135
+ this.LavalinkManager.emit("trackError", this, this.queue.current, error);
136
+ if (this.queue.tracks[0])
137
+ return this.play();
138
+ return;
139
+ }
140
+ }
127
141
  const track = this.queue.current;
128
142
  if (!track)
129
143
  throw new Error(`There is no Track in the Queue, nor provided in the PlayOptions`);
@@ -274,8 +288,7 @@ export class Player {
274
288
  async setRepeatMode(repeatMode) {
275
289
  if (!["off", "track", "queue"].includes(repeatMode))
276
290
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
277
- this.repeatMode = repeatMode;
278
- return;
291
+ return this.repeatMode = repeatMode;
279
292
  }
280
293
  /**
281
294
  * Skip the current song, or a specific amount of songs
@@ -375,6 +388,7 @@ export class Player {
375
388
  toJSON() {
376
389
  return {
377
390
  guildId: this.guildId,
391
+ options: this.options,
378
392
  voiceChannelId: this.voiceChannelId,
379
393
  textChannelId: this.textChannelId,
380
394
  position: this.position,
@@ -387,7 +401,6 @@ export class Player {
387
401
  createdTimeStamp: this.createdTimeStamp,
388
402
  filters: this.filterManager?.data || {},
389
403
  equalizer: this.filterManager?.equalizerBands || [],
390
- queue: this.queue?.utils?.getStored?.() || { current: null, tracks: [], previous: [] },
391
404
  nodeId: this.node?.id,
392
405
  };
393
406
  }
@@ -1,4 +1,4 @@
1
- import { Track } from "./Track";
1
+ import { Track, UnresolvedTrack } from "./Track";
2
2
  export interface StoredQueue {
3
3
  current: Track | null;
4
4
  previous: Track[];
@@ -45,23 +45,23 @@ export declare class DefaultQueueStore {
45
45
  }
46
46
  export declare class QueueChangesWatcher {
47
47
  constructor();
48
- tracksAdd(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
49
- tracksRemoved(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
48
+ tracksAdd(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
49
+ tracksRemoved(guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
50
50
  shuffled(guildId: string, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
51
51
  }
52
52
  export declare class Queue {
53
- readonly tracks: Track[];
53
+ readonly tracks: (Track | UnresolvedTrack)[];
54
54
  readonly previous: Track[];
55
55
  current: Track | null;
56
56
  options: {
57
57
  maxPreviousTracks: number;
58
58
  };
59
59
  private readonly guildId;
60
- protected readonly QueueSaver: QueueSaver | null;
61
- static readonly StaticSymbol: Symbol;
60
+ private readonly QueueSaver;
62
61
  private managerUtils;
63
62
  private queueChanges;
64
63
  constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
64
+ private applyData;
65
65
  /**
66
66
  * Utils for a Queue
67
67
  */
@@ -79,7 +79,7 @@ export declare class Queue {
79
79
  /**
80
80
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
81
81
  */
82
- getStored: () => StoredQueue;
82
+ toJSON: () => StoredQueue;
83
83
  /**
84
84
  * Get the Total Duration of the Queue-Songs summed up
85
85
  * @returns {number}
@@ -97,7 +97,7 @@ export declare class Queue {
97
97
  * @param {number} index At what position to add the Track
98
98
  * @returns {number} Queue-Size (for the next Tracks)
99
99
  */
100
- add(TrackOrTracks: Track | Track[], index?: number): any;
100
+ add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): any;
101
101
  /**
102
102
  * Splice the tracks in the Queue
103
103
  * @param {number} index Where to remove the Track
@@ -105,5 +105,5 @@ export declare class Queue {
105
105
  * @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
106
106
  * @returns {Track} Spliced Track
107
107
  */
108
- splice(index: number, amount: number, TrackOrTracks?: Track | Track[]): any;
108
+ splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): any;
109
109
  }
@@ -1,4 +1,4 @@
1
- import { ManagerUitls, QueueSymbol } from "./Utils";
1
+ import { ManagerUitls } from "./Utils";
2
2
  export class QueueSaver {
3
3
  constructor(options) {
4
4
  this._ = options.queueStore || new DefaultQueueStore();
@@ -59,7 +59,6 @@ export class Queue {
59
59
  options = { maxPreviousTracks: 25 };
60
60
  guildId = "";
61
61
  QueueSaver = null;
62
- static StaticSymbol = QueueSymbol;
63
62
  managerUtils = new ManagerUitls();
64
63
  queueChanges;
65
64
  constructor(guildId, data = {}, QueueSaver, queueOptions) {
@@ -68,8 +67,10 @@ export class Queue {
68
67
  this.QueueSaver = QueueSaver;
69
68
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
70
69
  this.current = this.managerUtils.isTrack(data.current) ? data.current : null;
71
- this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track)) : [];
72
- this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track)) : [];
70
+ this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
71
+ this.tracks = Array.isArray(data.tracks) && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) ? data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)) : [];
72
+ }
73
+ applyData(data) {
73
74
  }
74
75
  /**
75
76
  * Utils for a Queue
@@ -81,7 +82,7 @@ export class Queue {
81
82
  save: async () => {
82
83
  if (this.previous.length > this.options.maxPreviousTracks)
83
84
  this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
84
- return await this.QueueSaver.set(this.guildId, this.utils.getStored());
85
+ return await this.QueueSaver.set(this.guildId, this.utils.toJSON());
85
86
  },
86
87
  /**
87
88
  * Sync the current queue database/server with the cached one
@@ -91,12 +92,12 @@ export class Queue {
91
92
  const data = await this.QueueSaver.get(this.guildId);
92
93
  if (!data)
93
94
  return console.log("No data found to sync for guildId: ", this.guildId);
94
- if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current))
95
+ if (!dontSyncCurrent && !this.current && (this.managerUtils.isTrack(data.current)))
95
96
  this.current = data.current;
96
- if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track)))
97
- this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track)));
98
- if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track)))
99
- this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track)));
97
+ if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
98
+ this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
99
+ if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)))
100
+ this.previous.splice(0, override ? this.tracks.length : 0, ...data.previous.filter(track => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)));
100
101
  await this.utils.save();
101
102
  return;
102
103
  },
@@ -106,13 +107,13 @@ export class Queue {
106
107
  /**
107
108
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
108
109
  */
109
- getStored: () => {
110
+ toJSON: () => {
110
111
  if (this.previous.length > this.options.maxPreviousTracks)
111
112
  this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
112
113
  return {
113
- current: this.current,
114
- previous: this.previous,
115
- tracks: this.tracks,
114
+ current: this.current ? { ...this.current } : null,
115
+ previous: this.previous ? [...this.previous] : [],
116
+ tracks: this.tracks ? [...this.tracks] : [],
116
117
  };
117
118
  },
118
119
  /**
@@ -128,7 +129,7 @@ export class Queue {
128
129
  * @returns Amount of Tracks in the Queue
129
130
  */
130
131
  async shuffle() {
131
- const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.getStored() : null;
132
+ const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.toJSON() : null;
132
133
  if (this.tracks.length <= 1)
133
134
  return this.tracks.length;
134
135
  // swap #1 and #2 if only 2 tracks.
@@ -143,7 +144,7 @@ export class Queue {
143
144
  }
144
145
  // LOG
145
146
  if (typeof this.queueChanges?.shuffled === "function")
146
- this.queueChanges.shuffled(this.guildId, oldStored, this.utils.getStored());
147
+ this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
147
148
  await this.utils.save();
148
149
  return this.tracks.length;
149
150
  }
@@ -155,14 +156,14 @@ export class Queue {
155
156
  */
156
157
  async add(TrackOrTracks, index) {
157
158
  if (typeof index === "number" && index >= 0 && index < this.tracks.length)
158
- return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
159
- const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.getStored() : null;
159
+ return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
160
+ const oldStored = typeof this.queueChanges?.tracksAdd === "function" ? this.utils.toJSON() : null;
160
161
  // add the track(s)
161
- this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
162
+ this.tracks.push(...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)));
162
163
  // log if available
163
164
  if (typeof this.queueChanges?.tracksAdd === "function")
164
165
  try {
165
- this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), this.tracks.length, oldStored, this.utils.getStored());
166
+ this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), this.tracks.length, oldStored, this.utils.toJSON());
166
167
  }
167
168
  catch (e) { /* */ }
168
169
  // save the queue
@@ -178,7 +179,7 @@ export class Queue {
178
179
  * @returns {Track} Spliced Track
179
180
  */
180
181
  async splice(index, amount, TrackOrTracks) {
181
- const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.getStored() : null;
182
+ const oldStored = typeof this.queueChanges?.tracksAdd === "function" || typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null;
182
183
  // if no tracks to splice, add the tracks
183
184
  if (!this.tracks.length) {
184
185
  if (TrackOrTracks)
@@ -188,17 +189,17 @@ export class Queue {
188
189
  // Log if available
189
190
  if ((TrackOrTracks) && typeof this.queueChanges?.tracksAdd === "function")
190
191
  try {
191
- this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)), index, oldStored, this.utils.getStored());
192
+ this.queueChanges.tracksAdd(this.guildId, (Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v)), index, oldStored, this.utils.toJSON());
192
193
  }
193
194
  catch (e) { /* */ }
194
195
  // remove the tracks (and add the new ones)
195
- let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v))) : this.tracks.splice(index, amount);
196
+ let spliced = TrackOrTracks ? this.tracks.splice(index, amount, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v) || this.managerUtils.isUnresolvedTrack(v))) : this.tracks.splice(index, amount);
196
197
  // get the spliced array
197
198
  spliced = (Array.isArray(spliced) ? spliced : [spliced]);
198
199
  // Log if available
199
200
  if (typeof this.queueChanges?.tracksRemoved === "function")
200
201
  try {
201
- this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.getStored());
202
+ this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
202
203
  }
203
204
  catch (e) { /* */ }
204
205
  // save the queue