bobinejs 0.1.0 → 0.2.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/README.md +114 -108
- package/dist/core.d.ts +9 -2
- package/dist/core.js +18 -6
- package/dist/core.js.map +1 -1
- package/dist/hls.d.ts +5 -2
- package/dist/hls.js +5 -4
- package/dist/hls.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.js +148 -91
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,108 +1,114 @@
|
|
|
1
|
-
# bobine
|
|
2
|
-
|
|
3
|
-
Drop-in video and audio players for React. Swap `<video>` for `<VideoPlayer>` and keep every native prop.
|
|
4
|
-
|
|
5
|
-
Two ways to use it:
|
|
6
|
-
|
|
7
|
-
- **Own the source** (recommended): `npx shadcn@latest add https://bobine.fyi/r/video-player.json`
|
|
8
|
-
- **Install the package**: `pnpm add bobinejs`
|
|
9
|
-
|
|
10
|
-
## Package setup
|
|
11
|
-
|
|
12
|
-
Requires React 19 and Tailwind CSS v4 with shadcn
|
|
13
|
-
|
|
14
|
-
```css
|
|
15
|
-
@import "tailwindcss";
|
|
16
|
-
@import "bobinejs/styles.css";
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
import { VideoPlayer, AudioPlayer } from "bobinejs"
|
|
23
|
-
|
|
24
|
-
<VideoPlayer
|
|
25
|
-
src="/clip.mp4"
|
|
26
|
-
poster="/clip.jpg"
|
|
27
|
-
tracks={[{ src: "/clip.en.vtt", label: "English", srcLang: "en", default: true }]}
|
|
28
|
-
persistKey="bobine"
|
|
29
|
-
/>
|
|
30
|
-
|
|
31
|
-
<AudioPlayer src="/episode.mp3" title="Episode 12" description="Field notes" artwork="/cover.jpg" showSpeed />
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### HLS
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
store
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
1
|
+
# bobine
|
|
2
|
+
|
|
3
|
+
Drop-in video and audio players for React. Swap `<video>` for `<VideoPlayer>` and keep every native prop.
|
|
4
|
+
|
|
5
|
+
Two ways to use it:
|
|
6
|
+
|
|
7
|
+
- **Own the source** (recommended): `npx shadcn@latest add https://bobine.fyi/r/video-player.json`
|
|
8
|
+
- **Install the package**: `pnpm add bobinejs`
|
|
9
|
+
|
|
10
|
+
## Package setup
|
|
11
|
+
|
|
12
|
+
Requires React 19 and Tailwind CSS v4 with shadcn theme tokens. In a new project, `npx shadcn@latest init` sets them up. Without it, define `background`, `foreground`, `card`, `muted`, `popover`, `primary` and `border` (with their `-foreground` pairs) yourself, or the audio player renders unstyled.
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
@import "tailwindcss";
|
|
16
|
+
@import "bobinejs/styles.css";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { VideoPlayer, AudioPlayer } from "bobinejs"
|
|
23
|
+
|
|
24
|
+
<VideoPlayer
|
|
25
|
+
src="/clip.mp4"
|
|
26
|
+
poster="/clip.jpg"
|
|
27
|
+
tracks={[{ src: "/clip.en.vtt", label: "English", srcLang: "en", default: true }]}
|
|
28
|
+
persistKey="bobine"
|
|
29
|
+
/>
|
|
30
|
+
|
|
31
|
+
<AudioPlayer src="/episode.mp3" title="Episode 12" description="Field notes" artwork="/cover.jpg" showSpeed />
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### HLS
|
|
35
|
+
|
|
36
|
+
`bobinejs/hls` needs hls.js as a dependency. It loads only when an `.m3u8` source appears.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add hls.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
"use client"
|
|
44
|
+
import { VideoPlayer } from "bobinejs"
|
|
45
|
+
import { hlsLoader } from "bobinejs/hls" // loads hls.js on demand
|
|
46
|
+
|
|
47
|
+
<VideoPlayer src="https://example.com/stream.m3u8" loader={hlsLoader} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Compose your own
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { MediaRoot, MediaVideo, MediaSurface, MediaControls, MediaSeek, MediaPlayButton, MediaTime } from "bobinejs"
|
|
54
|
+
|
|
55
|
+
<MediaRoot className="aspect-video bg-media-scrim text-media-foreground">
|
|
56
|
+
<MediaVideo src="/clip.mp4" className="size-full" />
|
|
57
|
+
<MediaSurface />
|
|
58
|
+
<MediaControls className="absolute inset-x-3 bottom-3 flex-col">
|
|
59
|
+
<MediaSeek />
|
|
60
|
+
<div className="flex items-center gap-1">
|
|
61
|
+
<MediaPlayButton />
|
|
62
|
+
<MediaTime /> / <MediaTime type="duration" />
|
|
63
|
+
</div>
|
|
64
|
+
</MediaControls>
|
|
65
|
+
</MediaRoot>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Types
|
|
69
|
+
|
|
70
|
+
Every component exports its props type under its own name plus `Props`, so a
|
|
71
|
+
wrapper can extend it.
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { AudioPlayer, type AudioPlayerProps } from "bobinejs"
|
|
75
|
+
|
|
76
|
+
function EpisodePlayer(props: AudioPlayerProps) {
|
|
77
|
+
return <AudioPlayer showSpeed persistKey="episodes" {...props} />
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`MediaState`, `MediaStore` and `MediaInfo` type the store and its metadata.
|
|
82
|
+
|
|
83
|
+
### Framework-agnostic core
|
|
84
|
+
|
|
85
|
+
`bobinejs/core` exports `createMediaStore()`, a dependency-free store you can `attach` to any `HTMLMediaElement`.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { createMediaStore } from "bobinejs/core"
|
|
89
|
+
|
|
90
|
+
const store = createMediaStore()
|
|
91
|
+
store.attach(document.querySelector("video")!)
|
|
92
|
+
store.subscribe(() => console.log(store.getState().currentTime))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Keyboard
|
|
96
|
+
|
|
97
|
+
| Key | Action |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| Space / K | Play or pause |
|
|
100
|
+
| J / L | Seek 10s |
|
|
101
|
+
| ← / → | Seek 5s |
|
|
102
|
+
| ↑ / ↓ | Volume |
|
|
103
|
+
| 0–9 | Jump to 0–90% |
|
|
104
|
+
| Home / End | Start / end |
|
|
105
|
+
| M | Mute |
|
|
106
|
+
| C | Captions |
|
|
107
|
+
| I | Picture-in-picture |
|
|
108
|
+
| F | Fullscreen |
|
|
109
|
+
|
|
110
|
+
Shortcuts only apply to the focused player.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
package/dist/core.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ type MediaState = {
|
|
|
27
27
|
fullscreen: boolean;
|
|
28
28
|
pictureInPicture: boolean;
|
|
29
29
|
error: MediaError | null;
|
|
30
|
+
/** False while the element has no source to play. */
|
|
31
|
+
hasSource: boolean;
|
|
30
32
|
/** Caption and subtitle tracks, in document order. */
|
|
31
33
|
textTracks: MediaTextTrack[];
|
|
32
34
|
/** Index into `textTracks`, or -1 when captions are off. */
|
|
@@ -70,9 +72,14 @@ declare function createMediaStore({ persistKey }?: MediaStoreOptions): {
|
|
|
70
72
|
setContainer: (el: HTMLElement | null) => void;
|
|
71
73
|
};
|
|
72
74
|
type MediaStore = ReturnType<typeof createMediaStore>;
|
|
73
|
-
|
|
75
|
+
/**
|
|
76
|
+
* `m:ss`, or `h:mm:ss` from one hour. Pass the duration as `reference` so
|
|
77
|
+
* every time in a player uses the same fields: `0:00:05` beside `10:00:01`,
|
|
78
|
+
* and the label does not widen when playback passes an hour.
|
|
79
|
+
*/
|
|
80
|
+
declare function formatTime(seconds: number, reference?: number): string;
|
|
74
81
|
/** Human-readable message for a MediaError code. */
|
|
75
|
-
declare function describeMediaError(error: MediaError | null): "Playback was aborted." | "A network error stopped the download." | "This media could not be decoded." | "This
|
|
82
|
+
declare function describeMediaError(error: MediaError | null): "Playback was aborted." | "A network error stopped the download." | "This media could not be decoded." | "This media couldn't be loaded." | "Something went wrong during playback.";
|
|
76
83
|
|
|
77
84
|
export { createMediaStore, describeMediaError, formatTime };
|
|
78
85
|
export type { MediaInfo, MediaState, MediaStore, MediaStoreOptions, MediaTextTrack };
|
package/dist/core.js
CHANGED
|
@@ -15,6 +15,7 @@ var MEDIA_EVENTS = [
|
|
|
15
15
|
"volumechange",
|
|
16
16
|
"ratechange",
|
|
17
17
|
"emptied",
|
|
18
|
+
"loadstart",
|
|
18
19
|
"error",
|
|
19
20
|
"enterpictureinpicture",
|
|
20
21
|
"leavepictureinpicture"
|
|
@@ -34,6 +35,7 @@ var initialState = {
|
|
|
34
35
|
fullscreen: false,
|
|
35
36
|
pictureInPicture: false,
|
|
36
37
|
error: null,
|
|
38
|
+
hasSource: false,
|
|
37
39
|
textTracks: [],
|
|
38
40
|
textTrack: -1,
|
|
39
41
|
cues: []
|
|
@@ -54,7 +56,13 @@ function captionTracks(media) {
|
|
|
54
56
|
);
|
|
55
57
|
}
|
|
56
58
|
function cueText(cue) {
|
|
57
|
-
|
|
59
|
+
const vtt = cue;
|
|
60
|
+
const text = typeof vtt.getCueAsHTML === "function" ? vtt.getCueAsHTML().textContent : vtt.text?.replace(/<[^>]+>/g, "");
|
|
61
|
+
return (text ?? "").trim();
|
|
62
|
+
}
|
|
63
|
+
function defaultTrack(media, tracks) {
|
|
64
|
+
const el = Array.from(media?.querySelectorAll("track") ?? []).find((track) => track.default);
|
|
65
|
+
return el ? tracks.indexOf(el.track) : -1;
|
|
58
66
|
}
|
|
59
67
|
var sameList = (a, b) => a.length === b.length && a.every((value, i) => Object.is(value, b[i]));
|
|
60
68
|
var sameTracks = (a, b) => a.length === b.length && a.every((t, i) => t.label === b[i].label && t.language === b[i].language && t.kind === b[i].kind);
|
|
@@ -71,6 +79,7 @@ function createMediaStore({ persistKey } = {}) {
|
|
|
71
79
|
let container = null;
|
|
72
80
|
let cueTrack = null;
|
|
73
81
|
let metadata = null;
|
|
82
|
+
let trackChosen = false;
|
|
74
83
|
const listeners = /* @__PURE__ */ new Set();
|
|
75
84
|
const set = (patch) => {
|
|
76
85
|
let changed = false;
|
|
@@ -100,7 +109,8 @@ function createMediaStore({ persistKey } = {}) {
|
|
|
100
109
|
muted: media.muted,
|
|
101
110
|
playbackRate: media.playbackRate,
|
|
102
111
|
pictureInPicture: typeof document !== "undefined" && document.pictureInPictureElement === media,
|
|
103
|
-
error: media.error
|
|
112
|
+
error: media.error,
|
|
113
|
+
hasSource: Boolean(media.src || media.currentSrc || media.querySelector("source[src]"))
|
|
104
114
|
});
|
|
105
115
|
};
|
|
106
116
|
const readCues = () => {
|
|
@@ -115,7 +125,7 @@ function createMediaStore({ persistKey } = {}) {
|
|
|
115
125
|
};
|
|
116
126
|
const syncTracks = (requested = state.textTrack) => {
|
|
117
127
|
const tracks = captionTracks(media);
|
|
118
|
-
let active = requested;
|
|
128
|
+
let active = requested === -1 && !trackChosen ? defaultTrack(media, tracks) : requested;
|
|
119
129
|
tracks.forEach((track, i) => {
|
|
120
130
|
if (track.mode === "showing") active = i;
|
|
121
131
|
});
|
|
@@ -323,6 +333,7 @@ function createMediaStore({ persistKey } = {}) {
|
|
|
323
333
|
}
|
|
324
334
|
};
|
|
325
335
|
const syncTracksExplicit = (index) => {
|
|
336
|
+
trackChosen = true;
|
|
326
337
|
captionTracks(media).forEach((track, i) => {
|
|
327
338
|
if (i !== index && track.mode === "showing") track.mode = "disabled";
|
|
328
339
|
});
|
|
@@ -341,13 +352,14 @@ function createMediaStore({ persistKey } = {}) {
|
|
|
341
352
|
...actions
|
|
342
353
|
};
|
|
343
354
|
}
|
|
344
|
-
function formatTime(seconds) {
|
|
355
|
+
function formatTime(seconds, reference = seconds) {
|
|
345
356
|
if (!Number.isFinite(seconds) || seconds < 0) seconds = 0;
|
|
346
357
|
const s = Math.floor(seconds % 60);
|
|
347
358
|
const m = Math.floor(seconds / 60 % 60);
|
|
348
359
|
const h = Math.floor(seconds / 3600);
|
|
349
360
|
const ss = s.toString().padStart(2, "0");
|
|
350
|
-
|
|
361
|
+
const hours = h > 0 || Number.isFinite(reference) && reference >= 3600;
|
|
362
|
+
return hours ? `${h}:${m.toString().padStart(2, "0")}:${ss}` : `${m}:${ss}`;
|
|
351
363
|
}
|
|
352
364
|
function describeMediaError(error) {
|
|
353
365
|
switch (error?.code) {
|
|
@@ -358,7 +370,7 @@ function describeMediaError(error) {
|
|
|
358
370
|
case 3:
|
|
359
371
|
return "This media could not be decoded.";
|
|
360
372
|
case 4:
|
|
361
|
-
return "This
|
|
373
|
+
return "This media couldn't be loaded.";
|
|
362
374
|
default:
|
|
363
375
|
return "Something went wrong during playback.";
|
|
364
376
|
}
|
package/dist/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../lib/media-store.ts"],"names":[],"mappings":"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","file":"core.js","sourcesContent":["export type MediaTextTrack = {\r\n label: string\r\n language: string\r\n kind: \"captions\" | \"subtitles\"\r\n}\r\n\r\nexport type MediaInfo = {\r\n title?: string\r\n artist?: string\r\n album?: string\r\n artwork?: { src: string; sizes?: string; type?: string }[]\r\n}\r\n\r\nexport type MediaState = {\r\n paused: boolean\r\n ended: boolean\r\n started: boolean\r\n waiting: boolean\r\n currentTime: number\r\n duration: number\r\n bufferedEnd: number\r\n volume: number\r\n muted: boolean\r\n playbackRate: number\r\n fullscreen: boolean\r\n pictureInPicture: boolean\r\n error: MediaError | null\r\n /** Caption and subtitle tracks, in document order. */\r\n textTracks: MediaTextTrack[]\r\n /** Index into `textTracks`, or -1 when captions are off. */\r\n textTrack: number\r\n /** Text of the cues active right now, one entry per cue. */\r\n cues: string[]\r\n}\r\n\r\nexport type MediaStoreOptions = {\r\n /** localStorage key used to remember volume, mute and speed. Off by default. */\r\n persistKey?: string\r\n}\r\n\r\ntype Listener = () => void\r\n\r\nconst MEDIA_EVENTS = [\r\n \"play\",\r\n \"pause\",\r\n \"playing\",\r\n \"ended\",\r\n \"waiting\",\r\n \"canplay\",\r\n \"seeking\",\r\n \"seeked\",\r\n \"timeupdate\",\r\n \"durationchange\",\r\n \"loadedmetadata\",\r\n \"progress\",\r\n \"volumechange\",\r\n \"ratechange\",\r\n \"emptied\",\r\n \"error\",\r\n \"enterpictureinpicture\",\r\n \"leavepictureinpicture\",\r\n] as const\r\n\r\nconst TRACK_EVENTS = [\"addtrack\", \"removetrack\", \"change\"] as const\r\n\r\nconst initialState: MediaState = {\r\n paused: true,\r\n ended: false,\r\n started: false,\r\n waiting: false,\r\n currentTime: 0,\r\n duration: 0,\r\n bufferedEnd: 0,\r\n volume: 1,\r\n muted: false,\r\n playbackRate: 1,\r\n fullscreen: false,\r\n pictureInPicture: false,\r\n error: null,\r\n textTracks: [],\r\n textTrack: -1,\r\n cues: [],\r\n}\r\n\r\ntype WebkitVideo = HTMLVideoElement & {\r\n webkitEnterFullscreen?: () => void\r\n webkitDisplayingFullscreen?: boolean\r\n}\r\n\r\nfunction readBufferedEnd(media: HTMLMediaElement) {\r\n const { buffered, currentTime } = media\r\n for (let i = 0; i < buffered.length; i++) {\r\n if (buffered.start(i) <= currentTime && buffered.end(i) >= currentTime) {\r\n return buffered.end(i)\r\n }\r\n }\r\n return buffered.length ? buffered.end(buffered.length - 1) : 0\r\n}\r\n\r\nfunction captionTracks(media: HTMLMediaElement | null) {\r\n if (!media?.textTracks) return []\r\n return Array.from(media.textTracks).filter(\r\n (track) => track.kind === \"captions\" || track.kind === \"subtitles\"\r\n )\r\n}\r\n\r\nfunction cueText(cue: TextTrackCue) {\r\n return ((cue as VTTCue).text ?? \"\").replace(/<[^>]+>/g, \"\").trim()\r\n}\r\n\r\nconst sameList = (a: readonly unknown[], b: readonly unknown[]) =>\r\n a.length === b.length && a.every((value, i) => Object.is(value, b[i]))\r\n\r\nconst sameTracks = (a: MediaTextTrack[], b: MediaTextTrack[]) =>\r\n a.length === b.length &&\r\n a.every((t, i) => t.label === b[i].label && t.language === b[i].language && t.kind === b[i].kind)\r\n\r\ntype Preferences = Pick<MediaState, \"volume\" | \"muted\" | \"playbackRate\">\r\n\r\nfunction readPreferences(key: string): Partial<Preferences> {\r\n try {\r\n return JSON.parse(localStorage.getItem(key) ?? \"{}\")\r\n } catch {\r\n return {}\r\n }\r\n}\r\n\r\n/**\r\n * Framework-agnostic store over any HTMLMediaElement. React bindings,\r\n * web components, or anything else can subscribe to it.\r\n */\r\nexport function createMediaStore({ persistKey }: MediaStoreOptions = {}) {\r\n let state = initialState\r\n let media: HTMLMediaElement | null = null\r\n let container: HTMLElement | null = null\r\n let cueTrack: TextTrack | null = null\r\n let metadata: MediaInfo | null = null\r\n const listeners = new Set<Listener>()\r\n\r\n const set = (patch: Partial<MediaState>) => {\r\n let changed = false\r\n for (const key in patch) {\r\n const k = key as keyof MediaState\r\n const next = patch[k]\r\n const prev = state[k]\r\n if (k === \"cues\" ? !sameList(prev as string[], next as string[]) : k === \"textTracks\" ? !sameTracks(prev as MediaTextTrack[], next as MediaTextTrack[]) : !Object.is(prev, next)) {\r\n changed = true\r\n break\r\n }\r\n }\r\n if (!changed) return\r\n state = { ...state, ...patch }\r\n listeners.forEach((l) => l())\r\n }\r\n\r\n const sync = () => {\r\n if (!media) return\r\n set({\r\n paused: media.paused,\r\n ended: media.ended,\r\n started: state.started || !media.paused || media.currentTime > 0,\r\n currentTime: media.currentTime,\r\n duration: Number.isFinite(media.duration) ? media.duration : 0,\r\n bufferedEnd: readBufferedEnd(media),\r\n volume: media.volume,\r\n muted: media.muted,\r\n playbackRate: media.playbackRate,\r\n pictureInPicture:\r\n typeof document !== \"undefined\" && document.pictureInPictureElement === media,\r\n error: media.error,\r\n })\r\n }\r\n\r\n /* ------------------------------ Captions ------------------------------ */\r\n\r\n const readCues = () => {\r\n const active = cueTrack?.activeCues\r\n set({ cues: active ? Array.from(active).map(cueText).filter(Boolean) : [] })\r\n }\r\n\r\n const bindCueTrack = (track: TextTrack | null) => {\r\n if (cueTrack === track) return\r\n cueTrack?.removeEventListener(\"cuechange\", readCues)\r\n cueTrack = track\r\n cueTrack?.addEventListener(\"cuechange\", readCues)\r\n }\r\n\r\n // Native rendering is replaced by our own cue layer: the active track runs\r\n // in \"hidden\" mode (cues load, nothing paints) and every other track is off.\r\n const syncTracks = (requested = state.textTrack) => {\r\n const tracks = captionTracks(media)\r\n let active = requested\r\n tracks.forEach((track, i) => {\r\n if (track.mode === \"showing\") active = i\r\n })\r\n if (active >= tracks.length) active = -1\r\n tracks.forEach((track, i) => {\r\n const mode = i === active ? \"hidden\" : \"disabled\"\r\n if (track.mode !== mode) track.mode = mode\r\n })\r\n bindCueTrack(tracks[active] ?? null)\r\n set({\r\n textTracks: tracks.map((track, i) => ({\r\n label: track.label || track.language || `Track ${i + 1}`,\r\n language: track.language,\r\n kind: track.kind as MediaTextTrack[\"kind\"],\r\n })),\r\n textTrack: active,\r\n })\r\n readCues()\r\n }\r\n\r\n const onTracksChange = () => syncTracks()\r\n\r\n /* ---------------------------- Media Session --------------------------- */\r\n\r\n const applyMediaSession = () => {\r\n if (typeof navigator === \"undefined\" || !(\"mediaSession\" in navigator) || !metadata) return\r\n const session = navigator.mediaSession\r\n session.metadata = new MediaMetadata(metadata)\r\n const handlers: [MediaSessionAction, MediaSessionActionHandler][] = [\r\n [\"play\", () => actions.play()],\r\n [\"pause\", () => actions.pause()],\r\n [\"seekbackward\", (d) => actions.seekBy(-(d.seekOffset ?? 10))],\r\n [\"seekforward\", (d) => actions.seekBy(d.seekOffset ?? 10)],\r\n [\"seekto\", (d) => d.seekTime !== undefined && actions.seek(d.seekTime)],\r\n ]\r\n for (const [action, handler] of handlers) {\r\n try {\r\n session.setActionHandler(action, handler)\r\n } catch {\r\n // Action not supported by this browser.\r\n }\r\n }\r\n }\r\n\r\n const updatePositionState = () => {\r\n if (!metadata || !media || typeof navigator === \"undefined\" || !(\"mediaSession\" in navigator)) return\r\n if (!Number.isFinite(media.duration) || media.duration <= 0) return\r\n try {\r\n navigator.mediaSession.setPositionState({\r\n duration: media.duration,\r\n playbackRate: media.playbackRate,\r\n position: Math.min(media.currentTime, media.duration),\r\n })\r\n } catch {\r\n // Ignore transient invalid states.\r\n }\r\n }\r\n\r\n /* ------------------------------- Events ------------------------------- */\r\n\r\n const savePreferences = () => {\r\n if (!persistKey || !media) return\r\n try {\r\n const prefs: Preferences = {\r\n volume: media.volume,\r\n muted: media.muted,\r\n playbackRate: media.playbackRate,\r\n }\r\n localStorage.setItem(persistKey, JSON.stringify(prefs))\r\n } catch {\r\n // Storage may be full or disabled.\r\n }\r\n }\r\n\r\n const onEvent = (event: Event) => {\r\n switch (event.type) {\r\n case \"emptied\":\r\n set({ started: false, waiting: false })\r\n break\r\n case \"waiting\":\r\n set({ waiting: true })\r\n break\r\n case \"playing\":\r\n case \"canplay\":\r\n case \"pause\":\r\n case \"error\":\r\n set({ waiting: false })\r\n break\r\n case \"play\":\r\n applyMediaSession()\r\n break\r\n case \"volumechange\":\r\n case \"ratechange\":\r\n savePreferences()\r\n break\r\n case \"loadedmetadata\":\r\n syncTracks()\r\n break\r\n }\r\n if (event.type === \"durationchange\" || event.type === \"ratechange\" || event.type === \"seeked\") {\r\n updatePositionState()\r\n }\r\n sync()\r\n }\r\n\r\n const onFullscreenChange = () => {\r\n const el = document.fullscreenElement\r\n const video = media as WebkitVideo | null\r\n set({\r\n fullscreen:\r\n (!!el && (el === container || el === media)) || !!video?.webkitDisplayingFullscreen,\r\n })\r\n }\r\n\r\n const attach = (el: HTMLMediaElement | null) => {\r\n if (media === el) return\r\n if (media) {\r\n MEDIA_EVENTS.forEach((e) => media!.removeEventListener(e, onEvent))\r\n TRACK_EVENTS.forEach((e) => media!.textTracks?.removeEventListener?.(e, onTracksChange))\r\n media.removeEventListener(\"webkitbeginfullscreen\", onFullscreenChange)\r\n media.removeEventListener(\"webkitendfullscreen\", onFullscreenChange)\r\n bindCueTrack(null)\r\n }\r\n media = el\r\n if (!el) {\r\n state = initialState\r\n listeners.forEach((l) => l())\r\n return\r\n }\r\n if (persistKey) {\r\n const prefs = readPreferences(persistKey)\r\n if (typeof prefs.volume === \"number\") el.volume = Math.min(Math.max(prefs.volume, 0), 1)\r\n if (typeof prefs.muted === \"boolean\") el.muted = prefs.muted\r\n if (typeof prefs.playbackRate === \"number\") el.playbackRate = prefs.playbackRate\r\n }\r\n MEDIA_EVENTS.forEach((e) => el.addEventListener(e, onEvent))\r\n TRACK_EVENTS.forEach((e) => el.textTracks?.addEventListener?.(e, onTracksChange))\r\n el.addEventListener(\"webkitbeginfullscreen\", onFullscreenChange)\r\n el.addEventListener(\"webkitendfullscreen\", onFullscreenChange)\r\n sync()\r\n syncTracks()\r\n }\r\n\r\n const setContainer = (el: HTMLElement | null) => {\r\n if (typeof document === \"undefined\") return\r\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange)\r\n container = el\r\n if (el) document.addEventListener(\"fullscreenchange\", onFullscreenChange)\r\n }\r\n\r\n const play = async () => {\r\n if (!media) return\r\n try {\r\n await media.play()\r\n } catch {\r\n // Autoplay policies may reject; the paused state stays accurate.\r\n }\r\n }\r\n\r\n const pause = () => media?.pause()\r\n\r\n const actions = {\r\n play,\r\n pause,\r\n toggle: () => (media?.paused || media?.ended ? play() : pause()),\r\n seek: (time: number) => {\r\n if (!media) return\r\n const max = Number.isFinite(media.duration) ? media.duration : time\r\n media.currentTime = Math.min(Math.max(time, 0), max)\r\n sync()\r\n },\r\n seekBy: (delta: number) => actions.seek((media?.currentTime ?? 0) + delta),\r\n /** Jump to a fraction (0–1) of the duration. */\r\n seekToRatio: (ratio: number) => actions.seek(ratio * (media?.duration || 0)),\r\n setVolume: (volume: number) => {\r\n if (!media) return\r\n media.volume = Math.min(Math.max(volume, 0), 1)\r\n media.muted = media.volume === 0\r\n },\r\n toggleMute: () => {\r\n if (!media) return\r\n if (media.muted && media.volume === 0) media.volume = 1\r\n media.muted = !media.muted\r\n },\r\n setPlaybackRate: (rate: number) => {\r\n if (media) media.playbackRate = rate\r\n },\r\n /** Select a caption track by index, or -1 to turn captions off. */\r\n setTextTrack: (index: number) => syncTracksExplicit(index),\r\n toggleCaptions: () => {\r\n if (!state.textTracks.length) return\r\n syncTracksExplicit(state.textTrack === -1 ? 0 : -1)\r\n },\r\n /** Reload the current source after an error. */\r\n retry: () => {\r\n if (!media) return\r\n media.load()\r\n void play()\r\n },\r\n setMetadata: (next: MediaInfo | null) => {\r\n metadata = next\r\n if (media && !media.paused) applyMediaSession()\r\n },\r\n toggleFullscreen: async () => {\r\n if (typeof document === \"undefined\") return\r\n if (document.fullscreenElement) {\r\n await document.exitFullscreen().catch(() => {})\r\n return\r\n }\r\n if (container?.requestFullscreen) {\r\n await container.requestFullscreen().catch(() => {})\r\n return\r\n }\r\n // iOS Safari only supports fullscreen on the video element itself.\r\n ;(media as WebkitVideo | null)?.webkitEnterFullscreen?.()\r\n },\r\n togglePictureInPicture: async () => {\r\n if (!(media instanceof HTMLVideoElement)) return\r\n try {\r\n if (document.pictureInPictureElement) await document.exitPictureInPicture()\r\n else await media.requestPictureInPicture()\r\n } catch {\r\n // Unsupported or blocked by the browser.\r\n }\r\n },\r\n }\r\n\r\n // An explicit choice must win over a track the browser marked \"showing\".\r\n const syncTracksExplicit = (index: number) => {\r\n captionTracks(media).forEach((track, i) => {\r\n if (i !== index && track.mode === \"showing\") track.mode = \"disabled\"\r\n })\r\n syncTracks(index)\r\n }\r\n\r\n return {\r\n getState: () => state,\r\n getServerState: () => initialState,\r\n getMedia: () => media,\r\n subscribe: (listener: Listener) => {\r\n listeners.add(listener)\r\n return () => listeners.delete(listener)\r\n },\r\n attach,\r\n setContainer,\r\n ...actions,\r\n }\r\n}\r\n\r\nexport type MediaStore = ReturnType<typeof createMediaStore>\r\n\r\nexport function formatTime(seconds: number) {\r\n if (!Number.isFinite(seconds) || seconds < 0) seconds = 0\r\n const s = Math.floor(seconds % 60)\r\n const m = Math.floor((seconds / 60) % 60)\r\n const h = Math.floor(seconds / 3600)\r\n const ss = s.toString().padStart(2, \"0\")\r\n return h > 0 ? `${h}:${m.toString().padStart(2, \"0\")}:${ss}` : `${m}:${ss}`\r\n}\r\n\r\n/** Human-readable message for a MediaError code. */\r\nexport function describeMediaError(error: MediaError | null) {\r\n switch (error?.code) {\r\n case 1:\r\n return \"Playback was aborted.\"\r\n case 2:\r\n return \"A network error stopped the download.\"\r\n case 3:\r\n return \"This media could not be decoded.\"\r\n case 4:\r\n return \"This format or source isn't supported.\"\r\n default:\r\n return \"Something went wrong during playback.\"\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../lib/media-store.ts"],"names":[],"mappings":";AA4CA,IAAM,YAAA,GAAe;AAAA,EACnB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,uBAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,YAAA,GAAe,CAAC,UAAA,EAAY,aAAA,EAAe,QAAQ,CAAA;AAEzD,IAAM,YAAA,GAA2B;AAAA,EAC/B,MAAA,EAAQ,IAAA;AAAA,EACR,KAAA,EAAO,KAAA;AAAA,EACP,OAAA,EAAS,KAAA;AAAA,EACT,OAAA,EAAS,KAAA;AAAA,EACT,WAAA,EAAa,CAAA;AAAA,EACb,QAAA,EAAU,CAAA;AAAA,EACV,WAAA,EAAa,CAAA;AAAA,EACb,MAAA,EAAQ,CAAA;AAAA,EACR,KAAA,EAAO,KAAA;AAAA,EACP,YAAA,EAAc,CAAA;AAAA,EACd,UAAA,EAAY,KAAA;AAAA,EACZ,gBAAA,EAAkB,KAAA;AAAA,EAClB,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAW,KAAA;AAAA,EACX,YAAY,EAAC;AAAA,EACb,SAAA,EAAW,EAAA;AAAA,EACX,MAAM;AACR,CAAA;AAOA,SAAS,gBAAgB,KAAA,EAAyB;AAChD,EAAA,MAAM,EAAE,QAAA,EAAU,WAAA,EAAY,GAAI,KAAA;AAClC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,IAAA,IAAI,QAAA,CAAS,MAAM,CAAC,CAAA,IAAK,eAAe,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,IAAK,WAAA,EAAa;AACtE,MAAA,OAAO,QAAA,CAAS,IAAI,CAAC,CAAA;AAAA,IACvB;AAAA,EACF;AACA,EAAA,OAAO,SAAS,MAAA,GAAS,QAAA,CAAS,IAAI,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA,GAAI,CAAA;AAC/D;AAEA,SAAS,cAAc,KAAA,EAAgC;AACrD,EAAA,IAAI,CAAC,KAAA,EAAO,UAAA,EAAY,OAAO,EAAC;AAChC,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,CAAE,MAAA;AAAA,IAClC,CAAC,KAAA,KAAU,KAAA,CAAM,IAAA,KAAS,UAAA,IAAc,MAAM,IAAA,KAAS;AAAA,GACzD;AACF;AAMA,SAAS,QAAQ,GAAA,EAAmB;AAClC,EAAA,MAAM,GAAA,GAAM,GAAA;AACZ,EAAA,MAAM,IAAA,GAAO,OAAO,GAAA,CAAI,YAAA,KAAiB,UAAA,GAAa,GAAA,CAAI,YAAA,EAAa,CAAE,WAAA,GAAc,GAAA,CAAI,IAAA,EAAM,OAAA,CAAQ,YAAY,EAAE,CAAA;AACvH,EAAA,OAAA,CAAQ,IAAA,IAAQ,IAAI,IAAA,EAAK;AAC3B;AAGA,SAAS,YAAA,CAAa,OAAgC,MAAA,EAAqB;AACzE,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,iBAAiB,OAAO,CAAA,IAAK,EAAE,CAAA,CAAE,IAAA,CAAK,CAAC,KAAA,KAAU,MAAM,OAAO,CAAA;AAC3F,EAAA,OAAO,EAAA,GAAK,MAAA,CAAO,OAAA,CAAQ,EAAA,CAAG,KAAK,CAAA,GAAI,EAAA;AACzC;AAEA,IAAM,WAAW,CAAC,CAAA,EAAuB,MACvC,CAAA,CAAE,MAAA,KAAW,EAAE,MAAA,IAAU,CAAA,CAAE,MAAM,CAAC,KAAA,EAAO,MAAM,MAAA,CAAO,EAAA,CAAG,OAAO,CAAA,CAAE,CAAC,CAAC,CAAC,CAAA;AAEvE,IAAM,UAAA,GAAa,CAAC,CAAA,EAAqB,CAAA,KACvC,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,IACf,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,KAAU,CAAA,CAAE,CAAC,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,QAAA,KAAa,CAAA,CAAE,CAAC,CAAA,CAAE,QAAA,IAAY,CAAA,CAAE,IAAA,KAAS,CAAA,CAAE,CAAC,EAAE,IAAI,CAAA;AAIlG,SAAS,gBAAgB,GAAA,EAAmC;AAC1D,EAAA,IAAI;AACF,IAAA,OAAO,KAAK,KAAA,CAAM,YAAA,CAAa,OAAA,CAAQ,GAAG,KAAK,IAAI,CAAA;AAAA,EACrD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAMO,SAAS,gBAAA,CAAiB,EAAE,UAAA,EAAW,GAAuB,EAAC,EAAG;AACvE,EAAA,IAAI,KAAA,GAAQ,YAAA;AACZ,EAAA,IAAI,KAAA,GAAiC,IAAA;AACrC,EAAA,IAAI,SAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,QAAA,GAA6B,IAAA;AACjC,EAAA,IAAI,QAAA,GAA6B,IAAA;AAGjC,EAAA,IAAI,WAAA,GAAc,KAAA;AAClB,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAc;AAEpC,EAAA,MAAM,GAAA,GAAM,CAAC,KAAA,KAA+B;AAC1C,IAAA,IAAI,OAAA,GAAU,KAAA;AACd,IAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,MAAA,MAAM,CAAA,GAAI,GAAA;AACV,MAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,MAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,MAAA,IAAI,MAAM,MAAA,GAAS,CAAC,SAAS,IAAA,EAAkB,IAAgB,IAAI,CAAA,KAAM,YAAA,GAAe,CAAC,UAAA,CAAW,IAAA,EAA0B,IAAwB,CAAA,GAAI,CAAC,OAAO,EAAA,CAAG,IAAA,EAAM,IAAI,CAAA,EAAG;AAChL,QAAA,OAAA,GAAU,IAAA;AACV,QAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAO,GAAG,KAAA,EAAM;AAC7B,IAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA;AAAA,EAC9B,CAAA;AAEA,EAAA,MAAM,OAAO,MAAM;AACjB,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,GAAA,CAAI;AAAA,MACF,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,SAAS,KAAA,CAAM,OAAA,IAAW,CAAC,KAAA,CAAM,MAAA,IAAU,MAAM,WAAA,GAAc,CAAA;AAAA,MAC/D,aAAa,KAAA,CAAM,WAAA;AAAA,MACnB,UAAU,MAAA,CAAO,QAAA,CAAS,MAAM,QAAQ,CAAA,GAAI,MAAM,QAAA,GAAW,CAAA;AAAA,MAC7D,WAAA,EAAa,gBAAgB,KAAK,CAAA;AAAA,MAClC,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,cAAc,KAAA,CAAM,YAAA;AAAA,MACpB,gBAAA,EACE,OAAO,QAAA,KAAa,WAAA,IAAe,SAAS,uBAAA,KAA4B,KAAA;AAAA,MAC1E,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,SAAA,EAAW,QAAQ,KAAA,CAAM,GAAA,IAAO,MAAM,UAAA,IAAc,KAAA,CAAM,aAAA,CAAc,aAAa,CAAC;AAAA,KACvF,CAAA;AAAA,EACH,CAAA;AAIA,EAAA,MAAM,WAAW,MAAM;AACrB,IAAA,MAAM,SAAS,QAAA,EAAU,UAAA;AACzB,IAAA,GAAA,CAAI,EAAE,IAAA,EAAM,MAAA,GAAS,KAAA,CAAM,KAAK,MAAM,CAAA,CAAE,GAAA,CAAI,OAAO,EAAE,MAAA,CAAO,OAAO,CAAA,GAAI,IAAI,CAAA;AAAA,EAC7E,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAA4B;AAChD,IAAA,IAAI,aAAa,KAAA,EAAO;AACxB,IAAA,QAAA,EAAU,mBAAA,CAAoB,aAAa,QAAQ,CAAA;AACnD,IAAA,QAAA,GAAW,KAAA;AACX,IAAA,QAAA,EAAU,gBAAA,CAAiB,aAAa,QAAQ,CAAA;AAAA,EAClD,CAAA;AAIA,EAAA,MAAM,UAAA,GAAa,CAAC,SAAA,GAAY,KAAA,CAAM,SAAA,KAAc;AAClD,IAAA,MAAM,MAAA,GAAS,cAAc,KAAK,CAAA;AAKlC,IAAA,IAAI,MAAA,GAAS,cAAc,EAAA,IAAM,CAAC,cAAc,YAAA,CAAa,KAAA,EAAO,MAAM,CAAA,GAAI,SAAA;AAC9E,IAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,EAAO,CAAA,KAAM;AAC3B,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,SAAA,EAAW,MAAA,GAAS,CAAA;AAAA,IACzC,CAAC,CAAA;AACD,IAAA,IAAI,MAAA,IAAU,MAAA,CAAO,MAAA,EAAQ,MAAA,GAAS,EAAA;AACtC,IAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,EAAO,CAAA,KAAM;AAC3B,MAAA,MAAM,IAAA,GAAO,CAAA,KAAM,MAAA,GAAS,QAAA,GAAW,UAAA;AACvC,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,IAAA,EAAM,KAAA,CAAM,IAAA,GAAO,IAAA;AAAA,IACxC,CAAC,CAAA;AACD,IAAA,YAAA,CAAa,MAAA,CAAO,MAAM,CAAA,IAAK,IAAI,CAAA;AACnC,IAAA,GAAA,CAAI;AAAA,MACF,UAAA,EAAY,MAAA,CAAO,GAAA,CAAI,CAAC,OAAO,CAAA,MAAO;AAAA,QACpC,OAAO,KAAA,CAAM,KAAA,IAAS,MAAM,QAAA,IAAY,CAAA,MAAA,EAAS,IAAI,CAAC,CAAA,CAAA;AAAA,QACtD,UAAU,KAAA,CAAM,QAAA;AAAA,QAChB,MAAM,KAAA,CAAM;AAAA,OACd,CAAE,CAAA;AAAA,MACF,SAAA,EAAW;AAAA,KACZ,CAAA;AACD,IAAA,QAAA,EAAS;AAAA,EACX,CAAA;AAEA,EAAA,MAAM,cAAA,GAAiB,MAAM,UAAA,EAAW;AAIxC,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,EAAE,cAAA,IAAkB,SAAA,CAAA,IAAc,CAAC,QAAA,EAAU;AACrF,IAAA,MAAM,UAAU,SAAA,CAAU,YAAA;AAC1B,IAAA,OAAA,CAAQ,QAAA,GAAW,IAAI,aAAA,CAAc,QAAQ,CAAA;AAC7C,IAAA,MAAM,QAAA,GAA8D;AAAA,MAClE,CAAC,MAAA,EAAQ,MAAM,OAAA,CAAQ,MAAM,CAAA;AAAA,MAC7B,CAAC,OAAA,EAAS,MAAM,OAAA,CAAQ,OAAO,CAAA;AAAA,MAC/B,CAAC,cAAA,EAAgB,CAAC,CAAA,KAAM,OAAA,CAAQ,OAAO,EAAE,CAAA,CAAE,UAAA,IAAc,EAAA,CAAG,CAAC,CAAA;AAAA,MAC7D,CAAC,eAAe,CAAC,CAAA,KAAM,QAAQ,MAAA,CAAO,CAAA,CAAE,UAAA,IAAc,EAAE,CAAC,CAAA;AAAA,MACzD,CAAC,QAAA,EAAU,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,MAAA,IAAa,OAAA,CAAQ,IAAA,CAAK,CAAA,CAAE,QAAQ,CAAC;AAAA,KACxE;AACA,IAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,OAAO,CAAA,IAAK,QAAA,EAAU;AACxC,MAAA,IAAI;AACF,QAAA,OAAA,CAAQ,gBAAA,CAAiB,QAAQ,OAAO,CAAA;AAAA,MAC1C,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,IAAI,CAAC,YAAY,CAAC,KAAA,IAAS,OAAO,SAAA,KAAc,WAAA,IAAe,EAAE,cAAA,IAAkB,SAAA,CAAA,EAAY;AAC/F,IAAA,IAAI,CAAC,OAAO,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA,IAAK,KAAA,CAAM,YAAY,CAAA,EAAG;AAC7D,IAAA,IAAI;AACF,MAAA,SAAA,CAAU,aAAa,gBAAA,CAAiB;AAAA,QACtC,UAAU,KAAA,CAAM,QAAA;AAAA,QAChB,cAAc,KAAA,CAAM,YAAA;AAAA,QACpB,UAAU,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,WAAA,EAAa,MAAM,QAAQ;AAAA,OACrD,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA;AAIA,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,IAAI,CAAC,UAAA,IAAc,CAAC,KAAA,EAAO;AAC3B,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAqB;AAAA,QACzB,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,cAAc,KAAA,CAAM;AAAA,OACtB;AACA,MAAA,YAAA,CAAa,OAAA,CAAQ,UAAA,EAAY,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,IACxD,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAAiB;AAChC,IAAA,QAAQ,MAAM,IAAA;AAAM,MAClB,KAAK,SAAA;AACH,QAAA,GAAA,CAAI,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,OAAO,CAAA;AACtC,QAAA;AAAA,MACF,KAAK,SAAA;AACH,QAAA,GAAA,CAAI,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AACrB,QAAA;AAAA,MACF,KAAK,SAAA;AAAA,MACL,KAAK,SAAA;AAAA,MACL,KAAK,OAAA;AAAA,MACL,KAAK,OAAA;AACH,QAAA,GAAA,CAAI,EAAE,OAAA,EAAS,KAAA,EAAO,CAAA;AACtB,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,iBAAA,EAAkB;AAClB,QAAA;AAAA,MACF,KAAK,cAAA;AAAA,MACL,KAAK,YAAA;AACH,QAAA,eAAA,EAAgB;AAChB,QAAA;AAAA,MACF,KAAK,gBAAA;AACH,QAAA,UAAA,EAAW;AACX,QAAA;AAAA;AAEJ,IAAA,IAAI,KAAA,CAAM,SAAS,gBAAA,IAAoB,KAAA,CAAM,SAAS,YAAA,IAAgB,KAAA,CAAM,SAAS,QAAA,EAAU;AAC7F,MAAA,mBAAA,EAAoB;AAAA,IACtB;AACA,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AAEA,EAAA,MAAM,qBAAqB,MAAM;AAC/B,IAAA,MAAM,KAAK,QAAA,CAAS,iBAAA;AACpB,IAAA,MAAM,KAAA,GAAQ,KAAA;AACd,IAAA,GAAA,CAAI;AAAA,MACF,UAAA,EACG,CAAC,CAAC,EAAA,KAAO,EAAA,KAAO,aAAa,EAAA,KAAO,KAAA,CAAA,IAAW,CAAC,CAAC,KAAA,EAAO;AAAA,KAC5D,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,EAAA,KAAgC;AAC9C,IAAA,IAAI,UAAU,EAAA,EAAI;AAClB,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,YAAA,CAAa,QAAQ,CAAC,CAAA,KAAM,MAAO,mBAAA,CAAoB,CAAA,EAAG,OAAO,CAAC,CAAA;AAClE,MAAA,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,KAAM,KAAA,CAAO,YAAY,mBAAA,GAAsB,CAAA,EAAG,cAAc,CAAC,CAAA;AACvF,MAAA,KAAA,CAAM,mBAAA,CAAoB,yBAAyB,kBAAkB,CAAA;AACrE,MAAA,KAAA,CAAM,mBAAA,CAAoB,uBAAuB,kBAAkB,CAAA;AACnE,MAAA,YAAA,CAAa,IAAI,CAAA;AAAA,IACnB;AACA,IAAA,KAAA,GAAQ,EAAA;AACR,IAAA,IAAI,CAAC,EAAA,EAAI;AACP,MAAA,KAAA,GAAQ,YAAA;AACR,MAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA;AAC5B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,MAAM,KAAA,GAAQ,gBAAgB,UAAU,CAAA;AACxC,MAAA,IAAI,OAAO,KAAA,CAAM,MAAA,KAAW,QAAA,KAAa,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,MAAA,EAAQ,CAAC,GAAG,CAAC,CAAA;AACvF,MAAA,IAAI,OAAO,KAAA,CAAM,KAAA,KAAU,SAAA,EAAW,EAAA,CAAG,QAAQ,KAAA,CAAM,KAAA;AACvD,MAAA,IAAI,OAAO,KAAA,CAAM,YAAA,KAAiB,QAAA,EAAU,EAAA,CAAG,eAAe,KAAA,CAAM,YAAA;AAAA,IACtE;AACA,IAAA,YAAA,CAAa,QAAQ,CAAC,CAAA,KAAM,GAAG,gBAAA,CAAiB,CAAA,EAAG,OAAO,CAAC,CAAA;AAC3D,IAAA,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,KAAM,EAAA,CAAG,YAAY,gBAAA,GAAmB,CAAA,EAAG,cAAc,CAAC,CAAA;AAChF,IAAA,EAAA,CAAG,gBAAA,CAAiB,yBAAyB,kBAAkB,CAAA;AAC/D,IAAA,EAAA,CAAG,gBAAA,CAAiB,uBAAuB,kBAAkB,CAAA;AAC7D,IAAA,IAAA,EAAK;AACL,IAAA,UAAA,EAAW;AAAA,EACb,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,EAAA,KAA2B;AAC/C,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,IAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,kBAAkB,CAAA;AACnE,IAAA,SAAA,GAAY,EAAA;AACZ,IAAA,IAAI,EAAA,EAAI,QAAA,CAAS,gBAAA,CAAiB,kBAAA,EAAoB,kBAAkB,CAAA;AAAA,EAC1E,CAAA;AAEA,EAAA,MAAM,OAAO,YAAY;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,IAAI;AACF,MAAA,MAAM,MAAM,IAAA,EAAK;AAAA,IACnB,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,EAAO,KAAA,EAAM;AAEjC,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,IAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA,EAAQ,MAAO,KAAA,EAAO,MAAA,IAAU,OAAO,KAAA,GAAQ,IAAA,KAAS,KAAA,EAAM;AAAA,IAC9D,IAAA,EAAM,CAAC,IAAA,KAAiB;AACtB,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,MAAM,MAAM,MAAA,CAAO,QAAA,CAAS,MAAM,QAAQ,CAAA,GAAI,MAAM,QAAA,GAAW,IAAA;AAC/D,MAAA,KAAA,CAAM,WAAA,GAAc,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,IAAA,EAAM,CAAC,GAAG,GAAG,CAAA;AACnD,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,KAAA,KAAkB,OAAA,CAAQ,MAAM,KAAA,EAAO,WAAA,IAAe,KAAK,KAAK,CAAA;AAAA;AAAA,IAEzE,WAAA,EAAa,CAAC,KAAA,KAAkB,OAAA,CAAQ,KAAK,KAAA,IAAS,KAAA,EAAO,YAAY,CAAA,CAAE,CAAA;AAAA,IAC3E,SAAA,EAAW,CAAC,MAAA,KAAmB;AAC7B,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,KAAA,CAAM,MAAA,GAAS,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,MAAA,EAAQ,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAA,KAAA,CAAM,KAAA,GAAQ,MAAM,MAAA,KAAW,CAAA;AAAA,IACjC,CAAA;AAAA,IACA,YAAY,MAAM;AAChB,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,IAAI,MAAM,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,CAAA,QAAS,MAAA,GAAS,CAAA;AACtD,MAAA,KAAA,CAAM,KAAA,GAAQ,CAAC,KAAA,CAAM,KAAA;AAAA,IACvB,CAAA;AAAA,IACA,eAAA,EAAiB,CAAC,IAAA,KAAiB;AACjC,MAAA,IAAI,KAAA,QAAa,YAAA,GAAe,IAAA;AAAA,IAClC,CAAA;AAAA;AAAA,IAEA,YAAA,EAAc,CAAC,KAAA,KAAkB,kBAAA,CAAmB,KAAK,CAAA;AAAA,IACzD,gBAAgB,MAAM;AACpB,MAAA,IAAI,CAAC,KAAA,CAAM,UAAA,CAAW,MAAA,EAAQ;AAC9B,MAAA,kBAAA,CAAmB,KAAA,CAAM,SAAA,KAAc,EAAA,GAAK,CAAA,GAAI,EAAE,CAAA;AAAA,IACpD,CAAA;AAAA;AAAA,IAEA,OAAO,MAAM;AACX,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,KAAA,CAAM,IAAA,EAAK;AACX,MAAA,KAAK,IAAA,EAAK;AAAA,IACZ,CAAA;AAAA,IACA,WAAA,EAAa,CAAC,IAAA,KAA2B;AACvC,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,IAAI,KAAA,IAAS,CAAC,KAAA,CAAM,MAAA,EAAQ,iBAAA,EAAkB;AAAA,IAChD,CAAA;AAAA,IACA,kBAAkB,YAAY;AAC5B,MAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,MAAA,IAAI,SAAS,iBAAA,EAAmB;AAC9B,QAAA,MAAM,QAAA,CAAS,cAAA,EAAe,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAC9C,QAAA;AAAA,MACF;AACA,MAAA,IAAI,WAAW,iBAAA,EAAmB;AAChC,QAAA,MAAM,SAAA,CAAU,iBAAA,EAAkB,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAClD,QAAA;AAAA,MACF;AAEC,MAAC,OAA8B,qBAAA,IAAwB;AAAA,IAC1D,CAAA;AAAA,IACA,wBAAwB,YAAY;AAClC,MAAA,IAAI,EAAE,iBAAiB,gBAAA,CAAA,EAAmB;AAC1C,MAAA,IAAI;AACF,QAAA,IAAI,QAAA,CAAS,uBAAA,EAAyB,MAAM,QAAA,CAAS,oBAAA,EAAqB;AAAA,aACrE,MAAM,MAAM,uBAAA,EAAwB;AAAA,MAC3C,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,GACF;AAGA,EAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAkB;AAC5C,IAAA,WAAA,GAAc,IAAA;AACd,IAAA,aAAA,CAAc,KAAK,CAAA,CAAE,OAAA,CAAQ,CAAC,OAAO,CAAA,KAAM;AACzC,MAAA,IAAI,MAAM,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,SAAA,QAAiB,IAAA,GAAO,UAAA;AAAA,IAC5D,CAAC,CAAA;AACD,IAAA,UAAA,CAAW,KAAK,CAAA;AAAA,EAClB,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,UAAU,MAAM,KAAA;AAAA,IAChB,gBAAgB,MAAM,YAAA;AAAA,IACtB,UAAU,MAAM,KAAA;AAAA,IAChB,SAAA,EAAW,CAAC,QAAA,KAAuB;AACjC,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,MAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,MAAA;AAAA,IACA,YAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;AASO,SAAS,UAAA,CAAW,OAAA,EAAiB,SAAA,GAAY,OAAA,EAAS;AAC/D,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,IAAK,OAAA,GAAU,GAAG,OAAA,GAAU,CAAA;AACxD,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACjC,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAO,OAAA,GAAU,KAAM,EAAE,CAAA;AACxC,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,IAAI,CAAA;AACnC,EAAA,MAAM,KAAK,CAAA,CAAE,QAAA,EAAS,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACvC,EAAA,MAAM,QAAQ,CAAA,GAAI,CAAA,IAAM,OAAO,QAAA,CAAS,SAAS,KAAK,SAAA,IAAa,IAAA;AACnE,EAAA,OAAO,QAAQ,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,UAAS,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,EAAE,KAAK,CAAA,EAAG,CAAC,IAAI,EAAE,CAAA,CAAA;AAC3E;AAGO,SAAS,mBAAmB,KAAA,EAA0B;AAC3D,EAAA,QAAQ,OAAO,IAAA;AAAM,IACnB,KAAK,CAAA;AACH,MAAA,OAAO,uBAAA;AAAA,IACT,KAAK,CAAA;AACH,MAAA,OAAO,uCAAA;AAAA,IACT,KAAK,CAAA;AACH,MAAA,OAAO,kCAAA;AAAA,IACT,KAAK,CAAA;AACH,MAAA,OAAO,gCAAA;AAAA,IACT;AACE,MAAA,OAAO,uCAAA;AAAA;AAEb","file":"core.js","sourcesContent":["export type MediaTextTrack = {\r\n label: string\r\n language: string\r\n kind: \"captions\" | \"subtitles\"\r\n}\r\n\r\nexport type MediaInfo = {\r\n title?: string\r\n artist?: string\r\n album?: string\r\n artwork?: { src: string; sizes?: string; type?: string }[]\r\n}\r\n\r\nexport type MediaState = {\r\n paused: boolean\r\n ended: boolean\r\n started: boolean\r\n waiting: boolean\r\n currentTime: number\r\n duration: number\r\n bufferedEnd: number\r\n volume: number\r\n muted: boolean\r\n playbackRate: number\r\n fullscreen: boolean\r\n pictureInPicture: boolean\r\n error: MediaError | null\r\n /** False while the element has no source to play. */\r\n hasSource: boolean\r\n /** Caption and subtitle tracks, in document order. */\r\n textTracks: MediaTextTrack[]\r\n /** Index into `textTracks`, or -1 when captions are off. */\r\n textTrack: number\r\n /** Text of the cues active right now, one entry per cue. */\r\n cues: string[]\r\n}\r\n\r\nexport type MediaStoreOptions = {\r\n /** localStorage key used to remember volume, mute and speed. Off by default. */\r\n persistKey?: string\r\n}\r\n\r\ntype Listener = () => void\r\n\r\nconst MEDIA_EVENTS = [\r\n \"play\",\r\n \"pause\",\r\n \"playing\",\r\n \"ended\",\r\n \"waiting\",\r\n \"canplay\",\r\n \"seeking\",\r\n \"seeked\",\r\n \"timeupdate\",\r\n \"durationchange\",\r\n \"loadedmetadata\",\r\n \"progress\",\r\n \"volumechange\",\r\n \"ratechange\",\r\n \"emptied\",\r\n \"loadstart\",\r\n \"error\",\r\n \"enterpictureinpicture\",\r\n \"leavepictureinpicture\",\r\n] as const\r\n\r\nconst TRACK_EVENTS = [\"addtrack\", \"removetrack\", \"change\"] as const\r\n\r\nconst initialState: MediaState = {\r\n paused: true,\r\n ended: false,\r\n started: false,\r\n waiting: false,\r\n currentTime: 0,\r\n duration: 0,\r\n bufferedEnd: 0,\r\n volume: 1,\r\n muted: false,\r\n playbackRate: 1,\r\n fullscreen: false,\r\n pictureInPicture: false,\r\n error: null,\r\n hasSource: false,\r\n textTracks: [],\r\n textTrack: -1,\r\n cues: [],\r\n}\r\n\r\ntype WebkitVideo = HTMLVideoElement & {\r\n webkitEnterFullscreen?: () => void\r\n webkitDisplayingFullscreen?: boolean\r\n}\r\n\r\nfunction readBufferedEnd(media: HTMLMediaElement) {\r\n const { buffered, currentTime } = media\r\n for (let i = 0; i < buffered.length; i++) {\r\n if (buffered.start(i) <= currentTime && buffered.end(i) >= currentTime) {\r\n return buffered.end(i)\r\n }\r\n }\r\n return buffered.length ? buffered.end(buffered.length - 1) : 0\r\n}\r\n\r\nfunction captionTracks(media: HTMLMediaElement | null) {\r\n if (!media?.textTracks) return []\r\n return Array.from(media.textTracks).filter(\r\n (track) => track.kind === \"captions\" || track.kind === \"subtitles\"\r\n )\r\n}\r\n\r\n/**\r\n * The HTML form drops voice and class tags and decodes entities, so a cue\r\n * written as `Q&A` reads `Q&A`. jsdom has no `getCueAsHTML`.\r\n */\r\nfunction cueText(cue: TextTrackCue) {\r\n const vtt = cue as VTTCue\r\n const text = typeof vtt.getCueAsHTML === \"function\" ? vtt.getCueAsHTML().textContent : vtt.text?.replace(/<[^>]+>/g, \"\")\r\n return (text ?? \"\").trim()\r\n}\r\n\r\n/* the track a `<track default>` element asks for, or -1 */\r\nfunction defaultTrack(media: HTMLMediaElement | null, tracks: TextTrack[]) {\r\n const el = Array.from(media?.querySelectorAll(\"track\") ?? []).find((track) => track.default)\r\n return el ? tracks.indexOf(el.track) : -1\r\n}\r\n\r\nconst sameList = (a: readonly unknown[], b: readonly unknown[]) =>\r\n a.length === b.length && a.every((value, i) => Object.is(value, b[i]))\r\n\r\nconst sameTracks = (a: MediaTextTrack[], b: MediaTextTrack[]) =>\r\n a.length === b.length &&\r\n a.every((t, i) => t.label === b[i].label && t.language === b[i].language && t.kind === b[i].kind)\r\n\r\ntype Preferences = Pick<MediaState, \"volume\" | \"muted\" | \"playbackRate\">\r\n\r\nfunction readPreferences(key: string): Partial<Preferences> {\r\n try {\r\n return JSON.parse(localStorage.getItem(key) ?? \"{}\")\r\n } catch {\r\n return {}\r\n }\r\n}\r\n\r\n/**\r\n * Framework-agnostic store over any HTMLMediaElement. React bindings,\r\n * web components, or anything else can subscribe to it.\r\n */\r\nexport function createMediaStore({ persistKey }: MediaStoreOptions = {}) {\r\n let state = initialState\r\n let media: HTMLMediaElement | null = null\r\n let container: HTMLElement | null = null\r\n let cueTrack: TextTrack | null = null\r\n let metadata: MediaInfo | null = null\r\n\r\n /* set once the viewer picks a track, so `default` stops applying */\r\n let trackChosen = false\r\n const listeners = new Set<Listener>()\r\n\r\n const set = (patch: Partial<MediaState>) => {\r\n let changed = false\r\n for (const key in patch) {\r\n const k = key as keyof MediaState\r\n const next = patch[k]\r\n const prev = state[k]\r\n if (k === \"cues\" ? !sameList(prev as string[], next as string[]) : k === \"textTracks\" ? !sameTracks(prev as MediaTextTrack[], next as MediaTextTrack[]) : !Object.is(prev, next)) {\r\n changed = true\r\n break\r\n }\r\n }\r\n if (!changed) return\r\n state = { ...state, ...patch }\r\n listeners.forEach((l) => l())\r\n }\r\n\r\n const sync = () => {\r\n if (!media) return\r\n set({\r\n paused: media.paused,\r\n ended: media.ended,\r\n started: state.started || !media.paused || media.currentTime > 0,\r\n currentTime: media.currentTime,\r\n duration: Number.isFinite(media.duration) ? media.duration : 0,\r\n bufferedEnd: readBufferedEnd(media),\r\n volume: media.volume,\r\n muted: media.muted,\r\n playbackRate: media.playbackRate,\r\n pictureInPicture:\r\n typeof document !== \"undefined\" && document.pictureInPictureElement === media,\r\n error: media.error,\r\n hasSource: Boolean(media.src || media.currentSrc || media.querySelector(\"source[src]\")),\r\n })\r\n }\r\n\r\n /* ------------------------------ Captions ------------------------------ */\r\n\r\n const readCues = () => {\r\n const active = cueTrack?.activeCues\r\n set({ cues: active ? Array.from(active).map(cueText).filter(Boolean) : [] })\r\n }\r\n\r\n const bindCueTrack = (track: TextTrack | null) => {\r\n if (cueTrack === track) return\r\n cueTrack?.removeEventListener(\"cuechange\", readCues)\r\n cueTrack = track\r\n cueTrack?.addEventListener(\"cuechange\", readCues)\r\n }\r\n\r\n // Native rendering is replaced by our own cue layer: the active track runs\r\n // in \"hidden\" mode (cues load, nothing paints) and every other track is off.\r\n const syncTracks = (requested = state.textTrack) => {\r\n const tracks = captionTracks(media)\r\n /**\r\n * Attaching sets every track's mode before the browser applies `default`,\r\n * which cancels it, so the default is applied here instead.\r\n */\r\n let active = requested === -1 && !trackChosen ? defaultTrack(media, tracks) : requested\r\n tracks.forEach((track, i) => {\r\n if (track.mode === \"showing\") active = i\r\n })\r\n if (active >= tracks.length) active = -1\r\n tracks.forEach((track, i) => {\r\n const mode = i === active ? \"hidden\" : \"disabled\"\r\n if (track.mode !== mode) track.mode = mode\r\n })\r\n bindCueTrack(tracks[active] ?? null)\r\n set({\r\n textTracks: tracks.map((track, i) => ({\r\n label: track.label || track.language || `Track ${i + 1}`,\r\n language: track.language,\r\n kind: track.kind as MediaTextTrack[\"kind\"],\r\n })),\r\n textTrack: active,\r\n })\r\n readCues()\r\n }\r\n\r\n const onTracksChange = () => syncTracks()\r\n\r\n /* ---------------------------- Media Session --------------------------- */\r\n\r\n const applyMediaSession = () => {\r\n if (typeof navigator === \"undefined\" || !(\"mediaSession\" in navigator) || !metadata) return\r\n const session = navigator.mediaSession\r\n session.metadata = new MediaMetadata(metadata)\r\n const handlers: [MediaSessionAction, MediaSessionActionHandler][] = [\r\n [\"play\", () => actions.play()],\r\n [\"pause\", () => actions.pause()],\r\n [\"seekbackward\", (d) => actions.seekBy(-(d.seekOffset ?? 10))],\r\n [\"seekforward\", (d) => actions.seekBy(d.seekOffset ?? 10)],\r\n [\"seekto\", (d) => d.seekTime !== undefined && actions.seek(d.seekTime)],\r\n ]\r\n for (const [action, handler] of handlers) {\r\n try {\r\n session.setActionHandler(action, handler)\r\n } catch {\r\n // Action not supported by this browser.\r\n }\r\n }\r\n }\r\n\r\n const updatePositionState = () => {\r\n if (!metadata || !media || typeof navigator === \"undefined\" || !(\"mediaSession\" in navigator)) return\r\n if (!Number.isFinite(media.duration) || media.duration <= 0) return\r\n try {\r\n navigator.mediaSession.setPositionState({\r\n duration: media.duration,\r\n playbackRate: media.playbackRate,\r\n position: Math.min(media.currentTime, media.duration),\r\n })\r\n } catch {\r\n // Ignore transient invalid states.\r\n }\r\n }\r\n\r\n /* ------------------------------- Events ------------------------------- */\r\n\r\n const savePreferences = () => {\r\n if (!persistKey || !media) return\r\n try {\r\n const prefs: Preferences = {\r\n volume: media.volume,\r\n muted: media.muted,\r\n playbackRate: media.playbackRate,\r\n }\r\n localStorage.setItem(persistKey, JSON.stringify(prefs))\r\n } catch {\r\n // Storage may be full or disabled.\r\n }\r\n }\r\n\r\n const onEvent = (event: Event) => {\r\n switch (event.type) {\r\n case \"emptied\":\r\n set({ started: false, waiting: false })\r\n break\r\n case \"waiting\":\r\n set({ waiting: true })\r\n break\r\n case \"playing\":\r\n case \"canplay\":\r\n case \"pause\":\r\n case \"error\":\r\n set({ waiting: false })\r\n break\r\n case \"play\":\r\n applyMediaSession()\r\n break\r\n case \"volumechange\":\r\n case \"ratechange\":\r\n savePreferences()\r\n break\r\n case \"loadedmetadata\":\r\n syncTracks()\r\n break\r\n }\r\n if (event.type === \"durationchange\" || event.type === \"ratechange\" || event.type === \"seeked\") {\r\n updatePositionState()\r\n }\r\n sync()\r\n }\r\n\r\n const onFullscreenChange = () => {\r\n const el = document.fullscreenElement\r\n const video = media as WebkitVideo | null\r\n set({\r\n fullscreen:\r\n (!!el && (el === container || el === media)) || !!video?.webkitDisplayingFullscreen,\r\n })\r\n }\r\n\r\n const attach = (el: HTMLMediaElement | null) => {\r\n if (media === el) return\r\n if (media) {\r\n MEDIA_EVENTS.forEach((e) => media!.removeEventListener(e, onEvent))\r\n TRACK_EVENTS.forEach((e) => media!.textTracks?.removeEventListener?.(e, onTracksChange))\r\n media.removeEventListener(\"webkitbeginfullscreen\", onFullscreenChange)\r\n media.removeEventListener(\"webkitendfullscreen\", onFullscreenChange)\r\n bindCueTrack(null)\r\n }\r\n media = el\r\n if (!el) {\r\n state = initialState\r\n listeners.forEach((l) => l())\r\n return\r\n }\r\n if (persistKey) {\r\n const prefs = readPreferences(persistKey)\r\n if (typeof prefs.volume === \"number\") el.volume = Math.min(Math.max(prefs.volume, 0), 1)\r\n if (typeof prefs.muted === \"boolean\") el.muted = prefs.muted\r\n if (typeof prefs.playbackRate === \"number\") el.playbackRate = prefs.playbackRate\r\n }\r\n MEDIA_EVENTS.forEach((e) => el.addEventListener(e, onEvent))\r\n TRACK_EVENTS.forEach((e) => el.textTracks?.addEventListener?.(e, onTracksChange))\r\n el.addEventListener(\"webkitbeginfullscreen\", onFullscreenChange)\r\n el.addEventListener(\"webkitendfullscreen\", onFullscreenChange)\r\n sync()\r\n syncTracks()\r\n }\r\n\r\n const setContainer = (el: HTMLElement | null) => {\r\n if (typeof document === \"undefined\") return\r\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange)\r\n container = el\r\n if (el) document.addEventListener(\"fullscreenchange\", onFullscreenChange)\r\n }\r\n\r\n const play = async () => {\r\n if (!media) return\r\n try {\r\n await media.play()\r\n } catch {\r\n // Autoplay policies may reject; the paused state stays accurate.\r\n }\r\n }\r\n\r\n const pause = () => media?.pause()\r\n\r\n const actions = {\r\n play,\r\n pause,\r\n toggle: () => (media?.paused || media?.ended ? play() : pause()),\r\n seek: (time: number) => {\r\n if (!media) return\r\n const max = Number.isFinite(media.duration) ? media.duration : time\r\n media.currentTime = Math.min(Math.max(time, 0), max)\r\n sync()\r\n },\r\n seekBy: (delta: number) => actions.seek((media?.currentTime ?? 0) + delta),\r\n /** Jump to a fraction (0–1) of the duration. */\r\n seekToRatio: (ratio: number) => actions.seek(ratio * (media?.duration || 0)),\r\n setVolume: (volume: number) => {\r\n if (!media) return\r\n media.volume = Math.min(Math.max(volume, 0), 1)\r\n media.muted = media.volume === 0\r\n },\r\n toggleMute: () => {\r\n if (!media) return\r\n if (media.muted && media.volume === 0) media.volume = 1\r\n media.muted = !media.muted\r\n },\r\n setPlaybackRate: (rate: number) => {\r\n if (media) media.playbackRate = rate\r\n },\r\n /** Select a caption track by index, or -1 to turn captions off. */\r\n setTextTrack: (index: number) => syncTracksExplicit(index),\r\n toggleCaptions: () => {\r\n if (!state.textTracks.length) return\r\n syncTracksExplicit(state.textTrack === -1 ? 0 : -1)\r\n },\r\n /** Reload the current source after an error. */\r\n retry: () => {\r\n if (!media) return\r\n media.load()\r\n void play()\r\n },\r\n setMetadata: (next: MediaInfo | null) => {\r\n metadata = next\r\n if (media && !media.paused) applyMediaSession()\r\n },\r\n toggleFullscreen: async () => {\r\n if (typeof document === \"undefined\") return\r\n if (document.fullscreenElement) {\r\n await document.exitFullscreen().catch(() => {})\r\n return\r\n }\r\n if (container?.requestFullscreen) {\r\n await container.requestFullscreen().catch(() => {})\r\n return\r\n }\r\n // iOS Safari only supports fullscreen on the video element itself.\r\n ;(media as WebkitVideo | null)?.webkitEnterFullscreen?.()\r\n },\r\n togglePictureInPicture: async () => {\r\n if (!(media instanceof HTMLVideoElement)) return\r\n try {\r\n if (document.pictureInPictureElement) await document.exitPictureInPicture()\r\n else await media.requestPictureInPicture()\r\n } catch {\r\n // Unsupported or blocked by the browser.\r\n }\r\n },\r\n }\r\n\r\n // An explicit choice must win over a track the browser marked \"showing\".\r\n const syncTracksExplicit = (index: number) => {\r\n trackChosen = true\r\n captionTracks(media).forEach((track, i) => {\r\n if (i !== index && track.mode === \"showing\") track.mode = \"disabled\"\r\n })\r\n syncTracks(index)\r\n }\r\n\r\n return {\r\n getState: () => state,\r\n getServerState: () => initialState,\r\n getMedia: () => media,\r\n subscribe: (listener: Listener) => {\r\n listeners.add(listener)\r\n return () => listeners.delete(listener)\r\n },\r\n attach,\r\n setContainer,\r\n ...actions,\r\n }\r\n}\r\n\r\nexport type MediaStore = ReturnType<typeof createMediaStore>\r\n\r\n/**\r\n * `m:ss`, or `h:mm:ss` from one hour. Pass the duration as `reference` so\r\n * every time in a player uses the same fields: `0:00:05` beside `10:00:01`,\r\n * and the label does not widen when playback passes an hour.\r\n */\r\nexport function formatTime(seconds: number, reference = seconds) {\r\n if (!Number.isFinite(seconds) || seconds < 0) seconds = 0\r\n const s = Math.floor(seconds % 60)\r\n const m = Math.floor((seconds / 60) % 60)\r\n const h = Math.floor(seconds / 3600)\r\n const ss = s.toString().padStart(2, \"0\")\r\n const hours = h > 0 || (Number.isFinite(reference) && reference >= 3600)\r\n return hours ? `${h}:${m.toString().padStart(2, \"0\")}:${ss}` : `${m}:${ss}`\r\n}\r\n\r\n/** Human-readable message for a MediaError code. */\r\nexport function describeMediaError(error: MediaError | null) {\r\n switch (error?.code) {\r\n case 1:\r\n return \"Playback was aborted.\"\r\n case 2:\r\n return \"A network error stopped the download.\"\r\n case 3:\r\n return \"This media could not be decoded.\"\r\n case 4:\r\n return \"This media couldn't be loaded.\"\r\n default:\r\n return \"Something went wrong during playback.\"\r\n }\r\n}\r\n"]}
|
package/dist/hls.d.ts
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
type MediaSourceLoader = (media: HTMLMediaElement, src: string) => void | (() => void);
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Plays `.m3u8` streams.
|
|
9
|
-
*
|
|
8
|
+
* Plays `.m3u8` streams with hls.js, loaded on demand so it never lands in
|
|
9
|
+
* the main bundle. Native playback is only the fallback for browsers without
|
|
10
|
+
* Media Source Extensions: Chrome 142 and later report native HLS support,
|
|
11
|
+
* but cannot parse common MPEG-TS streams, so `canPlayType` is not a safe
|
|
12
|
+
* test.
|
|
10
13
|
*/
|
|
11
14
|
declare const hlsLoader: MediaSourceLoader;
|
|
12
15
|
|
package/dist/hls.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
// ../../lib/media-hls.ts
|
|
2
|
-
var
|
|
2
|
+
var hasMediaSource = () => typeof window !== "undefined" && ("MediaSource" in window || "ManagedMediaSource" in window);
|
|
3
3
|
var hlsLoader = (media, src) => {
|
|
4
|
-
|
|
4
|
+
const playNatively = () => {
|
|
5
5
|
media.src = src;
|
|
6
6
|
return () => {
|
|
7
7
|
media.removeAttribute("src");
|
|
8
8
|
media.load();
|
|
9
9
|
};
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
|
+
if (!/\.m3u8($|\?)/i.test(src) || !hasMediaSource()) return playNatively();
|
|
11
12
|
let disposed = false;
|
|
12
13
|
let destroy;
|
|
13
14
|
import('hls.js').then(({ default: Hls }) => {
|
|
14
15
|
if (disposed) return;
|
|
15
16
|
if (!Hls.isSupported()) {
|
|
16
|
-
|
|
17
|
+
destroy = playNatively();
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
const hls = new Hls({ enableWorker: true });
|
package/dist/hls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../lib/media-hls.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../lib/media-hls.ts"],"names":[],"mappings":";AAMA,IAAM,iBAAiB,MACrB,OAAO,WAAW,WAAA,KAAgB,aAAA,IAAiB,UAAU,oBAAA,IAAwB,MAAA,CAAA;AAShF,IAAM,SAAA,GAA+B,CAAC,KAAA,EAAO,GAAA,KAAQ;AAC1D,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,KAAA,CAAM,GAAA,GAAM,GAAA;AACZ,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,CAAM,gBAAgB,KAAK,CAAA;AAC3B,MAAA,KAAA,CAAM,IAAA,EAAK;AAAA,IACb,CAAA;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,CAAC,gBAAgB,IAAA,CAAK,GAAG,KAAK,CAAC,cAAA,EAAe,EAAG,OAAO,YAAA,EAAa;AAEzE,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,OAAA;AAEJ,EAAA,OAAO,QAAQ,CAAA,CAAE,IAAA,CAAK,CAAC,EAAE,OAAA,EAAS,KAAI,KAAM;AAC1C,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,IAAI,CAAC,GAAA,CAAI,WAAA,EAAY,EAAG;AACtB,MAAA,OAAA,GAAU,YAAA,EAAa;AACvB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,MAAM,IAAI,GAAA,CAAI,EAAE,YAAA,EAAc,MAAM,CAAA;AAC1C,IAAA,GAAA,CAAI,GAAG,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,CAAC,GAAG,IAAA,KAAS;AACpC,MAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACjB,MAAA,IAAI,KAAK,IAAA,KAAS,GAAA,CAAI,UAAA,CAAW,aAAA,MAAmB,SAAA,EAAU;AAAA,WAAA,IACrD,KAAK,IAAA,KAAS,GAAA,CAAI,UAAA,CAAW,WAAA,MAAiB,iBAAA,EAAkB;AAAA,eAChE,OAAA,EAAQ;AAAA,IACnB,CAAC,CAAA;AACD,IAAA,GAAA,CAAI,WAAW,GAAG,CAAA;AAClB,IAAA,GAAA,CAAI,YAAY,KAAK,CAAA;AACrB,IAAA,OAAA,GAAU,MAAM,IAAI,OAAA,EAAQ;AAAA,EAC9B,CAAC,CAAA;AAED,EAAA,OAAO,MAAM;AACX,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,OAAA,IAAU;AAAA,EACZ,CAAA;AACF","file":"hls.js","sourcesContent":["import type { MediaSourceLoader } from \"@/components/ui/media\"\r\n\r\n/**\r\n * Media Source Extensions, which hls.js needs. iPhones before iOS 17.1 have\r\n * neither API, and they are the browsers that must play HLS natively.\r\n */\r\nconst hasMediaSource = () =>\r\n typeof window !== \"undefined\" && (\"MediaSource\" in window || \"ManagedMediaSource\" in window)\r\n\r\n/**\r\n * Plays `.m3u8` streams with hls.js, loaded on demand so it never lands in\r\n * the main bundle. Native playback is only the fallback for browsers without\r\n * Media Source Extensions: Chrome 142 and later report native HLS support,\r\n * but cannot parse common MPEG-TS streams, so `canPlayType` is not a safe\r\n * test.\r\n */\r\nexport const hlsLoader: MediaSourceLoader = (media, src) => {\r\n const playNatively = () => {\r\n media.src = src\r\n return () => {\r\n media.removeAttribute(\"src\")\r\n media.load()\r\n }\r\n }\r\n\r\n if (!/\\.m3u8($|\\?)/i.test(src) || !hasMediaSource()) return playNatively()\r\n\r\n let disposed = false\r\n let destroy: (() => void) | undefined\r\n\r\n import(\"hls.js\").then(({ default: Hls }) => {\r\n if (disposed) return\r\n if (!Hls.isSupported()) {\r\n destroy = playNatively()\r\n return\r\n }\r\n const hls = new Hls({ enableWorker: true })\r\n hls.on(Hls.Events.ERROR, (_, data) => {\r\n if (!data.fatal) return\r\n if (data.type === Hls.ErrorTypes.NETWORK_ERROR) hls.startLoad()\r\n else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) hls.recoverMediaError()\r\n else hls.destroy()\r\n })\r\n hls.loadSource(src)\r\n hls.attachMedia(media)\r\n destroy = () => hls.destroy()\r\n })\r\n\r\n return () => {\r\n disposed = true\r\n destroy?.()\r\n }\r\n}\r\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ type MediaState = {
|
|
|
30
30
|
fullscreen: boolean;
|
|
31
31
|
pictureInPicture: boolean;
|
|
32
32
|
error: MediaError | null;
|
|
33
|
+
/** False while the element has no source to play. */
|
|
34
|
+
hasSource: boolean;
|
|
33
35
|
/** Caption and subtitle tracks, in document order. */
|
|
34
36
|
textTracks: MediaTextTrack[];
|
|
35
37
|
/** Index into `textTracks`, or -1 when captions are off. */
|
|
@@ -73,9 +75,14 @@ declare function createMediaStore({ persistKey }?: MediaStoreOptions): {
|
|
|
73
75
|
setContainer: (el: HTMLElement | null) => void;
|
|
74
76
|
};
|
|
75
77
|
type MediaStore = ReturnType<typeof createMediaStore>;
|
|
76
|
-
|
|
78
|
+
/**
|
|
79
|
+
* `m:ss`, or `h:mm:ss` from one hour. Pass the duration as `reference` so
|
|
80
|
+
* every time in a player uses the same fields: `0:00:05` beside `10:00:01`,
|
|
81
|
+
* and the label does not widen when playback passes an hour.
|
|
82
|
+
*/
|
|
83
|
+
declare function formatTime(seconds: number, reference?: number): string;
|
|
77
84
|
/** Human-readable message for a MediaError code. */
|
|
78
|
-
declare function describeMediaError(error: MediaError | null): "Playback was aborted." | "A network error stopped the download." | "This media could not be decoded." | "This
|
|
85
|
+
declare function describeMediaError(error: MediaError | null): "Playback was aborted." | "A network error stopped the download." | "This media could not be decoded." | "This media couldn't be loaded." | "Something went wrong during playback.";
|
|
79
86
|
|
|
80
87
|
declare function useMediaStore(): {
|
|
81
88
|
play: () => Promise<void>;
|