@editframe/elements 0.16.8-beta.0 → 0.18.3-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/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/ScrubTrackManager.d.ts +96 -0
- package/dist/ScrubTrackManager.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 +22 -3
- package/dist/elements/EFAudio.js +60 -43
- package/dist/elements/EFCaptions.js +337 -373
- package/dist/elements/EFImage.d.ts +1 -0
- package/dist/elements/EFImage.js +73 -91
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
- package/dist/elements/EFMedia/AssetIdMediaEngine.test.d.ts +1 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
- package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
- package/dist/elements/EFMedia/BaseMediaEngine.test.d.ts +1 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -0
- package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +62 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +138 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +22 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
- package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
- package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
- package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia.d.ts +95 -66
- package/dist/elements/EFMedia.js +204 -683
- package/dist/elements/EFSourceMixin.js +31 -48
- package/dist/elements/EFTemporal.d.ts +2 -1
- package/dist/elements/EFTemporal.js +266 -360
- package/dist/elements/EFTimegroup.d.ts +14 -1
- package/dist/elements/EFTimegroup.js +337 -323
- package/dist/elements/EFVideo.browsertest.d.ts +0 -0
- package/dist/elements/EFVideo.d.ts +123 -4
- package/dist/elements/EFVideo.js +308 -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/SampleBuffer.d.ts +14 -0
- package/dist/elements/SampleBuffer.js +52 -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/updateAnimations.js +39 -59
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/getRenderInfo.js +59 -67
- package/dist/gui/ContextMixin.js +150 -288
- package/dist/gui/EFConfiguration.js +27 -43
- package/dist/gui/EFFilmstrip.d.ts +3 -3
- package/dist/gui/EFFilmstrip.js +440 -620
- package/dist/gui/EFFitScale.d.ts +2 -2
- 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/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
- package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
- package/dist/gui/services/ElementConnectionManager.js +128 -0
- package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
- package/dist/gui/services/PlaybackController.d.ts +103 -0
- package/dist/gui/services/PlaybackController.js +290 -0
- package/dist/index.js +5 -30
- package/dist/msToTimeCode.js +11 -13
- package/dist/services/MediaSourceManager.d.ts +62 -0
- package/dist/services/MediaSourceManager.js +211 -0
- package/dist/style.css +2 -1
- package/dist/transcoding/cache/CacheManager.d.ts +73 -0
- package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
- package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
- package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
- package/dist/transcoding/types/index.d.ts +242 -0
- package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
- package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
- package/dist/transcoding/utils/UrlGenerator.js +45 -0
- package/dist/transcoding/utils/constants.d.ts +27 -0
- package/dist/utils/LRUCache.d.ts +34 -0
- package/dist/utils/LRUCache.js +115 -0
- package/package.json +4 -3
- package/src/elements/EFAudio.browsertest.ts +709 -0
- package/src/elements/EFAudio.ts +59 -15
- package/src/elements/EFCaptions.browsertest.ts +0 -1
- package/src/elements/EFImage.browsertest.ts +42 -1
- package/src/elements/EFImage.ts +23 -3
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
- package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
- package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
- package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
- package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
- package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
- package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
- package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
- package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
- package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia.browsertest.ts +696 -271
- package/src/elements/EFMedia.ts +218 -776
- package/src/elements/EFTemporal.browsertest.ts +0 -1
- package/src/elements/EFTemporal.ts +13 -3
- package/src/elements/EFTimegroup.browsertest.ts +6 -3
- package/src/elements/EFTimegroup.ts +221 -27
- package/src/elements/EFVideo.browsertest.ts +758 -0
- package/src/elements/EFVideo.ts +418 -68
- package/src/elements/EFWaveform.ts +5 -5
- package/src/elements/MediaController.ts +98 -0
- package/src/elements/SampleBuffer.ts +97 -0
- package/src/elements/printTaskStatus.ts +16 -0
- package/src/elements/updateAnimations.ts +6 -0
- package/src/gui/ContextMixin.ts +23 -104
- package/src/gui/TWMixin.ts +10 -3
- package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
- package/src/gui/services/ElementConnectionManager.ts +224 -0
- package/src/gui/services/PlaybackController.browsertest.ts +437 -0
- package/src/gui/services/PlaybackController.ts +521 -0
- package/src/services/MediaSourceManager.ts +333 -0
- package/src/transcoding/cache/CacheManager.ts +208 -0
- package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
- package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
- package/src/transcoding/types/index.ts +265 -0
- package/src/transcoding/utils/MediaUtils.ts +63 -0
- package/src/transcoding/utils/UrlGenerator.ts +68 -0
- package/src/transcoding/utils/constants.ts +36 -0
- package/src/utils/LRUCache.ts +153 -0
- package/test/EFVideo.framegen.browsertest.ts +127 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
- package/test/createJitTestClips.ts +425 -0
- package/test/recordReplayProxyPlugin.js +302 -0
- package/test/useAssetMSW.ts +49 -0
- package/test/useMSW.ts +44 -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
|
@@ -1,305 +1,46 @@
|
|
|
1
|
-
import { provide } from "@lit/context";
|
|
2
|
-
import { Task } from "@lit/task";
|
|
3
|
-
import debug from "debug";
|
|
4
|
-
import { LitElement, html, css } from "lit";
|
|
5
|
-
import { property, customElement } from "lit/decorators.js";
|
|
6
1
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
7
2
|
import { isContextMixin } from "../gui/ContextMixin.js";
|
|
8
|
-
import { deepGetMediaElements } from "./EFMedia.js";
|
|
9
|
-
import { EFTemporal, shallowGetTemporalElements, timegroupContext } from "./EFTemporal.js";
|
|
10
|
-
import { TimegroupController } from "./TimegroupController.js";
|
|
11
3
|
import { durationConverter } from "./durationConverter.js";
|
|
4
|
+
import { EFTemporal, deepGetElementsWithFrameTasks, flushStartTimeMsCache, shallowGetTemporalElements, timegroupContext } from "./EFTemporal.js";
|
|
12
5
|
import { updateAnimations } from "./updateAnimations.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
23
|
-
if (kind && result) __defProp(target, key, result);
|
|
24
|
-
return result;
|
|
25
|
-
};
|
|
26
|
-
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
27
|
-
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
28
|
-
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
29
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
30
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
31
|
-
var _currentTime, _resizeObserver, _EFTimegroup_instances, addAudioToContext_fn;
|
|
6
|
+
import { deepGetMediaElements } from "./EFMedia.js";
|
|
7
|
+
import { TimegroupController } from "./TimegroupController.js";
|
|
8
|
+
import { provide } from "@lit/context";
|
|
9
|
+
import { Task, TaskStatus } from "@lit/task";
|
|
10
|
+
import debug from "debug";
|
|
11
|
+
import { LitElement, css, html } from "lit";
|
|
12
|
+
import { customElement, property } from "lit/decorators.js";
|
|
13
|
+
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
14
|
+
var _EFTimegroup;
|
|
32
15
|
const log = debug("ef:elements:EFTimegroup");
|
|
33
16
|
const shallowGetTimegroups = (element, groups = []) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} else {
|
|
38
|
-
shallowGetTimegroups(child, groups);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return groups;
|
|
42
|
-
};
|
|
43
|
-
let EFTimegroup = class extends EFTemporal(LitElement) {
|
|
44
|
-
constructor() {
|
|
45
|
-
super(...arguments);
|
|
46
|
-
__privateAdd(this, _EFTimegroup_instances);
|
|
47
|
-
this._timeGroupContext = this;
|
|
48
|
-
__privateAdd(this, _currentTime, 0);
|
|
49
|
-
this.mode = "contain";
|
|
50
|
-
this.overlapMs = 0;
|
|
51
|
-
this.fit = "none";
|
|
52
|
-
__privateAdd(this, _resizeObserver);
|
|
53
|
-
this.frameTask = new Task(this, {
|
|
54
|
-
autoRun: EF_INTERACTIVE,
|
|
55
|
-
args: () => [this.ownCurrentTimeMs, this.currentTimeMs],
|
|
56
|
-
task: async ([], { signal: _signal }) => {
|
|
57
|
-
let fullyUpdated = await this.updateComplete;
|
|
58
|
-
while (!fullyUpdated) {
|
|
59
|
-
fullyUpdated = await this.updateComplete;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
set currentTime(time) {
|
|
65
|
-
__privateSet(this, _currentTime, Math.max(0, Math.min(time, this.durationMs / 1e3)));
|
|
66
|
-
try {
|
|
67
|
-
if (this.id) {
|
|
68
|
-
if (this.isConnected) {
|
|
69
|
-
localStorage.setItem(this.storageKey, time.toString());
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
log("Failed to save time to localStorage", error);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
get currentTime() {
|
|
77
|
-
return __privateGet(this, _currentTime);
|
|
78
|
-
}
|
|
79
|
-
get currentTimeMs() {
|
|
80
|
-
return this.currentTime * 1e3;
|
|
81
|
-
}
|
|
82
|
-
set currentTimeMs(ms) {
|
|
83
|
-
this.currentTime = ms / 1e3;
|
|
84
|
-
}
|
|
85
|
-
render() {
|
|
86
|
-
return html`<slot></slot> `;
|
|
87
|
-
}
|
|
88
|
-
maybeLoadTimeFromLocalStorage() {
|
|
89
|
-
if (this.id) {
|
|
90
|
-
try {
|
|
91
|
-
return Number.parseFloat(localStorage.getItem(this.storageKey) || "0");
|
|
92
|
-
} catch (error) {
|
|
93
|
-
log("Failed to load time from localStorage", error);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return 0;
|
|
97
|
-
}
|
|
98
|
-
connectedCallback() {
|
|
99
|
-
super.connectedCallback();
|
|
100
|
-
if (this.id) {
|
|
101
|
-
this.waitForMediaDurations().then(() => {
|
|
102
|
-
__privateSet(this, _currentTime, this.maybeLoadTimeFromLocalStorage());
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
if (this.parentTimegroup) {
|
|
106
|
-
new TimegroupController(this.parentTimegroup, this);
|
|
107
|
-
}
|
|
108
|
-
if (this.shouldWrapWithWorkbench()) {
|
|
109
|
-
this.wrapWithWorkbench();
|
|
110
|
-
}
|
|
111
|
-
requestAnimationFrame(() => {
|
|
112
|
-
this.updateAnimations();
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
disconnectedCallback() {
|
|
116
|
-
super.disconnectedCallback();
|
|
117
|
-
__privateGet(this, _resizeObserver)?.disconnect();
|
|
118
|
-
}
|
|
119
|
-
get storageKey() {
|
|
120
|
-
if (!this.id) {
|
|
121
|
-
throw new Error("Timegroup must have an id to use localStorage.");
|
|
122
|
-
}
|
|
123
|
-
return `ef-timegroup-${this.id}`;
|
|
124
|
-
}
|
|
125
|
-
get intrinsicDurationMs() {
|
|
126
|
-
if (this.hasExplicitDuration) {
|
|
127
|
-
return this.explicitDurationMs;
|
|
128
|
-
}
|
|
129
|
-
return void 0;
|
|
130
|
-
}
|
|
131
|
-
get hasOwnDuration() {
|
|
132
|
-
return this.mode === "contain" || this.mode === "sequence" || this.mode === "fixed" && this.hasExplicitDuration;
|
|
133
|
-
}
|
|
134
|
-
get durationMs() {
|
|
135
|
-
switch (this.mode) {
|
|
136
|
-
case "fit": {
|
|
137
|
-
if (!this.parentTimegroup) {
|
|
138
|
-
return 0;
|
|
139
|
-
}
|
|
140
|
-
return this.parentTimegroup.durationMs;
|
|
141
|
-
}
|
|
142
|
-
case "fixed":
|
|
143
|
-
return super.durationMs;
|
|
144
|
-
case "sequence": {
|
|
145
|
-
let duration = 0;
|
|
146
|
-
this.childTemporals.forEach((child, index) => {
|
|
147
|
-
if (child instanceof EFTimegroup && child.mode === "fit") {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (index > 0) {
|
|
151
|
-
duration -= this.overlapMs;
|
|
152
|
-
}
|
|
153
|
-
duration += child.durationMs;
|
|
154
|
-
});
|
|
155
|
-
return duration;
|
|
156
|
-
}
|
|
157
|
-
case "contain": {
|
|
158
|
-
let maxDuration = 0;
|
|
159
|
-
for (const child of this.childTemporals) {
|
|
160
|
-
if (child instanceof EFTimegroup && child.mode === "fit") {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (!child.hasOwnDuration) {
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
maxDuration = Math.max(maxDuration, child.durationMs);
|
|
167
|
-
}
|
|
168
|
-
return maxDuration;
|
|
169
|
-
}
|
|
170
|
-
default:
|
|
171
|
-
throw new Error(`Invalid time mode: ${this.mode}`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Wait for all media elements to load their initial segments.
|
|
176
|
-
* Ideally we would only need the extracted index json data, but
|
|
177
|
-
* that caused issues with constructing audio data. We had negative durations
|
|
178
|
-
* in calculations and it was not clear why.
|
|
179
|
-
*/
|
|
180
|
-
async waitForMediaDurations() {
|
|
181
|
-
const mediaElements = deepGetMediaElements(this);
|
|
182
|
-
return await Promise.all(
|
|
183
|
-
mediaElements.map((m) => m.trackFragmentIndexLoader.taskComplete)
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
get childTemporals() {
|
|
187
|
-
return shallowGetTemporalElements(this);
|
|
188
|
-
}
|
|
189
|
-
updated(changedProperties) {
|
|
190
|
-
super.updated(changedProperties);
|
|
191
|
-
if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
|
|
192
|
-
this.updateAnimations();
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
updateAnimations() {
|
|
196
|
-
updateAnimations(this);
|
|
197
|
-
}
|
|
198
|
-
get contextProvider() {
|
|
199
|
-
let parent = this.parentNode;
|
|
200
|
-
while (parent) {
|
|
201
|
-
if (isContextMixin(parent)) {
|
|
202
|
-
return parent;
|
|
203
|
-
}
|
|
204
|
-
parent = parent.parentNode;
|
|
205
|
-
}
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Returns true if the timegroup should be wrapped with a workbench.
|
|
210
|
-
*
|
|
211
|
-
* A timegroup should be wrapped with a workbench if it is the root-most timegroup
|
|
212
|
-
* and EF_INTERACTIVE is true.
|
|
213
|
-
*
|
|
214
|
-
* If the timegroup is already wrappedin a context provider like ef-preview,
|
|
215
|
-
* it should NOT be wrapped in a workbench.
|
|
216
|
-
*/
|
|
217
|
-
shouldWrapWithWorkbench() {
|
|
218
|
-
return EF_INTERACTIVE && this.closest("ef-timegroup") === this && this.closest("ef-preview") === null && this.closest("ef-workbench") === null && this.closest("test-context") === null;
|
|
219
|
-
}
|
|
220
|
-
wrapWithWorkbench() {
|
|
221
|
-
const workbench = document.createElement("ef-workbench");
|
|
222
|
-
this.parentElement?.append(workbench);
|
|
223
|
-
if (!this.hasAttribute("id")) {
|
|
224
|
-
this.setAttribute("id", "root-this");
|
|
225
|
-
}
|
|
226
|
-
this.setAttribute("slot", "canvas");
|
|
227
|
-
workbench.append(this);
|
|
228
|
-
const filmstrip = document.createElement("ef-filmstrip");
|
|
229
|
-
filmstrip.setAttribute("slot", "timeline");
|
|
230
|
-
filmstrip.setAttribute("target", this.id);
|
|
231
|
-
workbench.append(filmstrip);
|
|
232
|
-
}
|
|
233
|
-
get efElements() {
|
|
234
|
-
return Array.from(
|
|
235
|
-
this.querySelectorAll(
|
|
236
|
-
"ef-audio, ef-video, ef-image, ef-captions, ef-waveform"
|
|
237
|
-
)
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
async renderAudio(fromMs, toMs) {
|
|
241
|
-
const durationMs = toMs - fromMs;
|
|
242
|
-
const audioContext = new OfflineAudioContext(
|
|
243
|
-
2,
|
|
244
|
-
Math.round(48e3 * durationMs / 1e3),
|
|
245
|
-
48e3
|
|
246
|
-
);
|
|
247
|
-
await __privateMethod(this, _EFTimegroup_instances, addAudioToContext_fn).call(this, audioContext, fromMs, toMs);
|
|
248
|
-
return await audioContext.startRendering();
|
|
249
|
-
}
|
|
250
|
-
async loadMd5Sums() {
|
|
251
|
-
const efElements = this.efElements;
|
|
252
|
-
const loaderTasks = [];
|
|
253
|
-
for (const el of efElements) {
|
|
254
|
-
const md5SumLoader = el.md5SumLoader;
|
|
255
|
-
if (md5SumLoader instanceof Task) {
|
|
256
|
-
md5SumLoader.run();
|
|
257
|
-
loaderTasks.push(md5SumLoader.taskComplete);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
await Promise.all(loaderTasks);
|
|
261
|
-
efElements.map((el) => {
|
|
262
|
-
if ("productionSrc" in el && el.productionSrc instanceof Function) {
|
|
263
|
-
el.setAttribute("src", el.productionSrc());
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
_currentTime = /* @__PURE__ */ new WeakMap();
|
|
269
|
-
_resizeObserver = /* @__PURE__ */ new WeakMap();
|
|
270
|
-
_EFTimegroup_instances = /* @__PURE__ */ new WeakSet();
|
|
271
|
-
addAudioToContext_fn = async function(audioContext, fromMs, toMs) {
|
|
272
|
-
await this.waitForMediaDurations();
|
|
273
|
-
await Promise.all(
|
|
274
|
-
deepGetMediaElements(this).map(async (mediaElement) => {
|
|
275
|
-
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
276
|
-
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
277
|
-
const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
|
|
278
|
-
if (!mediaOverlaps || mediaElement.defaultAudioTrackId === void 0) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
const audio = await mediaElement.fetchAudioSpanningTime(fromMs, toMs);
|
|
282
|
-
if (!audio) {
|
|
283
|
-
throw new Error("Failed to fetch audio");
|
|
284
|
-
}
|
|
285
|
-
const bufferSource = audioContext.createBufferSource();
|
|
286
|
-
bufferSource.buffer = await audioContext.decodeAudioData(
|
|
287
|
-
await audio.blob.arrayBuffer()
|
|
288
|
-
);
|
|
289
|
-
bufferSource.connect(audioContext.destination);
|
|
290
|
-
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
291
|
-
const ctxEndMs = mediaElement.endTimeMs - fromMs;
|
|
292
|
-
const ctxDurationMs = ctxEndMs - ctxStartMs;
|
|
293
|
-
const offset = Math.max(0, fromMs - mediaElement.startTimeMs) - audio.startMs;
|
|
294
|
-
bufferSource.start(
|
|
295
|
-
ctxStartMs / 1e3,
|
|
296
|
-
offset / 1e3,
|
|
297
|
-
ctxDurationMs / 1e3
|
|
298
|
-
);
|
|
299
|
-
})
|
|
300
|
-
);
|
|
17
|
+
for (const child of Array.from(element.children)) if (child instanceof EFTimegroup) groups.push(child);
|
|
18
|
+
else shallowGetTimegroups(child, groups);
|
|
19
|
+
return groups;
|
|
301
20
|
};
|
|
302
|
-
EFTimegroup
|
|
21
|
+
let EFTimegroup = class EFTimegroup$1 extends EFTemporal(LitElement) {
|
|
22
|
+
static {
|
|
23
|
+
_EFTimegroup = this;
|
|
24
|
+
}
|
|
25
|
+
constructor(..._args) {
|
|
26
|
+
super(..._args);
|
|
27
|
+
this._timeGroupContext = this;
|
|
28
|
+
this.isFrameUpdateInProgress = false;
|
|
29
|
+
this.queuedTimeUpdate = null;
|
|
30
|
+
this.mode = "contain";
|
|
31
|
+
this.overlapMs = 0;
|
|
32
|
+
this.fit = "none";
|
|
33
|
+
this.frameTask = new Task(this, {
|
|
34
|
+
autoRun: EF_INTERACTIVE,
|
|
35
|
+
args: () => [this.ownCurrentTimeMs, this.currentTimeMs],
|
|
36
|
+
task: async ([], { signal: _signal }) => {
|
|
37
|
+
let fullyUpdated = await this.updateComplete;
|
|
38
|
+
while (!fullyUpdated) fullyUpdated = await this.updateComplete;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
static {
|
|
43
|
+
this.styles = css`
|
|
303
44
|
:host {
|
|
304
45
|
display: block;
|
|
305
46
|
width: 100%;
|
|
@@ -309,32 +50,305 @@ EFTimegroup.styles = css`
|
|
|
309
50
|
left: 0;
|
|
310
51
|
}
|
|
311
52
|
`;
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
53
|
+
}
|
|
54
|
+
#currentTime = 0;
|
|
55
|
+
#resizeObserver;
|
|
56
|
+
set currentTime(time) {
|
|
57
|
+
const newTime = Math.max(0, Math.min(time, this.durationMs / 1e3));
|
|
58
|
+
if (this.isRootTimegroup && this.isFrameUpdateInProgress) {
|
|
59
|
+
this.queuedTimeUpdate = newTime;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.isRootTimegroup) this.#executeTimeUpdate(newTime);
|
|
63
|
+
else {
|
|
64
|
+
this.#currentTime = newTime;
|
|
65
|
+
this.#saveTimeToLocalStorage(newTime);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
get currentTime() {
|
|
69
|
+
return this.#currentTime;
|
|
70
|
+
}
|
|
71
|
+
get currentTimeMs() {
|
|
72
|
+
return this.currentTime * 1e3;
|
|
73
|
+
}
|
|
74
|
+
set currentTimeMs(ms) {
|
|
75
|
+
this.currentTime = ms / 1e3;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Determines if this is a root timegroup (no parent timegroups)
|
|
79
|
+
*/
|
|
80
|
+
get isRootTimegroup() {
|
|
81
|
+
return this.closest("ef-timegroup") === this;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Executes time update with frame locking for root timegroups
|
|
85
|
+
*/
|
|
86
|
+
async #executeTimeUpdate(time) {
|
|
87
|
+
this.isFrameUpdateInProgress = true;
|
|
88
|
+
this.#currentTime = time;
|
|
89
|
+
try {
|
|
90
|
+
this.#saveTimeToLocalStorage(time);
|
|
91
|
+
await this.waitForFrameTasks();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("⚠️ [TIME_UPDATE_ERROR] Error during frame update:", error);
|
|
94
|
+
} finally {
|
|
95
|
+
this.isFrameUpdateInProgress = false;
|
|
96
|
+
if (this.queuedTimeUpdate !== null && this.queuedTimeUpdate !== time) {
|
|
97
|
+
const nextTime = this.queuedTimeUpdate;
|
|
98
|
+
this.queuedTimeUpdate = null;
|
|
99
|
+
setTimeout(() => this.#executeTimeUpdate(nextTime), 0);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Saves time to localStorage (extracted for reuse)
|
|
105
|
+
*/
|
|
106
|
+
#saveTimeToLocalStorage(time) {
|
|
107
|
+
try {
|
|
108
|
+
if (this.id && this.isConnected) localStorage.setItem(this.storageKey, time.toString());
|
|
109
|
+
} catch (error) {
|
|
110
|
+
log("Failed to save time to localStorage", error);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
render() {
|
|
114
|
+
return html`<slot></slot> `;
|
|
115
|
+
}
|
|
116
|
+
maybeLoadTimeFromLocalStorage() {
|
|
117
|
+
if (this.id) try {
|
|
118
|
+
return Number.parseFloat(localStorage.getItem(this.storageKey) || "0");
|
|
119
|
+
} catch (error) {
|
|
120
|
+
log("Failed to load time from localStorage", error);
|
|
121
|
+
}
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
connectedCallback() {
|
|
125
|
+
super.connectedCallback();
|
|
126
|
+
if (this.id) this.waitForMediaDurations().then(() => {
|
|
127
|
+
this.currentTime = this.maybeLoadTimeFromLocalStorage();
|
|
128
|
+
});
|
|
129
|
+
if (this.parentTimegroup) new TimegroupController(this.parentTimegroup, this);
|
|
130
|
+
if (this.shouldWrapWithWorkbench()) this.wrapWithWorkbench();
|
|
131
|
+
requestAnimationFrame(() => {
|
|
132
|
+
this.updateAnimations();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
disconnectedCallback() {
|
|
136
|
+
super.disconnectedCallback();
|
|
137
|
+
this.#resizeObserver?.disconnect();
|
|
138
|
+
}
|
|
139
|
+
get storageKey() {
|
|
140
|
+
if (!this.id) throw new Error("Timegroup must have an id to use localStorage.");
|
|
141
|
+
return `ef-timegroup-${this.id}`;
|
|
142
|
+
}
|
|
143
|
+
get intrinsicDurationMs() {
|
|
144
|
+
if (this.hasExplicitDuration) return this.explicitDurationMs;
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
get hasOwnDuration() {
|
|
148
|
+
return this.mode === "contain" || this.mode === "sequence" || this.mode === "fixed" && this.hasExplicitDuration;
|
|
149
|
+
}
|
|
150
|
+
get durationMs() {
|
|
151
|
+
switch (this.mode) {
|
|
152
|
+
case "fit": {
|
|
153
|
+
if (!this.parentTimegroup) return 0;
|
|
154
|
+
return this.parentTimegroup.durationMs;
|
|
155
|
+
}
|
|
156
|
+
case "fixed": return super.durationMs;
|
|
157
|
+
case "sequence": {
|
|
158
|
+
let duration = 0;
|
|
159
|
+
this.childTemporals.forEach((child, index) => {
|
|
160
|
+
if (child instanceof _EFTimegroup && child.mode === "fit") return;
|
|
161
|
+
if (index > 0) duration -= this.overlapMs;
|
|
162
|
+
duration += child.durationMs;
|
|
163
|
+
});
|
|
164
|
+
return duration;
|
|
165
|
+
}
|
|
166
|
+
case "contain": {
|
|
167
|
+
let maxDuration = 0;
|
|
168
|
+
for (const child of this.childTemporals) {
|
|
169
|
+
if (child instanceof _EFTimegroup && child.mode === "fit") continue;
|
|
170
|
+
if (!child.hasOwnDuration) continue;
|
|
171
|
+
maxDuration = Math.max(maxDuration, child.durationMs);
|
|
172
|
+
}
|
|
173
|
+
return maxDuration;
|
|
174
|
+
}
|
|
175
|
+
default: throw new Error(`Invalid time mode: ${this.mode}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async getPendingFrameTasks() {
|
|
179
|
+
await this.updateComplete;
|
|
180
|
+
const temporals = deepGetElementsWithFrameTasks(this);
|
|
181
|
+
return temporals.map((temporal) => temporal.frameTask).filter((task) => task.status < TaskStatus.COMPLETE);
|
|
182
|
+
}
|
|
183
|
+
async waitForFrameTasks() {
|
|
184
|
+
const limit = 10;
|
|
185
|
+
let step = 0;
|
|
186
|
+
await this.updateComplete;
|
|
187
|
+
while (step < limit) {
|
|
188
|
+
step++;
|
|
189
|
+
let pendingTasks = await this.getPendingFrameTasks();
|
|
190
|
+
await Promise.all(pendingTasks.map((task) => task.taskComplete));
|
|
191
|
+
await this.updateComplete;
|
|
192
|
+
pendingTasks = await this.getPendingFrameTasks();
|
|
193
|
+
if (pendingTasks.length === 0) break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Wait for all media elements to load their initial segments.
|
|
198
|
+
* Ideally we would only need the extracted index json data, but
|
|
199
|
+
* that caused issues with constructing audio data. We had negative durations
|
|
200
|
+
* in calculations and it was not clear why.
|
|
201
|
+
*/
|
|
202
|
+
async waitForMediaDurations() {
|
|
203
|
+
await this.updateComplete;
|
|
204
|
+
const mediaElements = deepGetMediaElements(this);
|
|
205
|
+
await Promise.all(mediaElements.map((m) => m.mediaEngineTask.taskComplete));
|
|
206
|
+
flushStartTimeMsCache();
|
|
207
|
+
this.requestUpdate("currentTime");
|
|
208
|
+
await this.updateComplete;
|
|
209
|
+
}
|
|
210
|
+
get childTemporals() {
|
|
211
|
+
return shallowGetTemporalElements(this);
|
|
212
|
+
}
|
|
213
|
+
updated(changedProperties) {
|
|
214
|
+
super.updated(changedProperties);
|
|
215
|
+
if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) this.updateAnimations();
|
|
216
|
+
}
|
|
217
|
+
updateAnimations() {
|
|
218
|
+
updateAnimations(this);
|
|
219
|
+
}
|
|
220
|
+
get contextProvider() {
|
|
221
|
+
let parent = this.parentNode;
|
|
222
|
+
while (parent) {
|
|
223
|
+
if (isContextMixin(parent)) return parent;
|
|
224
|
+
parent = parent.parentNode;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Returns true if the timegroup should be wrapped with a workbench.
|
|
230
|
+
*
|
|
231
|
+
* A timegroup should be wrapped with a workbench if it is the root-most timegroup
|
|
232
|
+
* and EF_INTERACTIVE is true.
|
|
233
|
+
*
|
|
234
|
+
* If the timegroup is already wrappedin a context provider like ef-preview,
|
|
235
|
+
* it should NOT be wrapped in a workbench.
|
|
236
|
+
*/
|
|
237
|
+
shouldWrapWithWorkbench() {
|
|
238
|
+
return EF_INTERACTIVE && this.closest("ef-timegroup") === this && this.closest("ef-preview") === null && this.closest("ef-workbench") === null && this.closest("test-context") === null;
|
|
239
|
+
}
|
|
240
|
+
wrapWithWorkbench() {
|
|
241
|
+
const workbench = document.createElement("ef-workbench");
|
|
242
|
+
this.parentElement?.append(workbench);
|
|
243
|
+
if (!this.hasAttribute("id")) this.setAttribute("id", "root-this");
|
|
244
|
+
this.setAttribute("slot", "canvas");
|
|
245
|
+
workbench.append(this);
|
|
246
|
+
const filmstrip = document.createElement("ef-filmstrip");
|
|
247
|
+
filmstrip.setAttribute("slot", "timeline");
|
|
248
|
+
filmstrip.setAttribute("target", this.id);
|
|
249
|
+
workbench.append(filmstrip);
|
|
250
|
+
}
|
|
251
|
+
get efElements() {
|
|
252
|
+
return Array.from(this.querySelectorAll("ef-audio, ef-video, ef-image, ef-captions, ef-waveform"));
|
|
253
|
+
}
|
|
254
|
+
async #addAudioToContext(audioContext, fromMs, toMs) {
|
|
255
|
+
await this.waitForMediaDurations();
|
|
256
|
+
const abortController = new AbortController();
|
|
257
|
+
await Promise.all(deepGetMediaElements(this).map(async (mediaElement) => {
|
|
258
|
+
if (mediaElement.mute) return;
|
|
259
|
+
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
260
|
+
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
261
|
+
const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
|
|
262
|
+
if (!mediaOverlaps) return;
|
|
263
|
+
const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
|
|
264
|
+
const mediaLocalToMs = Math.min(mediaElement.endTimeMs - mediaElement.startTimeMs, toMs - mediaElement.startTimeMs);
|
|
265
|
+
if (mediaLocalFromMs >= mediaLocalToMs) return;
|
|
266
|
+
const audio = await mediaElement.fetchAudioSpanningTime(mediaLocalFromMs, mediaLocalToMs, abortController.signal);
|
|
267
|
+
if (!audio) throw new Error("Failed to fetch audio");
|
|
268
|
+
const bufferSource = audioContext.createBufferSource();
|
|
269
|
+
bufferSource.buffer = await audioContext.decodeAudioData(await audio.blob.arrayBuffer());
|
|
270
|
+
bufferSource.connect(audioContext.destination);
|
|
271
|
+
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
272
|
+
const ctxEndMs = mediaElement.endTimeMs - fromMs;
|
|
273
|
+
const ctxDurationMs = ctxEndMs - ctxStartMs;
|
|
274
|
+
const requestedOffsetInMedia = mediaLocalFromMs;
|
|
275
|
+
const actualOffsetInBuffer = requestedOffsetInMedia - audio.startMs;
|
|
276
|
+
const safeOffset = Math.max(0, actualOffsetInBuffer);
|
|
277
|
+
if (safeOffset !== actualOffsetInBuffer) {}
|
|
278
|
+
bufferSource.start(ctxStartMs / 1e3, safeOffset / 1e3, ctxDurationMs / 1e3);
|
|
279
|
+
}));
|
|
280
|
+
}
|
|
281
|
+
async renderAudio(fromMs, toMs) {
|
|
282
|
+
const durationMs = toMs - fromMs;
|
|
283
|
+
const duration = durationMs / 1e3;
|
|
284
|
+
const exactSamples = 48e3 * duration;
|
|
285
|
+
const aacFrames = exactSamples / 1024;
|
|
286
|
+
const alignedFrames = Math.round(aacFrames);
|
|
287
|
+
const contextSize = alignedFrames * 1024;
|
|
288
|
+
if (contextSize <= 0) throw new Error(`Duration must be greater than 0 when rendering audio. ${contextSize}ms`);
|
|
289
|
+
let audioContext;
|
|
290
|
+
try {
|
|
291
|
+
audioContext = new OfflineAudioContext(2, contextSize, 48e3);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
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).`);
|
|
294
|
+
}
|
|
295
|
+
await this.#addAudioToContext(audioContext, fromMs, toMs);
|
|
296
|
+
const renderedBuffer = await audioContext.startRendering();
|
|
297
|
+
return renderedBuffer;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* TEMPORARY TEST METHOD: Renders audio and immediately plays it back
|
|
301
|
+
* Usage: timegroup.testPlayAudio(0, 5000) // Play first 5 seconds
|
|
302
|
+
*/
|
|
303
|
+
async testPlayAudio(fromMs, toMs) {
|
|
304
|
+
try {
|
|
305
|
+
const renderedBuffer = await this.renderAudio(fromMs, toMs);
|
|
306
|
+
const playbackContext = new AudioContext();
|
|
307
|
+
const bufferSource = playbackContext.createBufferSource();
|
|
308
|
+
bufferSource.buffer = renderedBuffer;
|
|
309
|
+
bufferSource.connect(playbackContext.destination);
|
|
310
|
+
bufferSource.start(0);
|
|
311
|
+
return new Promise((resolve) => {
|
|
312
|
+
bufferSource.onended = () => {
|
|
313
|
+
playbackContext.close();
|
|
314
|
+
resolve();
|
|
315
|
+
};
|
|
316
|
+
});
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error("🎵 [TEST_PLAY_AUDIO] Error:", error);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async loadMd5Sums() {
|
|
323
|
+
const efElements = this.efElements;
|
|
324
|
+
const loaderTasks = [];
|
|
325
|
+
for (const el of efElements) {
|
|
326
|
+
const md5SumLoader = el.md5SumLoader;
|
|
327
|
+
if (md5SumLoader instanceof Task) {
|
|
328
|
+
md5SumLoader.run();
|
|
329
|
+
loaderTasks.push(md5SumLoader.taskComplete);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
await Promise.all(loaderTasks);
|
|
333
|
+
efElements.map((el) => {
|
|
334
|
+
if ("productionSrc" in el && el.productionSrc instanceof Function) el.setAttribute("src", el.productionSrc());
|
|
335
|
+
});
|
|
336
|
+
}
|
|
340
337
|
};
|
|
338
|
+
_decorate([provide({ context: timegroupContext })], EFTimegroup.prototype, "_timeGroupContext", void 0);
|
|
339
|
+
_decorate([property({
|
|
340
|
+
type: String,
|
|
341
|
+
attribute: "mode"
|
|
342
|
+
})], EFTimegroup.prototype, "mode", void 0);
|
|
343
|
+
_decorate([property({
|
|
344
|
+
type: Number,
|
|
345
|
+
converter: durationConverter,
|
|
346
|
+
attribute: "overlap"
|
|
347
|
+
})], EFTimegroup.prototype, "overlapMs", void 0);
|
|
348
|
+
_decorate([property({ type: String })], EFTimegroup.prototype, "fit", void 0);
|
|
349
|
+
_decorate([property({
|
|
350
|
+
type: Number,
|
|
351
|
+
attribute: "currenttime"
|
|
352
|
+
})], EFTimegroup.prototype, "currentTime", null);
|
|
353
|
+
EFTimegroup = _EFTimegroup = _decorate([customElement("ef-timegroup")], EFTimegroup);
|
|
354
|
+
export { EFTimegroup, shallowGetTimegroups };
|
|
File without changes
|