ziplayer 0.2.7-dev.0 → 0.2.7-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/AI-Guide.md +407 -756
  2. package/README.md +265 -11
  3. package/dist/extensions/BaseExtension.d.ts +1 -0
  4. package/dist/extensions/BaseExtension.d.ts.map +1 -1
  5. package/dist/extensions/BaseExtension.js.map +1 -1
  6. package/dist/extensions/index.d.ts +38 -3
  7. package/dist/extensions/index.d.ts.map +1 -1
  8. package/dist/extensions/index.js +259 -41
  9. package/dist/extensions/index.js.map +1 -1
  10. package/dist/persistence/PersistenceManager.d.ts +61 -0
  11. package/dist/persistence/PersistenceManager.d.ts.map +1 -0
  12. package/dist/persistence/PersistenceManager.js +551 -0
  13. package/dist/persistence/PersistenceManager.js.map +1 -0
  14. package/dist/plugins/BasePlugin.js +1 -1
  15. package/dist/plugins/BasePlugin.js.map +1 -1
  16. package/dist/plugins/index.d.ts +19 -4
  17. package/dist/plugins/index.d.ts.map +1 -1
  18. package/dist/plugins/index.js +204 -113
  19. package/dist/plugins/index.js.map +1 -1
  20. package/dist/structures/FilterManager.js +3 -3
  21. package/dist/structures/FilterManager.js.map +1 -1
  22. package/dist/structures/Player.d.ts +64 -14
  23. package/dist/structures/Player.d.ts.map +1 -1
  24. package/dist/structures/Player.js +326 -88
  25. package/dist/structures/Player.js.map +1 -1
  26. package/dist/structures/PlayerManager.d.ts +125 -91
  27. package/dist/structures/PlayerManager.d.ts.map +1 -1
  28. package/dist/structures/PlayerManager.js +406 -111
  29. package/dist/structures/PlayerManager.js.map +1 -1
  30. package/dist/structures/Queue.d.ts +136 -31
  31. package/dist/structures/Queue.d.ts.map +1 -1
  32. package/dist/structures/Queue.js +265 -46
  33. package/dist/structures/Queue.js.map +1 -1
  34. package/dist/types/index.d.ts +39 -6
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/dist/types/index.js +1 -0
  37. package/dist/types/index.js.map +1 -1
  38. package/dist/types/persistence.d.ts +55 -0
  39. package/dist/types/persistence.d.ts.map +1 -0
  40. package/dist/types/persistence.js +3 -0
  41. package/dist/types/persistence.js.map +1 -0
  42. package/package.json +3 -2
  43. package/src/extensions/BaseExtension.ts +1 -0
  44. package/src/extensions/index.ts +320 -37
  45. package/src/persistence/PersistenceManager.ts +572 -0
  46. package/src/plugins/BasePlugin.ts +1 -1
  47. package/src/plugins/index.ts +248 -133
  48. package/src/structures/FilterManager.ts +3 -3
  49. package/src/structures/Player.ts +352 -94
  50. package/src/structures/PlayerManager.ts +488 -116
  51. package/src/structures/Queue.ts +300 -55
  52. package/src/types/index.ts +43 -10
  53. package/src/types/persistence.ts +65 -0
  54. package/src/types/plugin.ts +1 -1
