avbridge 2.5.0 → 2.6.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/CHANGELOG.md CHANGED
@@ -4,6 +4,47 @@ All notable changes to **avbridge.js** are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
5
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.6.0]
8
+
9
+ `<avbridge-player>` polish release. Four targeted ergonomics upgrades.
10
+
11
+ ### Added
12
+
13
+ - **Typed `addEventListener` / `removeEventListener` overloads** on both
14
+ `<avbridge-video>` and `<avbridge-player>`. Consumers using avbridge
15
+ custom events (`ready`, `strategychange`, `trackschange`, `timeupdate`,
16
+ `error`, etc.) now receive a typed `CustomEvent<Detail>` without the
17
+ `as unknown as CustomEvent` cast tax. Standard HTMLMediaElement events
18
+ (`play`, `pause`, `seeking`, etc.) retain their native typing via
19
+ `HTMLElementEventMap`. New type: `AvbridgeVideoElementEventMap`.
20
+ - **Drag-and-drop file input** on `<avbridge-player>`. Drop a video file
21
+ onto the player and it loads + plays, matching the demo's file-picker
22
+ flow. Visual dashed-border feedback during dragover (stylable via
23
+ `.avp-dragover`).
24
+ - **`<track>` children parsing.** Light-DOM `<track src="subs.vtt"
25
+ srclang="en">` children declared inside `<avbridge-player>` or
26
+ `<avbridge-video>` were already cloned into the shadow `<video>` for
27
+ native/remux strategies; they now also populate the subtitle list that
28
+ the player's settings menu renders. HTML-declared tracks get stable
29
+ IDs in the 10000+ range to avoid colliding with container-embedded
30
+ IDs. MutationObserver-driven — add or remove a `<track>` at any time
31
+ and the menu updates.
32
+ - **HTMLMediaElement parity — `readyState` and `seekable`** on canvas
33
+ strategies. Previously the inner `<video>` (with no `src`) returned
34
+ `readyState: 0` and empty `seekable` ranges for hybrid/fallback.
35
+ Now synthesized: `readyState` reflects frame+audio readiness,
36
+ `seekable` spans `[0, duration]` once probe completes. `buffered`
37
+ and `networkState` remain deferred — both need meaningful transport
38
+ state machinery.
39
+
40
+ ### Deprecated / Deferred
41
+
42
+ - `buffered` on canvas strategies still returns empty TimeRanges. Requires
43
+ decoder-position → media-time plumbing; tracked for a follow-up.
44
+ - `networkState` not yet exposed on the element. Needs a transport
45
+ state machine spanning probe → libav reader → decoder; out of scope
46
+ for this release.
47
+
7
48
  ## [2.5.0]
8
49
 
9
50
  The "legacy transcode breadth" release. avbridge.js can now transcode
@@ -1990,6 +1990,35 @@ async function loadBridge() {
1990
1990
  }
1991
1991
  }
1992
1992
 
1993
+ // src/util/time-ranges.ts
1994
+ function makeTimeRanges(ranges) {
1995
+ const frozen = ranges.slice();
1996
+ const impl = {
1997
+ get length() {
1998
+ return frozen.length;
1999
+ },
2000
+ start(index) {
2001
+ if (index < 0 || index >= frozen.length) {
2002
+ throw new DOMException(
2003
+ `TimeRanges.start: index ${index} out of range (length=${frozen.length})`,
2004
+ "IndexSizeError"
2005
+ );
2006
+ }
2007
+ return frozen[index][0];
2008
+ },
2009
+ end(index) {
2010
+ if (index < 0 || index >= frozen.length) {
2011
+ throw new DOMException(
2012
+ `TimeRanges.end: index ${index} out of range (length=${frozen.length})`,
2013
+ "IndexSizeError"
2014
+ );
2015
+ }
2016
+ return frozen[index][1];
2017
+ }
2018
+ };
2019
+ return impl;
2020
+ }
2021
+
1993
2022
  // src/strategies/hybrid/index.ts
1994
2023
  var READY_AUDIO_BUFFER_SECONDS = 0.3;
1995
2024
  var READY_TIMEOUT_SECONDS = 10;
@@ -2047,6 +2076,18 @@ async function createHybridSession(ctx, target, transport) {
2047
2076
  get: () => ctx.duration ?? NaN
2048
2077
  });
2049
2078
  }
2079
+ Object.defineProperty(target, "readyState", {
2080
+ configurable: true,
2081
+ get: () => {
2082
+ if (!renderer.hasFrames()) return 0;
2083
+ if (!audio.isPlaying() && audio.bufferAhead() <= 0 && !audio.isNoAudio()) return 1;
2084
+ return 2;
2085
+ }
2086
+ });
2087
+ Object.defineProperty(target, "seekable", {
2088
+ configurable: true,
2089
+ get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0 ? [[0, ctx.duration]] : [])
2090
+ });
2050
2091
  async function waitForBuffer() {
2051
2092
  const start = performance.now();
2052
2093
  while (true) {
@@ -2128,6 +2169,8 @@ async function createHybridSession(ctx, target, transport) {
2128
2169
  delete target.paused;
2129
2170
  delete target.volume;
2130
2171
  delete target.muted;
2172
+ delete target.readyState;
2173
+ delete target.seekable;
2131
2174
  } catch {
2132
2175
  }
2133
2176
  },
@@ -2648,6 +2691,18 @@ async function createFallbackSession(ctx, target, transport) {
2648
2691
  get: () => ctx.duration ?? NaN
2649
2692
  });
2650
2693
  }
2694
+ Object.defineProperty(target, "readyState", {
2695
+ configurable: true,
2696
+ get: () => {
2697
+ if (!renderer.hasFrames()) return 0;
2698
+ if (!audio.isPlaying() && audio.bufferAhead() <= 0 && !audio.isNoAudio()) return 1;
2699
+ return 2;
2700
+ }
2701
+ });
2702
+ Object.defineProperty(target, "seekable", {
2703
+ configurable: true,
2704
+ get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0 ? [[0, ctx.duration]] : [])
2705
+ });
2651
2706
  async function waitForBuffer() {
2652
2707
  const start = performance.now();
2653
2708
  let firstFrameAtMs = 0;
@@ -2750,6 +2805,8 @@ async function createFallbackSession(ctx, target, transport) {
2750
2805
  delete target.paused;
2751
2806
  delete target.volume;
2752
2807
  delete target.muted;
2808
+ delete target.readyState;
2809
+ delete target.seekable;
2753
2810
  } catch {
2754
2811
  }
2755
2812
  },
@@ -3309,5 +3366,5 @@ exports.NATIVE_VIDEO_CODECS = NATIVE_VIDEO_CODECS;
3309
3366
  exports.UnifiedPlayer = UnifiedPlayer;
3310
3367
  exports.classifyContext = classifyContext;
3311
3368
  exports.createPlayer = createPlayer;
3312
- //# sourceMappingURL=chunk-TBW26OPP.cjs.map
3313
- //# sourceMappingURL=chunk-TBW26OPP.cjs.map
3369
+ //# sourceMappingURL=chunk-6SOFJV44.cjs.map
3370
+ //# sourceMappingURL=chunk-6SOFJV44.cjs.map