@banou/media-player 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { i as e, n as t, o as n, s as r, t as i } from "./engine-Dmc7JSd9.js";
2
- import { Children as a, Fragment as o, isValidElement as s, useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
3
- import { css as p, keyframes as m } from "@emotion/react";
4
- import { createPlayer as h, useContainerAttach as g, useMediaAttach as _ } from "@videojs/react";
5
- import { definePlayerFeature as v, videoFeatures as y } from "@videojs/core/dom";
6
- import { Fragment as b, jsx as x, jsxs as S } from "@emotion/react/jsx-runtime";
7
- import { ChevronLeft as C, ChevronRight as w, Maximize as T, Minimize as E, Pause as D, Play as O, RotateCcw as k, Settings as A, Volume1 as j, Volume2 as M, VolumeX as ee } from "react-feather";
8
- import { Tooltip as te } from "react-tooltip";
1
+ import { a as e, c as t, n, r, s as i, t as a } from "./engine--OlGG-Ve.js";
2
+ import { Children as o, Fragment as s, isValidElement as c, useCallback as l, useEffect as u, useMemo as d, useRef as f, useState as p } from "react";
3
+ import { css as m, keyframes as h } from "@emotion/react";
4
+ import { createPlayer as g, useContainerAttach as _, useMediaAttach as v } from "@videojs/react";
5
+ import { definePlayerFeature as y, videoFeatures as b } from "@videojs/core/dom";
6
+ import { Fragment as x, jsx as S, jsxs as C } from "@emotion/react/jsx-runtime";
7
+ import { ChevronLeft as w, ChevronRight as T, Maximize as E, Minimize as D, Pause as O, Play as k, RotateCcw as A, Settings as j, Volume1 as M, Volume2 as ee, VolumeX as te } from "react-feather";
8
+ import { Tooltip as ne } from "react-tooltip";
9
9
  //#region src/lib/react/source-feature.ts
10
- var ne = {
10
+ var re = {
11
11
  indexes: [],
12
12
  thumbnails: [],
13
13
  subtitleTracks: [],
@@ -19,22 +19,24 @@ var ne = {
19
19
  hideUI: !1,
20
20
  setHideUI: () => {},
21
21
  togglePictureInPicture: null,
22
+ pictureInPictureMode: null,
23
+ burnedInSubtitles: !1,
22
24
  playbackError: null,
23
25
  ready: !1,
24
26
  setSourceState: () => {}
25
- }, N = v({
27
+ }, N = y({
26
28
  name: "source",
27
- state: () => ({ ...ne }),
29
+ state: () => ({ ...re }),
28
30
  attach({ set: e }) {
29
31
  e({
30
32
  setSourceState: (t) => e(t),
31
33
  setHideUI: (t) => e({ hideUI: t })
32
34
  });
33
35
  }
34
- }), P = h({
35
- features: [...y, N],
36
+ }), P = g({
37
+ features: [...b, N],
36
38
  displayName: "MediaPlayer"
37
- }), F = P.usePlayer, re = (e) => {
39
+ }), F = P.usePlayer, ie = (e) => {
38
40
  if (!(!e || e === "und")) try {
39
41
  return new Intl.DisplayNames([navigator.language || "en"], {
40
42
  type: "language",
@@ -43,8 +45,8 @@ var ne = {
43
45
  } catch {
44
46
  return;
45
47
  }
46
- }, I = (e) => e?.replace(/_/g, " ").trim() || void 0, L = (e) => {
47
- let t = e.map((e) => re(e.language) ?? I(e.title) ?? `Track ${e.streamIndex}`), n = t.reduce((e, t) => ({
48
+ }, I = (e) => e?.replace(/_/g, " ").trim() || void 0, ae = (e) => {
49
+ let t = e.map((e) => ie(e.language) ?? I(e.title) ?? `Track ${e.streamIndex}`), n = t.reduce((e, t) => ({
48
50
  ...e,
49
51
  [t]: (e[t] ?? 0) + 1
50
52
  }), {});
@@ -55,23 +57,23 @@ var ne = {
55
57
  label: (n[i] ?? 0) > 1 && a && a !== i ? `${i} (${a})` : i
56
58
  };
57
59
  });
58
- }, R = (e) => L(e).map(({ track: e, label: t }) => ({
60
+ }, L = (e) => ae(e).map(({ track: e, label: t }) => ({
59
61
  id: e.streamIndex,
60
62
  label: t
61
- })), ie = (t, n, r) => {
62
- let i = F(), { read: a, size: o, publicPath: s = "", libavWorkerUrl: u = "", jassubWorkerUrl: p = "", jassubWasmUrl: m = "", jassubLegacyWasmUrl: h, defaultFontUrl: g, bufferSize: _, autoplay: v = !1 } = r ?? {}, [y, b] = f(void 0), x = d(null), S = d(0), C = d(!1), w = d(a);
63
+ })), oe = (t, n, r) => {
64
+ let i = F(), { read: a, size: o, publicPath: s = "", libavWorkerUrl: c = "", jassubWorkerUrl: d = "", jassubWasmUrl: m = "", jassubLegacyWasmUrl: h, defaultFontUrl: g, bufferSize: _, autoplay: v = !1 } = r ?? {}, [y, b] = p(void 0), x = f(null), S = f(0), C = f(!1), w = f(a);
63
65
  w.current = a;
64
- let T = d(r?.onSeek);
66
+ let T = f(r?.onSeek);
65
67
  T.current = r?.onSeek;
66
- let E = d(r?.onPlaybackError);
68
+ let E = f(r?.onPlaybackError);
67
69
  E.current = r?.onPlaybackError;
68
- let D = c((e) => {
70
+ let D = l((e) => {
69
71
  let t = typeof e == "number" ? e : void 0;
70
72
  C.current = !0, i.setSourceState({ selectedSubtitleTrack: t }), x.current?.selectSubtitleStream(t);
71
- }, [i]), O = c((e) => {
73
+ }, [i]), O = l((e) => {
72
74
  typeof e == "number" && (i.setSourceState({ selectedAudioTrack: e }), b(e));
73
75
  }, [i]), k = F((e) => e.setSourceState);
74
- l(() => {
76
+ u(() => {
75
77
  k({
76
78
  selectSubtitleTrack: D,
77
79
  selectAudioTrack: O
@@ -80,14 +82,14 @@ var ne = {
80
82
  k,
81
83
  D,
82
84
  O
83
- ]), l(() => {
85
+ ]), u(() => {
84
86
  if (!t || !n || !o || !a) return;
85
87
  let r = !1;
86
88
  i.setSourceState({
87
89
  playbackError: null,
88
90
  ready: !1
89
91
  });
90
- let c = (e) => {
92
+ let l = (e) => {
91
93
  r || (console.error("playback failed", e), i.setSourceState({ playbackError: e }), E.current?.(e));
92
94
  };
93
95
  return (async () => {
@@ -98,8 +100,8 @@ var ne = {
98
100
  read: (e, t) => w.current(e, t),
99
101
  length: o,
100
102
  publicPath: s,
101
- libavWorkerUrl: u,
102
- jassubWorkerUrl: p,
103
+ libavWorkerUrl: c,
104
+ jassubWorkerUrl: d,
103
105
  jassubWasmUrl: m,
104
106
  jassubLegacyWasmUrl: h,
105
107
  defaultFontUrl: g,
@@ -108,20 +110,20 @@ var ne = {
108
110
  onReady: () => {
109
111
  r || (i.setSourceState({ ready: !0 }), S.current > 0 && (t.currentTime = S.current, S.current = 0), v && t.play().catch(() => {}));
110
112
  },
111
- onError: c,
113
+ onError: l,
112
114
  onRecovered: () => {
113
115
  r || i.setSourceState({ playbackError: null });
114
116
  },
115
117
  onSeek: (e) => T.current?.(e),
116
118
  onSubtitleStreams: (e) => {
117
119
  r || i.setSourceState({
118
- subtitleTracks: R(e),
120
+ subtitleTracks: L(e),
119
121
  ...C.current ? {} : { selectedSubtitleTrack: e[0]?.streamIndex }
120
122
  });
121
123
  },
122
124
  onAudioStreams: (e, t) => {
123
125
  r || i.setSourceState({
124
- audioTracks: R(e),
126
+ audioTracks: L(e),
125
127
  selectedAudioTrack: t
126
128
  });
127
129
  }
@@ -131,10 +133,10 @@ var ne = {
131
133
  return;
132
134
  }
133
135
  x.current = a, i.setSourceState({ indexes: a.indexes });
134
- let l = i.selectedSubtitleTrack;
135
- typeof l == "number" && a.selectSubtitleStream(l);
136
+ let u = i.selectedSubtitleTrack;
137
+ typeof u == "number" && a.selectSubtitleStream(u);
136
138
  } catch (e) {
137
- c(e);
139
+ l(e);
138
140
  }
139
141
  })(), () => {
140
142
  r = !0, S.current = t.currentTime, x.current?.destroy(), x.current = null, i.setSourceState({ ready: !1 });
@@ -145,8 +147,8 @@ var ne = {
145
147
  n,
146
148
  o,
147
149
  s,
148
- u,
149
- p,
150
+ c,
151
+ d,
150
152
  m,
151
153
  h,
152
154
  g,
@@ -154,18 +156,18 @@ var ne = {
154
156
  y,
155
157
  v
156
158
  ]);
157
- }, ae = 5e3, oe = 6e4, z = ({ publicPath: e, workerUrl: n, length: r, read: i, downloadedRanges: a }) => {
158
- let [o, s] = f([]), c = d(null), p = d(i);
159
- p.current = i;
160
- let m = u(() => a?.map(({ startByteOffset: e, endByteOffset: t }) => [e, t]), [a?.map(({ startByteOffset: e, endByteOffset: t }) => `${e}-${t}`).join(",")]), h = d(m);
161
- return h.current = m, l(() => {
162
- if (!r || !i || !e || !n) return;
163
- let a = !1, o = null, l, u = ae, d = () => {
164
- t({
159
+ }, se = 5e3, ce = 6e4, R = ({ publicPath: e, workerUrl: t, length: n, read: i, downloadedRanges: a }) => {
160
+ let [o, s] = p([]), c = f(null), l = f(i);
161
+ l.current = i;
162
+ let m = d(() => a?.map(({ startByteOffset: e, endByteOffset: t }) => [e, t]), [a?.map(({ startByteOffset: e, endByteOffset: t }) => `${e}-${t}`).join(",")]), h = f(m);
163
+ return h.current = m, u(() => {
164
+ if (!n || !i || !e || !t) return;
165
+ let a = !1, o = null, u, d = se, f = () => {
166
+ r({
165
167
  publicPath: e,
166
- workerUrl: n,
167
- length: r,
168
- read: (e, t) => p.current(e, t),
168
+ workerUrl: t,
169
+ length: n,
170
+ read: (e, t) => l.current(e, t),
169
171
  onThumbnails: (e) => {
170
172
  a || s(e);
171
173
  }
@@ -176,43 +178,48 @@ var ne = {
176
178
  }
177
179
  o = e, c.current = e, e.update(h.current);
178
180
  }, () => {
179
- a || (l = setTimeout(d, u), u = Math.min(u * 2, oe));
181
+ a || (u = setTimeout(f, d), d = Math.min(d * 2, ce));
180
182
  });
181
183
  };
182
- return d(), () => {
183
- a = !0, clearTimeout(l), c.current = null, o?.destroy(), s([]);
184
+ return f(), () => {
185
+ a = !0, clearTimeout(u), c.current = null, o?.destroy(), s([]);
184
186
  };
185
187
  }, [
186
- r,
188
+ n,
187
189
  e,
188
- n
189
- ]), l(() => {
190
+ t
191
+ ]), u(() => {
190
192
  c.current?.update(m);
191
193
  }, [m]), o;
192
- }, B = (e, t) => {
193
- let n = F(), r = d(null);
194
- l(() => {
195
- if (!e || !t) return;
196
- let a = i({
194
+ }, z = (e, t) => {
195
+ let r = f(null), [i, o] = p(!1), [s] = p(() => n());
196
+ u(() => {
197
+ if (!e || !t || !s) return;
198
+ let n = a({
197
199
  video: e,
198
200
  canvas: t,
199
- fallback: () => n.togglePictureInPicture()
201
+ mode: s,
202
+ onBurnedInChange: o
200
203
  });
201
- return r.current = a, () => {
202
- a.destroy(), r.current = null;
204
+ return r.current = n, () => {
205
+ n.destroy(), r.current = null, o(!1);
203
206
  };
204
207
  }, [
205
208
  e,
206
209
  t,
207
- n
210
+ s
208
211
  ]);
209
- let a = c(() => {
212
+ let c = l(() => {
210
213
  r.current?.toggle().catch((e) => {
211
214
  console.warn("picture in picture was refused", e);
212
215
  });
213
216
  }, []);
214
- return e && t ? a : null;
215
- }, V = {
217
+ return {
218
+ toggle: e && t && s ? c : null,
219
+ mode: s,
220
+ burnedIn: i
221
+ };
222
+ }, B = {
216
223
  headings: {
217
224
  large: "\n font-weight: 600;\n font-size: calc(2.8 * var(--mp-unit));\n line-height: calc(3.4 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(3.4 * var(--mp-unit));\n line-height: calc(4.1 * var(--mp-unit));\n }\n ",
218
225
  medium: "\n font-weight: 600;\n font-size: calc(2.4 * var(--mp-unit));\n line-height: calc(2.9 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(2.8 * var(--mp-unit));\n line-height: calc(3.4 * var(--mp-unit));\n }\n ",
@@ -239,14 +246,14 @@ var ne = {
239
246
  medium: "\n font-weight: 500;\n font-size: calc(0.8 * var(--mp-unit));\n line-height: calc(1.1 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(1 * var(--mp-unit));\n line-height: calc(1.4 * var(--mp-unit));\n }\n ",
240
247
  regular: "\n font-weight: 400;\n font-size: calc(0.8 * var(--mp-unit));\n line-height: calc(1.1 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(1 * var(--mp-unit));\n line-height: calc(1.4 * var(--mp-unit));\n }\n "
241
248
  }
242
- }, se = p`
249
+ }, le = m`
243
250
  top: unset !important;
244
251
  left: unset !important;
245
252
  width: 100%;
246
253
  height: 100%;
247
254
  margin: auto;
248
255
  pointer-events: none;
249
- `, ce = p`
256
+ `, ue = m`
250
257
  position: absolute;
251
258
  top: 0;
252
259
  left: 0;
@@ -254,7 +261,7 @@ var ne = {
254
261
  padding: calc(1.2 * var(--mp-unit)) calc(1.6 * var(--mp-unit));
255
262
  /* clears a notch once the player is fullscreen; resolves to zero everywhere else */
256
263
  padding-top: calc(calc(1.2 * var(--mp-unit)) + env(safe-area-inset-top, 0px));
257
- ${V.headings.small}
264
+ ${B.headings.small}
258
265
  color: white;
259
266
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
260
267
  z-index: 2;
@@ -275,7 +282,7 @@ var ne = {
275
282
 
276
283
  background: linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.3) 30%, rgba(0,0,0,0.2) 60%, rgba(0,0,0,0.1) 80%, transparent 100%);
277
284
  transition: opacity 0.1s cubic-bezier(.4,0,1,1);
278
- `, le = p`
285
+ `, de = m`
279
286
  position: absolute;
280
287
  inset: 0;
281
288
  z-index: 2;
@@ -291,47 +298,47 @@ var ne = {
291
298
  border-radius: 50%;
292
299
  border: 3px solid rgba(255, 255, 255, 0.25);
293
300
  border-top-color: #fff;
294
- animation: ${m`
301
+ animation: ${h`
295
302
  to { transform: rotate(360deg); }
296
303
  `} 0.8s linear infinite;
297
304
  }
298
- `, ue = p`
305
+ `, fe = m`
299
306
  position: absolute;
300
307
  inset: auto 0 20%;
301
308
  z-index: 3;
302
309
  padding: 0 calc(2 * var(--mp-unit));
303
310
  text-align: center;
304
311
  color: #fff;
305
- ${V.bLarge.regular}
312
+ ${B.bLarge.regular}
306
313
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
307
314
  pointer-events: none;
308
- `, de = (e) => e instanceof Error ? e.message : typeof e == "string" ? e : "Playback failed", fe = ({ onCanvasRef: e }) => {
315
+ `, pe = (e) => e instanceof Error ? e.message : typeof e == "string" ? e : "Playback failed", me = ({ onCanvasRef: e }) => {
309
316
  let t = F((e) => e.title), n = F((e) => e.hideUI), r = F((e) => e.playbackError), i = F((e) => e.ready), a = F((e) => e.size), o = F((e) => e.waiting);
310
- return /* @__PURE__ */ S(b, { children: [
311
- t ? /* @__PURE__ */ x("div", {
317
+ return /* @__PURE__ */ C(x, { children: [
318
+ t ? /* @__PURE__ */ S("div", {
312
319
  className: "title",
313
- css: ce,
320
+ css: ue,
314
321
  style: { ...n ? {
315
322
  opacity: "0",
316
323
  pointerEvents: "none"
317
324
  } : {} },
318
325
  children: t
319
326
  }) : void 0,
320
- (a ? !i : o) && !r ? /* @__PURE__ */ x("div", { css: le }) : void 0,
321
- r ? /* @__PURE__ */ x("div", {
322
- css: ue,
323
- children: de(r)
327
+ (a ? !i : o) && !r ? /* @__PURE__ */ S("div", { css: de }) : void 0,
328
+ r ? /* @__PURE__ */ S("div", {
329
+ css: fe,
330
+ children: pe(r)
324
331
  }) : void 0,
325
- /* @__PURE__ */ x("canvas", {
332
+ /* @__PURE__ */ S("canvas", {
326
333
  ref: e,
327
- css: se
334
+ css: le
328
335
  })
329
336
  ] });
330
- }, H = 1e-4, U = 1, W = (e) => Math.max(H, Math.min(U, e)) ** 2, G = (e) => Math.max(H, Math.min(U, e)) ** (U / 2), K = (e) => {
337
+ }, V = 1e-4, H = 1, U = (e) => Math.max(V, Math.min(H, e)) ** 2, W = (e) => Math.max(V, Math.min(H, e)) ** (H / 2), G = (e) => {
331
338
  if (e === void 0) return "0:00";
332
339
  let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60);
333
340
  return t > 0 ? `${t}:${n < 10 ? "0" : ""}${n}:${r < 10 ? "0" : ""}${r}` : `${n}:${r < 10 ? "0" : ""}${r}`;
334
- }, pe = (e, t) => `${K(e)} / ${K(t)}`, me = (e) => p`
341
+ }, he = (e, t) => `${G(e)} / ${G(t)}`, ge = (e) => m`
335
342
  display: flex;
336
343
  justify-content: flex-end;
337
344
 
@@ -341,19 +348,19 @@ var ne = {
341
348
  z-index: 3;
342
349
 
343
350
  * {
344
- ${V.bMedium.regular}
351
+ ${B.bMedium.regular}
345
352
  }
346
353
 
347
- ${e === "sm" && p`
354
+ ${e === "sm" && m`
348
355
  padding: calc(0.4 * var(--mp-unit))!important;
349
356
  `}
350
- ${e === "md" && p`
357
+ ${e === "md" && m`
351
358
  padding: calc(0.6 * var(--mp-unit))!important;
352
359
  `}
353
- ${e === "lg" && p`
360
+ ${e === "lg" && m`
354
361
  padding: calc(1.2 * var(--mp-unit))!important;
355
362
  `}
356
- `, q = ({ id: e, toolTipText: t, text: n, delayShow: r = 0, closeDelay: i = 0, offset: a = 20, tooltipPlace: o = "top", disabled: s = !1, size: c = "md" }) => /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("div", {
363
+ `, K = ({ id: e, toolTipText: t, text: n, delayShow: r = 0, closeDelay: i = 0, offset: a = 20, tooltipPlace: o = "top", disabled: s = !1, size: c = "md" }) => /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S("div", {
357
364
  "data-tooltip-id": e,
358
365
  "data-open": !0,
359
366
  "data-tooltip-offset": a,
@@ -361,39 +368,39 @@ var ne = {
361
368
  "data-tooltip-delay-hide": i,
362
369
  "data-tooltip-place": o,
363
370
  children: n
364
- }), !s && /* @__PURE__ */ x(te, {
365
- css: me(c),
371
+ }), !s && /* @__PURE__ */ S(ne, {
372
+ css: ge(c),
366
373
  id: e,
367
374
  noArrow: !0,
368
375
  children: t
369
- })] }), J = ({ ref: e, onChange: t, orientation: n = "horizontal", disabled: r = !1 }) => {
370
- let [i, a] = f(!1), o = d(t);
376
+ })] }), q = ({ ref: e, onChange: t, orientation: n = "horizontal", disabled: r = !1 }) => {
377
+ let [i, a] = p(!1), o = f(t);
371
378
  o.current = t;
372
- let s = d(null), u = c((t, r) => {
379
+ let s = f(null), c = l((t, r) => {
373
380
  let i = e.current;
374
381
  if (!i) return 0;
375
382
  let { left: a, right: o, top: s, bottom: c } = i.getBoundingClientRect(), l = n === "horizontal" ? (t - a) / (o - a) : (c - r) / (c - s);
376
383
  return Math.min(Math.max(l, 0), 1);
377
- }, [e, n]), p = c((e) => {
378
- r || e.button > 0 || (s.current = e.pointerId, e.currentTarget.setPointerCapture?.(e.pointerId), a(!0), o.current(u(e.clientX, e.clientY)));
379
- }, [r, u]), m = c((e) => {
380
- s.current === e.pointerId && o.current(u(e.clientX, e.clientY));
381
- }, [u]), h = c((e) => {
384
+ }, [e, n]), d = l((e) => {
385
+ r || e.button > 0 || (s.current = e.pointerId, e.currentTarget.setPointerCapture?.(e.pointerId), a(!0), o.current(c(e.clientX, e.clientY)));
386
+ }, [r, c]), m = l((e) => {
387
+ s.current === e.pointerId && o.current(c(e.clientX, e.clientY));
388
+ }, [c]), h = l((e) => {
382
389
  s.current === e.pointerId && (s.current = null, e.currentTarget.releasePointerCapture?.(e.pointerId), a(!1));
383
390
  }, []);
384
- return l(() => {
391
+ return u(() => {
385
392
  r && (s.current = null, a(!1));
386
393
  }, [r]), {
387
394
  dragging: i,
388
395
  handlers: {
389
- onPointerDown: p,
396
+ onPointerDown: d,
390
397
  onPointerMove: m,
391
398
  onPointerUp: h,
392
399
  onPointerCancel: h,
393
400
  style: { touchAction: "none" }
394
401
  }
395
402
  };
396
- }, he = p`
403
+ }, _e = m`
397
404
  position: relative;
398
405
  height: calc(.4 * var(--mp-unit));
399
406
 
@@ -437,14 +444,28 @@ var ne = {
437
444
  display: flex;
438
445
  justify-content: center;
439
446
 
447
+ /* The seekbar's other hover affordance, the thumbnail below, gets a rounded box and a drop
448
+ shadow. A source that ships no thumbnails, which is every source whose media the player does
449
+ not own, leaves this readout as the entire preview, so it carries the same treatment instead
450
+ of sitting as bare text on the picture. The ink comes from the player root. */
451
+ background-color: rgba(28, 28, 28, .95);
452
+ border-radius: calc(.4 * var(--mp-unit));
453
+ padding: 0 calc(.6 * var(--mp-unit));
454
+ box-shadow: 0 0 calc(1 * var(--mp-unit)) rgba(0, 0, 0, .5);
455
+
440
456
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
441
- ${V.bMedium.bold}
457
+ ${B.bMedium.bold}
442
458
 
443
459
  position: absolute;
444
- top: calc(-2.5 * var(--mp-unit));
445
- width: calc(5 * var(--mp-unit));
460
+ /* Anchored on its bottom edge rather than its top: now that it has a background its height
461
+ follows the font size, and a top-anchored box would grow downward into the track. */
462
+ bottom: calc(1.2 * var(--mp-unit));
463
+ /* Sized to its content, replacing a fixed 5 unit box that \`1:04:09\` overflows. Transparent, that
464
+ overflow was invisible; filled, it would not be. */
465
+ width: max-content;
466
+ white-space: nowrap;
467
+ transform: translateX(-50%);
446
468
 
447
- margin-left: calc(-2.5 * var(--mp-unit));
448
469
  pointer-events: none;
449
470
  }
450
471
 
@@ -550,15 +571,15 @@ var ne = {
550
571
  --thumbnail-width: calc(18 * var(--mp-unit));
551
572
  --thumbnail-half: calc(9 * var(--mp-unit));
552
573
  }
553
- `, ge = () => {
554
- let e = F(), t = F((e) => e.currentTime), n = F((e) => e.duration), r = F((e) => e.size), i = F((e) => e.downloadedRanges), a = F((e) => e.indexes), o = F((e) => e.thumbnails), s = F((e) => e.thumbnailAt), c = d(null), [p, m] = f(void 0), [h, g] = f(void 0), _ = d(void 0), { dragging: v, handlers: y } = J({
574
+ `, ve = () => {
575
+ let e = F(), t = F((e) => e.currentTime), n = F((e) => e.duration), r = F((e) => e.size), i = F((e) => e.downloadedRanges), a = F((e) => e.indexes), o = F((e) => e.thumbnails), s = F((e) => e.thumbnailAt), c = f(null), [l, m] = p(void 0), [h, g] = p(void 0), _ = f(void 0), { dragging: v, handlers: y } = q({
555
576
  ref: c,
556
577
  onChange: (e) => {
557
578
  m(e), _.current !== "mouse" && g(e * n);
558
579
  }
559
580
  }), b = (e) => {
560
581
  _.current = e.pointerType, y.onPointerDown(e);
561
- }, C = (e) => {
582
+ }, x = (e) => {
562
583
  y.onPointerUp(e), e.pointerType !== "mouse" && g(void 0);
563
584
  }, w = (e) => {
564
585
  if (!c.current) return;
@@ -568,12 +589,12 @@ var ne = {
568
589
  g(w(e.clientX));
569
590
  }, E = () => {
570
591
  c.current && g(void 0);
571
- }, D = (e) => n ? e / n * 100 : 0, O = u(() => i?.map((e, t) => {
592
+ }, D = (e) => n ? e / n * 100 : 0, O = d(() => i?.map((e, t) => {
572
593
  if (!r || !n) return null;
573
594
  let i = a.filter((t) => e.startByteOffset <= t.pos && t.pos <= e.endByteOffset), o = i.at(0), s = i.at(-1);
574
595
  if (!o || !s) return null;
575
596
  let c = o.timestamp / n, l = s.timestamp / n, u = Number((l - c).toFixed(2)), d = c * 100;
576
- return /* @__PURE__ */ x("div", {
597
+ return /* @__PURE__ */ S("div", {
577
598
  className: "loaded-part",
578
599
  style: {
579
600
  transform: `scaleX(${u})`,
@@ -584,21 +605,21 @@ var ne = {
584
605
  n,
585
606
  a.length,
586
607
  i?.map(({ startByteOffset: e, endByteOffset: t }) => `${e}/${t}`).join(",")
587
- ]), k = u(() => {
608
+ ]), k = d(() => {
588
609
  if (!h || h < 0) return;
589
610
  let e = Math.floor(h / 3600), t = Math.floor((h - e * 3600) / 60), n = Math.floor(h - e * 3600 - t * 60);
590
611
  return `${e > 0 ? `${e}:` : ""}${t < 10 ? "0" : ""}${t}:${n < 10 ? "0" : ""}${n}`;
591
612
  }, [h]);
592
- l(() => {
593
- if (p === void 0 || !n) return;
594
- let t = p * n;
613
+ u(() => {
614
+ if (l === void 0 || !n) return;
615
+ let t = l * n;
595
616
  e.seek(t);
596
617
  }, [
597
618
  e,
598
- p,
619
+ l,
599
620
  n
600
621
  ]);
601
- let A = u(() => !n || typeof t != "number" ? 0 : t / n, [n, t]), j = u(() => {
622
+ let A = d(() => !n || typeof t != "number" ? 0 : t / n, [n, t]), j = d(() => {
602
623
  if (h) {
603
624
  if (s) return s(h);
604
625
  if (o.length) return o.find(({ startTime: e, endTime: t }) => e <= h && h < t);
@@ -608,49 +629,105 @@ var ne = {
608
629
  s,
609
630
  h
610
631
  ]);
611
- return /* @__PURE__ */ S("div", {
612
- css: he,
632
+ return /* @__PURE__ */ C("div", {
633
+ css: _e,
613
634
  ref: c,
614
635
  className: v ? "progress-bar dragging" : "progress-bar",
615
636
  onMouseMove: T,
616
637
  onMouseOut: E,
617
638
  children: [
618
- /* @__PURE__ */ x("div", { className: "background-bar" }),
619
- h ? /* @__PURE__ */ x("div", {
639
+ /* @__PURE__ */ S("div", { className: "background-bar" }),
640
+ h ? /* @__PURE__ */ S("div", {
620
641
  className: "cursor-time",
621
- style: { left: `clamp(calc(1.8 * var(--mp-unit)), ${D(h)}%, calc(100% - calc(1.8 * var(--mp-unit))))` },
642
+ style: { left: `clamp(calc(3 * var(--mp-unit)), ${D(h)}%, calc(100% - calc(3 * var(--mp-unit))))` },
622
643
  children: k
623
644
  }) : void 0,
624
- /* @__PURE__ */ x("div", { className: "progress" }),
625
- /* @__PURE__ */ x("div", {
645
+ /* @__PURE__ */ S("div", { className: "progress" }),
646
+ /* @__PURE__ */ S("div", {
626
647
  className: "loaded",
627
648
  children: O
628
649
  }),
629
- /* @__PURE__ */ x("div", { className: "hover" }),
630
- /* @__PURE__ */ x("div", {
650
+ /* @__PURE__ */ S("div", { className: "hover" }),
651
+ /* @__PURE__ */ S("div", {
631
652
  className: "play-container",
632
- children: /* @__PURE__ */ x("div", {
653
+ children: /* @__PURE__ */ S("div", {
633
654
  className: "play",
634
655
  style: { transform: `scaleX(${A})` }
635
656
  })
636
657
  }),
637
- /* @__PURE__ */ x("div", { className: "chapters" }),
638
- /* @__PURE__ */ x("div", { className: "scrubber" }),
639
- /* @__PURE__ */ x("div", {
658
+ /* @__PURE__ */ S("div", { className: "chapters" }),
659
+ /* @__PURE__ */ S("div", { className: "scrubber" }),
660
+ /* @__PURE__ */ S("div", {
640
661
  className: "padding",
641
662
  ...y,
642
663
  onPointerDown: b,
643
- onPointerUp: C,
644
- onPointerCancel: C
664
+ onPointerUp: x,
665
+ onPointerCancel: x
645
666
  }),
646
- /* @__PURE__ */ x("div", {
667
+ /* @__PURE__ */ S("div", {
647
668
  className: "thumbnail",
648
669
  style: { left: `clamp(var(--thumbnail-half), ${D(h ?? 1)}%, calc(100% - var(--thumbnail-half)))` },
649
- children: j?.url ? /* @__PURE__ */ x("img", { src: j.url }) : void 0
670
+ children: j?.url ? /* @__PURE__ */ S("img", { src: j.url }) : void 0
650
671
  })
651
672
  ]
652
673
  });
653
- }, _e = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23fff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20class='icon%20icon-tabler%20icons-tabler-outline%20icon-tabler-picture-in-picture'%3e%3cpath%20stroke='none'%20d='M0%200h24v24H0z'%20fill='none'%20/%3e%3cpath%20d='M11%2019h-6a2%202%200%200%201%20-2%20-2v-10a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4'%20/%3e%3cpath%20d='M14%2014m0%201a1%201%200%200%201%201%20-1h5a1%201%200%200%201%201%201v3a1%201%200%200%201%20-1%201h-5a1%201%200%200%201%20-1%20-1z'%20/%3e%3c/svg%3e", ve = p`
674
+ }, ye = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23fff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20class='icon%20icon-tabler%20icons-tabler-outline%20icon-tabler-picture-in-picture'%3e%3cpath%20stroke='none'%20d='M0%200h24v24H0z'%20fill='none'%20/%3e%3cpath%20d='M11%2019h-6a2%202%200%200%201%20-2%20-2v-10a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4'%20/%3e%3cpath%20d='M14%2014m0%201a1%201%200%200%201%201%20-1h5a1%201%200%200%201%201%201v3a1%201%200%200%201%20-1%201h-5a1%201%200%200%201%20-1%20-1z'%20/%3e%3c/svg%3e", J = {
675
+ xmlns: "http://www.w3.org/2000/svg",
676
+ width: 24,
677
+ height: 24,
678
+ viewBox: "0 0 24 24",
679
+ fill: "none",
680
+ stroke: "currentColor",
681
+ strokeWidth: 2,
682
+ strokeLinecap: "round",
683
+ strokeLinejoin: "round"
684
+ }, be = (e) => /* @__PURE__ */ C("svg", {
685
+ ...J,
686
+ ...e,
687
+ children: [/* @__PURE__ */ S("rect", {
688
+ x: "3",
689
+ y: "5",
690
+ width: "18",
691
+ height: "14",
692
+ rx: "2",
693
+ ry: "2"
694
+ }), /* @__PURE__ */ S("path", { d: "M7 15h4m4 0h2M7 11h2m4 0h4" })]
695
+ }), xe = (e) => /* @__PURE__ */ C("svg", {
696
+ ...J,
697
+ ...e,
698
+ children: [
699
+ /* @__PURE__ */ S("rect", {
700
+ x: "3",
701
+ y: "5",
702
+ width: "18",
703
+ height: "14",
704
+ rx: "2",
705
+ ry: "2"
706
+ }),
707
+ /* @__PURE__ */ S("path", { d: "M7 15h4m4 0h2M7 11h2m4 0h4" }),
708
+ /* @__PURE__ */ S("line", {
709
+ x1: "2",
710
+ y1: "2",
711
+ x2: "22",
712
+ y2: "22"
713
+ })
714
+ ]
715
+ }), Se = (e) => /* @__PURE__ */ C("svg", {
716
+ ...J,
717
+ ...e,
718
+ children: [
719
+ /* @__PURE__ */ S("path", { d: "M21 11V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h5" }),
720
+ /* @__PURE__ */ S("rect", {
721
+ x: "12",
722
+ y: "13",
723
+ width: "10",
724
+ height: "8",
725
+ rx: "1",
726
+ ry: "1"
727
+ }),
728
+ /* @__PURE__ */ S("path", { d: "M14.5 18.5h2m2 0h1" })
729
+ ]
730
+ }), Ce = m`
654
731
  display: flex;
655
732
  align-items: center;
656
733
  justify-content: center;
@@ -703,72 +780,73 @@ width: 100%;
703
780
  }
704
781
  }
705
782
  }
706
- `, ye = () => {
707
- let e = F(), t = F((e) => e.playbackRate), n = d(null), r = d(null), i = .25, a = 3 - i, o = (e, t = .05) => Math.round(e / t) * t, s = o(t || 1), c = (e) => (e - i) / a * 100, u = (e) => o(i + e * a), { handlers: f } = J({
783
+ `, we = () => {
784
+ let e = F(), t = F((e) => e.playbackRate), n = f(null), r = f(null), i = .25, a = 3 - i, o = (e, t = .05) => Math.round(e / t) * t, s = o(t || 1), c = (e) => (e - i) / a * 100, l = (e) => o(i + e * a), { handlers: d } = q({
708
785
  ref: r,
709
- onChange: (t) => e.setPlaybackRate(u(t))
786
+ onChange: (t) => e.setPlaybackRate(l(t))
710
787
  }), p = (t) => {
711
788
  t.preventDefault();
712
789
  let n = .05, r = s;
713
790
  r = t.deltaY < 0 ? Math.min(3, r + n) : Math.max(i, r - n), e.setPlaybackRate(r);
714
791
  };
715
- l(() => {
792
+ u(() => {
716
793
  let e = n.current;
717
794
  return e && e.addEventListener("wheel", p, { passive: !1 }), () => {
718
795
  e && e.removeEventListener("wheel", p);
719
796
  };
720
797
  }, [t]);
721
798
  let m = c(s);
722
- return /* @__PURE__ */ S("div", {
723
- css: ve,
724
- children: [/* @__PURE__ */ S("div", { children: [s.toFixed(2), "x"] }), /* @__PURE__ */ x("div", {
799
+ return /* @__PURE__ */ C("div", {
800
+ css: Ce,
801
+ children: [/* @__PURE__ */ C("div", { children: [s.toFixed(2), "x"] }), /* @__PURE__ */ S("div", {
725
802
  className: "playback-slider",
726
803
  ref: n,
727
- ...f,
728
- children: /* @__PURE__ */ x("div", {
804
+ ...d,
805
+ children: /* @__PURE__ */ S("div", {
729
806
  ref: r,
730
807
  style: { background: `linear-gradient(to right,
731
808
  #fff 0% ${m}%,
732
809
  #3A3A3A ${m}% 100%
733
810
  )` },
734
- children: /* @__PURE__ */ x("div", {
811
+ children: /* @__PURE__ */ S("div", {
735
812
  className: "playback-handle",
736
813
  style: { left: `${m}%` }
737
814
  })
738
815
  })
739
816
  })]
740
817
  });
741
- }, be = p`
742
- position: relative;
743
-
744
- .settings {
745
- /* the icon keeps its size, the pressable box grows around it */
746
- @media (pointer: coarse) {
747
- box-sizing: border-box;
748
- justify-content: center;
749
-
750
- min-width: 44px;
751
- min-height: 44px;
752
- }
753
- }
754
-
818
+ }, Y = m`
755
819
  .popover {
756
820
  position: absolute;
757
- /* the gear sits a couple of buttons in from the right edge, so a centred popover hangs off that
758
- edge on a phone. It anchors to the button instead until the viewport has room to centre it. */
759
- right: 0;
760
- transform: none;
821
+ /* Anchored to the PLAYER's right edge, never to the gear. The gear is not the last control in the
822
+ bar, so a menu centred on it puts its own edges wherever the button happens to sit: with no
823
+ picture-in-picture button, which is every source whose media the player does not own, an edge
824
+ landed outside the box, and the root's \`overflow: hidden\` cut it off, taking the rows under it
825
+ out of reach. The inset matches the bar's own padding so the menu lines up with the last button. */
826
+ right: calc(12px + env(safe-area-inset-right, 0px));
827
+ bottom: calc(100% + 8px);
761
828
 
762
829
  overflow-y: auto;
763
830
  width: 180px;
764
- max-width: calc(100vw - 24px);
765
- height: 160px;
766
- top: -180px;
831
+ /* \`100%\` is the control bar, which is the width of the PLAYER. The old \`100vw\` was the viewport,
832
+ which equals the player only when the player is the whole document, and it is the wrong kind of
833
+ guard besides: a max-width shrinks the box, it never moves it back inside. */
834
+ max-width: calc(100% - 24px);
835
+ /* Sized to its rows, capped at what fits. A fixed height left the settings menu two thirds empty
836
+ once subtitles moved out to its own button, and a long track list scrolls at the cap either way. */
837
+ height: max-content;
838
+ /* The room actually above the bar. A short player had the top of the menu clipped by that same
839
+ \`overflow: hidden\`. With no size container in the ancestry this resolves against the small
840
+ viewport, so it can only ever shrink the box, never grow it. */
841
+ max-height: min(160px, calc(100cqh - 100% - 16px));
767
842
  @media (min-width: 768px) {
768
- right: 50%;
769
- transform: translateX(50%);
843
+ right: calc(16px + env(safe-area-inset-right, 0px));
770
844
  width: 250px;
771
- height: 160px;
845
+ max-width: calc(100% - 32px);
846
+ }
847
+ @media (min-width: 2560px) {
848
+ right: calc(24px + env(safe-area-inset-right, 0px));
849
+ max-width: calc(100% - 48px);
772
850
  }
773
851
 
774
852
  display: flex;
@@ -776,7 +854,7 @@ position: relative;
776
854
 
777
855
  border-radius: 8px;
778
856
  background-color: rgba(28,28,28,0.95);
779
- ${V.bMedium.regular}
857
+ ${B.bMedium.regular}
780
858
 
781
859
  z-index: 4;
782
860
 
@@ -819,7 +897,7 @@ position: relative;
819
897
 
820
898
  .secondary {
821
899
  color: #eee;
822
- ${V.bSmall.regular}
900
+ ${B.bSmall.regular}
823
901
  }
824
902
  }
825
903
  }
@@ -843,45 +921,6 @@ position: relative;
843
921
  }
844
922
  }
845
923
 
846
- .playback-rate {
847
- .slider {
848
- width: 100%;
849
- }
850
- .options {
851
- display: grid;
852
- grid-template-columns: 1fr 1fr 1fr 1fr;
853
- align-items: center;
854
-
855
- padding: 8px 12px;
856
- /* four presets across a 180px popover leave targets 34px wide, so a finger gets two rows of two
857
- until the popover is wide enough for the row of four */
858
- @media (pointer: coarse) {
859
- grid-template-columns: 1fr 1fr;
860
- }
861
- @media (pointer: coarse) and (min-width: 768px) {
862
- grid-template-columns: 1fr 1fr 1fr 1fr;
863
- }
864
-
865
- > div {
866
- display: flex;
867
- align-items: center;
868
- border-radius: 4px;
869
-
870
- padding: 8px 6px;
871
- height: 100%;
872
- @media (pointer: coarse) {
873
- box-sizing: border-box;
874
- min-height: 44px;
875
- }
876
-
877
- cursor: pointer;
878
- :hover {
879
- background-color: rgba(255,255,255,.1);
880
- }
881
- }
882
- }
883
- }
884
-
885
924
  .track-list {
886
925
  .description {
887
926
  word-break: break-word;
@@ -900,29 +939,29 @@ position: relative;
900
939
  .failed {
901
940
  border-bottom: 1px solid #4D4D4E;
902
941
  color: #f66;
903
- ${V.bSmall.regular}
942
+ ${B.bSmall.regular}
904
943
  }
905
944
  }
906
- `, Y = ({ title: e, tracks: t, selected: n, onSelect: r, onBack: i, offLabel: a, pending: o, failed: s }) => {
945
+ `, X = ({ title: e, tracks: t, selected: n, onSelect: r, onBack: i, offLabel: a, pending: o, failed: s }) => {
907
946
  let c = o !== void 0, l = (e, i, a) => {
908
947
  let s = c && o === e, l = c || t.find((t) => t.id === e)?.disabled;
909
- return /* @__PURE__ */ S("div", {
948
+ return /* @__PURE__ */ C("div", {
910
949
  onClick: () => {
911
950
  l || r(e ?? void 0);
912
951
  },
913
952
  className: [a, l ? "unavailable" : null].filter(Boolean).join(" ") || void 0,
914
- children: [/* @__PURE__ */ x("span", { children: i }), /* @__PURE__ */ x("span", { children: s ? "…" : (n ?? null) === e ? "✓" : "" })]
953
+ children: [/* @__PURE__ */ S("span", { children: i }), /* @__PURE__ */ S("span", { children: s ? "…" : (n ?? null) === e ? "✓" : "" })]
915
954
  }, e ?? "__off__");
916
955
  };
917
- return /* @__PURE__ */ S("div", {
956
+ return /* @__PURE__ */ C("div", {
918
957
  className: "popover track-list",
919
958
  children: [
920
- /* @__PURE__ */ S("div", {
921
- className: "back",
959
+ /* @__PURE__ */ C("div", {
960
+ className: i ? "back" : "back no-hover",
922
961
  onClick: i,
923
- children: [/* @__PURE__ */ x(C, {}), /* @__PURE__ */ x("span", { children: e })]
962
+ children: [i ? /* @__PURE__ */ S(w, {}) : null, /* @__PURE__ */ S("span", { children: e })]
924
963
  }),
925
- s ? /* @__PURE__ */ x("div", {
964
+ s ? /* @__PURE__ */ S("div", {
926
965
  className: "no-hover failed",
927
966
  children: "Could not switch. Try again."
928
967
  }) : null,
@@ -930,142 +969,238 @@ position: relative;
930
969
  t.map(({ id: e, label: t }) => l(e, t, "description"))
931
970
  ]
932
971
  });
933
- }, xe = () => {
934
- let e = F(), t = F((e) => e.playbackRate), n = F((e) => e.subtitleTracks), r = F((e) => e.selectedSubtitleTrack), i = F((e) => e.selectSubtitleTrack), a = F((e) => e.audioTracks), o = F((e) => e.selectedAudioTrack), s = F((e) => e.selectAudioTrack), c = F((e) => e.subtitleOffLabel), [u, p] = f(!1), [m, h] = f(0), g = d(null), [_, v] = f(void 0), [y, b] = f(!1), T = () => {
935
- p(!u), h(0), b(!1);
936
- }, E = () => {
937
- p(!1), h(0);
938
- }, D = (t) => {
939
- e.setPlaybackRate(t), h(0);
972
+ }, Z = ({ onReset: e } = {}) => {
973
+ let t = f(null), [n, r] = p(!1), [i, a] = p(void 0), [o, s] = p(!1), c = f(e);
974
+ c.current = e;
975
+ let l = () => {
976
+ r(!1), c.current?.();
940
977
  };
941
- l(() => {
978
+ return u(() => {
942
979
  let e = (e) => {
943
- u && g.current && !g.current.contains(e.target) && T();
980
+ n && t.current && !t.current.contains(e.target) && l();
944
981
  };
945
982
  return document.addEventListener("pointerdown", e), () => document.removeEventListener("pointerdown", e);
946
- }, [u]);
947
- let O = (e, t) => {
948
- if (_ !== void 0) return;
949
- b(!1);
950
- let n;
951
- try {
952
- n = t();
953
- } catch (e) {
954
- console.warn("[media-player] track selection failed:", e), b(!0);
955
- return;
956
- }
957
- if (!(n instanceof Promise)) {
958
- E();
959
- return;
983
+ }, [n]), {
984
+ open: n,
985
+ toggle: () => {
986
+ r((e) => !e), s(!1), c.current?.();
987
+ },
988
+ close: l,
989
+ containerRef: t,
990
+ pending: i,
991
+ failed: o,
992
+ runSelect: (e, t) => {
993
+ if (i !== void 0) return;
994
+ s(!1);
995
+ let n;
996
+ try {
997
+ n = t();
998
+ } catch (e) {
999
+ console.warn("[media-player] track selection failed:", e), s(!0);
1000
+ return;
1001
+ }
1002
+ if (!(n instanceof Promise)) {
1003
+ l();
1004
+ return;
1005
+ }
1006
+ a(e), n.then(() => {
1007
+ a(void 0), l();
1008
+ }, (e) => {
1009
+ console.warn("[media-player] track selection failed:", e), a(void 0), s(!0);
1010
+ });
960
1011
  }
961
- v(e), n.then(() => {
962
- v(void 0), E();
963
- }, (e) => {
964
- console.warn("[media-player] track selection failed:", e), v(void 0), b(!0);
965
- });
966
- }, k = (e) => O(e ?? null, () => i(e)), j = (e) => {
967
- e !== void 0 && O(e, () => s(e));
968
- }, M = (e) => () => {
969
- h(e);
970
1012
  };
971
- return /* @__PURE__ */ S("div", {
972
- css: be,
973
- ref: g,
1013
+ }, Te = m`
1014
+ /* Deliberately NOT a containing block. The menu anchors to the control bar instead, which is exactly
1015
+ as wide as the player box and can therefore be clamped to it. The outside-click check uses
1016
+ \`contains\` on the ref, which is DOM containment and needs no position, and the bar's other
1017
+ tooltips already resolve against the control bar with no positioned wrapper of their own. */
1018
+ position: static;
1019
+
1020
+ .settings {
1021
+ /* the icon keeps its size, the pressable box grows around it */
1022
+ @media (pointer: coarse) {
1023
+ box-sizing: border-box;
1024
+ justify-content: center;
1025
+
1026
+ min-width: 44px;
1027
+ min-height: 44px;
1028
+ }
1029
+ }
1030
+
1031
+ ${Y}
1032
+
1033
+ .playback-rate {
1034
+ .slider {
1035
+ width: 100%;
1036
+ }
1037
+ .options {
1038
+ display: grid;
1039
+ grid-template-columns: 1fr 1fr 1fr 1fr;
1040
+ align-items: center;
1041
+
1042
+ padding: 8px 12px;
1043
+ /* four presets across a 180px popover leave targets 34px wide, so a finger gets two rows of two
1044
+ until the popover is wide enough for the row of four */
1045
+ @media (pointer: coarse) {
1046
+ grid-template-columns: 1fr 1fr;
1047
+ }
1048
+ @media (pointer: coarse) and (min-width: 768px) {
1049
+ grid-template-columns: 1fr 1fr 1fr 1fr;
1050
+ }
1051
+
1052
+ > div {
1053
+ display: flex;
1054
+ align-items: center;
1055
+ border-radius: 4px;
1056
+
1057
+ padding: 8px 6px;
1058
+ height: 100%;
1059
+ @media (pointer: coarse) {
1060
+ box-sizing: border-box;
1061
+ min-height: 44px;
1062
+ }
1063
+
1064
+ cursor: pointer;
1065
+ :hover {
1066
+ background-color: rgba(255,255,255,.1);
1067
+ }
1068
+ }
1069
+ }
1070
+ }
1071
+
1072
+ `, Ee = () => {
1073
+ let e = F(), t = F((e) => e.playbackRate), n = F((e) => e.audioTracks), r = F((e) => e.selectedAudioTrack), i = F((e) => e.selectAudioTrack), [a, o] = p(0), { open: s, toggle: c, containerRef: l, pending: u, failed: d, runSelect: f } = Z({ onReset: () => o(0) }), m = (t) => {
1074
+ e.setPlaybackRate(t), o(0);
1075
+ }, h = (e) => {
1076
+ e !== void 0 && f(e, () => i(e));
1077
+ }, g = (e) => () => {
1078
+ o(e);
1079
+ };
1080
+ return /* @__PURE__ */ C("div", {
1081
+ css: Te,
1082
+ ref: l,
974
1083
  children: [
975
- /* @__PURE__ */ x(q, {
1084
+ /* @__PURE__ */ S(K, {
976
1085
  id: "settings",
977
- disabled: u,
978
- text: /* @__PURE__ */ x("button", {
1086
+ disabled: s,
1087
+ text: /* @__PURE__ */ S("button", {
979
1088
  className: "settings",
980
1089
  type: "button",
981
- onClick: T,
982
- children: /* @__PURE__ */ x(A, {})
1090
+ onClick: c,
1091
+ children: /* @__PURE__ */ S(j, {})
983
1092
  }),
984
- toolTipText: /* @__PURE__ */ x("span", { children: "Settings" })
1093
+ toolTipText: /* @__PURE__ */ S("span", { children: "Settings" })
985
1094
  }),
986
- u && m === 0 && /* @__PURE__ */ S("div", {
1095
+ s && a === 0 && /* @__PURE__ */ C("div", {
987
1096
  className: "popover menu",
988
- children: [
989
- a.length > 1 ? /* @__PURE__ */ S("div", {
990
- onClick: M(3),
991
- children: [/* @__PURE__ */ x("div", { children: "Audio" }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(w, {}) })]
992
- }) : null,
993
- n.length > 0 ? /* @__PURE__ */ S("div", {
994
- onClick: M(2),
995
- children: [/* @__PURE__ */ x("div", { children: "Subtitles" }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(w, {}) })]
996
- }) : null,
997
- /* @__PURE__ */ S("div", {
998
- onClick: M(1),
999
- children: [/* @__PURE__ */ x("div", { children: "Playback speed" }), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("span", {
1000
- className: "secondary",
1001
- children: t === 1 ? "(Default)" : t.toFixed(2)
1002
- }), /* @__PURE__ */ x(w, {})] })]
1003
- })
1004
- ]
1097
+ children: [n.length > 1 ? /* @__PURE__ */ C("div", {
1098
+ onClick: g(2),
1099
+ children: [/* @__PURE__ */ S("div", { children: "Audio" }), /* @__PURE__ */ S("div", { children: /* @__PURE__ */ S(T, {}) })]
1100
+ }) : null, /* @__PURE__ */ C("div", {
1101
+ onClick: g(1),
1102
+ children: [/* @__PURE__ */ S("div", { children: "Playback speed" }), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("span", {
1103
+ className: "secondary",
1104
+ children: t === 1 ? "(Default)" : t.toFixed(2)
1105
+ }), /* @__PURE__ */ S(T, {})] })]
1106
+ })]
1005
1107
  }),
1006
- u && m === 1 && /* @__PURE__ */ S("div", {
1108
+ s && a === 1 && /* @__PURE__ */ C("div", {
1007
1109
  className: "popover playback-rate",
1008
1110
  children: [
1009
- /* @__PURE__ */ S("div", {
1111
+ /* @__PURE__ */ C("div", {
1010
1112
  className: "back",
1011
- onClick: M(0),
1012
- children: [/* @__PURE__ */ x(C, {}), /* @__PURE__ */ x("span", { children: "Playback speed" })]
1113
+ onClick: g(0),
1114
+ children: [/* @__PURE__ */ S(w, {}), /* @__PURE__ */ S("span", { children: "Playback speed" })]
1013
1115
  }),
1014
- /* @__PURE__ */ x("div", {
1116
+ /* @__PURE__ */ S("div", {
1015
1117
  className: "slider no-hover",
1016
- children: /* @__PURE__ */ x(ye, {})
1118
+ children: /* @__PURE__ */ S(we, {})
1017
1119
  }),
1018
- /* @__PURE__ */ S("div", {
1120
+ /* @__PURE__ */ C("div", {
1019
1121
  className: "options no-hover",
1020
1122
  children: [
1021
- /* @__PURE__ */ x("div", {
1022
- onClick: () => D(.5),
1123
+ /* @__PURE__ */ S("div", {
1124
+ onClick: () => m(.5),
1023
1125
  children: "0.5x"
1024
1126
  }),
1025
- /* @__PURE__ */ x("div", {
1026
- onClick: () => D(1),
1127
+ /* @__PURE__ */ S("div", {
1128
+ onClick: () => m(1),
1027
1129
  children: "1x"
1028
1130
  }),
1029
- /* @__PURE__ */ x("div", {
1030
- onClick: () => D(1.5),
1131
+ /* @__PURE__ */ S("div", {
1132
+ onClick: () => m(1.5),
1031
1133
  children: "1.5x"
1032
1134
  }),
1033
- /* @__PURE__ */ x("div", {
1034
- onClick: () => D(2),
1135
+ /* @__PURE__ */ S("div", {
1136
+ onClick: () => m(2),
1035
1137
  children: "2x"
1036
1138
  })
1037
1139
  ]
1038
1140
  })
1039
1141
  ]
1040
1142
  }),
1041
- u && m === 2 && /* @__PURE__ */ x(Y, {
1042
- title: "Subtitles",
1143
+ s && a === 2 && /* @__PURE__ */ S(X, {
1144
+ title: "Audio",
1043
1145
  tracks: n,
1044
1146
  selected: r,
1045
- onSelect: k,
1046
- onBack: M(0),
1047
- offLabel: c ?? "Disable",
1048
- pending: _,
1049
- failed: y
1050
- }),
1051
- u && m === 3 && /* @__PURE__ */ x(Y, {
1052
- title: "Audio",
1053
- tracks: a,
1054
- selected: o,
1055
- onSelect: j,
1056
- onBack: M(0),
1057
- pending: _,
1058
- failed: y
1147
+ onSelect: h,
1148
+ onBack: g(0),
1149
+ pending: u,
1150
+ failed: d
1059
1151
  })
1060
1152
  ]
1061
1153
  });
1062
- }, Se = {
1154
+ }, De = m`
1155
+ /* Not a containing block, for the reason given on popoverStyle: the menu anchors to the control bar,
1156
+ which is the width of the player box, so it can be clamped to it. */
1157
+ position: static;
1158
+
1159
+ .subtitles {
1160
+ /* the icon keeps its size, the pressable box grows around it */
1161
+ @media (pointer: coarse) {
1162
+ box-sizing: border-box;
1163
+ justify-content: center;
1164
+
1165
+ min-width: 44px;
1166
+ min-height: 44px;
1167
+ }
1168
+ }
1169
+
1170
+ ${Y}
1171
+ `, Oe = () => {
1172
+ let e = F((e) => e.subtitleTracks), t = F((e) => e.selectedSubtitleTrack), n = F((e) => e.selectSubtitleTrack), r = F((e) => e.subtitleOffLabel), { open: i, toggle: a, containerRef: o, pending: s, failed: c, runSelect: l } = Z();
1173
+ return e.length === 0 ? null : /* @__PURE__ */ C("div", {
1174
+ css: De,
1175
+ ref: o,
1176
+ children: [/* @__PURE__ */ S(K, {
1177
+ id: "subtitles",
1178
+ disabled: i,
1179
+ text: /* @__PURE__ */ S("button", {
1180
+ className: "subtitles",
1181
+ type: "button",
1182
+ onClick: a,
1183
+ children: t === void 0 ? /* @__PURE__ */ S(xe, { className: "captions-off" }) : /* @__PURE__ */ S(be, { className: "captions" })
1184
+ }),
1185
+ toolTipText: /* @__PURE__ */ S("span", { children: "Subtitles" })
1186
+ }), i && /* @__PURE__ */ S(X, {
1187
+ title: "Subtitles",
1188
+ tracks: e,
1189
+ selected: t,
1190
+ onSelect: (e) => l(e ?? null, () => n(e)),
1191
+ offLabel: r ?? "Disable",
1192
+ pending: s,
1193
+ failed: c
1194
+ })]
1195
+ });
1196
+ }, Q = {
1063
1197
  primary: "#EAEBEE",
1064
1198
  secondary: "#D0D0D9",
1065
1199
  hover: "rgba(255, 255, 255, 0.13)",
1200
+ accent: "#6EA8FE",
1066
1201
  borderPrimary: "#384F70",
1067
1202
  backgroundTooltip: "#222222"
1068
- }, Ce = p`
1203
+ }, ke = m`
1069
1204
  display: flex;
1070
1205
  align-items: center;
1071
1206
 
@@ -1108,8 +1243,8 @@ position: relative;
1108
1243
  width: 10px;
1109
1244
  height: 10px;
1110
1245
  }
1111
- `, we = ({ value: e, onChange: t }) => {
1112
- let n = F((e) => e.volume), r = F((e) => e.muted), i = d(null), a = d(null), { handlers: o } = J({
1246
+ `, Ae = ({ value: e, onChange: t }) => {
1247
+ let n = F((e) => e.volume), r = F((e) => e.muted), i = f(null), a = f(null), { handlers: o } = q({
1113
1248
  ref: a,
1114
1249
  onChange: t
1115
1250
  }), s = (n) => {
@@ -1117,37 +1252,37 @@ position: relative;
1117
1252
  let r = .05, i = e;
1118
1253
  i = n.deltaY < 0 ? Math.min(1, i + r) : Math.max(0, i - r), t(i);
1119
1254
  };
1120
- l(() => {
1255
+ u(() => {
1121
1256
  let e = i.current;
1122
1257
  return e && e.addEventListener("wheel", s, { passive: !1 }), () => {
1123
1258
  e && e.removeEventListener("wheel", s);
1124
1259
  };
1125
1260
  }, [e]);
1126
- let c = e * 100, f = u(() => Math.round(r ? 0 : G(n) * 100), [n, r]);
1127
- return /* @__PURE__ */ x(q, {
1261
+ let c = e * 100, l = d(() => Math.round(r ? 0 : W(n) * 100), [n, r]);
1262
+ return /* @__PURE__ */ S(K, {
1128
1263
  id: "volume-slider",
1129
- text: /* @__PURE__ */ x("div", {
1264
+ text: /* @__PURE__ */ S("div", {
1130
1265
  ref: i,
1131
- css: Ce,
1266
+ css: ke,
1132
1267
  ...o,
1133
- children: /* @__PURE__ */ x("div", {
1268
+ children: /* @__PURE__ */ S("div", {
1134
1269
  ref: a,
1135
1270
  style: { background: `linear-gradient(to right,
1136
1271
  #fff 0% ${c}%,
1137
1272
  #3A3A3A ${c}% 100%
1138
1273
  )` },
1139
- children: /* @__PURE__ */ x("div", {
1274
+ children: /* @__PURE__ */ S("div", {
1140
1275
  className: "volume-handle",
1141
1276
  style: { left: `${e * 100}%` }
1142
1277
  })
1143
1278
  })
1144
1279
  }),
1145
- toolTipText: /* @__PURE__ */ S("div", {
1280
+ toolTipText: /* @__PURE__ */ C("div", {
1146
1281
  className: "volume-value",
1147
- children: [f, "%"]
1282
+ children: [l, "%"]
1148
1283
  })
1149
1284
  });
1150
- }, Te = p`
1285
+ }, je = m`
1151
1286
  position: relative;
1152
1287
  display: flex;
1153
1288
  align-items: center;
@@ -1172,7 +1307,7 @@ position: relative;
1172
1307
  border-radius: 4px;
1173
1308
 
1174
1309
  .volume-value {
1175
- ${V.bMedium.regular};
1310
+ ${B.bMedium.regular};
1176
1311
  color: #ffffff;
1177
1312
  }
1178
1313
  }
@@ -1210,37 +1345,48 @@ position: relative;
1210
1345
  }
1211
1346
  }
1212
1347
 
1213
- `, Ee = ({ ref: e }) => {
1214
- let t = F(), n = F((e) => e.volume), r = F((e) => e.muted), i = u(() => G(n), [n]);
1215
- return /* @__PURE__ */ S("div", {
1216
- css: Te,
1217
- children: [/* @__PURE__ */ x(q, {
1348
+ `, Me = ({ ref: e }) => {
1349
+ let t = F(), n = F((e) => e.volume), r = F((e) => e.muted), i = d(() => W(n), [n]);
1350
+ return /* @__PURE__ */ C("div", {
1351
+ css: je,
1352
+ children: [/* @__PURE__ */ S(K, {
1218
1353
  id: "sound",
1219
- text: /* @__PURE__ */ x("button", {
1354
+ text: /* @__PURE__ */ S("button", {
1220
1355
  className: "sound",
1221
1356
  type: "button",
1222
1357
  onClick: () => t.toggleMuted(),
1223
1358
  ref: e,
1224
- children: x(r || n === 0 ? ee : n <= .5 ? j : M, {
1359
+ children: S(r || n === 0 ? te : n <= .5 ? M : ee, {
1225
1360
  size: 18,
1226
1361
  color: "#fff"
1227
1362
  })
1228
1363
  }),
1229
- toolTipText: /* @__PURE__ */ x("span", { children: r ? "Unmute (m)" : "Mute (m)" })
1230
- }), /* @__PURE__ */ x("div", {
1364
+ toolTipText: /* @__PURE__ */ S("span", { children: r ? "Unmute (m)" : "Mute (m)" })
1365
+ }), /* @__PURE__ */ S("div", {
1231
1366
  className: "volume-slider-container",
1232
- children: /* @__PURE__ */ x("div", {
1367
+ children: /* @__PURE__ */ S("div", {
1233
1368
  className: "volume-slider-background",
1234
- children: /* @__PURE__ */ x(we, {
1369
+ children: /* @__PURE__ */ S(Ae, {
1235
1370
  value: r ? 0 : i,
1236
1371
  onChange: (e) => {
1237
- t.setVolume(W(e));
1372
+ t.setVolume(U(e));
1238
1373
  }
1239
1374
  })
1240
1375
  })
1241
1376
  })]
1242
1377
  });
1243
- }, X = .05, Z = 5, De = p`
1378
+ }, $ = .05, Ne = 5, Pe = m`
1379
+ display: flex;
1380
+ flex-direction: column;
1381
+ gap: calc(0.4 * var(--mp-unit));
1382
+ max-width: calc(26 * var(--mp-unit));
1383
+ white-space: normal;
1384
+
1385
+ .hint {
1386
+ opacity: 0.72;
1387
+ font-size: 0.9em;
1388
+ }
1389
+ `, Fe = m`
1244
1390
  position: absolute;
1245
1391
  bottom: 0;
1246
1392
  width: 100%;
@@ -1290,9 +1436,25 @@ position: relative;
1290
1436
  svg {
1291
1437
  stroke: #fff;
1292
1438
  }
1439
+
1440
+ /* Reads as unavailable rather than absent, so the bar does not reflow when tracks land. */
1441
+ &:disabled {
1442
+ cursor: default;
1443
+ opacity: .4;
1444
+ }
1293
1445
  }
1294
1446
 
1295
- .play, .sound, .time, .settings, .picture-in-picture, .full-screen {
1447
+ /**
1448
+ * The burn-in control's own on state.
1449
+ *
1450
+ * Not \`colors.hover\`: the pointer is on the button at the moment of the click, so an on state
1451
+ * drawn in the hover colour is invisible exactly when it is being looked for.
1452
+ */
1453
+ button[aria-pressed='true'] svg {
1454
+ stroke: ${Q.accent};
1455
+ }
1456
+
1457
+ .play, .sound, .time, .subtitles, .settings, .picture-in-picture, .full-screen {
1296
1458
  display: flex;
1297
1459
  align-items: center;
1298
1460
 
@@ -1310,7 +1472,7 @@ position: relative;
1310
1472
  }
1311
1473
  }
1312
1474
 
1313
- .play, .sound, .settings, .picture-in-picture, .full-screen {
1475
+ .play, .sound, .subtitles, .settings, .picture-in-picture, .full-screen {
1314
1476
  border-radius: 4px;
1315
1477
 
1316
1478
  padding: 8px;
@@ -1324,7 +1486,7 @@ position: relative;
1324
1486
  cursor: pointer;
1325
1487
 
1326
1488
  :hover {
1327
- background-color: ${Se.hover};
1489
+ background-color: ${Q.hover};
1328
1490
  }
1329
1491
 
1330
1492
  /* the hit area grows, the icon does not, keyed on the pointer because a narrow desktop
@@ -1341,7 +1503,7 @@ position: relative;
1341
1503
 
1342
1504
  .left {
1343
1505
  .time {
1344
- ${V.bMedium.regular}
1506
+ ${B.bMedium.regular}
1345
1507
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
1346
1508
  }
1347
1509
  }
@@ -1362,12 +1524,12 @@ position: relative;
1362
1524
  }
1363
1525
  }
1364
1526
  }
1365
- `, Oe = () => {
1366
- let e = F(), t = F((e) => e.paused), n = F((e) => e.currentTime), r = F((e) => e.duration), i = F((e) => e.fullscreen), a = F((e) => e.hideUI), o = F((e) => e.togglePictureInPicture), [s, u] = f(null), d = r > 0 && n === r, p = c(({ direction: t, stepSize: n }) => {
1367
- let r = G(e.volume), i = t === "up" ? n : -n, a = Math.max(0, Math.min(1, r + i)), o = e.muted;
1368
- e.setVolume(W(a)), o && !e.muted && e.toggleMuted();
1527
+ `, Ie = () => {
1528
+ let e = F(), t = F((e) => e.paused), n = F((e) => e.currentTime), r = F((e) => e.duration), i = F((e) => e.fullscreen), a = F((e) => e.hideUI), o = F((e) => e.togglePictureInPicture), s = F((e) => e.pictureInPictureMode), c = F((e) => e.burnedInSubtitles), d = F((e) => e.subtitleTracks), [f, m] = p(null), h = s === "burn-in", g = d.length > 0, _ = r > 0 && n === r, v = l(({ direction: t, stepSize: n }) => {
1529
+ let r = W(e.volume), i = t === "up" ? n : -n, a = Math.max(0, Math.min(1, r + i)), o = e.muted;
1530
+ e.setVolume(U(a)), o && !e.muted && e.toggleMuted();
1369
1531
  }, [e]);
1370
- l(() => {
1532
+ u(() => {
1371
1533
  let t = (t) => {
1372
1534
  let n = t.target;
1373
1535
  if (n?.isContentEditable || /^(input|textarea|select)$/i.test(n?.tagName ?? "")) return;
@@ -1376,91 +1538,194 @@ position: relative;
1376
1538
  else if (t.key === "k") e.togglePaused();
1377
1539
  else if (t.key === " ") e.togglePaused();
1378
1540
  else if (t.key === "m") e.toggleMuted();
1379
- else if (t.key === "ArrowUp") p({
1541
+ else if (t.key === "ArrowUp") v({
1380
1542
  direction: "up",
1381
- stepSize: X
1543
+ stepSize: $
1382
1544
  });
1383
- else if (t.key === "ArrowDown") p({
1545
+ else if (t.key === "ArrowDown") v({
1384
1546
  direction: "down",
1385
- stepSize: X
1547
+ stepSize: $
1386
1548
  });
1387
1549
  else if (t.key === "ArrowRight") {
1388
1550
  if (!e.duration) return;
1389
- e.seek(Math.min(e.currentTime + Z, e.duration));
1390
- } else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime - Z, 0)) : r = !1;
1551
+ e.seek(Math.min(e.currentTime + Ne, e.duration));
1552
+ } else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime - Ne, 0)) : r = !1;
1391
1553
  r && t.preventDefault();
1392
1554
  };
1393
1555
  return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t);
1394
- }, [e, p]);
1395
- let m = c((e) => {
1396
- e.preventDefault(), e.deltaY < 0 ? p({
1556
+ }, [e, v]);
1557
+ let y = l((e) => {
1558
+ e.preventDefault(), e.deltaY < 0 ? v({
1397
1559
  direction: "up",
1398
- stepSize: X
1399
- }) : p({
1560
+ stepSize: $
1561
+ }) : v({
1400
1562
  direction: "down",
1401
- stepSize: X
1563
+ stepSize: $
1402
1564
  });
1403
- }, [p]);
1404
- return l(() => {
1405
- if (s) return s.addEventListener("wheel", m, { passive: !1 }), () => s.removeEventListener("wheel", m);
1406
- }, [s, m]), /* @__PURE__ */ S("div", {
1407
- css: De,
1565
+ }, [v]);
1566
+ return u(() => {
1567
+ if (f) return f.addEventListener("wheel", y, { passive: !1 }), () => f.removeEventListener("wheel", y);
1568
+ }, [f, y]), /* @__PURE__ */ C("div", {
1569
+ css: Fe,
1408
1570
  style: { ...a ? {
1409
1571
  opacity: "0",
1410
1572
  pointerEvents: "none"
1411
1573
  } : {} },
1412
- children: [/* @__PURE__ */ x(ge, {}), /* @__PURE__ */ S("div", {
1574
+ children: [/* @__PURE__ */ S(ve, {}), /* @__PURE__ */ C("div", {
1413
1575
  className: "actions",
1414
- children: [/* @__PURE__ */ S("div", {
1576
+ children: [/* @__PURE__ */ C("div", {
1415
1577
  className: "left",
1416
1578
  children: [
1417
- /* @__PURE__ */ x(q, {
1579
+ /* @__PURE__ */ S(K, {
1418
1580
  id: "play",
1419
1581
  tooltipPlace: "top-start",
1420
- text: /* @__PURE__ */ x("button", {
1582
+ text: /* @__PURE__ */ S("button", {
1421
1583
  className: "play",
1422
1584
  type: "button",
1423
1585
  onClick: () => e.togglePaused(),
1424
- children: x(d ? k : t ? O : D, {})
1586
+ children: S(_ ? A : t ? k : O, {})
1425
1587
  }),
1426
- toolTipText: /* @__PURE__ */ x("span", { children: d ? "Replay (k)" : t ? "Play (k)" : "Pause (k)" })
1588
+ toolTipText: /* @__PURE__ */ S("span", { children: _ ? "Replay (k)" : t ? "Play (k)" : "Pause (k)" })
1427
1589
  }),
1428
- /* @__PURE__ */ x(Ee, { ref: u }),
1429
- /* @__PURE__ */ x("div", {
1590
+ /* @__PURE__ */ S(Me, { ref: m }),
1591
+ /* @__PURE__ */ S("div", {
1430
1592
  className: "time",
1431
- children: pe(n, r)
1593
+ children: he(n, r)
1432
1594
  })
1433
1595
  ]
1434
- }), /* @__PURE__ */ S("div", {
1596
+ }), /* @__PURE__ */ C("div", {
1435
1597
  className: "right",
1436
1598
  children: [
1437
- /* @__PURE__ */ x(xe, {}),
1438
- o ? /* @__PURE__ */ x(q, {
1599
+ /* @__PURE__ */ S(Oe, {}),
1600
+ /* @__PURE__ */ S(Ee, {}),
1601
+ o ? /* @__PURE__ */ S(K, {
1439
1602
  id: "picture-in-picture",
1440
- text: /* @__PURE__ */ x("button", {
1603
+ tooltipPlace: "top-end",
1604
+ text: /* @__PURE__ */ S("button", {
1441
1605
  className: "picture-in-picture",
1442
1606
  type: "button",
1443
1607
  onClick: o,
1444
- children: /* @__PURE__ */ x("img", { src: _e })
1608
+ disabled: h && !g,
1609
+ "aria-label": h ? "Put the subtitles in the video" : "Picture in picture",
1610
+ "aria-pressed": h ? c : void 0,
1611
+ children: h ? /* @__PURE__ */ S(Se, {}) : /* @__PURE__ */ S("img", {
1612
+ src: ye,
1613
+ alt: ""
1614
+ })
1445
1615
  }),
1446
- toolTipText: /* @__PURE__ */ x("span", { children: "Picture in picture" })
1616
+ toolTipText: /* @__PURE__ */ C("span", {
1617
+ css: Pe,
1618
+ children: [/* @__PURE__ */ S("span", {
1619
+ className: "lead",
1620
+ children: h ? g ? c ? "Subtitles are in the picture" : "Put the subtitles in the picture" : "This file has no subtitles" : "Picture in picture"
1621
+ }), h && g ? /* @__PURE__ */ S("span", {
1622
+ className: "hint",
1623
+ children: "Then hover the video and click your browser's own pop out button"
1624
+ }) : null]
1625
+ })
1447
1626
  }) : null,
1448
- /* @__PURE__ */ x(q, {
1627
+ /* @__PURE__ */ S(K, {
1449
1628
  id: "full-screen",
1450
1629
  tooltipPlace: "top-end",
1451
- text: /* @__PURE__ */ x("button", {
1630
+ text: /* @__PURE__ */ S("button", {
1452
1631
  className: "full-screen",
1453
1632
  type: "button",
1454
1633
  onClick: () => e.toggleFullscreen(),
1455
- children: x(i ? E : T, {})
1634
+ children: S(i ? D : E, {})
1456
1635
  }),
1457
- toolTipText: /* @__PURE__ */ x("span", { children: i ? "Exit full screen (f)" : "Full screen (f)" })
1636
+ toolTipText: /* @__PURE__ */ S("span", { children: i ? "Exit full screen (f)" : "Full screen (f)" })
1458
1637
  })
1459
1638
  ]
1460
1639
  })]
1461
1640
  })]
1462
1641
  });
1463
- }, ke = 3e3, Ae = p`
1642
+ }, Le = 9e3, Re = m`
1643
+ position: absolute;
1644
+ inset: 0;
1645
+ z-index: 2;
1646
+ pointer-events: none;
1647
+
1648
+ .card {
1649
+ position: absolute;
1650
+ /* Where Firefox draws its own toggle: right aligned, a little past the middle of the height. */
1651
+ top: 52%;
1652
+ right: calc(7 * var(--mp-unit));
1653
+ transform: translateY(-50%);
1654
+
1655
+ display: flex;
1656
+ align-items: center;
1657
+ gap: calc(1.2 * var(--mp-unit));
1658
+
1659
+ max-width: min(calc(42 * var(--mp-unit)), 60%);
1660
+ padding: calc(1.4 * var(--mp-unit)) calc(1.8 * var(--mp-unit));
1661
+ border-radius: calc(0.8 * var(--mp-unit));
1662
+ background-color: rgba(20, 20, 22, 0.94);
1663
+ box-shadow: 0 0 calc(2 * var(--mp-unit)) rgba(0, 0, 0, 0.6);
1664
+
1665
+ opacity: 0;
1666
+ transition: opacity 0.25s ease;
1667
+ }
1668
+
1669
+ &.show .card {
1670
+ opacity: 1;
1671
+ }
1672
+
1673
+ .words {
1674
+ display: flex;
1675
+ flex-direction: column;
1676
+ gap: calc(0.3 * var(--mp-unit));
1677
+ }
1678
+
1679
+ .title {
1680
+ ${B.bMedium.bold}
1681
+ color: #fff;
1682
+ }
1683
+
1684
+ .body {
1685
+ ${B.bSmall.regular}
1686
+ color: rgba(255, 255, 255, 0.75);
1687
+ }
1688
+
1689
+ /* Points at the edge the browser's control lives on, which is the whole message. */
1690
+ .arrow {
1691
+ flex: none;
1692
+ font-size: calc(2.6 * var(--mp-unit));
1693
+ line-height: 1;
1694
+ color: #6EA8FE;
1695
+ }
1696
+ `, ze = () => {
1697
+ let e = F((e) => e.burnedInSubtitles), t = F((e) => e.pictureInPictureMode), [n, r] = p(!1);
1698
+ return u(() => {
1699
+ if (t !== "burn-in" || !e) {
1700
+ r(!1);
1701
+ return;
1702
+ }
1703
+ r(!0);
1704
+ let n = setTimeout(() => r(!1), Le);
1705
+ return () => clearTimeout(n);
1706
+ }, [t, e]), t !== "burn-in" || !e ? null : /* @__PURE__ */ S("div", {
1707
+ css: Re,
1708
+ className: n ? "show" : "",
1709
+ role: "status",
1710
+ children: /* @__PURE__ */ C("div", {
1711
+ className: "card",
1712
+ children: [/* @__PURE__ */ C("div", {
1713
+ className: "words",
1714
+ children: [/* @__PURE__ */ S("div", {
1715
+ className: "title",
1716
+ children: "Subtitles are in the picture"
1717
+ }), /* @__PURE__ */ S("div", {
1718
+ className: "body",
1719
+ children: "Now hover the video and click your browser's own pop out button"
1720
+ })]
1721
+ }), /* @__PURE__ */ S("div", {
1722
+ className: "arrow",
1723
+ "aria-hidden": "true",
1724
+ children: "→"
1725
+ })]
1726
+ })
1727
+ });
1728
+ }, Be = 3e3, Ve = m`
1464
1729
  position: absolute;
1465
1730
  inset: 0;
1466
1731
  z-index: 2;
@@ -1471,7 +1736,7 @@ position: relative;
1471
1736
  hoverable while faded out, popping a tooltip over nothing. It cascades where pointer-events does
1472
1737
  not, and transitioning it holds the item on screen for the length of the fade. */
1473
1738
  transition: opacity 0.1s cubic-bezier(.4,0,1,1), visibility 0.1s;
1474
- `, je = p`
1739
+ `, He = m`
1475
1740
  position: relative;
1476
1741
  background-color: black;
1477
1742
  display: flex;
@@ -1503,38 +1768,38 @@ position: relative;
1503
1768
  &.hide {
1504
1769
  cursor: none;
1505
1770
  }
1506
- `, Q = (e, t = "") => a.toArray(e).flatMap((e, n) => {
1507
- let r = `${t}${s(e) && e.key != null ? e.key : n}`;
1508
- return s(e) && e.type === o ? Q(e.props.children, `${r}/`) : [{
1771
+ `, Ue = (e, t = "") => o.toArray(e).flatMap((e, n) => {
1772
+ let r = `${t}${c(e) && e.key != null ? e.key : n}`;
1773
+ return c(e) && e.type === s ? Ue(e.props.children, `${r}/`) : [{
1509
1774
  key: r,
1510
1775
  item: e
1511
1776
  }];
1512
- }), Me = ({ ref: e, onVideoRef: t, onCanvasRef: n, overlay: r, controls: i, children: a }) => {
1513
- let o = F(), s = F((e) => e.hideUI), c = F((e) => e.setHideUI), u = d(void 0), f = d("mouse");
1514
- l(() => () => clearTimeout(u.current), []);
1777
+ }), We = ({ ref: e, onVideoRef: t, onCanvasRef: n, overlay: r, controls: i, children: a }) => {
1778
+ let o = F(), s = F((e) => e.hideUI), c = F((e) => e.setHideUI), l = f(void 0), d = f("mouse");
1779
+ u(() => () => clearTimeout(l.current), []);
1515
1780
  let p = () => {
1516
- c(!1), clearTimeout(u.current), u.current = setTimeout(() => c(!0), ke);
1781
+ c(!1), clearTimeout(l.current), l.current = setTimeout(() => c(!0), Be);
1517
1782
  };
1518
- return /* @__PURE__ */ S("div", {
1519
- css: je,
1783
+ return /* @__PURE__ */ C("div", {
1784
+ css: He,
1520
1785
  ref: e,
1521
1786
  onPointerMove: (e) => {
1522
- f.current = e.pointerType, e.pointerType === "mouse" && p();
1787
+ d.current = e.pointerType, e.pointerType === "mouse" && p();
1523
1788
  },
1524
1789
  onPointerDown: (e) => {
1525
- f.current = e.pointerType;
1790
+ d.current = e.pointerType;
1526
1791
  },
1527
1792
  onMouseOut: (e) => {
1528
1793
  let t = e.relatedTarget;
1529
1794
  if (t && e.currentTarget.contains(t)) return;
1530
1795
  let { left: n, right: r, top: i, bottom: a } = e.currentTarget.getBoundingClientRect();
1531
- e.clientX >= n && e.clientX < r && e.clientY >= i && e.clientY < a || (clearTimeout(u.current), c(!0));
1796
+ e.clientX >= n && e.clientX < r && e.clientY >= i && e.clientY < a || (clearTimeout(l.current), c(!0));
1532
1797
  },
1533
1798
  className: s ? "hide" : "",
1534
1799
  children: [
1535
- /* @__PURE__ */ x(fe, { onCanvasRef: n }),
1536
- Q(r).map(({ key: e, item: t }) => /* @__PURE__ */ x("div", {
1537
- css: Ae,
1800
+ /* @__PURE__ */ S(me, { onCanvasRef: n }),
1801
+ Ue(r).map(({ key: e, item: t }) => /* @__PURE__ */ S("div", {
1802
+ css: Ve,
1538
1803
  style: { ...s ? {
1539
1804
  opacity: "0",
1540
1805
  visibility: "hidden",
@@ -1542,89 +1807,94 @@ position: relative;
1542
1807
  } : {} },
1543
1808
  children: t
1544
1809
  }, e)),
1545
- i === !1 ? null : /* @__PURE__ */ x(Oe, {}),
1546
- /* @__PURE__ */ S("div", {
1810
+ i === !1 ? null : /* @__PURE__ */ S(Ie, {}),
1811
+ /* @__PURE__ */ S(ze, {}),
1812
+ /* @__PURE__ */ C("div", {
1547
1813
  className: "video",
1548
1814
  onClick: () => {
1549
- if (f.current === "mouse") {
1815
+ if (d.current === "mouse") {
1550
1816
  o.togglePaused();
1551
1817
  return;
1552
1818
  }
1553
- s ? p() : (clearTimeout(u.current), c(!0));
1819
+ s ? p() : (clearTimeout(l.current), c(!0));
1554
1820
  },
1555
- children: [t ? /* @__PURE__ */ x("video", {
1821
+ children: [t ? /* @__PURE__ */ S("video", {
1556
1822
  ref: t,
1557
1823
  playsInline: !0
1558
1824
  }) : null, a]
1559
1825
  })
1560
1826
  ]
1561
1827
  });
1562
- }, Ne = ({ options: e, children: t }) => {
1563
- let n = "media" in e ? e : null, r = n ? null : e, { title: i } = e, { size: a, downloadedRanges: o, publicPath: s, libavWorkerUrl: c, read: u, thumbnailRead: d, thumbnailsEnabled: p } = r ?? {}, m = _(), h = g(), [v, y] = f(null), [b, S] = f(null), C = n?.media ?? v;
1564
- l(() => (m?.(C), () => m?.(null)), [C, m]), ie(v, b, r);
1565
- let w = z({
1828
+ }, Ge = ({ options: e, children: t }) => {
1829
+ let n = "media" in e ? e : null, r = n ? null : e, { title: i } = e, { size: a, downloadedRanges: o, publicPath: s, libavWorkerUrl: c, read: l, thumbnailRead: d, thumbnailsEnabled: f } = r ?? {}, m = v(), h = _(), [g, y] = p(null), [b, x] = p(null), C = n?.media ?? g;
1830
+ u(() => (m?.(C), () => m?.(null)), [C, m]), oe(g, b, r);
1831
+ let w = R({
1566
1832
  publicPath: s,
1567
1833
  workerUrl: c,
1568
- length: p === !1 ? void 0 : a,
1569
- read: d ?? u,
1834
+ length: f === !1 ? void 0 : a,
1835
+ read: d ?? l,
1570
1836
  downloadedRanges: o
1571
- }), T = n?.thumbnails?.all ?? w, E = B(v, b), D = F((e) => e.setSourceState);
1572
- l(() => {
1573
- D({
1837
+ }), T = n?.thumbnails?.all ?? w, { toggle: E, mode: D, burnedIn: O } = z(g, b), k = F((e) => e.setSourceState);
1838
+ u(() => {
1839
+ k({
1574
1840
  title: i,
1575
1841
  size: a,
1576
1842
  downloadedRanges: o
1577
1843
  });
1578
1844
  }, [
1579
- D,
1845
+ k,
1580
1846
  i,
1581
1847
  a,
1582
1848
  o
1583
1849
  ]);
1584
- let O = n?.thumbnails?.at;
1585
- l(() => {
1586
- D({
1850
+ let A = n?.thumbnails?.at;
1851
+ u(() => {
1852
+ k({
1587
1853
  thumbnails: T,
1588
- thumbnailAt: O,
1589
- togglePictureInPicture: E
1854
+ thumbnailAt: A,
1855
+ togglePictureInPicture: E,
1856
+ pictureInPictureMode: D,
1857
+ burnedInSubtitles: O
1590
1858
  });
1591
1859
  }, [
1592
- D,
1860
+ k,
1593
1861
  T,
1594
- O,
1595
- E
1862
+ A,
1863
+ E,
1864
+ D,
1865
+ O
1596
1866
  ]);
1597
- let k = n?.subtitles?.selection, A = n?.audioTracks?.selection;
1598
- return l(() => {
1599
- k && D({
1600
- subtitleTracks: k.options.map(({ id: e, label: t, disabled: n }) => ({
1867
+ let j = n?.subtitles?.selection, M = n?.audioTracks?.selection;
1868
+ return u(() => {
1869
+ j && k({
1870
+ subtitleTracks: j.options.map(({ id: e, label: t, disabled: n }) => ({
1601
1871
  id: e,
1602
1872
  label: t,
1603
1873
  disabled: n
1604
1874
  })),
1605
- selectedSubtitleTrack: k.selectedId ?? void 0,
1606
- selectSubtitleTrack: (e) => k.select(e == null ? null : String(e)),
1607
- subtitleOffLabel: k.offLabel
1875
+ selectedSubtitleTrack: j.selectedId ?? void 0,
1876
+ selectSubtitleTrack: (e) => j.select(e == null ? null : String(e)),
1877
+ subtitleOffLabel: j.offLabel
1608
1878
  });
1609
- }, [D, k]), l(() => {
1610
- A && D({
1611
- audioTracks: A.options.map(({ id: e, label: t, disabled: n }) => ({
1879
+ }, [k, j]), u(() => {
1880
+ M && k({
1881
+ audioTracks: M.options.map(({ id: e, label: t, disabled: n }) => ({
1612
1882
  id: e,
1613
1883
  label: t,
1614
1884
  disabled: n
1615
1885
  })),
1616
- selectedAudioTrack: A.selectedId ?? void 0,
1617
- selectAudioTrack: (e) => A.select(String(e))
1886
+ selectedAudioTrack: M.selectedId ?? void 0,
1887
+ selectAudioTrack: (e) => M.select(String(e))
1618
1888
  });
1619
- }, [D, A]), /* @__PURE__ */ x(Me, {
1889
+ }, [k, M]), /* @__PURE__ */ S(We, {
1620
1890
  ref: h,
1621
1891
  onVideoRef: n ? void 0 : y,
1622
- onCanvasRef: S,
1892
+ onCanvasRef: x,
1623
1893
  overlay: e.overlay,
1624
1894
  controls: e.controls,
1625
1895
  children: t
1626
1896
  });
1627
- }, Pe = p`
1897
+ }, Ke = m`
1628
1898
  /**
1629
1899
  * The chrome's whole scale, in one place.
1630
1900
  *
@@ -1636,6 +1906,45 @@ position: relative;
1636
1906
  */
1637
1907
  --mp-unit: 10px;
1638
1908
 
1909
+ /**
1910
+ * The chrome's own typeface, for exactly the reason the unit above exists.
1911
+ *
1912
+ * \`font-family\` inherits, and this library declared it nowhere, so every label drew in whatever the
1913
+ * embedding document happened to set, and in the UA's serif where it set nothing. Not hypothetical:
1914
+ * stub mounts the player in a second document, \`embed.html\`, which sets no font and loads no face,
1915
+ * and the entire settings menu came out in Times New Roman.
1916
+ *
1917
+ * Named faces only, no bundled webfont. The chrome is a handful of short labels, so a font request
1918
+ * on the critical path of a document whose job is to paint video buys a round trip and a flash of
1919
+ * unstyled text for nothing.
1920
+ *
1921
+ * Read through \`var()\` so a host with a brand face sets \`--mp-font-family\` on any ancestor and it
1922
+ * inherits in. A bare \`font-family\` on the host can no longer reach the chrome: this declaration is
1923
+ * on the player element itself and beats anything inherited.
1924
+ */
1925
+ font-family: var(
1926
+ --mp-font-family,
1927
+ system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
1928
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji'
1929
+ );
1930
+
1931
+ /**
1932
+ * The chrome's default ink, same argument again.
1933
+ *
1934
+ * Most text here names its own colour, but the two time readouts do not: the elapsed/duration pair
1935
+ * and the seekbar's hover time carry a font token and a black text-shadow and nothing else.
1936
+ * Inherited from a host that declares none that resolves to \`canvastext\`, which is black text under
1937
+ * a black halo on a dark gradient.
1938
+ */
1939
+ color: #fff;
1940
+
1941
+ /**
1942
+ * The settings menu scrolls, and a UA that has not been told the surface is dark paints that
1943
+ * scrollbar in its light theme: a white track down the side of a #1c1c1c menu. Declared here rather
1944
+ * than asked of the host, so it reaches the menu and nothing outside the player.
1945
+ */
1946
+ color-scheme: dark;
1947
+
1639
1948
  /**
1640
1949
  * The other half of owning the chrome's own scale.
1641
1950
  *
@@ -1655,17 +1964,17 @@ position: relative;
1655
1964
  height: 100%;
1656
1965
  width: 100%;
1657
1966
  overflow: hidden;
1658
- `, $ = (e) => /* @__PURE__ */ x("div", {
1659
- css: Pe,
1660
- children: /* @__PURE__ */ x(P.Provider, { children: /* @__PURE__ */ x(Ne, {
1967
+ `, qe = (e) => /* @__PURE__ */ S("div", {
1968
+ css: Ke,
1969
+ children: /* @__PURE__ */ S(P.Provider, { children: /* @__PURE__ */ S(Ge, {
1661
1970
  options: e,
1662
1971
  children: e.children
1663
1972
  }) })
1664
- }), Fe = (e) => !!e && typeof e == "object" && "at" in e, Ie = (e) => !!e && typeof e == "object" && "selection" in e, Le = ({ blob: e, name: t }) => ({
1973
+ }), Je = (e) => !!e && typeof e == "object" && "at" in e, Ye = (e) => !!e && typeof e == "object" && "selection" in e, Xe = ({ blob: e, name: t }) => ({
1665
1974
  length: e.size,
1666
1975
  name: t ?? (e instanceof File ? e.name : void 0),
1667
1976
  read: (t, n) => e.slice(t, t + n).arrayBuffer()
1668
- }), Re = async (e, t) => {
1977
+ }), Ze = async (e, t) => {
1669
1978
  let n = await fetch(e, {
1670
1979
  headers: { Range: "bytes=0-1" },
1671
1980
  credentials: t
@@ -1675,8 +1984,8 @@ position: relative;
1675
1984
  if (!Number.isFinite(i) || i <= 0) throw Error("The source did not report its length");
1676
1985
  if (!r && n.status !== 206) throw Error("The source does not support range requests");
1677
1986
  return i;
1678
- }, ze = async ({ url: e, length: t, name: n, credentials: r }) => {
1679
- let i = t ?? await Re(e, r);
1987
+ }, Qe = async ({ url: e, length: t, name: n, credentials: r }) => {
1988
+ let i = t ?? await Ze(e, r);
1680
1989
  return {
1681
1990
  length: i,
1682
1991
  name: n,
@@ -1689,9 +1998,9 @@ position: relative;
1689
1998
  return a.arrayBuffer();
1690
1999
  }
1691
2000
  };
1692
- }, Be = async (e) => {
1693
- if ("blob" in e) return Le(e);
1694
- if ("url" in e) return ze(e);
2001
+ }, $e = async (e) => {
2002
+ if ("blob" in e) return Xe(e);
2003
+ if ("url" in e) return Qe(e);
1695
2004
  if ("read" in e) return {
1696
2005
  length: e.length,
1697
2006
  name: e.name,
@@ -1700,4 +2009,4 @@ position: relative;
1700
2009
  throw Error(`Unknown source type: ${e}`);
1701
2010
  };
1702
2011
  //#endregion
1703
- export { $ as MediaPlayer, $ as default, P as Player, n as SUBTITLES_OFF, i as createPictureInPicture, r as createSubtitleRenderer, t as createThumbnailGenerator, Be as inputToRemuxerInput, Ie as isDelegatedTracks, Fe as isExternalThumbnails, N as sourceFeature, e as startPlayback, B as usePictureInPicture, F as usePlayer, z as useSeekThumbnails };
2012
+ export { qe as MediaPlayer, qe as default, P as Player, i as SUBTITLES_OFF, a as createPictureInPicture, t as createSubtitleRenderer, r as createThumbnailGenerator, $e as inputToRemuxerInput, Ye as isDelegatedTracks, Je as isExternalThumbnails, N as sourceFeature, e as startPlayback, z as usePictureInPicture, F as usePlayer, R as useSeekThumbnails };