lavalink-client 2.5.6 → 2.5.8

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