lavalink-client 1.1.7 → 1.1.10

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.
@@ -56,6 +56,11 @@ export interface ManagerOptions {
56
56
  playerOptions?: ManagerPlayerOptions;
57
57
  /** If it should skip to the next Track on TrackEnd / TrackError etc. events */
58
58
  autoSkip?: boolean;
59
+ /** optional */
60
+ debugOptions?: {
61
+ /** logs for debugging the "no-Audio" playing error */
62
+ noAudio: boolean;
63
+ };
59
64
  }
60
65
  interface LavalinkManagerEvents {
61
66
  /**
@@ -124,8 +129,8 @@ export declare class LavalinkManager extends EventEmitter {
124
129
  static SourceLinksRegexes: Record<import("./Utils").SourcesRegex, RegExp>;
125
130
  initiated: boolean;
126
131
  readonly players: MiniMap<string, Player>;
127
- private applyDefaultOptions;
128
- private validateAndApply;
132
+ private applyOptions;
133
+ private validateOptions;
129
134
  constructor(options: ManagerOptions);
130
135
  createPlayer(options: PlayerOptions): Player;
131
136
  getPlayer(guildId: string): Player;
@@ -12,94 +12,83 @@ class LavalinkManager extends events_1.EventEmitter {
12
12
  static SourceLinksRegexes = LavalinkManagerStatics_1.SourceLinksRegexes;
13
13
  initiated = false;
14
14
  players = new Utils_1.MiniMap();
15
- applyDefaultOptions() {
16
- if (!this.options.playerOptions)
17
- this.options.playerOptions = {
18
- applyVolumeAsFilter: false,
19
- clientBasedPositionUpdateInterval: 100,
20
- defaultSearchPlatform: "ytsearch",
15
+ applyOptions(options) {
16
+ this.options = {
17
+ client: {
18
+ ...(options?.client || {}),
19
+ id: options?.client?.id,
20
+ username: options?.client?.username ?? "lavalink-client"
21
+ },
22
+ sendToShard: options?.sendToShard,
23
+ nodes: options?.nodes,
24
+ playerOptions: {
25
+ applyVolumeAsFilter: options?.playerOptions?.applyVolumeAsFilter ?? false,
26
+ clientBasedPositionUpdateInterval: options?.playerOptions?.clientBasedPositionUpdateInterval ?? 100,
27
+ defaultSearchPlatform: options?.playerOptions?.defaultSearchPlatform ?? "ytsearch",
21
28
  onDisconnect: {
22
- destroyPlayer: true,
23
- autoReconnect: false
29
+ destroyPlayer: options?.playerOptions?.onDisconnect?.destroyPlayer ?? true,
30
+ autoReconnect: options?.playerOptions?.onDisconnect?.autoReconnect ?? false
24
31
  },
25
32
  onEmptyQueue: {
26
- autoPlayFunction: null,
27
- destroyAfterMs: undefined
33
+ autoPlayFunction: options?.playerOptions?.onEmptyQueue?.autoPlayFunction ?? null,
34
+ destroyAfterMs: options?.playerOptions?.onEmptyQueue?.destroyAfterMs ?? undefined
28
35
  },
29
- requesterTransformer: (requester) => {
30
- // if it's already the transformed requester
31
- if (typeof requester === "object" && "avatar" in requester && Object.keys(requester).length === 3)
32
- return requester;
33
- // if it's still a discord.js User
34
- if (typeof requester === "object" && "displayAvatarURL" in requester) { // it's a user
35
- return {
36
- id: requester.id,
37
- username: requester.username,
38
- avatar: requester.displayAvatarURL(),
39
- };
40
- }
41
- // if it's non of the above
42
- return { id: requester.toString(), username: "unknown" }; // reteurn something that makes sense for you!
43
- },
44
- volumeDecrementer: 1
45
- };
46
- if (!this.options.autoSkip)
47
- this.options.autoSkip = true;
48
- if (!this.options.playerOptions.defaultSearchPlatform)
49
- this.options.playerOptions.defaultSearchPlatform = "ytsearch";
50
- // default queue options
51
- if (!this.options.queueOptions)
52
- this.options.queueOptions = {
53
- maxPreviousTracks: 25,
54
- queueChangesWatcher: null,
55
- queueStore: new Queue_1.DefaultQueueStore()
56
- };
57
- if (typeof this.options?.queueOptions?.maxPreviousTracks !== "number" || this.options.queueOptions.maxPreviousTracks < 0)
58
- this.options.queueOptions.maxPreviousTracks = 25;
36
+ volumeDecrementer: options?.playerOptions?.volumeDecrementer ?? 1,
37
+ requesterTransformer: options?.playerOptions?.requesterTransformer ?? null,
38
+ useUnresolvedData: options?.playerOptions?.useUnresolvedData ?? false,
39
+ },
40
+ autoSkip: options?.autoSkip ?? true,
41
+ queueOptions: {
42
+ maxPreviousTracks: options?.queueOptions?.maxPreviousTracks ?? 25,
43
+ queueChangesWatcher: options?.queueOptions?.queueChangesWatcher ?? null,
44
+ queueStore: options?.queueOptions?.queueStore ?? new Queue_1.DefaultQueueStore(),
45
+ },
46
+ debugOptions: {
47
+ noAudio: options?.debugOptions?.noAudio ?? false
48
+ }
49
+ };
59
50
  return;
60
51
  }
61
- validateAndApply(options) {
62
- if (typeof options.sendToShard !== "function")
52
+ validateOptions(options) {
53
+ if (typeof options?.sendToShard !== "function")
63
54
  throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
64
55
  // only check in .init()
65
- // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
66
- if (options.autoSkip && typeof options.autoSkip !== "boolean")
56
+ // if(typeof options?.client !== "object" || typeof options?.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
57
+ if (options?.autoSkip && typeof options?.autoSkip !== "boolean")
67
58
  throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
68
- if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
59
+ if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every(node => this.utils.isNodeOptions(node)))
69
60
  throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
70
61
  /* QUEUE STORE */
71
- if (options.queueOptions?.queueStore) {
72
- const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueStore));
62
+ if (options?.queueOptions?.queueStore) {
63
+ const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueStore));
73
64
  const requiredKeys = ["get", "set", "stringify", "parse", "delete"];
