@editframe/elements 0.16.7-beta.0 → 0.17.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/README.md +30 -0
- package/dist/DecoderResetFrequency.test.d.ts +1 -0
- package/dist/DecoderResetRecovery.test.d.ts +1 -0
- package/dist/DelayedLoadingState.d.ts +48 -0
- package/dist/DelayedLoadingState.integration.test.d.ts +1 -0
- package/dist/DelayedLoadingState.js +113 -0
- package/dist/DelayedLoadingState.test.d.ts +1 -0
- package/dist/EF_FRAMEGEN.d.ts +10 -1
- package/dist/EF_FRAMEGEN.js +199 -179
- package/dist/EF_INTERACTIVE.js +2 -6
- package/dist/EF_RENDERING.js +1 -3
- package/dist/JitTranscodingClient.browsertest.d.ts +1 -0
- package/dist/JitTranscodingClient.d.ts +167 -0
- package/dist/JitTranscodingClient.js +373 -0
- package/dist/JitTranscodingClient.test.d.ts +1 -0
- package/dist/LoadingDebounce.test.d.ts +1 -0
- package/dist/LoadingIndicator.browsertest.d.ts +0 -0
- package/dist/ManualScrubTest.test.d.ts +1 -0
- package/dist/ScrubResolvedFlashing.test.d.ts +1 -0
- package/dist/ScrubTrackIntegration.test.d.ts +1 -0
- package/dist/ScrubTrackManager.d.ts +96 -0
- package/dist/ScrubTrackManager.js +216 -0
- package/dist/ScrubTrackManager.test.d.ts +1 -0
- package/dist/SegmentSwitchLoading.test.d.ts +1 -0
- package/dist/VideoSeekFlashing.browsertest.d.ts +0 -0
- package/dist/VideoStuckDiagnostic.test.d.ts +1 -0
- package/dist/elements/CrossUpdateController.js +13 -15
- package/dist/elements/EFAudio.browsertest.d.ts +0 -0
- package/dist/elements/EFAudio.d.ts +1 -1
- package/dist/elements/EFAudio.js +30 -43
- package/dist/elements/EFCaptions.js +337 -373
- package/dist/elements/EFImage.js +64 -90
- package/dist/elements/EFMedia.d.ts +98 -33
- package/dist/elements/EFMedia.js +1169 -678
- package/dist/elements/EFSourceMixin.js +31 -48
- package/dist/elements/EFTemporal.d.ts +1 -0
- package/dist/elements/EFTemporal.js +266 -360
- package/dist/elements/EFTimegroup.d.ts +3 -1
- package/dist/elements/EFTimegroup.js +262 -323
- package/dist/elements/EFVideo.browsertest.d.ts +0 -0
- package/dist/elements/EFVideo.d.ts +90 -2
- package/dist/elements/EFVideo.js +408 -111
- package/dist/elements/EFWaveform.js +375 -411
- package/dist/elements/FetchMixin.js +14 -24
- package/dist/elements/MediaController.d.ts +30 -0
- package/dist/elements/TargetController.js +130 -156
- package/dist/elements/TimegroupController.js +17 -19
- package/dist/elements/durationConverter.js +15 -4
- package/dist/elements/parseTimeToMs.js +4 -10
- package/dist/elements/printTaskStatus.d.ts +2 -0
- package/dist/elements/printTaskStatus.js +11 -0
- package/dist/elements/updateAnimations.js +39 -59
- package/dist/getRenderInfo.js +58 -67
- package/dist/gui/ContextMixin.js +203 -288
- package/dist/gui/EFConfiguration.js +27 -43
- package/dist/gui/EFFilmstrip.js +440 -620
- package/dist/gui/EFFitScale.js +112 -135
- package/dist/gui/EFFocusOverlay.js +45 -61
- package/dist/gui/EFPreview.js +30 -49
- package/dist/gui/EFScrubber.js +78 -99
- package/dist/gui/EFTimeDisplay.js +49 -70
- package/dist/gui/EFToggleLoop.js +17 -34
- package/dist/gui/EFTogglePlay.js +37 -58
- package/dist/gui/EFWorkbench.js +66 -88
- package/dist/gui/TWMixin.js +2 -48
- package/dist/gui/TWMixin2.js +31 -0
- package/dist/gui/efContext.js +2 -6
- package/dist/gui/fetchContext.js +1 -3
- package/dist/gui/focusContext.js +1 -3
- package/dist/gui/focusedElementContext.js +2 -6
- package/dist/gui/playingContext.js +1 -4
- package/dist/index.js +5 -30
- package/dist/msToTimeCode.js +11 -13
- package/dist/style.css +2 -1
- package/package.json +3 -3
- package/src/elements/EFAudio.browsertest.ts +569 -0
- package/src/elements/EFAudio.ts +4 -6
- package/src/elements/EFCaptions.browsertest.ts +0 -1
- package/src/elements/EFImage.browsertest.ts +0 -1
- package/src/elements/EFMedia.browsertest.ts +147 -115
- package/src/elements/EFMedia.ts +1339 -307
- package/src/elements/EFTemporal.browsertest.ts +0 -1
- package/src/elements/EFTemporal.ts +11 -0
- package/src/elements/EFTimegroup.ts +73 -10
- package/src/elements/EFVideo.browsertest.ts +680 -0
- package/src/elements/EFVideo.ts +729 -50
- package/src/elements/EFWaveform.ts +4 -4
- package/src/elements/MediaController.ts +108 -0
- package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
- package/src/elements/printTaskStatus.ts +16 -0
- package/src/elements/updateAnimations.ts +6 -0
- package/src/gui/TWMixin.ts +10 -3
- package/test/EFVideo.frame-tasks.browsertest.ts +524 -0
- package/test/EFVideo.framegen.browsertest.ts +118 -0
- package/test/createJitTestClips.ts +293 -0
- package/test/useAssetMSW.ts +49 -0
- package/test/useMSW.ts +31 -0
- package/types.json +1 -1
- package/dist/gui/TWMixin.css.js +0 -4
- /package/dist/elements/{TargetController.test.d.ts → TargetController.browsertest.d.ts} +0 -0
- /package/src/elements/{TargetController.test.ts → TargetController.browsertest.ts} +0 -0
package/dist/msToTimeCode.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
const msToTimeCode = (ms, subSecond = false) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
13
|
-
export {
|
|
14
|
-
msToTimeCode
|
|
2
|
+
const seconds = Math.floor(ms / 1e3);
|
|
3
|
+
const minutes = Math.floor(seconds / 60);
|
|
4
|
+
const hours = Math.floor(minutes / 60);
|
|
5
|
+
const pad = (num) => num.toString().padStart(2, "0");
|
|
6
|
+
let timecode = `${pad(hours)}:${pad(minutes % 60)}:${pad(seconds % 60)}`;
|
|
7
|
+
if (subSecond) {
|
|
8
|
+
const subSeconds = Math.floor(ms % 1e3 / 10);
|
|
9
|
+
timecode += `.${subSeconds.toString().padStart(2, "0")}`;
|
|
10
|
+
}
|
|
11
|
+
return timecode;
|
|
15
12
|
};
|
|
13
|
+
export { msToTimeCode };
|
package/dist/style.css
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
*,:before,:after{box-sizing:border-box;border
|
|
1
|
+
*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\[1px\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-\[1\.1rem\]{height:1.1rem}.h-\[5px\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\[2px\]{width:2px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\[1px\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\[8px\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\[focused\]\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}
|
|
2
|
+
/*$vite$:1*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.6-beta.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"license": "UNLICENSED",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@bramus/style-observer": "^1.3.0",
|
|
30
|
-
"@editframe/assets": "0.
|
|
30
|
+
"@editframe/assets": "0.17.6-beta.0",
|
|
31
31
|
"@lit/context": "^1.1.2",
|
|
32
32
|
"@lit/task": "^1.0.1",
|
|
33
33
|
"d3": "^7.9.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"autoprefixer": "^10.4.19",
|
|
44
44
|
"rollup-plugin-tsconfig-paths": "^1.5.2",
|
|
45
45
|
"typescript": "^5.5.4",
|
|
46
|
-
"vite-plugin-dts": "^4.
|
|
46
|
+
"vite-plugin-dts": "^4.5.4",
|
|
47
47
|
"vite-tsconfig-paths": "^4.3.2"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
import { html, render } from "lit";
|
|
2
|
+
import { http, HttpResponse } from "msw";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
4
|
+
import { assetMSWHandlers } from "../../test/useAssetMSW.js";
|
|
5
|
+
import { useMSW } from "../../test/useMSW.js";
|
|
6
|
+
import type { EFAudio } from "./EFAudio.js";
|
|
7
|
+
import "./EFAudio.js";
|
|
8
|
+
import "../gui/EFWorkbench.js";
|
|
9
|
+
import "../gui/EFPreview.js";
|
|
10
|
+
import "./EFTimegroup.js";
|
|
11
|
+
|
|
12
|
+
describe("EFAudio", () => {
|
|
13
|
+
const worker = useMSW();
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
// Clean up DOM and localStorage
|
|
17
|
+
while (document.body.children.length) {
|
|
18
|
+
document.body.children[0]?.remove();
|
|
19
|
+
}
|
|
20
|
+
localStorage.clear();
|
|
21
|
+
|
|
22
|
+
// Set up centralized MSW handlers to proxy requests to test assets
|
|
23
|
+
worker.use(...assetMSWHandlers);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
// Clean up any remaining elements
|
|
28
|
+
const audios = document.querySelectorAll("ef-audio");
|
|
29
|
+
for (const audio of audios) {
|
|
30
|
+
audio.remove();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("basic rendering", () => {
|
|
35
|
+
test("should be defined and render audio element", async () => {
|
|
36
|
+
const container = document.createElement("div");
|
|
37
|
+
render(
|
|
38
|
+
html`
|
|
39
|
+
<ef-workbench>
|
|
40
|
+
<ef-preview>
|
|
41
|
+
<ef-audio></ef-audio>
|
|
42
|
+
</ef-preview>
|
|
43
|
+
</ef-workbench>
|
|
44
|
+
`,
|
|
45
|
+
container,
|
|
46
|
+
);
|
|
47
|
+
document.body.appendChild(container);
|
|
48
|
+
|
|
49
|
+
const element = container.querySelector("ef-audio") as EFAudio;
|
|
50
|
+
// Wait for element to render
|
|
51
|
+
await element.updateComplete;
|
|
52
|
+
|
|
53
|
+
expect(element.tagName).toBe("EF-AUDIO");
|
|
54
|
+
expect(element.audioElement).toBeDefined();
|
|
55
|
+
expect(element.audioElement?.tagName).toBe("AUDIO");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("audio element has correct default properties", async () => {
|
|
59
|
+
const container = document.createElement("div");
|
|
60
|
+
render(
|
|
61
|
+
html`
|
|
62
|
+
<ef-workbench>
|
|
63
|
+
<ef-preview>
|
|
64
|
+
<ef-audio></ef-audio>
|
|
65
|
+
</ef-preview>
|
|
66
|
+
</ef-workbench>
|
|
67
|
+
`,
|
|
68
|
+
container,
|
|
69
|
+
);
|
|
70
|
+
document.body.appendChild(container);
|
|
71
|
+
|
|
72
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
73
|
+
|
|
74
|
+
// Wait for element to render
|
|
75
|
+
await audio.updateComplete;
|
|
76
|
+
|
|
77
|
+
const audioElement = audio.audioElement;
|
|
78
|
+
|
|
79
|
+
expect(audioElement).toBeDefined();
|
|
80
|
+
expect(audioElement?.controls).toBe(false); // Should not have controls by default
|
|
81
|
+
expect(audioElement?.preload).toBe("metadata");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("inherits media properties from EFMedia", async () => {
|
|
85
|
+
const container = document.createElement("div");
|
|
86
|
+
render(
|
|
87
|
+
html`
|
|
88
|
+
<ef-workbench>
|
|
89
|
+
<ef-preview>
|
|
90
|
+
<ef-audio src="/test-audio.mp3"></ef-audio>
|
|
91
|
+
</ef-preview>
|
|
92
|
+
</ef-workbench>
|
|
93
|
+
`,
|
|
94
|
+
container,
|
|
95
|
+
);
|
|
96
|
+
document.body.appendChild(container);
|
|
97
|
+
|
|
98
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
99
|
+
|
|
100
|
+
// Wait for element to render
|
|
101
|
+
await audio.updateComplete;
|
|
102
|
+
|
|
103
|
+
// Should inherit properties from EFMedia base class
|
|
104
|
+
expect(audio.src).toBe("/test-audio.mp3");
|
|
105
|
+
expect(audio.currentTimeMs).toBeDefined();
|
|
106
|
+
expect(audio.durationMs).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("audio asset integration", () => {
|
|
111
|
+
test("integrates with audio asset loading", async () => {
|
|
112
|
+
const container = document.createElement("div");
|
|
113
|
+
render(
|
|
114
|
+
html`
|
|
115
|
+
<ef-preview>
|
|
116
|
+
<ef-audio src="/test-assets/media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
117
|
+
</ef-preview>
|
|
118
|
+
`,
|
|
119
|
+
container,
|
|
120
|
+
);
|
|
121
|
+
document.body.appendChild(container);
|
|
122
|
+
|
|
123
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
124
|
+
await audio.updateComplete;
|
|
125
|
+
await audio.fragmentIndexTask.taskComplete;
|
|
126
|
+
|
|
127
|
+
expect(audio.src).toBe("/test-assets/media/bars-n-tone2.mp4");
|
|
128
|
+
|
|
129
|
+
// The audio should have loaded successfully and have a duration > 0
|
|
130
|
+
// We don't test for specific duration since real assets may vary
|
|
131
|
+
expect(audio.intrinsicDurationMs).toBeGreaterThan(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("handles missing audio asset gracefully", async () => {
|
|
135
|
+
const container = document.createElement("div");
|
|
136
|
+
render(
|
|
137
|
+
html`
|
|
138
|
+
<ef-preview>
|
|
139
|
+
<ef-audio src="/nonexistent.mp3"></ef-audio>
|
|
140
|
+
</ef-preview>
|
|
141
|
+
`,
|
|
142
|
+
container,
|
|
143
|
+
);
|
|
144
|
+
document.body.appendChild(container);
|
|
145
|
+
|
|
146
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
147
|
+
|
|
148
|
+
// Should not throw when audio asset is missing
|
|
149
|
+
expect(() => {
|
|
150
|
+
audio.frameTask.run();
|
|
151
|
+
}).not.toThrow();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("handles audio loading errors gracefully", async () => {
|
|
155
|
+
// Mock 404 response for audio asset
|
|
156
|
+
worker.use(
|
|
157
|
+
http.get("/@ef-track-fragment-index//error-audio.mp3", () => {
|
|
158
|
+
return new HttpResponse(null, { status: 404 });
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const container = document.createElement("div");
|
|
163
|
+
render(
|
|
164
|
+
html`
|
|
165
|
+
<ef-preview>
|
|
166
|
+
<ef-audio src="/error-audio.mp3"></ef-audio>
|
|
167
|
+
</ef-preview>
|
|
168
|
+
`,
|
|
169
|
+
container,
|
|
170
|
+
);
|
|
171
|
+
document.body.appendChild(container);
|
|
172
|
+
|
|
173
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
174
|
+
|
|
175
|
+
// Should handle loading errors gracefully
|
|
176
|
+
expect(() => {
|
|
177
|
+
audio.frameTask.run();
|
|
178
|
+
}).not.toThrow();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe("frame task integration", () => {
|
|
183
|
+
test("frameTask coordinates all required media tasks", async () => {
|
|
184
|
+
const container = document.createElement("div");
|
|
185
|
+
render(
|
|
186
|
+
html`
|
|
187
|
+
<ef-preview>
|
|
188
|
+
<ef-audio src="/test-audio.mp3"></ef-audio>
|
|
189
|
+
</ef-preview>
|
|
190
|
+
`,
|
|
191
|
+
container,
|
|
192
|
+
);
|
|
193
|
+
document.body.appendChild(container);
|
|
194
|
+
|
|
195
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
196
|
+
|
|
197
|
+
// frameTask should complete without errors
|
|
198
|
+
expect(() => {
|
|
199
|
+
audio.frameTask.run();
|
|
200
|
+
}).not.toThrow();
|
|
201
|
+
|
|
202
|
+
// Should coordinate the expected tasks
|
|
203
|
+
expect(audio.fragmentIndexTask).toBeDefined();
|
|
204
|
+
expect(audio.mediaSegmentsTask).toBeDefined();
|
|
205
|
+
expect(audio.seekTask).toBeDefined();
|
|
206
|
+
expect(audio.videoAssetTask).toBeDefined();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("frameTask handles missing dependencies", () => {
|
|
210
|
+
const container = document.createElement("div");
|
|
211
|
+
render(
|
|
212
|
+
html`
|
|
213
|
+
<ef-workbench>
|
|
214
|
+
<ef-preview>
|
|
215
|
+
<ef-audio></ef-audio>
|
|
216
|
+
</ef-preview>
|
|
217
|
+
</ef-workbench>
|
|
218
|
+
`,
|
|
219
|
+
container,
|
|
220
|
+
);
|
|
221
|
+
document.body.appendChild(container);
|
|
222
|
+
|
|
223
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
224
|
+
|
|
225
|
+
// Should handle missing dependencies gracefully
|
|
226
|
+
expect(() => {
|
|
227
|
+
audio.frameTask.run();
|
|
228
|
+
}).not.toThrow();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("frameTask completion triggers timegroup updates", async () => {
|
|
232
|
+
const container = document.createElement("div");
|
|
233
|
+
render(
|
|
234
|
+
html`
|
|
235
|
+
<ef-preview>
|
|
236
|
+
<ef-timegroup mode="sequence">
|
|
237
|
+
<ef-audio src="/test-assets/media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
238
|
+
</ef-timegroup>
|
|
239
|
+
</ef-preview>
|
|
240
|
+
`,
|
|
241
|
+
container,
|
|
242
|
+
);
|
|
243
|
+
document.body.appendChild(container);
|
|
244
|
+
|
|
245
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
246
|
+
const timegroup = container.querySelector("ef-timegroup");
|
|
247
|
+
await audio.updateComplete;
|
|
248
|
+
|
|
249
|
+
// Wait for fragment index to load
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
251
|
+
|
|
252
|
+
// frameTask should trigger timegroup updates
|
|
253
|
+
await audio.frameTask.run();
|
|
254
|
+
|
|
255
|
+
expect(timegroup).toBeDefined();
|
|
256
|
+
// The frameTask should request updates on the root timegroup
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe("audio element behavior", () => {
|
|
261
|
+
test("audio element can be controlled programmatically", async () => {
|
|
262
|
+
const container = document.createElement("div");
|
|
263
|
+
render(
|
|
264
|
+
html`
|
|
265
|
+
<ef-workbench>
|
|
266
|
+
<ef-preview>
|
|
267
|
+
<ef-audio></ef-audio>
|
|
268
|
+
</ef-preview>
|
|
269
|
+
</ef-workbench>
|
|
270
|
+
`,
|
|
271
|
+
container,
|
|
272
|
+
);
|
|
273
|
+
document.body.appendChild(container);
|
|
274
|
+
|
|
275
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
276
|
+
await audio.updateComplete;
|
|
277
|
+
|
|
278
|
+
const audioElement = audio.audioElement!;
|
|
279
|
+
|
|
280
|
+
// Should be able to control audio element properties
|
|
281
|
+
expect(() => {
|
|
282
|
+
audioElement.volume = 0.5;
|
|
283
|
+
audioElement.muted = true;
|
|
284
|
+
audioElement.loop = false;
|
|
285
|
+
}).not.toThrow();
|
|
286
|
+
|
|
287
|
+
expect(audioElement.volume).toBe(0.5);
|
|
288
|
+
expect(audioElement.muted).toBe(true);
|
|
289
|
+
expect(audioElement.loop).toBe(false);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("audio element handles invalid src gracefully", async () => {
|
|
293
|
+
const container = document.createElement("div");
|
|
294
|
+
render(
|
|
295
|
+
html`
|
|
296
|
+
<ef-workbench>
|
|
297
|
+
<ef-preview>
|
|
298
|
+
<ef-audio></ef-audio>
|
|
299
|
+
</ef-preview>
|
|
300
|
+
</ef-workbench>
|
|
301
|
+
`,
|
|
302
|
+
container,
|
|
303
|
+
);
|
|
304
|
+
document.body.appendChild(container);
|
|
305
|
+
|
|
306
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
307
|
+
await audio.updateComplete;
|
|
308
|
+
|
|
309
|
+
const audioElement = audio.audioElement!;
|
|
310
|
+
|
|
311
|
+
// Should handle invalid src without throwing
|
|
312
|
+
expect(() => {
|
|
313
|
+
audioElement.src = "invalid://url";
|
|
314
|
+
}).not.toThrow();
|
|
315
|
+
|
|
316
|
+
expect(() => {
|
|
317
|
+
audioElement.src = "";
|
|
318
|
+
}).not.toThrow();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("audio element events can be handled", async () => {
|
|
322
|
+
const container = document.createElement("div");
|
|
323
|
+
render(
|
|
324
|
+
html`
|
|
325
|
+
<ef-workbench>
|
|
326
|
+
<ef-preview>
|
|
327
|
+
<ef-audio></ef-audio>
|
|
328
|
+
</ef-preview>
|
|
329
|
+
</ef-workbench>
|
|
330
|
+
`,
|
|
331
|
+
container,
|
|
332
|
+
);
|
|
333
|
+
document.body.appendChild(container);
|
|
334
|
+
|
|
335
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
336
|
+
await audio.updateComplete;
|
|
337
|
+
|
|
338
|
+
const audioElement = audio.audioElement!;
|
|
339
|
+
|
|
340
|
+
let eventFired = false;
|
|
341
|
+
|
|
342
|
+
// Should be able to add event listeners
|
|
343
|
+
expect(() => {
|
|
344
|
+
audioElement.addEventListener("loadstart", () => {
|
|
345
|
+
eventFired = true;
|
|
346
|
+
});
|
|
347
|
+
}).not.toThrow();
|
|
348
|
+
|
|
349
|
+
// Trigger a loadstart event
|
|
350
|
+
audioElement.dispatchEvent(new Event("loadstart"));
|
|
351
|
+
expect(eventFired).toBe(true);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
describe("error handling and edge cases", () => {
|
|
356
|
+
test("handles audio element removal during playback", () => {
|
|
357
|
+
const container = document.createElement("div");
|
|
358
|
+
render(
|
|
359
|
+
html`
|
|
360
|
+
<ef-workbench>
|
|
361
|
+
<ef-preview>
|
|
362
|
+
<ef-audio></ef-audio>
|
|
363
|
+
</ef-preview>
|
|
364
|
+
</ef-workbench>
|
|
365
|
+
`,
|
|
366
|
+
container,
|
|
367
|
+
);
|
|
368
|
+
document.body.appendChild(container);
|
|
369
|
+
|
|
370
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
371
|
+
|
|
372
|
+
// Start some operations
|
|
373
|
+
audio.frameTask.run();
|
|
374
|
+
|
|
375
|
+
// Remove element
|
|
376
|
+
audio.remove();
|
|
377
|
+
|
|
378
|
+
// Should not cause errors
|
|
379
|
+
expect(() => {
|
|
380
|
+
audio.frameTask.run();
|
|
381
|
+
}).not.toThrow();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test("handles seek operations on audio", () => {
|
|
385
|
+
const container = document.createElement("div");
|
|
386
|
+
render(
|
|
387
|
+
html`
|
|
388
|
+
<ef-workbench>
|
|
389
|
+
<ef-preview>
|
|
390
|
+
<ef-audio></ef-audio>
|
|
391
|
+
</ef-preview>
|
|
392
|
+
</ef-workbench>
|
|
393
|
+
`,
|
|
394
|
+
container,
|
|
395
|
+
);
|
|
396
|
+
document.body.appendChild(container);
|
|
397
|
+
|
|
398
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
399
|
+
|
|
400
|
+
// Should handle seek operations gracefully
|
|
401
|
+
expect(() => {
|
|
402
|
+
audio.desiredSeekTimeMs = 1000; // Seek to 1 second
|
|
403
|
+
audio.frameTask.run();
|
|
404
|
+
}).not.toThrow();
|
|
405
|
+
|
|
406
|
+
expect(() => {
|
|
407
|
+
audio.desiredSeekTimeMs = -500; // Invalid negative time
|
|
408
|
+
audio.frameTask.run();
|
|
409
|
+
}).not.toThrow();
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("handles audio without src gracefully", async () => {
|
|
413
|
+
const container = document.createElement("div");
|
|
414
|
+
render(
|
|
415
|
+
html`
|
|
416
|
+
<ef-workbench>
|
|
417
|
+
<ef-preview>
|
|
418
|
+
<ef-audio></ef-audio>
|
|
419
|
+
</ef-preview>
|
|
420
|
+
</ef-workbench>
|
|
421
|
+
`,
|
|
422
|
+
container,
|
|
423
|
+
);
|
|
424
|
+
document.body.appendChild(container);
|
|
425
|
+
|
|
426
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
427
|
+
await audio.updateComplete;
|
|
428
|
+
|
|
429
|
+
// Should handle missing src gracefully - src defaults to empty string, not null
|
|
430
|
+
expect(audio.src).toBe("");
|
|
431
|
+
|
|
432
|
+
expect(() => {
|
|
433
|
+
audio.frameTask.run();
|
|
434
|
+
}).not.toThrow();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test("handles simultaneous frame task executions", async () => {
|
|
438
|
+
const container = document.createElement("div");
|
|
439
|
+
render(
|
|
440
|
+
html`
|
|
441
|
+
<ef-workbench>
|
|
442
|
+
<ef-preview>
|
|
443
|
+
<ef-audio></ef-audio>
|
|
444
|
+
</ef-preview>
|
|
445
|
+
</ef-workbench>
|
|
446
|
+
`,
|
|
447
|
+
container,
|
|
448
|
+
);
|
|
449
|
+
document.body.appendChild(container);
|
|
450
|
+
|
|
451
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
452
|
+
|
|
453
|
+
// Should handle multiple simultaneous executions
|
|
454
|
+
const task1 = audio.frameTask.run();
|
|
455
|
+
const task2 = audio.frameTask.run();
|
|
456
|
+
const task3 = audio.frameTask.run();
|
|
457
|
+
|
|
458
|
+
// All should complete without throwing
|
|
459
|
+
await expect(
|
|
460
|
+
Promise.allSettled([task1, task2, task3]),
|
|
461
|
+
).resolves.toBeDefined();
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
describe("integration with timegroups", () => {
|
|
466
|
+
test("integrates correctly within timegroup structure", async () => {
|
|
467
|
+
const container = document.createElement("div");
|
|
468
|
+
render(
|
|
469
|
+
html`
|
|
470
|
+
<ef-preview>
|
|
471
|
+
<ef-timegroup mode="sequence">
|
|
472
|
+
<ef-audio src="/test-assets/media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
473
|
+
</ef-timegroup>
|
|
474
|
+
</ef-preview>
|
|
475
|
+
`,
|
|
476
|
+
container,
|
|
477
|
+
);
|
|
478
|
+
document.body.appendChild(container);
|
|
479
|
+
|
|
480
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
481
|
+
const timegroup = container.querySelector("ef-timegroup");
|
|
482
|
+
await audio.updateComplete;
|
|
483
|
+
|
|
484
|
+
// Wait for fragment index to load
|
|
485
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
486
|
+
|
|
487
|
+
expect(timegroup).toBeDefined();
|
|
488
|
+
|
|
489
|
+
// The audio should have loaded successfully within the timegroup
|
|
490
|
+
// We test that it has a valid duration instead of a specific value
|
|
491
|
+
expect(audio.intrinsicDurationMs).toBeGreaterThan(0);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test("respects timegroup timing properties", async () => {
|
|
495
|
+
const container = document.createElement("div");
|
|
496
|
+
render(
|
|
497
|
+
html`
|
|
498
|
+
<ef-preview>
|
|
499
|
+
<ef-timegroup mode="contain">
|
|
500
|
+
<ef-audio src="/test-assets/media/bars-n-tone2.mp4" mode="asset" sourcein="1s" sourceout="4s"></ef-audio>
|
|
501
|
+
</ef-timegroup>
|
|
502
|
+
</ef-preview>
|
|
503
|
+
`,
|
|
504
|
+
container,
|
|
505
|
+
);
|
|
506
|
+
document.body.appendChild(container);
|
|
507
|
+
|
|
508
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
509
|
+
await audio.updateComplete;
|
|
510
|
+
|
|
511
|
+
// Wait for fragment index to load
|
|
512
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
513
|
+
|
|
514
|
+
// Should respect sourcein/sourceout timing
|
|
515
|
+
expect(audio.sourceInMs).toBe(1000);
|
|
516
|
+
expect(audio.sourceOutMs).toBe(4000);
|
|
517
|
+
expect(audio.durationMs).toBe(3000); // 4s - 1s
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
describe("audio-specific functionality", () => {
|
|
522
|
+
test("inherits audio analysis capabilities from EFMedia", () => {
|
|
523
|
+
const container = document.createElement("div");
|
|
524
|
+
render(
|
|
525
|
+
html`
|
|
526
|
+
<ef-workbench>
|
|
527
|
+
<ef-preview>
|
|
528
|
+
<ef-audio></ef-audio>
|
|
529
|
+
</ef-preview>
|
|
530
|
+
</ef-workbench>
|
|
531
|
+
`,
|
|
532
|
+
container,
|
|
533
|
+
);
|
|
534
|
+
document.body.appendChild(container);
|
|
535
|
+
|
|
536
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
537
|
+
|
|
538
|
+
// Should inherit audio analysis from EFMedia
|
|
539
|
+
expect(audio.audioBufferTask).toBeDefined();
|
|
540
|
+
expect(audio.frequencyDataTask).toBeDefined();
|
|
541
|
+
expect(audio.byteTimeDomainTask).toBeDefined();
|
|
542
|
+
expect(audio.fftSize).toBeDefined();
|
|
543
|
+
expect(audio.fftGain).toBeDefined();
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test("can access audio track information", async () => {
|
|
547
|
+
const container = document.createElement("div");
|
|
548
|
+
render(
|
|
549
|
+
html`
|
|
550
|
+
<ef-preview>
|
|
551
|
+
<ef-audio src="/test-assets/media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
552
|
+
</ef-preview>
|
|
553
|
+
`,
|
|
554
|
+
container,
|
|
555
|
+
);
|
|
556
|
+
document.body.appendChild(container);
|
|
557
|
+
|
|
558
|
+
const audio = container.querySelector("ef-audio") as EFAudio;
|
|
559
|
+
await audio.updateComplete;
|
|
560
|
+
|
|
561
|
+
// Wait for fragment index to load
|
|
562
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
563
|
+
|
|
564
|
+
// Should be able to access default audio track
|
|
565
|
+
// We test that the audio loads successfully instead of checking specific track ID
|
|
566
|
+
expect(audio.intrinsicDurationMs).toBeGreaterThan(0);
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
});
|
package/src/elements/EFAudio.ts
CHANGED
|
@@ -19,17 +19,15 @@ export class EFAudio extends EFMedia {
|
|
|
19
19
|
frameTask = new Task(this, {
|
|
20
20
|
args: () =>
|
|
21
21
|
[
|
|
22
|
-
this.
|
|
23
|
-
this.initSegmentsLoader.status,
|
|
22
|
+
this.fragmentIndexTask.status,
|
|
24
23
|
this.seekTask.status,
|
|
25
|
-
this.
|
|
24
|
+
this.mediaSegmentsTask.status,
|
|
26
25
|
this.videoAssetTask.status,
|
|
27
26
|
] as const,
|
|
28
27
|
task: async () => {
|
|
29
|
-
await this.
|
|
30
|
-
await this.initSegmentsLoader.taskComplete;
|
|
28
|
+
await this.fragmentIndexTask.taskComplete;
|
|
31
29
|
await this.seekTask.taskComplete;
|
|
32
|
-
await this.
|
|
30
|
+
await this.mediaSegmentsTask.taskComplete;
|
|
33
31
|
await this.videoAssetTask.taskComplete;
|
|
34
32
|
this.rootTimegroup?.requestUpdate();
|
|
35
33
|
},
|