@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
package/src/elements/EFMedia.ts
CHANGED
|
@@ -14,9 +14,8 @@ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
|
14
14
|
import { EF_RENDERING } from "../EF_RENDERING.ts";
|
|
15
15
|
import { apiHostContext } from "../gui/apiHostContext.ts";
|
|
16
16
|
import { EFSourceMixin } from "./EFSourceMixin.ts";
|
|
17
|
-
import { EFTemporal } from "./EFTemporal.ts";
|
|
17
|
+
import { EFTemporal, isEFTemporal } from "./EFTemporal.ts";
|
|
18
18
|
import { FetchMixin } from "./FetchMixin.ts";
|
|
19
|
-
import { getStartTimeMs } from "./util.ts";
|
|
20
19
|
|
|
21
20
|
const log = debug("ef:elements:EFMedia");
|
|
22
21
|
|
|
@@ -57,11 +56,6 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
57
56
|
#assetId: string | null = null;
|
|
58
57
|
@property({ type: String, attribute: "asset-id", reflect: true })
|
|
59
58
|
set assetId(value: string | null) {
|
|
60
|
-
if (!value?.match(/^.{8}-.{4}-.{4}-.{4}-.{12}:.*$/)) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
"EFMedia: asset-id must match <uuid>:<basename>. (like: 550e8400-e29b-41d4-a716-446655440000:example.mp4)",
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
59
|
this.#assetId = value;
|
|
66
60
|
}
|
|
67
61
|
|
|
@@ -104,7 +98,7 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
104
98
|
},
|
|
105
99
|
});
|
|
106
100
|
|
|
107
|
-
|
|
101
|
+
public initSegmentsLoader = new Task(this, {
|
|
108
102
|
autoRun: EF_INTERACTIVE,
|
|
109
103
|
args: () =>
|
|
110
104
|
[this.trackFragmentIndexLoader.value, this.src, this.fetch] as const,
|
|
@@ -115,10 +109,10 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
115
109
|
return await Promise.all(
|
|
116
110
|
Object.entries(fragmentIndex).map(async ([trackId, track]) => {
|
|
117
111
|
const start = track.initSegment.offset;
|
|
118
|
-
const end = track.initSegment.offset + track.initSegment.size
|
|
112
|
+
const end = track.initSegment.offset + track.initSegment.size;
|
|
119
113
|
const response = await fetch(this.fragmentTrackPath(trackId), {
|
|
120
114
|
signal,
|
|
121
|
-
headers: { Range: `bytes=${start}-${end}` },
|
|
115
|
+
headers: { Range: `bytes=${start}-${end - 1}` },
|
|
122
116
|
});
|
|
123
117
|
const buffer =
|
|
124
118
|
(await response.arrayBuffer()) as MP4Box.MP4ArrayBuffer;
|
|
@@ -225,7 +219,7 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
225
219
|
|
|
226
220
|
const response = await fetch(this.fragmentTrackPath(trackId), {
|
|
227
221
|
signal,
|
|
228
|
-
headers: { Range: `bytes=${start}-${end}` },
|
|
222
|
+
headers: { Range: `bytes=${start}-${end - 1}` },
|
|
229
223
|
});
|
|
230
224
|
|
|
231
225
|
if (nextSegment) {
|
|
@@ -233,7 +227,7 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
233
227
|
const nextEnd = nextSegment.offset + nextSegment.size;
|
|
234
228
|
fetch(this.fragmentTrackPath(trackId), {
|
|
235
229
|
signal,
|
|
236
|
-
headers: { Range: `bytes=${nextStart}-${nextEnd}` },
|
|
230
|
+
headers: { Range: `bytes=${nextStart}-${nextEnd - 1}` },
|
|
237
231
|
})
|
|
238
232
|
.then(() => {
|
|
239
233
|
log("Prefetched next segment");
|
|
@@ -302,6 +296,83 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
302
296
|
if (changedProperties.has("ownCurrentTimeMs")) {
|
|
303
297
|
this.executeSeek(this.trimAdjustedOwnCurrentTimeMs);
|
|
304
298
|
}
|
|
299
|
+
// TODO: this is copied straight from EFTimegroup.ts
|
|
300
|
+
// and should be refactored to be shared/reduce bad duplication of
|
|
301
|
+
// critical logic.
|
|
302
|
+
if (
|
|
303
|
+
changedProperties.has("currentTime") ||
|
|
304
|
+
changedProperties.has("ownCurrentTimeMs")
|
|
305
|
+
) {
|
|
306
|
+
const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
|
|
307
|
+
if (
|
|
308
|
+
this.startTimeMs > timelineTimeMs ||
|
|
309
|
+
this.endTimeMs < timelineTimeMs
|
|
310
|
+
) {
|
|
311
|
+
this.style.display = "none";
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
this.style.display = "";
|
|
315
|
+
|
|
316
|
+
const animations = this.getAnimations({ subtree: true });
|
|
317
|
+
this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
|
|
318
|
+
this.style.setProperty(
|
|
319
|
+
"--ef-transition--duration",
|
|
320
|
+
`${this.parentTimegroup?.overlapMs ?? 0}ms`,
|
|
321
|
+
);
|
|
322
|
+
this.style.setProperty(
|
|
323
|
+
"--ef-transition-out-start",
|
|
324
|
+
`${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`,
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
for (const animation of animations) {
|
|
328
|
+
if (animation.playState === "running") {
|
|
329
|
+
animation.pause();
|
|
330
|
+
}
|
|
331
|
+
const effect = animation.effect;
|
|
332
|
+
if (!(effect && effect instanceof KeyframeEffect)) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const target = effect.target;
|
|
336
|
+
// TODO: better generalize work avoidance for temporal elements
|
|
337
|
+
if (!target) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (target.closest("ef-video, ef-audio") !== this) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Important to avoid going to the end of the animation
|
|
345
|
+
// or it will reset awkwardly.
|
|
346
|
+
if (isEFTemporal(target)) {
|
|
347
|
+
const timing = effect.getTiming();
|
|
348
|
+
const duration = Number(timing.duration) ?? 0;
|
|
349
|
+
const delay = Number(timing.delay);
|
|
350
|
+
const newTime = Math.floor(
|
|
351
|
+
Math.min(target.ownCurrentTimeMs, duration - 1 + delay),
|
|
352
|
+
);
|
|
353
|
+
if (Number.isNaN(newTime)) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
animation.currentTime = newTime;
|
|
357
|
+
} else if (target) {
|
|
358
|
+
const nearestTimegroup = target.closest("ef-timegroup");
|
|
359
|
+
if (!nearestTimegroup) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const timing = effect.getTiming();
|
|
363
|
+
const duration = Number(timing.duration) ?? 0;
|
|
364
|
+
const delay = Number(timing.delay);
|
|
365
|
+
const newTime = Math.floor(
|
|
366
|
+
Math.min(nearestTimegroup.ownCurrentTimeMs, duration - 1 + delay),
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
if (Number.isNaN(newTime)) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
animation.currentTime = newTime;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
305
376
|
}
|
|
306
377
|
|
|
307
378
|
get hasOwnDuration() {
|
|
@@ -356,10 +427,6 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
356
427
|
return Math.max(...durations) - this.trimStartMs - this.trimEndMs;
|
|
357
428
|
}
|
|
358
429
|
|
|
359
|
-
get startTimeMs() {
|
|
360
|
-
return getStartTimeMs(this);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
430
|
#audioContext = new OfflineAudioContext(2, 48000 / 30, 48000);
|
|
364
431
|
|
|
365
432
|
audioBufferTask = new Task(this, {
|
|
@@ -418,11 +485,11 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
418
485
|
|
|
419
486
|
const start = audioTrackIndex.initSegment.offset;
|
|
420
487
|
const end =
|
|
421
|
-
audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size
|
|
488
|
+
audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size;
|
|
422
489
|
const audioInitFragmentRequest = this.fetch(
|
|
423
490
|
this.fragmentTrackPath(String(audioTrackId)),
|
|
424
491
|
{
|
|
425
|
-
headers: { Range: `bytes=${start}-${end}` },
|
|
492
|
+
headers: { Range: `bytes=${start}-${end - 1}` },
|
|
426
493
|
},
|
|
427
494
|
);
|
|
428
495
|
|
|
@@ -448,12 +515,12 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
|
|
|
448
515
|
return;
|
|
449
516
|
}
|
|
450
517
|
const fragmentStart = firstFragment.offset;
|
|
451
|
-
const fragmentEnd = lastFragment.offset + lastFragment.size
|
|
518
|
+
const fragmentEnd = lastFragment.offset + lastFragment.size;
|
|
452
519
|
|
|
453
520
|
const audioFragmentRequest = this.fetch(
|
|
454
521
|
this.fragmentTrackPath(String(audioTrackId)),
|
|
455
522
|
{
|
|
456
|
-
headers: { Range: `bytes=${fragmentStart}-${fragmentEnd}` },
|
|
523
|
+
headers: { Range: `bytes=${fragmentStart}-${fragmentEnd - 1}` },
|
|
457
524
|
},
|
|
458
525
|
);
|
|
459
526
|
|
|
@@ -63,3 +63,17 @@ describe("trimstart and trimend", () => {
|
|
|
63
63
|
expect(element.trimEndMs).toBe(5_000);
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
describe("duration", () => {
|
|
68
|
+
test("duration is parsed correctly", () => {
|
|
69
|
+
const element = document.createElement("test-temporal");
|
|
70
|
+
element.setAttribute("duration", "10s");
|
|
71
|
+
expect(element.durationMs).toBe(10_000);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("duration can be set directly on the element", () => {
|
|
75
|
+
const element = document.createElement("test-temporal");
|
|
76
|
+
element.duration = "10s";
|
|
77
|
+
expect(element.durationMs).toBe(10_000);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -169,6 +169,14 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
|
|
|
169
169
|
})
|
|
170
170
|
private _durationMs?: number;
|
|
171
171
|
|
|
172
|
+
set duration(value: string | undefined) {
|
|
173
|
+
if (value !== undefined) {
|
|
174
|
+
this.setAttribute("duration", value);
|
|
175
|
+
} else {
|
|
176
|
+
this.removeAttribute("duration");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
172
180
|
private _trimStartMs = 0;
|
|
173
181
|
@property({
|
|
174
182
|
type: Number,
|
|
@@ -179,6 +187,9 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
|
|
|
179
187
|
return this._trimStartMs;
|
|
180
188
|
}
|
|
181
189
|
public set trimStartMs(value: number) {
|
|
190
|
+
if (this._trimStartMs === value) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
182
193
|
this._trimStartMs = value;
|
|
183
194
|
this.setAttribute(
|
|
184
195
|
"trimstart",
|
|
@@ -203,6 +214,9 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
|
|
|
203
214
|
return this._trimEndMs;
|
|
204
215
|
}
|
|
205
216
|
public set trimEndMs(value: number) {
|
|
217
|
+
if (this._trimEndMs === value) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
206
220
|
this._trimEndMs = value;
|
|
207
221
|
this.setAttribute("trimend", durationConverter.toAttribute(value / 1000));
|
|
208
222
|
}
|
|
@@ -8,7 +8,10 @@ import { assert, beforeEach, describe, test } from "vitest";
|
|
|
8
8
|
import { EFTimegroup } from "./EFTimegroup.ts";
|
|
9
9
|
import "./EFTimegroup.ts";
|
|
10
10
|
import { customElement } from "lit/decorators/custom-element.js";
|
|
11
|
+
import { ContextMixin } from "../gui/ContextMixin.ts";
|
|
11
12
|
import { EFTemporal } from "./EFTemporal.ts";
|
|
13
|
+
// Need workbench to make workbench wrapping occurs
|
|
14
|
+
import "../gui/EFWorkbench.ts";
|
|
12
15
|
|
|
13
16
|
beforeEach(() => {
|
|
14
17
|
for (let i = 0; i < localStorage.length; i++) {
|
|
@@ -21,6 +24,9 @@ beforeEach(() => {
|
|
|
21
24
|
}
|
|
22
25
|
});
|
|
23
26
|
|
|
27
|
+
@customElement("test-context")
|
|
28
|
+
class TestContext extends ContextMixin(LitElement) {}
|
|
29
|
+
|
|
24
30
|
@customElement("test-temporal")
|
|
25
31
|
class TestTemporal extends EFTemporal(LitElement) {
|
|
26
32
|
get hasOwnDuration(): boolean {
|
|
@@ -31,6 +37,7 @@ class TestTemporal extends EFTemporal(LitElement) {
|
|
|
31
37
|
declare global {
|
|
32
38
|
interface HTMLElementTagNameMap {
|
|
33
39
|
"test-temporal": TestTemporal;
|
|
40
|
+
"test-context": TestContext;
|
|
34
41
|
}
|
|
35
42
|
}
|
|
36
43
|
|
|
@@ -331,3 +338,33 @@ describe("setting currentTime", () => {
|
|
|
331
338
|
assert.equal(b.ownCurrentTimeMs, 2_500);
|
|
332
339
|
});
|
|
333
340
|
});
|
|
341
|
+
|
|
342
|
+
describe("shouldWrapWithWorkbench", () => {
|
|
343
|
+
test.skip("should not wrap if EF_INTERACTIVE is false", () => {
|
|
344
|
+
// TODO: need a way to define EF_INTERACTIVE in a test
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("should wrap if root-most timegroup", () => {
|
|
348
|
+
const root = document.createElement("ef-timegroup");
|
|
349
|
+
const child = document.createElement("ef-timegroup");
|
|
350
|
+
root.appendChild(child);
|
|
351
|
+
assert.isTrue(child.shouldWrapWithWorkbench());
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("should not wrap if contained within a preview context", () => {
|
|
355
|
+
const timegorup = document.createElement("ef-timegroup");
|
|
356
|
+
const context = document.createElement("test-context");
|
|
357
|
+
context.append(timegorup);
|
|
358
|
+
assert.isFalse(timegorup.shouldWrapWithWorkbench());
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
describe("DOM nodes", () => {
|
|
363
|
+
test("can have mode and duration set as attributes", () => {
|
|
364
|
+
const timegroup = document.createElement("ef-timegroup");
|
|
365
|
+
timegroup.setAttribute("mode", "fixed");
|
|
366
|
+
timegroup.setAttribute("duration", "10s");
|
|
367
|
+
assert.equal(timegroup.mode, "fixed");
|
|
368
|
+
assert.equal(timegroup.durationMs, 10_000);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { LitElement, html, css, type PropertyValueMap } from "lit";
|
|
2
1
|
import { provide } from "@lit/context";
|
|
3
2
|
import { Task } from "@lit/task";
|
|
4
|
-
import { customElement, property } from "lit/decorators.js";
|
|
5
3
|
import debug from "debug";
|
|
4
|
+
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
5
|
+
import { customElement, property } from "lit/decorators.js";
|
|
6
6
|
|
|
7
|
+
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
8
|
+
import { isContextMixin } from "../gui/ContextMixin.ts";
|
|
9
|
+
import { deepGetMediaElements } from "./EFMedia.ts";
|
|
7
10
|
import {
|
|
8
11
|
EFTemporal,
|
|
9
12
|
isEFTemporal,
|
|
@@ -11,8 +14,6 @@ import {
|
|
|
11
14
|
timegroupContext,
|
|
12
15
|
} from "./EFTemporal.ts";
|
|
13
16
|
import { TimegroupController } from "./TimegroupController.ts";
|
|
14
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
15
|
-
import { deepGetMediaElements } from "./EFMedia.ts";
|
|
16
17
|
import { durationConverter } from "./durationConverter.ts";
|
|
17
18
|
|
|
18
19
|
const log = debug("ef:elements:EFTimegroup");
|
|
@@ -151,10 +152,16 @@ export class EFTimegroup extends EFTemporal(LitElement) {
|
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Wait for all media elements to load their initial segments.
|
|
157
|
+
* Ideally we would only need the extracted index json data, but
|
|
158
|
+
* that caused issues with constructing audio data. We had negative durations
|
|
159
|
+
* in calculations and it was not clear why.
|
|
160
|
+
*/
|
|
154
161
|
async waitForMediaDurations() {
|
|
155
162
|
return await Promise.all(
|
|
156
163
|
deepGetMediaElements(this).map(
|
|
157
|
-
(media) => media.
|
|
164
|
+
(media) => media.initSegmentsLoader.taskComplete,
|
|
158
165
|
),
|
|
159
166
|
);
|
|
160
167
|
}
|
|
@@ -243,12 +250,34 @@ export class EFTimegroup extends EFTemporal(LitElement) {
|
|
|
243
250
|
}
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
get contextProvider() {
|
|
254
|
+
let parent = this.parentNode;
|
|
255
|
+
while (parent) {
|
|
256
|
+
if (isContextMixin(parent)) {
|
|
257
|
+
return parent;
|
|
258
|
+
}
|
|
259
|
+
parent = parent.parentNode;
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Returns true if the timegroup should be wrapped with a workbench.
|
|
266
|
+
*
|
|
267
|
+
* A timegroup should be wrapped with a workbench if it is the root-most timegroup
|
|
268
|
+
* and EF_INTERACTIVE is true.
|
|
269
|
+
*
|
|
270
|
+
* If the timegroup is already wrappedin a context provider like ef-preview,
|
|
271
|
+
* it should NOT be wrapped in a workbench.
|
|
272
|
+
*
|
|
273
|
+
*/
|
|
246
274
|
shouldWrapWithWorkbench() {
|
|
247
275
|
return (
|
|
248
276
|
EF_INTERACTIVE &&
|
|
249
277
|
this.closest("ef-timegroup") === this &&
|
|
278
|
+
this.closest("ef-preview") === null &&
|
|
250
279
|
this.closest("ef-workbench") === null &&
|
|
251
|
-
this.closest("
|
|
280
|
+
this.closest("test-context") === null
|
|
252
281
|
);
|
|
253
282
|
}
|
|
254
283
|
|
|
@@ -286,12 +315,8 @@ export class EFTimegroup extends EFTemporal(LitElement) {
|
|
|
286
315
|
) {
|
|
287
316
|
await this.waitForMediaDurations();
|
|
288
317
|
|
|
289
|
-
const durationMs = toMs - fromMs;
|
|
290
|
-
|
|
291
318
|
await Promise.all(
|
|
292
319
|
deepGetMediaElements(this).map(async (mediaElement) => {
|
|
293
|
-
await mediaElement.trackFragmentIndexLoader.taskComplete;
|
|
294
|
-
|
|
295
320
|
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
296
321
|
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
297
322
|
const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
|
|
@@ -304,19 +329,19 @@ export class EFTimegroup extends EFTemporal(LitElement) {
|
|
|
304
329
|
throw new Error("Failed to fetch audio");
|
|
305
330
|
}
|
|
306
331
|
|
|
307
|
-
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
308
|
-
const ctxEndMs = Math.min(durationMs, mediaElement.endTimeMs - fromMs);
|
|
309
|
-
const ctxDurationMs = ctxEndMs - ctxStartMs;
|
|
310
|
-
|
|
311
|
-
const offset =
|
|
312
|
-
Math.max(0, fromMs - mediaElement.startTimeMs) - audio.startMs;
|
|
313
|
-
|
|
314
332
|
const bufferSource = audioContext.createBufferSource();
|
|
315
333
|
bufferSource.buffer = await audioContext.decodeAudioData(
|
|
316
334
|
await audio.blob.arrayBuffer(),
|
|
317
335
|
);
|
|
318
336
|
bufferSource.connect(audioContext.destination);
|
|
319
337
|
|
|
338
|
+
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
339
|
+
const ctxEndMs = mediaElement.endTimeMs - fromMs;
|
|
340
|
+
const ctxDurationMs = ctxEndMs - ctxStartMs;
|
|
341
|
+
|
|
342
|
+
const offset =
|
|
343
|
+
Math.max(0, fromMs - mediaElement.startTimeMs) - audio.startMs;
|
|
344
|
+
|
|
320
345
|
bufferSource.start(
|
|
321
346
|
ctxStartMs / 1000,
|
|
322
347
|
offset / 1000,
|
package/src/elements/EFVideo.ts
CHANGED
|
@@ -20,10 +20,7 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
20
20
|
];
|
|
21
21
|
canvasRef = createRef<HTMLCanvasElement>();
|
|
22
22
|
render() {
|
|
23
|
-
return html` <canvas
|
|
24
|
-
class="h-full w-full object-fill"
|
|
25
|
-
${ref(this.canvasRef)}
|
|
26
|
-
></canvas>`;
|
|
23
|
+
return html` <canvas ${ref(this.canvasRef)}></canvas>`;
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
get canvasElement() {
|