@editframe/elements 0.20.4-beta.0 → 0.23.6-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.
- package/dist/DelayedLoadingState.js +0 -27
- package/dist/EF_FRAMEGEN.d.ts +5 -3
- package/dist/EF_FRAMEGEN.js +49 -11
- package/dist/_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js +7 -0
- package/dist/attachContextRoot.d.ts +1 -0
- package/dist/attachContextRoot.js +9 -0
- package/dist/elements/ContextProxiesController.d.ts +1 -2
- package/dist/elements/EFAudio.js +5 -9
- package/dist/elements/EFCaptions.d.ts +1 -3
- package/dist/elements/EFCaptions.js +112 -129
- package/dist/elements/EFImage.js +6 -7
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -5
- package/dist/elements/EFMedia/AssetMediaEngine.js +36 -33
- package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -78
- package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +7 -13
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +9 -25
- package/dist/elements/EFMedia/shared/BufferUtils.js +2 -17
- package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
- package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -18
- package/dist/elements/EFMedia.d.ts +19 -0
- package/dist/elements/EFMedia.js +44 -25
- package/dist/elements/EFSourceMixin.js +5 -7
- package/dist/elements/EFSurface.js +6 -9
- package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
- package/dist/elements/EFTemporal.d.ts +10 -0
- package/dist/elements/EFTemporal.js +100 -41
- package/dist/elements/EFThumbnailStrip.js +23 -73
- package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
- package/dist/elements/EFTimegroup.d.ts +35 -14
- package/dist/elements/EFTimegroup.js +138 -181
- package/dist/elements/EFVideo.d.ts +16 -2
- package/dist/elements/EFVideo.js +156 -108
- package/dist/elements/EFWaveform.js +23 -40
- package/dist/elements/SampleBuffer.js +3 -7
- package/dist/elements/TargetController.js +5 -5
- package/dist/elements/durationConverter.js +4 -4
- package/dist/elements/renderTemporalAudio.d.ts +10 -0
- package/dist/elements/renderTemporalAudio.js +35 -0
- package/dist/elements/updateAnimations.js +19 -43
- package/dist/gui/ContextMixin.d.ts +5 -5
- package/dist/gui/ContextMixin.js +167 -162
- package/dist/gui/Controllable.browsertest.d.ts +0 -0
- package/dist/gui/Controllable.d.ts +15 -0
- package/dist/gui/Controllable.js +9 -0
- package/dist/gui/EFConfiguration.js +7 -7
- package/dist/gui/EFControls.browsertest.d.ts +11 -0
- package/dist/gui/EFControls.d.ts +18 -4
- package/dist/gui/EFControls.js +70 -28
- package/dist/gui/EFDial.browsertest.d.ts +0 -0
- package/dist/gui/EFDial.d.ts +18 -0
- package/dist/gui/EFDial.js +141 -0
- package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
- package/dist/gui/EFFilmstrip.d.ts +12 -2
- package/dist/gui/EFFilmstrip.js +214 -129
- package/dist/gui/EFFitScale.js +5 -8
- package/dist/gui/EFFocusOverlay.js +4 -4
- package/dist/gui/EFPause.browsertest.d.ts +0 -0
- package/dist/gui/EFPause.d.ts +23 -0
- package/dist/gui/EFPause.js +59 -0
- package/dist/gui/EFPlay.browsertest.d.ts +0 -0
- package/dist/gui/EFPlay.d.ts +23 -0
- package/dist/gui/EFPlay.js +59 -0
- package/dist/gui/EFPreview.d.ts +4 -0
- package/dist/gui/EFPreview.js +18 -9
- package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
- package/dist/gui/EFResizableBox.d.ts +34 -0
- package/dist/gui/EFResizableBox.js +547 -0
- package/dist/gui/EFScrubber.d.ts +9 -3
- package/dist/gui/EFScrubber.js +13 -13
- package/dist/gui/EFTimeDisplay.d.ts +7 -1
- package/dist/gui/EFTimeDisplay.js +8 -8
- package/dist/gui/EFToggleLoop.d.ts +9 -3
- package/dist/gui/EFToggleLoop.js +7 -5
- package/dist/gui/EFTogglePlay.d.ts +12 -4
- package/dist/gui/EFTogglePlay.js +26 -21
- package/dist/gui/EFWorkbench.js +5 -5
- package/dist/gui/PlaybackController.d.ts +67 -0
- package/dist/gui/PlaybackController.js +310 -0
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin2.js +1 -1
- package/dist/gui/TargetOrContextMixin.d.ts +10 -0
- package/dist/gui/TargetOrContextMixin.js +98 -0
- package/dist/gui/efContext.d.ts +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -1
- package/dist/otel/BridgeSpanExporter.d.ts +13 -0
- package/dist/otel/BridgeSpanExporter.js +87 -0
- package/dist/otel/setupBrowserTracing.d.ts +12 -0
- package/dist/otel/setupBrowserTracing.js +32 -0
- package/dist/otel/tracingHelpers.d.ts +34 -0
- package/dist/otel/tracingHelpers.js +112 -0
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
- package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
- package/dist/transcoding/utils/UrlGenerator.js +2 -19
- package/dist/utils/LRUCache.js +6 -53
- package/package.json +13 -5
- package/src/elements/ContextProxiesController.ts +10 -10
- package/src/elements/EFAudio.ts +1 -0
- package/src/elements/EFCaptions.browsertest.ts +128 -56
- package/src/elements/EFCaptions.ts +60 -34
- package/src/elements/EFImage.browsertest.ts +1 -2
- package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
- package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
- package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
- package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
- package/src/elements/EFMedia.browsertest.ts +8 -15
- package/src/elements/EFMedia.ts +54 -8
- package/src/elements/EFSurface.browsertest.ts +2 -6
- package/src/elements/EFSurface.ts +1 -0
- package/src/elements/EFTemporal.browsertest.ts +58 -1
- package/src/elements/EFTemporal.ts +140 -4
- package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
- package/src/elements/EFThumbnailStrip.ts +1 -0
- package/src/elements/EFTimegroup.browsertest.ts +16 -15
- package/src/elements/EFTimegroup.ts +281 -275
- package/src/elements/EFVideo.browsertest.ts +162 -74
- package/src/elements/EFVideo.ts +229 -101
- package/src/elements/FetchContext.browsertest.ts +7 -2
- package/src/elements/TargetController.browsertest.ts +1 -0
- package/src/elements/TargetController.ts +1 -0
- package/src/elements/renderTemporalAudio.ts +108 -0
- package/src/elements/updateAnimations.browsertest.ts +181 -6
- package/src/elements/updateAnimations.ts +6 -6
- package/src/gui/ContextMixin.browsertest.ts +274 -27
- package/src/gui/ContextMixin.ts +230 -175
- package/src/gui/Controllable.browsertest.ts +258 -0
- package/src/gui/Controllable.ts +41 -0
- package/src/gui/EFControls.browsertest.ts +294 -80
- package/src/gui/EFControls.ts +139 -28
- package/src/gui/EFDial.browsertest.ts +84 -0
- package/src/gui/EFDial.ts +172 -0
- package/src/gui/EFFilmstrip.browsertest.ts +712 -0
- package/src/gui/EFFilmstrip.ts +213 -23
- package/src/gui/EFPause.browsertest.ts +202 -0
- package/src/gui/EFPause.ts +73 -0
- package/src/gui/EFPlay.browsertest.ts +202 -0
- package/src/gui/EFPlay.ts +73 -0
- package/src/gui/EFPreview.ts +20 -5
- package/src/gui/EFResizableBox.browsertest.ts +79 -0
- package/src/gui/EFResizableBox.ts +898 -0
- package/src/gui/EFScrubber.ts +7 -5
- package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
- package/src/gui/EFTimeDisplay.ts +3 -1
- package/src/gui/EFToggleLoop.ts +6 -5
- package/src/gui/EFTogglePlay.ts +30 -23
- package/src/gui/PlaybackController.ts +522 -0
- package/src/gui/TWMixin.css +3 -0
- package/src/gui/TargetOrContextMixin.ts +185 -0
- package/src/gui/efContext.ts +2 -2
- package/src/otel/BridgeSpanExporter.ts +150 -0
- package/src/otel/setupBrowserTracing.ts +73 -0
- package/src/otel/tracingHelpers.ts +251 -0
- package/test/cache-integration-verification.browsertest.ts +1 -1
- package/types.json +1 -1
- package/dist/elements/ContextProxiesController.js +0 -69
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
3
|
+
import { parseTimeToMs } from "./parseTimeToMs.js";
|
|
4
|
+
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
|
|
4
5
|
import { EFTemporal, deepGetElementsWithFrameTasks, flushStartTimeMsCache, resetTemporalCache, shallowGetTemporalElements, timegroupContext } from "./EFTemporal.js";
|
|
6
|
+
import { efContext } from "../gui/efContext.js";
|
|
7
|
+
import { isContextMixin } from "../gui/ContextMixin.js";
|
|
8
|
+
import { TWMixin } from "../gui/TWMixin2.js";
|
|
9
|
+
import { isTracingEnabled, withSpan } from "../otel/tracingHelpers.js";
|
|
10
|
+
import { renderTemporalAudio } from "./renderTemporalAudio.js";
|
|
11
|
+
import { EFTargetable } from "./TargetController.js";
|
|
5
12
|
import { deepGetMediaElements } from "./EFMedia.js";
|
|
6
13
|
import { TimegroupController } from "./TimegroupController.js";
|
|
7
14
|
import { evaluateTemporalStateForAnimation, updateAnimations } from "./updateAnimations.js";
|
|
@@ -10,10 +17,9 @@ import { Task, TaskStatus } from "@lit/task";
|
|
|
10
17
|
import debug from "debug";
|
|
11
18
|
import { LitElement, css, html } from "lit";
|
|
12
19
|
import { customElement, property } from "lit/decorators.js";
|
|
13
|
-
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
14
20
|
var _EFTimegroup;
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
var log = debug("ef:elements:EFTimegroup");
|
|
22
|
+
var sequenceDurationCache = /* @__PURE__ */ new WeakMap();
|
|
17
23
|
const flushSequenceDurationCache = () => {
|
|
18
24
|
sequenceDurationCache = /* @__PURE__ */ new WeakMap();
|
|
19
25
|
};
|
|
@@ -22,25 +28,30 @@ const shallowGetTimegroups = (element, groups = []) => {
|
|
|
22
28
|
else shallowGetTimegroups(child, groups);
|
|
23
29
|
return groups;
|
|
24
30
|
};
|
|
25
|
-
|
|
31
|
+
var EFTimegroup = class EFTimegroup$1 extends EFTargetable(EFTemporal(TWMixin(LitElement))) {
|
|
26
32
|
static {
|
|
27
33
|
_EFTimegroup = this;
|
|
28
34
|
}
|
|
29
35
|
constructor(..._args) {
|
|
30
36
|
super(..._args);
|
|
31
37
|
this._timeGroupContext = this;
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
38
|
+
this.efContext = this;
|
|
39
|
+
this.mode = "contain";
|
|
40
|
+
this.overlapMs = 0;
|
|
34
41
|
this.fit = "none";
|
|
35
42
|
this.mediaDurationsPromise = void 0;
|
|
36
43
|
this.frameTask = new Task(this, {
|
|
37
44
|
autoRun: false,
|
|
38
45
|
args: () => [this.ownCurrentTimeMs, this.currentTimeMs],
|
|
39
|
-
task: async ([]) => {
|
|
40
|
-
if (this.isRootTimegroup) {
|
|
46
|
+
task: async ([ownCurrentTimeMs, currentTimeMs]) => {
|
|
47
|
+
if (this.isRootTimegroup) await withSpan("timegroup.frameTask", {
|
|
48
|
+
timegroupId: this.id || "unknown",
|
|
49
|
+
ownCurrentTimeMs,
|
|
50
|
+
currentTimeMs
|
|
51
|
+
}, void 0, async () => {
|
|
41
52
|
await this.waitForFrameTasks();
|
|
42
53
|
updateAnimations(this);
|
|
43
|
-
}
|
|
54
|
+
});
|
|
44
55
|
}
|
|
45
56
|
});
|
|
46
57
|
this.seekTask = new Task(this, {
|
|
@@ -48,79 +59,75 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
48
59
|
args: () => [this.#pendingSeekTime ?? this.#currentTime],
|
|
49
60
|
onComplete: () => {},
|
|
50
61
|
task: async ([targetTime]) => {
|
|
62
|
+
if (this.playbackController) {
|
|
63
|
+
await this.playbackController.seekTask.taskComplete;
|
|
64
|
+
return this.currentTime;
|
|
65
|
+
}
|
|
51
66
|
if (!this.isRootTimegroup) return;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
return withSpan("timegroup.seekTask", {
|
|
68
|
+
timegroupId: this.id || "unknown",
|
|
69
|
+
targetTime: targetTime ?? 0,
|
|
70
|
+
durationMs: this.durationMs
|
|
71
|
+
}, void 0, async (span) => {
|
|
72
|
+
await this.waitForMediaDurations();
|
|
73
|
+
const newTime = Math.max(0, Math.min(targetTime ?? 0, this.durationMs / 1e3));
|
|
74
|
+
if (isTracingEnabled()) span.setAttribute("newTime", newTime);
|
|
75
|
+
this.#currentTime = newTime;
|
|
76
|
+
this.requestUpdate("currentTime");
|
|
77
|
+
await this.runThrottledFrameTask();
|
|
78
|
+
this.saveTimeToLocalStorage(this.#currentTime);
|
|
79
|
+
this.#seekInProgress = false;
|
|
80
|
+
return newTime;
|
|
81
|
+
});
|
|
60
82
|
}
|
|
61
83
|
});
|
|
62
84
|
}
|
|
85
|
+
static get observedAttributes() {
|
|
86
|
+
return [
|
|
87
|
+
...super.observedAttributes || [],
|
|
88
|
+
"mode",
|
|
89
|
+
"overlap",
|
|
90
|
+
"currenttime",
|
|
91
|
+
"fit"
|
|
92
|
+
];
|
|
93
|
+
}
|
|
63
94
|
static {
|
|
64
95
|
this.styles = css`
|
|
65
96
|
:host {
|
|
66
97
|
display: block;
|
|
98
|
+
position: relative;
|
|
99
|
+
overflow: hidden;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
::slotted(ef-timegroup) {
|
|
103
|
+
position: absolute;
|
|
67
104
|
width: 100%;
|
|
68
105
|
height: 100%;
|
|
69
|
-
position: absolute;
|
|
70
106
|
top: 0;
|
|
71
107
|
left: 0;
|
|
72
108
|
}
|
|
73
109
|
`;
|
|
74
110
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
get mode() {
|
|
81
|
-
return this._mode;
|
|
82
|
-
}
|
|
83
|
-
set overlapMs(value) {
|
|
84
|
-
sequenceDurationCache.delete(this);
|
|
85
|
-
this._overlapMs = value;
|
|
86
|
-
}
|
|
87
|
-
get overlapMs() {
|
|
88
|
-
return this._overlapMs;
|
|
111
|
+
attributeChangedCallback(name, old, value) {
|
|
112
|
+
if (name === "mode" && value) this.mode = value;
|
|
113
|
+
if (name === "overlap" && value) this.overlapMs = parseTimeToMs(value);
|
|
114
|
+
super.attributeChangedCallback(name, old, value);
|
|
89
115
|
}
|
|
90
116
|
#resizeObserver;
|
|
117
|
+
#currentTime = void 0;
|
|
91
118
|
#seekInProgress = false;
|
|
92
119
|
#pendingSeekTime;
|
|
93
120
|
#processingPendingSeek = false;
|
|
94
|
-
#frameTaskInProgress = false;
|
|
95
|
-
#pendingFrameTaskRun = false;
|
|
96
|
-
#processingPendingFrameTask = false;
|
|
97
|
-
/**
|
|
98
|
-
* Throttles frameTask execution to ensure only one runs at a time while preserving the last request
|
|
99
|
-
*/
|
|
100
121
|
async runThrottledFrameTask() {
|
|
101
|
-
if (this
|
|
102
|
-
|
|
103
|
-
while (this.#frameTaskInProgress) await this.frameTask.taskComplete;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
this.#frameTaskInProgress = true;
|
|
107
|
-
try {
|
|
108
|
-
await this.frameTask.run();
|
|
109
|
-
} finally {
|
|
110
|
-
this.#frameTaskInProgress = false;
|
|
111
|
-
if (this.#pendingFrameTaskRun && !this.#processingPendingFrameTask) {
|
|
112
|
-
this.#pendingFrameTaskRun = false;
|
|
113
|
-
this.#processingPendingFrameTask = true;
|
|
114
|
-
try {
|
|
115
|
-
await this.runThrottledFrameTask();
|
|
116
|
-
} finally {
|
|
117
|
-
this.#processingPendingFrameTask = false;
|
|
118
|
-
}
|
|
119
|
-
} else this.#pendingFrameTaskRun = false;
|
|
120
|
-
}
|
|
122
|
+
if (this.playbackController) return this.playbackController.runThrottledFrameTask();
|
|
123
|
+
await this.frameTask.run();
|
|
121
124
|
}
|
|
122
125
|
set currentTime(time) {
|
|
123
|
-
|
|
126
|
+
if (this.playbackController) {
|
|
127
|
+
this.playbackController.currentTime = time;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
time = Math.max(0, Math.min(this.durationMs / 1e3, time));
|
|
124
131
|
if (!this.isRootTimegroup) return;
|
|
125
132
|
if (Number.isNaN(time)) return;
|
|
126
133
|
if (time === this.#currentTime && !this.#processingPendingSeek) return;
|
|
@@ -146,6 +153,7 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
146
153
|
});
|
|
147
154
|
}
|
|
148
155
|
get currentTime() {
|
|
156
|
+
if (this.playbackController) return this.playbackController.currentTime;
|
|
149
157
|
return this.#currentTime ?? 0;
|
|
150
158
|
}
|
|
151
159
|
set currentTimeMs(ms) {
|
|
@@ -154,16 +162,23 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
154
162
|
get currentTimeMs() {
|
|
155
163
|
return this.currentTime * 1e3;
|
|
156
164
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
async seek(timeMs) {
|
|
166
|
+
this.currentTimeMs = timeMs;
|
|
167
|
+
await this.seekTask.taskComplete;
|
|
168
|
+
if (this.playbackController) this.saveTimeToLocalStorage(this.currentTime);
|
|
169
|
+
await this.frameTask.taskComplete;
|
|
170
|
+
const visibleElements = deepGetElementsWithFrameTasks(this).filter((element) => {
|
|
171
|
+
return evaluateTemporalStateForAnimation(element).isVisible;
|
|
172
|
+
});
|
|
173
|
+
await Promise.all(visibleElements.map(async (element) => {
|
|
174
|
+
if ("waitForFrameReady" in element && typeof element.waitForFrameReady === "function") await element.waitForFrameReady();
|
|
175
|
+
else await element.updateComplete;
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
160
178
|
get isRootTimegroup() {
|
|
161
179
|
return !this.parentTimegroup;
|
|
162
180
|
}
|
|
163
|
-
|
|
164
|
-
* Saves time to localStorage (extracted for reuse)
|
|
165
|
-
*/
|
|
166
|
-
#saveTimeToLocalStorage(time) {
|
|
181
|
+
saveTimeToLocalStorage(time) {
|
|
167
182
|
try {
|
|
168
183
|
if (this.id && this.isConnected && !Number.isNaN(time)) localStorage.setItem(this.storageKey, time.toString());
|
|
169
184
|
} catch (error) {
|
|
@@ -179,10 +194,10 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
179
194
|
flushStartTimeMsCache();
|
|
180
195
|
this.requestUpdate();
|
|
181
196
|
};
|
|
182
|
-
|
|
197
|
+
loadTimeFromLocalStorage() {
|
|
183
198
|
if (this.id) try {
|
|
184
199
|
const storedValue = localStorage.getItem(this.storageKey);
|
|
185
|
-
if (storedValue === null) return
|
|
200
|
+
if (storedValue === null) return;
|
|
186
201
|
return Number.parseFloat(storedValue);
|
|
187
202
|
} catch (error) {
|
|
188
203
|
log("Failed to load time from localStorage", error);
|
|
@@ -190,9 +205,9 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
190
205
|
}
|
|
191
206
|
connectedCallback() {
|
|
192
207
|
super.connectedCallback();
|
|
193
|
-
this.waitForMediaDurations().then(() => {
|
|
208
|
+
if (!this.playbackController) this.waitForMediaDurations().then(() => {
|
|
194
209
|
if (this.id) {
|
|
195
|
-
const maybeLoadedTime = this.
|
|
210
|
+
const maybeLoadedTime = this.loadTimeFromLocalStorage();
|
|
196
211
|
if (maybeLoadedTime !== void 0) this.currentTime = maybeLoadedTime;
|
|
197
212
|
}
|
|
198
213
|
if (EF_INTERACTIVE && this.seekTask.status === TaskStatus.INITIAL) this.seekTask.run();
|
|
@@ -201,7 +216,9 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
201
216
|
if (this.shouldWrapWithWorkbench()) this.wrapWithWorkbench();
|
|
202
217
|
}
|
|
203
218
|
#previousDurationMs = 0;
|
|
204
|
-
updated(
|
|
219
|
+
updated(changedProperties) {
|
|
220
|
+
super.updated(changedProperties);
|
|
221
|
+
if (changedProperties.has("mode") || changedProperties.has("overlapMs")) sequenceDurationCache.delete(this);
|
|
205
222
|
if (this.#previousDurationMs !== this.durationMs) {
|
|
206
223
|
this.#previousDurationMs = this.durationMs;
|
|
207
224
|
this.runThrottledFrameTask();
|
|
@@ -217,17 +234,15 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
217
234
|
}
|
|
218
235
|
get intrinsicDurationMs() {
|
|
219
236
|
if (this.hasExplicitDuration) return this.explicitDurationMs;
|
|
220
|
-
return void 0;
|
|
221
237
|
}
|
|
222
238
|
get hasOwnDuration() {
|
|
223
239
|
return this.mode === "contain" || this.mode === "sequence" || this.mode === "fixed" && this.hasExplicitDuration;
|
|
224
240
|
}
|
|
225
241
|
get durationMs() {
|
|
226
242
|
switch (this.mode) {
|
|
227
|
-
case "fit":
|
|
243
|
+
case "fit":
|
|
228
244
|
if (!this.parentTimegroup) return 0;
|
|
229
245
|
return this.parentTimegroup.durationMs;
|
|
230
|
-
}
|
|
231
246
|
case "fixed": return super.durationMs;
|
|
232
247
|
case "sequence": {
|
|
233
248
|
const cachedDuration = sequenceDurationCache.get(this);
|
|
@@ -258,18 +273,15 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
258
273
|
signal?.throwIfAborted();
|
|
259
274
|
const temporals = deepGetElementsWithFrameTasks(this);
|
|
260
275
|
const timelineTimeMs = (this.#pendingSeekTime ?? this.#currentTime ?? 0) * 1e3;
|
|
261
|
-
const
|
|
276
|
+
const frameTasks = temporals.filter((temporal) => {
|
|
262
277
|
if (!("startTimeMs" in temporal) || !("endTimeMs" in temporal)) return true;
|
|
263
278
|
const epsilon = .001;
|
|
264
279
|
const startTimeMs = temporal.startTimeMs;
|
|
265
280
|
const endTimeMs = temporal.endTimeMs;
|
|
266
281
|
const elementStartsBeforeEnd = startTimeMs <= timelineTimeMs + epsilon;
|
|
267
|
-
const
|
|
268
|
-
const useInclusiveEnd = isRootTimegroup;
|
|
269
|
-
const elementEndsAfterStart = useInclusiveEnd ? endTimeMs >= timelineTimeMs : endTimeMs > timelineTimeMs;
|
|
282
|
+
const elementEndsAfterStart = temporal.tagName.toLowerCase() === "ef-timegroup" && !temporal.parentTimegroup ? endTimeMs >= timelineTimeMs : endTimeMs > timelineTimeMs;
|
|
270
283
|
return elementStartsBeforeEnd && elementEndsAfterStart;
|
|
271
|
-
});
|
|
272
|
-
const frameTasks = activeTemporals.map((temporal) => temporal.frameTask);
|
|
284
|
+
}).map((temporal) => temporal.frameTask);
|
|
273
285
|
frameTasks.forEach((task) => {
|
|
274
286
|
task.run();
|
|
275
287
|
});
|
|
@@ -288,31 +300,45 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
288
300
|
}
|
|
289
301
|
}
|
|
290
302
|
async waitForFrameTasks() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
303
|
+
return await withSpan("timegroup.waitForFrameTasks", {
|
|
304
|
+
timegroupId: this.id || "unknown",
|
|
305
|
+
mode: this.mode
|
|
306
|
+
}, void 0, async (span) => {
|
|
307
|
+
const innerStart = performance.now();
|
|
308
|
+
const temporalElements = deepGetElementsWithFrameTasks(this);
|
|
309
|
+
if (isTracingEnabled()) span.setAttribute("temporalElementsCount", temporalElements.length);
|
|
310
|
+
const visibleElements = temporalElements.filter((element) => {
|
|
311
|
+
return evaluateTemporalStateForAnimation(element).isVisible;
|
|
312
|
+
});
|
|
313
|
+
if (isTracingEnabled()) span.setAttribute("visibleElementsCount", visibleElements.length);
|
|
314
|
+
const promiseStart = performance.now();
|
|
315
|
+
await Promise.all(visibleElements.map((element) => element.frameTask.run()));
|
|
316
|
+
const promiseEnd = performance.now();
|
|
317
|
+
const innerEnd = performance.now();
|
|
318
|
+
if (isTracingEnabled()) {
|
|
319
|
+
span.setAttribute("actualInnerMs", innerEnd - innerStart);
|
|
320
|
+
span.setAttribute("promiseAwaitMs", promiseEnd - promiseStart);
|
|
321
|
+
}
|
|
295
322
|
});
|
|
296
|
-
await Promise.all(visibleElements.map((element) => element.frameTask.run()));
|
|
297
323
|
}
|
|
298
324
|
async waitForMediaDurations() {
|
|
299
325
|
if (!this.mediaDurationsPromise) this.mediaDurationsPromise = this.#waitForMediaDurations();
|
|
300
326
|
return this.mediaDurationsPromise;
|
|
301
327
|
}
|
|
302
|
-
/**
|
|
303
|
-
* Wait for all media elements to load their initial segments.
|
|
304
|
-
* Ideally we would only need the extracted index json data, but
|
|
305
|
-
* that caused issues with constructing audio data. We had negative durations
|
|
306
|
-
* in calculations and it was not clear why.
|
|
307
|
-
*/
|
|
308
328
|
async #waitForMediaDurations() {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
329
|
+
return withSpan("timegroup.waitForMediaDurations", {
|
|
330
|
+
timegroupId: this.id || "unknown",
|
|
331
|
+
mode: this.mode
|
|
332
|
+
}, void 0, async (span) => {
|
|
333
|
+
await this.updateComplete;
|
|
334
|
+
const mediaElements = deepGetMediaElements(this);
|
|
335
|
+
if (isTracingEnabled()) span.setAttribute("mediaElementsCount", mediaElements.length);
|
|
336
|
+
await Promise.all(mediaElements.map((m) => m.mediaEngineTask.value ? Promise.resolve() : m.mediaEngineTask.run()));
|
|
337
|
+
flushStartTimeMsCache();
|
|
338
|
+
flushSequenceDurationCache();
|
|
339
|
+
this.requestUpdate("currentTime");
|
|
340
|
+
await this.updateComplete;
|
|
341
|
+
});
|
|
316
342
|
}
|
|
317
343
|
get childTemporals() {
|
|
318
344
|
return shallowGetTemporalElements(this);
|
|
@@ -325,16 +351,9 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
325
351
|
}
|
|
326
352
|
return null;
|
|
327
353
|
}
|
|
328
|
-
/**
|
|
329
|
-
* Returns true if the timegroup should be wrapped with a workbench.
|
|
330
|
-
*
|
|
331
|
-
* A timegroup should be wrapped with a workbench if it is the root-most timegroup
|
|
332
|
-
* and EF_INTERACTIVE is true.
|
|
333
|
-
*
|
|
334
|
-
* If the timegroup is already wrappedin a context provider like ef-preview,
|
|
335
|
-
* it should NOT be wrapped in a workbench.
|
|
336
|
-
*/
|
|
337
354
|
shouldWrapWithWorkbench() {
|
|
355
|
+
if (EF_RENDERING?.() === true) return this.closest("ef-timegroup") === this && this.closest("ef-preview") === null && this.closest("ef-workbench") === null && this.closest("test-context") === null;
|
|
356
|
+
if (!globalThis.EF_DEV_WORKBENCH) return false;
|
|
338
357
|
return EF_INTERACTIVE && this.closest("ef-timegroup") === this && this.closest("ef-preview") === null && this.closest("ef-workbench") === null && this.closest("test-context") === null;
|
|
339
358
|
}
|
|
340
359
|
wrapWithWorkbench() {
|
|
@@ -351,66 +370,12 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
351
370
|
get efElements() {
|
|
352
371
|
return Array.from(this.querySelectorAll("ef-audio, ef-video, ef-image, ef-captions, ef-waveform"));
|
|
353
372
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const abortController = new AbortController();
|
|
357
|
-
await Promise.all(deepGetMediaElements(this).map(async (mediaElement) => {
|
|
358
|
-
if (mediaElement.mute) return;
|
|
359
|
-
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
360
|
-
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
361
|
-
const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
|
|
362
|
-
if (!mediaOverlaps) return;
|
|
363
|
-
const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
|
|
364
|
-
const mediaLocalToMs = Math.min(mediaElement.endTimeMs - mediaElement.startTimeMs, toMs - mediaElement.startTimeMs);
|
|
365
|
-
if (mediaLocalFromMs >= mediaLocalToMs) return;
|
|
366
|
-
const sourceInMs = mediaElement.sourceInMs || mediaElement.trimStartMs || 0;
|
|
367
|
-
const mediaSourceFromMs = mediaLocalFromMs + sourceInMs;
|
|
368
|
-
const mediaSourceToMs = mediaLocalToMs + sourceInMs;
|
|
369
|
-
let audio;
|
|
370
|
-
try {
|
|
371
|
-
audio = await mediaElement.fetchAudioSpanningTime(mediaSourceFromMs, mediaSourceToMs, abortController.signal);
|
|
372
|
-
} catch (error) {
|
|
373
|
-
if (error instanceof Error && error.message.includes("No audio track available")) return;
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
if (!audio) return;
|
|
377
|
-
const bufferSource = audioContext.createBufferSource();
|
|
378
|
-
bufferSource.buffer = await audioContext.decodeAudioData(await audio.blob.arrayBuffer());
|
|
379
|
-
bufferSource.connect(audioContext.destination);
|
|
380
|
-
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
381
|
-
const requestedSourceFromMs = mediaSourceFromMs;
|
|
382
|
-
const actualSourceStartMs = audio.startMs;
|
|
383
|
-
const offsetInBufferMs = requestedSourceFromMs - actualSourceStartMs;
|
|
384
|
-
const safeOffsetMs = Math.max(0, offsetInBufferMs);
|
|
385
|
-
const requestedDurationMs = mediaSourceToMs - mediaSourceFromMs;
|
|
386
|
-
const availableAudioMs = audio.endMs - audio.startMs;
|
|
387
|
-
const actualDurationMs = Math.min(requestedDurationMs, availableAudioMs - safeOffsetMs);
|
|
388
|
-
if (actualDurationMs <= 0) return;
|
|
389
|
-
bufferSource.start(ctxStartMs / 1e3, safeOffsetMs / 1e3, actualDurationMs / 1e3);
|
|
390
|
-
}));
|
|
373
|
+
getMediaElements() {
|
|
374
|
+
return deepGetMediaElements(this);
|
|
391
375
|
}
|
|
392
376
|
async renderAudio(fromMs, toMs) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const exactSamples = 48e3 * duration;
|
|
396
|
-
const aacFrames = exactSamples / 1024;
|
|
397
|
-
const alignedFrames = Math.round(aacFrames);
|
|
398
|
-
const contextSize = alignedFrames * 1024;
|
|
399
|
-
if (contextSize <= 0) throw new Error(`Duration must be greater than 0 when rendering audio. ${contextSize}ms`);
|
|
400
|
-
let audioContext;
|
|
401
|
-
try {
|
|
402
|
-
audioContext = new OfflineAudioContext(2, contextSize, 48e3);
|
|
403
|
-
} catch (error) {
|
|
404
|
-
throw new Error(`[EFTimegroup.renderAudio] Failed to create OfflineAudioContext(2, ${contextSize}, 48000) for renderAudio(${fromMs}, ${toMs}) with contextSize=${contextSize}: ${error instanceof Error ? error.message : String(error)}. This typically happens when audio parameters are invalid (e.g., contextSize <= 0).`);
|
|
405
|
-
}
|
|
406
|
-
await this.#addAudioToContext(audioContext, fromMs, toMs);
|
|
407
|
-
const renderedBuffer = await audioContext.startRendering();
|
|
408
|
-
return renderedBuffer;
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* TEMPORARY TEST METHOD: Renders audio and immediately plays it back
|
|
412
|
-
* Usage: timegroup.testPlayAudio(0, 5000) // Play first 5 seconds
|
|
413
|
-
*/
|
|
377
|
+
return renderTemporalAudio(this, fromMs, toMs);
|
|
378
|
+
}
|
|
414
379
|
async testPlayAudio(fromMs, toMs) {
|
|
415
380
|
const renderedBuffer = await this.renderAudio(fromMs, toMs);
|
|
416
381
|
const playbackContext = new AudioContext();
|
|
@@ -436,25 +401,17 @@ let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
|
436
401
|
}
|
|
437
402
|
}
|
|
438
403
|
await Promise.all(loaderTasks);
|
|
439
|
-
efElements.
|
|
404
|
+
efElements.forEach((el) => {
|
|
440
405
|
if ("productionSrc" in el && el.productionSrc instanceof Function) el.setAttribute("src", el.productionSrc());
|
|
441
406
|
});
|
|
442
407
|
}
|
|
443
408
|
};
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
})], EFTimegroup.prototype, "mode", null);
|
|
449
|
-
_decorate([property({
|
|
450
|
-
type: Number,
|
|
451
|
-
converter: durationConverter,
|
|
452
|
-
attribute: "overlap"
|
|
453
|
-
})], EFTimegroup.prototype, "overlapMs", null);
|
|
454
|
-
_decorate([property({ type: String })], EFTimegroup.prototype, "fit", void 0);
|
|
455
|
-
_decorate([property({
|
|
409
|
+
__decorate([provide({ context: timegroupContext })], EFTimegroup.prototype, "_timeGroupContext", void 0);
|
|
410
|
+
__decorate([provide({ context: efContext })], EFTimegroup.prototype, "efContext", void 0);
|
|
411
|
+
__decorate([property({ type: String })], EFTimegroup.prototype, "fit", void 0);
|
|
412
|
+
__decorate([property({
|
|
456
413
|
type: Number,
|
|
457
414
|
attribute: "currenttime"
|
|
458
415
|
})], EFTimegroup.prototype, "currentTime", null);
|
|
459
|
-
EFTimegroup = _EFTimegroup =
|
|
416
|
+
EFTimegroup = _EFTimegroup = __decorate([customElement("ef-timegroup")], EFTimegroup);
|
|
460
417
|
export { EFTimegroup, flushSequenceDurationCache, shallowGetTimegroups };
|
|
@@ -67,7 +67,11 @@ export declare class EFVideo extends EFVideo_base {
|
|
|
67
67
|
* Set loading state for user feedback
|
|
68
68
|
*/
|
|
69
69
|
private setLoadingState;
|
|
70
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Paint the current video frame to canvas
|
|
72
|
+
* Called by frameTask after seek is complete
|
|
73
|
+
*/
|
|
74
|
+
paint(seekToMs: number, parentSpan?: any): void;
|
|
71
75
|
/**
|
|
72
76
|
* Clear the canvas when element becomes inactive
|
|
73
77
|
*/
|
|
@@ -75,7 +79,7 @@ export declare class EFVideo extends EFVideo_base {
|
|
|
75
79
|
/**
|
|
76
80
|
* Display a video frame on the canvas
|
|
77
81
|
*/
|
|
78
|
-
displayFrame(frame: VideoFrame, seekToMs: number):
|
|
82
|
+
displayFrame(frame: VideoFrame, seekToMs: number, parentSpan?: any): void;
|
|
79
83
|
/**
|
|
80
84
|
* Check if we're in production rendering mode (EF_FRAMEGEN active) vs preview mode
|
|
81
85
|
*/
|
|
@@ -89,10 +93,20 @@ export declare class EFVideo extends EFVideo_base {
|
|
|
89
93
|
* Still used by EFCaptions - maps to unified video seek task
|
|
90
94
|
*/
|
|
91
95
|
get fragmentIndexTask(): Task<readonly [number], import('mediabunny').VideoSample | undefined>;
|
|
96
|
+
/**
|
|
97
|
+
* Helper method for tests: wait for the current frame to be ready
|
|
98
|
+
* This encapsulates the complexity of ensuring the video has updated
|
|
99
|
+
* and its frameTask has completed.
|
|
100
|
+
*
|
|
101
|
+
* @returns Promise that resolves when the frame is ready
|
|
102
|
+
*/
|
|
103
|
+
waitForFrameReady(): Promise<void>;
|
|
92
104
|
/**
|
|
93
105
|
* Clean up resources when component is disconnected
|
|
94
106
|
*/
|
|
95
107
|
disconnectedCallback(): void;
|
|
108
|
+
didBecomeRoot(): void;
|
|
109
|
+
didBecomeChild(): void;
|
|
96
110
|
}
|
|
97
111
|
declare global {
|
|
98
112
|
interface HTMLElementTagNameMap {
|