@editframe/elements 0.6.0-beta.18 → 0.6.0-beta.19

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.
Files changed (82) hide show
  1. package/package.json +2 -2
  2. package/src/gui/EFFilmstrip.ts +19 -17
  3. package/dist/lib/av/EncodedAsset.cjs +0 -570
  4. package/dist/lib/av/EncodedAsset.js +0 -553
  5. package/dist/lib/av/MP4File.cjs +0 -182
  6. package/dist/lib/av/MP4File.js +0 -165
  7. package/dist/lib/av/msToTimeCode.cjs +0 -15
  8. package/dist/lib/av/msToTimeCode.js +0 -15
  9. package/dist/lib/util/awaitMicrotask.cjs +0 -4
  10. package/dist/lib/util/awaitMicrotask.js +0 -4
  11. package/dist/lib/util/memoize.cjs +0 -14
  12. package/dist/lib/util/memoize.js +0 -14
  13. package/dist/packages/elements/src/EF_FRAMEGEN.cjs +0 -200
  14. package/dist/packages/elements/src/EF_FRAMEGEN.d.ts +0 -45
  15. package/dist/packages/elements/src/EF_FRAMEGEN.js +0 -200
  16. package/dist/packages/elements/src/EF_INTERACTIVE.cjs +0 -4
  17. package/dist/packages/elements/src/EF_INTERACTIVE.d.ts +0 -1
  18. package/dist/packages/elements/src/EF_INTERACTIVE.js +0 -4
  19. package/dist/packages/elements/src/elements/CrossUpdateController.cjs +0 -16
  20. package/dist/packages/elements/src/elements/CrossUpdateController.d.ts +0 -9
  21. package/dist/packages/elements/src/elements/CrossUpdateController.js +0 -16
  22. package/dist/packages/elements/src/elements/EFAudio.cjs +0 -53
  23. package/dist/packages/elements/src/elements/EFAudio.d.ts +0 -10
  24. package/dist/packages/elements/src/elements/EFAudio.js +0 -54
  25. package/dist/packages/elements/src/elements/EFCaptions.cjs +0 -164
  26. package/dist/packages/elements/src/elements/EFCaptions.d.ts +0 -38
  27. package/dist/packages/elements/src/elements/EFCaptions.js +0 -166
  28. package/dist/packages/elements/src/elements/EFImage.cjs +0 -79
  29. package/dist/packages/elements/src/elements/EFImage.d.ts +0 -14
  30. package/dist/packages/elements/src/elements/EFImage.js +0 -80
  31. package/dist/packages/elements/src/elements/EFMedia.cjs +0 -334
  32. package/dist/packages/elements/src/elements/EFMedia.d.ts +0 -61
  33. package/dist/packages/elements/src/elements/EFMedia.js +0 -334
  34. package/dist/packages/elements/src/elements/EFSourceMixin.cjs +0 -55
  35. package/dist/packages/elements/src/elements/EFSourceMixin.d.ts +0 -12
  36. package/dist/packages/elements/src/elements/EFSourceMixin.js +0 -55
  37. package/dist/packages/elements/src/elements/EFTemporal.cjs +0 -198
  38. package/dist/packages/elements/src/elements/EFTemporal.d.ts +0 -36
  39. package/dist/packages/elements/src/elements/EFTemporal.js +0 -198
  40. package/dist/packages/elements/src/elements/EFTimegroup.browsertest.d.ts +0 -12
  41. package/dist/packages/elements/src/elements/EFTimegroup.cjs +0 -350
  42. package/dist/packages/elements/src/elements/EFTimegroup.d.ts +0 -39
  43. package/dist/packages/elements/src/elements/EFTimegroup.js +0 -351
  44. package/dist/packages/elements/src/elements/EFTimeline.cjs +0 -15
  45. package/dist/packages/elements/src/elements/EFTimeline.d.ts +0 -3
  46. package/dist/packages/elements/src/elements/EFTimeline.js +0 -15
  47. package/dist/packages/elements/src/elements/EFVideo.cjs +0 -109
  48. package/dist/packages/elements/src/elements/EFVideo.d.ts +0 -14
  49. package/dist/packages/elements/src/elements/EFVideo.js +0 -110
  50. package/dist/packages/elements/src/elements/EFWaveform.cjs +0 -235
  51. package/dist/packages/elements/src/elements/EFWaveform.d.ts +0 -28
  52. package/dist/packages/elements/src/elements/EFWaveform.js +0 -219
  53. package/dist/packages/elements/src/elements/FetchMixin.cjs +0 -28
  54. package/dist/packages/elements/src/elements/FetchMixin.d.ts +0 -8
  55. package/dist/packages/elements/src/elements/FetchMixin.js +0 -28
  56. package/dist/packages/elements/src/elements/TimegroupController.cjs +0 -20
  57. package/dist/packages/elements/src/elements/TimegroupController.d.ts +0 -14
  58. package/dist/packages/elements/src/elements/TimegroupController.js +0 -20
  59. package/dist/packages/elements/src/elements/durationConverter.cjs +0 -8
  60. package/dist/packages/elements/src/elements/durationConverter.d.ts +0 -4
  61. package/dist/packages/elements/src/elements/durationConverter.js +0 -8
  62. package/dist/packages/elements/src/elements/parseTimeToMs.cjs +0 -12
  63. package/dist/packages/elements/src/elements/parseTimeToMs.d.ts +0 -1
  64. package/dist/packages/elements/src/elements/parseTimeToMs.js +0 -12
  65. package/dist/packages/elements/src/elements/util.cjs +0 -11
  66. package/dist/packages/elements/src/elements/util.d.ts +0 -4
  67. package/dist/packages/elements/src/elements/util.js +0 -11
  68. package/dist/packages/elements/src/gui/EFFilmstrip.cjs +0 -820
  69. package/dist/packages/elements/src/gui/EFFilmstrip.d.ts +0 -144
  70. package/dist/packages/elements/src/gui/EFFilmstrip.js +0 -828
  71. package/dist/packages/elements/src/gui/EFWorkbench.cjs +0 -213
  72. package/dist/packages/elements/src/gui/EFWorkbench.d.ts +0 -45
  73. package/dist/packages/elements/src/gui/EFWorkbench.js +0 -214
  74. package/dist/packages/elements/src/gui/TWMixin.cjs +0 -28
  75. package/dist/packages/elements/src/gui/TWMixin.css.cjs +0 -3
  76. package/dist/packages/elements/src/gui/TWMixin.css.js +0 -4
  77. package/dist/packages/elements/src/gui/TWMixin.d.ts +0 -3
  78. package/dist/packages/elements/src/gui/TWMixin.js +0 -28
  79. package/dist/packages/elements/src/index.cjs +0 -51
  80. package/dist/packages/elements/src/index.d.ts +0 -10
  81. package/dist/packages/elements/src/index.js +0 -24
  82. package/dist/style.css +0 -787
