@editframe/elements 0.26.2-beta.0 → 0.26.4-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/elements/EFTimegroup.js +7 -2
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/package.json +2 -2
- package/scripts/build-css.js +3 -3
- package/tsdown.config.ts +1 -1
- package/types.json +1 -1
- package/src/elements/ContextProxiesController.ts +0 -124
- package/src/elements/CrossUpdateController.ts +0 -22
- package/src/elements/EFAudio.browsertest.ts +0 -706
- package/src/elements/EFAudio.ts +0 -56
- package/src/elements/EFCaptions.browsertest.ts +0 -1960
- package/src/elements/EFCaptions.ts +0 -823
- package/src/elements/EFImage.browsertest.ts +0 -120
- package/src/elements/EFImage.ts +0 -113
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +0 -224
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +0 -110
- package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +0 -140
- package/src/elements/EFMedia/AssetMediaEngine.ts +0 -385
- package/src/elements/EFMedia/BaseMediaEngine.browsertest.ts +0 -400
- package/src/elements/EFMedia/BaseMediaEngine.ts +0 -505
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +0 -386
- package/src/elements/EFMedia/BufferedSeekingInput.ts +0 -430
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +0 -226
- package/src/elements/EFMedia/JitMediaEngine.ts +0 -256
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +0 -679
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +0 -117
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +0 -246
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +0 -59
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +0 -27
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +0 -55
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +0 -53
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +0 -207
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +0 -72
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +0 -32
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +0 -29
- package/src/elements/EFMedia/audioTasks/makeAudioTasksVideoOnly.browsertest.ts +0 -95
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +0 -184
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +0 -129
- package/src/elements/EFMedia/shared/BufferUtils.ts +0 -342
- package/src/elements/EFMedia/shared/GlobalInputCache.ts +0 -77
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +0 -44
- package/src/elements/EFMedia/shared/PrecisionUtils.ts +0 -46
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +0 -246
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +0 -56
- package/src/elements/EFMedia/shared/ThumbnailExtractor.ts +0 -227
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +0 -167
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +0 -88
- package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +0 -76
- package/src/elements/EFMedia/videoTasks/ScrubInputCache.ts +0 -61
- package/src/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.ts +0 -114
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.ts +0 -35
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +0 -52
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +0 -124
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.ts +0 -44
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.ts +0 -32
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +0 -370
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +0 -109
- package/src/elements/EFMedia.browsertest.ts +0 -872
- package/src/elements/EFMedia.ts +0 -341
- package/src/elements/EFSourceMixin.ts +0 -60
- package/src/elements/EFSurface.browsertest.ts +0 -151
- package/src/elements/EFSurface.ts +0 -142
- package/src/elements/EFTemporal.browsertest.ts +0 -215
- package/src/elements/EFTemporal.ts +0 -800
- package/src/elements/EFThumbnailStrip.browsertest.ts +0 -585
- package/src/elements/EFThumbnailStrip.media-engine.browsertest.ts +0 -714
- package/src/elements/EFThumbnailStrip.ts +0 -906
- package/src/elements/EFTimegroup.browsertest.ts +0 -870
- package/src/elements/EFTimegroup.ts +0 -878
- package/src/elements/EFVideo.browsertest.ts +0 -1482
- package/src/elements/EFVideo.ts +0 -564
- package/src/elements/EFWaveform.ts +0 -547
- package/src/elements/FetchContext.browsertest.ts +0 -401
- package/src/elements/FetchMixin.ts +0 -38
- package/src/elements/SampleBuffer.ts +0 -94
- package/src/elements/TargetController.browsertest.ts +0 -230
- package/src/elements/TargetController.ts +0 -224
- package/src/elements/TimegroupController.ts +0 -26
- package/src/elements/durationConverter.ts +0 -35
- package/src/elements/parseTimeToMs.ts +0 -9
- package/src/elements/printTaskStatus.ts +0 -16
- package/src/elements/renderTemporalAudio.ts +0 -108
- package/src/elements/updateAnimations.browsertest.ts +0 -1884
- package/src/elements/updateAnimations.ts +0 -217
- package/src/elements/util.ts +0 -24
- package/src/gui/ContextMixin.browsertest.ts +0 -860
- package/src/gui/ContextMixin.ts +0 -562
- package/src/gui/Controllable.browsertest.ts +0 -258
- package/src/gui/Controllable.ts +0 -41
- package/src/gui/EFConfiguration.ts +0 -40
- package/src/gui/EFControls.browsertest.ts +0 -389
- package/src/gui/EFControls.ts +0 -195
- package/src/gui/EFDial.browsertest.ts +0 -84
- package/src/gui/EFDial.ts +0 -172
- package/src/gui/EFFilmstrip.browsertest.ts +0 -712
- package/src/gui/EFFilmstrip.ts +0 -1349
- package/src/gui/EFFitScale.ts +0 -152
- package/src/gui/EFFocusOverlay.ts +0 -79
- package/src/gui/EFPause.browsertest.ts +0 -202
- package/src/gui/EFPause.ts +0 -73
- package/src/gui/EFPlay.browsertest.ts +0 -202
- package/src/gui/EFPlay.ts +0 -73
- package/src/gui/EFPreview.ts +0 -74
- package/src/gui/EFResizableBox.browsertest.ts +0 -79
- package/src/gui/EFResizableBox.ts +0 -898
- package/src/gui/EFScrubber.ts +0 -151
- package/src/gui/EFTimeDisplay.browsertest.ts +0 -237
- package/src/gui/EFTimeDisplay.ts +0 -55
- package/src/gui/EFToggleLoop.ts +0 -35
- package/src/gui/EFTogglePlay.ts +0 -70
- package/src/gui/EFWorkbench.ts +0 -115
- package/src/gui/PlaybackController.ts +0 -527
- package/src/gui/TWMixin.css +0 -6
- package/src/gui/TWMixin.ts +0 -61
- package/src/gui/TargetOrContextMixin.ts +0 -185
- package/src/gui/currentTimeContext.ts +0 -5
- package/src/gui/durationContext.ts +0 -3
- package/src/gui/efContext.ts +0 -6
- package/src/gui/fetchContext.ts +0 -5
- package/src/gui/focusContext.ts +0 -7
- package/src/gui/focusedElementContext.ts +0 -5
- package/src/gui/playingContext.ts +0 -5
- package/src/otel/BridgeSpanExporter.ts +0 -150
- package/src/otel/setupBrowserTracing.ts +0 -73
- package/src/otel/tracingHelpers.ts +0 -251
- package/src/transcoding/cache/RequestDeduplicator.test.ts +0 -170
- package/src/transcoding/cache/RequestDeduplicator.ts +0 -65
- package/src/transcoding/cache/URLTokenDeduplicator.test.ts +0 -182
- package/src/transcoding/cache/URLTokenDeduplicator.ts +0 -101
- package/src/transcoding/types/index.ts +0 -312
- package/src/transcoding/utils/MediaUtils.ts +0 -63
- package/src/transcoding/utils/UrlGenerator.ts +0 -68
- package/src/transcoding/utils/constants.ts +0 -36
- package/src/utils/LRUCache.test.ts +0 -274
- package/src/utils/LRUCache.ts +0 -696
|
@@ -1,585 +0,0 @@
|
|
|
1
|
-
import { html, render } from "lit";
|
|
2
|
-
import { beforeEach, describe } from "vitest";
|
|
3
|
-
|
|
4
|
-
import { test as baseTest } from "../../test/useMSW.js";
|
|
5
|
-
import "../gui/EFPreview.js";
|
|
6
|
-
import "../gui/EFWorkbench.js";
|
|
7
|
-
import "./EFThumbnailStrip.js";
|
|
8
|
-
import type { EFThumbnailStrip } from "./EFThumbnailStrip.js";
|
|
9
|
-
import "./EFTimegroup.js";
|
|
10
|
-
import "./EFVideo.js";
|
|
11
|
-
|
|
12
|
-
import type { EFTimegroup } from "./EFTimegroup.js";
|
|
13
|
-
import type { EFVideo } from "./EFVideo.js";
|
|
14
|
-
|
|
15
|
-
beforeEach(async () => {
|
|
16
|
-
localStorage.clear();
|
|
17
|
-
await fetch("/@ef-clear-cache", { method: "DELETE" });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// IMPLEMENTATION GUIDELINES: Test initial thumbnail loading without requiring resize events
|
|
21
|
-
|
|
22
|
-
interface ThumbnailStripFixture {
|
|
23
|
-
video: EFVideo;
|
|
24
|
-
thumbnailStrip: EFThumbnailStrip;
|
|
25
|
-
timegroup: EFTimegroup;
|
|
26
|
-
container: HTMLElement;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const test = baseTest.extend<{
|
|
30
|
-
thumbnailStripSetup: ThumbnailStripFixture;
|
|
31
|
-
alternateSetup: ThumbnailStripFixture;
|
|
32
|
-
}>({
|
|
33
|
-
thumbnailStripSetup: async ({}, use) => {
|
|
34
|
-
const container = document.createElement("div");
|
|
35
|
-
render(
|
|
36
|
-
html`
|
|
37
|
-
<ef-configuration api-host="http://localhost:63315" signing-url="">
|
|
38
|
-
<div style="width: 600px; height: 400px;">
|
|
39
|
-
<ef-preview class="w-[600px] h-[300px]">
|
|
40
|
-
<ef-timegroup mode="contain" class="w-full h-full bg-black">
|
|
41
|
-
<ef-video src="http://web:3000/head-moov-480p.mp4" id="test-video" class="size-full object-contain"></ef-video>
|
|
42
|
-
</ef-timegroup>
|
|
43
|
-
</ef-preview>
|
|
44
|
-
<ef-thumbnail-strip
|
|
45
|
-
target="test-video"
|
|
46
|
-
thumbnail-width="80"
|
|
47
|
-
class="w-full"
|
|
48
|
-
style="height: 48px;"
|
|
49
|
-
></ef-thumbnail-strip>
|
|
50
|
-
</div>
|
|
51
|
-
</ef-configuration>
|
|
52
|
-
`,
|
|
53
|
-
container,
|
|
54
|
-
);
|
|
55
|
-
document.body.appendChild(container);
|
|
56
|
-
|
|
57
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
58
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
59
|
-
const thumbnailStrip = container.querySelector(
|
|
60
|
-
"ef-thumbnail-strip",
|
|
61
|
-
) as EFThumbnailStrip;
|
|
62
|
-
|
|
63
|
-
await Promise.all([
|
|
64
|
-
timegroup.updateComplete,
|
|
65
|
-
video.updateComplete,
|
|
66
|
-
thumbnailStrip.updateComplete,
|
|
67
|
-
]);
|
|
68
|
-
|
|
69
|
-
await use({ video, thumbnailStrip, timegroup, container });
|
|
70
|
-
container.remove();
|
|
71
|
-
},
|
|
72
|
-
alternateSetup: async ({}, use) => {
|
|
73
|
-
const container = document.createElement("div");
|
|
74
|
-
render(
|
|
75
|
-
html`
|
|
76
|
-
<ef-configuration api-host="http://localhost:63315" signing-url="">
|
|
77
|
-
<div style="width: 400px; height: 300px;">
|
|
78
|
-
<ef-preview class="w-full h-[200px]">
|
|
79
|
-
<ef-timegroup mode="contain" class="w-full h-full bg-black">
|
|
80
|
-
<ef-video src="http://web:3000/head-moov-480p.mp4" id="alt-video" class="size-full object-contain"></ef-video>
|
|
81
|
-
</ef-timegroup>
|
|
82
|
-
</ef-preview>
|
|
83
|
-
<ef-thumbnail-strip
|
|
84
|
-
target="alt-video"
|
|
85
|
-
thumbnail-width="80"
|
|
86
|
-
class="w-full"
|
|
87
|
-
style="height: 48px;"
|
|
88
|
-
></ef-thumbnail-strip>
|
|
89
|
-
</div>
|
|
90
|
-
</ef-configuration>
|
|
91
|
-
`,
|
|
92
|
-
container,
|
|
93
|
-
);
|
|
94
|
-
document.body.appendChild(container);
|
|
95
|
-
|
|
96
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
97
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
98
|
-
const thumbnailStrip = container.querySelector(
|
|
99
|
-
"ef-thumbnail-strip",
|
|
100
|
-
) as EFThumbnailStrip;
|
|
101
|
-
|
|
102
|
-
await Promise.all([
|
|
103
|
-
timegroup.updateComplete,
|
|
104
|
-
video.updateComplete,
|
|
105
|
-
thumbnailStrip.updateComplete,
|
|
106
|
-
]);
|
|
107
|
-
|
|
108
|
-
await use({ video, thumbnailStrip, timegroup, container });
|
|
109
|
-
container.remove();
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const awaitThumbnailLayout = async (thumbnailStrip: EFThumbnailStrip) => {
|
|
114
|
-
// @ts-expect-error missing implementation
|
|
115
|
-
await thumbnailStrip.thumbnailLayoutTask.taskComplete;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
describe("EFThumbnailStrip", () => {
|
|
119
|
-
describe("initialization", () => {
|
|
120
|
-
test("should detect dimensions and target element on connection", async ({
|
|
121
|
-
expect,
|
|
122
|
-
thumbnailStripSetup,
|
|
123
|
-
}) => {
|
|
124
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
125
|
-
|
|
126
|
-
await video.mediaEngineTask.taskComplete;
|
|
127
|
-
|
|
128
|
-
expect(thumbnailStrip.targetElement).toBe(video);
|
|
129
|
-
// @ts-expect-error testing private property
|
|
130
|
-
expect(thumbnailStrip.stripWidth).toBeGreaterThan(0);
|
|
131
|
-
|
|
132
|
-
const canvas = thumbnailStrip.shadowRoot?.querySelector("canvas");
|
|
133
|
-
expect(canvas).toBeTruthy();
|
|
134
|
-
expect(canvas?.width).toBeGreaterThan(0);
|
|
135
|
-
expect(canvas?.height).toBeGreaterThan(0);
|
|
136
|
-
}, 1000);
|
|
137
|
-
|
|
138
|
-
test("should select target element by ID", async ({
|
|
139
|
-
expect,
|
|
140
|
-
thumbnailStripSetup,
|
|
141
|
-
}) => {
|
|
142
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
143
|
-
|
|
144
|
-
expect(thumbnailStrip.targetElement).toBe(video);
|
|
145
|
-
expect(thumbnailStrip.target).toBe("test-video");
|
|
146
|
-
}, 1000);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
describe("trimmed duration behavior", () => {
|
|
150
|
-
test("should show thumbnails from trimmed time range by default", async ({
|
|
151
|
-
expect,
|
|
152
|
-
thumbnailStripSetup,
|
|
153
|
-
}) => {
|
|
154
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
155
|
-
|
|
156
|
-
// Set trim properties on the video
|
|
157
|
-
video.setAttribute("trimstart", "2s");
|
|
158
|
-
video.setAttribute("trimend", "1s");
|
|
159
|
-
await video.updateComplete;
|
|
160
|
-
await video.mediaEngineTask.taskComplete;
|
|
161
|
-
|
|
162
|
-
// Wait for thumbnail layout to complete
|
|
163
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
164
|
-
|
|
165
|
-
// Video should have trimmed duration
|
|
166
|
-
expect(video.sourceStartMs).toBe(2000); // trimstart 2s
|
|
167
|
-
expect(video.durationMs).toBe(7000); // 10s - 2s trimstart - 1s trimend
|
|
168
|
-
|
|
169
|
-
// Thumbnails should be generated for the trimmed range by default (not intrinsic)
|
|
170
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(false);
|
|
171
|
-
}, 1000);
|
|
172
|
-
|
|
173
|
-
test("should recalculate thumbnails when trim properties change dynamically", async ({
|
|
174
|
-
expect,
|
|
175
|
-
thumbnailStripSetup,
|
|
176
|
-
}) => {
|
|
177
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
178
|
-
|
|
179
|
-
await video.mediaEngineTask.taskComplete;
|
|
180
|
-
|
|
181
|
-
// Start with no trimming - should use full duration
|
|
182
|
-
expect(video.sourceStartMs).toBe(0);
|
|
183
|
-
expect(video.durationMs).toBe(10000); // full 10s duration
|
|
184
|
-
|
|
185
|
-
// Wait for initial thumbnail layout
|
|
186
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
187
|
-
|
|
188
|
-
// Now add trim properties dynamically
|
|
189
|
-
video.setAttribute("trimstart", "3s");
|
|
190
|
-
video.setAttribute("trimend", "2s");
|
|
191
|
-
await video.updateComplete;
|
|
192
|
-
|
|
193
|
-
// @ts-expect-error testing private task
|
|
194
|
-
await thumbnailStrip.thumbnailLayoutTask.taskComplete;
|
|
195
|
-
|
|
196
|
-
// Wait for the thumbnail update to complete
|
|
197
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
198
|
-
|
|
199
|
-
// Video should now have updated trimmed values
|
|
200
|
-
expect(video.sourceStartMs).toBe(3000); // trimstart 3s
|
|
201
|
-
expect(video.durationMs).toBe(5000); // 10s - 3s trimstart - 2s trimend
|
|
202
|
-
|
|
203
|
-
// Change trim properties again
|
|
204
|
-
video.setAttribute("trimstart", "1s");
|
|
205
|
-
video.setAttribute("trimend", "1s");
|
|
206
|
-
await video.updateComplete;
|
|
207
|
-
|
|
208
|
-
// Wait for the second thumbnail update
|
|
209
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
210
|
-
|
|
211
|
-
// Video should reflect the new trim values
|
|
212
|
-
expect(video.sourceStartMs).toBe(1000); // trimstart 1s
|
|
213
|
-
expect(video.durationMs).toBe(8000); // 10s - 1s trimstart - 1s trimend
|
|
214
|
-
}, 2000);
|
|
215
|
-
|
|
216
|
-
test("should recalculate thumbnails when sourcein/sourceout properties change", async ({
|
|
217
|
-
expect,
|
|
218
|
-
thumbnailStripSetup,
|
|
219
|
-
}) => {
|
|
220
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
221
|
-
|
|
222
|
-
await video.mediaEngineTask.taskComplete;
|
|
223
|
-
|
|
224
|
-
// Start with sourcein/sourceout properties
|
|
225
|
-
video.setAttribute("sourcein", "2s");
|
|
226
|
-
video.setAttribute("sourceout", "8s");
|
|
227
|
-
await video.updateComplete;
|
|
228
|
-
|
|
229
|
-
// Wait for thumbnail layout
|
|
230
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
231
|
-
|
|
232
|
-
// Video should have source-based duration
|
|
233
|
-
expect(video.sourceStartMs).toBe(2000); // sourcein 2s
|
|
234
|
-
expect(video.durationMs).toBe(6000); // sourceout 8s - sourcein 2s
|
|
235
|
-
|
|
236
|
-
// Change the source properties
|
|
237
|
-
video.setAttribute("sourcein", "1s");
|
|
238
|
-
video.setAttribute("sourceout", "9s");
|
|
239
|
-
await video.updateComplete;
|
|
240
|
-
|
|
241
|
-
// Wait for thumbnail update
|
|
242
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
243
|
-
|
|
244
|
-
// Video should reflect new source values
|
|
245
|
-
expect(video.sourceStartMs).toBe(1000); // sourcein 1s
|
|
246
|
-
expect(video.durationMs).toBe(8000); // sourceout 9s - sourcein 1s
|
|
247
|
-
}, 2000);
|
|
248
|
-
|
|
249
|
-
test("should show thumbnails from full duration when useIntrinsicDuration is true", async ({
|
|
250
|
-
expect,
|
|
251
|
-
thumbnailStripSetup,
|
|
252
|
-
}) => {
|
|
253
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
254
|
-
|
|
255
|
-
// Set trim properties and useIntrinsicDuration
|
|
256
|
-
video.setAttribute("trimstart", "2s");
|
|
257
|
-
video.setAttribute("trimend", "1s");
|
|
258
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "true");
|
|
259
|
-
|
|
260
|
-
await Promise.all([video.updateComplete, thumbnailStrip.updateComplete]);
|
|
261
|
-
await video.mediaEngineTask.taskComplete;
|
|
262
|
-
|
|
263
|
-
// Wait for thumbnail layout to complete
|
|
264
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
265
|
-
|
|
266
|
-
// Video should have trimmed duration but thumbnail strip uses intrinsic
|
|
267
|
-
expect(video.sourceStartMs).toBe(2000); // trimstart 2s
|
|
268
|
-
expect(video.durationMs).toBe(7000); // trimmed duration (10s - 2s - 1s)
|
|
269
|
-
expect(video.intrinsicDurationMs).toBe(10000); // full duration
|
|
270
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(true);
|
|
271
|
-
}, 1000);
|
|
272
|
-
|
|
273
|
-
test("should ignore all trim properties when useIntrinsicDuration is true", async ({
|
|
274
|
-
expect,
|
|
275
|
-
thumbnailStripSetup,
|
|
276
|
-
}) => {
|
|
277
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
278
|
-
|
|
279
|
-
await video.mediaEngineTask.taskComplete;
|
|
280
|
-
|
|
281
|
-
// First verify default trimmed behavior
|
|
282
|
-
video.setAttribute("trimstart", "3s");
|
|
283
|
-
video.setAttribute("trimend", "2s");
|
|
284
|
-
await video.updateComplete;
|
|
285
|
-
|
|
286
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
287
|
-
|
|
288
|
-
// Should respect trim by default
|
|
289
|
-
expect(video.sourceStartMs).toBe(3000); // trimstart 3s
|
|
290
|
-
expect(video.durationMs).toBe(5000); // 10s - 3s - 2s
|
|
291
|
-
|
|
292
|
-
// Now enable useIntrinsicDuration
|
|
293
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "true");
|
|
294
|
-
await thumbnailStrip.updateComplete;
|
|
295
|
-
|
|
296
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
297
|
-
|
|
298
|
-
// Video properties should still reflect trim settings
|
|
299
|
-
expect(video.sourceStartMs).toBe(3000); // trimstart 3s
|
|
300
|
-
expect(video.durationMs).toBe(5000); // trimmed duration
|
|
301
|
-
expect(video.intrinsicDurationMs).toBe(10000); // full duration
|
|
302
|
-
|
|
303
|
-
// But thumbnail strip should ignore trims and use full duration
|
|
304
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(true);
|
|
305
|
-
|
|
306
|
-
// The layout calculation should use 0 to intrinsicDurationMs instead of trimmed range
|
|
307
|
-
// We can verify this by checking that the implementation correctly handles the flag
|
|
308
|
-
}, 2000);
|
|
309
|
-
|
|
310
|
-
test("should handle custom start-time-ms/end-time-ms relative to correct timeline", async ({
|
|
311
|
-
expect,
|
|
312
|
-
thumbnailStripSetup,
|
|
313
|
-
}) => {
|
|
314
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
315
|
-
|
|
316
|
-
// Set up trim: source 0-10s becomes trimmed 0-7s (source 2-9s)
|
|
317
|
-
video.setAttribute("trimstart", "2s");
|
|
318
|
-
video.setAttribute("trimend", "1s");
|
|
319
|
-
await video.updateComplete;
|
|
320
|
-
// CRITICAL: Wait for media engine task completion AFTER setting trim attributes
|
|
321
|
-
await video.mediaEngineTask.taskComplete;
|
|
322
|
-
|
|
323
|
-
// Verify base setup
|
|
324
|
-
expect(video.sourceStartMs).toBe(2000); // Trim starts at 2s in source
|
|
325
|
-
expect(video.durationMs).toBe(7000); // 7s trimmed duration
|
|
326
|
-
|
|
327
|
-
// Test custom time range in TRIMMED mode (default)
|
|
328
|
-
// start-time-ms="1000" should mean 1s into the trimmed portion = 3s in source
|
|
329
|
-
// end-time-ms="5000" should mean 5s into the trimmed portion = 7s in source
|
|
330
|
-
thumbnailStrip.setAttribute("start-time-ms", "1000"); // 1s into trimmed timeline
|
|
331
|
-
thumbnailStrip.setAttribute("end-time-ms", "5000"); // 5s into trimmed timeline
|
|
332
|
-
await thumbnailStrip.updateComplete;
|
|
333
|
-
|
|
334
|
-
// Verify the properties were set
|
|
335
|
-
expect(thumbnailStrip.startTimeMs).toBe(1000);
|
|
336
|
-
expect(thumbnailStrip.endTimeMs).toBe(5000);
|
|
337
|
-
|
|
338
|
-
// Force thumbnail layout to run with new properties
|
|
339
|
-
// @ts-expect-error missing implementation
|
|
340
|
-
thumbnailStrip.thumbnailLayoutTask.run();
|
|
341
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
342
|
-
|
|
343
|
-
// Get layout and check timestamps
|
|
344
|
-
// @ts-expect-error missing implementation
|
|
345
|
-
const layout = thumbnailStrip.thumbnailLayoutTask.value;
|
|
346
|
-
expect(layout).toBeTruthy();
|
|
347
|
-
|
|
348
|
-
if (layout) {
|
|
349
|
-
const allTimestamps = layout.segments.flatMap((segment) =>
|
|
350
|
-
segment.thumbnails.map((thumb) => thumb.timeMs),
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
expect(allTimestamps.length).toBeGreaterThan(0);
|
|
354
|
-
|
|
355
|
-
// Thumbnails should be from 3000ms to 7000ms in source timeline
|
|
356
|
-
// (trimstart 2000ms + custom start 1000ms = 3000ms to trimstart 2000ms + custom end 5000ms = 7000ms)
|
|
357
|
-
const minTime = Math.min(...allTimestamps);
|
|
358
|
-
const maxTime = Math.max(...allTimestamps);
|
|
359
|
-
|
|
360
|
-
expect(minTime).toBeGreaterThanOrEqual(3000); // Should start from 3s in source
|
|
361
|
-
expect(minTime).toBeLessThan(3500); // Should be close to 3s
|
|
362
|
-
expect(maxTime).toBeLessThanOrEqual(7000); // Should end at 7s in source
|
|
363
|
-
expect(maxTime).toBeGreaterThan(6500); // Should be close to 7s
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Test INTRINSIC mode with custom times
|
|
367
|
-
// start-time-ms="1000" should mean 1s in source timeline
|
|
368
|
-
// end-time-ms="8000" should mean 8s in source timeline
|
|
369
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "true");
|
|
370
|
-
thumbnailStrip.setAttribute("start-time-ms", "1000"); // 1s in source timeline
|
|
371
|
-
thumbnailStrip.setAttribute("end-time-ms", "8000"); // 8s in source timeline
|
|
372
|
-
await thumbnailStrip.updateComplete;
|
|
373
|
-
|
|
374
|
-
// Verify the properties were set correctly for intrinsic mode
|
|
375
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(true);
|
|
376
|
-
expect(thumbnailStrip.startTimeMs).toBe(1000);
|
|
377
|
-
expect(thumbnailStrip.endTimeMs).toBe(8000);
|
|
378
|
-
|
|
379
|
-
// Force thumbnail layout to run with intrinsic mode properties
|
|
380
|
-
// @ts-expect-error missing implementation
|
|
381
|
-
thumbnailStrip.thumbnailLayoutTask.run();
|
|
382
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
383
|
-
|
|
384
|
-
// @ts-expect-error missing implementation
|
|
385
|
-
const intrinsicLayout = thumbnailStrip.thumbnailLayoutTask.value;
|
|
386
|
-
expect(intrinsicLayout).toBeTruthy();
|
|
387
|
-
|
|
388
|
-
if (intrinsicLayout) {
|
|
389
|
-
const intrinsicTimestamps = intrinsicLayout.segments.flatMap(
|
|
390
|
-
(segment) => segment.thumbnails.map((thumb) => thumb.timeMs),
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
expect(intrinsicTimestamps.length).toBeGreaterThan(0);
|
|
394
|
-
|
|
395
|
-
// In intrinsic mode, should be 1000ms to 8000ms directly in source timeline
|
|
396
|
-
const intrinsicMin = Math.min(...intrinsicTimestamps);
|
|
397
|
-
const intrinsicMax = Math.max(...intrinsicTimestamps);
|
|
398
|
-
|
|
399
|
-
expect(intrinsicMin).toBeGreaterThanOrEqual(1000); // Should start from 1s in source
|
|
400
|
-
expect(intrinsicMin).toBeLessThan(1500); // Should be close to 1s
|
|
401
|
-
expect(intrinsicMax).toBeLessThanOrEqual(8000); // Should end at 8s in source
|
|
402
|
-
expect(intrinsicMax).toBeGreaterThan(7500); // Should be close to 8s
|
|
403
|
-
}
|
|
404
|
-
}, 3000);
|
|
405
|
-
|
|
406
|
-
test("should correctly parse use-intrinsic-duration string values", async ({
|
|
407
|
-
expect,
|
|
408
|
-
thumbnailStripSetup,
|
|
409
|
-
}) => {
|
|
410
|
-
const { thumbnailStrip } = thumbnailStripSetup;
|
|
411
|
-
|
|
412
|
-
// Test default value
|
|
413
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(false);
|
|
414
|
-
|
|
415
|
-
// Test "true" string value
|
|
416
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "true");
|
|
417
|
-
await thumbnailStrip.updateComplete;
|
|
418
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(true);
|
|
419
|
-
|
|
420
|
-
// Test "false" string value (this is the key fix)
|
|
421
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "false");
|
|
422
|
-
await thumbnailStrip.updateComplete;
|
|
423
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(false); // Should be false, not true!
|
|
424
|
-
|
|
425
|
-
// Test removing attribute
|
|
426
|
-
thumbnailStrip.removeAttribute("use-intrinsic-duration");
|
|
427
|
-
await thumbnailStrip.updateComplete;
|
|
428
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(false);
|
|
429
|
-
|
|
430
|
-
// Test setting via property
|
|
431
|
-
thumbnailStrip.useIntrinsicDuration = true;
|
|
432
|
-
await thumbnailStrip.updateComplete;
|
|
433
|
-
expect(thumbnailStrip.getAttribute("use-intrinsic-duration")).toBe(
|
|
434
|
-
"true",
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
thumbnailStrip.useIntrinsicDuration = false;
|
|
438
|
-
await thumbnailStrip.updateComplete;
|
|
439
|
-
expect(thumbnailStrip.hasAttribute("use-intrinsic-duration")).toBe(false);
|
|
440
|
-
}, 1000);
|
|
441
|
-
|
|
442
|
-
test("should show trimmed thumbnails when use-intrinsic-duration='false'", async ({
|
|
443
|
-
expect,
|
|
444
|
-
thumbnailStripSetup,
|
|
445
|
-
}) => {
|
|
446
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
447
|
-
|
|
448
|
-
// Set trim and explicitly set use-intrinsic-duration="false"
|
|
449
|
-
video.setAttribute("trimstart", "2s");
|
|
450
|
-
thumbnailStrip.setAttribute("use-intrinsic-duration", "false"); // This should be false!
|
|
451
|
-
|
|
452
|
-
await video.updateComplete;
|
|
453
|
-
await thumbnailStrip.updateComplete;
|
|
454
|
-
await video.mediaEngineTask.taskComplete;
|
|
455
|
-
|
|
456
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
457
|
-
|
|
458
|
-
// Verify the boolean parsing worked correctly
|
|
459
|
-
expect(thumbnailStrip.useIntrinsicDuration).toBe(false); // Should be false, not true!
|
|
460
|
-
expect(thumbnailStrip.getAttribute("use-intrinsic-duration")).toBe(
|
|
461
|
-
"false",
|
|
462
|
-
);
|
|
463
|
-
|
|
464
|
-
// Verify thumbnail behavior: should use trimmed timeline, starting from 2s
|
|
465
|
-
expect(video.sourceStartMs).toBe(2000); // trimstart 2s
|
|
466
|
-
expect(video.durationMs).toBe(8000); // 10s - 2s = 8s trimmed duration
|
|
467
|
-
|
|
468
|
-
// @ts-expect-error testing private task
|
|
469
|
-
const layout = thumbnailStrip.thumbnailLayoutTask.value;
|
|
470
|
-
if (layout) {
|
|
471
|
-
const allTimestamps = layout.segments.flatMap((segment) =>
|
|
472
|
-
segment.thumbnails.map((thumb) => thumb.timeMs),
|
|
473
|
-
);
|
|
474
|
-
expect(allTimestamps.length).toBeGreaterThan(0);
|
|
475
|
-
|
|
476
|
-
// Thumbnails should start from 2000ms (trimstart), not 0ms
|
|
477
|
-
const firstTimestamp = Math.min(...allTimestamps);
|
|
478
|
-
expect(firstTimestamp).toBeGreaterThanOrEqual(2000);
|
|
479
|
-
expect(firstTimestamp).toBeLessThan(2500);
|
|
480
|
-
}
|
|
481
|
-
}, 1000);
|
|
482
|
-
|
|
483
|
-
test("should align first thumbnail with video currentTime=0 frame", async ({
|
|
484
|
-
expect,
|
|
485
|
-
thumbnailStripSetup,
|
|
486
|
-
}) => {
|
|
487
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
488
|
-
|
|
489
|
-
// Set trim to 2s - both video and thumbnails should show same frame
|
|
490
|
-
video.setAttribute("trimstart", "2s");
|
|
491
|
-
video.setAttribute("current-time", "0"); // 0 in trimmed timeline = 2s in source
|
|
492
|
-
|
|
493
|
-
await video.updateComplete;
|
|
494
|
-
await video.mediaEngineTask.taskComplete;
|
|
495
|
-
|
|
496
|
-
// Wait for thumbnail calculations
|
|
497
|
-
// @ts-expect-error testing private task
|
|
498
|
-
await thumbnailStrip.thumbnailLayoutTask.taskComplete;
|
|
499
|
-
|
|
500
|
-
// Get the video's current source time (what frame it's showing)
|
|
501
|
-
const videoSourceTime = video.sourceStartMs + (video.currentTimeMs || 0);
|
|
502
|
-
expect(videoSourceTime).toBe(2000); // Should be at 2s in source (frame 61)
|
|
503
|
-
|
|
504
|
-
// Get the first thumbnail timestamp
|
|
505
|
-
// @ts-expect-error testing private task
|
|
506
|
-
const layout = thumbnailStrip.thumbnailLayoutTask.value;
|
|
507
|
-
if (layout) {
|
|
508
|
-
const allTimestamps = layout.segments.flatMap((segment) =>
|
|
509
|
-
segment.thumbnails.map((thumb) => thumb.timeMs),
|
|
510
|
-
);
|
|
511
|
-
expect(allTimestamps.length).toBeGreaterThan(0);
|
|
512
|
-
|
|
513
|
-
const firstThumbnailTime = Math.min(...allTimestamps);
|
|
514
|
-
|
|
515
|
-
// The first thumbnail should be at exactly the same source time as video currentTime=0
|
|
516
|
-
// This ensures frame 61 shows in both video and thumbnail
|
|
517
|
-
expect(firstThumbnailTime).toBe(videoSourceTime); // Should be exactly 2000ms
|
|
518
|
-
}
|
|
519
|
-
}, 1000);
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
describe("layout behavior", () => {
|
|
523
|
-
test("should calculate layout immediately after initialization", async ({
|
|
524
|
-
expect,
|
|
525
|
-
alternateSetup,
|
|
526
|
-
}) => {
|
|
527
|
-
const { video, thumbnailStrip } = alternateSetup;
|
|
528
|
-
|
|
529
|
-
await video.mediaEngineTask.taskComplete;
|
|
530
|
-
|
|
531
|
-
// @ts-expect-error testing private property
|
|
532
|
-
expect(thumbnailStrip.stripWidth).toBe(400); // Uses container inner width
|
|
533
|
-
expect(thumbnailStrip.targetElement).toBe(video);
|
|
534
|
-
}, 1000);
|
|
535
|
-
|
|
536
|
-
test("should remain stable when video properties change", async ({
|
|
537
|
-
expect,
|
|
538
|
-
thumbnailStripSetup,
|
|
539
|
-
}) => {
|
|
540
|
-
const { video, thumbnailStrip } = thumbnailStripSetup;
|
|
541
|
-
|
|
542
|
-
await video.mediaEngineTask.taskComplete;
|
|
543
|
-
|
|
544
|
-
const initialState = {
|
|
545
|
-
// @ts-expect-error testing private property
|
|
546
|
-
stripWidth: thumbnailStrip.stripWidth,
|
|
547
|
-
targetElement: thumbnailStrip.targetElement,
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
video.setAttribute("trimstart", "2s");
|
|
551
|
-
video.setAttribute("trimend", "2s");
|
|
552
|
-
await video.updateComplete;
|
|
553
|
-
|
|
554
|
-
// @ts-expect-error testing private property
|
|
555
|
-
expect(thumbnailStrip.stripWidth).toBe(initialState.stripWidth);
|
|
556
|
-
expect(thumbnailStrip.targetElement).toBe(initialState.targetElement);
|
|
557
|
-
expect(video.getAttribute("trimstart")).toBe("2s");
|
|
558
|
-
expect(video.getAttribute("trimend")).toBe("2s");
|
|
559
|
-
}, 1000);
|
|
560
|
-
|
|
561
|
-
test("should update dimensions when container resizes", async ({
|
|
562
|
-
expect,
|
|
563
|
-
alternateSetup,
|
|
564
|
-
}) => {
|
|
565
|
-
const { video, thumbnailStrip } = alternateSetup;
|
|
566
|
-
|
|
567
|
-
await video.mediaEngineTask.taskComplete;
|
|
568
|
-
|
|
569
|
-
// @ts-expect-error testing private property
|
|
570
|
-
const initialWidth = thumbnailStrip.stripWidth;
|
|
571
|
-
expect(initialWidth).toBe(400); // Container inner width
|
|
572
|
-
|
|
573
|
-
// Wait for any pending thumbnail layout tasks to complete
|
|
574
|
-
await awaitThumbnailLayout(thumbnailStrip);
|
|
575
|
-
|
|
576
|
-
// Simulate resize by directly setting the internal width and triggering update
|
|
577
|
-
(thumbnailStrip as any)._stripWidth = 800;
|
|
578
|
-
// @ts-expect-error testing private property
|
|
579
|
-
const finalWidth = thumbnailStrip.stripWidth;
|
|
580
|
-
|
|
581
|
-
expect(finalWidth).toBe(800);
|
|
582
|
-
expect(finalWidth).toBeGreaterThan(initialWidth);
|
|
583
|
-
}, 1000);
|
|
584
|
-
});
|
|
585
|
-
});
|