ziplayer 0.2.7-dev.3 → 0.3.0

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 (47) hide show
  1. package/AI-Guide.md +624 -607
  2. package/README.md +526 -524
  3. package/dist/plugins/index.d.ts +62 -12
  4. package/dist/plugins/index.d.ts.map +1 -1
  5. package/dist/plugins/index.js +497 -57
  6. package/dist/plugins/index.js.map +1 -1
  7. package/dist/structures/PersistenceManager.d.ts +96 -0
  8. package/dist/structures/PersistenceManager.d.ts.map +1 -0
  9. package/dist/structures/PersistenceManager.js +1008 -0
  10. package/dist/structures/PersistenceManager.js.map +1 -0
  11. package/dist/structures/Player.d.ts +109 -18
  12. package/dist/structures/Player.d.ts.map +1 -1
  13. package/dist/structures/Player.js +902 -182
  14. package/dist/structures/Player.js.map +1 -1
  15. package/dist/structures/PlayerManager.d.ts +1 -22
  16. package/dist/structures/PlayerManager.d.ts.map +1 -1
  17. package/dist/structures/PlayerManager.js +1 -73
  18. package/dist/structures/PlayerManager.js.map +1 -1
  19. package/dist/structures/StreamManager.d.ts +137 -0
  20. package/dist/structures/StreamManager.d.ts.map +1 -0
  21. package/dist/structures/StreamManager.js +420 -0
  22. package/dist/structures/StreamManager.js.map +1 -0
  23. package/dist/types/index.d.ts +149 -16
  24. package/dist/types/index.d.ts.map +1 -1
  25. package/dist/types/index.js +0 -1
  26. package/dist/types/index.js.map +1 -1
  27. package/dist/types/persistence.d.ts +3 -2
  28. package/dist/types/persistence.d.ts.map +1 -1
  29. package/package.json +47 -47
  30. package/src/extensions/BaseExtension.ts +36 -36
  31. package/src/extensions/index.ts +473 -473
  32. package/src/index.ts +16 -16
  33. package/src/plugins/BasePlugin.ts +27 -27
  34. package/src/plugins/index.ts +950 -403
  35. package/src/structures/FilterManager.ts +303 -303
  36. package/src/structures/Player.ts +2797 -1970
  37. package/src/structures/PlayerManager.ts +725 -822
  38. package/src/structures/Queue.ts +599 -599
  39. package/src/structures/StreamManager.ts +524 -0
  40. package/src/types/extension.ts +129 -129
  41. package/src/types/fillter.ts +264 -264
  42. package/src/types/index.ts +548 -415
  43. package/src/types/plugin.ts +59 -59
  44. package/src/utils/timeout.ts +10 -10
  45. package/tsconfig.json +22 -22
  46. package/src/persistence/PersistenceManager.ts +0 -1077
  47. package/src/types/persistence.ts +0 -85
