@editframe/elements 0.11.0-beta.9 → 0.12.0-beta.10
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/EF_FRAMEGEN.d.ts +8 -15
- package/dist/assets/src/MP4File.js +73 -20
- package/dist/elements/EFCaptions.d.ts +50 -6
- package/dist/elements/EFMedia.d.ts +1 -2
- package/dist/elements/EFTimegroup.browsertest.d.ts +4 -0
- package/dist/elements/EFTimegroup.d.ts +23 -2
- package/dist/elements/EFWaveform.d.ts +15 -11
- package/dist/elements/src/EF_FRAMEGEN.js +24 -26
- package/dist/elements/src/elements/EFCaptions.js +295 -42
- package/dist/elements/src/elements/EFImage.js +0 -6
- package/dist/elements/src/elements/EFMedia.js +70 -18
- package/dist/elements/src/elements/EFTemporal.js +13 -10
- package/dist/elements/src/elements/EFTimegroup.js +37 -12
- package/dist/elements/src/elements/EFVideo.js +1 -4
- package/dist/elements/src/elements/EFWaveform.js +250 -143
- package/dist/elements/src/gui/ContextMixin.js +44 -11
- package/dist/elements/src/gui/EFPreview.js +3 -1
- package/dist/elements/src/gui/EFScrubber.js +142 -0
- package/dist/elements/src/gui/EFTimeDisplay.js +81 -0
- package/dist/elements/src/gui/EFTogglePlay.js +11 -19
- package/dist/elements/src/gui/EFWorkbench.js +1 -24
- package/dist/elements/src/gui/TWMixin.css.js +1 -1
- package/dist/elements/src/index.js +8 -1
- package/dist/gui/ContextMixin.d.ts +2 -1
- package/dist/gui/EFScrubber.d.ts +23 -0
- package/dist/gui/EFTimeDisplay.d.ts +17 -0
- package/dist/gui/EFTogglePlay.d.ts +0 -2
- package/dist/gui/EFWorkbench.d.ts +0 -1
- package/dist/index.d.ts +3 -1
- package/dist/style.css +6 -801
- package/package.json +2 -2
- package/src/elements/EFCaptions.browsertest.ts +6 -6
- package/src/elements/EFCaptions.ts +325 -56
- package/src/elements/EFImage.browsertest.ts +4 -17
- package/src/elements/EFImage.ts +0 -6
- package/src/elements/EFMedia.browsertest.ts +10 -19
- package/src/elements/EFMedia.ts +87 -20
- package/src/elements/EFTemporal.browsertest.ts +14 -0
- package/src/elements/EFTemporal.ts +14 -0
- package/src/elements/EFTimegroup.browsertest.ts +37 -0
- package/src/elements/EFTimegroup.ts +42 -17
- package/src/elements/EFVideo.ts +1 -4
- package/src/elements/EFWaveform.ts +339 -314
- package/src/gui/ContextMixin.browsertest.ts +28 -2
- package/src/gui/ContextMixin.ts +52 -14
- package/src/gui/EFPreview.ts +4 -2
- package/src/gui/EFScrubber.ts +145 -0
- package/src/gui/EFTimeDisplay.ts +81 -0
- package/src/gui/EFTogglePlay.ts +19 -25
- package/src/gui/EFWorkbench.ts +3 -36
- package/dist/elements/src/elements/util.js +0 -11
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { html, css, LitElement } from "lit";
|
|
2
1
|
import { Task } from "@lit/task";
|
|
2
|
+
import { html, css, LitElement } from "lit";
|
|
3
3
|
import { property, customElement } from "lit/decorators.js";
|
|
4
|
-
import {
|
|
4
|
+
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
5
|
+
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
6
|
+
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
5
7
|
import { EFAudio } from "./EFAudio.js";
|
|
8
|
+
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
6
9
|
import { EFTemporal } from "./EFTemporal.js";
|
|
7
|
-
import {
|
|
10
|
+
import { EFVideo } from "./EFVideo.js";
|
|
8
11
|
import { FetchMixin } from "./FetchMixin.js";
|
|
9
|
-
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
10
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
11
|
-
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
12
12
|
var __defProp = Object.defineProperty;
|
|
13
13
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
14
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -19,15 +19,22 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
19
19
|
if (kind && result) __defProp(target, key, result);
|
|
20
20
|
return result;
|
|
21
21
|
};
|
|
22
|
+
const stopWords = /* @__PURE__ */ new Set(["", ".", "!", "?", ","]);
|
|
22
23
|
let EFCaptionsActiveWord = class extends EFTemporal(LitElement) {
|
|
23
24
|
constructor() {
|
|
24
25
|
super(...arguments);
|
|
25
26
|
this.wordStartMs = 0;
|
|
26
27
|
this.wordEndMs = 0;
|
|
27
28
|
this.wordText = "";
|
|
29
|
+
this.hidden = false;
|
|
28
30
|
}
|
|
29
31
|
render() {
|
|
30
|
-
|
|
32
|
+
if (stopWords.has(this.wordText)) {
|
|
33
|
+
this.hidden = true;
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
this.hidden = false;
|
|
37
|
+
return html` ${this.wordText.trim()} `;
|
|
31
38
|
}
|
|
32
39
|
get startTimeMs() {
|
|
33
40
|
return this.wordStartMs || 0;
|
|
@@ -40,6 +47,10 @@ EFCaptionsActiveWord.styles = [
|
|
|
40
47
|
css`
|
|
41
48
|
:host {
|
|
42
49
|
display: inline-block;
|
|
50
|
+
white-space: pre;
|
|
51
|
+
}
|
|
52
|
+
:host([hidden]) {
|
|
53
|
+
display: none;
|
|
43
54
|
}
|
|
44
55
|
`
|
|
45
56
|
];
|
|
@@ -52,18 +63,176 @@ __decorateClass([
|
|
|
52
63
|
__decorateClass([
|
|
53
64
|
property({ type: String, attribute: false })
|
|
54
65
|
], EFCaptionsActiveWord.prototype, "wordText", 2);
|
|
66
|
+
__decorateClass([
|
|
67
|
+
property({ type: Boolean, reflect: true })
|
|
68
|
+
], EFCaptionsActiveWord.prototype, "hidden", 2);
|
|
55
69
|
EFCaptionsActiveWord = __decorateClass([
|
|
56
70
|
customElement("ef-captions-active-word")
|
|
57
71
|
], EFCaptionsActiveWord);
|
|
72
|
+
let EFCaptionsSegment = class extends EFTemporal(LitElement) {
|
|
73
|
+
constructor() {
|
|
74
|
+
super(...arguments);
|
|
75
|
+
this.segmentStartMs = 0;
|
|
76
|
+
this.segmentEndMs = 0;
|
|
77
|
+
this.segmentText = "";
|
|
78
|
+
this.hidden = false;
|
|
79
|
+
}
|
|
80
|
+
render() {
|
|
81
|
+
if (stopWords.has(this.segmentText)) {
|
|
82
|
+
this.hidden = true;
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
this.hidden = false;
|
|
86
|
+
return html`${this.segmentText}`;
|
|
87
|
+
}
|
|
88
|
+
get startTimeMs() {
|
|
89
|
+
return this.segmentStartMs || 0;
|
|
90
|
+
}
|
|
91
|
+
get durationMs() {
|
|
92
|
+
return this.segmentEndMs - this.segmentStartMs;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
EFCaptionsSegment.styles = [
|
|
96
|
+
css`
|
|
97
|
+
:host {
|
|
98
|
+
display: block;
|
|
99
|
+
}
|
|
100
|
+
:host([hidden]) {
|
|
101
|
+
display: none;
|
|
102
|
+
}
|
|
103
|
+
`
|
|
104
|
+
];
|
|
105
|
+
__decorateClass([
|
|
106
|
+
property({ type: Number, attribute: false })
|
|
107
|
+
], EFCaptionsSegment.prototype, "segmentStartMs", 2);
|
|
108
|
+
__decorateClass([
|
|
109
|
+
property({ type: Number, attribute: false })
|
|
110
|
+
], EFCaptionsSegment.prototype, "segmentEndMs", 2);
|
|
111
|
+
__decorateClass([
|
|
112
|
+
property({ type: String, attribute: false })
|
|
113
|
+
], EFCaptionsSegment.prototype, "segmentText", 2);
|
|
114
|
+
__decorateClass([
|
|
115
|
+
property({ type: Boolean, reflect: true })
|
|
116
|
+
], EFCaptionsSegment.prototype, "hidden", 2);
|
|
117
|
+
EFCaptionsSegment = __decorateClass([
|
|
118
|
+
customElement("ef-captions-segment")
|
|
119
|
+
], EFCaptionsSegment);
|
|
120
|
+
let EFCaptionsBeforeActiveWord = class extends EFCaptionsSegment {
|
|
121
|
+
constructor() {
|
|
122
|
+
super(...arguments);
|
|
123
|
+
this.hidden = false;
|
|
124
|
+
this.segmentText = "";
|
|
125
|
+
this.segmentStartMs = 0;
|
|
126
|
+
this.segmentEndMs = 0;
|
|
127
|
+
}
|
|
128
|
+
render() {
|
|
129
|
+
if (stopWords.has(this.segmentText)) {
|
|
130
|
+
this.hidden = true;
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
this.hidden = false;
|
|
134
|
+
return html` ${this.segmentText}`;
|
|
135
|
+
}
|
|
136
|
+
get startTimeMs() {
|
|
137
|
+
return this.segmentStartMs || 0;
|
|
138
|
+
}
|
|
139
|
+
get durationMs() {
|
|
140
|
+
return this.segmentEndMs - this.segmentStartMs;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
EFCaptionsBeforeActiveWord.styles = [
|
|
144
|
+
css`
|
|
145
|
+
:host {
|
|
146
|
+
display: inline-block;
|
|
147
|
+
white-space: pre;
|
|
148
|
+
}
|
|
149
|
+
:host([hidden]) {
|
|
150
|
+
display: none;
|
|
151
|
+
}
|
|
152
|
+
`
|
|
153
|
+
];
|
|
154
|
+
__decorateClass([
|
|
155
|
+
property({ type: Boolean, reflect: true })
|
|
156
|
+
], EFCaptionsBeforeActiveWord.prototype, "hidden", 2);
|
|
157
|
+
__decorateClass([
|
|
158
|
+
property({ type: String, attribute: false })
|
|
159
|
+
], EFCaptionsBeforeActiveWord.prototype, "segmentText", 2);
|
|
160
|
+
__decorateClass([
|
|
161
|
+
property({ type: Number, attribute: false })
|
|
162
|
+
], EFCaptionsBeforeActiveWord.prototype, "segmentStartMs", 2);
|
|
163
|
+
__decorateClass([
|
|
164
|
+
property({ type: Number, attribute: false })
|
|
165
|
+
], EFCaptionsBeforeActiveWord.prototype, "segmentEndMs", 2);
|
|
166
|
+
EFCaptionsBeforeActiveWord = __decorateClass([
|
|
167
|
+
customElement("ef-captions-before-active-word")
|
|
168
|
+
], EFCaptionsBeforeActiveWord);
|
|
169
|
+
let EFCaptionsAfterActiveWord = class extends EFCaptionsSegment {
|
|
170
|
+
constructor() {
|
|
171
|
+
super(...arguments);
|
|
172
|
+
this.hidden = false;
|
|
173
|
+
this.segmentText = "";
|
|
174
|
+
this.segmentStartMs = 0;
|
|
175
|
+
this.segmentEndMs = 0;
|
|
176
|
+
}
|
|
177
|
+
render() {
|
|
178
|
+
if (stopWords.has(this.segmentText)) {
|
|
179
|
+
this.hidden = true;
|
|
180
|
+
return void 0;
|
|
181
|
+
}
|
|
182
|
+
this.hidden = false;
|
|
183
|
+
return html`${this.segmentText} `;
|
|
184
|
+
}
|
|
185
|
+
get startTimeMs() {
|
|
186
|
+
return this.segmentStartMs || 0;
|
|
187
|
+
}
|
|
188
|
+
get durationMs() {
|
|
189
|
+
return this.segmentEndMs - this.segmentStartMs;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
EFCaptionsAfterActiveWord.styles = [
|
|
193
|
+
css`
|
|
194
|
+
:host {
|
|
195
|
+
display: inline-block;
|
|
196
|
+
white-space: pre;
|
|
197
|
+
}
|
|
198
|
+
:host([hidden]) {
|
|
199
|
+
display: none;
|
|
200
|
+
}
|
|
201
|
+
`
|
|
202
|
+
];
|
|
203
|
+
__decorateClass([
|
|
204
|
+
property({ type: Boolean, reflect: true })
|
|
205
|
+
], EFCaptionsAfterActiveWord.prototype, "hidden", 2);
|
|
206
|
+
__decorateClass([
|
|
207
|
+
property({ type: String, attribute: false })
|
|
208
|
+
], EFCaptionsAfterActiveWord.prototype, "segmentText", 2);
|
|
209
|
+
__decorateClass([
|
|
210
|
+
property({ type: Number, attribute: false })
|
|
211
|
+
], EFCaptionsAfterActiveWord.prototype, "segmentStartMs", 2);
|
|
212
|
+
__decorateClass([
|
|
213
|
+
property({ type: Number, attribute: false })
|
|
214
|
+
], EFCaptionsAfterActiveWord.prototype, "segmentEndMs", 2);
|
|
215
|
+
EFCaptionsAfterActiveWord = __decorateClass([
|
|
216
|
+
customElement("ef-captions-after-active-word")
|
|
217
|
+
], EFCaptionsAfterActiveWord);
|
|
58
218
|
let EFCaptions = class extends EFSourceMixin(
|
|
59
219
|
EFTemporal(FetchMixin(LitElement)),
|
|
60
220
|
{ assetType: "caption_files" }
|
|
61
221
|
) {
|
|
62
222
|
constructor() {
|
|
63
223
|
super(...arguments);
|
|
224
|
+
this.displayMode = "segment";
|
|
225
|
+
this.contextWords = 3;
|
|
64
226
|
this.targetSelector = "";
|
|
65
227
|
this.wordStyle = "";
|
|
66
228
|
this.activeWordContainers = this.getElementsByTagName("ef-captions-active-word");
|
|
229
|
+
this.segmentContainers = this.getElementsByTagName("ef-captions-segment");
|
|
230
|
+
this.beforeActiveWordContainers = this.getElementsByTagName(
|
|
231
|
+
"ef-captions-before-active-word"
|
|
232
|
+
);
|
|
233
|
+
this.afterActiveWordContainers = this.getElementsByTagName(
|
|
234
|
+
"ef-captions-after-active-word"
|
|
235
|
+
);
|
|
67
236
|
this.md5SumLoader = new Task(this, {
|
|
68
237
|
autoRun: false,
|
|
69
238
|
args: () => [this.target, this.fetch],
|
|
@@ -73,25 +242,72 @@ let EFCaptions = class extends EFSourceMixin(
|
|
|
73
242
|
return response.headers.get("etag") ?? void 0;
|
|
74
243
|
}
|
|
75
244
|
});
|
|
76
|
-
this.
|
|
245
|
+
this.transcriptionDataTask = new Task(this, {
|
|
246
|
+
autoRun: EF_INTERACTIVE,
|
|
247
|
+
args: () => [this.transcriptionsPath(), this.fetch],
|
|
248
|
+
task: async ([transcriptionsPath, fetch], { signal }) => {
|
|
249
|
+
if (!transcriptionsPath) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
const response = await fetch(transcriptionsPath, { signal });
|
|
253
|
+
return response.json();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
this.fragmentIndexTask = new Task(this, {
|
|
257
|
+
autoRun: EF_INTERACTIVE,
|
|
258
|
+
args: () => [this.transcriptionDataTask.value, this.ownCurrentTimeMs],
|
|
259
|
+
task: async ([transcription, ownCurrentTimeMs]) => {
|
|
260
|
+
if (!transcription) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const fragmentIndex = Math.floor(
|
|
264
|
+
ownCurrentTimeMs / transcription.work_slice_ms
|
|
265
|
+
);
|
|
266
|
+
return fragmentIndex;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
this.transcriptionFragmentDataTask = new Task(this, {
|
|
77
270
|
autoRun: EF_INTERACTIVE,
|
|
78
|
-
args: () => [
|
|
79
|
-
|
|
80
|
-
|
|
271
|
+
args: () => [
|
|
272
|
+
this.transcriptionDataTask.value,
|
|
273
|
+
this.fragmentIndexTask.value,
|
|
274
|
+
this.fetch
|
|
275
|
+
],
|
|
276
|
+
task: async ([transcription, fragmentIndex, fetch], { signal }) => {
|
|
277
|
+
if (transcription === null || transcription === void 0 || fragmentIndex === null || fragmentIndex === void 0) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const fragmentPath = this.transcriptionFragmentPath(
|
|
281
|
+
transcription.id,
|
|
282
|
+
fragmentIndex
|
|
283
|
+
);
|
|
284
|
+
const response = await fetch(fragmentPath, { signal });
|
|
81
285
|
return response.json();
|
|
82
286
|
}
|
|
83
287
|
});
|
|
84
288
|
this.frameTask = new Task(this, {
|
|
85
289
|
autoRun: EF_INTERACTIVE,
|
|
86
|
-
args: () => [this.
|
|
290
|
+
args: () => [this.transcriptionFragmentDataTask.status],
|
|
87
291
|
task: async () => {
|
|
88
|
-
await this.
|
|
292
|
+
await this.transcriptionFragmentDataTask.taskComplete;
|
|
89
293
|
}
|
|
90
294
|
});
|
|
91
295
|
}
|
|
92
296
|
set target(value) {
|
|
93
297
|
this.targetSelector = value;
|
|
94
298
|
}
|
|
299
|
+
render() {
|
|
300
|
+
return html`<slot></slot>`;
|
|
301
|
+
}
|
|
302
|
+
transcriptionsPath() {
|
|
303
|
+
if (this.targetElement.assetId) {
|
|
304
|
+
if (EF_RENDERING()) {
|
|
305
|
+
return `editframe://api/v1/isobmff_files/${this.targetElement.assetId}/transcription`;
|
|
306
|
+
}
|
|
307
|
+
return `${this.apiHost}/api/v1/isobmff_files/${this.targetElement.assetId}/transcription`;
|
|
308
|
+
}
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
95
311
|
captionsPath() {
|
|
96
312
|
if (this.targetElement.assetId) {
|
|
97
313
|
if (EF_RENDERING()) {
|
|
@@ -102,45 +318,66 @@ let EFCaptions = class extends EFSourceMixin(
|
|
|
102
318
|
const targetSrc = this.targetElement.src;
|
|
103
319
|
return `/@ef-captions/${targetSrc}`;
|
|
104
320
|
}
|
|
321
|
+
transcriptionFragmentPath(transcriptionId, fragmentIndex) {
|
|
322
|
+
return `${this.apiHost}/api/v1/transcriptions/${transcriptionId}/fragments/${fragmentIndex}`;
|
|
323
|
+
}
|
|
105
324
|
connectedCallback() {
|
|
106
325
|
super.connectedCallback();
|
|
107
326
|
if (this.targetElement) {
|
|
108
327
|
new CrossUpdateController(this.targetElement, this);
|
|
109
328
|
}
|
|
110
329
|
}
|
|
111
|
-
render() {
|
|
112
|
-
return this.captionsDataTask.render({
|
|
113
|
-
pending: () => html`<div>Generating captions data...</div>`,
|
|
114
|
-
error: () => html`<div>🚫 Error generating captions data</div>`,
|
|
115
|
-
complete: () => html`<slot></slot>`
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
330
|
updated(_changedProperties) {
|
|
119
|
-
this.
|
|
331
|
+
this.updateTextContainers();
|
|
120
332
|
}
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
if (!
|
|
333
|
+
updateTextContainers() {
|
|
334
|
+
const transcriptionFragment = this.transcriptionFragmentDataTask.value;
|
|
335
|
+
if (!transcriptionFragment) {
|
|
124
336
|
return;
|
|
125
337
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
338
|
+
const currentTimeMs = this.targetElement.trimAdjustedOwnCurrentTimeMs;
|
|
339
|
+
const currentTimeSec = currentTimeMs / 1e3;
|
|
340
|
+
const currentWord = transcriptionFragment.word_segments.find(
|
|
341
|
+
(word) => currentTimeSec >= word.start && currentTimeSec <= word.end
|
|
342
|
+
);
|
|
343
|
+
const currentSegment = transcriptionFragment.segments.find(
|
|
344
|
+
(segment) => currentTimeSec >= segment.start && currentTimeSec <= segment.end
|
|
345
|
+
);
|
|
346
|
+
for (const wordContainer of this.activeWordContainers) {
|
|
347
|
+
if (currentWord) {
|
|
348
|
+
wordContainer.wordText = currentWord.text;
|
|
349
|
+
wordContainer.wordStartMs = currentWord.start * 1e3;
|
|
350
|
+
wordContainer.wordEndMs = currentWord.end * 1e3;
|
|
138
351
|
}
|
|
139
352
|
}
|
|
140
|
-
for (const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
353
|
+
for (const segmentContainer of this.segmentContainers) {
|
|
354
|
+
if (currentSegment) {
|
|
355
|
+
segmentContainer.segmentText = currentSegment.text;
|
|
356
|
+
segmentContainer.segmentStartMs = currentSegment.start * 1e3;
|
|
357
|
+
segmentContainer.segmentEndMs = currentSegment.end * 1e3;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (currentWord && currentSegment) {
|
|
361
|
+
const segmentWords = transcriptionFragment.word_segments.filter(
|
|
362
|
+
(word) => word.start >= currentSegment.start && word.end <= currentSegment.end
|
|
363
|
+
);
|
|
364
|
+
const currentWordIndex = segmentWords.findIndex(
|
|
365
|
+
(word) => word.start === currentWord.start && word.end === currentWord.end
|
|
366
|
+
);
|
|
367
|
+
if (currentWordIndex !== -1) {
|
|
368
|
+
const beforeWords = segmentWords.slice(0, currentWordIndex).map((w) => w.text.trim()).join(" ");
|
|
369
|
+
const afterWords = segmentWords.slice(currentWordIndex + 1).map((w) => w.text.trim()).join(" ");
|
|
370
|
+
for (const container of this.beforeActiveWordContainers) {
|
|
371
|
+
container.segmentText = beforeWords;
|
|
372
|
+
container.segmentStartMs = currentSegment.start * 1e3;
|
|
373
|
+
container.segmentEndMs = currentWord.start * 1e3;
|
|
374
|
+
}
|
|
375
|
+
for (const container of this.afterActiveWordContainers) {
|
|
376
|
+
container.segmentText = afterWords;
|
|
377
|
+
container.segmentStartMs = currentWord.end * 1e3;
|
|
378
|
+
container.segmentEndMs = currentSegment.end * 1e3;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
144
381
|
}
|
|
145
382
|
}
|
|
146
383
|
get targetElement() {
|
|
@@ -154,10 +391,23 @@ let EFCaptions = class extends EFSourceMixin(
|
|
|
154
391
|
EFCaptions.styles = [
|
|
155
392
|
css`
|
|
156
393
|
:host {
|
|
157
|
-
display:
|
|
394
|
+
display: flex;
|
|
395
|
+
flex-wrap: wrap;
|
|
396
|
+
align-items: baseline;
|
|
397
|
+
width: fit-content;
|
|
398
|
+
}
|
|
399
|
+
::slotted(*) {
|
|
400
|
+
margin: 0;
|
|
401
|
+
padding: 0;
|
|
158
402
|
}
|
|
159
403
|
`
|
|
160
404
|
];
|
|
405
|
+
__decorateClass([
|
|
406
|
+
property({ type: String, attribute: "display-mode", reflect: true })
|
|
407
|
+
], EFCaptions.prototype, "displayMode", 2);
|
|
408
|
+
__decorateClass([
|
|
409
|
+
property({ type: Number, attribute: "context-words", reflect: true })
|
|
410
|
+
], EFCaptions.prototype, "contextWords", 2);
|
|
161
411
|
__decorateClass([
|
|
162
412
|
property({ type: String, attribute: "target", reflect: true })
|
|
163
413
|
], EFCaptions.prototype, "targetSelector", 2);
|
|
@@ -169,5 +419,8 @@ EFCaptions = __decorateClass([
|
|
|
169
419
|
], EFCaptions);
|
|
170
420
|
export {
|
|
171
421
|
EFCaptions,
|
|
172
|
-
EFCaptionsActiveWord
|
|
422
|
+
EFCaptionsActiveWord,
|
|
423
|
+
EFCaptionsAfterActiveWord,
|
|
424
|
+
EFCaptionsBeforeActiveWord,
|
|
425
|
+
EFCaptionsSegment
|
|
173
426
|
};
|
|
@@ -59,12 +59,6 @@ let EFImage = class extends EFSourceMixin(FetchMixin(LitElement), {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
set assetId(value) {
|
|
62
|
-
if (!value?.match(/^.{8}-.{4}-.{4}-.{4}-.{12}:.*$/)) {
|
|
63
|
-
console.error(`EFMedia ${value} is not valid asset-id`);
|
|
64
|
-
throw new Error(
|
|
65
|
-
"EFMedia: asset-id must match <uuid>:<basename>. (like: 550e8400-e29b-41d4-a716-446655440000:example.mp4)"
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
62
|
__privateSet(this, _assetId, value);
|
|
69
63
|
}
|
|
70
64
|
get assetId() {
|
|
@@ -10,9 +10,8 @@ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
|
10
10
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
11
11
|
import { apiHostContext } from "../gui/apiHostContext.js";
|
|
12
12
|
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
13
|
-
import { EFTemporal } from "./EFTemporal.js";
|
|
13
|
+
import { EFTemporal, isEFTemporal } from "./EFTemporal.js";
|
|
14
14
|
import { FetchMixin } from "./FetchMixin.js";
|
|
15
|
-
import { getStartTimeMs } from "./util.js";
|
|
16
15
|
var __defProp = Object.defineProperty;
|
|
17
16
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
18
17
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -62,10 +61,10 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
62
61
|
return await Promise.all(
|
|
63
62
|
Object.entries(fragmentIndex).map(async ([trackId, track]) => {
|
|
64
63
|
const start = track.initSegment.offset;
|
|
65
|
-
const end = track.initSegment.offset + track.initSegment.size
|
|
64
|
+
const end = track.initSegment.offset + track.initSegment.size;
|
|
66
65
|
const response = await fetch(this.fragmentTrackPath(trackId), {
|
|
67
66
|
signal,
|
|
68
|
-
headers: { Range: `bytes=${start}-${end}` }
|
|
67
|
+
headers: { Range: `bytes=${start}-${end - 1}` }
|
|
69
68
|
});
|
|
70
69
|
const buffer = await response.arrayBuffer();
|
|
71
70
|
buffer.fileStart = 0;
|
|
@@ -131,14 +130,14 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
131
130
|
const end = segment.offset + segment.size;
|
|
132
131
|
const response = await fetch(this.fragmentTrackPath(trackId), {
|
|
133
132
|
signal,
|
|
134
|
-
headers: { Range: `bytes=${start}-${end}` }
|
|
133
|
+
headers: { Range: `bytes=${start}-${end - 1}` }
|
|
135
134
|
});
|
|
136
135
|
if (nextSegment) {
|
|
137
136
|
const nextStart = nextSegment.offset;
|
|
138
137
|
const nextEnd = nextSegment.offset + nextSegment.size;
|
|
139
138
|
fetch(this.fragmentTrackPath(trackId), {
|
|
140
139
|
signal,
|
|
141
|
-
headers: { Range: `bytes=${nextStart}-${nextEnd}` }
|
|
140
|
+
headers: { Range: `bytes=${nextStart}-${nextEnd - 1}` }
|
|
142
141
|
}).then(() => {
|
|
143
142
|
log("Prefetched next segment");
|
|
144
143
|
}).catch((error) => {
|
|
@@ -230,11 +229,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
230
229
|
}
|
|
231
230
|
#assetId;
|
|
232
231
|
set assetId(value) {
|
|
233
|
-
if (!value?.match(/^.{8}-.{4}-.{4}-.{4}-.{12}:.*$/)) {
|
|
234
|
-
throw new Error(
|
|
235
|
-
"EFMedia: asset-id must match <uuid>:<basename>. (like: 550e8400-e29b-41d4-a716-446655440000:example.mp4)"
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
232
|
this.#assetId = value;
|
|
239
233
|
}
|
|
240
234
|
get assetId() {
|
|
@@ -275,6 +269,67 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
275
269
|
if (changedProperties.has("ownCurrentTimeMs")) {
|
|
276
270
|
this.executeSeek(this.trimAdjustedOwnCurrentTimeMs);
|
|
277
271
|
}
|
|
272
|
+
if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
|
|
273
|
+
const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
|
|
274
|
+
if (this.startTimeMs > timelineTimeMs || this.endTimeMs < timelineTimeMs) {
|
|
275
|
+
this.style.display = "none";
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
this.style.display = "";
|
|
279
|
+
const animations = this.getAnimations({ subtree: true });
|
|
280
|
+
this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
|
|
281
|
+
this.style.setProperty(
|
|
282
|
+
"--ef-transition--duration",
|
|
283
|
+
`${this.parentTimegroup?.overlapMs ?? 0}ms`
|
|
284
|
+
);
|
|
285
|
+
this.style.setProperty(
|
|
286
|
+
"--ef-transition-out-start",
|
|
287
|
+
`${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`
|
|
288
|
+
);
|
|
289
|
+
for (const animation of animations) {
|
|
290
|
+
if (animation.playState === "running") {
|
|
291
|
+
animation.pause();
|
|
292
|
+
}
|
|
293
|
+
const effect = animation.effect;
|
|
294
|
+
if (!(effect && effect instanceof KeyframeEffect)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const target = effect.target;
|
|
298
|
+
if (!target) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (target.closest("ef-video, ef-audio") !== this) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (isEFTemporal(target)) {
|
|
305
|
+
const timing = effect.getTiming();
|
|
306
|
+
const duration = Number(timing.duration) ?? 0;
|
|
307
|
+
const delay = Number(timing.delay);
|
|
308
|
+
const newTime = Math.floor(
|
|
309
|
+
Math.min(target.ownCurrentTimeMs, duration - 1 + delay)
|
|
310
|
+
);
|
|
311
|
+
if (Number.isNaN(newTime)) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
animation.currentTime = newTime;
|
|
315
|
+
} else if (target) {
|
|
316
|
+
const nearestTimegroup = target.closest("ef-timegroup");
|
|
317
|
+
if (!nearestTimegroup) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const timing = effect.getTiming();
|
|
321
|
+
const duration = Number(timing.duration) ?? 0;
|
|
322
|
+
const delay = Number(timing.delay);
|
|
323
|
+
const newTime = Math.floor(
|
|
324
|
+
Math.min(nearestTimegroup.ownCurrentTimeMs, duration - 1 + delay)
|
|
325
|
+
);
|
|
326
|
+
if (Number.isNaN(newTime)) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
animation.currentTime = newTime;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
278
333
|
}
|
|
279
334
|
get hasOwnDuration() {
|
|
280
335
|
return true;
|
|
@@ -305,9 +360,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
305
360
|
}
|
|
306
361
|
return Math.max(...durations) - this.trimStartMs - this.trimEndMs;
|
|
307
362
|
}
|
|
308
|
-
get startTimeMs() {
|
|
309
|
-
return getStartTimeMs(this);
|
|
310
|
-
}
|
|
311
363
|
#audioContext;
|
|
312
364
|
async fetchAudioSpanningTime(fromMs, toMs) {
|
|
313
365
|
if (this.sourceInMs) {
|
|
@@ -330,11 +382,11 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
330
382
|
return;
|
|
331
383
|
}
|
|
332
384
|
const start = audioTrackIndex.initSegment.offset;
|
|
333
|
-
const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size
|
|
385
|
+
const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size;
|
|
334
386
|
const audioInitFragmentRequest = this.fetch(
|
|
335
387
|
this.fragmentTrackPath(String(audioTrackId)),
|
|
336
388
|
{
|
|
337
|
-
headers: { Range: `bytes=${start}-${end}` }
|
|
389
|
+
headers: { Range: `bytes=${start}-${end - 1}` }
|
|
338
390
|
}
|
|
339
391
|
);
|
|
340
392
|
const fragments = Object.values(audioTrackIndex.segments).filter(
|
|
@@ -355,11 +407,11 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
355
407
|
return;
|
|
356
408
|
}
|
|
357
409
|
const fragmentStart = firstFragment.offset;
|
|
358
|
-
const fragmentEnd = lastFragment.offset + lastFragment.size
|
|
410
|
+
const fragmentEnd = lastFragment.offset + lastFragment.size;
|
|
359
411
|
const audioFragmentRequest = this.fetch(
|
|
360
412
|
this.fragmentTrackPath(String(audioTrackId)),
|
|
361
413
|
{
|
|
362
|
-
headers: { Range: `bytes=${fragmentStart}-${fragmentEnd}` }
|
|
414
|
+
headers: { Range: `bytes=${fragmentStart}-${fragmentEnd - 1}` }
|
|
363
415
|
}
|
|
364
416
|
);
|
|
365
417
|
const initResponse = await audioInitFragmentRequest;
|
|
@@ -18,15 +18,6 @@ const timegroupContext = createContext(
|
|
|
18
18
|
);
|
|
19
19
|
const isEFTemporal = (obj) => obj[EF_TEMPORAL];
|
|
20
20
|
const EF_TEMPORAL = Symbol("EF_TEMPORAL");
|
|
21
|
-
const deepGetTemporalElements = (element, temporals = []) => {
|
|
22
|
-
for (const child of element.children) {
|
|
23
|
-
if (isEFTemporal(child)) {
|
|
24
|
-
temporals.push(child);
|
|
25
|
-
}
|
|
26
|
-
deepGetTemporalElements(child, temporals);
|
|
27
|
-
}
|
|
28
|
-
return temporals;
|
|
29
|
-
};
|
|
30
21
|
const deepGetElementsWithFrameTasks = (element, elements = []) => {
|
|
31
22
|
for (const child of element.children) {
|
|
32
23
|
if ("frameTask" in child && child.frameTask instanceof Task) {
|
|
@@ -115,10 +106,20 @@ const EFTemporal = (superClass) => {
|
|
|
115
106
|
get parentTimegroup() {
|
|
116
107
|
return this.#parentTimegroup;
|
|
117
108
|
}
|
|
109
|
+
set duration(value) {
|
|
110
|
+
if (value !== void 0) {
|
|
111
|
+
this.setAttribute("duration", value);
|
|
112
|
+
} else {
|
|
113
|
+
this.removeAttribute("duration");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
118
116
|
get trimStartMs() {
|
|
119
117
|
return this._trimStartMs;
|
|
120
118
|
}
|
|
121
119
|
set trimStartMs(value) {
|
|
120
|
+
if (this._trimStartMs === value) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
122
123
|
this._trimStartMs = value;
|
|
123
124
|
this.setAttribute(
|
|
124
125
|
"trimstart",
|
|
@@ -136,6 +137,9 @@ const EFTemporal = (superClass) => {
|
|
|
136
137
|
return this._trimEndMs;
|
|
137
138
|
}
|
|
138
139
|
set trimEndMs(value) {
|
|
140
|
+
if (this._trimEndMs === value) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
139
143
|
this._trimEndMs = value;
|
|
140
144
|
this.setAttribute("trimend", durationConverter.toAttribute(value / 1e3));
|
|
141
145
|
}
|
|
@@ -366,7 +370,6 @@ export {
|
|
|
366
370
|
EFTemporal,
|
|
367
371
|
OwnCurrentTimeController,
|
|
368
372
|
deepGetElementsWithFrameTasks,
|
|
369
|
-
deepGetTemporalElements,
|
|
370
373
|
isEFTemporal,
|
|
371
374
|
shallowGetTemporalElements,
|
|
372
375
|
timegroupContext
|