@editframe/elements 0.21.0-beta.0 → 0.23.7-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/EF_FRAMEGEN.js +2 -3
  2. package/dist/attachContextRoot.d.ts +1 -0
  3. package/dist/attachContextRoot.js +9 -0
  4. package/dist/elements/ContextProxiesController.d.ts +1 -2
  5. package/dist/elements/EFAudio.js +2 -2
  6. package/dist/elements/EFCaptions.d.ts +1 -3
  7. package/dist/elements/EFCaptions.js +59 -51
  8. package/dist/elements/EFImage.js +2 -2
  9. package/dist/elements/EFMedia/AssetIdMediaEngine.js +1 -2
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +1 -3
  11. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
  12. package/dist/elements/EFMedia/BufferedSeekingInput.js +2 -4
  13. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +4 -7
  14. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +1 -2
  15. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +5 -9
  16. package/dist/elements/EFMedia/shared/BufferUtils.js +1 -3
  17. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +4 -7
  18. package/dist/elements/EFMedia.d.ts +19 -0
  19. package/dist/elements/EFMedia.js +19 -2
  20. package/dist/elements/EFSourceMixin.js +1 -1
  21. package/dist/elements/EFSurface.js +1 -1
  22. package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
  23. package/dist/elements/EFTemporal.d.ts +10 -0
  24. package/dist/elements/EFTemporal.js +82 -5
  25. package/dist/elements/EFThumbnailStrip.js +9 -16
  26. package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
  27. package/dist/elements/EFTimegroup.d.ts +35 -14
  28. package/dist/elements/EFTimegroup.js +73 -120
  29. package/dist/elements/EFVideo.d.ts +10 -0
  30. package/dist/elements/EFVideo.js +15 -2
  31. package/dist/elements/EFWaveform.js +10 -18
  32. package/dist/elements/SampleBuffer.js +1 -2
  33. package/dist/elements/TargetController.js +2 -2
  34. package/dist/elements/renderTemporalAudio.d.ts +10 -0
  35. package/dist/elements/renderTemporalAudio.js +35 -0
  36. package/dist/elements/updateAnimations.js +7 -10
  37. package/dist/gui/ContextMixin.d.ts +5 -5
  38. package/dist/gui/ContextMixin.js +151 -117
  39. package/dist/gui/Controllable.browsertest.d.ts +0 -0
  40. package/dist/gui/Controllable.d.ts +15 -0
  41. package/dist/gui/Controllable.js +9 -0
  42. package/dist/gui/EFConfiguration.js +1 -1
  43. package/dist/gui/EFControls.browsertest.d.ts +11 -0
  44. package/dist/gui/EFControls.d.ts +18 -4
  45. package/dist/gui/EFControls.js +67 -25
  46. package/dist/gui/EFDial.browsertest.d.ts +0 -0
  47. package/dist/gui/EFDial.d.ts +18 -0
  48. package/dist/gui/EFDial.js +141 -0
  49. package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
  50. package/dist/gui/EFFilmstrip.d.ts +12 -2
  51. package/dist/gui/EFFilmstrip.js +140 -34
  52. package/dist/gui/EFFitScale.js +2 -4
  53. package/dist/gui/EFFocusOverlay.js +1 -1
  54. package/dist/gui/EFPause.browsertest.d.ts +0 -0
  55. package/dist/gui/EFPause.d.ts +23 -0
  56. package/dist/gui/EFPause.js +59 -0
  57. package/dist/gui/EFPlay.browsertest.d.ts +0 -0
  58. package/dist/gui/EFPlay.d.ts +23 -0
  59. package/dist/gui/EFPlay.js +59 -0
  60. package/dist/gui/EFPreview.d.ts +4 -0
  61. package/dist/gui/EFPreview.js +15 -6
  62. package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
  63. package/dist/gui/EFResizableBox.d.ts +34 -0
  64. package/dist/gui/EFResizableBox.js +547 -0
  65. package/dist/gui/EFScrubber.d.ts +9 -3
  66. package/dist/gui/EFScrubber.js +7 -7
  67. package/dist/gui/EFTimeDisplay.d.ts +7 -1
  68. package/dist/gui/EFTimeDisplay.js +5 -5
  69. package/dist/gui/EFToggleLoop.d.ts +9 -3
  70. package/dist/gui/EFToggleLoop.js +6 -4
  71. package/dist/gui/EFTogglePlay.d.ts +12 -4
  72. package/dist/gui/EFTogglePlay.js +24 -19
  73. package/dist/gui/EFWorkbench.js +1 -1
  74. package/dist/gui/PlaybackController.d.ts +67 -0
  75. package/dist/gui/PlaybackController.js +310 -0
  76. package/dist/gui/TWMixin.js +1 -1
  77. package/dist/gui/TargetOrContextMixin.d.ts +10 -0
  78. package/dist/gui/TargetOrContextMixin.js +98 -0
  79. package/dist/gui/efContext.d.ts +2 -2
  80. package/dist/index.d.ts +4 -0
  81. package/dist/index.js +5 -1
  82. package/dist/otel/setupBrowserTracing.d.ts +1 -1
  83. package/dist/otel/setupBrowserTracing.js +6 -4
  84. package/dist/otel/tracingHelpers.js +1 -2
  85. package/dist/style.css +1 -1
  86. package/package.json +5 -5
  87. package/src/elements/ContextProxiesController.ts +10 -10
  88. package/src/elements/EFAudio.ts +1 -0
  89. package/src/elements/EFCaptions.browsertest.ts +128 -58
  90. package/src/elements/EFCaptions.ts +60 -34
  91. package/src/elements/EFImage.browsertest.ts +1 -2
  92. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
  93. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
  94. package/src/elements/EFMedia.browsertest.ts +8 -15
  95. package/src/elements/EFMedia.ts +38 -7
  96. package/src/elements/EFSurface.browsertest.ts +2 -6
  97. package/src/elements/EFSurface.ts +1 -0
  98. package/src/elements/EFTemporal.browsertest.ts +58 -1
  99. package/src/elements/EFTemporal.ts +140 -4
  100. package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
  101. package/src/elements/EFThumbnailStrip.ts +1 -0
  102. package/src/elements/EFTimegroup.browsertest.ts +6 -7
  103. package/src/elements/EFTimegroup.ts +163 -244
  104. package/src/elements/EFVideo.browsertest.ts +143 -47
  105. package/src/elements/EFVideo.ts +26 -0
  106. package/src/elements/FetchContext.browsertest.ts +7 -2
  107. package/src/elements/TargetController.browsertest.ts +1 -0
  108. package/src/elements/TargetController.ts +1 -0
  109. package/src/elements/renderTemporalAudio.ts +108 -0
  110. package/src/elements/updateAnimations.browsertest.ts +181 -6
  111. package/src/elements/updateAnimations.ts +6 -6
  112. package/src/gui/ContextMixin.browsertest.ts +274 -27
  113. package/src/gui/ContextMixin.ts +230 -175
  114. package/src/gui/Controllable.browsertest.ts +258 -0
  115. package/src/gui/Controllable.ts +41 -0
  116. package/src/gui/EFControls.browsertest.ts +294 -80
  117. package/src/gui/EFControls.ts +139 -28
  118. package/src/gui/EFDial.browsertest.ts +84 -0
  119. package/src/gui/EFDial.ts +172 -0
  120. package/src/gui/EFFilmstrip.browsertest.ts +712 -0
  121. package/src/gui/EFFilmstrip.ts +213 -23
  122. package/src/gui/EFPause.browsertest.ts +202 -0
  123. package/src/gui/EFPause.ts +73 -0
  124. package/src/gui/EFPlay.browsertest.ts +202 -0
  125. package/src/gui/EFPlay.ts +73 -0
  126. package/src/gui/EFPreview.ts +20 -5
  127. package/src/gui/EFResizableBox.browsertest.ts +79 -0
  128. package/src/gui/EFResizableBox.ts +898 -0
  129. package/src/gui/EFScrubber.ts +7 -5
  130. package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
  131. package/src/gui/EFTimeDisplay.ts +3 -1
  132. package/src/gui/EFToggleLoop.ts +6 -5
  133. package/src/gui/EFTogglePlay.ts +30 -23
  134. package/src/gui/PlaybackController.ts +522 -0
  135. package/src/gui/TWMixin.css +3 -0
  136. package/src/gui/TargetOrContextMixin.ts +185 -0
  137. package/src/gui/efContext.ts +2 -2
  138. package/src/otel/setupBrowserTracing.ts +17 -12
  139. package/test/cache-integration-verification.browsertest.ts +1 -1
  140. package/types.json +1 -1
  141. package/dist/elements/ContextProxiesController.js +0 -49
  142. /package/dist/_virtual/{_@oxc-project_runtime@0.93.0 → _@oxc-project_runtime@0.94.0}/helpers/decorate.js +0 -0
