ziplayer 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +212 -212
  2. package/dist/plugins/SoundCloudPlugin.d.ts +22 -0
  3. package/dist/plugins/SoundCloudPlugin.d.ts.map +1 -0
  4. package/dist/plugins/SoundCloudPlugin.js +171 -0
  5. package/dist/plugins/SoundCloudPlugin.js.map +1 -0
  6. package/dist/plugins/SpotifyPlugin.d.ts +26 -0
  7. package/dist/plugins/SpotifyPlugin.d.ts.map +1 -0
  8. package/dist/plugins/SpotifyPlugin.js +183 -0
  9. package/dist/plugins/SpotifyPlugin.js.map +1 -0
  10. package/dist/plugins/YouTubePlugin.d.ts +25 -0
  11. package/dist/plugins/YouTubePlugin.d.ts.map +1 -0
  12. package/dist/plugins/YouTubePlugin.js +314 -0
  13. package/dist/plugins/YouTubePlugin.js.map +1 -0
  14. package/dist/structures/Player.d.ts +61 -70
  15. package/dist/structures/Player.d.ts.map +1 -1
  16. package/dist/structures/Player.js +332 -355
  17. package/dist/structures/Player.js.map +1 -1
  18. package/dist/structures/PlayerManager.d.ts +5 -1
  19. package/dist/structures/PlayerManager.d.ts.map +1 -1
  20. package/dist/structures/PlayerManager.js.map +1 -1
  21. package/dist/types/index.d.ts +58 -16
  22. package/dist/types/index.d.ts.map +1 -1
  23. package/package.json +45 -45
  24. package/src/extensions/BaseExtension.ts +35 -35
  25. package/src/extensions/index.ts +32 -32
  26. package/src/index.ts +16 -16
  27. package/src/plugins/BasePlugin.ts +26 -26
  28. package/src/plugins/index.ts +32 -32
  29. package/src/structures/Player.ts +1693 -1747
  30. package/src/structures/PlayerManager.ts +416 -411
  31. package/src/structures/Queue.ts +354 -354
  32. package/src/types/index.ts +510 -470
  33. package/src/utils/timeout.ts +10 -10
  34. package/tsconfig.json +23 -23