@@ -1,166 +0,0 @@
1
- import { EFAudio } from "./EFAudio.js";
2
- import { html, css, LitElement } from "lit";
3
- import { Task } from "@lit/task";
4
- import { property, customElement } from "lit/decorators.js";
5
- import { EFVideo } from "./EFVideo.js";
6
- import { EFTemporal } from "./EFTemporal.js";
7
- import { CrossUpdateController } from "./CrossUpdateController.js";
8
- import { FetchMixin } from "./FetchMixin.js";
9
- import { EFSourceMixin } from "./EFSourceMixin.js";
10
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
11
- var __defProp = Object.defineProperty;
12
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
- var __decorateClass = (decorators, target, key, kind) => {
14
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
15
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
16
- if (decorator = decorators[i])
17
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
18
- if (kind && result) __defProp(target, key, result);
19
- return result;
20
- };
21
- let EFCaptionsActiveWord = class extends EFTemporal(LitElement) {
22
- constructor() {
23
- super(...arguments);
24
- this.wordStartMs = 0;
25
- this.wordEndMs = 0;
26
- this.wordText = "";
27
- }
28
- render() {
29
- return html`${this.wordText}`;
30
- }
31
- get startTimeMs() {
32
- return this.wordStartMs || 0;
33
- }
34
- get durationMs() {
35
- return this.wordEndMs - this.wordStartMs;
36
- }
37
- };
38
- EFCaptionsActiveWord.styles = [
39
- css`
40
- :host {
41
- display: inline-block;
42
- }
43
- `
44
- ];
45
- __decorateClass([
46
- property({ type: Number, attribute: false })
47
- ], EFCaptionsActiveWord.prototype, "wordStartMs", 2);
48
- __decorateClass([
49
- property({ type: Number, attribute: false })
50
- ], EFCaptionsActiveWord.prototype, "wordEndMs", 2);
51
- __decorateClass([
52
- property({ type: String, attribute: false })
53
- ], EFCaptionsActiveWord.prototype, "wordText", 2);
54
- EFCaptionsActiveWord = __decorateClass([
55
- customElement("ef-captions-active-word")
56
- ], EFCaptionsActiveWord);
57
- let EFCaptions = class extends EFSourceMixin(
58
- EFTemporal(FetchMixin(LitElement)),
59
- { assetType: "caption_files" }
60
- ) {
61
- constructor() {
62
- super(...arguments);
63
- this.target = null;
64
- this.wordStyle = "";
65
- this.activeWordContainers = this.getElementsByTagName("ef-captions-active-word");
66
- this.md5SumLoader = new Task(this, {
67
- autoRun: false,
68
- args: () => [this.target],
69
- task: async ([], { signal }) => {
70
- const md5Path = `/@ef-asset/${this.targetElement.src ?? ""}`;
71
- const response = await fetch(md5Path, { method: "HEAD", signal });
72
- return response.headers.get("etag") ?? void 0;
73
- }
74
- });
75
- this.captionsDataTask = new Task(this, {
76
- autoRun: EF_INTERACTIVE,
77
- args: () => [this.captionsPath(), this.fetch],
78
- task: async ([captionsPath, fetch2], { signal }) => {
79
- const response = await fetch2(captionsPath, { signal });
80
- return response.json();
81
- }
82
- });
83
- this.frameTask = new Task(this, {
84
- autoRun: EF_INTERACTIVE,
85
- args: () => [this.captionsDataTask.status],
86
- task: async () => {
87
- await this.captionsDataTask.taskComplete;
88
- }
89
- });
90
- }
91
- captionsPath() {
92
- const targetSrc = this.targetElement.src;
93
- if (targetSrc.startsWith("editframe://") || targetSrc.startsWith("http")) {
94
- return targetSrc.replace("isobmff", "caption");
95
- }
96
- return `/@ef-captions/${targetSrc}`;
97
- }
98
- connectedCallback() {
99
- super.connectedCallback();
100
- if (this.targetElement) {
101
- new CrossUpdateController(this.targetElement, this);
102
- }
103
- }
104
- render() {
105
- return this.captionsDataTask.render({
106
- pending: () => html`<div>Generating captions data...</div>`,
107
- error: () => html`<div>🚫 Error generating captions data</div>`,
108
- complete: () => html`<slot></slot>`
109
- });
110
- }
111
- updated(_changedProperties) {
112
- this.updateActiveWord();
113
- }
114
- updateActiveWord() {
115
- const caption = this.captionsDataTask.value;
116
- if (!caption) {
117
- return;
118
- }
119
- const words = [];
120
- let startMs = 0;
121
- let endMs = 0;
122
- for (const segment of caption.segments) {
123
- if (this.targetElement.ownCurrentTimeMs >= segment.start * 1e3 && this.targetElement.ownCurrentTimeMs <= segment.end * 1e3) {
124
- for (const word of segment.words) {
125
- if (this.targetElement.ownCurrentTimeMs >= word.start * 1e3 && this.targetElement.ownCurrentTimeMs <= word.end * 1e3) {
126
- words.push(word.text);
127
- startMs = word.start * 1e3;
128
- endMs = word.end * 1e3;
129
- }
130
- }
131
- }
132
- }
133
- for (const container of Array.from(this.activeWordContainers)) {
134
- container.wordText = words.join(" ");
135
- container.wordStartMs = startMs;
136
- container.wordEndMs = endMs;
137
- }
138
- }
139
- get targetElement() {
140
- const target = document.querySelector(this.getAttribute("target") ?? "");
141
- if (target instanceof EFAudio || target instanceof EFVideo) {
142
- return target;
143
- }
144
- throw new Error("Invalid target, must be an EFAudio or EFVideo element");
145
- }
146
- };
147
- EFCaptions.styles = [
148
- css`
149
- :host {
150
- display: block;
151
- }
152
- `
153
- ];
154
- __decorateClass([
155
- property({ type: String, attribute: "target" })
156
- ], EFCaptions.prototype, "target", 2);
157
- __decorateClass([
158
- property({ attribute: "word-style" })
159
- ], EFCaptions.prototype, "wordStyle", 2);
160
- EFCaptions = __decorateClass([
161
- customElement("ef-captions")
162
- ], EFCaptions);
163
- export {
164
- EFCaptions,
165
- EFCaptionsActiveWord
166
- };
@@ -1,79 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const task = require("@lit/task");
4
- const lit = require("lit");
5
- const decorators_js = require("lit/decorators.js");
6
- const ref_js = require("lit/directives/ref.js");
7
- const FetchMixin = require("./FetchMixin.cjs");
8
- const EFSourceMixin = require("./EFSourceMixin.cjs");
9
- const EF_INTERACTIVE = require("../EF_INTERACTIVE.cjs");
10
- var __defProp = Object.defineProperty;
11
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
- var __decorateClass = (decorators, target, key, kind) => {
13
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
14
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
15
- if (decorator = decorators[i])
16
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
17
- if (kind && result) __defProp(target, key, result);
18
- return result;
19
- };
20
- exports.EFImage = class EFImage extends EFSourceMixin.EFSourceMixin(FetchMixin.FetchMixin(lit.LitElement), {
21
- assetType: "image_files"
22
- }) {
23
- constructor() {
24
- super(...arguments);
25
- this.imageRef = ref_js.createRef();
26
- this.canvasRef = ref_js.createRef();
27
- this.fetchImage = new task.Task(this, {
28
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
29
- args: () => [this.assetPath(), this.fetch],
30
- task: async ([assetPath, fetch], { signal }) => {
31
- const response = await fetch(assetPath, { signal });
32
- const image = new Image();
33
- image.src = URL.createObjectURL(await response.blob());
34
- await new Promise((resolve) => {
35
- image.onload = resolve;
36
- });
37
- if (!this.canvasRef.value) throw new Error("Canvas not ready");
38
- const ctx = this.canvasRef.value.getContext("2d");
39
- if (!ctx) throw new Error("Canvas 2d context not ready");
40
- this.canvasRef.value.width = image.width;
41
- this.canvasRef.value.height = image.height;
42
- ctx.drawImage(image, 0, 0);
43
- }
44
- });
45
- this.frameTask = new task.Task(this, {
46
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
47
- args: () => [this.fetchImage.status],
48
- task: async () => {
49
- await this.fetchImage.taskComplete;
50
- }
51
- });
52
- }
53
- render() {
54
- return lit.html`<canvas ${ref_js.ref(this.canvasRef)}></canvas>`;
55
- }
56
- assetPath() {
57
- if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
58
- return this.src;
59
- }
60
- return `/@ef-image/${this.src}`;
61
- }
62
- };
63
- exports.EFImage.styles = [
64
- lit.css`
65
- :host {
66
- display: block;
67
- }
68
- canvas {
69
- display: block;
70
- width: 100%;
71
- height: 100%;
72
- object-fit: fill;
73
- object-position: center;
74
- }
75
- `
76
- ];
77
- exports.EFImage = __decorateClass([
78
- decorators_js.customElement("ef-image")
79
- ], exports.EFImage);
@@ -1,14 +0,0 @@
1
- import { Task } from '@lit/task';
2
- import { LitElement } from 'lit';
3
-
4
- declare const EFImage_base: (new (...args: any[]) => import('./EFSourceMixin').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin').FetchMixinInterface) & typeof LitElement;
5
- export declare class EFImage extends EFImage_base {
6
- static styles: import('lit').CSSResult[];
7
- imageRef: import('lit-html/directives/ref').Ref<HTMLImageElement>;
8
- canvasRef: import('lit-html/directives/ref').Ref<HTMLCanvasElement>;
9
- render(): import('lit-html').TemplateResult<1>;
10
- assetPath(): string;
11
- fetchImage: Task<readonly [string, typeof fetch], void>;
12
- frameTask: Task<readonly [import('@lit/task').TaskStatus], void>;
13
- }
14
- export {};
@@ -1,80 +0,0 @@
1
- import { Task } from "@lit/task";
2
- import { html, css, LitElement } from "lit";
3
- import { customElement } from "lit/decorators.js";
4
- import { createRef, ref } from "lit/directives/ref.js";
5
- import { FetchMixin } from "./FetchMixin.js";
6
- import { EFSourceMixin } from "./EFSourceMixin.js";
7
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
8
- var __defProp = Object.defineProperty;
9
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
- var __decorateClass = (decorators, target, key, kind) => {
11
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
12
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
13
- if (decorator = decorators[i])
14
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
15
- if (kind && result) __defProp(target, key, result);
16
- return result;
17
- };
18
- let EFImage = class extends EFSourceMixin(FetchMixin(LitElement), {
19
- assetType: "image_files"
20
- }) {
21
- constructor() {
22
- super(...arguments);
23
- this.imageRef = createRef();
24
- this.canvasRef = createRef();
25
- this.fetchImage = new Task(this, {
26
- autoRun: EF_INTERACTIVE,
27
- args: () => [this.assetPath(), this.fetch],
28
- task: async ([assetPath, fetch], { signal }) => {
29
- const response = await fetch(assetPath, { signal });
30
- const image = new Image();
31
- image.src = URL.createObjectURL(await response.blob());
32
- await new Promise((resolve) => {
33
- image.onload = resolve;
34
- });
35
- if (!this.canvasRef.value) throw new Error("Canvas not ready");
36
- const ctx = this.canvasRef.value.getContext("2d");
37
- if (!ctx) throw new Error("Canvas 2d context not ready");
38
- this.canvasRef.value.width = image.width;
39
- this.canvasRef.value.height = image.height;
40
- ctx.drawImage(image, 0, 0);
41
- }
42
- });
43
- this.frameTask = new Task(this, {
44
- autoRun: EF_INTERACTIVE,
45
- args: () => [this.fetchImage.status],
46
- task: async () => {
47
- await this.fetchImage.taskComplete;
48
- }
49
- });
50
- }
51
- render() {
52
- return html`<canvas ${ref(this.canvasRef)}></canvas>`;
53
- }
54
- assetPath() {
55
- if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
56
- return this.src;
57
- }
58
- return `/@ef-image/${this.src}`;
59
- }
60
- };
61
- EFImage.styles = [
62
- css`
63
- :host {
64
- display: block;
65
- }
66
- canvas {
67
- display: block;
68
- width: 100%;
69
- height: 100%;
70
- object-fit: fill;
71
- object-position: center;
72
- }
73
- `
74
- ];
75
- EFImage = __decorateClass([
76
- customElement("ef-image")
77
- ], EFImage);
78
- export {
79
- EFImage
80
- };
@@ -1,334 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const lit = require("lit");
4
- const EFTemporal = require("./EFTemporal.cjs");
5
- const decorators_js = require("lit/decorators.js");
6
- const deepEquals_js = require("@lit/task/deep-equals.js");
7
- const task = require("@lit/task");
8
- const MP4File = require("../../../../lib/av/MP4File.cjs");
9
- const util = require("./util.cjs");
10
- const EncodedAsset = require("../../../../lib/av/EncodedAsset.cjs");
11
- const FetchMixin = require("./FetchMixin.cjs");
12
- const EFWorkbench = require("../gui/EFWorkbench.cjs");
13
- const context = require("@lit/context");
14
- const EFSourceMixin = require("./EFSourceMixin.cjs");
15
- const EF_INTERACTIVE = require("../EF_INTERACTIVE.cjs");
16
- var __defProp = Object.defineProperty;
17
- var __decorateClass = (decorators, target, key, kind) => {
18
- var result = void 0;
19
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
20
- if (decorator = decorators[i])
21
- result = decorator(target, key, result) || result;
22
- if (result) __defProp(target, key, result);
23
- return result;
24
- };
25
- const deepGetMediaElements = (element, medias = []) => {
26
- for (const child of Array.from(element.children)) {
27
- if (child instanceof EFMedia) {
28
- medias.push(child);
29
- } else {
30
- deepGetMediaElements(child, medias);
31
- }
32
- }
33
- return medias;
34
- };
35
- class EFMedia extends EFSourceMixin.EFSourceMixin(EFTemporal.EFTemporal(FetchMixin.FetchMixin(lit.LitElement)), {
36
- assetType: "isobmff_files"
37
- }) {
38
- constructor() {
39
- super(...arguments);
40
- this.currentTimeMs = 0;
41
- this.trackFragmentIndexLoader = new task.Task(this, {
42
- args: () => [this.fragmentIndexPath(), this.fetch],
43
- task: async ([fragmentIndexPath, fetch], { signal }) => {
44
- const response = await fetch(fragmentIndexPath, { signal });
45
- return await response.json();
46
- },
47
- onComplete: () => {
48
- this.requestUpdate("ownCurrentTimeMs");
49
- this.rootTimegroup?.requestUpdate("ownCurrentTimeMs");
50
- }
51
- });
52
- this.initSegmentsLoader = new task.Task(this, {
53
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
54
- args: () => [this.trackFragmentIndexLoader.value, this.src, this.fetch],
55
- task: async ([fragmentIndex, _src, fetch], { signal }) => {
56
- if (!fragmentIndex) {
57
- return;
58
- }
59
- return await Promise.all(
60
- Object.entries(fragmentIndex).map(async ([trackId, track]) => {
61
- const start = track.initSegment.offset;
62
- const end = track.initSegment.offset + track.initSegment.size - 1;
63
- const response = await fetch(this.fragmentTrackPath(trackId), {
64
- signal,
65
- headers: { Range: `bytes=${start}-${end}` }
66
- });
67
- const buffer = await response.arrayBuffer();
68
- buffer.fileStart = 0;
69
- const mp4File = new MP4File.MP4File();
70
- mp4File.appendBuffer(buffer, true);
71
- mp4File.flush();
72
- await mp4File.readyPromise;
73
- return { trackId, buffer, mp4File };
74
- })
75
- );
76
- }
77
- });
78
- this.seekTask = new task.Task(this, {
79
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
80
- args: () => [
81
- this.desiredSeekTimeMs,
82
- this.trackFragmentIndexLoader.value,
83
- this.initSegmentsLoader.value
84
- ],
85
- task: async ([seekToMs, fragmentIndex, initSegments], { signal: _signal }) => {
86
- if (fragmentIndex === void 0) {
87
- return;
88
- }
89
- if (initSegments === void 0) {
90
- return;
91
- }
92
- const result = {};
93
- for (const index of Object.values(fragmentIndex)) {
94
- const track = initSegments.find((segment2) => segment2.trackId === String(index.track))?.mp4File.getInfo().tracks[0];
95
- if (!track) {
96
- throw new Error("Could not finding matching track");
97
- }
98
- const segment = index.segments.toReversed().find((segment2) => {
99
- return segment2.dts / track.timescale * 1e3 <= seekToMs;
100
- });
101
- if (!segment) {
102
- return;
103
- }
104
- result[index.track] = { segment, track };
105
- }
106
- return result;
107
- }
108
- });
109
- this.fetchSeekTask = new task.Task(this, {
110
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
111
- argsEqual: deepEquals_js.deepArrayEquals,
112
- args: () => [this.initSegmentsLoader.value, this.seekTask.value, this.fetch],
113
- task: async ([initSegments, seekResult, fetch], { signal }) => {
114
- if (!initSegments) {
115
- return;
116
- }
117
- if (!seekResult) {
118
- return;
119
- }
120
- const files = {};
121
- for (const [trackId, { segment, track }] of Object.entries(seekResult)) {
122
- const start = segment.offset;
123
- const end = segment.offset + segment.size;
124
- const response = await fetch(this.fragmentTrackPath(trackId), {
125
- signal,
126
- headers: { Range: `bytes=${start}-${end}` }
127
- });
128
- const initSegment = Object.values(initSegments).find(
129
- (initSegment2) => initSegment2.trackId === String(track.id)
130
- );
131
- if (!initSegment) {
132
- throw new Error("Could not find matching init segment");
133
- }
134
- const initBuffer = initSegment.buffer;
135
- const mediaBuffer = await response.arrayBuffer();
136
- files[trackId] = new File([initBuffer, mediaBuffer], "video.mp4", {
137
- type: "video/mp4"
138
- });
139
- }
140
- return files;
141
- }
142
- });
143
- this.videoAssetTask = new task.Task(this, {
144
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
145
- args: () => [this.fetchSeekTask.value],
146
- task: async ([files], { signal: _signal }) => {
147
- if (!files) {
148
- return;
149
- }
150
- if (!this.defaultVideoTrackId) {
151
- return;
152
- }
153
- const videoFile = files[this.defaultVideoTrackId];
154
- if (!videoFile) {
155
- return;
156
- }
157
- for (const frame of this.videoAssetTask.value?.decodedFrames || []) {
158
- frame.close();
159
- }
160
- this.videoAssetTask.value?.videoDecoder?.close();
161
- return await EncodedAsset.VideoAsset.createFromReadableStream(
162
- "video.mp4",
163
- videoFile.stream(),
164
- videoFile
165
- );
166
- }
167
- });
168
- this.desiredSeekTimeMs = 0;
169
- this.#audioContext = new OfflineAudioContext(2, 48e3 / 30, 48e3);
170
- this.audioBufferTask = new task.Task(this, {
171
- autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
172
- args: () => [this.fetchSeekTask.value, this.seekTask.value],
173
- task: async ([files, segments], { signal: _signal }) => {
174
- if (!files) {
175
- return;
176
- }
177
- if (!segments) {
178
- return;
179
- }
180
- if (!this.defaultAudioTrackId) {
181
- return;
182
- }
183
- const segment = segments[this.defaultAudioTrackId];
184
- if (!segment) {
185
- return;
186
- }
187
- const audioFile = files[this.defaultAudioTrackId];
188
- if (!audioFile) {
189
- return;
190
- }
191
- return {
192
- buffer: await this.#audioContext.decodeAudioData(
193
- await audioFile.arrayBuffer()
194
- ),
195
- startOffsetMs: segment.segment.cts / segment.track.timescale * 1e3
196
- };
197
- }
198
- });
199
- }
200
- static {
201
- this.styles = [
202
- lit.css`
203
- :host {
204
- display: block;
205
- position: relative;
206
- overflow: hidden;
207
- }
208
- `
209
- ];
210
- }
211
- fragmentIndexPath() {
212
- if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
213
- return `${this.src}/index`;
214
- }
215
- return `/@ef-track-fragment-index/${this.src ?? ""}`;
216
- }
217
- fragmentTrackPath(trackId) {
218
- if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
219
- return `${this.src.replace("files", "tracks")}/${trackId}`;
220
- }
221
- return `/@ef-track/${this.src ?? ""}?trackId=${trackId}`;
222
- }
223
- get defaultVideoTrackId() {
224
- return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
225
- (track) => track.type === "video"
226
- )?.track;
227
- }
228
- get defaultAudioTrackId() {
229
- return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
230
- (track) => track.type === "audio"
231
- )?.track;
232
- }
233
- async executeSeek(seekToMs) {
234
- this.desiredSeekTimeMs = seekToMs;
235
- }
236
- updated(changedProperties) {
237
- if (changedProperties.has("ownCurrentTimeMs")) {
238
- this.executeSeek(this.ownCurrentTimeMs);
239
- }
240
- }
241
- get hasOwnDuration() {
242
- return true;
243
- }
244
- get durationMs() {
245
- if (!this.trackFragmentIndexLoader.value) {
246
- return 0;
247
- }
248
- const durations = Object.values(this.trackFragmentIndexLoader.value).map(
249
- (track) => {
250
- return track.duration / track.timescale * 1e3;
251
- }
252
- );
253
- if (durations.length === 0) {
254
- return 0;
255
- }
256
- return Math.max(...durations);
257
- }
258
- get startTimeMs() {
259
- return util.getStartTimeMs(this);
260
- }
261
- #audioContext;
262
- async fetchAudioSpanningTime(fromMs, toMs) {
263
- fromMs -= this.startTimeMs;
264
- toMs -= this.startTimeMs;
265
- await this.trackFragmentIndexLoader.taskComplete;
266
- const audioTrackId = this.defaultAudioTrackId;
267
- if (!audioTrackId) {
268
- console.warn("No audio track found");
269
- return;
270
- }
271
- const audioTrackIndex = this.trackFragmentIndexLoader.value?.[audioTrackId];
272
- if (!audioTrackIndex) {
273
- console.warn("No audio track found");
274
- return;
275
- }
276
- const start = audioTrackIndex.initSegment.offset;
277
- const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size - 1;
278
- const audioInitFragmentRequest = this.fetch(
279
- this.fragmentTrackPath(String(audioTrackId)),
280
- {
281
- headers: { Range: `bytes=${start}-${end}` }
282
- }
283
- );
284
- const fragments = Object.values(audioTrackIndex.segments).filter(
285
- (segment) => {
286
- const segmentStartsBeforeEnd = segment.dts <= toMs * audioTrackIndex.timescale / 1e3;
287
- const segmentEndsAfterStart = segment.dts + segment.duration >= fromMs * audioTrackIndex.timescale / 1e3;
288
- return segmentStartsBeforeEnd && segmentEndsAfterStart;
289
- }
290
- );
291
- const firstFragment = fragments[0];
292
- if (!firstFragment) {
293
- console.warn("No audio fragments found");
294
- return;
295
- }
296
- const lastFragment = fragments[fragments.length - 1];
297
- if (!lastFragment) {
298
- console.warn("No audio fragments found");
299
- return;
300
- }
301
- const fragmentStart = firstFragment.offset;
302
- const fragmentEnd = lastFragment.offset + lastFragment.size - 1;
303
- const audioFragmentRequest = this.fetch(
304
- this.fragmentTrackPath(String(audioTrackId)),
305
- {
306
- headers: { Range: `bytes=${fragmentStart}-${fragmentEnd}` }
307
- }
308
- );
309
- const initResponse = await audioInitFragmentRequest;
310
- const dataResponse = await audioFragmentRequest;
311
- const initBuffer = await initResponse.arrayBuffer();
312
- const dataBuffer = await dataResponse.arrayBuffer();
313
- const audioBlob = new Blob([initBuffer, dataBuffer], {
314
- type: "audio/mp4"
315
- });
316
- return {
317
- blob: audioBlob,
318
- startMs: firstFragment.dts / audioTrackIndex.timescale * 1e3,
319
- endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3
320
- };
321
- }
322
- }
323
- __decorateClass([
324
- decorators_js.property({ type: Number })
325
- ], EFMedia.prototype, "currentTimeMs");
326
- __decorateClass([
327
- context.consume({ context: EFWorkbench.apiHostContext, subscribe: true }),
328
- decorators_js.state()
329
- ], EFMedia.prototype, "efHost");
330
- __decorateClass([
331
- decorators_js.state()
332
- ], EFMedia.prototype, "desiredSeekTimeMs");
333
- exports.EFMedia = EFMedia;
334
- exports.deepGetMediaElements = deepGetMediaElements;