libbitsub 1.7.3 → 1.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/pkg/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # libbit(map)sub
2
2
 
3
- High-performance WASM renderer for graphical subtitles (PGS and VobSub), written in Rust.
3
+ High-performance WASM renderer for graphical subtitles (PGS, VobSub, and MKS-embedded VobSub), written in Rust.
4
4
 
5
5
  Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js), this project was reworked for higher performance and broader format support. It keeps the familiar high-level PGS-oriented API while adding a lower-level parser surface, VobSub support, GPU backends, and worker-backed rendering.
6
6
 
@@ -8,6 +8,7 @@ Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js)
8
8
 
9
9
  - PGS (Blu-ray) subtitle parsing and rendering
10
10
  - VobSub (DVD) subtitle parsing and rendering
11
+ - Matroska `.mks` extraction for embedded `S_VOBSUB` tracks
11
12
  - WebGPU, WebGL2, and Canvas2D rendering with automatic fallback
12
13
  - Worker-backed parsing/rendering for large subtitle files
13
14
  - Rich layout controls: scale, horizontal/vertical offsets, alignment, bottom padding, safe area, opacity
@@ -46,15 +47,16 @@ deno add jsr:@altq/libbitsub
46
47
 
47
48
  ## Worker setup
48
49
 
49
- For best performance, make the generated WASM assets reachable by the browser so the shared worker can load them:
50
+ 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.
51
+
52
+ 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/libbitsub_bg.wasm`:
50
53
 
51
54
  ```bash
52
55
  mkdir -p public/libbitsub
53
56
  cp node_modules/libbitsub/pkg/libbitsub_bg.wasm public/libbitsub/
54
- cp node_modules/libbitsub/pkg/libbitsub.js public/libbitsub/
55
57
  ```
56
58
 
57
- `workerUrl` still exists in the option type for compatibility, but the current implementation creates an inline shared worker and resolves the WASM asset from the package loader. Supplying `workerUrl` does not change runtime behavior.
59
+ The worker is still created inline. `workerUrl` remains in the option type only for compatibility and does not change runtime behavior.
58
60
 
59
61
  ## Building from source
60
62
 
@@ -130,6 +132,12 @@ const renderer = new VobSubRenderer({
130
132
  idxUrl: '/subtitles/movie.idx'
131
133
  })
132
134
 
135
+ const mksRenderer = new VobSubRenderer({
136
+ video: videoElement,
137
+ subUrl: '/subtitles/movie.mks',
138
+ fileName: 'movie.mks'
139
+ })
140
+
133
141
  renderer.setDebandThreshold(64)
134
142
  renderer.setDebandRange(15)
135
143
  ```
@@ -146,7 +154,7 @@ const renderer = createAutoSubtitleRenderer({
146
154
  })
147
155
  ```
148
156
 
149
- Automatic detection uses file hints when available and otherwise inspects the binary payload. If the format cannot be identified confidently, it throws instead of silently forcing a parser.
157
+ Automatic detection uses file hints when available and otherwise inspects the binary payload. `.mks` sources are treated as VobSub only when they contain an embedded `S_VOBSUB` track. If the format cannot be identified confidently, it throws instead of silently forcing a parser.
150
158
 
151
159
  ## Layout controls
152
160
 
@@ -194,8 +202,11 @@ Low-level parsers expose the same model:
194
202
  ```ts
195
203
  import { PgsParser, UnifiedSubtitleParser, VobSubParserLowLevel } from 'libbitsub'
196
204
 
205
+ const vob = new VobSubParserLowLevel()
206
+ vob.loadFromMks(new Uint8Array(mksBuffer))
207
+
197
208
  const parser = new UnifiedSubtitleParser()
198
- const detected = parser.loadAuto({ data: subtitleBytes, fileName: 'track.sup' })
209
+ const detected = parser.loadAuto({ data: subtitleBytes, fileName: 'track.mks' })
199
210
 
