@editframe/elements 0.18.3-beta.0 → 0.18.7-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/EFMedia/AssetMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +2 -4
- package/dist/elements/EFMedia/AssetMediaEngine.js +22 -3
- package/dist/elements/EFMedia/BaseMediaEngine.js +20 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +5 -5
- package/dist/elements/EFMedia/BufferedSeekingInput.js +27 -7
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +1 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +22 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +4 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +11 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +10 -2
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +11 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +3 -2
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +4 -1
- package/dist/elements/EFMedia/shared/PrecisionUtils.d.ts +28 -0
- package/dist/elements/EFMedia/shared/PrecisionUtils.js +29 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +11 -2
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +11 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +3 -2
- package/dist/elements/EFMedia.d.ts +0 -12
- package/dist/elements/EFMedia.js +4 -30
- package/dist/elements/EFTimegroup.js +12 -17
- package/dist/elements/EFVideo.d.ts +0 -9
- package/dist/elements/EFVideo.js +0 -7
- package/dist/elements/SampleBuffer.js +6 -6
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/gui/ContextMixin.js +71 -17
- package/dist/gui/TWMixin.js +1 -1
- package/dist/style.css +1 -1
- package/dist/transcoding/types/index.d.ts +9 -9
- package/package.json +2 -3
- package/src/elements/EFAudio.browsertest.ts +7 -7
- package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +100 -0
- package/src/elements/EFMedia/AssetMediaEngine.ts +52 -7
- package/src/elements/EFMedia/BaseMediaEngine.ts +50 -1
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +135 -54
- package/src/elements/EFMedia/BufferedSeekingInput.ts +74 -17
- package/src/elements/EFMedia/JitMediaEngine.ts +58 -2
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +10 -1
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +16 -8
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +199 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +25 -3
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +12 -1
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +3 -2
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +10 -1
- package/src/elements/EFMedia/shared/PrecisionUtils.ts +46 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +27 -3
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +12 -1
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +3 -2
- package/src/elements/EFMedia.browsertest.ts +73 -33
- package/src/elements/EFMedia.ts +11 -54
- package/src/elements/EFTimegroup.ts +21 -26
- package/src/elements/EFVideo.browsertest.ts +895 -162
- package/src/elements/EFVideo.ts +0 -16
- package/src/elements/SampleBuffer.ts +8 -10
- package/src/gui/ContextMixin.ts +104 -26
- package/src/transcoding/types/index.ts +10 -6
- package/test/EFVideo.framegen.browsertest.ts +1 -1
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +3 -3
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +3 -3
- 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 +21 -0
- 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 +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +3 -3
- 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 +4 -4
- package/test/recordReplayProxyPlugin.js +50 -0
- package/types.json +1 -1
- package/dist/DecoderResetFrequency.test.d.ts +0 -1
- package/dist/DecoderResetRecovery.test.d.ts +0 -1
- package/dist/ScrubTrackManager.d.ts +0 -96
- package/dist/elements/EFMedia/services/AudioElementFactory.browsertest.d.ts +0 -1
- package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +0 -22
- package/dist/elements/EFMedia/services/AudioElementFactory.js +0 -72
- package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +0 -1
- package/dist/elements/EFMedia/services/MediaSourceService.d.ts +0 -47
- package/dist/elements/EFMedia/services/MediaSourceService.js +0 -73
- package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +0 -1
- package/dist/gui/services/ElementConnectionManager.d.ts +0 -59
- package/dist/gui/services/ElementConnectionManager.js +0 -128
- package/dist/gui/services/PlaybackController.browsertest.d.ts +0 -1
- package/dist/gui/services/PlaybackController.d.ts +0 -103
- package/dist/gui/services/PlaybackController.js +0 -290
- package/dist/services/MediaSourceManager.d.ts +0 -62
- package/dist/services/MediaSourceManager.js +0 -211
- package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +0 -325
- package/src/elements/EFMedia/services/AudioElementFactory.ts +0 -119
- package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +0 -257
- package/src/elements/EFMedia/services/MediaSourceService.ts +0 -102
- package/src/gui/services/ElementConnectionManager.browsertest.ts +0 -263
- package/src/gui/services/ElementConnectionManager.ts +0 -224
- package/src/gui/services/PlaybackController.browsertest.ts +0 -437
- package/src/gui/services/PlaybackController.ts +0 -521
- package/src/services/MediaSourceManager.ts +0 -333
package/dist/elements/EFVideo.js
CHANGED
|
@@ -243,12 +243,6 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
|
243
243
|
return currentTime >= renderStartTime;
|
|
244
244
|
}
|
|
245
245
|
/**
|
|
246
|
-
* Get scrub track performance statistics
|
|
247
|
-
*/
|
|
248
|
-
getScrubTrackStats() {
|
|
249
|
-
return this.scrubTrackManager?.getCacheStats() || null;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
246
|
* Effective mode - always returns "asset" for EFVideo
|
|
253
247
|
*/
|
|
254
248
|
get effectiveMode() {
|
|
@@ -307,7 +301,6 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
|
307
301
|
*/
|
|
308
302
|
disconnectedCallback() {
|
|
309
303
|
super.disconnectedCallback();
|
|
310
|
-
this.scrubTrackManager?.cleanup();
|
|
311
304
|
this.delayedLoadingState.clearAllLoading();
|
|
312
305
|
}
|
|
313
306
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { roundToMilliseconds } from "./EFMedia/shared/PrecisionUtils.js";
|
|
1
2
|
var SampleBuffer = class {
|
|
2
3
|
constructor(bufferSize = 10) {
|
|
3
4
|
this.buffer = [];
|
|
@@ -28,13 +29,12 @@ var SampleBuffer = class {
|
|
|
28
29
|
find(desiredSeekTimeMs) {
|
|
29
30
|
const currentBuffer = [...this.buffer];
|
|
30
31
|
if (currentBuffer.length === 0) return void 0;
|
|
31
|
-
const
|
|
32
|
-
const targetTimeMs = roundToMicroseconds(desiredSeekTimeMs);
|
|
32
|
+
const targetTimeMs = roundToMilliseconds(desiredSeekTimeMs);
|
|
33
33
|
for (const sample of currentBuffer) {
|
|
34
|
-
const sampleStartMs =
|
|
35
|
-
const sampleDurationMs =
|
|
36
|
-
const sampleEndMs = sampleStartMs + sampleDurationMs;
|
|
37
|
-
if (targetTimeMs >= sampleStartMs && targetTimeMs
|
|
34
|
+
const sampleStartMs = roundToMilliseconds((sample.timestamp || 0) * 1e3);
|
|
35
|
+
const sampleDurationMs = roundToMilliseconds((sample.duration || 0) * 1e3);
|
|
36
|
+
const sampleEndMs = roundToMilliseconds(sampleStartMs + sampleDurationMs);
|
|
37
|
+
if (targetTimeMs >= sampleStartMs && targetTimeMs <= sampleEndMs) return sample;
|
|
38
38
|
}
|
|
39
39
|
return void 0;
|
|
40
40
|
}
|
package/dist/getRenderInfo.d.ts
CHANGED
|
@@ -18,20 +18,20 @@ export declare const RenderInfo: z.ZodObject<{
|
|
|
18
18
|
efImage: string[];
|
|
19
19
|
}>;
|
|
20
20
|
}, "strip", z.ZodTypeAny, {
|
|
21
|
-
fps: number;
|
|
22
21
|
width: number;
|
|
23
22
|
height: number;
|
|
24
23
|
durationMs: number;
|
|
24
|
+
fps: number;
|
|
25
25
|
assets: {
|
|
26
26
|
efMedia: Record<string, any>;
|
|
27
27
|
efCaptions: string[];
|
|
28
28
|
efImage: string[];
|
|
29
29
|
};
|
|
30
30
|
}, {
|
|
31
|
-
fps: number;
|
|
32
31
|
width: number;
|
|
33
32
|
height: number;
|
|
34
33
|
durationMs: number;
|
|
34
|
+
fps: number;
|
|
35
35
|
assets: {
|
|
36
36
|
efMedia: Record<string, any>;
|
|
37
37
|
efCaptions: string[];
|
package/dist/gui/ContextMixin.js
CHANGED
|
@@ -4,8 +4,6 @@ import { fetchContext } from "./fetchContext.js";
|
|
|
4
4
|
import { focusContext } from "./focusContext.js";
|
|
5
5
|
import { focusedElementContext } from "./focusedElementContext.js";
|
|
6
6
|
import { loopContext, playingContext } from "./playingContext.js";
|
|
7
|
-
import { ElementConnectionManager } from "./services/ElementConnectionManager.js";
|
|
8
|
-
import { PlaybackController } from "./services/PlaybackController.js";
|
|
9
7
|
import { consume, createContext, provide } from "@lit/context";
|
|
10
8
|
import { property, state } from "lit/decorators.js";
|
|
11
9
|
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
@@ -42,19 +40,6 @@ function ContextMixin(superClass) {
|
|
|
42
40
|
this.loop = false;
|
|
43
41
|
this.rendering = false;
|
|
44
42
|
this.currentTimeMs = 0;
|
|
45
|
-
this._elementConnectionManager = new ElementConnectionManager(3e3);
|
|
46
|
-
this.playbackController = new PlaybackController({
|
|
47
|
-
fps: 30,
|
|
48
|
-
onTimeUpdate: (timeMs) => {
|
|
49
|
-
this.currentTimeMs = timeMs;
|
|
50
|
-
},
|
|
51
|
-
onPlayStateChange: (playing) => {
|
|
52
|
-
this.playing = playing;
|
|
53
|
-
},
|
|
54
|
-
onError: (error) => {
|
|
55
|
-
console.error("🎵 [PLAYBACK_ERROR]:", error);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
43
|
}
|
|
59
44
|
static {
|
|
60
45
|
this[contextMixinSymbol] = true;
|
|
@@ -78,6 +63,8 @@ function ContextMixin(superClass) {
|
|
|
78
63
|
set signingURL(value) {
|
|
79
64
|
this.#signingURL = value;
|
|
80
65
|
}
|
|
66
|
+
#FPS = 30;
|
|
67
|
+
#MS_PER_FRAME = 1e3 / this.#FPS;
|
|
81
68
|
#timegroupObserver = new MutationObserver((mutations) => {
|
|
82
69
|
for (const mutation of mutations) if (mutation.type === "childList") {
|
|
83
70
|
const newTimegroup = this.querySelector("ef-timegroup");
|
|
@@ -119,13 +106,80 @@ function ContextMixin(superClass) {
|
|
|
119
106
|
pause() {
|
|
120
107
|
this.playing = false;
|
|
121
108
|
}
|
|
109
|
+
#playbackAudioContext = null;
|
|
110
|
+
#playbackAnimationFrameRequest = null;
|
|
111
|
+
#AUDIO_PLAYBACK_SLICE_MS = 47 * 1024 / 48e3 * 1e3;
|
|
112
|
+
#syncPlayheadToAudioContext(target, startMs) {
|
|
113
|
+
const rawTimeMs = startMs + (this.#playbackAudioContext?.currentTime ?? 0) * 1e3;
|
|
114
|
+
const nextTimeMs = Math.round(rawTimeMs / this.#MS_PER_FRAME) * this.#MS_PER_FRAME;
|
|
115
|
+
if (nextTimeMs !== this.currentTimeMs) this.currentTimeMs = nextTimeMs;
|
|
116
|
+
this.#playbackAnimationFrameRequest = requestAnimationFrame(() => {
|
|
117
|
+
this.#syncPlayheadToAudioContext(target, startMs);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
122
120
|
async stopPlayback() {
|
|
123
|
-
|
|
121
|
+
if (this.#playbackAudioContext) {
|
|
122
|
+
if (this.#playbackAudioContext.state !== "closed") await this.#playbackAudioContext.close();
|
|
123
|
+
}
|
|
124
|
+
if (this.#playbackAnimationFrameRequest) cancelAnimationFrame(this.#playbackAnimationFrameRequest);
|
|
125
|
+
this.#playbackAudioContext = null;
|
|
126
|
+
this.#playbackAnimationFrameRequest = null;
|
|
124
127
|
}
|
|
125
128
|
async startPlayback() {
|
|
129
|
+
await this.stopPlayback();
|
|
126
130
|
const timegroup = this.targetTimegroup;
|
|
127
131
|
if (!timegroup) return;
|
|
128
|
-
await
|
|
132
|
+
await timegroup.waitForMediaDurations();
|
|
133
|
+
let currentMs = timegroup.currentTimeMs;
|
|
134
|
+
const fromMs = currentMs;
|
|
135
|
+
const toMs = timegroup.endTimeMs;
|
|
136
|
+
if (fromMs >= toMs) {
|
|
137
|
+
this.pause();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
let bufferCount = 0;
|
|
141
|
+
this.#playbackAudioContext = new AudioContext({ latencyHint: "playback" });
|
|
142
|
+
if (this.#playbackAnimationFrameRequest) cancelAnimationFrame(this.#playbackAnimationFrameRequest);
|
|
143
|
+
this.#syncPlayheadToAudioContext(timegroup, currentMs);
|
|
144
|
+
const playbackContext = this.#playbackAudioContext;
|
|
145
|
+
if (playbackContext.state === "suspended") {
|
|
146
|
+
console.warn("AudioContext is suspended, media playback will not work until user has interacted with page.");
|
|
147
|
+
this.playing = false;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
await playbackContext.suspend();
|
|
151
|
+
const fillBuffer = async () => {
|
|
152
|
+
if (bufferCount > 2) return;
|
|
153
|
+
const canFillBuffer = await queueBufferSource();
|
|
154
|
+
if (canFillBuffer) fillBuffer();
|
|
155
|
+
};
|
|
156
|
+
const queueBufferSource = async () => {
|
|
157
|
+
if (currentMs >= toMs) return false;
|
|
158
|
+
const startMs = currentMs;
|
|
159
|
+
const endMs = currentMs + this.#AUDIO_PLAYBACK_SLICE_MS;
|
|
160
|
+
currentMs += this.#AUDIO_PLAYBACK_SLICE_MS;
|
|
161
|
+
const audioBuffer = await timegroup.renderAudio(startMs, endMs);
|
|
162
|
+
bufferCount++;
|
|
163
|
+
const source = playbackContext.createBufferSource();
|
|
164
|
+
source.buffer = audioBuffer;
|
|
165
|
+
source.connect(playbackContext.destination);
|
|
166
|
+
source.start((startMs - fromMs) / 1e3);
|
|
167
|
+
source.onended = () => {
|
|
168
|
+
bufferCount--;
|
|
169
|
+
if (endMs >= toMs) {
|
|
170
|
+
this.pause();
|
|
171
|
+
if (this.loop) this.updateComplete.then(() => {
|
|
172
|
+
this.currentTimeMs = 0;
|
|
173
|
+
this.updateComplete.then(() => {
|
|
174
|
+
this.play();
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
} else fillBuffer();
|
|
178
|
+
};
|
|
179
|
+
return true;
|
|
180
|
+
};
|
|
181
|
+
await fillBuffer();
|
|
182
|
+
await playbackContext.resume();
|
|
129
183
|
}
|
|
130
184
|
}
|
|
131
185
|
_decorate([consume({
|
package/dist/gui/TWMixin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var TWMixin_default = "*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:\"\"}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\\[1px\\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-\\[1\\.1rem\\]{height:1.1rem}.h-\\[270px\\]{height:270px}.h-\\[5px\\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\\[2px\\]{width:2px}.w-\\[480px\\]{width:480px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\\[1px\\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\\[8px\\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\\[focused\\]\\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}";
|
|
1
|
+
var TWMixin_default = "*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:\"\"}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-0{left:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\\[1px\\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-full{width:100%;height:100%}.h-\\[1\\.1rem\\]{height:1.1rem}.h-\\[270px\\]{height:270px}.h-\\[500px\\]{height:500px}.h-\\[5px\\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\\[1000px\\]{width:1000px}.w-\\[2px\\]{width:2px}.w-\\[480px\\]{width:480px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-500{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\\[1px\\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\\[8px\\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\\[focused\\]\\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}";
|
|
2
2
|
export { TWMixin_default as default };
|
package/dist/style.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\[1px\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-\[1\.1rem\]{height:1.1rem}.h-\[270px\]{height:270px}.h-\[5px\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\[2px\]{width:2px}.w-\[480px\]{width:480px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.
|
|
1
|
+
*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-0{left:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\[1px\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-full{width:100%;height:100%}.h-\[1\.1rem\]{height:1.1rem}.h-\[270px\]{height:270px}.h-\[500px\]{height:500px}.h-\[5px\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\[1000px\]{width:1000px}.w-\[2px\]{width:2px}.w-\[480px\]{width:480px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-500{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\[1px\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\[8px\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\[focused\]\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}
|
|
2
2
|
/*$vite$:1*/
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Core types and interfaces for JIT Transcoding System
|
|
3
|
-
*/
|
|
1
|
+
import { MediaRendition } from '../../elements/EFMedia/shared/MediaTaskUtils';
|
|
4
2
|
export interface QualityPreset {
|
|
5
3
|
name: string;
|
|
6
4
|
width: number;
|
|
@@ -68,6 +66,8 @@ export interface ManifestVideoRendition {
|
|
|
68
66
|
segmentDuration: number;
|
|
69
67
|
/** Duration of each segment in milliseconds */
|
|
70
68
|
segmentDurationMs: number;
|
|
69
|
+
/** Actual segment durations array (overrides fixed segmentDurationMs if provided) */
|
|
70
|
+
segmentDurationsMs?: number[];
|
|
71
71
|
/** Video width in pixels */
|
|
72
72
|
width: number;
|
|
73
73
|
/** Video height in pixels */
|
|
@@ -94,6 +94,8 @@ export interface ManifestAudioRendition {
|
|
|
94
94
|
segmentDuration: number;
|
|
95
95
|
/** Duration of each segment in milliseconds */
|
|
96
96
|
segmentDurationMs: number;
|
|
97
|
+
/** Actual segment durations array (overrides fixed segmentDurationMs if provided) */
|
|
98
|
+
segmentDurationsMs?: number[];
|
|
97
99
|
/** Number of audio channels */
|
|
98
100
|
channels: number;
|
|
99
101
|
/** Sample rate in Hz */
|
|
@@ -173,12 +175,15 @@ export interface AudioRendition {
|
|
|
173
175
|
trackId: number | undefined;
|
|
174
176
|
src: string;
|
|
175
177
|
segmentDurationMs?: number;
|
|
178
|
+
segmentDurationsMs?: number[];
|
|
179
|
+
startTimeOffsetMs?: number;
|
|
176
180
|
}
|
|
177
181
|
export interface VideoRendition {
|
|
178
182
|
id?: RenditionId;
|
|
179
183
|
trackId: number | undefined;
|
|
180
184
|
src: string;
|
|
181
185
|
segmentDurationMs?: number;
|
|
186
|
+
segmentDurationsMs?: number[];
|
|
182
187
|
startTimeOffsetMs?: number;
|
|
183
188
|
}
|
|
184
189
|
export interface MediaEngine {
|
|
@@ -200,12 +205,7 @@ export interface MediaEngine {
|
|
|
200
205
|
trackId: number | undefined;
|
|
201
206
|
src: string;
|
|
202
207
|
}, signal?: AbortSignal) => Promise<ArrayBuffer>;
|
|
203
|
-
computeSegmentId: (desiredSeekTimeMs: number, rendition:
|
|
204
|
-
id?: RenditionId;
|
|
205
|
-
trackId: number | undefined;
|
|
206
|
-
src: string;
|
|
207
|
-
segmentDurationMs?: number;
|
|
208
|
-
}) => number | undefined;
|
|
208
|
+
computeSegmentId: (desiredSeekTimeMs: number, rendition: MediaRendition) => number | undefined;
|
|
209
209
|
/**
|
|
210
210
|
* Get the video rendition, or throws if no video rendition is available
|
|
211
211
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/elements",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.7-beta.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -27,14 +27,13 @@
|
|
|
27
27
|
"license": "UNLICENSED",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@bramus/style-observer": "^1.3.0",
|
|
30
|
-
"@editframe/assets": "0.18.
|
|
30
|
+
"@editframe/assets": "0.18.7-beta.0",
|
|
31
31
|
"@lit/context": "^1.1.2",
|
|
32
32
|
"@lit/task": "^1.0.1",
|
|
33
33
|
"d3": "^7.9.0",
|
|
34
34
|
"debug": "^4.3.5",
|
|
35
35
|
"lit": "^3.1.4",
|
|
36
36
|
"mediabunny": "^1.1.1",
|
|
37
|
-
"mp4box": "^0.5.2",
|
|
38
37
|
"zod": "^3.24.1"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
@@ -124,7 +124,7 @@ describe("EFAudio", () => {
|
|
|
124
124
|
render(
|
|
125
125
|
html`
|
|
126
126
|
<ef-preview>
|
|
127
|
-
<ef-audio src="
|
|
127
|
+
<ef-audio src="media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
128
128
|
</ef-preview>
|
|
129
129
|
`,
|
|
130
130
|
container,
|
|
@@ -151,11 +151,11 @@ describe("EFAudio", () => {
|
|
|
151
151
|
"Fragment index loading failed, skipping duration test:",
|
|
152
152
|
error,
|
|
153
153
|
);
|
|
154
|
-
expect(audio.src).toBe("
|
|
154
|
+
expect(audio.src).toBe("media/bars-n-tone2.mp4");
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
expect(audio.src).toBe("
|
|
158
|
+
expect(audio.src).toBe("media/bars-n-tone2.mp4");
|
|
159
159
|
|
|
160
160
|
// The audio should have loaded successfully and have a duration > 0
|
|
161
161
|
// We don't test for specific duration since real assets may vary
|
|
@@ -272,7 +272,7 @@ describe("EFAudio", () => {
|
|
|
272
272
|
html`
|
|
273
273
|
<ef-preview>
|
|
274
274
|
<ef-timegroup mode="sequence">
|
|
275
|
-
<ef-audio src="
|
|
275
|
+
<ef-audio src="media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
276
276
|
</ef-timegroup>
|
|
277
277
|
</ef-preview>
|
|
278
278
|
`,
|
|
@@ -612,7 +612,7 @@ describe("EFAudio", () => {
|
|
|
612
612
|
html`
|
|
613
613
|
<ef-preview>
|
|
614
614
|
<ef-timegroup mode="sequence">
|
|
615
|
-
<ef-audio src="
|
|
615
|
+
<ef-audio src="media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
616
616
|
</ef-timegroup>
|
|
617
617
|
</ef-preview>
|
|
618
618
|
`,
|
|
@@ -637,7 +637,7 @@ describe("EFAudio", () => {
|
|
|
637
637
|
html`
|
|
638
638
|
<ef-preview>
|
|
639
639
|
<ef-timegroup mode="contain">
|
|
640
|
-
<ef-audio src="
|
|
640
|
+
<ef-audio src="media/bars-n-tone2.mp4" mode="asset" sourcein="1s" sourceout="4s"></ef-audio>
|
|
641
641
|
</ef-timegroup>
|
|
642
642
|
</ef-preview>
|
|
643
643
|
`,
|
|
@@ -688,7 +688,7 @@ describe("EFAudio", () => {
|
|
|
688
688
|
render(
|
|
689
689
|
html`
|
|
690
690
|
<ef-preview>
|
|
691
|
-
<ef-audio src="
|
|
691
|
+
<ef-audio src="media/bars-n-tone2.mp4" mode="asset"></ef-audio>
|
|
692
692
|
</ef-preview>
|
|
693
693
|
`,
|
|
694
694
|
container,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe } from "vitest";
|
|
2
|
+
import { test as baseTest } from "../../../test/useMSW.js";
|
|
3
|
+
|
|
4
|
+
import { UrlGenerator } from "../../transcoding/utils/UrlGenerator";
|
|
5
|
+
import "../EFVideo.js";
|
|
6
|
+
import type { EFVideo } from "../EFVideo.js";
|
|
7
|
+
import { AssetMediaEngine } from "./AssetMediaEngine";
|
|
8
|
+
|
|
9
|
+
const test = baseTest.extend<{
|
|
10
|
+
urlGenerator: UrlGenerator;
|
|
11
|
+
mediaEngine: AssetMediaEngine;
|
|
12
|
+
host: EFVideo;
|
|
13
|
+
}>({
|
|
14
|
+
host: async ({}, use: any) => {
|
|
15
|
+
const configuration = document.createElement("ef-configuration");
|
|
16
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
17
|
+
configuration.setAttribute("api-host", apiHost);
|
|
18
|
+
configuration.apiHost = apiHost;
|
|
19
|
+
|
|
20
|
+
const host = document.createElement("ef-video");
|
|
21
|
+
configuration.appendChild(host);
|
|
22
|
+
host.src = "bars-n-tone.mp4";
|
|
23
|
+
await use(host as EFVideo);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
urlGenerator: async ({}, use: any) => {
|
|
27
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
28
|
+
const generator = new UrlGenerator(() => apiHost);
|
|
29
|
+
await use(generator);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
mediaEngine: async ({ urlGenerator, host }, use: any) => {
|
|
33
|
+
const engine = await AssetMediaEngine.fetch(host, urlGenerator, host.src);
|
|
34
|
+
await use(engine);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("AssetMediaEngine", () => {
|
|
39
|
+
test("provides duration from fragment index data", async ({
|
|
40
|
+
mediaEngine,
|
|
41
|
+
expect,
|
|
42
|
+
}) => {
|
|
43
|
+
expect(mediaEngine.durationMs).toBeCloseTo(10023, 0); // Updated: improved mediabunny processing changed duration
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("provides source URL from constructor", async ({
|
|
47
|
+
mediaEngine,
|
|
48
|
+
host,
|
|
49
|
+
expect,
|
|
50
|
+
}) => {
|
|
51
|
+
expect(mediaEngine.src).toBe(host.src);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("returns audio rendition with correct properties", ({
|
|
55
|
+
mediaEngine,
|
|
56
|
+
host,
|
|
57
|
+
expect,
|
|
58
|
+
}) => {
|
|
59
|
+
const audioRendition = mediaEngine.audioRendition;
|
|
60
|
+
expect(audioRendition.trackId).toBe(2);
|
|
61
|
+
expect(audioRendition.src).toBe(host.src);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("returns video rendition with correct properties", ({
|
|
65
|
+
mediaEngine,
|
|
66
|
+
host,
|
|
67
|
+
expect,
|
|
68
|
+
}) => {
|
|
69
|
+
const videoRendition = mediaEngine.videoRendition;
|
|
70
|
+
expect(videoRendition.trackId).toBe(1);
|
|
71
|
+
expect(videoRendition.src).toBe(host.src);
|
|
72
|
+
expect(videoRendition.startTimeOffsetMs).toBeCloseTo(66.6, 0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("provides templates for asset endpoints", ({ mediaEngine, expect }) => {
|
|
76
|
+
expect(mediaEngine.templates).toEqual({
|
|
77
|
+
initSegment: "/@ef-track/{src}?trackId={trackId}",
|
|
78
|
+
mediaSegment: "/@ef-track/{src}?trackId={trackId}",
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("builds init and media segment URLs", ({
|
|
83
|
+
mediaEngine,
|
|
84
|
+
host,
|
|
85
|
+
expect,
|
|
86
|
+
}) => {
|
|
87
|
+
expect(mediaEngine.buildInitSegmentUrl(2)).toBe(
|
|
88
|
+
`/@ef-track/${host.src}?trackId=2`,
|
|
89
|
+
);
|
|
90
|
+
expect(mediaEngine.buildMediaSegmentUrl(2, 5)).toBe(
|
|
91
|
+
`/@ef-track/${host.src}?trackId=2&segmentId=5`,
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("computes segment ID for audio (0-based)", ({ mediaEngine, expect }) => {
|
|
96
|
+
const audio = mediaEngine.audioRendition;
|
|
97
|
+
expect(mediaEngine.computeSegmentId(500, audio as any)).toBe(0);
|
|
98
|
+
expect(mediaEngine.computeSegmentId(1500, audio as any)).toBe(0);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -9,6 +9,11 @@ import type {
|
|
|
9
9
|
import type { UrlGenerator } from "../../transcoding/utils/UrlGenerator";
|
|
10
10
|
import type { EFMedia } from "../EFMedia";
|
|
11
11
|
import { BaseMediaEngine } from "./BaseMediaEngine";
|
|
12
|
+
import type { MediaRendition } from "./shared/MediaTaskUtils";
|
|
13
|
+
import {
|
|
14
|
+
convertToScaledTime,
|
|
15
|
+
roundToMilliseconds,
|
|
16
|
+
} from "./shared/PrecisionUtils";
|
|
12
17
|
|
|
13
18
|
export class AssetMediaEngine extends BaseMediaEngine implements MediaEngine {
|
|
14
19
|
static async fetch(host: EFMedia, urlGenerator: UrlGenerator, src: string) {
|
|
@@ -185,10 +190,7 @@ export class AssetMediaEngine extends BaseMediaEngine implements MediaEngine {
|
|
|
185
190
|
return segmentRanges;
|
|
186
191
|
}
|
|
187
192
|
|
|
188
|
-
computeSegmentId(
|
|
189
|
-
desiredSeekTimeMs: number,
|
|
190
|
-
rendition: { trackId: number | undefined; src: string },
|
|
191
|
-
) {
|
|
193
|
+
computeSegmentId(desiredSeekTimeMs: number, rendition: MediaRendition) {
|
|
192
194
|
if (!rendition.trackId) {
|
|
193
195
|
throw new Error("Track ID is required for asset metadata");
|
|
194
196
|
}
|
|
@@ -197,14 +199,57 @@ export class AssetMediaEngine extends BaseMediaEngine implements MediaEngine {
|
|
|
197
199
|
throw new Error("Track not found");
|
|
198
200
|
}
|
|
199
201
|
const { timescale, segments } = track;
|
|
200
|
-
|
|
202
|
+
|
|
203
|
+
// Apply startTimeOffsetMs to map user timeline to media timeline for segment selection
|
|
204
|
+
const startTimeOffsetMs =
|
|
205
|
+
("startTimeOffsetMs" in rendition && rendition.startTimeOffsetMs) || 0;
|
|
206
|
+
const mediaTimeMs = roundToMilliseconds(
|
|
207
|
+
desiredSeekTimeMs + startTimeOffsetMs,
|
|
208
|
+
);
|
|
209
|
+
// Convert to timescale units using consistent precision
|
|
210
|
+
const scaledSeekTime = convertToScaledTime(mediaTimeMs, timescale);
|
|
211
|
+
|
|
212
|
+
// Find the segment that contains the actual seek time
|
|
201
213
|
for (let i = segments.length - 1; i >= 0; i--) {
|
|
202
214
|
// biome-ignore lint/style/noNonNullAssertion: we know the segment is not null
|
|
203
215
|
const segment = segments[i]!;
|
|
204
|
-
|
|
216
|
+
const segmentEndTime = segment.cts + segment.duration;
|
|
217
|
+
|
|
218
|
+
// Check if the seek time falls within this segment
|
|
219
|
+
if (segment.cts <= scaledSeekTime && scaledSeekTime < segmentEndTime) {
|
|
205
220
|
return i;
|
|
206
221
|
}
|
|
207
222
|
}
|
|
208
|
-
|
|
223
|
+
|
|
224
|
+
// Handle gaps: if no exact segment contains the time, find the nearest one
|
|
225
|
+
// This handles cases where seek time falls between segments (like 8041.667ms)
|
|
226
|
+
let nearestSegmentIndex = 0;
|
|
227
|
+
let nearestDistance = Number.MAX_SAFE_INTEGER;
|
|
228
|
+
|
|
229
|
+
for (let i = 0; i < segments.length; i++) {
|
|
230
|
+
// biome-ignore lint/style/noNonNullAssertion: we know the segment is not null
|
|
231
|
+
const segment = segments[i]!;
|
|
232
|
+
const segmentStartTime = segment.cts;
|
|
233
|
+
const segmentEndTime = segment.cts + segment.duration;
|
|
234
|
+
|
|
235
|
+
let distance: number;
|
|
236
|
+
if (scaledSeekTime < segmentStartTime) {
|
|
237
|
+
// Time is before this segment
|
|
238
|
+
distance = segmentStartTime - scaledSeekTime;
|
|
239
|
+
} else if (scaledSeekTime >= segmentEndTime) {
|
|
240
|
+
// Time is after this segment
|
|
241
|
+
distance = scaledSeekTime - segmentEndTime;
|
|
242
|
+
} else {
|
|
243
|
+
// Time is within this segment (should have been caught above, but just in case)
|
|
244
|
+
return i;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (distance < nearestDistance) {
|
|
248
|
+
nearestDistance = distance;
|
|
249
|
+
nearestSegmentIndex = i;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return nearestSegmentIndex;
|
|
209
254
|
}
|
|
210
255
|
}
|