mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
85 lines
3.6 KiB
JavaScript
85 lines
3.6 KiB
JavaScript
import { computed } from "../../core/signals/primitives.js";
|
|
import { defineBehavior } from "../../core/composition/create-composition.js";
|
|
import { createMachineReactor } from "../../core/reactors/create-machine-reactor.js";
|
|
import { isResolvedPresentation } from "../../media/types/index.js";
|
|
import { fetchResolvable, getResponseText } from "../../network/fetch.js";
|
|
import { isBlockingPreload } from "../../media/utils/preload.js";
|
|
//#region src/playback/behaviors/resolve-presentation.ts
|
|
/**
|
|
* **Resolve an unresolved presentation by fetching and parsing its manifest.**
|
|
*
|
|
* Reads `state.presentation`; when it holds `{ url }` (unresolved) and the
|
|
* preload / load-activation gate is met, fetches the manifest, parses it via
|
|
* the **required** `config.parsePresentation`, and writes the resolved
|
|
* `Presentation` back to the same slot. The behavior is format-neutral: the
|
|
* composing engine wires in its parser (e.g. the HLS engine supplies the
|
|
* multivariant-playlist parser).
|
|
*
|
|
* Source-identity-driven, expressed as a 4-state machine:
|
|
*
|
|
* ```
|
|
* 'preconditions-unmet' → 'idle' → 'resolving' → 'resolved'
|
|
* ```
|
|
*
|
|
* - `'preconditions-unmet'`: no presentation, or presentation has no URL.
|
|
* - `'idle'`: URL present, unresolved, gate unmet (blocking preload + no
|
|
* load-activation). Waits for the gate to open.
|
|
* - `'resolving'`: URL present, unresolved, gate met. Entry starts the fetch
|
|
* and returns the AbortController — the reactor calls `.abort()` on state
|
|
* exit, so source change / gate-close / destroy all cancel cleanly.
|
|
* - `'resolved'`: `state.presentation` holds a resolved `Presentation`.
|
|
*
|
|
* Gate semantics: `state.preload` (or `config.defaultPreload`, default
|
|
* `'metadata'`, when state.preload is unset) blocks resolution when its
|
|
* value is `'none'` (see `isBlockingPreload` in `media/utils/preload`).
|
|
* `state.loadActivated` is an override — true bypasses the preload gate
|
|
* entirely.
|
|
*
|
|
* Multi-writer with the engine adapter, which writes the initial unresolved
|
|
* `{ url }` to `state.presentation` from src input. Different domains
|
|
* (config-input vs. derived state via fetch) — legitimate multi-writer.
|
|
*/
|
|
function deriveState(presentation, preload, loadActivated, defaultPreload) {
|
|
if (!presentation?.url) return "preconditions-unmet";
|
|
if (isResolvedPresentation(presentation)) return "resolved";
|
|
return !!loadActivated || !isBlockingPreload(preload, defaultPreload) ? "resolving" : "idle";
|
|
}
|
|
function resolvePresentationSetup({ state, config }) {
|
|
const { parsePresentation } = config;
|
|
const defaultPreload = config.defaultPreload ?? "metadata";
|
|
const derivedStateSignal = computed(() => deriveState(state.presentation.get(), state.preload.get(), state.loadActivated.get(), defaultPreload));
|
|
return createMachineReactor({
|
|
initial: "preconditions-unmet",
|
|
monitor: () => derivedStateSignal.get(),
|
|
states: {
|
|
"preconditions-unmet": {},
|
|
idle: {},
|
|
resolving: { entry: () => {
|
|
const presentation = state.presentation.get();
|
|
const ac = new AbortController();
|
|
fetchResolvable(presentation, { signal: ac.signal }).then((response) => getResponseText(response)).then((text) => {
|
|
const parsed = parsePresentation(text, presentation);
|
|
state.presentation.set(parsed);
|
|
}).catch((error) => {
|
|
if (error instanceof Error && error.name === "AbortError") return;
|
|
console.error("[resolvePresentation] manifest fetch/parse failed:", error);
|
|
});
|
|
return ac;
|
|
} },
|
|
resolved: {}
|
|
}
|
|
});
|
|
}
|
|
const resolvePresentation = defineBehavior({
|
|
stateKeys: [
|
|
"presentation",
|
|
"preload",
|
|
"loadActivated"
|
|
],
|
|
contextKeys: [],
|
|
setup: resolvePresentationSetup
|
|
});
|
|
//#endregion
|
|
export { resolvePresentation };
|
|
|
|
//# sourceMappingURL=resolve-presentation.js.map
|