lavalink-client 2.5.0 → 2.5.1

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.
@@ -495,7 +495,7 @@ class LavalinkManager extends events_1.EventEmitter {
495
495
  functionLayer: "LavalinkManager > sendRawData()",
496
496
  });
497
497
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
498
- console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, playerVoice: player.voice, update });
498
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, update, playerVoice: player.voice });
499
499
  }
500
500
  else {
501
501
  await player.node.updatePlayer({
@@ -505,8 +505,8 @@ class LavalinkManager extends events_1.EventEmitter {
505
505
  token: update.token,
506
506
  endpoint: update.endpoint,
507
507
  sessionId: sessionId2Use,
508
- }
509
- }
508
+ },
509
+ },
510
510
  });
511
511
  if (this.options?.advancedOptions?.enableDebugEvents) {
512
512
  this.emit("debug", Constants_1.DebugEvents.NoAudioDebug, {
@@ -516,7 +516,7 @@ class LavalinkManager extends events_1.EventEmitter {
516
516
  });
517
517
  }
518
518
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
519
- console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, } });
519
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, playerVoice: player.voice, update });
520
520
  }
521
521
  return;
522
522
  }
@@ -51,6 +51,12 @@ exports.DefaultSources = {
51
51
  "vkmusic": "vksearch",
52
52
  "vk music": "vksearch",
53
53
  "vkrec": "vkrec",
54
+ "vk": "vksearch",
55
+ // Qobuz (lavasrc)
56
+ "qbsearch": "qbsearch",
57
+ "qobuz": "qbsearch",
58
+ "qbisrc": "qbisrc",
59
+ "qbrec": "qbrec",
54
60
  // speak PLUGIN
55
61
  "speak": "speak",
56
62
  "tts": "tts",
@@ -73,6 +79,12 @@ exports.DefaultSources = {
73
79
  "https": "https",
74
80
  "link": "link",
75
81
  "uri": "uri",
82
+ // tidal
83
+ "tidal": "tdsearch",
84
+ "td": "tdsearch",
85
+ "tidal music": "tdsearch",
86
+ "tdsearch": "tdsearch",
87
+ "tdrec": "tdrec",
76
88
  // jiosaavn
77
89
  "jiosaavn": "jssearch",
78
90
  "js": "jssearch",
@@ -125,6 +137,8 @@ exports.SourceLinksRegexes = {
125
137
  SpotifyAlbumRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?album\/(?<identifier>[a-zA-Z0-9-_]+)/,
126
138
  AllSpotifyRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?(?<type>track|album|playlist|artist|episode|show)\/(?<identifier>[a-zA-Z0-9-_]+)/,
127
139
  appleMusic: /https?:\/\/?(?:www\.)?music\.apple\.com\/(\S+)/,
140
+ /** From tidal */
141
+ tidal: /https?:\/\/?(?:www\.)?(?:tidal|listen)\.tidal\.com\/(?<type>track|album|playlist|artist)\/(?<identifier>[a-zA-Z0-9-_]+)/,
128
142
  /** From jiosaavn-plugin */
129
143
  jiosaavn: /(https?:\/\/)(www\.)?jiosaavn\.com\/(?<type>song|album|featured|artist)\/([a-zA-Z0-9-_\/,]+)/,
130
144
  /** FROM DUNCTE BOT PLUGIN */
@@ -1271,8 +1271,15 @@ class LavalinkNode {
1271
1271
  }
1272
1272
  this.NodeManager.LavalinkManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
1273
1273
  // If there are no songs in the queue
1274
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1275
- return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1274
+ if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) {
1275
+ try { //Sometimes the trackStuck event triggers from the Lavalink server, but the track continues playing or resumes after. We explicitly end the track in such cases
1276
+ await player.node.updatePlayer({ guildId: player.guildId, playerOptions: { track: { encoded: null } } }); //trackEnd -> queueEnd
1277
+ return;
1278
+ }
1279
+ catch {
1280
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1281
+ }
1282
+ }
1276
1283
  // remove the current track, and enqueue the next one
1277
1284
  await (0, Utils_1.queueTrackEnd)(player);
1278
1285
  // if no track available, end queue
@@ -1281,7 +1288,7 @@ class LavalinkNode {
1281
1288
  }
1282
1289
  // play track if autoSkip is true
1283
1290
  if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1284
- player.play({ noReplace: true });
1291
+ player.play({ track: player.queue.current, noReplace: false }); // Replace the stuck track with the new track.
1285
1292
  }
1286
1293
  return;
1287
1294
  }
