lavalink-client 2.5.7 → 2.5.9

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 (98) hide show
  1. package/README.md +10 -2
  2. package/dist/index.d.mts +3046 -0
  3. package/dist/index.d.ts +3046 -0
  4. package/dist/index.js +4993 -0
  5. package/dist/index.mjs +4932 -0
  6. package/package.json +21 -24
  7. package/dist/cjs/index.d.ts +0 -16
  8. package/dist/cjs/index.js +0 -19
  9. package/dist/cjs/package.json +0 -3
  10. package/dist/cjs/structures/Constants.d.ts +0 -90
  11. package/dist/cjs/structures/Constants.js +0 -296
  12. package/dist/cjs/structures/CustomSearches/BandCampSearch.d.ts +0 -3
  13. package/dist/cjs/structures/CustomSearches/BandCampSearch.js +0 -39
  14. package/dist/cjs/structures/Filters.d.ts +0 -169
  15. package/dist/cjs/structures/Filters.js +0 -700
  16. package/dist/cjs/structures/LavalinkManager.d.ts +0 -232
  17. package/dist/cjs/structures/LavalinkManager.js +0 -621
  18. package/dist/cjs/structures/LavalinkManagerStatics.d.ts +0 -15
  19. package/dist/cjs/structures/LavalinkManagerStatics.js +0 -149
  20. package/dist/cjs/structures/Node.d.ts +0 -523
  21. package/dist/cjs/structures/Node.js +0 -1605
  22. package/dist/cjs/structures/NodeManager.d.ts +0 -100
  23. package/dist/cjs/structures/NodeManager.js +0 -224
  24. package/dist/cjs/structures/Player.d.ts +0 -223
  25. package/dist/cjs/structures/Player.js +0 -807
  26. package/dist/cjs/structures/Queue.d.ts +0 -186
  27. package/dist/cjs/structures/Queue.js +0 -390
  28. package/dist/cjs/structures/Types/Filters.d.ts +0 -190
  29. package/dist/cjs/structures/Types/Filters.js +0 -2
  30. package/dist/cjs/structures/Types/Manager.d.ts +0 -271
  31. package/dist/cjs/structures/Types/Manager.js +0 -2
  32. package/dist/cjs/structures/Types/Node.d.ts +0 -238
  33. package/dist/cjs/structures/Types/Node.js +0 -2
  34. package/dist/cjs/structures/Types/Player.d.ts +0 -114
  35. package/dist/cjs/structures/Types/Player.js +0 -2
  36. package/dist/cjs/structures/Types/Queue.d.ts +0 -35
  37. package/dist/cjs/structures/Types/Queue.js +0 -2
  38. package/dist/cjs/structures/Types/Track.d.ts +0 -134
  39. package/dist/cjs/structures/Types/Track.js +0 -2
  40. package/dist/cjs/structures/Types/Utils.d.ts +0 -443
  41. package/dist/cjs/structures/Types/Utils.js +0 -2
  42. package/dist/cjs/structures/Utils.d.ts +0 -116
  43. package/dist/cjs/structures/Utils.js +0 -567
  44. package/dist/esm/index.d.ts +0 -16
  45. package/dist/esm/index.js +0 -16
  46. package/dist/esm/package.json +0 -3
  47. package/dist/esm/structures/Constants.d.ts +0 -90
  48. package/dist/esm/structures/Constants.js +0 -293
  49. package/dist/esm/structures/CustomSearches/BandCampSearch.d.ts +0 -3
  50. package/dist/esm/structures/CustomSearches/BandCampSearch.js +0 -35
  51. package/dist/esm/structures/Filters.d.ts +0 -169
  52. package/dist/esm/structures/Filters.js +0 -696
  53. package/dist/esm/structures/LavalinkManager.d.ts +0 -232
  54. package/dist/esm/structures/LavalinkManager.js +0 -617
  55. package/dist/esm/structures/LavalinkManagerStatics.d.ts +0 -15
  56. package/dist/esm/structures/LavalinkManagerStatics.js +0 -146
  57. package/dist/esm/structures/Node.d.ts +0 -523
  58. package/dist/esm/structures/Node.js +0 -1600
  59. package/dist/esm/structures/NodeManager.d.ts +0 -100
  60. package/dist/esm/structures/NodeManager.js +0 -220
  61. package/dist/esm/structures/Player.d.ts +0 -223
  62. package/dist/esm/structures/Player.js +0 -803
  63. package/dist/esm/structures/Queue.d.ts +0 -186
  64. package/dist/esm/structures/Queue.js +0 -384
  65. package/dist/esm/structures/Types/Filters.d.ts +0 -190
  66. package/dist/esm/structures/Types/Filters.js +0 -1
  67. package/dist/esm/structures/Types/Manager.d.ts +0 -271
  68. package/dist/esm/structures/Types/Manager.js +0 -1
  69. package/dist/esm/structures/Types/Node.d.ts +0 -238
  70. package/dist/esm/structures/Types/Node.js +0 -1
  71. package/dist/esm/structures/Types/Player.d.ts +0 -114
  72. package/dist/esm/structures/Types/Player.js +0 -1
  73. package/dist/esm/structures/Types/Queue.d.ts +0 -35
  74. package/dist/esm/structures/Types/Queue.js +0 -1
  75. package/dist/esm/structures/Types/Track.d.ts +0 -134
  76. package/dist/esm/structures/Types/Track.js +0 -1
  77. package/dist/esm/structures/Types/Utils.d.ts +0 -443
  78. package/dist/esm/structures/Types/Utils.js +0 -1
  79. package/dist/esm/structures/Utils.d.ts +0 -116
  80. package/dist/esm/structures/Utils.js +0 -559
  81. package/dist/types/index.d.ts +0 -16
  82. package/dist/types/structures/Constants.d.ts +0 -90
  83. package/dist/types/structures/CustomSearches/BandCampSearch.d.ts +0 -3
  84. package/dist/types/structures/Filters.d.ts +0 -169
  85. package/dist/types/structures/LavalinkManager.d.ts +0 -232
  86. package/dist/types/structures/LavalinkManagerStatics.d.ts +0 -15
  87. package/dist/types/structures/Node.d.ts +0 -523
  88. package/dist/types/structures/NodeManager.d.ts +0 -100
  89. package/dist/types/structures/Player.d.ts +0 -223
  90. package/dist/types/structures/Queue.d.ts +0 -186
  91. package/dist/types/structures/Types/Filters.d.ts +0 -190
  92. package/dist/types/structures/Types/Manager.d.ts +0 -271
  93. package/dist/types/structures/Types/Node.d.ts +0 -238
  94. package/dist/types/structures/Types/Player.d.ts +0 -114
  95. package/dist/types/structures/Types/Queue.d.ts +0 -35
  96. package/dist/types/structures/Types/Track.d.ts +0 -134
  97. package/dist/types/structures/Types/Utils.d.ts +0 -443
  98. package/dist/types/structures/Utils.d.ts +0 -116
