@basmilius/apple-devices 0.9.11 → 0.9.13

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.mts CHANGED
@@ -5,11 +5,12 @@ import { EventEmitter } from "node:events";
5
5
  import { AccessoryCredentials, AudioSource, DiscoveryResult, TimingServer } from "@basmilius/apple-common";
6
6
  import { AttentionState, ButtonPressType, HidCommandKey, LaunchableApp, MediaControlCommandKey, Protocol as Protocol$1, UserAccount } from "@basmilius/apple-companion-link";
7
7
 
8
- //#region src/airplay/client.d.ts
9
- declare class Client {
8
+ //#region src/airplay/player.d.ts
9
+ declare class Player {
10
10
  #private;
11
- get bundleIdentifier(): string;
11
+ get identifier(): string;
12
12
  get displayName(): string;
13
+ get isDefaultPlayer(): boolean;
13
14
  get nowPlayingInfo(): Proto.NowPlayingInfo | null;
14
15
  get playbackQueue(): Proto.PlaybackQueue | null;
15
16
  get playbackState(): Proto.PlaybackState_Enum;
@@ -35,7 +36,7 @@ declare class Client {
35
36
  get currentItemArtwork(): Uint8Array | null;
36
37
  get currentItemArtworkUrl(): string | null;
37
38
  get currentItemLyrics(): Proto.LyricsItem | null;
38
- constructor(bundleIdentifier: string, displayName: string);
39
+ constructor(identifier: string, displayName: string);
39
40
  isCommandSupported(command: Proto.Command): boolean;
40
41
  setNowPlayingInfo(nowPlayingInfo: Proto.NowPlayingInfo): void;
41
42
  setPlaybackQueue(playbackQueue: Proto.PlaybackQueue): void;
@@ -44,6 +45,46 @@ declare class Client {
44
45
  updateContentItem(item: Proto.ContentItem): void;
45
46
  }
46
47
  //#endregion
48
+ //#region src/airplay/client.d.ts
49
+ declare class Client {
50
+ #private;
51
+ get bundleIdentifier(): string;
52
+ get displayName(): string;
53
+ get players(): Map<string, Player>;
54
+ get activePlayer(): Player | null;
55
+ get nowPlayingInfo(): Proto.NowPlayingInfo | null;
56
+ get playbackQueue(): Proto.PlaybackQueue | null;
57
+ get playbackState(): Proto.PlaybackState_Enum;
58
+ get playbackStateTimestamp(): number;
59
+ get supportedCommands(): Proto.CommandInfo[];
60
+ get title(): string;
61
+ get artist(): string;
62
+ get album(): string;
63
+ get genre(): string;
64
+ get seriesName(): string;
65
+ get seasonNumber(): number;
66
+ get episodeNumber(): number;
67
+ get mediaType(): Proto.ContentItemMetadata_MediaType;
68
+ get contentIdentifier(): string;
69
+ get duration(): number;
70
+ get playbackRate(): number;
71
+ get isPlaying(): boolean;
72
+ get shuffleMode(): Proto.ShuffleMode_Enum;
73
+ get repeatMode(): Proto.RepeatMode_Enum;
74
+ get elapsedTime(): number;
75
+ get currentItem(): Proto.ContentItem | null;
76
+ get currentItemMetadata(): Proto.ContentItemMetadata | null;
77
+ get currentItemArtwork(): Uint8Array | null;
78
+ get currentItemArtworkUrl(): string | null;
79
+ get currentItemLyrics(): Proto.LyricsItem | null;
80
+ constructor(bundleIdentifier: string, displayName: string);
81
+ getOrCreatePlayer(identifier: string, displayName?: string): Player;
82
+ setActivePlayer(identifier: string): void;
83
+ removePlayer(identifier: string): void;
84
+ setDefaultSupportedCommands(supportedCommands: Proto.CommandInfo[]): void;
85
+ isCommandSupported(command: Proto.Command): boolean;
86
+ }
87
+ //#endregion
47
88
  //#region src/airplay/const.d.ts
48
89
  declare const PROTOCOL: unique symbol;
49
90
  declare const STATE_SUBSCRIBE_SYMBOL: unique symbol;
@@ -99,9 +140,11 @@ type EventMap$4 = {
99
140
  readonly clients: [Record<string, Client>];
100
141
  readonly deviceInfo: [Proto.DeviceInfoMessage];
101
142
  readonly deviceInfoUpdate: [Proto.DeviceInfoMessage];
143
+ readonly nowPlayingChanged: [client: Client | null, player: Player | null];
102
144
  readonly originClientProperties: [Proto.OriginClientPropertiesMessage];
103
145
  readonly playerClientProperties: [Proto.PlayerClientPropertiesMessage];
104
146
  readonly removeClient: [Proto.RemoveClientMessage];
147
+ readonly removePlayer: [Proto.RemovePlayerMessage];
105
148
  readonly sendCommandResult: [Proto.SendCommandResultMessage];
106
149
  readonly setArtwork: [Proto.SetArtworkMessage];
107
150
  readonly setDefaultSupportedCommands: [Proto.SetDefaultSupportedCommandsMessage];
@@ -144,6 +187,7 @@ declare class export_default$7 extends EventEmitter<EventMap$4> {
144
187
  onUpdateContentItem(message: Proto.UpdateContentItemMessage): void;
145
188
  onUpdateContentItemArtwork(message: Proto.UpdateContentItemArtworkMessage): void;
146
189
  onUpdatePlayer(message: Proto.UpdatePlayerMessage): void;
190
+ onRemovePlayer(message: Proto.RemovePlayerMessage): void;
147
191
  onUpdateClient(message: Proto.UpdateClientMessage): void;
148
192
  onUpdateOutputDevice(message: Proto.UpdateOutputDeviceMessage): void;
149
193
  onVolumeControlAvailability(message: Proto.VolumeControlAvailabilityMessage): void;
package/dist/index.mjs CHANGED
@@ -4,21 +4,25 @@ import { EventEmitter } from "node:events";
4
4
  import { waitFor } from "@basmilius/apple-common";
5
5
  import { Protocol as Protocol$1, convertAttentionState } from "@basmilius/apple-companion-link";
6
6
 
7
- //#region src/airplay/client.ts
7
+ //#region src/airplay/player.ts
8
8
  const COCOA_EPOCH_OFFSET = 978307200;
9
+ const DEFAULT_PLAYER_ID = "MediaRemote-DefaultPlayer";
9
10
  const extrapolateElapsed = (elapsed, cocoaTimestamp, rate) => {
10
11
  if (!rate) return elapsed;
11
12
  const timestampUnix = cocoaTimestamp + COCOA_EPOCH_OFFSET;
12
13
  const delta = (Date.now() / 1e3 - timestampUnix) * rate;
13
14
  return Math.max(0, elapsed + delta);
14
15
  };
15
- var Client = class {
16
- get bundleIdentifier() {
17
- return this.#bundleIdentifier;
16
+ var Player = class {
17
+ get identifier() {
18
+ return this.#identifier;
18
19
  }
19
20
  get displayName() {
20
21
  return this.#displayName;
21
22
  }
23
+ get isDefaultPlayer() {
24
+ return this.#identifier === DEFAULT_PLAYER_ID;
25
+ }
22
26
  get nowPlayingInfo() {
23
27
  return this.#nowPlayingInfo;
24
28
  }
@@ -79,8 +83,14 @@ var Client = class {
79
83
  get elapsedTime() {
80
84
  const npi = this.#nowPlayingInfo;
81
85
  const meta = this.currentItemMetadata;
82
- if (npi?.elapsedTime != null && npi.timestamp) return extrapolateElapsed(npi.elapsedTime, npi.timestamp, npi.playbackRate);
83
- if (meta?.elapsedTime != null && meta.elapsedTimeTimestamp) return extrapolateElapsed(meta.elapsedTime, meta.elapsedTimeTimestamp, meta.playbackRate);
86
+ const npiValid = npi?.elapsedTime != null && npi.timestamp;
87
+ const metaValid = meta?.elapsedTime != null && meta.elapsedTimeTimestamp;
88
+ if (npiValid && metaValid) {
89
+ if (meta.elapsedTimeTimestamp > npi.timestamp) return extrapolateElapsed(meta.elapsedTime, meta.elapsedTimeTimestamp, meta.playbackRate);
90
+ return extrapolateElapsed(npi.elapsedTime, npi.timestamp, npi.playbackRate);
91
+ }
92
+ if (npiValid) return extrapolateElapsed(npi.elapsedTime, npi.timestamp, npi.playbackRate);
93
+ if (metaValid) return extrapolateElapsed(meta.elapsedTime, meta.elapsedTimeTimestamp, meta.playbackRate);
84
94
  return npi?.elapsedTime || meta?.elapsedTime || 0;
85
95
  }
86
96
  get currentItem() {
@@ -107,18 +117,17 @@ var Client = class {
107
117
  get currentItemLyrics() {
108
118
  return this.currentItem?.lyrics ?? null;
109
119
  }
110
- #bundleIdentifier;
120
+ #identifier;
111
121
  #displayName;
112
122
  #nowPlayingInfo = null;
113
123
  #playbackQueue = null;
114
124
  #playbackState;
115
- #playbackStateTimestamp;
125
+ #playbackStateTimestamp = 0;
116
126
  #supportedCommands = [];
117
- constructor(bundleIdentifier, displayName) {
118
- this.#bundleIdentifier = bundleIdentifier;
127
+ constructor(identifier, displayName) {
128
+ this.#identifier = identifier;
119
129
  this.#displayName = displayName;
120
130
  this.#playbackState = Proto.PlaybackState_Enum.Unknown;
121
- this.#supportedCommands = [];
122
131
  }
123
132
  isCommandSupported(command) {
124
133
  return this.#supportedCommands.some((c) => c.command === command);
@@ -150,6 +159,129 @@ var Client = class {
150
159
  }
151
160
  };
152
161
 
162
+ //#endregion
163
+ //#region src/airplay/client.ts
164
+ var Client = class {
165
+ get bundleIdentifier() {
166
+ return this.#bundleIdentifier;
167
+ }
168
+ get displayName() {
169
+ return this.#displayName;
170
+ }
171
+ get players() {
172
+ return this.#players;
173
+ }
174
+ get activePlayer() {
175
+ if (this.#activePlayerId) return this.#players.get(this.#activePlayerId) ?? null;
176
+ return this.#players.get(DEFAULT_PLAYER_ID) ?? null;
177
+ }
178
+ get nowPlayingInfo() {
179
+ return this.activePlayer?.nowPlayingInfo ?? null;
180
+ }
181
+ get playbackQueue() {
182
+ return this.activePlayer?.playbackQueue ?? null;
183
+ }
184
+ get playbackState() {
185
+ return this.activePlayer?.playbackState ?? Proto.PlaybackState_Enum.Unknown;
186
+ }
187
+ get playbackStateTimestamp() {
188
+ return this.activePlayer?.playbackStateTimestamp ?? -1;
189
+ }
190
+ get supportedCommands() {
191
+ return this.activePlayer?.supportedCommands ?? this.#defaultSupportedCommands;
192
+ }
193
+ get title() {
194
+ return this.activePlayer?.title ?? "";
195
+ }
196
+ get artist() {
197
+ return this.activePlayer?.artist ?? "";
198
+ }
199
+ get album() {
200
+ return this.activePlayer?.album ?? "";
201
+ }
202
+ get genre() {
203
+ return this.activePlayer?.genre ?? "";
204
+ }
205
+ get seriesName() {
206
+ return this.activePlayer?.seriesName ?? "";
207
+ }
208
+ get seasonNumber() {
209
+ return this.activePlayer?.seasonNumber ?? 0;
210
+ }
211
+ get episodeNumber() {
212
+ return this.activePlayer?.episodeNumber ?? 0;
213
+ }
214
+ get mediaType() {
215
+ return this.activePlayer?.mediaType ?? Proto.ContentItemMetadata_MediaType.UnknownMediaType;
216
+ }
217
+ get contentIdentifier() {
218
+ return this.activePlayer?.contentIdentifier ?? "";
219
+ }
220
+ get duration() {
221
+ return this.activePlayer?.duration ?? 0;
222
+ }
223
+ get playbackRate() {
224
+ return this.activePlayer?.playbackRate ?? 0;
225
+ }
226
+ get isPlaying() {
227
+ return this.activePlayer?.isPlaying ?? false;
228
+ }
229
+ get shuffleMode() {
230
+ return this.activePlayer?.shuffleMode ?? Proto.ShuffleMode_Enum.Unknown;
231
+ }
232
+ get repeatMode() {
233
+ return this.activePlayer?.repeatMode ?? Proto.RepeatMode_Enum.Unknown;
234
+ }
235
+ get elapsedTime() {
236
+ return this.activePlayer?.elapsedTime ?? 0;
237
+ }
238
+ get currentItem() {
239
+ return this.activePlayer?.currentItem ?? null;
240
+ }
241
+ get currentItemMetadata() {
242
+ return this.activePlayer?.currentItemMetadata ?? null;
243
+ }
244
+ get currentItemArtwork() {
245
+ return this.activePlayer?.currentItemArtwork ?? null;
246
+ }
247
+ get currentItemArtworkUrl() {
248
+ return this.activePlayer?.currentItemArtworkUrl ?? null;
249
+ }
250
+ get currentItemLyrics() {
251
+ return this.activePlayer?.currentItemLyrics ?? null;
252
+ }
253
+ #bundleIdentifier;
254
+ #displayName;
255
+ #players = /* @__PURE__ */ new Map();
256
+ #activePlayerId = null;
257
+ #defaultSupportedCommands = [];
258
+ constructor(bundleIdentifier, displayName) {
259
+ this.#bundleIdentifier = bundleIdentifier;
260
+ this.#displayName = displayName;
261
+ }
262
+ getOrCreatePlayer(identifier, displayName) {
263
+ let player = this.#players.get(identifier);
264
+ if (!player) {
265
+ player = new Player(identifier, displayName ?? identifier);
266
+ this.#players.set(identifier, player);
267
+ }
268
+ return player;
269
+ }
270
+ setActivePlayer(identifier) {
271
+ this.#activePlayerId = identifier;
272
+ }
273
+ removePlayer(identifier) {
274
+ this.#players.delete(identifier);
275
+ if (this.#activePlayerId === identifier) this.#activePlayerId = null;
276
+ }
277
+ setDefaultSupportedCommands(supportedCommands) {
278
+ this.#defaultSupportedCommands = supportedCommands;
279
+ }
280
+ isCommandSupported(command) {
281
+ return this.activePlayer?.isCommandSupported(command) ?? false;
282
+ }
283
+ };
284
+
153
285
  //#endregion
154
286
  //#region src/airplay/const.ts
155
287
  const FEEDBACK_INTERVAL = 2e3;
@@ -350,6 +482,7 @@ var state_default = class extends EventEmitter {
350
482
  #device;
351
483
  #clients;
352
484
  #nowPlayingClientBundleIdentifier;
485
+ #nowPlayingSnapshot;
353
486
  #outputDeviceUID;
354
487
  #outputDevices = [];
355
488
  #volume;
@@ -364,6 +497,7 @@ var state_default = class extends EventEmitter {
364
497
  this.onOriginClientProperties = this.onOriginClientProperties.bind(this);
365
498
  this.onPlayerClientProperties = this.onPlayerClientProperties.bind(this);
366
499
  this.onRemoveClient = this.onRemoveClient.bind(this);
500
+ this.onRemovePlayer = this.onRemovePlayer.bind(this);
367
501
  this.onSendCommandResult = this.onSendCommandResult.bind(this);
368
502
  this.onSetArtwork = this.onSetArtwork.bind(this);
369
503
  this.onSetDefaultSupportedCommands = this.onSetDefaultSupportedCommands.bind(this);
@@ -385,6 +519,7 @@ var state_default = class extends EventEmitter {
385
519
  this.#dataStream.on("originClientProperties", this.onOriginClientProperties);
386
520
  this.#dataStream.on("playerClientProperties", this.onPlayerClientProperties);
387
521
  this.#dataStream.on("removeClient", this.onRemoveClient);
522
+ this.#dataStream.on("removePlayer", this.onRemovePlayer);
388
523
  this.#dataStream.on("sendCommandResult", this.onSendCommandResult);
389
524
  this.#dataStream.on("setArtwork", this.onSetArtwork);
390
525
  this.#dataStream.on("setDefaultSupportedCommands", this.onSetDefaultSupportedCommands);
@@ -408,6 +543,7 @@ var state_default = class extends EventEmitter {
408
543
  dataStream.off("originClientProperties", this.onOriginClientProperties);
409
544
  dataStream.off("playerClientProperties", this.onPlayerClientProperties);
410
545
  dataStream.off("removeClient", this.onRemoveClient);
546
+ dataStream.off("removePlayer", this.onRemovePlayer);
411
547
  dataStream.off("sendCommandResult", this.onSendCommandResult);
412
548
  dataStream.off("setArtwork", this.onSetArtwork);
413
549
  dataStream.off("setDefaultSupportedCommands", this.onSetDefaultSupportedCommands);
@@ -426,6 +562,7 @@ var state_default = class extends EventEmitter {
426
562
  clear() {
427
563
  this.#clients = {};
428
564
  this.#nowPlayingClientBundleIdentifier = null;
565
+ this.#nowPlayingSnapshot = null;
429
566
  this.#outputDeviceUID = null;
430
567
  this.#outputDevices = [];
431
568
  this.#volume = 0;
@@ -452,8 +589,12 @@ var state_default = class extends EventEmitter {
452
589
  }
453
590
  onRemoveClient(message) {
454
591
  if (!(message.client.bundleIdentifier in this.#clients)) return;
592
+ const wasActive = this.#nowPlayingClientBundleIdentifier === message.client.bundleIdentifier;
455
593
  delete this.#clients[message.client.bundleIdentifier];
594
+ if (wasActive) this.#nowPlayingClientBundleIdentifier = null;
595
+ this.emit("removeClient", message);
456
596
  this.emit("clients", this.#clients);
597
+ if (wasActive) this.#emitNowPlayingChangedIfNeeded();
457
598
  }
458
599
  onSendCommandResult(message) {
459
600
  this.emit("sendCommandResult", message);
@@ -462,35 +603,59 @@ var state_default = class extends EventEmitter {
462
603
  this.emit("setArtwork", message);
463
604
  }
464
605
  onSetDefaultSupportedCommands(message) {
606
+ if (message.playerPath?.client?.bundleIdentifier && message.supportedCommands) this.#client(message.playerPath.client.bundleIdentifier, message.playerPath.client.displayName).setDefaultSupportedCommands(message.supportedCommands.supportedCommands);
465
607
  this.emit("setDefaultSupportedCommands", message);
466
608
  }
467
609
  onSetNowPlayingClient(message) {
468
610
  this.#nowPlayingClientBundleIdentifier = message.client?.bundleIdentifier ?? null;
469
611
  this.emit("setNowPlayingClient", message);
612
+ this.#emitNowPlayingChangedIfNeeded();
470
613
  }
471
614
  onSetNowPlayingPlayer(message) {
615
+ if (message.playerPath?.client?.bundleIdentifier && message.playerPath?.player?.identifier) {
616
+ const client = this.#client(message.playerPath.client.bundleIdentifier, message.playerPath.client.displayName);
617
+ client.getOrCreatePlayer(message.playerPath.player.identifier, message.playerPath.player.displayName);
618
+ client.setActivePlayer(message.playerPath.player.identifier);
619
+ }
472
620
  this.emit("setNowPlayingPlayer", message);
621
+ this.#emitNowPlayingChangedIfNeeded();
473
622
  }
474
623
  onSetState(message) {
475
- const client = this.#client(message.playerPath.client.bundleIdentifier, message.displayName);
476
- if (message.nowPlayingInfo) client.setNowPlayingInfo(message.nowPlayingInfo);
477
- if (message.playbackState) client.setPlaybackState(message.playbackState, message.playbackStateTimestamp);
478
- if (message.supportedCommands) client.setSupportedCommands(message.supportedCommands.supportedCommands);
479
- if (message.playbackQueue) client.setPlaybackQueue(message.playbackQueue);
624
+ const bundleIdentifier = message.playerPath.client.bundleIdentifier;
625
+ const client = this.#client(bundleIdentifier, message.displayName);
626
+ const playerIdentifier = message.playerPath?.player?.identifier || "MediaRemote-DefaultPlayer";
627
+ const player = client.getOrCreatePlayer(playerIdentifier, message.playerPath?.player?.displayName);
628
+ if (message.nowPlayingInfo) player.setNowPlayingInfo(message.nowPlayingInfo);
629
+ if (message.playbackState) player.setPlaybackState(message.playbackState, message.playbackStateTimestamp);
630
+ if (message.supportedCommands) player.setSupportedCommands(message.supportedCommands.supportedCommands);
631
+ if (message.playbackQueue) player.setPlaybackQueue(message.playbackQueue);
480
632
  this.emit("setState", message);
633
+ if (bundleIdentifier === this.#nowPlayingClientBundleIdentifier) this.#emitNowPlayingChangedIfNeeded();
481
634
  }
482
635
  onUpdateContentItem(message) {
483
- const client = this.#client(message.playerPath.client.bundleIdentifier, message.playerPath.client.displayName);
484
- if (!client) return;
485
- for (const item of message.contentItems) client.updateContentItem(item);
636
+ const bundleIdentifier = message.playerPath.client.bundleIdentifier;
637
+ const client = this.#client(bundleIdentifier, message.playerPath.client.displayName);
638
+ const playerIdentifier = message.playerPath?.player?.identifier || "MediaRemote-DefaultPlayer";
639
+ const player = client.getOrCreatePlayer(playerIdentifier, message.playerPath?.player?.displayName);
640
+ for (const item of message.contentItems) player.updateContentItem(item);
486
641
  this.emit("updateContentItem", message);
642
+ if (bundleIdentifier === this.#nowPlayingClientBundleIdentifier) this.#emitNowPlayingChangedIfNeeded();
487
643
  }
488
644
  onUpdateContentItemArtwork(message) {
489
645
  this.emit("updateContentItemArtwork", message);
490
646
  }
491
647
  onUpdatePlayer(message) {
648
+ if (message.playerPath?.client?.bundleIdentifier && message.playerPath?.player?.identifier) this.#client(message.playerPath.client.bundleIdentifier, message.playerPath.client.displayName).getOrCreatePlayer(message.playerPath.player.identifier, message.playerPath.player.displayName);
492
649
  this.emit("updatePlayer", message);
493
650
  }
651
+ onRemovePlayer(message) {
652
+ if (message.playerPath?.client?.bundleIdentifier && message.playerPath?.player?.identifier) {
653
+ const client = this.#clients[message.playerPath.client.bundleIdentifier];
654
+ if (client) client.removePlayer(message.playerPath.player.identifier);
655
+ }
656
+ this.emit("removePlayer", message);
657
+ if (message.playerPath?.client?.bundleIdentifier === this.#nowPlayingClientBundleIdentifier) this.#emitNowPlayingChangedIfNeeded();
658
+ }
494
659
  onUpdateClient(message) {
495
660
  this.#client(message.client.bundleIdentifier, message.client.displayName);
496
661
  this.emit("clients", this.#clients);
@@ -522,6 +687,38 @@ var state_default = class extends EventEmitter {
522
687
  return client;
523
688
  }
524
689
  }
690
+ #createNowPlayingSnapshot() {
691
+ const client = this.nowPlayingClient;
692
+ const player = client?.activePlayer ?? null;
693
+ return {
694
+ bundleIdentifier: client?.bundleIdentifier ?? null,
695
+ playerIdentifier: player?.identifier ?? null,
696
+ playbackState: player?.playbackState ?? Proto.PlaybackState_Enum.Unknown,
697
+ title: player?.title ?? "",
698
+ artist: player?.artist ?? "",
699
+ album: player?.album ?? "",
700
+ genre: player?.genre ?? "",
701
+ duration: player?.duration ?? 0,
702
+ shuffleMode: player?.shuffleMode ?? Proto.ShuffleMode_Enum.Unknown,
703
+ repeatMode: player?.repeatMode ?? Proto.RepeatMode_Enum.Unknown,
704
+ mediaType: player?.mediaType ?? Proto.ContentItemMetadata_MediaType.UnknownMediaType,
705
+ seriesName: player?.seriesName ?? "",
706
+ seasonNumber: player?.seasonNumber ?? 0,
707
+ episodeNumber: player?.episodeNumber ?? 0,
708
+ contentIdentifier: player?.contentIdentifier ?? ""
709
+ };
710
+ }
711
+ #emitNowPlayingChangedIfNeeded() {
712
+ const snapshot = this.#createNowPlayingSnapshot();
713
+ const previous = this.#nowPlayingSnapshot;
714
+ if (previous && this.#snapshotsEqual(previous, snapshot)) return;
715
+ this.#nowPlayingSnapshot = snapshot;
716
+ const client = this.nowPlayingClient;
717
+ this.emit("nowPlayingChanged", client, client?.activePlayer ?? null);
718
+ }
719
+ #snapshotsEqual(a, b) {
720
+ return a.bundleIdentifier === b.bundleIdentifier && a.playerIdentifier === b.playerIdentifier && a.playbackState === b.playbackState && a.title === b.title && a.artist === b.artist && a.album === b.album && a.genre === b.genre && a.duration === b.duration && a.shuffleMode === b.shuffleMode && a.repeatMode === b.repeatMode && a.mediaType === b.mediaType && a.seriesName === b.seriesName && a.seasonNumber === b.seasonNumber && a.episodeNumber === b.episodeNumber && a.contentIdentifier === b.contentIdentifier;
721
+ }
525
722
  };
526
723
 
527
724
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@basmilius/apple-devices",
3
3
  "description": "Exposes various Apple devices to connect with either AirPlay or Companion Link.",
4
- "version": "0.9.11",
4
+ "version": "0.9.13",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -49,10 +49,10 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@basmilius/apple-airplay": "0.9.11",
53
- "@basmilius/apple-common": "0.9.11",
54
- "@basmilius/apple-companion-link": "0.9.11",
55
- "@basmilius/apple-encoding": "0.9.11"
52
+ "@basmilius/apple-airplay": "0.9.13",
53
+ "@basmilius/apple-common": "0.9.13",
54
+ "@basmilius/apple-companion-link": "0.9.13",
55
+ "@basmilius/apple-encoding": "0.9.13"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/bun": "^1.3.9",