magmastream 2.9.0-dev.33 → 2.9.0-dev.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -266,6 +266,9 @@ declare enum ManagerEventTypes {
266
266
  ChapterStarted = "chapterStarted",
267
267
  ChaptersLoaded = "chaptersLoaded",
268
268
  Debug = "debug",
269
+ LyricsFoundEvent = "lyricsFoundEvent",
270
+ LyricsLineEvent = "lyricsLineEvent",
271
+ LyricsNotFoundEvent = "lyricsNotFoundEvent",
269
272
  NodeConnect = "nodeConnect",
270
273
  NodeCreate = "nodeCreate",
271
274
  NodeDestroy = "nodeDestroy",
@@ -546,37 +549,68 @@ interface RedisConfig {
546
549
  /**
547
550
  * Player State Update Event
548
551
  */
549
- interface PlayerStateUpdateEvent {
550
- changeType: PlayerStateEventTypes;
551
- details?: AutoplayChangeEvent | ConnectionChangeEvent | RepeatChangeEvent | PauseChangeEvent | QueueChangeEvent | TrackChangeEvent | VolumeChangeEvent | ChannelChangeEvent;
552
- }
552
+ type PlayerStateUpdateEvent = {
553
+ changeType: PlayerStateEventTypes.TrackChange;
554
+ details: TrackChangeEvent;
555
+ } | {
556
+ changeType: PlayerStateEventTypes.PauseChange;
557
+ details: PauseChangeEvent;
558
+ } | {
559
+ changeType: PlayerStateEventTypes.QueueChange;
560
+ details: QueueChangeEvent;
561
+ } | {
562
+ changeType: PlayerStateEventTypes.ConnectionChange;
563
+ details: ConnectionChangeEvent;
564
+ } | {
565
+ changeType: PlayerStateEventTypes.AutoPlayChange;
566
+ details: AutoplayChangeEvent;
567
+ } | {
568
+ changeType: PlayerStateEventTypes.ChannelChange;
569
+ details: ChannelChangeEvent;
570
+ } | {
571
+ changeType: PlayerStateEventTypes.VolumeChange;
572
+ details: VolumeChangeEvent;
573
+ } | {
574
+ changeType: PlayerStateEventTypes.RepeatChange;
575
+ details: RepeatChangeEvent;
576
+ };
577
+ /**
578
+ * Player State Change Data
579
+ */
580
+ type PlayerStateChangeData = AutoplayChangeEvent | ConnectionChangeEvent | RepeatChangeEvent | PauseChangeEvent | QueueChangeEvent | TrackChangeEvent | VolumeChangeEvent | ChannelChangeEvent;
553
581
  /**
554
582
  * Autoplay Change Event
555
583
  */
556
584
  interface AutoplayChangeEvent {
557
- previousAutoplay: boolean;
558
- currentAutoplay: boolean;
585
+ type: "autoplay";
586
+ action: "toggle";
587
+ previousAutoplay: boolean | null;
588
+ currentAutoplay: boolean | null;
559
589
  }
560
590
  /**
561
591
  * Connection Change Event
562
592
  */
563
593
  interface ConnectionChangeEvent {
564
- changeType: "connect" | "disconnect";
565
- previousConnection: boolean;
566
- currentConnection: boolean;
594
+ type: "connection";
595
+ action: "connect" | "disconnect";
596
+ previousConnection: boolean | null;
597
+ currentConnection: boolean | null;
567
598
  }
568
599
  /**
569
600
  * Repeat Change Event
570
601
  */
571
602
  interface RepeatChangeEvent {
572
- changeType: "dynamic" | "track" | "queue" | null;
573
- previousRepeat: string | null;
574
- currentRepeat: string | null;
603
+ type: "repeat";
604
+ action: "dynamic" | "track" | "queue" | "none";
605
+ previousRepeat: "dynamic" | "track" | "queue" | null;
606
+ currentRepeat: "dynamic" | "track" | "queue" | null;
575
607
  }
576
608
  /**
577
609
  * Pause Change Event
578
610
  */
579
611
  interface PauseChangeEvent {
612
+ type: "pause";
613
+ action: "pause" | "resume" | "toggle";
580
614
  previousPause: boolean | null;
581
615
  currentPause: boolean | null;
582
616
  }
@@ -584,14 +618,18 @@ interface PauseChangeEvent {
584
618
  * Queue Change Event
585
619
  */
586
620
  interface QueueChangeEvent {
587
- changeType: "add" | "remove" | "clear" | "shuffle" | "roundRobin" | "userBlock" | "autoPlayAdd";
621
+ type: "queue";
622
+ action: "add" | "remove" | "clear" | "shuffle" | "roundRobin" | "userBlock" | "autoPlayAdd";
623
+ previousQueueLength: number | null;
624
+ currentQueueLength: number | null;
588
625
  tracks?: Track[];
589
626
  }
590
627
  /**
591
628
  * Track Change Event
592
629
  */
593
630
  interface TrackChangeEvent {
594
- changeType: "start" | "end" | "previous" | "timeUpdate" | "autoPlay";
631
+ type: "track";
632
+ action: "start" | "end" | "previous" | "timeUpdate" | "autoPlay";
595
633
  track: Track;
596
634
  previousTime?: number | null;
597
635
  currentTime?: number | null;
@@ -600,6 +638,8 @@ interface TrackChangeEvent {
600
638
  * Volume Change Event
601
639
  */
602
640
  interface VolumeChangeEvent {
641
+ type: "volume";
642
+ action: "adjust";
603
643
  previousVolume: number | null;
604
644
  currentVolume: number | null;
605
645
  }
@@ -607,7 +647,8 @@ interface VolumeChangeEvent {
607
647
  * Channel Change Event
608
648
  */
609
649
  interface ChannelChangeEvent {
610
- changeType: "text" | "voice";
650
+ type: "channel";
651
+ action: "text" | "voice";
611
652
  previousChannel: string | null;
612
653
  currentChannel: string | null;
613
654
  }
@@ -808,6 +849,9 @@ interface ManagerEvents {
808
849
  [ManagerEventTypes.ChapterStarted]: [player: Player, track: Track, payload: SponsorBlockChapterStarted];
809
850
  [ManagerEventTypes.ChaptersLoaded]: [player: Player, track: Track, payload: SponsorBlockChaptersLoaded];
810
851
  [ManagerEventTypes.Debug]: [info: string];
852
+ [ManagerEventTypes.LyricsFoundEvent]: [player: Player, track: Track, payload: LyricsFoundEvent];
853
+ [ManagerEventTypes.LyricsLineEvent]: [player: Player, track: Track, payload: LyricsLineEvent];
854
+ [ManagerEventTypes.LyricsNotFoundEvent]: [player: Player, track: Track, payload: LyricsNotFoundEvent];
811
855
  [ManagerEventTypes.NodeConnect]: [node: Node];
812
856
  [ManagerEventTypes.NodeCreate]: [node: Node];
813
857
  [ManagerEventTypes.NodeDestroy]: [node: Node];
@@ -1178,6 +1222,31 @@ interface Lyrics {
1178
1222
  lines: LyricsLine[];
1179
1223
  plugin: object[];
1180
1224
  }
1225
+ /**
1226
+ * LyricsFoundEvent interface
1227
+ */
1228
+ interface LyricsFoundEvent extends PlayerEvent {
1229
+ type: "LyricsFoundEvent";
1230
+ guildId: string;
1231
+ lyrics: Lyrics;
1232
+ }
1233
+ /**
1234
+ * LyricsNotFoundEvent interface
1235
+ */
1236
+ interface LyricsNotFoundEvent extends PlayerEvent {
1237
+ type: "LyricsNotFoundEvent";
1238
+ guildId: string;
1239
+ }
1240
+ /**
1241
+ * LyricsLineEvent interface
1242
+ */
1243
+ interface LyricsLineEvent extends PlayerEvent {
1244
+ type: "LyricsLineEvent";
1245
+ guildId: string;
1246
+ lineIndex: number;
1247
+ line: LyricsLine;
1248
+ skipped: boolean;
1249
+ }
1181
1250
  /**
1182
1251
  * NodeLink Get Lyrics Multiple interface
1183
1252
  */
@@ -1363,7 +1432,7 @@ type TrackEndReason = keyof typeof TrackEndReasonTypes;
1363
1432
  /**
1364
1433
  * Player Event Type Enum type
1365
1434
  */
1366
- type PlayerEventType = "TrackStartEvent" | "TrackEndEvent" | "TrackExceptionEvent" | "TrackStuckEvent" | "WebSocketClosedEvent" | "SegmentSkipped" | "SegmentsLoaded" | "ChaptersLoaded" | "ChapterStarted";
1435
+ type PlayerEventType = "TrackStartEvent" | "TrackEndEvent" | "TrackExceptionEvent" | "TrackStuckEvent" | "WebSocketClosedEvent" | "SegmentSkipped" | "SegmentsLoaded" | "ChaptersLoaded" | "ChapterStarted" | "LyricsFoundEvent" | "LyricsNotFoundEvent" | "LyricsLineEvent";
1367
1436
  /**
1368
1437
  * Severity Types Enum type
1369
1438
  */
@@ -1379,7 +1448,7 @@ type SponsorBlockSegmentEventType = "SegmentSkipped" | "SegmentsLoaded" | "Chapt
1379
1448
  /**
1380
1449
  * Player Events Enum type
1381
1450
  */
1382
- type PlayerEvents = TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent | SponsorBlockSegmentEvents;
1451
+ type PlayerEvents = TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent | SponsorBlockSegmentEvents | LyricsEvent;
1383
1452
  /**
1384
1453
  * Load Type Enum type
1385
1454
  */
@@ -1396,6 +1465,14 @@ type VoiceReceiverEvent = StartSpeakingEventVoiceReceiver | EndSpeakingEventVoic
1396
1465
  * Search Result Enum type
1397
1466
  */
1398
1467
  type SearchResult = TrackSearchResult | SearchSearchResult | PlaylistSearchResult | ErrorOrEmptySearchResult;
1468
+ /**
1469
+ * Lyrics Event Enum type
1470
+ */
1471
+ type LyricsEvent = LyricsFoundEvent | LyricsNotFoundEvent | LyricsLineEvent;
1472
+ /**
1473
+ * Lyrics Event Type Enum type
1474
+ */
1475
+ type LyricsEventType = "LyricsFoundEvent" | "LyricsNotFoundEvent" | "LyricsLineEvent";
1399
1476
 
1400
1477
  declare class Node$1 {
1401
1478
  manager: Manager;
@@ -1560,7 +1637,7 @@ declare class Node$1 {
1560
1637
  * @param {TrackEndEvent} payload - The payload of the event emitted by the node.
1561
1638
  * @private
1562
1639
  */
1563
- protected trackEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>;
1640
+ trackEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>;
1564
1641
  /**
1565
1642
  * Handles autoplay logic for a player.
1566
1643
  * This method is responsible for selecting an appropriate method of autoplay
@@ -1622,14 +1699,32 @@ declare class Node$1 {
1622
1699
  queueEnd(player: Player, track: Track, payload: TrackEndEvent): Promise<void>;
1623
1700
  /**
1624
1701
  * Fetches the lyrics of a track from the Lavalink node.
1625
- * This method uses the `lavalyrics-plugin` to fetch the lyrics.
1626
- * If the plugin is not available, it will throw a RangeError.
1702
+ *
1703
+ * If the node is a NodeLink, it will use the `NodeLinkGetLyrics` method to fetch the lyrics.
1704
+ *
1705
+ * Requires the `lavalyrics-plugin` to be present in the Lavalink node.
1706
+ * Requires the `lavasrc-plugin` or `java-lyrics-plugin` to be present in the Lavalink node.
1627
1707
  *
1628
1708
  * @param {Track} track - The track to fetch the lyrics for.
1629
1709
  * @param {boolean} [skipTrackSource=false] - Whether to skip using the track's source URL.
1630
1710
  * @returns {Promise<Lyrics | NodeLinkGetLyrics>} A promise that resolves with the lyrics data.
1631
1711
  */
1632
1712
  getLyrics(track: Track, skipTrackSource?: boolean): Promise<Lyrics | NodeLinkGetLyrics>;
1713
+ /**
1714
+ * Subscribes to lyrics for a player.
1715
+ * @param {string} guildId - The ID of the guild to subscribe to lyrics for.
1716
+ * @param {boolean} [skipTrackSource=false] - Whether to skip using the track's source URL.
1717
+ * @returns {Promise<unknown>} A promise that resolves when the subscription is complete.
1718
+ * @throws {RangeError} If the node is not connected to the lavalink server or if the java-lyrics-plugin is not available.
1719
+ */
1720
+ lyricsSubscribe(guildId: string, skipTrackSource?: boolean): Promise<unknown>;
1721
+ /**
1722
+ * Unsubscribes from lyrics for a player.
1723
+ * @param {string} guildId - The ID of the guild to unsubscribe from lyrics for.
1724
+ * @returns {Promise<unknown>} A promise that resolves when the unsubscription is complete.
1725
+ * @throws {RangeError} If the node is not connected to the lavalink server or if the java-lyrics-plugin is not available.
1726
+ */
1727
+ lyricsUnsubscribe(guildId: string): Promise<unknown>;
1633
1728
  /**
1634
1729
  * Handles the event when a track becomes stuck during playback.
1635
1730
  * Stops the current track and emits a `trackStuck` event.
@@ -1691,6 +1786,30 @@ declare class Node$1 {
1691
1786
  * @param {SponsorBlockChapterStarted} payload - The event payload containing additional data about the chapter started event.
1692
1787
  */
1693
1788
  private sponsorBlockChapterStarted;
1789
+ /**
1790
+ * Emitted when lyrics for a track are found.
1791
+ * The payload of the event will contain the lyrics.
1792
+ * @param {Player} player - The player associated with the lyrics.
1793
+ * @param {Track} track - The track associated with the lyrics.
1794
+ * @param {LyricsFoundEvent} payload - The event payload containing additional data about the lyrics found event.
1795
+ */
1796
+ private lyricsFound;
1797
+ /**
1798
+ * Emitted when lyrics for a track are not found.
1799
+ * The payload of the event will contain the track.
1800
+ * @param {Player} player - The player associated with the lyrics.
1801
+ * @param {Track} track - The track associated with the lyrics.
1802
+ * @param {LyricsNotFoundEvent} payload - The event payload containing additional data about the lyrics not found event.
1803
+ */
1804
+ private lyricsNotFound;
1805
+ /**
1806
+ * Emitted when a line of lyrics for a track is received.
1807
+ * The payload of the event will contain the lyrics line.
1808
+ * @param {Player} player - The player associated with the lyrics line.
1809
+ * @param {Track} track - The track associated with the lyrics line.
1810
+ * @param {LyricsLineEvent} payload - The event payload containing additional data about the lyrics line event.
1811
+ */
1812
+ private lyricsLine;
1694
1813
  /**
1695
1814
  * Fetches Lavalink node information.
1696
1815
  * @returns {Promise<LavalinkInfo>} A promise that resolves to the Lavalink node information.
@@ -1735,7 +1854,7 @@ declare class Node$1 {
1735
1854
  }
1736
1855
 
1737
1856
  /**
1738
- * The main hub for interacting with Lavalink and using Magmastream,
1857
+ * The main hub for interacting with Lavalink and using Magmastream.
1739
1858
  */
1740
1859
  declare class Manager extends EventEmitter {
1741
1860
  /** The map of players. */
@@ -1937,7 +2056,7 @@ declare class Manager extends EventEmitter {
1937
2056
  * @param player The Player instance to serialize
1938
2057
  * @returns The serialized Player instance
1939
2058
  */
1940
- serializePlayer(player: Player): Record<string, unknown>;
2059
+ serializePlayer(player: Player): Promise<Record<string, unknown>>;
1941
2060
  /**
1942
2061
  * Checks for players that are no longer active and deletes their saved state files.
1943
2062
  * This is done to prevent stale state files from accumulating on the file system.
@@ -2850,4 +2969,4 @@ declare class OceanicManager extends Manager {
2850
2969
  }
2851
2970
 
2852
2971
  export { AutoPlayPlatform, AutoPlayUtils, AvailableFilters, DetritusManager, DiscordJSManager, ErisManager, Filters, LoadTypes, Manager, ManagerEventTypes, Node$1 as Node, OceanicManager, Player, PlayerStateEventTypes, Plugin$1 as Plugin, Queue, Rest, SearchPlatform, SeverityTypes, SponsorBlockSegment, StateStorageType, StateTypes, Structure, TrackEndReasonTypes, TrackPartial, TrackSourceTypes, TrackUtils, UseNodeOptions };
2853
- export type { CPUStats, DiscordPacket, EndSpeakingEventVoiceReceiver, EndSpeakingEventVoiceReceiverData, EqualizerBand, ErrorOrEmptySearchResult, Exception, Extendable, FrameStats, IQueue, LavaPlayer, LavalinkInfo, LavalinkResponse, LoadType, Lyrics, LyricsLine, ManagerEvents, ManagerInitOptions, ManagerOptions, MemoryStats, NodeLinkGetLyrics, NodeLinkGetLyricsEmpty, NodeLinkGetLyricsError, NodeLinkGetLyricsMultiple, NodeLinkGetLyricsSingle, NodeMessage, NodeOptions, NodeStats, Payload, PlayOptions, PlayerEvent, PlayerEventType, PlayerEvents, PlayerOptions, PlayerStateUpdateEvent, PlayerUpdate, PlayerUpdateVoiceState, PlaylistData, PlaylistInfoData, PlaylistRawData, PlaylistSearchResult, RedisConfig, SearchQuery, SearchResult, SearchSearchResult, Severity, Sizes, SponsorBlockChapterStarted, SponsorBlockChaptersLoaded, SponsorBlockSegmentEventType, SponsorBlockSegmentEvents, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, StartSpeakingEventVoiceReceiver, StartSpeakingEventVoiceReceiverData, StateStorageOptions, Track, TrackData, TrackDataInfo, TrackEndEvent, TrackEndReason, TrackExceptionEvent, TrackPluginInfo, TrackSearchResult, TrackSourceName, TrackStartEvent, TrackStuckEvent, UseNodeOption, VoicePacket, VoiceReceiverEvent, VoiceServer, VoiceServerUpdate, VoiceState, WebSocketClosedEvent };
2972
+ export type { CPUStats, DiscordPacket, EndSpeakingEventVoiceReceiver, EndSpeakingEventVoiceReceiverData, EqualizerBand, ErrorOrEmptySearchResult, Exception, Extendable, FrameStats, IQueue, LavaPlayer, LavalinkInfo, LavalinkResponse, LoadType, Lyrics, LyricsEvent, LyricsEventType, LyricsFoundEvent, LyricsLine, LyricsLineEvent, LyricsNotFoundEvent, ManagerEvents, ManagerInitOptions, ManagerOptions, MemoryStats, NodeLinkGetLyrics, NodeLinkGetLyricsEmpty, NodeLinkGetLyricsError, NodeLinkGetLyricsMultiple, NodeLinkGetLyricsSingle, NodeMessage, NodeOptions, NodeStats, Payload, PlayOptions, PlayerEvent, PlayerEventType, PlayerEvents, PlayerOptions, PlayerStateChangeData, PlayerStateUpdateEvent, PlayerUpdate, PlayerUpdateVoiceState, PlaylistData, PlaylistInfoData, PlaylistRawData, PlaylistSearchResult, RedisConfig, SearchQuery, SearchResult, SearchSearchResult, Severity, Sizes, SponsorBlockChapterStarted, SponsorBlockChaptersLoaded, SponsorBlockSegmentEventType, SponsorBlockSegmentEvents, SponsorBlockSegmentSkipped, SponsorBlockSegmentsLoaded, StartSpeakingEventVoiceReceiver, StartSpeakingEventVoiceReceiverData, StateStorageOptions, Track, TrackData, TrackDataInfo, TrackEndEvent, TrackEndReason, TrackExceptionEvent, TrackPluginInfo, TrackSearchResult, TrackSourceName, TrackStartEvent, TrackStuckEvent, UseNodeOption, VoicePacket, VoiceReceiverEvent, VoiceServer, VoiceServerUpdate, VoiceState, WebSocketClosedEvent };
@@ -141,6 +141,9 @@ var ManagerEventTypes;
141
141
  ManagerEventTypes["ChapterStarted"] = "chapterStarted";
142
142
  ManagerEventTypes["ChaptersLoaded"] = "chaptersLoaded";
143
143
  ManagerEventTypes["Debug"] = "debug";
144
+ ManagerEventTypes["LyricsFoundEvent"] = "lyricsFoundEvent";
145
+ ManagerEventTypes["LyricsLineEvent"] = "lyricsLineEvent";
146
+ ManagerEventTypes["LyricsNotFoundEvent"] = "lyricsNotFoundEvent";
144
147
  ManagerEventTypes["NodeConnect"] = "nodeConnect";
145
148
  ManagerEventTypes["NodeCreate"] = "nodeCreate";
146
149
  ManagerEventTypes["NodeDestroy"] = "nodeDestroy";
@@ -14,7 +14,7 @@ const path_1 = tslib_1.__importDefault(require("path"));
14
14
  const ioredis_1 = tslib_1.__importDefault(require("ioredis"));
15
15
  const Enums_1 = require("./Enums");
16
16
  /**
17
- * The main hub for interacting with Lavalink and using Magmastream,
17
+ * The main hub for interacting with Lavalink and using Magmastream.
18
18
  */
19
19
  class Manager extends events_1.EventEmitter {
20
20
  /** The map of players. */
@@ -394,7 +394,7 @@ class Manager extends events_1.EventEmitter {
394
394
  console.warn(`Skipping save for inactive player: ${guildId}`);
395
395
  return;
396
396
  }
397
- const serializedPlayer = this.serializePlayer(player);
397
+ const serializedPlayer = await this.serializePlayer(player);
398
398
  await promises_1.default.writeFile(playerStateFilePath, JSON.stringify(serializedPlayer, null, 2), "utf-8");
399
399
  this.emit(Enums_1.ManagerEventTypes.Debug, `[MANAGER] Player state saved: ${guildId}`);
400
400
  }
@@ -411,7 +411,7 @@ class Manager extends events_1.EventEmitter {
411
411
  console.warn(`Skipping save for inactive player: ${guildId}`);
412
412
  return;
413
413
  }
414
- const serializedPlayer = this.serializePlayer(player);
414
+ const serializedPlayer = await this.serializePlayer(player);
415
415
  const redisKey = `${this.options.stateStorage.redisConfig.prefix?.endsWith(":")
416
416
  ? this.options.stateStorage.redisConfig.prefix
417
417
  : this.options.stateStorage.redisConfig.prefix ?? "magmastream:"}playerstore:${guildId}`;
@@ -491,39 +491,72 @@ class Manager extends events_1.EventEmitter {
491
491
  const tracks = [];
492
492
  const currentTrack = state.queue.current;
493
493
  const queueTracks = state.queue.tracks;
494
- if (lavaPlayer) {
495
- if (lavaPlayer.track) {
496
- tracks.push(...queueTracks);
497
- if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
498
- await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
499
- }
494
+ if (state.isAutoplay) {
495
+ Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
496
+ player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
497
+ }
498
+ if (lavaPlayer?.track) {
499
+ // If lavaPlayer has a track, push all queue tracks
500
+ tracks.push(...queueTracks);
501
+ // Set current track if matches lavaPlayer's track URI
502
+ if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
503
+ await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
500
504
  }
501
- else {
502
- if (!currentTrack) {
503
- const payload = {
504
- reason: Enums_1.TrackEndReasonTypes.Finished,
505
- };
506
- await node.queueEnd(player, currentTrack, payload);
507
- }
508
- else {
509
- tracks.push(currentTrack, ...queueTracks);
510
- }
505
+ // Add tracks to queue
506
+ if (tracks.length > 0) {
507
+ await player.queue.clear();
508
+ await player.queue.add(tracks);
511
509
  }
512
510
  }
513
511
  else {
514
- if (!currentTrack) {
515
- const payload = {
512
+ // LavaPlayer missing track or lavaPlayer is falsy
513
+ if (currentTrack) {
514
+ if (queueTracks.length > 0) {
515
+ tracks.push(...queueTracks);
516
+ await player.queue.clear();
517
+ await player.queue.add(tracks);
518
+ }
519
+ await node.trackEnd(player, currentTrack, {
516
520
  reason: Enums_1.TrackEndReasonTypes.Finished,
517
- };
518
- await node.queueEnd(player, currentTrack, payload);
521
+ type: "TrackEndEvent",
522
+ });
519
523
  }
520
524
  else {
521
- tracks.push(currentTrack, ...queueTracks);
525
+ // No current track, check previous queue for last track
526
+ const previousQueue = await player.queue.getPrevious();
527
+ const lastTrack = previousQueue?.at(-1);
528
+ if (lastTrack) {
529
+ if (queueTracks.length === 0) {
530
+ // If no tracks in queue, end last track
531
+ await node.trackEnd(player, lastTrack, {
532
+ reason: Enums_1.TrackEndReasonTypes.Finished,
533
+ type: "TrackEndEvent",
534
+ });
535
+ }
536
+ else {
537
+ // If there are queued tracks, add them
538
+ tracks.push(...queueTracks);
539
+ if (tracks.length > 0) {
540
+ await player.queue.clear();
541
+ await player.queue.add(tracks);
542
+ }
543
+ }
544
+ }
545
+ else {
546
+ if (queueTracks.length > 0) {
547
+ tracks.push(...queueTracks);
548
+ if (tracks.length > 0) {
549
+ await player.queue.clear();
550
+ await player.queue.add(tracks);
551
+ }
552
+ await node.trackEnd(player, lastTrack, {
553
+ reason: Enums_1.TrackEndReasonTypes.Finished,
554
+ type: "TrackEndEvent",
555
+ });
556
+ }
557
+ }
522
558
  }
523
559
  }
524
- if (tracks.length > 0) {
525
- await player.queue.add(tracks);
526
- }
527
560
  if (state.queue.previous.length > 0) {
528
561
  await player.queue.addPrevious(state.queue.previous);
529
562
  }
@@ -543,10 +576,6 @@ class Manager extends events_1.EventEmitter {
543
576
  if (state.dynamicRepeat) {
544
577
  player.setDynamicRepeat(state.dynamicRepeat, state.dynamicLoopInterval._idleTimeout);
545
578
  }
546
- if (state.isAutoplay) {
547
- Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
548
- player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
549
- }
550
579
  if (state.data) {
551
580
  for (const [name, value] of Object.entries(state.data)) {
552
581
  player.set(name, value);
@@ -661,39 +690,72 @@ class Manager extends events_1.EventEmitter {
661
690
  const tracks = [];
662
691
  const currentTrack = state.queue.current;
663
692
  const queueTracks = state.queue.tracks;
664
- if (lavaPlayer) {
665
- if (lavaPlayer.track) {
666
- tracks.push(...queueTracks);
667
- if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
668
- await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
669
- }
693
+ if (state.isAutoplay) {
694
+ Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
695
+ player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
696
+ }
697
+ if (lavaPlayer?.track) {
698
+ // If lavaPlayer has a track, push all queue tracks
699
+ tracks.push(...queueTracks);
700
+ // Set current track if matches lavaPlayer's track URI
701
+ if (currentTrack && currentTrack.uri === lavaPlayer.track.info.uri) {
702
+ await player.queue.setCurrent(Utils_1.TrackUtils.build(lavaPlayer.track, currentTrack.requester));
670
703
  }
671
- else {
672
- if (!currentTrack) {
673
- const payload = {
674
- reason: Enums_1.TrackEndReasonTypes.Finished,
675
- };
676
- await node.queueEnd(player, currentTrack, payload);
677
- }
678
- else {
679
- tracks.push(currentTrack, ...queueTracks);
680
- }
704
+ // Add tracks to queue
705
+ if (tracks.length > 0) {
706
+ await player.queue.clear();
707
+ await player.queue.add(tracks);
681
708
  }
682
709
  }
683
710
  else {
684
- if (!currentTrack) {
685
- const payload = {
711
+ // LavaPlayer missing track or lavaPlayer is falsy
712
+ if (currentTrack) {
713
+ if (queueTracks.length > 0) {
714
+ tracks.push(...queueTracks);
715
+ await player.queue.clear();
716
+ await player.queue.add(tracks);
717
+ }
718
+ await node.trackEnd(player, currentTrack, {
686
719
  reason: Enums_1.TrackEndReasonTypes.Finished,
687
- };
688
- await node.queueEnd(player, currentTrack, payload);
720
+ type: "TrackEndEvent",
721
+ });
689
722
  }
690
723
  else {
691
- tracks.push(currentTrack, ...queueTracks);
724
+ // No current track, check previous queue for last track
725
+ const previousQueue = await player.queue.getPrevious();
726
+ const lastTrack = previousQueue?.at(-1);
727
+ if (lastTrack) {
728
+ if (queueTracks.length === 0) {
729
+ // If no tracks in queue, end last track
730
+ await node.trackEnd(player, lastTrack, {
731
+ reason: Enums_1.TrackEndReasonTypes.Finished,
732
+ type: "TrackEndEvent",
733
+ });
734
+ }
735
+ else {
736
+ // If there are queued tracks, add them
737
+ tracks.push(...queueTracks);
738
+ if (tracks.length > 0) {
739
+ await player.queue.clear();
740
+ await player.queue.add(tracks);
741
+ }
742
+ }
743
+ }
744
+ else {
745
+ if (queueTracks.length > 0) {
746
+ tracks.push(...queueTracks);
747
+ if (tracks.length > 0) {
748
+ await player.queue.clear();
749
+ await player.queue.add(tracks);
750
+ }
751
+ await node.trackEnd(player, lastTrack, {
752
+ reason: Enums_1.TrackEndReasonTypes.Finished,
753
+ type: "TrackEndEvent",
754
+ });
755
+ }
756
+ }
692
757
  }
693
758
  }
694
- if (tracks.length > 0) {
695
- await player.queue.add(tracks);
696
- }
697
759
  if (state.queue.previous.length > 0) {
698
760
  await player.queue.addPrevious(state.queue.previous);
699
761
  }
@@ -713,10 +775,6 @@ class Manager extends events_1.EventEmitter {
713
775
  if (state.dynamicRepeat) {
714
776
  player.setDynamicRepeat(state.dynamicRepeat, state.dynamicLoopInterval._idleTimeout);
715
777
  }
716
- if (state.isAutoplay) {
717
- Object.setPrototypeOf(state.data.clientUser, { constructor: { name: "User" } });
718
- player.setAutoplay(true, state.data.clientUser, state.autoplayTries);
719
- }
720
778
  if (state.data) {
721
779
  for (const [name, value] of Object.entries(state.data)) {
722
780
  player.set(name, value);
@@ -988,8 +1046,12 @@ class Manager extends events_1.EventEmitter {
988
1046
  * @param player The Player instance to serialize
989
1047
  * @returns The serialized Player instance
990
1048
  */
991
- serializePlayer(player) {
1049
+ async serializePlayer(player) {
992
1050
  const seen = new WeakSet();
1051
+ // Fetch async queue data once before serializing
1052
+ const current = await player.queue.getCurrent();
1053
+ const tracks = Array.isArray(await player.queue.getTracks()) ? await player.queue.getTracks() : [];
1054
+ const previous = Array.isArray(await player.queue.getPrevious()) ? await player.queue.getPrevious() : [];
993
1055
  /**
994
1056
  * Recursively serializes an object, avoiding circular references.
995
1057
  * @param obj The object to serialize
@@ -1025,9 +1087,9 @@ class Manager extends events_1.EventEmitter {
1025
1087
  }
1026
1088
  if (key === "queue") {
1027
1089
  return {
1028
- current: value.current || null,
1029
- tracks: Array.isArray(value) ? [...value] : [],
1030
- previous: Array.isArray(value.previous) ? [...value.previous] : [],
1090
+ current,
1091
+ tracks,
1092
+ previous,
1031
1093
  };
1032
1094
  }
1033
1095
  if (key === "data") {
@@ -485,6 +485,15 @@ class Node {
485
485
  case "ChapterStarted":
486
486
  this.sponsorBlockChapterStarted(player, track, payload);
487
487
  break;
488
+ case "LyricsFoundEvent":
489
+ this.lyricsFound(player, track, payload);
490
+ break;
491
+ case "LyricsNotFoundEvent":
492
+ this.lyricsNotFound(player, track, payload);
493
+ break;
494
+ case "LyricsLineEvent":
495
+ this.lyricsLine(player, track, payload);
496
+ break;
488
497
  default:
489
498
  error = new Error(`Node#event unknown event '${type}'.`);
490
499
  this.manager.emit(Enums_1.ManagerEventTypes.NodeError, this, error);
@@ -508,7 +517,8 @@ class Node {
508
517
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, player, {
509
518
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
510
519
  details: {
511
- changeType: "autoPlay",
520
+ type: "track",
521
+ action: "autoPlay",
512
522
  track: track,
513
523
  },
514
524
  });
@@ -517,7 +527,8 @@ class Node {
517
527
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, player, {
518
528
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
519
529
  details: {
520
- changeType: "start",
530
+ type: "track",
531
+ action: "start",
521
532
  track: track,
522
533
  },
523
534
  });
@@ -584,7 +595,8 @@ class Node {
584
595
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, player, {
585
596
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
586
597
  details: {
587
- changeType: "end",
598
+ type: "track",
599
+ action: "end",
588
600
  track: track,
589
601
  },
590
602
  });
@@ -734,19 +746,28 @@ class Node {
734
746
  }
735
747
  /**
736
748
  * Fetches the lyrics of a track from the Lavalink node.
737
- * This method uses the `lavalyrics-plugin` to fetch the lyrics.
738
- * If the plugin is not available, it will throw a RangeError.
749
+ *
750
+ * If the node is a NodeLink, it will use the `NodeLinkGetLyrics` method to fetch the lyrics.
751
+ *
752
+ * Requires the `lavalyrics-plugin` to be present in the Lavalink node.
753
+ * Requires the `lavasrc-plugin` or `java-lyrics-plugin` to be present in the Lavalink node.
739
754
  *
740
755
  * @param {Track} track - The track to fetch the lyrics for.
741
756
  * @param {boolean} [skipTrackSource=false] - Whether to skip using the track's source URL.
742
757
  * @returns {Promise<Lyrics | NodeLinkGetLyrics>} A promise that resolves with the lyrics data.
743
758
  */
744
759
  async getLyrics(track, skipTrackSource = false) {
760
+ if (!this.connected)
761
+ throw new RangeError(`The node is not connected to the lavalink server: ${this.options.identifier}`);
745
762
  if (this.isNodeLink) {
746
763
  return (await this.rest.get(`/v4/lyrics?track=${encodeURIComponent(track.track)}&skipTrackSource=${skipTrackSource}`));
747
764
  }
748
- if (!this.info.plugins.some((plugin) => plugin.name === "lavalyrics-plugin"))
749
- throw new RangeError(`there is no lavalyrics-plugin available in the lavalink node: ${this.options.identifier}`);
765
+ if (!this.info.plugins.some((plugin) => plugin.name === "lavalyrics-plugin")) {
766
+ throw new RangeError(`The plugin "lavalyrics-plugin" must be present in the lavalink node: ${this.options.identifier}`);
767
+ }
768
+ if (!this.info.plugins.some((plugin) => plugin.name === "lavasrc-plugin" || plugin.name === "java-lyrics-plugin")) {
769
+ throw new RangeError(`One of the following plugins must also be present in the lavalink node: "lavasrc-plugin" or "java-lyrics-plugin" (Node: ${this.options.identifier})`);
770
+ }
750
771
  return ((await this.rest.get(`/v4/lyrics?track=${encodeURIComponent(track.track)}&skipTrackSource=${skipTrackSource}`)) || {
751
772
  source: null,
752
773
  provider: null,
@@ -755,6 +776,42 @@ class Node {
755
776
  plugin: [],
756
777
  });
757
778
  }
779
+ /**
780
+ * Subscribes to lyrics for a player.
781
+ * @param {string} guildId - The ID of the guild to subscribe to lyrics for.
782
+ * @param {boolean} [skipTrackSource=false] - Whether to skip using the track's source URL.
783
+ * @returns {Promise<unknown>} A promise that resolves when the subscription is complete.
784
+ * @throws {RangeError} If the node is not connected to the lavalink server or if the java-lyrics-plugin is not available.
785
+ */
786
+ async lyricsSubscribe(guildId, skipTrackSource = false) {
787
+ if (!this.connected)
788
+ throw new RangeError(`The node is not connected to the lavalink server: ${this.options.identifier}`);
789
+ if (this.isNodeLink)
790
+ throw new RangeError(`The node is a node link: ${this.options.identifier}`);
791
+ if (!this.info.plugins.some((plugin) => plugin.name === "lavalyrics-plugin")) {
792
+ throw new RangeError(`The plugin "lavalyrics-plugin" must be present in the lavalink node: ${this.options.identifier}`);
793
+ }
794
+ if (!this.info.plugins.some((plugin) => plugin.name === "lavasrc-plugin" || plugin.name === "java-lyrics-plugin")) {
795
+ throw new RangeError(`One of the following plugins must also be present in the lavalink node: "lavasrc-plugin" or "java-lyrics-plugin" (Node: ${this.options.identifier})`);
796
+ }
797
+ return await this.rest.post(`/v4/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe?skipTrackSource=${skipTrackSource}`, {});
798
+ }
799
+ /**
800
+ * Unsubscribes from lyrics for a player.
801
+ * @param {string} guildId - The ID of the guild to unsubscribe from lyrics for.
802
+ * @returns {Promise<unknown>} A promise that resolves when the unsubscription is complete.
803
+ * @throws {RangeError} If the node is not connected to the lavalink server or if the java-lyrics-plugin is not available.
804
+ */
805
+ async lyricsUnsubscribe(guildId) {
806
+ if (!this.connected)
807
+ throw new RangeError(`The node is not connected to the lavalink server: ${this.options.identifier}`);
808
+ if (this.isNodeLink)
809
+ throw new RangeError(`The node is a node link: ${this.options.identifier}`);
810
+ if (!this.info.plugins.some((plugin) => plugin.name === "java-lyrics-plugin")) {
811
+ throw new RangeError(`there is no java-lyrics-plugin available in the lavalink node: ${this.options.identifier}`);
812
+ }
813
+ return await this.rest.delete(`/v4/sessions/${this.sessionId}/players/${guildId}/lyrics/subscribe`);
814
+ }
758
815
  /**
759
816
  * Handles the event when a track becomes stuck during playback.
760
817
  * Stops the current track and emits a `trackStuck` event.
@@ -833,6 +890,36 @@ class Node {
833
890
  sponsorBlockChapterStarted(player, track, payload) {
834
891
  return this.manager.emit(Enums_1.ManagerEventTypes.ChapterStarted, player, track, payload);
835
892
  }
893
+ /**
894
+ * Emitted when lyrics for a track are found.
895
+ * The payload of the event will contain the lyrics.
896
+ * @param {Player} player - The player associated with the lyrics.
897
+ * @param {Track} track - The track associated with the lyrics.
898
+ * @param {LyricsFoundEvent} payload - The event payload containing additional data about the lyrics found event.
899
+ */
900
+ lyricsFound(player, track, payload) {
901
+ return this.manager.emit(Enums_1.ManagerEventTypes.LyricsFoundEvent, player, track, payload);
902
+ }
903
+ /**
904
+ * Emitted when lyrics for a track are not found.
905
+ * The payload of the event will contain the track.
906
+ * @param {Player} player - The player associated with the lyrics.
907
+ * @param {Track} track - The track associated with the lyrics.
908
+ * @param {LyricsNotFoundEvent} payload - The event payload containing additional data about the lyrics not found event.
909
+ */
910
+ lyricsNotFound(player, track, payload) {
911
+ return this.manager.emit(Enums_1.ManagerEventTypes.LyricsNotFoundEvent, player, track, payload);
912
+ }
913
+ /**
914
+ * Emitted when a line of lyrics for a track is received.
915
+ * The payload of the event will contain the lyrics line.
916
+ * @param {Player} player - The player associated with the lyrics line.
917
+ * @param {Track} track - The track associated with the lyrics line.
918
+ * @param {LyricsLineEvent} payload - The event payload containing additional data about the lyrics line event.
919
+ */
920
+ lyricsLine(player, track, payload) {
921
+ return this.manager.emit(Enums_1.ManagerEventTypes.LyricsLineEvent, player, track, payload);
922
+ }
836
923
  /**
837
924
  * Fetches Lavalink node information.
838
925
  * @returns {Promise<LavalinkInfo>} A promise that resolves to the Lavalink node information.
@@ -8,7 +8,6 @@ const Utils_1 = require("./Utils");
8
8
  const _ = tslib_1.__importStar(require("lodash"));
9
9
  const playerCheck_1 = tslib_1.__importDefault(require("../utils/playerCheck"));
10
10
  const RedisQueue_1 = require("./RedisQueue");
11
- // import { IQueue, Lyrics, PlayerOptions, PlayerUpdateVoiceState, PlayOptions, SearchQuery, SearchResult, Track, VoiceState } from "./Types";
12
11
  const Enums_1 = require("./Enums");
13
12
  const ws_1 = require("ws");
14
13
  class Player {
@@ -181,7 +180,8 @@ class Player {
181
180
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
182
181
  changeType: Enums_1.PlayerStateEventTypes.ConnectionChange,
183
182
  details: {
184
- changeType: "connect",
183
+ type: "connection",
184
+ action: "connect",
185
185
  previousConnection: oldPlayer?.state === Enums_1.StateTypes.Connected,
186
186
  currentConnection: true,
187
187
  },
@@ -216,7 +216,8 @@ class Player {
216
216
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
217
217
  changeType: Enums_1.PlayerStateEventTypes.ConnectionChange,
218
218
  details: {
219
- changeType: "disconnect",
219
+ type: "connection",
220
+ action: "disconnect",
220
221
  previousConnection: oldPlayer.state === Enums_1.StateTypes.Connected,
221
222
  currentConnection: false,
222
223
  },
@@ -231,7 +232,6 @@ class Player {
231
232
  * @emits {PlayerStateUpdate} - Emitted when the player state is updated.
232
233
  */
233
234
  async destroy(disconnect = true) {
234
- const oldPlayer = this ? { ...this } : null;
235
235
  this.state = Enums_1.StateTypes.Destroying;
236
236
  if (disconnect) {
237
237
  await this.disconnect().catch((err) => {
@@ -244,9 +244,6 @@ class Player {
244
244
  await this.queue.clear();
245
245
  await this.queue.clearPrevious();
246
246
  await this.queue.setCurrent(null);
247
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, null, {
248
- changeType: Enums_1.PlayerStateEventTypes.PlayerDestroy,
249
- });
250
247
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerDestroy, this);
251
248
  const deleted = this.manager.players.delete(this.guildId);
252
249
  return deleted;
@@ -270,7 +267,8 @@ class Player {
270
267
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
271
268
  changeType: Enums_1.PlayerStateEventTypes.ChannelChange,
272
269
  details: {
273
- changeType: "voice",
270
+ type: "channel",
271
+ action: "voice",
274
272
  previousChannel: oldPlayer.voiceChannelId || null,
275
273
  currentChannel: this.voiceChannelId,
276
274
  },
@@ -299,7 +297,8 @@ class Player {
299
297
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
300
298
  changeType: Enums_1.PlayerStateEventTypes.ChannelChange,
301
299
  details: {
302
- changeType: "text",
300
+ type: "channel",
301
+ action: "text",
303
302
  previousChannel: oldPlayer.textChannelId || null,
304
303
  currentChannel: this.textChannelId,
305
304
  },
@@ -378,6 +377,8 @@ class Player {
378
377
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
379
378
  changeType: Enums_1.PlayerStateEventTypes.AutoPlayChange,
380
379
  details: {
380
+ type: "autoplay",
381
+ action: "toggle",
381
382
  previousAutoplay: oldPlayer.isAutoplay,
382
383
  currentAutoplay: this.isAutoplay,
383
384
  },
@@ -410,17 +411,19 @@ class Player {
410
411
  if (volume < 0 || volume > 1000)
411
412
  throw new RangeError("Volume must be between 0 and 1000.");
412
413
  const oldVolume = this.volume;
414
+ const oldPlayer = { ...this };
413
415
  await this.node.rest.updatePlayer({
414
416
  guildId: this.options.guildId,
415
417
  data: { volume },
416
418
  });
417
419
  this.volume = volume;
418
- this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, {
420
+ this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
419
421
  changeType: Enums_1.PlayerStateEventTypes.VolumeChange,
420
422
  details: {
423
+ type: "volume",
424
+ action: "adjust",
421
425
  previousVolume: oldVolume,
422
426
  currentVolume: this.volume,
423
- isGradual: false,
424
427
  },
425
428
  });
426
429
  return this;
@@ -477,8 +480,9 @@ class Player {
477
480
  // Emit an event indicating the repeat mode has changed
478
481
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
479
482
  changeType: Enums_1.PlayerStateEventTypes.RepeatChange,
480
- detail: {
481
- changeType: "track",
483
+ details: {
484
+ type: "repeat",
485
+ action: "track",
482
486
  previousRepeat: this.getRepeatState(oldPlayer),
483
487
  currentRepeat: this.getRepeatState(this),
484
488
  },
@@ -511,8 +515,9 @@ class Player {
511
515
  // Emit the player state update event
512
516
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
513
517
  changeType: Enums_1.PlayerStateEventTypes.RepeatChange,
514
- detail: {
515
- changeType: "queue",
518
+ details: {
519
+ type: "repeat",
520
+ action: "queue",
516
521
  previousRepeat: this.getRepeatState(oldPlayer),
517
522
  currentRepeat: this.getRepeatState(this),
518
523
  },
@@ -567,8 +572,9 @@ class Player {
567
572
  // Emit a player state update event
568
573
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
569
574
  changeType: Enums_1.PlayerStateEventTypes.RepeatChange,
570
- detail: {
571
- changeType: "dynamic",
575
+ details: {
576
+ type: "repeat",
577
+ action: "dynamic",
572
578
  previousRepeat: this.getRepeatState(oldPlayer),
573
579
  currentRepeat: this.getRepeatState(this),
574
580
  },
@@ -622,7 +628,8 @@ class Player {
622
628
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
623
629
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
624
630
  details: {
625
- changeType: "remove",
631
+ type: "queue",
632
+ action: "remove",
626
633
  tracks: removedTracks,
627
634
  },
628
635
  });
@@ -657,6 +664,8 @@ class Player {
657
664
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
658
665
  changeType: Enums_1.PlayerStateEventTypes.PauseChange,
659
666
  details: {
667
+ type: "pause",
668
+ action: "pause",
660
669
  previousPause: oldPlayer.paused,
661
670
  currentPause: this.paused,
662
671
  },
@@ -684,7 +693,8 @@ class Player {
684
693
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
685
694
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
686
695
  details: {
687
- changeType: "previous",
696
+ type: "track",
697
+ action: "previous",
688
698
  track: lastTrack,
689
699
  },
690
700
  });
@@ -724,7 +734,8 @@ class Player {
724
734
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this, {
725
735
  changeType: Enums_1.PlayerStateEventTypes.TrackChange,
726
736
  details: {
727
- changeType: "timeUpdate",
737
+ type: "track",
738
+ action: "timeUpdate",
728
739
  previousTime: oldPlayer.position,
729
740
  currentTime: this.position,
730
741
  },
@@ -137,7 +137,8 @@ class Queue extends Array {
137
137
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
138
138
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
139
139
  details: {
140
- changeType: "autoPlayAdd",
140
+ type: "queue",
141
+ action: "autoPlayAdd",
141
142
  tracks: Array.isArray(track) ? track : [track],
142
143
  },
143
144
  });
@@ -149,7 +150,8 @@ class Queue extends Array {
149
150
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
150
151
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
151
152
  details: {
152
- changeType: "add",
153
+ type: "queue",
154
+ action: "add",
153
155
  tracks: Array.isArray(track) ? track : [track],
154
156
  },
155
157
  });
@@ -169,7 +171,8 @@ class Queue extends Array {
169
171
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
170
172
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
171
173
  details: {
172
- changeType: "remove",
174
+ type: "queue",
175
+ action: "remove",
173
176
  tracks: removedTracks,
174
177
  },
175
178
  });
@@ -183,7 +186,8 @@ class Queue extends Array {
183
186
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
184
187
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
185
188
  details: {
186
- changeType: "remove",
189
+ type: "queue",
190
+ action: "remove",
187
191
  tracks: tracksToEmit,
188
192
  },
189
193
  });
@@ -202,7 +206,8 @@ class Queue extends Array {
202
206
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
203
207
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
204
208
  details: {
205
- changeType: "clear",
209
+ type: "queue",
210
+ action: "clear",
206
211
  tracks: [], // No tracks are left after clearing
207
212
  },
208
213
  });
@@ -225,7 +230,8 @@ class Queue extends Array {
225
230
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
226
231
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
227
232
  details: {
228
- changeType: "shuffle",
233
+ type: "queue",
234
+ action: "shuffle",
229
235
  },
230
236
  });
231
237
  // Emit a debug message indicating the queue has been shuffled for a specific guild ID.
@@ -265,7 +271,8 @@ class Queue extends Array {
265
271
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
266
272
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
267
273
  details: {
268
- changeType: "userBlock",
274
+ type: "queue",
275
+ action: "userBlock",
269
276
  },
270
277
  });
271
278
  // Emit a debug message indicating the queue has been shuffled for a specific guild ID.
@@ -315,7 +322,8 @@ class Queue extends Array {
315
322
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
316
323
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
317
324
  details: {
318
- changeType: "roundRobin",
325
+ type: "queue",
326
+ action: "roundRobin",
319
327
  },
320
328
  });
321
329
  // Emit a debug message indicating the queue has been shuffled for a specific guild ID.
@@ -101,7 +101,8 @@ class RedisQueue {
101
101
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
102
102
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
103
103
  details: {
104
- changeType: "autoPlayAdd",
104
+ type: "queue",
105
+ action: "autoPlayAdd",
105
106
  tracks: Array.isArray(track) ? track : [track],
106
107
  },
107
108
  });
@@ -112,7 +113,8 @@ class RedisQueue {
112
113
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
113
114
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
114
115
  details: {
115
- changeType: "add",
116
+ type: "queue",
117
+ action: "add",
116
118
  tracks,
117
119
  },
118
120
  });
@@ -140,7 +142,8 @@ class RedisQueue {
140
142
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
141
143
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
142
144
  details: {
143
- changeType: "remove",
145
+ type: "queue",
146
+ action: "remove",
144
147
  tracks: deserialized,
145
148
  },
146
149
  });
@@ -152,7 +155,8 @@ class RedisQueue {
152
155
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
153
156
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
154
157
  details: {
155
- changeType: "clear",
158
+ type: "queue",
159
+ action: "clear",
156
160
  tracks: [],
157
161
  },
158
162
  });
@@ -192,7 +196,10 @@ class RedisQueue {
192
196
  }
193
197
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
194
198
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
195
- details: { changeType: "shuffle" },
199
+ details: {
200
+ type: "queue",
201
+ action: "shuffle",
202
+ },
196
203
  });
197
204
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] Shuffled the queue for: ${this.guildId}`);
198
205
  }
@@ -219,7 +226,10 @@ class RedisQueue {
219
226
  await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
220
227
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
221
228
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
222
- details: { changeType: "userBlock" },
229
+ details: {
230
+ type: "queue",
231
+ action: "userBlock",
232
+ },
223
233
  });
224
234
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] userBlockShuffled the queue for: ${this.guildId}`);
225
235
  }
@@ -255,7 +265,10 @@ class RedisQueue {
255
265
  await this.redis.rpush(this.queueKey, ...shuffledQueue.map(this.serialize));
256
266
  this.manager.emit(Enums_1.ManagerEventTypes.PlayerStateUpdate, oldPlayer, this.manager.players.get(this.guildId), {
257
267
  changeType: Enums_1.PlayerStateEventTypes.QueueChange,
258
- details: { changeType: "roundRobin" },
268
+ details: {
269
+ type: "queue",
270
+ action: "roundRobin",
271
+ },
259
272
  });
260
273
  this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[QUEUE] roundRobinShuffled the queue for: ${this.guildId}`);
261
274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magmastream",
3
- "version": "2.9.0-dev.33",
3
+ "version": "2.9.0-dev.35",
4
4
  "description": "A user-friendly Lavalink client designed for NodeJS.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",