@@ -270,6 +270,8 @@ class Player {
270
270
  delete options.clientTrack;
271
271
  if (options && "track" in options)
272
272
  delete options.track;
273
+ // 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
274
+ await (0, Utils_1.queueTrackEnd)(this, true);
273
275
  // try to play the next track if possible
274
276
  if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
275
277
  return this.play(options);
@@ -405,6 +407,8 @@ class Player {
405
407
  const now = performance.now();
406
408
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
407
409
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
410
+ // emit the event
411
+ this.LavalinkManager.emit("playerPaused", this, this.queue.current);
408
412
  return this;
409
413
  }
410
414
  /**
@@ -417,6 +421,8 @@ class Player {
417
421
  const now = performance.now();
418
422
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
419
423
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
424
+ // emit the event
425
+ this.LavalinkManager.emit("playerResumed", this, this.queue.current);
420
426
  return this;
421
427
  }
422
428
  /**
@@ -682,6 +688,7 @@ class Player {
682
688
  }
683
689
  const data = this.toJSON();
684
690
  const currentTrack = this.queue.current;
691
+ const segments = await this.getSponsorBlock().catch(() => []);
685
692
  const voiceData = this.voice;
686
693
  if (!voiceData.endpoint ||
687
694
  !voiceData.sessionId ||
@@ -706,6 +713,33 @@ class Player {
706
713
  }
707
714
  });
708
715
  });
716
+ const hasSponsorBlock = this.node.info?.plugins?.find(v => v.name === "sponsorblock-plugin");
717
+ if (hasSponsorBlock) {
718
+ if (segments.length) {
719
+ await this.setSponsorBlock(segments).catch(error => {
720
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
721
+ this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
722
+ state: "error",
723
+ error: error,
724
+ message: `Player > changeNode() Unable to set SponsorBlock Segments`,
725
+ functionLayer: "Player > changeNode()",
726
+ });
727
+ }
728
+ });
729
+ }
730
+ else {
731
+ await this.setSponsorBlock().catch(error => {
732
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
733
+ this.LavalinkManager.emit("debug", Constants_1.DebugEvents.PlayerChangeNode, {
734
+ state: "error",
735
+ error: error,
736
+ message: `Player > changeNode() Unable to set SponsorBlock Segments`,
737
+ functionLayer: "Player > changeNode()",
738
+ });
739
+ }
740
+ });
741
+ }
742
+ }
709
743
  if (currentTrack) { // If there is a current track, send it to the new node.
710
744
  await this.node.updatePlayer({
711
745
  guildId: this.guildId,
@@ -719,6 +753,8 @@ class Player {
719
753
  }
720
754
  });
721
755
  }
756
+ this.paused = data.paused;
757
+ this.playing = data.playing;
722
758
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
723
759
  return this.node.id;
724
760
  }
@@ -172,6 +172,8 @@ export interface LavalinkManagerEvents {
172
172
  * @event Manager#LyricsNotFound
173
173
  */
174
174
  "LyricsNotFound": (player: Player, track: Track | UnresolvedTrack | null, payload: LyricsNotFoundEvent) => void;
175
+ "playerResumed": (player: Player, track: Track | UnresolvedTrack | null) => void;
176
+ "playerPaused": (player: Player, track: Track | UnresolvedTrack | null) => void;
175
177
  }
176
178
  /**
177
179
  * The Bot client Options needed for the manager
@@ -4,7 +4,7 @@ import type { Base64 } from "./Utils.js";
4
4
  /** Sourcenames provided by lavalink server */
5
5
  export type LavalinkSourceNames = "youtube" | "youtubemusic" | "soundcloud" | "bandcamp" | "twitch";
6
6
  /** Source Names provided by lava src plugin */
7
- export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts";
7
+ export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts" | "vkmusic" | "tidal" | "qobuz";
8
8
  /** Source Names provided by jiosaavan plugin */
9
9
  export type LavalinkPlugin_JioSaavn_SourceNames = "jiosaavn";
10
10
  /** The SourceNames provided by lavalink */