74
- if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueStore[v] === "function"))
65
+ if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options?.queueOptions?.queueStore[v] === "function"))
75
66
  throw new SyntaxError(`The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
76
67
  }
77
- else
78
- this.options.queueOptions.queueStore = new Queue_1.DefaultQueueStore();
79
68
  /* QUEUE WATCHER */
80
- if (options.queueOptions?.queueChangesWatcher) {
81
- const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueChangesWatcher));
69
+ if (options?.queueOptions?.queueChangesWatcher) {
70
+ const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueChangesWatcher));
82
71
  const requiredKeys = ["tracksAdd", "tracksRemoved", "shuffled"];
83
- if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueChangesWatcher[v] === "function"))
72
+ if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options?.queueOptions?.queueChangesWatcher[v] === "function"))
84
73
  throw new SyntaxError(`The provided ManagerOption.DefaultQueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`);
85
74
  }
75
+ if (typeof options?.queueOptions?.maxPreviousTracks !== "number" || options?.queueOptions?.maxPreviousTracks < 0)
76
+ options.queueOptions.maxPreviousTracks = 25;
86
77
  }
87
78
  constructor(options) {
88
79
  super();
89
80
  if (!options)
90
81
  throw new SyntaxError("No Manager Options Provided");
91
- // create options
92
- this.options = options;
93
82
  this.utils = new Utils_1.ManagerUtils(this);
94
83
  // use the validators
95
- this.validateAndApply(options);
96
- this.applyDefaultOptions();
84
+ this.applyOptions(options);
85
+ this.validateOptions(options);
97
86
  // create classes
98
87
  this.nodeManager = new NodeManager_1.NodeManager(this);
99
88
  }
100
89
  createPlayer(options) {
101
- if (this.players.has(options.guildId))
102
- return this.players.get(options.guildId);
90
+ if (this.players.has(options?.guildId))
91
+ return this.players.get(options?.guildId);
103
92
  const newPlayer = new Player_1.Player(options, this);
104
93
  this.players.set(newPlayer.guildId, newPlayer);
105
94
  return newPlayer;
@@ -122,10 +111,11 @@ class LavalinkManager extends events_1.EventEmitter {
122
111
  async init(clientData) {
123
112
  if (this.initiated)
124
113
  return this;
125
- this.options.client = { ...(this.options.client || {}), ...clientData };
126
- if (!this.options.client.id)
114
+ clientData = clientData ?? {};
115
+ this.options.client = { ...(this.options?.client || {}), ...clientData };
116
+ if (!this.options?.client.id)
127
117
  throw new Error('"client.id" is not set. Pass it in Manager#init() or as a option in the constructor.');
128
- if (typeof this.options.client.id !== "string")
118
+ if (typeof this.options?.client.id !== "string")
129
119
  throw new Error('"client.id" set is not type of "string"');
130
120
  let success = 0;
131
121
  for (const node of [...this.nodeManager.nodes.values()]) {
@@ -149,8 +139,16 @@ class LavalinkManager extends events_1.EventEmitter {
149
139
  * @param data
150
140
  */
151
141
  async sendRawData(data) {
152
- if (!this.initiated || !("t" in data))
142
+ if (!this.initiated) {
143
+ if (this.options?.debugOptions?.noAudio === true)
144
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet");
145
+ return;
146
+ }
147
+ if (!("t" in data)) {
148
+ if (this.options?.debugOptions?.noAudio === true)
149
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:", data);
153
150
  return;
151
+ }
154
152
  // for channel Delete
155
153
  if ("CHANNEL_DELETE" === data.t) {
156
154
  const update = "d" in data ? data.d : data;
@@ -163,11 +161,22 @@ class LavalinkManager extends events_1.EventEmitter {
163
161
  // for voice updates
164
162
  if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
165
163
  const update = "d" in data ? data.d : data;
166
- if (!update || !("token" in update) && !("session_id" in update))
164
+ if (!update) {
165
+ if (this.options?.debugOptions?.noAudio === true)
166
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:", data);
167
+ return;
168
+ }
169
+ if (!("token" in update) && !("session_id" in update)) {
170
+ if (this.options?.debugOptions?.noAudio === true)
171
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:", data);
167
172
  return;
173
+ }
168
174
  const player = this.getPlayer(update.guild_id);
169
- if (!player)
175
+ if (!player) {
176
+ if (this.options?.debugOptions?.noAudio === true)
177
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:", update);
170
178
  return;
179
+ }
171
180
  if ("token" in update) {
172
181
  if (!player.node?.sessionId)
173
182
  throw new Error("Lavalink Node is either not ready or not up to date");
@@ -181,11 +190,16 @@ class LavalinkManager extends events_1.EventEmitter {
181
190
  }
182
191
  }
183
192
  });
193
+ if (this.options?.debugOptions?.noAudio === true)
194
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, } });
184
195
  return;
185
196
  }
186
197
  /* voice state update */
187
- if (update.user_id !== this.options.client.id)
198
+ if (update.user_id !== this.options?.client.id) {
199
+ if (this.options?.debugOptions?.noAudio === true)
200
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id", "user:", update.user_id, "manager client id:", this.options?.client.id);
188
201
  return;
202
+ }
189
203
  if (update.channel_id) {
190
204
  if (player.voiceChannelId !== update.channel_id)
191
205
  this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
@@ -193,12 +207,12 @@ class LavalinkManager extends events_1.EventEmitter {
193
207
  player.voiceChannelId = update.channel_id;
194
208
  }
195
209
  else {
196
- if (this.options.playerOptions.onDisconnect?.destroyPlayer === true) {
210
+ if (this.options?.playerOptions?.onDisconnect?.destroyPlayer === true) {
197
211
  return await player.destroy(Player_1.DestroyReasons.Disconnected);
198
212
  }
199
213
  this.emit("playerDisconnect", player, player.voiceChannelId);
200
214
  await player.pause();
201
- if (this.options.playerOptions.onDisconnect?.autoReconnect === true) {
215
+ if (this.options?.playerOptions?.onDisconnect?.autoReconnect === true) {
202
216
  try {
203
217
  await player.connect();
204
218
  }
@@ -1,3 +1,10 @@
1
1
  import { LavalinkSearchPlatform, SearchPlatform, SourcesRegex } from "./Utils";
2
2
  export declare const DefaultSources: Record<SearchPlatform, LavalinkSearchPlatform>;
3
+ export declare const LavalinkPlugins: {
4
+ DuncteBot_Plugin: string;
5
+ LavaSrc: string;
6
+ GoogleCloudTTS: string;
7
+ LavaSearch: string;
8
+ LavalinkFilterPlugin: string;
9
+ };
3
10
  export declare const SourceLinksRegexes: Record<SourcesRegex, RegExp>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SourceLinksRegexes = exports.DefaultSources = void 0;
3
+ exports.SourceLinksRegexes = exports.LavalinkPlugins = exports.DefaultSources = void 0;
4
4
  exports.DefaultSources = {
5
5
  // youtubemusic
6
6
  "youtube music": "ytmsearch",
@@ -42,6 +42,13 @@ exports.DefaultSources = {
42
42
  "tts": "tts",
43
43
  "ftts": "ftts"
44
44
  };
45
+ exports.LavalinkPlugins = {
46
+ DuncteBot_Plugin: "DuncteBot-plugin",
47
+ LavaSrc: "lavasrc-plugin",
48
+ GoogleCloudTTS: "tts-plugin",
49
+ LavaSearch: "lavasearch-plugin",
50
+ LavalinkFilterPlugin: "lavalink-filter-plugin"
51
+ };
45
52
  exports.SourceLinksRegexes = {
46
53
  /** DEFAULT SUPPORTED BY LAVALINK */
47
54
  YoutubeRegex: /https?:\/\/?(?:www\.)?(?:(m|www)\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|shorts|playlist\?|watch\?v=|watch\?.+(?:&|&#38;);v=))([a-zA-Z0-9\-_]{11})?(?:(?:\?|&|&#38;)index=((?:\d){1,3}))?(?:(?:\?|&|&#38;)?list=([a-zA-Z\-_0-9]{34}))?(?:\S+)?/,
@@ -339,12 +339,12 @@ class LavalinkNode {
339
339
  player.voice = data.playerOptions.voice;
340
340
  if (typeof data.playerOptions.volume !== "undefined") {
341
341
  if (this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer) {
342
- player.volume = data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer;
343
- player.lavalinkVolume = data.playerOptions.volume;
342
+ player.volume = Math.round(data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer);
343
+ player.lavalinkVolume = Math.round(data.playerOptions.volume);
344
344
  }
345
345
  else {
346
- player.volume = data.playerOptions.volume;
347
- player.lavalinkVolume = data.playerOptions.volume;
346
+ player.volume = Math.round(data.playerOptions.volume);
347
+ player.lavalinkVolume = Math.round(data.playerOptions.volume);
348
348
  }
349
349
  }
350
350
  if (typeof data.playerOptions.filters !== "undefined") {
@@ -73,11 +73,13 @@ class Player {
73
73
  }
74
74
  if (!this.node)
75
75
  throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
76
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
77
- this.volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
78
- this.LavalinkManager.emit("playerCreate", this);
79
76
  if (typeof options.volume === "number" && !isNaN(options.volume))
80
- this.setVolume(options.volume);
77
+ this.volume = Number(options.volume);
78
+ this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
79
+ this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
80
+ ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
81
+ : this.volume), 1000), 0));
82
+ this.LavalinkManager.emit("playerCreate", this);
81
83
  this.queue = new Queue_1.Queue(this.guildId, {}, new Queue_1.QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
82
84
  }
83
85
  /**
@@ -155,8 +157,8 @@ class Player {
155
157
  let vol = Number(this.volume);
156
158
  if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
157
159
  vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
158
- this.lavalinkVolume = Math.floor(vol * 100) / 100;
159
- options.volume = vol;
160
+ this.lavalinkVolume = Math.round(vol);
161
+ options.volume = this.lavalinkVolume;
160
162
  }
161
163
  const finalOptions = {
162
164
  encodedTrack: track.encoded,
@@ -193,17 +195,16 @@ class Player {
193
195
  volume = Number(volume);
194
196
  if (isNaN(volume))
195
197
  throw new TypeError("Volume must be a number.");
196
- this.volume = Math.max(Math.min(volume, 500), 0);
197
- volume = Number(this.volume);
198
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer)
199
- volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
200
- this.lavalinkVolume = Math.floor(volume * 100) / 100;
198
+ this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
199
+ this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
200
+ ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
201
+ : this.volume), 1000), 0));
201
202
  const now = performance.now();
202
203
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
203
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: volume / 100 } } });
204
+ await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
204
205
  }
205
206
  else {
206
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume } });
207
+ await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
207
208
  }
208
209
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
209
210
  return;
@@ -420,7 +421,7 @@ class Player {
420
421
  noReplace: false,
421
422
  playerOptions: {
422
423
  position: data.position,
423
- volume: data.volume,
424
+ volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)),
424
425
  paused: data.paused,
425
426
  filters: { ...data.filters, equalizer: data.equalizer },
426
427
  },
@@ -218,15 +218,14 @@ class ManagerUtils {
218
218
  if (source === "scsearch" && !node.info.sourceManagers.includes("soundcloud")) {
219
219
  throw new Error("Lavalink Node has not 'soundcloud' enabled, which is required to have 'scsearch' work");
220
220
  }
221
- if (source === "speak" && !node.info.sourceManagers.includes("speak")) {
221
+ if (source === "speak" && !node.info.plugins.find(c => c.name.toLowerCase().includes(LavalinkManagerStatics_1.LavalinkPlugins.DuncteBot_Plugin.toLowerCase()))) {
222
222
  throw new Error("Lavalink Node has not 'speak' enabled, which is required to have 'speak' work");
223
223
  }
224
- if (source === "tts" && !node.info.sourceManagers.includes("tts")) {
224
+ if (source === "tts" && !node.info.plugins.find(c => c.name.toLowerCase().includes(LavalinkManagerStatics_1.LavalinkPlugins.GoogleCloudTTS.toLowerCase()))) {
225
225
  throw new Error("Lavalink Node has not 'tts' enabled, which is required to have 'tts' work");
226
226
  }
227
- if (source === "ftts" && !node.info.sourceManagers.includes("ftts") && !node.info.sourceManagers.includes("flowerytts")) {
228
- console.log(node.info.sourceManagers);
229
- throw new Error("Lavalink Node has not 'ftts' enabled, which is required to have 'ftts' work");
227
+ if (source === "ftts" && !(node.info.sourceManagers.includes("ftts") || node.info.sourceManagers.includes("flowery-tts") || node.info.sourceManagers.includes("flowerytts"))) {
228
+ throw new Error("Lavalink Node has not 'flowery-tts' enabled, which is required to have 'ftts' work");
230
229
  }
231
230
  if (source === "ymsearch" && !node.info.sourceManagers.includes("yandexmusic")) {
232
231
  throw new Error("Lavalink Node has not 'yandexmusic' enabled, which is required to have 'ymsearch' work");
@@ -293,9 +292,9 @@ exports.queueTrackEnd = queueTrackEnd;
293
292
  async function applyUnresolvedData(resTrack, data, utils) {
294
293
  if (!resTrack?.info || !data?.info)
295
294
  return;
295
+ if (data.info.uri)
296
+ resTrack.info.uri = data.info.uri;
296
297
  if (utils?.LavalinkManager?.options?.playerOptions?.useUnresolvedData === true) { // overwrite values
297
- if (data.info.uri)
298
- resTrack.info.uri = data.info.uri;
299
298
  if (data.info.artworkUrl?.length)
300
299
  resTrack.info.artworkUrl = data.info.artworkUrl;
301
300
  if (data.info.title?.length)
@@ -56,6 +56,11 @@ export interface ManagerOptions {
56
56
  playerOptions?: ManagerPlayerOptions;
57
57
  /** If it should skip to the next Track on TrackEnd / TrackError etc. events */
58
58
  autoSkip?: boolean;
59
+ /** optional */
60
+ debugOptions?: {
61
+ /** logs for debugging the "no-Audio" playing error */
62
+ noAudio: boolean;
63
+ };
59
64
  }
60
65
  interface LavalinkManagerEvents {
61
66
  /**
@@ -124,8 +129,8 @@ export declare class LavalinkManager extends EventEmitter {
124
129
  static SourceLinksRegexes: Record<import("./Utils").SourcesRegex, RegExp>;
125
130
  initiated: boolean;
126
131
  readonly players: MiniMap<string, Player>;
127
- private applyDefaultOptions;
128
- private validateAndApply;
132
+ private applyOptions;
133
+ private validateOptions;
129
134
  constructor(options: ManagerOptions);
130
135
  createPlayer(options: PlayerOptions): Player;
131
136
  getPlayer(guildId: string): Player;
@@ -9,94 +9,83 @@ export class LavalinkManager extends EventEmitter {
9
9
  static SourceLinksRegexes = SourceLinksRegexes;
10
10
  initiated = false;
11
11
  players = new MiniMap();
12
- applyDefaultOptions() {
13
- if (!this.options.playerOptions)
14
- this.options.playerOptions = {
15
- applyVolumeAsFilter: false,
16
- clientBasedPositionUpdateInterval: 100,
17
- defaultSearchPlatform: "ytsearch",
12
+ applyOptions(options) {
13
+ this.options = {
14
+ client: {
15
+ ...(options?.client || {}),
16
+ id: options?.client?.id,
17
+ username: options?.client?.username ?? "lavalink-client"
18
+ },
19
+ sendToShard: options?.sendToShard,
20
+ nodes: options?.nodes,
21
+ playerOptions: {
22
+ applyVolumeAsFilter: options?.playerOptions?.applyVolumeAsFilter ?? false,
23
+ clientBasedPositionUpdateInterval: options?.playerOptions?.clientBasedPositionUpdateInterval ?? 100,
24
+ defaultSearchPlatform: options?.playerOptions?.defaultSearchPlatform ?? "ytsearch",
18
25
  onDisconnect: {
19
- destroyPlayer: true,
20
- autoReconnect: false
26
+ destroyPlayer: options?.playerOptions?.onDisconnect?.destroyPlayer ?? true,
27
+ autoReconnect: options?.playerOptions?.onDisconnect?.autoReconnect ?? false
21
28
  },
22
29
  onEmptyQueue: {
23
- autoPlayFunction: null,
24
- destroyAfterMs: undefined
30
+ autoPlayFunction: options?.playerOptions?.onEmptyQueue?.autoPlayFunction ?? null,
31
+ destroyAfterMs: options?.playerOptions?.onEmptyQueue?.destroyAfterMs ?? undefined
25
32
  },
26
- requesterTransformer: (requester) => {
27
- // if it's already the transformed requester
28
- if (typeof requester === "object" && "avatar" in requester && Object.keys(requester).length === 3)
29
- return requester;
30
- // if it's still a discord.js User
31
- if (typeof requester === "object" && "displayAvatarURL" in requester) { // it's a user
32
- return {
33
- id: requester.id,
34
- username: requester.username,
35
- avatar: requester.displayAvatarURL(),
36
- };
37
- }
38
- // if it's non of the above
39
- return { id: requester.toString(), username: "unknown" }; // reteurn something that makes sense for you!
40
- },
41
- volumeDecrementer: 1
42
- };
43
- if (!this.options.autoSkip)
44
- this.options.autoSkip = true;
45
- if (!this.options.playerOptions.defaultSearchPlatform)
46
- this.options.playerOptions.defaultSearchPlatform = "ytsearch";
47
- // default queue options
48
- if (!this.options.queueOptions)
49
- this.options.queueOptions = {
50
- maxPreviousTracks: 25,
51
- queueChangesWatcher: null,
52
- queueStore: new DefaultQueueStore()
53
- };
54
- if (typeof this.options?.queueOptions?.maxPreviousTracks !== "number" || this.options.queueOptions.maxPreviousTracks < 0)
55
- this.options.queueOptions.maxPreviousTracks = 25;
33
+ volumeDecrementer: options?.playerOptions?.volumeDecrementer ?? 1,
34
+ requesterTransformer: options?.playerOptions?.requesterTransformer ?? null,
35
+ useUnresolvedData: options?.playerOptions?.useUnresolvedData ?? false,
36
+ },
37
+ autoSkip: options?.autoSkip ?? true,
38
+ queueOptions: {
39
+ maxPreviousTracks: options?.queueOptions?.maxPreviousTracks ?? 25,
40
+ queueChangesWatcher: options?.queueOptions?.queueChangesWatcher ?? null,
41
+ queueStore: options?.queueOptions?.queueStore ?? new DefaultQueueStore(),
42
+ },
43
+ debugOptions: {
44
+ noAudio: options?.debugOptions?.noAudio ?? false
45
+ }
46
+ };
56
47
  return;
57
48
  }
58
- validateAndApply(options) {
59
- if (typeof options.sendToShard !== "function")
49
+ validateOptions(options) {
50
+ if (typeof options?.sendToShard !== "function")
60
51
  throw new SyntaxError("ManagerOption.sendToShard was not provided, which is required!");
61
52
  // only check in .init()
62
- // if(typeof options.client !== "object" || typeof options.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
63
- if (options.autoSkip && typeof options.autoSkip !== "boolean")
53
+ // if(typeof options?.client !== "object" || typeof options?.client.id !== "string") throw new SyntaxError("ManagerOption.client = { id: string, username?:string } was not provided, which is required");
54
+ if (options?.autoSkip && typeof options?.autoSkip !== "boolean")
64
55
  throw new SyntaxError("ManagerOption.autoSkip must be either false | true aka boolean");
65
- if (!options.nodes || !Array.isArray(options.nodes) || !options.nodes.every(node => this.utils.isNodeOptions(node)))
56
+ if (!options?.nodes || !Array.isArray(options?.nodes) || !options?.nodes.every(node => this.utils.isNodeOptions(node)))
66
57
  throw new SyntaxError("ManagerOption.nodes must be an Array of NodeOptions and is required of at least 1 Node");
67
58
  /* QUEUE STORE */
68
- if (options.queueOptions?.queueStore) {
69
- const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueStore));
59
+ if (options?.queueOptions?.queueStore) {
60
+ const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueStore));
70
61
  const requiredKeys = ["get", "set", "stringify", "parse", "delete"];
71
- if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueStore[v] === "function"))
62
+ if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options?.queueOptions?.queueStore[v] === "function"))
72
63
  throw new SyntaxError(`The provided ManagerOption.QueueStore, does not have all required functions: ${requiredKeys.join(", ")}`);
73
64
  }
74
- else
75
- this.options.queueOptions.queueStore = new DefaultQueueStore();
76
65
  /* QUEUE WATCHER */
77
- if (options.queueOptions?.queueChangesWatcher) {
78
- const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options.queueOptions?.queueChangesWatcher));
66
+ if (options?.queueOptions?.queueChangesWatcher) {
67
+ const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(options?.queueOptions?.queueChangesWatcher));
79
68
  const requiredKeys = ["tracksAdd", "tracksRemoved", "shuffled"];
80
- if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options.queueOptions?.queueChangesWatcher[v] === "function"))
69
+ if (!requiredKeys.every(v => keys.includes(v)) || !requiredKeys.every(v => typeof options?.queueOptions?.queueChangesWatcher[v] === "function"))
81
70
  throw new SyntaxError(`The provided ManagerOption.DefaultQueueChangesWatcher, does not have all required functions: ${requiredKeys.join(", ")}`);
82
71
  }
72
+ if (typeof options?.queueOptions?.maxPreviousTracks !== "number" || options?.queueOptions?.maxPreviousTracks < 0)
73
+ options.queueOptions.maxPreviousTracks = 25;
83
74
  }
84
75
  constructor(options) {
85
76
  super();
86
77
  if (!options)
87
78
  throw new SyntaxError("No Manager Options Provided");
88
- // create options
89
- this.options = options;
90
79
  this.utils = new ManagerUtils(this);
91
80
  // use the validators
92
- this.validateAndApply(options);
93
- this.applyDefaultOptions();
81
+ this.applyOptions(options);
82
+ this.validateOptions(options);
94
83
  // create classes
95
84
  this.nodeManager = new NodeManager(this);
96
85
  }
97
86
  createPlayer(options) {
98
- if (this.players.has(options.guildId))
99
- return this.players.get(options.guildId);
87
+ if (this.players.has(options?.guildId))
88
+ return this.players.get(options?.guildId);
100
89
  const newPlayer = new Player(options, this);
101
90
  this.players.set(newPlayer.guildId, newPlayer);
102
91
  return newPlayer;
@@ -119,10 +108,11 @@ export class LavalinkManager extends EventEmitter {
119
108
  async init(clientData) {
120
109
  if (this.initiated)
121
110
  return this;
122
- this.options.client = { ...(this.options.client || {}), ...clientData };
123
- if (!this.options.client.id)
111
+ clientData = clientData ?? {};
112
+ this.options.client = { ...(this.options?.client || {}), ...clientData };
113
+ if (!this.options?.client.id)
124
114
  throw new Error('"client.id" is not set. Pass it in Manager#init() or as a option in the constructor.');
125
- if (typeof this.options.client.id !== "string")
115
+ if (typeof this.options?.client.id !== "string")
126
116
  throw new Error('"client.id" set is not type of "string"');
127
117
  let success = 0;
128
118
  for (const node of [...this.nodeManager.nodes.values()]) {
@@ -146,8 +136,16 @@ export class LavalinkManager extends EventEmitter {
146
136
  * @param data
147
137
  */
148
138
  async sendRawData(data) {
149
- if (!this.initiated || !("t" in data))
139
+ if (!this.initiated) {
140
+ if (this.options?.debugOptions?.noAudio === true)
141
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet");
142
+ return;
143
+ }
144
+ if (!("t" in data)) {
145
+ if (this.options?.debugOptions?.noAudio === true)
146
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:", data);
150
147
  return;
148
+ }
151
149
  // for channel Delete
152
150
  if ("CHANNEL_DELETE" === data.t) {
153
151
  const update = "d" in data ? data.d : data;
@@ -160,11 +158,22 @@ export class LavalinkManager extends EventEmitter {
160
158
  // for voice updates
161
159
  if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
162
160
  const update = "d" in data ? data.d : data;
163
- if (!update || !("token" in update) && !("session_id" in update))
161
+ if (!update) {
162
+ if (this.options?.debugOptions?.noAudio === true)
163
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:", data);
164
+ return;
165
+ }
166
+ if (!("token" in update) && !("session_id" in update)) {
167
+ if (this.options?.debugOptions?.noAudio === true)
168
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:", data);
164
169
  return;
170
+ }
165
171
  const player = this.getPlayer(update.guild_id);
166
- if (!player)
172
+ if (!player) {
173
+ if (this.options?.debugOptions?.noAudio === true)
174
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:", update);
167
175
  return;
176
+ }
168
177
  if ("token" in update) {
169
178
  if (!player.node?.sessionId)
170
179
  throw new Error("Lavalink Node is either not ready or not up to date");
@@ -178,11 +187,16 @@ export class LavalinkManager extends EventEmitter {
178
187
  }
179
188
  }
180
189
  });
190
+ if (this.options?.debugOptions?.noAudio === true)
191
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, } });
181
192
  return;
182
193
  }
183
194
  /* voice state update */
184
- if (update.user_id !== this.options.client.id)
195
+ if (update.user_id !== this.options?.client.id) {
196
+ if (this.options?.debugOptions?.noAudio === true)
197
+ console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id", "user:", update.user_id, "manager client id:", this.options?.client.id);
185
198
  return;
199
+ }
186
200
  if (update.channel_id) {
187
201
  if (player.voiceChannelId !== update.channel_id)
188
202
  this.emit("playerMove", player, player.voiceChannelId, update.channel_id);
@@ -190,12 +204,12 @@ export class LavalinkManager extends EventEmitter {
190
204
  player.voiceChannelId = update.channel_id;
191
205
  }
192
206
  else {
193
- if (this.options.playerOptions.onDisconnect?.destroyPlayer === true) {
207
+ if (this.options?.playerOptions?.onDisconnect?.destroyPlayer === true) {
194
208
  return await player.destroy(DestroyReasons.Disconnected);
195
209
  }
196
210
  this.emit("playerDisconnect", player, player.voiceChannelId);
197
211
  await player.pause();
198
- if (this.options.playerOptions.onDisconnect?.autoReconnect === true) {
212
+ if (this.options?.playerOptions?.onDisconnect?.autoReconnect === true) {
199
213
  try {
200
214
  await player.connect();
201
215
  }
@@ -1,3 +1,10 @@
1
1
  import { LavalinkSearchPlatform, SearchPlatform, SourcesRegex } from "./Utils";
2
2
  export declare const DefaultSources: Record<SearchPlatform, LavalinkSearchPlatform>;
3
+ export declare const LavalinkPlugins: {
4
+ DuncteBot_Plugin: string;
5
+ LavaSrc: string;
6
+ GoogleCloudTTS: string;
7
+ LavaSearch: string;
8
+ LavalinkFilterPlugin: string;
9
+ };
3
10
  export declare const SourceLinksRegexes: Record<SourcesRegex, RegExp>;
@@ -39,6 +39,13 @@ export const DefaultSources = {
39
39
  "tts": "tts",
40
40
  "ftts": "ftts"
41
41
  };
42
+ export const LavalinkPlugins = {
43
+ DuncteBot_Plugin: "DuncteBot-plugin",
44
+ LavaSrc: "lavasrc-plugin",
45
+ GoogleCloudTTS: "tts-plugin",
46
+ LavaSearch: "lavasearch-plugin",
47
+ LavalinkFilterPlugin: "lavalink-filter-plugin"
48
+ };
42
49
  export const SourceLinksRegexes = {
43
50
  /** DEFAULT SUPPORTED BY LAVALINK */
44
51
  YoutubeRegex: /https?:\/\/?(?:www\.)?(?:(m|www)\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|shorts|playlist\?|watch\?v=|watch\?.+(?:&|&#38;);v=))([a-zA-Z0-9\-_]{11})?(?:(?:\?|&|&#38;)index=((?:\d){1,3}))?(?:(?:\?|&|&#38;)?list=([a-zA-Z\-_0-9]{34}))?(?:\S+)?/,
@@ -335,12 +335,12 @@ export class LavalinkNode {
335
335
  player.voice = data.playerOptions.voice;
336
336
  if (typeof data.playerOptions.volume !== "undefined") {
337
337
  if (this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer) {
338
- player.volume = data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer;
339
- player.lavalinkVolume = data.playerOptions.volume;
338
+ player.volume = Math.round(data.playerOptions.volume / this.NodeManager.LavalinkManager.options.playerOptions.volumeDecrementer);
339
+ player.lavalinkVolume = Math.round(data.playerOptions.volume);
340
340
  }
341
341
  else {
342
- player.volume = data.playerOptions.volume;
343
- player.lavalinkVolume = data.playerOptions.volume;
342
+ player.volume = Math.round(data.playerOptions.volume);
343
+ player.lavalinkVolume = Math.round(data.playerOptions.volume);
344
344
  }
345
345
  }
346
346
  if (typeof data.playerOptions.filters !== "undefined") {
@@ -70,11 +70,13 @@ export class Player {
70
70
  }
71
71
  if (!this.node)
72
72
  throw new Error("No available Node was found, please add a LavalinkNode to the Manager via Manager.NodeManager#createNode");
73
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
74
- this.volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
75
- this.LavalinkManager.emit("playerCreate", this);
76
73
  if (typeof options.volume === "number" && !isNaN(options.volume))
77
- this.setVolume(options.volume);
74
+ this.volume = Number(options.volume);
75
+ this.volume = Math.round(Math.max(Math.min(this.volume, 1000), 0));
76
+ this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer
77
+ ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
78
+ : this.volume), 1000), 0));
79
+ this.LavalinkManager.emit("playerCreate", this);
78
80
  this.queue = new Queue(this.guildId, {}, new QueueSaver(this.LavalinkManager.options.queueOptions), this.LavalinkManager.options.queueOptions);
79
81
  }
80
82
  /**
@@ -152,8 +154,8 @@ export class Player {
152
154
  let vol = Number(this.volume);
153
155
  if (this.LavalinkManager.options.playerOptions.volumeDecrementer)
154
156
  vol *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
155
- this.lavalinkVolume = Math.floor(vol * 100) / 100;
156
- options.volume = vol;
157
+ this.lavalinkVolume = Math.round(vol);
158
+ options.volume = this.lavalinkVolume;
157
159
  }
158
160
  const finalOptions = {
159
161
  encodedTrack: track.encoded,
@@ -190,17 +192,16 @@ export class Player {
190
192
  volume = Number(volume);
191
193
  if (isNaN(volume))
192
194
  throw new TypeError("Volume must be a number.");
193
- this.volume = Math.max(Math.min(volume, 500), 0);
194
- volume = Number(this.volume);
195
- if (this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer)
196
- volume *= this.LavalinkManager.options.playerOptions.volumeDecrementer;
197
- this.lavalinkVolume = Math.floor(volume * 100) / 100;
195
+ this.volume = Math.round(Math.max(Math.min(volume, 1000), 0));
196
+ this.lavalinkVolume = Math.round(Math.max(Math.min(Math.round(this.LavalinkManager.options.playerOptions.volumeDecrementer && !ignoreVolumeDecrementer
197
+ ? this.volume * this.LavalinkManager.options.playerOptions.volumeDecrementer
198
+ : this.volume), 1000), 0));
198
199
  const now = performance.now();
199
200
  if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) {
200
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: volume / 100 } } });
201
+ await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } });
201
202
  }
202
203
  else {
203
- await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume } });
204
+ await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } });
204
205
  }
205
206
  this.ping.lavalink = Math.round((performance.now() - now) / 10) / 100;
206
207
  return;
@@ -417,7 +418,7 @@ export class Player {
417
418
  noReplace: false,
418
419
  playerOptions: {
419
420
  position: data.position,
420
- volume: data.volume,
421
+ volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)),
421
422
  paused: data.paused,
422
423
  filters: { ...data.filters, equalizer: data.equalizer },
423
424
  },
@@ -1,4 +1,4 @@
1
- import { DefaultSources, SourceLinksRegexes } from "./LavalinkManagerStatics";
1
+ import { DefaultSources, LavalinkPlugins, SourceLinksRegexes } from "./LavalinkManagerStatics";
2
2
  export const TrackSymbol = Symbol("LC-Track");
3
3
  export const UnresolvedTrackSymbol = Symbol("LC-Track-Unresolved");
4
4
  export const QueueSymbol = Symbol("LC-Queue");
@@ -215,15 +215,14 @@ export class ManagerUtils {
215
215
  if (source === "scsearch" && !node.info.sourceManagers.includes("soundcloud")) {
216
216
  throw new Error("Lavalink Node has not 'soundcloud' enabled, which is required to have 'scsearch' work");
217
217
  }
218
- if (source === "speak" && !node.info.sourceManagers.includes("speak")) {
218
+ if (source === "speak" && !node.info.plugins.find(c => c.name.toLowerCase().includes(LavalinkPlugins.DuncteBot_Plugin.toLowerCase()))) {
219
219
  throw new Error("Lavalink Node has not 'speak' enabled, which is required to have 'speak' work");
220
220
  }
221
- if (source === "tts" && !node.info.sourceManagers.includes("tts")) {
221
+ if (source === "tts" && !node.info.plugins.find(c => c.name.toLowerCase().includes(LavalinkPlugins.GoogleCloudTTS.toLowerCase()))) {
222
222
  throw new Error("Lavalink Node has not 'tts' enabled, which is required to have 'tts' work");
223
223
  }
224
- if (source === "ftts" && !node.info.sourceManagers.includes("ftts") && !node.info.sourceManagers.includes("flowerytts")) {
225
- console.log(node.info.sourceManagers);
226
- throw new Error("Lavalink Node has not 'ftts' enabled, which is required to have 'ftts' work");
224
+ if (source === "ftts" && !(node.info.sourceManagers.includes("ftts") || node.info.sourceManagers.includes("flowery-tts") || node.info.sourceManagers.includes("flowerytts"))) {
225
+ throw new Error("Lavalink Node has not 'flowery-tts' enabled, which is required to have 'ftts' work");
227
226
  }
228
227
  if (source === "ymsearch" && !node.info.sourceManagers.includes("yandexmusic")) {
229
228
  throw new Error("Lavalink Node has not 'yandexmusic' enabled, which is required to have 'ymsearch' work");
@@ -287,9 +286,9 @@ export async function queueTrackEnd(player) {
287
286
  async function applyUnresolvedData(resTrack, data, utils) {
288
287
  if (!resTrack?.info || !data?.info)
289
288
  return;
289
+ if (data.info.uri)
290
+ resTrack.info.uri = data.info.uri;
290
291
  if (utils?.LavalinkManager?.options?.playerOptions?.useUnresolvedData === true) { // overwrite values
291
- if (data.info.uri)
292
- resTrack.info.uri = data.info.uri;
293
292
  if (data.info.artworkUrl?.length)
294
293
  resTrack.info.artworkUrl = data.info.artworkUrl;
295
294
  if (data.info.title?.length)
@@ -56,6 +56,11 @@ export interface ManagerOptions {
56
56
  playerOptions?: ManagerPlayerOptions;
57
57
  /** If it should skip to the next Track on TrackEnd / TrackError etc. events */
58
58
  autoSkip?: boolean;
59
+ /** optional */
60
+ debugOptions?: {
61
+ /** logs for debugging the "no-Audio" playing error */
62
+ noAudio: boolean;
63
+ };
59
64
  }
60
65
  interface LavalinkManagerEvents {
61
66
  /**
@@ -124,8 +129,8 @@ export declare class LavalinkManager extends EventEmitter {
124
129
  static SourceLinksRegexes: Record<import("./Utils").SourcesRegex, RegExp>;
125
130
  initiated: boolean;
126
131
  readonly players: MiniMap<string, Player>;
127
- private applyDefaultOptions;
128
- private validateAndApply;
132
+ private applyOptions;
133
+ private validateOptions;
129
134
  constructor(options: ManagerOptions);
130
135
  createPlayer(options: PlayerOptions): Player;
131
136
  getPlayer(guildId: string): Player;
@@ -1,3 +1,10 @@
1
1
  import { LavalinkSearchPlatform, SearchPlatform, SourcesRegex } from "./Utils";
2
2
  export declare const DefaultSources: Record<SearchPlatform, LavalinkSearchPlatform>;
3
+ export declare const LavalinkPlugins: {
4
+ DuncteBot_Plugin: string;
5
+ LavaSrc: string;
6
+ GoogleCloudTTS: string;
7
+ LavaSearch: string;
8
+ LavalinkFilterPlugin: string;
9
+ };
3
10
  export declare const SourceLinksRegexes: Record<SourcesRegex, RegExp>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavalink-client",
3
- "version": "1.1.7",
3
+ "version": "1.1.10",
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",