@lightbird/core 0.8.0 → 0.9.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/dist/index.cjs CHANGED
@@ -765,14 +765,32 @@ function isHlsUrl(url) {
765
765
  if (HLS_MIME_HINTS.some((hint) => lower.includes(hint))) return true;
766
766
  return lower.split(/[?#]/)[0].endsWith(".m3u8");
767
767
  }
768
+ function parseHlsCodec(codec) {
769
+ if (!codec) return null;
770
+ switch (codec.slice(0, 4).toLowerCase()) {
771
+ case "avc1":
772
+ return "H.264 (AVC)";
773
+ case "hvc1":
774
+ case "hev1":
775
+ return "H.265 (HEVC)";
776
+ case "vp09":
777
+ return "VP9";
778
+ case "av01":
779
+ return "AV1";
780
+ default:
781
+ return codec;
782
+ }
783
+ }
768
784
  var HLSPlayer = class {
769
785
  constructor(url) {
770
786
  this.hls = null;
787
+ this.hlsCtor = null;
771
788
  this.url = url;
772
789
  this.playerFile = { url, qualityLevels: [] };
773
790
  }
774
791
  async initialize(videoElement) {
775
792
  const { default: HlsCtor } = await import('hls.js');
793
+ this.hlsCtor = HlsCtor;
776
794
  if (!HlsCtor.isSupported()) {
777
795
  videoElement.src = this.url;
778
796
  return this.playerFile;
@@ -818,6 +836,50 @@ var HLSPlayer = class {
818
836
  setQualityLevel(levelIndex) {
819
837
  if (this.hls) this.hls.currentLevel = levelIndex;
820
838
  }
839
+ /**
840
+ * HLS-specific metadata for the video info panel, derived from the active
841
+ * rendition. Returns an empty object before the manifest loads or on the
842
+ * native-HLS path (where hls.js is never instantiated).
843
+ */
844
+ getMetadata() {
845
+ const hls = this.hls;
846
+ if (!hls) return {};
847
+ const levels = hls.levels ?? [];
848
+ const activeIndex = hls.currentLevel >= 0 && hls.currentLevel < levels.length ? hls.currentLevel : 0;
849
+ const active = levels[activeIndex];
850
+ return {
851
+ container: "HLS",
852
+ videoCodec: parseHlsCodec(active?.videoCodec),
853
+ videoBitrate: active?.bitrate ?? null,
854
+ streamRenditions: levels.length,
855
+ audioTracks: (hls.audioTracks ?? []).map((track, index) => ({
856
+ index,
857
+ codec: track.audioCodec ?? null,
858
+ channels: null,
859
+ sampleRate: null,
860
+ language: track.lang ?? null,
861
+ bitrate: null
862
+ }))
863
+ };
864
+ }
865
+ /**
866
+ * Subscribe to HLS events that change the info-panel metadata (manifest
867
+ * parsed, quality level switched, audio tracks updated). Returns an
868
+ * unsubscribe function. A no-op on the native-HLS path.
869
+ */
870
+ onMetadataChange(callback) {
871
+ const hls = this.hls;
872
+ const HlsCtor = this.hlsCtor;
873
+ if (!hls || !HlsCtor) return () => {
874
+ };
875
+ const events = [
876
+ HlsCtor.Events.MANIFEST_PARSED,
877
+ HlsCtor.Events.LEVEL_SWITCHED,
878
+ HlsCtor.Events.AUDIO_TRACKS_UPDATED
879
+ ];
880
+ events.forEach((event) => hls.on(event, callback));
881
+ return () => events.forEach((event) => hls.off(event, callback));
882
+ }
821
883
  destroy() {
822
884
  if (this.hls) {
823
885
  this.hls.destroy();
@@ -1823,6 +1885,7 @@ exports.loadShortcuts = loadShortcuts;
1823
1885
  exports.matchesShortcut = matchesShortcut;
1824
1886
  exports.parseChaptersFromFFmpegLog = parseChaptersFromFFmpegLog;
1825
1887
  exports.parseChaptersFromVtt = parseChaptersFromVtt;
1888
+ exports.parseHlsCodec = parseHlsCodec;
1826
1889
  exports.parseM3U8 = parseM3U8;
1827
1890
  exports.parseMediaError = parseMediaError;
1828
1891
  exports.resetFFmpeg = resetFFmpeg;
package/dist/index.d.cts CHANGED
@@ -69,6 +69,8 @@ interface VideoMetadata {
69
69
  colorSpace: string | null;
70
70
  audioTracks: AudioTrackMeta[];
71
71
  subtitleTracks: SubtitleTrackMeta[];
72
+ /** Number of HLS/adaptive renditions, when playing an adaptive stream. */
73
+ streamRenditions?: number | null;
72
74
  }
73
75
  interface AudioTrackMeta {
74
76
  index: number;
@@ -196,16 +198,27 @@ interface VideoPlayer {
196
198
  * For all other players/paths this is already resolved when initialize() returns.
197
199
  */
198
200
  tracksReady?: Promise<void>;
201
+ /** HLS-only: metadata derived from the active rendition (see HLSPlayer). */
202
+ getMetadata?(): Partial<VideoMetadata>;
203
+ /** HLS-only: subscribe to stream events that change metadata. Returns an unsubscribe fn. */
204
+ onMetadataChange?(callback: () => void): () => void;
199
205
  }
200
206
  declare function createVideoPlayer(source: File | string, externalSubtitles?: File[], onProgress?: (progress: number) => void): VideoPlayer;
201
207
 
202
208
  /** True for HLS playlist URLs — a `.m3u8` path or an HLS MIME hint. */
203
209
  declare function isHlsUrl(url: string): boolean;
210
+ /**
211
+ * Map an hls.js MIME codec string (e.g. `avc1.640028`) to a human-friendly
212
+ * label by inspecting the leading four-character codec family. Unknown
213
+ * families fall back to the raw string; empty input yields `null`.
214
+ */
215
+ declare function parseHlsCodec(codec: string | null | undefined): string | null;
204
216
  /** Plays HLS (`.m3u8`) streams via hls.js, falling back to native HLS (Safari). */
205
217
  declare class HLSPlayer implements VideoPlayer {
206
218
  private readonly url;
207
219
  private readonly playerFile;
208
220
  private hls;
221
+ private hlsCtor;
209
222
  constructor(url: string);
210
223
  initialize(videoElement: HTMLVideoElement): Promise<HLSPlayerFile>;
211
224
  getAudioTracks(): AudioTrack[];
@@ -216,6 +229,18 @@ declare class HLSPlayer implements VideoPlayer {
216
229
  getQualityLevels(): QualityLevel[];
217
230
  /** Pins a quality level; `-1` restores automatic (ABR) selection. */
218
231
  setQualityLevel(levelIndex: number): void;
232
+ /**
233
+ * HLS-specific metadata for the video info panel, derived from the active
234
+ * rendition. Returns an empty object before the manifest loads or on the
235
+ * native-HLS path (where hls.js is never instantiated).
236
+ */
237
+ getMetadata(): Partial<VideoMetadata>;
238
+ /**
239
+ * Subscribe to HLS events that change the info-panel metadata (manifest
240
+ * parsed, quality level switched, audio tracks updated). Returns an
241
+ * unsubscribe function. A no-op on the native-HLS path.
242
+ */
243
+ onMetadataChange(callback: () => void): () => void;
219
244
  destroy(): void;
220
245
  static isCompatible(url: string): boolean;
221
246
  }
@@ -495,4 +520,4 @@ declare function resetFFmpeg(): void;
495
520
  */
496
521
  declare function getLanguageName(code?: string | null): string | undefined;
497
522
 
498
- export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, type ExportFrameOptions, FLAG_MAGNET_LINK, HLSPlayer, type HLSPlayerFile, type LightBirdConfig, MKVPlayer, type MKVPlayerFile, type MediaErrorType, type ParsedMediaError, type PlaylistItem, type ProcessedFile, ProgressEstimator, type QualityLevel, type ShortcutAction, type ShortcutBinding, SimplePlayer, type SimplePlayerFile, type Subtitle, SubtitleConverter, type SubtitleCue, type SubtitleTrackMeta, type TorrentStatus, UniversalSubtitleManager, VIDEO_EXTENSIONS, type VideoFilters, type VideoMetadata, type VideoPlayer, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
523
+ export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, type ExportFrameOptions, FLAG_MAGNET_LINK, HLSPlayer, type HLSPlayerFile, type LightBirdConfig, MKVPlayer, type MKVPlayerFile, type MediaErrorType, type ParsedMediaError, type PlaylistItem, type ProcessedFile, ProgressEstimator, type QualityLevel, type ShortcutAction, type ShortcutBinding, SimplePlayer, type SimplePlayerFile, type Subtitle, SubtitleConverter, type SubtitleCue, type SubtitleTrackMeta, type TorrentStatus, UniversalSubtitleManager, VIDEO_EXTENSIONS, type VideoFilters, type VideoMetadata, type VideoPlayer, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseHlsCodec, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
package/dist/index.d.ts CHANGED
@@ -69,6 +69,8 @@ interface VideoMetadata {
69
69
  colorSpace: string | null;
70
70
  audioTracks: AudioTrackMeta[];
71
71
  subtitleTracks: SubtitleTrackMeta[];
72
+ /** Number of HLS/adaptive renditions, when playing an adaptive stream. */
73
+ streamRenditions?: number | null;
72
74
  }
73
75
  interface AudioTrackMeta {
74
76
  index: number;
@@ -196,16 +198,27 @@ interface VideoPlayer {
196
198
  * For all other players/paths this is already resolved when initialize() returns.
197
199
  */
198
200
  tracksReady?: Promise<void>;
201
+ /** HLS-only: metadata derived from the active rendition (see HLSPlayer). */
202
+ getMetadata?(): Partial<VideoMetadata>;
203
+ /** HLS-only: subscribe to stream events that change metadata. Returns an unsubscribe fn. */
204
+ onMetadataChange?(callback: () => void): () => void;
199
205
  }
200
206
  declare function createVideoPlayer(source: File | string, externalSubtitles?: File[], onProgress?: (progress: number) => void): VideoPlayer;
201
207
 
202
208
  /** True for HLS playlist URLs — a `.m3u8` path or an HLS MIME hint. */
203
209
  declare function isHlsUrl(url: string): boolean;
210
+ /**
211
+ * Map an hls.js MIME codec string (e.g. `avc1.640028`) to a human-friendly
212
+ * label by inspecting the leading four-character codec family. Unknown
213
+ * families fall back to the raw string; empty input yields `null`.
214
+ */
215
+ declare function parseHlsCodec(codec: string | null | undefined): string | null;
204
216
  /** Plays HLS (`.m3u8`) streams via hls.js, falling back to native HLS (Safari). */
205
217
  declare class HLSPlayer implements VideoPlayer {
206
218
  private readonly url;
207
219
  private readonly playerFile;
208
220
  private hls;
221
+ private hlsCtor;
209
222
  constructor(url: string);
210
223
  initialize(videoElement: HTMLVideoElement): Promise<HLSPlayerFile>;
211
224
  getAudioTracks(): AudioTrack[];
@@ -216,6 +229,18 @@ declare class HLSPlayer implements VideoPlayer {
216
229
  getQualityLevels(): QualityLevel[];
217
230
  /** Pins a quality level; `-1` restores automatic (ABR) selection. */
218
231
  setQualityLevel(levelIndex: number): void;
232
+ /**
233
+ * HLS-specific metadata for the video info panel, derived from the active
234
+ * rendition. Returns an empty object before the manifest loads or on the
235
+ * native-HLS path (where hls.js is never instantiated).
236
+ */
237
+ getMetadata(): Partial<VideoMetadata>;
238
+ /**
239
+ * Subscribe to HLS events that change the info-panel metadata (manifest
240
+ * parsed, quality level switched, audio tracks updated). Returns an
241
+ * unsubscribe function. A no-op on the native-HLS path.
242
+ */
243
+ onMetadataChange(callback: () => void): () => void;
219
244
  destroy(): void;
220
245
  static isCompatible(url: string): boolean;
221
246
  }
@@ -495,4 +520,4 @@ declare function resetFFmpeg(): void;
495
520
  */
496
521
  declare function getLanguageName(code?: string | null): string | undefined;
497
522
 
498
- export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, type ExportFrameOptions, FLAG_MAGNET_LINK, HLSPlayer, type HLSPlayerFile, type LightBirdConfig, MKVPlayer, type MKVPlayerFile, type MediaErrorType, type ParsedMediaError, type PlaylistItem, type ProcessedFile, ProgressEstimator, type QualityLevel, type ShortcutAction, type ShortcutBinding, SimplePlayer, type SimplePlayerFile, type Subtitle, SubtitleConverter, type SubtitleCue, type SubtitleTrackMeta, type TorrentStatus, UniversalSubtitleManager, VIDEO_EXTENSIONS, type VideoFilters, type VideoMetadata, type VideoPlayer, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
523
+ export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, type ExportFrameOptions, FLAG_MAGNET_LINK, HLSPlayer, type HLSPlayerFile, type LightBirdConfig, MKVPlayer, type MKVPlayerFile, type MediaErrorType, type ParsedMediaError, type PlaylistItem, type ProcessedFile, ProgressEstimator, type QualityLevel, type ShortcutAction, type ShortcutBinding, SimplePlayer, type SimplePlayerFile, type Subtitle, SubtitleConverter, type SubtitleCue, type SubtitleTrackMeta, type TorrentStatus, UniversalSubtitleManager, VIDEO_EXTENSIONS, type VideoFilters, type VideoMetadata, type VideoPlayer, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseHlsCodec, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
package/dist/index.js CHANGED
@@ -762,14 +762,32 @@ function isHlsUrl(url) {
762
762
  if (HLS_MIME_HINTS.some((hint) => lower.includes(hint))) return true;
763
763
  return lower.split(/[?#]/)[0].endsWith(".m3u8");
764
764
  }
765
+ function parseHlsCodec(codec) {
766
+ if (!codec) return null;
767
+ switch (codec.slice(0, 4).toLowerCase()) {
768
+ case "avc1":
769
+ return "H.264 (AVC)";
770
+ case "hvc1":
771
+ case "hev1":
772
+ return "H.265 (HEVC)";
773
+ case "vp09":
774
+ return "VP9";
775
+ case "av01":
776
+ return "AV1";
777
+ default:
778
+ return codec;
779
+ }
780
+ }
765
781
  var HLSPlayer = class {
766
782
  constructor(url) {
767
783
  this.hls = null;
784
+ this.hlsCtor = null;
768
785
  this.url = url;
769
786
  this.playerFile = { url, qualityLevels: [] };
770
787
  }
771
788
  async initialize(videoElement) {
772
789
  const { default: HlsCtor } = await import('hls.js');
790
+ this.hlsCtor = HlsCtor;
773
791
  if (!HlsCtor.isSupported()) {
774
792
  videoElement.src = this.url;
775
793
  return this.playerFile;
@@ -815,6 +833,50 @@ var HLSPlayer = class {
815
833
  setQualityLevel(levelIndex) {
816
834
  if (this.hls) this.hls.currentLevel = levelIndex;
817
835
  }
836
+ /**
837
+ * HLS-specific metadata for the video info panel, derived from the active
838
+ * rendition. Returns an empty object before the manifest loads or on the
839
+ * native-HLS path (where hls.js is never instantiated).
840
+ */
841
+ getMetadata() {
842
+ const hls = this.hls;
843
+ if (!hls) return {};
844
+ const levels = hls.levels ?? [];
845
+ const activeIndex = hls.currentLevel >= 0 && hls.currentLevel < levels.length ? hls.currentLevel : 0;
846
+ const active = levels[activeIndex];
847
+ return {
848
+ container: "HLS",
849
+ videoCodec: parseHlsCodec(active?.videoCodec),
850
+ videoBitrate: active?.bitrate ?? null,
851
+ streamRenditions: levels.length,
852
+ audioTracks: (hls.audioTracks ?? []).map((track, index) => ({
853
+ index,
854
+ codec: track.audioCodec ?? null,
855
+ channels: null,
856
+ sampleRate: null,
857
+ language: track.lang ?? null,
858
+ bitrate: null
859
+ }))
860
+ };
861
+ }
862
+ /**
863
+ * Subscribe to HLS events that change the info-panel metadata (manifest
864
+ * parsed, quality level switched, audio tracks updated). Returns an
865
+ * unsubscribe function. A no-op on the native-HLS path.
866
+ */
867
+ onMetadataChange(callback) {
868
+ const hls = this.hls;
869
+ const HlsCtor = this.hlsCtor;
870
+ if (!hls || !HlsCtor) return () => {
871
+ };
872
+ const events = [
873
+ HlsCtor.Events.MANIFEST_PARSED,
874
+ HlsCtor.Events.LEVEL_SWITCHED,
875
+ HlsCtor.Events.AUDIO_TRACKS_UPDATED
876
+ ];
877
+ events.forEach((event) => hls.on(event, callback));
878
+ return () => events.forEach((event) => hls.off(event, callback));
879
+ }
818
880
  destroy() {
819
881
  if (this.hls) {
820
882
  this.hls.destroy();
@@ -1779,4 +1841,4 @@ function resetFFmpeg() {
1779
1841
  loading = null;
1780
1842
  }
1781
1843
 
1782
- export { ASSRenderer, CancellationError, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, FLAG_MAGNET_LINK, HLSPlayer, MKVPlayer, ProgressEstimator, SimplePlayer, SubtitleConverter, UniversalSubtitleManager, VIDEO_EXTENSIONS, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
1844
+ export { ASSRenderer, CancellationError, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, FLAG_MAGNET_LINK, HLSPlayer, MKVPlayer, ProgressEstimator, SimplePlayer, SubtitleConverter, UniversalSubtitleManager, VIDEO_EXTENSIONS, acceptDisclaimer, applyOffsetToVtt, captureFrameAt, captureVideoThumbnail, configureLightBird, createOffsetVttUrl, createVideoPlayer, destroyWebTorrentClient, downloadDataUrl, exportPlaylist, exportVideoFrame, extractNativeMetadata, formatShortcutKey, frameExportFilename, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseHlsCodec, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
@@ -81,6 +81,8 @@ interface VideoMetadata {
81
81
  colorSpace: string | null;
82
82
  audioTracks: AudioTrackMeta[];
83
83
  subtitleTracks: SubtitleTrackMeta[];
84
+ /** Number of HLS/adaptive renditions, when playing an adaptive stream. */
85
+ streamRenditions?: number | null;
84
86
  }
85
87
  interface AudioTrackMeta {
86
88
  index: number;
@@ -264,6 +266,10 @@ interface VideoPlayer {
264
266
  * For all other players/paths this is already resolved when initialize() returns.
265
267
  */
266
268
  tracksReady?: Promise<void>;
269
+ /** HLS-only: metadata derived from the active rendition (see HLSPlayer). */
270
+ getMetadata?(): Partial<VideoMetadata>;
271
+ /** HLS-only: subscribe to stream events that change metadata. Returns an unsubscribe fn. */
272
+ onMetadataChange?(callback: () => void): () => void;
267
273
  }
268
274
 
269
275
  declare function useChapters(videoRef: RefObject<HTMLVideoElement>, playerRef: RefObject<VideoPlayer | null>): {
@@ -81,6 +81,8 @@ interface VideoMetadata {
81
81
  colorSpace: string | null;
82
82
  audioTracks: AudioTrackMeta[];
83
83
  subtitleTracks: SubtitleTrackMeta[];
84
+ /** Number of HLS/adaptive renditions, when playing an adaptive stream. */
85
+ streamRenditions?: number | null;
84
86
  }
85
87
  interface AudioTrackMeta {
86
88
  index: number;
@@ -264,6 +266,10 @@ interface VideoPlayer {
264
266
  * For all other players/paths this is already resolved when initialize() returns.
265
267
  */
266
268
  tracksReady?: Promise<void>;
269
+ /** HLS-only: metadata derived from the active rendition (see HLSPlayer). */
270
+ getMetadata?(): Partial<VideoMetadata>;
271
+ /** HLS-only: subscribe to stream events that change metadata. Returns an unsubscribe fn. */
272
+ onMetadataChange?(callback: () => void): () => void;
267
273
  }
268
274
 
269
275
  declare function useChapters(videoRef: RefObject<HTMLVideoElement>, playerRef: RefObject<VideoPlayer | null>): {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightbird/core",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Client-side video player engine. Plays MKV, MP4, WebM with full subtitle, audio track, and chapter support. No server required.",
5
5
  "license": "MIT",
6
6
  "author": "Punyam Singh",