@@ -11,7 +11,7 @@ export type Opaque<T, K> = T & {
11
11
  export type IntegerNumber = Opaque<number, 'Int'>;
12
12
  /** Opqaue tyep for floatnumber */
13
13
  export type FloatNumber = Opaque<number, 'Float'>;
14
- export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec";
14
+ export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec" | "tdsearch" | "tdrec" | "qbsearch" | "qbisrc" | "qbrec";
15
15
  export type LavaSrcSearchPlatform = LavaSrcSearchPlatformBase | "ftts";
16
16
  export type JioSaavnSearchPlatform = "jssearch" | "jsrec";
17
17
  export type DuncteSearchPlatform = "speak" | "phsearch" | "pornhub" | "porn" | "tts";
@@ -20,9 +20,9 @@ export type LavalinkClientSearchPlatformResolve = "bandcamp" | "bc";
20
20
  export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | JioSaavnSearchPlatform | LavalinkClientSearchPlatform;
21
21
  export type ClientCustomSearchPlatformUtils = "local" | "http" | "https" | "link" | "uri";
22
22
  export type ClientSearchPlatform = ClientCustomSearchPlatformUtils | // for file/link requests
23
- "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk music" | "vkmusic" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn";
23
+ "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk" | "vk music" | "vkmusic" | "tidal" | "tidal music" | "qobuz" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn" | "td" | "tidal" | "tdrec";
24
24
  export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
25
- export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "TwitchTv" | "vimeo";
25
+ export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "tidal" | "TwitchTv" | "vimeo";
26
26
  export interface PlaylistInfo {
27
27
  /** The playlist name */
28
28
  name: string;
@@ -92,13 +92,13 @@ export interface TrackEndEvent extends PlayerEvent {
92
92
  export interface TrackExceptionEvent extends PlayerEvent {
93
93
  type: "TrackExceptionEvent";
94
94
  exception?: Exception;
95
- tracK: LavalinkTrack;
95
+ track: LavalinkTrack;
96
96
  error: string;
97
97
  }
98
98
  export interface TrackStuckEvent extends PlayerEvent {
99
99
  type: "TrackStuckEvent";
100
100
  thresholdMs: number;
101
- tracK: LavalinkTrack;
101
+ track: LavalinkTrack;
102
102
  }
103
103
  export interface WebSocketClosedEvent extends PlayerEvent {
104
104
  type: "WebSocketClosedEvent";
@@ -112,4 +112,4 @@ export declare class MiniMap<K, V> extends Map<K, V> {
112
112
  map<T>(fn: (value: V, key: K, miniMap: this) => T): T[];
113
113
  map<This, T>(fn: (this: This, value: V, key: K, miniMap: this) => T, thisArg: This): T[];
114
114
  }
115
- export declare function queueTrackEnd(player: Player): Promise<Track>;
115
+ export declare function queueTrackEnd(player: Player, dontShiftQueue?: boolean): Promise<Track>;
@@ -307,6 +307,9 @@ class ManagerUtils {
307
307
  if (LavalinkManagerStatics_1.SourceLinksRegexes.jiosaavn.test(queryString) && !node.info?.sourceManagers?.includes("jiosaavn")) {
308
308
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled");
309
309
  }
310
+ if (LavalinkManagerStatics_1.SourceLinksRegexes.tidal.test(queryString) && !node.info?.sourceManagers?.includes("tidal")) {
311
+ throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'tidal' enabled");
312
+ }
310
313
  return;
311
314
  }
312
315
  transformQuery(query) {
@@ -371,6 +374,12 @@ class ManagerUtils {
371
374
  if (source === "speak" && !node.info?.plugins?.find(c => c.name.toLowerCase().includes(LavalinkManagerStatics_1.LavalinkPlugins.DuncteBot_Plugin.toLowerCase()))) {
372
375
  throw new Error("Lavalink Node has not 'speak' enabled, which is required to have 'speak' work");
373
376
  }
377
+ if (source === "tdsearch" && !node.info?.sourceManagers?.includes("tidal")) {
378
+ throw new Error("Lavalink Node has not 'tidal' enabled, which is required to have 'tdsearch' work");
379
+ }
380
+ if (source === "tdrec" && !node.info?.sourceManagers?.includes("tidal")) {
381
+ throw new Error("Lavalink Node has not 'tidal' enabled, which is required to have 'tdrec' work");
382
+ }
374
383
  if (source === "tts" && !node.info?.plugins?.find(c => c.name.toLowerCase().includes(LavalinkManagerStatics_1.LavalinkPlugins.GoogleCloudTTS.toLowerCase()))) {
375
384
  throw new Error("Lavalink Node has not 'tts' enabled, which is required to have 'tts' work");
376
385
  }
@@ -386,6 +395,21 @@ class ManagerUtils {
386
395
  if (source === "ytsearch" && !node.info?.sourceManagers?.includes("youtube")) {
387
396
  throw new Error("Lavalink Node has not 'youtube' enabled, which is required to have 'ytsearch' work");
388
397
  }
398
+ if (source === "vksearch" && !node.info?.sourceManagers?.includes("vkmusic")) {
399
+ throw new Error("Lavalink Node has not 'vkmusic' enabled, which is required to have 'vksearch' work");
400
+ }
401
+ if (source === "vkrec" && !node.info?.sourceManagers?.includes("vkmusic")) {
402
+ throw new Error("Lavalink Node has not 'vkmusic' enabled, which is required to have 'vkrec' work");
403
+ }
404
+ if (source === "qbsearch" && !node.info?.sourceManagers?.includes("qobuz")) {
405
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbsearch' work");
406
+ }
407
+ if (source === "qbisrc" && !node.info?.sourceManagers?.includes("qobuz")) {
408
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbisrc' work");
409
+ }
410
+ if (source === "qbrec" && !node.info?.sourceManagers?.includes("qobuz")) {
411
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbrec' work");
412
+ }
389
413
  return;
390
414
  }
391
415
  }
@@ -418,7 +442,7 @@ class MiniMap extends Map {
418
442
  }
419
443
  }
420
444
  exports.MiniMap = MiniMap;
421
- async function queueTrackEnd(player) {
445
+ async function queueTrackEnd(player, dontShiftQueue = false) {
422
446
  if (player.queue.current && !player.queue.current?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
423
447
  player.queue.previous.unshift(player.queue.current);
424
448
  if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
@@ -428,10 +452,10 @@ async function queueTrackEnd(player) {
428
452
  // and if repeatMode == queue, add it back to the queue!
429
453
  if (player.repeatMode === "queue" && player.queue.current)
430
454
  player.queue.tracks.push(player.queue.current);
431
- // change the current Track to the next upcoming one
432
- const nextSong = player.queue.tracks.shift();
455
+ // change the current Track to the next upcoming one
456
+ const nextSong = dontShiftQueue ? null : player.queue.tracks.shift();
433
457
  try {
434
- if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
458
+ if (nextSong && player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
435
459
  await nextSong.resolve(player);
436
460
  player.queue.current = nextSong || null;
437
461
  // save it in the DB
@@ -448,7 +472,7 @@ async function queueTrackEnd(player) {
448
472
  }
449
473
  player.LavalinkManager.emit("trackError", player, player.queue.current, error);
450
474
  // try to play the next track if possible
451
- if (player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
475
+ if (!dontShiftQueue && player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
452
476
  return queueTrackEnd(player);
453
477
  }
454
478
  // return the new current Track
@@ -492,7 +492,7 @@ export class LavalinkManager extends EventEmitter {
492
492
  functionLayer: "LavalinkManager > sendRawData()",
493
493
  });
494
494
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
495
- console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, playerVoice: player.voice, update });
495
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, update, playerVoice: player.voice });
496
496
  }
497
497
  else {
498
498
  await player.node.updatePlayer({
@@ -502,8 +502,8 @@ export class LavalinkManager extends EventEmitter {
502
502
  token: update.token,
503
503
  endpoint: update.endpoint,
504
504
  sessionId: sessionId2Use,
505
- }
506
- }
505
+ },
506
+ },
507
507
  });
508
508
  if (this.options?.advancedOptions?.enableDebugEvents) {
509
509
  this.emit("debug", DebugEvents.NoAudioDebug, {
@@ -513,7 +513,7 @@ export class LavalinkManager extends EventEmitter {
513
513
  });
514
514
  }
515
515
  if (this.options?.advancedOptions?.debugOptions?.noAudio === true)
516
- console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Can't send updatePlayer for voice token session - Missing sessionId", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, } });
516
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: sessionId2Use, }, playerVoice: player.voice, update });
517
517
  }
