@gentomiyano/optimized-web-audio-player 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useId, useEffect } from 'react';
1
+ import { useState, useRef, useId, useEffect, useMemo } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  // src/ui/player-primitives.tsx
@@ -174,6 +174,8 @@ function getErrorMessage(error) {
174
174
  return "This media could not be decoded.";
175
175
  case "unsupported":
176
176
  return "This media format is not supported.";
177
+ case "seek":
178
+ return "Seeking failed. Try again.";
177
179
  case "audio-context":
178
180
  return "Audio output is not available.";
179
181
  case "unknown":
@@ -293,6 +295,9 @@ function TrackMetadata({
293
295
  scrollTitle = false,
294
296
  status
295
297
  }) {
298
+ const intrinsicContext = item?.contentContext;
299
+ const creatorName = item?.creatorName ?? (intrinsicContext?.sourceType === "release-track" ? intrinsicContext.artistName : void 0);
300
+ const collectionTitle = item?.collectionTitle ?? (intrinsicContext?.sourceType === "release-track" ? intrinsicContext.releaseTitle : intrinsicContext?.sourceType === "podcast-episode" ? intrinsicContext.programTitle : void 0);
296
301
  return /* @__PURE__ */ jsxs(
297
302
  "div",
298
303
  {
@@ -307,8 +312,8 @@ function TrackMetadata({
307
312
  },
308
313
  item?.title ?? "No media selected"
309
314
  ),
310
- /* @__PURE__ */ jsx("span", { className: "player-creator", children: item === null ? "Select media to begin" : item.creatorName ?? "Artist unavailable" }),
311
- item?.collectionTitle === void 0 ? null : /* @__PURE__ */ jsx("span", { className: "player-collection", children: item.collectionTitle })
315
+ /* @__PURE__ */ jsx("span", { className: "player-creator", children: item === null ? "Select media to begin" : creatorName ?? "Artist unavailable" }),
316
+ collectionTitle === void 0 ? null : /* @__PURE__ */ jsx("span", { className: "player-collection", children: collectionTitle })
312
317
  ]
313
318
  }
314
319
  );
@@ -724,59 +729,84 @@ function Waveform({
724
729
  }
725
730
  );
726
731
  }