@@ -96,7 +96,7 @@ var EFFramegen = class {
96
96
  BRIDGE.onInitialize(async (renderOptions, traceContext, otelEndpoint) => {
97
97
  if (renderOptions.enableTracing && otelEndpoint) {
98
98
  enableTracing();
99
- setupBrowserTracing({
99
+ await setupBrowserTracing({
100
100
  otelEndpoint,
101
101
  serviceName: "telecine-browser",
102
102
  bridge: BRIDGE,
@@ -136,8 +136,7 @@ var EFFramegen = class {
136
136
  });
137
137
  });
138
138
  BRIDGE.onTriggerCanvas((traceContext) => {
139
- const parentContext = extractParentContext(traceContext);
140
- withSpan("browser.canvas.trigger", {}, parentContext, async () => {
139
+ withSpan("browser.canvas.trigger", {}, extractParentContext(traceContext), async () => {
141
140
  this.triggerCanvas.trigger();
142
141
  }).catch((error) => {
143
142
  console.error("[EF_FRAMEGEN.triggerCanvas] error:", error);
@@ -0,0 +1 @@
1
+ export declare const attachContextRoot: () => void;
@@ -0,0 +1,9 @@
1
+ import { ContextRoot } from "@lit/context";
2
+ var contextRoot = null;
3
+ const attachContextRoot = () => {
4
+ if (typeof window === "undefined") return;
5
+ if (contextRoot !== null) return;
6
+ contextRoot = new ContextRoot();
7
+ contextRoot.attach(document.body);
8
+ };
9
+ export { attachContextRoot };
@@ -20,7 +20,7 @@ export type ContextProxyConfig = {
20
20
  * // @ts-expect-error controller is intentionally not referenced directly
21
21
  * #contextProxyController = new ContextProxyController(this, {
22
22
  * target: () => this.targetElement,
23
- * contexts: [playingContext, loopContext, targetTimegroupContext]
23
+ * contexts: [playingContext, loopContext, targetTemporalContext]
24
24
  * });
25
25
  * }
26
26
  * ```
@@ -28,7 +28,6 @@ export type ContextProxyConfig = {
28
28
  export declare class ContextProxyController implements ReactiveController {
29
29
  private host;
30
30
  private proxyMap;
31
- private boundHandler;
32
31
  private pendingRequests;
33
32
  constructor(host: LitElement, config: ContextProxyConfig);
34
33
  hostConnected(): void;
@@ -1,7 +1,7 @@
1
1
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
3
- import { EFMedia } from "./EFMedia.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
4
3
  import { TWMixin } from "../gui/TWMixin2.js";
4
+ import { EFMedia } from "./EFMedia.js";
5
5
  import { Task } from "@lit/task";
6
6
  import { html } from "lit";
7
7
  import { customElement, property } from "lit/decorators.js";
@@ -66,8 +66,6 @@ export declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
66
66
  declare const EFCaptions_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
67
67
  export declare class EFCaptions extends EFCaptions_base {
68
68
  static styles: import('lit').CSSResult[];
69
- displayMode: "word" | "segment" | "context";
70
- contextWords: number;
71
69
  targetSelector: string;
72
70
  set target(value: string);
73
71
  wordStyle: string;
@@ -100,7 +98,7 @@ export declare class EFCaptions extends EFCaptions_base {
100
98
  private customCaptionsDataTask;
101
99
  private transcriptionFragmentDataTask;
102
100
  unifiedCaptionsDataTask: Task<readonly [Caption | null | undefined, Caption | null | undefined], Caption | null | undefined>;
103
- frameTask: Task<TaskStatus[], void>;
101
+ frameTask: Task<readonly [TaskStatus, number], void>;
104
102
  connectedCallback(): void;
105
103
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
106
104
  updateTextContainers(): void;
@@ -1,7 +1,7 @@
1
1
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
3
- import { EFSourceMixin } from "./EFSourceMixin.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
4
3
  import { EFTemporal, flushStartTimeMsCache } from "./EFTemporal.js";
4
+ import { EFSourceMixin } from "./EFSourceMixin.js";
5
5
  import { FetchMixin } from "./FetchMixin.js";
6
6
  import { flushSequenceDurationCache } from "./EFTimegroup.js";
7
7
  import { EFAudio } from "./EFAudio.js";
@@ -30,11 +30,12 @@ var EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitEl
30
30
  this.styles = [css`
31
31
  :host {
32
32
  display: inline-block;
33
- white-space: pre;
34
- transform-origin: center;
33
+ white-space: normal;
34
+ line-height: 1;
35
35
  }
36
36
  :host([hidden]) {
37
- display: none;
37
+ opacity: 0;
38
+ pointer-events: none;
38
39
  }
39
40
  `];
40
41
  }
@@ -46,7 +47,7 @@ var EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitEl
46
47
  this.hidden = false;
47
48
  const seedValue = this.wordIndex * 9007 % 233 / 233;
48
49
  this.style.setProperty("--ef-word-seed", seedValue.toString());
49
- return html` ${this.wordText.trim()} `;
50
+ return html`${this.wordText}`;
50
51
  }
51
52
  get startTimeMs() {
52
53
  return (this.closest("ef-captions")?.startTimeMs || 0) + (this.wordStartMs || 0);
@@ -90,10 +91,9 @@ var EFCaptionsSegment = class EFCaptionsSegment$1 extends EFTemporal(LitElement)
90
91
  static {
91
92
  this.styles = [css`
92
93
  :host {
93
- display: block;
94
- }
95
- :host([hidden]) {
96
- display: none;
94
+ display: inline-block;
95
+ white-space: normal;
96
+ line-height: 1;
97
97
  }
98
98
  `];
99
99
  }
@@ -145,9 +145,11 @@ var EFCaptionsBeforeActiveWord = class EFCaptionsBeforeActiveWord$1 extends EFCa
145
145
  :host {
146
146
  display: inline-block;
147
147
  white-space: pre;
148
+ line-height: 1;
148
149
  }
149
150
  :host([hidden]) {
150
- display: none;
151
+ opacity: 0;
152
+ pointer-events: none;
151
153
  }
152
154
  `];
153
155
  }
@@ -157,7 +159,9 @@ var EFCaptionsBeforeActiveWord = class EFCaptionsBeforeActiveWord$1 extends EFCa
157
159
  return;
158
160
  }
159
161
  this.hidden = false;
160
- return html` ${this.segmentText}`;
162
+ const activeWord = this.closest("ef-captions")?.querySelector("ef-captions-active-word");
163
+ const hasActiveWord = activeWord?.wordText && !activeWord.hidden;
164
+ return html`${this.segmentText}${hasActiveWord ? " " : ""}`;
161
165
  }
162
166
  get startTimeMs() {
163
167
  return (this.closest("ef-captions")?.startTimeMs || 0) + (this.segmentStartMs || 0);
@@ -199,9 +203,11 @@ var EFCaptionsAfterActiveWord = class EFCaptionsAfterActiveWord$1 extends EFCapt
199
203
  :host {
200
204
  display: inline-block;
201
205
  white-space: pre;
206
+ line-height: 1;
202
207
  }
203
208
  :host([hidden]) {
204
- display: none;
209
+ opacity: 0;
210
+ pointer-events: none;
205
211
  }
206
212
  `];
207
213
  }
@@ -211,7 +217,8 @@ var EFCaptionsAfterActiveWord = class EFCaptionsAfterActiveWord$1 extends EFCapt
211
217
  return;
212
218
  }
213
219
  this.hidden = false;
214
- return html`${this.segmentText} `;
220
+ const activeWord = this.closest("ef-captions")?.querySelector("ef-captions-active-word");
221
+ return html`${activeWord?.wordText && !activeWord.hidden ? " " : ""}${this.segmentText}`;
215
222
  }
216
223
  get startTimeMs() {
217
224
  return (this.closest("ef-captions")?.startTimeMs || 0) + (this.segmentStartMs || 0);
@@ -243,8 +250,6 @@ EFCaptionsAfterActiveWord = __decorate([customElement("ef-captions-after-active-
243
250
  var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), { assetType: "caption_files" }) {
244
251
  constructor(..._args5) {
245
252
  super(..._args5);
246
- this.displayMode = "segment";
247
- this.contextWords = 3;
248
253
  this.targetSelector = "";
249
254
  this.wordStyle = "";
250
255
  this.captionsSrc = "";
@@ -259,8 +264,7 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
259
264
  args: () => [this.target, this.fetch],
260
265
  task: async ([_target, fetch], { signal }) => {
261
266
  if (!this.targetElement) return null;
262
- const md5Path = `/@ef-asset/${this.targetElement.src ?? ""}`;
263
- return (await fetch(md5Path, {
267
+ return (await fetch(`/@ef-asset/${this.targetElement.src ?? ""}`, {
264
268
  method: "HEAD",
265
269
  signal
266
270
  })).headers.get("etag") ?? void 0;
@@ -323,8 +327,7 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
323
327
  ],
324
328
  task: async ([transcription, fragmentIndex, fetch], { signal }) => {
325
329
  if (transcription === null || transcription === void 0 || fragmentIndex === null || fragmentIndex === void 0) return null;
326
- const fragmentPath = this.transcriptionFragmentPath(transcription.id, fragmentIndex);
327
- return (await fetch(fragmentPath, { signal })).json();
330
+ return (await fetch(this.transcriptionFragmentPath(transcription.id, fragmentIndex), { signal })).json();
328
331
  }
329
332
  });
330
333
  this.unifiedCaptionsDataTask = new Task(this, {
@@ -338,9 +341,10 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
338
341
  });
339
342
  this.frameTask = new Task(this, {
340
343
  autoRun: EF_INTERACTIVE,
341
- args: () => [this.unifiedCaptionsDataTask.status],
344
+ args: () => [this.unifiedCaptionsDataTask.status, this.ownCurrentTimeMs],
342
345
  task: async () => {
343
346
  await this.unifiedCaptionsDataTask.taskComplete;
347
+ this.updateTextContainers();
344
348
  }
345
349
  });
346
350
  }
@@ -348,22 +352,15 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
348
352
  this.styles = [css`
349
353
  :host {
350
354
  display: inline-flex;
351
- width: fit-content;
352
- align-items: baseline;
355
+ white-space: normal;
356
+ line-height: 1;
357
+ gap: 0;
353
358
  }
354
359
  ::slotted(*) {
360
+ display: inline-block;
355
361
  margin: 0;
356
362
  padding: 0;
357
363
  }
358
- ::slotted(ef-captions-active-word) {
359
- min-width: 0.5ch; /* Maintain minimum width when empty */
360
- min-height: 1em; /* Maintain height for baseline alignment */
361
- }
362
- ::slotted(ef-captions-active-word[hidden]) {
363
- opacity: 0; /* Hide when empty but maintain layout */
364
- min-width: 0.5ch;
365
- min-height: 1em;
366
- }
367
364
  `];
368
365
  }
369
366
  set target(value) {
@@ -390,6 +387,16 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
390
387
  const target = this.targetSelector ? document.getElementById(this.targetSelector) : null;
391
388
  if (target && (target instanceof EFAudio || target instanceof EFVideo)) new CrossUpdateController(target, this);
392
389
  else if (this.hasCustomCaptionsData && this.rootTimegroup) new CrossUpdateController(this.rootTimegroup, this);
390
+ new MutationObserver(() => {
391
+ if (this.style.display === "none") {
392
+ this.style.removeProperty("display");
393
+ this.style.opacity = "0";
394
+ this.style.pointerEvents = "none";
395
+ }
396
+ }).observe(this, {
397
+ attributes: true,
398
+ attributeFilter: ["style"]
399
+ });
393
400
  }
394
401
  updated(changedProperties) {
395
402
  this.updateTextContainers();
@@ -407,7 +414,7 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
407
414
  updateTextContainers() {
408
415
  const captionsData = this.unifiedCaptionsDataTask.value;
409
416
  if (!captionsData) return;
410
- const currentTimeSec = (this.targetElement ? this.targetElement.currentSourceTimeMs : this.ownCurrentTimeMs) / 1e3;
417
+ const currentTimeSec = this.ownCurrentTimeMs / 1e3;
411
418
  const currentWord = captionsData.word_segments.find((word) => currentTimeSec >= word.start && currentTimeSec < word.end);
412
419
  const currentSegment = captionsData.segments.find((segment) => currentTimeSec >= segment.start && currentTimeSec < segment.end);
413
420
  for (const wordContainer of this.activeWordContainers) if (currentWord) {
@@ -423,14 +430,17 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
423
430
  wordContainer.wordEndMs = 0;
424
431
  wordContainer.requestUpdate();
425
432
  }
426
- for (const segmentContainer of this.segmentContainers) if (currentSegment) {
427
- segmentContainer.segmentText = currentSegment.text;
428
- segmentContainer.segmentStartMs = currentSegment.start * 1e3;
429
- segmentContainer.segmentEndMs = currentSegment.end * 1e3;
430
- } else {
431
- segmentContainer.segmentText = "";
432
- segmentContainer.segmentStartMs = 0;
433
- segmentContainer.segmentEndMs = 0;
433
+ for (const segmentContainer of this.segmentContainers) {
434
+ if (currentSegment) {
435
+ segmentContainer.segmentText = currentSegment.text;
436
+ segmentContainer.segmentStartMs = currentSegment.start * 1e3;
437
+ segmentContainer.segmentEndMs = currentSegment.end * 1e3;
438
+ } else {
439
+ segmentContainer.segmentText = "";
440
+ segmentContainer.segmentStartMs = 0;
441
+ segmentContainer.segmentEndMs = 0;
442
+ }
443
+ segmentContainer.requestUpdate();
434
444
  }
435
445
  if (currentWord && currentSegment) {
436
446
  const segmentWords = captionsData.word_segments.filter((word) => word.start >= currentSegment.start && word.end <= currentSegment.end);
@@ -442,11 +452,13 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
442
452
  container.segmentText = beforeWords;
443
453
  container.segmentStartMs = currentWord.start * 1e3;
444
454
  container.segmentEndMs = currentWord.end * 1e3;
455
+ container.requestUpdate();
445
456
  }
446
457
  for (const container of this.afterActiveWordContainers) {
447
458
  container.segmentText = afterWords;
448
459
  container.segmentStartMs = currentWord.start * 1e3;
449
460
  container.segmentEndMs = currentWord.end * 1e3;
461
+ container.requestUpdate();
450
462
  }
451
463
  }
452
464
  } else if (currentSegment) {
@@ -458,11 +470,13 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
458
470
  container.segmentText = "";
459
471
  container.segmentStartMs = currentSegment.start * 1e3;
460
472
  container.segmentEndMs = currentSegment.end * 1e3;
473
+ container.requestUpdate();
461
474
  }
462
475
  for (const container of this.afterActiveWordContainers) {
463
476
  container.segmentText = allWords;
464
477
  container.segmentStartMs = currentSegment.start * 1e3;
465
478
  container.segmentEndMs = currentSegment.end * 1e3;
479
+ container.requestUpdate();
466
480
  }
467
481
  } else {
468
482
  const allCompletedWords = segmentWords.map((w) => w.text.trim()).join(" ");
@@ -470,11 +484,13 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
470
484
  container.segmentText = allCompletedWords;
471
485
  container.segmentStartMs = currentSegment.start * 1e3;
472
486
  container.segmentEndMs = currentSegment.end * 1e3;
487
+ container.requestUpdate();
473
488
  }
474
489
  for (const container of this.afterActiveWordContainers) {
475
490
  container.segmentText = "";
476
491
  container.segmentStartMs = currentSegment.start * 1e3;
477
492
  container.segmentEndMs = currentSegment.end * 1e3;
493
+ container.requestUpdate();
478
494
  }
479
495
  }
480
496
  } else {
@@ -482,11 +498,13 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
482
498
  container.segmentText = "";
483
499
  container.segmentStartMs = 0;
484
500
  container.segmentEndMs = 0;
501
+ container.requestUpdate();
485
502
  }
486
503
  for (const container of this.afterActiveWordContainers) {
487
504
  container.segmentText = "";
488
505
  container.segmentStartMs = 0;
489
506
  container.segmentEndMs = 0;
507
+ container.requestUpdate();
490
508
  }
491
509
  }
492
510
  }
@@ -518,16 +536,6 @@ var EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
518
536
  return !!(this.captionsData || this.captionsScript || this.customCaptionsDataTask.value);
519
537
  }
520
538
  };
521
- __decorate([property({
522
- type: String,
523
- attribute: "display-mode",
524
- reflect: true
525
- })], EFCaptions.prototype, "displayMode", void 0);
526
- __decorate([property({
527
- type: Number,
528
- attribute: "context-words",
529
- reflect: true
530
- })], EFCaptions.prototype, "contextWords", void 0);
531
539
  __decorate([property({
532
540
  type: String,
533
541
  attribute: "target",
@@ -1,7 +1,7 @@
1
1
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
3
- import { EFSourceMixin } from "./EFSourceMixin.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
4
3
  import { EFTemporal } from "./EFTemporal.js";
4
+ import { EFSourceMixin } from "./EFSourceMixin.js";
5
5
  import { FetchMixin } from "./FetchMixin.js";
6
6
  import { Task } from "@lit/task";
7
7
  import { LitElement, css, html } from "lit";
@@ -2,8 +2,7 @@ import { AssetMediaEngine } from "./AssetMediaEngine.js";
2
2
  var AssetIdMediaEngine = class AssetIdMediaEngine extends AssetMediaEngine {
3
3
  static async fetchByAssetId(host, _urlGenerator, assetId, apiHost) {
4
4
  const url = `${apiHost}/api/v1/isobmff_files/${assetId}/index`;
5
- const data = await (await host.fetch(url)).json();
6
- return new AssetIdMediaEngine(host, assetId, data, apiHost);
5
+ return new AssetIdMediaEngine(host, assetId, await (await host.fetch(url)).json(), apiHost);
7
6
  }
8
7
  constructor(host, assetId, data, apiHost) {
9
8
  super(host, assetId);
@@ -135,9 +135,7 @@ var AssetMediaEngine = class AssetMediaEngine extends BaseMediaEngine {
135
135
  const track = this.data[rendition.trackId];
136
136
  if (!track) throw new Error("Track not found");
137
137
  const { timescale, segments } = track;
138
- const startTimeOffsetMs = "startTimeOffsetMs" in rendition && rendition.startTimeOffsetMs || 0;
139
- const offsetSeekTimeMs = roundToMilliseconds(seekTimeMs + startTimeOffsetMs);
140
- const scaledSeekTime = convertToScaledTime(offsetSeekTimeMs, timescale);
138
+ const scaledSeekTime = convertToScaledTime(roundToMilliseconds(seekTimeMs + ("startTimeOffsetMs" in rendition && rendition.startTimeOffsetMs || 0)), timescale);
141
139
  for (let i = segments.length - 1; i >= 0; i--) {
142
140
  const segment = segments[i];
143
141
  const segmentEndTime = segment.cts + segment.duration;
@@ -37,7 +37,7 @@ export declare class BufferedSeekingInput {
37
37
  getVideoTrack(trackId: number): Promise<InputVideoTrack>;
38
38
  getFirstVideoTrack(): Promise<InputVideoTrack | undefined>;
39
39
  getFirstAudioTrack(): Promise<InputAudioTrack | undefined>;
40
- getTrackIterator(track: InputTrack): AsyncIterator<MediaSample, any, undefined>;
40
+ getTrackIterator(track: InputTrack): AsyncIterator<MediaSample, any, any>;
41
41
  createTrackSampleSink(track: InputTrack): AudioSampleSink | VideoSampleSink;
42
42
  createTrackIterator(track: InputTrack): AsyncGenerator<import('mediabunny').VideoSample, void, unknown> | AsyncGenerator<import('mediabunny').AudioSample, void, unknown>;
43
43
  createTrackBuffer(track: InputTrack): SampleBuffer;
@@ -14,9 +14,8 @@ var BufferedSeekingInput = class {
14
14
  this.trackBuffers = /* @__PURE__ */ new Map();
15
15
  this.trackIteratorCreationPromises = /* @__PURE__ */ new Map();
16
16
  this.trackSeekPromises = /* @__PURE__ */ new Map();
17
- const bufferSource = new BufferSource(arrayBuffer);
18
17
  this.input = new Input({
19
- source: bufferSource,
18
+ source: new BufferSource(arrayBuffer),
20
19
  formats: [MP4]
21
20
  });
22
21
  this.options = {
@@ -99,8 +98,7 @@ var BufferedSeekingInput = class {
99
98
  timeMs,
100
99
  startTimeOffsetMs: this.startTimeOffsetMs
101
100
  }, void 0, async (span) => {
102
- const mediaTimeMs = timeMs + this.startTimeOffsetMs;
103
- const roundedMediaTimeMs = roundToMilliseconds(mediaTimeMs);
101
+ const roundedMediaTimeMs = roundToMilliseconds(timeMs + this.startTimeOffsetMs);
104
102
  span.setAttribute("roundedMediaTimeMs", roundedMediaTimeMs);
105
103
  const existingSeek = this.trackSeekPromises.get(trackId);
106
104
  if (existingSeek) {
@@ -24,14 +24,11 @@ const makeAudioBufferTask = (host) => {
24
24
  const mediaEngine = await getLatestMediaEngine(host, signal);
25
25
  if (!mediaEngine.audioRendition) return currentState;
26
26
  const engineConfig = mediaEngine.getBufferConfig();
27
- const bufferDurationMs = engineConfig.audioBufferDurationMs;
28
- const maxParallelFetches = engineConfig.maxAudioBufferFetches;
29
- const currentConfig = {
30
- bufferDurationMs,
31
- maxParallelFetches,
27
+ return manageMediaBuffer(seekTimeMs, {
28
+ bufferDurationMs: engineConfig.audioBufferDurationMs,
29
+ maxParallelFetches: engineConfig.maxAudioBufferFetches,
32
30
  enableBuffering: host.enableAudioBuffering
33
- };
34
- return manageMediaBuffer(seekTimeMs, currentConfig, currentState, host.intrinsicDurationMs || 1e4, signal, {
31
+ }, currentState, host.intrinsicDurationMs || 1e4, signal, {
35
32
  computeSegmentId: async (timeMs, rendition) => {
36
33
  return (await getLatestMediaEngine(host, signal)).computeSegmentId(timeMs, rendition);
37
34
  },
@@ -13,8 +13,7 @@ function processFFTData(fftData, zeroThresholdPercent = .1) {
13
13
  break;
14
14
  }
15
15
  if (cutoffIndex < zeroThresholdCount) return fftData;
16
- const goodData = fftData.slice(0, cutoffIndex);
17
- const resampledData = interpolateData(goodData, fftData.length);
16
+ const resampledData = interpolateData(fftData.slice(0, cutoffIndex), fftData.length);
18
17
  const attenuationStartIndex = Math.floor(totalBins * .9);
19
18
  for (let i = attenuationStartIndex; i < totalBins; i++) {
20
19
  const attenuationProgress = (i - attenuationStartIndex) / (totalBins - attenuationStartIndex) + .2;
@@ -3,8 +3,7 @@ var fetchAudioSegmentData = async (segmentIds, mediaEngine, signal) => {
3
3
  if (!audioRendition) throw new Error("Audio rendition not available");
4
4
  const segmentData = /* @__PURE__ */ new Map();
5
5
  const fetchPromises = segmentIds.map(async (segmentId) => {
6
- const arrayBuffer = await mediaEngine.fetchMediaSegment(segmentId, audioRendition, signal);
7
- return [segmentId, arrayBuffer];
6
+ return [segmentId, await mediaEngine.fetchMediaSegment(segmentId, audioRendition, signal)];
8
7
  });
9
8
  const fetchedSegments = await Promise.all(fetchPromises);
10
9
  signal.throwIfAborted();
@@ -25,17 +24,14 @@ const fetchAudioSpanningTime = async (host, fromMs, toMs, signal) => {
25
24
  if (segmentRanges.length === 0) throw new Error(`No segments found for time range ${fromMs}-${toMs}ms`);
26
25
  const segmentIds = segmentRanges.map((r) => r.segmentId);
27
26
  const segmentData = await fetchAudioSegmentData(segmentIds, mediaEngine, signal);
28
- const orderedSegments = segmentIds.map((id) => {
27
+ const blob = createAudioSpanBlob(initSegment, segmentIds.map((id) => {
29
28
  const segment = segmentData.get(id);
30
29
  if (!segment) throw new Error(`Missing segment data for segment ID ${id}`);
31
30
  return segment;
32
- });
33
- const blob = createAudioSpanBlob(initSegment, orderedSegments);
34
- const actualStartMs = Math.min(...segmentRanges.map((r) => r.startMs));
35
- const actualEndMs = Math.max(...segmentRanges.map((r) => r.endMs));
31
+ }));
36
32
  return {
37
- startMs: actualStartMs,
38
- endMs: actualEndMs,
33
+ startMs: Math.min(...segmentRanges.map((r) => r.startMs)),
34
+ endMs: Math.max(...segmentRanges.map((r) => r.endMs)),
39
35
  blob
40
36
  };
41
37
  };
@@ -19,9 +19,7 @@ const manageMediaBuffer = async (seekTimeMs, config, currentState, durationMs, s
19
19
  if (!config.enableBuffering) return currentState;
20
20
  const rendition = await deps.getRendition();
21
21
  if (!rendition) return currentState;
22
- const endTimeMs = seekTimeMs + config.bufferDurationMs;
23
- const uncachedSegments = (await computeSegmentRangeAsync(seekTimeMs, endTimeMs, durationMs, rendition, deps.computeSegmentId)).filter((segmentId) => !deps.isSegmentCached(segmentId, rendition));
24
- const newQueue = computeBufferQueue(uncachedSegments, currentState.requestedSegments);
22
+ const newQueue = computeBufferQueue((await computeSegmentRangeAsync(seekTimeMs, seekTimeMs + config.bufferDurationMs, durationMs, rendition, deps.computeSegmentId)).filter((segmentId) => !deps.isSegmentCached(segmentId, rendition)), currentState.requestedSegments);
25
23
  const newRequestedSegments = new Set(currentState.requestedSegments);
26
24
  const newActiveRequests = new Set(currentState.activeRequests);
27
25
  const remainingQueue = [...newQueue];
@@ -22,14 +22,11 @@ const makeVideoBufferTask = (host) => {
22
22
  task: async ([seekTimeMs], { signal }) => {
23
23
  if (EF_RENDERING()) return currentState;
24
24
  const engineConfig = (await getLatestMediaEngine(host, signal)).getBufferConfig();
25
- const bufferDurationMs = engineConfig.videoBufferDurationMs;
26
- const maxParallelFetches = engineConfig.maxVideoBufferFetches;
27
- const currentConfig = {
28
- bufferDurationMs,
29
- maxParallelFetches,
25
+ return manageMediaBuffer(seekTimeMs, {
26
+ bufferDurationMs: engineConfig.videoBufferDurationMs,
27
+ maxParallelFetches: engineConfig.maxVideoBufferFetches,
30
28
  enableBuffering: host.enableVideoBuffering
31
- };
32
- return manageMediaBuffer(seekTimeMs, currentConfig, currentState, host.intrinsicDurationMs || 1e4, signal, {
29
+ }, currentState, host.intrinsicDurationMs || 1e4, signal, {
33
30
  computeSegmentId: async (timeMs, rendition) => {
34
31
  return (await getLatestMediaEngine(host, signal)).computeSegmentId(timeMs, rendition);
35
32
  },
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValueMap } from 'lit';
2
+ import { ControllableInterface } from '../gui/Controllable.js';
2
3
  import { AudioSpan } from '../transcoding/types/index.ts';
3
4
  import { UrlGenerator } from '../transcoding/utils/UrlGenerator.ts';
4
5
  declare global {
@@ -9,6 +10,7 @@ export declare class IgnorableError extends Error {
9
10
  export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
10
11
  declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
11
12
  export declare class EFMedia extends EFMedia_base {
13
+ get efContext(): ControllableInterface | null;
12
14
  static readonly VIDEO_SAMPLE_BUFFER_SIZE = 30;
13
15
  static readonly AUDIO_SAMPLE_BUFFER_SIZE = 120;
14
16
  static get observedAttributes(): string[];
@@ -84,5 +86,22 @@ export declare class EFMedia extends EFMedia_base {
84
86
  * Returns undefined if no audio rendition is available
85
87
  */
86
88
  fetchAudioSpanningTime(fromMs: number, toMs: number, signal?: AbortSignal): Promise<AudioSpan | undefined>;
89
+ /**
90
+ * Wait for media engine to load and determine duration
91
+ * Ensures media is ready for playback
92
+ */
93
+ waitForMediaDurations(): Promise<void>;
94
+ /**
95
+ * Returns media elements for playback audio rendering
96
+ * For standalone media, returns [this]; for timegroups, returns all descendants
97
+ * Used by PlaybackController for audio-driven playback
98
+ */
99
+ getMediaElements(): EFMedia[];
100
+ /**
101
+ * Render audio buffer for playback
102
+ * Called by PlaybackController during live playback
103
+ * Delegates to shared renderTemporalAudio utility for consistent behavior
104
+ */
105
+ renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer>;
87
106
  }
88
107
  export {};
@@ -1,4 +1,6 @@
1
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
2
+ import { EFTemporal } from "./EFTemporal.js";
3
+ import { efContext } from "../gui/efContext.js";
2
4
  import { isContextMixin } from "../gui/ContextMixin.js";
3
5
  import { withSpan } from "../otel/tracingHelpers.js";
4
6
  import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
@@ -13,9 +15,10 @@ import { makeAudioSegmentIdTask } from "./EFMedia/audioTasks/makeAudioSegmentIdT
13
15
  import { makeAudioTimeDomainAnalysisTask } from "./EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js";
14
16
  import { fetchAudioSpanningTime } from "./EFMedia/shared/AudioSpanUtils.js";
15
17
  import { EFSourceMixin } from "./EFSourceMixin.js";
16
- import { EFTemporal } from "./EFTemporal.js";
17
18
  import { FetchMixin } from "./FetchMixin.js";
19
+ import { renderTemporalAudio } from "./renderTemporalAudio.js";
18
20
  import { EFTargetable } from "./TargetController.js";
21
+ import { provide } from "@lit/context";
19
22
  import { LitElement, css } from "lit";
20
23
  import { property, state } from "lit/decorators.js";
21
24
  var freqWeightsCache = /* @__PURE__ */ new Map();
@@ -48,6 +51,9 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
48
51
  this.assetId = null;
49
52
  this._desiredSeekTimeMs = 0;
50
53
  }
54
+ get efContext() {
55
+ return this.rootTimegroup ?? this;
56
+ }
51
57
  static {
52
58
  this.VIDEO_SAMPLE_BUFFER_SIZE = 30;
53
59
  }
@@ -152,7 +158,18 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
152
158
  return fetchAudioSpanningTime(this, fromMs, toMs, signal);
153
159
  });
154
160
  }
161
+ async waitForMediaDurations() {
162
+ if (this.mediaEngineTask.value) return;
163
+ await this.mediaEngineTask.run();
164
+ }
165
+ getMediaElements() {
166
+ return [this];
167
+ }
168
+ async renderAudio(fromMs, toMs) {
169
+ return renderTemporalAudio(this, fromMs, toMs);
170
+ }
155
171
  };
172
+ __decorate([provide({ context: efContext })], EFMedia.prototype, "efContext", null);
156
173
  __decorate([property({
157
174
  type: Number,
158
175
  attribute: "audio-buffer-duration"
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
2
2
  import { Task } from "@lit/task";
3
3
  import { property } from "lit/decorators/property.js";
4
4
  function EFSourceMixin(superClass, options) {
@@ -1,4 +1,4 @@
1
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.93.0/helpers/decorate.js";
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
2
2
  import { TargetController } from "./TargetController.js";
3
3
  import { Task } from "@lit/task";
4
4
  import { LitElement, css, html } from "lit";
@@ -8,4 +8,15 @@ declare global {
8
8
  "ten-seconds": TenSeconds;
9
9
  }
10
10
  }
11
+ declare const TestLifecycleChild_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
12
+ declare class TestLifecycleChild extends TestLifecycleChild_base {
13
+ role: "root" | "child" | null;
14
+ didBecomeRoot(): void;
15
+ didBecomeChild(): void;
16
+ }
17
+ declare global {
18
+ interface HTMLElementTagNameMap {
19
+ "test-root-lifecycle": TestLifecycleChild;
20
+ }
21
+ }
11
22
  export {};