@editframe/elements 0.8.0-beta.1 → 0.8.0-beta.2

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.
@@ -29,6 +29,7 @@ export declare class EFMedia extends EFMedia_base {
29
29
  }[] | undefined], Record<string, {
30
30
  segment: TrackSegment;
31
31
  track: MP4Box.TrackInfo;
32
+ nextSegment?: TrackSegment;
32
33
  }> | undefined>;
33
34
  fetchSeekTask: Task<readonly [{
34
35
  trackId: string;
@@ -37,6 +38,7 @@ export declare class EFMedia extends EFMedia_base {
37
38
  }[] | undefined, Record<string, {
38
39
  segment: TrackSegment;
39
40
  track: MP4Box.TrackInfo;
41
+ nextSegment?: TrackSegment;
40
42
  }> | undefined, typeof fetch], Record<string, File> | undefined>;
41
43
  videoAssetTask: Task<readonly [Record<string, File> | undefined], VideoAsset | undefined>;
42
44
  desiredSeekTimeMs: number;
@@ -48,6 +50,7 @@ export declare class EFMedia extends EFMedia_base {
48
50
  audioBufferTask: Task<readonly [Record<string, File> | undefined, Record<string, {
49
51
  segment: TrackSegment;
50
52
  track: MP4Box.TrackInfo;
53
+ nextSegment?: TrackSegment;
51
54
  }> | undefined], {
52
55
  buffer: AudioBuffer;
53
56
  startOffsetMs: number;
@@ -101,10 +101,13 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
101
101
  const segment = index.segments.toReversed().find((segment2) => {
102
102
  return segment2.dts / track.timescale * 1e3 <= seekToMs;
103
103
  });
104
+ const nextSegment = index.segments.find((segment2) => {
105
+ return segment2.dts / track.timescale * 1e3 > seekToMs;
106
+ });
104
107
  if (!segment) {
105
108
  return;
106
109
  }
107
- result[index.track] = { segment, track };
110
+ result[index.track] = { segment, track, nextSegment };
108
111
  }
109
112
  return result;
110
113
  }
@@ -121,13 +124,27 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
121
124
  return;
122
125
  }
123
126
  const files = {};
124
- for (const [trackId, { segment, track }] of Object.entries(seekResult)) {
127
+ for (const [trackId, { segment, track, nextSegment }] of Object.entries(
128
+ seekResult
129
+ )) {
125
130
  const start = segment.offset;
126
131
  const end = segment.offset + segment.size;
127
132
  const response = await fetch(this.fragmentTrackPath(trackId), {
128
133
  signal,
129
134
  headers: { Range: `bytes=${start}-${end}` }
130
135
  });
136
+ if (nextSegment) {
137
+ const nextStart = nextSegment.offset;
138
+ const nextEnd = nextSegment.offset + nextSegment.size;
139
+ fetch(this.fragmentTrackPath(trackId), {
140
+ signal,
141
+ headers: { Range: `bytes=${nextStart}-${nextEnd}` }
142
+ }).then(() => {
143
+ log("Prefetched next segment");
144
+ }).catch((error) => {
145
+ log("Failed to prefetch next segment", error);
146
+ });
147
+ }
131
148
  const initSegment = Object.values(initSegments).find(
132
149
  (initSegment2) => initSegment2.trackId === String(track.id)
133
150
  );
@@ -32,25 +32,27 @@ function ContextMixin(superClass) {
32
32
  });
33
33
  }
34
34
  if (this.signingURL) {
35
- if (!this.#signedURLs[url]) {
36
- this.#signedURLs[url] = fetch(this.signingURL, {
35
+ if (!this.#URLTokens[url]) {
36
+ this.#URLTokens[url] = fetch(this.signingURL, {
37
37
  method: "POST",
38
38
  body: JSON.stringify({ url })
39
39
  }).then(async (response) => {
40
40
  if (response.ok) {
41
- return (await response.json()).url;
41
+ return (await response.json()).token;
42
42
  }
43
43
  throw new Error(
44
44
  `Failed to sign URL: ${url}. SigningURL: ${this.signingURL} ${response.status} ${response.statusText}`
45
45
  );
46
46
  });
47
47
  }
48
- const signedURL = await this.#signedURLs[url];
49
- return fetch(signedURL, init);
48
+ const urlToken = await this.#URLTokens[url];
49
+ Object.assign(init.headers, {
50
+ authorization: `Bearer ${urlToken}`
51
+ });
50
52
  }
51
53
  return fetch(url, init);
52
54
  };
53
- this.#signedURLs = {};
55
+ this.#URLTokens = {};
54
56
  this.apiHost = "";
55
57
  this.playing = false;
56
58
  this.loop = false;
