@videojs/spf 0.1.0-alpha.2 → 10.0.0-beta.1
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/LICENSE +20 -0
- package/dist/adapter-CMw-rvbk.js +3512 -0
- package/dist/adapter-CMw-rvbk.js.map +1 -0
- package/dist/adapter-l8iJN_GI.d.ts +689 -0
- package/dist/adapter-l8iJN_GI.d.ts.map +1 -0
- package/dist/dom/index.d.ts +243 -0
- package/dist/dom/index.d.ts.map +1 -0
- package/dist/dom/index.js +38 -0
- package/dist/dom/index.js.map +1 -0
- package/dist/dom/playback-engine/index.d.ts +2 -0
- package/dist/dom/playback-engine/index.js +4 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1
- package/dist/src-DRsS_H80.js +14 -0
- package/dist/src-DRsS_H80.js.map +1 -0
- package/package.json +19 -14
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { a as PresentationAction, c as SourceBufferActor, d as WritableState, f as BandwidthState, l as TrackSelectionState, o as EventStream, s as loadTextTrackCues, t as SpfMedia, u as Presentation } from "../adapter-l8iJN_GI.js";
|
|
2
|
+
|
|
3
|
+
//#region src/dom/features/setup-sourcebuffer.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Media track type for SourceBuffer setup.
|
|
7
|
+
* Text tracks are excluded as they don't use MSE SourceBuffers.
|
|
8
|
+
*/
|
|
9
|
+
type MediaTrackType = 'video' | 'audio';
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/dom/features/load-segments.d.ts
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* State shape for segment loading.
|
|
15
|
+
*/
|
|
16
|
+
interface SegmentLoadingState extends TrackSelectionState {
|
|
17
|
+
presentation?: Presentation;
|
|
18
|
+
preload?: string;
|
|
19
|
+
bandwidthState?: BandwidthState;
|
|
20
|
+
/** Current playback position in seconds. Defaults to 0 when undefined. */
|
|
21
|
+
currentTime?: number;
|
|
22
|
+
/** True once the user has initiated playback. Allows segment loading regardless of preload setting. */
|
|
23
|
+
playbackInitiated?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Owners shape for segment loading.
|
|
27
|
+
*/
|
|
28
|
+
interface SegmentLoadingOwners {
|
|
29
|
+
videoBuffer?: SourceBuffer;
|
|
30
|
+
audioBuffer?: SourceBuffer;
|
|
31
|
+
videoBufferActor?: SourceBufferActor;
|
|
32
|
+
audioBufferActor?: SourceBufferActor;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load segments orchestration — Reactor layer.
|
|
36
|
+
*
|
|
37
|
+
* Sends typed load messages to a SegmentLoaderActor when relevant conditions
|
|
38
|
+
* change. Uses targeted subscriptions rather than broad combineLatest so only
|
|
39
|
+
* meaningful state changes trigger evaluation.
|
|
40
|
+
*
|
|
41
|
+
* Condition hierarchy (see SegmentLoadingKey for detail):
|
|
42
|
+
*
|
|
43
|
+
* !playbackInitiated
|
|
44
|
+
* preload==='none' (or unset) → dormant; no trigger
|
|
45
|
+
* preload==='metadata' → trigger on transition to 'metadata'
|
|
46
|
+
* preload==='auto' → trigger on transition to 'auto'
|
|
47
|
+
*
|
|
48
|
+
* !playbackInitiated → playbackInitiated
|
|
49
|
+
* preload !== 'auto' → trigger (message shape changes)
|
|
50
|
+
* preload === 'auto' → suppressed (was already full-range mode;
|
|
51
|
+
* let segmentStart take over post-play)
|
|
52
|
+
* KNOWN LIMITATION: seek-before-play with
|
|
53
|
+
* preload='auto' is not supported — if the
|
|
54
|
+
* user seeks before pressing play, the
|
|
55
|
+
* first re-send is delayed until the next
|
|
56
|
+
* segment boundary crossing post-play.
|
|
57
|
+
*
|
|
58
|
+
* playbackInitiated
|
|
59
|
+
* resolvedTrackId changes → trigger
|
|
60
|
+
* segmentStart(currentTime) changes → trigger (segment boundary only)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const cleanup = loadSegments({ state, owners }, { type: 'video' });
|
|
64
|
+
*/
|
|
65
|
+
declare function loadSegments({
|
|
66
|
+
state,
|
|
67
|
+
owners
|
|
68
|
+
}: {
|
|
69
|
+
state: WritableState<SegmentLoadingState>;
|
|
70
|
+
owners: WritableState<SegmentLoadingOwners>;
|
|
71
|
+
}, config: {
|
|
72
|
+
type: MediaTrackType;
|
|
73
|
+
}): () => void;
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/dom/features/track-current-time.d.ts
|
|
76
|
+
/**
|
|
77
|
+
* State shape for current time tracking.
|
|
78
|
+
*/
|
|
79
|
+
interface CurrentTimeState {
|
|
80
|
+
currentTime?: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Owners shape for current time tracking.
|
|
84
|
+
*/
|
|
85
|
+
interface CurrentTimeOwners {
|
|
86
|
+
mediaElement?: HTMLMediaElement | undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Track current playback position from the media element.
|
|
90
|
+
*
|
|
91
|
+
* Mirrors `mediaElement.currentTime` into reactive state on:
|
|
92
|
+
* - `timeupdate` — fires during playback (~4 Hz)
|
|
93
|
+
* - `seeking` — fires when a seek begins; per spec, `currentTime` is
|
|
94
|
+
* already at the new position when this event dispatches, so buffer
|
|
95
|
+
* management can react immediately rather than waiting for `timeupdate`,
|
|
96
|
+
* which does not fire while paused.
|
|
97
|
+
*
|
|
98
|
+
* Also syncs immediately when a media element becomes available.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* const cleanup = trackCurrentTime({ state, owners });
|
|
102
|
+
*/
|
|
103
|
+
declare function trackCurrentTime({
|
|
104
|
+
state,
|
|
105
|
+
owners
|
|
106
|
+
}: {
|
|
107
|
+
state: WritableState<CurrentTimeState>;
|
|
108
|
+
owners: WritableState<CurrentTimeOwners>;
|
|
109
|
+
}): () => void;
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/dom/features/track-playback-initiated.d.ts
|
|
112
|
+
/**
|
|
113
|
+
* State shape for playback initiation tracking.
|
|
114
|
+
*/
|
|
115
|
+
interface PlaybackInitiatedState {
|
|
116
|
+
/** True once the user has initiated playback (play event fired). */
|
|
117
|
+
playbackInitiated?: boolean;
|
|
118
|
+
/** Current presentation — watched for URL changes to reset playbackInitiated. */
|
|
119
|
+
presentation?: {
|
|
120
|
+
url?: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Owners shape for playback initiation tracking.
|
|
125
|
+
*/
|
|
126
|
+
interface PlaybackInitiatedOwners {
|
|
127
|
+
mediaElement?: HTMLMediaElement | undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Track whether playback has been initiated by the user.
|
|
131
|
+
*
|
|
132
|
+
* Sets `state.playbackInitiated = true` when the media element fires a `play`
|
|
133
|
+
* event (via `element.play()`, native controls, or autoplay) and simultaneously
|
|
134
|
+
* dispatches `{ type: 'play' }` to the event stream so `resolvePresentation`
|
|
135
|
+
* can react.
|
|
136
|
+
*
|
|
137
|
+
* Resets `state.playbackInitiated = false` when `presentation.url` changes,
|
|
138
|
+
* so a new source with `preload="none"` won't load segments until play is
|
|
139
|
+
* triggered again.
|
|
140
|
+
*
|
|
141
|
+
* This flag is used by `shouldLoadSegments` to allow segment loading after
|
|
142
|
+
* play is initiated regardless of the initial `preload` setting — `preload`
|
|
143
|
+
* is a startup hint, not a runtime gate.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* const cleanup = trackPlaybackInitiated({ state, owners, events });
|
|
147
|
+
*/
|
|
148
|
+
declare function trackPlaybackInitiated({
|
|
149
|
+
state,
|
|
150
|
+
owners,
|
|
151
|
+
events
|
|
152
|
+
}: {
|
|
153
|
+
state: WritableState<PlaybackInitiatedState>;
|
|
154
|
+
owners: WritableState<PlaybackInitiatedOwners>;
|
|
155
|
+
events: EventStream<PresentationAction>;
|
|
156
|
+
}): () => void;
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/dom/features/track-playback-rate.d.ts
|
|
159
|
+
/**
|
|
160
|
+
* State shape for playback rate tracking.
|
|
161
|
+
*/
|
|
162
|
+
interface PlaybackRateState {
|
|
163
|
+
playbackRate?: number;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Owners shape for playback rate tracking.
|
|
167
|
+
*/
|
|
168
|
+
interface PlaybackRateOwners {
|
|
169
|
+
mediaElement?: HTMLMediaElement | undefined;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Track playback rate from the media element.
|
|
173
|
+
*
|
|
174
|
+
* Mirrors `mediaElement.playbackRate` into reactive state on each `ratechange`
|
|
175
|
+
* event. Also syncs immediately when a media element becomes available.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* const cleanup = trackPlaybackRate({ state, owners });
|
|
179
|
+
*/
|
|
180
|
+
declare function trackPlaybackRate({
|
|
181
|
+
state,
|
|
182
|
+
owners
|
|
183
|
+
}: {
|
|
184
|
+
state: WritableState<PlaybackRateState>;
|
|
185
|
+
owners: WritableState<PlaybackRateOwners>;
|
|
186
|
+
}): () => void;
|
|
187
|
+
//#endregion
|
|
188
|
+
//#region src/dom/media/append-segment.d.ts
|
|
189
|
+
/**
|
|
190
|
+
* Segment appender helper (P11)
|
|
191
|
+
*
|
|
192
|
+
* Appends media segments (ArrayBuffer) to SourceBuffer.
|
|
193
|
+
*/
|
|
194
|
+
/**
|
|
195
|
+
* Append a media segment to a SourceBuffer.
|
|
196
|
+
*
|
|
197
|
+
* Waits for the SourceBuffer to be ready (not updating), then appends
|
|
198
|
+
* the segment data. Returns a promise that resolves when append completes.
|
|
199
|
+
*
|
|
200
|
+
* @param sourceBuffer - The SourceBuffer to append to
|
|
201
|
+
* @param segmentData - The segment data as ArrayBuffer
|
|
202
|
+
* @returns Promise that resolves when append completes
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const data = await fetch(segmentUrl).then(r => r.arrayBuffer());
|
|
206
|
+
* await appendSegment(videoSourceBuffer, data);
|
|
207
|
+
*/
|
|
208
|
+
declare function appendSegment(sourceBuffer: SourceBuffer, segmentData: ArrayBuffer): Promise<void>;
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/dom/media/buffer-flusher.d.ts
|
|
211
|
+
/**
|
|
212
|
+
* Buffer flusher helper (P12)
|
|
213
|
+
*
|
|
214
|
+
* Removes a time range from a SourceBuffer to manage memory.
|
|
215
|
+
*/
|
|
216
|
+
/**
|
|
217
|
+
* Remove a time range from a SourceBuffer.
|
|
218
|
+
*
|
|
219
|
+
* Waits for the SourceBuffer to be ready (not updating), then removes
|
|
220
|
+
* the specified range. Returns a promise that resolves when removal completes.
|
|
221
|
+
*
|
|
222
|
+
* @param sourceBuffer - The SourceBuffer to remove data from
|
|
223
|
+
* @param start - Start of the time range to remove (seconds)
|
|
224
|
+
* @param end - End of the time range to remove (seconds)
|
|
225
|
+
* @returns Promise that resolves when removal completes
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* await flushBuffer(videoSourceBuffer, 0, 30);
|
|
229
|
+
*/
|
|
230
|
+
declare function flushBuffer(sourceBuffer: SourceBuffer, start: number, end: number): Promise<void>;
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/dom/text/parse-vtt-segment.d.ts
|
|
233
|
+
/**
|
|
234
|
+
* Parse a VTT segment using browser's native parser.
|
|
235
|
+
*
|
|
236
|
+
* Creates a dummy video element with a track element to leverage
|
|
237
|
+
* the browser's optimized VTT parsing. Returns parsed VTTCue objects.
|
|
238
|
+
*/
|
|
239
|
+
declare function parseVttSegment(url: string): Promise<VTTCue[]>;
|
|
240
|
+
declare function destroyVttParser(): void;
|
|
241
|
+
//#endregion
|
|
242
|
+
export { type CurrentTimeOwners, type CurrentTimeState, type PlaybackInitiatedOwners, type PlaybackInitiatedState, type PlaybackRateOwners, type PlaybackRateState, SpfMedia, appendSegment, destroyVttParser, flushBuffer, loadSegments, loadTextTrackCues, parseVttSegment, trackCurrentTime, trackPlaybackInitiated, trackPlaybackRate };
|
|
243
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/dom/features/setup-sourcebuffer.ts","../../src/dom/features/load-segments.ts","../../src/dom/features/track-current-time.ts","../../src/dom/features/track-playback-initiated.ts","../../src/dom/features/track-playback-rate.ts","../../src/dom/media/append-segment.ts","../../src/dom/media/buffer-flusher.ts","../../src/dom/text/parse-vtt-segment.ts"],"sourcesContent":[],"mappings":";;;;;;;AC+DA;AACiB,KD7CL,cAAA,GC6CK,OAAA,GAAA,OAAA;;;;;;;AAD+C,UAA/C,mBAAA,SAA4B,mBAAmB,CAAA;EAa/C,YAAA,CAAA,EAZA,YAYoB;EACrB,OAAA,CAAA,EAAA,MAAA;EACA,cAAA,CAAA,EAZG,cAYH;EACK;EACA,WAAA,CAAA,EAAA,MAAA;EAAiB;EAgItB,iBAAY,CAAA,EAAA,OAAA;;;;;AAMF,UA1IT,oBAAA,CA0IS;EAAd,WAAA,CAAA,EAzII,YAyIJ;EAEM,WAAA,CAAA,EA1IF,YA0IE;EAAc,gBAAA,CAAA,EAzIX,iBAyIW;qBAxIX;;;AC1ErB;AAOA;AA6BA;;;;;;;;;;;AClCA;AAUA;AAuBA;;;;;;;;;;;;;;ACnCA;AAOiB,iBHmMD,YAAA,CGlMC;EAAA,KAAA;EAAA;CAAgB,EAAA;EAsBjB,KAAA,EHiLL,aGjLsB,CHiLR,mBGjLQ,CAAA;EAC/B,MAAA,EHiLU,aGjLV,CHiLwB,oBGjLxB,CAAA;CACA,EAAA,MAAA,EAAA;EAEqB,IAAA,EHgLL,cGhLK;CAAd,CAAA,EAAA,GAAA,GAAA,IAAA;;;;;AJrBT;UEbiB,gBAAA;;;ADyDjB;;;AAA6C,UClD5B,iBAAA,CDkD4B;EAAmB,YAAA,CAAA,ECjD/C,gBDiD+C,GAAA,SAAA;AAahE;;;;;;;;;;;ACtEA;AAOA;AA6BA;;;AAIuB,iBAJP,gBAAA,CAIO;EAAA,KAAA;EAAA;CAAA,EAAA;EAAd,KAAA,EAAA,aAAA,CAAc,gBAAd,CAAA;EACe,MAAA,EAAd,aAAc,CAAA,iBAAA,CAAA;CAAd,CAAA,EAAA,GAAA,GAAA,IAAA;;;AF5BV;;;UGXiB,sBAAA;EFuDA;EACA,iBAAA,CAAA,EAAA,OAAA;EAEE;EAH0B,YAAA,CAAA,EAAA;IAAmB,GAAA,CAAA,EAAA,MAAA;EAa/C,CAAA;;;;;AAIqB,UE9DrB,uBAAA,CF8DqB;EAgItB,YAAA,CAAA,EE7LC,gBF6LW,GAAA,SAAA;;;;;;;;;;;;AC1M5B;AAOA;AA6BA;;;;;;;AAKuB,iBCNP,sBAAA,CDMO;EAAA,KAAA;EAAA,MAAA;EAAA;ACvCvB,CDuCuB,EAAA;SCDd,cAAc;UACb,cAAc;UACd,YAAY;AAxCtB,CAAA,CAAA,EAAiB,GAAA,GAAA,IAAA;;;;;AHWjB;UIbiB,iBAAA;;;AHyDjB;;;AAA6C,UGlD5B,kBAAA,CHkD4B;EAAmB,YAAA,CAAA,EGjD/C,gBHiD+C,GAAA,SAAA;AAahE;;;;;;;;;;iBGxCgB,iBAAA;;;AFMhB;EApCiB,KAAA,EEkCR,aFlCwB,CEkCV,iBFlCU,CAAA;EAOhB,MAAA,EE4BP,aF5BwB,CE4BV,kBF3BP,CAAA;AA4BjB,CAAA,CAAA,EAAgB,GAAA,GAAA,IAAA;;;;;;AFvBhB;;;;AC4CA;;;;;AAaA;;;;;;AAoIA;AAEI,iBI9LkB,aAAA,CJ8LlB,YAAA,EI9L8C,YJ8L9C,EAAA,WAAA,EI9LyE,WJ8LzE,CAAA,EI9LuF,OJ8LvF,CAAA,IAAA,CAAA;;;;;;AD/LJ;;;;AC4CA;;;;;AAaA;;;;;;AAoIA;AAEI,iBK9LkB,WAAA,CL8LlB,YAAA,EK9L4C,YL8L5C,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EK9LuF,OL8LvF,CAAA,IAAA,CAAA;;;;;;AD/LJ;;;iBOEgB,eAAA,eAA8B,QAAQ;AN0CrC,iBMAD,gBAAA,CAAA,CNAqB,EAAA,IAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "../src-DRsS_H80.js";
|
|
2
|
+
import { a as trackPlaybackInitiated, c as destroyVttParser, i as appendSegment, l as parseVttSegment, o as trackCurrentTime, r as flushBuffer, s as loadTextTrackCues, t as SpfMedia, u as loadSegments } from "../adapter-CMw-rvbk.js";
|
|
3
|
+
import { listen } from "@videojs/utils/dom";
|
|
4
|
+
|
|
5
|
+
//#region src/dom/features/track-playback-rate.ts
|
|
6
|
+
/**
|
|
7
|
+
* Track playback rate from the media element.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors `mediaElement.playbackRate` into reactive state on each `ratechange`
|
|
10
|
+
* event. Also syncs immediately when a media element becomes available.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const cleanup = trackPlaybackRate({ state, owners });
|
|
14
|
+
*/
|
|
15
|
+
function trackPlaybackRate({ state, owners }) {
|
|
16
|
+
let lastMediaElement;
|
|
17
|
+
let removeListener = null;
|
|
18
|
+
const unsubscribe = owners.subscribe((currentOwners) => {
|
|
19
|
+
const { mediaElement } = currentOwners;
|
|
20
|
+
if (mediaElement === lastMediaElement) return;
|
|
21
|
+
removeListener?.();
|
|
22
|
+
removeListener = null;
|
|
23
|
+
lastMediaElement = mediaElement;
|
|
24
|
+
if (!mediaElement) return;
|
|
25
|
+
state.patch({ playbackRate: mediaElement.playbackRate });
|
|
26
|
+
removeListener = listen(mediaElement, "ratechange", () => {
|
|
27
|
+
state.patch({ playbackRate: mediaElement.playbackRate });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return () => {
|
|
31
|
+
removeListener?.();
|
|
32
|
+
unsubscribe();
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { SpfMedia, appendSegment, destroyVttParser, flushBuffer, loadSegments, loadTextTrackCues, parseVttSegment, trackCurrentTime, trackPlaybackInitiated, trackPlaybackRate };
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["lastMediaElement: HTMLMediaElement | undefined","removeListener: (() => void) | null"],"sources":["../../src/dom/features/track-playback-rate.ts"],"sourcesContent":["import { listen } from '@videojs/utils/dom';\nimport type { WritableState } from '../../core/state/create-state';\n\n/**\n * State shape for playback rate tracking.\n */\nexport interface PlaybackRateState {\n playbackRate?: number;\n}\n\n/**\n * Owners shape for playback rate tracking.\n */\nexport interface PlaybackRateOwners {\n mediaElement?: HTMLMediaElement | undefined;\n}\n\n/**\n * Check if we can track playback rate.\n *\n * Requires:\n * - mediaElement exists in owners\n */\nexport function canTrackPlaybackRate(owners: PlaybackRateOwners): boolean {\n return !!owners.mediaElement;\n}\n\n/**\n * Track playback rate from the media element.\n *\n * Mirrors `mediaElement.playbackRate` into reactive state on each `ratechange`\n * event. Also syncs immediately when a media element becomes available.\n *\n * @example\n * const cleanup = trackPlaybackRate({ state, owners });\n */\nexport function trackPlaybackRate({\n state,\n owners,\n}: {\n state: WritableState<PlaybackRateState>;\n owners: WritableState<PlaybackRateOwners>;\n}): () => void {\n let lastMediaElement: HTMLMediaElement | undefined;\n let removeListener: (() => void) | null = null;\n\n const unsubscribe = owners.subscribe((currentOwners) => {\n const { mediaElement } = currentOwners;\n\n if (mediaElement === lastMediaElement) return;\n\n removeListener?.();\n removeListener = null;\n lastMediaElement = mediaElement;\n\n if (!mediaElement) return;\n\n state.patch({ playbackRate: mediaElement.playbackRate });\n\n removeListener = listen(mediaElement, 'ratechange', () => {\n state.patch({ playbackRate: mediaElement.playbackRate });\n });\n });\n\n return () => {\n removeListener?.();\n unsubscribe();\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAoCA,SAAgB,kBAAkB,EAChC,OACA,UAIa;CACb,IAAIA;CACJ,IAAIC,iBAAsC;CAE1C,MAAM,cAAc,OAAO,WAAW,kBAAkB;EACtD,MAAM,EAAE,iBAAiB;AAEzB,MAAI,iBAAiB,iBAAkB;AAEvC,oBAAkB;AAClB,mBAAiB;AACjB,qBAAmB;AAEnB,MAAI,CAAC,aAAc;AAEnB,QAAM,MAAM,EAAE,cAAc,aAAa,cAAc,CAAC;AAExD,mBAAiB,OAAO,cAAc,oBAAoB;AACxD,SAAM,MAAM,EAAE,cAAc,aAAa,cAAc,CAAC;IACxD;GACF;AAEF,cAAa;AACX,oBAAkB;AAClB,eAAa"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Stream Processing Framework (SPF) for Video.js 10
|
|
4
|
+
*
|
|
5
|
+
* Bundle size target: < 20KB (minified + gzipped)
|
|
6
|
+
* Primary use case: CMAF HLS playback with Video.js v10
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
declare const VERSION = "0.1.0";
|
|
11
|
+
//#endregion
|
|
12
|
+
export { VERSION };
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAWA;;;;;;;cAAa,OAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{isNil as e,isUndefined as t}from"@videojs/utils/predicate";import{listen as n}from"@videojs/utils/dom";const r=Symbol(`@videojs/event-stream`);function i(){let e=new Set;return{[r]:!0,dispatch(t){let n=Array.from(e);for(let e of n)e(t)},subscribe(t){return e.add(t),()=>e.delete(t)}}}function a(e){let t=t=>{let n=Array(e.length),r=Array(e.length).fill(!1),i=[];for(let a=0;a<e.length;a++){let o=e[a].subscribe(e=>{n[a]=e,r[a]=!0,r.every(e=>e)&&t([...n])});i.push(o)}return()=>{for(let e of i)e()}};return{subscribe(e,n,r){if(n===void 0)return t(e);let i=e,a=n,o=r?.equalityFn??Object.is,s,c=!1;return t(e=>{let t=i(e);(!c||!o(s,t))&&(s=t,c=!0,a(t))})}}}function o(e){return`segments`in e}function s(e){return e.duration!==void 0}const c={video:`selectedVideoTrackId`,audio:`selectedAudioTrackId`,text:`selectedTextTrackId`},l={video:`videoBuffer`,audio:`audioBuffer`};function u(e,t){let{presentation:n}=e;if(!n||!(`id`in n))return;let r=e[c[t]];return n.selectionSets.find(({type:e})=>e===t)?.switchingSets[0]?.tracks.find(({id:e})=>e===r)}function d(e){return e.presentation?!!(e.selectedVideoTrackId||e.selectedAudioTrackId):!1}function f(e){if(!d(e))return!1;let{presentation:t}=e;if(t.duration!==void 0)return!1;let n=e.selectedVideoTrackId?u(e,`video`):void 0,r=e.selectedAudioTrackId?u(e,`audio`):void 0;return!!(n&&o(n)||r&&o(r))}function p(e){let t=e.selectedVideoTrackId?u(e,`video`):void 0;if(t&&o(t))return t.duration;let n=e.selectedAudioTrackId?u(e,`audio`):void 0;if(n&&o(n))return n.duration}function m({state:e}){return a([e]).subscribe(([t])=>{if(!f(t))return;let n=p(t);if(n===void 0||!Number.isFinite(n))return;let{presentation:r}=t;e.patch({presentation:{...r,duration:n}})})}function h(e){return Math.exp(Math.log(.5)/e)}function g(e,t,n,r){let i=h(r)**n;return t*(1-i)+i*e}function _(e,t,n){return t===0?0:e/(1-h(n)**t)}const v={fastHalfLife:2,slowHalfLife:5,minTotalBytes:128e3,minBytes:16e3,minDuration:5};function ee(e,t,n,r=v){let i=e.bytesSampled+n;if(n<r.minBytes||t<r.minDuration)return{...e,bytesSampled:i};let a=8e3*n/t,o=t/1e3;return{fastEstimate:g(e.fastEstimate,a,o,r.fastHalfLife),fastTotalWeight:e.fastTotalWeight+o,slowEstimate:g(e.slowEstimate,a,o,r.slowHalfLife),slowTotalWeight:e.slowTotalWeight+o,bytesSampled:i}}function te(e,t,n=v){if(e.bytesSampled<n.minTotalBytes)return t;let r=_(e.fastEstimate,e.fastTotalWeight,n.fastHalfLife),i=_(e.slowEstimate,e.slowTotalWeight,n.slowHalfLife);return Math.min(r,i)}const ne={safetyMargin:.85};function y(e,t,n=ne){if(e.length===0)return;let r=e.slice().sort((e,t)=>e.bandwidth-t.bandwidth),i;for(let e of r)t>=e.bandwidth/n.safetyMargin&&(!i||e.bandwidth>i.bandwidth||e.bandwidth===i.bandwidth&&re(e,i))&&(i=e);return i??r[0]}function re(e,t){return(e.width??0)*(e.height??0)>(t.width??0)*(t.height??0)}const b={safetyMargin:.85,minUpgradeInterval:8e3,defaultBandwidth:5e6};function ie(e){return(e.selectionSets?.find(e=>e.type===`video`))?.switchingSets[0]?.tracks??[]}function ae({state:e},t={}){let n=t.safetyMargin??b.safetyMargin,r=t.minUpgradeInterval??b.minUpgradeInterval,i=t.defaultBandwidth??b.defaultBandwidth,a=Date.now(),o=!0;return e.subscribe(t=>{let{presentation:s,bandwidthState:c,selectedVideoTrackId:l,abrDisabled:u}=t;if(u===!0||!s||!c)return;let d=ie(s);if(d.length===0)return;let f=o;o=!1;let p=y(d,te(c,i),{safetyMargin:n});if(!p||p.id===l)return;let m=d.find(e=>e.id===l);if(!m||p.bandwidth>m.bandwidth){let e=Date.now();if(!f&&e-a<r)return;a=e}e.patch({selectedVideoTrackId:p.id})})}async function x(e,t){let n=new Headers(t?.headers);if(e.byteRange){let{start:t,end:r}=e.byteRange;n.set(`Range`,`bytes=${t}-${r}`)}let r=new Request(e.url,{method:`GET`,headers:n,...t});return fetch(r)}async function S(e,t){return(await x(e,t)).arrayBuffer()}function C(e){return e.text()}function w(){return`${Date.now()}-${Math.floor(Math.random()*1e6)}`}function oe(e){let t=new Map;for(let n of e.matchAll(/([A-Z0-9-]+)=(?:"([^"]*)"|([^,]*))/g)){let e=n[1],r=n[2]??n[3]??``;e&&t.set(e,r)}return t}function se(e){let t=/^(\d+)x(\d+)$/.exec(e);return t?{width:Number.parseInt(t[1],10),height:Number.parseInt(t[2],10)}:null}function ce(e){let t=Number.parseFloat(e);if(!(Number.isNaN(t)||t<=0))return Math.abs(t-23.976)<.01?{frameRateNumerator:24e3,frameRateDenominator:1001}:Math.abs(t-29.97)<.01?{frameRateNumerator:3e4,frameRateDenominator:1001}:Math.abs(t-59.94)<.01?{frameRateNumerator:6e4,frameRateDenominator:1001}:(t%1,{frameRateNumerator:Math.round(t)})}function T(e){let t=e.split(`,`).map(e=>e.trim()),n={};for(let e of t)e.startsWith(`avc1.`)||e.startsWith(`hvc1.`)||e.startsWith(`hev1.`)?n.video=e:e.startsWith(`mp4a.`)&&(n.audio=e);return n}function le(e){let t=e.split(`,`)[0]??e,n=Number.parseFloat(t);return Number.isNaN(n)?0:n}function E(e,t){let n=/^(\d+)(?:@(\d+))?$/.exec(e);if(!n)return null;let r=Number.parseInt(n[1],10);if(Number.isNaN(r))return null;let i;if(n[2]!==void 0){if(i=Number.parseInt(n[2],10),Number.isNaN(i))return null}else if(t!==void 0)i=t;else return null;return{start:i,end:i+r-1}}function ue(e){let t=oe(e);return{get(e){return t.get(e)},getInt(e,n){let r=t.get(e);if(r===void 0)return n;let i=Number.parseInt(r,10);return Number.isNaN(i)?n:i},getFloat(e,n){let r=t.get(e);if(r===void 0)return n;let i=Number.parseFloat(r);return Number.isNaN(i)?n:i},getBool(e){return t.get(e)===`YES`},getResolution(e){let n=t.get(e);if(n)return se(n)??void 0},getFrameRate(e){let n=t.get(e);if(n)return ce(n)}}}function D(e,t){let n=`#${t}:`;return e.startsWith(n)?ue(e.slice(n.length)):null}function O(e,t){return new URL(e,t).href}function de(e,t){let n=t.url,r=e.split(/\r?\n/),i=[],a=[],o=[],s=null;for(let e of r){let t=e.trim();if(!t||t.startsWith(`#`)&&!t.startsWith(`#EXT`)||t===`#EXTM3U`||t.startsWith(`#EXT-X-VERSION:`)||t.startsWith(`#EXT-X-INDEPENDENT-SEGMENTS`))continue;let r=D(t,`EXT-X-MEDIA`);if(r){let e=r.get(`TYPE`),t=r.get(`GROUP-ID`),i=r.get(`NAME`);if(e===`AUDIO`&&t&&i){let e=r.get(`URI`);a.push({groupId:t,name:i,language:r.get(`LANGUAGE`),uri:e?O(e,n):void 0,default:r.getBool(`DEFAULT`),autoselect:r.getBool(`AUTOSELECT`)})}if(e===`SUBTITLES`&&t&&i){let e=r.get(`URI`);e&&o.push({groupId:t,name:i,language:r.get(`LANGUAGE`),uri:O(e,n),default:r.getBool(`DEFAULT`),autoselect:r.getBool(`AUTOSELECT`),forced:r.getBool(`FORCED`)})}continue}let c=D(t,`EXT-X-STREAM-INF`);if(c){s={bandwidth:c.getInt(`BANDWIDTH`,0),resolution:c.getResolution(`RESOLUTION`),codecs:c.get(`CODECS`),frameRate:c.getFrameRate(`FRAME-RATE`),audioGroupId:c.get(`AUDIO`)};continue}!t.startsWith(`#`)&&s&&(i.push({...s,uri:O(t,n)}),s=null)}let c=[],l=[];for(let e of i){if(!e.codecs){c.push(e);continue}let t=T(e.codecs);e.codecs.split(`,`).length===1&&t.audio&&!t.video?l.push(e):c.push(e)}let u=c.map(e=>{let t=e.codecs?T(e.codecs):void 0,n={type:`video`,id:w(),url:e.uri,bandwidth:e.bandwidth,mimeType:`video/mp4`,codecs:[]};return e.resolution?.width!==void 0&&(n.width=e.resolution.width),e.resolution?.height!==void 0&&(n.height=e.resolution.height),t?.video&&(n.codecs=[t.video]),e.frameRate&&(n.frameRate=e.frameRate),e.audioGroupId&&(n.audioGroupId=e.audioGroupId),n}),d=l.map(e=>{let t=e.codecs?T(e.codecs):void 0;return{type:`audio`,id:w(),url:e.uri,bandwidth:e.bandwidth,mimeType:`audio/mp4`,codecs:t?.audio?[t.audio]:[],groupId:e.audioGroupId||`default`,name:`Default`,sampleRate:48e3,channels:2}}),f=[...a.map(e=>{let t;for(let n of i)if(n.audioGroupId===e.groupId&&n.codecs){let e=T(n.codecs);if(e.audio){t=[e.audio];break}}let n={type:`audio`,id:w(),url:e.uri??``,groupId:e.groupId,name:e.name,mimeType:`audio/mp4`,bandwidth:0,sampleRate:48e3,channels:2,codecs:[]};return e.language&&(n.language=e.language),t&&(n.codecs=t),e.default&&(n.default=e.default),e.autoselect&&(n.autoselect=e.autoselect),n}),...d],p=o.map(e=>{let t={type:`text`,id:w(),url:e.uri,groupId:e.groupId,label:e.name,kind:`subtitles`,mimeType:`text/vtt`,bandwidth:0};return e.language&&(t.language=e.language),e.default&&e.autoselect&&(t.default=!0),e.autoselect&&(t.autoselect=e.autoselect),e.forced&&(t.forced=e.forced),t}),m=[];if(u.length>0){let e={id:w(),type:`video`,tracks:u},t={id:w(),type:`video`,switchingSets:[e]};m.push(t)}if(f.length>0){let e={id:w(),type:`audio`,tracks:f},t={id:w(),type:`audio`,switchingSets:[e]};m.push(t)}if(p.length>0){let e={id:w(),type:`text`,tracks:p},t={id:w(),type:`text`,switchingSets:[e]};m.push(t)}return{id:w(),url:t.url,startTime:0,selectionSets:m}}function fe(e){return e!==void 0&&`url`in e&&!(`id`in e)}function pe(e){return fe(e.presentation)}function me(e,t){let{preload:n}=e;return[`auto`,`metadata`].includes(n)||t.type===`play`}function he(e,t){return t.subscribe(t=>{let n=t.mediaElement?.preload||void 0;e.patch({preload:n})})}function ge({state:e,events:t}){let n=!1,r=null,i=a([e,t]).subscribe(async([t,i])=>{if(!(!pe(t)||!me(t,i)||n))try{n=!0,r=new AbortController;let{presentation:i}=t,a=de(await C(await x(i,{signal:r.signal})),i);e.patch({presentation:a})}catch(e){if(e instanceof Error&&e.name===`AbortError`)return;throw e}finally{n=!1,r=null}});return()=>{r?.abort(),i()}}function _e(e,t){let n=e.split(/\r?\n/),r=t.url,i=[],a,o,s=0,c,l=0,u=0,d;for(let e of n){let t=e.trim();if(!t||t.startsWith(`#`)&&!t.startsWith(`#EXT`)||t===`#EXTM3U`||t.startsWith(`#EXT-X-VERSION:`)||t.startsWith(`#EXT-X-TARGETDURATION:`)||t.startsWith(`#EXT-X-PLAYLIST-TYPE:`)||t.startsWith(`#EXT-X-INDEPENDENT-SEGMENTS`))continue;let n=D(t,`EXT-X-MAP`);if(n){let e=n.get(`URI`);if(e){a=O(e,r);let t=n.get(`BYTERANGE`);t&&(o=E(t,0)??void 0)}continue}if(t.startsWith(`#EXTINF:`)){s=le(t.slice(8));continue}if(t.startsWith(`#EXT-X-BYTERANGE:`)){c=E(t.slice(17),d)??void 0;continue}if(t!==`#EXT-X-ENDLIST`&&!t.startsWith(`#`)&&s>0){let e={id:`segment-${u}`,url:O(t,r),duration:s,startTime:l};c?(e.byteRange=c,d=c.end+1):d=void 0,i.push(e),l+=s,u++,s=0,c=void 0}}let f=l,p=t.type===`text`&&!a?void 0:a?{url:a,...o?{byteRange:o}:{}}:{url:``};return{...t,startTime:0,duration:f,segments:i,initialization:p}}var k=class{id;#e;#t=new AbortController;#n;#r=`pending`;#i=void 0;#a=void 0;constructor(e,t){this.#e=e;let n=t?.id;this.id=typeof n==`function`?n():n??w(),this.#n=t?.signal?AbortSignal.any([this.#t.signal,t.signal]):this.#t.signal}get status(){return this.#r}get value(){return this.#i}get error(){return this.#a}async run(){this.#r=`running`;try{let e=await this.#e(this.#n);return this.#i=e,this.#r=`done`,e}catch(e){throw this.#a=e,this.#r=`error`,e}}abort(){this.#t.abort()}},ve=class{#e=new Map;schedule(e){this.#e.has(e.id)||(this.#e.set(e.id,e),e.run().catch(e=>{if(!(e instanceof Error&&e.name===`AbortError`))throw e}).finally(()=>{this.#e.delete(e.id)}))}abortAll(){for(let e of this.#e.values())e.abort();this.#e.clear()}},ye=class{#e=Promise.resolve();#t=new Set;#n=null;schedule(e){let t=e;this.#t.add(t);let n=this.#e.then(()=>(this.#t.delete(t),this.#n=t,e.run())).finally(()=>{this.#n=null});return this.#e=n.then(()=>{},()=>{}),n}abortAll(){for(let e of this.#t)e.abort();this.#t.clear(),this.#n?.abort()}destroy(){this.abortAll()}};function be(e,t){let n=u(e,t.type);return n?!o(n):!1}function xe(e,t){return!0}function A(e,t){let n=t.id;return{...e,selectionSets:e.selectionSets.map(e=>({...e,switchingSets:e.switchingSets.map(e=>({...e,tracks:e.tracks.map(e=>e.id===n?t:e)}))}))}}function j({state:e,events:t},n){let r=new ve,i=a([e,t]).subscribe(([t,i])=>{if(!be(t,n)||!xe(t,i))return;let a=u(t,n.type);if(!a)return;let o=a;r.schedule(new k(async t=>{let n=_e(await C(await x(o,{signal:t})),o),r=e.current.presentation,i=A(r,n);e.patch({presentation:i})},{id:a.id}))});return()=>{r.abortAll(),i()}}function M(e,t){let n=e.selectionSets.find(e=>e.type===`text`);if(!n?.switchingSets?.[0]?.tracks.length)return;let r=n.switchingSets[0].tracks,i=t.includeForcedTracks?r:r.filter(e=>!e.forced);if(i.length===0)return;let{preferredSubtitleLanguage:a,enableDefaultTrack:o=!1}=t;if(a){let e=i.find(e=>e.language===a);if(e)return e.id}if(o){let e=i.find(e=>e.default===!0);if(e)return e.id}}function N(e,t){return!!e?.presentation?.selectionSets?.find(({type:e})=>e===t.type)?.switchingSets?.[0]?.tracks.length}function P(e,t){return!e[c[t.type]]}function Se({state:e},t={type:`video`}){let n=!1;return e.subscribe(async r=>{if(!(!N(r,t)||!P(r,t)||n))try{n=!0;let i=r.presentation?.selectionSets.find(({type:e})=>e===t.type)?.switchingSets[0]?.tracks[0]?.id;if(i){let n=c[t.type];e.patch({[n]:i})}}finally{n=!1}})}function Ce({state:e},t={type:`audio`}){let n=!1;return e.subscribe(async r=>{if(!(!N(r,t)||!P(r,t)||n))try{n=!0;let t=r.presentation?.selectionSets.find(({type:e})=>e===`audio`)?.switchingSets[0]?.tracks[0]?.id;t&&e.patch({selectedAudioTrackId:t})}finally{n=!1}})}function we({state:e},t={type:`text`}){let n=!1;return e.subscribe(async r=>{if(!(!N(r,t)||!P(r,t)||n))try{n=!0;let i=M(r.presentation,t);i&&e.patch({selectedTextTrackId:i})}finally{n=!1}})}const Te=Symbol(`@videojs/spf/state`);function Ee(e,t){return Object.is(e,t)}var De=class{[Te]=!0;#e;#t=null;#n=!1;#r;#i=new Set;#a=new Set;constructor(e,t){this.#e=typeof e==`object`&&e?{...e}:e,this.#r=t?.equalityFn??Ee}get current(){return this.#t??this.#e}patch(e){let t=this.#t??this.#e;if(typeof t!=`object`||!t){let n=e;Object.is(t,n)||(this.#t=n,this.#o());return}let n={...t},r=!1;for(let i in e){if(!Object.hasOwn(e,i))continue;let a=e[i];Object.is(t[i],a)||(n[i]=a,r=!0)}r&&(this.#t=n,this.#o())}subscribe(e,t,n){if(t===void 0){let t=e;return this.#i.add(t),t(this.current),()=>{this.#i.delete(t)}}let r=e,i=t,a={selector:r,listener:i,options:n??{}};return this.#a.add(a),i(r(this.current)),()=>{this.#a.delete(a)}}flush(){if(this.#t===null)return;let e=this.#e,t=this.#t;if(this.#t=null,this.#n=!1,!this.#r(e,t)){this.#e=t;for(let e of this.#i)e(this.#e);for(let t of this.#a){let n=t.selector(e),r=t.selector(this.#e);(t.options.equalityFn??Object.is)(n,r)||t.listener(r)}}}#o(){this.#n||(this.#n=!0,queueMicrotask(()=>this.flush()))}};function F(e,t){return new De(e,t)}function I(e,t){if(e.length===0)return!0;let n=e[e.length-1];return n?t?.snapshot.context.segments.some(e=>e.id===n.id)??!1:!1}function Oe(e,t){let n=e.selectedVideoTrackId?u(e,`video`):void 0,r=e.selectedAudioTrackId?u(e,`audio`):void 0;return!(n&&!o(n)||r&&!o(r)||n&&o(n)&&!I(n.segments,t.videoBufferActor)||r&&o(r)&&!I(r.segments,t.audioBufferActor))}function ke(e,t){return!!(t.mediaSource&&e.presentation)}function Ae(e,t){if(!ke(e,t))return!1;let{mediaSource:n,mediaElement:r}=t;if(n.readyState!==`open`||r&&r.readyState<HTMLMediaElement.HAVE_METADATA)return!1;let i=!!e.selectedVideoTrackId,a=!!e.selectedAudioTrackId;if(i&&!t.videoBuffer||a&&!t.audioBuffer||t.videoBufferActor?.snapshot.status===`updating`||t.audioBufferActor?.snapshot.status===`updating`||!Oe(e,t))return!1;if(r){let t=i?u(e,`video`):void 0,n=a?u(e,`audio`):void 0,s=t&&o(t)?t:n&&o(n)?n:void 0;if(s&&s.segments.length>0){let e=s.segments[s.segments.length-1];if(r.currentTime<e.startTime)return!1}}return!0}function je(e){let t=[e.videoBufferActor,e.audioBufferActor].filter(e=>e!==void 0&&e.snapshot.status===`updating`);return t.length===0?Promise.resolve():Promise.all(t.map(e=>new Promise(t=>{let n=e.subscribe(e=>{e.status!==`updating`&&(n(),t())})}))).then(()=>void 0)}function Me(e){let t=0;for(let n of[e.videoBuffer,e.audioBuffer])if(n&&n.buffered.length>0){let e=n.buffered.end(n.buffered.length-1);e>t&&(t=e)}return t}const Ne=async({currentOwners:e},t)=>{let{mediaSource:n}=e;if(n.readyState===`ended`||(await je(e),n.readyState!==`open`))return;let r=Me(e);r>0&&(n.duration=r),n.endOfStream(),await new Promise(e=>requestAnimationFrame(e))};function Pe({state:e,owners:t}){let n=!1,r=[],i=async()=>{let r=e.current,i=t.current;if(n){if(i.mediaSource?.readyState!==`open`)return;n=!1}if(Ae(r,i)){n=!0;try{await Ne({currentOwners:i},{})}catch(e){console.error(`Failed to call endOfStream:`,e)}}},o=t.subscribe(e=>{r.forEach(e=>e()),r.length=0;for(let t of[e.videoBufferActor,e.audioBufferActor]){if(!t)continue;let e=!0;r.push(t.subscribe(()=>{if(e){e=!1;return}i()}))}}),s=a([e,t]).subscribe(async()=>i());return()=>{r.forEach(e=>e()),o(),s()}}const Fe={keepSegments:2};function Ie(e,t,n=Fe){if(e.length===0)return 0;let r=e.filter(e=>e.startTime<t);if(r.length===0)return 0;let i=r.length-n.keepSegments;return i<=0?0:i>=r.length?t:r[i].startTime}const L={bufferDuration:30};function Le(e,t,n=L){if(e.length===0)return 1/0;let r=t+n.bufferDuration,i=e.filter(e=>e.startTime>=r);return i.length===0?1/0:Math.min(...i.map(e=>e.startTime))}function R(e,t,n,r=L){if(e.length===0)return[];let i=n+r.bufferDuration,a=new Set(t.map(e=>e.startTime));return e.filter(e=>{let t=e.startTime+e.duration,r=e.startTime<i&&t>n,o=!a.has(e.startTime);return r&&o})}function z(){return typeof MediaSource<`u`}function B(){return typeof ManagedMediaSource<`u`}function Re(e={}){let{preferManaged:t=!1}=e;if(t&&B())return new ManagedMediaSource;if(z())return new MediaSource;throw Error(`MediaSource API is not supported`)}function ze(e,t){if(B()&&e instanceof ManagedMediaSource)return t.srcObject=e,{url:``,detach:()=>{t.srcObject=null,t.load()}};let n=URL.createObjectURL(e);return t.src=n,{url:n,detach:()=>{t.removeAttribute(`src`),t.load(),URL.revokeObjectURL(n)}}}function Be(e,t){return new Promise((n,r)=>{if(e.readyState===`open`){n();return}if(t?.aborted){r(new DOMException(`Aborted`,`AbortError`));return}let i=new AbortController,a={signal:i.signal};e.addEventListener(`sourceopen`,()=>{i.abort(),n()},a),t?.addEventListener(`abort`,()=>{i.abort(),r(new DOMException(`Aborted`,`AbortError`))},a)})}function Ve(e,t){if(e.readyState!==`open`)throw Error(`MediaSource is not open`);if(!He(t))throw Error(`Codec not supported: ${t}`);return e.addSourceBuffer(t)}function He(e){return z()?MediaSource.isTypeSupported(e):!1}function Ue(e,t){let n=null,r=null,i=null,a=null,o=!1,s=!1,c=t=>{let n=new Set(e.snapshot.context.segments.map(e=>e.id));return t.filter(e=>n.has(e.id))},l=t=>{let{track:n,range:r}=t,i=e.snapshot.context,a=c(n.segments),o=r?.start??0,s=[];if(r){let e=Le(a,o);e<1/0&&s.push({type:`remove`,start:e,end:1/0});let t=Ie(a,o);t>0&&s.push({type:`remove`,start:0,end:t})}if(i.initTrackId!==n.id&&s.push({type:`append-init`,meta:{trackId:n.id},url:n.initialization.url}),r){let e=R(n.segments,a,o).filter(e=>{let t=i.segments.find(t=>Math.abs(t.startTime-e.startTime)<1e-4);return!t?.trackBandwidth||!n.bandwidth?!0:n.bandwidth>t.trackBandwidth});for(let t of e)s.push({type:`append-segment`,meta:{id:t.id,startTime:t.startTime,duration:t.duration,trackId:n.id,trackBandwidth:n.bandwidth},url:t.url})}return s},u=async o=>{let s=a.signal;try{if(o.type===`remove`){await e.send(o,s);return}if(o.type===`append-init`){if(r=o.meta.trackId,!s.aborted){let r=await t(o,{signal:s}),i=n?.some(e=>e.type===`append-init`&&e.meta.trackId!==o.meta.trackId);if(!s.aborted||!i){let t=s.aborted?new AbortController().signal:s;await e.send({type:`append-init`,data:r,meta:o.meta},t)}}return}if(i=o.meta.id,!s.aborted){let n=await t(o,{signal:s});s.aborted||await e.send({type:`append-segment`,data:n,meta:o.meta},s)}}finally{r=null,i=null}},d=async e=>{o=!0,a=new AbortController;let t=e;for(;t.length>0&&!s;){let e=t[0];t=t.slice(1);try{await u(e)}catch(e){e instanceof Error&&e.name===`AbortError`||(console.error(`Unexpected error in segment loader:`,e),t=[])}if(n!==null)t=n,n=null,a=new AbortController;else if(a.signal.aborted)break}a=null,o=!1};return{send(e){if(s)return;let t=l(e);if(!o){if(t.length===0)return;d(t);return}i!==null&&t.some(e=>e.type===`append-segment`&&e.meta.id===i)||r!==null&&t.some(e=>e.type===`append-init`&&e.meta.trackId===r)?n=t.filter(e=>!(e.type===`append-segment`&&e.meta.id===i)&&!(e.type===`append-init`&&e.meta.trackId===r)):(n=t,a?.abort())},destroy(){s=!0,a?.abort()}}}const We={video:`videoBufferActor`,audio:`audioBufferActor`};function Ge(e,t){return async(n,r)=>{let i=performance.now(),a=await S(n,r),o=performance.now()-i,s=ee(e.current,o,a.byteLength);return e.patch(s),e.flush(),t?.(s),a}}function Ke([e,t],n){let{playbackInitiated:r,preload:i,currentTime:a}=t;return{playbackInitiated:r,preload:i,currentTime:a,track:u(t,n),segmentsCanLoad:e}}const V=(e,t)=>{if(e!=null)return t?.segments.find(({startTime:t,duration:n},r,i)=>e>=t&&(e<t+n||r===i.length-1))?.startTime};function qe(e,t){return t.segmentsCanLoad?t.playbackInitiated?!e.playbackInitiated&&t.playbackInitiated&&e.preload!==`auto`?!1:!t.track||!o(t.track)?!0:e.track?.id!==t.track.id&&o(t.track)?!1:V(e.currentTime,t.track)===V(t.currentTime,t.track):t.preload===`none`?!0:t.preload===e.preload:!0}function H({state:e,owners:t},n){let{type:r}=n,i=We[r],s=e.current.bandwidthState,c=F(s??{fastEstimate:0,fastTotalWeight:0,slowEstimate:0,slowTotalWeight:0,bytesSampled:0}),l=r===`video`?Ge(c,s===void 0?void 0:t=>{e.patch({bandwidthState:t}),e.flush()}):S,d=F(void 0),f=t.subscribe(e=>e[i],e=>(e?d.patch(Ue(e,l)):!e&&d.current&&(d.current.destroy(),d.patch(void 0)),()=>{d.current?.destroy(),d.patch(void 0)})),p=F(!1),m=a([e,d]).subscribe(([e,t])=>{let n=u(e,r),i=!!n&&o(n),a=!!t;p.patch(i&&a)}),h=a([p,e]).subscribe(([e,t])=>Ke([e,t],r),({preload:e,playbackInitiated:t,currentTime:n,track:r})=>{e===`auto`||t?d.current?.send({type:`load`,track:r,range:{start:n,end:n+L.bufferDuration}}):d.current?.send({type:`load`,track:r})},{equalityFn:qe});return()=>{m(),h(),f()}}let U=null;function Je(){return U||(U=document.createElement(`video`),U.muted=!0,U.preload=`none`,U.style.display=`none`,U.crossOrigin=`anonymous`),U}function Ye(e){let t=Je(),n=document.createElement(`track`);return n.kind=`subtitles`,n.default=!0,new Promise((r,i)=>{let a=()=>{let e=[],t=n.track;if(t.cues)for(let n=0;n<t.cues.length;n++){let r=t.cues[n];r&&e.push(r)}s(),r(e)},o=()=>{s(),i(Error(`Failed to load VTT segment: ${e}`))},s=()=>{n.removeEventListener(`load`,a),n.removeEventListener(`error`,o),t.removeChild(n)};n.addEventListener(`load`,a),n.addEventListener(`error`,o),t.appendChild(n),n.src=e})}function Xe(){U=null}function Ze(e,t){let{cues:n}=t;if(!n)return!1;for(let t=0;t<n.length;t++){let r=n[t];if(r.startTime===e.startTime&&r.endTime===e.endTime&&r.text===e.text)return!0}return!1}const Qe=async({segment:e},t)=>{let n=await Ye(e.url);for(let e of n)Ze(e,t.textTrack)||t.textTrack.addCue(e)},$e=async({currentState:e},t)=>{let n=W(e);if(!n||!o(n))return;let{segments:r}=n;if(r.length===0)return;let i=n.id,a=new Set((e.textBufferState?.[i]?.segments??[]).map(e=>e.id)),s=R(r,r.filter(e=>a.has(e.id)),e.currentTime??0).filter(e=>!a.has(e.id));if(s.length!==0){for(let e of s){if(t.signal.aborted)break;try{await Qe({segment:e},{textTrack:t.textTrack});let n=t.state.current.textBufferState??{},r=n[i]??{segments:[]};t.state.patch({textBufferState:{...n,[i]:{segments:[...r.segments,{id:e.id}]}}})}catch(e){if(e instanceof Error&&e.name===`AbortError`)break;console.error(`Failed to load VTT segment:`,e)}}await new Promise(e=>requestAnimationFrame(e))}};function W(e){if(!e.presentation||!e.selectedTextTrackId)return;let t=e.presentation.selectionSets.find(e=>e.type===`text`);if(t?.switchingSets?.[0]?.tracks)return t.switchingSets[0].tracks.find(t=>t.id===e.selectedTextTrackId)}function G(e,t){let n=e.selectedTextTrackId;if(!(!n||!t.textTracks))return t.textTracks.get(n)?.track}function et(e,t){return!!e.selectedTextTrackId&&!!t.textTracks&&t.textTracks.has(e.selectedTextTrackId)}function tt(e,t){if(!et(e,t))return!1;let n=W(e);return!(!n||!o(n)||n.segments.length===0||!G(e,t))}function nt({state:e,owners:t}){let n=null,r=null,i;return a([e,t]).subscribe(async([t,a])=>{if(t.selectedTextTrackId!==i&&(i=t.selectedTextTrackId,r?.abort(),n=null),n||!tt(t,a))return;let o=G(t,a);o&&(r=new AbortController,n=$e({currentState:t},{signal:r.signal,textTrack:o,state:e}).finally(()=>{n=null}))})}function rt(t,n){return!e(n.mediaElement)&&!e(t.presentation?.url)}function it(t,n){return e(n.mediaSource)}function at({state:e,owners:t}){let n=!1;return a([e,t]).subscribe(async([e,r])=>{if(!(!rt(e,r)||!it(e,r)||n))try{n=!0;let e=Re({preferManaged:!0});ze(e,r.mediaElement),await Be(e),t.patch({mediaSource:e})}finally{n=!1}})}async function K(e,t){return e.updating&&await new Promise(t=>{let n=()=>{e.removeEventListener(`updateend`,n),t()};e.addEventListener(`updateend`,n)}),new Promise((n,r)=>{let i=()=>{o(),n()},a=e=>{o(),r(Error(`SourceBuffer append error: ${e.type}`))},o=()=>{e.removeEventListener(`updateend`,i),e.removeEventListener(`error`,a)};e.addEventListener(`updateend`,i),e.addEventListener(`error`,a);try{e.appendBuffer(t)}catch(e){o(),r(e)}})}async function ot(e,t,n){return e.updating&&await new Promise(t=>{let n=()=>{e.removeEventListener(`updateend`,n),t()};e.addEventListener(`updateend`,n)}),new Promise((r,i)=>{let a=()=>{s(),r()},o=e=>{s(),i(Error(`SourceBuffer remove error: ${e.type}`))},s=()=>{e.removeEventListener(`updateend`,a),e.removeEventListener(`error`,o)};e.addEventListener(`updateend`,a),e.addEventListener(`error`,o);try{e.remove(t,n)}catch(e){s(),i(e)}})}var q=class extends Error{constructor(e){super(e),this.name=`SourceBufferActorError`}};function J(e){let t=[];for(let n=0;n<e.length;n++)t.push({start:e.start(n),end:e.end(n)});return t}function st(e,{signal:t,getCtx:n,sourceBuffer:r}){return new k(async t=>{let i=n();return t.aborted?i:(await K(r,e.data),{...i,initTrackId:e.meta.trackId})},{signal:t})}function ct(e,{signal:t,getCtx:n,sourceBuffer:r}){return new k(async t=>{let i=n();if(t.aborted)return i;await K(r,e.data);let{meta:a}=e,o=i.segments.filter(e=>Math.abs(e.startTime-a.startTime)>=1e-4);return{...i,segments:[...o,{id:a.id,startTime:a.startTime,duration:a.duration,trackId:a.trackId,...a.trackBandwidth!==void 0&&{trackBandwidth:a.trackBandwidth}}],bufferedRanges:J(r.buffered)}},{signal:t})}function lt(e,{signal:t,getCtx:n,sourceBuffer:r}){return new k(async t=>{let i=n();if(t.aborted)return i;await ot(r,e.start,e.end);let a=J(r.buffered),o=i.segments.filter(e=>{let t=e.startTime+e.duration/2;return a.some(e=>t>=e.start&&t<e.end)});return{...i,segments:o,bufferedRanges:a}},{signal:t})}const ut={"append-init":st,"append-segment":ct,remove:lt};function Y(e,t){let n=ut[e.type];return n(e,t)}function dt(e,t){let n=F({status:`idle`,context:{segments:[],bufferedRanges:[],initTrackId:void 0,...t}}),r=new ye;function i(e){let t=n.current.status===`destroyed`?`destroyed`:`idle`;n.patch({status:t,context:e}),n.flush()}function a(e){let t=n.current.status===`destroyed`?`destroyed`:`idle`;throw n.patch({status:t}),n.flush(),e}return{get snapshot(){return n.current},subscribe(e){return n.subscribe(e)},send(t,o){if(n.current.status!==`idle`)return Promise.reject(new q(`send() called while actor is ${n.current.status}`));n.patch({status:`updating`});let s=Y(t,{signal:o,getCtx:()=>n.current.context,sourceBuffer:e});return r.schedule(s).then(i).catch(a)},batch(t,o){if(n.current.status!==`idle`)return Promise.reject(new q(`batch() called while actor is ${n.current.status}`));if(t.length===0)return Promise.resolve();n.patch({status:`updating`});let s=n.current.context;for(let n of t.slice(0,-1)){let t=Y(n,{signal:o,getCtx:()=>s,sourceBuffer:e});r.schedule(t).then(e=>{s=e})}let c=Y(t[t.length-1],{signal:o,getCtx:()=>s,sourceBuffer:e});return r.schedule(c).then(i).catch(a)},destroy(){n.patch({status:`destroyed`}),n.flush(),r.destroy()}}}const ft={video:`videoBufferActor`,audio:`audioBufferActor`},pt=async({currentState:e,currentOwners:t},n)=>{let r=u(e,n.config.type);if(!r||!o(r)||!r.codecs||r.codecs.length===0)return;let i=mt(r),a=Ve(t.mediaSource,i),s=dt(a),c=l[n.config.type],d=ft[n.config.type];n.owners.patch({[c]:a,[d]:s}),await new Promise(e=>requestAnimationFrame(e))};function mt(e){let t=e.codecs?.join(`,`)??``;return`${e.mimeType}; codecs="${t}"`}function ht(e,t,n){return!(!t.mediaSource||!u(e,n))}function gt(e,n){let r=l[n];return t(e[r])}function X({state:e,owners:t},n){let r=null;return a([e,t]).subscribe(async([e,i])=>{if(!r&&!(!ht(e,i,n.type)||!gt(i,n.type))){r=pt({currentState:e,currentOwners:i},{owners:t,config:n});try{await r}finally{r=null}}})}function Z(e){if(!e?.selectionSets)return[];let t=e.selectionSets.find(e=>e.type===`text`);return t?.switchingSets?.[0]?.tracks?t.switchingSets[0].tracks:[]}function _t(e,t){return!!t.mediaElement&&!!Z(e.presentation).length}function vt(e){return!e.textTracks}function yt(e){let t=document.createElement(`track`);return t.id=e.id,t.kind=e.kind,t.label=e.label,e.language&&(t.srclang=e.language),e.default&&(t.default=!0),t.src=e.url,t}function bt({state:e,owners:t}){let n=!1,r=[],i=a([e,t]).subscribe(([e,i])=>{if(n||!_t(e,i)||!vt(i))return;n=!0;let a=Z(e.presentation);if(a.length===0)return;let o=new Map;for(let e of a){let t=yt(e);i.mediaElement.appendChild(t),o.set(e.id,t),r.push(t)}t.patch({textTracks:o})});return()=>{for(let e of r)e.remove();r=[],i()}}function Q(e){return!!e.textTracks&&e.textTracks.size>0}function xt({state:e,owners:t}){return a([e,t]).subscribe(([e,t])=>{if(!Q(t))return;let n=e.selectedTextTrackId;for(let[e,r]of t.textTracks)e===n?r.track.mode=`showing`:r.track.mode=`hidden`})}function St({state:e,owners:t}){let r,i=null,a=t.subscribe(t=>{let{mediaElement:a}=t;if(a===r||(i?.(),i=null,r=a,!a))return;e.patch({currentTime:a.currentTime});let o=()=>e.patch({currentTime:a.currentTime}),s=n(a,`timeupdate`,o),c=n(a,`seeking`,o);i=()=>{s(),c()}});return()=>{i?.(),a()}}function Ct({state:e,owners:t,events:r}){let i,a=null,o,s=e.subscribe(t=>{let n=t.presentation?.url;n!==o&&(o!==void 0&&e.patch({playbackInitiated:!1}),o=n)}),c=t.subscribe(t=>{let{mediaElement:o}=t;o!==i&&(a?.(),a=null,i=o,o&&(a=n(o,`play`,()=>{e.patch({playbackInitiated:!0}),r.dispatch({type:`play`})})))});return()=>{a?.(),s(),c()}}function wt(e,t){return!!(t.mediaSource&&e.presentation&&s(e.presentation))}function Tt(e){let t=0,n=[e.videoSourceBuffer,e.audioSourceBuffer].filter(e=>e!==void 0);for(let e of n){let{buffered:n}=e;if(n.length>0){let e=n.end(n.length-1);e>t&&(t=e)}}return t}function Et(e,t){if(!wt(e,t))return!1;let{mediaSource:n}=t,{presentation:r}=e;if(n.readyState!==`open`)return!1;let i=r.duration;return!Number.isFinite(i)||Number.isNaN(i)||i<=0?!1:isNaN(n.duration)}function Dt(e){let t=[e.videoSourceBuffer,e.audioSourceBuffer].filter(e=>e!==void 0&&e.updating);return t.length===0?Promise.resolve():Promise.all(t.map(e=>new Promise(t=>e.addEventListener(`updateend`,()=>t(),{once:!0})))).then(()=>void 0)}function Ot({state:e,owners:t}){return a([e,t]).subscribe(async([e,t])=>{if(!Et(e,t))return;let{mediaSource:n}=t;if(await Dt(t),n.readyState!==`open`)return;let r=e.presentation.duration,i=Tt(t);i>r&&(r=i),n.duration=r})}function $(e={}){let t=F({bandwidthState:{fastEstimate:0,fastTotalWeight:0,slowEstimate:0,slowTotalWeight:0,bytesSampled:0}}),n=F({}),r=i(),a=[he(t,n),Ct({state:t,owners:n,events:r}),ge({state:t,events:r}),Se({state:t,owners:n,events:r},{type:`video`,...e.initialBandwidth!==void 0&&{initialBandwidth:e.initialBandwidth}}),Ce({state:t,owners:n,events:r},{type:`audio`,...e.preferredAudioLanguage!==void 0&&{preferredAudioLanguage:e.preferredAudioLanguage}}),we({state:t,owners:n,events:r},{type:`text`,...e.preferredSubtitleLanguage!==void 0&&{preferredSubtitleLanguage:e.preferredSubtitleLanguage},...e.includeForcedTracks!==void 0&&{includeForcedTracks:e.includeForcedTracks},...e.enableDefaultTrack!==void 0&&{enableDefaultTrack:e.enableDefaultTrack}}),j({state:t,events:r},{type:`video`}),j({state:t,events:r},{type:`audio`}),j({state:t,events:r},{type:`text`}),m({state:t}),at({state:t,owners:n}),Ot({state:t,owners:n}),X({state:t,owners:n},{type:`video`}),X({state:t,owners:n},{type:`audio`}),St({state:t,owners:n}),ae({state:t}),H({state:t,owners:n},{type:`video`}),H({state:t,owners:n},{type:`audio`}),Pe({state:t,owners:n}),bt({state:t,owners:n}),xt({state:t,owners:n}),nt({state:t,owners:n})];return r.dispatch({type:`@@INITIALIZE@@`}),{state:t,owners:n,events:r,destroy:()=>{a.forEach(e=>e()),Xe()}}}var kt=class{engine;#e=null;constructor(e={}){this.engine=$(e)}attach(e){this.engine.owners.patch({mediaElement:e})}detach(){this.#t(),this.engine.owners.patch({mediaElement:void 0})}destroy(){this.#t(),this.engine.destroy()}get src(){return this.engine.state.current.presentation?.url??``}set src(e){this.engine.state.patch({presentation:e?{url:e}:void 0})}play(){let{mediaElement:e}=this.engine.owners.current;return e?(this.engine.state.patch({playbackInitiated:!0}),e.play().catch(t=>{if(this.src)return new Promise((t,n)=>{let r=()=>{this.#e=null,e.play().then(t,n)};this.#e=r,e.addEventListener(`loadstart`,r,{once:!0})});throw t})):Promise.reject(Error(`SpfMedia: no media element attached`))}#t(){if(!this.#e)return;let{mediaElement:e}=this.engine.owners.current;e?.removeEventListener(`loadstart`,this.#e),this.#e=null}};export{kt as SpfMedia,$ as createPlaybackEngine};
|
|
1
|
+
import { t as VERSION } from "./src-DRsS_H80.js";
|
|
2
|
+
|
|
3
|
+
export { VERSION };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Stream Processing Framework (SPF) for Video.js 10
|
|
4
|
+
*
|
|
5
|
+
* Bundle size target: < 20KB (minified + gzipped)
|
|
6
|
+
* Primary use case: CMAF HLS playback with Video.js v10
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
const VERSION = "0.1.0";
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { VERSION as t };
|
|
14
|
+
//# sourceMappingURL=src-DRsS_H80.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src-DRsS_H80.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Stream Processing Framework (SPF) for Video.js 10\n *\n * Bundle size target: < 20KB (minified + gzipped)\n * Primary use case: CMAF HLS playback with Video.js v10\n *\n * @packageDocumentation\n */\n\n// Public API exports will be added here as features are implemented\n\nexport const VERSION = '0.1.0';\n"],"mappings":";;;;;;;;;AAWA,MAAa,UAAU"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@videojs/spf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "10.0.0-beta.1",
|
|
5
5
|
"description": "Stream Processing Framework for Video.js 10",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/videojs/v10",
|
|
10
|
+
"directory": "packages/spf"
|
|
11
|
+
},
|
|
7
12
|
"keywords": [
|
|
8
13
|
"video",
|
|
9
14
|
"hls",
|
|
@@ -34,19 +39,8 @@
|
|
|
34
39
|
"files": [
|
|
35
40
|
"dist"
|
|
36
41
|
],
|
|
37
|
-
"scripts": {
|
|
38
|
-
"build": "tsc --build && tsdown",
|
|
39
|
-
"build:watch": "tsdown --watch --silent",
|
|
40
|
-
"dev": "pnpm run build:watch",
|
|
41
|
-
"test": "vitest run",
|
|
42
|
-
"test:ci": "vitest run --project=core --project=dom --project=utils",
|
|
43
|
-
"test:watch": "vitest",
|
|
44
|
-
"clean": "rm -rf dist types",
|
|
45
|
-
"size": "node scripts/measure-size.js --playback-engine",
|
|
46
|
-
"size:all": "node scripts/measure-size.js --all"
|
|
47
|
-
},
|
|
48
42
|
"dependencies": {
|
|
49
|
-
"@videojs/utils": "
|
|
43
|
+
"@videojs/utils": "10.0.0-beta.1"
|
|
50
44
|
},
|
|
51
45
|
"devDependencies": {
|
|
52
46
|
"@vitest/browser": "^3.2.4",
|
|
@@ -59,5 +53,16 @@
|
|
|
59
53
|
},
|
|
60
54
|
"publishConfig": {
|
|
61
55
|
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc --build && tsdown",
|
|
59
|
+
"build:watch": "tsdown --watch --silent",
|
|
60
|
+
"dev": "pnpm run build:watch",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:ci": "vitest run --project=core --project=dom --project=utils",
|
|
63
|
+
"test:watch": "vitest",
|
|
64
|
+
"clean": "rm -rf dist types",
|
|
65
|
+
"size": "node scripts/measure-size.js --playback-engine",
|
|
66
|
+
"size:all": "node scripts/measure-size.js --all"
|
|
62
67
|
}
|
|
63
|
-
}
|
|
68
|
+
}
|