518
518
  return;
519
519
  }
@@ -48,6 +48,12 @@ export const DefaultSources = {
48
48
  "vkmusic": "vksearch",
49
49
  "vk music": "vksearch",
50
50
  "vkrec": "vkrec",
51
+ "vk": "vksearch",
52
+ // Qobuz (lavasrc)
53
+ "qbsearch": "qbsearch",
54
+ "qobuz": "qbsearch",
55
+ "qbisrc": "qbisrc",
56
+ "qbrec": "qbrec",
51
57
  // speak PLUGIN
52
58
  "speak": "speak",
53
59
  "tts": "tts",
@@ -70,6 +76,12 @@ export const DefaultSources = {
70
76
  "https": "https",
71
77
  "link": "link",
72
78
  "uri": "uri",
79
+ // tidal
80
+ "tidal": "tdsearch",
81
+ "td": "tdsearch",
82
+ "tidal music": "tdsearch",
83
+ "tdsearch": "tdsearch",
84
+ "tdrec": "tdrec",
73
85
  // jiosaavn
74
86
  "jiosaavn": "jssearch",
75
87
  "js": "jssearch",
@@ -122,6 +134,8 @@ export const SourceLinksRegexes = {
122
134
  SpotifyAlbumRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?album\/(?<identifier>[a-zA-Z0-9-_]+)/,
123
135
  AllSpotifyRegex: /(https?:\/\/)(www\.)?open\.spotify\.com\/((?<region>[a-zA-Z-]+)\/)?(user\/(?<user>[a-zA-Z0-9-_]+)\/)?(?<type>track|album|playlist|artist|episode|show)\/(?<identifier>[a-zA-Z0-9-_]+)/,
124
136
  appleMusic: /https?:\/\/?(?:www\.)?music\.apple\.com\/(\S+)/,
137
+ /** From tidal */
138
+ tidal: /https?:\/\/?(?:www\.)?(?:tidal|listen)\.tidal\.com\/(?<type>track|album|playlist|artist)\/(?<identifier>[a-zA-Z0-9-_]+)/,
125
139
  /** From jiosaavn-plugin */
126
140
  jiosaavn: /(https?:\/\/)(www\.)?jiosaavn\.com\/(?<type>song|album|featured|artist)\/([a-zA-Z0-9-_\/,]+)/,
127
141
  /** FROM DUNCTE BOT PLUGIN */
@@ -1267,8 +1267,15 @@ export class LavalinkNode {
1267
1267
  }
1268
1268
  this.NodeManager.LavalinkManager.emit("trackStuck", player, track || this.getTrackOfPayload(payload), payload);
1269
1269
  // If there are no songs in the queue
1270
- if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying")))
1271
- return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1270
+ if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) {
1271
+ try { //Sometimes the trackStuck event triggers from the Lavalink server, but the track continues playing or resumes after. We explicitly end the track in such cases
1272
+ await player.node.updatePlayer({ guildId: player.guildId, playerOptions: { track: { encoded: null } } }); //trackEnd -> queueEnd
1273
+ return;
1274
+ }
1275
+ catch {
1276
+ return this.queueEnd(player, track || this.getTrackOfPayload(payload), payload);
1277
+ }
1278
+ }
1272
1279
  // remove the current track, and enqueue the next one
1273
1280
  await queueTrackEnd(player);
1274
1281
  // if no track available, end queue
@@ -1277,7 +1284,7 @@ export class LavalinkNode {
1277
1284
  }
1278
1285
  // play track if autoSkip is true
1279
1286
  if (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) {
1280
- player.play({ noReplace: true });
1287
+ player.play({ track: player.queue.current, noReplace: false }); // Replace the stuck track with the new track.
1281
1288
  }
1282
1289
  return;
1283
1290
  }
@@ -267,6 +267,8 @@ export class Player {
267
267
  delete options.clientTrack;
268
268
  if (options && "track" in options)
269
269
  delete options.track;
270
+ // 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
271
+ await queueTrackEnd(this, true);
270
272
  // try to play the next track if possible
271
273
  if (this.LavalinkManager.options?.autoSkipOnResolveError === true && this.queue.tracks[0])
272
274
  return this.play(options);
@@ -402,6 +404,8 @@ export class Player {
402
404
  const now = performance.now();
403
405
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
404
406
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
407
+ // emit the event
408
+ this.LavalinkManager.emit("playerPaused", this, this.queue.current);
405
409
  return this;
406
410
  }
407
411
  /**
@@ -414,6 +418,8 @@ export class Player {
414
418
  const now = performance.now();
415
419
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
416
420
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
421
+ // emit the event
422
+ this.LavalinkManager.emit("playerResumed", this, this.queue.current);
417
423
  return this;
418
424
  }
419
425
  /**
@@ -679,6 +685,7 @@ export class Player {
679
685
  }
680
686
  const data = this.toJSON();
681
687
  const currentTrack = this.queue.current;
688
+ const segments = await this.getSponsorBlock().catch(() => []);
682
689
  const voiceData = this.voice;
683
690
  if (!voiceData.endpoint ||
684
691
  !voiceData.sessionId ||
@@ -703,6 +710,33 @@ export class Player {
703
710
  }
704
711
  });
705
712
  });
713
+ const hasSponsorBlock = this.node.info?.plugins?.find(v => v.name === "sponsorblock-plugin");
714
+ if (hasSponsorBlock) {
715
+ if (segments.length) {
716
+ await this.setSponsorBlock(segments).catch(error => {
717
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
718
+ this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
719
+ state: "error",
720
+ error: error,
721
+ message: `Player > changeNode() Unable to set SponsorBlock Segments`,
722
+ functionLayer: "Player > changeNode()",
723
+ });
724
+ }
725
+ });
726
+ }
727
+ else {
728
+ await this.setSponsorBlock().catch(error => {
729
+ if (this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) {
730
+ this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, {
731
+ state: "error",
732
+ error: error,
733
+ message: `Player > changeNode() Unable to set SponsorBlock Segments`,
734
+ functionLayer: "Player > changeNode()",
735
+ });
736
+ }
737
+ });
738
+ }
739
+ }
706
740
  if (currentTrack) { // If there is a current track, send it to the new node.
707
741
  await this.node.updatePlayer({
708
742
  guildId: this.guildId,
@@ -716,6 +750,8 @@ export class Player {
716
750
  }
717
751
  });
718
752
  }
753
+ this.paused = data.paused;
754
+ this.playing = data.playing;
719
755
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
720
756
  return this.node.id;
721
757
  }
@@ -172,6 +172,8 @@ export interface LavalinkManagerEvents {
172
172
  * @event Manager#LyricsNotFound
173
173
  */
174
174
  "LyricsNotFound": (player: Player, track: Track | UnresolvedTrack | null, payload: LyricsNotFoundEvent) => void;
175
+ "playerResumed": (player: Player, track: Track | UnresolvedTrack | null) => void;
176
+ "playerPaused": (player: Player, track: Track | UnresolvedTrack | null) => void;
175
177
  }
176
178
  /**
177
179
  * The Bot client Options needed for the manager
@@ -4,7 +4,7 @@ import type { Base64 } from "./Utils.js";
4
4
  /** Sourcenames provided by lavalink server */
5
5
  export type LavalinkSourceNames = "youtube" | "youtubemusic" | "soundcloud" | "bandcamp" | "twitch";
6
6
  /** Source Names provided by lava src plugin */
7
- export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts";
7
+ export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts" | "vkmusic" | "tidal" | "qobuz";
8
8
  /** Source Names provided by jiosaavan plugin */
9
9
  export type LavalinkPlugin_JioSaavn_SourceNames = "jiosaavn";
10
10
  /** The SourceNames provided by lavalink */
@@ -11,7 +11,7 @@ export type Opaque<T, K> = T & {
11
11
  export type IntegerNumber = Opaque<number, 'Int'>;
12
12
  /** Opqaue tyep for floatnumber */
13
13
  export type FloatNumber = Opaque<number, 'Float'>;
14
- export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec";
14
+ export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec" | "tdsearch" | "tdrec" | "qbsearch" | "qbisrc" | "qbrec";
15
15
  export type LavaSrcSearchPlatform = LavaSrcSearchPlatformBase | "ftts";
16
16
  export type JioSaavnSearchPlatform = "jssearch" | "jsrec";
17
17
  export type DuncteSearchPlatform = "speak" | "phsearch" | "pornhub" | "porn" | "tts";
@@ -20,9 +20,9 @@ export type LavalinkClientSearchPlatformResolve = "bandcamp" | "bc";
20
20
  export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | JioSaavnSearchPlatform | LavalinkClientSearchPlatform;
21
21
  export type ClientCustomSearchPlatformUtils = "local" | "http" | "https" | "link" | "uri";
22
22
  export type ClientSearchPlatform = ClientCustomSearchPlatformUtils | // for file/link requests
23
- "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk music" | "vkmusic" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn";
23
+ "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk" | "vk music" | "vkmusic" | "tidal" | "tidal music" | "qobuz" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn" | "td" | "tidal" | "tdrec";
24
24
  export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
25
- export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "TwitchTv" | "vimeo";
25
+ export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "tidal" | "TwitchTv" | "vimeo";
26
26
  export interface PlaylistInfo {
27
27
  /** The playlist name */
28
28
  name: string;
@@ -92,13 +92,13 @@ export interface TrackEndEvent extends PlayerEvent {
92
92
  export interface TrackExceptionEvent extends PlayerEvent {
93
93
  type: "TrackExceptionEvent";
94
94
  exception?: Exception;
95
- tracK: LavalinkTrack;
95
+ track: LavalinkTrack;
96
96
  error: string;
97
97
  }
98
98
  export interface TrackStuckEvent extends PlayerEvent {
99
99
  type: "TrackStuckEvent";
100
100
  thresholdMs: number;
101
- tracK: LavalinkTrack;
101
+ track: LavalinkTrack;
102
102
  }
103
103
  export interface WebSocketClosedEvent extends PlayerEvent {
104
104
  type: "WebSocketClosedEvent";
@@ -112,4 +112,4 @@ export declare class MiniMap<K, V> extends Map<K, V> {
112
112
  map<T>(fn: (value: V, key: K, miniMap: this) => T): T[];
113
113
  map<This, T>(fn: (this: This, value: V, key: K, miniMap: this) => T, thisArg: This): T[];
114
114
  }
115
- export declare function queueTrackEnd(player: Player): Promise<Track>;
115
+ export declare function queueTrackEnd(player: Player, dontShiftQueue?: boolean): Promise<Track>;
@@ -302,6 +302,9 @@ export class ManagerUtils {
302
302
  if (SourceLinksRegexes.jiosaavn.test(queryString) && !node.info?.sourceManagers?.includes("jiosaavn")) {
303
303
  throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'jiosaavn' (via jiosaavn-plugin) enabled");
304
304
  }
305
+ if (SourceLinksRegexes.tidal.test(queryString) && !node.info?.sourceManagers?.includes("tidal")) {
306
+ throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'tidal' enabled");
307
+ }
305
308
  return;
306
309
  }
307
310
  transformQuery(query) {
@@ -366,6 +369,12 @@ export class ManagerUtils {
366
369
  if (source === "speak" && !node.info?.plugins?.find(c => c.name.toLowerCase().includes(LavalinkPlugins.DuncteBot_Plugin.toLowerCase()))) {
367
370
  throw new Error("Lavalink Node has not 'speak' enabled, which is required to have 'speak' work");
368
371
  }
372
+ if (source === "tdsearch" && !node.info?.sourceManagers?.includes("tidal")) {
373
+ throw new Error("Lavalink Node has not 'tidal' enabled, which is required to have 'tdsearch' work");
374
+ }
375
+ if (source === "tdrec" && !node.info?.sourceManagers?.includes("tidal")) {
376
+ throw new Error("Lavalink Node has not 'tidal' enabled, which is required to have 'tdrec' work");
377
+ }
369
378
  if (source === "tts" && !node.info?.plugins?.find(c => c.name.toLowerCase().includes(LavalinkPlugins.GoogleCloudTTS.toLowerCase()))) {
370
379
  throw new Error("Lavalink Node has not 'tts' enabled, which is required to have 'tts' work");
371
380
  }
@@ -381,6 +390,21 @@ export class ManagerUtils {
381
390
  if (source === "ytsearch" && !node.info?.sourceManagers?.includes("youtube")) {
382
391
  throw new Error("Lavalink Node has not 'youtube' enabled, which is required to have 'ytsearch' work");
383
392
  }
393
+ if (source === "vksearch" && !node.info?.sourceManagers?.includes("vkmusic")) {
394
+ throw new Error("Lavalink Node has not 'vkmusic' enabled, which is required to have 'vksearch' work");
395
+ }
396
+ if (source === "vkrec" && !node.info?.sourceManagers?.includes("vkmusic")) {
397
+ throw new Error("Lavalink Node has not 'vkmusic' enabled, which is required to have 'vkrec' work");
398
+ }
399
+ if (source === "qbsearch" && !node.info?.sourceManagers?.includes("qobuz")) {
400
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbsearch' work");
401
+ }
402
+ if (source === "qbisrc" && !node.info?.sourceManagers?.includes("qobuz")) {
403
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbisrc' work");
404
+ }
405
+ if (source === "qbrec" && !node.info?.sourceManagers?.includes("qobuz")) {
406
+ throw new Error("Lavalink Node has not 'qobuz' enabled, which is required to have 'qbrec' work");
407
+ }
384
408
  return;
385
409
  }
386
410
  }
@@ -411,7 +435,7 @@ export class MiniMap extends Map {
411
435
  });
412
436
  }
413
437
  }
414
- export async function queueTrackEnd(player) {
438
+ export async function queueTrackEnd(player, dontShiftQueue = false) {
415
439
  if (player.queue.current && !player.queue.current?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue.
416
440
  player.queue.previous.unshift(player.queue.current);
417
441
  if (player.queue.previous.length > player.queue.options.maxPreviousTracks)
@@ -421,10 +445,10 @@ export async function queueTrackEnd(player) {
421
445
  // and if repeatMode == queue, add it back to the queue!
422
446
  if (player.repeatMode === "queue" && player.queue.current)
423
447
  player.queue.tracks.push(player.queue.current);
424
- // change the current Track to the next upcoming one
425
- const nextSong = player.queue.tracks.shift();
448
+ // change the current Track to the next upcoming one
449
+ const nextSong = dontShiftQueue ? null : player.queue.tracks.shift();
426
450
  try {
427
- if (player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
451
+ if (nextSong && player.LavalinkManager.utils.isUnresolvedTrack(nextSong))
428
452
  await nextSong.resolve(player);
429
453
  player.queue.current = nextSong || null;
430
454
  // save it in the DB
@@ -441,7 +465,7 @@ export async function queueTrackEnd(player) {
441
465
  }
442
466
  player.LavalinkManager.emit("trackError", player, player.queue.current, error);
443
467
  // try to play the next track if possible
444
- if (player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
468
+ if (!dontShiftQueue && player.LavalinkManager.options?.autoSkipOnResolveError === true && player.queue.tracks[0])
445
469
  return queueTrackEnd(player);
446
470
  }
447
471
  // return the new current Track
@@ -172,6 +172,8 @@ export interface LavalinkManagerEvents {
172
172
  * @event Manager#LyricsNotFound
173
173
  */
174
174
  "LyricsNotFound": (player: Player, track: Track | UnresolvedTrack | null, payload: LyricsNotFoundEvent) => void;
175
+ "playerResumed": (player: Player, track: Track | UnresolvedTrack | null) => void;
176
+ "playerPaused": (player: Player, track: Track | UnresolvedTrack | null) => void;
175
177
  }
176
178
  /**
177
179
  * The Bot client Options needed for the manager
@@ -4,7 +4,7 @@ import type { Base64 } from "./Utils";
4
4
  /** Sourcenames provided by lavalink server */
5
5
  export type LavalinkSourceNames = "youtube" | "youtubemusic" | "soundcloud" | "bandcamp" | "twitch";
6
6
  /** Source Names provided by lava src plugin */
7
- export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts";
7
+ export type LavalinkPlugin_LavaSrc_SourceNames = "deezer" | "spotify" | "applemusic" | "yandexmusic" | "flowery-tts" | "vkmusic" | "tidal" | "qobuz";
8
8
  /** Source Names provided by jiosaavan plugin */
9
9
  export type LavalinkPlugin_JioSaavn_SourceNames = "jiosaavn";
10
10
  /** The SourceNames provided by lavalink */
@@ -11,7 +11,7 @@ export type Opaque<T, K> = T & {
11
11
  export type IntegerNumber = Opaque<number, 'Int'>;
12
12
  /** Opqaue tyep for floatnumber */
13
13
  export type FloatNumber = Opaque<number, 'Float'>;
14
- export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec";
14
+ export type LavaSrcSearchPlatformBase = "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec" | "tdsearch" | "tdrec" | "qbsearch" | "qbisrc" | "qbrec";
15
15
  export type LavaSrcSearchPlatform = LavaSrcSearchPlatformBase | "ftts";
16
16
  export type JioSaavnSearchPlatform = "jssearch" | "jsrec";
17
17
  export type DuncteSearchPlatform = "speak" | "phsearch" | "pornhub" | "porn" | "tts";
@@ -20,9 +20,9 @@ export type LavalinkClientSearchPlatformResolve = "bandcamp" | "bc";
20
20
  export type LavalinkSearchPlatform = "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | LavaSrcSearchPlatform | DuncteSearchPlatform | JioSaavnSearchPlatform | LavalinkClientSearchPlatform;
21
21
  export type ClientCustomSearchPlatformUtils = "local" | "http" | "https" | "link" | "uri";
22
22
  export type ClientSearchPlatform = ClientCustomSearchPlatformUtils | // for file/link requests
23
- "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk music" | "vkmusic" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn";
23
+ "youtube" | "yt" | "youtube music" | "youtubemusic" | "ytm" | "musicyoutube" | "music youtube" | "soundcloud" | "sc" | "am" | "apple music" | "applemusic" | "apple" | "musicapple" | "music apple" | "sp" | "spsuggestion" | "spotify" | "spotify.com" | "spotifycom" | "dz" | "deezer" | "yandex" | "yandex music" | "yandexmusic" | "vk" | "vk music" | "vkmusic" | "tidal" | "tidal music" | "qobuz" | "flowerytts" | "flowery" | "flowery.tts" | LavalinkClientSearchPlatformResolve | LavalinkClientSearchPlatform | "js" | "jiosaavn" | "td" | "tidal" | "tdrec";
24
24
  export type SearchPlatform = LavalinkSearchPlatform | ClientSearchPlatform;
25
- export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "TwitchTv" | "vimeo";
25
+ export type SourcesRegex = "YoutubeRegex" | "YoutubeMusicRegex" | "SoundCloudRegex" | "SoundCloudMobileRegex" | "DeezerTrackRegex" | "DeezerArtistRegex" | "DeezerEpisodeRegex" | "DeezerMixesRegex" | "DeezerPageLinkRegex" | "DeezerPlaylistRegex" | "DeezerAlbumRegex" | "AllDeezerRegex" | "AllDeezerRegexWithoutPageLink" | "SpotifySongRegex" | "SpotifyPlaylistRegex" | "SpotifyArtistRegex" | "SpotifyEpisodeRegex" | "SpotifyShowRegex" | "SpotifyAlbumRegex" | "AllSpotifyRegex" | "mp3Url" | "m3uUrl" | "m3u8Url" | "mp4Url" | "m4aUrl" | "wavUrl" | "aacpUrl" | "tiktok" | "mixcloud" | "musicYandex" | "radiohost" | "bandcamp" | "jiosaavn" | "appleMusic" | "tidal" | "TwitchTv" | "vimeo";
26
26
  export interface PlaylistInfo {
27
27
  /** The playlist name */
28
28
  name: string;
@@ -92,13 +92,13 @@ export interface TrackEndEvent extends PlayerEvent {
92
92
  export interface TrackExceptionEvent extends PlayerEvent {
93
93
  type: "TrackExceptionEvent";
94
94
  exception?: Exception;
95
- tracK: LavalinkTrack;
95
+ track: LavalinkTrack;
96
96
  error: string;
97
97
  }
98
98
  export interface TrackStuckEvent extends PlayerEvent {
99
99
  type: "TrackStuckEvent";
100
100
  thresholdMs: number;
101
- tracK: LavalinkTrack;
101
+ track: LavalinkTrack;
102
102
  }
103
103
  export interface WebSocketClosedEvent extends PlayerEvent {
104
104
  type: "WebSocketClosedEvent";
@@ -112,4 +112,4 @@ export declare class MiniMap<K, V> extends Map<K, V> {
112
112
  map<T>(fn: (value: V, key: K, miniMap: this) => T): T[];
113
113
  map<This, T>(fn: (this: This, value: V, key: K, miniMap: this) => T, thisArg: This): T[];
114
114
  }
115
- export declare function queueTrackEnd(player: Player): Promise<Track>;
115
+ export declare function queueTrackEnd(player: Player, dontShiftQueue?: boolean): Promise<Track>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavalink-client",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -58,19 +58,19 @@
58
58
  },
59
59
  "homepage": "https://tomato6966.github.io/lavalink-client/",
60
60
  "devDependencies": {
61
- "@eslint/eslintrc": "^3.2.0",
62
- "@eslint/js": "^9.20.0",
63
- "@types/node": "^22.13.4",
64
- "@types/ws": "^8.5.14",
65
- "@typescript-eslint/eslint-plugin": "^8.24.1",
66
- "@typescript-eslint/parser": "^8.24.1",
67
- "eslint": "^9.20.1",
68
- "tsc-alias": "^1.8.10",
69
- "typescript": "^5.7.3"
61
+ "@eslint/eslintrc": "^3.3.1",
62
+ "@eslint/js": "^9.25.0",
63
+ "@types/node": "^22.14.1",
64
+ "@types/ws": "^8.18.1",
65
+ "@typescript-eslint/eslint-plugin": "^8.30.1",
66
+ "@typescript-eslint/parser": "^8.30.1",
67
+ "eslint": "^9.25.0",
68
+ "tsc-alias": "^1.8.15",
69
+ "typescript": "^5.8.3"
70
70
  },
71
71
  "dependencies": {
72
72
  "tslib": "^2.8.1",
73
- "ws": "^8.18.0"
73
+ "ws": "^8.18.1"
74
74
  },
75
75
  "engines": {
76
76
  "node": ">=18.0.0",