lavalink-client 1.0.3 → 1.0.5

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 (32) hide show
  1. package/README.md +32 -98
  2. package/dist/cjs/structures/LavalinkManager.d.ts +17 -15
  3. package/dist/cjs/structures/LavalinkManager.js +66 -16
  4. package/dist/cjs/structures/Node.js +16 -13
  5. package/dist/cjs/structures/NodeManager.d.ts +1 -1
  6. package/dist/cjs/structures/NodeManager.js +55 -5
  7. package/dist/cjs/structures/Player.d.ts +4 -4
  8. package/dist/cjs/structures/Player.js +22 -7
  9. package/dist/cjs/structures/Queue.d.ts +13 -11
  10. package/dist/cjs/structures/Queue.js +31 -28
  11. package/dist/cjs/structures/Track.d.ts +14 -3
  12. package/dist/cjs/structures/Utils.d.ts +34 -7
  13. package/dist/cjs/structures/Utils.js +136 -13
  14. package/dist/esm/structures/LavalinkManager.d.ts +17 -15
  15. package/dist/esm/structures/LavalinkManager.js +66 -16
  16. package/dist/esm/structures/Node.js +16 -13
  17. package/dist/esm/structures/NodeManager.d.ts +1 -1
  18. package/dist/esm/structures/NodeManager.js +55 -5
  19. package/dist/esm/structures/Player.d.ts +4 -4
  20. package/dist/esm/structures/Player.js +22 -7
  21. package/dist/esm/structures/Queue.d.ts +13 -11
  22. package/dist/esm/structures/Queue.js +32 -29
  23. package/dist/esm/structures/Track.d.ts +14 -3
  24. package/dist/esm/structures/Utils.d.ts +34 -7
  25. package/dist/esm/structures/Utils.js +136 -13
  26. package/dist/types/structures/LavalinkManager.d.ts +17 -15
  27. package/dist/types/structures/NodeManager.d.ts +1 -1
  28. package/dist/types/structures/Player.d.ts +4 -4
  29. package/dist/types/structures/Queue.d.ts +13 -11
  30. package/dist/types/structures/Track.d.ts +14 -3
  31. package/dist/types/structures/Utils.d.ts +34 -7
  32. package/package.json +1 -1
