@basmilius/apple-devices 0.9.15 → 0.9.17

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
@@ -14,6 +14,7 @@ declare class Player {
14
14
  get nowPlayingInfo(): Proto.NowPlayingInfo | null;
15
15
  get playbackQueue(): Proto.PlaybackQueue | null;
16
16
  get playbackState(): Proto.PlaybackState_Enum;
17
+ get rawPlaybackState(): Proto.PlaybackState_Enum;
17
18
  get playbackStateTimestamp(): number;
18
19
  get supportedCommands(): Proto.CommandInfo[];
19
20
  get title(): string;
@@ -33,10 +34,13 @@ declare class Player {
33
34
  get elapsedTime(): number;
34
35
  get currentItem(): Proto.ContentItem | null;
35
36
  get currentItemMetadata(): Proto.ContentItemMetadata | null;
37
+ get artworkId(): string | null;
38
+ artworkUrl(width?: number, height?: number): string | null;
36
39
  get currentItemArtwork(): Uint8Array | null;
37
40
  get currentItemArtworkUrl(): string | null;
38
41
  get currentItemLyrics(): Proto.LyricsItem | null;
39
42
  constructor(identifier: string, displayName: string);
43
+ findCommand(command: Proto.Command): Proto.CommandInfo | null;
40
44
  isCommandSupported(command: Proto.Command): boolean;
41
45
  setNowPlayingInfo(nowPlayingInfo: Proto.NowPlayingInfo): void;
42
46
  setPlaybackQueue(playbackQueue: Proto.PlaybackQueue): void;
@@ -72,6 +76,8 @@ declare class Client {
72
76
  get shuffleMode(): Proto.ShuffleMode_Enum;
73
77
  get repeatMode(): Proto.RepeatMode_Enum;
74
78
  get elapsedTime(): number;
79
+ get artworkId(): string | null;
80
+ artworkUrl(width?: number, height?: number): string | null;
75
81
  get currentItem(): Proto.ContentItem | null;
76
82
  get currentItemMetadata(): Proto.ContentItemMetadata | null;
77
83
  get currentItemArtwork(): Uint8Array | null;
@@ -82,7 +88,9 @@ declare class Client {
82
88
  setActivePlayer(identifier: string): void;
83
89
  removePlayer(identifier: string): void;
84
90
  setDefaultSupportedCommands(supportedCommands: Proto.CommandInfo[]): void;
91
+ findCommand(command: Proto.Command): Proto.CommandInfo | null;
85
92
  isCommandSupported(command: Proto.Command): boolean;
93
+ updateDisplayName(displayName: string): void;
86
94
  }
87
95
  //#endregion
88
96
  //#region src/airplay/const.d.ts
@@ -91,6 +99,11 @@ declare const STATE_SUBSCRIBE_SYMBOL: unique symbol;
91
99
  declare const STATE_UNSUBSCRIBE_SYMBOL: unique symbol;
92
100
  //#endregion
93
101
  //#region src/airplay/remote.d.ts
102
+ declare class SendCommandError extends Error {
103
+ readonly sendError: Proto.SendError_Enum;
104
+ readonly handlerReturnStatus: Proto.HandlerReturnStatus_Enum;
105
+ constructor(sendError: Proto.SendError_Enum, handlerReturnStatus: Proto.HandlerReturnStatus_Enum);
106
+ }
94
107
  declare class export_default$1 {
95
108
  #private;
96
109
  constructor(device: export_default);
@@ -123,8 +136,18 @@ declare class export_default$1 {
123
136
  commandSetShuffleMode(mode: Proto.ShuffleMode_Enum): Promise<void>;
124
137
  commandSetRepeatMode(mode: Proto.RepeatMode_Enum): Promise<void>;
125
138
  commandChangePlaybackRate(rate: number): Promise<void>;
139
+ commandAdvanceShuffleMode(): Promise<void>;
140
+ commandAdvanceRepeatMode(): Promise<void>;
141
+ commandBeginFastForward(): Promise<void>;
142
+ commandEndFastForward(): Promise<void>;
143
+ commandBeginRewind(): Promise<void>;
144
+ commandEndRewind(): Promise<void>;
126
145
  commandNextChapter(): Promise<void>;
127
146
  commandPreviousChapter(): Promise<void>;
147
+ commandLikeTrack(): Promise<void>;
148
+ commandDislikeTrack(): Promise<void>;
149
+ commandBookmarkTrack(): Promise<void>;
150
+ commandAddNowPlayingItemToLibrary(): Promise<void>;
128
151
  tap(x: number, y: number, finger?: number): Promise<void>;
129
152
  swipeUp(duration?: number): Promise<void>;
130
153
  swipeDown(duration?: number): Promise<void>;
@@ -363,4 +386,4 @@ declare class export_default$6 extends export_default$8 {}
363
386
  //#region src/model/homepod-mini.d.ts
364
387
  declare class export_default$7 extends export_default$8 {}
365
388
  //#endregion
366
- export { PROTOCOL as AIRPLAY, Client as AirPlayClient, export_default as AirPlayDevice, Player as AirPlayPlayer, export_default$1 as AirPlayRemote, export_default$2 as AirPlayState, export_default$3 as AirPlayVolume, export_default$4 as AppleTV, PROTOCOL$1 as COMPANION_LINK, export_default$5 as CompanionLinkDevice, export_default$6 as HomePod, export_default$7 as HomePodMini };
389
+ export { PROTOCOL as AIRPLAY, Client as AirPlayClient, export_default as AirPlayDevice, Player as AirPlayPlayer, export_default$1 as AirPlayRemote, export_default$2 as AirPlayState, export_default$3 as AirPlayVolume, export_default$4 as AppleTV, PROTOCOL$1 as COMPANION_LINK, export_default$5 as CompanionLinkDevice, export_default$6 as HomePod, export_default$7 as HomePodMini, SendCommandError };
package/dist/index.mjs CHANGED
@@ -30,6 +30,10 @@ var Player = class {
30
30
  return this.#playbackQueue;
31
31
  }
32
32
  get playbackState() {
33
+ if (this.#playbackState === Proto.PlaybackState_Enum.Playing && this.playbackRate === 0) return Proto.PlaybackState_Enum.Paused;
34
+ return this.#playbackState;
35
+ }
36
+ get rawPlaybackState() {
33
37
  return this.#playbackState;
34
38
  }
35
39
  get playbackStateTimestamp() {
@@ -83,8 +87,8 @@ var Player = class {
83
87
  get elapsedTime() {
84
88
  const npi = this.#nowPlayingInfo;
85
89
  const meta = this.currentItemMetadata;
86
- const npiValid = npi?.elapsedTime != null && npi.timestamp;
87
- const metaValid = meta?.elapsedTime != null && meta.elapsedTimeTimestamp;
90
+ const npiValid = npi?.elapsedTime != null && npi.timestamp != null && npi.timestamp !== 0;
91
+ const metaValid = meta?.elapsedTime != null && meta.elapsedTimeTimestamp != null && meta.elapsedTimeTimestamp !== 0;
88
92
  if (npiValid && metaValid) {
89
93
  if (meta.elapsedTimeTimestamp > npi.timestamp) return extrapolateElapsed(meta.elapsedTime, meta.elapsedTimeTimestamp, meta.playbackRate);
90
94
  return extrapolateElapsed(npi.elapsedTime, npi.timestamp, npi.playbackRate);
@@ -100,6 +104,25 @@ var Player = class {
100
104
  get currentItemMetadata() {
101
105
  return this.currentItem?.metadata ?? null;
102
106
  }
107
+ get artworkId() {
108
+ const metadata = this.currentItemMetadata;
109
+ if (!metadata) return null;
110
+ if (!metadata.artworkAvailable && !metadata.artworkURL && !metadata.artworkIdentifier) return null;
111
+ if (metadata.artworkIdentifier) return metadata.artworkIdentifier;
112
+ if (metadata.contentIdentifier) return metadata.contentIdentifier;
113
+ return this.currentItem?.identifier ?? null;
114
+ }
115
+ artworkUrl(width = 600, height = -1) {
116
+ const metadata = this.currentItemMetadata;
117
+ if (metadata?.artworkURL) return metadata.artworkURL;
118
+ const item = this.currentItem;
119
+ if (item?.remoteArtworks.length > 0 && item.remoteArtworks[0].artworkURLString) return item.remoteArtworks[0].artworkURLString;
120
+ if (metadata?.artworkIdentifier) try {
121
+ const url = metadata.artworkIdentifier.replace("{w}", String(width < 1 ? 999999 : width)).replace("{h}", String(height < 1 ? 999999 : height)).replace("{c}", "bb").replace("{f}", "png");
122
+ if (url.startsWith("http://") || url.startsWith("https://")) return url;
123
+ } catch {}
124
+ return null;
125
+ }
103
126
  get currentItemArtwork() {
104
127
  const item = this.currentItem;
105
128
  if (!item) return null;
@@ -108,11 +131,7 @@ var Player = class {
108
131
  return null;
109
132
  }
110
133
  get currentItemArtworkUrl() {
111
- const metadata = this.currentItemMetadata;
112
- if (metadata?.artworkURL) return metadata.artworkURL;
113
- const item = this.currentItem;
114
- if (item?.remoteArtworks.length > 0 && item.remoteArtworks[0].artworkURLString) return item.remoteArtworks[0].artworkURLString;
115
- return null;
134
+ return this.artworkUrl();
116
135
  }
117
136
  get currentItemLyrics() {
118
137
  return this.currentItem?.lyrics ?? null;
@@ -129,8 +148,12 @@ var Player = class {
129
148
  this.#displayName = displayName;
130
149
  this.#playbackState = Proto.PlaybackState_Enum.Unknown;
131
150
  }
151
+ findCommand(command) {
152
+ return this.#supportedCommands.find((c) => c.command === command) ?? null;
153
+ }
132
154
  isCommandSupported(command) {
133
- return this.#supportedCommands.some((c) => c.command === command);
155
+ const info = this.findCommand(command);
156
+ return info != null && info.enabled !== false;
134
157
  }
135
158
  setNowPlayingInfo(nowPlayingInfo) {
136
159
  this.#nowPlayingInfo = nowPlayingInfo;
@@ -172,8 +195,7 @@ var Client = class {
172
195
  return this.#players;
173
196
  }
174
197
  get activePlayer() {
175
- if (this.#activePlayerId) return this.#players.get(this.#activePlayerId) ?? null;
176
- return this.#players.get("MediaRemote-DefaultPlayer") ?? null;
198
+ return this.#players.get(this.#activePlayerId ?? "MediaRemote-DefaultPlayer") ?? null;
177
199
  }
178
200
  get nowPlayingInfo() {
179
201
  return this.activePlayer?.nowPlayingInfo ?? null;
@@ -188,7 +210,13 @@ var Client = class {
188
210
  return this.activePlayer?.playbackStateTimestamp ?? -1;
189
211
  }
190
212
  get supportedCommands() {
191
- return this.activePlayer?.supportedCommands ?? this.#defaultSupportedCommands;
213
+ const playerCommands = this.activePlayer?.supportedCommands ?? [];
214
+ if (playerCommands.length === 0) return this.#defaultSupportedCommands;
215
+ if (this.#defaultSupportedCommands.length === 0) return playerCommands;
216
+ const playerCommandSet = new Set(playerCommands.map((c) => c.command));
217
+ const merged = [...playerCommands];
218
+ for (const cmd of this.#defaultSupportedCommands) if (!playerCommandSet.has(cmd.command)) merged.push(cmd);
219
+ return merged;
192
220
  }
193
221
  get title() {
194
222
  return this.activePlayer?.title ?? "";
@@ -235,6 +263,12 @@ var Client = class {
235
263
  get elapsedTime() {
236
264
  return this.activePlayer?.elapsedTime ?? 0;
237
265
  }
266
+ get artworkId() {
267
+ return this.activePlayer?.artworkId ?? null;
268
+ }
269
+ artworkUrl(width = 600, height = -1) {
270
+ return this.activePlayer?.artworkUrl(width, height) ?? null;
271
+ }
238
272
  get currentItem() {
239
273
  return this.activePlayer?.currentItem ?? null;
240
274
  }
@@ -277,8 +311,17 @@ var Client = class {
277
311
  setDefaultSupportedCommands(supportedCommands) {
278
312
  this.#defaultSupportedCommands = supportedCommands;
279
313
  }
314
+ findCommand(command) {
315
+ const playerCmd = this.activePlayer?.findCommand(command) ?? null;
316
+ if (playerCmd) return playerCmd;
317
+ return this.#defaultSupportedCommands.find((c) => c.command === command) ?? null;
318
+ }
280
319
  isCommandSupported(command) {
281
- return this.activePlayer?.isCommandSupported(command) ?? false;
320
+ const info = this.findCommand(command);
321
+ return info != null && info.enabled !== false;
322
+ }
323
+ updateDisplayName(displayName) {
324
+ this.#displayName = displayName;
282
325
  }
283
326
  };
284
327
 
@@ -291,6 +334,16 @@ const STATE_UNSUBSCRIBE_SYMBOL = Symbol("com.basmilius.airplay:unsubscribe");
291
334
 
292
335
  //#endregion
293
336
  //#region src/airplay/remote.ts
337
+ var SendCommandError = class extends Error {
338
+ sendError;
339
+ handlerReturnStatus;
340
+ constructor(sendError, handlerReturnStatus) {
341
+ super(`SendCommand failed: sendError=${Proto.SendError_Enum[sendError]}, handlerReturnStatus=${Proto.HandlerReturnStatus_Enum[handlerReturnStatus]}`);
342
+ this.name = "SendCommandError";
343
+ this.sendError = sendError;
344
+ this.handlerReturnStatus = handlerReturnStatus;
345
+ }
346
+ };
294
347
  var remote_default = class {
295
348
  get #dataStream() {
296
349
  return this.#protocol.dataStream;
@@ -373,22 +426,40 @@ var remote_default = class {
373
426
  await this.#sendCommand(Proto.Command.PreviousTrack);
374
427
  }
375
428
  async commandSkipForward(interval = 15) {
376
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithSkipInterval(Proto.Command.SkipForward, interval));
429
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithSkipInterval(Proto.Command.SkipForward, interval));
377
430
  }
378
431
  async commandSkipBackward(interval = 15) {
379
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithSkipInterval(Proto.Command.SkipBackward, interval));
432
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithSkipInterval(Proto.Command.SkipBackward, interval));
380
433
  }
381
434
  async commandSeekToPosition(position) {
382
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithPlaybackPosition(Proto.Command.SeekToPlaybackPosition, position));
435
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithPlaybackPosition(Proto.Command.SeekToPlaybackPosition, position));
383
436
  }
384
437
  async commandSetShuffleMode(mode) {
385
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithShuffleMode(Proto.Command.ChangeShuffleMode, mode));
438
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithShuffleMode(Proto.Command.ChangeShuffleMode, mode));
386
439
  }
387
440
  async commandSetRepeatMode(mode) {
388
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithRepeatMode(Proto.Command.ChangeRepeatMode, mode));
441
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithRepeatMode(Proto.Command.ChangeRepeatMode, mode));
389
442
  }
390
443
  async commandChangePlaybackRate(rate) {
391
- await this.#dataStream.exchange(DataStreamMessage.sendCommandWithPlaybackRate(Proto.Command.ChangePlaybackRate, rate));
444
+ await this.#sendCommandRaw(DataStreamMessage.sendCommandWithPlaybackRate(Proto.Command.ChangePlaybackRate, rate));
445
+ }
446
+ async commandAdvanceShuffleMode() {
447
+ await this.#sendCommand(Proto.Command.AdvanceShuffleMode);
448
+ }
449
+ async commandAdvanceRepeatMode() {
450
+ await this.#sendCommand(Proto.Command.AdvanceRepeatMode);
451
+ }
452
+ async commandBeginFastForward() {
453
+ await this.#sendCommand(Proto.Command.BeginFastForward);
454
+ }
455
+ async commandEndFastForward() {
456
+ await this.#sendCommand(Proto.Command.EndFastForward);
457
+ }
458
+ async commandBeginRewind() {
459
+ await this.#sendCommand(Proto.Command.BeginRewind);
460
+ }
461
+ async commandEndRewind() {
462
+ await this.#sendCommand(Proto.Command.EndRewind);
392
463
  }
393
464
  async commandNextChapter() {
394
465
  await this.#sendCommand(Proto.Command.NextChapter);
@@ -396,6 +467,18 @@ var remote_default = class {
396
467
  async commandPreviousChapter() {
397
468
  await this.#sendCommand(Proto.Command.PreviousChapter);
398
469
  }
470
+ async commandLikeTrack() {
471
+ await this.#sendCommand(Proto.Command.LikeTrack);
472
+ }
473
+ async commandDislikeTrack() {
474
+ await this.#sendCommand(Proto.Command.DislikeTrack);
475
+ }
476
+ async commandBookmarkTrack() {
477
+ await this.#sendCommand(Proto.Command.BookmarkTrack);
478
+ }
479
+ async commandAddNowPlayingItemToLibrary() {
480
+ await this.#sendCommand(Proto.Command.AddNowPlayingItemToLibrary);
481
+ }
399
482
  async tap(x, y, finger = 1) {
400
483
  await this.#sendTouch(x, y, 1, finger);
401
484
  await waitFor(50);
@@ -429,7 +512,17 @@ var remote_default = class {
429
512
  await this.#dataStream.exchange(DataStreamMessage.sendHIDEvent(usePage, usage, false));
430
513
  }
431
514
  async #sendCommand(command, options) {
432
- await this.#dataStream.exchange(DataStreamMessage.sendCommand(command, options));
515
+ const response = await this.#dataStream.exchange(DataStreamMessage.sendCommand(command, options));
516
+ return this.#checkCommandResult(response);
517
+ }
518
+ async #sendCommandRaw(message) {
519
+ const response = await this.#dataStream.exchange(message);
520
+ return this.#checkCommandResult(response);
521
+ }
522
+ #checkCommandResult(response) {
523
+ const result = DataStreamMessage.getExtension(response, Proto.sendCommandResultMessage);
524
+ if (result.sendError !== Proto.SendError_Enum.NoError) throw new SendCommandError(result.sendError, result.handlerReturnStatus);
525
+ return result;
433
526
  }
434
527
  async #sendTouch(x, y, phase, finger) {
435
528
  await this.#dataStream.exchange(DataStreamMessage.sendVirtualTouchEvent(x, y, phase, finger));
@@ -570,15 +663,11 @@ var state_default = class extends EventEmitter {
570
663
  this.#volumeCapabilities = Proto.VolumeCapabilities_Enum.None;
571
664
  }
572
665
  onDeviceInfo(message) {
573
- if (message.clusterID) this.#outputDeviceUID = message.clusterID;
574
- else if (message.deviceUID) this.#outputDeviceUID = message.deviceUID;
575
- else if (message.uniqueIdentifier) this.#outputDeviceUID = message.uniqueIdentifier;
666
+ this.#updateOutputDeviceUID(message);
576
667
  this.emit("deviceInfo", message);
577
668
  }
578
669
  onDeviceInfoUpdate(message) {
579
- if (message.clusterID) this.#outputDeviceUID = message.clusterID;
580
- else if (message.deviceUID) this.#outputDeviceUID = message.deviceUID;
581
- else if (message.uniqueIdentifier) this.#outputDeviceUID = message.uniqueIdentifier;
670
+ this.#updateOutputDeviceUID(message);
582
671
  this.emit("deviceInfoUpdate", message);
583
672
  }
584
673
  onOriginClientProperties(message) {
@@ -608,6 +697,7 @@ var state_default = class extends EventEmitter {
608
697
  }
609
698
  onSetNowPlayingClient(message) {
610
699
  this.#nowPlayingClientBundleIdentifier = message.client?.bundleIdentifier ?? null;
700
+ if (message.client?.bundleIdentifier && message.client?.displayName) this.#client(message.client.bundleIdentifier, message.client.displayName);
611
701
  this.emit("setNowPlayingClient", message);
612
702
  this.#emitNowPlayingChangedIfNeeded();
613
703
  }
@@ -678,9 +768,15 @@ var state_default = class extends EventEmitter {
678
768
  this.#volume = message.volume;
679
769
  this.emit("volumeDidChange", message.volume);
680
770
  }
771
+ #updateOutputDeviceUID(message) {
772
+ this.#outputDeviceUID = message.clusterID || message.deviceUID || message.uniqueIdentifier || null;
773
+ }
681
774
  #client(bundleIdentifier, displayName) {
682
- if (bundleIdentifier in this.#clients) return this.#clients[bundleIdentifier];
683
- else {
775
+ if (bundleIdentifier in this.#clients) {
776
+ const client = this.#clients[bundleIdentifier];
777
+ if (displayName) client.updateDisplayName(displayName);
778
+ return client;
779
+ } else {
684
780
  const client = new Client(bundleIdentifier, displayName);
685
781
  this.#clients[bundleIdentifier] = client;
686
782
  this.emit("clients", this.#clients);
@@ -705,7 +801,10 @@ var state_default = class extends EventEmitter {
705
801
  seriesName: player?.seriesName ?? "",
706
802
  seasonNumber: player?.seasonNumber ?? 0,
707
803
  episodeNumber: player?.episodeNumber ?? 0,
708
- contentIdentifier: player?.contentIdentifier ?? ""
804
+ contentIdentifier: player?.contentIdentifier ?? "",
805
+ artworkId: player?.artworkId ?? null,
806
+ hasArtworkUrl: player?.artworkUrl() != null,
807
+ hasArtworkData: player?.currentItemArtwork != null
709
808
  };
710
809
  }
711
810
  #emitNowPlayingChangedIfNeeded() {
@@ -717,7 +816,7 @@ var state_default = class extends EventEmitter {
717
816
  this.emit("nowPlayingChanged", client, client?.activePlayer ?? null);
718
817
  }
719
818
  #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;
819
+ 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 && a.artworkId === b.artworkId && a.hasArtworkUrl === b.hasArtworkUrl && a.hasArtworkData === b.hasArtworkData;
721
820
  }
722
821
  };
723
822
 
@@ -851,7 +950,9 @@ var device_default = class extends EventEmitter {
851
950
  disconnectSafely() {
852
951
  try {
853
952
  this.disconnect();
854
- } catch (_) {}
953
+ } catch (err) {
954
+ this.#protocol?.context?.logger?.warn("[device]", "Error during safe disconnect", err);
955
+ }
855
956
  }
856
957
  async addOutputDevices(deviceUIDs) {
857
958
  await this.#protocol.dataStream.exchange(DataStreamMessage.modifyOutputContext(deviceUIDs));
@@ -900,21 +1001,26 @@ var device_default = class extends EventEmitter {
900
1001
  this.#protocol.controlStream.enableEncryption(keys.accessoryToControllerKey, keys.controllerToAccessoryKey);
901
1002
  this.#unsubscribe();
902
1003
  if (this.#timingServer) this.#protocol.useTimingServer(this.#timingServer);
903
- await this.#protocol.setupEventStream(keys.sharedSecret, keys.pairingId);
904
- await this.#protocol.setupDataStream(keys.sharedSecret, () => this.#subscribe());
905
- this.#protocol.dataStream.on("error", this.#onError.bind(this));
906
- this.#protocol.dataStream.on("timeout", this.#onTimeout.bind(this));
907
- this.#protocol.eventStream.on("error", this.#onError.bind(this));
908
- this.#protocol.eventStream.on("timeout", this.#onTimeout.bind(this));
909
- this.#feedbackInterval = setInterval(async () => await this.#feedback(), FEEDBACK_INTERVAL);
910
1004
  try {
1005
+ await this.#protocol.setupEventStream(keys.sharedSecret, keys.pairingId);
1006
+ await this.#protocol.setupDataStream(keys.sharedSecret, () => this.#subscribe());
1007
+ this.#protocol.dataStream.on("error", this.#onError.bind(this));
1008
+ this.#protocol.dataStream.on("timeout", this.#onTimeout.bind(this));
1009
+ this.#protocol.eventStream.on("error", this.#onError.bind(this));
1010
+ this.#protocol.eventStream.on("timeout", this.#onTimeout.bind(this));
1011
+ if (this.#feedbackInterval) clearInterval(this.#feedbackInterval);
1012
+ this.#feedbackInterval = setInterval(async () => await this.#feedback(), FEEDBACK_INTERVAL);
911
1013
  await this.#protocol.dataStream.exchange(DataStreamMessage.deviceInfo(keys.pairingId));
912
1014
  await this.#protocol.dataStream.exchange(DataStreamMessage.setConnectionState());
913
1015
  await this.#protocol.dataStream.exchange(DataStreamMessage.clientUpdatesConfig());
914
1016
  this.#protocol.context.logger.info("Protocol ready.");
915
1017
  } catch (err) {
916
- clearInterval(this.#feedbackInterval);
917
- this.#feedbackInterval = void 0;
1018
+ if (this.#feedbackInterval) {
1019
+ clearInterval(this.#feedbackInterval);
1020
+ this.#feedbackInterval = void 0;
1021
+ }
1022
+ this.#protocol.context.logger.error("[device]", "Setup failed, cleaning up", err);
1023
+ this.#protocol.disconnect();
918
1024
  throw err;
919
1025
  }
920
1026
  }
@@ -1354,4 +1460,4 @@ var homepod_default = class extends homepod_base_default {};
1354
1460
  var homepod_mini_default = class extends homepod_base_default {};
1355
1461
 
1356
1462
  //#endregion
1357
- export { PROTOCOL as AIRPLAY, Client as AirPlayClient, device_default as AirPlayDevice, Player as AirPlayPlayer, remote_default as AirPlayRemote, state_default as AirPlayState, volume_default as AirPlayVolume, apple_tv_default as AppleTV, PROTOCOL$1 as COMPANION_LINK, device_default$1 as CompanionLinkDevice, homepod_default as HomePod, homepod_mini_default as HomePodMini };
1463
+ export { PROTOCOL as AIRPLAY, Client as AirPlayClient, device_default as AirPlayDevice, Player as AirPlayPlayer, remote_default as AirPlayRemote, state_default as AirPlayState, volume_default as AirPlayVolume, apple_tv_default as AppleTV, PROTOCOL$1 as COMPANION_LINK, device_default$1 as CompanionLinkDevice, homepod_default as HomePod, homepod_mini_default as HomePodMini, SendCommandError };
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.15",
4
+ "version": "0.9.17",
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.15",
53
- "@basmilius/apple-common": "0.9.15",
54
- "@basmilius/apple-companion-link": "0.9.15",
55
- "@basmilius/apple-encoding": "0.9.15"
52
+ "@basmilius/apple-airplay": "0.9.17",
53
+ "@basmilius/apple-common": "0.9.17",
54
+ "@basmilius/apple-companion-link": "0.9.17",
55
+ "@basmilius/apple-encoding": "0.9.17"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/bun": "^1.3.11",