200
211
  console.log(detected)
201
212
  console.log(parser.getMetadata())
@@ -210,6 +221,10 @@ Metadata includes:
210
221
  - PGS composition count, palette ID, composition state
211
222
  - VobSub language, track ID, IDX metadata presence, file position where available
212
223
 
224
+ ## MKS security and corruption checks
225
+
226
+ The `.mks` path validates Matroska structure before handing payloads to the VobSub decoder. Embedded subtitle blocks are size-checked, compressed blocks use bounded zlib inflation, and extracted SPU packets are rejected if their declared payload lengths or control offsets are inconsistent. Malformed or oversized `.mks` payloads fail fast instead of being partially decoded.
227
+
213
228
  ## Cache control and prefetching
214
229
 
215
230
  High-level renderers expose cache helpers:
@@ -194,6 +194,10 @@ export class SubtitleRenderer {
194
194
  * Load VobSub subtitle data from IDX and SUB.
195
195
  */
196
196
  loadVobSub(idx_content: string, sub_data: Uint8Array): void;
197
+ /**
198
+ * Load VobSub subtitle data from a Matroska subtitle container.
199
+ */
200
+ loadVobSubMks(mks_data: Uint8Array): void;
197
201
  /**
198
202
  * Load VobSub from SUB file only.
199
203
  */
@@ -303,6 +307,10 @@ export class VobSubParser {
303
307
  * Load VobSub from IDX content and SUB data.
304
308
  */
305
309
  loadFromData(idx_content: string, sub_data: Uint8Array): void;
310
+ /**
311
+ * Load VobSub from a Matroska subtitle container with embedded S_VOBSUB tracks.
312
+ */
313
+ loadFromMks(mks_data: Uint8Array): void;
306
314
  /**
307
315
  * Load VobSub from SUB file only (scans for timestamps).
308
316
  */
@@ -414,6 +422,7 @@ export interface InitOutput {
414
422
  readonly subtitlerenderer_language: (a: number) => [number, number];
415
423
  readonly subtitlerenderer_loadPgs: (a: number, b: number, c: number) => number;
416
424
  readonly subtitlerenderer_loadVobSub: (a: number, b: number, c: number, d: number, e: number) => void;
425
+ readonly subtitlerenderer_loadVobSubMks: (a: number, b: number, c: number) => [number, number];
417
426
  readonly subtitlerenderer_loadVobSubOnly: (a: number, b: number, c: number) => void;
418
427
  readonly subtitlerenderer_new: () => number;
419
428
  readonly subtitlerenderer_renderAtIndex: (a: number, b: number) => number;
@@ -441,6 +450,7 @@ export interface InitOutput {
441
450
  readonly vobsubparser_hasIdxMetadata: (a: number) => number;
442
451
  readonly vobsubparser_language: (a: number) => [number, number];
443
452
  readonly vobsubparser_loadFromData: (a: number, b: number, c: number, d: number, e: number) => void;
453
+ readonly vobsubparser_loadFromMks: (a: number, b: number, c: number) => [number, number];
444
454
  readonly vobsubparser_loadFromSubOnly: (a: number, b: number, c: number) => void;
445
455
  readonly vobsubparser_new: () => number;
446
456
  readonly vobsubparser_renderAtIndex: (a: number, b: number) => number;
@@ -458,6 +468,7 @@ export interface InitOutput {
458
468
  readonly __wbindgen_malloc: (a: number, b: number) => number;
459
469
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
460
470
  readonly __wbindgen_externrefs: WebAssembly.Table;
471
+ readonly __externref_table_dealloc: (a: number) => void;
461
472
  readonly __wbindgen_start: () => void;
462
473
  }
463
474
 
package/pkg/libbitsub.js CHANGED
@@ -494,6 +494,18 @@ export class SubtitleRenderer {
494
494
  const len1 = WASM_VECTOR_LEN;
495
495
  wasm.subtitlerenderer_loadVobSub(this.__wbg_ptr, ptr0, len0, ptr1, len1);
496
496
  }
497
+ /**
498
+ * Load VobSub subtitle data from a Matroska subtitle container.
499
+ * @param {Uint8Array} mks_data
500
+ */
501
+ loadVobSubMks(mks_data) {
502
+ const ptr0 = passArray8ToWasm0(mks_data, wasm.__wbindgen_malloc);
503
+ const len0 = WASM_VECTOR_LEN;
504
+ const ret = wasm.subtitlerenderer_loadVobSubMks(this.__wbg_ptr, ptr0, len0);
505
+ if (ret[1]) {
506
+ throw takeFromExternrefTable0(ret[0]);
507
+ }
508
+ }
497
509
  /**
498
510
  * Load VobSub from SUB file only.
499
511
  * @param {Uint8Array} sub_data
@@ -772,6 +784,18 @@ export class VobSubParser {
772
784
  const len1 = WASM_VECTOR_LEN;
773
785
  wasm.vobsubparser_loadFromData(this.__wbg_ptr, ptr0, len0, ptr1, len1);
774
786
  }
787
+ /**
788
+ * Load VobSub from a Matroska subtitle container with embedded S_VOBSUB tracks.
789
+ * @param {Uint8Array} mks_data
790
+ */
791
+ loadFromMks(mks_data) {
792
+ const ptr0 = passArray8ToWasm0(mks_data, wasm.__wbindgen_malloc);
793
+ const len0 = WASM_VECTOR_LEN;
794
+ const ret = wasm.vobsubparser_loadFromMks(this.__wbg_ptr, ptr0, len0);
795
+ if (ret[1]) {
796
+ throw takeFromExternrefTable0(ret[0]);
797
+ }
798
+ }
775
799
  /**
776
800
  * Load VobSub from SUB file only (scans for timestamps).
777
801
  * @param {Uint8Array} sub_data
@@ -865,7 +889,7 @@ export function init() {
865
889
  function __wbg_get_imports() {
866
890
  const import0 = {
867
891
  __proto__: null,
868
- __wbg___wbindgen_throw_5549492daedad139: function(arg0, arg1) {
892
+ __wbg___wbindgen_throw_81fc77679af83bc6: function(arg0, arg1) {
869
893
  throw new Error(getStringFromWasm0(arg0, arg1));
870
894
  },
871
895
  __wbg_error_a6fa202b58aa1cd3: function(arg0, arg1) {
@@ -879,7 +903,7 @@ function __wbg_get_imports() {
879
903
  wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
880
904
  }
881
905
  },
882
- __wbg_length_e6e1633fbea6cfa9: function(arg0) {
906
+ __wbg_length_0c32cb8543c8e4c8: function(arg0) {
883
907
  const ret = arg0.length;
884
908
  return ret;
885
909
  },
@@ -887,22 +911,22 @@ function __wbg_get_imports() {
887
911
  const ret = new Error();
888
912
  return ret;
889
913
  },
890
- __wbg_new_from_slice_0bc58e36f82a1b50: function(arg0, arg1) {
914
+ __wbg_new_from_slice_2580ff33d0d10520: function(arg0, arg1) {
891
915
  const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
892
916
  return ret;
893
917
  },
894
- __wbg_new_with_length_0f3108b57e05ed7c: function(arg0) {
895
- const ret = new Uint8Array(arg0 >>> 0);
918
+ __wbg_new_with_length_6402c1de5dfd4085: function(arg0) {
919
+ const ret = new Float64Array(arg0 >>> 0);
896
920
  return ret;
897
921
  },
898
- __wbg_new_with_length_4295fc6d4f8fdbb6: function(arg0) {
899
- const ret = new Float64Array(arg0 >>> 0);
922
+ __wbg_new_with_length_9cedd08484b73942: function(arg0) {
923
+ const ret = new Uint8Array(arg0 >>> 0);
900
924
  return ret;
901
925
  },
902
- __wbg_prototypesetcall_3875d54d12ef2eec: function(arg0, arg1, arg2) {
926
+ __wbg_prototypesetcall_3e05eb9545565046: function(arg0, arg1, arg2) {
903
927
  Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
904
928
  },
905
- __wbg_set_index_aba8326dc4ba779d: function(arg0, arg1, arg2) {
929
+ __wbg_set_index_e93e681c9c5b6486: function(arg0, arg1, arg2) {
906
930
  arg0[arg1 >>> 0] = arg2;
907
931
  },
908
932
  __wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
@@ -912,6 +936,11 @@ function __wbg_get_imports() {
912
936
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
913
937
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
914
938
  },
939
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
940
+ // Cast intrinsic for `Ref(String) -> Externref`.
941
+ const ret = getStringFromWasm0(arg0, arg1);
942
+ return ret;
943
+ },
915
944
  __wbindgen_init_externref_table: function() {
916
945
  const table = wasm.__wbindgen_externrefs;
917
946
  const offset = table.grow(4);
@@ -1020,6 +1049,12 @@ function passStringToWasm0(arg, malloc, realloc) {
1020
1049
  return ptr;
1021
1050
  }
1022
1051
 
1052
+ function takeFromExternrefTable0(idx) {
1053
+ const value = wasm.__wbindgen_externrefs.get(idx);
1054
+ wasm.__externref_table_dealloc(idx);
1055
+ return value;
1056
+ }
1057
+
1023
1058
  let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
1024
1059
  cachedTextDecoder.decode();
1025
1060
  const MAX_SAFARI_DECODE_BYTES = 2146435072;
Binary file
@@ -49,6 +49,7 @@ export const subtitlerenderer_hasIdxMetadata: (a: number) => number;
49
49
  export const subtitlerenderer_language: (a: number) => [number, number];
50
50
  export const subtitlerenderer_loadPgs: (a: number, b: number, c: number) => number;
51
51
  export const subtitlerenderer_loadVobSub: (a: number, b: number, c: number, d: number, e: number) => void;
52
+ export const subtitlerenderer_loadVobSubMks: (a: number, b: number, c: number) => [number, number];
52
53
  export const subtitlerenderer_loadVobSubOnly: (a: number, b: number, c: number) => void;
53
54
  export const subtitlerenderer_new: () => number;
54
55
  export const subtitlerenderer_renderAtIndex: (a: number, b: number) => number;
@@ -76,6 +77,7 @@ export const vobsubparser_getTimestamps: (a: number) => any;
76
77
  export const vobsubparser_hasIdxMetadata: (a: number) => number;
77
78
  export const vobsubparser_language: (a: number) => [number, number];
78
79
  export const vobsubparser_loadFromData: (a: number, b: number, c: number, d: number, e: number) => void;
80
+ export const vobsubparser_loadFromMks: (a: number, b: number, c: number) => [number, number];
79
81
  export const vobsubparser_loadFromSubOnly: (a: number, b: number, c: number) => void;
80
82
  export const vobsubparser_new: () => number;
81
83
  export const vobsubparser_renderAtIndex: (a: number, b: number) => number;
@@ -93,4 +95,5 @@ export const __wbindgen_free: (a: number, b: number, c: number) => void;
93
95
  export const __wbindgen_malloc: (a: number, b: number) => number;
94
96
  export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
95
97
  export const __wbindgen_externrefs: WebAssembly.Table;
98
+ export const __externref_table_dealloc: (a: number) => void;
96
99
  export const __wbindgen_start: () => void;
package/pkg/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "altqx"
6
6
  ],
7
7
  "description": "High-performance WASM renderer for graphical subtitles (PGS and VobSub)",
8
- "version": "1.7.3",
8
+ "version": "1.8.0",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",