@@ -1,470 +1,510 @@
1
- import { VoiceConnection } from "@discordjs/voice";
2
- import { Readable } from "stream";
3
- import { Player } from "../structures/Player";
4
- import type { PlayerManager } from "../structures/PlayerManager";
5
-
6
- /**
7
- * Represents a music track with metadata and streaming information.
8
- *
9
- * @example
10
- * // Basic track from YouTube
11
- * const track: Track = {
12
- * id: "dQw4w9WgXcQ",
13
- * title: "Never Gonna Give You Up",
14
- * url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
15
- * duration: 212000,
16
- * thumbnail: "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
17
- * requestedBy: "123456789",
18
- * source: "youtube",
19
- * metadata: {
20
- * artist: "Rick Astley",
21
- * album: "Whenever You Need Somebody"
22
- * }
23
- * };
24
- *
25
- * // Track from SoundCloud
26
- * const soundcloudTrack: Track = {
27
- * id: "soundcloud-track-123",
28
- * title: "Electronic Song",
29
- * url: "https://soundcloud.com/artist/electronic-song",
30
- * duration: 180000,
31
- * requestedBy: "user456",
32
- * source: "soundcloud",
33
- * metadata: {
34
- * artist: "Electronic Artist",
35
- * genre: "Electronic"
36
- * }
37
- * };
38
- *
39
- * // TTS track
40
- * const ttsTrack: Track = {
41
- * id: "tts-" + Date.now(),
42
- * title: "TTS: Hello everyone!",
43
- * url: "tts: Hello everyone!",
44
- * duration: 5000,
45
- * requestedBy: "user789",
46
- * source: "tts",
47
- * metadata: {
48
- * text: "Hello everyone!",
49
- * language: "en"
50
- * }
51
- * };
52
- */
53
- export interface Track {
54
- id: string;
55
- title: string;
56
- url: string;
57
- duration: number;
58
- thumbnail?: string;
59
- requestedBy: string;
60
- source: string;
61
- metadata?: Record<string, any>;
62
- }
63
-
64
- /**
65
- * Contains search results from plugins, including tracks and optional playlist information.
66
- *
67
- * @example
68
- * const result: SearchResult = {
69
- * tracks: [
70
- * {
71
- * id: "track1",
72
- * title: "Song 1",
73
- * url: "https://example.com/track1",
74
- * duration: 180000,
75
- * requestedBy: "user123",
76
- * source: "youtube"
77
- * }
78
- * ],
79
- * playlist: {
80
- * name: "My Playlist",
81
- * url: "https://example.com/playlist",
82
- * thumbnail: "https://example.com/thumb.jpg"
83
- * }
84
- * };
85
- */
86
- export interface SearchResult {
87
- tracks: Track[];
88
- playlist?: {
89
- name: string;
90
- url: string;
91
- thumbnail?: string;
92
- };
93
- }
94
-
95
- /**
96
- * Contains streaming information for audio playback.
97
- *
98
- * @example
99
- * const streamInfo: StreamInfo = {
100
- * stream: audioStream,
101
- * type: "webm/opus",
102
- * metadata: {
103
- * bitrate: 128000,
104
- * sampleRate: 48000
105
- * }
106
- * };
107
- */
108
- export interface StreamInfo {
109
- stream: Readable;
110
- type: "webm/opus" | "ogg/opus" | "arbitrary";
111
- metadata?: Record<string, any>;
112
- }
113
-
114
- /**
115
- * Configuration options for creating a new player instance.
116
- *
117
- * @example
118
- * const options: PlayerOptions = {
119
- * leaveOnEnd: true,
120
- * leaveOnEmpty: true,
121
- * leaveTimeout: 30000,
122
- * volume: 0.5,
123
- * quality: "high",
124
- * selfDeaf: false,
125
- * selfMute: false,
126
- * extractorTimeout: 10000,
127
- * tts: {
128
- * createPlayer: true,
129
- * interrupt: true,
130
- * volume: 1.0,
131
- * Max_Time_TTS: 30000
132
- * }
133
- * };
134
- */
135
- export interface PlayerOptions {
136
- leaveOnEnd?: boolean;
137
- leaveOnEmpty?: boolean;
138
- leaveTimeout?: number;
139
- volume?: number;
140
- quality?: "high" | "low";
141
- selfDeaf?: boolean;
142
- selfMute?: boolean;
143
- /**
144
- * Timeout in milliseconds for plugin operations (search, streaming, etc.)
145
- * to prevent long-running tasks from blocking the player.
146
- */
147
- extractorTimeout?: number;
148
- userdata?: Record<string, any>;
149
- /**
150
- * Text-to-Speech settings. When enabled, the player can create a
151
- * dedicated AudioPlayer to play TTS while pausing the music player
152
- * then resume the music after TTS finishes.
153
- */
154
- tts?: {
155
- /** Create a dedicated tts AudioPlayer at construction time */
156
- createPlayer?: boolean;
157
- /** Pause music and swap subscription to play TTS */
158
- interrupt?: boolean;
159
- /** Default TTS volume multiplier 1 => 100% */
160
- volume?: number;
161
- /** Max time tts playback Duration */
162
- Max_Time_TTS?: number;
163
- };
164
- /**
165
- * Optional per-player extension selection. When provided, only these
166
- * extensions will be activated for the created player.
167
- * - Provide instances or constructors to use them explicitly
168
- * - Or provide names (string) to select from manager-registered extensions
169
- */
170
- extensions?: any[] | string[];
171
- }
172
-
173
- /**
174
- * Constructor for a SourcePlugin
175
- *
176
- * @example
177
- * const plugin = new YouTubePlugin();
178
- * console.log(`Plugin: ${plugin.name}`);
179
- */
180
- export type SourcePluginCtor<T extends SourcePlugin = SourcePlugin> = new (...args: any[]) => T;
181
-
182
- /**
183
- * SourcePlugin or SourcePluginCtor
184
- *
185
- * @example
186
- * const plugin = new YouTubePlugin();
187
- * console.log(`Plugin: ${plugin.name}`);
188
- */
189
- export type SourcePluginLike = SourcePlugin | SourcePluginCtor;
190
-
191
- /**
192
- * Configuration options for creating a PlayerManager instance.
193
- *
194
- * @example
195
- * const managerOptions: PlayerManagerOptions = {
196
- * plugins: [
197
- * new YouTubePlugin(),
198
- * new SoundCloudPlugin(),
199
- * new SpotifyPlugin(),
200
- * new TTSPlugin({ defaultLang: "en" })
201
- * ],
202
- * extensions: [
203
- * new voiceExt(null, { lang: "en-US" }),
204
- * new lavalinkExt(null, { nodes: [...] })
205
- * ],
206
- * extractorTimeout: 10000
207
- * };
208
- */
209
- export interface PlayerManagerOptions {
210
- plugins?: SourcePluginLike[];
211
- extensions?: any[];
212
- /**
213
- * Timeout in milliseconds for manager-level operations (e.g. search)
214
- * when running without a Player instance.
215
- */
216
- extractorTimeout?: number;
217
- }
218
-
219
- /**
220
- * Options for the progress bar
221
- *
222
- * @example
223
- * const options: ProgressBarOptions = {
224
- * size: 10,
225
- * barChar: "=",
226
- * progressChar: ">"
227
- * };
228
- */
229
- export interface ProgressBarOptions {
230
- size?: number;
231
- barChar?: string;
232
- progressChar?: string;
233
- }
234
-
235
- export type LoopMode = "off" | "track" | "queue";
236
-
237
- /**
238
- * Context for the extension
239
- *
240
- * @example
241
- * const context: ExtensionContext = {
242
- * player: player,
243
- * manager: manager
244
- * };
245
- */
246
- export interface ExtensionContext {
247
- player: Player;
248
- manager: PlayerManager;
249
- }
250
-
251
- /**
252
- * Request for the extension to play a track
253
- *
254
- * @example
255
- * const request: ExtensionPlayRequest = {
256
- * query: "Song Name",
257
- * requestedBy: "user123"
258
- * };
259
- */
260
- export interface ExtensionPlayRequest {
261
- query: string | Track;
262
- requestedBy?: string;
263
- }
264
-
265
- /**
266
- * Response for the extension to play a track
267
- *
268
- * @example
269
- * const response: ExtensionPlayResponse = {
270
- * handled: true,
271
- * query: "Song Name",
272
- * requestedBy: "user123"
273
- * };
274
- */
275
- export interface ExtensionPlayResponse {
276
- handled?: boolean;
277
- query?: string | Track;
278
- requestedBy?: string;
279
- tracks?: Track[];
280
- isPlaylist?: boolean;
281
- success?: boolean;
282
- error?: Error;
283
- }
284
-
285
- /**
286
- * Payload for the extension to play a track
287
- *
288
- * @example
289
- * const payload: ExtensionAfterPlayPayload = {
290
- * success: true,
291
- * query: "Song Name",
292
- * requestedBy: "user123"
293
- * };
294
- */
295
- export interface ExtensionAfterPlayPayload {
296
- success: boolean;
297
- query: string | Track;
298
- requestedBy?: string;
299
- tracks?: Track[];
300
- isPlaylist?: boolean;
301
- error?: Error;
302
- }
303
-
304
- /**
305
- * Request for the extension to stream a track
306
- *
307
- * @example
308
- * const request: ExtensionStreamRequest = {
309
- * track: track
310
- * };
311
- */
312
- export interface ExtensionStreamRequest {
313
- track: Track;
314
- }
315
-
316
- /**
317
- * Request for the extension to search for a track
318
- *
319
- * @example
320
- * const request: ExtensionSearchRequest = {
321
- * query: "Song Name",
322
- * requestedBy: "user123"
323
- * };
324
- */
325
- export interface ExtensionSearchRequest {
326
- query: string;
327
- requestedBy: string;
328
- }
329
-
330
- /**
331
- * Event types emitted by Player instances.
332
- *
333
- * @example
334
- *
335
- * player.on("willPlay", (player, track) => {
336
- * console.log(`Up next: ${track.title}`);
337
- * });
338
- *
339
- * player.on("trackEnd", (player, track) => {
340
- * console.log(`Now playing: ${track.title}`);
341
- * });
342
- *
343
- * player.on("queueAdd", (player, track) => {
344
- * console.log(`Queue added: ${track.title}`);
345
- * });
346
- *
347
- * player.on("queueAddList", (player, tracks) => {
348
- * console.log(`Queue added: ${tracks.length} tracks`);
349
- * });
350
- *
351
- * player.on("queueRemove", (player, track, index) => {
352
- * console.log(`Queue removed: ${track.title} at index ${index}`);
353
- * });
354
- *
355
- * player.on("playerPause", (player, track) => {
356
- * console.log(`Player paused: ${track.title}`);
357
- * });
358
- *
359
- * player.on("playerResume", (player, track) => {
360
- * console.log(`Player resumed: ${track.title}`);
361
- * });
362
- *
363
- * player.on("playerStop", (player) => {
364
- * console.log("Player stopped");
365
- * });
366
- *
367
- * player.on("playerDestroy", (player) => {
368
- * console.log("Player destroyed");
369
- * });
370
- *
371
- * player.on("ttsStart", (player, payload) => {
372
- * console.log(`TTS started: ${payload.text}`);
373
- * });
374
- *
375
- * player.on("ttsEnd", (player) => {
376
- * console.log("TTS ended");
377
- * });
378
- *
379
- * player.on("playerError", (player, error, track) => {
380
- * console.log(`Player error: ${error.message}`);
381
- * });
382
- *
383
- * player.on("connectionError", (player, error) => {
384
- * console.log(`Connection error: ${error.message}`);
385
- * });
386
- * player.on("trackStart", (player, track) => {
387
- * console.log(`Track started: ${track.title}`);
388
- * });
389
- *
390
- * player.on("volumeChange", (player, oldVolume, newVolume) => {
391
- * console.log(`Volume changed: ${oldVolume} -> ${newVolume}`);
392
- * });
393
- *
394
- * player.on("queueEnd", (player) => {
395
- * console.log("Queue finished");
396
- * });
397
- *
398
- */
399
- export interface PlayerEvents {
400
- debug: [message: string, ...args: any[]];
401
- willPlay: [track: Track, upcomingTracks: Track[]];
402
- trackStart: [track: Track];
403
- trackEnd: [track: Track];
404
- queueEnd: [];
405
- playerError: [error: Error, track?: Track];
406
- connectionError: [error: Error];
407
- volumeChange: [oldVolume: number, newVolume: number];
408
- queueAdd: [track: Track];
409
- queueAddList: [tracks: Track[]];
410
- queueRemove: [track: Track, index: number];
411
- playerPause: [track: Track];
412
- playerResume: [track: Track];
413
- playerStop: [];
414
- playerDestroy: [];
415
- /** Emitted when TTS starts playing (interruption mode) */
416
- ttsStart: [payload: { text?: string; track?: Track }];
417
- /** Emitted when TTS finished (interruption mode) */
418
- ttsEnd: [];
419
- }
420
- /**
421
- * Plugin interface
422
- *
423
- * @example
424
- * const plugin: SourcePlugin = {
425
- * name: "YouTube",
426
- * version: "1.0.0"
427
- * };
428
- */
429
- export interface SourcePlugin {
430
- name: string;
431
- version: string;
432
- canHandle(query: string): boolean;
433
- search(query: string, requestedBy: string): Promise<SearchResult>;
434
- getStream(track: Track): Promise<StreamInfo>;
435
- getRelatedTracks?(track: string | number, opts?: { limit?: number; offset?: number }): Promise<Track[]>;
436
- validate?(url: string): boolean;
437
- extractPlaylist?(url: string, requestedBy: string): Promise<Track[]>;
438
- }
439
-
440
- /**
441
- * Extension interface
442
- *
443
- * @example
444
- * const extension: SourceExtension = {
445
- * name: "YouTube",
446
- * version: "1.0.0"
447
- * };
448
- */
449
- export interface SourceExtension {
450
- name: string;
451
- version: string;
452
- connection?: VoiceConnection;
453
- player: Player | null;
454
- active(alas: any): boolean | Promise<boolean>;
455
- onRegister?(context: ExtensionContext): void | Promise<void>;
456
- onDestroy?(context: ExtensionContext): void | Promise<void>;
457
- beforePlay?(
458
- context: ExtensionContext,
459
- payload: ExtensionPlayRequest,
460
- ): Promise<ExtensionPlayResponse | void> | ExtensionPlayResponse | void;
461
- afterPlay?(context: ExtensionContext, payload: ExtensionAfterPlayPayload): Promise<void> | void;
462
- provideSearch?(
463
- context: ExtensionContext,
464
- payload: ExtensionSearchRequest,
465
- ): Promise<SearchResult | null | undefined> | SearchResult | null | undefined;
466
- provideStream?(
467
- context: ExtensionContext,
468
- payload: ExtensionStreamRequest,
469
- ): Promise<StreamInfo | null | undefined> | StreamInfo | null | undefined;
470
- }
1
+ import { VoiceConnection } from "@discordjs/voice";
2
+ import { Readable } from "stream";
3
+ import { Player } from "../structures/Player";
4
+ import type { PlayerManager } from "../structures/PlayerManager";
5
+
6
+ /**
7
+ * Represents a music track with metadata and streaming information.
8
+ *
9
+ * @example
10
+ * // Basic track from YouTube
11
+ * const track: Track = {
12
+ * id: "dQw4w9WgXcQ",
13
+ * title: "Never Gonna Give You Up",
14
+ * url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
15
+ * duration: 212000,
16
+ * thumbnail: "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
17
+ * requestedBy: "123456789",
18
+ * source: "youtube",
19
+ * metadata: {
20
+ * artist: "Rick Astley",
21
+ * album: "Whenever You Need Somebody"
22
+ * }
23
+ * };
24
+ *
25
+ * // Track from SoundCloud
26
+ * const soundcloudTrack: Track = {
27
+ * id: "soundcloud-track-123",
28
+ * title: "Electronic Song",
29
+ * url: "https://soundcloud.com/artist/electronic-song",
30
+ * duration: 180000,
31
+ * requestedBy: "user456",
32
+ * source: "soundcloud",
33
+ * metadata: {
34
+ * artist: "Electronic Artist",
35
+ * genre: "Electronic"
36
+ * }
37
+ * };
38
+ *
39
+ * // TTS track
40
+ * const ttsTrack: Track = {
41
+ * id: "tts-" + Date.now(),
42
+ * title: "TTS: Hello everyone!",
43
+ * url: "tts: Hello everyone!",
44
+ * duration: 5000,
45
+ * requestedBy: "user789",
46
+ * source: "tts",
47
+ * metadata: {
48
+ * text: "Hello everyone!",
49
+ * language: "en"
50
+ * }
51
+ * };
52
+ */
53
+ export interface Track {
54
+ id: string;
55
+ title: string;
56
+ url: string;
57
+ duration: number;
58
+ thumbnail?: string;
59
+ requestedBy: string;
60
+ source: string;
61
+ metadata?: Record<string, any>;
62
+ }
63
+
64
+ /**
65
+ * Contains search results from plugins, including tracks and optional playlist information.
66
+ *
67
+ * @example
68
+ * const result: SearchResult = {
69
+ * tracks: [
70
+ * {
71
+ * id: "track1",
72
+ * title: "Song 1",
73
+ * url: "https://example.com/track1",
74
+ * duration: 180000,
75
+ * requestedBy: "user123",
76
+ * source: "youtube"
77
+ * }
78
+ * ],
79
+ * playlist: {
80
+ * name: "My Playlist",
81
+ * url: "https://example.com/playlist",
82
+ * thumbnail: "https://example.com/thumb.jpg"
83
+ * }
84
+ * };
85
+ */
86
+ export interface SearchResult {
87
+ tracks: Track[];
88
+ playlist?: {
89
+ name: string;
90
+ url: string;
91
+ thumbnail?: string;
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Contains streaming information for audio playback.
97
+ *
98
+ * @example
99
+ * const streamInfo: StreamInfo = {
100
+ * stream: audioStream,
101
+ * type: "webm/opus",
102
+ * metadata: {
103
+ * bitrate: 128000,
104
+ * sampleRate: 48000
105
+ * }
106
+ * };
107
+ */
108
+ export interface StreamInfo {
109
+ stream: Readable;
110
+ type: "webm/opus" | "ogg/opus" | "arbitrary";
111
+ metadata?: Record<string, any>;
112
+ }
113
+
114
+ /**
115
+ * Configuration options for creating a new player instance.
116
+ *
117
+ * @example
118
+ * const options: PlayerOptions = {
119
+ * leaveOnEnd: true,
120
+ * leaveOnEmpty: true,
121
+ * leaveTimeout: 30000,
122
+ * volume: 0.5,
123
+ * quality: "high",
124
+ * selfDeaf: false,
125
+ * selfMute: false,
126
+ * extractorTimeout: 10000,
127
+ * tts: {
128
+ * createPlayer: true,
129
+ * interrupt: true,
130
+ * volume: 1.0,
131
+ * Max_Time_TTS: 30000
132
+ * }
133
+ * };
134
+ */
135
+ export interface PlayerOptions {
136
+ leaveOnEnd?: boolean;
137
+ leaveOnEmpty?: boolean;
138
+ leaveTimeout?: number;
139
+ volume?: number;
140
+ quality?: "high" | "low";
141
+ selfDeaf?: boolean;
142
+ selfMute?: boolean;
143
+ /**
144
+ * Timeout in milliseconds for plugin operations (search, streaming, etc.)
145
+ * to prevent long-running tasks from blocking the player.
146
+ */
147
+ extractorTimeout?: number;
148
+ userdata?: Record<string, any>;
149
+ /**
150
+ * Text-to-Speech settings. When enabled, the player can create a
151
+ * dedicated AudioPlayer to play TTS while pausing the music player
152
+ * then resume the music after TTS finishes.
153
+ */
154
+ tts?: {
155
+ /** Create a dedicated tts AudioPlayer at construction time */
156
+ createPlayer?: boolean;
157
+ /** Pause music and swap subscription to play TTS */
158
+ interrupt?: boolean;
159
+ /** Default TTS volume multiplier 1 => 100% */
160
+ volume?: number;
161
+ /** Max time tts playback Duration */
162
+ Max_Time_TTS?: number;
163
+ };
164
+ /**
165
+ * Optional per-player extension selection. When provided, only these
166
+ * extensions will be activated for the created player.
167
+ * - Provide instances or constructors to use them explicitly
168
+ * - Or provide names (string) to select from manager-registered extensions
169
+ */
170
+ extensions?: any[] | string[];
171
+ }
172
+
173
+ /**
174
+ * Constructor for a SourcePlugin
175
+ *
176
+ * @example
177
+ * const plugin = new YouTubePlugin();
178
+ * console.log(`Plugin: ${plugin.name}`);
179
+ */
180
+ export type SourcePluginCtor<T extends SourcePlugin = SourcePlugin> = new (...args: any[]) => T;
181
+
182
+ /**
183
+ * SourcePlugin or SourcePluginCtor
184
+ *
185
+ * @example
186
+ * const plugin = new YouTubePlugin();
187
+ * console.log(`Plugin: ${plugin.name}`);
188
+ */
189
+ export type SourcePluginLike = SourcePlugin | SourcePluginCtor;
190
+
191
+ /**
192
+ * Configuration options for creating a PlayerManager instance.
193
+ *
194
+ * @example
195
+ * const managerOptions: PlayerManagerOptions = {
196
+ * plugins: [
197
+ * new YouTubePlugin(),
198
+ * new SoundCloudPlugin(),
199
+ * new SpotifyPlugin(),
200
+ * new TTSPlugin({ defaultLang: "en" })
201
+ * ],
202
+ * extensions: [
203
+ * new voiceExt(null, { lang: "en-US" }),
204
+ * new lavalinkExt(null, { nodes: [...] })
205
+ * ],
206
+ * extractorTimeout: 10000
207
+ * };
208
+ */
209
+ export interface PlayerManagerOptions {
210
+ plugins?: SourcePluginLike[];
211
+ extensions?: any[];
212
+ /**
213
+ * Timeout in milliseconds for manager-level operations (e.g. search)
214
+ * when running without a Player instance.
215
+ */
216
+ extractorTimeout?: number;
217
+ }
218
+
219
+ /**
220
+ * Options for the progress bar
221
+ *
222
+ * @example
223
+ * const options: ProgressBarOptions = {
224
+ * size: 10,
225
+ * barChar: "=",
226
+ * progressChar: ">"
227
+ * };
228
+ */
229
+ export interface ProgressBarOptions {
230
+ size?: number;
231
+ barChar?: string;
232
+ progressChar?: string;
233
+ }
234
+
235
+ /**
236
+ * Options for saving tracks
237
+ *
238
+ * @example
239
+ * const options: SaveOptions = {
240
+ * filename: "my-song.mp3",
241
+ * quality: "high",
242
+ * timeout: 30000
243
+ * };
244
+ */
245
+ export interface SaveOptions {
246
+ /** Optional filename for the saved file */
247
+ filename?: string;
248
+ /** Quality of the saved audio ("high" | "low") */
249
+ quality?: "high" | "low";
250
+ /** Timeout in milliseconds for the save operation */
251
+ timeout?: number;
252
+ /** Additional metadata to include */
253
+ metadata?: Record<string, any>;
254
+ }
255
+
256
+ export type LoopMode = "off" | "track" | "queue";
257
+
258
+ /**
259
+ * Context for the extension
260
+ *
261
+ * @example
262
+ * const context: ExtensionContext = {
263
+ * player: player,
264
+ * manager: manager
265
+ * };
266
+ */
267
+ export interface ExtensionContext {
268
+ player: Player;
269
+ manager: PlayerManager;
270
+ }
271
+
272
+ /**
273
+ * Request for the extension to play a track
274
+ *
275
+ * @example
276
+ * const request: ExtensionPlayRequest = {
277
+ * query: "Song Name",
278
+ * requestedBy: "user123"
279
+ * };
280
+ */
281
+ export interface ExtensionPlayRequest {
282
+ query: string | Track;
283
+ requestedBy?: string;
284
+ }
285
+
286
+ /**
287
+ * Response for the extension to play a track
288
+ *
289
+ * @example
290
+ * const response: ExtensionPlayResponse = {
291
+ * handled: true,
292
+ * query: "Song Name",
293
+ * requestedBy: "user123"
294
+ * };
295
+ */
296
+ export interface ExtensionPlayResponse {
297
+ handled?: boolean;
298
+ query?: string | Track;
299
+ requestedBy?: string;
300
+ tracks?: Track[];
301
+ isPlaylist?: boolean;
302
+ success?: boolean;
303
+ error?: Error;
304
+ }
305
+
306
+ /**
307
+ * Payload for the extension to play a track
308
+ *
309
+ * @example
310
+ * const payload: ExtensionAfterPlayPayload = {
311
+ * success: true,
312
+ * query: "Song Name",
313
+ * requestedBy: "user123"
314
+ * };
315
+ */
316
+ export interface ExtensionAfterPlayPayload {
317
+ success: boolean;
318
+ query: string | Track;
319
+ requestedBy?: string;
320
+ tracks?: Track[];
321
+ isPlaylist?: boolean;
322
+ error?: Error;
323
+ }
324
+
325
+ /**
326
+ * Request for the extension to stream a track
327
+ *
328
+ * @example
329
+ * const request: ExtensionStreamRequest = {
330
+ * track: track
331
+ * };
332
+ */
333
+ export interface ExtensionStreamRequest {
334
+ track: Track;
335
+ }
336
+
337
+ /**
338
+ * Request for the extension to search for a track
339
+ *
340
+ * @example
341
+ * const request: ExtensionSearchRequest = {
342
+ * query: "Song Name",
343
+ * requestedBy: "user123"
344
+ * };
345
+ */
346
+ export interface ExtensionSearchRequest {
347
+ query: string;
348
+ requestedBy: string;
349
+ }
350
+
351
+ /**
352
+ * Event types emitted by Player instances.
353
+ *
354
+ * @example
355
+ *
356
+ * manager.on("willPlay", (player, track) => {
357
+ * console.log(`Up next: ${track.title}`);
358
+ * });
359
+ *
360
+ * manager.on("trackEnd", (player, track) => {
361
+ * console.log(`Now playing: ${track.title}`);
362
+ * });
363
+ *
364
+ * manager.on("queueAdd", (player, track) => {
365
+ * console.log(`Queue added: ${track.title}`);
366
+ * });
367
+ *
368
+ * manager.on("queueAddList", (player, tracks) => {
369
+ * console.log(`Queue added: ${tracks.length} tracks`);
370
+ * });
371
+ *
372
+ * manager.on("queueRemove", (player, track, index) => {
373
+ * console.log(`Queue removed: ${track.title} at index ${index}`);
374
+ * });
375
+ *
376
+ * manager.on("playerPause", (player, track) => {
377
+ * console.log(`Player paused: ${track.title}`);
378
+ * });
379
+ *
380
+ * manager.on("playerResume", (player, track) => {
381
+ * console.log(`Player resumed: ${track.title}`);
382
+ * });
383
+ *
384
+ * manager.on("playerStop", (player) => {
385
+ * console.log("Player stopped");
386
+ * });
387
+ *
388
+ * manager.on("playerDestroy", (player) => {
389
+ * console.log("Player destroyed");
390
+ * });
391
+ *
392
+ * manager.on("ttsStart", (player, payload) => {
393
+ * console.log(`TTS started: ${payload.text}`);
394
+ * });
395
+ *
396
+ * manager.on("ttsEnd", (player) => {
397
+ * console.log("TTS ended");
398
+ * });
399
+ *
400
+ * manager.on("playerError", (player, error, track) => {
401
+ * console.log(`Player error: ${error.message}`);
402
+ * });
403
+ *
404
+ * manager.on("connectionError", (player, error) => {
405
+ * console.log(`Connection error: ${error.message}`);
406
+ * });
407
+ * manager.on("trackStart", (player, track) => {
408
+ * console.log(`Track started: ${track.title}`);
409
+ * });
410
+ *
411
+ * manager.on("volumeChange", (player, oldVolume, newVolume) => {
412
+ * console.log(`Volume changed: ${oldVolume} -> ${newVolume}`);
413
+ * });
414
+ *
415
+ * manager.on("queueEnd", (player) => {
416
+ * console.log("Queue finished");
417
+ * });
418
+ *
419
+ */
420
+ export interface ManagerEvents {
421
+ debug: [message: string, ...args: any[]];
422
+ willPlay: [player: Player, track: Track, upcomingTracks: Track[]];
423
+ trackStart: [player: Player, track: Track];
424
+ trackEnd: [player: Player, track: Track];
425
+ queueEnd: [player: Player];
426
+ playerError: [player: Player, error: Error, track?: Track];
427
+ connectionError: [player: Player, error: Error];
428
+ volumeChange: [player: Player, oldVolume: number, newVolume: number];
429
+ queueAdd: [player: Player, track: Track];
430
+ queueAddList: [player: Player, tracks: Track[]];
431
+ queueRemove: [player: Player, track: Track, index: number];
432
+ playerPause: [player: Player, track: Track];
433
+ playerResume: [player: Player, track: Track];
434
+ playerStop: [player: Player];
435
+ playerDestroy: [player: Player];
436
+ ttsStart: [player: Player, payload: { text?: string; track?: Track }];
437
+ ttsEnd: [player: Player];
438
+ }
439
+ export interface PlayerEvents {
440
+ debug: [message: string, ...args: any[]];
441
+ willPlay: [track: Track, upcomingTracks: Track[]];
442
+ trackStart: [track: Track];
443
+ trackEnd: [track: Track];
444
+ queueEnd: [];
445
+ playerError: [error: Error, track?: Track];
446
+ connectionError: [error: Error];
447
+ volumeChange: [oldVolume: number, newVolume: number];
448
+ queueAdd: [track: Track];
449
+ queueAddList: [tracks: Track[]];
450
+ queueRemove: [track: Track, index: number];
451
+ playerPause: [track: Track];
452
+ playerResume: [track: Track];
453
+ playerStop: [];
454
+ playerDestroy: [];
455
+ /** Emitted when TTS starts playing (interruption mode) */
456
+ ttsStart: [payload: { text?: string; track?: Track }];
457
+ /** Emitted when TTS finished (interruption mode) */
458
+ ttsEnd: [];
459
+ }
460
+ /**
461
+ * Plugin interface
462
+ *
463
+ * @example
464
+ * const plugin: SourcePlugin = {
465
+ * name: "YouTube",
466
+ * version: "1.0.0"
467
+ * };
468
+ */
469
+ export interface SourcePlugin {
470
+ name: string;
471
+ version: string;
472
+ canHandle(query: string): boolean;
473
+ search(query: string, requestedBy: string): Promise<SearchResult>;
474
+ getStream(track: Track): Promise<StreamInfo>;
475
+ getRelatedTracks?(track: string | number, opts?: { limit?: number; offset?: number }): Promise<Track[]>;
476
+ validate?(url: string): boolean;
477
+ extractPlaylist?(url: string, requestedBy: string): Promise<Track[]>;
478
+ }
479
+
480
+ /**
481
+ * Extension interface
482
+ *
483
+ * @example
484
+ * const extension: SourceExtension = {
485
+ * name: "YouTube",
486
+ * version: "1.0.0"
487
+ * };
488
+ */
489
+ export interface SourceExtension {
490
+ name: string;
491
+ version: string;
492
+ connection?: VoiceConnection;
493
+ player: Player | null;
494
+ active(alas: any): boolean | Promise<boolean>;
495
+ onRegister?(context: ExtensionContext): void | Promise<void>;
496
+ onDestroy?(context: ExtensionContext): void | Promise<void>;
497
+ beforePlay?(
498
+ context: ExtensionContext,
499
+ payload: ExtensionPlayRequest,
500
+ ): Promise<ExtensionPlayResponse | void> | ExtensionPlayResponse | void;
501
+ afterPlay?(context: ExtensionContext, payload: ExtensionAfterPlayPayload): Promise<void> | void;
502
+ provideSearch?(
503
+ context: ExtensionContext,
504
+ payload: ExtensionSearchRequest,
505
+ ): Promise<SearchResult | null | undefined> | SearchResult | null | undefined;
506
+ provideStream?(
507
+ context: ExtensionContext,
508
+ payload: ExtensionStreamRequest,
509
+ ): Promise<StreamInfo | null | undefined> | StreamInfo | null | undefined;
510
+ }