libbitsub 1.10.2 → 1.11.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/README.md +184 -34
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/hlsjs.d.ts +45 -0
- package/dist/integrations/hlsjs.d.ts.map +1 -0
- package/dist/integrations/hlsjs.js +121 -0
- package/dist/integrations/hlsjs.js.map +1 -0
- package/dist/integrations/index.d.ts +11 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +11 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/react.d.ts +55 -0
- package/dist/integrations/react.d.ts.map +1 -0
- package/dist/integrations/react.js +127 -0
- package/dist/integrations/react.js.map +1 -0
- package/dist/integrations/shaka.d.ts +38 -0
- package/dist/integrations/shaka.d.ts.map +1 -0
- package/dist/integrations/shaka.js +71 -0
- package/dist/integrations/shaka.js.map +1 -0
- package/dist/integrations/shared.d.ts +41 -0
- package/dist/integrations/shared.d.ts.map +1 -0
- package/dist/integrations/shared.js +123 -0
- package/dist/integrations/shared.js.map +1 -0
- package/dist/integrations/videojs.d.ts +85 -0
- package/dist/integrations/videojs.d.ts.map +1 -0
- package/dist/integrations/videojs.js +111 -0
- package/dist/integrations/videojs.js.map +1 -0
- package/dist/ts/diagnostics.d.ts.map +1 -1
- package/dist/ts/diagnostics.js.map +1 -1
- package/dist/ts/frame-export.d.ts.map +1 -1
- package/dist/ts/frame-export.js +4 -4
- package/dist/ts/frame-export.js.map +1 -1
- package/dist/ts/parsers.d.ts +7 -6
- package/dist/ts/parsers.d.ts.map +1 -1
- package/dist/ts/parsers.js +76 -13
- package/dist/ts/parsers.js.map +1 -1
- package/dist/ts/range-loader.d.ts +31 -0
- package/dist/ts/range-loader.d.ts.map +1 -0
- package/dist/ts/range-loader.js +220 -0
- package/dist/ts/range-loader.js.map +1 -0
- package/dist/ts/renderers.d.ts +14 -0
- package/dist/ts/renderers.d.ts.map +1 -1
- package/dist/ts/renderers.js +445 -162
- package/dist/ts/renderers.js.map +1 -1
- package/dist/ts/types.d.ts +51 -1
- package/dist/ts/types.d.ts.map +1 -1
- package/dist/ts/utils.d.ts.map +1 -1
- package/dist/ts/utils.js.map +1 -1
- package/dist/ts/wasm.d.ts +2 -0
- package/dist/ts/wasm.d.ts.map +1 -1
- package/dist/ts/wasm.js +12 -0
- package/dist/ts/wasm.js.map +1 -1
- package/dist/ts/webgl2-renderer.d.ts +9 -0
- package/dist/ts/webgl2-renderer.d.ts.map +1 -1
- package/dist/ts/webgl2-renderer.js +34 -0
- package/dist/ts/webgl2-renderer.js.map +1 -1
- package/dist/ts/webgpu-renderer.d.ts +9 -0
- package/dist/ts/webgpu-renderer.d.ts.map +1 -1
- package/dist/ts/webgpu-renderer.js +70 -2
- package/dist/ts/webgpu-renderer.js.map +1 -1
- package/dist/ts/worker.d.ts +11 -0
- package/dist/ts/worker.d.ts.map +1 -1
- package/dist/ts/worker.js +229 -161
- package/dist/ts/worker.js.map +1 -1
- package/dist/wrapper.d.ts +3 -1
- package/dist/wrapper.d.ts.map +1 -1
- package/dist/wrapper.js +2 -0
- package/dist/wrapper.js.map +1 -1
- package/examples/README.md +38 -0
- package/examples/hlsjs/README.md +53 -0
- package/examples/react/README.md +60 -0
- package/examples/shaka/README.md +61 -0
- package/examples/videojs/README.md +55 -0
- package/package.json +64 -7
- package/pkg/README.md +184 -34
- package/pkg/libbitsub.d.ts +14 -0
- package/pkg/libbitsub.js +50 -0
- package/pkg/libbitsub_bg.wasm +0 -0
- package/pkg/libbitsub_bg.wasm.d.ts +7 -0
- package/pkg/package.json +1 -1
- package/src/integrations/hlsjs.ts +154 -0
- package/src/integrations/index.ts +36 -0
- package/src/integrations/react.tsx +170 -0
- package/src/integrations/shaka.ts +92 -0
- package/src/integrations/shared.ts +170 -0
- package/src/integrations/videojs.ts +200 -0
- package/src/wrapper.ts +12 -0
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js)
|
|
|
11
11
|
- Matroska `.mks` extraction for embedded `S_VOBSUB` tracks
|
|
12
12
|
- WebGPU, WebGL2, and Canvas2D rendering with automatic fallback
|
|
13
13
|
- Worker-backed parsing/rendering for large subtitle files
|
|
14
|
+
- HTTP Range / streaming loads for large `.sup`, `.sub`, `.idx`, and `.mks` assets (progressive indexing where feasible)
|
|
14
15
|
- Rich layout controls: scale, aspect mode, horizontal/vertical offsets, alignment, bottom padding, safe area, opacity
|
|
15
16
|
- Cue metadata and parser introspection APIs
|
|
16
17
|
- Rendered-frame export helpers for ImageData, ImageBitmap, Blob, and custom canvas targets
|
|
@@ -18,6 +19,7 @@ Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js)
|
|
|
18
19
|
- Automatic format detection and unified loading helpers
|
|
19
20
|
- First-class diagnostics with structured error codes, warning hooks, and render/cache snapshots
|
|
20
21
|
- TypeScript support with exported event and metadata types
|
|
22
|
+
- Optional player integrations for Video.js, Shaka Player, hls.js, and React (core stays dependency-free)
|
|
21
23
|
|
|
22
24
|
## Showcase
|
|
23
25
|
|
|
@@ -67,11 +69,11 @@ deno add jsr:@altq/libbitsub
|
|
|
67
69
|
|
|
68
70
|
In most bundler-based projects, no manual worker setup is required. `libbitsub` now resolves the WASM asset relative to the package module URL, so bundlers such as Vite, webpack, and Rollup can emit the asset automatically.
|
|
69
71
|
|
|
70
|
-
If your app serves package files in a way that does not expose that emitted WASM asset to the browser, you can still provide the legacy public fallback by copying the WASM file to `/libbitsub
|
|
72
|
+
If your app serves package files in a way that does not expose that emitted WASM asset to the browser, you can still provide the legacy public fallback by copying the WASM file and its JS glue to `/libbitsub/`:
|
|
71
73
|
|
|
72
74
|
```bash
|
|
73
75
|
mkdir -p public/libbitsub
|
|
74
|
-
cp node_modules/libbitsub/pkg/libbitsub_bg.wasm public/libbitsub/
|
|
76
|
+
cp node_modules/libbitsub/pkg/libbitsub_bg.wasm node_modules/libbitsub/pkg/libbitsub.js public/libbitsub/
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
The worker is still created inline. `workerUrl` remains in the option type only for compatibility and does not change runtime behavior.
|
|
@@ -110,6 +112,129 @@ const parser = new PgsParser()
|
|
|
110
112
|
|
|
111
113
|
Calling `initWasm()` multiple times is safe (it deduplicates).
|
|
112
114
|
|
|
115
|
+
### Worker prewarm (TV / players)
|
|
116
|
+
|
|
117
|
+
On devices where the first subtitle track switch should not pay worker + WASM startup cost (for example TV apps), prewarm the shared parsing worker during app startup:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { warmup, ready, PgsRenderer } from 'libbitsub'
|
|
121
|
+
|
|
122
|
+
// Fire-and-forget at app boot (safe to call multiple times).
|
|
123
|
+
void warmup()
|
|
124
|
+
|
|
125
|
+
// Before the user changes tracks, ensure the worker is ready.
|
|
126
|
+
await ready()
|
|
127
|
+
|
|
128
|
+
const renderer = new PgsRenderer({ video: videoElement, subContent: trackBytes })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`warmup()` and `ready()` share a single worker-init promise with renderer creation. The shared worker is only published after in-worker WASM initialization succeeds. When Web Workers are unavailable, both resolve immediately and renderers use the main thread.
|
|
132
|
+
|
|
133
|
+
### Range / streaming loads (TV / slow networks)
|
|
134
|
+
|
|
135
|
+
URL-based loads (`subUrl` / `idxUrl`) use progressive fetch by default:
|
|
136
|
+
|
|
137
|
+
- Probe HTTP Range support and, for large assets, download with Range chunks when the origin allows it
|
|
138
|
+
- Stream the response body otherwise and report `load-progress` events
|
|
139
|
+
- **PGS (`.sup`)**: feed chunks into the parser as they arrive so cues can be indexed before the full file finishes
|
|
140
|
+
- **VobSub (`.idx` + `.sub`)**: parse the small `.idx` first for timestamps, then stream/Range-download the `.sub` body and attach packets
|
|
141
|
+
- **MKS**: stream/Range-download the container first (Matroska extraction still needs the assembled payload), then parse
|
|
142
|
+
- **In-memory** `subContent` / `idxContent` remains the simple full-buffer path
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { PgsRenderer } from 'libbitsub'
|
|
146
|
+
|
|
147
|
+
const renderer = new PgsRenderer({
|
|
148
|
+
video: videoElement,
|
|
149
|
+
subUrl: '/subtitles/movie.sup',
|
|
150
|
+
// streamingLoad: true, // default
|
|
151
|
+
// rangeRequests: true, // default
|
|
152
|
+
onEvent: (event) => {
|
|
153
|
+
if (event.type === 'load-progress') {
|
|
154
|
+
console.log(event.strategy, event.loadedBytes, event.totalBytes, event.indexedCues)
|
|
155
|
+
}
|
|
156
|
+
if (event.type === 'indexed') {
|
|
157
|
+
console.log('cues ready', event.metadata.cueCount, event.partial ? '(partial)' : '(final)')
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Disable progressive behavior when you want a single blocking GET:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
new PgsRenderer({ video, subUrl, streamingLoad: false, rangeRequests: false })
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Low-level helpers are also exported: `probeRangeSupport()`, `fetchSubtitleAsset()`, and `fetchSubtitleText()`.
|
|
170
|
+
|
|
171
|
+
## Player integrations
|
|
172
|
+
|
|
173
|
+
Optional adapters ship as **subpath exports**. They wrap the high-level renderers for common players while keeping the core package free of player/React dependencies (peer deps are optional and only needed when you import that adapter).
|
|
174
|
+
|
|
175
|
+
| Import | Adapter | Optional peer |
|
|
176
|
+
| ------------------------ | ---------------------------------------- | ------------------- |
|
|
177
|
+
| `libbitsub/videojs` | Video.js plugin (`registerBitSubPlugin`) | `video.js` >= 7 |
|
|
178
|
+
| `libbitsub/shaka` | `attachBitSubToShaka(player, options)` | `shaka-player` >= 4 |
|
|
179
|
+
| `libbitsub/hlsjs` | `attachBitSubToHls(hls, options)` | `hls.js` >= 1 |
|
|
180
|
+
| `libbitsub/react` | `useBitSub` / `BitSubOverlay` | `react` >= 18 |
|
|
181
|
+
| `libbitsub/integrations` | Shared `attachBitSub` controller | — |
|
|
182
|
+
|
|
183
|
+
Copy-paste recipes live under [`examples/`](./examples).
|
|
184
|
+
|
|
185
|
+
### Video.js
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import videojs from 'video.js'
|
|
189
|
+
import { registerBitSubPlugin } from 'libbitsub/videojs'
|
|
190
|
+
|
|
191
|
+
registerBitSubPlugin(videojs)
|
|
192
|
+
const player = videojs('my-video')
|
|
193
|
+
const bitsub = player.bitsub({ subUrl: '/subs/movie.sup' })
|
|
194
|
+
bitsub.load({ subUrl: '/subs/other.sup' })
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Shaka Player
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { attachBitSubToShaka } from 'libbitsub/shaka'
|
|
201
|
+
|
|
202
|
+
const bitsub = attachBitSubToShaka(player, { subUrl: '/subs/movie.sup' })
|
|
203
|
+
// later
|
|
204
|
+
bitsub.dispose()
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### hls.js
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import Hls from 'hls.js'
|
|
211
|
+
import { attachBitSubToHls } from 'libbitsub/hlsjs'
|
|
212
|
+
|
|
213
|
+
const hls = new Hls()
|
|
214
|
+
hls.loadSource(url)
|
|
215
|
+
hls.attachMedia(video)
|
|
216
|
+
const bitsub = attachBitSubToHls(hls, { subUrl: '/subs/movie.sup' })
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### React
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { useRef } from 'react'
|
|
223
|
+
import { useBitSub } from 'libbitsub/react'
|
|
224
|
+
|
|
225
|
+
function Player({ src, subUrl }: { src: string; subUrl: string }) {
|
|
226
|
+
const videoRef = useRef<HTMLVideoElement>(null)
|
|
227
|
+
useBitSub(videoRef, { subUrl })
|
|
228
|
+
return (
|
|
229
|
+
<div style={{ position: 'relative' }}>
|
|
230
|
+
<video ref={videoRef} src={src} controls playsInline />
|
|
231
|
+
</div>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Bitmap PGS/VobSub/MKS tracks are external canvas overlays, not native HTML/TextTrack entries. Prefer deep imports so unused adapters stay out of your bundle.
|
|
237
|
+
|
|
113
238
|
## High-level video renderers
|
|
114
239
|
|
|
115
240
|
The high-level API manages subtitle loading, canvas overlay creation, playback sync, resize handling, worker usage, and renderer fallback.
|
|
@@ -207,16 +332,16 @@ renderer.resetDisplaySettings()
|
|
|
207
332
|
|
|
208
333
|
`SubtitleDisplaySettings`:
|
|
209
334
|
|
|
210
|
-
| Field
|
|
211
|
-
|
|
|
212
|
-
| `scale`
|
|
213
|
-
| `aspectMode`
|
|
214
|
-
| `verticalOffset`
|
|
215
|
-
| `horizontalOffset` | number
|
|
216
|
-
| `horizontalAlign`
|
|
217
|
-
| `bottomPadding`
|
|
218
|
-
| `safeArea`
|
|
219
|
-
| `opacity`
|
|
335
|
+
| Field | Type | Range / values | Meaning |
|
|
336
|
+
| ------------------ | ----------------------------------- | -------------- | -------------------------------------------------------------- |
|
|
337
|
+
| `scale` | number | `0.1` to `3.0` | Overall subtitle scale |
|
|
338
|
+
| `aspectMode` | `'stretch' \| 'contain' \| 'cover'` | fixed set | How subtitle screen coordinates map into the visible video box |
|
|
339
|
+
| `verticalOffset` | number | `-50` to `50` | Vertical movement as percent of video height |
|
|
340
|
+
| `horizontalOffset` | number | `-50` to `50` | Horizontal movement as percent of video width |
|
|
341
|
+
| `horizontalAlign` | `'left' \| 'center' \| 'right'` | fixed set | Anchor used when scaling subtitle groups |
|
|
342
|
+
| `bottomPadding` | number | `0` to `50` | Extra padding from the bottom edge |
|
|
343
|
+
| `safeArea` | number | `0` to `25` | Clamp subtitles inside a video-safe area |
|
|
344
|
+
| `opacity` | number | `0.0` to `1.0` | Global subtitle opacity |
|
|
220
345
|
|
|
221
346
|
## Metadata and introspection
|
|
222
347
|
|
|
@@ -291,14 +416,7 @@ Like `UnifiedSubtitleParser.loadAuto()`, this is a low-level in-memory API: pass
|
|
|
291
416
|
Low-level parser output can be flattened into a single exportable frame for previews, editors, snapshots, fixture generation, or visual diffing.
|
|
292
417
|
|
|
293
418
|
```ts
|
|
294
|
-
import {
|
|
295
|
-
PgsParser,
|
|
296
|
-
initWasm,
|
|
297
|
-
renderFrameData,
|
|
298
|
-
toBlob,
|
|
299
|
-
toCanvas,
|
|
300
|
-
toImageBitmap
|
|
301
|
-
} from 'libbitsub'
|
|
419
|
+
import { PgsParser, initWasm, renderFrameData, toBlob, toCanvas, toImageBitmap } from 'libbitsub'
|
|
302
420
|
|
|
303
421
|
await initWasm()
|
|
304
422
|
|
|
@@ -385,7 +503,7 @@ Structured diagnostic error codes currently include:
|
|
|
385
503
|
- `WORKER_FALLBACK`
|
|
386
504
|
- `UNKNOWN`
|
|
387
505
|
|
|
388
|
-
Warnings use a smaller code set focused on non-fatal conditions such as malformed bitmap buffers, worker fallback, and missing PGS palettes during render.
|
|
506
|
+
Warnings use a smaller code set focused on non-fatal conditions such as malformed bitmap buffers, worker fallback, progressive/Range fallback (`RANGE_FALLBACK`), and missing PGS palettes during render.
|
|
389
507
|
|
|
390
508
|
## MKS security and corruption checks
|
|
391
509
|
|
|
@@ -415,6 +533,8 @@ const renderer = new PgsRenderer({
|
|
|
415
533
|
onEvent: (event) => {
|
|
416
534
|
switch (event.type) {
|
|
417
535
|
case 'loading':
|
|
536
|
+
case 'load-progress':
|
|
537
|
+
case 'indexed':
|
|
418
538
|
case 'loaded':
|
|
419
539
|
case 'error':
|
|
420
540
|
case 'warning':
|
|
@@ -482,17 +602,17 @@ renderer.dispose()
|
|
|
482
602
|
|
|
483
603
|
Emitted events:
|
|
484
604
|
|
|
485
|
-
| Event
|
|
486
|
-
|
|
|
487
|
-
| `loading`
|
|
488
|
-
| `loaded`
|
|
489
|
-
| `error`
|
|
490
|
-
| `warning`
|
|
491
|
-
| `renderer-change` | active backend: `webgpu`, `webgl2`, or `canvas2d`
|
|
492
|
-
| `worker-state`
|
|
493
|
-
| `cache-change`
|
|
494
|
-
| `cue-change`
|
|
495
|
-
| `stats`
|
|
605
|
+
| Event | Payload |
|
|
606
|
+
| ----------------- | --------------------------------------------------------------------------------- |
|
|
607
|
+
| `loading` | subtitle format |
|
|
608
|
+
| `loaded` | subtitle format and parser metadata |
|
|
609
|
+
| `error` | subtitle format and `SubtitleDiagnosticErrorLike` |
|
|
610
|
+
| `warning` | `SubtitleDiagnosticWarning` |
|
|
611
|
+
| `renderer-change` | active backend: `webgpu`, `webgl2`, or `canvas2d` |
|
|
612
|
+
| `worker-state` | whether worker mode is enabled, ready, fallback status, and the active session ID |
|
|
613
|
+
| `cache-change` | cached frame count, pending renders, and configured cache limit |
|
|
614
|
+
| `cue-change` | current cue metadata or `null` when nothing is displayed |
|
|
615
|
+
| `stats` | periodic renderer stats snapshot |
|
|
496
616
|
|
|
497
617
|
## Performance stats
|
|
498
618
|
|
|
@@ -581,6 +701,25 @@ console.log({
|
|
|
581
701
|
|
|
582
702
|
WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2Fallback`, `onEvent`, or `onWarning` if you need to observe backend changes.
|
|
583
703
|
|
|
704
|
+
## Compatibility & visual regression
|
|
705
|
+
|
|
706
|
+
A formal suite locks decoder edge cases and backend pixel parity:
|
|
707
|
+
|
|
708
|
+
- Malformed PGS / VobSub / MKS fixtures
|
|
709
|
+
- Palette edge cases and zero-length RLE runs
|
|
710
|
+
- Alternate display sizes (SD → 4K)
|
|
711
|
+
- Slow worker startup / shared init
|
|
712
|
+
- Pixel-level goldens across software, Canvas2D, WebGL2, and WebGPU
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
bun run test # Rust core (includes compatibility fixtures)
|
|
716
|
+
bun run test:ts # TypeScript fixtures, goldens, worker startup
|
|
717
|
+
bun run test:visual # Headless Chromium backend parity
|
|
718
|
+
bun run test:all # All of the above
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
Browser/device support matrix (including webOS TV): [docs/COMPATIBILITY.md](./docs/COMPATIBILITY.md).
|
|
722
|
+
|
|
584
723
|
## Notes
|
|
585
724
|
|
|
586
725
|
- Worker mode is shared, but subtitle parser state is isolated per renderer session.
|
|
@@ -594,10 +733,13 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
594
733
|
|
|
595
734
|
- `initWasm(): Promise<void>` initializes the WASM module. Called automatically by high-level renderers and on first import in browser environments. Safe to call multiple times. Only needed explicitly for low-level parser usage.
|
|
596
735
|
- `isWasmInitialized(): boolean` reports whether initialization has completed.
|
|
736
|
+
- `warmup(): Promise<void>` / `ready(): Promise<void>` pre-initialize the shared subtitle worker (including in-worker WASM). Safe to call multiple times; concurrent callers share one init promise. Prefer these in TV/player apps before the first track switch.
|
|
737
|
+
- `isWorkerAvailable(): boolean` / `isWorkerReady(): boolean` report worker support and whether the shared worker has finished initializing.
|
|
597
738
|
- `isWebGPUSupported(): boolean` checks WebGPU support.
|
|
598
739
|
- `detectSubtitleFormat(source: AutoSubtitleSource): 'pgs' | 'vobsub' | null` detects the bitmap subtitle format from file hints or binary data.
|
|
599
740
|
- `createAutoSubtitleRenderer(options: AutoVideoSubtitleOptions): PgsRenderer | VobSubRenderer` creates a high-level renderer after format detection.
|
|
600
741
|
- `openSubtitles(source, options?): Promise<OpenedSubtitles>` initializes WASM, auto-detects the low-level format, and returns a normalized parser handle.
|
|
742
|
+
- `probeRangeSupport(url, options?)` / `fetchSubtitleAsset(url, options?, onChunk?)` / `fetchSubtitleText(url, options?)` perform Range-aware progressive asset downloads for custom loaders.
|
|
601
743
|
- `renderFrameData(frame, options?): SubtitleRenderedFrameData | null` composes a `SubtitleData` frame into exportable pixels.
|
|
602
744
|
- `toCanvas(frame, target?, options?): HTMLCanvasElement | OffscreenCanvas` draws a rendered frame to a new or existing canvas/context.
|
|
603
745
|
- `toImageBitmap(frame, options?): Promise<ImageBitmap>` creates an `ImageBitmap` from a subtitle frame export.
|
|
@@ -605,6 +747,7 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
605
747
|
- `SubtitleDiagnosticError` is the structured error class libbitsub uses for coded diagnostics.
|
|
606
748
|
- `createSubtitleDiagnosticError(...)` and `normalizeSubtitleError(...)` are exported for integrations that want to preserve libbitsub-style error codes.
|
|
607
749
|
- Legacy aliases remain exported: `PGSRenderer`, `VobsubRenderer`, `UnifiedSubtitleRenderer`.
|
|
750
|
+
- Optional integration entry points: `libbitsub/videojs`, `libbitsub/shaka`, `libbitsub/hlsjs`, `libbitsub/react`, `libbitsub/integrations` (see [examples/](./examples) and [references/api.md](./references/api.md)).
|
|
608
751
|
|
|
609
752
|
### High-level renderers
|
|
610
753
|
|
|
@@ -639,7 +782,9 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
639
782
|
|
|
640
783
|
#### `PgsParser`
|
|
641
784
|
|
|
642
|
-
- `load(data: Uint8Array): number` loads PGS data and returns the cue count.
|
|
785
|
+
- `load(data: Uint8Array): number` loads PGS data and returns the cue count (simple in-memory path).
|
|
786
|
+
- `reset(): void` / `feed(data: Uint8Array): number` / `finishFeed(): number` progressive indexing APIs for streamed chunks.
|
|
787
|
+
- `pendingLen: number` incomplete trailing bytes retained between `feed()` calls.
|
|
643
788
|
- `getTimestamps(): Float64Array` returns cue timestamps in milliseconds.
|
|
644
789
|
- `count: number` returns the number of cues.
|
|
645
790
|
- `findIndexAtTimestamp(timeSeconds: number): number` finds the cue index for a playback time in seconds.
|
|
@@ -652,7 +797,10 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
652
797
|
|
|
653
798
|
#### `VobSubParserLowLevel`
|
|
654
799
|
|
|
655
|
-
- `loadFromData(idxContent: string, subData: Uint8Array): void` loads IDX and SUB data.
|
|
800
|
+
- `loadFromData(idxContent: string, subData: Uint8Array): void` loads IDX and SUB data (simple in-memory path).
|
|
801
|
+
- `loadFromIdx(idxContent: string): void` indexes timestamps from IDX before packet bytes arrive.
|
|
802
|
+
- `attachSubData(subData: Uint8Array): void` attaches `.sub` packets after an IDX-first load.
|
|
803
|
+
- `hasSubData: boolean` whether packet bytes are currently attached.
|
|
656
804
|
- `loadFromSubOnly(subData: Uint8Array): void` loads SUB-only VobSub data.
|
|
657
805
|
- `getTimestamps(): Float64Array`, `count`, `findIndexAtTimestamp()`, `renderAtIndex()`, `renderAtTimestamp()`, `getMetadata()`, `getCueMetadata()`, `clearCache()`, and `dispose()` behave like `PgsParser`.
|
|
658
806
|
- `setDebandEnabled(enabled: boolean): void`, `setDebandThreshold(threshold: number): void`, `setDebandRange(range: number): void`, and `debandEnabled` control debanding.
|
|
@@ -687,6 +835,8 @@ interface VideoSubtitleOptions {
|
|
|
687
835
|
before?: number
|
|
688
836
|
after?: number
|
|
689
837
|
}
|
|
838
|
+
streamingLoad?: boolean // default true — progressive URL loads
|
|
839
|
+
rangeRequests?: boolean // default true — use HTTP Range when supported
|
|
690
840
|
onEvent?: (event: SubtitleRendererEvent) => void
|
|
691
841
|
}
|
|
692
842
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { PgsRenderer, VobSubRenderer, createAutoSubtitleRenderer, type VideoSubtitleOptions, type VideoVobSubOptions, type SubtitleRendererStats } from './wrapper';
|
|
7
7
|
export { PgsParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
8
|
-
export { initWasm, isWasmInitialized, isWebGPUSupported, detectSubtitleFormat, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError, type AutoSubtitleSource, type AutoVideoSubtitleOptions, type OpenedSubtitles, type SubtitleAspectMode, type SubtitleCacheStats, type SubtitleCueBounds, type SubtitleCueMetadata, type SubtitleData, type SubtitleDiagnosticDetailValue, type SubtitleDiagnosticErrorCode, type SubtitleDiagnosticErrorLike, type SubtitleDiagnosticsOptions, type SubtitleDiagnosticWarning, type SubtitleDiagnosticWarningCode, type SubtitleCompositionData, type SubtitleDisplaySettings, type SubtitleFrameCanvasOptions, type SubtitleFrameCanvasTarget, type SubtitleFrameCropMode, type SubtitleFrameRenderOptions, type SubtitleRenderedFrameData, type SubtitleFormatName, type SubtitleHorizontalAlign, type SubtitleLastRenderInfo, type SubtitleParserMetadata, type SubtitleRendererBackend, type SubtitleRendererEvent, type SubtitleRendererStatsSnapshot } from './wrapper';
|
|
8
|
+
export { initWasm, isWasmInitialized, isWebGPUSupported, isWorkerAvailable, isWorkerReady, warmup, ready, detectSubtitleFormat, fetchSubtitleAsset, fetchSubtitleText, probeRangeSupport, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError, type AssetFetchOptions, type AssetFetchProgress, type AssetFetchStrategy, type AutoSubtitleSource, type AutoVideoSubtitleOptions, type OpenedSubtitles, type RangeProbeResult, type SubtitleAspectMode, type SubtitleCacheStats, type SubtitleCueBounds, type SubtitleCueMetadata, type SubtitleData, type SubtitleDiagnosticDetailValue, type SubtitleDiagnosticErrorCode, type SubtitleDiagnosticErrorLike, type SubtitleDiagnosticsOptions, type SubtitleDiagnosticWarning, type SubtitleDiagnosticWarningCode, type SubtitleCompositionData, type SubtitleDisplaySettings, type SubtitleFrameCanvasOptions, type SubtitleFrameCanvasTarget, type SubtitleFrameCropMode, type SubtitleFrameRenderOptions, type SubtitleRenderedFrameData, type SubtitleFormatName, type SubtitleHorizontalAlign, type SubtitleLastRenderInfo, type SubtitleParserMetadata, type SubtitleRendererBackend, type SubtitleRendererEvent, type SubtitleRendererStatsSnapshot } from './wrapper';
|
|
9
9
|
export type { RenderResult, SubtitleFrame, VobSubFrame } from './wrapper';
|
|
10
10
|
export { PGSRenderer, VobsubRenderer, UnifiedSubtitleRenderer } from './wrapper';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAA;AAGlB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAGjG,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EACnC,MAAM,WAAW,CAAA;AAGlB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAGzE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAA;AAGlB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAGjG,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,MAAM,EACN,KAAK,EACL,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EACnC,MAAM,WAAW,CAAA;AAGlB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAGzE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { PgsRenderer, VobSubRenderer, createAutoSubtitleRenderer } from './wrapp
|
|
|
8
8
|
// Low-level parsers for programmatic use
|
|
9
9
|
export { PgsParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
10
10
|
// Utility exports
|
|
11
|
-
export { initWasm, isWasmInitialized, isWebGPUSupported, detectSubtitleFormat, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError } from './wrapper';
|
|
11
|
+
export { initWasm, isWasmInitialized, isWebGPUSupported, isWorkerAvailable, isWorkerReady, warmup, ready, detectSubtitleFormat, fetchSubtitleAsset, fetchSubtitleText, probeRangeSupport, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError } from './wrapper';
|
|
12
12
|
// Legacy aliases
|
|
13
13
|
export { PGSRenderer, VobsubRenderer, UnifiedSubtitleRenderer } from './wrapper';
|
|
14
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4EAA4E;AAC5E,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAI3B,MAAM,WAAW,CAAA;AAElB,yCAAyC;AACzC,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEjG,kBAAkB;AAClB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4EAA4E;AAC5E,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAI3B,MAAM,WAAW,CAAA;AAElB,yCAAyC;AACzC,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEjG,kBAAkB;AAClB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,MAAM,EACN,KAAK,EACL,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EAiCxB,MAAM,WAAW,CAAA;AAKlB,iBAAiB;AACjB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional hls.js adapter for libbitsub bitmap subtitles.
|
|
3
|
+
*
|
|
4
|
+
* hls.js handles HLS media and WebVTT/IMSC text tracks; use this helper for
|
|
5
|
+
* external PGS/VobSub/MKS bitmap overlays on the same media element.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Hls from 'hls.js'
|
|
10
|
+
* import { attachBitSubToHls } from 'libbitsub/hlsjs'
|
|
11
|
+
*
|
|
12
|
+
* const hls = new Hls()
|
|
13
|
+
* hls.loadSource(playlistUrl)
|
|
14
|
+
* hls.attachMedia(video)
|
|
15
|
+
* const bitsub = attachBitSubToHls(hls, { subUrl: '/subs/movie.sup' })
|
|
16
|
+
* // later
|
|
17
|
+
* bitsub.dispose()
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { type AttachBitSubOptions, type BitSubController } from './shared';
|
|
21
|
+
/** Minimal hls.js surface used by the adapter. */
|
|
22
|
+
export interface HlsLike {
|
|
23
|
+
media: HTMLMediaElement | null;
|
|
24
|
+
on?(event: string, listener: (...args: unknown[]) => void): void;
|
|
25
|
+
off?(event: string, listener: (...args: unknown[]) => void): void;
|
|
26
|
+
/** hls.js Events map — optional so callers can pass event name strings. */
|
|
27
|
+
Events?: {
|
|
28
|
+
MEDIA_ATTACHED?: string;
|
|
29
|
+
MEDIA_DETACHED?: string;
|
|
30
|
+
DESTROYING?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export type BitSubHlsOptions = AttachBitSubOptions;
|
|
34
|
+
export interface BitSubHlsHandle extends BitSubController {
|
|
35
|
+
/** Underlying hls.js instance. */
|
|
36
|
+
readonly hls: HlsLike;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Attach libbitsub to an hls.js instance.
|
|
40
|
+
* Binds to `hls.media` and re-attaches on MEDIA_ATTACHED when event APIs exist.
|
|
41
|
+
*/
|
|
42
|
+
export declare function attachBitSubToHls(hls: HlsLike, options?: BitSubHlsOptions): BitSubHlsHandle;
|
|
43
|
+
export type { AttachBitSubOptions, BitSubController, BitSubSourceOptions, BitSubRenderer } from './shared';
|
|
44
|
+
export { attachBitSub, createBitSubRenderer } from './shared';
|
|
45
|
+
//# sourceMappingURL=hlsjs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hlsjs.d.ts","sourceRoot":"","sources":["../../src/integrations/hlsjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAgB,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAA4B,MAAM,UAAU,CAAA;AAElH,kDAAkD;AAClD,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC9B,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAChE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IACjE,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;AAElD,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,kCAAkC;IAClC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;CACtB;AAUD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAgG/F;AAED,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional hls.js adapter for libbitsub bitmap subtitles.
|
|
3
|
+
*
|
|
4
|
+
* hls.js handles HLS media and WebVTT/IMSC text tracks; use this helper for
|
|
5
|
+
* external PGS/VobSub/MKS bitmap overlays on the same media element.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Hls from 'hls.js'
|
|
10
|
+
* import { attachBitSubToHls } from 'libbitsub/hlsjs'
|
|
11
|
+
*
|
|
12
|
+
* const hls = new Hls()
|
|
13
|
+
* hls.loadSource(playlistUrl)
|
|
14
|
+
* hls.attachMedia(video)
|
|
15
|
+
* const bitsub = attachBitSubToHls(hls, { subUrl: '/subs/movie.sup' })
|
|
16
|
+
* // later
|
|
17
|
+
* bitsub.dispose()
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { attachBitSub } from './shared';
|
|
21
|
+
function eventName(hls, key, fallback) {
|
|
22
|
+
return hls.Events?.[key] ?? fallback;
|
|
23
|
+
}
|
|
24
|
+
function hasSubtitleSource(source) {
|
|
25
|
+
return Boolean(source.subUrl || source.subContent || source.idxUrl || source.idxContent || source.fileName);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Attach libbitsub to an hls.js instance.
|
|
29
|
+
* Binds to `hls.media` and re-attaches on MEDIA_ATTACHED when event APIs exist.
|
|
30
|
+
*/
|
|
31
|
+
export function attachBitSubToHls(hls, options = {}) {
|
|
32
|
+
const initialMedia = hls.media;
|
|
33
|
+
if (initialMedia && !(initialMedia instanceof HTMLVideoElement)) {
|
|
34
|
+
throw new Error('libbitsub hls.js adapter requires hls.media to be an HTMLVideoElement');
|
|
35
|
+
}
|
|
36
|
+
// Allow constructing before attachMedia(); load waits until a video is available.
|
|
37
|
+
const placeholderVideo = initialMedia instanceof HTMLVideoElement ? initialMedia : document.createElement('video');
|
|
38
|
+
const { autoLoad: initialAutoLoad = true, ...initialSource } = options;
|
|
39
|
+
let lastSource = { ...initialSource };
|
|
40
|
+
let autoLoad = initialAutoLoad;
|
|
41
|
+
const controller = attachBitSub(placeholderVideo, {
|
|
42
|
+
...initialSource,
|
|
43
|
+
autoLoad: initialMedia instanceof HTMLVideoElement ? initialAutoLoad : false
|
|
44
|
+
});
|
|
45
|
+
const bindMedia = (media) => {
|
|
46
|
+
if (controller.disposed)
|
|
47
|
+
return;
|
|
48
|
+
if (media && !(media instanceof HTMLVideoElement)) {
|
|
49
|
+
throw new Error('libbitsub hls.js adapter requires hls.media to be an HTMLVideoElement');
|
|
50
|
+
}
|
|
51
|
+
if (!media) {
|
|
52
|
+
controller.setVideo(null);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// setVideo reloads the last source when present; otherwise load explicitly if autoLoad.
|
|
56
|
+
const needsExplicitLoad = autoLoad && hasSubtitleSource(lastSource) && controller.renderer === null;
|
|
57
|
+
controller.setVideo(media);
|
|
58
|
+
if (needsExplicitLoad && controller.renderer === null && hasSubtitleSource(lastSource)) {
|
|
59
|
+
controller.load(lastSource);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const onMediaAttached = () => bindMedia(hls.media);
|
|
63
|
+
const onMediaDetached = () => {
|
|
64
|
+
if (!controller.disposed)
|
|
65
|
+
controller.clear();
|
|
66
|
+
};
|
|
67
|
+
const onDestroying = () => dispose();
|
|
68
|
+
const mediaAttached = eventName(hls, 'MEDIA_ATTACHED', 'hlsMediaAttached');
|
|
69
|
+
const mediaDetached = eventName(hls, 'MEDIA_DETACHED', 'hlsMediaDetached');
|
|
70
|
+
const destroying = eventName(hls, 'DESTROYING', 'hlsDestroying');
|
|
71
|
+
hls.on?.(mediaAttached, onMediaAttached);
|
|
72
|
+
hls.on?.(mediaDetached, onMediaDetached);
|
|
73
|
+
hls.on?.(destroying, onDestroying);
|
|
74
|
+
if (initialMedia instanceof HTMLVideoElement) {
|
|
75
|
+
bindMedia(initialMedia);
|
|
76
|
+
}
|
|
77
|
+
const dispose = () => {
|
|
78
|
+
hls.off?.(mediaAttached, onMediaAttached);
|
|
79
|
+
hls.off?.(mediaDetached, onMediaDetached);
|
|
80
|
+
hls.off?.(destroying, onDestroying);
|
|
81
|
+
controller.dispose();
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
hls,
|
|
85
|
+
get renderer() {
|
|
86
|
+
return controller.renderer;
|
|
87
|
+
},
|
|
88
|
+
get video() {
|
|
89
|
+
return controller.video;
|
|
90
|
+
},
|
|
91
|
+
get disposed() {
|
|
92
|
+
return controller.disposed;
|
|
93
|
+
},
|
|
94
|
+
load: (source) => {
|
|
95
|
+
lastSource = { ...source };
|
|
96
|
+
autoLoad = true;
|
|
97
|
+
if (!(controller.video instanceof HTMLVideoElement) || controller.video === placeholderVideo) {
|
|
98
|
+
const media = hls.media;
|
|
99
|
+
if (media instanceof HTMLVideoElement) {
|
|
100
|
+
controller.setVideo(media);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error('libbitsub hls.js adapter: call hls.attachMedia(video) before load()');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return controller.load(source);
|
|
107
|
+
},
|
|
108
|
+
clear: () => {
|
|
109
|
+
autoLoad = false;
|
|
110
|
+
controller.clear();
|
|
111
|
+
},
|
|
112
|
+
dispose,
|
|
113
|
+
getDisplaySettings: () => controller.getDisplaySettings(),
|
|
114
|
+
setDisplaySettings: (settings) => controller.setDisplaySettings(settings),
|
|
115
|
+
resetDisplaySettings: () => controller.resetDisplaySettings(),
|
|
116
|
+
getStats: () => controller.getStats(),
|
|
117
|
+
setVideo: (video) => controller.setVideo(video)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export { attachBitSub, createBitSubRenderer } from './shared';
|
|
121
|
+
//# sourceMappingURL=hlsjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hlsjs.js","sourceRoot":"","sources":["../../src/integrations/hlsjs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional player integrations for libbitsub.
|
|
3
|
+
* Prefer deep imports (`libbitsub/videojs`, `libbitsub/shaka`, `libbitsub/hlsjs`, `libbitsub/react`)
|
|
4
|
+
* so unused peer dependencies stay out of your bundle.
|
|
5
|
+
*/
|
|
6
|
+
export { attachBitSub, createBitSubRenderer, type AttachBitSubOptions, type BitSubController, type BitSubRenderer, type BitSubSourceOptions } from './shared';
|
|
7
|
+
export { registerBitSubPlugin, type BitSubVideoJsApi, type BitSubVideoJsOptions, type VideoJsBitSubPlayer, type VideoJsLike, type VideoJsPlayerLike } from './videojs';
|
|
8
|
+
export { attachBitSubToShaka, type BitSubShakaHandle, type BitSubShakaOptions, type ShakaPlayerLike } from './shaka';
|
|
9
|
+
export { attachBitSubToHls, type BitSubHlsHandle, type BitSubHlsOptions, type HlsLike } from './hlsjs';
|
|
10
|
+
export { BitSubOverlay, useBitSub, type BitSubOverlayProps, type BitSubReactSource, type UseBitSubOptions, type UseBitSubResult } from './react';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACzB,MAAM,UAAU,CAAA;AAEjB,OAAO,EACL,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAEpH,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtG,OAAO,EACL,aAAa,EACb,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional player integrations for libbitsub.
|
|
3
|
+
* Prefer deep imports (`libbitsub/videojs`, `libbitsub/shaka`, `libbitsub/hlsjs`, `libbitsub/react`)
|
|
4
|
+
* so unused peer dependencies stay out of your bundle.
|
|
5
|
+
*/
|
|
6
|
+
export { attachBitSub, createBitSubRenderer } from './shared';
|
|
7
|
+
export { registerBitSubPlugin } from './videojs';
|
|
8
|
+
export { attachBitSubToShaka } from './shaka';
|
|
9
|
+
export { attachBitSubToHls } from './hlsjs';
|
|
10
|
+
export { BitSubOverlay, useBitSub } from './react';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/integrations/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,oBAAoB,EAKrB,MAAM,UAAU,CAAA;AAEjB,OAAO,EACL,oBAAoB,EAMrB,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,mBAAmB,EAAyE,MAAM,SAAS,CAAA;AAEpH,OAAO,EAAE,iBAAiB,EAA6D,MAAM,SAAS,CAAA;AAEtG,OAAO,EACL,aAAa,EACb,SAAS,EAKV,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional React bindings for libbitsub bitmap subtitles.
|
|
3
|
+
*
|
|
4
|
+
* Peer dependency: react >= 18
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useRef } from 'react'
|
|
9
|
+
* import { useBitSub } from 'libbitsub/react'
|
|
10
|
+
*
|
|
11
|
+
* function Player({ src, subUrl }: { src: string; subUrl: string }) {
|
|
12
|
+
* const videoRef = useRef<HTMLVideoElement>(null)
|
|
13
|
+
* useBitSub(videoRef, { subUrl })
|
|
14
|
+
* return (
|
|
15
|
+
* <div style={{ position: 'relative' }}>
|
|
16
|
+
* <video ref={videoRef} src={src} controls playsInline />
|
|
17
|
+
* </div>
|
|
18
|
+
* )
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Prefer either `useBitSub` *or* `BitSubOverlay` for a given video — not both.
|
|
23
|
+
*/
|
|
24
|
+
import { type CSSProperties, type ReactElement, type RefObject } from 'react';
|
|
25
|
+
import { type BitSubController, type BitSubSourceOptions } from './shared';
|
|
26
|
+
import type { SubtitleDisplaySettings } from '../wrapper';
|
|
27
|
+
export type BitSubReactSource = BitSubSourceOptions;
|
|
28
|
+
export interface UseBitSubOptions extends BitSubReactSource {
|
|
29
|
+
/** When false, do not load even if source fields are set. Default true. */
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface UseBitSubResult {
|
|
33
|
+
controller: BitSubController | null;
|
|
34
|
+
error: Error | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Bind a libbitsub renderer to a video element ref for the lifetime of the source.
|
|
38
|
+
* Cleans up automatically on unmount or when the source identity changes.
|
|
39
|
+
*/
|
|
40
|
+
export declare function useBitSub(videoRef: RefObject<HTMLVideoElement | null>, options: UseBitSubOptions | null): UseBitSubResult;
|
|
41
|
+
export interface BitSubOverlayProps extends UseBitSubOptions {
|
|
42
|
+
videoRef: RefObject<HTMLVideoElement | null>;
|
|
43
|
+
/** Optional class name applied to a zero-size host span for debugging. */
|
|
44
|
+
className?: string;
|
|
45
|
+
style?: CSSProperties;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Declarative overlay helper. Renders nothing visible itself — libbitsub attaches
|
|
49
|
+
* its canvas next to the video element. Useful when you want JSX-configured tracks.
|
|
50
|
+
*/
|
|
51
|
+
export declare function BitSubOverlay(props: BitSubOverlayProps): ReactElement | null;
|
|
52
|
+
export type { AttachBitSubOptions, BitSubController, BitSubSourceOptions, BitSubRenderer } from './shared';
|
|
53
|
+
export { attachBitSub, createBitSubRenderer } from './shared';
|
|
54
|
+
export type { SubtitleDisplaySettings };
|
|
55
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/integrations/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAA+B,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC1G,OAAO,EAA0C,KAAK,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAClH,OAAO,KAAK,EAAE,uBAAuB,EAAoD,MAAM,YAAY,CAAA;AAE3G,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAA;AAEnD,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACnC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAoBD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,EAC5C,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC/B,eAAe,CAiFjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,QAAQ,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC5C,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,GAAG,IAAI,CAM5E;AAED,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC7D,YAAY,EAAE,uBAAuB,EAAE,CAAA"}
|