@@ -1,8 +1,10 @@
1
- import { ManagerUitls, QueueSymbol } from "./Utils";
1
+ import { ManagerUitls } from "./Utils";
2
2
  export class QueueSaver {
3
- constructor(storeManager, options) {
4
- this._ = storeManager;
5
- this.options = options;
3
+ constructor(options) {
4
+ this._ = options.queueStore || new DefaultQueueStore();
5
+ this.options = {
6
+ maxPreviousTracks: options.maxPreviousTracks
7
+ };
6
8
  }
7
9
  async get(guildId) {
8
10
  return await this._.parse(await this._.get(guildId));
@@ -57,17 +59,18 @@ export class Queue {
57
59
  options = { maxPreviousTracks: 25 };
58
60
  guildId = "";
59
61
  QueueSaver = null;
60
- static StaticSymbol = QueueSymbol;
61
62
  managerUtils = new ManagerUitls();
62
63
  queueChanges;
63
- constructor(guildId, data = {}, QueueSaver, queueChangesWatcher) {
64
- this.queueChanges = queueChangesWatcher || null;
64
+ constructor(guildId, data = {}, QueueSaver, queueOptions) {
65
+ this.queueChanges = queueOptions.queueChangesWatcher || null;
65
66
  this.guildId = guildId;
66
67
  this.QueueSaver = QueueSaver;
67
68
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
68
69
  this.current = this.managerUtils.isTrack(data.current) ? data.current : null;
69
- this.previous = Array.isArray(data.previous) && data.previous.some(track => this.managerUtils.isTrack(track)) ? data.previous.filter(track => this.managerUtils.isTrack(track)) : [];
70
- 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) {
71
74
  }
72
75
  /**
73
76
  * Utils for a Queue
@@ -79,7 +82,7 @@ export class Queue {
79
82
  save: async () => {
80
83
  if (this.previous.length > this.options.maxPreviousTracks)
81
84
  this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
82
- return await this.QueueSaver.set(this.guildId, this.utils.getStored());
85
+ return await this.QueueSaver.set(this.guildId, this.utils.toJSON());
83
86
  },
84
87
  /**
85
88
  * Sync the current queue database/server with the cached one
@@ -89,12 +92,12 @@ export class Queue {
89
92
  const data = await this.QueueSaver.get(this.guildId);
90
93
  if (!data)
91
94
  return console.log("No data found to sync for guildId: ", this.guildId);
92
- if (!dontSyncCurrent && !this.current && this.managerUtils.isTrack(data.current))
95
+ if (!dontSyncCurrent && !this.current && (this.managerUtils.isTrack(data.current)))
93
96
  this.current = data.current;
94
- if (Array.isArray(data.tracks) && data?.tracks.length && data.tracks.some(track => this.managerUtils.isTrack(track)))
95
- this.tracks.splice(override ? 0 : this.tracks.length, override ? this.tracks.length : 0, ...data.tracks.filter(track => this.managerUtils.isTrack(track)));
96
- if (Array.isArray(data.previous) && data?.previous.length && data.previous.some(track => this.managerUtils.isTrack(track)))
97
- 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)));
98
101
  await this.utils.save();
99
102
  return;
100
103
  },
@@ -104,13 +107,13 @@ export class Queue {
104
107
  /**
105
108
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
106
109
  */
107
- getStored: () => {
110
+ toJSON: () => {
108
111
  if (this.previous.length > this.options.maxPreviousTracks)
109
112
  this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
110
113
  return {
111
- current: this.current,
112
- previous: this.previous,
113
- tracks: this.tracks,
114
+ current: this.current ? { ...this.current } : null,
115
+ previous: this.previous ? [...this.previous] : [],
116
+ tracks: this.tracks ? [...this.tracks] : [],
114
117
  };
115
118
  },
116
119
  /**
@@ -126,7 +129,7 @@ export class Queue {
126
129
  * @returns Amount of Tracks in the Queue
127
130
  */
128
131
  async shuffle() {
129
- const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.getStored() : null;
132
+ const oldStored = typeof this.queueChanges?.shuffled === "function" ? this.utils.toJSON() : null;
130
133
  if (this.tracks.length <= 1)
131
134
  return this.tracks.length;
132
135
  // swap #1 and #2 if only 2 tracks.
@@ -141,7 +144,7 @@ export class Queue {
141
144
  }
142
145
  // LOG
143
146
  if (typeof this.queueChanges?.shuffled === "function")
144
- this.queueChanges.shuffled(this.guildId, oldStored, this.utils.getStored());
147
+ this.queueChanges.shuffled(this.guildId, oldStored, this.utils.toJSON());
145
148
  await this.utils.save();
146
149
  return this.tracks.length;
147
150
  }
@@ -153,14 +156,14 @@ export class Queue {
153
156
  */
154
157
  async add(TrackOrTracks, index) {
155
158
  if (typeof index === "number" && index >= 0 && index < this.tracks.length)
156
- return await this.splice(index, 0, ...(Array.isArray(TrackOrTracks) ? TrackOrTracks : [TrackOrTracks]).filter(v => this.managerUtils.isTrack(v)));
157
- 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;
158
161
  // add the track(s)
159
- 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)));
160
163
  // log if available
161
164
  if (typeof this.queueChanges?.tracksAdd === "function")
162
165
  try {
163
- 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());
164
167
  }
165
168
  catch (e) { /* */ }
166
169
  // save the queue
@@ -176,7 +179,7 @@ export class Queue {
176
179
  * @returns {Track} Spliced Track
177
180
  */
178
181
  async splice(index, amount, TrackOrTracks) {
179
- 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;
180
183
  // if no tracks to splice, add the tracks
181
184
  if (!this.tracks.length) {
182
185
  if (TrackOrTracks)
@@ -186,17 +189,17 @@ export class Queue {
186
189
  // Log if available
187
190
  if ((TrackOrTracks) && typeof this.queueChanges?.tracksAdd === "function")
188
191
  try {
189
- 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());
190
193
  }
191
194
  catch (e) { /* */ }
192
195
  // remove the tracks (and add the new ones)
193
- 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);
194
197
  // get the spliced array
195
198
  spliced = (Array.isArray(spliced) ? spliced : [spliced]);
196
199
  // Log if available
197
200
  if (typeof this.queueChanges?.tracksRemoved === "function")
198
201
  try {
199
- this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.getStored());
202
+ this.queueChanges.tracksRemoved(this.guildId, spliced, index, oldStored, this.utils.toJSON());
200
203
  }
201
204
  catch (e) { /* */ }
202
205
  // save the queue
@@ -1,3 +1,4 @@
1
+ import { Player } from "./Player";
1
2
  import { Base64 } from "./Utils";
2
3
  type LavalinkSourceNames = "youtube" | "youtubemusic" | "soundcloud" | "bandcamp" | "twitch";
3
4
  type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts";
@@ -44,11 +45,21 @@ export interface Track extends LavalinkTrack {
44
45
  /** The Track's Requester */
45
46
  requester?: unknown;
46
47
  }
47
- export interface UnresolvedQuery {
48
+ export interface UnresolvedTrackInfo extends Partial<TrackInfo> {
49
+ /** Required */
50
+ title: string;
51
+ }
52
+ export interface UnresolvedQuery extends UnresolvedTrackInfo {
48
53
  /** The base64 of the unresolved track to "encode" */
49
54
  encoded?: Base64;
50
- /** Search for the closest track possible, by providing as much information as you can! */
51
- info?: Partial<TrackInfo>;
55
+ }
56
+ export interface UnresolvedTrack {
57
+ /** Required */
58
+ resolve: (player: Player) => Promise<void>;
59
+ /** The Base 64 encoded String */
60
+ encoded?: Base64;
61
+ /** Track Information */
62
+ info: UnresolvedTrackInfo;
52
63
  /** The Track's Requester */
53
64
  requester?: unknown;
54
65
  }
@@ -1,9 +1,8 @@
1
1
  import { LavalinkFilterData } from "./Filters";
2
2
  import { LavalinkManager } from "./LavalinkManager";
3
- import { LavalinkNode, NodeStats } from "./Node";
4
- import { PlayOptions } from "./Player";
5
- import { Queue } from "./Queue";
6
- import { PluginInfo, Track } from "./Track";
3
+ import { LavalinkNode, LavalinkNodeOptions, NodeStats } from "./Node";
4
+ import { PlayOptions, Player } from "./Player";
5
+ import { PluginInfo, Track, UnresolvedTrack, UnresolvedQuery } from "./Track";
7
6
  export declare const TrackSymbol: unique symbol;
8
7
  export declare const UnresolvedTrackSymbol: unique symbol;
9
8
  export declare const QueueSymbol: unique symbol;
@@ -40,12 +39,39 @@ export interface ManagerUitls {
40
39
  export declare class ManagerUitls {
41
40
  constructor(LavalinkManager?: LavalinkManager);
42
41
  buildTrack(data: any, requester: any): Track;
42
+ /**
43
+ * Validate if a data is equal to a node
44
+ * @param data
45
+ */
46
+ isNode(data: LavalinkNode): boolean;
47
+ /**
48
+ * Validate if a data is equal to node options
49
+ * @param data
50
+ */
51
+ isNodeOptions(data: LavalinkNodeOptions | any): boolean;
43
52
  /**
44
53
  * Validate if a data is euqal to a track
45
- * @param {Track|any} data the Track to validate
46
- * @returns {boolean}
54
+ * @param data the Track to validate
55
+ * @returns
47
56
  */
48
57
  isTrack(data: Track | any): boolean;
58
+ /**
59
+ * Checks if the provided argument is a valid UnresolvedTrack.
60
+ * @param track
61
+ */
62
+ isUnresolvedTrack(data: UnresolvedTrack | any): boolean;
63
+ /**
64
+ * Checks if the provided argument is a valid UnresolvedTrack.
65
+ * @param track
66
+ */
67
+ isUnresolvedTrackQuery(data: UnresolvedTrack | any): boolean;
68
+ getClosestTrack(data: UnresolvedTrack, player: Player): Promise<Track>;
69
+ /**
70
+ * Builds a UnresolvedTrack to be resolved before being played .
71
+ * @param query
72
+ * @param requester
73
+ */
74
+ buildUnresolvedTrack(query: UnresolvedQuery | UnresolvedTrack, requester: unknown): UnresolvedTrack;
49
75
  validatedQuery(queryString: string, node: LavalinkNode): void;
50
76
  }
51
77
  /**
@@ -85,6 +111,7 @@ export declare class MiniMap<K, V> extends Map<K, V> {
85
111
  filter<This, K2 extends K>(fn: (this: This, value: V, key: K, miniMap: this) => key is K2, thisArg: This): MiniMap<K2, V>;
86
112
  filter<This, V2 extends V>(fn: (this: This, value: V, key: K, miniMap: this) => value is V2, thisArg: This): MiniMap<K, V2>;
87
113
  filter<This>(fn: (this: This, value: V, key: K, miniMap: this) => boolean, thisArg: This): MiniMap<K, V>;
114
+ toJSON(): V[];
88
115
  /**
89
116
  * Maps each item to another value into an array. Identical in behavior to
90
117
  * [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
@@ -254,5 +281,5 @@ export interface NodeMessage extends NodeStats {
254
281
  op: "stats" | "playerUpdate" | "event";
255
282
  guildId: string;
256
283
  }
257
- export declare function queueTrackEnd(queue: Queue, addBackToQueue?: boolean): Promise<Track>;
284
+ export declare function queueTrackEnd(player: Player): Promise<Track>;
258
285
  export {};
@@ -38,14 +38,103 @@ export class ManagerUitls {
38
38
  throw new RangeError(`Argument "data" is not a valid track: ${error.message}`);
39
39
  }
40
40
  }
41
+ /**
42
+ * Validate if a data is equal to a node
43
+ * @param data
44
+ */
45
+ isNode(data) {
46
+ if (!data)
47
+ return false;
48
+ const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(data));
49
+ if (!keys.includes("constructor"))
50
+ return false;
51
+ if (!keys.length)
52
+ return false;
53
+ // all required functions
54
+ if (!["connect", "destroy", "destroyPlayer", "fetchAllPlayers", "fetchInfo", "fetchPlayer", "fetchStats", "fetchVersion", "request", "updatePlayer", "updateSession"].every(v => keys.includes(v)))
55
+ return false;
56
+ return true;
57
+ }
58
+ /**
59
+ * Validate if a data is equal to node options
60
+ * @param data
61
+ */
62
+ isNodeOptions(data) {
63
+ if (!data || typeof data !== "object" || Array.isArray(data))
64
+ return false;
65
+ if (typeof data.host !== "string" || !data.host.length)
66
+ return false;
67
+ if (typeof data.port !== "number" || isNaN(data.port) || data.port < 0 || data.port > 65535)
68
+ return false;
69
+ if (typeof data.authorization !== "string" || !data.authorization.length)
70
+ return false;
71
+ if ("secure" in data && typeof data.secure !== "boolean")
72
+ return false;
73
+ if ("sessionId" in data && typeof data.sessionId !== "string")
74
+ return false;
75
+ if ("id" in data && typeof data.id !== "string")
76
+ return false;
77
+ if ("regions" in data && (!Array.isArray(data.regions) || !data.regions.every(v => typeof v === "string")))
78
+ return false;
79
+ if ("poolOptions" in data && typeof data.poolOptions !== "object")
80
+ return false;
81
+ if ("retryAmount" in data && (typeof data.retryAmount !== "number" || isNaN(data.retryAmount) || data.retryAmount <= 0))
82
+ return false;
83
+ if ("retryDelay" in data && (typeof data.retryDelay !== "number" || isNaN(data.retryDelay) || data.retryDelay <= 0))
84
+ return false;
85
+ if ("requestTimeout" in data && (typeof data.requestTimeout !== "number" || isNaN(data.requestTimeout) || data.requestTimeout <= 0))
86
+ return false;
87
+ return true;
88
+ }
41
89
  /**
42
90
  * Validate if a data is euqal to a track
43
- * @param {Track|any} data the Track to validate
44
- * @returns {boolean}
91
+ * @param data the Track to validate
92
+ * @returns
45
93
  */
46
94
  isTrack(data) {
47
95
  return typeof data?.encoded === "string" && typeof data?.info === "object";
48
96
  }
97
+ /**
98
+ * Checks if the provided argument is a valid UnresolvedTrack.
99
+ * @param track
100
+ */
101
+ isUnresolvedTrack(data) {
102
+ return typeof data === "object" && "info" in data && typeof data.info.title === "string" && typeof data.resolve === "function";
103
+ }
104
+ /**
105
+ * Checks if the provided argument is a valid UnresolvedTrack.
106
+ * @param track
107
+ */
108
+ isUnresolvedTrackQuery(data) {
109
+ return typeof data === "object" && !("info" in data) && typeof data.title === "string";
110
+ }
111
+ async getClosestTrack(data, player) {
112
+ return getClosestTrack(data, player, this);
113
+ }
114
+ /**
115
+ * Builds a UnresolvedTrack to be resolved before being played .
116
+ * @param query
117
+ * @param requester
118
+ */
119
+ buildUnresolvedTrack(query, requester) {
120
+ if (typeof query === "undefined")
121
+ throw new RangeError('Argument "query" must be present.');
122
+ const unresolvedTrack = {
123
+ encoded: query.encoded || undefined,
124
+ info: query.info ?? query,
125
+ requester: typeof this.manager.options?.playerOptions?.requesterTransformer === "function" ? this.manager.options?.playerOptions?.requesterTransformer((query?.requester || requester)) : requester,
126
+ async resolve(player) {
127
+ const closest = await getClosestTrack(this, player, player.LavalinkManager.utils);
128
+ if (!closest)
129
+ throw new SyntaxError("No closest Track found");
130
+ Object.getOwnPropertyNames(this).forEach(prop => delete this[prop]);
131
+ Object.assign(this, closest);
132
+ return;
133
+ }
134
+ };
135
+ Object.defineProperty(unresolvedTrack, UnresolvedTrackSymbol, { configurable: true, value: true });
136
+ return unresolvedTrack;
137
+ }
49
138
  validatedQuery(queryString, node) {
50
139
  if (!node.info)
51
140
  throw new Error("No Lavalink Node was provided");
@@ -148,6 +237,10 @@ export class MiniMap extends Map {
148
237
  }
149
238
  return results;
150
239
  }
240
+ toJSON() {
241
+ // toJSON is called recursively by JSON.stringify.
242
+ return [...this.values()];
243
+ }
151
244
  map(fn, thisArg) {
152
245
  if (typeof thisArg !== 'undefined')
153
246
  fn = fn.bind(thisArg);
@@ -159,19 +252,49 @@ export class MiniMap extends Map {
159
252
  });
160
253
  }
161
254
  }
162
- export async function queueTrackEnd(queue, addBackToQueue = false) {
163
- if (queue.current) { // if there was a current Track -> Add it
164
- queue.previous.unshift(queue.current);
165
- if (queue.previous.length > queue.options.maxPreviousTracks)
166
- queue.previous.splice(queue.options.maxPreviousTracks, queue.previous.length);
255
+ export async function queueTrackEnd(player) {
256
+ if (player.queue.current) { // if there was a current Track -> Add it
257
+ player.queue.previous.unshift(player.queue.current);
258
+ if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
259
+ player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length);
167
260
  }
168
- // change the current Track to the next upcoming one
169
- queue.current = queue.tracks.shift() || null;
170
261
  // and if repeatMode == queue, add it back to the queue!
171
- if (addBackToQueue && queue.current)
172
- queue.tracks.push(queue.current);
262
+ if (player.repeatMode === "queue" && player.queue.current)
263
+ player.queue.tracks.push(player.queue.current);
264
+ // change the current Track to the next upcoming one
265
+ const nextSong = player.queue.tracks.shift();
266
+ if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
267
+ await nextSong.resolve(player);
268
+ player.queue.current = nextSong || null;
173
269
  // save it in the DB
174
- await queue.utils.save();
270
+ await player.queue.utils.save();
175
271
  // return the new current Track
176
- return queue.current;
272
+ return player.queue.current;
273
+ }
274
+ async function getClosestTrack(data, player, utils) {
275
+ if (!player || !player.node)
276
+ throw new RangeError("No player with a lavalink node was provided");
277
+ if (utils.isTrack(data))
278
+ return utils.buildTrack(data, data.requester);
279
+ if (!utils.isUnresolvedTrack(data))
280
+ throw new RangeError("Track is not an unresolved Track");
281
+ if (!data?.info?.title)
282
+ throw new SyntaxError("the track title is required for unresolved tracks");
283
+ if (!data.requester)
284
+ throw new SyntaxError("The requester is required");
285
+ if (typeof data.encoded === "string") {
286
+ const r = await player.node.decode.singleTrack(data.encoded);
287
+ if (r)
288
+ return utils.buildTrack(r, data.requester);
289
+ }
290
+ if (typeof data.info.uri === "string") {
291
+ const r = await player.search({ query: data?.info?.uri }, data.requester).then(v => v.tracks[0]);
292
+ if (r)
293
+ return r;
294
+ }
295
+ const query = [data.info?.title, data.info?.author].filter(str => !!str).join(" by ");
296
+ const sourceName = data.info?.sourceName;
297
+ return await player.search({
298
+ query, source: sourceName !== "bandcamp" && sourceName !== "twitch" && sourceName !== "flowery-tts" ? sourceName : player.LavalinkManager.options?.playerOptions?.defaultSearchPlatform,
299
+ }, data.requester).then(v => v.tracks[0]);
177
300
  }
@@ -1,17 +1,16 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from "events";
3
3
  import { NodeManager } from "./NodeManager";
4
- import { QueueChangesWatcher, QueueSaverOptions, StoreManager } from "./Queue";
4
+ import { QueueSaverOptions } from "./Queue";
5
5
  import { GuildShardPayload, LavalinkSearchPlatform, ManagerUitls, MiniMap, SearchPlatform, TrackEndEvent, TrackExceptionEvent, TrackStartEvent, TrackStuckEvent, VoicePacket, VoiceServer, VoiceState, WebSocketClosedEvent } from "./Utils";
6
6
  import { LavalinkNodeOptions } from "./Node";
7
7
  import { DestroyReasonsType, Player, PlayerOptions } from "./Player";
8
- import { Track } from "./Track";
8
+ import { Track, UnresolvedTrack } from "./Track";
9
9
  export interface LavalinkManager {
10
10
  nodeManager: NodeManager;
11
11
  utils: ManagerUitls;
12
12
  }
13
13
  export interface BotClientOptions {
14
- shards?: number | number[] | "auto";
15
14
  id: string;
16
15
  username?: string;
17
16
  /** So users can pass entire objects / classes */
@@ -44,8 +43,6 @@ export interface LavalinkPlayerOptions {
44
43
  export interface ManagerOptions {
45
44
  nodes: LavalinkNodeOptions[];
46
45
  queueOptions?: QueueSaverOptions;
47
- queueStore?: StoreManager;
48
- queueChangesWatcher?: QueueChangesWatcher;
49
46
  client?: BotClientOptions;
50
47
  playerOptions?: LavalinkPlayerOptions;
51
48
  autoSkip?: boolean;
@@ -55,32 +52,32 @@ export interface ManagerOptions {
55
52
  interface LavalinkManagerEvents {
56
53
  /**
57
54
  * Emitted when a Track started playing.
58
- * @event Manager.playerManager#trackStart
55
+ * @event Manager#trackStart
59
56
  */
60
57
  "trackStart": (player: Player, track: Track, payload: TrackStartEvent) => void;
61
58
  /**
62
59
  * Emitted when a Track finished.
63
- * @event Manager.playerManager#trackEnd
60
+ * @event Manager#trackEnd
64
61
  */
65
62
  "trackEnd": (player: Player, track: Track, payload: TrackEndEvent) => void;
66
63
  /**
67
64
  * Emitted when a Track got stuck while playing.
68
- * @event Manager.playerManager#trackStuck
65
+ * @event Manager#trackStuck
69
66
  */
70
67
  "trackStuck": (player: Player, track: Track, payload: TrackStuckEvent) => void;
71
68
  /**
72
69
  * Emitted when a Track errored.
73
- * @event Manager.playerManager#trackError
70
+ * @event Manager#trackError
74
71
  */
75
- "trackError": (player: Player, track: Track, payload: TrackExceptionEvent) => void;
72
+ "trackError": (player: Player, track: Track | UnresolvedTrack, payload: TrackExceptionEvent) => void;
76
73
  /**
77
74
  * Emitted when the Playing finished and no more tracks in the queue.
78
- * @event Manager.playerManager#queueEnd
75
+ * @event Manager#queueEnd
79
76
  */
80
77
  "queueEnd": (player: Player, track: Track, payload: TrackEndEvent | TrackStuckEvent | TrackExceptionEvent) => void;
81
78
  /**
82
79
  * Emitted when a Player is created.
83
- * @event Manager.playerManager#create
80
+ * @event Manager#playerCreate
84
81
  */
85
82
  "playerCreate": (player: Player) => void;
86
83
  /**
@@ -90,19 +87,24 @@ interface LavalinkManagerEvents {
90
87
  "playerMove": (player: Player, oldVoiceChannelId: string, newVoiceChannelId: string) => void;
91
88
  /**
92
89
  * Emitted when a Player is disconnected from a channel.
93
- * @event Manager.playerManager#disconnect
90
+ * @event Manager#playerDisconnect
94
91
  */
95
92
  "playerDisconnect": (player: Player, voiceChannelId: string) => void;
96
93
  /**
97
94
  * Emitted when a Node-Socket got closed for a specific Player.
98
- * @event Manager.playerManager#socketClosed
95
+ * @event Manager#playerSocketClosed
99
96
  */
100
97
  "playerSocketClosed": (player: Player, payload: WebSocketClosedEvent) => void;
101
98
  /**
102
99
  * Emitted when a Player get's destroyed
103
- * @event Manager.playerManager#destroy
100
+ * @event Manager#playerDestroy
104
101
  */
105
102
  "playerDestroy": (player: Player, destroyReason?: DestroyReasonsType) => void;
103
+ /**
104
+ * Always emits when the player (on lavalink side) got updated
105
+ * @event Manager#playerUpdate
106
+ */
107
+ "playerUpdate": (player: Player) => void;
106
108
  }
107
109
  export interface LavalinkManager {
108
110
  options: ManagerOptions;
@@ -55,7 +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[];
58
+ leastUsedNodes(sortType?: "memory" | "cpuLavalink" | "cpuSystem" | "calls" | "playingPlayers" | "players"): LavalinkNode[];
59
59
  deleteNode(node: LavalinkNodeIdentifier | LavalinkNode): void;
60
60
  }
61
61
  export {};
@@ -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
  }
@@ -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[];
@@ -18,6 +18,8 @@ export interface StoreManager extends Record<any, any> {
18
18
  }
19
19
  export interface QueueSaverOptions {
20
20
  maxPreviousTracks: number;
21
+ queueStore?: StoreManager;
22
+ queueChangesWatcher?: QueueChangesWatcher;
21
23
  }
22
24
  export interface QueueSaver {
23
25
  /** @private */
@@ -26,7 +28,7 @@ export interface QueueSaver {
26
28
  options: QueueSaverOptions;
27
29
  }
28
30
  export declare class QueueSaver {
29
- constructor(storeManager: StoreManager, options: QueueSaverOptions);
31
+ constructor(options: QueueSaverOptions);
30
32
  get(guildId: string): Promise<Partial<StoredQueue>>;
31
33
  delete(guildId: string): Promise<any>;
32
34
  set(guildId: string, value: any): Promise<any>;
@@ -43,23 +45,23 @@ export declare class DefaultQueueStore {
43
45
  }
44
46
  export declare class QueueChangesWatcher {
45
47
  constructor();
46
- tracksAdd(guildId: string, tracks: Track[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
47
- 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;
48
50
  shuffled(guildId: string, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue): void;
49
51
  }
50
52
  export declare class Queue {
51
- readonly tracks: Track[];
53
+ readonly tracks: (Track | UnresolvedTrack)[];
52
54
  readonly previous: Track[];
53
55
  current: Track | null;
54
56
  options: {
55
57
  maxPreviousTracks: number;
56
58
  };
57
59
  private readonly guildId;
58
- protected readonly QueueSaver: QueueSaver | null;
59
- static readonly StaticSymbol: Symbol;
60
+ private readonly QueueSaver;
60
61
  private managerUtils;
61
62
  private queueChanges;
62
- constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueChangesWatcher?: QueueChangesWatcher);
63
+ constructor(guildId: string, data?: Partial<StoredQueue>, QueueSaver?: QueueSaver, queueOptions?: QueueSaverOptions);
64
+ private applyData;
63
65
  /**
64
66
  * Utils for a Queue
65
67
  */
@@ -77,7 +79,7 @@ export declare class Queue {
77
79
  /**
78
80
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the storeManager
79
81
  */
80
- getStored: () => StoredQueue;
82
+ toJSON: () => StoredQueue;
81
83
  /**
82
84
  * Get the Total Duration of the Queue-Songs summed up
83
85
  * @returns {number}
@@ -95,7 +97,7 @@ export declare class Queue {
95
97
  * @param {number} index At what position to add the Track
96
98
  * @returns {number} Queue-Size (for the next Tracks)
97
99
  */
98
- add(TrackOrTracks: Track | Track[], index?: number): any;
100
+ add(TrackOrTracks: Track | UnresolvedTrack | (Track | UnresolvedTrack)[], index?: number): any;
99
101
  /**
100
102
  * Splice the tracks in the Queue
101
103
  * @param {number} index Where to remove the Track
@@ -103,5 +105,5 @@ export declare class Queue {
103
105
  * @param {Track | Track[]} TrackOrTracks Want to Add more Tracks?
104
106
  * @returns {Track} Spliced Track
105
107
  */
106
- splice(index: number, amount: number, TrackOrTracks?: Track | Track[]): any;
108
+ splice(index: number, amount: number, TrackOrTracks?: Track | UnresolvedTrack | (Track | UnresolvedTrack)[]): any;
107
109
  }