@@ -93,7 +95,7 @@ function ContextMixin(superClass) {
93
95
  this.#playbackAnimationFrameRequest = null;
94
96
  this.#AUDIO_PLAYBACK_SLICE_MS = 1e3;
95
97
  }
96
- #signedURLs;
98
+ #URLTokens;
97
99
  connectedCallback() {
98
100
  super.connectedCallback();
99
101
  requestAnimationFrame(this.setStageScale);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/elements",
3
- "version": "0.8.0-beta.1",
3
+ "version": "0.8.0-beta.2",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
@@ -20,7 +20,7 @@
20
20
  "author": "",
21
21
  "license": "UNLICENSED",
22
22
  "dependencies": {
23
- "@editframe/assets": "0.8.0-beta.1",
23
+ "@editframe/assets": "0.8.0-beta.2",
24
24
  "@lit/context": "^1.1.2",
25
25
  "@lit/task": "^1.0.1",
26
26
  "d3": "^7.9.0",
@@ -145,7 +145,11 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
145
145
 
146
146
  const result: Record<
147
147
  string,
148
- { segment: TrackSegment; track: MP4Box.TrackInfo }
148
+ {
149
+ segment: TrackSegment;
150
+ track: MP4Box.TrackInfo;
151
+ nextSegment?: TrackSegment;
152
+ }
149
153
  > = {};
150
154
 
151
155
  for (const index of Object.values(fragmentIndex)) {
@@ -161,11 +165,15 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
161
165
  return (segment.dts / track.timescale) * 1000 <= seekToMs;
162
166
  });
163
167
 
168
+ const nextSegment = index.segments.find((segment) => {
169
+ return (segment.dts / track.timescale) * 1000 > seekToMs;
170
+ });
171
+
164
172
  if (!segment) {
165
173
  return;
166
174
  }
167
175
 
168
- result[index.track] = { segment, track };
176
+ result[index.track] = { segment, track, nextSegment };
169
177
  }
170
178
 
171
179
  return result;
@@ -187,7 +195,9 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
187
195
 
188
196
  const files: Record<string, File> = {};
189
197
 
190
- for (const [trackId, { segment, track }] of Object.entries(seekResult)) {
198
+ for (const [trackId, { segment, track, nextSegment }] of Object.entries(
199
+ seekResult,
200
+ )) {
191
201
  const start = segment.offset;
192
202
  const end = segment.offset + segment.size;
193
203
 
@@ -196,6 +206,21 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
196
206
  headers: { Range: `bytes=${start}-${end}` },
197
207
  });
198
208
 
209
+ if (nextSegment) {
210
+ const nextStart = nextSegment.offset;
211
+ const nextEnd = nextSegment.offset + nextSegment.size;
212
+ fetch(this.fragmentTrackPath(trackId), {
213
+ signal,
214
+ headers: { Range: `bytes=${nextStart}-${nextEnd}` },
215
+ })
216
+ .then(() => {
217
+ log("Prefetched next segment");
218
+ })
219
+ .catch((error) => {
220
+ log("Failed to prefetch next segment", error);
221
+ });
222
+ }
223
+
199
224
  const initSegment = Object.values(initSegments).find(
200
225
  (initSegment) => initSegment.trackId === String(track.id),
201
226
  );
@@ -51,13 +51,13 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
51
51
  }
52
52
 
53
53
  if (this.signingURL) {
54
- if (!this.#signedURLs[url]) {
55
- this.#signedURLs[url] = fetch(this.signingURL, {
54
+ if (!this.#URLTokens[url]) {
55
+ this.#URLTokens[url] = fetch(this.signingURL, {
56
56
  method: "POST",
57
57
  body: JSON.stringify({ url }),
58
58
  }).then(async (response) => {
59
59
  if (response.ok) {
60
- return (await response.json()).url;
60
+ return (await response.json()).token;
61
61
  }
62
62
  throw new Error(
63
63
  `Failed to sign URL: ${url}. SigningURL: ${this.signingURL} ${response.status} ${response.statusText}`,
@@ -65,15 +65,17 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
65
65
  });
66
66
  }
67
67
 
68
- const signedURL = await this.#signedURLs[url];
68
+ const urlToken = await this.#URLTokens[url];
69
69
 
70
- return fetch(signedURL, init);
70
+ Object.assign(init.headers, {
71
+ authorization: `Bearer ${urlToken}`,
72
+ });
71
73
  }
72
74
 
73
75
  return fetch(url, init);
74
76
  };
75
77
 
76
- #signedURLs: Record<string, Promise<string>> = {};
78
+ #URLTokens: Record<string, Promise<string>> = {};
77
79
 
78
80
  @property({ type: String })
79
81
  signingURL?: string;