727
- function CompactPlayer({
732
+ function CompactPlayerLayout({
728
733
  appearance,
729
734
  className,
730
- commands,
731
- state
735
+ contextId,
736
+ contextMode,
737
+ currentTimeSec,
738
+ durationSec,
739
+ errorNotice,
740
+ isActive,
741
+ isPlaying,
742
+ item,
743
+ label,
744
+ primaryControl,
745
+ queueItemId,
746
+ runtimeStatus,
747
+ seekControl,
748
+ status,
749
+ trailingControl,
750
+ waveformOpacity,
751
+ waveformPlayedStateEnabled
732
752
  }) {
733
- const progress = state.durationSec === null || state.durationSec <= 0 ? 0 : state.currentTimeSec / state.durationSec;
753
+ const progress = durationSec === null || durationSec <= 0 ? 0 : currentTimeSec / durationSec;
734
754
  return /* @__PURE__ */ jsxs(
735
755
  PlayerSurface,
736
756
  {
737
757
  appearance,
738
758
  className: ["player-compact", className].filter(Boolean).join(" "),
739
- label: "Compact music player",
759
+ label,
740
760
  children: [
741
- /* @__PURE__ */ jsxs("div", { className: "player-compact__main", children: [
742
- /* @__PURE__ */ jsx(PrimaryPlaybackButton, { commands, state }),
743
- /* @__PURE__ */ jsx(Artwork, { className: "player-compact__artwork", item: state.currentItem }),
744
- /* @__PURE__ */ jsx(
745
- TrackMetadata,
746
- {
747
- item: state.currentItem,
748
- scrollTitle: state.status === "playing"
749
- }
750
- ),
751
- /* @__PURE__ */ jsxs("div", { className: "player-compact__signal", children: [
752
- /* @__PURE__ */ jsx(PlayerStatus, { state }),
753
- /* @__PURE__ */ jsx(
754
- Waveform,
755
- {
756
- opacity: state.experienceConfig.waveformOpacity,
757
- playedStateEnabled: state.experienceConfig.waveformPlayedStateEnabled,
758
- progress,
759
- waveform: state.currentItem?.waveform
760
- }
761
- ),
762
- /* @__PURE__ */ jsx(
763
- TimeReadout,
764
- {
765
- currentTimeSec: state.currentTimeSec,
766
- durationSec: state.durationSec
767
- }
768
- )
769
- ] }),
770
- /* @__PURE__ */ jsx(
771
- PopoverVolumeControl,
772
- {
773
- commands,
774
- label: "Compact volume",
775
- state
776
- }
777
- )
778
- ] }),
779
- /* @__PURE__ */ jsx(PlayerErrorNotice, { commands, state })
761
+ /* @__PURE__ */ jsxs(
762
+ "div",
763
+ {
764
+ className: "player-compact__main",
765
+ ...isActive === void 0 ? {} : { "data-active": isActive ? "true" : "false" },
766
+ "data-has-status": status === void 0 ? "false" : "true",
767
+ "data-has-trailing-control": trailingControl === void 0 ? "false" : "true",
768
+ "data-playback-context-id": contextId,
769
+ "data-playback-context-mode": contextMode,
770
+ "data-player-runtime-status": runtimeStatus,
771
+ "data-queue-item-id": queueItemId,
772
+ children: [
773
+ primaryControl,
774
+ /* @__PURE__ */ jsx(Artwork, { className: "player-compact__artwork", item }),
775
+ /* @__PURE__ */ jsx(TrackMetadata, { item, scrollTitle: isPlaying }),
776
+ /* @__PURE__ */ jsxs("div", { className: "player-compact__signal", children: [
777
+ status,
778
+ /* @__PURE__ */ jsxs(
779
+ "div",
780
+ {
781
+ className: "player-compact__scrubber",
782
+ "data-seek-enabled": seekControl === void 0 ? "false" : "true",
783
+ children: [
784
+ /* @__PURE__ */ jsx(
785
+ Waveform,
786
+ {
787
+ opacity: waveformOpacity,
788
+ playedStateEnabled: waveformPlayedStateEnabled,
789
+ progress,
790
+ waveform: item?.waveform
791
+ }
792
+ ),
793
+ seekControl
794
+ ]
795
+ }
796
+ ),
797
+ /* @__PURE__ */ jsx(
798
+ TimeReadout,
799
+ {
800
+ currentTimeSec,
801
+ durationSec
802
+ }
803
+ )
804
+ ] }),
805
+ trailingControl
806
+ ]
807
+ }
808
+ ),
809
+ errorNotice
780
810
  ]
781
811
  }
782
812
  );
@@ -875,6 +905,52 @@ function SeekBar({
875
905
  }
876
906
  );
877
907
  }
908
+ function CompactPlayer({
909
+ appearance,
910
+ className,
911
+ commands,
912
+ state
913
+ }) {
914
+ return /* @__PURE__ */ jsx(
915
+ CompactPlayerLayout,
916
+ {
917
+ appearance,
918
+ ...className === void 0 ? {} : { className },
919
+ currentTimeSec: state.currentTimeSec,
920
+ durationSec: state.durationSec,
921
+ errorNotice: /* @__PURE__ */ jsx(PlayerErrorNotice, { commands, state }),
922
+ isPlaying: state.status === "playing",
923
+ item: state.currentItem,
924
+ label: "Compact music player",
925
+ primaryControl: /* @__PURE__ */ jsx(PrimaryPlaybackButton, { commands, state }),
926
+ seekControl: /* @__PURE__ */ jsx(
927
+ SeekBar,
928
+ {
929
+ canSeek: state.canSeek,
930
+ commitMode: state.experienceConfig.seekCommitMode,
931
+ currentTimeSec: state.currentTimeSec,
932
+ durationSec: state.durationSec,
933
+ label: `Seek in ${state.currentItem?.title ?? "current media"}`,
934
+ onSeek: (seconds) => {
935
+ commands.seekTo(seconds);
936
+ },
937
+ status: state.status
938
+ }
939
+ ),
940
+ status: /* @__PURE__ */ jsx(PlayerStatus, { state }),
941
+ trailingControl: /* @__PURE__ */ jsx(
942
+ PopoverVolumeControl,
943
+ {
944
+ commands,
945
+ label: "Compact volume",
946
+ state
947
+ }
948
+ ),
949
+ waveformOpacity: state.experienceConfig.waveformOpacity,
950
+ waveformPlayedStateEnabled: state.experienceConfig.waveformPlayedStateEnabled
951
+ }
952
+ );
953
+ }
878
954
  function BoundCompactPlayerView({
879
955
  appearance,
880
956
  className,
@@ -885,77 +961,48 @@ function BoundCompactPlayerView({
885
961
  runtimeStatus,
886
962
  state
887
963
  }) {
888
- const progress = state.durationSec === null || state.durationSec <= 0 ? 0 : state.currentTimeSec / state.durationSec;
889
964
  return /* @__PURE__ */ jsx(
890
- PlayerSurface,
965
+ CompactPlayerLayout,
891
966
  {
892
967
  appearance,
893
- className: ["player-bound-compact", className].filter(Boolean).join(" "),
968
+ ...className === void 0 ? {} : { className },
969
+ ...contextId === void 0 ? {} : { contextId },
970
+ ...contextMode === void 0 ? {} : { contextMode },
971
+ currentTimeSec: state.currentTimeSec,
972
+ durationSec: state.durationSec,
973
+ isActive: state.isActive,
974
+ isPlaying: state.isPlaying,
975
+ item: state.item,
894
976
  label: `Inline player: ${state.item.title}`,
895
- children: /* @__PURE__ */ jsxs(
896
- "div",
977
+ primaryControl: /* @__PURE__ */ jsx(
978
+ IconButton,
897
979
  {
898
- className: "player-bound-compact__main",
899
- "data-active": state.isActive ? "true" : "false",
900
- "data-playback-context-id": contextId,
901
- "data-playback-context-mode": contextMode,
902
- "data-player-runtime-status": runtimeStatus,
903
- "data-queue-item-id": state.queueItemId,
904
- children: [
905
- /* @__PURE__ */ jsx(
906
- IconButton,
907
- {
908
- className: "player-play-button",
909
- label: state.isPlaying ? "Pause" : "Play",
910
- onClick: () => {
911
- void commands.togglePlayback();
912
- },
913
- children: state.isPlaying ? /* @__PURE__ */ jsx(PauseIcon, { size: 22 }) : /* @__PURE__ */ jsx(PlayIcon, { size: 22 })
914
- }
915
- ),
916
- /* @__PURE__ */ jsx(
917
- Artwork,
918
- {
919
- className: "player-bound-compact__artwork",
920
- item: state.item
921
- }
922
- ),
923
- /* @__PURE__ */ jsx(TrackMetadata, { item: state.item, scrollTitle: state.isPlaying }),
924
- /* @__PURE__ */ jsxs("div", { className: "player-bound-compact__signal", children: [
925
- /* @__PURE__ */ jsx(
926
- Waveform,
927
- {
928
- opacity: options.waveformOpacity,
929
- playedStateEnabled: options.waveformPlayedStateEnabled,
930
- progress,
931
- waveform: state.item.waveform
932
- }
933
- ),
934
- /* @__PURE__ */ jsx(
935
- TimeReadout,
936
- {
937
- currentTimeSec: state.currentTimeSec,
938
- durationSec: state.durationSec
939
- }
940
- )
941
- ] }),
942
- /* @__PURE__ */ jsx(
943
- SeekBar,
944
- {
945
- canSeek: state.canSeek,
946
- commitMode: options.seekCommitMode,
947
- currentTimeSec: state.currentTimeSec,
948
- durationSec: state.durationSec,
949
- label: `Seek in ${state.item.title}`,
950
- onSeek: (seconds) => {
951
- commands.seekTo(seconds);
952
- },
953
- status: state.status
954
- }
955
- )
956
- ]
980
+ className: "player-play-button",
981
+ label: state.isPlaying ? "Pause" : "Play",
982
+ onClick: () => {
983
+ void commands.togglePlayback();
984
+ },
985
+ children: state.isPlaying ? /* @__PURE__ */ jsx(PauseIcon, { size: 22 }) : /* @__PURE__ */ jsx(PlayIcon, { size: 22 })
957
986
  }
958
- )
987
+ ),
988
+ queueItemId: state.queueItemId,
989
+ ...runtimeStatus === void 0 ? {} : { runtimeStatus },
990
+ seekControl: /* @__PURE__ */ jsx(
991
+ SeekBar,
992
+ {
993
+ canSeek: state.canSeek,
994
+ commitMode: options.seekCommitMode,
995
+ currentTimeSec: state.currentTimeSec,
996
+ durationSec: state.durationSec,
997
+ label: `Seek in ${state.item.title}`,
998
+ onSeek: (seconds) => {
999
+ commands.seekTo(seconds);
1000
+ },
1001
+ status: state.status
1002
+ }
1003
+ ),
1004
+ waveformOpacity: options.waveformOpacity,
1005
+ waveformPlayedStateEnabled: options.waveformPlayedStateEnabled
959
1006
  }
960
1007
  );
961
1008
  }
@@ -1092,6 +1139,747 @@ function DetailedPlayer({
1092
1139
  }
1093
1140
  );
1094
1141
  }
1142
+
1143
+ // src/consumer/content-context.ts
1144
+ function contentContextMatches(context, expected) {
1145
+ if (context?.sourceType !== expected.sourceType) {
1146
+ return false;
1147
+ }
1148
+ if (context.sourceType === "release-track") {
1149
+ return context.releaseId === expected.parentId && context.trackId === expected.entryId;
1150
+ }
1151
+ return context.programId === expected.parentId && context.episodeId === expected.entryId;
1152
+ }
1153
+ function buildIntrinsicContext(entries, contextId, label, expectedSourceType, parentId) {
1154
+ const queue = [];
1155
+ const rejected = [];
1156
+ const contentIds = /* @__PURE__ */ new Set();
1157
+ const queueItemIds = /* @__PURE__ */ new Set();
1158
+ entries.forEach((entry, entryIndex) => {
1159
+ if (contentIds.has(entry.id)) {
1160
+ rejected.push({
1161
+ entryId: entry.id,
1162
+ entryIndex,
1163
+ reason: "duplicate-content-id"
1164
+ });
1165
+ return;
1166
+ }
1167
+ contentIds.add(entry.id);
1168
+ if (entry.availability.state !== "ready") {
1169
+ if (entry.queueItem !== void 0) {
1170
+ rejected.push({
1171
+ entryId: entry.id,
1172
+ entryIndex,
1173
+ reason: "non-ready-with-queue-item"
1174
+ });
1175
+ }
1176
+ return;
1177
+ }
1178
+ if (entry.queueItem === void 0) {
1179
+ rejected.push({
1180
+ entryId: entry.id,
1181
+ entryIndex,
1182
+ reason: "ready-without-queue-item"
1183
+ });
1184
+ return;
1185
+ }
1186
+ if (queueItemIds.has(entry.queueItem.queueItemId)) {
1187
+ rejected.push({
1188
+ entryId: entry.id,
1189
+ entryIndex,
1190
+ reason: "duplicate-queue-item-id"
1191
+ });
1192
+ return;
1193
+ }
1194
+ if (!contentContextMatches(entry.queueItem.item.contentContext, {
1195
+ sourceType: expectedSourceType,
1196
+ parentId,
1197
+ entryId: entry.id
1198
+ })) {
1199
+ rejected.push({
1200
+ entryId: entry.id,
1201
+ entryIndex,
1202
+ reason: "content-context-mismatch"
1203
+ });
1204
+ return;
1205
+ }
1206
+ queueItemIds.add(entry.queueItem.queueItemId);
1207
+ queue.push(entry.queueItem);
1208
+ });
1209
+ return Object.freeze({
1210
+ context: Object.freeze({
1211
+ id: contextId,
1212
+ mode: "ordered-queue",
1213
+ label,
1214
+ queue: Object.freeze(queue)
1215
+ }),
1216
+ rejected: Object.freeze(
1217
+ rejected.map((rejection) => Object.freeze(rejection))
1218
+ )
1219
+ });
1220
+ }
1221
+ function buildReleasePlaybackContext(release) {
1222
+ return buildIntrinsicContext(
1223
+ release.tracks,
1224
+ release.contextId ?? `release:${release.id}`,
1225
+ release.title,
1226
+ "release-track",
1227
+ release.id
1228
+ );
1229
+ }
1230
+ function buildPodcastPlaybackContext(program) {
1231
+ return buildIntrinsicContext(
1232
+ program.episodes,
1233
+ program.contextId ?? `podcast:${program.id}`,
1234
+ program.title,
1235
+ "podcast-episode",
1236
+ program.id
1237
+ );
1238
+ }
1239
+ function findActivePodcastChapter(chapters, currentTimeSec) {
1240
+ if (chapters === void 0 || !Number.isFinite(currentTimeSec)) {
1241
+ return null;
1242
+ }
1243
+ let active = null;
1244
+ for (const chapter of chapters) {
1245
+ if (!Number.isFinite(chapter.startTimeSec) || chapter.startTimeSec < 0 || chapter.startTimeSec > currentTimeSec) {
1246
+ continue;
1247
+ }
1248
+ if (active === null || chapter.startTimeSec >= active.startTimeSec) {
1249
+ active = chapter;
1250
+ }
1251
+ }
1252
+ return active;
1253
+ }
1254
+ function ContentArtwork({
1255
+ alt,
1256
+ artwork,
1257
+ className
1258
+ }) {
1259
+ return /* @__PURE__ */ jsx(
1260
+ "span",
1261
+ {
1262
+ className: ["player-content__artwork", className].filter(Boolean).join(" "),
1263
+ children: artwork === void 0 ? /* @__PURE__ */ jsx("span", { "aria-label": `${alt} artwork unavailable`, role: "img" }) : /* @__PURE__ */ jsx("img", { alt: artwork.alt, src: artwork.url })
1264
+ }
1265
+ );
1266
+ }
1267
+ function availabilityLabel(state) {
1268
+ switch (state) {
1269
+ case "ready":
1270
+ return "Ready";
1271
+ case "processing":
1272
+ return "Processing";
1273
+ case "locked":
1274
+ return "Locked";
1275
+ case "failed":
1276
+ return "Unavailable";
1277
+ case "unavailable":
1278
+ return "Unavailable";
1279
+ }
1280
+ }
1281
+ function IntrinsicTransport({
1282
+ active,
1283
+ canStart,
1284
+ commands,
1285
+ onStart,
1286
+ state
1287
+ }) {
1288
+ const isPlaying = active && state.status === "playing";
1289
+ return /* @__PURE__ */ jsxs(
1290
+ "div",
1291
+ {
1292
+ "aria-label": "Content playback controls",
1293
+ className: "player-content__transport",
1294
+ role: "group",
1295
+ children: [
1296
+ /* @__PURE__ */ jsx(
1297
+ IconButton,
1298
+ {
1299
+ disabled: !active || !state.canGoPrevious,
1300
+ label: "Previous item",
1301
+ onClick: () => {
1302
+ void commands.previous();
1303
+ },
1304
+ children: /* @__PURE__ */ jsx(PreviousIcon, {})
1305
+ }
1306
+ ),
1307
+ /* @__PURE__ */ jsx(
1308
+ IconButton,
1309
+ {
1310
+ className: [
1311
+ "player-play-button",
1312
+ isPlaying ? "player-play-button--active" : ""
1313
+ ].filter(Boolean).join(" "),
1314
+ disabled: !canStart || active && state.status === "loading",
1315
+ label: isPlaying ? "Pause" : "Play",
1316
+ onClick: () => {
1317
+ if (active) {
1318
+ void commands.togglePlayback();
1319
+ } else {
1320
+ onStart();
1321
+ }
1322
+ },
1323
+ children: isPlaying ? /* @__PURE__ */ jsx(PauseIcon, { size: 22 }) : /* @__PURE__ */ jsx(PlayIcon, { size: 22 })
1324
+ }
1325
+ ),
1326
+ /* @__PURE__ */ jsx(
1327
+ IconButton,
1328
+ {
1329
+ disabled: !active || !state.canGoNext,
1330
+ label: "Next item",
1331
+ onClick: () => {
1332
+ void commands.next();
1333
+ },
1334
+ children: /* @__PURE__ */ jsx(NextIcon, {})
1335
+ }
1336
+ )
1337
+ ]
1338
+ }
1339
+ );
1340
+ }
1341
+ function activateIntrinsicItem(commands, context, queueItemId) {
1342
+ commands.setShuffle(false);
1343
+ commands.setRepeatMode("off");
1344
+ return commands.activateContext({
1345
+ contextId: context.id,
1346
+ mode: "ordered-queue",
1347
+ ...context.label === void 0 ? {} : { label: context.label },
1348
+ queue: context.queue,
1349
+ startQueueItemId: queueItemId,
1350
+ autoplay: true
1351
+ });
1352
+ }
1353
+ function useIntrinsicContextGuard(commands, context, state) {
1354
+ const nextQueueKey = context.queue.map((entry) => entry.queueItemId).join("\0");
1355
+ const activeQueueKey = state.activeContext?.queue.map((entry) => entry.queueItemId).join("\0");
1356
+ useEffect(() => {
1357
+ if (state.activeContext?.id !== context.id || state.currentQueueItemId === null) {
1358
+ return;
1359
+ }
1360
+ if (!context.queue.some(
1361
+ (entry) => entry.queueItemId === state.currentQueueItemId
1362
+ )) {
1363
+ void commands.clear();
1364
+ return;
1365
+ }
1366
+ if (activeQueueKey !== nextQueueKey) {
1367
+ commands.setShuffle(false);
1368
+ commands.setRepeatMode("off");
1369
+ void commands.activateContext({
1370
+ contextId: context.id,
1371
+ mode: "ordered-queue",
1372
+ ...context.label === void 0 ? {} : { label: context.label },
1373
+ queue: context.queue,
1374
+ startQueueItemId: state.currentQueueItemId,
1375
+ autoplay: state.status === "playing"
1376
+ });
1377
+ }
1378
+ }, [
1379
+ activeQueueKey,
1380
+ commands,
1381
+ context,
1382
+ nextQueueKey,
1383
+ state.activeContext?.id,
1384
+ state.currentQueueItemId,
1385
+ state.status
1386
+ ]);
1387
+ }
1388
+ function ReleasePlayer({
1389
+ appearance,
1390
+ className,
1391
+ commands,
1392
+ release,
1393
+ state
1394
+ }) {
1395
+ const build = useMemo(
1396
+ () => buildReleasePlaybackContext(release),
1397
+ [release]
1398
+ );
1399
+ const playableIds = new Set(
1400
+ build.context.queue.map((entry) => entry.queueItemId)
1401
+ );
1402
+ const active = state.activeContext?.id === build.context.id;
1403
+ useIntrinsicContextGuard(commands, build.context, state);
1404
+ const currentTrackId = active && state.currentItem?.contentContext?.sourceType === "release-track" ? state.currentItem.contentContext.trackId : null;
1405
+ const first = build.context.queue[0];
1406
+ const currentTrack = release.tracks.find((track) => track.id === currentTrackId) ?? release.tracks.find(
1407
+ (track) => track.queueItem?.queueItemId === first?.queueItemId
1408
+ ) ?? null;
1409
+ const displayItem = active ? state.currentItem : first?.item ?? null;
1410
+ const displayCurrentTimeSec = active ? state.currentTimeSec : 0;
1411
+ const displayDurationSec = active ? state.durationSec : displayItem?.durationHintSec ?? null;
1412
+ const waveformProgress = displayDurationSec === null || displayDurationSec <= 0 ? 0 : displayCurrentTimeSec / displayDurationSec;
1413
+ const playTrack = (track) => {
1414
+ if (track.queueItem === void 0 || !playableIds.has(track.queueItem.queueItemId)) {
1415
+ return;
1416
+ }
1417
+ void activateIntrinsicItem(
1418
+ commands,
1419
+ build.context,
1420
+ track.queueItem.queueItemId
1421
+ );
1422
+ };
1423
+ return /* @__PURE__ */ jsxs(
1424
+ PlayerSurface,
1425
+ {
1426
+ appearance,
1427
+ className: ["player-release", "player-content", className].filter(Boolean).join(" "),
1428
+ label: "Release player",
1429
+ children: [
1430
+ /* @__PURE__ */ jsxs("div", { className: "player-release__hero", children: [
1431
+ /* @__PURE__ */ jsx(
1432
+ ContentArtwork,
1433
+ {
1434
+ alt: release.title,
1435
+ artwork: release.artwork,
1436
+ className: "player-release__artwork"
1437
+ }
1438
+ ),
1439
+ /* @__PURE__ */ jsxs("div", { className: "player-release__detail", children: [
1440
+ /* @__PURE__ */ jsxs("header", { className: "player-release__identity", children: [
1441
+ /* @__PURE__ */ jsx("span", { className: "player-kicker", children: "Release" }),
1442
+ /* @__PURE__ */ jsx("h2", { children: release.title }),
1443
+ /* @__PURE__ */ jsx("p", { className: "player-release__artist", children: release.artistName }),
1444
+ release.releaseDate === void 0 && release.releaseType === void 0 ? null : /* @__PURE__ */ jsxs("dl", { className: "player-release__facts", children: [
1445
+ release.releaseDate === void 0 ? null : /* @__PURE__ */ jsxs("div", { children: [
1446
+ /* @__PURE__ */ jsx("dt", { children: "Released" }),
1447
+ /* @__PURE__ */ jsx("dd", { children: release.releaseDate })
1448
+ ] }),
1449
+ release.releaseType === void 0 ? null : /* @__PURE__ */ jsxs("div", { children: [
1450
+ /* @__PURE__ */ jsx("dt", { children: "Format" }),
1451
+ /* @__PURE__ */ jsx("dd", { children: release.releaseType })
1452
+ ] })
1453
+ ] })
1454
+ ] }),
1455
+ release.notes === void 0 ? null : /* @__PURE__ */ jsx("p", { className: "player-release__notes", children: release.notes }),
1456
+ release.credits === void 0 || release.credits.length === 0 ? null : /* @__PURE__ */ jsxs("div", { className: "player-release__credits", children: [
1457
+ /* @__PURE__ */ jsx("span", { children: "Credits" }),
1458
+ /* @__PURE__ */ jsx("ul", { children: release.credits.map((credit) => /* @__PURE__ */ jsx("li", { children: credit }, credit)) })
1459
+ ] }),
1460
+ /* @__PURE__ */ jsxs(
1461
+ "section",
1462
+ {
1463
+ "aria-label": "Current Release Track",
1464
+ className: "player-release__playback",
1465
+ children: [
1466
+ /* @__PURE__ */ jsxs("div", { className: "player-release__now-playing", children: [
1467
+ /* @__PURE__ */ jsx("span", { children: "Current Track" }),
1468
+ /* @__PURE__ */ jsx("strong", { children: currentTrack === null ? "No playable Tracks" : currentTrack.title }),
1469
+ active ? /* @__PURE__ */ jsx(PlayerStatus, { state }) : null
1470
+ ] }),
1471
+ /* @__PURE__ */ jsxs("div", { className: "player-release__signal", children: [
1472
+ /* @__PURE__ */ jsx(
1473
+ Waveform,
1474
+ {
1475
+ opacity: state.experienceConfig.waveformOpacity,
1476
+ playedStateEnabled: state.experienceConfig.waveformPlayedStateEnabled,
1477
+ progress: waveformProgress,
1478
+ waveform: displayItem?.waveform
1479
+ }
1480
+ ),
1481
+ /* @__PURE__ */ jsx(
1482
+ SeekBar,
1483
+ {
1484
+ canSeek: active && state.canSeek,
1485
+ commitMode: state.experienceConfig.seekCommitMode,
1486
+ currentTimeSec: displayCurrentTimeSec,
1487
+ durationSec: displayDurationSec,
1488
+ label: "Seek in current Release Track",
1489
+ onSeek: (seconds) => {
1490
+ commands.seekTo(seconds);
1491
+ },
1492
+ status: active ? state.status : "paused"
1493
+ }
1494
+ ),
1495
+ /* @__PURE__ */ jsx(
1496
+ TimeReadout,
1497
+ {
1498
+ currentTimeSec: displayCurrentTimeSec,
1499
+ durationSec: displayDurationSec
1500
+ }
1501
+ )
1502
+ ] }),
1503
+ /* @__PURE__ */ jsx(
1504
+ IntrinsicTransport,
1505
+ {
1506
+ active,
1507
+ canStart: first !== void 0,
1508
+ commands,
1509
+ onStart: () => {
1510
+ if (first !== void 0) {
1511
+ void activateIntrinsicItem(
1512
+ commands,
1513
+ build.context,
1514
+ first.queueItemId
1515
+ );
1516
+ }
1517
+ },
1518
+ state
1519
+ }
1520
+ )
1521
+ ]
1522
+ }
1523
+ )
1524
+ ] })
1525
+ ] }),
1526
+ /* @__PURE__ */ jsxs(
1527
+ "section",
1528
+ {
1529
+ "aria-labelledby": `release-tracklist-${release.id}`,
1530
+ className: "player-release__tracklist",
1531
+ children: [
1532
+ /* @__PURE__ */ jsxs("div", { className: "player-section-heading", children: [
1533
+ /* @__PURE__ */ jsx("span", { id: `release-tracklist-${release.id}`, children: "Tracklist" }),
1534
+ /* @__PURE__ */ jsxs("span", { className: "player-queue-count", children: [
1535
+ String(release.tracks.length),
1536
+ " tracks"
1537
+ ] })
1538
+ ] }),
1539
+ release.tracks.length === 0 ? /* @__PURE__ */ jsx("p", { className: "player-empty", children: "Tracklist is empty." }) : /* @__PURE__ */ jsx("ol", { className: "player-content__list", children: release.tracks.map((track, index) => {
1540
+ const playable = track.queueItem !== void 0 && playableIds.has(track.queueItem.queueItemId);
1541
+ const isCurrent = track.id === currentTrackId;
1542
+ return /* @__PURE__ */ jsx(
1543
+ "li",
1544
+ {
1545
+ "data-availability": track.availability.state,
1546
+ "data-current": isCurrent ? "true" : "false",
1547
+ children: /* @__PURE__ */ jsxs(
1548
+ "button",
1549
+ {
1550
+ "aria-current": isCurrent ? "true" : void 0,
1551
+ "aria-label": playable ? `Play track ${track.title}` : `${track.title}: ${availabilityLabel(track.availability.state)}`,
1552
+ disabled: !playable,
1553
+ onClick: () => {
1554
+ playTrack(track);
1555
+ },
1556
+ type: "button",
1557
+ children: [
1558
+ /* @__PURE__ */ jsx("span", { className: "player-queue-number", children: String(track.trackNumber ?? index + 1).padStart(2, "0") }),
1559
+ /* @__PURE__ */ jsxs("span", { className: "player-content__entry-copy", children: [
1560
+ /* @__PURE__ */ jsx("strong", { children: track.title }),
1561
+ /* @__PURE__ */ jsx("small", { children: availabilityLabel(track.availability.state) })
1562
+ ] }),
1563
+ /* @__PURE__ */ jsx("time", { children: formatTime(track.durationHintSec ?? null) })
1564
+ ]
1565
+ }
1566
+ )
1567
+ },
1568
+ `${track.id}:${String(index)}`
1569
+ );
1570
+ }) })
1571
+ ]
1572
+ }
1573
+ ),
1574
+ /* @__PURE__ */ jsx(PlayerErrorNotice, { commands, state })
1575
+ ]
1576
+ }
1577
+ );
1578
+ }
1579
+ function PodcastProgramPlayer({
1580
+ appearance,
1581
+ className,
1582
+ commands,
1583
+ program,
1584
+ state
1585
+ }) {
1586
+ const build = useMemo(
1587
+ () => buildPodcastPlaybackContext(program),
1588
+ [program]
1589
+ );
1590
+ const playableIds = new Set(
1591
+ build.context.queue.map((entry) => entry.queueItemId)
1592
+ );
1593
+ const active = state.activeContext?.id === build.context.id;
1594
+ useIntrinsicContextGuard(commands, build.context, state);
1595
+ const currentEpisodeId = active && state.currentItem?.contentContext?.sourceType === "podcast-episode" ? state.currentItem.contentContext.episodeId : null;
1596
+ const currentEpisode = program.episodes.find((episode) => episode.id === currentEpisodeId) ?? null;
1597
+ const first = build.context.queue[0];
1598
+ const displayEpisode = currentEpisode ?? program.episodes.find(
1599
+ (episode) => episode.queueItem?.queueItemId === first?.queueItemId
1600
+ ) ?? null;
1601
+ const selectedEpisodeId = displayEpisode?.id ?? null;
1602
+ const displayItem = active ? state.currentItem : first?.item ?? null;
1603
+ const displayCurrentTimeSec = active ? state.currentTimeSec : 0;
1604
+ const displayDurationSec = active ? state.durationSec : displayEpisode?.durationHintSec ?? displayItem?.durationHintSec ?? null;
1605
+ const waveformProgress = displayDurationSec === null || displayDurationSec <= 0 ? 0 : displayCurrentTimeSec / displayDurationSec;
1606
+ const activeChapter = findActivePodcastChapter(
1607
+ displayEpisode?.chapters,
1608
+ displayCurrentTimeSec
1609
+ );
1610
+ const [pendingChapter, setPendingChapter] = useState(null);
1611
+ const [chaptersExpanded, setChaptersExpanded] = useState(false);
1612
+ useEffect(() => {
1613
+ setChaptersExpanded(false);
1614
+ }, [displayEpisode?.id]);
1615
+ useEffect(() => {
1616
+ if (pendingChapter !== null && state.currentQueueItemId === pendingChapter.queueItemId && state.canSeek) {
1617
+ commands.seekTo(pendingChapter.seconds);
1618
+ setPendingChapter(null);
1619
+ }
1620
+ }, [commands, pendingChapter, state.canSeek, state.currentQueueItemId]);
1621
+ const playEpisode = (episode) => {
1622
+ if (episode.queueItem === void 0 || !playableIds.has(episode.queueItem.queueItemId)) {
1623
+ return null;
1624
+ }
1625
+ return activateIntrinsicItem(
1626
+ commands,
1627
+ build.context,
1628
+ episode.queueItem.queueItemId
1629
+ );
1630
+ };
1631
+ const selectChapter = (episode, chapter) => {
1632
+ if (episode.queueItem === void 0 || !playableIds.has(episode.queueItem.queueItemId)) {
1633
+ return;
1634
+ }
1635
+ if (active && state.currentQueueItemId === episode.queueItem.queueItemId && state.canSeek) {
1636
+ commands.seekTo(chapter.startTimeSec);
1637
+ return;
1638
+ }
1639
+ setPendingChapter({
1640
+ queueItemId: episode.queueItem.queueItemId,
1641
+ seconds: chapter.startTimeSec
1642
+ });
1643
+ void playEpisode(episode)?.then((result) => {
1644
+ if (!result.ok) {
1645
+ setPendingChapter(null);
1646
+ }
1647
+ });
1648
+ };
1649
+ const backSeconds = state.experienceConfig.podcastBackSec;
1650
+ const forwardSeconds = state.experienceConfig.podcastForwardSec;
1651
+ const chapters = displayEpisode?.chapters ?? [];
1652
+ const visibleChapters = chaptersExpanded ? chapters : chapters.slice(0, 4);
1653
+ return /* @__PURE__ */ jsxs(
1654
+ PlayerSurface,
1655
+ {
1656
+ appearance,
1657
+ className: ["player-program", "player-content", className].filter(Boolean).join(" "),
1658
+ label: "Podcast program player",
1659
+ children: [
1660
+ /* @__PURE__ */ jsxs("header", { className: "player-program__hero", children: [
1661
+ /* @__PURE__ */ jsx(
1662
+ ContentArtwork,
1663
+ {
1664
+ alt: program.title,
1665
+ artwork: program.artwork,
1666
+ className: "player-program__artwork"
1667
+ }
1668
+ ),
1669
+ /* @__PURE__ */ jsxs("div", { className: "player-program__detail", children: [
1670
+ /* @__PURE__ */ jsx("span", { className: "player-kicker", children: "Podcast Program" }),
1671
+ /* @__PURE__ */ jsx("h2", { children: program.title }),
1672
+ program.description === void 0 ? null : /* @__PURE__ */ jsx("p", { className: "player-program__description", children: program.description }),
1673
+ program.hosts === void 0 && program.credits === void 0 ? null : /* @__PURE__ */ jsxs("dl", { className: "player-program__credits", children: [
1674
+ program.hosts === void 0 || program.hosts.length === 0 ? null : /* @__PURE__ */ jsxs("div", { children: [
1675
+ /* @__PURE__ */ jsx("dt", { children: "Host" }),
1676
+ /* @__PURE__ */ jsx("dd", { children: program.hosts.join(" / ") })
1677
+ ] }),
1678
+ program.credits === void 0 || program.credits.length === 0 ? null : /* @__PURE__ */ jsxs("div", { children: [
1679
+ /* @__PURE__ */ jsx("dt", { children: "Credits" }),
1680
+ /* @__PURE__ */ jsx("dd", { children: program.credits.join(" / ") })
1681
+ ] })
1682
+ ] })
1683
+ ] })
1684
+ ] }),
1685
+ /* @__PURE__ */ jsxs(
1686
+ "section",
1687
+ {
1688
+ "aria-label": "Current Podcast Episode",
1689
+ className: "player-program__episode",
1690
+ children: [
1691
+ /* @__PURE__ */ jsxs("header", { className: "player-program__episode-heading", children: [
1692
+ /* @__PURE__ */ jsx("span", { className: "player-kicker", children: "Current Episode" }),
1693
+ /* @__PURE__ */ jsx("h3", { children: displayEpisode === null ? "No playable Episodes" : displayEpisode.title }),
1694
+ displayEpisode === null ? null : /* @__PURE__ */ jsxs("dl", { className: "player-program__episode-facts", children: [
1695
+ displayEpisode.publishedAt === void 0 ? null : /* @__PURE__ */ jsxs("div", { children: [
1696
+ /* @__PURE__ */ jsx("dt", { children: "Published" }),
1697
+ /* @__PURE__ */ jsx("dd", { children: displayEpisode.publishedAt })
1698
+ ] }),
1699
+ /* @__PURE__ */ jsxs("div", { children: [
1700
+ /* @__PURE__ */ jsx("dt", { children: "Duration" }),
1701
+ /* @__PURE__ */ jsx("dd", { children: formatTime(displayDurationSec) })
1702
+ ] })
1703
+ ] }),
1704
+ displayEpisode?.description === void 0 ? null : /* @__PURE__ */ jsx("p", { children: displayEpisode.description }),
1705
+ active ? /* @__PURE__ */ jsx(PlayerStatus, { state }) : null
1706
+ ] }),
1707
+ /* @__PURE__ */ jsxs("div", { className: "player-program__playback", children: [
1708
+ /* @__PURE__ */ jsxs("div", { className: "player-program__signal", children: [
1709
+ /* @__PURE__ */ jsx(
1710
+ Waveform,
1711
+ {
1712
+ opacity: state.experienceConfig.waveformOpacity,
1713
+ playedStateEnabled: state.experienceConfig.waveformPlayedStateEnabled,
1714
+ progress: waveformProgress,
1715
+ waveform: displayItem?.waveform
1716
+ }
1717
+ ),
1718
+ /* @__PURE__ */ jsx(
1719
+ SeekBar,
1720
+ {
1721
+ canSeek: active && state.canSeek,
1722
+ commitMode: state.experienceConfig.seekCommitMode,
1723
+ currentTimeSec: displayCurrentTimeSec,
1724
+ durationSec: displayDurationSec,
1725
+ label: "Seek in current Podcast Episode",
1726
+ onSeek: (seconds) => {
1727
+ commands.seekTo(seconds);
1728
+ },
1729
+ status: active ? state.status : "paused"
1730
+ }
1731
+ ),
1732
+ /* @__PURE__ */ jsx(
1733
+ TimeReadout,
1734
+ {
1735
+ currentTimeSec: displayCurrentTimeSec,
1736
+ durationSec: displayDurationSec
1737
+ }
1738
+ )
1739
+ ] }),
1740
+ /* @__PURE__ */ jsxs("div", { className: "player-program__transport-row", children: [
1741
+ /* @__PURE__ */ jsx(
1742
+ IntrinsicTransport,
1743
+ {
1744
+ active,
1745
+ canStart: first !== void 0,
1746
+ commands,
1747
+ onStart: () => {
1748
+ if (first !== void 0) {
1749
+ void activateIntrinsicItem(
1750
+ commands,
1751
+ build.context,
1752
+ first.queueItemId
1753
+ );
1754
+ }
1755
+ },
1756
+ state
1757
+ }
1758
+ ),
1759
+ /* @__PURE__ */ jsxs(
1760
+ "div",
1761
+ {
1762
+ "aria-label": "Podcast seek controls",
1763
+ className: "player-program__skip-controls",
1764
+ role: "group",
1765
+ children: [
1766
+ /* @__PURE__ */ jsx(
1767
+ IconButton,
1768
+ {
1769
+ disabled: !active || !state.canSeek,
1770
+ label: `Skip back ${String(backSeconds)} seconds`,
1771
+ onClick: () => {
1772
+ commands.seekBy(-backSeconds);
1773
+ },
1774
+ children: /* @__PURE__ */ jsx(PodcastSkipBackIcon, {})
1775
+ }
1776
+ ),
1777
+ /* @__PURE__ */ jsx(
1778
+ IconButton,
1779
+ {
1780
+ disabled: !active || !state.canSeek,
1781
+ label: `Skip forward ${String(forwardSeconds)} seconds`,
1782
+ onClick: () => {
1783
+ commands.seekBy(forwardSeconds);
1784
+ },
1785
+ children: /* @__PURE__ */ jsx(PodcastSkipForwardIcon, {})
1786
+ }
1787
+ )
1788
+ ]
1789
+ }
1790
+ )
1791
+ ] })
1792
+ ] }),
1793
+ chapters.length === 0 || displayEpisode === null ? null : /* @__PURE__ */ jsxs("div", { className: "player-program__chapters", children: [
1794
+ /* @__PURE__ */ jsxs("div", { className: "player-section-heading", children: [
1795
+ /* @__PURE__ */ jsx("span", { id: `program-chapters-${program.id}`, children: "Chapters" }),
1796
+ /* @__PURE__ */ jsxs("span", { className: "player-queue-count", children: [
1797
+ String(chapters.length),
1798
+ " chapters"
1799
+ ] })
1800
+ ] }),
1801
+ /* @__PURE__ */ jsx("ol", { "aria-labelledby": `program-chapters-${program.id}`, children: visibleChapters.map((chapter) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
1802
+ "button",
1803
+ {
1804
+ "aria-current": chapter.id === activeChapter?.id ? "true" : void 0,
1805
+ onClick: () => {
1806
+ selectChapter(displayEpisode, chapter);
1807
+ },
1808
+ type: "button",
1809
+ children: [
1810
+ /* @__PURE__ */ jsx("time", { children: formatTime(chapter.startTimeSec) }),
1811
+ /* @__PURE__ */ jsx("span", { children: chapter.title })
1812
+ ]
1813
+ }
1814
+ ) }, chapter.id)) }),
1815
+ chapters.length <= 4 ? null : /* @__PURE__ */ jsx(
1816
+ "button",
1817
+ {
1818
+ className: "player-program__chapters-toggle",
1819
+ onClick: () => {
1820
+ setChaptersExpanded((expanded) => !expanded);
1821
+ },
1822
+ type: "button",
1823
+ children: chaptersExpanded ? "Show fewer chapters" : `Show all ${String(chapters.length)} chapters`
1824
+ }
1825
+ )
1826
+ ] })
1827
+ ]
1828
+ }
1829
+ ),
1830
+ /* @__PURE__ */ jsxs(
1831
+ "section",
1832
+ {
1833
+ "aria-labelledby": `program-episodes-${program.id}`,
1834
+ className: "player-program__episode-list",
1835
+ children: [
1836
+ /* @__PURE__ */ jsxs("div", { className: "player-section-heading", children: [
1837
+ /* @__PURE__ */ jsx("span", { id: `program-episodes-${program.id}`, children: "Episodes" }),
1838
+ /* @__PURE__ */ jsxs("span", { className: "player-queue-count", children: [
1839
+ String(program.episodes.length),
1840
+ " episodes"
1841
+ ] })
1842
+ ] }),
1843
+ program.episodes.length === 0 ? /* @__PURE__ */ jsx("p", { className: "player-empty", children: "No Episodes are available." }) : /* @__PURE__ */ jsx("ol", { className: "player-content__list player-content__episodes", children: program.episodes.map((episode, index) => {
1844
+ const playable = episode.queueItem !== void 0 && playableIds.has(episode.queueItem.queueItemId);
1845
+ const isCurrent = episode.id === selectedEpisodeId;
1846
+ return /* @__PURE__ */ jsx(
1847
+ "li",
1848
+ {
1849
+ "data-availability": episode.availability.state,
1850
+ "data-current": isCurrent ? "true" : "false",
1851
+ children: /* @__PURE__ */ jsxs(
1852
+ "button",
1853
+ {
1854
+ "aria-current": isCurrent ? "true" : void 0,
1855
+ "aria-label": playable ? `Play episode ${episode.title}` : `${episode.title}: ${availabilityLabel(episode.availability.state)}`,
1856
+ disabled: !playable,
1857
+ onClick: () => {
1858
+ void playEpisode(episode);
1859
+ },
1860
+ type: "button",
1861
+ children: [
1862
+ /* @__PURE__ */ jsx("span", { className: "player-queue-number", children: String(index + 1).padStart(2, "0") }),
1863
+ /* @__PURE__ */ jsxs("span", { className: "player-content__entry-copy", children: [
1864
+ /* @__PURE__ */ jsx("strong", { children: episode.title }),
1865
+ /* @__PURE__ */ jsx("small", { children: availabilityLabel(episode.availability.state) })
1866
+ ] }),
1867
+ /* @__PURE__ */ jsx("time", { children: formatTime(episode.durationHintSec ?? null) })
1868
+ ]
1869
+ }
1870
+ )
1871
+ },
1872
+ `${episode.id}:${String(index)}`
1873
+ );
1874
+ }) })
1875
+ ]
1876
+ }
1877
+ ),
1878
+ /* @__PURE__ */ jsx(PlayerErrorNotice, { commands, state })
1879
+ ]
1880
+ }
1881
+ );
1882
+ }
1095
1883
  function MiniPlayer({
1096
1884
  appearance,
1097
1885
  className,
@@ -1101,17 +1889,23 @@ function MiniPlayer({
1101
1889
  if (state.currentItem === null) {
1102
1890
  return null;
1103
1891
  }
1892
+ const contentContext = state.currentItem.contentContext;
1104
1893
  return /* @__PURE__ */ jsxs(
1105
1894
  PlayerSurface,
1106
1895
  {
1107
1896
  appearance,
1108
1897
  className: ["player-mini", className].filter(Boolean).join(" "),
1109
- label: "Mini music player",
1898
+ label: contentContext?.sourceType === "podcast-episode" ? "Podcast mini player" : "Mini music player",
1110
1899
  children: [
1111
1900
  /* @__PURE__ */ jsxs(
1112
1901
  "div",
1113
1902
  {
1114
1903
  className: "player-mini__main",
1904
+ "data-content-source": contentContext?.sourceType,
1905
+ "data-episode-id": contentContext?.sourceType === "podcast-episode" ? contentContext.episodeId : void 0,
1906
+ "data-program-id": contentContext?.sourceType === "podcast-episode" ? contentContext.programId : void 0,
1907
+ "data-release-id": contentContext?.sourceType === "release-track" ? contentContext.releaseId : void 0,
1908
+ "data-track-id": contentContext?.sourceType === "release-track" ? contentContext.trackId : void 0,
1115
1909
  "data-playback-context-id": state.activeContext?.id,
1116
1910
  "data-playback-context-mode": state.activeContext?.mode,
1117
1911
  children: [
@@ -1434,6 +2228,6 @@ function WidePlayer({
1434
2228
  );
1435
2229
  }
1436
2230
 
1437
- export { Artwork, BoundCompactPlayerView, CompactPlayer, DetailedPlayer, IconButton, MiniPlayer, PlayerErrorNotice, PlayerStatus, PlayerSurface, PodcastPlayer, PopoverVolumeControl, PrimaryPlaybackButton, QueuePanel, QueueToggle, SeekBar, TimeReadout, TrackMetadata, TransportControls, VolumeControl, Waveform, WidePlayer, clamp, formatTime, formatTimeAria, getErrorMessage, getNextRepeatMode, getRepeatLabel, getStatusLabel };
2231
+ export { Artwork, BoundCompactPlayerView, CompactPlayer, DetailedPlayer, IconButton, MiniPlayer, PlayerErrorNotice, PlayerStatus, PlayerSurface, PodcastPlayer, PodcastProgramPlayer, PopoverVolumeControl, PrimaryPlaybackButton, QueuePanel, QueueToggle, ReleasePlayer, SeekBar, TimeReadout, TrackMetadata, TransportControls, VolumeControl, Waveform, WidePlayer, clamp, formatTime, formatTimeAria, getErrorMessage, getNextRepeatMode, getRepeatLabel, getStatusLabel };
1438
2232
  //# sourceMappingURL=index.js.map
1439
2233
  //# sourceMappingURL=index.js.map