@@ -1,803 +0,0 @@
1
- import { DebugEvents } from "./Constants.js";
2
- import { bandCampSearch } from "./CustomSearches/BandCampSearch.js";
3
- import { FilterManager } from "./Filters.js";
4
- import { Queue, QueueSaver } from "./Queue.js";
5
- import { queueTrackEnd, safeStringify } from "./Utils.js";
6
- export class Player {
7
- /** Filter Manager per player */
8
- filterManager;
9
- /** circular reference to the lavalink Manager from the Player for easier use */
10
- LavalinkManager;
11
- /** Player options currently used, mutation doesn't affect player's state */
12
- options;
13
- /** The lavalink node assigned the the player, don't change it manually */
14
- node;
15
- /** The queue from the player */
16
- queue;
17
- /** The Guild Id of the Player */
18
- guildId;
19
- /** The Voice Channel Id of the Player */
20
- voiceChannelId = null;
21
- /** The Text Channel Id of the Player */
22
- textChannelId = null;
23
- /** States if the Bot is supposed to be outputting audio */
24
- playing = false;
25
- /** States if the Bot is paused or not */
26
- paused = false;
27
- /** Repeat Mode of the Player */
28
- repeatMode = "off";
29
- /** Player's ping */
30
- ping = {
31
- /* Response time for rest actions with Lavalink Server */
32
- lavalink: 0,
33
- /* Latency of the Discord's Websocket Voice Server */
34
- ws: 0
35
- };
36
- /** The Display Volume */
37
- volume = 100;
38
- /** The Volume Lavalink actually is outputting */
39
- lavalinkVolume = 100;
40
- /** The current Positin of the player (Calculated) */
41
- get position() {
42
- return this.lastPosition + (this.lastPositionChange ? Date.now() - this.lastPositionChange : 0);
43
- }
44
- /** The timestamp when the last position change update happened */
45
- lastPositionChange = null;
46
- /** The current Positin of the player (from Lavalink) */
47
- lastPosition = 0;
48
- lastSavedPosition = 0;
49
- /** When the player was created [Timestamp in Ms] (from lavalink) */
50
- createdTimeStamp;
51
- /** The Player Connection's State (from Lavalink) */
52
- connected = false;
53
- /** Voice Server Data (from Lavalink) */
54
- voice = {
55
- endpoint: null,
56
- sessionId: null,
57
- token: null
58
- };
59
- voiceState = {
60
- selfDeaf: false,
61
- selfMute: false,
62
- serverDeaf: false,
63
- serverMute: false,
64
- suppress: false,
65
- };
66
- /** Custom data for the player */
67
- data = {};
68
- /**
69
- * Create a new Player
70
- * @param options
71
- * @param LavalinkManager
72
- */
73
- constructor(options, LavalinkManager, dontEmitPlayerCreateEvent) {
74
- if (typeof options?.customData === "object")
75
- for (const [key, value] of Object.entries(options.customData))
76
- this.set(key, value);
77
- this.options = options;
78
- this.filterManager = new FilterManager(this);
79
- this.LavalinkManager = LavalinkManager;
80
- this.guildId = this.options.guildId;
81
- this.voiceChannelId = this.options.voiceChannelId;
82
- this.textChannelId = this.options.textChannelId || null;
83
- this.node = typeof this.options.node === "string"
84
- ? this.LavalinkManager.nodeManager.nodes.get(this.options.node)
85
- : this.options.node;
86
- if (!this.node || typeof this.node.request !== "function") {
87
- if (typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
88
- this.LavalinkManager.emit("debug", DebugEvents.PlayerCreateNodeNotFound, {
89
- state: "warn",
90
- message: `Player was created with provided node Id: ${this.options.node}, but no node with that Id was found.`,
91
- functionLayer: "Player > constructor()",
92
- });
93
- }
94
- const least = this.LavalinkManager.nodeManager.leastUsedNodes();
95
- this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null;
96
- }
97
- if (!this.node)
98
- throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
99
- if (typeof options.volume === "number" && !isNaN(options.volume))
100
- this.volume = Number(options.volume);
101
- this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
102
- this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
103
- ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
104
- : this.volume), 1000), 0));
105
- if (!dontEmitPlayerCreateEvent)
106
- this.LavalinkManager.emit("playerCreate", this);
107
- this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
108
- }
109
- /**
110
- * Set custom data.
111
- * @param key
112
- * @param value
113
- */
114
- set(key, value) {
115
- this.data[key] = value;
116
- return this;
117
- }
118
- /**
119
- * Get custom data.
120
- * @param key
121
- */
122
- get(key) {
123
- return this.data[key];
124
- }
125
- /**
126
- * CLears all the custom data.
127
- */
128
- clearData() {
129
- const toKeep = Object.keys(this.data).filter(v => v.startsWith("internal_"));
130
- for (const key in this.data) {
131
- if (toKeep.includes(key))
132
- continue;
133
- delete this.data[key];
134
- }
135
- return this;
136
- }
137
- /**
138
- * Get all custom Data
139
- */
140
- getAllData() {
141
- return Object.fromEntries(Object.entries(this.data).filter(v => !v[0].startsWith("internal_")));
142
- }
143
- /**
144
- * Play the next track from the queue / a specific track, with playoptions for Lavalink
145
- * @param options
146
- */
147
- async play(options = {}) {
148
- if (this.get("internal_queueempty")) {
149
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
150
- this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayQueueEmptyTimeoutClear, {
151
- state: "log",
152
- message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`,
153
- functionLayer: "Player > play()",
154
- });
155
- }
156
- this.LavalinkManager.emit("playerQueueEmptyCancel", this);
157
- clearTimeout(this.get("internal_queueempty"));
158
- this.set("internal_queueempty", undefined);
159
- }
160
- // if clientTrack provided, override options.track object
161
- if (options?.clientTrack && (this.LavalinkManager.utils.isTrack(options?.clientTrack) || this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack))) {
162
- if (this.LavalinkManager.utils.isUnresolvedTrack(options.clientTrack)) {
163
- try {
164
- // resolve the unresolved track
165
- await options.clientTrack.resolve(this);
166
- }
167
- catch (error) {
168
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
169
- this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
170
- state: "error",
171
- error: error,
172
- message: `Player Play was called with clientTrack, Song is unresolved, but couldn't resolve it`,
173
- functionLayer: "Player > play() > resolve currentTrack",
174
- });
175
- }
176
- this.LavalinkManager.emit("trackError", this, this.queue.current, error);
177
- if (options && "clientTrack" in options)
178
- delete options.clientTrack;
179
- if (options && "track" in options)
180
- delete options.track;
181
- // try to play the next track if possible
182
- if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
183
- return this.play(options);
184
- return this;
185
- }
186
- }
187
- if ((typeof options.track?.userData === "object" || typeof options.clientTrack?.userData === "object") && options.clientTrack)
188
- options.clientTrack.userData = {
189
- ...(typeof options?.clientTrack?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.clientTrack?.requester || {}) } : {}),
190
- ...options?.clientTrack.userData,
191
- ...options.track?.userData,
192
- };
193
- options.track = {
194
- encoded: options.clientTrack?.encoded,
195
- requester: options.clientTrack?.requester,
196
- userData: options.clientTrack?.userData,
197
- };
198
- }
199
- // if either encoded or identifier is provided generate the data to play them
200
- if (options?.track?.encoded || options?.track?.identifier) {
201
- this.queue.current = options.clientTrack || null;
202
- this.queue.utils.save();
203
- if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
204
- this.volume = Math.max(Math.min(options?.volume, 500), 0);
205
- let vol = Number(this.volume);
206
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
207
- vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
208
- this.lavalinkVolume = Math.round(vol);
209
- options.volume = this.lavalinkVolume;
210
- }
211
- const track = Object.fromEntries(Object.entries({
212
- encoded: options.track.encoded,
213
- identifier: options.track.identifier,
214
- userData: {
215
- ...(typeof options?.track?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {}) } : {}),
216
- ...options.track.userData,
217
- }
218
- }).filter(v => typeof v[1] !== "undefined"));
219
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
220
- this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayWithTrackReplace, {
221
- state: "log",
222
- message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`,
223
- functionLayer: "Player > play()",
224
- });
225
- }
226
- return this.node.updatePlayer({
227
- guildId: this.guildId,
228
- noReplace: false,
229
- playerOptions: Object.fromEntries(Object.entries({
230
- track,
231
- position: options.position ?? undefined,
232
- paused: options.paused ?? undefined,
233
- endTime: options?.endTime ?? undefined,
234
- filters: options?.filters ?? undefined,
235
- volume: options.volume ?? this.lavalinkVolume ?? undefined,
236
- voice: options.voice ?? undefined,
237
- }).filter(v => typeof v[1] !== "undefined")),
238
- });
239
- }
240
- if (!this.queue.current && this.queue.tracks.length)
241
- await queueTrackEnd(this);
242
- if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) {
243
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
244
- this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrack, {
245
- state: "log",
246
- message: `Player Play was called, current Queue Song is unresolved, resolving the track.`,
247
- functionLayer: "Player > play()",
248
- });
249
- }
250
- try {
251
- // resolve the unresolved track
252
- await this.queue.current.resolve(this);
253
- if (typeof options.track?.userData === "object" && this.queue.current)
254
- this.queue.current.userData = {
255
- ...(typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {}),
256
- ...this.queue.current?.userData,
257
- ...options.track?.userData
258
- };
259
- }
260
- catch (error) {
261
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
262
- this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, {
263
- state: "error",
264
- error: error,
265
- message: `Player Play was called, current Queue Song is unresolved, but couldn't resolve it`,
266
- functionLayer: "Player > play() > resolve currentTrack",
267
- });
268
- }
269
- this.LavalinkManager.emit("trackError", this, this.queue.current, error);
270
- if (options && "clientTrack" in options)
271
- delete options.clientTrack;
272
- if (options && "track" in options)
273
- delete options.track;
274
- // get rid of the current song without shifting the queue, so that the shifting can happen inside the next .play() call when "autoSkipOnResolveError" is true
275
- await queueTrackEnd(this, true);
276
- // try to play the next track if possible
277
- if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
278
- return this.play(options);
279
- return this;
280
- }
281
- }
282
- if (!this.queue.current)
283
- throw new Error(`There is no Track in the Queue, nor provided in the PlayOptions`);
284
- if (typeof options?.volume === "number" && !isNaN(options?.volume)) {
285
- this.volume = Math.max(Math.min(options?.volume, 500), 0);
286
- let vol = Number(this.volume);
287
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
288
- vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
289
- this.lavalinkVolume = Math.round(vol);
290
- options.volume = this.lavalinkVolume;
291
- }
292
- const finalOptions = Object.fromEntries(Object.entries({
293
- track: {
294
- encoded: this.queue.current?.encoded || null,
295
- // identifier: options.identifier,
296
- userData: {
297
- ...(typeof this.queue.current?.requester === "object" ? { requester: this.LavalinkManager.utils.getTransformedRequester(this.queue.current?.requester || {}) } : {}),
298
- ...options?.track?.userData,
299
- ...this.queue.current?.userData,
300
- },
301
- },
302
- volume: this.lavalinkVolume,
303
- position: options?.position ?? 0,
304
- endTime: options?.endTime ?? undefined,
305
- filters: options?.filters ?? undefined,
306
- paused: options?.paused ?? undefined,
307
- voice: options?.voice ?? undefined
308
- }).filter(v => typeof v[1] !== "undefined"));
309
- if ((typeof finalOptions.position !== "undefined" && isNaN(finalOptions.position)) || (typeof finalOptions.position === "number" && (finalOptions.position < 0 || finalOptions.position >= this.queue.current.info.duration)))
310
- throw new Error("PlayerOption#position must be a positive number, less than track's duration");
311
- if ((typeof finalOptions.volume !== "undefined" && isNaN(finalOptions.volume) || (typeof finalOptions.volume === "number" && finalOptions.volume < 0)))
312
- throw new Error("PlayerOption#volume must be a positive number");
313
- if ((typeof finalOptions.endTime !== "undefined" && isNaN(finalOptions.endTime)) || (typeof finalOptions.endTime === "number" && (finalOptions.endTime < 0 || finalOptions.endTime >= this.queue.current.info.duration)))
314
- throw new Error("PlayerOption#endTime must be a positive number, less than track's duration");
315
- if (typeof finalOptions.position === "number" && typeof finalOptions.endTime === "number" && finalOptions.endTime < finalOptions.position)
316
- throw new Error("PlayerOption#endTime must be bigger than PlayerOption#position");
317
- const now = performance.now();
318
- await this.node.updatePlayer({
319
- guildId: this.guildId,
320
- noReplace: (options?.noReplace ?? false),
321
- playerOptions: finalOptions,
322
- });
323
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
324
- return this;
325
- }
326
- /**
327
- * Set the Volume for the Player
328
- * @param volume The Volume in percent
329
- * @param ignoreVolumeDecrementer If it should ignore the volumedecrementer option
330
- */
331
- async setVolume(volume, ignoreVolumeDecrementer = false) {
332
- volume = Number(volume);
333
- if (isNaN(volume))
334
- throw new TypeError("Volume must be a number.");
335
- this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
336
- this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
337
- ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
338
- : this.volume), 1000), 0));
339
- const now = performance.now();
340
- if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
341
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
342
- this.LavalinkManager.emit("debug", DebugEvents.PlayerVolumeAsFilter, {
343
- state: "log",
344
- message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`,
345
- functionLayer: "Player > setVolume()",
346
- });
347
- }
348
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
349
- }
350
- else {
351
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
352
- }
353
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
354
- return this;
355
- }
356
- /**
357
- * Search for a track
358
- * @param query The query to search for
359
- * @param requestUser The user that requested the track
360
- * @param throwOnEmpty If an error should be thrown if no track is found
361
- * @returns The search result
362
- */
363
- async lavaSearch(query, requestUser, throwOnEmpty = false) {
364
- return this.node.lavaSearch(query, requestUser, throwOnEmpty);
365
- }
366
- /**
367
- * Set the SponsorBlock
368
- * @param segments The segments to set
369
- */
370
- async setSponsorBlock(segments = ["sponsor", "selfpromo"]) {
371
- return this.node.setSponsorBlock(this, segments);
372
- }
373
- /**
374
- * Get the SponsorBlock
375
- */
376
- async getSponsorBlock() {
377
- return this.node.getSponsorBlock(this);
378
- }
379
- /**
380
- * Delete the SponsorBlock
381
- */
382
- async deleteSponsorBlock() {
383
- return this.node.deleteSponsorBlock(this);
384
- }
385
- /**
386
- *
387
- * @param query Query for your data
388
- * @param requestUser
389
- */
390
- async search(query, requestUser, throwOnEmpty = false) {
391
- const Query = this.LavalinkManager.utils.transformQuery(query);
392
- if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) {
393
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
394
- this.LavalinkManager.emit("debug", DebugEvents.BandcampSearchLokalEngine, {
395
- state: "log",
396
- message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`,
397
- functionLayer: "Player > search()",
398
- });
399
- }
400
- return await bandCampSearch(this, Query.query, requestUser);
401
- }
402
- return this.node.search(Query, requestUser, throwOnEmpty);
403
- }
404
- /**
405
- * Pause the player
406
- */
407
- async pause() {
408
- if (this.paused && !this.playing)
409
- throw new Error("Player is already paused - not able to pause.");
410
- this.paused = true;
411
- this.lastPositionChange = null; // needs to removed to not cause issues
412
- const now = performance.now();
413
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
414
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
415
- // emit the event
416
- this.LavalinkManager.emit("playerPaused", this, this.queue.current);
417
- return this;
418
- }
419
- /**
420
- * Resume the Player
421
- */
422
- async resume() {
423
- if (!this.paused)
424
- throw new Error("Player isn't paused - not able to resume.");
425
- this.paused = false;
426
- const now = performance.now();
427
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
428
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
429
- // emit the event
430
- this.LavalinkManager.emit("playerResumed", this, this.queue.current);
431
- return this;
432
- }
433
- /**
434
- * Seek to a specific Position
435
- * @param position
436
- */
437
- async seek(position) {
438
- if (!this.queue.current)
439
- return undefined;
440
- position = Number(position);
441
- if (isNaN(position))
442
- throw new RangeError("Position must be a number.");
443
- if (!this.queue.current.info.isSeekable || this.queue.current.info.isStream)
444
- throw new RangeError("Current Track is not seekable / a stream");
445
- if (position < 0 || position > this.queue.current.info.duration)
446
- position = Math.max(Math.min(position, this.queue.current.info.duration), 0);
447
- this.lastPositionChange = Date.now();
448
- this.lastPosition = position;
449
- const now = performance.now();
450
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
451
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
452
- return this;
453
- }
454
- /**
455
- * Set the Repeatmode of the Player
456
- * @param repeatMode
457
- */
458
- async setRepeatMode(repeatMode) {
459
- if (!["off", "track", "queue"].includes(repeatMode))
460
- throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
461
- this.repeatMode = repeatMode;
462
- return this;
463
- }
464
- /**
465
- * Skip the current song, or a specific amount of songs
466
- * @param amount provide the index of the next track to skip to
467
- */
468
- async skip(skipTo = 0, throwError = true) {
469
- if (!this.queue.tracks.length && (throwError || (typeof skipTo === "boolean" && skipTo === true)))
470
- throw new RangeError("Can't skip more than the queue size");
471
- if (typeof skipTo === "number" && skipTo > 1) {
472
- if (skipTo > this.queue.tracks.length)
473
- throw new RangeError("Can't skip more than the queue size");
474
- await this.queue.splice(0, skipTo - 1);
475
- }
476
- if (!this.playing && !this.queue.current)
477
- return (this.play(), this);
478
- const now = performance.now();
479
- this.set("internal_skipped", true);
480
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null }, paused: false } });
481
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
482
- return this;
483
- }
484
- /**
485
- * Clears the queue and stops playing. Does not destroy the Player and not leave the channel
486
- * @returns
487
- */
488
- async stopPlaying(clearQueue = true, executeAutoplay = false) {
489
- // use internal_stopPlaying on true, so that it doesn't utilize current loop states. on trackEnd event
490
- this.set("internal_stopPlaying", true);
491
- // remove tracks from the queue
492
- if (this.queue.tracks.length && clearQueue === true)
493
- await this.queue.splice(0, this.queue.tracks.length);
494
- if (executeAutoplay === false)
495
- this.set("internal_autoplayStopPlaying", true);
496
- else
497
- this.set("internal_autoplayStopPlaying", undefined);
498
- const now = performance.now();
499
- // send to lavalink, that it should stop playing
500
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { track: { encoded: null } } });
501
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
502
- return this;
503
- }
504
- /**
505
- * Connects the Player to the Voice Channel
506
- * @returns
507
- */
508
- async connect() {
509
- if (!this.options.voiceChannelId)
510
- throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
511
- await this.LavalinkManager.options.sendToShard(this.guildId, {
512
- op: 4,
513
- d: {
514
- guild_id: this.guildId,
515
- channel_id: this.options.voiceChannelId,
516
- self_mute: this.options.selfMute ?? false,
517
- self_deaf: this.options.selfDeaf ?? true,
518
- }
519
- });
520
- this.voiceChannelId = this.options.voiceChannelId;
521
- return this;
522
- }
523
- async changeVoiceState(data) {
524
- if (this.options.voiceChannelId === data.voiceChannelId)
525
- throw new RangeError("New Channel can't be equal to the old Channel.");
526
- await this.LavalinkManager.options.sendToShard(this.guildId, {
527
- op: 4,
528
- d: {
529
- guild_id: this.guildId,
530
- channel_id: data.voiceChannelId,
531
- self_mute: data.selfMute ?? this.options.selfMute ?? false,
532
- self_deaf: data.selfDeaf ?? this.options.selfDeaf ?? true,
533
- }
534
- });
535
- // override the options
536
- this.options.voiceChannelId = data.voiceChannelId;
537
- this.options.selfMute = data.selfMute;
538
- this.options.selfDeaf = data.selfDeaf;
539
- this.voiceChannelId = data.voiceChannelId;
540
- return this;
541
- }
542
- /**
543
- * Disconnects the Player from the Voice Channel, but keeps the player in the cache
544
- * @param force If false it throws an error, if player thinks it's already disconnected
545
- * @returns
546
- */
547
- async disconnect(force = false) {
548
- if (!force && !this.options.voiceChannelId)
549
- throw new RangeError("No Voice Channel id has been set. (player.options.voiceChannelId)");
550
- await this.LavalinkManager.options.sendToShard(this.guildId, {
551
- op: 4,
552
- d: {
553
- guild_id: this.guildId,
554
- channel_id: null,
555
- self_mute: false,
556
- self_deaf: false,
557
- }
558
- });
559
- this.voiceChannelId = null;
560
- return this;
561
- }
562
- /**
563
- * Destroy the player and disconnect from the voice channel
564
- */
565
- async destroy(reason, disconnect = true) {
566
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
567
- console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`);
568
- if (this.get("internal_queueempty")) {
569
- clearTimeout(this.get("internal_queueempty"));
570
- this.set("internal_queueempty", undefined);
571
- }
572
- if (this.get("internal_destroystatus") === true) {
573
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
574
- this.LavalinkManager.emit("debug", DebugEvents.PlayerDestroyingSomewhereElse, {
575
- state: "warn",
576
- message: `Player is already destroying somewhere else..`,
577
- functionLayer: "Player > destroy()",
578
- });
579
- }
580
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
581
- console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`);
582
- return;
583
- }
584
- this.set("internal_destroystatus", true);
585
- // disconnect player and set VoiceChannel to Null
586
- if (disconnect)
587
- await this.disconnect(true);
588
- else
589
- this.set("internal_destroywithoutdisconnect", true);
590
- // Destroy the queue
591
- await this.queue.utils.destroy();
592
- // delete the player from cache
593
- this.LavalinkManager.deletePlayer(this.guildId);
594
- // destroy the player on lavalink side
595
- await this.node.destroyPlayer(this.guildId);
596
- if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog)
597
- console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Player got destroyed successfully`);
598
- // emit the event
599
- this.LavalinkManager.emit("playerDestroy", this, reason);
600
- // return smt
601
- return this;
602
- }
603
- /**
604
- * Get the current lyrics of the track currently playing on the guild
605
- * @param guildId The guild id to get the current lyrics for
606
- * @param skipTrackSource If true, it will not try to get the lyrics from the track source
607
- * @returns The current lyrics
608
- * @example
609
- * ```ts
610
- * const lyrics = await player.getCurrentLyrics();
611
- * ```
612
- */
613
- async getCurrentLyrics(skipTrackSource) {
614
- return await this.node.lyrics.getCurrent(this.guildId, skipTrackSource);
615
- }
616
- /**
617
- * Get the lyrics of a specific track
618
- * @param track The track to get the lyrics for
619
- * @param skipTrackSource If true, it will not try to get the lyrics from the track source
620
- * @returns The lyrics of the track
621
- * @example
622
- * ```ts
623
- * const lyrics = await player.getLyrics(player.queue.tracks[0], true);
624
- * ```
625
- */
626
- async getLyrics(track, skipTrackSource) {
627
- return await this.node.lyrics.get(track, skipTrackSource);
628
- }
629
- /**
630
- * Subscribe to the lyrics event on a specific guild to active live lyrics events
631
- * @returns The unsubscribe function
632
- * @example
633
- * ```ts
634
- * const lyrics = await player.subscribeLyrics();
635
- * ```
636
- */
637
- subscribeLyrics() {
638
- return this.node.lyrics.subscribe(this.guildId);
639
- }
640
- /**
641
- * Unsubscribe from the lyrics event on a specific guild to disable live lyrics events
642
- * @returns The unsubscribe function
643
- * @example
644
- * ```ts
645
- * const lyrics = await player.unsubscribeLyrics();
646
- * ```
647
- */
648
- unsubscribeLyrics() {
649
- return this.node.lyrics.unsubscribe(this.guildId);
650
- }
651
- /**
652
- * Move the player on a different Audio-Node
653
- * @param newNode New Node / New Node Id
654
- * @param checkSources If it should check if the sources are supported by the new node
655
- */
656
- async changeNode(newNode, checkSources = true) {
657
- const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode;
658
- if (!updateNode)
659
- throw new Error("Could not find the new Node");
660
- if (!updateNode.connected)
661
- throw new Error("The provided Node is not active or disconnected");
662
- if (this.node.id === updateNode.id)
663
- throw new Error("Player is already on the provided Node");
664
- if (this.get("internal_nodeChanging") === true)
665
- throw new Error("Player is already changing the node please wait");
666
- if (checkSources) {
667
- const isDefaultSource = () => {
668
- try {
669
- this.LavalinkManager.utils.validateSourceString(updateNode, this.LavalinkManager.options.playerOptions.defaultSearchPlatform);
670
- return true;
671
- }
672
- catch {
673
- return false;
674
- }
675
- };
676
- if (!isDefaultSource())
677
- throw new RangeError(`defaultSearchPlatform "${this.LavalinkManager.options.playerOptions.defaultSearchPlatform}" is not supported by the newNode`);
678
- if (this.queue.current || this.queue.tracks.length) { // Check if all queued track sources are supported by the new node
679
- const trackSources = new Set([this.queue.current, ...this.queue.tracks].map(track => track.info.sourceName));
680
- const missingSources = [...trackSources].filter(source => !updateNode.info.sourceManagers.includes(source));
681
- if (missingSources.length)
682
- throw new RangeError(`Sources missing for Node ${updateNode.id}: ${missingSources.join(', ')}`);
683
- }
684
- }
685
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
686
- this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
687
- state: "log",
688
- message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`,
689
- functionLayer: "Player > changeNode()",
690
- });
691
- }
692
- const data = this.toJSON();
693
- const currentTrack = this.queue.current;
694
- const segments = await this.getSponsorBlock().catch(() => []);
695
- const voiceData = this.voice;
696
- if (!voiceData.endpoint ||
697
- !voiceData.sessionId ||
698
- !voiceData.token)
699
- throw new Error("Voice Data is missing, can't change the node");
700
- this.set("internal_nodeChanging", true); // This will stop execution of trackEnd or queueEnd event while changing the node
701
- if (this.node.connected)
702
- await this.node.destroyPlayer(this.guildId); // destroy the player on the currentNode if it's connected
703
- this.node = updateNode;
704
- const now = performance.now();
705
- try {
706
- await this.connect();
707
- const endpoint = `/sessions/${this.node.sessionId}/players/${this.guildId}`; //Send the VoiceData to the newly connected node.
708
- await this.node.request(endpoint, r => {
709
- r.method = "PATCH";
710
- r.headers["Content-Type"] = "application/json";
711
- r.body = safeStringify({
712
- voice: {
713
- token: voiceData.token,
714
- endpoint: voiceData.endpoint,
715
- sessionId: voiceData.sessionId
716
- }
717
- });
718
- });
719
- const hasSponsorBlock = this.node.info?.plugins?.find(v => v.name === "sponsorblock-plugin");
720
- if (hasSponsorBlock) {
721
- if (segments.length) {
722
- await this.setSponsorBlock(segments).catch(error => {
723
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
724
- this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
725
- state: "error",
726
- error: error,
727
- message: `Player > changeNode() Unable to set SponsorBlock Segments`,
728
- functionLayer: "Player > changeNode()",
729
- });
730
- }
731
- });
732
- }
733
- else {
734
- await this.setSponsorBlock().catch(error => {
735
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
736
- this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
737
- state: "error",
738
- error: error,
739
- message: `Player > changeNode() Unable to set SponsorBlock Segments`,
740
- functionLayer: "Player > changeNode()",
741
- });
742
- }
743
- });
744
- }
745
- }
746
- if (currentTrack) { // If there is a current track, send it to the new node.
747
- await this.node.updatePlayer({
748
- guildId: this.guildId,
749
- noReplace: false,
750
- playerOptions: {
751
- track: currentTrack ?? null,
752
- position: currentTrack ? data.position : 0,
753
- volume: data.lavalinkVolume,
754
- paused: data.paused,
755
- //filters: { ...data.filters, equalizer: data.equalizer }, Sending filters on nodeChange causes issues (player gets dicsonnected)
756
- }
757
- });
758
- }
759
- this.paused = data.paused;
760
- this.playing = data.playing;
761
- this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
762
- return this.node.id;
763
- }
764
- catch (error) {
765
- if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
766
- this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
767
- state: "error",
768
- error: error,
769
- message: `Player.changeNode() execution failed`,
770
- functionLayer: "Player > changeNode()",
771
- });
772
- }
773
- throw new Error(`Failed to change the node: ${error}`);
774
- }
775
- finally {
776
- this.set("internal_nodeChanging", undefined);
777
- }
778
- }
779
- /** Converts the Player including Queue to a Json state */
780
- toJSON() {
781
- return {
782
- guildId: this.guildId,
783
- options: this.options,
784
- voiceChannelId: this.voiceChannelId,
785
- textChannelId: this.textChannelId,
786
- position: this.position,
787
- lastPosition: this.lastPosition,
788
- lastPositionChange: this.lastPositionChange,
789
- volume: this.volume,
790
- lavalinkVolume: this.lavalinkVolume,
791
- repeatMode: this.repeatMode,
792
- paused: this.paused,
793
- playing: this.playing,
794
- createdTimeStamp: this.createdTimeStamp,
795
- filters: this.filterManager?.data || {},
796
- equalizer: this.filterManager?.equalizerBands || [],
797
- nodeId: this.node?.id,
798
- nodeSessionId: this.node?.sessionId,
799
- ping: this.ping,
800
- queue: this.queue.utils.toJSON(),
801
- };
802
- }
803
- }