@editframe/elements 0.19.4-beta.0 → 0.20.1-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/ContextProxiesController.d.ts +40 -0
- package/dist/elements/ContextProxiesController.js +69 -0
- package/dist/elements/EFCaptions.d.ts +45 -6
- package/dist/elements/EFCaptions.js +220 -26
- package/dist/elements/EFImage.js +4 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +2 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +9 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +1 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +11 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +13 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +9 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +7 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +15 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +2 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +3 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +6 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +3 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +2 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +2 -2
- package/dist/elements/EFMedia/shared/GlobalInputCache.d.ts +39 -0
- package/dist/elements/EFMedia/shared/GlobalInputCache.js +57 -0
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.d.ts +27 -0
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +106 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -1
- package/dist/elements/EFMedia.d.ts +2 -2
- package/dist/elements/EFMedia.js +25 -1
- package/dist/elements/EFSurface.browsertest.d.ts +0 -0
- package/dist/elements/EFSurface.d.ts +30 -0
- package/dist/elements/EFSurface.js +96 -0
- package/dist/elements/EFTemporal.js +7 -6
- package/dist/elements/EFThumbnailStrip.browsertest.d.ts +0 -0
- package/dist/elements/EFThumbnailStrip.d.ts +86 -0
- package/dist/elements/EFThumbnailStrip.js +490 -0
- package/dist/elements/EFThumbnailStrip.media-engine.browsertest.d.ts +0 -0
- package/dist/elements/EFTimegroup.d.ts +6 -1
- package/dist/elements/EFTimegroup.js +53 -11
- package/dist/elements/updateAnimations.browsertest.d.ts +13 -0
- package/dist/elements/updateAnimations.d.ts +5 -0
- package/dist/elements/updateAnimations.js +37 -13
- package/dist/getRenderInfo.js +1 -1
- package/dist/gui/ContextMixin.js +27 -14
- package/dist/gui/EFControls.browsertest.d.ts +0 -0
- package/dist/gui/EFControls.d.ts +38 -0
- package/dist/gui/EFControls.js +51 -0
- package/dist/gui/EFFilmstrip.d.ts +40 -1
- package/dist/gui/EFFilmstrip.js +240 -3
- package/dist/gui/EFPreview.js +2 -1
- package/dist/gui/EFScrubber.d.ts +6 -5
- package/dist/gui/EFScrubber.js +31 -21
- package/dist/gui/EFTimeDisplay.browsertest.d.ts +0 -0
- package/dist/gui/EFTimeDisplay.d.ts +2 -6
- package/dist/gui/EFTimeDisplay.js +13 -23
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/currentTimeContext.d.ts +3 -0
- package/dist/gui/currentTimeContext.js +3 -0
- package/dist/gui/durationContext.d.ts +3 -0
- package/dist/gui/durationContext.js +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/dist/style.css +1 -1
- package/dist/transcoding/types/index.d.ts +11 -0
- package/dist/utils/LRUCache.d.ts +46 -0
- package/dist/utils/LRUCache.js +382 -1
- package/dist/utils/LRUCache.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/elements/ContextProxiesController.ts +124 -0
- package/src/elements/EFCaptions.browsertest.ts +1820 -0
- package/src/elements/EFCaptions.ts +373 -36
- package/src/elements/EFImage.ts +4 -1
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +30 -1
- package/src/elements/EFMedia/AssetMediaEngine.ts +33 -0
- package/src/elements/EFMedia/BaseMediaEngine.browsertest.ts +3 -8
- package/src/elements/EFMedia/BaseMediaEngine.ts +35 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +34 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +6 -5
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +5 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +8 -5
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +5 -5
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +11 -12
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +7 -4
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +5 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +2 -2
- package/src/elements/EFMedia/shared/GlobalInputCache.ts +77 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +2 -2
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +2 -2
- package/src/elements/EFMedia/shared/ThumbnailExtractor.ts +227 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +1 -1
- package/src/elements/EFMedia.ts +38 -1
- package/src/elements/EFSurface.browsertest.ts +155 -0
- package/src/elements/EFSurface.ts +141 -0
- package/src/elements/EFTemporal.ts +14 -8
- package/src/elements/EFThumbnailStrip.browsertest.ts +591 -0
- package/src/elements/EFThumbnailStrip.media-engine.browsertest.ts +713 -0
- package/src/elements/EFThumbnailStrip.ts +905 -0
- package/src/elements/EFTimegroup.browsertest.ts +56 -7
- package/src/elements/EFTimegroup.ts +88 -16
- package/src/elements/updateAnimations.browsertest.ts +333 -11
- package/src/elements/updateAnimations.ts +68 -19
- package/src/gui/ContextMixin.browsertest.ts +0 -25
- package/src/gui/ContextMixin.ts +44 -20
- package/src/gui/EFControls.browsertest.ts +175 -0
- package/src/gui/EFControls.ts +84 -0
- package/src/gui/EFFilmstrip.ts +323 -4
- package/src/gui/EFPreview.ts +2 -1
- package/src/gui/EFScrubber.ts +29 -25
- package/src/gui/EFTimeDisplay.browsertest.ts +237 -0
- package/src/gui/EFTimeDisplay.ts +12 -40
- package/src/gui/currentTimeContext.ts +5 -0
- package/src/gui/durationContext.ts +3 -0
- package/src/transcoding/types/index.ts +13 -0
- package/src/utils/LRUCache.test.ts +272 -0
- package/src/utils/LRUCache.ts +543 -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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/metadata.json +1 -1
- 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_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -1
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +1 -1
- package/types.json +1 -1
- package/dist/transcoding/cache/CacheManager.d.ts +0 -73
- package/src/transcoding/cache/CacheManager.ts +0 -208
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Context } from '@lit/context';
|
|
2
|
+
import { LitElement, ReactiveController } from 'lit';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for context proxying
|
|
5
|
+
*/
|
|
6
|
+
export type ContextProxyConfig = {
|
|
7
|
+
target: () => HTMLElement | null;
|
|
8
|
+
contexts: Context<any, any>[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A ReactiveController that proxies context requests to a target element.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* @customElement('my-proxy')
|
|
16
|
+
* class MyProxy extends LitElement {
|
|
17
|
+
* @state()
|
|
18
|
+
* targetElement: HTMLElement | null = null;
|
|
19
|
+
*
|
|
20
|
+
* // @ts-expect-error controller is intentionally not referenced directly
|
|
21
|
+
* #contextProxyController = new ContextProxyController(this, {
|
|
22
|
+
* target: () => this.targetElement,
|
|
23
|
+
* contexts: [playingContext, loopContext, targetTimegroupContext]
|
|
24
|
+
* });
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class ContextProxyController implements ReactiveController {
|
|
29
|
+
private host;
|
|
30
|
+
private proxyMap;
|
|
31
|
+
private boundHandler;
|
|
32
|
+
private pendingRequests;
|
|
33
|
+
constructor(host: LitElement, config: ContextProxyConfig);
|
|
34
|
+
hostConnected(): void;
|
|
35
|
+
hostDisconnected(): void;
|
|
36
|
+
hostUpdate(): void;
|
|
37
|
+
private processPendingRequests;
|
|
38
|
+
private handleContextRequest;
|
|
39
|
+
private processContextRequest;
|
|
40
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ContextEvent } from "@lit/context";
|
|
2
|
+
/**
|
|
3
|
+
* A ReactiveController that proxies context requests to a target element.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* @customElement('my-proxy')
|
|
8
|
+
* class MyProxy extends LitElement {
|
|
9
|
+
* @state()
|
|
10
|
+
* targetElement: HTMLElement | null = null;
|
|
11
|
+
*
|
|
12
|
+
* // @ts-expect-error controller is intentionally not referenced directly
|
|
13
|
+
* #contextProxyController = new ContextProxyController(this, {
|
|
14
|
+
* target: () => this.targetElement,
|
|
15
|
+
* contexts: [playingContext, loopContext, targetTimegroupContext]
|
|
16
|
+
* });
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
var ContextProxyController = class {
|
|
21
|
+
constructor(host, config) {
|
|
22
|
+
this.proxyMap = /* @__PURE__ */ new Map();
|
|
23
|
+
this.pendingRequests = [];
|
|
24
|
+
this.host = host;
|
|
25
|
+
this.host.addController(this);
|
|
26
|
+
this.boundHandler = this.handleContextRequest.bind(this);
|
|
27
|
+
for (const context of config.contexts) this.proxyMap.set(context, config.target);
|
|
28
|
+
}
|
|
29
|
+
hostConnected() {
|
|
30
|
+
this.host.addEventListener("context-request", this.boundHandler);
|
|
31
|
+
}
|
|
32
|
+
hostDisconnected() {
|
|
33
|
+
this.host.removeEventListener("context-request", this.boundHandler);
|
|
34
|
+
}
|
|
35
|
+
hostUpdate() {
|
|
36
|
+
this.processPendingRequests();
|
|
37
|
+
}
|
|
38
|
+
processPendingRequests() {
|
|
39
|
+
if (this.pendingRequests.length === 0) return;
|
|
40
|
+
const requestsToProcess = [...this.pendingRequests];
|
|
41
|
+
this.pendingRequests = [];
|
|
42
|
+
for (const contextEvent of requestsToProcess) this.processContextRequest(contextEvent);
|
|
43
|
+
}
|
|
44
|
+
handleContextRequest(event) {
|
|
45
|
+
const contextEvent = event;
|
|
46
|
+
const targetGetter = this.proxyMap.get(contextEvent.context);
|
|
47
|
+
if (targetGetter) {
|
|
48
|
+
contextEvent.stopPropagation();
|
|
49
|
+
const processed = this.processContextRequest(contextEvent);
|
|
50
|
+
if (!processed) this.pendingRequests.push(contextEvent);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
processContextRequest(contextEvent) {
|
|
54
|
+
const targetGetter = this.proxyMap.get(contextEvent.context);
|
|
55
|
+
if (!targetGetter) return false;
|
|
56
|
+
const targetElement = targetGetter();
|
|
57
|
+
if (!targetElement) return false;
|
|
58
|
+
const tempElement = document.createElement("div");
|
|
59
|
+
targetElement.appendChild(tempElement);
|
|
60
|
+
try {
|
|
61
|
+
const newEvent = new ContextEvent(contextEvent.context, contextEvent.callback, contextEvent.subscribe);
|
|
62
|
+
tempElement.dispatchEvent(newEvent);
|
|
63
|
+
return true;
|
|
64
|
+
} finally {
|
|
65
|
+
targetElement.removeChild(tempElement);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
export { ContextProxyController };
|
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
import { Task } from '@lit/task';
|
|
1
|
+
import { Task, TaskStatus } from '@lit/task';
|
|
2
2
|
import { LitElement, PropertyValueMap } from 'lit';
|
|
3
3
|
import { EFAudio } from './EFAudio.js';
|
|
4
4
|
import { EFVideo } from './EFVideo.js';
|
|
5
|
+
export interface WordSegment {
|
|
6
|
+
text: string;
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Segment {
|
|
11
|
+
start: number;
|
|
12
|
+
end: number;
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Caption {
|
|
16
|
+
segments: Segment[];
|
|
17
|
+
word_segments: WordSegment[];
|
|
18
|
+
}
|
|
5
19
|
declare const EFCaptionsActiveWord_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
|
|
6
20
|
export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
7
21
|
static styles: import('lit').CSSResult[];
|
|
@@ -9,8 +23,10 @@ export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
|
9
23
|
wordStartMs: number;
|
|
10
24
|
wordEndMs: number;
|
|
11
25
|
wordText: string;
|
|
26
|
+
wordIndex: number;
|
|
12
27
|
hidden: boolean;
|
|
13
28
|
get startTimeMs(): number;
|
|
29
|
+
get endTimeMs(): number;
|
|
14
30
|
get durationMs(): number;
|
|
15
31
|
}
|
|
16
32
|
declare const EFCaptionsSegment_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
|
|
@@ -22,6 +38,7 @@ export declare class EFCaptionsSegment extends EFCaptionsSegment_base {
|
|
|
22
38
|
segmentText: string;
|
|
23
39
|
hidden: boolean;
|
|
24
40
|
get startTimeMs(): number;
|
|
41
|
+
get endTimeMs(): number;
|
|
25
42
|
get durationMs(): number;
|
|
26
43
|
}
|
|
27
44
|
export declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
@@ -32,6 +49,7 @@ export declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
|
32
49
|
segmentStartMs: number;
|
|
33
50
|
segmentEndMs: number;
|
|
34
51
|
get startTimeMs(): number;
|
|
52
|
+
get endTimeMs(): number;
|
|
35
53
|
get durationMs(): number;
|
|
36
54
|
}
|
|
37
55
|
export declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
@@ -42,6 +60,7 @@ export declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
|
42
60
|
segmentStartMs: number;
|
|
43
61
|
segmentEndMs: number;
|
|
44
62
|
get startTimeMs(): number;
|
|
63
|
+
get endTimeMs(): number;
|
|
45
64
|
get durationMs(): number;
|
|
46
65
|
}
|
|
47
66
|
declare const EFCaptions_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
|
|
@@ -52,23 +71,43 @@ export declare class EFCaptions extends EFCaptions_base {
|
|
|
52
71
|
targetSelector: string;
|
|
53
72
|
set target(value: string);
|
|
54
73
|
wordStyle: string;
|
|
74
|
+
/**
|
|
75
|
+
* URL or path to a JSON file containing custom captions data.
|
|
76
|
+
* The JSON should conform to the Caption interface with 'segments' and 'word_segments' arrays.
|
|
77
|
+
*/
|
|
78
|
+
captionsSrc: string;
|
|
79
|
+
/**
|
|
80
|
+
* Direct captions data object. Takes priority over captions-src and captions-script.
|
|
81
|
+
* Should conform to the Caption interface with 'segments' and 'word_segments' arrays.
|
|
82
|
+
*/
|
|
83
|
+
captionsData: Caption | null;
|
|
84
|
+
/**
|
|
85
|
+
* ID of a <script> element containing JSON captions data.
|
|
86
|
+
* The script's textContent should be valid JSON conforming to the Caption interface.
|
|
87
|
+
*/
|
|
88
|
+
captionsScript: string;
|
|
55
89
|
activeWordContainers: HTMLCollectionOf<EFCaptionsActiveWord>;
|
|
56
90
|
segmentContainers: HTMLCollectionOf<EFCaptionsSegment>;
|
|
57
91
|
beforeActiveWordContainers: HTMLCollectionOf<EFCaptionsBeforeActiveWord>;
|
|
58
92
|
afterActiveWordContainers: HTMLCollectionOf<EFCaptionsAfterActiveWord>;
|
|
59
93
|
render(): import('lit-html').TemplateResult<1>;
|
|
60
94
|
transcriptionsPath(): string | null;
|
|
61
|
-
captionsPath(): string;
|
|
62
|
-
protected md5SumLoader: Task<readonly [string, typeof fetch], string | undefined>;
|
|
95
|
+
captionsPath(): string | null;
|
|
96
|
+
protected md5SumLoader: Task<readonly [string, typeof fetch], string | null | undefined>;
|
|
63
97
|
private transcriptionDataTask;
|
|
64
98
|
private transcriptionFragmentPath;
|
|
65
99
|
private fragmentIndexTask;
|
|
100
|
+
private customCaptionsDataTask;
|
|
66
101
|
private transcriptionFragmentDataTask;
|
|
67
|
-
|
|
102
|
+
unifiedCaptionsDataTask: Task<readonly [Caption | null | undefined, Caption | null | undefined], Caption | null | undefined>;
|
|
103
|
+
frameTask: Task<TaskStatus[], void>;
|
|
68
104
|
connectedCallback(): void;
|
|
69
|
-
protected updated(
|
|
105
|
+
protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
|
70
106
|
updateTextContainers(): void;
|
|
71
|
-
get targetElement(): EFAudio | EFVideo;
|
|
107
|
+
get targetElement(): EFAudio | EFVideo | null;
|
|
108
|
+
get hasCustomCaptionsData(): boolean;
|
|
109
|
+
get intrinsicDurationMs(): number | undefined;
|
|
110
|
+
get hasOwnDuration(): boolean;
|
|
72
111
|
}
|
|
73
112
|
declare global {
|
|
74
113
|
interface HTMLElementTagNameMap {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
2
2
|
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
3
|
-
import { EFTemporal } from "./EFTemporal.js";
|
|
3
|
+
import { EFTemporal, flushStartTimeMsCache } from "./EFTemporal.js";
|
|
4
4
|
import { FetchMixin } from "./FetchMixin.js";
|
|
5
|
+
import { flushSequenceDurationCache } from "./EFTimegroup.js";
|
|
5
6
|
import { EFAudio } from "./EFAudio.js";
|
|
6
7
|
import { EFVideo } from "./EFVideo.js";
|
|
7
8
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
8
|
-
import { Task } from "@lit/task";
|
|
9
|
+
import { Task, TaskStatus } from "@lit/task";
|
|
9
10
|
import { LitElement, css, html } from "lit";
|
|
10
11
|
import { customElement, property } from "lit/decorators.js";
|
|
11
12
|
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
@@ -22,6 +23,7 @@ let EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitEl
|
|
|
22
23
|
this.wordStartMs = 0;
|
|
23
24
|
this.wordEndMs = 0;
|
|
24
25
|
this.wordText = "";
|
|
26
|
+
this.wordIndex = 0;
|
|
25
27
|
this.hidden = false;
|
|
26
28
|
}
|
|
27
29
|
static {
|
|
@@ -29,6 +31,7 @@ let EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitEl
|
|
|
29
31
|
:host {
|
|
30
32
|
display: inline-block;
|
|
31
33
|
white-space: pre;
|
|
34
|
+
transform-origin: center;
|
|
32
35
|
}
|
|
33
36
|
:host([hidden]) {
|
|
34
37
|
display: none;
|
|
@@ -41,10 +44,20 @@ let EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitEl
|
|
|
41
44
|
return void 0;
|
|
42
45
|
}
|
|
43
46
|
this.hidden = false;
|
|
47
|
+
const seed = this.wordIndex * 9007 % 233;
|
|
48
|
+
const seedValue = seed / 233;
|
|
49
|
+
this.style.setProperty("--ef-word-seed", seedValue.toString());
|
|
44
50
|
return html` ${this.wordText.trim()} `;
|
|
45
51
|
}
|
|
46
52
|
get startTimeMs() {
|
|
47
|
-
|
|
53
|
+
const parentCaptions = this.closest("ef-captions");
|
|
54
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
55
|
+
return parentStartTime + (this.wordStartMs || 0);
|
|
56
|
+
}
|
|
57
|
+
get endTimeMs() {
|
|
58
|
+
const parentCaptions = this.closest("ef-captions");
|
|
59
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
60
|
+
return parentStartTime + (this.wordEndMs || 0);
|
|
48
61
|
}
|
|
49
62
|
get durationMs() {
|
|
50
63
|
return this.wordEndMs - this.wordStartMs;
|
|
@@ -62,6 +75,10 @@ _decorate([property({
|
|
|
62
75
|
type: String,
|
|
63
76
|
attribute: false
|
|
64
77
|
})], EFCaptionsActiveWord.prototype, "wordText", void 0);
|
|
78
|
+
_decorate([property({
|
|
79
|
+
type: Number,
|
|
80
|
+
attribute: false
|
|
81
|
+
})], EFCaptionsActiveWord.prototype, "wordIndex", void 0);
|
|
65
82
|
_decorate([property({
|
|
66
83
|
type: Boolean,
|
|
67
84
|
reflect: true
|
|
@@ -94,7 +111,14 @@ let EFCaptionsSegment = class EFCaptionsSegment$1 extends EFTemporal(LitElement)
|
|
|
94
111
|
return html`${this.segmentText}`;
|
|
95
112
|
}
|
|
96
113
|
get startTimeMs() {
|
|
97
|
-
|
|
114
|
+
const parentCaptions = this.closest("ef-captions");
|
|
115
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
116
|
+
return parentStartTime + (this.segmentStartMs || 0);
|
|
117
|
+
}
|
|
118
|
+
get endTimeMs() {
|
|
119
|
+
const parentCaptions = this.closest("ef-captions");
|
|
120
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
121
|
+
return parentStartTime + (this.segmentEndMs || 0);
|
|
98
122
|
}
|
|
99
123
|
get durationMs() {
|
|
100
124
|
return this.segmentEndMs - this.segmentStartMs;
|
|
@@ -145,7 +169,14 @@ let EFCaptionsBeforeActiveWord = class EFCaptionsBeforeActiveWord$1 extends EFCa
|
|
|
145
169
|
return html` ${this.segmentText}`;
|
|
146
170
|
}
|
|
147
171
|
get startTimeMs() {
|
|
148
|
-
|
|
172
|
+
const parentCaptions = this.closest("ef-captions");
|
|
173
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
174
|
+
return parentStartTime + (this.segmentStartMs || 0);
|
|
175
|
+
}
|
|
176
|
+
get endTimeMs() {
|
|
177
|
+
const parentCaptions = this.closest("ef-captions");
|
|
178
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
179
|
+
return parentStartTime + (this.segmentEndMs || 0);
|
|
149
180
|
}
|
|
150
181
|
get durationMs() {
|
|
151
182
|
return this.segmentEndMs - this.segmentStartMs;
|
|
@@ -196,7 +227,14 @@ let EFCaptionsAfterActiveWord = class EFCaptionsAfterActiveWord$1 extends EFCapt
|
|
|
196
227
|
return html`${this.segmentText} `;
|
|
197
228
|
}
|
|
198
229
|
get startTimeMs() {
|
|
199
|
-
|
|
230
|
+
const parentCaptions = this.closest("ef-captions");
|
|
231
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
232
|
+
return parentStartTime + (this.segmentStartMs || 0);
|
|
233
|
+
}
|
|
234
|
+
get endTimeMs() {
|
|
235
|
+
const parentCaptions = this.closest("ef-captions");
|
|
236
|
+
const parentStartTime = parentCaptions?.startTimeMs || 0;
|
|
237
|
+
return parentStartTime + (this.segmentEndMs || 0);
|
|
200
238
|
}
|
|
201
239
|
get durationMs() {
|
|
202
240
|
return this.segmentEndMs - this.segmentStartMs;
|
|
@@ -226,6 +264,9 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
226
264
|
this.contextWords = 3;
|
|
227
265
|
this.targetSelector = "";
|
|
228
266
|
this.wordStyle = "";
|
|
267
|
+
this.captionsSrc = "";
|
|
268
|
+
this.captionsData = null;
|
|
269
|
+
this.captionsScript = "";
|
|
229
270
|
this.activeWordContainers = this.getElementsByTagName("ef-captions-active-word");
|
|
230
271
|
this.segmentContainers = this.getElementsByTagName("ef-captions-segment");
|
|
231
272
|
this.beforeActiveWordContainers = this.getElementsByTagName("ef-captions-before-active-word");
|
|
@@ -234,6 +275,7 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
234
275
|
autoRun: false,
|
|
235
276
|
args: () => [this.target, this.fetch],
|
|
236
277
|
task: async ([_target, fetch], { signal }) => {
|
|
278
|
+
if (!this.targetElement) return null;
|
|
237
279
|
const md5Path = `/@ef-asset/${this.targetElement.src ?? ""}`;
|
|
238
280
|
const response = await fetch(md5Path, {
|
|
239
281
|
method: "HEAD",
|
|
@@ -244,9 +286,13 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
244
286
|
});
|
|
245
287
|
this.transcriptionDataTask = new Task(this, {
|
|
246
288
|
autoRun: EF_INTERACTIVE,
|
|
247
|
-
args: () => [
|
|
248
|
-
|
|
249
|
-
|
|
289
|
+
args: () => [
|
|
290
|
+
this.transcriptionsPath(),
|
|
291
|
+
this.fetch,
|
|
292
|
+
this.hasCustomCaptionsData
|
|
293
|
+
],
|
|
294
|
+
task: async ([transcriptionsPath, fetch, hasCustomData], { signal }) => {
|
|
295
|
+
if (hasCustomData || !transcriptionsPath) return null;
|
|
250
296
|
const response = await fetch(transcriptionsPath, { signal });
|
|
251
297
|
return response.json();
|
|
252
298
|
}
|
|
@@ -260,6 +306,35 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
260
306
|
return fragmentIndex;
|
|
261
307
|
}
|
|
262
308
|
});
|
|
309
|
+
this.customCaptionsDataTask = new Task(this, {
|
|
310
|
+
autoRun: EF_INTERACTIVE,
|
|
311
|
+
args: () => [
|
|
312
|
+
this.captionsSrc,
|
|
313
|
+
this.captionsData,
|
|
314
|
+
this.captionsScript,
|
|
315
|
+
this.fetch
|
|
316
|
+
],
|
|
317
|
+
task: async ([captionsSrc, captionsData, captionsScript, fetch], { signal }) => {
|
|
318
|
+
if (captionsData) return captionsData;
|
|
319
|
+
if (captionsScript) {
|
|
320
|
+
const scriptElement = document.getElementById(captionsScript);
|
|
321
|
+
if (scriptElement?.textContent) try {
|
|
322
|
+
return JSON.parse(scriptElement.textContent);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error(`Failed to parse captions from script #${captionsScript}:`, error);
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (captionsSrc) try {
|
|
329
|
+
const response = await fetch(captionsSrc, { signal });
|
|
330
|
+
return await response.json();
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.error(`Failed to load captions from ${captionsSrc}:`, error);
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
263
338
|
this.transcriptionFragmentDataTask = new Task(this, {
|
|
264
339
|
autoRun: EF_INTERACTIVE,
|
|
265
340
|
args: () => [
|
|
@@ -274,26 +349,43 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
274
349
|
return response.json();
|
|
275
350
|
}
|
|
276
351
|
});
|
|
352
|
+
this.unifiedCaptionsDataTask = new Task(this, {
|
|
353
|
+
autoRun: EF_INTERACTIVE,
|
|
354
|
+
args: () => [this.customCaptionsDataTask.value, this.transcriptionFragmentDataTask.value],
|
|
355
|
+
task: async ([_customData, _transcriptionData]) => {
|
|
356
|
+
if (this.customCaptionsDataTask.status === TaskStatus.PENDING) await this.customCaptionsDataTask.taskComplete;
|
|
357
|
+
if (this.transcriptionFragmentDataTask.status === TaskStatus.PENDING) await this.transcriptionFragmentDataTask.taskComplete;
|
|
358
|
+
return this.customCaptionsDataTask.value || this.transcriptionFragmentDataTask.value;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
277
361
|
this.frameTask = new Task(this, {
|
|
278
362
|
autoRun: EF_INTERACTIVE,
|
|
279
|
-
args: () => [this.
|
|
363
|
+
args: () => [this.unifiedCaptionsDataTask.status],
|
|
280
364
|
task: async () => {
|
|
281
|
-
await this.
|
|
365
|
+
await this.unifiedCaptionsDataTask.taskComplete;
|
|
282
366
|
}
|
|
283
367
|
});
|
|
284
368
|
}
|
|
285
369
|
static {
|
|
286
370
|
this.styles = [css`
|
|
287
371
|
:host {
|
|
288
|
-
display: flex;
|
|
289
|
-
flex-wrap: wrap;
|
|
290
|
-
align-items: baseline;
|
|
372
|
+
display: inline-flex;
|
|
291
373
|
width: fit-content;
|
|
374
|
+
align-items: baseline;
|
|
292
375
|
}
|
|
293
376
|
::slotted(*) {
|
|
294
377
|
margin: 0;
|
|
295
378
|
padding: 0;
|
|
296
379
|
}
|
|
380
|
+
::slotted(ef-captions-active-word) {
|
|
381
|
+
min-width: 0.5ch; /* Maintain minimum width when empty */
|
|
382
|
+
min-height: 1em; /* Maintain height for baseline alignment */
|
|
383
|
+
}
|
|
384
|
+
::slotted(ef-captions-active-word[hidden]) {
|
|
385
|
+
opacity: 0; /* Hide when empty but maintain layout */
|
|
386
|
+
min-width: 0.5ch;
|
|
387
|
+
min-height: 1em;
|
|
388
|
+
}
|
|
297
389
|
`];
|
|
298
390
|
}
|
|
299
391
|
set target(value) {
|
|
@@ -303,10 +395,12 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
303
395
|
return html`<slot></slot>`;
|
|
304
396
|
}
|
|
305
397
|
transcriptionsPath() {
|
|
398
|
+
if (!this.targetElement) return null;
|
|
306
399
|
if (this.targetElement.assetId) return `${this.apiHost}/api/v1/isobmff_files/${this.targetElement.assetId}/transcription`;
|
|
307
400
|
return null;
|
|
308
401
|
}
|
|
309
402
|
captionsPath() {
|
|
403
|
+
if (!this.targetElement) return null;
|
|
310
404
|
if (this.targetElement.assetId) return `${this.apiHost}/api/v1/caption_files/${this.targetElement.assetId}`;
|
|
311
405
|
const targetSrc = this.targetElement.src;
|
|
312
406
|
return `/@ef-captions/${targetSrc}`;
|
|
@@ -316,51 +410,137 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
316
410
|
}
|
|
317
411
|
connectedCallback() {
|
|
318
412
|
super.connectedCallback();
|
|
319
|
-
|
|
413
|
+
const target = this.targetSelector ? document.getElementById(this.targetSelector) : null;
|
|
414
|
+
if (target && (target instanceof EFAudio || target instanceof EFVideo)) new CrossUpdateController(target, this);
|
|
415
|
+
else if (this.hasCustomCaptionsData && this.rootTimegroup) new CrossUpdateController(this.rootTimegroup, this);
|
|
320
416
|
}
|
|
321
|
-
updated(
|
|
417
|
+
updated(changedProperties) {
|
|
322
418
|
this.updateTextContainers();
|
|
419
|
+
if (changedProperties.has("captionsData") || changedProperties.has("captionsSrc") || changedProperties.has("captionsScript")) {
|
|
420
|
+
this.requestUpdate("intrinsicDurationMs");
|
|
421
|
+
flushSequenceDurationCache();
|
|
422
|
+
flushStartTimeMsCache();
|
|
423
|
+
if (this.parentTimegroup) {
|
|
424
|
+
this.parentTimegroup.requestUpdate("durationMs");
|
|
425
|
+
this.parentTimegroup.requestUpdate("currentTime");
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (changedProperties.has("ownCurrentTimeMs")) this.updateTextContainers();
|
|
323
429
|
}
|
|
324
430
|
updateTextContainers() {
|
|
325
|
-
const
|
|
326
|
-
if (!
|
|
327
|
-
const currentTimeMs = this.targetElement.currentSourceTimeMs;
|
|
431
|
+
const captionsData = this.unifiedCaptionsDataTask.value;
|
|
432
|
+
if (!captionsData) return;
|
|
433
|
+
const currentTimeMs = this.targetElement ? this.targetElement.currentSourceTimeMs : this.ownCurrentTimeMs;
|
|
328
434
|
const currentTimeSec = currentTimeMs / 1e3;
|
|
329
|
-
const currentWord =
|
|
330
|
-
const currentSegment =
|
|
435
|
+
const currentWord = captionsData.word_segments.find((word) => currentTimeSec >= word.start && currentTimeSec < word.end);
|
|
436
|
+
const currentSegment = captionsData.segments.find((segment) => currentTimeSec >= segment.start && currentTimeSec < segment.end);
|
|
331
437
|
for (const wordContainer of this.activeWordContainers) if (currentWord) {
|
|
332
438
|
wordContainer.wordText = currentWord.text;
|
|
333
439
|
wordContainer.wordStartMs = currentWord.start * 1e3;
|
|
334
440
|
wordContainer.wordEndMs = currentWord.end * 1e3;
|
|
441
|
+
const wordIndex = captionsData.word_segments.findIndex((w) => w.start === currentWord.start && w.end === currentWord.end && w.text === currentWord.text);
|
|
442
|
+
wordContainer.wordIndex = wordIndex >= 0 ? wordIndex : 0;
|
|
443
|
+
wordContainer.requestUpdate();
|
|
444
|
+
} else {
|
|
445
|
+
wordContainer.wordText = "";
|
|
446
|
+
wordContainer.wordStartMs = 0;
|
|
447
|
+
wordContainer.wordEndMs = 0;
|
|
448
|
+
wordContainer.requestUpdate();
|
|
335
449
|
}
|
|
336
450
|
for (const segmentContainer of this.segmentContainers) if (currentSegment) {
|
|
337
451
|
segmentContainer.segmentText = currentSegment.text;
|
|
338
452
|
segmentContainer.segmentStartMs = currentSegment.start * 1e3;
|
|
339
453
|
segmentContainer.segmentEndMs = currentSegment.end * 1e3;
|
|
454
|
+
} else {
|
|
455
|
+
segmentContainer.segmentText = "";
|
|
456
|
+
segmentContainer.segmentStartMs = 0;
|
|
457
|
+
segmentContainer.segmentEndMs = 0;
|
|
340
458
|
}
|
|
341
459
|
if (currentWord && currentSegment) {
|
|
342
|
-
const segmentWords =
|
|
460
|
+
const segmentWords = captionsData.word_segments.filter((word) => word.start >= currentSegment.start && word.end <= currentSegment.end);
|
|
343
461
|
const currentWordIndex = segmentWords.findIndex((word) => word.start === currentWord.start && word.end === currentWord.end);
|
|
344
462
|
if (currentWordIndex !== -1) {
|
|
345
463
|
const beforeWords = segmentWords.slice(0, currentWordIndex).map((w) => w.text.trim()).join(" ");
|
|
346
464
|
const afterWords = segmentWords.slice(currentWordIndex + 1).map((w) => w.text.trim()).join(" ");
|
|
347
465
|
for (const container of this.beforeActiveWordContainers) {
|
|
348
466
|
container.segmentText = beforeWords;
|
|
349
|
-
container.segmentStartMs =
|
|
350
|
-
container.segmentEndMs = currentWord.
|
|
467
|
+
container.segmentStartMs = currentWord.start * 1e3;
|
|
468
|
+
container.segmentEndMs = currentWord.end * 1e3;
|
|
351
469
|
}
|
|
352
470
|
for (const container of this.afterActiveWordContainers) {
|
|
353
471
|
container.segmentText = afterWords;
|
|
354
|
-
container.segmentStartMs = currentWord.
|
|
472
|
+
container.segmentStartMs = currentWord.start * 1e3;
|
|
473
|
+
container.segmentEndMs = currentWord.end * 1e3;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
} else if (currentSegment) {
|
|
477
|
+
const segmentWords = captionsData.word_segments.filter((word) => word.start >= currentSegment.start && word.end <= currentSegment.end);
|
|
478
|
+
const firstWord = segmentWords[0];
|
|
479
|
+
const isBeforeFirstWord = firstWord && currentTimeSec < firstWord.start;
|
|
480
|
+
if (isBeforeFirstWord) {
|
|
481
|
+
const allWords = segmentWords.map((w) => w.text.trim()).join(" ");
|
|
482
|
+
for (const container of this.beforeActiveWordContainers) {
|
|
483
|
+
container.segmentText = "";
|
|
484
|
+
container.segmentStartMs = currentSegment.start * 1e3;
|
|
485
|
+
container.segmentEndMs = currentSegment.end * 1e3;
|
|
486
|
+
}
|
|
487
|
+
for (const container of this.afterActiveWordContainers) {
|
|
488
|
+
container.segmentText = allWords;
|
|
489
|
+
container.segmentStartMs = currentSegment.start * 1e3;
|
|
490
|
+
container.segmentEndMs = currentSegment.end * 1e3;
|
|
491
|
+
}
|
|
492
|
+
} else {
|
|
493
|
+
const allCompletedWords = segmentWords.map((w) => w.text.trim()).join(" ");
|
|
494
|
+
for (const container of this.beforeActiveWordContainers) {
|
|
495
|
+
container.segmentText = allCompletedWords;
|
|
496
|
+
container.segmentStartMs = currentSegment.start * 1e3;
|
|
497
|
+
container.segmentEndMs = currentSegment.end * 1e3;
|
|
498
|
+
}
|
|
499
|
+
for (const container of this.afterActiveWordContainers) {
|
|
500
|
+
container.segmentText = "";
|
|
501
|
+
container.segmentStartMs = currentSegment.start * 1e3;
|
|
355
502
|
container.segmentEndMs = currentSegment.end * 1e3;
|
|
356
503
|
}
|
|
357
504
|
}
|
|
505
|
+
} else {
|
|
506
|
+
for (const container of this.beforeActiveWordContainers) {
|
|
507
|
+
container.segmentText = "";
|
|
508
|
+
container.segmentStartMs = 0;
|
|
509
|
+
container.segmentEndMs = 0;
|
|
510
|
+
}
|
|
511
|
+
for (const container of this.afterActiveWordContainers) {
|
|
512
|
+
container.segmentText = "";
|
|
513
|
+
container.segmentStartMs = 0;
|
|
514
|
+
container.segmentEndMs = 0;
|
|
515
|
+
}
|
|
358
516
|
}
|
|
359
517
|
}
|
|
360
518
|
get targetElement() {
|
|
361
519
|
const target = document.getElementById(this.targetSelector ?? "");
|
|
362
520
|
if (target instanceof EFAudio || target instanceof EFVideo) return target;
|
|
363
|
-
|
|
521
|
+
if (this.hasCustomCaptionsData) return null;
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
get hasCustomCaptionsData() {
|
|
525
|
+
return !!(this.captionsData || this.captionsSrc || this.captionsScript);
|
|
526
|
+
}
|
|
527
|
+
get intrinsicDurationMs() {
|
|
528
|
+
let captionsData = null;
|
|
529
|
+
if (this.captionsData) captionsData = this.captionsData;
|
|
530
|
+
else if (this.captionsScript) {
|
|
531
|
+
const scriptElement = document.getElementById(this.captionsScript);
|
|
532
|
+
if (scriptElement?.textContent) try {
|
|
533
|
+
captionsData = JSON.parse(scriptElement.textContent);
|
|
534
|
+
} catch {}
|
|
535
|
+
} else if (this.customCaptionsDataTask.value) captionsData = this.customCaptionsDataTask.value;
|
|
536
|
+
if (!captionsData) return void 0;
|
|
537
|
+
if (captionsData.segments.length === 0 && captionsData.word_segments.length === 0) return 0;
|
|
538
|
+
const maxSegmentEnd = captionsData.segments.length > 0 ? Math.max(...captionsData.segments.map((s) => s.end)) : 0;
|
|
539
|
+
const maxWordEnd = captionsData.word_segments.length > 0 ? Math.max(...captionsData.word_segments.map((w) => w.end)) : 0;
|
|
540
|
+
return Math.max(maxSegmentEnd, maxWordEnd) * 1e3;
|
|
541
|
+
}
|
|
542
|
+
get hasOwnDuration() {
|
|
543
|
+
return !!(this.captionsData || this.captionsScript || this.customCaptionsDataTask.value);
|
|
364
544
|
}
|
|
365
545
|
};
|
|
366
546
|
_decorate([property({
|
|
@@ -379,5 +559,19 @@ _decorate([property({
|
|
|
379
559
|
reflect: true
|
|
380
560
|
})], EFCaptions.prototype, "targetSelector", void 0);
|
|
381
561
|
_decorate([property({ attribute: "word-style" })], EFCaptions.prototype, "wordStyle", void 0);
|
|
562
|
+
_decorate([property({
|
|
563
|
+
type: String,
|
|
564
|
+
attribute: "captions-src",
|
|
565
|
+
reflect: true
|
|
566
|
+
})], EFCaptions.prototype, "captionsSrc", void 0);
|
|
567
|
+
_decorate([property({
|
|
568
|
+
type: Object,
|
|
569
|
+
attribute: false
|
|
570
|
+
})], EFCaptions.prototype, "captionsData", void 0);
|
|
571
|
+
_decorate([property({
|
|
572
|
+
type: String,
|
|
573
|
+
attribute: "captions-script",
|
|
574
|
+
reflect: true
|
|
575
|
+
})], EFCaptions.prototype, "captionsScript", void 0);
|
|
382
576
|
EFCaptions = _decorate([customElement("ef-captions")], EFCaptions);
|
|
383
577
|
export { EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment };
|
package/dist/elements/EFImage.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TrackFragmentIndex } from '../../../../assets/src/index.ts';
|
|
2
|
-
import { InitSegmentPaths, MediaEngine } from '../../transcoding/types';
|
|
2
|
+
import { InitSegmentPaths, MediaEngine, VideoRendition } from '../../transcoding/types';
|
|
3
3
|
import { UrlGenerator } from '../../transcoding/utils/UrlGenerator';
|
|
4
4
|
import { EFMedia } from '../EFMedia';
|
|
5
5
|
import { AssetMediaEngine } from './AssetMediaEngine';
|
|
@@ -15,4 +15,5 @@ export declare class AssetIdMediaEngine extends AssetMediaEngine implements Medi
|
|
|
15
15
|
};
|
|
16
16
|
buildInitSegmentUrl(trackId: number): string;
|
|
17
17
|
buildMediaSegmentUrl(trackId: number, _segmentId: number): string;
|
|
18
|
+
convertToSegmentRelativeTimestamps(globalTimestamps: number[], segmentId: number, rendition: VideoRendition): number[];
|
|
18
19
|
}
|
|
@@ -40,5 +40,14 @@ var AssetIdMediaEngine = class AssetIdMediaEngine extends AssetMediaEngine {
|
|
|
40
40
|
buildMediaSegmentUrl(trackId, _segmentId) {
|
|
41
41
|
return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;
|
|
42
42
|
}
|
|
43
|
+
convertToSegmentRelativeTimestamps(globalTimestamps, segmentId, rendition) {
|
|
44
|
+
if (!rendition.trackId) throw new Error("Track ID is required for asset metadata");
|
|
45
|
+
const trackData = this.data[rendition.trackId];
|
|
46
|
+
if (!trackData) throw new Error("Track not found");
|
|
47
|
+
const segment = trackData.segments?.[segmentId];
|
|
48
|
+
if (!segment) throw new Error("Segment not found");
|
|
49
|
+
const segmentStartMs = segment.cts / trackData.timescale * 1e3;
|
|
50
|
+
return globalTimestamps.map((globalMs) => (globalMs - segmentStartMs) / 1e3);
|
|
51
|
+
}
|
|
43
52
|
};
|
|
44
53
|
export { AssetIdMediaEngine };
|
|
@@ -52,4 +52,5 @@ export declare class AssetMediaEngine extends BaseMediaEngine implements MediaEn
|
|
|
52
52
|
maxVideoBufferFetches: number;
|
|
53
53
|
maxAudioBufferFetches: number;
|
|
54
54
|
};
|
|
55
|
+
convertToSegmentRelativeTimestamps(globalTimestamps: number[], segmentId: number, rendition: VideoRendition): number[];
|
|
55
56
|
}
|