@@ -1,415 +1,548 @@
1
- import { Readable } from "stream";
2
- import { Player } from "../structures/Player";
3
- import type { PlayerManager } from "../structures/PlayerManager";
4
- import type { AudioFilter } from "./fillter";
5
- import type { SourcePluginLike } from "./plugin";
6
- import type { PersistenceOptions } from "./persistence";
7
- /**
8
- * Represents a music track with metadata and streaming information.
9
- *
10
- * @example
11
- * // Basic track from YouTube
12
- * const track: Track = {
13
- * id: "dQw4w9WgXcQ",
14
- * title: "Never Gonna Give You Up",
15
- * url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
16
- * duration: 212000,
17
- * thumbnail: "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
18
- * requestedBy: "123456789",
19
- * source: "youtube",
20
- * metadata: {
21
- * artist: "Rick Astley",
22
- * album: "Whenever You Need Somebody"
23
- * }
24
- * };
25
- *
26
- * // Track from SoundCloud
27
- * const soundcloudTrack: Track = {
28
- * id: "soundcloud-track-123",
29
- * title: "Electronic Song",
30
- * url: "https://soundcloud.com/artist/electronic-song",
31
- * duration: 180000,
32
- * requestedBy: "user456",
33
- * source: "soundcloud",
34
- * metadata: {
35
- * artist: "Electronic Artist",
36
- * genre: "Electronic"
37
- * }
38
- * };
39
- *
40
- * // TTS track
41
- * const ttsTrack: Track = {
42
- * id: "tts-" + Date.now(),
43
- * title: "TTS: Hello everyone!",
44
- * url: "tts: Hello everyone!",
45
- * duration: 5000,
46
- * requestedBy: "user789",
47
- * source: "tts",
48
- * metadata: {
49
- * text: "Hello everyone!",
50
- * language: "en"
51
- * }
52
- * };
53
- */
54
- export interface Track {
55
- id: string;
56
- title: string;
57
- url: string;
58
- duration: number;
59
- thumbnail?: string;
60
- requestedBy: string;
61
- source: string;
62
- metadata?: Record<string, any>;
63
- isLive?: boolean;
64
- }
65
-
66
- /**
67
- * Contains search results from plugins, including tracks and optional playlist information.
68
- *
69
- * @example
70
- * const result: SearchResult = {
71
- * tracks: [
72
- * {
73
- * id: "track1",
74
- * title: "Song 1",
75
- * url: "https://example.com/track1",
76
- * duration: 180000,
77
- * requestedBy: "user123",
78
- * source: "youtube"
79
- * }
80
- * ],
81
- * playlist: {
82
- * name: "My Playlist",
83
- * url: "https://example.com/playlist",
84
- * thumbnail: "https://example.com/thumb.jpg"
85
- * }
86
- * };
87
- */
88
- export interface SearchResult {
89
- tracks: Track[];
90
- playlist?: {
91
- name: string;
92
- url: string;
93
- thumbnail?: string;
94
- };
95
- }
96
-
97
- /**
98
- * Contains streaming information for audio playback.
99
- *
100
- * @example
101
- * const streamInfo: StreamInfo = {
102
- * stream: audioStream,
103
- * type: "webm/opus",
104
- * metadata: {
105
- * bitrate: 128000,
106
- * sampleRate: 48000
107
- * }
108
- * };
109
- */
110
- export interface StreamInfo {
111
- stream: Readable;
112
- type: "webm/opus" | "ogg/opus" | "arbitrary";
113
- metadata?: Record<string, any>;
114
- }
115
-
116
- /**
117
- * Configuration options for creating a new player instance.
118
- *
119
- * @example
120
- * const options: PlayerOptions = {
121
- * leaveOnEnd: true,
122
- * leaveOnEmpty: true,
123
- * leaveTimeout: 30000,
124
- * volume: 0.5,
125
- * quality: "high",
126
- * selfDeaf: false,
127
- * selfMute: false,
128
- * extractorTimeout: 10000,
129
- * tts: {
130
- * createPlayer: true,
131
- * interrupt: true,
132
- * volume: 1.0,
133
- * maxTimeTts: 30000
134
- * }
135
- * };
136
- */
137
- export interface PlayerOptions {
138
- leaveOnEnd?: boolean;
139
- leaveOnEmpty?: boolean;
140
- leaveTimeout?: number;
141
- volume?: number;
142
- quality?: "high" | "low";
143
- selfDeaf?: boolean;
144
- selfMute?: boolean;
145
- /**
146
- * Timeout in milliseconds for plugin operations (search, streaming, etc.)
147
- * to prevent long-running tasks from blocking the player.
148
- */
149
- extractorTimeout?: number;
150
- userdata?: Record<string, any>;
151
- /**
152
- * Text-to-Speech settings. When enabled, the player can create a
153
- * dedicated AudioPlayer to play TTS while pausing the music player
154
- * then resume the music after TTS finishes.
155
- */
156
- tts?: {
157
- /** Create a dedicated tts AudioPlayer at construction time */
158
- createPlayer?: boolean;
159
- /** Pause music and swap subscription to play TTS */
160
- interrupt?: boolean;
161
- /** Default TTS volume multiplier 1 => 100% */
162
- volume?: number;
163
- /** Max time tts playback Duration */
164
- maxTimeTts?: number;
165
- };
166
- /**
167
- * Optional per-player extension selection. When provided, only these
168
- * extensions will be activated for the created player.
169
- * - Provide instances or constructors to use them explicitly
170
- * - Or provide names (string) to select from manager-registered extensions
171
- */
172
- extensions?: any[] | string[];
173
- /**
174
- * Audio filters configuration. When provided, these filters will be
175
- * applied to all audio streams played by this player.
176
- * - Provide filter names (string) to use predefined filters
177
- * - Or provide AudioFilter objects for custom filters
178
- * - Multiple filters can be combined
179
- */
180
- filters?: (string | AudioFilter)[];
181
- }
182
-
183
- export interface PlayerManagerOptions {
184
- plugins?: SourcePluginLike[];
185
- extensions?: any[];
186
- extractorTimeout?: number;
187
- autoCleanup?: boolean; // Auto cleanup inactive players
188
- cleanupInterval?: number; // Cleanup interval in ms
189
- enableSearchCache?: boolean; // Enable search result caching
190
- enableStatsCollection?: boolean; // Enable stats collection events
191
- persistence?: PersistenceOptions;
192
- }
193
-
194
- /**
195
- * Options for the progress bar
196
- *
197
- * @example
198
- * const options: ProgressBarOptions = {
199
- * size: 10,
200
- * barChar: "=",
201
- * progressChar: ">"
202
- * };
203
- */
204
- export interface ProgressBarOptions {
205
- size?: number; // Bar length (default: 20)
206
- barChar?: string; // Character for empty bar (default: "▬")
207
- progressChar?: string; // Character for progress pointer (default: "🔘")
208
- timeFormat?: "compact" | "full"; // Time format style (default: "compact")
209
- showPercentage?: boolean; // Show percentage at end (default: false)
210
- showTime?: boolean; // Show time labels (default: true)
211
- hideProgressChar?: boolean; // Hide progress character (default: false)
212
- }
213
-
214
- /**
215
- * Options for saving tracks
216
- *
217
- * @example
218
- * const options: SaveOptions = {
219
- * filename: "my-song.mp3",
220
- * quality: "high",
221
- * timeout: 30000
222
- * };
223
- */
224
- export interface SaveOptions {
225
- /** Optional filename for the saved file */
226
- filename?: string;
227
- /** Quality of the saved audio ("high" | "low") */
228
- quality?: "high" | "low";
229
- /** Timeout in milliseconds for the save operation */
230
- timeout?: number;
231
- /** Additional metadata to include */
232
- metadata?: Record<string, any>;
233
- /** Filter */
234
- filter?: AudioFilter[];
235
- /** Seek position in milliseconds to start saving from */
236
- seek?: number;
237
- }
238
- export interface PlayerSession {
239
- guildId: string;
240
- queue: Track[];
241
- currentTrack: Track | null;
242
- volume: number;
243
- loopMode: LoopMode;
244
- autoPlay: boolean;
245
- position: number | null;
246
- extensions: string[];
247
- plugins: string[];
248
- userdata?: Record<string, any>;
249
- }
250
-
251
- export interface PlayerStats {
252
- totalPlayers: number;
253
- activePlayers: number;
254
- pausedPlayers: number;
255
- connectedPlayers: number;
256
- totalTracksInQueue: number;
257
- }
258
-
259
- export type LoopMode = "off" | "track" | "queue";
260
-
261
- export interface VoiceChannel {
262
- id: string;
263
- guildId: string;
264
- type: any;
265
- guild: any;
266
- // Placeholder for VoiceConnection properties and methods
267
- }
268
-
269
- /**
270
- * Event types emitted by Player instances.
271
- *
272
- * @example
273
- *
274
- * manager.on("willPlay", (player, track) => {
275
- * console.log(`Up next: ${track.title}`);
276
- * });
277
- *
278
- * manager.on("trackEnd", (player, track) => {
279
- * console.log(`Now playing: ${track.title}`);
280
- * });
281
- *
282
- * manager.on("queueAdd", (player, track) => {
283
- * console.log(`Queue added: ${track.title}`);
284
- * });
285
- *
286
- * manager.on("queueAddList", (player, tracks) => {
287
- * console.log(`Queue added: ${tracks.length} tracks`);
288
- * });
289
- *
290
- * manager.on("queueRemove", (player, track, index) => {
291
- * console.log(`Queue removed: ${track.title} at index ${index}`);
292
- * });
293
- *
294
- * manager.on("playerPause", (player, track) => {
295
- * console.log(`Player paused: ${track.title}`);
296
- * });
297
- *
298
- * manager.on("playerResume", (player, track) => {
299
- * console.log(`Player resumed: ${track.title}`);
300
- * });
301
- *
302
- * manager.on("playerStop", (player) => {
303
- * console.log("Player stopped");
304
- * });
305
- *
306
- * manager.on("playerDestroy", (player) => {
307
- * console.log("Player destroyed");
308
- * });
309
- *
310
- * manager.on("ttsStart", (player, payload) => {
311
- * console.log(`TTS started: ${payload.text}`);
312
- * });
313
- *
314
- * manager.on("ttsEnd", (player) => {
315
- * console.log("TTS ended");
316
- * });
317
- *
318
- * manager.on("playerError", (player, error, track) => {
319
- * console.log(`Player error: ${error.message}`);
320
- * });
321
- *
322
- * manager.on("connectionError", (player, error) => {
323
- * console.log(`Connection error: ${error.message}`);
324
- * });
325
- * manager.on("trackStart", (player, track) => {
326
- * console.log(`Track started: ${track.title}`);
327
- * });
328
- *
329
- * manager.on("volumeChange", (player, oldVolume, newVolume) => {
330
- * console.log(`Volume changed: ${oldVolume} -> ${newVolume}`);
331
- * });
332
- *
333
- * manager.on("queueEnd", (player) => {
334
- * console.log("Queue finished");
335
- * });
336
- *
337
- */
338
- export interface ManagerEvents {
339
- debug: [message: string, ...args: any[]];
340
- willPlay: [player: Player, track: Track, upcomingTracks: Track[]];
341
- trackStart: [player: Player, track: Track];
342
- trackEnd: [player: Player, track: Track];
343
- queueEnd: [player: Player];
344
- playerError: [player: Player, error: Error, track?: Track];
345
- connectionError: [player: Player, error: Error];
346
- volumeChange: [player: Player, oldVolume: number, newVolume: number];
347
- queueAdd: [player: Player, track: Track];
348
- queueAddList: [player: Player, tracks: Track[]];
349
- queueRemove: [player: Player, track: Track, index: number];
350
- playerPause: [player: Player, track: Track];
351
- playerResume: [player: Player, track: Track];
352
- playerStop: [player: Player];
353
- playerDestroy: [player: Player];
354
- ttsStart: [player: Player, payload: { text?: string; track?: Track }];
355
- ttsEnd: [player: Player];
356
- /** Emitted when audio filter is applied */
357
- filterApplied: [player: Player, filter: AudioFilter];
358
- /** Emitted when audio filter is removed */
359
- filterRemoved: [player: Player, filter: AudioFilter];
360
- /** Emitted when all filters are cleared */
361
- filtersCleared: [player: Player];
362
- //extension events
363
- lyricsCreate: [player: Player, track: Track, lyrics: any];
364
- lyricsChange: [player: Player, track: Track, lyrics: any];
365
- voiceCreate: [player: Player, evt: any];
366
-
367
- // Persistence events
368
- stats: [stats: PlayerStats];
369
- playerSaved: [guildId: string];
370
- playerLoaded: [guildId: string, data: any];
371
- savedAll: [results: Map<string, boolean>];
372
- loadedAll: [results: Map<string, boolean>];
373
- RTSkipped: [guildId: string, reason: string];
374
- RTMarkedDestroyed: [guildId: string];
375
- RTDestroyedCleared: [guildId: string];
376
- backupsCleaned: [guildId: string, count: number];
377
- allBackupsCleaned: [count: number];
378
- backupStats: [stats: any];
379
- backupCleanupDone: [];
380
- }
381
- export interface PlayerEvents {
382
- debug: [message: string, ...args: any[]];
383
- willPlay: [track: Track, upcomingTracks: Track[]];
384
- trackStart: [track: Track];
385
- trackEnd: [track: Track];
386
- queueEnd: [];
387
- playerError: [error: Error, track?: Track];
388
- connectionError: [error: Error];
389
- volumeChange: [oldVolume: number, newVolume: number];
390
- queueAdd: [track: Track];
391
- queueAddList: [tracks: Track[]];
392
- queueRemove: [track: Track, index: number];
393
- playerPause: [track: Track];
394
- playerResume: [track: Track];
395
- playerStop: [];
396
- playerDestroy: [];
397
- /** Emitted when seeking to a position in current track */
398
- seek: [payload: { track: Track; position: number }];
399
- /** Emitted when TTS starts playing (interruption mode) */
400
- ttsStart: [payload: { text?: string; track?: Track }];
401
- /** Emitted when TTS finished (interruption mode) */
402
- ttsEnd: [];
403
- /** Emitted when audio filter is applied */
404
- filterApplied: [filter: AudioFilter];
405
- /** Emitted when audio filter is removed */
406
- filterRemoved: [filter: AudioFilter];
407
- /** Emitted when all filters are cleared */
408
- filtersCleared: [];
409
- trackStuck: [track: Track | null];
410
- }
411
-
412
- export * from "./fillter";
413
- export * from "./plugin";
414
- export * from "./extension";
415
- export * from "./persistence";
1
+ import { Readable } from "stream";
2
+ import { Player } from "../structures/Player";
3
+ import type { PlayerManager } from "../structures/PlayerManager";
4
+ import type { AudioFilter } from "./fillter";
5
+ import type { SourcePluginLike } from "./plugin";
6
+ import type { AudioResource } from "@discordjs/voice";
7
+ /**
8
+ * Represents a music track with metadata and streaming information.
9
+ *
10
+ * @example
11
+ * // Basic track from YouTube
12
+ * const track: Track = {
13
+ * id: "dQw4w9WgXcQ",
14
+ * title: "Never Gonna Give You Up",
15
+ * url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
16
+ * duration: 212000,
17
+ * thumbnail: "https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
18
+ * requestedBy: "123456789",
19
+ * source: "youtube",
20
+ * metadata: {
21
+ * artist: "Rick Astley",
22
+ * album: "Whenever You Need Somebody"
23
+ * }
24
+ * };
25
+ *
26
+ * // Track from SoundCloud
27
+ * const soundcloudTrack: Track = {
28
+ * id: "soundcloud-track-123",
29
+ * title: "Electronic Song",
30
+ * url: "https://soundcloud.com/artist/electronic-song",
31
+ * duration: 180000,
32
+ * requestedBy: "user456",
33
+ * source: "soundcloud",
34
+ * metadata: {
35
+ * artist: "Electronic Artist",
36
+ * genre: "Electronic"
37
+ * }
38
+ * };
39
+ *
40
+ * // TTS track
41
+ * const ttsTrack: Track = {
42
+ * id: "tts-" + Date.now(),
43
+ * title: "TTS: Hello everyone!",
44
+ * url: "tts: Hello everyone!",
45
+ * duration: 5000,
46
+ * requestedBy: "user789",
47
+ * source: "tts",
48
+ * metadata: {
49
+ * text: "Hello everyone!",
50
+ * language: "en"
51
+ * }
52
+ * };
53
+ */
54
+ export interface Track {
55
+ id: string;
56
+ title: string;
57
+ url: string;
58
+ duration: number;
59
+ thumbnail?: string;
60
+ requestedBy: string;
61
+ source: string;
62
+ metadata?: Record<string, any>;
63
+ isLive?: boolean;
64
+ }
65
+
66
+ /**
67
+ * Contains search results from plugins, including tracks and optional playlist information.
68
+ *
69
+ * @example
70
+ * const result: SearchResult = {
71
+ * tracks: [
72
+ * {
73
+ * id: "track1",
74
+ * title: "Song 1",
75
+ * url: "https://example.com/track1",
76
+ * duration: 180000,
77
+ * requestedBy: "user123",
78
+ * source: "youtube"
79
+ * }
80
+ * ],
81
+ * playlist: {
82
+ * name: "My Playlist",
83
+ * url: "https://example.com/playlist",
84
+ * thumbnail: "https://example.com/thumb.jpg"
85
+ * }
86
+ * };
87
+ */
88
+ export interface SearchResult {
89
+ tracks: Track[];
90
+ playlist?: {
91
+ name: string;
92
+ url?: string;
93
+ thumbnail?: string;
94
+ } | null;
95
+ query?: string;
96
+ score?: SearchScore;
97
+ source?: string;
98
+ }
99
+
100
+ export interface SearchScore {
101
+ score: number; // 0-100
102
+ reason: string; // Lý do đạt điểm
103
+ matchedBy: "url" | "title" | "partial" | "none" | "playlist";
104
+ exactMatch: boolean;
105
+ }
106
+ /**
107
+ * Contains streaming information for audio playback.
108
+ *
109
+ * @example
110
+ * const streamInfo: StreamInfo = {
111
+ * stream: audioStream,
112
+ * type: "webm/opus",
113
+ * metadata: {
114
+ * bitrate: 128000,
115
+ * sampleRate: 48000
116
+ * }
117
+ * };
118
+ */
119
+ export interface StreamInfo {
120
+ stream: Readable;
121
+ type: "webm/opus" | "ogg/opus" | "arbitrary";
122
+ metadata?: Record<string, any>;
123
+ }
124
+
125
+ /**
126
+ * Configuration options for creating a new player instance.
127
+ *
128
+ * @example
129
+ * const options: PlayerOptions = {
130
+ * leaveOnEnd: true,
131
+ * leaveOnEmpty: true,
132
+ * leaveTimeout: 30000,
133
+ * volume: 0.5,
134
+ * quality: "high",
135
+ * selfDeaf: false,
136
+ * selfMute: false,
137
+ * extractorTimeout: 10000,
138
+ * tts: {
139
+ * createPlayer: true,
140
+ * interrupt: true,
141
+ * volume: 1.0,
142
+ * maxTimeTts: 30000
143
+ * }
144
+ * };
145
+ */
146
+ export interface PlayerOptions {
147
+ leaveOnEnd?: boolean;
148
+ leaveOnEmpty?: boolean;
149
+ leaveTimeout?: number;
150
+ volume?: number;
151
+ quality?: "high" | "low";
152
+ selfDeaf?: boolean;
153
+ selfMute?: boolean;
154
+ /**
155
+ * Timeout in milliseconds for plugin operations (search, streaming, etc.)
156
+ * to prevent long-running tasks from blocking the player.
157
+ */
158
+ extractorTimeout?: number;
159
+ userdata?: Record<string, any>;
160
+ /**
161
+ * Text-to-Speech settings. When enabled, the player can create a
162
+ * dedicated AudioPlayer to play TTS while pausing the music player
163
+ * then resume the music after TTS finishes.
164
+ */
165
+ tts?: {
166
+ /** Create a dedicated tts AudioPlayer at construction time */
167
+ createPlayer?: boolean;
168
+ /** Pause music and swap subscription to play TTS */
169
+ interrupt?: boolean;
170
+ /** Default TTS volume multiplier 1 => 100% */
171
+ volume?: number;
172
+ /** Max time tts playback Duration */
173
+ maxTimeTts?: number;
174
+ };
175
+ /**
176
+ * Optional per-player extension selection. When provided, only these
177
+ * extensions will be activated for the created player.
178
+ * - Provide instances or constructors to use them explicitly
179
+ * - Or provide names (string) to select from manager-registered extensions
180
+ */
181
+ extensions?: any[] | string[];
182
+ /**
183
+ * Audio filters configuration. When provided, these filters will be
184
+ * applied to all audio streams played by this player.
185
+ * - Provide filter names (string) to use predefined filters
186
+ * - Or provide AudioFilter objects for custom filters
187
+ * - Multiple filters can be combined
188
+ */
189
+ filters?: (string | AudioFilter)[];
190
+ /**
191
+ * Enable low performance mode.
192
+ * When enabled, heavy features such as preload and crossfade can be auto-disabled.
193
+ */
194
+ lowPerformance?: boolean;
195
+ /**
196
+ * Preload behavior configuration.
197
+ */
198
+ preload?: {
199
+ /**
200
+ * Enable/disable preload explicitly.
201
+ * Default: true
202
+ */
203
+ enabled?: boolean;
204
+ /**
205
+ * Auto disable preload when lowPerformance is enabled.
206
+ * Default: true
207
+ */
208
+ autoDisableInLowPerformance?: boolean;
209
+ };
210
+ /**
211
+ * Crossfade behavior configuration.
212
+ */
213
+ crossfade?: {
214
+ /**
215
+ * Enable/disable crossfade explicitly.
216
+ * If omitted and autoEnable=true, ZiPlayer may enable it automatically.
217
+ */
218
+ enabled?: boolean;
219
+ /**
220
+ * Auto enable crossfade if runtime profile allows.
221
+ * Default: true
222
+ */
223
+ autoEnable?: boolean;
224
+ /**
225
+ * Auto disable crossfade when lowPerformance is enabled.
226
+ * Default: true
227
+ */
228
+ autoDisableInLowPerformance?: boolean;
229
+ /**
230
+ * Target crossfade duration in milliseconds.
231
+ * Default: 5000
232
+ */
233
+ durationMs?: number;
234
+ };
235
+ /**
236
+ * Smart transition engine settings.
237
+ */
238
+ smartTransition?: {
239
+ enabled?: boolean;
240
+ /**
241
+ * Prefer genre-aware fade duration when metadata.genre is available.
242
+ */
243
+ genreAware?: boolean;
244
+ /**
245
+ * Try to align transition with beat boundary using metadata.bpm.
246
+ */
247
+ beatAlign?: boolean;
248
+ /**
249
+ * Base duration in milliseconds when no specific profile matched.
250
+ */
251
+ baseDurationMs?: number;
252
+ minDurationMs?: number;
253
+ maxDurationMs?: number;
254
+ /**
255
+ * Genre profiles in milliseconds (e.g. chill, edm, pop, rock).
256
+ */
257
+ genreDurations?: Record<string, number>;
258
+ /**
259
+ * Max wait time while trying to align to beat boundary.
260
+ */
261
+ beatAlignMaxWaitMs?: number;
262
+ };
263
+ /**
264
+ * Recovery strategy for stream/player failures.
265
+ */
266
+ antiStuck?: {
267
+ enabled?: boolean;
268
+ maxRetries?: number;
269
+ retryDelayMs?: number;
270
+ /**
271
+ * Reuse preload/current cached stream before hard retries.
272
+ */
273
+ reusePreloadFirst?: boolean;
274
+ /**
275
+ * Temporarily force low quality during retry attempts.
276
+ */
277
+ reduceQualityOnRetry?: boolean;
278
+ /**
279
+ * If consecutive failures exceed this threshold, allow skipping track.
280
+ */
281
+ controlledSkipThreshold?: number;
282
+ };
283
+ /**
284
+ * Loudness normalization and limiter.
285
+ */
286
+ loudnessNormalization?: {
287
+ enabled?: boolean;
288
+ /**
289
+ * Target LUFS (integrated). Track metadata.lufs is used if available.
290
+ */
291
+ targetLUFS?: number;
292
+ /**
293
+ * Cap gain boost to avoid over-amplification.
294
+ */
295
+ maxBoostDb?: number;
296
+ /**
297
+ * Cap attenuation.
298
+ */
299
+ maxCutDb?: number;
300
+ /**
301
+ * Output ceiling multiplier (<= 1.0), acts as soft limiter ceiling.
302
+ */
303
+ limiterCeiling?: number;
304
+ };
305
+ }
306
+
307
+ export interface PlayerManagerOptions {
308
+ plugins?: SourcePluginLike[];
309
+ extensions?: any[];
310
+ extractorTimeout?: number;
311
+ autoCleanup?: boolean; // Auto cleanup inactive players
312
+ cleanupInterval?: number; // Cleanup interval in ms
313
+ enableSearchCache?: boolean; // Enable search result caching
314
+ enableStatsCollection?: boolean; // Enable stats collection events
315
+ }
316
+
317
+ /**
318
+ * Options for the progress bar
319
+ *
320
+ * @example
321
+ * const options: ProgressBarOptions = {
322
+ * size: 10,
323
+ * barChar: "=",
324
+ * progressChar: ">"
325
+ * };
326
+ */
327
+ export interface ProgressBarOptions {
328
+ size?: number; // Bar length (default: 20)
329
+ barChar?: string; // Character for empty bar (default: "▬")
330
+ progressChar?: string; // Character for progress pointer (default: "🔘")
331
+ timeFormat?: "compact" | "full"; // Time format style (default: "compact")
332
+ showPercentage?: boolean; // Show percentage at end (default: false)
333
+ showTime?: boolean; // Show time labels (default: true)
334
+ hideProgressChar?: boolean; // Hide progress character (default: false)
335
+ }
336
+
337
+ /**
338
+ * Options for saving tracks
339
+ *
340
+ * @example
341
+ * const options: SaveOptions = {
342
+ * filename: "my-song.mp3",
343
+ * quality: "high",
344
+ * timeout: 30000
345
+ * };
346
+ */
347
+ export interface SaveOptions {
348
+ /** Optional filename for the saved file */
349
+ filename?: string;
350
+ /** Quality of the saved audio ("high" | "low") */
351
+ quality?: "high" | "low";
352
+ /** Timeout in milliseconds for the save operation */
353
+ timeout?: number;
354
+ /** Additional metadata to include */
355
+ metadata?: Record<string, any>;
356
+ /** Filter */
357
+ filter?: AudioFilter[];
358
+ /** Seek position in milliseconds to start saving from */
359
+ seek?: number;
360
+ }
361
+ export interface PlayerSession {
362
+ guildId: string;
363
+ queue: Track[];
364
+ currentTrack: Track | null;
365
+ volume: number;
366
+ loopMode: LoopMode;
367
+ autoPlay: boolean;
368
+ position: number | null;
369
+ extensions: string[];
370
+ plugins: string[];
371
+ userdata?: Record<string, any>;
372
+ }
373
+
374
+ export interface PreloadState {
375
+ resource: AudioResource | null;
376
+ track: Track | null;
377
+ abortController: AbortController | null;
378
+ timeoutId: NodeJS.Timeout | null;
379
+ isValid: boolean;
380
+ streamId?: string;
381
+ isBeingUsed: boolean;
382
+ }
383
+
384
+ export interface PlayerStats {
385
+ totalPlayers: number;
386
+ activePlayers: number;
387
+ pausedPlayers: number;
388
+ connectedPlayers: number;
389
+ totalTracksInQueue: number;
390
+ }
391
+
392
+ export interface StreamSlot {
393
+ resource: AudioResource | null;
394
+ track: Track | null;
395
+ streamId: string | null;
396
+ abortController: AbortController | null;
397
+ isValid: boolean;
398
+ isLoading: boolean;
399
+ loadPromise: Promise<void> | null;
400
+ }
401
+
402
+ export type LoopMode = "off" | "track" | "queue";
403
+
404
+ export interface VoiceChannel {
405
+ id: string;
406
+ guildId: string;
407
+ type: any;
408
+ guild: any;
409
+ // Placeholder for VoiceConnection properties and methods
410
+ }
411
+
412
+ /**
413
+ * Event types emitted by Player instances.
414
+ *
415
+ * @example
416
+ *
417
+ * manager.on("willPlay", (player, track) => {
418
+ * console.log(`Up next: ${track.title}`);
419
+ * });
420
+ *
421
+ * manager.on("trackEnd", (player, track) => {
422
+ * console.log(`Now playing: ${track.title}`);
423
+ * });
424
+ *
425
+ * manager.on("queueAdd", (player, track) => {
426
+ * console.log(`Queue added: ${track.title}`);
427
+ * });
428
+ *
429
+ * manager.on("queueAddList", (player, tracks) => {
430
+ * console.log(`Queue added: ${tracks.length} tracks`);
431
+ * });
432
+ *
433
+ * manager.on("queueRemove", (player, track, index) => {
434
+ * console.log(`Queue removed: ${track.title} at index ${index}`);
435
+ * });
436
+ *
437
+ * manager.on("playerPause", (player, track) => {
438
+ * console.log(`Player paused: ${track.title}`);
439
+ * });
440
+ *
441
+ * manager.on("playerResume", (player, track) => {
442
+ * console.log(`Player resumed: ${track.title}`);
443
+ * });
444
+ *
445
+ * manager.on("playerStop", (player) => {
446
+ * console.log("Player stopped");
447
+ * });
448
+ *
449
+ * manager.on("playerDestroy", (player) => {
450
+ * console.log("Player destroyed");
451
+ * });
452
+ *
453
+ * manager.on("ttsStart", (player, payload) => {
454
+ * console.log(`TTS started: ${payload.text}`);
455
+ * });
456
+ *
457
+ * manager.on("ttsEnd", (player) => {
458
+ * console.log("TTS ended");
459
+ * });
460
+ *
461
+ * manager.on("playerError", (player, error, track) => {
462
+ * console.log(`Player error: ${error.message}`);
463
+ * });
464
+ *
465
+ * manager.on("connectionError", (player, error) => {
466
+ * console.log(`Connection error: ${error.message}`);
467
+ * });
468
+ * manager.on("trackStart", (player, track) => {
469
+ * console.log(`Track started: ${track.title}`);
470
+ * });
471
+ *
472
+ * manager.on("volumeChange", (player, oldVolume, newVolume) => {
473
+ * console.log(`Volume changed: ${oldVolume} -> ${newVolume}`);
474
+ * });
475
+ *
476
+ * manager.on("queueEnd", (player) => {
477
+ * console.log("Queue finished");
478
+ * });
479
+ *
480
+ */
481
+ export interface ManagerEvents {
482
+ debug: [message: string, ...args: any[]];
483
+ willPlay: [player: Player, track: Track, upcomingTracks: Track[]];
484
+ trackStart: [player: Player, track: Track];
485
+ trackEnd: [player: Player, track: Track];
486
+ queueEnd: [player: Player];
487
+ playerError: [player: Player, error: Error, track?: Track];
488
+ connectionError: [player: Player, error: Error];
489
+ volumeChange: [player: Player, oldVolume: number, newVolume: number];
490
+ queueAdd: [player: Player, track: Track];
491
+ queueAddList: [player: Player, tracks: Track[]];
492
+ queueRemove: [player: Player, track: Track, index: number];
493
+ playerPause: [player: Player, track: Track];
494
+ playerResume: [player: Player, track: Track];
495
+ playerStop: [player: Player];
496
+ playerDestroy: [player: Player];
497
+ ttsStart: [player: Player, payload: { text?: string; track?: Track }];
498
+ ttsEnd: [player: Player];
499
+ /** Emitted when audio filter is applied */
500
+ filterApplied: [player: Player, filter: AudioFilter];
501
+ /** Emitted when audio filter is removed */
502
+ filterRemoved: [player: Player, filter: AudioFilter];
503
+ /** Emitted when all filters are cleared */
504
+ filtersCleared: [player: Player];
505
+ //extension events
506
+ lyricsCreate: [player: Player, track: Track, lyrics: any];
507
+ lyricsChange: [player: Player, track: Track, lyrics: any];
508
+ voiceCreate: [player: Player, evt: any];
509
+ stats: [stats: PlayerStats];
510
+ streamError: [error: Error, track: Track | null];
511
+ }
512
+ export interface PlayerEvents {
513
+ debug: [message: string, ...args: any[]];
514
+ willPlay: [track: Track, upcomingTracks: Track[]];
515
+ trackStart: [track: Track];
516
+ trackEnd: [track: Track];
517
+ queueEnd: [];
518
+ playerError: [error: Error, track?: Track];
519
+ connectionError: [error: Error];
520
+ volumeChange: [oldVolume: number, newVolume: number];
521
+ queueAdd: [track: Track];
522
+ queueAddList: [tracks: Track[]];
523
+ queueRemove: [track: Track, index: number];
524
+ playerPause: [track: Track];
525
+ playerResume: [track: Track];
526
+ playerStop: [];
527
+ playerDestroy: [];
528
+ /** Emitted when seeking to a position in current track */
529
+ seek: [payload: { track: Track; position: number }];
530
+ /** Emitted when TTS starts playing (interruption mode) */
531
+ ttsStart: [payload: { text?: string; track?: Track }];
532
+ /** Emitted when TTS finished (interruption mode) */
533
+ ttsEnd: [];
534
+ /** Emitted when audio filter is applied */
535
+ filterApplied: [filter: AudioFilter];
536
+ /** Emitted when audio filter is removed */
537
+ filterRemoved: [filter: AudioFilter];
538
+ /** Emitted when all filters are cleared */
539
+ filtersCleared: [];
540
+ trackStuck: [track: Track | null];
541
+ streamError: [error: Error, track: Track | null];
542
+ /** Emitted when player stats are updated (if enabled) */
543
+ stats: [stats: PlayerStats];
544
+ }
545
+
546
+ export * from "./fillter";
547
+ export * from "./plugin";
548
+ export * from "./extension";