@memberjunction/ng-media-player 6.1.4 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,10 +15,14 @@ import { MediaTranscriptCue } from '../media-player.types';
15
15
  * @param cues the ordered transcript cues
16
16
  * @returns the index of the active cue, or -1 if none is active (e.g. before the first cue)
17
17
  */
18
+ export declare function ComputeActiveCueIndex(currentMs: number, cues: MediaTranscriptCue[] | null | undefined): number;
19
+ /** @deprecated Use {@link ComputeActiveCueIndex}. */
18
20
  export declare function computeActiveCueIndex(currentMs: number, cues: MediaTranscriptCue[] | null | undefined): number;
19
21
  /**
20
22
  * Resolves the effective end time (exclusive) of the cue at `index`.
21
23
  * Uses the cue's own `EndMs`, else the next cue's `StartMs`, else `+Infinity`.
22
24
  */
25
+ export declare function ResolveCueEndMs(cues: MediaTranscriptCue[], index: number): number;
26
+ /** @deprecated Use {@link ResolveCueEndMs}. */
23
27
  export declare function resolveCueEndMs(cues: MediaTranscriptCue[], index: number): number;
24
28
  //# sourceMappingURL=cue-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cue-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/cue-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAe9G;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjF"}
1
+ {"version":3,"file":"cue-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/cue-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAe9G;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE9G;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUjF;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjF"}
@@ -14,7 +14,7 @@
14
14
  * @param cues the ordered transcript cues
15
15
  * @returns the index of the active cue, or -1 if none is active (e.g. before the first cue)
16
16
  */
