@lightbird/ui 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
@@ -1436,6 +1436,7 @@ function VideoInfoPanel({ metadata, onClose }) {
1436
1436
  ["Frame Rate", metadata.frameRate ? `${metadata.frameRate} fps` : "\u2014"],
1437
1437
  ["Video Codec", metadata.videoCodec ?? "\u2014"],
1438
1438
  ["Video Bitrate", formatBitrate(metadata.videoBitrate)],
1439
+ ...metadata.streamRenditions ? [["Stream Renditions", `${metadata.streamRenditions} levels`]] : [],
1439
1440
  ...metadata.audioTracks.map(
1440
1441
  (t, i) => [
1441
1442
  `Audio ${i + 1}`,
@@ -1962,7 +1963,7 @@ var LightBirdPlayer = () => {
1962
1963
  getBrightness: () => filters.filters.brightness / 200,
1963
1964
  setBrightness: (v) => filters.setFilters({ ...filters.filters, brightness: Math.round(v * 200) })
1964
1965
  });
1965
- const { metadata: videoMetadata } = react.useVideoInfo(videoRef, playlist.currentItem?.file ?? null);
1966
+ const { metadata: videoMetadata, enrichMetadata } = react.useVideoInfo(videoRef, playlist.currentItem?.file ?? null);
1966
1967
  react.useProgressPersistence(videoRef, playlist.currentItem?.name ?? null);
1967
1968
  const { chapters, currentChapter, goToChapter } = react.useChapters(videoRef, playerRef);
1968
1969
  const magnetLinkEnabled = reactSdk.useBooleanFlagValue(core.FLAG_MAGNET_LINK, true);
@@ -2176,19 +2177,37 @@ var LightBirdPlayer = () => {
2176
2177
  if (item.type === "stream") {
2177
2178
  playerRef.current?.destroy();
2178
2179
  playerRef.current = null;
2179
- if (videoRef.current) videoRef.current.src = item.url;
2180
2180
  subtitles.reset();
2181
2181
  setAudioTracks([]);
2182
2182
  setActiveAudioTrack("0");
2183
2183
  isStreamRef.current = true;
2184
2184
  startStallDetection();
2185
+ if (core.isHlsUrl(item.url) && videoRef.current) {
2186
+ const player = core.createVideoPlayer(item.url);
2187
+ playerRef.current = player;
2188
+ player.initialize(videoRef.current).then(() => {
2189
+ const refresh = () => {
2190
+ if (playerRef.current !== player) return;
2191
+ enrichMetadata(player.getMetadata?.() ?? {});
2192
+ const tracks = player.getAudioTracks();
2193
+ setAudioTracks(tracks);
2194
+ setActiveAudioTrack((prev) => prev || tracks[0]?.id || "0");
2195
+ };
2196
+ player.onMetadataChange?.(refresh);
2197
+ refresh();
2198
+ }).catch((error) => {
2199
+ console.error(error);
2200
+ });
2201
+ } else if (videoRef.current) {
2202
+ videoRef.current.src = item.url;
2203
+ }
2185
2204
  } else if (item.file) {
2186
2205
  isStreamRef.current = false;
2187
2206
  stopStallDetection();
2188
2207
  const subs = subtitleFilesMapRef.current.get(item.name) ?? [];
2189
2208
  processFile(item.file, subs);
2190
2209
  }
2191
- }, [playlist.playlist, playlist.selectItem, subtitles, processFile]);
2210
+ }, [playlist.playlist, playlist.selectItem, subtitles, processFile, enrichMetadata]);
2192
2211
  const handleSkipToNext = React11.useCallback(() => {
2193
2212
  setPlayerError(null);
2194
2213
  clearRetryTimer();
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import { SortableContext, verticalListSortingStrategy, arrayMove, useSortable }
18
18
  import { CSS } from '@dnd-kit/utilities';
19
19
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
20
20
  import * as SelectPrimitive from '@radix-ui/react-select';
21
- import { exportPlaylist, formatShortcutKey, FLAG_MAGNET_LINK, loadShortcuts, ProgressEstimator, createVideoPlayer, CancellationError, hasAcceptedDisclaimer, acceptDisclaimer, exportVideoFrame, downloadDataUrl, frameExportFilename, initFeatureFlags, parseMediaError, captureVideoThumbnail, validateFile, parseM3U8, matchesShortcut, saveShortcuts, DEFAULT_SHORTCUTS } from '@lightbird/core';
21
+ import { exportPlaylist, formatShortcutKey, FLAG_MAGNET_LINK, loadShortcuts, ProgressEstimator, createVideoPlayer, CancellationError, isHlsUrl, hasAcceptedDisclaimer, acceptDisclaimer, exportVideoFrame, downloadDataUrl, frameExportFilename, initFeatureFlags, parseMediaError, captureVideoThumbnail, validateFile, parseM3U8, matchesShortcut, saveShortcuts, DEFAULT_SHORTCUTS } from '@lightbird/core';
22
22
  import * as DialogPrimitive from '@radix-ui/react-dialog';
23
23
  import { useBooleanFlagValue, OpenFeatureProvider } from '@openfeature/react-sdk';
24
24
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
@@ -1405,6 +1405,7 @@ function VideoInfoPanel({ metadata, onClose }) {
1405
1405
  ["Frame Rate", metadata.frameRate ? `${metadata.frameRate} fps` : "\u2014"],
1406
1406
  ["Video Codec", metadata.videoCodec ?? "\u2014"],
1407
1407
  ["Video Bitrate", formatBitrate(metadata.videoBitrate)],
1408
+ ...metadata.streamRenditions ? [["Stream Renditions", `${metadata.streamRenditions} levels`]] : [],
1408
1409
  ...metadata.audioTracks.map(
1409
1410
  (t, i) => [
1410
1411
  `Audio ${i + 1}`,
@@ -1931,7 +1932,7 @@ var LightBirdPlayer = () => {
1931
1932
  getBrightness: () => filters.filters.brightness / 200,
1932
1933
  setBrightness: (v) => filters.setFilters({ ...filters.filters, brightness: Math.round(v * 200) })
1933
1934
  });
1934
- const { metadata: videoMetadata } = useVideoInfo(videoRef, playlist.currentItem?.file ?? null);
1935
+ const { metadata: videoMetadata, enrichMetadata } = useVideoInfo(videoRef, playlist.currentItem?.file ?? null);
1935
1936
  useProgressPersistence(videoRef, playlist.currentItem?.name ?? null);
1936
1937
  const { chapters, currentChapter, goToChapter } = useChapters(videoRef, playerRef);
1937
1938
  const magnetLinkEnabled = useBooleanFlagValue(FLAG_MAGNET_LINK, true);
@@ -2145,19 +2146,37 @@ var LightBirdPlayer = () => {
2145
2146
  if (item.type === "stream") {
2146
2147
  playerRef.current?.destroy();
2147
2148
  playerRef.current = null;
2148
- if (videoRef.current) videoRef.current.src = item.url;
2149
2149
  subtitles.reset();
2150
2150
  setAudioTracks([]);
2151
2151
  setActiveAudioTrack("0");
2152
2152
  isStreamRef.current = true;
2153
2153
  startStallDetection();
2154
+ if (isHlsUrl(item.url) && videoRef.current) {
2155
+ const player = createVideoPlayer(item.url);
2156
+ playerRef.current = player;
2157
+ player.initialize(videoRef.current).then(() => {
2158
+ const refresh = () => {
2159
+ if (playerRef.current !== player) return;
2160
+ enrichMetadata(player.getMetadata?.() ?? {});
2161
+ const tracks = player.getAudioTracks();
2162
+ setAudioTracks(tracks);
2163
+ setActiveAudioTrack((prev) => prev || tracks[0]?.id || "0");
2164
+ };
2165
+ player.onMetadataChange?.(refresh);
2166
+ refresh();
2167
+ }).catch((error) => {
2168
+ console.error(error);
2169
+ });
2170
+ } else if (videoRef.current) {
2171
+ videoRef.current.src = item.url;
2172
+ }
2154
2173
  } else if (item.file) {
2155
2174
  isStreamRef.current = false;
2156
2175
  stopStallDetection();
2157
2176
  const subs = subtitleFilesMapRef.current.get(item.name) ?? [];
2158
2177
  processFile(item.file, subs);
2159
2178
  }
2160
- }, [playlist.playlist, playlist.selectItem, subtitles, processFile]);
2179
+ }, [playlist.playlist, playlist.selectItem, subtitles, processFile, enrichMetadata]);
2161
2180
  const handleSkipToNext = useCallback(() => {
2162
2181
  setPlayerError(null);
2163
2182
  clearRetryTimer();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightbird/ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Drop-in React video player component powered by LightBird. Full controls, playlist, subtitles, chapters — one import.",
5
5
  "license": "MIT",
6
6
  "author": "Punyam Singh",
@@ -65,7 +65,7 @@
65
65
  "clsx": "^2.1.1",
66
66
  "lucide-react": "^0.475.0",
67
67
  "tailwind-merge": "^3.0.1",
68
- "@lightbird/core": "0.8.0"
68
+ "@lightbird/core": "0.9.0"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "react": "^18.0.0 || ^19.0.0",