@lightbird/core 0.7.0 → 0.8.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 +33 -0
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +31 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1614,6 +1614,36 @@ async function captureFrameAt(videoEl, timeSeconds, width = 160, height = 90) {
|
|
|
1614
1614
|
});
|
|
1615
1615
|
}
|
|
1616
1616
|
|
|
1617
|
+
// src/utils/frame-export.ts
|
|
1618
|
+
function exportVideoFrame(videoEl, options = {}) {
|
|
1619
|
+
const { type = "image/png", quality, filter } = options;
|
|
1620
|
+
const width = videoEl.videoWidth;
|
|
1621
|
+
const height = videoEl.videoHeight;
|
|
1622
|
+
if (!width || !height) return null;
|
|
1623
|
+
const canvas = document.createElement("canvas");
|
|
1624
|
+
canvas.width = width;
|
|
1625
|
+
canvas.height = height;
|
|
1626
|
+
const ctx = canvas.getContext("2d");
|
|
1627
|
+
if (!ctx) return null;
|
|
1628
|
+
try {
|
|
1629
|
+
if (filter) ctx.filter = filter;
|
|
1630
|
+
ctx.drawImage(videoEl, 0, 0, width, height);
|
|
1631
|
+
return canvas.toDataURL(type, quality);
|
|
1632
|
+
} catch {
|
|
1633
|
+
return null;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
function downloadDataUrl(dataUrl, filename) {
|
|
1637
|
+
const a = document.createElement("a");
|
|
1638
|
+
a.href = dataUrl;
|
|
1639
|
+
a.download = filename;
|
|
1640
|
+
a.click();
|
|
1641
|
+
}
|
|
1642
|
+
function frameExportFilename(extension = "png") {
|
|
1643
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
1644
|
+
return `lightbird-screenshot-${stamp}.${extension}`;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1617
1647
|
// src/utils/keyboard-shortcuts.ts
|
|
1618
1648
|
var DEFAULT_SHORTCUTS = [
|
|
1619
1649
|
{ action: "play-pause", label: "Play / Pause", defaultKey: " ", key: " " },
|
|
@@ -1773,9 +1803,12 @@ exports.configureLightBird = configureLightBird;
|
|
|
1773
1803
|
exports.createOffsetVttUrl = createOffsetVttUrl;
|
|
1774
1804
|
exports.createVideoPlayer = createVideoPlayer;
|
|
1775
1805
|
exports.destroyWebTorrentClient = destroyWebTorrentClient;
|
|
1806
|
+
exports.downloadDataUrl = downloadDataUrl;
|
|
1776
1807
|
exports.exportPlaylist = exportPlaylist;
|
|
1808
|
+
exports.exportVideoFrame = exportVideoFrame;
|
|
1777
1809
|
exports.extractNativeMetadata = extractNativeMetadata;
|
|
1778
1810
|
exports.formatShortcutKey = formatShortcutKey;
|
|
1811
|
+
exports.frameExportFilename = frameExportFilename;
|
|
1779
1812
|
exports.getFFmpeg = getFFmpeg;
|
|
1780
1813
|
exports.getLanguageName = getLanguageName;
|
|
1781
1814
|
exports.getVideoFiles = getVideoFiles;
|
package/dist/index.d.cts
CHANGED
|
@@ -388,6 +388,51 @@ declare function captureVideoThumbnail(videoEl: HTMLVideoElement, atSeconds?: nu
|
|
|
388
388
|
*/
|
|
389
389
|
declare function captureFrameAt(videoEl: HTMLVideoElement, timeSeconds: number, width?: number, height?: number): Promise<string | null>;
|
|
390
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Frame / screenshot export.
|
|
393
|
+
*
|
|
394
|
+
* Captures the currently displayed frame of a playing video element to an
|
|
395
|
+
* image and (optionally) triggers a browser download. Unlike the seek-hover
|
|
396
|
+
* preview in {@link ./video-thumbnail}, this grabs the frame *in place* at the
|
|
397
|
+
* video's native resolution without seeking, so it never disturbs playback.
|
|
398
|
+
*/
|
|
399
|
+
interface ExportFrameOptions {
|
|
400
|
+
/** Output image MIME type. Defaults to `"image/png"`. */
|
|
401
|
+
type?: string;
|
|
402
|
+
/** Quality (0–1) for lossy formats such as jpeg/webp. Ignored for png. */
|
|
403
|
+
quality?: number;
|
|
404
|
+
/**
|
|
405
|
+
* CSS `filter` string to bake into the exported image (e.g. the
|
|
406
|
+
* brightness/contrast filters applied to the video element). When omitted,
|
|
407
|
+
* the raw frame is captured.
|
|
408
|
+
*/
|
|
409
|
+
filter?: string;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Capture the current frame of a video element at its native resolution.
|
|
413
|
+
*
|
|
414
|
+
* @param videoEl - The video element to capture from.
|
|
415
|
+
* @param options - Output format and an optional CSS filter to bake in.
|
|
416
|
+
* @returns An image data URL, or `null` if capture failed — no 2d context, the
|
|
417
|
+
* video has no decoded dimensions yet, or the canvas is tainted by a
|
|
418
|
+
* cross-origin source.
|
|
419
|
+
*/
|
|
420
|
+
declare function exportVideoFrame(videoEl: HTMLVideoElement, options?: ExportFrameOptions): string | null;
|
|
421
|
+
/**
|
|
422
|
+
* Trigger a browser download of a data URL by synthesizing an anchor click.
|
|
423
|
+
*
|
|
424
|
+
* @param dataUrl - The data (or object) URL to download.
|
|
425
|
+
* @param filename - The suggested filename for the saved file.
|
|
426
|
+
*/
|
|
427
|
+
declare function downloadDataUrl(dataUrl: string, filename: string): void;
|
|
428
|
+
/**
|
|
429
|
+
* Build a timestamped default filename for an exported frame.
|
|
430
|
+
*
|
|
431
|
+
* @param extension - File extension without a leading dot. Defaults to `"png"`.
|
|
432
|
+
* @returns e.g. `lightbird-screenshot-2026-05-30T12-00-00-000Z.png`.
|
|
433
|
+
*/
|
|
434
|
+
declare function frameExportFilename(extension?: string): string;
|
|
435
|
+
|
|
391
436
|
type ShortcutAction = 'play-pause' | 'seek-forward-5' | 'seek-backward-5' | 'seek-forward-30' | 'seek-backward-30' | 'volume-up' | 'volume-down' | 'mute' | 'fullscreen' | 'next-item' | 'prev-item' | 'screenshot' | 'show-shortcuts' | 'next-chapter' | 'prev-chapter' | 'frame-step-forward' | 'frame-step-backward' | 'loop-toggle' | 'ab-loop-cycle';
|
|
392
437
|
interface ShortcutBinding {
|
|
393
438
|
action: ShortcutAction;
|
|
@@ -450,4 +495,4 @@ declare function resetFFmpeg(): void;
|
|
|
450
495
|
*/
|
|
451
496
|
declare function getLanguageName(code?: string | null): string | undefined;
|
|
452
497
|
|
|
453
|
-
export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, 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, exportPlaylist, extractNativeMetadata, formatShortcutKey, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -388,6 +388,51 @@ declare function captureVideoThumbnail(videoEl: HTMLVideoElement, atSeconds?: nu
|
|
|
388
388
|
*/
|
|
389
389
|
declare function captureFrameAt(videoEl: HTMLVideoElement, timeSeconds: number, width?: number, height?: number): Promise<string | null>;
|
|
390
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Frame / screenshot export.
|
|
393
|
+
*
|
|
394
|
+
* Captures the currently displayed frame of a playing video element to an
|
|
395
|
+
* image and (optionally) triggers a browser download. Unlike the seek-hover
|
|
396
|
+
* preview in {@link ./video-thumbnail}, this grabs the frame *in place* at the
|
|
397
|
+
* video's native resolution without seeking, so it never disturbs playback.
|
|
398
|
+
*/
|
|
399
|
+
interface ExportFrameOptions {
|
|
400
|
+
/** Output image MIME type. Defaults to `"image/png"`. */
|
|
401
|
+
type?: string;
|
|
402
|
+
/** Quality (0–1) for lossy formats such as jpeg/webp. Ignored for png. */
|
|
403
|
+
quality?: number;
|
|
404
|
+
/**
|
|
405
|
+
* CSS `filter` string to bake into the exported image (e.g. the
|
|
406
|
+
* brightness/contrast filters applied to the video element). When omitted,
|
|
407
|
+
* the raw frame is captured.
|
|
408
|
+
*/
|
|
409
|
+
filter?: string;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Capture the current frame of a video element at its native resolution.
|
|
413
|
+
*
|
|
414
|
+
* @param videoEl - The video element to capture from.
|
|
415
|
+
* @param options - Output format and an optional CSS filter to bake in.
|
|
416
|
+
* @returns An image data URL, or `null` if capture failed — no 2d context, the
|
|
417
|
+
* video has no decoded dimensions yet, or the canvas is tainted by a
|
|
418
|
+
* cross-origin source.
|
|
419
|
+
*/
|
|
420
|
+
declare function exportVideoFrame(videoEl: HTMLVideoElement, options?: ExportFrameOptions): string | null;
|
|
421
|
+
/**
|
|
422
|
+
* Trigger a browser download of a data URL by synthesizing an anchor click.
|
|
423
|
+
*
|
|
424
|
+
* @param dataUrl - The data (or object) URL to download.
|
|
425
|
+
* @param filename - The suggested filename for the saved file.
|
|
426
|
+
*/
|
|
427
|
+
declare function downloadDataUrl(dataUrl: string, filename: string): void;
|
|
428
|
+
/**
|
|
429
|
+
* Build a timestamped default filename for an exported frame.
|
|
430
|
+
*
|
|
431
|
+
* @param extension - File extension without a leading dot. Defaults to `"png"`.
|
|
432
|
+
* @returns e.g. `lightbird-screenshot-2026-05-30T12-00-00-000Z.png`.
|
|
433
|
+
*/
|
|
434
|
+
declare function frameExportFilename(extension?: string): string;
|
|
435
|
+
|
|
391
436
|
type ShortcutAction = 'play-pause' | 'seek-forward-5' | 'seek-backward-5' | 'seek-forward-30' | 'seek-backward-30' | 'volume-up' | 'volume-down' | 'mute' | 'fullscreen' | 'next-item' | 'prev-item' | 'screenshot' | 'show-shortcuts' | 'next-chapter' | 'prev-chapter' | 'frame-step-forward' | 'frame-step-backward' | 'loop-toggle' | 'ab-loop-cycle';
|
|
392
437
|
interface ShortcutBinding {
|
|
393
438
|
action: ShortcutAction;
|
|
@@ -450,4 +495,4 @@ declare function resetFFmpeg(): void;
|
|
|
450
495
|
*/
|
|
451
496
|
declare function getLanguageName(code?: string | null): string | undefined;
|
|
452
497
|
|
|
453
|
-
export { ASSRenderer, type AudioTrack, type AudioTrackMeta, CancellationError, type Chapter, DEFAULT_SHORTCUTS, DEFAULT_TRACKERS, DISCLAIMER_KEY, 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, exportPlaylist, extractNativeMetadata, formatShortcutKey, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1611,6 +1611,36 @@ async function captureFrameAt(videoEl, timeSeconds, width = 160, height = 90) {
|
|
|
1611
1611
|
});
|
|
1612
1612
|
}
|
|
1613
1613
|
|
|
1614
|
+
// src/utils/frame-export.ts
|
|
1615
|
+
function exportVideoFrame(videoEl, options = {}) {
|
|
1616
|
+
const { type = "image/png", quality, filter } = options;
|
|
1617
|
+
const width = videoEl.videoWidth;
|
|
1618
|
+
const height = videoEl.videoHeight;
|
|
1619
|
+
if (!width || !height) return null;
|
|
1620
|
+
const canvas = document.createElement("canvas");
|
|
1621
|
+
canvas.width = width;
|
|
1622
|
+
canvas.height = height;
|
|
1623
|
+
const ctx = canvas.getContext("2d");
|
|
1624
|
+
if (!ctx) return null;
|
|
1625
|
+
try {
|
|
1626
|
+
if (filter) ctx.filter = filter;
|
|
1627
|
+
ctx.drawImage(videoEl, 0, 0, width, height);
|
|
1628
|
+
return canvas.toDataURL(type, quality);
|
|
1629
|
+
} catch {
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
function downloadDataUrl(dataUrl, filename) {
|
|
1634
|
+
const a = document.createElement("a");
|
|
1635
|
+
a.href = dataUrl;
|
|
1636
|
+
a.download = filename;
|
|
1637
|
+
a.click();
|
|
1638
|
+
}
|
|
1639
|
+
function frameExportFilename(extension = "png") {
|
|
1640
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
1641
|
+
return `lightbird-screenshot-${stamp}.${extension}`;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1614
1644
|
// src/utils/keyboard-shortcuts.ts
|
|
1615
1645
|
var DEFAULT_SHORTCUTS = [
|
|
1616
1646
|
{ action: "play-pause", label: "Play / Pause", defaultKey: " ", key: " " },
|
|
@@ -1749,4 +1779,4 @@ function resetFFmpeg() {
|
|
|
1749
1779
|
loading = null;
|
|
1750
1780
|
}
|
|
1751
1781
|
|
|
1752
|
-
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, exportPlaylist, extractNativeMetadata, formatShortcutKey, getFFmpeg, getLanguageName, getVideoFiles, getWebTorrentClient, hasAcceptedDisclaimer, initFeatureFlags, isHlsUrl, isInteractiveElement, isMagnetUri, isVideoFile, loadShortcuts, matchesShortcut, parseChaptersFromFFmpegLog, parseChaptersFromVtt, parseM3U8, parseMediaError, resetFFmpeg, saveShortcuts, validateFile };
|
|
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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightbird/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|