17
- export function computeActiveCueIndex(currentMs, cues) {
17
+ export function ComputeActiveCueIndex(currentMs, cues) {
18
18
  if (!cues || cues.length === 0) {
19
19
  return -1;
20
20
  }
@@ -22,18 +22,22 @@ export function computeActiveCueIndex(currentMs, cues) {
22
22
  for (let i = 0; i < cues.length; i++) {
23
23
  const cue = cues[i];
24
24
  const start = cue.StartMs;
25
- const end = resolveCueEndMs(cues, i);
25
+ const end = ResolveCueEndMs(cues, i);
26
26
  if (currentMs >= start && currentMs < end) {
27
27
  activeIndex = i; // last qualifying wins
28
28
  }
29
29
  }
30
30
  return activeIndex;
31
31
  }
32
+ /** @deprecated Use {@link ComputeActiveCueIndex}. */
33
+ export function computeActiveCueIndex(currentMs, cues) {
34
+ return ComputeActiveCueIndex(currentMs, cues);
35
+ }
32
36
  /**
33
37
  * Resolves the effective end time (exclusive) of the cue at `index`.
34
38
  * Uses the cue's own `EndMs`, else the next cue's `StartMs`, else `+Infinity`.
35
39
  */
36
- export function resolveCueEndMs(cues, index) {
40
+ export function ResolveCueEndMs(cues, index) {
37
41
  const cue = cues[index];
38
42
  if (cue.EndMs != null) {
39
43
  return cue.EndMs;
@@ -44,4 +48,8 @@ export function resolveCueEndMs(cues, index) {
44
48
  }
45
49
  return Number.POSITIVE_INFINITY;
46
50
  }
51
+ /** @deprecated Use {@link ResolveCueEndMs}. */
52
+ export function resolveCueEndMs(cues, index) {
53
+ return ResolveCueEndMs(cues, index);
54
+ }
47
55
  //# sourceMappingURL=cue-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cue-utils.js","sourceRoot":"","sources":["../../../src/lib/media-player/cue-utils.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,IAA6C;IACpG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC;QAC1B,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrC,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;YAC1C,WAAW,GAAG,CAAC,CAAC,CAAC,uBAAuB;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAA0B,EAAE,KAAa;IACvE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC,KAAK,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7B,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC,iBAAiB,CAAC;AAClC,CAAC","sourcesContent":["import { MediaTranscriptCue } from '../media-player.types';\n\n/**\n * Pure computation of the active transcript cue for a given playback position.\n *\n * A cue is active when `currentMs` falls within `[StartMs, end)` where `end` is:\n * - the cue's own `EndMs` when present, OR\n * - the next cue's `StartMs` (the cue runs until the next one begins), OR\n * - `+Infinity` for the final cue with no `EndMs` (runs to the end of the media).\n *\n * Cues are assumed to be in chronological order by `StartMs`. When more than one\n * cue qualifies (overlapping ranges), the LAST qualifying cue wins, which matches\n * the \"most recently started\" intuition for transcripts.\n *\n * @param currentMs current playback position in milliseconds\n * @param cues the ordered transcript cues\n * @returns the index of the active cue, or -1 if none is active (e.g. before the first cue)\n */\nexport function computeActiveCueIndex(currentMs: number, cues: MediaTranscriptCue[] | null | undefined): number {\n if (!cues || cues.length === 0) {\n return -1;\n }\n\n let activeIndex = -1;\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const start = cue.StartMs;\n const end = resolveCueEndMs(cues, i);\n if (currentMs >= start && currentMs < end) {\n activeIndex = i; // last qualifying wins\n }\n }\n return activeIndex;\n}\n\n/**\n * Resolves the effective end time (exclusive) of the cue at `index`.\n * Uses the cue's own `EndMs`, else the next cue's `StartMs`, else `+Infinity`.\n */\nexport function resolveCueEndMs(cues: MediaTranscriptCue[], index: number): number {\n const cue = cues[index];\n if (cue.EndMs != null) {\n return cue.EndMs;\n }\n const next = cues[index + 1];\n if (next) {\n return next.StartMs;\n }\n return Number.POSITIVE_INFINITY;\n}\n"]}
1
+ {"version":3,"file":"cue-utils.js","sourceRoot":"","sources":["../../../src/lib/media-player/cue-utils.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,IAA6C;IACpG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,CAAC,CAAC;IACZ,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC;QAC1B,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrC,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;YAC1C,WAAW,GAAG,CAAC,CAAC,CAAC,uBAAuB;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,IAA6C;IACpG,OAAO,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAA0B,EAAE,KAAa;IACvE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC,KAAK,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7B,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC,iBAAiB,CAAC;AAClC,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,eAAe,CAAC,IAA0B,EAAE,KAAa;IACvE,OAAO,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC","sourcesContent":["import { MediaTranscriptCue } from '../media-player.types';\n\n/**\n * Pure computation of the active transcript cue for a given playback position.\n *\n * A cue is active when `currentMs` falls within `[StartMs, end)` where `end` is:\n * - the cue's own `EndMs` when present, OR\n * - the next cue's `StartMs` (the cue runs until the next one begins), OR\n * - `+Infinity` for the final cue with no `EndMs` (runs to the end of the media).\n *\n * Cues are assumed to be in chronological order by `StartMs`. When more than one\n * cue qualifies (overlapping ranges), the LAST qualifying cue wins, which matches\n * the \"most recently started\" intuition for transcripts.\n *\n * @param currentMs current playback position in milliseconds\n * @param cues the ordered transcript cues\n * @returns the index of the active cue, or -1 if none is active (e.g. before the first cue)\n */\nexport function ComputeActiveCueIndex(currentMs: number, cues: MediaTranscriptCue[] | null | undefined): number {\n if (!cues || cues.length === 0) {\n return -1;\n }\n\n let activeIndex = -1;\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const start = cue.StartMs;\n const end = ResolveCueEndMs(cues, i);\n if (currentMs >= start && currentMs < end) {\n activeIndex = i; // last qualifying wins\n }\n }\n return activeIndex;\n}\n\n/** @deprecated Use {@link ComputeActiveCueIndex}. */\nexport function computeActiveCueIndex(currentMs: number, cues: MediaTranscriptCue[] | null | undefined): number {\n return ComputeActiveCueIndex(currentMs, cues);\n}\n\n/**\n * Resolves the effective end time (exclusive) of the cue at `index`.\n * Uses the cue's own `EndMs`, else the next cue's `StartMs`, else `+Infinity`.\n */\nexport function ResolveCueEndMs(cues: MediaTranscriptCue[], index: number): number {\n const cue = cues[index];\n if (cue.EndMs != null) {\n return cue.EndMs;\n }\n const next = cues[index + 1];\n if (next) {\n return next.StartMs;\n }\n return Number.POSITIVE_INFINITY;\n}\n\n/** @deprecated Use {@link ResolveCueEndMs}. */\nexport function resolveCueEndMs(cues: MediaTranscriptCue[], index: number): number {\n return ResolveCueEndMs(cues, index);\n}\n"]}
@@ -84,7 +84,11 @@ export declare class MJMediaPlayerComponent implements OnDestroy {
84
84
  /** Emits the new visibility (`true` = shown) whenever the transcript is toggled. */
85
85
  TranscriptVisibilityChanged: EventEmitter<boolean>;
86
86
  /** The primary media element (the single audio/video, or the first video in a grid). */
87
- primaryMedia?: ElementRef<HTMLMediaElement>;
87
+ PrimaryMedia?: ElementRef<HTMLMediaElement>;
88
+ /** @deprecated Use {@link PrimaryMedia}. */
89
+ get primaryMedia(): ElementRef<HTMLMediaElement> | undefined;
90
+ /** @deprecated Use {@link PrimaryMedia}. */
91
+ set primaryMedia(value: ElementRef<HTMLMediaElement> | undefined);
88
92
  private _currentTimeMs;
89
93
  private _durationMs;
90
94
  private _isPlaying;
@@ -165,7 +169,7 @@ export declare class MJMediaPlayerComponent implements OnDestroy {
165
169
  get ScrubPercent(): number;
166
170
  get PrefersReducedMotion(): boolean;
167
171
  /** The active audio track that drives the waveform (the first audio track, if any). */
168
- private get WaveformTrack();
172
+ private get waveformTrack();
169
173
  /**
170
174
  * True when the waveform should render as bars — i.e. it's enabled, the active track
171
175
  * is audio, and we have peaks (supplied or successfully decoded) for it. When false
@@ -1 +1 @@
1
- {"version":3,"file":"media-player.component.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/media-player.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"media-player.component.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/media-player.component.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Input, Output, ViewChild, inject, } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
- import { computeActiveCueIndex } from './cue-utils';
4
- import { nextPlaybackState } from './playback-state';
5
- import { resolveTranscriptToggleVisible, resolveTranscriptVisible, } from './transcript-layout';
6
- import { DEFAULT_WAVEFORM_BARS, downsamplePeaks } from './waveform-utils';
3
+ import { ComputeActiveCueIndex } from './cue-utils';
4
+ import { NextPlaybackState } from './playback-state';
5
+ import { ResolveTranscriptToggleVisible, ResolveTranscriptVisible, } from './transcript-layout';
6
+ import { DEFAULT_WAVEFORM_BARS, DownsamplePeaks } from './waveform-utils';
7
7
  import * as i0 from "@angular/core";
8
8
  const _c0 = ["primaryMedia"];
9
9
  function MJMediaPlayerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
@@ -509,7 +509,15 @@ export class MJMediaPlayerComponent {
509
509
  // View references
510
510
  // ---------------------------------------------------------------------------
511
511
  /** The primary media element (the single audio/video, or the first video in a grid). */
512
- primaryMedia;
512
+ PrimaryMedia;
513
+ /** @deprecated Use {@link PrimaryMedia}. */
514
+ get primaryMedia() {
515
+ return this.PrimaryMedia;
516
+ }
517
+ /** @deprecated Use {@link PrimaryMedia}. */
518
+ set primaryMedia(value) {
519
+ this.PrimaryMedia = value;
520
+ }
513
521
  // ---------------------------------------------------------------------------
514
522
  // Internal state
515
523
  // ---------------------------------------------------------------------------
@@ -642,7 +650,7 @@ export class MJMediaPlayerComponent {
642
650
  * the `ShowTranscript` master switch, AND the runtime toggle to be visible.
643
651
  */
644
652
  get ShowTranscriptPanel() {
645
- return resolveTranscriptVisible(this.HasTranscript, this.ShowTranscript, this._transcriptUserVisible);
653
+ return ResolveTranscriptVisible(this.HasTranscript, this.ShowTranscript, this._transcriptUserVisible);
646
654
  }
647
655
  /** The current runtime visibility of the transcript (toggle-driven). */
648
656
  get TranscriptVisible() {
@@ -650,7 +658,7 @@ export class MJMediaPlayerComponent {
650
658
  }
651
659
  /** Whether the transcript show/hide toggle button should render in the transport. */
652
660
  get ShowTranscriptToggleButton() {
653
- return resolveTranscriptToggleVisible(this.HasTranscript, this.ShowTranscript, this.ShowTranscriptToggle);
661
+ return ResolveTranscriptToggleVisible(this.HasTranscript, this.ShowTranscript, this.ShowTranscriptToggle);
654
662
  }
655
663
  get ScrubFraction() {
656
664
  return this._durationMs > 0 ? this._currentTimeMs / this._durationMs : 0;
@@ -662,7 +670,7 @@ export class MJMediaPlayerComponent {
662
670
  return this._prefersReducedMotion;
663
671
  }
664
672
  /** The active audio track that drives the waveform (the first audio track, if any). */
665
- get WaveformTrack() {
673
+ get waveformTrack() {
666
674
  return this.IsAudioOnly ? this.AudioTracks[0] ?? null : null;
667
675
  }
668
676
  /**
@@ -671,7 +679,7 @@ export class MJMediaPlayerComponent {
671
679
  * (decode pending/failed, no track), the template shows a plain progress bar instead.
672
680
  */
673
681
  get ShowWaveformBars() {
674
- const track = this.WaveformTrack;
682
+ const track = this.waveformTrack;
675
683
  if (!this.ShowWaveform || !track) {
676
684
  return false;
677
685
  }
@@ -683,7 +691,7 @@ export class MJMediaPlayerComponent {
683
691
  * client-side extraction when needed — re-renders/seeks never re-decode (cached by Id).
684
692
  */
685
693
  get WaveformPeaks() {
686
- const track = this.WaveformTrack;
694
+ const track = this.waveformTrack;
687
695
  if (!this.ShowWaveform || !track) {
688
696
  return null;
689
697
  }
@@ -1050,7 +1058,7 @@ export class MJMediaPlayerComponent {
1050
1058
  ReadyState: el?.readyState ?? 0,
1051
1059
  Ended: el?.ended ?? false,
1052
1060
  };
1053
- const next = nextPlaybackState(event, this._mediaState, ctx);
1061
+ const next = NextPlaybackState(event, this._mediaState, ctx);
1054
1062
  this.setMediaState(next);
1055
1063
  }
1056
1064
  /** Commits a new state, syncs the buffering spinner, and emits on change. */
@@ -1285,7 +1293,7 @@ export class MJMediaPlayerComponent {
1285
1293
  if (this._activeMediaEl) {
1286
1294
  return this._activeMediaEl;
1287
1295
  }
1288
- return this.primaryMedia?.nativeElement ?? null;
1296
+ return this.PrimaryMedia?.nativeElement ?? null;
1289
1297
  }
1290
1298
  initializeMediaElement(el) {
1291
1299
  if (!this._rateInitialized) {
@@ -1310,7 +1318,7 @@ export class MJMediaPlayerComponent {
1310
1318
  this.SeekToMs(fraction * this._durationMs);
1311
1319
  }
1312
1320
  refreshActiveCue() {
1313
- const newIndex = computeActiveCueIndex(this._currentTimeMs, this._transcript);
1321
+ const newIndex = ComputeActiveCueIndex(this._currentTimeMs, this._transcript);
1314
1322
  if (newIndex !== this._activeCueIndex) {
1315
1323
  this._activeCueIndex = newIndex;
1316
1324
  if (newIndex >= 0 && this._transcript) {
@@ -1395,7 +1403,7 @@ export class MJMediaPlayerComponent {
1395
1403
  const arrayBuffer = await response.arrayBuffer();
1396
1404
  const audioBuffer = await ctx.decodeAudioData(arrayBuffer.slice(0));
1397
1405
  const channel = audioBuffer.getChannelData(0);
1398
- const peaks = downsamplePeaks(channel, this.WaveformBarCount, 'max-abs');
1406
+ const peaks = DownsamplePeaks(channel, this.WaveformBarCount, 'max-abs');
1399
1407
  this._peaksByTrackId.set(track.Id, peaks);
1400
1408
  this.cdr.markForCheck();
1401
1409
  }
@@ -1451,7 +1459,7 @@ export class MJMediaPlayerComponent {
1451
1459
  i0.ɵɵviewQuery(_c0, 5);
1452
1460
  } if (rf & 2) {
1453
1461
  let _t;
1454
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.primaryMedia = _t.first);
1462
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.PrimaryMedia = _t.first);
1455
1463
  } }, hostBindings: function MJMediaPlayerComponent_HostBindings(rf, ctx) { if (rf & 1) {
1456
1464
  i0.ɵɵlistener("keydown", function MJMediaPlayerComponent_keydown_HostBindingHandler($event) { return ctx.OnHostKeyDown($event); })("fullscreenchange", function MJMediaPlayerComponent_fullscreenchange_HostBindingHandler() { return ctx.OnFullscreenChange(); }, i0.ɵɵresolveDocument);
1457
1465
  } }, inputs: { Tracks: "Tracks", Transcript: "Transcript", Autoplay: "Autoplay", StartAtMs: "StartAtMs", ShowTranscript: "ShowTranscript", ShowTranscriptToggle: "ShowTranscriptToggle", ShowSpeedControl: "ShowSpeedControl", ShowSkipControls: "ShowSkipControls", ShowVolume: "ShowVolume", ShowWaveform: "ShowWaveform", WaveformBarCount: "WaveformBarCount", ShowFullscreen: "ShowFullscreen", SkipSeconds: "SkipSeconds", PlaybackRates: "PlaybackRates", InitialRate: "InitialRate", InitialVolume: "InitialVolume", TranscriptPosition: "TranscriptPosition" }, outputs: { BeforePlay: "BeforePlay", AfterPlay: "AfterPlay", BeforePause: "BeforePause", AfterPause: "AfterPause", BeforeSeek: "BeforeSeek", AfterSeek: "AfterSeek", BeforeRateChange: "BeforeRateChange", AfterRateChange: "AfterRateChange", CueActivated: "CueActivated", CueClicked: "CueClicked", TimeUpdate: "TimeUpdate", DurationChange: "DurationChange", Ended: "Ended", StateChanged: "StateChanged", TranscriptVisibilityChanged: "TranscriptVisibilityChanged" }, decls: 3, vars: 9, consts: [["scrubTrack", ""], ["primaryMedia", ""], ["waveTrack", ""], ["tabindex", "0", "role", "group", "aria-label", "Media player", 1, "mj-media-player"], ["role", "status", 1, "mj-media-empty"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle-play", "mj-media-empty__icon"], [1, "mj-media-empty__text"], [1, "mj-media-main"], [1, "mj-media-stage"], ["role", "alert", 1, "mj-media-error"], ["role", "status", "aria-hidden", "true", 1, "mj-media-busy", 3, "mj-media-busy--static"], [1, "mj-media-video-grid", 3, "mj-media-video-grid--multi"], [1, "mj-media-transport"], ["role", "status", "aria-live", "polite", 1, "mj-media-status"], ["aria-hidden", "true", 1, "mj-media-status__dot"], [1, "mj-media-status__text"], [1, "mj-media-scrubber-row"], [1, "mj-media-time"], ["role", "slider", "tabindex", "0", "aria-label", "Seek", 1, "mj-media-scrubber", 3, "pointerdown", "pointermove", "pointerup", "pointercancel", "keydown"], [1, "mj-media-scrubber__rail"], [1, "mj-media-scrubber__fill"], [1, "mj-media-scrubber__handle"], [1, "mj-media-time", "mj-media-time--total"], [1, "mj-media-controls"], [1, "mj-media-controls__left"], ["type", "button", 1, "mj-media-btn", 3, "title"], ["type", "button", 1, "mj-media-btn", "mj-media-btn--primary", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid"], [1, "mj-media-controls__right"], [1, "mj-media-volume"], [1, "mj-media-rate"], ["type", "button", 1, "mj-media-btn", 3, "mj-media-btn--active", "title"], ["role", "list", "aria-label", "Transcript", 1, "mj-media-transcript"], ["aria-hidden", "true", 1, "fa-solid", "fa-triangle-exclamation"], ["role", "status", "aria-hidden", "true", 1, "mj-media-busy"], [1, "mj-media-busy__spinner"], [1, "mj-media-busy__label"], ["role", "slider", "tabindex", "0", "aria-label", "Seek", 1, "mj-media-waveform", 3, "mj-media-waveform--static"], ["role", "slider", "tabindex", "0", "aria-label", "Seek", 1, "mj-media-waveform-fallback"], ["aria-hidden", "true", 1, "mj-media-audio-art"], ["preload", "metadata", 1, "mj-media-audio", 3, "src"], ["preload", "metadata", 1, "mj-media-audio", 3, "loadstart", "loadedmetadata", "canplay", "canplaythrough", "waiting", "seeking", "seeked", "playing", "stalled", "suspend", "emptied", "timeupdate", "durationchange", "play", "pause", "ended", "error", "src"], ["role", "slider", "tabindex", "0", "aria-label", "Seek", 1, "mj-media-waveform", 3, "pointerdown", "pointermove", "pointerup", "pointercancel", "keydown"], [1, "mj-media-waveform__bar", 3, "mj-media-waveform__bar--played", "height"], [1, "mj-media-waveform__progress"], [1, "mj-media-waveform__bar"], ["role", "slider", "tabindex", "0", "aria-label", "Seek", 1, "mj-media-waveform-fallback", 3, "pointerdown", "pointermove", "pointerup", "pointercancel", "keydown"], [1, "mj-media-waveform-fallback__rail"], [1, "mj-media-waveform-fallback__fill"], [1, "fa-solid", "fa-music"], [1, "mj-media-video-grid"], [1, "mj-media-video-cell"], [1, "mj-media-video-cell__label"], ["playsinline", "", "preload", "metadata", 1, "mj-media-video", 3, "src", "poster"], ["playsinline", "", "preload", "metadata", "muted", "", 1, "mj-media-video", 3, "src", "poster"], ["playsinline", "", "preload", "metadata", 1, "mj-media-video", 3, "loadstart", "loadedmetadata", "canplay", "canplaythrough", "waiting", "seeking", "seeked", "playing", "stalled", "suspend", "emptied", "timeupdate", "durationchange", "play", "pause", "ended", "error", "src", "poster"], ["type", "button", 1, "mj-media-btn", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-left"], [1, "mj-media-btn__skip-label"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-right"], ["type", "range", "min", "0", "max", "1", "step", "0.05", "aria-label", "Volume", 1, "mj-media-volume__slider", 3, "input", "value"], ["type", "button", "aria-haspopup", "true", "aria-label", "Playback speed", "title", "Playback speed", 1, "mj-media-btn", "mj-media-rate__toggle", 3, "click"], ["role", "menu", 1, "mj-media-rate__menu"], ["role", "none"], ["type", "button", "role", "menuitemradio", 1, "mj-media-rate__item", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-closed-captioning"], ["type", "button", "role", "listitem", 1, "mj-media-cue", 3, "mj-media-cue--active"], ["type", "button", "role", "listitem", 1, "mj-media-cue", 3, "click", "keydown"], [1, "mj-media-cue__time"], [1, "mj-media-cue__body"], [1, "mj-media-cue__speaker", 3, "color"], [1, "mj-media-cue__text"], [1, "mj-media-cue__speaker"]], template: function MJMediaPlayerComponent_Template(rf, ctx) { if (rf & 1) {
@@ -1531,7 +1539,7 @@ export class MJMediaPlayerComponent {
1531
1539
  type: Output
1532
1540
  }], TranscriptVisibilityChanged: [{
1533
1541
  type: Output
1534
- }], primaryMedia: [{
1542
+ }], PrimaryMedia: [{
1535
1543
  type: ViewChild,
1536
1544
  args: ['primaryMedia']
1537
1545
  }], OnHostKeyDown: [{
@@ -1 +1 @@
1
- {"version":3,"file":"media-player.component.js","sourceRoot":"","sources":["../../../src/lib/media-player/media-player.component.ts","../../../src/lib/media-player/media-player.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n OnDestroy,\n Output,\n ViewChild,\n inject,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n MediaCueEvent,\n MediaPlaybackState,\n MediaPlayerCancelableEvent,\n MediaRateEvent,\n MediaSeekEvent,\n MediaTrack,\n MediaTranscriptCue,\n} from '../media-player.types';\nimport { computeActiveCueIndex } from './cue-utils';\nimport { MediaStateContext, MediaStateEvent, nextPlaybackState } from './playback-state';\nimport {\n TranscriptPosition,\n resolveTranscriptToggleVisible,\n resolveTranscriptVisible,\n} from './transcript-layout';\nimport { DEFAULT_WAVEFORM_BARS, downsamplePeaks } from './waveform-utils';\n\n/**\n * Delay (ms) before the *buffering* spinner is shown, to avoid flicker on instant seeks\n * that resolve immediately. The *loading* indicator shows with no delay. If a buffering\n * state clears before this elapses, the spinner never appears.\n */\nconst BUFFERING_INDICATOR_DELAY_MS = 200;\n\n/**\n * `mj-media-player` — a generic, framework-agnostic media player.\n *\n * Renders one or many audio/video tracks with a custom transport bar (play/pause,\n * click-and-drag scrubber, skip ±N, playback-rate menu, volume + mute, fullscreen),\n * a **real** audio waveform (decoded client-side, or supplied precomputed via\n * `MediaTrack.Peaks`) that doubles as the scrubber, and an optional time-synced\n * transcript panel whose cues are clickable and auto-highlight as playback advances.\n *\n * This component has ZERO MemberJunction-core dependencies — it is pure Angular and\n * is safe to reuse in any application. The MJStorage binding lives in the separate\n * `mj-storage-media-player` wrapper.\n */\n@Component({\n selector: 'mj-media-player',\n standalone: true,\n imports: [CommonModule],\n templateUrl: './media-player.component.html',\n styleUrls: ['./media-player.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJMediaPlayerComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n private host = inject(ElementRef<HTMLElement>);\n\n constructor() {\n this._prefersReducedMotion = this.detectReducedMotion();\n }\n\n // ---------------------------------------------------------------------------\n // Inputs\n // ---------------------------------------------------------------------------\n\n /** The track(s) to play. One audio track → transport bar; many videos → grid. */\n @Input()\n set Tracks(value: MediaTrack[]) {\n this._tracks = value ?? [];\n this._activeMediaEl = null;\n this.resetPlaybackState();\n this.ensureWaveforms();\n this.cdr.markForCheck();\n }\n get Tracks(): MediaTrack[] {\n return this._tracks;\n }\n private _tracks: MediaTrack[] = [];\n\n /** Optional transcript cues. When set (and `ShowTranscript`), a transcript panel renders. */\n @Input()\n set Transcript(value: MediaTranscriptCue[] | null) {\n this._transcript = value;\n this._activeCueIndex = -1;\n // A newly-supplied transcript defaults to visible (the user can hide it via the toggle).\n this._transcriptUserVisible = true;\n this.cdr.markForCheck();\n }\n get Transcript(): MediaTranscriptCue[] | null {\n return this._transcript;\n }\n private _transcript: MediaTranscriptCue[] | null = null;\n\n /** Begin playback automatically once media is ready. */\n @Input() Autoplay = false;\n /** Start playback at this position (ms) once metadata loads. */\n @Input() StartAtMs: number | null = null;\n /** Whether the transcript panel is shown (when a transcript is provided). */\n @Input() ShowTranscript = true;\n /** Whether the transcript show/hide toggle button renders in the transport bar. */\n @Input() ShowTranscriptToggle = true;\n /** Whether the playback-rate menu is shown. */\n @Input() ShowSpeedControl = true;\n /** Whether the ±skip buttons are shown. */\n @Input() ShowSkipControls = true;\n /** Whether the volume slider + mute are shown. */\n @Input() ShowVolume = true;\n /**\n * Whether the real audio waveform (which doubles as the scrubber) is shown for\n * audio-only tracks. On by default. When a track supplies {@link MediaTrack.Peaks}\n * those are rendered directly; otherwise the player decodes the track URL client-side\n * to extract real peaks, falling back to a plain progress bar if decoding fails.\n */\n @Input() ShowWaveform = true;\n /** Number of bars the waveform renders / downsamples to. */\n @Input() WaveformBarCount = DEFAULT_WAVEFORM_BARS;\n /** Whether the fullscreen button is shown for video. */\n @Input() ShowFullscreen = true;\n /** Number of seconds the skip buttons jump. */\n @Input() SkipSeconds = 30;\n /** The playback rates offered in the rate menu. */\n @Input() PlaybackRates: number[] = [0.5, 1, 1.25, 1.5, 2];\n /** The initial playback rate. */\n @Input() InitialRate = 1;\n /** The initial volume (0..1). */\n @Input() InitialVolume = 1;\n /**\n * Where the transcript panel sits relative to the media. Defaults to `'bottom'`\n * (full width below the player, filling remaining height) which reads better than\n * the narrower side layout; consumers can opt into `'side'`.\n */\n @Input() TranscriptPosition: TranscriptPosition = 'bottom';\n\n // ---------------------------------------------------------------------------\n // Outputs — Before* are cancelable (set event.Cancel = true to abort)\n // ---------------------------------------------------------------------------\n\n @Output() BeforePlay = new EventEmitter<MediaPlayerCancelableEvent>();\n @Output() AfterPlay = new EventEmitter<void>();\n @Output() BeforePause = new EventEmitter<MediaPlayerCancelableEvent>();\n @Output() AfterPause = new EventEmitter<void>();\n @Output() BeforeSeek = new EventEmitter<MediaSeekEvent>();\n @Output() AfterSeek = new EventEmitter<number>();\n @Output() BeforeRateChange = new EventEmitter<MediaRateEvent>();\n @Output() AfterRateChange = new EventEmitter<number>();\n @Output() CueActivated = new EventEmitter<MediaCueEvent>();\n @Output() CueClicked = new EventEmitter<MediaCueEvent>();\n @Output() TimeUpdate = new EventEmitter<number>();\n @Output() DurationChange = new EventEmitter<number>();\n @Output() Ended = new EventEmitter<void>();\n /** Emits whenever the primary element's {@link MediaPlaybackState} transitions. */\n @Output() StateChanged = new EventEmitter<MediaPlaybackState>();\n /** Emits the new visibility (`true` = shown) whenever the transcript is toggled. */\n @Output() TranscriptVisibilityChanged = new EventEmitter<boolean>();\n\n // ---------------------------------------------------------------------------\n // View references\n // ---------------------------------------------------------------------------\n\n /** The primary media element (the single audio/video, or the first video in a grid). */\n @ViewChild('primaryMedia') primaryMedia?: ElementRef<HTMLMediaElement>;\n\n // ---------------------------------------------------------------------------\n // Internal state\n // ---------------------------------------------------------------------------\n\n private _currentTimeMs = 0;\n private _durationMs = 0;\n private _isPlaying = false;\n private _playbackRate = 1;\n private _volume = 1;\n private _muted = false;\n private _activeCueIndex = -1;\n private _isFullscreen = false;\n private _isScrubbing = false;\n private _hasError = false;\n private _rateMenuOpen = false;\n /** Media elements we've already nudged to resolve a real (finite) duration. */\n private _durationForced = new WeakSet<HTMLMediaElement>();\n /** True while a force-duration nudge is in flight — suppresses the transient time/position jump. */\n private _suppressTimeUpdate = false;\n private _activeMediaEl: HTMLMediaElement | null = null;\n private _rateInitialized = false;\n /** Runtime (toggle-driven) transcript visibility. Reset to `true` when a transcript is set. */\n private _transcriptUserVisible = true;\n\n /** The high-level playback lifecycle state of the primary element. */\n private _mediaState: MediaPlaybackState = 'idle';\n /**\n * Whether the buffering spinner is currently visible. Distinct from `_mediaState ===\n * 'buffering'`: the state flips immediately, but the *visible* spinner is debounced by\n * {@link BUFFERING_INDICATOR_DELAY_MS} so instant seeks don't flash it.\n */\n private _bufferingVisible = false;\n /** Pending timer that promotes a `buffering` state to a visible spinner after the delay. */\n private _bufferingTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Per-track computed/supplied waveform peaks (0..1), keyed by track Id. */\n private _peaksByTrackId = new Map<string, number[]>();\n /** Track Ids whose client-side decode failed (→ fall back to a plain progress bar). */\n private _waveformFailedTrackIds = new Set<string>();\n /** Track Ids currently being decoded (avoid duplicate in-flight decodes). */\n private _waveformPendingTrackIds = new Set<string>();\n /** Lazily-created AudioContext used only for client-side peak extraction. */\n private _audioCtx: AudioContext | null = null;\n /** Whether the user prefers reduced motion (suppresses the bar draw-in animation). */\n private _prefersReducedMotion = false;\n\n // ---------------------------------------------------------------------------\n // Public getters (imperative read API + template bindings)\n // ---------------------------------------------------------------------------\n\n get CurrentTimeMs(): number {\n return this._currentTimeMs;\n }\n get DurationMs(): number {\n return this._durationMs;\n }\n get IsPlaying(): boolean {\n return this._isPlaying;\n }\n get PlaybackRate(): number {\n return this._playbackRate;\n }\n get ActiveCueIndex(): number {\n return this._activeCueIndex;\n }\n\n // Template-only convenience getters\n get Muted(): boolean {\n return this._muted;\n }\n get Volume(): number {\n return this._volume;\n }\n get IsFullscreen(): boolean {\n return this._isFullscreen;\n }\n get RateMenuOpen(): boolean {\n return this._rateMenuOpen;\n }\n get HasError(): boolean {\n return this._hasError;\n }\n\n /** The current high-level playback lifecycle state of the primary element. */\n get MediaState(): MediaPlaybackState {\n return this._mediaState;\n }\n /** True during the initial source load (shows the \"Loading…\" stage indicator). */\n get IsLoading(): boolean {\n return this._mediaState === 'loading';\n }\n /**\n * True while buffering — but reflects the *debounced* visible flag, so an instant seek\n * that resolves within {@link BUFFERING_INDICATOR_DELAY_MS} never shows the spinner.\n */\n get IsBuffering(): boolean {\n return this._bufferingVisible;\n }\n /** Whether the stage should show ANY busy indicator (loading or visible buffering). */\n get ShowBusyIndicator(): boolean {\n return this.IsLoading || this.IsBuffering;\n }\n /** The label shown alongside the busy spinner. */\n get BusyLabel(): string {\n return this.IsLoading ? 'Loading…' : 'Buffering…';\n }\n /** A short, screen-reader-friendly status phrase reflecting the current state. */\n get StatusLabel(): string {\n switch (this._mediaState) {\n case 'loading':\n return 'Loading';\n case 'buffering':\n return 'Buffering';\n case 'playing':\n return 'Playing';\n case 'paused':\n return 'Paused';\n case 'ready':\n return 'Ready';\n case 'ended':\n return 'Ended';\n case 'error':\n return 'Error';\n default:\n return 'Idle';\n }\n }\n get HasTracks(): boolean {\n return this._tracks.length > 0;\n }\n /** Whether a transcript (one or more cues) is available, regardless of visibility. */\n get HasTranscript(): boolean {\n return !!this._transcript && this._transcript.length > 0;\n }\n /**\n * Whether the transcript panel should render right now — requires a transcript,\n * the `ShowTranscript` master switch, AND the runtime toggle to be visible.\n */\n get ShowTranscriptPanel(): boolean {\n return resolveTranscriptVisible(this.HasTranscript, this.ShowTranscript, this._transcriptUserVisible);\n }\n /** The current runtime visibility of the transcript (toggle-driven). */\n get TranscriptVisible(): boolean {\n return this._transcriptUserVisible;\n }\n /** Whether the transcript show/hide toggle button should render in the transport. */\n get ShowTranscriptToggleButton(): boolean {\n return resolveTranscriptToggleVisible(this.HasTranscript, this.ShowTranscript, this.ShowTranscriptToggle);\n }\n get ScrubFraction(): number {\n return this._durationMs > 0 ? this._currentTimeMs / this._durationMs : 0;\n }\n get ScrubPercent(): number {\n return Math.min(100, Math.max(0, this.ScrubFraction * 100));\n }\n get PrefersReducedMotion(): boolean {\n return this._prefersReducedMotion;\n }\n\n /** The active audio track that drives the waveform (the first audio track, if any). */\n private get WaveformTrack(): MediaTrack | null {\n return this.IsAudioOnly ? this.AudioTracks[0] ?? null : null;\n }\n\n /**\n * True when the waveform should render as bars — i.e. it's enabled, the active track\n * is audio, and we have peaks (supplied or successfully decoded) for it. When false\n * (decode pending/failed, no track), the template shows a plain progress bar instead.\n */\n get ShowWaveformBars(): boolean {\n const track = this.WaveformTrack;\n if (!this.ShowWaveform || !track) {\n return false;\n }\n return this.peaksForTrack(track) !== null;\n }\n\n /**\n * The normalized `0..1` peaks for the active audio track, or `null` when none are\n * available yet (still decoding) or decoding failed. Reading this lazily kicks off\n * client-side extraction when needed — re-renders/seeks never re-decode (cached by Id).\n */\n get WaveformPeaks(): number[] | null {\n const track = this.WaveformTrack;\n if (!this.ShowWaveform || !track) {\n return null;\n }\n return this.peaksForTrack(track);\n }\n\n /** The played/unplayed split point for the waveform, as a `0..1` fraction. */\n get WaveformPlayedFraction(): number {\n return this.ScrubFraction;\n }\n\n /** The single audio track when this is an audio-only player (drives waveform). */\n get AudioTracks(): MediaTrack[] {\n return this._tracks.filter((t) => t.Kind === 'audio');\n }\n get VideoTracks(): MediaTrack[] {\n return this._tracks.filter((t) => t.Kind === 'video');\n }\n /** True when the layout is a single audio track with no video. */\n get IsAudioOnly(): boolean {\n return this.VideoTracks.length === 0 && this.AudioTracks.length > 0;\n }\n get IsMultiVideo(): boolean {\n return this.VideoTracks.length > 1;\n }\n\n // ---------------------------------------------------------------------------\n // Imperative control API\n // ---------------------------------------------------------------------------\n\n /** Begin playback. Honors {@link BeforePlay}. */\n Play(): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const evt: MediaPlayerCancelableEvent = { Cancel: false };\n this.BeforePlay.emit(evt);\n if (evt.Cancel) {\n return;\n }\n void el.play().catch(() => {\n /* autoplay/user-gesture rejections are non-fatal */\n });\n }\n\n /** Pause playback. Honors {@link BeforePause}. */\n Pause(): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const evt: MediaPlayerCancelableEvent = { Cancel: false };\n this.BeforePause.emit(evt);\n if (evt.Cancel) {\n return;\n }\n el.pause();\n }\n\n /** Toggle play/pause. */\n TogglePlay(): void {\n if (this._isPlaying) {\n this.Pause();\n } else {\n this.Play();\n }\n }\n\n /** Seek to an absolute position in milliseconds. Honors {@link BeforeSeek}. */\n SeekToMs(ms: number): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const target = this.clampMs(ms);\n const evt: MediaSeekEvent = { Cancel: false, FromMs: this._currentTimeMs, ToMs: target };\n this.BeforeSeek.emit(evt);\n if (evt.Cancel) {\n return;\n }\n el.currentTime = target / 1000;\n this._currentTimeMs = target;\n this.AfterSeek.emit(target);\n this.refreshActiveCue();\n this.cdr.markForCheck();\n }\n\n /** Skip forward by {@link SkipSeconds}. */\n SkipForward(): void {\n this.SeekToMs(this._currentTimeMs + this.SkipSeconds * 1000);\n }\n\n /** Skip backward by {@link SkipSeconds}. */\n SkipBackward(): void {\n this.SeekToMs(this._currentTimeMs - this.SkipSeconds * 1000);\n }\n\n /** Set the playback rate. Honors {@link BeforeRateChange}. */\n SetPlaybackRate(rate: number): void {\n const evt: MediaRateEvent = { Cancel: false, FromRate: this._playbackRate, ToRate: rate };\n this.BeforeRateChange.emit(evt);\n if (evt.Cancel) {\n return;\n }\n this._playbackRate = rate;\n this.applyToAllMedia((el) => (el.playbackRate = rate));\n this._rateMenuOpen = false;\n this.AfterRateChange.emit(rate);\n this.cdr.markForCheck();\n }\n\n /**\n * Seek to the cue at `index`. If currently playing, playback continues from the\n * cue's start; if paused, the timeline is repositioned without starting playback.\n */\n SeekToCue(index: number): void {\n const cues = this._transcript;\n if (!cues || index < 0 || index >= cues.length) {\n return;\n }\n const wasPlaying = this._isPlaying;\n this.SeekToMs(cues[index].StartMs);\n if (wasPlaying) {\n // keep playing — currentTime change above does not pause; ensure we're playing\n this.Play();\n }\n // when paused, we leave it paused (timeline repositioned only)\n }\n\n /** Set the volume (0..1). Unmutes if volume > 0. */\n SetVolume(v: number): void {\n this._volume = Math.min(1, Math.max(0, v));\n this._muted = this._volume === 0;\n this.applyToAllMedia((el) => {\n el.volume = this._volume;\n el.muted = this._muted;\n });\n this.cdr.markForCheck();\n }\n\n /** Toggle mute. */\n ToggleMute(): void {\n this._muted = !this._muted;\n this.applyToAllMedia((el) => (el.muted = this._muted));\n this.cdr.markForCheck();\n }\n\n /** Request fullscreen for the player surface (video). */\n EnterFullscreen(): void {\n const target = this.host.nativeElement.querySelector('.mj-media-stage') as HTMLElement | null;\n if (target?.requestFullscreen) {\n void target.requestFullscreen().catch(() => undefined);\n }\n }\n\n /** Exit fullscreen. */\n ExitFullscreen(): void {\n if (document.fullscreenElement && document.exitFullscreen) {\n void document.exitFullscreen().catch(() => undefined);\n }\n }\n\n /** Toggle fullscreen. */\n ToggleFullscreen(): void {\n if (this._isFullscreen) {\n this.ExitFullscreen();\n } else {\n this.EnterFullscreen();\n }\n }\n\n /**\n * Show/hide the transcript panel (pure component state — nothing is persisted).\n * Emits {@link TranscriptVisibilityChanged} with the new visibility.\n */\n ToggleTranscript(): void {\n this._transcriptUserVisible = !this._transcriptUserVisible;\n this.TranscriptVisibilityChanged.emit(this._transcriptUserVisible);\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Media element event handlers (bound in template)\n // ---------------------------------------------------------------------------\n\n /** Initial source fetch began — drives the \"Loading…\" indicator. */\n OnMediaLoadStart(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('loadstart', el);\n }\n\n /** Wire-up when a media element fires its first event — caches the primary element & applies initial state. */\n OnMediaLoadedMetadata(el: HTMLMediaElement): void {\n this._hasError = false;\n if (!this._activeMediaEl) {\n this._activeMediaEl = el;\n }\n this.initializeMediaElement(el);\n const dur = el.duration;\n if (isFinite(dur) && dur > 0) {\n this._durationMs = Math.round(dur * 1000);\n this.DurationChange.emit(this._durationMs);\n } else {\n // MediaRecorder/streamed webm files often carry no duration in their header, so the\n // element reports `Infinity` — which makes fraction-based seeking compute 0 (every\n // timeline click snaps to the start). Nudge the element once to resolve a real duration;\n // this also builds its internal seek index. The resulting `durationchange` is handled in\n // OnMediaDurationChange.\n this.forceDurationResolution(el);\n }\n if (this.StartAtMs != null && el === this._activeMediaEl) {\n el.currentTime = this.clampMs(this.StartAtMs) / 1000;\n }\n if (this.Autoplay && el === this._activeMediaEl) {\n this.Play();\n }\n this.applyMediaEvent('loadedmetadata', el);\n this.cdr.markForCheck();\n }\n\n /** Enough data buffered to begin playback — clears loading/buffering. */\n OnMediaCanPlay(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('canplay', el);\n }\n\n /** Ran out of buffered data mid-playback — enters buffering. */\n OnMediaWaiting(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('waiting', el);\n }\n\n /** Seek began (skip / scrub into un-buffered territory) — show buffering during the seek. */\n OnMediaSeeking(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('seeking', el);\n }\n\n /** Seek completed — clears buffering once the element has playable data. */\n OnMediaSeeked(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('seeked', el);\n }\n\n /** Element is actively playing — clears loading + buffering. */\n OnMediaPlaying(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('playing', el);\n }\n\n /** Conservative buffering signals — only buffer when actively trying to play. */\n OnMediaStalled(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('stalled', el);\n }\n\n OnMediaSuspend(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('suspend', el);\n }\n\n /** Track switch / source cleared — resets the lifecycle. */\n OnMediaEmptied(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('emptied', el);\n }\n\n OnMediaTimeUpdate(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n if (this._suppressTimeUpdate) {\n // Ignore the transient end-seek the duration nudge produces.\n return;\n }\n this._currentTimeMs = Math.round(el.currentTime * 1000);\n this.TimeUpdate.emit(this._currentTimeMs);\n this.refreshActiveCue();\n this.cdr.markForCheck();\n }\n\n OnMediaDurationChange(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n if (isFinite(el.duration)) {\n this._durationMs = Math.round(el.duration * 1000);\n this.DurationChange.emit(this._durationMs);\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Forces a header-less media element (e.g. a MediaRecorder webm that reports `Infinity`\n * duration) to resolve a real, finite duration by briefly seeking far past the end. The browser\n * clamps to the true end, fires `durationchange` with the real value (picked up by\n * {@link OnMediaDurationChange}) and builds its seek index — after which fraction-based seeking\n * works. We then restore the prior position and suppress the transient time jump. Runs at most\n * once per element.\n */\n private forceDurationResolution(el: HTMLMediaElement): void {\n if (this._durationForced.has(el)) {\n return;\n }\n this._durationForced.add(el);\n const restoreSeconds = el.currentTime || 0;\n this._suppressTimeUpdate = true;\n const onResolved = (): void => {\n if (!isFinite(el.duration)) {\n return; // not the real value yet — wait for the next durationchange\n }\n el.removeEventListener('durationchange', onResolved);\n this._suppressTimeUpdate = false;\n try {\n el.currentTime = restoreSeconds;\n } catch {\n /* best effort — restoring position is non-critical */\n }\n };\n el.addEventListener('durationchange', onResolved);\n try {\n el.currentTime = 1e101;\n } catch {\n el.removeEventListener('durationchange', onResolved);\n this._suppressTimeUpdate = false;\n }\n }\n\n OnMediaPlay(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = true;\n this.applyMediaEvent('play', el);\n this.AfterPlay.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaPause(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = false;\n this.applyMediaEvent('pause', el);\n this.AfterPause.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaEnded(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = false;\n this.applyMediaEvent('ended', el);\n this.Ended.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaError(el?: HTMLMediaElement): void {\n this._hasError = true;\n this.applyMediaEvent('error', el ?? this.resolveMediaElement());\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Playback state machine (driven by the pure reducer + buffering debounce)\n // ---------------------------------------------------------------------------\n\n /**\n * Runs the pure {@link nextPlaybackState} reducer for a native media event, commits the\n * resulting state, manages the debounced buffering spinner, and emits {@link StateChanged}\n * on transitions. The single funnel for all media-event → state changes.\n */\n private applyMediaEvent(event: MediaStateEvent, el: HTMLMediaElement | null): void {\n const ctx: MediaStateContext = {\n IsPlaying: this._isPlaying,\n ReadyState: el?.readyState ?? 0,\n Ended: el?.ended ?? false,\n };\n const next = nextPlaybackState(event, this._mediaState, ctx);\n this.setMediaState(next);\n }\n\n /** Commits a new state, syncs the buffering spinner, and emits on change. */\n private setMediaState(next: MediaPlaybackState): void {\n this.syncBufferingIndicator(next);\n if (next !== this._mediaState) {\n this._mediaState = next;\n this.StateChanged.emit(next);\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Keeps the visible buffering spinner in sync with the target state. `loading` shows\n * immediately (no debounce); `buffering` is debounced so instant seeks don't flash it;\n * any non-busy state clears the spinner and cancels a pending show.\n */\n private syncBufferingIndicator(next: MediaPlaybackState): void {\n if (next === 'buffering') {\n if (this._bufferingVisible || this._bufferingTimer) {\n return; // already shown or scheduled\n }\n this._bufferingTimer = setTimeout(() => {\n this._bufferingTimer = null;\n if (this._mediaState === 'buffering') {\n this._bufferingVisible = true;\n this.cdr.markForCheck();\n }\n }, BUFFERING_INDICATOR_DELAY_MS);\n return;\n }\n // Any non-buffering target clears the pending/visible buffering spinner.\n this.clearBufferingTimer();\n if (this._bufferingVisible) {\n this._bufferingVisible = false;\n }\n }\n\n private clearBufferingTimer(): void {\n if (this._bufferingTimer) {\n clearTimeout(this._bufferingTimer);\n this._bufferingTimer = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Scrubber (click + drag) — pointer-based\n // ---------------------------------------------------------------------------\n\n OnScrubPointerDown(event: PointerEvent, trackEl: HTMLElement): void {\n event.preventDefault();\n this._isScrubbing = true;\n (event.target as Element).setPointerCapture?.(event.pointerId);\n this.applyScrubFromPointer(event, trackEl);\n }\n\n OnScrubPointerMove(event: PointerEvent, trackEl: HTMLElement): void {\n if (!this._isScrubbing) {\n return;\n }\n this.applyScrubFromPointer(event, trackEl);\n }\n\n OnScrubPointerUp(event: PointerEvent): void {\n if (!this._isScrubbing) {\n return;\n }\n this._isScrubbing = false;\n (event.target as Element).releasePointerCapture?.(event.pointerId);\n }\n\n // The waveform IS a scrubber: reuse the exact same pointer/keyboard seek logic.\n OnWaveformPointerDown(event: PointerEvent, trackEl: HTMLElement): void {\n this.OnScrubPointerDown(event, trackEl);\n }\n OnWaveformPointerMove(event: PointerEvent, trackEl: HTMLElement): void {\n this.OnScrubPointerMove(event, trackEl);\n }\n OnWaveformPointerUp(event: PointerEvent): void {\n this.OnScrubPointerUp(event);\n }\n\n /** Keyboard support for the scrubber (role=\"slider\"). */\n OnScrubKeyDown(event: KeyboardEvent): void {\n let handled = true;\n switch (event.key) {\n case 'ArrowLeft':\n this.SeekToMs(this._currentTimeMs - 5000);\n break;\n case 'ArrowRight':\n this.SeekToMs(this._currentTimeMs + 5000);\n break;\n case 'Home':\n this.SeekToMs(0);\n break;\n case 'End':\n this.SeekToMs(this._durationMs);\n break;\n default:\n handled = false;\n }\n if (handled) {\n event.preventDefault();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Transcript cue interaction\n // ---------------------------------------------------------------------------\n\n OnCueClicked(index: number): void {\n const cues = this._transcript;\n if (!cues || index < 0 || index >= cues.length) {\n return;\n }\n this.CueClicked.emit({ Cue: cues[index], Index: index });\n this.SeekToCue(index);\n }\n\n OnCueKeyDown(event: KeyboardEvent, index: number): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.OnCueClicked(index);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Rate menu\n // ---------------------------------------------------------------------------\n\n ToggleRateMenu(): void {\n this._rateMenuOpen = !this._rateMenuOpen;\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Volume slider input\n // ---------------------------------------------------------------------------\n\n OnVolumeInput(event: Event): void {\n const value = parseFloat((event.target as HTMLInputElement).value);\n this.SetVolume(value);\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard shortcuts (host-level, when the player has focus)\n // ---------------------------------------------------------------------------\n\n @HostListener('keydown', ['$event'])\n OnHostKeyDown(event: KeyboardEvent): void {\n // ignore typing in form controls (e.g. the volume range / scrubber handle has its own handler)\n const target = event.target as HTMLElement;\n if (target?.tagName === 'INPUT' || target?.getAttribute('role') === 'slider') {\n return;\n }\n switch (event.key) {\n case ' ':\n event.preventDefault();\n this.TogglePlay();\n break;\n case 'ArrowLeft':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs - 5000);\n break;\n case 'ArrowRight':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs + 5000);\n break;\n case 'j':\n case 'J':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs - 10000);\n break;\n case 'l':\n case 'L':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs + 10000);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.SetVolume(this._volume + 0.05);\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.SetVolume(this._volume - 0.05);\n break;\n case 'm':\n case 'M':\n event.preventDefault();\n this.ToggleMute();\n break;\n case 'f':\n case 'F':\n if (this.ShowFullscreen && this.VideoTracks.length > 0) {\n event.preventDefault();\n this.ToggleFullscreen();\n }\n break;\n default:\n break;\n }\n }\n\n @HostListener('document:fullscreenchange')\n OnFullscreenChange(): void {\n this._isFullscreen = !!document.fullscreenElement;\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Formatting helpers (template)\n // ---------------------------------------------------------------------------\n\n /** Formats a millisecond value as `mm:ss` (or `h:mm:ss` for long media). */\n FormatTime(ms: number): string {\n if (!isFinite(ms) || ms < 0) {\n ms = 0;\n }\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const mm = hours > 0 ? String(minutes).padStart(2, '0') : String(minutes);\n const ss = String(seconds).padStart(2, '0');\n return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;\n }\n\n /** Stable color for a speaker label (deterministic hue from the label string). */\n SpeakerColor(label: string | undefined): string {\n if (!label) {\n return 'var(--mj-text-secondary)';\n }\n let hash = 0;\n for (let i = 0; i < label.length; i++) {\n hash = (hash * 31 + label.charCodeAt(i)) & 0xffffffff;\n }\n const hue = Math.abs(hash) % 360;\n return `hsl(${hue}, 55%, 45%)`;\n }\n\n TrackById(_index: number, track: MediaTrack): string {\n return track.Id;\n }\n\n CueTrackById(_index: number, cue: MediaTranscriptCue): string {\n return cue.Id;\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * The element that owns the master timeline. In a single audio track or a single\n * video, that's the primary element. For one-video-plus-audio, the video carries\n * playback (audio track is muted/secondary). For multi-video, the first video leads.\n */\n private resolveMediaElement(): HTMLMediaElement | null {\n if (this._activeMediaEl) {\n return this._activeMediaEl;\n }\n return this.primaryMedia?.nativeElement ?? null;\n }\n\n private initializeMediaElement(el: HTMLMediaElement): void {\n if (!this._rateInitialized) {\n this._playbackRate = this.InitialRate;\n this._volume = this.InitialVolume;\n this._rateInitialized = true;\n }\n el.playbackRate = this._playbackRate;\n el.volume = this._volume;\n el.muted = this._muted;\n }\n\n private applyToAllMedia(fn: (el: HTMLMediaElement) => void): void {\n const els = this.host.nativeElement.querySelectorAll('audio, video');\n els.forEach((el: Element) => fn(el as HTMLMediaElement));\n }\n\n private applyScrubFromPointer(event: PointerEvent, trackEl: HTMLElement): void {\n const rect = trackEl.getBoundingClientRect();\n if (rect.width <= 0) {\n return;\n }\n const fraction = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n this.SeekToMs(fraction * this._durationMs);\n }\n\n private refreshActiveCue(): void {\n const newIndex = computeActiveCueIndex(this._currentTimeMs, this._transcript);\n if (newIndex !== this._activeCueIndex) {\n this._activeCueIndex = newIndex;\n if (newIndex >= 0 && this._transcript) {\n this.CueActivated.emit({ Cue: this._transcript[newIndex], Index: newIndex });\n }\n }\n }\n\n private clampMs(ms: number): number {\n if (ms < 0) {\n return 0;\n }\n if (this._durationMs > 0 && ms > this._durationMs) {\n return this._durationMs;\n }\n return ms;\n }\n\n private resetPlaybackState(): void {\n this._currentTimeMs = 0;\n this._durationMs = 0;\n this._isPlaying = false;\n this._activeCueIndex = -1;\n this._hasError = false;\n this._rateInitialized = false;\n this.clearBufferingTimer();\n this._bufferingVisible = false;\n this.setMediaState(this._tracks.length > 0 ? 'loading' : 'idle');\n }\n\n // ---------------------------------------------------------------------------\n // Waveform peak extraction (client-side, best-effort, cached per track Id)\n // ---------------------------------------------------------------------------\n\n /**\n * Resolves peaks for a track: supplied {@link MediaTrack.Peaks} win (rendered as-is,\n * no decode); otherwise returns any cached/decoded peaks, kicking off a best-effort\n * client-side decode on first miss. Returns `null` while decoding or after a failure.\n */\n private peaksForTrack(track: MediaTrack): number[] | null {\n if (track.Peaks && track.Peaks.length > 0) {\n return track.Peaks;\n }\n const cached = this._peaksByTrackId.get(track.Id);\n if (cached) {\n return cached;\n }\n if (this._waveformFailedTrackIds.has(track.Id)) {\n return null;\n }\n void this.extractPeaks(track);\n return null;\n }\n\n /** Kicks off client-side extraction for every audio track that still needs it. */\n private ensureWaveforms(): void {\n if (!this.ShowWaveform) {\n return;\n }\n const track = this.IsAudioOnly ? this.AudioTracks[0] : null;\n if (track) {\n // Reading via peaksForTrack triggers a decode when needed (and is cache-safe).\n this.peaksForTrack(track);\n }\n }\n\n /**\n * Best-effort: fetch → arrayBuffer → decodeAudioData → downsample channel 0 → cache.\n * Never throws into the view; on any failure marks the track as failed so the template\n * falls back to a plain progress bar (not the old synthetic bars).\n */\n private async extractPeaks(track: MediaTrack): Promise<void> {\n if (this._waveformPendingTrackIds.has(track.Id)) {\n return;\n }\n this._waveformPendingTrackIds.add(track.Id);\n try {\n const ctx = this.resolveAudioContext();\n if (!ctx) {\n this.markWaveformFailed(track.Id);\n return;\n }\n const response = await fetch(track.Url);\n if (!response.ok) {\n this.markWaveformFailed(track.Id);\n return;\n }\n const arrayBuffer = await response.arrayBuffer();\n const audioBuffer = await ctx.decodeAudioData(arrayBuffer.slice(0));\n const channel = audioBuffer.getChannelData(0);\n const peaks = downsamplePeaks(channel, this.WaveformBarCount, 'max-abs');\n this._peaksByTrackId.set(track.Id, peaks);\n this.cdr.markForCheck();\n } catch {\n // CORS, unsupported codec, decode error → graceful fallback (no throw).\n this.markWaveformFailed(track.Id);\n } finally {\n this._waveformPendingTrackIds.delete(track.Id);\n }\n }\n\n private markWaveformFailed(trackId: string): void {\n this._waveformFailedTrackIds.add(trackId);\n this.cdr.markForCheck();\n }\n\n /** Lazily creates a single AudioContext used only for offline peak extraction. */\n private resolveAudioContext(): AudioContext | null {\n if (this._audioCtx) {\n return this._audioCtx;\n }\n const Ctor =\n typeof window !== 'undefined'\n ? window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext\n : undefined;\n if (!Ctor) {\n return null;\n }\n try {\n this._audioCtx = new Ctor();\n return this._audioCtx;\n } catch {\n return null;\n }\n }\n\n private detectReducedMotion(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n } catch {\n return false;\n }\n }\n\n ngOnDestroy(): void {\n this.clearBufferingTimer();\n // object URLs are owned by the wrapper that created them; close our decode context.\n if (this._audioCtx) {\n void this._audioCtx.close().catch(() => undefined);\n this._audioCtx = null;\n }\n }\n}\n","<div\n class=\"mj-media-player\"\n [class.mj-media-player--bottom-transcript]=\"TranscriptPosition === 'bottom'\"\n [class.mj-media-player--has-transcript]=\"ShowTranscriptPanel\"\n [class.mj-media-player--audio]=\"IsAudioOnly\"\n [class.mj-media-player--video]=\"VideoTracks.length > 0\"\n tabindex=\"0\"\n role=\"group\"\n aria-label=\"Media player\"\n>\n @if (!HasTracks) {\n <!-- Empty / no-track state -->\n <div class=\"mj-media-empty\" role=\"status\">\n <i class=\"fa-solid fa-circle-play mj-media-empty__icon\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-empty__text\">No media to play.</span>\n </div>\n } @else {\n <div class=\"mj-media-main\">\n <!-- Media stage -->\n <div class=\"mj-media-stage\">\n @if (HasError) {\n <div class=\"mj-media-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <span>This media could not be played.</span>\n </div>\n }\n\n <!-- Loading / buffering overlay (primary element only). -->\n @if (ShowBusyIndicator && !HasError) {\n <div\n class=\"mj-media-busy\"\n [class.mj-media-busy--static]=\"PrefersReducedMotion\"\n role=\"status\"\n aria-hidden=\"true\"\n >\n <span class=\"mj-media-busy__spinner\"></span>\n <span class=\"mj-media-busy__label\">{{ BusyLabel }}</span>\n </div>\n }\n\n @if (IsAudioOnly) {\n <!-- Single audio track: hidden <audio> + optional waveform -->\n @for (track of AudioTracks; track TrackById($index, track); let first = $first) {\n @if (first) {\n <audio\n #primaryMedia\n class=\"mj-media-audio\"\n [src]=\"track.Url\"\n preload=\"metadata\"\n (loadstart)=\"OnMediaLoadStart($any($event.target))\"\n (loadedmetadata)=\"OnMediaLoadedMetadata($any($event.target))\"\n (canplay)=\"OnMediaCanPlay($any($event.target))\"\n (canplaythrough)=\"OnMediaCanPlay($any($event.target))\"\n (waiting)=\"OnMediaWaiting($any($event.target))\"\n (seeking)=\"OnMediaSeeking($any($event.target))\"\n (seeked)=\"OnMediaSeeked($any($event.target))\"\n (playing)=\"OnMediaPlaying($any($event.target))\"\n (stalled)=\"OnMediaStalled($any($event.target))\"\n (suspend)=\"OnMediaSuspend($any($event.target))\"\n (emptied)=\"OnMediaEmptied($any($event.target))\"\n (timeupdate)=\"OnMediaTimeUpdate($any($event.target))\"\n (durationchange)=\"OnMediaDurationChange($any($event.target))\"\n (play)=\"OnMediaPlay($any($event.target))\"\n (pause)=\"OnMediaPause($any($event.target))\"\n (ended)=\"OnMediaEnded($any($event.target))\"\n (error)=\"OnMediaError($any($event.target))\"\n ></audio>\n }\n }\n @if (ShowWaveform && ShowWaveformBars) {\n <!-- Real audio waveform — doubles as the scrubber (click/drag to seek). -->\n <div\n #waveTrack\n class=\"mj-media-waveform\"\n [class.mj-media-waveform--static]=\"PrefersReducedMotion\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnWaveformPointerDown($event, waveTrack)\"\n (pointermove)=\"OnWaveformPointerMove($event, waveTrack)\"\n (pointerup)=\"OnWaveformPointerUp($event)\"\n (pointercancel)=\"OnWaveformPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n @for (p of WaveformPeaks; track $index; let i = $index; let count = $count) {\n <span\n class=\"mj-media-waveform__bar\"\n [class.mj-media-waveform__bar--played]=\"(i + 1) / count <= WaveformPlayedFraction\"\n [style.height.%]=\"2 + p * 98\"\n ></span>\n }\n <div class=\"mj-media-waveform__progress\" [style.left.%]=\"ScrubPercent\"></div>\n </div>\n } @else if (ShowWaveform) {\n <!-- Decode pending or failed (CORS/codec/etc) → plain progress bar fallback. -->\n <div\n #waveTrack\n class=\"mj-media-waveform-fallback\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnWaveformPointerDown($event, waveTrack)\"\n (pointermove)=\"OnWaveformPointerMove($event, waveTrack)\"\n (pointerup)=\"OnWaveformPointerUp($event)\"\n (pointercancel)=\"OnWaveformPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n <div class=\"mj-media-waveform-fallback__rail\">\n <div class=\"mj-media-waveform-fallback__fill\" [style.width.%]=\"ScrubPercent\"></div>\n </div>\n </div>\n } @else {\n <div class=\"mj-media-audio-art\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-music\"></i>\n </div>\n }\n } @else {\n <!-- Video: single, or responsive grid for multiple -->\n <div\n class=\"mj-media-video-grid\"\n [class.mj-media-video-grid--multi]=\"IsMultiVideo\"\n >\n @for (track of VideoTracks; track TrackById($index, track); let i = $index) {\n <div class=\"mj-media-video-cell\">\n @if (track.Label) {\n <span class=\"mj-media-video-cell__label\">{{ track.Label }}</span>\n }\n @if (i === 0) {\n <video\n #primaryMedia\n class=\"mj-media-video\"\n [src]=\"track.Url\"\n [poster]=\"track.PosterUrl || null\"\n playsinline\n preload=\"metadata\"\n (loadstart)=\"OnMediaLoadStart($any($event.target))\"\n (loadedmetadata)=\"OnMediaLoadedMetadata($any($event.target))\"\n (canplay)=\"OnMediaCanPlay($any($event.target))\"\n (canplaythrough)=\"OnMediaCanPlay($any($event.target))\"\n (waiting)=\"OnMediaWaiting($any($event.target))\"\n (seeking)=\"OnMediaSeeking($any($event.target))\"\n (seeked)=\"OnMediaSeeked($any($event.target))\"\n (playing)=\"OnMediaPlaying($any($event.target))\"\n (stalled)=\"OnMediaStalled($any($event.target))\"\n (suspend)=\"OnMediaSuspend($any($event.target))\"\n (emptied)=\"OnMediaEmptied($any($event.target))\"\n (timeupdate)=\"OnMediaTimeUpdate($any($event.target))\"\n (durationchange)=\"OnMediaDurationChange($any($event.target))\"\n (play)=\"OnMediaPlay($any($event.target))\"\n (pause)=\"OnMediaPause($any($event.target))\"\n (ended)=\"OnMediaEnded($any($event.target))\"\n (error)=\"OnMediaError($any($event.target))\"\n ></video>\n } @else {\n <!-- Secondary videos follow the leader's timeline; no own controls -->\n <video\n class=\"mj-media-video\"\n [src]=\"track.Url\"\n [poster]=\"track.PosterUrl || null\"\n playsinline\n preload=\"metadata\"\n muted\n ></video>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Transport bar -->\n <div class=\"mj-media-transport\">\n <!-- Screen-reader + visible playback status (announced on transitions). -->\n <div\n class=\"mj-media-status\"\n [class.mj-media-status--busy]=\"ShowBusyIndicator\"\n role=\"status\"\n aria-live=\"polite\"\n >\n @if (ShowBusyIndicator) {\n <span class=\"mj-media-status__dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"mj-media-status__text\">{{ StatusLabel }}</span>\n </div>\n\n <!-- Scrubber -->\n <div class=\"mj-media-scrubber-row\">\n <span class=\"mj-media-time\">{{ FormatTime(CurrentTimeMs) }}</span>\n <div\n #scrubTrack\n class=\"mj-media-scrubber\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnScrubPointerDown($event, scrubTrack)\"\n (pointermove)=\"OnScrubPointerMove($event, scrubTrack)\"\n (pointerup)=\"OnScrubPointerUp($event)\"\n (pointercancel)=\"OnScrubPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n <div class=\"mj-media-scrubber__rail\">\n <div class=\"mj-media-scrubber__fill\" [style.width.%]=\"ScrubPercent\"></div>\n </div>\n <div class=\"mj-media-scrubber__handle\" [style.left.%]=\"ScrubPercent\"></div>\n </div>\n <span class=\"mj-media-time mj-media-time--total\">{{ FormatTime(DurationMs) }}</span>\n </div>\n\n <!-- Controls -->\n <div class=\"mj-media-controls\">\n <div class=\"mj-media-controls__left\">\n @if (ShowSkipControls) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"'Skip back ' + SkipSeconds + ' seconds'\"\n title=\"Skip back {{ SkipSeconds }}s\"\n (click)=\"SkipBackward()\"\n >\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-btn__skip-label\">{{ SkipSeconds }}</span>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"mj-media-btn mj-media-btn--primary\"\n [attr.aria-label]=\"IsPlaying ? 'Pause' : 'Play'\"\n [title]=\"IsPlaying ? 'Pause' : 'Play'\"\n (click)=\"TogglePlay()\"\n >\n <i class=\"fa-solid\" [class.fa-pause]=\"IsPlaying\" [class.fa-play]=\"!IsPlaying\" aria-hidden=\"true\"></i>\n </button>\n\n @if (ShowSkipControls) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"'Skip forward ' + SkipSeconds + ' seconds'\"\n title=\"Skip forward {{ SkipSeconds }}s\"\n (click)=\"SkipForward()\"\n >\n <i class=\"fa-solid fa-rotate-right\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-btn__skip-label\">{{ SkipSeconds }}</span>\n </button>\n }\n </div>\n\n <div class=\"mj-media-controls__right\">\n @if (ShowVolume) {\n <div class=\"mj-media-volume\">\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"Muted ? 'Unmute' : 'Mute'\"\n [title]=\"Muted ? 'Unmute' : 'Mute'\"\n (click)=\"ToggleMute()\"\n >\n <i\n class=\"fa-solid\"\n [class.fa-volume-xmark]=\"Muted || Volume === 0\"\n [class.fa-volume-low]=\"!Muted && Volume > 0 && Volume <= 0.5\"\n [class.fa-volume-high]=\"!Muted && Volume > 0.5\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"range\"\n class=\"mj-media-volume__slider\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [value]=\"Muted ? 0 : Volume\"\n aria-label=\"Volume\"\n (input)=\"OnVolumeInput($event)\"\n />\n </div>\n }\n\n @if (ShowSpeedControl) {\n <div class=\"mj-media-rate\">\n <button\n type=\"button\"\n class=\"mj-media-btn mj-media-rate__toggle\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"RateMenuOpen\"\n aria-label=\"Playback speed\"\n title=\"Playback speed\"\n (click)=\"ToggleRateMenu()\"\n >\n {{ PlaybackRate }}&times;\n </button>\n @if (RateMenuOpen) {\n <ul class=\"mj-media-rate__menu\" role=\"menu\">\n @for (rate of PlaybackRates; track rate) {\n <li role=\"none\">\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"rate === PlaybackRate\"\n class=\"mj-media-rate__item\"\n [class.mj-media-rate__item--active]=\"rate === PlaybackRate\"\n (click)=\"SetPlaybackRate(rate)\"\n >\n {{ rate }}&times;\n </button>\n </li>\n }\n </ul>\n }\n </div>\n }\n\n @if (ShowTranscriptToggleButton) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [class.mj-media-btn--active]=\"TranscriptVisible\"\n [attr.aria-pressed]=\"TranscriptVisible\"\n [attr.aria-label]=\"TranscriptVisible ? 'Hide transcript' : 'Show transcript'\"\n [title]=\"TranscriptVisible ? 'Hide transcript' : 'Show transcript'\"\n (click)=\"ToggleTranscript()\"\n >\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n }\n\n @if (ShowFullscreen && VideoTracks.length > 0) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"IsFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n [title]=\"IsFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n (click)=\"ToggleFullscreen()\"\n >\n <i\n class=\"fa-solid\"\n [class.fa-compress]=\"IsFullscreen\"\n [class.fa-expand]=\"!IsFullscreen\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- Transcript panel -->\n @if (ShowTranscriptPanel) {\n <div class=\"mj-media-transcript\" role=\"list\" aria-label=\"Transcript\">\n @for (cue of Transcript; track CueTrackById($index, cue); let i = $index) {\n <button\n type=\"button\"\n role=\"listitem\"\n class=\"mj-media-cue\"\n [class.mj-media-cue--active]=\"i === ActiveCueIndex\"\n [attr.aria-current]=\"i === ActiveCueIndex ? 'true' : null\"\n (click)=\"OnCueClicked(i)\"\n (keydown)=\"OnCueKeyDown($event, i)\"\n >\n <span class=\"mj-media-cue__time\">{{ FormatTime(cue.StartMs) }}</span>\n <span class=\"mj-media-cue__body\">\n @if (cue.SpeakerLabel) {\n <span class=\"mj-media-cue__speaker\" [style.color]=\"SpeakerColor(cue.SpeakerLabel)\">\n {{ cue.SpeakerLabel }}\n </span>\n }\n <span class=\"mj-media-cue__text\">{{ cue.Text }}</span>\n </span>\n </button>\n }\n </div>\n }\n }\n</div>\n"]}
1
+ {"version":3,"file":"media-player.component.js","sourceRoot":"","sources":["../../../src/lib/media-player/media-player.component.ts","../../../src/lib/media-player/media-player.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n OnDestroy,\n Output,\n ViewChild,\n inject,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n MediaCueEvent,\n MediaPlaybackState,\n MediaPlayerCancelableEvent,\n MediaRateEvent,\n MediaSeekEvent,\n MediaTrack,\n MediaTranscriptCue,\n} from '../media-player.types';\nimport { ComputeActiveCueIndex } from './cue-utils';\nimport { MediaStateContext, MediaStateEvent, NextPlaybackState } from './playback-state';\nimport {\n TranscriptPosition,\n ResolveTranscriptToggleVisible,\n ResolveTranscriptVisible,\n} from './transcript-layout';\nimport { DEFAULT_WAVEFORM_BARS, DownsamplePeaks } from './waveform-utils';\n\n/**\n * Delay (ms) before the *buffering* spinner is shown, to avoid flicker on instant seeks\n * that resolve immediately. The *loading* indicator shows with no delay. If a buffering\n * state clears before this elapses, the spinner never appears.\n */\nconst BUFFERING_INDICATOR_DELAY_MS = 200;\n\n/**\n * `mj-media-player` — a generic, framework-agnostic media player.\n *\n * Renders one or many audio/video tracks with a custom transport bar (play/pause,\n * click-and-drag scrubber, skip ±N, playback-rate menu, volume + mute, fullscreen),\n * a **real** audio waveform (decoded client-side, or supplied precomputed via\n * `MediaTrack.Peaks`) that doubles as the scrubber, and an optional time-synced\n * transcript panel whose cues are clickable and auto-highlight as playback advances.\n *\n * This component has ZERO MemberJunction-core dependencies — it is pure Angular and\n * is safe to reuse in any application. The MJStorage binding lives in the separate\n * `mj-storage-media-player` wrapper.\n */\n@Component({\n selector: 'mj-media-player',\n standalone: true,\n imports: [CommonModule],\n templateUrl: './media-player.component.html',\n styleUrls: ['./media-player.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJMediaPlayerComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n private host = inject(ElementRef<HTMLElement>);\n\n constructor() {\n this._prefersReducedMotion = this.detectReducedMotion();\n }\n\n // ---------------------------------------------------------------------------\n // Inputs\n // ---------------------------------------------------------------------------\n\n /** The track(s) to play. One audio track → transport bar; many videos → grid. */\n @Input()\n set Tracks(value: MediaTrack[]) {\n this._tracks = value ?? [];\n this._activeMediaEl = null;\n this.resetPlaybackState();\n this.ensureWaveforms();\n this.cdr.markForCheck();\n }\n get Tracks(): MediaTrack[] {\n return this._tracks;\n }\n private _tracks: MediaTrack[] = [];\n\n /** Optional transcript cues. When set (and `ShowTranscript`), a transcript panel renders. */\n @Input()\n set Transcript(value: MediaTranscriptCue[] | null) {\n this._transcript = value;\n this._activeCueIndex = -1;\n // A newly-supplied transcript defaults to visible (the user can hide it via the toggle).\n this._transcriptUserVisible = true;\n this.cdr.markForCheck();\n }\n get Transcript(): MediaTranscriptCue[] | null {\n return this._transcript;\n }\n private _transcript: MediaTranscriptCue[] | null = null;\n\n /** Begin playback automatically once media is ready. */\n @Input() Autoplay = false;\n /** Start playback at this position (ms) once metadata loads. */\n @Input() StartAtMs: number | null = null;\n /** Whether the transcript panel is shown (when a transcript is provided). */\n @Input() ShowTranscript = true;\n /** Whether the transcript show/hide toggle button renders in the transport bar. */\n @Input() ShowTranscriptToggle = true;\n /** Whether the playback-rate menu is shown. */\n @Input() ShowSpeedControl = true;\n /** Whether the ±skip buttons are shown. */\n @Input() ShowSkipControls = true;\n /** Whether the volume slider + mute are shown. */\n @Input() ShowVolume = true;\n /**\n * Whether the real audio waveform (which doubles as the scrubber) is shown for\n * audio-only tracks. On by default. When a track supplies {@link MediaTrack.Peaks}\n * those are rendered directly; otherwise the player decodes the track URL client-side\n * to extract real peaks, falling back to a plain progress bar if decoding fails.\n */\n @Input() ShowWaveform = true;\n /** Number of bars the waveform renders / downsamples to. */\n @Input() WaveformBarCount = DEFAULT_WAVEFORM_BARS;\n /** Whether the fullscreen button is shown for video. */\n @Input() ShowFullscreen = true;\n /** Number of seconds the skip buttons jump. */\n @Input() SkipSeconds = 30;\n /** The playback rates offered in the rate menu. */\n @Input() PlaybackRates: number[] = [0.5, 1, 1.25, 1.5, 2];\n /** The initial playback rate. */\n @Input() InitialRate = 1;\n /** The initial volume (0..1). */\n @Input() InitialVolume = 1;\n /**\n * Where the transcript panel sits relative to the media. Defaults to `'bottom'`\n * (full width below the player, filling remaining height) which reads better than\n * the narrower side layout; consumers can opt into `'side'`.\n */\n @Input() TranscriptPosition: TranscriptPosition = 'bottom';\n\n // ---------------------------------------------------------------------------\n // Outputs — Before* are cancelable (set event.Cancel = true to abort)\n // ---------------------------------------------------------------------------\n\n @Output() BeforePlay = new EventEmitter<MediaPlayerCancelableEvent>();\n @Output() AfterPlay = new EventEmitter<void>();\n @Output() BeforePause = new EventEmitter<MediaPlayerCancelableEvent>();\n @Output() AfterPause = new EventEmitter<void>();\n @Output() BeforeSeek = new EventEmitter<MediaSeekEvent>();\n @Output() AfterSeek = new EventEmitter<number>();\n @Output() BeforeRateChange = new EventEmitter<MediaRateEvent>();\n @Output() AfterRateChange = new EventEmitter<number>();\n @Output() CueActivated = new EventEmitter<MediaCueEvent>();\n @Output() CueClicked = new EventEmitter<MediaCueEvent>();\n @Output() TimeUpdate = new EventEmitter<number>();\n @Output() DurationChange = new EventEmitter<number>();\n @Output() Ended = new EventEmitter<void>();\n /** Emits whenever the primary element's {@link MediaPlaybackState} transitions. */\n @Output() StateChanged = new EventEmitter<MediaPlaybackState>();\n /** Emits the new visibility (`true` = shown) whenever the transcript is toggled. */\n @Output() TranscriptVisibilityChanged = new EventEmitter<boolean>();\n\n // ---------------------------------------------------------------------------\n // View references\n // ---------------------------------------------------------------------------\n\n /** The primary media element (the single audio/video, or the first video in a grid). */\n @ViewChild('primaryMedia') PrimaryMedia?: ElementRef<HTMLMediaElement>;\n\n /** @deprecated Use {@link PrimaryMedia}. */\n get primaryMedia(): ElementRef<HTMLMediaElement> | undefined {\n return this.PrimaryMedia;\n }\n /** @deprecated Use {@link PrimaryMedia}. */\n set primaryMedia(value: ElementRef<HTMLMediaElement> | undefined) {\n this.PrimaryMedia = value;\n }\n\n // ---------------------------------------------------------------------------\n // Internal state\n // ---------------------------------------------------------------------------\n\n private _currentTimeMs = 0;\n private _durationMs = 0;\n private _isPlaying = false;\n private _playbackRate = 1;\n private _volume = 1;\n private _muted = false;\n private _activeCueIndex = -1;\n private _isFullscreen = false;\n private _isScrubbing = false;\n private _hasError = false;\n private _rateMenuOpen = false;\n /** Media elements we've already nudged to resolve a real (finite) duration. */\n private _durationForced = new WeakSet<HTMLMediaElement>();\n /** True while a force-duration nudge is in flight — suppresses the transient time/position jump. */\n private _suppressTimeUpdate = false;\n private _activeMediaEl: HTMLMediaElement | null = null;\n private _rateInitialized = false;\n /** Runtime (toggle-driven) transcript visibility. Reset to `true` when a transcript is set. */\n private _transcriptUserVisible = true;\n\n /** The high-level playback lifecycle state of the primary element. */\n private _mediaState: MediaPlaybackState = 'idle';\n /**\n * Whether the buffering spinner is currently visible. Distinct from `_mediaState ===\n * 'buffering'`: the state flips immediately, but the *visible* spinner is debounced by\n * {@link BUFFERING_INDICATOR_DELAY_MS} so instant seeks don't flash it.\n */\n private _bufferingVisible = false;\n /** Pending timer that promotes a `buffering` state to a visible spinner after the delay. */\n private _bufferingTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Per-track computed/supplied waveform peaks (0..1), keyed by track Id. */\n private _peaksByTrackId = new Map<string, number[]>();\n /** Track Ids whose client-side decode failed (→ fall back to a plain progress bar). */\n private _waveformFailedTrackIds = new Set<string>();\n /** Track Ids currently being decoded (avoid duplicate in-flight decodes). */\n private _waveformPendingTrackIds = new Set<string>();\n /** Lazily-created AudioContext used only for client-side peak extraction. */\n private _audioCtx: AudioContext | null = null;\n /** Whether the user prefers reduced motion (suppresses the bar draw-in animation). */\n private _prefersReducedMotion = false;\n\n // ---------------------------------------------------------------------------\n // Public getters (imperative read API + template bindings)\n // ---------------------------------------------------------------------------\n\n get CurrentTimeMs(): number {\n return this._currentTimeMs;\n }\n get DurationMs(): number {\n return this._durationMs;\n }\n get IsPlaying(): boolean {\n return this._isPlaying;\n }\n get PlaybackRate(): number {\n return this._playbackRate;\n }\n get ActiveCueIndex(): number {\n return this._activeCueIndex;\n }\n\n // Template-only convenience getters\n get Muted(): boolean {\n return this._muted;\n }\n get Volume(): number {\n return this._volume;\n }\n get IsFullscreen(): boolean {\n return this._isFullscreen;\n }\n get RateMenuOpen(): boolean {\n return this._rateMenuOpen;\n }\n get HasError(): boolean {\n return this._hasError;\n }\n\n /** The current high-level playback lifecycle state of the primary element. */\n get MediaState(): MediaPlaybackState {\n return this._mediaState;\n }\n /** True during the initial source load (shows the \"Loading…\" stage indicator). */\n get IsLoading(): boolean {\n return this._mediaState === 'loading';\n }\n /**\n * True while buffering — but reflects the *debounced* visible flag, so an instant seek\n * that resolves within {@link BUFFERING_INDICATOR_DELAY_MS} never shows the spinner.\n */\n get IsBuffering(): boolean {\n return this._bufferingVisible;\n }\n /** Whether the stage should show ANY busy indicator (loading or visible buffering). */\n get ShowBusyIndicator(): boolean {\n return this.IsLoading || this.IsBuffering;\n }\n /** The label shown alongside the busy spinner. */\n get BusyLabel(): string {\n return this.IsLoading ? 'Loading…' : 'Buffering…';\n }\n /** A short, screen-reader-friendly status phrase reflecting the current state. */\n get StatusLabel(): string {\n switch (this._mediaState) {\n case 'loading':\n return 'Loading';\n case 'buffering':\n return 'Buffering';\n case 'playing':\n return 'Playing';\n case 'paused':\n return 'Paused';\n case 'ready':\n return 'Ready';\n case 'ended':\n return 'Ended';\n case 'error':\n return 'Error';\n default:\n return 'Idle';\n }\n }\n get HasTracks(): boolean {\n return this._tracks.length > 0;\n }\n /** Whether a transcript (one or more cues) is available, regardless of visibility. */\n get HasTranscript(): boolean {\n return !!this._transcript && this._transcript.length > 0;\n }\n /**\n * Whether the transcript panel should render right now — requires a transcript,\n * the `ShowTranscript` master switch, AND the runtime toggle to be visible.\n */\n get ShowTranscriptPanel(): boolean {\n return ResolveTranscriptVisible(this.HasTranscript, this.ShowTranscript, this._transcriptUserVisible);\n }\n /** The current runtime visibility of the transcript (toggle-driven). */\n get TranscriptVisible(): boolean {\n return this._transcriptUserVisible;\n }\n /** Whether the transcript show/hide toggle button should render in the transport. */\n get ShowTranscriptToggleButton(): boolean {\n return ResolveTranscriptToggleVisible(this.HasTranscript, this.ShowTranscript, this.ShowTranscriptToggle);\n }\n get ScrubFraction(): number {\n return this._durationMs > 0 ? this._currentTimeMs / this._durationMs : 0;\n }\n get ScrubPercent(): number {\n return Math.min(100, Math.max(0, this.ScrubFraction * 100));\n }\n get PrefersReducedMotion(): boolean {\n return this._prefersReducedMotion;\n }\n\n /** The active audio track that drives the waveform (the first audio track, if any). */\n private get waveformTrack(): MediaTrack | null {\n return this.IsAudioOnly ? this.AudioTracks[0] ?? null : null;\n }\n\n /**\n * True when the waveform should render as bars — i.e. it's enabled, the active track\n * is audio, and we have peaks (supplied or successfully decoded) for it. When false\n * (decode pending/failed, no track), the template shows a plain progress bar instead.\n */\n get ShowWaveformBars(): boolean {\n const track = this.waveformTrack;\n if (!this.ShowWaveform || !track) {\n return false;\n }\n return this.peaksForTrack(track) !== null;\n }\n\n /**\n * The normalized `0..1` peaks for the active audio track, or `null` when none are\n * available yet (still decoding) or decoding failed. Reading this lazily kicks off\n * client-side extraction when needed — re-renders/seeks never re-decode (cached by Id).\n */\n get WaveformPeaks(): number[] | null {\n const track = this.waveformTrack;\n if (!this.ShowWaveform || !track) {\n return null;\n }\n return this.peaksForTrack(track);\n }\n\n /** The played/unplayed split point for the waveform, as a `0..1` fraction. */\n get WaveformPlayedFraction(): number {\n return this.ScrubFraction;\n }\n\n /** The single audio track when this is an audio-only player (drives waveform). */\n get AudioTracks(): MediaTrack[] {\n return this._tracks.filter((t) => t.Kind === 'audio');\n }\n get VideoTracks(): MediaTrack[] {\n return this._tracks.filter((t) => t.Kind === 'video');\n }\n /** True when the layout is a single audio track with no video. */\n get IsAudioOnly(): boolean {\n return this.VideoTracks.length === 0 && this.AudioTracks.length > 0;\n }\n get IsMultiVideo(): boolean {\n return this.VideoTracks.length > 1;\n }\n\n // ---------------------------------------------------------------------------\n // Imperative control API\n // ---------------------------------------------------------------------------\n\n /** Begin playback. Honors {@link BeforePlay}. */\n Play(): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const evt: MediaPlayerCancelableEvent = { Cancel: false };\n this.BeforePlay.emit(evt);\n if (evt.Cancel) {\n return;\n }\n void el.play().catch(() => {\n /* autoplay/user-gesture rejections are non-fatal */\n });\n }\n\n /** Pause playback. Honors {@link BeforePause}. */\n Pause(): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const evt: MediaPlayerCancelableEvent = { Cancel: false };\n this.BeforePause.emit(evt);\n if (evt.Cancel) {\n return;\n }\n el.pause();\n }\n\n /** Toggle play/pause. */\n TogglePlay(): void {\n if (this._isPlaying) {\n this.Pause();\n } else {\n this.Play();\n }\n }\n\n /** Seek to an absolute position in milliseconds. Honors {@link BeforeSeek}. */\n SeekToMs(ms: number): void {\n const el = this.resolveMediaElement();\n if (!el) {\n return;\n }\n const target = this.clampMs(ms);\n const evt: MediaSeekEvent = { Cancel: false, FromMs: this._currentTimeMs, ToMs: target };\n this.BeforeSeek.emit(evt);\n if (evt.Cancel) {\n return;\n }\n el.currentTime = target / 1000;\n this._currentTimeMs = target;\n this.AfterSeek.emit(target);\n this.refreshActiveCue();\n this.cdr.markForCheck();\n }\n\n /** Skip forward by {@link SkipSeconds}. */\n SkipForward(): void {\n this.SeekToMs(this._currentTimeMs + this.SkipSeconds * 1000);\n }\n\n /** Skip backward by {@link SkipSeconds}. */\n SkipBackward(): void {\n this.SeekToMs(this._currentTimeMs - this.SkipSeconds * 1000);\n }\n\n /** Set the playback rate. Honors {@link BeforeRateChange}. */\n SetPlaybackRate(rate: number): void {\n const evt: MediaRateEvent = { Cancel: false, FromRate: this._playbackRate, ToRate: rate };\n this.BeforeRateChange.emit(evt);\n if (evt.Cancel) {\n return;\n }\n this._playbackRate = rate;\n this.applyToAllMedia((el) => (el.playbackRate = rate));\n this._rateMenuOpen = false;\n this.AfterRateChange.emit(rate);\n this.cdr.markForCheck();\n }\n\n /**\n * Seek to the cue at `index`. If currently playing, playback continues from the\n * cue's start; if paused, the timeline is repositioned without starting playback.\n */\n SeekToCue(index: number): void {\n const cues = this._transcript;\n if (!cues || index < 0 || index >= cues.length) {\n return;\n }\n const wasPlaying = this._isPlaying;\n this.SeekToMs(cues[index].StartMs);\n if (wasPlaying) {\n // keep playing — currentTime change above does not pause; ensure we're playing\n this.Play();\n }\n // when paused, we leave it paused (timeline repositioned only)\n }\n\n /** Set the volume (0..1). Unmutes if volume > 0. */\n SetVolume(v: number): void {\n this._volume = Math.min(1, Math.max(0, v));\n this._muted = this._volume === 0;\n this.applyToAllMedia((el) => {\n el.volume = this._volume;\n el.muted = this._muted;\n });\n this.cdr.markForCheck();\n }\n\n /** Toggle mute. */\n ToggleMute(): void {\n this._muted = !this._muted;\n this.applyToAllMedia((el) => (el.muted = this._muted));\n this.cdr.markForCheck();\n }\n\n /** Request fullscreen for the player surface (video). */\n EnterFullscreen(): void {\n const target = this.host.nativeElement.querySelector('.mj-media-stage') as HTMLElement | null;\n if (target?.requestFullscreen) {\n void target.requestFullscreen().catch(() => undefined);\n }\n }\n\n /** Exit fullscreen. */\n ExitFullscreen(): void {\n if (document.fullscreenElement && document.exitFullscreen) {\n void document.exitFullscreen().catch(() => undefined);\n }\n }\n\n /** Toggle fullscreen. */\n ToggleFullscreen(): void {\n if (this._isFullscreen) {\n this.ExitFullscreen();\n } else {\n this.EnterFullscreen();\n }\n }\n\n /**\n * Show/hide the transcript panel (pure component state — nothing is persisted).\n * Emits {@link TranscriptVisibilityChanged} with the new visibility.\n */\n ToggleTranscript(): void {\n this._transcriptUserVisible = !this._transcriptUserVisible;\n this.TranscriptVisibilityChanged.emit(this._transcriptUserVisible);\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Media element event handlers (bound in template)\n // ---------------------------------------------------------------------------\n\n /** Initial source fetch began — drives the \"Loading…\" indicator. */\n OnMediaLoadStart(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('loadstart', el);\n }\n\n /** Wire-up when a media element fires its first event — caches the primary element & applies initial state. */\n OnMediaLoadedMetadata(el: HTMLMediaElement): void {\n this._hasError = false;\n if (!this._activeMediaEl) {\n this._activeMediaEl = el;\n }\n this.initializeMediaElement(el);\n const dur = el.duration;\n if (isFinite(dur) && dur > 0) {\n this._durationMs = Math.round(dur * 1000);\n this.DurationChange.emit(this._durationMs);\n } else {\n // MediaRecorder/streamed webm files often carry no duration in their header, so the\n // element reports `Infinity` — which makes fraction-based seeking compute 0 (every\n // timeline click snaps to the start). Nudge the element once to resolve a real duration;\n // this also builds its internal seek index. The resulting `durationchange` is handled in\n // OnMediaDurationChange.\n this.forceDurationResolution(el);\n }\n if (this.StartAtMs != null && el === this._activeMediaEl) {\n el.currentTime = this.clampMs(this.StartAtMs) / 1000;\n }\n if (this.Autoplay && el === this._activeMediaEl) {\n this.Play();\n }\n this.applyMediaEvent('loadedmetadata', el);\n this.cdr.markForCheck();\n }\n\n /** Enough data buffered to begin playback — clears loading/buffering. */\n OnMediaCanPlay(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('canplay', el);\n }\n\n /** Ran out of buffered data mid-playback — enters buffering. */\n OnMediaWaiting(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('waiting', el);\n }\n\n /** Seek began (skip / scrub into un-buffered territory) — show buffering during the seek. */\n OnMediaSeeking(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('seeking', el);\n }\n\n /** Seek completed — clears buffering once the element has playable data. */\n OnMediaSeeked(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('seeked', el);\n }\n\n /** Element is actively playing — clears loading + buffering. */\n OnMediaPlaying(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('playing', el);\n }\n\n /** Conservative buffering signals — only buffer when actively trying to play. */\n OnMediaStalled(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('stalled', el);\n }\n\n OnMediaSuspend(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('suspend', el);\n }\n\n /** Track switch / source cleared — resets the lifecycle. */\n OnMediaEmptied(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this.applyMediaEvent('emptied', el);\n }\n\n OnMediaTimeUpdate(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n if (this._suppressTimeUpdate) {\n // Ignore the transient end-seek the duration nudge produces.\n return;\n }\n this._currentTimeMs = Math.round(el.currentTime * 1000);\n this.TimeUpdate.emit(this._currentTimeMs);\n this.refreshActiveCue();\n this.cdr.markForCheck();\n }\n\n OnMediaDurationChange(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n if (isFinite(el.duration)) {\n this._durationMs = Math.round(el.duration * 1000);\n this.DurationChange.emit(this._durationMs);\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Forces a header-less media element (e.g. a MediaRecorder webm that reports `Infinity`\n * duration) to resolve a real, finite duration by briefly seeking far past the end. The browser\n * clamps to the true end, fires `durationchange` with the real value (picked up by\n * {@link OnMediaDurationChange}) and builds its seek index — after which fraction-based seeking\n * works. We then restore the prior position and suppress the transient time jump. Runs at most\n * once per element.\n */\n private forceDurationResolution(el: HTMLMediaElement): void {\n if (this._durationForced.has(el)) {\n return;\n }\n this._durationForced.add(el);\n const restoreSeconds = el.currentTime || 0;\n this._suppressTimeUpdate = true;\n const onResolved = (): void => {\n if (!isFinite(el.duration)) {\n return; // not the real value yet — wait for the next durationchange\n }\n el.removeEventListener('durationchange', onResolved);\n this._suppressTimeUpdate = false;\n try {\n el.currentTime = restoreSeconds;\n } catch {\n /* best effort — restoring position is non-critical */\n }\n };\n el.addEventListener('durationchange', onResolved);\n try {\n el.currentTime = 1e101;\n } catch {\n el.removeEventListener('durationchange', onResolved);\n this._suppressTimeUpdate = false;\n }\n }\n\n OnMediaPlay(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = true;\n this.applyMediaEvent('play', el);\n this.AfterPlay.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaPause(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = false;\n this.applyMediaEvent('pause', el);\n this.AfterPause.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaEnded(el: HTMLMediaElement): void {\n if (el !== this.resolveMediaElement()) {\n return;\n }\n this._isPlaying = false;\n this.applyMediaEvent('ended', el);\n this.Ended.emit();\n this.cdr.markForCheck();\n }\n\n OnMediaError(el?: HTMLMediaElement): void {\n this._hasError = true;\n this.applyMediaEvent('error', el ?? this.resolveMediaElement());\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Playback state machine (driven by the pure reducer + buffering debounce)\n // ---------------------------------------------------------------------------\n\n /**\n * Runs the pure {@link nextPlaybackState} reducer for a native media event, commits the\n * resulting state, manages the debounced buffering spinner, and emits {@link StateChanged}\n * on transitions. The single funnel for all media-event → state changes.\n */\n private applyMediaEvent(event: MediaStateEvent, el: HTMLMediaElement | null): void {\n const ctx: MediaStateContext = {\n IsPlaying: this._isPlaying,\n ReadyState: el?.readyState ?? 0,\n Ended: el?.ended ?? false,\n };\n const next = NextPlaybackState(event, this._mediaState, ctx);\n this.setMediaState(next);\n }\n\n /** Commits a new state, syncs the buffering spinner, and emits on change. */\n private setMediaState(next: MediaPlaybackState): void {\n this.syncBufferingIndicator(next);\n if (next !== this._mediaState) {\n this._mediaState = next;\n this.StateChanged.emit(next);\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Keeps the visible buffering spinner in sync with the target state. `loading` shows\n * immediately (no debounce); `buffering` is debounced so instant seeks don't flash it;\n * any non-busy state clears the spinner and cancels a pending show.\n */\n private syncBufferingIndicator(next: MediaPlaybackState): void {\n if (next === 'buffering') {\n if (this._bufferingVisible || this._bufferingTimer) {\n return; // already shown or scheduled\n }\n this._bufferingTimer = setTimeout(() => {\n this._bufferingTimer = null;\n if (this._mediaState === 'buffering') {\n this._bufferingVisible = true;\n this.cdr.markForCheck();\n }\n }, BUFFERING_INDICATOR_DELAY_MS);\n return;\n }\n // Any non-buffering target clears the pending/visible buffering spinner.\n this.clearBufferingTimer();\n if (this._bufferingVisible) {\n this._bufferingVisible = false;\n }\n }\n\n private clearBufferingTimer(): void {\n if (this._bufferingTimer) {\n clearTimeout(this._bufferingTimer);\n this._bufferingTimer = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Scrubber (click + drag) — pointer-based\n // ---------------------------------------------------------------------------\n\n OnScrubPointerDown(event: PointerEvent, trackEl: HTMLElement): void {\n event.preventDefault();\n this._isScrubbing = true;\n (event.target as Element).setPointerCapture?.(event.pointerId);\n this.applyScrubFromPointer(event, trackEl);\n }\n\n OnScrubPointerMove(event: PointerEvent, trackEl: HTMLElement): void {\n if (!this._isScrubbing) {\n return;\n }\n this.applyScrubFromPointer(event, trackEl);\n }\n\n OnScrubPointerUp(event: PointerEvent): void {\n if (!this._isScrubbing) {\n return;\n }\n this._isScrubbing = false;\n (event.target as Element).releasePointerCapture?.(event.pointerId);\n }\n\n // The waveform IS a scrubber: reuse the exact same pointer/keyboard seek logic.\n OnWaveformPointerDown(event: PointerEvent, trackEl: HTMLElement): void {\n this.OnScrubPointerDown(event, trackEl);\n }\n OnWaveformPointerMove(event: PointerEvent, trackEl: HTMLElement): void {\n this.OnScrubPointerMove(event, trackEl);\n }\n OnWaveformPointerUp(event: PointerEvent): void {\n this.OnScrubPointerUp(event);\n }\n\n /** Keyboard support for the scrubber (role=\"slider\"). */\n OnScrubKeyDown(event: KeyboardEvent): void {\n let handled = true;\n switch (event.key) {\n case 'ArrowLeft':\n this.SeekToMs(this._currentTimeMs - 5000);\n break;\n case 'ArrowRight':\n this.SeekToMs(this._currentTimeMs + 5000);\n break;\n case 'Home':\n this.SeekToMs(0);\n break;\n case 'End':\n this.SeekToMs(this._durationMs);\n break;\n default:\n handled = false;\n }\n if (handled) {\n event.preventDefault();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Transcript cue interaction\n // ---------------------------------------------------------------------------\n\n OnCueClicked(index: number): void {\n const cues = this._transcript;\n if (!cues || index < 0 || index >= cues.length) {\n return;\n }\n this.CueClicked.emit({ Cue: cues[index], Index: index });\n this.SeekToCue(index);\n }\n\n OnCueKeyDown(event: KeyboardEvent, index: number): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.OnCueClicked(index);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Rate menu\n // ---------------------------------------------------------------------------\n\n ToggleRateMenu(): void {\n this._rateMenuOpen = !this._rateMenuOpen;\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Volume slider input\n // ---------------------------------------------------------------------------\n\n OnVolumeInput(event: Event): void {\n const value = parseFloat((event.target as HTMLInputElement).value);\n this.SetVolume(value);\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard shortcuts (host-level, when the player has focus)\n // ---------------------------------------------------------------------------\n\n @HostListener('keydown', ['$event'])\n OnHostKeyDown(event: KeyboardEvent): void {\n // ignore typing in form controls (e.g. the volume range / scrubber handle has its own handler)\n const target = event.target as HTMLElement;\n if (target?.tagName === 'INPUT' || target?.getAttribute('role') === 'slider') {\n return;\n }\n switch (event.key) {\n case ' ':\n event.preventDefault();\n this.TogglePlay();\n break;\n case 'ArrowLeft':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs - 5000);\n break;\n case 'ArrowRight':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs + 5000);\n break;\n case 'j':\n case 'J':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs - 10000);\n break;\n case 'l':\n case 'L':\n event.preventDefault();\n this.SeekToMs(this._currentTimeMs + 10000);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.SetVolume(this._volume + 0.05);\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.SetVolume(this._volume - 0.05);\n break;\n case 'm':\n case 'M':\n event.preventDefault();\n this.ToggleMute();\n break;\n case 'f':\n case 'F':\n if (this.ShowFullscreen && this.VideoTracks.length > 0) {\n event.preventDefault();\n this.ToggleFullscreen();\n }\n break;\n default:\n break;\n }\n }\n\n @HostListener('document:fullscreenchange')\n OnFullscreenChange(): void {\n this._isFullscreen = !!document.fullscreenElement;\n this.cdr.markForCheck();\n }\n\n // ---------------------------------------------------------------------------\n // Formatting helpers (template)\n // ---------------------------------------------------------------------------\n\n /** Formats a millisecond value as `mm:ss` (or `h:mm:ss` for long media). */\n FormatTime(ms: number): string {\n if (!isFinite(ms) || ms < 0) {\n ms = 0;\n }\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n const mm = hours > 0 ? String(minutes).padStart(2, '0') : String(minutes);\n const ss = String(seconds).padStart(2, '0');\n return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;\n }\n\n /** Stable color for a speaker label (deterministic hue from the label string). */\n SpeakerColor(label: string | undefined): string {\n if (!label) {\n return 'var(--mj-text-secondary)';\n }\n let hash = 0;\n for (let i = 0; i < label.length; i++) {\n hash = (hash * 31 + label.charCodeAt(i)) & 0xffffffff;\n }\n const hue = Math.abs(hash) % 360;\n return `hsl(${hue}, 55%, 45%)`;\n }\n\n TrackById(_index: number, track: MediaTrack): string {\n return track.Id;\n }\n\n CueTrackById(_index: number, cue: MediaTranscriptCue): string {\n return cue.Id;\n }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * The element that owns the master timeline. In a single audio track or a single\n * video, that's the primary element. For one-video-plus-audio, the video carries\n * playback (audio track is muted/secondary). For multi-video, the first video leads.\n */\n private resolveMediaElement(): HTMLMediaElement | null {\n if (this._activeMediaEl) {\n return this._activeMediaEl;\n }\n return this.PrimaryMedia?.nativeElement ?? null;\n }\n\n private initializeMediaElement(el: HTMLMediaElement): void {\n if (!this._rateInitialized) {\n this._playbackRate = this.InitialRate;\n this._volume = this.InitialVolume;\n this._rateInitialized = true;\n }\n el.playbackRate = this._playbackRate;\n el.volume = this._volume;\n el.muted = this._muted;\n }\n\n private applyToAllMedia(fn: (el: HTMLMediaElement) => void): void {\n const els = this.host.nativeElement.querySelectorAll('audio, video');\n els.forEach((el: Element) => fn(el as HTMLMediaElement));\n }\n\n private applyScrubFromPointer(event: PointerEvent, trackEl: HTMLElement): void {\n const rect = trackEl.getBoundingClientRect();\n if (rect.width <= 0) {\n return;\n }\n const fraction = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));\n this.SeekToMs(fraction * this._durationMs);\n }\n\n private refreshActiveCue(): void {\n const newIndex = ComputeActiveCueIndex(this._currentTimeMs, this._transcript);\n if (newIndex !== this._activeCueIndex) {\n this._activeCueIndex = newIndex;\n if (newIndex >= 0 && this._transcript) {\n this.CueActivated.emit({ Cue: this._transcript[newIndex], Index: newIndex });\n }\n }\n }\n\n private clampMs(ms: number): number {\n if (ms < 0) {\n return 0;\n }\n if (this._durationMs > 0 && ms > this._durationMs) {\n return this._durationMs;\n }\n return ms;\n }\n\n private resetPlaybackState(): void {\n this._currentTimeMs = 0;\n this._durationMs = 0;\n this._isPlaying = false;\n this._activeCueIndex = -1;\n this._hasError = false;\n this._rateInitialized = false;\n this.clearBufferingTimer();\n this._bufferingVisible = false;\n this.setMediaState(this._tracks.length > 0 ? 'loading' : 'idle');\n }\n\n // ---------------------------------------------------------------------------\n // Waveform peak extraction (client-side, best-effort, cached per track Id)\n // ---------------------------------------------------------------------------\n\n /**\n * Resolves peaks for a track: supplied {@link MediaTrack.Peaks} win (rendered as-is,\n * no decode); otherwise returns any cached/decoded peaks, kicking off a best-effort\n * client-side decode on first miss. Returns `null` while decoding or after a failure.\n */\n private peaksForTrack(track: MediaTrack): number[] | null {\n if (track.Peaks && track.Peaks.length > 0) {\n return track.Peaks;\n }\n const cached = this._peaksByTrackId.get(track.Id);\n if (cached) {\n return cached;\n }\n if (this._waveformFailedTrackIds.has(track.Id)) {\n return null;\n }\n void this.extractPeaks(track);\n return null;\n }\n\n /** Kicks off client-side extraction for every audio track that still needs it. */\n private ensureWaveforms(): void {\n if (!this.ShowWaveform) {\n return;\n }\n const track = this.IsAudioOnly ? this.AudioTracks[0] : null;\n if (track) {\n // Reading via peaksForTrack triggers a decode when needed (and is cache-safe).\n this.peaksForTrack(track);\n }\n }\n\n /**\n * Best-effort: fetch → arrayBuffer → decodeAudioData → downsample channel 0 → cache.\n * Never throws into the view; on any failure marks the track as failed so the template\n * falls back to a plain progress bar (not the old synthetic bars).\n */\n private async extractPeaks(track: MediaTrack): Promise<void> {\n if (this._waveformPendingTrackIds.has(track.Id)) {\n return;\n }\n this._waveformPendingTrackIds.add(track.Id);\n try {\n const ctx = this.resolveAudioContext();\n if (!ctx) {\n this.markWaveformFailed(track.Id);\n return;\n }\n const response = await fetch(track.Url);\n if (!response.ok) {\n this.markWaveformFailed(track.Id);\n return;\n }\n const arrayBuffer = await response.arrayBuffer();\n const audioBuffer = await ctx.decodeAudioData(arrayBuffer.slice(0));\n const channel = audioBuffer.getChannelData(0);\n const peaks = DownsamplePeaks(channel, this.WaveformBarCount, 'max-abs');\n this._peaksByTrackId.set(track.Id, peaks);\n this.cdr.markForCheck();\n } catch {\n // CORS, unsupported codec, decode error → graceful fallback (no throw).\n this.markWaveformFailed(track.Id);\n } finally {\n this._waveformPendingTrackIds.delete(track.Id);\n }\n }\n\n private markWaveformFailed(trackId: string): void {\n this._waveformFailedTrackIds.add(trackId);\n this.cdr.markForCheck();\n }\n\n /** Lazily creates a single AudioContext used only for offline peak extraction. */\n private resolveAudioContext(): AudioContext | null {\n if (this._audioCtx) {\n return this._audioCtx;\n }\n const Ctor =\n typeof window !== 'undefined'\n ? window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext\n : undefined;\n if (!Ctor) {\n return null;\n }\n try {\n this._audioCtx = new Ctor();\n return this._audioCtx;\n } catch {\n return null;\n }\n }\n\n private detectReducedMotion(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n } catch {\n return false;\n }\n }\n\n ngOnDestroy(): void {\n this.clearBufferingTimer();\n // object URLs are owned by the wrapper that created them; close our decode context.\n if (this._audioCtx) {\n void this._audioCtx.close().catch(() => undefined);\n this._audioCtx = null;\n }\n }\n}\n","<div\n class=\"mj-media-player\"\n [class.mj-media-player--bottom-transcript]=\"TranscriptPosition === 'bottom'\"\n [class.mj-media-player--has-transcript]=\"ShowTranscriptPanel\"\n [class.mj-media-player--audio]=\"IsAudioOnly\"\n [class.mj-media-player--video]=\"VideoTracks.length > 0\"\n tabindex=\"0\"\n role=\"group\"\n aria-label=\"Media player\"\n>\n @if (!HasTracks) {\n <!-- Empty / no-track state -->\n <div class=\"mj-media-empty\" role=\"status\">\n <i class=\"fa-solid fa-circle-play mj-media-empty__icon\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-empty__text\">No media to play.</span>\n </div>\n } @else {\n <div class=\"mj-media-main\">\n <!-- Media stage -->\n <div class=\"mj-media-stage\">\n @if (HasError) {\n <div class=\"mj-media-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <span>This media could not be played.</span>\n </div>\n }\n\n <!-- Loading / buffering overlay (primary element only). -->\n @if (ShowBusyIndicator && !HasError) {\n <div\n class=\"mj-media-busy\"\n [class.mj-media-busy--static]=\"PrefersReducedMotion\"\n role=\"status\"\n aria-hidden=\"true\"\n >\n <span class=\"mj-media-busy__spinner\"></span>\n <span class=\"mj-media-busy__label\">{{ BusyLabel }}</span>\n </div>\n }\n\n @if (IsAudioOnly) {\n <!-- Single audio track: hidden <audio> + optional waveform -->\n @for (track of AudioTracks; track TrackById($index, track); let first = $first) {\n @if (first) {\n <audio\n #primaryMedia\n class=\"mj-media-audio\"\n [src]=\"track.Url\"\n preload=\"metadata\"\n (loadstart)=\"OnMediaLoadStart($any($event.target))\"\n (loadedmetadata)=\"OnMediaLoadedMetadata($any($event.target))\"\n (canplay)=\"OnMediaCanPlay($any($event.target))\"\n (canplaythrough)=\"OnMediaCanPlay($any($event.target))\"\n (waiting)=\"OnMediaWaiting($any($event.target))\"\n (seeking)=\"OnMediaSeeking($any($event.target))\"\n (seeked)=\"OnMediaSeeked($any($event.target))\"\n (playing)=\"OnMediaPlaying($any($event.target))\"\n (stalled)=\"OnMediaStalled($any($event.target))\"\n (suspend)=\"OnMediaSuspend($any($event.target))\"\n (emptied)=\"OnMediaEmptied($any($event.target))\"\n (timeupdate)=\"OnMediaTimeUpdate($any($event.target))\"\n (durationchange)=\"OnMediaDurationChange($any($event.target))\"\n (play)=\"OnMediaPlay($any($event.target))\"\n (pause)=\"OnMediaPause($any($event.target))\"\n (ended)=\"OnMediaEnded($any($event.target))\"\n (error)=\"OnMediaError($any($event.target))\"\n ></audio>\n }\n }\n @if (ShowWaveform && ShowWaveformBars) {\n <!-- Real audio waveform — doubles as the scrubber (click/drag to seek). -->\n <div\n #waveTrack\n class=\"mj-media-waveform\"\n [class.mj-media-waveform--static]=\"PrefersReducedMotion\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnWaveformPointerDown($event, waveTrack)\"\n (pointermove)=\"OnWaveformPointerMove($event, waveTrack)\"\n (pointerup)=\"OnWaveformPointerUp($event)\"\n (pointercancel)=\"OnWaveformPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n @for (p of WaveformPeaks; track $index; let i = $index; let count = $count) {\n <span\n class=\"mj-media-waveform__bar\"\n [class.mj-media-waveform__bar--played]=\"(i + 1) / count <= WaveformPlayedFraction\"\n [style.height.%]=\"2 + p * 98\"\n ></span>\n }\n <div class=\"mj-media-waveform__progress\" [style.left.%]=\"ScrubPercent\"></div>\n </div>\n } @else if (ShowWaveform) {\n <!-- Decode pending or failed (CORS/codec/etc) → plain progress bar fallback. -->\n <div\n #waveTrack\n class=\"mj-media-waveform-fallback\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnWaveformPointerDown($event, waveTrack)\"\n (pointermove)=\"OnWaveformPointerMove($event, waveTrack)\"\n (pointerup)=\"OnWaveformPointerUp($event)\"\n (pointercancel)=\"OnWaveformPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n <div class=\"mj-media-waveform-fallback__rail\">\n <div class=\"mj-media-waveform-fallback__fill\" [style.width.%]=\"ScrubPercent\"></div>\n </div>\n </div>\n } @else {\n <div class=\"mj-media-audio-art\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-music\"></i>\n </div>\n }\n } @else {\n <!-- Video: single, or responsive grid for multiple -->\n <div\n class=\"mj-media-video-grid\"\n [class.mj-media-video-grid--multi]=\"IsMultiVideo\"\n >\n @for (track of VideoTracks; track TrackById($index, track); let i = $index) {\n <div class=\"mj-media-video-cell\">\n @if (track.Label) {\n <span class=\"mj-media-video-cell__label\">{{ track.Label }}</span>\n }\n @if (i === 0) {\n <video\n #primaryMedia\n class=\"mj-media-video\"\n [src]=\"track.Url\"\n [poster]=\"track.PosterUrl || null\"\n playsinline\n preload=\"metadata\"\n (loadstart)=\"OnMediaLoadStart($any($event.target))\"\n (loadedmetadata)=\"OnMediaLoadedMetadata($any($event.target))\"\n (canplay)=\"OnMediaCanPlay($any($event.target))\"\n (canplaythrough)=\"OnMediaCanPlay($any($event.target))\"\n (waiting)=\"OnMediaWaiting($any($event.target))\"\n (seeking)=\"OnMediaSeeking($any($event.target))\"\n (seeked)=\"OnMediaSeeked($any($event.target))\"\n (playing)=\"OnMediaPlaying($any($event.target))\"\n (stalled)=\"OnMediaStalled($any($event.target))\"\n (suspend)=\"OnMediaSuspend($any($event.target))\"\n (emptied)=\"OnMediaEmptied($any($event.target))\"\n (timeupdate)=\"OnMediaTimeUpdate($any($event.target))\"\n (durationchange)=\"OnMediaDurationChange($any($event.target))\"\n (play)=\"OnMediaPlay($any($event.target))\"\n (pause)=\"OnMediaPause($any($event.target))\"\n (ended)=\"OnMediaEnded($any($event.target))\"\n (error)=\"OnMediaError($any($event.target))\"\n ></video>\n } @else {\n <!-- Secondary videos follow the leader's timeline; no own controls -->\n <video\n class=\"mj-media-video\"\n [src]=\"track.Url\"\n [poster]=\"track.PosterUrl || null\"\n playsinline\n preload=\"metadata\"\n muted\n ></video>\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Transport bar -->\n <div class=\"mj-media-transport\">\n <!-- Screen-reader + visible playback status (announced on transitions). -->\n <div\n class=\"mj-media-status\"\n [class.mj-media-status--busy]=\"ShowBusyIndicator\"\n role=\"status\"\n aria-live=\"polite\"\n >\n @if (ShowBusyIndicator) {\n <span class=\"mj-media-status__dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"mj-media-status__text\">{{ StatusLabel }}</span>\n </div>\n\n <!-- Scrubber -->\n <div class=\"mj-media-scrubber-row\">\n <span class=\"mj-media-time\">{{ FormatTime(CurrentTimeMs) }}</span>\n <div\n #scrubTrack\n class=\"mj-media-scrubber\"\n role=\"slider\"\n tabindex=\"0\"\n aria-label=\"Seek\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"DurationMs\"\n [attr.aria-valuenow]=\"CurrentTimeMs\"\n [attr.aria-valuetext]=\"FormatTime(CurrentTimeMs) + ' of ' + FormatTime(DurationMs)\"\n (pointerdown)=\"OnScrubPointerDown($event, scrubTrack)\"\n (pointermove)=\"OnScrubPointerMove($event, scrubTrack)\"\n (pointerup)=\"OnScrubPointerUp($event)\"\n (pointercancel)=\"OnScrubPointerUp($event)\"\n (keydown)=\"OnScrubKeyDown($event)\"\n >\n <div class=\"mj-media-scrubber__rail\">\n <div class=\"mj-media-scrubber__fill\" [style.width.%]=\"ScrubPercent\"></div>\n </div>\n <div class=\"mj-media-scrubber__handle\" [style.left.%]=\"ScrubPercent\"></div>\n </div>\n <span class=\"mj-media-time mj-media-time--total\">{{ FormatTime(DurationMs) }}</span>\n </div>\n\n <!-- Controls -->\n <div class=\"mj-media-controls\">\n <div class=\"mj-media-controls__left\">\n @if (ShowSkipControls) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"'Skip back ' + SkipSeconds + ' seconds'\"\n title=\"Skip back {{ SkipSeconds }}s\"\n (click)=\"SkipBackward()\"\n >\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-btn__skip-label\">{{ SkipSeconds }}</span>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"mj-media-btn mj-media-btn--primary\"\n [attr.aria-label]=\"IsPlaying ? 'Pause' : 'Play'\"\n [title]=\"IsPlaying ? 'Pause' : 'Play'\"\n (click)=\"TogglePlay()\"\n >\n <i class=\"fa-solid\" [class.fa-pause]=\"IsPlaying\" [class.fa-play]=\"!IsPlaying\" aria-hidden=\"true\"></i>\n </button>\n\n @if (ShowSkipControls) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"'Skip forward ' + SkipSeconds + ' seconds'\"\n title=\"Skip forward {{ SkipSeconds }}s\"\n (click)=\"SkipForward()\"\n >\n <i class=\"fa-solid fa-rotate-right\" aria-hidden=\"true\"></i>\n <span class=\"mj-media-btn__skip-label\">{{ SkipSeconds }}</span>\n </button>\n }\n </div>\n\n <div class=\"mj-media-controls__right\">\n @if (ShowVolume) {\n <div class=\"mj-media-volume\">\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"Muted ? 'Unmute' : 'Mute'\"\n [title]=\"Muted ? 'Unmute' : 'Mute'\"\n (click)=\"ToggleMute()\"\n >\n <i\n class=\"fa-solid\"\n [class.fa-volume-xmark]=\"Muted || Volume === 0\"\n [class.fa-volume-low]=\"!Muted && Volume > 0 && Volume <= 0.5\"\n [class.fa-volume-high]=\"!Muted && Volume > 0.5\"\n aria-hidden=\"true\"\n ></i>\n </button>\n <input\n type=\"range\"\n class=\"mj-media-volume__slider\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [value]=\"Muted ? 0 : Volume\"\n aria-label=\"Volume\"\n (input)=\"OnVolumeInput($event)\"\n />\n </div>\n }\n\n @if (ShowSpeedControl) {\n <div class=\"mj-media-rate\">\n <button\n type=\"button\"\n class=\"mj-media-btn mj-media-rate__toggle\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"RateMenuOpen\"\n aria-label=\"Playback speed\"\n title=\"Playback speed\"\n (click)=\"ToggleRateMenu()\"\n >\n {{ PlaybackRate }}&times;\n </button>\n @if (RateMenuOpen) {\n <ul class=\"mj-media-rate__menu\" role=\"menu\">\n @for (rate of PlaybackRates; track rate) {\n <li role=\"none\">\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"rate === PlaybackRate\"\n class=\"mj-media-rate__item\"\n [class.mj-media-rate__item--active]=\"rate === PlaybackRate\"\n (click)=\"SetPlaybackRate(rate)\"\n >\n {{ rate }}&times;\n </button>\n </li>\n }\n </ul>\n }\n </div>\n }\n\n @if (ShowTranscriptToggleButton) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [class.mj-media-btn--active]=\"TranscriptVisible\"\n [attr.aria-pressed]=\"TranscriptVisible\"\n [attr.aria-label]=\"TranscriptVisible ? 'Hide transcript' : 'Show transcript'\"\n [title]=\"TranscriptVisible ? 'Hide transcript' : 'Show transcript'\"\n (click)=\"ToggleTranscript()\"\n >\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n </button>\n }\n\n @if (ShowFullscreen && VideoTracks.length > 0) {\n <button\n type=\"button\"\n class=\"mj-media-btn\"\n [attr.aria-label]=\"IsFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n [title]=\"IsFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n (click)=\"ToggleFullscreen()\"\n >\n <i\n class=\"fa-solid\"\n [class.fa-compress]=\"IsFullscreen\"\n [class.fa-expand]=\"!IsFullscreen\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- Transcript panel -->\n @if (ShowTranscriptPanel) {\n <div class=\"mj-media-transcript\" role=\"list\" aria-label=\"Transcript\">\n @for (cue of Transcript; track CueTrackById($index, cue); let i = $index) {\n <button\n type=\"button\"\n role=\"listitem\"\n class=\"mj-media-cue\"\n [class.mj-media-cue--active]=\"i === ActiveCueIndex\"\n [attr.aria-current]=\"i === ActiveCueIndex ? 'true' : null\"\n (click)=\"OnCueClicked(i)\"\n (keydown)=\"OnCueKeyDown($event, i)\"\n >\n <span class=\"mj-media-cue__time\">{{ FormatTime(cue.StartMs) }}</span>\n <span class=\"mj-media-cue__body\">\n @if (cue.SpeakerLabel) {\n <span class=\"mj-media-cue__speaker\" [style.color]=\"SpeakerColor(cue.SpeakerLabel)\">\n {{ cue.SpeakerLabel }}\n </span>\n }\n <span class=\"mj-media-cue__text\">{{ cue.Text }}</span>\n </span>\n </button>\n }\n </div>\n }\n }\n</div>\n"]}
@@ -42,5 +42,7 @@ export interface MediaStateContext {
42
42
  * @param ctx element-derived context (play intent, readyState, ended)
43
43
  * @returns the next playback state
44
44
  */
45
+ export declare function NextPlaybackState(event: MediaStateEvent, current: MediaPlaybackState, ctx: MediaStateContext): MediaPlaybackState;
46
+ /** @deprecated Use {@link NextPlaybackState}. */
45
47
  export declare function nextPlaybackState(event: MediaStateEvent, current: MediaPlaybackState, ctx: MediaStateContext): MediaPlaybackState;
46
48
  //# sourceMappingURL=playback-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"playback-state.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/playback-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,SAAS,GACT,MAAM,GACN,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;uFACmF;IACnF,SAAS,EAAE,OAAO,CAAC;IACnB;wFACoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,KAAK,EAAE,OAAO,CAAC;CAChB;AAKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,iBAAiB,GACrB,kBAAkB,CAyEpB"}
1
+ {"version":3,"file":"playback-state.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/playback-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,SAAS,GACT,MAAM,GACN,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;uFACmF;IACnF,SAAS,EAAE,OAAO,CAAC;IACnB;wFACoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,KAAK,EAAE,OAAO,CAAC;CAChB;AAKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,iBAAiB,GACrB,kBAAkB,CAyEpB;AAED,iDAAiD;AACjD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,iBAAiB,GACrB,kBAAkB,CAEpB"}
@@ -23,7 +23,7 @@ const HAVE_FUTURE_DATA = 3;
23
23
  * @param ctx element-derived context (play intent, readyState, ended)
24
24
  * @returns the next playback state
25
25
  */
26
- export function nextPlaybackState(event, current, ctx) {
26
+ export function NextPlaybackState(event, current, ctx) {
27
27
  // `error` is terminal until a new source resets via `emptied`.
28
28
  if (current === 'error' && event !== 'emptied' && event !== 'loadstart') {
29
29
  return 'error';
@@ -83,4 +83,8 @@ export function nextPlaybackState(event, current, ctx) {
83
83
  return current;
84
84
  }
85
85
  }
86
+ /** @deprecated Use {@link NextPlaybackState}. */
87
+ export function nextPlaybackState(event, current, ctx) {
88
+ return NextPlaybackState(event, current, ctx);
89
+ }
86
90
  //# sourceMappingURL=playback-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"playback-state.js","sourceRoot":"","sources":["../../../src/lib/media-player/playback-state.ts"],"names":[],"mappings":"AAuCA,kFAAkF;AAClF,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAsB,EACtB,OAA2B,EAC3B,GAAsB;IAEtB,+DAA+D;IAC/D,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACxE,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QAEjB,KAAK,SAAS;YACZ,sEAAsE;YACtE,OAAO,SAAS,CAAC;QAEnB,KAAK,WAAW;YACd,OAAO,SAAS,CAAC;QAEnB,KAAK,gBAAgB;YACnB,+EAA+E;YAC/E,4EAA4E;YAC5E,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAE3E,KAAK,SAAS,CAAC;QACf,KAAK,gBAAgB;YACnB,0DAA0D;YAC1D,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAE7C,KAAK,SAAS;YACZ,yCAAyC;YACzC,OAAO,WAAW,CAAC;QAErB,KAAK,SAAS;YACZ,sFAAsF;YACtF,OAAO,WAAW,CAAC;QAErB,KAAK,QAAQ;YACX,sFAAsF;YACtF,IAAI,GAAG,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAC;gBACvC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7C,CAAC;YACD,OAAO,WAAW,CAAC;QAErB,KAAK,SAAS;YACZ,mEAAmE;YACnE,OAAO,SAAS,CAAC;QAEnB,KAAK,MAAM;YACT,kFAAkF;YAClF,gEAAgE;YAChE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBACrD,OAAO,OAAO,CAAC;YACjB,CAAC;YACD,OAAO,SAAS,CAAC;QAEnB,KAAK,OAAO;YACV,qDAAqD;YACrD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QAExC,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QAEjB,KAAK,SAAS,CAAC;QACf,KAAK,SAAS;YACZ,gFAAgF;YAChF,+EAA+E;YAC/E,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBAChC,OAAO,WAAW,CAAC;YACrB,CAAC;YACD,OAAO,OAAO,CAAC;QAEjB;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import { MediaPlaybackState } from '../media-player.types';\n\n/**\n * The native HTMLMediaElement event names that drive the {@link MediaPlaybackState}\n * machine. We bind exactly these on the PRIMARY media element.\n */\nexport type MediaStateEvent =\n | 'loadstart'\n | 'loadedmetadata'\n | 'canplay'\n | 'canplaythrough'\n | 'waiting'\n | 'seeking'\n | 'seeked'\n | 'playing'\n | 'play'\n | 'pause'\n | 'ended'\n | 'error'\n | 'stalled'\n | 'suspend'\n | 'emptied';\n\n/**\n * Context the reducer needs beyond the raw event + current state. These are read off the\n * media element at the moment the event fires (kept as plain inputs so the reducer stays\n * a pure, fully unit-testable function with no DOM dependency).\n */\nexport interface MediaStateContext {\n /** Whether the user intends playback (the element is not paused). Drives ready-vs-playing\n * and whether conservative events (`stalled`/`suspend`) should show buffering. */\n IsPlaying: boolean;\n /** The element's `readyState` (HAVE_NOTHING=0 … HAVE_ENOUGH_DATA=4). Used by `seeked` to\n * decide whether we can clear buffering immediately or must wait for `canplay`. */\n ReadyState: number;\n /** Whether the element has ended (mirrors `el.ended`). Suppresses benign buffering. */\n Ended: boolean;\n}\n\n/** `HTMLMediaElement.HAVE_FUTURE_DATA` — enough to advance at least one frame. */\nconst HAVE_FUTURE_DATA = 3;\n\n/**\n * Pure transition function for the media playback state machine.\n *\n * Given the native media event, the current high-level state, and a small context read\n * off the element, returns the next {@link MediaPlaybackState}. This is the single source\n * of truth for the component's state — the component binds native events to this reducer\n * and reflects the result; it never invents transitions of its own.\n *\n * Design rules baked in here:\n * - `error` always wins (an errored element can still emit stray `suspend`/`stalled`).\n * - `seeking` → `buffering` so a ±30s skip / scrub into un-buffered territory shows the\n * indicator during the seek; `seeked` clears it only when the element actually has data\n * (else we stay `buffering` until `canplay`).\n * - `stalled` / `suspend` are CONSERVATIVE: they only buffer when the user is actively\n * trying to play (not paused, not ended) — `suspend` fires benignly after a normal load,\n * and we must not flash a spinner then.\n * - `playing` always clears loading/buffering (the element resumed on its own after a seek).\n *\n * @param event the native media event that fired\n * @param current the current high-level playback state\n * @param ctx element-derived context (play intent, readyState, ended)\n * @returns the next playback state\n */\nexport function nextPlaybackState(\n event: MediaStateEvent,\n current: MediaPlaybackState,\n ctx: MediaStateContext,\n): MediaPlaybackState {\n // `error` is terminal until a new source resets via `emptied`.\n if (current === 'error' && event !== 'emptied' && event !== 'loadstart') {\n return 'error';\n }\n\n switch (event) {\n case 'error':\n return 'error';\n\n case 'emptied':\n // Track switch / source cleared — back to the start of the lifecycle.\n return 'loading';\n\n case 'loadstart':\n return 'loading';\n\n case 'loadedmetadata':\n // Metadata is in but we may not have playable data yet — stay in loading until\n // `canplay`. Don't regress out of a more-advanced state if it arrives late.\n return current === 'idle' || current === 'loading' ? 'loading' : current;\n\n case 'canplay':\n case 'canplaythrough':\n // Enough data buffered to play — clear loading/buffering.\n return ctx.IsPlaying ? 'playing' : 'ready';\n\n case 'waiting':\n // Ran out of buffered data mid-playback.\n return 'buffering';\n\n case 'seeking':\n // Seeking into (possibly) un-buffered territory — show the indicator during the seek.\n return 'buffering';\n\n case 'seeked':\n // Clear buffering only if the element now has playable data; else wait for `canplay`.\n if (ctx.ReadyState >= HAVE_FUTURE_DATA) {\n return ctx.IsPlaying ? 'playing' : 'ready';\n }\n return 'buffering';\n\n case 'playing':\n // Authoritative \"we are now playing\" — clears loading + buffering.\n return 'playing';\n\n case 'play':\n // Play was requested; if we're already past loading keep showing the right state,\n // otherwise the load/buffer indicator stays until data arrives.\n if (current === 'loading' || current === 'buffering') {\n return current;\n }\n return 'playing';\n\n case 'pause':\n // Don't override a terminal ended state with paused.\n return ctx.Ended ? 'ended' : 'paused';\n\n case 'ended':\n return 'ended';\n\n case 'stalled':\n case 'suspend':\n // Conservative: only treat as buffering when actively trying to play. `suspend`\n // fires benignly after a normal metadata load — must not flash a spinner then.\n if (ctx.IsPlaying && !ctx.Ended) {\n return 'buffering';\n }\n return current;\n\n default:\n return current;\n }\n}\n"]}
1
+ {"version":3,"file":"playback-state.js","sourceRoot":"","sources":["../../../src/lib/media-player/playback-state.ts"],"names":[],"mappings":"AAuCA,kFAAkF;AAClF,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAsB,EACtB,OAA2B,EAC3B,GAAsB;IAEtB,+DAA+D;IAC/D,IAAI,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACxE,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QAEjB,KAAK,SAAS;YACZ,sEAAsE;YACtE,OAAO,SAAS,CAAC;QAEnB,KAAK,WAAW;YACd,OAAO,SAAS,CAAC;QAEnB,KAAK,gBAAgB;YACnB,+EAA+E;YAC/E,4EAA4E;YAC5E,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAE3E,KAAK,SAAS,CAAC;QACf,KAAK,gBAAgB;YACnB,0DAA0D;YAC1D,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAE7C,KAAK,SAAS;YACZ,yCAAyC;YACzC,OAAO,WAAW,CAAC;QAErB,KAAK,SAAS;YACZ,sFAAsF;YACtF,OAAO,WAAW,CAAC;QAErB,KAAK,QAAQ;YACX,sFAAsF;YACtF,IAAI,GAAG,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAC;gBACvC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7C,CAAC;YACD,OAAO,WAAW,CAAC;QAErB,KAAK,SAAS;YACZ,mEAAmE;YACnE,OAAO,SAAS,CAAC;QAEnB,KAAK,MAAM;YACT,kFAAkF;YAClF,gEAAgE;YAChE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBACrD,OAAO,OAAO,CAAC;YACjB,CAAC;YACD,OAAO,SAAS,CAAC;QAEnB,KAAK,OAAO;YACV,qDAAqD;YACrD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QAExC,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QAEjB,KAAK,SAAS,CAAC;QACf,KAAK,SAAS;YACZ,gFAAgF;YAChF,+EAA+E;YAC/E,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBAChC,OAAO,WAAW,CAAC;YACrB,CAAC;YACD,OAAO,OAAO,CAAC;QAEjB;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,iBAAiB,CAC/B,KAAsB,EACtB,OAA2B,EAC3B,GAAsB;IAEtB,OAAO,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC","sourcesContent":["import { MediaPlaybackState } from '../media-player.types';\n\n/**\n * The native HTMLMediaElement event names that drive the {@link MediaPlaybackState}\n * machine. We bind exactly these on the PRIMARY media element.\n */\nexport type MediaStateEvent =\n | 'loadstart'\n | 'loadedmetadata'\n | 'canplay'\n | 'canplaythrough'\n | 'waiting'\n | 'seeking'\n | 'seeked'\n | 'playing'\n | 'play'\n | 'pause'\n | 'ended'\n | 'error'\n | 'stalled'\n | 'suspend'\n | 'emptied';\n\n/**\n * Context the reducer needs beyond the raw event + current state. These are read off the\n * media element at the moment the event fires (kept as plain inputs so the reducer stays\n * a pure, fully unit-testable function with no DOM dependency).\n */\nexport interface MediaStateContext {\n /** Whether the user intends playback (the element is not paused). Drives ready-vs-playing\n * and whether conservative events (`stalled`/`suspend`) should show buffering. */\n IsPlaying: boolean;\n /** The element's `readyState` (HAVE_NOTHING=0 … HAVE_ENOUGH_DATA=4). Used by `seeked` to\n * decide whether we can clear buffering immediately or must wait for `canplay`. */\n ReadyState: number;\n /** Whether the element has ended (mirrors `el.ended`). Suppresses benign buffering. */\n Ended: boolean;\n}\n\n/** `HTMLMediaElement.HAVE_FUTURE_DATA` — enough to advance at least one frame. */\nconst HAVE_FUTURE_DATA = 3;\n\n/**\n * Pure transition function for the media playback state machine.\n *\n * Given the native media event, the current high-level state, and a small context read\n * off the element, returns the next {@link MediaPlaybackState}. This is the single source\n * of truth for the component's state — the component binds native events to this reducer\n * and reflects the result; it never invents transitions of its own.\n *\n * Design rules baked in here:\n * - `error` always wins (an errored element can still emit stray `suspend`/`stalled`).\n * - `seeking` → `buffering` so a ±30s skip / scrub into un-buffered territory shows the\n * indicator during the seek; `seeked` clears it only when the element actually has data\n * (else we stay `buffering` until `canplay`).\n * - `stalled` / `suspend` are CONSERVATIVE: they only buffer when the user is actively\n * trying to play (not paused, not ended) — `suspend` fires benignly after a normal load,\n * and we must not flash a spinner then.\n * - `playing` always clears loading/buffering (the element resumed on its own after a seek).\n *\n * @param event the native media event that fired\n * @param current the current high-level playback state\n * @param ctx element-derived context (play intent, readyState, ended)\n * @returns the next playback state\n */\nexport function NextPlaybackState(\n event: MediaStateEvent,\n current: MediaPlaybackState,\n ctx: MediaStateContext,\n): MediaPlaybackState {\n // `error` is terminal until a new source resets via `emptied`.\n if (current === 'error' && event !== 'emptied' && event !== 'loadstart') {\n return 'error';\n }\n\n switch (event) {\n case 'error':\n return 'error';\n\n case 'emptied':\n // Track switch / source cleared — back to the start of the lifecycle.\n return 'loading';\n\n case 'loadstart':\n return 'loading';\n\n case 'loadedmetadata':\n // Metadata is in but we may not have playable data yet — stay in loading until\n // `canplay`. Don't regress out of a more-advanced state if it arrives late.\n return current === 'idle' || current === 'loading' ? 'loading' : current;\n\n case 'canplay':\n case 'canplaythrough':\n // Enough data buffered to play — clear loading/buffering.\n return ctx.IsPlaying ? 'playing' : 'ready';\n\n case 'waiting':\n // Ran out of buffered data mid-playback.\n return 'buffering';\n\n case 'seeking':\n // Seeking into (possibly) un-buffered territory — show the indicator during the seek.\n return 'buffering';\n\n case 'seeked':\n // Clear buffering only if the element now has playable data; else wait for `canplay`.\n if (ctx.ReadyState >= HAVE_FUTURE_DATA) {\n return ctx.IsPlaying ? 'playing' : 'ready';\n }\n return 'buffering';\n\n case 'playing':\n // Authoritative \"we are now playing\" — clears loading + buffering.\n return 'playing';\n\n case 'play':\n // Play was requested; if we're already past loading keep showing the right state,\n // otherwise the load/buffer indicator stays until data arrives.\n if (current === 'loading' || current === 'buffering') {\n return current;\n }\n return 'playing';\n\n case 'pause':\n // Don't override a terminal ended state with paused.\n return ctx.Ended ? 'ended' : 'paused';\n\n case 'ended':\n return 'ended';\n\n case 'stalled':\n case 'suspend':\n // Conservative: only treat as buffering when actively trying to play. `suspend`\n // fires benignly after a normal metadata load — must not flash a spinner then.\n if (ctx.IsPlaying && !ctx.Ended) {\n return 'buffering';\n }\n return current;\n\n default:\n return current;\n }\n}\n\n/** @deprecated Use {@link NextPlaybackState}. */\nexport function nextPlaybackState(\n event: MediaStateEvent,\n current: MediaPlaybackState,\n ctx: MediaStateContext,\n): MediaPlaybackState {\n return NextPlaybackState(event, current, ctx);\n}\n"]}
@@ -20,6 +20,8 @@ export type TranscriptPosition = 'side' | 'bottom';
20
20
  * @param userVisible the runtime (toggle-driven) visibility state
21
21
  * @returns true when the transcript panel should render
22
22
  */
23
+ export declare function ResolveTranscriptVisible(hasTranscript: boolean, showTranscript: boolean, userVisible: boolean): boolean;
24
+ /** @deprecated Use {@link ResolveTranscriptVisible}. */
23
25
  export declare function resolveTranscriptVisible(hasTranscript: boolean, showTranscript: boolean, userVisible: boolean): boolean;
24
26
  /**
25
27
  * Resolves whether the show/hide toggle button should render. The toggle only
@@ -31,5 +33,7 @@ export declare function resolveTranscriptVisible(hasTranscript: boolean, showTra
31
33
  * @param showToggle the `ShowTranscriptToggle` input (whether the button renders)
32
34
  * @returns true when the toggle button should render
33
35
  */
36
+ export declare function ResolveTranscriptToggleVisible(hasTranscript: boolean, showTranscript: boolean, showToggle: boolean): boolean;
37
+ /** @deprecated Use {@link ResolveTranscriptToggleVisible}. */
34
38
  export declare function resolveTranscriptToggleVisible(hasTranscript: boolean, showTranscript: boolean, showToggle: boolean): boolean;
35
39
  //# sourceMappingURL=transcript-layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcript-layout.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/transcript-layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,WAAW,EAAE,OAAO,GACnB,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,UAAU,EAAE,OAAO,GAClB,OAAO,CAET"}
1
+ {"version":3,"file":"transcript-layout.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/transcript-layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,WAAW,EAAE,OAAO,GACnB,OAAO,CAET;AAED,wDAAwD;AACxD,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,WAAW,EAAE,OAAO,GACnB,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,UAAU,EAAE,OAAO,GAClB,OAAO,CAET;AAED,8DAA8D;AAC9D,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,OAAO,EACvB,UAAU,EAAE,OAAO,GAClB,OAAO,CAET"}
@@ -18,9 +18,13 @@
18
18
  * @param userVisible the runtime (toggle-driven) visibility state
19
19
  * @returns true when the transcript panel should render
20
20
  */
21
- export function resolveTranscriptVisible(hasTranscript, showTranscript, userVisible) {
21
+ export function ResolveTranscriptVisible(hasTranscript, showTranscript, userVisible) {
22
22
  return hasTranscript && showTranscript && userVisible;
23
23
  }
24
+ /** @deprecated Use {@link ResolveTranscriptVisible}. */
25
+ export function resolveTranscriptVisible(hasTranscript, showTranscript, userVisible) {
26
+ return ResolveTranscriptVisible(hasTranscript, showTranscript, userVisible);
27
+ }
24
28
  /**
25
29
  * Resolves whether the show/hide toggle button should render. The toggle only
26
30
  * makes sense when there is a transcript to toggle AND the consumer opted into
@@ -31,7 +35,11 @@ export function resolveTranscriptVisible(hasTranscript, showTranscript, userVisi
31
35
  * @param showToggle the `ShowTranscriptToggle` input (whether the button renders)
32
36
  * @returns true when the toggle button should render
33
37
  */
34
- export function resolveTranscriptToggleVisible(hasTranscript, showTranscript, showToggle) {
38
+ export function ResolveTranscriptToggleVisible(hasTranscript, showTranscript, showToggle) {
35
39
  return hasTranscript && showTranscript && showToggle;
36
40
  }
41
+ /** @deprecated Use {@link ResolveTranscriptToggleVisible}. */
42
+ export function resolveTranscriptToggleVisible(hasTranscript, showTranscript, showToggle) {
43
+ return ResolveTranscriptToggleVisible(hasTranscript, showTranscript, showToggle);
44
+ }
37
45
  //# sourceMappingURL=transcript-layout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcript-layout.js","sourceRoot":"","sources":["../../../src/lib/media-player/transcript-layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB,CACtC,aAAsB,EACtB,cAAuB,EACvB,WAAoB;IAEpB,OAAO,aAAa,IAAI,cAAc,IAAI,WAAW,CAAC;AACxD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAC5C,aAAsB,EACtB,cAAuB,EACvB,UAAmB;IAEnB,OAAO,aAAa,IAAI,cAAc,IAAI,UAAU,CAAC;AACvD,CAAC","sourcesContent":["/**\n * Pure layout/visibility logic for the media player's transcript panel.\n *\n * Kept framework-agnostic and side-effect-free so the rules (default-below,\n * show/hide toggle, effective visibility) are independently unit-testable.\n */\n\n/** Where the transcript panel sits relative to the media. */\nexport type TranscriptPosition = 'side' | 'bottom';\n\n/**\n * Resolves whether the transcript panel should actually render, combining:\n * - whether a transcript exists at all (`hasTranscript`),\n * - the consumer's `ShowTranscript` master switch,\n * - the user's runtime show/hide toggle state (`userVisible`).\n *\n * All three must be truthy for the panel to render. When no transcript exists\n * (or `ShowTranscript` is false) the runtime toggle is irrelevant.\n *\n * @param hasTranscript whether one or more transcript cues are present\n * @param showTranscript the `ShowTranscript` master input\n * @param userVisible the runtime (toggle-driven) visibility state\n * @returns true when the transcript panel should render\n */\nexport function resolveTranscriptVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n userVisible: boolean,\n): boolean {\n return hasTranscript && showTranscript && userVisible;\n}\n\n/**\n * Resolves whether the show/hide toggle button should render. The toggle only\n * makes sense when there is a transcript to toggle AND the consumer opted into\n * showing it (`ShowTranscript`) AND the consumer enabled the toggle control.\n *\n * @param hasTranscript whether one or more transcript cues are present\n * @param showTranscript the `ShowTranscript` master input\n * @param showToggle the `ShowTranscriptToggle` input (whether the button renders)\n * @returns true when the toggle button should render\n */\nexport function resolveTranscriptToggleVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n showToggle: boolean,\n): boolean {\n return hasTranscript && showTranscript && showToggle;\n}\n"]}
1
+ {"version":3,"file":"transcript-layout.js","sourceRoot":"","sources":["../../../src/lib/media-player/transcript-layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB,CACtC,aAAsB,EACtB,cAAuB,EACvB,WAAoB;IAEpB,OAAO,aAAa,IAAI,cAAc,IAAI,WAAW,CAAC;AACxD,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,wBAAwB,CACtC,aAAsB,EACtB,cAAuB,EACvB,WAAoB;IAEpB,OAAO,wBAAwB,CAAC,aAAa,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,8BAA8B,CAC5C,aAAsB,EACtB,cAAuB,EACvB,UAAmB;IAEnB,OAAO,aAAa,IAAI,cAAc,IAAI,UAAU,CAAC;AACvD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,8BAA8B,CAC5C,aAAsB,EACtB,cAAuB,EACvB,UAAmB;IAEnB,OAAO,8BAA8B,CAAC,aAAa,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;AACnF,CAAC","sourcesContent":["/**\n * Pure layout/visibility logic for the media player's transcript panel.\n *\n * Kept framework-agnostic and side-effect-free so the rules (default-below,\n * show/hide toggle, effective visibility) are independently unit-testable.\n */\n\n/** Where the transcript panel sits relative to the media. */\nexport type TranscriptPosition = 'side' | 'bottom';\n\n/**\n * Resolves whether the transcript panel should actually render, combining:\n * - whether a transcript exists at all (`hasTranscript`),\n * - the consumer's `ShowTranscript` master switch,\n * - the user's runtime show/hide toggle state (`userVisible`).\n *\n * All three must be truthy for the panel to render. When no transcript exists\n * (or `ShowTranscript` is false) the runtime toggle is irrelevant.\n *\n * @param hasTranscript whether one or more transcript cues are present\n * @param showTranscript the `ShowTranscript` master input\n * @param userVisible the runtime (toggle-driven) visibility state\n * @returns true when the transcript panel should render\n */\nexport function ResolveTranscriptVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n userVisible: boolean,\n): boolean {\n return hasTranscript && showTranscript && userVisible;\n}\n\n/** @deprecated Use {@link ResolveTranscriptVisible}. */\nexport function resolveTranscriptVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n userVisible: boolean,\n): boolean {\n return ResolveTranscriptVisible(hasTranscript, showTranscript, userVisible);\n}\n\n/**\n * Resolves whether the show/hide toggle button should render. The toggle only\n * makes sense when there is a transcript to toggle AND the consumer opted into\n * showing it (`ShowTranscript`) AND the consumer enabled the toggle control.\n *\n * @param hasTranscript whether one or more transcript cues are present\n * @param showTranscript the `ShowTranscript` master input\n * @param showToggle the `ShowTranscriptToggle` input (whether the button renders)\n * @returns true when the toggle button should render\n */\nexport function ResolveTranscriptToggleVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n showToggle: boolean,\n): boolean {\n return hasTranscript && showTranscript && showToggle;\n}\n\n/** @deprecated Use {@link ResolveTranscriptToggleVisible}. */\nexport function resolveTranscriptToggleVisible(\n hasTranscript: boolean,\n showTranscript: boolean,\n showToggle: boolean,\n): boolean {\n return ResolveTranscriptToggleVisible(hasTranscript, showTranscript, showToggle);\n}\n"]}
@@ -33,13 +33,19 @@ export declare const DEFAULT_WAVEFORM_BARS = 160;
33
33
  * @param aggregation per-bucket reducer (default `'max-abs'`)
34
34
  * @returns a `barCount`-length array of normalized `0..1` peaks
35
35
  */
36
+ export declare function DownsamplePeaks(samples: Float32Array | number[] | null | undefined, barCount?: number, aggregation?: WaveformAggregation): number[];
37
+ /** @deprecated Use {@link DownsamplePeaks}. */
36
38
  export declare function downsamplePeaks(samples: Float32Array | number[] | null | undefined, barCount?: number, aggregation?: WaveformAggregation): number[];
37
39
  /**
38
40
  * Normalizes an array of non-negative amplitudes to `0..1` by dividing by the maximum.
39
41
  * Returns a copy. When the maximum is `0` (silence) or non-finite, returns the values
40
42
  * clamped to `[0, 1]` without scaling (so an all-zero input stays all-zero).
41
43
  */
44
+ export declare function NormalizePeaks(values: number[]): number[];
45
+ /** @deprecated Use {@link NormalizePeaks}. */
42
46
  export declare function normalizePeaks(values: number[]): number[];
43
47
  /** Clamps a number to the `[0, 1]` range. */
48
+ export declare function Clamp01(v: number): number;
49
+ /** @deprecated Use {@link Clamp01}. */
44
50
  export declare function clamp01(v: number): number;
45
51
  //# sourceMappingURL=waveform-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"waveform-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/waveform-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,KAAK,CAAC;AAEpD,wDAAwD;AACxD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,GAAE,MAA8B,EACxC,WAAW,GAAE,mBAA+B,GAC3C,MAAM,EAAE,CASV;AAoDD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAYzD;AAED,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAQzC"}
1
+ {"version":3,"file":"waveform-utils.d.ts","sourceRoot":"","sources":["../../../src/lib/media-player/waveform-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,mEAAmE;AACnE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,KAAK,CAAC;AAEpD,wDAAwD;AACxD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,GAAE,MAA8B,EACxC,WAAW,GAAE,mBAA+B,GAC3C,MAAM,EAAE,CASV;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,GAAE,MAA8B,EACxC,WAAW,GAAE,mBAA+B,GAC3C,MAAM,EAAE,CAEV;AAoDD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAYzD;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEzD;AAED,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAQzC;AAED,uCAAuC;AACvC,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC"}
@@ -31,14 +31,18 @@ export const DEFAULT_WAVEFORM_BARS = 160;
31
31
  * @param aggregation per-bucket reducer (default `'max-abs'`)
32
32
  * @returns a `barCount`-length array of normalized `0..1` peaks
33
33
  */
34
- export function downsamplePeaks(samples, barCount = DEFAULT_WAVEFORM_BARS, aggregation = 'max-abs') {
34
+ export function DownsamplePeaks(samples, barCount = DEFAULT_WAVEFORM_BARS, aggregation = 'max-abs') {
35
35
  const bars = Math.max(1, Math.floor(barCount));
36
36
  const length = samples ? samples.length : 0;
37
37
  if (length === 0) {
38
38
  return new Array(bars).fill(0);
39
39
  }
40
40
  const raw = aggregateBuckets(samples, length, bars, aggregation);
41
- return normalizePeaks(raw);
41
+ return NormalizePeaks(raw);
42
+ }
43
+ /** @deprecated Use {@link DownsamplePeaks}. */
44
+ export function downsamplePeaks(samples, barCount = DEFAULT_WAVEFORM_BARS, aggregation = 'max-abs') {
45
+ return DownsamplePeaks(samples, barCount, aggregation);
42
46
  }
43
47
  /**
44
48
  * Reduces a sample buffer to `bars` per-bucket amplitudes (un-normalized).
@@ -82,7 +86,7 @@ function reduceBucket(samples, start, end, aggregation) {
82
86
  * Returns a copy. When the maximum is `0` (silence) or non-finite, returns the values
83
87
  * clamped to `[0, 1]` without scaling (so an all-zero input stays all-zero).
84
88
  */
85
- export function normalizePeaks(values) {
89
+ export function NormalizePeaks(values) {
86
90
  let max = 0;
87
91
  for (const v of values) {
88
92
  const a = Math.abs(v);
@@ -91,12 +95,16 @@ export function normalizePeaks(values) {
91
95
  }
92
96
  }
93
97
  if (max <= 0 || !isFinite(max)) {
94
- return values.map((v) => clamp01(v));
98
+ return values.map((v) => Clamp01(v));
95
99
  }
96
- return values.map((v) => clamp01(Math.abs(v) / max));
100
+ return values.map((v) => Clamp01(Math.abs(v) / max));
101
+ }
102
+ /** @deprecated Use {@link NormalizePeaks}. */
103
+ export function normalizePeaks(values) {
104
+ return NormalizePeaks(values);
97
105
  }
98
106
  /** Clamps a number to the `[0, 1]` range. */
99
- export function clamp01(v) {
107
+ export function Clamp01(v) {
100
108
  if (!isFinite(v) || v < 0) {
101
109
  return 0;
102
110
  }
@@ -105,4 +113,8 @@ export function clamp01(v) {
105
113
  }
106
114
  return v;
107
115
  }
116
+ /** @deprecated Use {@link Clamp01}. */
117
+ export function clamp01(v) {
118
+ return Clamp01(v);
119
+ }
108
120
  //# sourceMappingURL=waveform-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"waveform-utils.js","sourceRoot":"","sources":["../../../src/lib/media-player/waveform-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, framework-agnostic waveform math for the media player.\n *\n * These helpers turn a raw mono PCM channel (a `Float32Array` of sample amplitudes,\n * typically in the `[-1, 1]` range that the Web Audio API produces) into a small,\n * fixed-size array of normalized `0..1` peak values — one per rendered waveform bar.\n *\n * They carry no DOM / Angular / `AudioContext` dependency so they can be unit-tested\n * in isolation, mirroring how `cue-utils.ts` splits the cue math out of the component.\n */\n\n/** How each downsample bucket is reduced to a single amplitude. */\nexport type WaveformAggregation = 'max-abs' | 'rms';\n\n/** The default number of bars a waveform renders at. */\nexport const DEFAULT_WAVEFORM_BARS = 160;\n\n/**\n * Downsamples a raw mono sample buffer into `barCount` per-bucket amplitudes and\n * normalizes the result to `0..1` (the loudest bucket becomes `1`).\n *\n * The samples are partitioned into `barCount` contiguous, (near-)equal buckets in\n * index order; each bucket is reduced to one amplitude via `aggregation`:\n * - `'max-abs'` (default) — the maximum absolute sample in the bucket (crisp peaks),\n * - `'rms'` — the root-mean-square of the bucket (smoother, energy-weighted).\n *\n * Edge cases:\n * - empty / null input → an array of `barCount` zeros,\n * - fewer samples than bars → every sample still lands in a bucket; trailing empty\n * buckets are `0` (no out-of-bounds reads),\n * - a silent or constant-zero buffer → all zeros (normalization is skipped when the\n * peak is `0`, so we never divide by zero).\n *\n * @param samples raw mono channel data (e.g. `AudioBuffer.getChannelData(0)`)\n * @param barCount number of output bars (clamped to `>= 1`)\n * @param aggregation per-bucket reducer (default `'max-abs'`)\n * @returns a `barCount`-length array of normalized `0..1` peaks\n */\nexport function downsamplePeaks(\n samples: Float32Array | number[] | null | undefined,\n barCount: number = DEFAULT_WAVEFORM_BARS,\n aggregation: WaveformAggregation = 'max-abs',\n): number[] {\n const bars = Math.max(1, Math.floor(barCount));\n const length = samples ? samples.length : 0;\n if (length === 0) {\n return new Array<number>(bars).fill(0);\n }\n\n const raw = aggregateBuckets(samples as Float32Array | number[], length, bars, aggregation);\n return normalizePeaks(raw);\n}\n\n/**\n * Reduces a sample buffer to `bars` per-bucket amplitudes (un-normalized).\n * Buckets are contiguous and index-ordered; the last bucket absorbs any remainder.\n */\nfunction aggregateBuckets(\n samples: Float32Array | number[],\n length: number,\n bars: number,\n aggregation: WaveformAggregation,\n): number[] {\n const out = new Array<number>(bars).fill(0);\n const bucketSize = length / bars;\n\n for (let b = 0; b < bars; b++) {\n const start = Math.floor(b * bucketSize);\n const end = b === bars - 1 ? length : Math.floor((b + 1) * bucketSize);\n out[b] = reduceBucket(samples, start, end, aggregation);\n }\n return out;\n}\n\n/** Reduces one bucket `[start, end)` of `samples` to a single amplitude. */\nfunction reduceBucket(\n samples: Float32Array | number[],\n start: number,\n end: number,\n aggregation: WaveformAggregation,\n): number {\n if (end <= start) {\n return 0;\n }\n if (aggregation === 'rms') {\n let sumSquares = 0;\n for (let i = start; i < end; i++) {\n const v = samples[i];\n sumSquares += v * v;\n }\n return Math.sqrt(sumSquares / (end - start));\n }\n // 'max-abs'\n let peak = 0;\n for (let i = start; i < end; i++) {\n const v = Math.abs(samples[i]);\n if (v > peak) {\n peak = v;\n }\n }\n return peak;\n}\n\n/**\n * Normalizes an array of non-negative amplitudes to `0..1` by dividing by the maximum.\n * Returns a copy. When the maximum is `0` (silence) or non-finite, returns the values\n * clamped to `[0, 1]` without scaling (so an all-zero input stays all-zero).\n */\nexport function normalizePeaks(values: number[]): number[] {\n let max = 0;\n for (const v of values) {\n const a = Math.abs(v);\n if (a > max) {\n max = a;\n }\n }\n if (max <= 0 || !isFinite(max)) {\n return values.map((v) => clamp01(v));\n }\n return values.map((v) => clamp01(Math.abs(v) / max));\n}\n\n/** Clamps a number to the `[0, 1]` range. */\nexport function clamp01(v: number): number {\n if (!isFinite(v) || v < 0) {\n return 0;\n }\n if (v > 1) {\n return 1;\n }\n return v;\n}\n"]}
1
+ {"version":3,"file":"waveform-utils.js","sourceRoot":"","sources":["../../../src/lib/media-player/waveform-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, framework-agnostic waveform math for the media player.\n *\n * These helpers turn a raw mono PCM channel (a `Float32Array` of sample amplitudes,\n * typically in the `[-1, 1]` range that the Web Audio API produces) into a small,\n * fixed-size array of normalized `0..1` peak values — one per rendered waveform bar.\n *\n * They carry no DOM / Angular / `AudioContext` dependency so they can be unit-tested\n * in isolation, mirroring how `cue-utils.ts` splits the cue math out of the component.\n */\n\n/** How each downsample bucket is reduced to a single amplitude. */\nexport type WaveformAggregation = 'max-abs' | 'rms';\n\n/** The default number of bars a waveform renders at. */\nexport const DEFAULT_WAVEFORM_BARS = 160;\n\n/**\n * Downsamples a raw mono sample buffer into `barCount` per-bucket amplitudes and\n * normalizes the result to `0..1` (the loudest bucket becomes `1`).\n *\n * The samples are partitioned into `barCount` contiguous, (near-)equal buckets in\n * index order; each bucket is reduced to one amplitude via `aggregation`:\n * - `'max-abs'` (default) — the maximum absolute sample in the bucket (crisp peaks),\n * - `'rms'` — the root-mean-square of the bucket (smoother, energy-weighted).\n *\n * Edge cases:\n * - empty / null input → an array of `barCount` zeros,\n * - fewer samples than bars → every sample still lands in a bucket; trailing empty\n * buckets are `0` (no out-of-bounds reads),\n * - a silent or constant-zero buffer → all zeros (normalization is skipped when the\n * peak is `0`, so we never divide by zero).\n *\n * @param samples raw mono channel data (e.g. `AudioBuffer.getChannelData(0)`)\n * @param barCount number of output bars (clamped to `>= 1`)\n * @param aggregation per-bucket reducer (default `'max-abs'`)\n * @returns a `barCount`-length array of normalized `0..1` peaks\n */\nexport function DownsamplePeaks(\n samples: Float32Array | number[] | null | undefined,\n barCount: number = DEFAULT_WAVEFORM_BARS,\n aggregation: WaveformAggregation = 'max-abs',\n): number[] {\n const bars = Math.max(1, Math.floor(barCount));\n const length = samples ? samples.length : 0;\n if (length === 0) {\n return new Array<number>(bars).fill(0);\n }\n\n const raw = aggregateBuckets(samples as Float32Array | number[], length, bars, aggregation);\n return NormalizePeaks(raw);\n}\n\n/** @deprecated Use {@link DownsamplePeaks}. */\nexport function downsamplePeaks(\n samples: Float32Array | number[] | null | undefined,\n barCount: number = DEFAULT_WAVEFORM_BARS,\n aggregation: WaveformAggregation = 'max-abs',\n): number[] {\n return DownsamplePeaks(samples, barCount, aggregation);\n}\n\n/**\n * Reduces a sample buffer to `bars` per-bucket amplitudes (un-normalized).\n * Buckets are contiguous and index-ordered; the last bucket absorbs any remainder.\n */\nfunction aggregateBuckets(\n samples: Float32Array | number[],\n length: number,\n bars: number,\n aggregation: WaveformAggregation,\n): number[] {\n const out = new Array<number>(bars).fill(0);\n const bucketSize = length / bars;\n\n for (let b = 0; b < bars; b++) {\n const start = Math.floor(b * bucketSize);\n const end = b === bars - 1 ? length : Math.floor((b + 1) * bucketSize);\n out[b] = reduceBucket(samples, start, end, aggregation);\n }\n return out;\n}\n\n/** Reduces one bucket `[start, end)` of `samples` to a single amplitude. */\nfunction reduceBucket(\n samples: Float32Array | number[],\n start: number,\n end: number,\n aggregation: WaveformAggregation,\n): number {\n if (end <= start) {\n return 0;\n }\n if (aggregation === 'rms') {\n let sumSquares = 0;\n for (let i = start; i < end; i++) {\n const v = samples[i];\n sumSquares += v * v;\n }\n return Math.sqrt(sumSquares / (end - start));\n }\n // 'max-abs'\n let peak = 0;\n for (let i = start; i < end; i++) {\n const v = Math.abs(samples[i]);\n if (v > peak) {\n peak = v;\n }\n }\n return peak;\n}\n\n/**\n * Normalizes an array of non-negative amplitudes to `0..1` by dividing by the maximum.\n * Returns a copy. When the maximum is `0` (silence) or non-finite, returns the values\n * clamped to `[0, 1]` without scaling (so an all-zero input stays all-zero).\n */\nexport function NormalizePeaks(values: number[]): number[] {\n let max = 0;\n for (const v of values) {\n const a = Math.abs(v);\n if (a > max) {\n max = a;\n }\n }\n if (max <= 0 || !isFinite(max)) {\n return values.map((v) => Clamp01(v));\n }\n return values.map((v) => Clamp01(Math.abs(v) / max));\n}\n\n/** @deprecated Use {@link NormalizePeaks}. */\nexport function normalizePeaks(values: number[]): number[] {\n return NormalizePeaks(values);\n}\n\n/** Clamps a number to the `[0, 1]` range. */\nexport function Clamp01(v: number): number {\n if (!isFinite(v) || v < 0) {\n return 0;\n }\n if (v > 1) {\n return 1;\n }\n return v;\n}\n\n/** @deprecated Use {@link Clamp01}. */\nexport function clamp01(v: number): number {\n return Clamp01(v);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-media-player",
3
- "version": "6.1.4",
3
+ "version": "6.2.0-edge.1",
4
4
  "description": "World-class generic media (audio/video) player with transcript sync, plus an MJStorage-bound wrapper.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -13,7 +13,7 @@
13
13
  "devDependencies": {
14
14
  "@angular/compiler": "21.2.22",
15
15
  "@angular/compiler-cli": "21.2.22",
16
- "@memberjunction/ng-test-utils": "6.1.4",
16
+ "@memberjunction/ng-test-utils": "6.2.0-edge.1",
17
17
  "vitest": "^4.0.18"
18
18
  },
19
19
  "peerDependencies": {
@@ -22,9 +22,9 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "tslib": "^2.8.1",
25
- "@memberjunction/core": "6.1.4",
26
- "@memberjunction/graphql-dataprovider": "6.1.4",
27
- "@memberjunction/ng-base-types": "6.1.4"
25
+ "@memberjunction/core": "6.2.0-edge.1",
26
+ "@memberjunction/graphql-dataprovider": "6.2.0-edge.1",
27
+ "@memberjunction/ng-base-types": "6.2.0-edge.1"
28
28
  },
29
29
  "sideEffects": false,
30
30
  "repository": {