lavalink-client 2.9.0 → 2.9.2

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.
package/README.md CHANGED
@@ -44,7 +44,7 @@
44
44
 
45
45
  ## 📦 Installation
46
46
 
47
- **Latest Stable Version: `v2.5.x`**
47
+ **Latest Stable Version: `v2.9.x`**
48
48
 
49
49
  <details>
50
50
  <summary><strong>👉 via NPM</strong></summary>
@@ -359,6 +359,7 @@ This client powers various Discord bots:
359
359
  - [All Time Bot](https://top.gg/bot/1163027457671180418) (@PeterGamez)
360
360
  - [BeatDock](https://github.com/lazaroagomez/BeatDock) (@lazaroagomez)
361
361
  - [Nazha](https://top.gg/bot/1124681788070055967) (@Nazha-Team)
362
+ - [Arii Music](https://arimusic.me/) (@friston_ae)
362
363
 
363
364
  ---
364
365
 
package/dist/index.d.mts CHANGED
@@ -417,7 +417,19 @@ declare function parseLavalinkConnUrl(connectionUrl: string): {
417
417
  declare class ManagerUtils {
418
418
  LavalinkManager: LavalinkManager | undefined;
419
419
  constructor(LavalinkManager?: LavalinkManager);
420
+ /**
421
+ * Builds a pluginInfo object based on the provided data, extracting relevant information from the data and clientData parameters. This function is used to construct the pluginInfo property for tracks, allowing for consistent handling of plugin-related information across different track sources and formats.
422
+ * @param data
423
+ * @param clientData
424
+ * @returns
425
+ */
420
426
  buildPluginInfo(data: any, clientData?: any): any;
427
+ /**
428
+ * Builds a Track object from the provided data and requester information. It validates the presence of required properties in the data, transforms the requester using a custom transformer function if provided, and constructs a Track object with the appropriate properties and plugin information. The function also includes error handling to ensure that the input data is valid and provides debug information if track building fails.
429
+ * @param data
430
+ * @param requester
431
+ * @returns
432
+ */
421
433
  buildTrack(data: LavalinkTrack | Track, requester: unknown): Track;
422
434
  /**
423
435
  * Builds a UnresolvedTrack to be resolved before being played .
@@ -430,6 +442,11 @@ declare class ManagerUtils {
430
442
  * @param data
431
443
  */
432
444
  isNode(data: LavalinkNode): boolean;
445
+ /**
446
+ * Gets the transformed requester based on the LavalinkManager options. If a custom requester transformer function is provided in the player options, it applies that function to the requester; otherwise, it returns the requester as is. The function also includes error handling to catch any exceptions that may occur during the transformation process and emits a debug event if the transformation fails.
447
+ * @param requester
448
+ * @returns
449
+ */
433
450
  getTransformedRequester(requester: unknown): unknown;
434
451
  /**
435
452
  * Validate if a data is equal to node options
@@ -470,18 +487,73 @@ declare class ManagerUtils {
470
487
  * @param track
471
488
  */
472
489
  isUnresolvedTrackQuery(data: UnresolvedQuery): boolean;
490
+ /**
491
+ * Gets the closest track by resolving the provided UnresolvedTrack using the getClosestTrack function. It includes error handling to catch any exceptions that may occur during the resolution process and emits a debug event if the resolution fails. The function returns a Promise that resolves to a Track object if successful, or undefined if no closest track is found.
492
+ * @param data
493
+ * @param player
494
+ * @returns
495
+ */
473
496
  getClosestTrack(data: UnresolvedTrack, player: Player): Promise<Track | undefined>;
474
- validateQueryString(node: LavalinkNode, queryString: string, sourceString?: LavalinkSearchPlatform): void;
497
+ /**
498
+ * Validates the query string against various criteria, including checking for empty strings, length limits for specific sources, blacklisted links or words, and ensuring that the Lavalink node has the necessary source managers enabled for the provided query. The function also includes debug event emissions to assist with troubleshooting and understanding the validation process.
499
+ * @param node
500
+ * @param queryString
501
+ * @param sourceString
502
+ * @returns
503
+ */
504
+ validateQueryString(node: LavalinkNode, queryString: string, sourceString?: SearchPlatform): void;
505
+ /**
506
+ * Finds the source of a query string by checking if it starts with a valid source prefix defined in the DefaultSources object. If a valid source prefix is found, it returns the corresponding SearchPlatform; otherwise, it returns null. This function is useful for determining the intended search platform for a given query string, allowing for more accurate search results when the user specifies a source (e.g., "ytsearch:Never Gonna Give You Up" would indicate that the search should be performed on YouTube).
507
+ * @param queryString
508
+ * @returns
509
+ */
510
+ findSourceOfQuery(queryString: string): SearchPlatform;
511
+ /**
512
+ * Extracts the source from the query if it starts with a valid source prefix (e.g., "ytsearch:") and updates the searchQuery object accordingly.
513
+ * @param searchQuery
514
+ * @returns The updated searchQuery object with the extracted source and modified query string.
515
+ */
516
+ extractSourceOfQuery<T extends {
517
+ query: string;
518
+ source?: string;
519
+ }>(searchQuery: T): T;
520
+ /**
521
+ * Converts a string to lowercase if the input is a string, otherwise returns the input as is. This is useful for ensuring that search platform identifiers are case-insensitive while allowing other types of input to pass through unchanged.
522
+ * @param input
523
+ * @returns
524
+ */
525
+ typedLowerCase<T extends unknown>(input: T): T;
526
+ /**
527
+ * Transforms a search query by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, and the determined search platform to be used for the search operation.
528
+ * @param query
529
+ * @returns
530
+ */
475
531
  transformQuery(query: SearchQuery): {
476
532
  query: string;
477
- extraQueryUrlParams: URLSearchParams;
478
- source: any;
533
+ extraQueryUrlParams: any;
534
+ source: SearchPlatform;
479
535
  };
536
+ /**
537
+ * Transforms a LavaSearchQuery by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, the determined search platform to be used for the search operation, and the types of search (track, playlist, artist, album, text) to be performed.
538
+ * @param query
539
+ * @returns
540
+ */
480
541
  transformLavaSearchQuery(query: LavaSearchQuery): {
542
+ query: never;
543
+ types: any[];
544
+ extraQueryUrlParams: any;
545
+ source: SearchPlatform;
546
+ } | {
481
547
  query: string;
482
548
  types: string[];
483
- source: any;
549
+ source: "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec" | "tdsearch" | "tdrec" | "qbsearch" | "qbisrc" | "qbrec" | "pdsearch" | "pdisrc" | "pdrec" | "ftts" | "speak" | "phsearch" | "pornhub" | "porn" | "tts" | "jssearch" | "jsrec" | "local" | "http" | "https" | "link" | "uri" | "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" | "pandora" | "pd" | "pandora music" | "pandoramusic" | "flowerytts" | "flowery" | "flowery.tts" | "bandcamp" | "bc" | "js" | "jiosaavn" | "td";
484
550
  };
551
+ /**
552
+ * Validates the provided source string against the capabilities of the Lavalink node. It checks if the source string is supported by the node's enabled source managers and plugins, throwing errors if any required sources or plugins are missing for the specified search platform. This ensures that search queries are only executed with compatible sources based on the node's configuration.
553
+ * @param node
554
+ * @param sourceString
555
+ * @returns
556
+ */
485
557
  validateSourceString(node: LavalinkNode, sourceString: SearchPlatform): void;
486
558
  }
487
559
  /**
@@ -2627,6 +2699,14 @@ declare class Player {
2627
2699
  * @param options
2628
2700
  */
2629
2701
  play(options?: Partial<PlayOptions>): any;
2702
+ /**
2703
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2704
+ */
2705
+ oldJSON: PlayerJson;
2706
+ /**
2707
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2708
+ */
2709
+ triggerPlayerClientUpdate(): void;
2630
2710
  /**
2631
2711
  * Set the Volume for the Player
2632
2712
  * @param volume The Volume in percent
@@ -3721,6 +3801,20 @@ interface LavalinkManagerEvents<CustomPlayerT extends Player = Player> {
3721
3801
  * @event Manager#playerUpdate
3722
3802
  */
3723
3803
  playerUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3804
+ /**
3805
+ * Always emits when the player (on client side) got updated via a function-call.
3806
+ * This is useful for example, if you want to save the player data on every update, or similar.
3807
+ * @event Manager#playerClientUpdate
3808
+ *
3809
+ * Emits only when you call one of those functions:
3810
+ * player.pause()
3811
+ * player.resume()
3812
+ * player.seek()
3813
+ * player.setRepeatMode()
3814
+ * player.setVolume()
3815
+ * and on every call of the filterManager.
3816
+ */
3817
+ playerClientUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3724
3818
  /**
3725
3819
  * Emitted when the player's selfMuted or serverMuted state changed (true -> false | false -> true)
3726
3820
  * @event Manager#playerMuteChange
@@ -3842,6 +3936,8 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3842
3936
  clientBasedPositionUpdateInterval?: number;
3843
3937
  /** What should be used as a searchPlatform, if no source was provided during the query */
3844
3938
  defaultSearchPlatform?: SearchPlatform;
3939
+ /** Allow custom sources which lavalink-client does not support (yet) */
3940
+ allowCustomSources?: boolean;
3845
3941
  /** Applies the volume via a filter, not via the lavalink volume transformer */
3846
3942
  applyVolumeAsFilter?: boolean;
3847
3943
  /** Transforms the saved data of a requested user */
@@ -3870,6 +3966,14 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3870
3966
  destroyAfterMs?: number;
3871
3967
  };
3872
3968
  useUnresolvedData?: boolean;
3969
+ /**
3970
+ * If true (default), when changing nodes, `setSponsorBlock()` with default categories is called
3971
+ * even if the user never explicitly set categories. This is needed so the SponsorBlock plugin
3972
+ * registers its event listeners (ChapterStarted/ChapterLoaded) on the new node.
3973
+ * Set to false to disable this behavior if you don't use SponsorBlock events.
3974
+ * @default true
3975
+ */
3976
+ enforceSponsorBlockRequestForEventEnablement?: boolean;
3873
3977
  }
3874
3978
  type DeepRequired<T> = {
3875
3979
  [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]>;
@@ -4016,6 +4120,7 @@ declare class LavalinkManager<CustomPlayerT extends Player = Player> extends Eve
4016
4120
  * applyVolumeAsFilter: false,
4017
4121
  * clientBasedPositionUpdateInterval: 150,
4018
4122
  * defaultSearchPlatform: "ytmsearch",
4123
+ * allowCustomSources: false,
4019
4124
  * volumeDecrementer: 0.75,
4020
4125
  * //requesterTransformer: YourRequesterTransformerFunction,
4021
4126
  * onDisconnect: {
package/dist/index.d.ts CHANGED
@@ -417,7 +417,19 @@ declare function parseLavalinkConnUrl(connectionUrl: string): {
417
417
  declare class ManagerUtils {
418
418
  LavalinkManager: LavalinkManager | undefined;
419
419
  constructor(LavalinkManager?: LavalinkManager);
420
+ /**
421
+ * Builds a pluginInfo object based on the provided data, extracting relevant information from the data and clientData parameters. This function is used to construct the pluginInfo property for tracks, allowing for consistent handling of plugin-related information across different track sources and formats.
422
+ * @param data
423
+ * @param clientData
424
+ * @returns
425
+ */
420
426
  buildPluginInfo(data: any, clientData?: any): any;
427
+ /**
428
+ * Builds a Track object from the provided data and requester information. It validates the presence of required properties in the data, transforms the requester using a custom transformer function if provided, and constructs a Track object with the appropriate properties and plugin information. The function also includes error handling to ensure that the input data is valid and provides debug information if track building fails.
429
+ * @param data
430
+ * @param requester
431
+ * @returns
432
+ */
421
433
  buildTrack(data: LavalinkTrack | Track, requester: unknown): Track;
422
434
  /**
423
435
  * Builds a UnresolvedTrack to be resolved before being played .
@@ -430,6 +442,11 @@ declare class ManagerUtils {
430
442
  * @param data
431
443
  */
432
444
  isNode(data: LavalinkNode): boolean;
445
+ /**
446
+ * Gets the transformed requester based on the LavalinkManager options. If a custom requester transformer function is provided in the player options, it applies that function to the requester; otherwise, it returns the requester as is. The function also includes error handling to catch any exceptions that may occur during the transformation process and emits a debug event if the transformation fails.
447
+ * @param requester
448
+ * @returns
449
+ */
433
450
  getTransformedRequester(requester: unknown): unknown;
434
451
  /**
435
452
  * Validate if a data is equal to node options
@@ -470,18 +487,73 @@ declare class ManagerUtils {
470
487
  * @param track
471
488
  */
472
489
  isUnresolvedTrackQuery(data: UnresolvedQuery): boolean;
490
+ /**
491
+ * Gets the closest track by resolving the provided UnresolvedTrack using the getClosestTrack function. It includes error handling to catch any exceptions that may occur during the resolution process and emits a debug event if the resolution fails. The function returns a Promise that resolves to a Track object if successful, or undefined if no closest track is found.
492
+ * @param data
493
+ * @param player
494
+ * @returns
495
+ */
473
496
  getClosestTrack(data: UnresolvedTrack, player: Player): Promise<Track | undefined>;
474
- validateQueryString(node: LavalinkNode, queryString: string, sourceString?: LavalinkSearchPlatform): void;
497
+ /**
498
+ * Validates the query string against various criteria, including checking for empty strings, length limits for specific sources, blacklisted links or words, and ensuring that the Lavalink node has the necessary source managers enabled for the provided query. The function also includes debug event emissions to assist with troubleshooting and understanding the validation process.
499
+ * @param node
500
+ * @param queryString
501
+ * @param sourceString
502
+ * @returns
503
+ */
504
+ validateQueryString(node: LavalinkNode, queryString: string, sourceString?: SearchPlatform): void;
505
+ /**
506
+ * Finds the source of a query string by checking if it starts with a valid source prefix defined in the DefaultSources object. If a valid source prefix is found, it returns the corresponding SearchPlatform; otherwise, it returns null. This function is useful for determining the intended search platform for a given query string, allowing for more accurate search results when the user specifies a source (e.g., "ytsearch:Never Gonna Give You Up" would indicate that the search should be performed on YouTube).
507
+ * @param queryString
508
+ * @returns
509
+ */
510
+ findSourceOfQuery(queryString: string): SearchPlatform;
511
+ /**
512
+ * Extracts the source from the query if it starts with a valid source prefix (e.g., "ytsearch:") and updates the searchQuery object accordingly.
513
+ * @param searchQuery
514
+ * @returns The updated searchQuery object with the extracted source and modified query string.
515
+ */
516
+ extractSourceOfQuery<T extends {
517
+ query: string;
518
+ source?: string;
519
+ }>(searchQuery: T): T;
520
+ /**
521
+ * Converts a string to lowercase if the input is a string, otherwise returns the input as is. This is useful for ensuring that search platform identifiers are case-insensitive while allowing other types of input to pass through unchanged.
522
+ * @param input
523
+ * @returns
524
+ */
525
+ typedLowerCase<T extends unknown>(input: T): T;
526
+ /**
527
+ * Transforms a search query by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, and the determined search platform to be used for the search operation.
528
+ * @param query
529
+ * @returns
530
+ */
475
531
  transformQuery(query: SearchQuery): {
476
532
  query: string;
477
- extraQueryUrlParams: URLSearchParams;
478
- source: any;
533
+ extraQueryUrlParams: any;
534
+ source: SearchPlatform;
479
535
  };
536
+ /**
537
+ * Transforms a LavaSearchQuery by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, the determined search platform to be used for the search operation, and the types of search (track, playlist, artist, album, text) to be performed.
538
+ * @param query
539
+ * @returns
540
+ */
480
541
  transformLavaSearchQuery(query: LavaSearchQuery): {
542
+ query: never;
543
+ types: any[];
544
+ extraQueryUrlParams: any;
545
+ source: SearchPlatform;
546
+ } | {
481
547
  query: string;
482
548
  types: string[];
483
- source: any;
549
+ source: "ytsearch" | "ytmsearch" | "scsearch" | "bcsearch" | "spsearch" | "sprec" | "amsearch" | "dzsearch" | "dzisrc" | "dzrec" | "ymsearch" | "ymrec" | "vksearch" | "vkrec" | "tdsearch" | "tdrec" | "qbsearch" | "qbisrc" | "qbrec" | "pdsearch" | "pdisrc" | "pdrec" | "ftts" | "speak" | "phsearch" | "pornhub" | "porn" | "tts" | "jssearch" | "jsrec" | "local" | "http" | "https" | "link" | "uri" | "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" | "pandora" | "pd" | "pandora music" | "pandoramusic" | "flowerytts" | "flowery" | "flowery.tts" | "bandcamp" | "bc" | "js" | "jiosaavn" | "td";
484
550
  };
551
+ /**
552
+ * Validates the provided source string against the capabilities of the Lavalink node. It checks if the source string is supported by the node's enabled source managers and plugins, throwing errors if any required sources or plugins are missing for the specified search platform. This ensures that search queries are only executed with compatible sources based on the node's configuration.
553
+ * @param node
554
+ * @param sourceString
555
+ * @returns
556
+ */
485
557
  validateSourceString(node: LavalinkNode, sourceString: SearchPlatform): void;
486
558
  }
487
559
  /**
@@ -2627,6 +2699,14 @@ declare class Player {
2627
2699
  * @param options
2628
2700
  */
2629
2701
  play(options?: Partial<PlayOptions>): any;
2702
+ /**
2703
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2704
+ */
2705
+ oldJSON: PlayerJson;
2706
+ /**
2707
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
2708
+ */
2709
+ triggerPlayerClientUpdate(): void;
2630
2710
  /**
2631
2711
  * Set the Volume for the Player
2632
2712
  * @param volume The Volume in percent
@@ -3721,6 +3801,20 @@ interface LavalinkManagerEvents<CustomPlayerT extends Player = Player> {
3721
3801
  * @event Manager#playerUpdate
3722
3802
  */
3723
3803
  playerUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3804
+ /**
3805
+ * Always emits when the player (on client side) got updated via a function-call.
3806
+ * This is useful for example, if you want to save the player data on every update, or similar.
3807
+ * @event Manager#playerClientUpdate
3808
+ *
3809
+ * Emits only when you call one of those functions:
3810
+ * player.pause()
3811
+ * player.resume()
3812
+ * player.seek()
3813
+ * player.setRepeatMode()
3814
+ * player.setVolume()
3815
+ * and on every call of the filterManager.
3816
+ */
3817
+ playerClientUpdate: (oldPlayerJson: PlayerJson, newPlayer: CustomPlayerT) => void;
3724
3818
  /**
3725
3819
  * Emitted when the player's selfMuted or serverMuted state changed (true -> false | false -> true)
3726
3820
  * @event Manager#playerMuteChange
@@ -3842,6 +3936,8 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3842
3936
  clientBasedPositionUpdateInterval?: number;
3843
3937
  /** What should be used as a searchPlatform, if no source was provided during the query */
3844
3938
  defaultSearchPlatform?: SearchPlatform;
3939
+ /** Allow custom sources which lavalink-client does not support (yet) */
3940
+ allowCustomSources?: boolean;
3845
3941
  /** Applies the volume via a filter, not via the lavalink volume transformer */
3846
3942
  applyVolumeAsFilter?: boolean;
3847
3943
  /** Transforms the saved data of a requested user */
@@ -3870,6 +3966,14 @@ interface ManagerPlayerOptions<CustomPlayerT extends Player = Player> {
3870
3966
  destroyAfterMs?: number;
3871
3967
  };
3872
3968
  useUnresolvedData?: boolean;
3969
+ /**
3970
+ * If true (default), when changing nodes, `setSponsorBlock()` with default categories is called
3971
+ * even if the user never explicitly set categories. This is needed so the SponsorBlock plugin
3972
+ * registers its event listeners (ChapterStarted/ChapterLoaded) on the new node.
3973
+ * Set to false to disable this behavior if you don't use SponsorBlock events.
3974
+ * @default true
3975
+ */
3976
+ enforceSponsorBlockRequestForEventEnablement?: boolean;
3873
3977
  }
3874
3978
  type DeepRequired<T> = {
3875
3979
  [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]>;
@@ -4016,6 +4120,7 @@ declare class LavalinkManager<CustomPlayerT extends Player = Player> extends Eve
4016
4120
  * applyVolumeAsFilter: false,
4017
4121
  * clientBasedPositionUpdateInterval: 150,
4018
4122
  * defaultSearchPlatform: "ytmsearch",
4123
+ * allowCustomSources: false,
4019
4124
  * volumeDecrementer: 0.75,
4020
4125
  * //requesterTransformer: YourRequesterTransformerFunction,
4021
4126
  * onDisconnect: {
package/dist/index.js CHANGED
@@ -604,12 +604,24 @@ var ManagerUtils = class {
604
604
  constructor(LavalinkManager2) {
605
605
  this.LavalinkManager = LavalinkManager2;
606
606
  }
607
+ /**
608
+ * Builds a pluginInfo object based on the provided data, extracting relevant information from the data and clientData parameters. This function is used to construct the pluginInfo property for tracks, allowing for consistent handling of plugin-related information across different track sources and formats.
609
+ * @param data
610
+ * @param clientData
611
+ * @returns
612
+ */
607
613
  buildPluginInfo(data, clientData = {}) {
608
614
  return {
609
615
  clientData,
610
616
  ...data.pluginInfo || data.plugin
611
617
  };
612
618
  }
619
+ /**
620
+ * Builds a Track object from the provided data and requester information. It validates the presence of required properties in the data, transforms the requester using a custom transformer function if provided, and constructs a Track object with the appropriate properties and plugin information. The function also includes error handling to ensure that the input data is valid and provides debug information if track building fails.
621
+ * @param data
622
+ * @param requester
623
+ * @returns
624
+ */
613
625
  buildTrack(data, requester) {
614
626
  if (!data?.encoded || typeof data.encoded !== "string")
615
627
  throw new RangeError("Argument 'data.encoded' must be present.");
@@ -707,6 +719,11 @@ var ManagerUtils = class {
707
719
  return false;
708
720
  return true;
709
721
  }
722
+ /**
723
+ * Gets the transformed requester based on the LavalinkManager options. If a custom requester transformer function is provided in the player options, it applies that function to the requester; otherwise, it returns the requester as is. The function also includes error handling to catch any exceptions that may occur during the transformation process and emits a debug event if the transformation fails.
724
+ * @param requester
725
+ * @returns
726
+ */
710
727
  getTransformedRequester(requester) {
711
728
  try {
712
729
  return typeof this.LavalinkManager?.options?.playerOptions?.requesterTransformer === "function" ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer(requester) : requester;
@@ -795,6 +812,12 @@ var ManagerUtils = class {
795
812
  isUnresolvedTrackQuery(data) {
796
813
  return typeof data === "object" && !("info" in data) && typeof data.title === "string";
797
814
  }
815
+ /**
816
+ * Gets the closest track by resolving the provided UnresolvedTrack using the getClosestTrack function. It includes error handling to catch any exceptions that may occur during the resolution process and emits a debug event if the resolution fails. The function returns a Promise that resolves to a Track object if successful, or undefined if no closest track is found.
817
+ * @param data
818
+ * @param player
819
+ * @returns
820
+ */
798
821
  async getClosestTrack(data, player) {
799
822
  try {
800
823
  return getClosestTrack(data, player);
@@ -810,6 +833,13 @@ var ManagerUtils = class {
810
833
  throw e;
811
834
  }
812
835
  }
836
+ /**
837
+ * Validates the query string against various criteria, including checking for empty strings, length limits for specific sources, blacklisted links or words, and ensuring that the Lavalink node has the necessary source managers enabled for the provided query. The function also includes debug event emissions to assist with troubleshooting and understanding the validation process.
838
+ * @param node
839
+ * @param queryString
840
+ * @param sourceString
841
+ * @returns
842
+ */
813
843
  validateQueryString(node, queryString, sourceString) {
814
844
  if (!node.info) throw new Error("No Lavalink Node was provided");
815
845
  if (node._checkForSources && !node.info.sourceManagers?.length)
@@ -897,24 +927,84 @@ var ManagerUtils = class {
897
927
  }
898
928
  return;
899
929
  }
900
- transformQuery(query) {
901
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
902
- const Query = {
903
- query: typeof query === "string" ? query : query.query,
904
- extraQueryUrlParams: typeof query !== "string" ? query.extraQueryUrlParams : void 0,
905
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
906
- };
907
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
930
+ /**
931
+ * Finds the source of a query string by checking if it starts with a valid source prefix defined in the DefaultSources object. If a valid source prefix is found, it returns the corresponding SearchPlatform; otherwise, it returns null. This function is useful for determining the intended search platform for a given query string, allowing for more accurate search results when the user specifies a source (e.g., "ytsearch:Never Gonna Give You Up" would indicate that the search should be performed on YouTube).
932
+ * @param queryString
933
+ * @returns
934
+ */
935
+ findSourceOfQuery(queryString) {
936
+ const foundSource = Object.keys(DefaultSources).find((source) => queryString?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
908
937
  if (foundSource && !["https", "http"].includes(foundSource) && DefaultSources[foundSource]) {
909
- Query.source = DefaultSources[foundSource];
910
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
938
+ return foundSource;
939
+ }
940
+ return null;
941
+ }
942
+ /**
943
+ * Extracts the source from the query if it starts with a valid source prefix (e.g., "ytsearch:") and updates the searchQuery object accordingly.
944
+ * @param searchQuery
945
+ * @returns The updated searchQuery object with the extracted source and modified query string.
946
+ */
947
+ extractSourceOfQuery(searchQuery) {
948
+ const foundSource = this.findSourceOfQuery(searchQuery.query);
949
+ if (foundSource) {
950
+ searchQuery.source = DefaultSources[foundSource];
951
+ searchQuery.query = searchQuery.query.slice(`${foundSource}:`.length, searchQuery.query.length);
911
952
  }
912
- return Query;
953
+ return searchQuery;
954
+ }
955
+ /**
956
+ * Converts a string to lowercase if the input is a string, otherwise returns the input as is. This is useful for ensuring that search platform identifiers are case-insensitive while allowing other types of input to pass through unchanged.
957
+ * @param input
958
+ * @returns
959
+ */
960
+ typedLowerCase(input) {
961
+ if (!input) return input;
962
+ if (typeof input === "string") return input.toLowerCase();
963
+ return input;
913
964
  }
965
+ /**
966
+ * Transforms a search query by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, and the determined search platform to be used for the search operation.
967
+ * @param query
968
+ * @returns
969
+ */
970
+ transformQuery(query) {
971
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
972
+ if (typeof query === "string") {
973
+ const Query = {
974
+ query,
975
+ extraQueryUrlParams: void 0,
976
+ source: typedDefault
977
+ };
978
+ return this.extractSourceOfQuery(Query);
979
+ }
980
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
981
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
982
+ return this.extractSourceOfQuery({
983
+ query: query.query,
984
+ extraQueryUrlParams: query.extraQueryUrlParams,
985
+ source: validSourceExtracted ?? providedSource ?? typedDefault
986
+ });
987
+ }
988
+ /**
989
+ * Transforms a LavaSearchQuery by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, the determined search platform to be used for the search operation, and the types of search (track, playlist, artist, album, text) to be performed.
990
+ * @param query
991
+ * @returns
992
+ */
914
993
  transformLavaSearchQuery(query) {
915
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
994
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
995
+ if (typeof query === "string") {
996
+ const Query2 = {
997
+ query,
998
+ types: [],
999
+ extraQueryUrlParams: void 0,
1000
+ source: typedDefault
1001
+ };
1002
+ return this.extractSourceOfQuery(Query2);
1003
+ }
1004
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
1005
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
916
1006
  const Query = {
917
- query: typeof query === "string" ? query : query.query,
1007
+ query: query.query,
918
1008
  types: query.types ? ["track", "playlist", "artist", "album", "text"].filter(
919
1009
  (v) => query.types?.find((x) => x.toLowerCase().startsWith(v))
920
1010
  ) : [
@@ -924,19 +1014,23 @@ var ManagerUtils = class {
924
1014
  "album"
925
1015
  /*"text"*/
926
1016
  ],
927
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
1017
+ source: validSourceExtracted ?? providedSource ?? typedDefault
928
1018
  };
929
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query.toLowerCase().startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
930
- if (foundSource && DefaultSources[foundSource]) {
931
- Query.source = DefaultSources[foundSource];
932
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
933
- }
934
- return Query;
1019
+ return this.extractSourceOfQuery(Query);
935
1020
  }
1021
+ /**
1022
+ * Validates the provided source string against the capabilities of the Lavalink node. It checks if the source string is supported by the node's enabled source managers and plugins, throwing errors if any required sources or plugins are missing for the specified search platform. This ensures that search queries are only executed with compatible sources based on the node's configuration.
1023
+ * @param node
1024
+ * @param sourceString
1025
+ * @returns
1026
+ */
936
1027
  validateSourceString(node, sourceString) {
937
1028
  if (!sourceString) throw new Error(`No SourceString was provided`);
938
1029
  const source = DefaultSources[sourceString.toLowerCase().trim()];
939
- if (!source) throw new Error(`Lavalink Node SearchQuerySource: '${sourceString}' is not available`);
1030
+ if (!source && !!this.LavalinkManager.options.playerOptions.allowCustomSources)
1031
+ throw new Error(
1032
+ `Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`
1033
+ );
940
1034
  if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
941
1035
  if (!node._checkForSources) return;
942
1036
  if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) {
@@ -2487,12 +2581,13 @@ var LavalinkNode = class _LavalinkNode {
2487
2581
  if (!error) return;
2488
2582
  this.NodeManager.emit("error", this, error);
2489
2583
  this.reconnectionState = "IDLE" /* IDLE */;
2490
- this.reconnect();
2491
2584
  if (this.options.closeOnError) {
2492
2585
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
2493
2586
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
2494
2587
  this.socket?.close(500, "Node-Error - Force Reconnect");
2588
+ return;
2495
2589
  }
2590
+ this.reconnect();
2496
2591
  }
2497
2592
  /** @private util function for handling message events from websocket */
2498
2593
  async message(d) {
@@ -2716,7 +2811,7 @@ var LavalinkNode = class _LavalinkNode {
2716
2811
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2717
2812
  );
2718
2813
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2719
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2814
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2720
2815
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
2721
2816
  state: "log",
2722
2817
  message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -2754,7 +2849,7 @@ var LavalinkNode = class _LavalinkNode {
2754
2849
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2755
2850
  );
2756
2851
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2757
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2852
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2758
2853
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
2759
2854
  state: "log",
2760
2855
  message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -3814,6 +3909,7 @@ var FilterManager = class {
3814
3909
  }
3815
3910
  const now = performance.now();
3816
3911
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
3912
+ this.player.triggerPlayerClientUpdate();
3817
3913
  await this.player.node.updatePlayer({
3818
3914
  guildId: this.player.guildId,
3819
3915
  playerOptions: {
@@ -3908,7 +4004,7 @@ var FilterManager = class {
3908
4004
  this.filters.tremolo = false;
3909
4005
  this.filters.vibrato = false;
3910
4006
  this.filters.karaoke = false;
3911
- this.filters.karaoke = false;
4007
+ this.filters.vaporwave = false;
3912
4008
  this.filters.volume = false;
3913
4009
  this.filters.nodeLinkEcho = false;
3914
4010
  this.filters.nodeLinkChorus = false;
@@ -3989,7 +4085,7 @@ var FilterManager = class {
3989
4085
  this.data = this.data ?? {};
3990
4086
  this.filters.nightcore = false;
3991
4087
  this.filters.vaporwave = false;
3992
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, speed };
4088
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, speed };
3993
4089
  this.isCustomFilterActive();
3994
4090
  await this.applyPlayerFilters();
3995
4091
  return this;
@@ -4011,7 +4107,7 @@ var FilterManager = class {
4011
4107
  this.data = this.data ?? {};
4012
4108
  this.filters.nightcore = false;
4013
4109
  this.filters.vaporwave = false;
4014
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, pitch };
4110
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, pitch };
4015
4111
  this.isCustomFilterActive();
4016
4112
  await this.applyPlayerFilters();
4017
4113
  return this;
@@ -4033,7 +4129,7 @@ var FilterManager = class {
4033
4129
  this.data = this.data ?? {};
4034
4130
  this.filters.nightcore = false;
4035
4131
  this.filters.vaporwave = false;
4036
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, rate };
4132
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, rate };
4037
4133
  this.isCustomFilterActive();
4038
4134
  await this.applyPlayerFilters();
4039
4135
  return this;
@@ -4462,6 +4558,7 @@ var FilterManager = class {
4462
4558
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
4463
4559
  const now = performance.now();
4464
4560
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
4561
+ this.player.triggerPlayerClientUpdate();
4465
4562
  await this.player.node.updatePlayer({
4466
4563
  guildId: this.player.guildId,
4467
4564
  playerOptions: {
@@ -4618,7 +4715,7 @@ var Queue = class {
4618
4715
  * @param queueOptions
4619
4716
  */
4620
4717
  constructor(guildId, data = {}, QueueSaver2, queueOptions) {
4621
- this.queueChanges = queueOptions.queueChangesWatcher || null;
4718
+ this.queueChanges = queueOptions?.queueChangesWatcher || null;
4622
4719
  this.guildId = guildId;
4623
4720
  this.QueueSaver = QueueSaver2;
4624
4721
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
@@ -4669,7 +4766,7 @@ var Queue = class {
4669
4766
  ))
4670
4767
  this.previous.splice(
4671
4768
  0,
4672
- override ? this.tracks.length : 0,
4769
+ override ? this.previous.length : 0,
4673
4770
  ...data.previous.filter(
4674
4771
  (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4675
4772
  )
@@ -4684,8 +4781,8 @@ var Queue = class {
4684
4781
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
4685
4782
  */
4686
4783
  toJSON: () => {
4687
- if (this.previous.length > this.options.maxPreviousTracks)
4688
- this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4784
+ if (this.previous?.length > this.options?.maxPreviousTracks)
4785
+ this.previous?.splice(this.options?.maxPreviousTracks, this.previous.length);
4689
4786
  return {
4690
4787
  current: this.current ? { ...this.current } : null,
4691
4788
  previous: this.previous ? [...this.previous] : [],
@@ -5501,6 +5598,17 @@ var Player = class {
5501
5598
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5502
5599
  return this;
5503
5600
  }
5601
+ /**
5602
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5603
+ */
5604
+ oldJSON = this.toJSON();
5605
+ /**
5606
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5607
+ */
5608
+ triggerPlayerClientUpdate() {
5609
+ this.LavalinkManager.emit("playerClientUpdate", this.oldJSON, this);
5610
+ this.oldJSON = this.toJSON();
5611
+ }
5504
5612
  /**
5505
5613
  * Set the Volume for the Player
5506
5614
  * @param volume The Volume in percent
@@ -5521,6 +5629,7 @@ var Player = class {
5521
5629
  0
5522
5630
  )
5523
5631
  );
5632
+ this.triggerPlayerClientUpdate();
5524
5633
  const now = performance.now();
5525
5634
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
5526
5635
  this._emitDebugEvent("PlayerVolumeAsFilter" /* PlayerVolumeAsFilter */, {
@@ -5595,6 +5704,7 @@ var Player = class {
5595
5704
  this.paused = true;
5596
5705
  this.lastPositionChange = null;
5597
5706
  const now = performance.now();
5707
+ this.triggerPlayerClientUpdate();
5598
5708
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
5599
5709
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5600
5710
  this.LavalinkManager.emit("playerPaused", this, this.queue.current);
@@ -5607,6 +5717,7 @@ var Player = class {
5607
5717
  if (!this.paused) throw new Error("Player isn't paused - not able to resume.");
5608
5718
  this.paused = false;
5609
5719
  const now = performance.now();
5720
+ this.triggerPlayerClientUpdate();
5610
5721
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
5611
5722
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5612
5723
  this.LavalinkManager.emit("playerResumed", this, this.queue.current);
@@ -5627,6 +5738,7 @@ var Player = class {
5627
5738
  this.lastPositionChange = Date.now();
5628
5739
  this.lastPosition = position;
5629
5740
  const now = performance.now();
5741
+ this.triggerPlayerClientUpdate();
5630
5742
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
5631
5743
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5632
5744
  return this;
@@ -5639,6 +5751,7 @@ var Player = class {
5639
5751
  if (!["off", "track", "queue"].includes(repeatMode))
5640
5752
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
5641
5753
  this.repeatMode = repeatMode;
5754
+ this.triggerPlayerClientUpdate();
5642
5755
  return this;
5643
5756
  }
5644
5757
  /**
@@ -5893,7 +6006,7 @@ var Player = class {
5893
6006
  functionLayer: "Player > changeNode()"
5894
6007
  });
5895
6008
  });
5896
- } else {
6009
+ } else if (this.LavalinkManager.options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement !== false) {
5897
6010
  await this.setSponsorBlock().catch((error) => {
5898
6011
  this._emitDebugEvent("PlayerChangeNode" /* PlayerChangeNode */, {
5899
6012
  state: "error",
@@ -5989,7 +6102,7 @@ var Player = class {
5989
6102
  nodeId: this.node?.id,
5990
6103
  nodeSessionId: this.node?.sessionId,
5991
6104
  ping: this.ping,
5992
- queue: this.queue.utils.toJSON()
6105
+ queue: this.queue?.utils?.toJSON?.()
5993
6106
  };
5994
6107
  }
5995
6108
  };
@@ -6072,6 +6185,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6072
6185
  applyVolumeAsFilter: options?.playerOptions?.applyVolumeAsFilter ?? false,
6073
6186
  clientBasedPositionUpdateInterval: options?.playerOptions?.clientBasedPositionUpdateInterval ?? 100,
6074
6187
  defaultSearchPlatform: options?.playerOptions?.defaultSearchPlatform ?? "ytsearch",
6188
+ allowCustomSources: options?.playerOptions?.allowCustomSources ?? false,
6075
6189
  onDisconnect: {
6076
6190
  destroyPlayer: options?.playerOptions?.onDisconnect?.destroyPlayer ?? true,
6077
6191
  autoReconnect: options?.playerOptions?.onDisconnect?.autoReconnect ?? false,
@@ -6088,7 +6202,8 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6088
6202
  maxErrorsPerTime: {
6089
6203
  threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35e3,
6090
6204
  maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3
6091
- }
6205
+ },
6206
+ enforceSponsorBlockRequestForEventEnablement: options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement ?? true
6092
6207
  },
6093
6208
  linksWhitelist: options?.linksWhitelist ?? [],
6094
6209
  linksBlacklist: options?.linksBlacklist ?? [],
@@ -6188,6 +6303,7 @@ var LavalinkManager = class extends import_events2.EventEmitter {
6188
6303
  * applyVolumeAsFilter: false,
6189
6304
  * clientBasedPositionUpdateInterval: 150,
6190
6305
  * defaultSearchPlatform: "ytmsearch",
6306
+ * allowCustomSources: false,
6191
6307
  * volumeDecrementer: 0.75,
6192
6308
  * //requesterTransformer: YourRequesterTransformerFunction,
6193
6309
  * onDisconnect: {
package/dist/index.mjs CHANGED
@@ -540,12 +540,24 @@ var ManagerUtils = class {
540
540
  constructor(LavalinkManager2) {
541
541
  this.LavalinkManager = LavalinkManager2;
542
542
  }
543
+ /**
544
+ * Builds a pluginInfo object based on the provided data, extracting relevant information from the data and clientData parameters. This function is used to construct the pluginInfo property for tracks, allowing for consistent handling of plugin-related information across different track sources and formats.
545
+ * @param data
546
+ * @param clientData
547
+ * @returns
548
+ */
543
549
  buildPluginInfo(data, clientData = {}) {
544
550
  return {
545
551
  clientData,
546
552
  ...data.pluginInfo || data.plugin
547
553
  };
548
554
  }
555
+ /**
556
+ * Builds a Track object from the provided data and requester information. It validates the presence of required properties in the data, transforms the requester using a custom transformer function if provided, and constructs a Track object with the appropriate properties and plugin information. The function also includes error handling to ensure that the input data is valid and provides debug information if track building fails.
557
+ * @param data
558
+ * @param requester
559
+ * @returns
560
+ */
549
561
  buildTrack(data, requester) {
550
562
  if (!data?.encoded || typeof data.encoded !== "string")
551
563
  throw new RangeError("Argument 'data.encoded' must be present.");
@@ -643,6 +655,11 @@ var ManagerUtils = class {
643
655
  return false;
644
656
  return true;
645
657
  }
658
+ /**
659
+ * Gets the transformed requester based on the LavalinkManager options. If a custom requester transformer function is provided in the player options, it applies that function to the requester; otherwise, it returns the requester as is. The function also includes error handling to catch any exceptions that may occur during the transformation process and emits a debug event if the transformation fails.
660
+ * @param requester
661
+ * @returns
662
+ */
646
663
  getTransformedRequester(requester) {
647
664
  try {
648
665
  return typeof this.LavalinkManager?.options?.playerOptions?.requesterTransformer === "function" ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer(requester) : requester;
@@ -731,6 +748,12 @@ var ManagerUtils = class {
731
748
  isUnresolvedTrackQuery(data) {
732
749
  return typeof data === "object" && !("info" in data) && typeof data.title === "string";
733
750
  }
751
+ /**
752
+ * Gets the closest track by resolving the provided UnresolvedTrack using the getClosestTrack function. It includes error handling to catch any exceptions that may occur during the resolution process and emits a debug event if the resolution fails. The function returns a Promise that resolves to a Track object if successful, or undefined if no closest track is found.
753
+ * @param data
754
+ * @param player
755
+ * @returns
756
+ */
734
757
  async getClosestTrack(data, player) {
735
758
  try {
736
759
  return getClosestTrack(data, player);
@@ -746,6 +769,13 @@ var ManagerUtils = class {
746
769
  throw e;
747
770
  }
748
771
  }
772
+ /**
773
+ * Validates the query string against various criteria, including checking for empty strings, length limits for specific sources, blacklisted links or words, and ensuring that the Lavalink node has the necessary source managers enabled for the provided query. The function also includes debug event emissions to assist with troubleshooting and understanding the validation process.
774
+ * @param node
775
+ * @param queryString
776
+ * @param sourceString
777
+ * @returns
778
+ */
749
779
  validateQueryString(node, queryString, sourceString) {
750
780
  if (!node.info) throw new Error("No Lavalink Node was provided");
751
781
  if (node._checkForSources && !node.info.sourceManagers?.length)
@@ -833,24 +863,84 @@ var ManagerUtils = class {
833
863
  }
834
864
  return;
835
865
  }
836
- transformQuery(query) {
837
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
838
- const Query = {
839
- query: typeof query === "string" ? query : query.query,
840
- extraQueryUrlParams: typeof query !== "string" ? query.extraQueryUrlParams : void 0,
841
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
842
- };
843
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
866
+ /**
867
+ * Finds the source of a query string by checking if it starts with a valid source prefix defined in the DefaultSources object. If a valid source prefix is found, it returns the corresponding SearchPlatform; otherwise, it returns null. This function is useful for determining the intended search platform for a given query string, allowing for more accurate search results when the user specifies a source (e.g., "ytsearch:Never Gonna Give You Up" would indicate that the search should be performed on YouTube).
868
+ * @param queryString
869
+ * @returns
870
+ */
871
+ findSourceOfQuery(queryString) {
872
+ const foundSource = Object.keys(DefaultSources).find((source) => queryString?.toLowerCase?.()?.startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
844
873
  if (foundSource && !["https", "http"].includes(foundSource) && DefaultSources[foundSource]) {
845
- Query.source = DefaultSources[foundSource];
846
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
874
+ return foundSource;
875
+ }
876
+ return null;
877
+ }
878
+ /**
879
+ * Extracts the source from the query if it starts with a valid source prefix (e.g., "ytsearch:") and updates the searchQuery object accordingly.
880
+ * @param searchQuery
881
+ * @returns The updated searchQuery object with the extracted source and modified query string.
882
+ */
883
+ extractSourceOfQuery(searchQuery) {
884
+ const foundSource = this.findSourceOfQuery(searchQuery.query);
885
+ if (foundSource) {
886
+ searchQuery.source = DefaultSources[foundSource];
887
+ searchQuery.query = searchQuery.query.slice(`${foundSource}:`.length, searchQuery.query.length);
847
888
  }
848
- return Query;
889
+ return searchQuery;
890
+ }
891
+ /**
892
+ * Converts a string to lowercase if the input is a string, otherwise returns the input as is. This is useful for ensuring that search platform identifiers are case-insensitive while allowing other types of input to pass through unchanged.
893
+ * @param input
894
+ * @returns
895
+ */
896
+ typedLowerCase(input) {
897
+ if (!input) return input;
898
+ if (typeof input === "string") return input.toLowerCase();
899
+ return input;
849
900
  }
901
+ /**
902
+ * Transforms a search query by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, and the determined search platform to be used for the search operation.
903
+ * @param query
904
+ * @returns
905
+ */
906
+ transformQuery(query) {
907
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
908
+ if (typeof query === "string") {
909
+ const Query = {
910
+ query,
911
+ extraQueryUrlParams: void 0,
912
+ source: typedDefault
913
+ };
914
+ return this.extractSourceOfQuery(Query);
915
+ }
916
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
917
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
918
+ return this.extractSourceOfQuery({
919
+ query: query.query,
920
+ extraQueryUrlParams: query.extraQueryUrlParams,
921
+ source: validSourceExtracted ?? providedSource ?? typedDefault
922
+ });
923
+ }
924
+ /**
925
+ * Transforms a LavaSearchQuery by determining the appropriate search platform based on the query string and the default search platform specified in the LavalinkManager options. It checks if the query string starts with a valid source prefix and extracts it if present. The function returns an object containing the modified query string, any extra URL parameters, the determined search platform to be used for the search operation, and the types of search (track, playlist, artist, album, text) to be performed.
926
+ * @param query
927
+ * @returns
928
+ */
850
929
  transformLavaSearchQuery(query) {
851
- const sourceOfQuery = typeof query === "string" ? void 0 : DefaultSources[query.source?.trim?.()?.toLowerCase?.() ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()] ?? query.source?.trim?.()?.toLowerCase?.();
930
+ const typedDefault = this.typedLowerCase(this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform);
931
+ if (typeof query === "string") {
932
+ const Query2 = {
933
+ query,
934
+ types: [],
935
+ extraQueryUrlParams: void 0,
936
+ source: typedDefault
937
+ };
938
+ return this.extractSourceOfQuery(Query2);
939
+ }
940
+ const providedSource = query?.source?.trim?.()?.toLowerCase?.();
941
+ const validSourceExtracted = DefaultSources[providedSource ?? typedDefault];
852
942
  const Query = {
853
- query: typeof query === "string" ? query : query.query,
943
+ query: query.query,
854
944
  types: query.types ? ["track", "playlist", "artist", "album", "text"].filter(
855
945
  (v) => query.types?.find((x) => x.toLowerCase().startsWith(v))
856
946
  ) : [
@@ -860,19 +950,23 @@ var ManagerUtils = class {
860
950
  "album"
861
951
  /*"text"*/
862
952
  ],
863
- source: sourceOfQuery ?? this.LavalinkManager?.options?.playerOptions?.defaultSearchPlatform?.toLowerCase?.()
953
+ source: validSourceExtracted ?? providedSource ?? typedDefault
864
954
  };
865
- const foundSource = Object.keys(DefaultSources).find((source) => Query.query.toLowerCase().startsWith(`${source}:`.toLowerCase()))?.trim?.()?.toLowerCase?.();
866
- if (foundSource && DefaultSources[foundSource]) {
867
- Query.source = DefaultSources[foundSource];
868
- Query.query = Query.query.slice(`${foundSource}:`.length, Query.query.length);
869
- }
870
- return Query;
955
+ return this.extractSourceOfQuery(Query);
871
956
  }
957
+ /**
958
+ * Validates the provided source string against the capabilities of the Lavalink node. It checks if the source string is supported by the node's enabled source managers and plugins, throwing errors if any required sources or plugins are missing for the specified search platform. This ensures that search queries are only executed with compatible sources based on the node's configuration.
959
+ * @param node
960
+ * @param sourceString
961
+ * @returns
962
+ */
872
963
  validateSourceString(node, sourceString) {
873
964
  if (!sourceString) throw new Error(`No SourceString was provided`);
874
965
  const source = DefaultSources[sourceString.toLowerCase().trim()];
875
- if (!source) throw new Error(`Lavalink Node SearchQuerySource: '${sourceString}' is not available`);
966
+ if (!source && !!this.LavalinkManager.options.playerOptions.allowCustomSources)
967
+ throw new Error(
968
+ `Lavalink-Client does not support SearchQuerySource: '${sourceString}'. You can disable this check by setting 'ManagerOptions.PlayerOptions.allowCustomSources' to true`
969
+ );
876
970
  if (!node.info) throw new Error("Lavalink Node does not have any info cached yet, not ready yet!");
877
971
  if (!node._checkForSources) return;
878
972
  if (source === "amsearch" && !node.info?.sourceManagers?.includes("applemusic")) {
@@ -2423,12 +2517,13 @@ var LavalinkNode = class _LavalinkNode {
2423
2517
  if (!error) return;
2424
2518
  this.NodeManager.emit("error", this, error);
2425
2519
  this.reconnectionState = "IDLE" /* IDLE */;
2426
- this.reconnect();
2427
2520
  if (this.options.closeOnError) {
2428
2521
  if (this.heartBeatInterval) clearInterval(this.heartBeatInterval);
2429
2522
  if (this.pingTimeout) clearTimeout(this.pingTimeout);
2430
2523
  this.socket?.close(500, "Node-Error - Force Reconnect");
2524
+ return;
2431
2525
  }
2526
+ this.reconnect();
2432
2527
  }
2433
2528
  /** @private util function for handling message events from websocket */
2434
2529
  async message(d) {
@@ -2652,7 +2747,7 @@ var LavalinkNode = class _LavalinkNode {
2652
2747
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2653
2748
  );
2654
2749
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2655
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2750
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2656
2751
  this._emitDebugEvent("TrackStuckMaxTracksErroredPerTime" /* TrackStuckMaxTracksErroredPerTime */, {
2657
2752
  state: "log",
2658
2753
  message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -2690,7 +2785,7 @@ var LavalinkNode = class _LavalinkNode {
2690
2785
  (v) => Date.now() - v < this._LManager.options.playerOptions.maxErrorsPerTime?.threshold
2691
2786
  );
2692
2787
  player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]);
2693
- if (oldTimestamps.length > this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2788
+ if (oldTimestamps.length >= this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount) {
2694
2789
  this._emitDebugEvent("TrackErrorMaxTracksErroredPerTime" /* TrackErrorMaxTracksErroredPerTime */, {
2695
2790
  state: "log",
2696
2791
  message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this._LManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this._LManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`,
@@ -3750,6 +3845,7 @@ var FilterManager = class {
3750
3845
  }
3751
3846
  const now = performance.now();
3752
3847
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
3848
+ this.player.triggerPlayerClientUpdate();
3753
3849
  await this.player.node.updatePlayer({
3754
3850
  guildId: this.player.guildId,
3755
3851
  playerOptions: {
@@ -3844,7 +3940,7 @@ var FilterManager = class {
3844
3940
  this.filters.tremolo = false;
3845
3941
  this.filters.vibrato = false;
3846
3942
  this.filters.karaoke = false;
3847
- this.filters.karaoke = false;
3943
+ this.filters.vaporwave = false;
3848
3944
  this.filters.volume = false;
3849
3945
  this.filters.nodeLinkEcho = false;
3850
3946
  this.filters.nodeLinkChorus = false;
@@ -3925,7 +4021,7 @@ var FilterManager = class {
3925
4021
  this.data = this.data ?? {};
3926
4022
  this.filters.nightcore = false;
3927
4023
  this.filters.vaporwave = false;
3928
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, speed };
4024
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, speed };
3929
4025
  this.isCustomFilterActive();
3930
4026
  await this.applyPlayerFilters();
3931
4027
  return this;
@@ -3947,7 +4043,7 @@ var FilterManager = class {
3947
4043
  this.data = this.data ?? {};
3948
4044
  this.filters.nightcore = false;
3949
4045
  this.filters.vaporwave = false;
3950
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, pitch };
4046
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, pitch };
3951
4047
  this.isCustomFilterActive();
3952
4048
  await this.applyPlayerFilters();
3953
4049
  return this;
@@ -3969,7 +4065,7 @@ var FilterManager = class {
3969
4065
  this.data = this.data ?? {};
3970
4066
  this.filters.nightcore = false;
3971
4067
  this.filters.vaporwave = false;
3972
- this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, rate };
4068
+ this.data.timescale = { ...DEFAULT_FILTER_DATAS.timescale, ...this.data.timescale, rate };
3973
4069
  this.isCustomFilterActive();
3974
4070
  await this.applyPlayerFilters();
3975
4071
  return this;
@@ -4398,6 +4494,7 @@ var FilterManager = class {
4398
4494
  if (!this.player.node.sessionId) throw new Error("The Lavalink-Node is either not ready or not up to date");
4399
4495
  const now = performance.now();
4400
4496
  if (this.player.options.instaUpdateFiltersFix === true) this.filterUpdatedState = true;
4497
+ this.player.triggerPlayerClientUpdate();
4401
4498
  await this.player.node.updatePlayer({
4402
4499
  guildId: this.player.guildId,
4403
4500
  playerOptions: {
@@ -4554,7 +4651,7 @@ var Queue = class {
4554
4651
  * @param queueOptions
4555
4652
  */
4556
4653
  constructor(guildId, data = {}, QueueSaver2, queueOptions) {
4557
- this.queueChanges = queueOptions.queueChangesWatcher || null;
4654
+ this.queueChanges = queueOptions?.queueChangesWatcher || null;
4558
4655
  this.guildId = guildId;
4559
4656
  this.QueueSaver = QueueSaver2;
4560
4657
  this.options.maxPreviousTracks = this.QueueSaver?.options?.maxPreviousTracks ?? this.options.maxPreviousTracks;
@@ -4605,7 +4702,7 @@ var Queue = class {
4605
4702
  ))
4606
4703
  this.previous.splice(
4607
4704
  0,
4608
- override ? this.tracks.length : 0,
4705
+ override ? this.previous.length : 0,
4609
4706
  ...data.previous.filter(
4610
4707
  (track) => this.managerUtils.isTrack(track) || this.managerUtils.isUnresolvedTrack(track)
4611
4708
  )
@@ -4620,8 +4717,8 @@ var Queue = class {
4620
4717
  * @returns {{current:Track|null, previous:Track[], tracks:Track[]}}The Queue, but in a raw State, which allows easier handling for the QueueStoreManager
4621
4718
  */
4622
4719
  toJSON: () => {
4623
- if (this.previous.length > this.options.maxPreviousTracks)
4624
- this.previous.splice(this.options.maxPreviousTracks, this.previous.length);
4720
+ if (this.previous?.length > this.options?.maxPreviousTracks)
4721
+ this.previous?.splice(this.options?.maxPreviousTracks, this.previous.length);
4625
4722
  return {
4626
4723
  current: this.current ? { ...this.current } : null,
4627
4724
  previous: this.previous ? [...this.previous] : [],
@@ -5437,6 +5534,17 @@ var Player = class {
5437
5534
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5438
5535
  return this;
5439
5536
  }
5537
+ /**
5538
+ * The old JSON of the player, used for the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5539
+ */
5540
+ oldJSON = this.toJSON();
5541
+ /**
5542
+ * Emits the "playerClientUpdate" event, which is emitted on every update of the player via a function call, so that you can compare the old data with the new data and do something with it if you want to.
5543
+ */
5544
+ triggerPlayerClientUpdate() {
5545
+ this.LavalinkManager.emit("playerClientUpdate", this.oldJSON, this);
5546
+ this.oldJSON = this.toJSON();
5547
+ }
5440
5548
  /**
5441
5549
  * Set the Volume for the Player
5442
5550
  * @param volume The Volume in percent
@@ -5457,6 +5565,7 @@ var Player = class {
5457
5565
  0
5458
5566
  )
5459
5567
  );
5568
+ this.triggerPlayerClientUpdate();
5460
5569
  const now = performance.now();
5461
5570
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
5462
5571
  this._emitDebugEvent("PlayerVolumeAsFilter" /* PlayerVolumeAsFilter */, {
@@ -5531,6 +5640,7 @@ var Player = class {
5531
5640
  this.paused = true;
5532
5641
  this.lastPositionChange = null;
5533
5642
  const now = performance.now();
5643
+ this.triggerPlayerClientUpdate();
5534
5644
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: true } });
5535
5645
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5536
5646
  this.LavalinkManager.emit("playerPaused", this, this.queue.current);
@@ -5543,6 +5653,7 @@ var Player = class {
5543
5653
  if (!this.paused) throw new Error("Player isn't paused - not able to resume.");
5544
5654
  this.paused = false;
5545
5655
  const now = performance.now();
5656
+ this.triggerPlayerClientUpdate();
5546
5657
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { paused: false } });
5547
5658
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5548
5659
  this.LavalinkManager.emit("playerResumed", this, this.queue.current);
@@ -5563,6 +5674,7 @@ var Player = class {
5563
5674
  this.lastPositionChange = Date.now();
5564
5675
  this.lastPosition = position;
5565
5676
  const now = performance.now();
5677
+ this.triggerPlayerClientUpdate();
5566
5678
  await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { position } });
5567
5679
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
5568
5680
  return this;
@@ -5575,6 +5687,7 @@ var Player = class {
5575
5687
  if (!["off", "track", "queue"].includes(repeatMode))
5576
5688
  throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'");
5577
5689
  this.repeatMode = repeatMode;
5690
+ this.triggerPlayerClientUpdate();
5578
5691
  return this;
5579
5692
  }
5580
5693
  /**
@@ -5829,7 +5942,7 @@ var Player = class {
5829
5942
  functionLayer: "Player > changeNode()"
5830
5943
  });
5831
5944
  });
5832
- } else {
5945
+ } else if (this.LavalinkManager.options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement !== false) {
5833
5946
  await this.setSponsorBlock().catch((error) => {
5834
5947
  this._emitDebugEvent("PlayerChangeNode" /* PlayerChangeNode */, {
5835
5948
  state: "error",
@@ -5925,7 +6038,7 @@ var Player = class {
5925
6038
  nodeId: this.node?.id,
5926
6039
  nodeSessionId: this.node?.sessionId,
5927
6040
  ping: this.ping,
5928
- queue: this.queue.utils.toJSON()
6041
+ queue: this.queue?.utils?.toJSON?.()
5929
6042
  };
5930
6043
  }
5931
6044
  };
@@ -6008,6 +6121,7 @@ var LavalinkManager = class extends EventEmitter2 {
6008
6121
  applyVolumeAsFilter: options?.playerOptions?.applyVolumeAsFilter ?? false,
6009
6122
  clientBasedPositionUpdateInterval: options?.playerOptions?.clientBasedPositionUpdateInterval ?? 100,
6010
6123
  defaultSearchPlatform: options?.playerOptions?.defaultSearchPlatform ?? "ytsearch",
6124
+ allowCustomSources: options?.playerOptions?.allowCustomSources ?? false,
6011
6125
  onDisconnect: {
6012
6126
  destroyPlayer: options?.playerOptions?.onDisconnect?.destroyPlayer ?? true,
6013
6127
  autoReconnect: options?.playerOptions?.onDisconnect?.autoReconnect ?? false,
@@ -6024,7 +6138,8 @@ var LavalinkManager = class extends EventEmitter2 {
6024
6138
  maxErrorsPerTime: {
6025
6139
  threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35e3,
6026
6140
  maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3
6027
- }
6141
+ },
6142
+ enforceSponsorBlockRequestForEventEnablement: options?.playerOptions?.enforceSponsorBlockRequestForEventEnablement ?? true
6028
6143
  },
6029
6144
  linksWhitelist: options?.linksWhitelist ?? [],
6030
6145
  linksBlacklist: options?.linksBlacklist ?? [],
@@ -6124,6 +6239,7 @@ var LavalinkManager = class extends EventEmitter2 {
6124
6239
  * applyVolumeAsFilter: false,
6125
6240
  * clientBasedPositionUpdateInterval: 150,
6126
6241
  * defaultSearchPlatform: "ytmsearch",
6242
+ * allowCustomSources: false,
6127
6243
  * volumeDecrementer: 0.75,
6128
6244
  * //requesterTransformer: YourRequesterTransformerFunction,
6129
6245
  * onDisconnect: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavalink-client",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients. - Supports NodeLink@v3 too.",
5
5
  "keywords": [
6
6
  "advanced",