@@ -44,27 +44,41 @@ export class Queue {
44
44
  private _loop: LoopMode = "off";
45
45
  private willnext: Track | null = null;
46
46
 
47
+ // Configuration
48
+ private readonly MAX_HISTORY_SIZE = 200;
49
+ private readonly MAX_QUEUE_SIZE = 1000; // Prevent memory issues
50
+
47
51
  /**
48
52
  * Add track(s) to the queue
49
53
  *
50
54
  * @param {Track | Track[]} track - Track or array of tracks to add
55
+ * @returns {number} New queue size
51
56
  * @example
52
57
  * queue.add(track);
53
58
  * queue.add([track1, track2, track3]);
54
59
  */
55
- add(track: Track): void {
60
+ add(track: Track): number {
61
+ if (this.tracks.length >= this.MAX_QUEUE_SIZE) {
62
+ throw new Error(`Queue size limit reached (${this.MAX_QUEUE_SIZE})`);
63
+ }
56
64
  this.tracks.push(track);
65
+ return this.tracks.length;
57
66
  }
58
67
 
59
68
  /**
60
69
  * Add multiple tracks to the queue
61
70
  *
62
71
  * @param {Track[]} tracks - Tracks to add
72
+ * @returns {number} New queue size
63
73
  * @example
64
74
  * queue.addMultiple([track1, track2, track3]);
65
75
  */
66
- addMultiple(tracks: Track[]): void {
76
+ addMultiple(tracks: Track[]): number {
77
+ if (this.tracks.length + tracks.length > this.MAX_QUEUE_SIZE) {
78
+ throw new Error(`Adding ${tracks.length} tracks would exceed queue size limit (${this.MAX_QUEUE_SIZE})`);
79
+ }
67
80
  this.tracks.push(...tracks);
81
+ return this.tracks.length;
68
82
  }
69
83
 
70
84
  /**
@@ -72,24 +86,31 @@ export class Queue {
72
86
  *
73
87
  * @param {Track} track - Track to insert
74
88
  * @param {number} index - Index to insert the track at
89
+ * @returns {number} New queue size
75
90
  * @example
76
91
  * queue.insert(track, 0);
77
92
  */
78
- insert(track: Track, index: number): void {
93
+ insert(track: Track, index: number): number {
94
+ if (this.tracks.length >= this.MAX_QUEUE_SIZE) {
95
+ throw new Error(`Queue size limit reached (${this.MAX_QUEUE_SIZE})`);
96
+ }
97
+
79
98
  if (!Number.isFinite(index)) {
80
99
  this.tracks.push(track);
81
- return;
100
+ return this.tracks.length;
82
101
  }
102
+
83
103
  const i = Math.max(0, Math.min(Math.floor(index), this.tracks.length));
104
+
84
105
  if (i === this.tracks.length) {
85
106
  this.tracks.push(track);
86
- return;
87
- }
88
- if (i <= 0) {
107
+ } else if (i <= 0) {
89
108
  this.tracks.unshift(track);
90
- return;
109
+ } else {
110
+ this.tracks.splice(i, 0, track);
91
111
  }
92
- this.tracks.splice(i, 0, track);
112
+
113
+ return this.tracks.length;
93
114
  }
94
115
 
95
116
  /**
@@ -97,25 +118,33 @@ export class Queue {
97
118
  *
98
119
  * @param {Track[]} tracks - Tracks to insert
99
120
  * @param {number} index - Index to insert the tracks at
121
+ * @returns {number} New queue size
100
122
  * @example
101
123
  * queue.insertMultiple([track1, track2, track3], 0);
102
124
  */
103
- insertMultiple(tracks: Track[], index: number): void {
104
- if (!Array.isArray(tracks) || tracks.length === 0) return;
125
+ insertMultiple(tracks: Track[], index: number): number {
126
+ if (!Array.isArray(tracks) || tracks.length === 0) return this.tracks.length;
127
+
128
+ if (this.tracks.length + tracks.length > this.MAX_QUEUE_SIZE) {
129
+ throw new Error(`Inserting ${tracks.length} tracks would exceed queue size limit (${this.MAX_QUEUE_SIZE})`);
130
+ }
131
+
105
132
  if (!Number.isFinite(index)) {
106
133
  this.tracks.push(...tracks);
107
- return;
134
+ return this.tracks.length;
108
135
  }
136
+
109
137
  const i = Math.max(0, Math.min(Math.floor(index), this.tracks.length));
138
+
110
139
  if (i === 0) {
111
140
  this.tracks = [...tracks, ...this.tracks];
112
- return;
113
- }
114
- if (i === this.tracks.length) {
141
+ } else if (i === this.tracks.length) {
115
142
  this.tracks.push(...tracks);
116
- return;
143
+ } else {
144
+ this.tracks.splice(i, 0, ...tracks);
117
145
  }
118
- this.tracks.splice(i, 0, ...tracks);
146
+
147
+ return this.tracks.length;
119
148
  }
120
149
 
121
150
  /**
@@ -127,10 +156,49 @@ export class Queue {
127
156
  * const removed = queue.remove(0);
128
157
  * console.log(`Removed: ${removed?.title}`);
129
158
  */
130
-
131
159
  remove(index: number): Track | null {
132
160
  if (index < 0 || index >= this.tracks.length) return null;
133
- return this.tracks.splice(index, 1)[0];
161
+ const removed = this.tracks.splice(index, 1)[0];
162
+ return removed;
163
+ }
164
+
165
+ /**
166
+ * Remove multiple tracks by indices
167
+ *
168
+ * @param {number[]} indices - Array of indices to remove
169
+ * @returns {Track[]} Removed tracks
170
+ * @example
171
+ * const removed = queue.removeMultiple([0, 2, 5]);
172
+ */
173
+ removeMultiple(indices: number[]): Track[] {
174
+ const sorted = [...new Set(indices)].sort((a, b) => b - a);
175
+ const removed: Track[] = [];
176
+
177
+ for (const index of sorted) {
178
+ if (index >= 0 && index < this.tracks.length) {
179
+ removed.unshift(this.tracks.splice(index, 1)[0]);
180
+ }
181
+ }
182
+
183
+ return removed;
184
+ }
185
+
186
+ /**
187
+ * Remove tracks by predicate
188
+ *
189
+ * @param {(track: Track, index: number) => boolean} predicate - Filter function
190
+ * @returns {Track[]} Removed tracks
191
+ * @example
192
+ * const removed = queue.removeWhere(track => track.source === "youtube");
193
+ */
194
+ removeWhere(predicate: (track: Track, index: number) => boolean): Track[] {
195
+ const removed: Track[] = [];
196
+ for (let i = this.tracks.length - 1; i >= 0; i--) {
197
+ if (predicate(this.tracks[i], i)) {
198
+ removed.unshift(this.tracks.splice(i, 1)[0]);
199
+ }
200
+ }
201
+ return removed;
134
202
  }
135
203
 
136
204
  /**
@@ -143,24 +211,39 @@ export class Queue {
143
211
  * console.log(`Next track: ${nextTrack?.title}`);
144
212
  */
145
213
  next(ignoreLoop = false): Track | null {
214
+ // Handle track loop
215
+ if (this.current && this._loop === "track" && !ignoreLoop) {
216
+ return this.current;
217
+ }
218
+
219
+ // Save current to history before moving to next
146
220
  if (this.current) {
147
- if (this._loop === "track" && !ignoreLoop) {
148
- return this.current;
149
- }
150
- this.history.push(this.current);
151
- if (this.history.length > 200) {
152
- this.history.shift();
153
- }
221
+ this.addToHistory(this.current);
154
222
  }
223
+
224
+ // Get next track
155
225
  this.current = this.tracks.shift() || null;
226
+
227
+ // Handle queue loop
156
228
  if (!this.current && this._loop === "queue" && this.history.length > 0 && !ignoreLoop) {
157
229
  this.tracks = [...this.history];
158
230
  this.history = [];
159
231
  this.current = this.tracks.shift() || null;
160
232
  }
233
+
161
234
  return this.current;
162
235
  }
163
236
 
237
+ /**
238
+ * Add track to history with size limit
239
+ */
240
+ private addToHistory(track: Track): void {
241
+ this.history.push(track);
242
+ if (this.history.length > this.MAX_HISTORY_SIZE) {
243
+ this.history.shift();
244
+ }
245
+ }
246
+
164
247
  /**
165
248
  * Clear all tracks from the queue
166
249
  *
@@ -169,6 +252,31 @@ export class Queue {
169
252
  */
170
253
  clear(): void {
171
254
  this.tracks = [];
255
+ // Optionally reset current track? Usually not, but provide option
256
+ }
257
+
258
+ /**
259
+ * Clear history
260
+ *
261
+ * @example
262
+ * queue.clearHistory();
263
+ */
264
+ clearHistory(): void {
265
+ this.history = [];
266
+ }
267
+
268
+ /**
269
+ * Reset entire queue (current, history, tracks)
270
+ *
271
+ * @example
272
+ * queue.reset();
273
+ */
274
+ reset(): void {
275
+ this.tracks = [];
276
+ this.current = null;
277
+ this.history = [];
278
+ this.related = [];
279
+ this.willnext = null;
172
280
  }
173
281
 
174
282
  /**
@@ -180,7 +288,6 @@ export class Queue {
180
288
  * queue.autoPlay(true);
181
289
  * queue.autoPlay(); // Get current auto-play state
182
290
  */
183
-
184
291
  autoPlay(value?: boolean): boolean {
185
292
  if (typeof value !== "undefined") {
186
293
  this._autoPlay = value;
@@ -203,14 +310,32 @@ export class Queue {
203
310
  return this._loop;
204
311
  }
205
312
 
313
+ /**
314
+ * Check if queue is currently looping
315
+ *
316
+ * @returns {boolean} True if looping
317
+ */
318
+ isLooping(): boolean {
319
+ return this._loop !== "off";
320
+ }
321
+
322
+ /**
323
+ * Get current loop mode
324
+ *
325
+ * @returns {LoopMode} Current loop mode
326
+ */
327
+ getLoopMode(): LoopMode {
328
+ return this._loop;
329
+ }
330
+
206
331
  /**
207
332
  * Shuffle the queue
208
333
  *
209
334
  * @example
210
335
  * queue.shuffle();
211
336
  */
212
-
213
337
  shuffle(): void {
338
+ // Fisher-Yates shuffle
214
339
  for (let i = this.tracks.length - 1; i > 0; i--) {
215
340
  const j = Math.floor(Math.random() * (i + 1));
216
341
  [this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]];
@@ -218,12 +343,44 @@ export class Queue {
218
343
  }
219
344
 
220
345
  /**
221
- * Get the size of the queue
346
+ * Move a track from one position to another
347
+ *
348
+ * @param {number} fromIndex - Current index
349
+ * @param {number} toIndex - Target index
350
+ * @returns {boolean} True if move was successful
351
+ * @example
352
+ * queue.move(3, 0); // Move track at index 3 to position 0
353
+ */
354
+ move(fromIndex: number, toIndex: number): boolean {
355
+ if (fromIndex < 0 || fromIndex >= this.tracks.length) return false;
356
+ if (toIndex < 0 || toIndex >= this.tracks.length) return false;
357
+ if (fromIndex === toIndex) return true;
358
+
359
+ const [track] = this.tracks.splice(fromIndex, 1);
360
+ this.tracks.splice(toIndex, 0, track);
361
+ return true;
362
+ }
363
+
364
+ /**
365
+ * Swap two tracks in the queue
222
366
  *
223
- * @returns {number} The size of the queue
367
+ * @param {number} indexA - First track index
368
+ * @param {number} indexB - Second track index
369
+ * @returns {boolean} True if swap was successful
224
370
  * @example
225
- * const size = queue.size;
226
- * console.log(`Queue size: ${size}`);
371
+ * queue.swap(0, 3);
372
+ */
373
+ swap(indexA: number, indexB: number): boolean {
374
+ if (indexA < 0 || indexA >= this.tracks.length) return false;
375
+ if (indexB < 0 || indexB >= this.tracks.length) return false;
376
+ if (indexA === indexB) return true;
377
+
378
+ [this.tracks[indexA], this.tracks[indexB]] = [this.tracks[indexB], this.tracks[indexA]];
379
+ return true;
380
+ }
381
+
382
+ /**
383
+ * Get the size of the queue
227
384
  */
228
385
  get size(): number {
229
386
  return this.tracks.length;
@@ -231,11 +388,6 @@ export class Queue {
231
388
 
232
389
  /**
233
390
  * Check if the queue is empty
234
- *
235
- * @returns {boolean} True if the queue is empty
236
- * @example
237
- * const empty = queue.isEmpty;
238
- * console.log(`Queue is empty: ${empty}`);
239
391
  */
240
392
  get isEmpty(): boolean {
241
393
  return this.tracks.length === 0;
@@ -243,11 +395,6 @@ export class Queue {
243
395
 
244
396
  /**
245
397
  * Get the current track
246
- *
247
- * @returns {Track | null} The current track or null
248
- * @example
249
- * const currentTrack = queue.currentTrack;
250
- * console.log(`Current track: ${currentTrack?.title}`);
251
398
  */
252
399
  get currentTrack(): Track | null {
253
400
  return this.current;
@@ -255,28 +402,32 @@ export class Queue {
255
402
 
256
403
  /**
257
404
  * Get the previous tracks
258
- *
259
- * @returns {Track[]} The previous tracks
260
- * @example
261
- * const previousTracks = queue.previousTracks;
262
- * console.log(`Previous tracks: ${previousTracks.length}`);
263
405
  */
264
406
  get previousTracks(): Track[] {
265
407
  return [...this.history];
266
408
  }
267
409
 
410
+ /**
411
+ * Get the number of previous tracks
412
+ */
413
+ get previousTracksCount(): number {
414
+ return this.history.length;
415
+ }
416
+
268
417
  /**
269
418
  * Get the next track
270
- *
271
- * @returns {Track | null} The next track or null
272
- * @example
273
- * const nextTrack = queue.nextTrack;
274
- * console.log(`Next track: ${nextTrack?.title}`);
275
419
  */
276
420
  get nextTrack(): Track | null {
277
421
  return this.tracks[0] || null;
278
422
  }
279
423
 
424
+ /**
425
+ * Get the last track in the queue
426
+ */
427
+ get lastTrack(): Track | null {
428
+ return this.tracks[this.tracks.length - 1] || null;
429
+ }
430
+
280
431
  /**
281
432
  * Move back to the previously played track.
282
433
  * Makes the current track the next upcoming track, then sets previous as current.
@@ -288,15 +439,48 @@ export class Queue {
288
439
  */
289
440
  previous(): Track | null {
290
441
  if (this.history.length === 0) return null;
442
+
291
443
  if (this.current) {
292
444
  this.tracks.unshift(this.current);
293
445
  }
446
+
294
447
  this.current = this.history.pop() || null;
295
448
  return this.current;
296
449
  }
297
450
 
298
451
  /**
299
- * Get the next track
452
+ * Jump to a specific track in history
453
+ *
454
+ * @param {number} stepsBack - Number of steps back in history (1 = previous)
455
+ * @returns {Track | null} The jumped-to track or null
456
+ * @example
457
+ * queue.jumpToHistory(2); // Go back 2 tracks
458
+ */
459
+ jumpToHistory(stepsBack: number): Track | null {
460
+ if (stepsBack <= 0 || stepsBack > this.history.length) return null;
461
+
462
+ const targetIndex = this.history.length - stepsBack;
463
+ if (targetIndex < 0) return null;
464
+
465
+ // Save current track to queue if exists
466
+ if (this.current) {
467
+ this.tracks.unshift(this.current);
468
+ }
469
+
470
+ // Get tracks after target to push back to queue
471
+ const tracksAfterTarget = this.history.splice(targetIndex + 1);
472
+ this.current = this.history.pop() || null;
473
+
474
+ // Push tracks after target back to queue (in reverse order to maintain sequence)
475
+ for (let i = tracksAfterTarget.length - 1; i >= 0; i--) {
476
+ this.tracks.unshift(tracksAfterTarget[i]);
477
+ }
478
+
479
+ return this.current;
480
+ }
481
+
482
+ /**
483
+ * Get the next track (for auto-play)
300
484
  *
301
485
  * @param {Track} track - The next track
302
486
  * @returns {Track | null} The next track or null
@@ -328,9 +512,9 @@ export class Queue {
328
512
  }
329
513
 
330
514
  /**
331
- * Get the tracks
515
+ * Get all tracks in the queue
332
516
  *
333
- * @returns {Track[]} The tracks
517
+ * @returns {Track[]} Copy of tracks array
334
518
  * @example
335
519
  * const tracks = queue.getTracks();
336
520
  * console.log(`Tracks: ${tracks.length}`);
@@ -338,7 +522,31 @@ export class Queue {
338
522
  getTracks(): Track[] {
339
523
  return [...this.tracks];
340
524
  }
525
+
526
+ /**
527
+ * Get serializable queue data
528
+ */
529
+ toJSON(): object {
530
+ return {
531
+ tracks: this.tracks,
532
+ current: this.current,
533
+ history: this.history,
534
+ size: this.size,
535
+ loopMode: this._loop,
536
+ autoPlay: this._autoPlay,
537
+ };
538
+ }
341
539
 
540
+ /**
541
+ * Restore queue from serialized data
542
+ */
543
+ fromJSON(data: { tracks: Track[]; current: Track | null; history: Track[]; loopMode: LoopMode; autoPlay: boolean }): void {
544
+ this.tracks = [...data.tracks];
545
+ this.current = data.current;
546
+ this.history = [...data.history];
547
+ this._loop = data.loopMode;
548
+ this._autoPlay = data.autoPlay;
549
+ }
342
550
  /**
343
551
  * Get a track at a specific index
344
552
  *
@@ -351,4 +559,41 @@ export class Queue {
351
559
  getTrack(index: number): Track | null {
352
560
  return this.tracks[index] || null;
353
561
  }
562
+
563
+ /**
564
+ * Find tracks by predicate
565
+ *
566
+ * @param {(track: Track) => boolean} predicate - Search function
567
+ * @returns {Track[]} Matching tracks
568
+ * @example
569
+ * const youtubeTracks = queue.findTracks(track => track.source === "youtube");
570
+ */
571
+ findTracks(predicate: (track: Track) => boolean): Track[] {
572
+ return this.tracks.filter(predicate);
573
+ }
574
+
575
+ /**
576
+ * Get the index of a track in the queue
577
+ *
578
+ * @param {string | Track} identifier - Track ID, URL, or Track object
579
+ * @returns {number} Index of the track, -1 if not found
580
+ * @example
581
+ * const index = queue.indexOf(track);
582
+ */
583
+ indexOf(identifier: string | Track): number {
584
+ if (typeof identifier === "string") {
585
+ return this.tracks.findIndex((t) => t.id === identifier || t.url === identifier);
586
+ }
587
+ return this.tracks.findIndex((t) => t.id === identifier.id);
588
+ }
589
+
590
+ /**
591
+ * Check if a track exists in the queue
592
+ *
593
+ * @param {string | Track} identifier - Track ID, URL, or Track object
594
+ * @returns {boolean} True if track exists
595
+ */
596
+ has(identifier: string | Track): boolean {
597
+ return this.indexOf(identifier) !== -1;
598
+ }
354
599
  }
@@ -3,7 +3,7 @@ import { Player } from "../structures/Player";
3
3
  import type { PlayerManager } from "../structures/PlayerManager";
4
4
  import type { AudioFilter } from "./fillter";
5
5
  import type { SourcePluginLike } from "./plugin";
6
-
6
+ import type { PersistenceOptions } from "./persistence";
7
7
  /**
8
8
  * Represents a music track with metadata and streaming information.
9
9
  *
@@ -60,6 +60,7 @@ export interface Track {
60
60
  requestedBy: string;
61
61
  source: string;
62
62
  metadata?: Record<string, any>;
63
+ isLive?: boolean;
63
64
  }
64
65
 
65
66
  /**
@@ -129,7 +130,7 @@ export interface StreamInfo {
129
130
  * createPlayer: true,
130
131
  * interrupt: true,
131
132
  * volume: 1.0,
132
- * Max_Time_TTS: 30000
133
+ * maxTimeTts: 30000
133
134
  * }
134
135
  * };
135
136
  */
@@ -160,7 +161,7 @@ export interface PlayerOptions {
160
161
  /** Default TTS volume multiplier 1 => 100% */
161
162
  volume?: number;
162
163
  /** Max time tts playback Duration */
163
- Max_Time_TTS?: number;
164
+ maxTimeTts?: number;
164
165
  };
165
166
  /**
166
167
  * Optional per-player extension selection. When provided, only these
@@ -182,11 +183,12 @@ export interface PlayerOptions {
182
183
  export interface PlayerManagerOptions {
183
184
  plugins?: SourcePluginLike[];
184
185
  extensions?: any[];
185
- /**
186
- * Timeout in milliseconds for manager-level operations (e.g. search)
187
- * when running without a Player instance.
188
- */
189
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;
190
192
  }
191
193
 
192
194
  /**
@@ -200,9 +202,13 @@ export interface PlayerManagerOptions {
200
202
  * };
201
203
  */
202
204
  export interface ProgressBarOptions {
203
- size?: number;
204
- barChar?: string;
205
- progressChar?: string;
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)
206
212
  }
207
213
 
208
214
  /**
@@ -229,6 +235,26 @@ export interface SaveOptions {
229
235
  /** Seek position in milliseconds to start saving from */
230
236
  seek?: number;
231
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
+ }
232
258
 
233
259
  export type LoopMode = "off" | "track" | "queue";
234
260
 
@@ -337,6 +363,11 @@ export interface ManagerEvents {
337
363
  lyricsCreate: [player: Player, track: Track, lyrics: any];
338
364
  lyricsChange: [player: Player, track: Track, lyrics: any];
339
365
  voiceCreate: [player: Player, evt: any];
366
+ stats: [stats: PlayerStats];
367
+ playerSaved: [guildId: string];
368
+ playerLoaded: [guildId: string, data: any];
369
+ savedAll: [results: Map<string, boolean>];
370
+ loadedAll: [results: Map<string, boolean>];
340
371
  }
341
372
  export interface PlayerEvents {
342
373
  debug: [message: string, ...args: any[]];
@@ -366,8 +397,10 @@ export interface PlayerEvents {
366
397
  filterRemoved: [filter: AudioFilter];
367
398
  /** Emitted when all filters are cleared */
368
399
  filtersCleared: [];
400
+ trackStuck: [track: Track | null];
369
401
  }
370
402
 
371
403
  export * from "./fillter";
372
404
  export * from "./plugin";
373
405
  export * from "./extension";
406
+ export * from "./persistence";