@banou/media-player 0.10.11 → 0.10.12

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.
@@ -1,2 +1,2 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "../engine-_RCEvBvl.js";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "../engine-DKjUYAmJ.js";
2
2
  export { i as DEFAULT_BUFFER_SIZE, e as MediaElementError, a as SUBTITLES_OFF, u as createPictureInPicture, d as createSubtitleRenderer, c as createThumbnailGenerator, n as getTimeRanges, s as isMediaElementError, o as pictureInPictureMode, l as startPlayback, t as terminateRemuxer, r as updateSourceBuffer };
@@ -306,11 +306,11 @@ var i = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
306
306
  } finally {
307
307
  e === H && (I = !1);
308
308
  }
309
- }, ye = (e) => e >= de && !!me(), be = (e) => i(A).some((t) => t.start <= e + T && e < t.end), Y = (e) => {
309
+ }, ye = (e) => e >= de && be(e), be = (e) => i(A).some((t) => t.start <= e && e < t.end), Y = (e) => {
310
310
  let t = i(A).find((t) => t.start <= e + T && e < t.end);
311
311
  return t ? t.end - e : 0;
312
312
  }, xe = async (e) => {
313
- if (!N && !(Y(e) >= E)) {
313
+ if (!N && !(be(e) && Y(e) >= E)) {
314
314
  V = !1, R++, z = e;
315
315
  try {
316
316
  be(e) || await J(e);
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { l as e, n as t, o as n, r, s as i, t as a, u as o } from "./engine-_RCEvBvl.js";
1
+ import { l as e, n as t, o as n, r, s as i, t as a, u as o } from "./engine-DKjUYAmJ.js";
2
2
  import { Children as s, Fragment as c, isValidElement as l, useCallback as u, useEffect as d, useMemo as f, useRef as p, useState as m, useSyncExternalStore as h } from "react";
3
3
  import { css as g, keyframes as _ } from "@emotion/react";
4
4
  import { createPlayer as v, useContainerAttach as y, useMediaAttach as b } from "@videojs/react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@banou/media-player",
3
- "version": "0.10.11",
3
+ "version": "0.10.12",
4
4
  "description": "A video player for containers and codecs the browser cannot play natively, remuxed on the fly",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -102,7 +102,15 @@ const PRE_EVICT_TIGHT = -5
102
102
  const POST_EVICT_TIGHT = 20
103
103
  const MAX_APPEND_ATTEMPTS = 5
104
104
  const SOURCE_OPEN_TIMEOUT = 15_000
105
- // how far past the playhead a range may start and still count as the one holding it
105
+ /*
106
+ * How far past the playhead a range may start and still count as the one holding it, which decides how
107
+ * much to read and never whether to fetch.
108
+ *
109
+ * Firefox 151 reports a range from its first presented frame, the reorder delay past its keyframe: 82 ms
110
+ * on most fixtures and 166 ms on anime-chapters, at load and after every remuxer seek, where Chrome 153
111
+ * reports the keyframe itself. Without the slack a playhead paused at 0 reads the whole file, and a
112
+ * prepared seek to a keyframe builds no runway (measured 2026-10-11).
113
+ */
106
114
  const BOUNDARY_SLACK = 1
107
115
  /*
108
116
  * Seconds of data a seek target needs behind it before the playhead is allowed to move there.
@@ -451,11 +459,17 @@ export const startPlayback = async (options: PlaybackOptions): Promise<PlaybackC
451
459
  * seek, and playback would stall at the end of this range instead. At or after it, the bytes from
452
460
  * here to the read cursor are contiguous and reading simply carries on.
453
461
  */
454
- const alreadyPlayable = (time: number) => time >= lastSeekPosition && !!playheadRange()
462
+ const alreadyPlayable = (time: number) => time >= lastSeekPosition && playableAt(time)
455
463
 
456
- /** Whether a GIVEN time has data behind it, as opposed to whether the playhead does. */
464
+ /**
465
+ * Whether the element can play from a GIVEN time without a fetch.
466
+ *
467
+ * Exact. A seek that lands before a range waits there for good once the gap passes 60 to 90 ms in
468
+ * Chrome 153, or 250 to 300 ms in Firefox 151, so Firefox's reorder delay cannot be allowed for here
469
+ * and a target inside it costs a remuxer seek (24 fps fixtures, measured 2026-10-11).
470
+ */
457
471
  const playableAt = (time: number) =>
458
- getTimeRanges(sourceBuffer).some((r) => r.start <= time + BOUNDARY_SLACK && time < r.end)
472
+ getTimeRanges(sourceBuffer).some((r) => r.start <= time && time < r.end)
459
473
 
460
474
  /**
461
475
  * Put the data in place for a position the playhead has NOT moved to yet.
@@ -482,7 +496,7 @@ export const startPlayback = async (options: PlaybackOptions): Promise<PlaybackC
482
496
 
483
497
  const prepareSeek = async (time: number) => {
484
498
  if (destroyed) return
485
- if (runwayFrom(time) >= SEEK_RUNWAY) return
499
+ if (playableAt(time) && runwayFrom(time) >= SEEK_RUNWAY) return
486
500
  finished = false
487
501
  preparing++
488
502
  prepareTarget = time