akarisub 0.2.0 → 0.2.2

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.
Files changed (46) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +56 -54
  3. package/THIRD_PARTY_NOTICES.md +1590 -0
  4. package/dist/COPYRIGHT +1588 -949
  5. package/dist/akarisub-worker.js +2 -2
  6. package/dist/akarisub-worker.wasm +0 -0
  7. package/dist/akarisub.umd.js +3 -3
  8. package/dist/index.js +3 -3
  9. package/dist/ts/index.d.ts +14 -0
  10. package/dist/ts/index.d.ts.map +1 -0
  11. package/dist/ts/index.js +17 -0
  12. package/dist/ts/index.js.map +1 -0
  13. package/dist/ts/ts/akarisub.d.ts +225 -0
  14. package/dist/ts/ts/akarisub.d.ts.map +1 -0
  15. package/dist/ts/ts/akarisub.js +1073 -0
  16. package/dist/ts/ts/akarisub.js.map +1 -0
  17. package/dist/ts/ts/types.d.ts +424 -0
  18. package/dist/ts/ts/types.d.ts.map +1 -0
  19. package/dist/ts/ts/types.js +5 -0
  20. package/dist/ts/ts/types.js.map +1 -0
  21. package/dist/ts/ts/utils.d.ts +78 -0
  22. package/dist/ts/ts/utils.d.ts.map +1 -0
  23. package/dist/ts/ts/utils.js +395 -0
  24. package/dist/ts/ts/utils.js.map +1 -0
  25. package/dist/ts/ts/webgl2-renderer.d.ts +52 -0
  26. package/dist/ts/ts/webgl2-renderer.d.ts.map +1 -0
  27. package/dist/ts/ts/webgl2-renderer.js +391 -0
  28. package/dist/ts/ts/webgl2-renderer.js.map +1 -0
  29. package/dist/ts/ts/webgpu-renderer.d.ts +62 -0
  30. package/dist/ts/ts/webgpu-renderer.d.ts.map +1 -0
  31. package/dist/ts/ts/webgpu-renderer.js +577 -0
  32. package/dist/ts/ts/webgpu-renderer.js.map +1 -0
  33. package/dist/ts/ts/worker.d.ts +6 -0
  34. package/dist/ts/ts/worker.d.ts.map +1 -0
  35. package/dist/ts/ts/worker.js +1762 -0
  36. package/dist/ts/ts/worker.js.map +1 -0
  37. package/dist/ts/wrapper.d.ts +8 -0
  38. package/dist/ts/wrapper.d.ts.map +1 -0
  39. package/dist/ts/wrapper.js +9 -0
  40. package/dist/ts/wrapper.js.map +1 -0
  41. package/package.json +9 -6
  42. package/src/ts/akarisub.ts +48 -12
  43. package/src/ts/types.ts +22 -7
  44. package/src/ts/webgl2-renderer.ts +19 -13
  45. package/src/ts/webgpu-renderer.ts +26 -71
  46. package/src/ts/worker.ts +303 -70
package/LICENSE CHANGED
@@ -21,3 +21,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
21
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  SOFTWARE.
24
+
25
+ Third-party components and bundled assets are licensed separately. See
26
+ THIRD_PARTY_NOTICES.md, also shipped as dist/COPYRIGHT, for dependency notices.
package/README.md CHANGED
@@ -25,9 +25,10 @@ AkariSub is a JS wrapper for <a href="https://github.com/libass/libass">libass</
25
25
 
26
26
  ### Fork Enhancements
27
27
 
28
- - **WebGPU Support** - Hardware-accelerated rendering using the modern WebGPU API [(on browsers which support it)](https://caniuse.com/webgpu)
28
+ - **GPU Rendering** - Hardware-accelerated rendering with an automatic fallback chain: WebGPU [(on browsers which support it)](https://caniuse.com/webgpu) → WebGL2 → Canvas2D
29
29
  - **Hyper Optimizations** - Performance improvements and intelligent caching for smoother playback
30
30
  - **Proper Fontconfig Implementation** - add Fontconfig support with multiple fallback fonts supported
31
+ - **Encrypted Subtitles** - optionally load AES-GCM encrypted subtitle payloads that are decrypted inside the worker, so plaintext never touches the main thread
31
32
  - **Statistics Reporting** - Built-in statistics and performance metrics for debugging and monitoring
32
33
  - **TypeScript Support** - Full TypeScript definitions and type safety
33
34
  - **Updated Dependencies** - All dependencies updated to their latest versions, including libass
@@ -51,7 +52,7 @@ deno add jsr:@altq/akarisub
51
52
  By default all you need to do is copy the files from the `dist/` folder of the repository into the same folder as where your JS runs, then do:
52
53
 
53
54
  ```js
54
- import AkariSub from './akarisub.es.js'
55
+ import AkariSub from './index.js'
55
56
 
56
57
  const renderer = new AkariSub({
57
58
  video: document.querySelector('video'),
@@ -65,39 +66,42 @@ If you use a bundler like Vite, you can instead do:
65
66
 
66
67
  ```js
67
68
  import AkariSub from 'akarisub'
68
- import workerUrl from 'akarisub/dist/akarisub-worker.js?url'
69
- import wasmUrl from 'akarisub/dist/akarisub-worker.wasm?url'
69
+ import workerUrl from 'akarisub/worker?url'
70
+ import wasmUrl from 'akarisub/worker.wasm?url'
70
71
 
71
72
  const renderer = new AkariSub({
72
73
  video: document.querySelector('video'),
73
74
  subContent: subtitleString,
74
- workerUrl, // you can also use: `new URL('akarisub/dist/akarisub-worker.js', import.meta.url)` instead of importing it as an url
75
+ workerUrl,
75
76
  wasmUrl
76
77
  })
77
78
  ```
78
79
 
79
80
  ## Using only with canvas
80
81
 
81
- You're also able to use it without any video. However, that requires you to set the time the subtitles should render at yourself:
82
+ You're also able to use it without any video. However, that requires you to set the time the subtitles should render at yourself. Disable `onDemandRender` (it relies on video frame callbacks) and drive the clock manually:
82
83
 
83
84
  ```js
84
- import AkariSub from './akarisub.es.js'
85
+ import AkariSub from './index.js'
85
86
 
86
87
  const renderer = new AkariSub({
87
88
  canvas: document.querySelector('canvas'),
88
- subUrl: './tracks/sub.ass'
89
+ subUrl: './tracks/sub.ass',
90
+ onDemandRender: false
89
91
  })
90
92
 
91
- renderer.setCurrentTime(15)
93
+ // setCurrentTime(isPaused?, currentTime?, rate?)
94
+ renderer.setCurrentTime(true, 15)
92
95
  ```
93
96
 
94
97
  ## Changing subtitles
95
98
 
96
- You're not limited to only display the subtitle file you referenced in your options. You're able to dynamically change subtitles on the fly. There's three methods that you can use for this specifically:
99
+ You're not limited to only display the subtitle file you referenced in your options. You're able to dynamically change subtitles on the fly. There's four methods that you can use for this specifically:
97
100
 
98
101
  - `setTrackByUrl(url):` works the same as the `subUrl` option. It will set the subtitle to display by its URL.
99
- - `setTrack(content):` works the same as the `subContent` option. It will set the subtitle to display by its content.
100
- - `freeTrack():` this simply removes the subtitles. You can use the two methods above to set a new subtitle file to be displayed.
102
+ - `setTrack(content):` works the same as the `subContent` option. It will set the subtitle to display by its content (string, `Uint8Array` or `ArrayBuffer`).
103
+ - `setEncryptedTrack(content):` works the same as the `encryptedSubContent` option. The payload is decrypted inside the worker, so plaintext subtitles are never materialized on the main thread.
104
+ - `freeTrack():` this simply removes the subtitles. You can use the methods above to set a new subtitle file to be displayed.
101
105
 
102
106
  ```js
103
107
  renderer.setTrackByUrl('/newsub.ass')
@@ -168,9 +172,9 @@ console.log(`Events: ${eventCount}, Styles: ${styleCount}`)
168
172
  | `cacheHits` | number | Number of cache hits (unchanged frames) |
169
173
  | `cacheMisses` | number | Number of cache misses (rendered frames) |
170
174
 
171
- ## WebGPU Rendering
175
+ ## GPU Rendering
172
176
 
173
- AkariSub automatically uses WebGPU for GPU-accelerated rendering when available, with automatic fallback to Canvas2D:
177
+ AkariSub automatically picks the fastest available renderer: WebGPU WebGL2 → Canvas2D. GPU renderers are used when no custom canvas is given and the browser supports them:
174
178
 
175
179
  ```typescript
176
180
  import AkariSub from 'akarisub'
@@ -178,14 +182,14 @@ import AkariSub from 'akarisub'
178
182
  const renderer = new AkariSub({
179
183
  video: document.querySelector('video'),
180
184
  subUrl: './tracks/sub.ass',
181
- preferWebGPU: true, // Enable WebGPU (default: true)
182
- onWebGPUFallback: () => {
183
- console.log('WebGPU unavailable, using Canvas2D fallback')
185
+ onCanvasFallback: () => {
186
+ console.log('No GPU renderer available, using Canvas2D fallback')
184
187
  }
185
188
  })
186
189
 
187
- // Check if WebGPU is being used
188
- if (renderer.isUsingWebGPU) {
190
+ console.log(renderer.rendererType) // 'webgpu' | 'webgl2' | 'canvas2d'
191
+
192
+ if (renderer.isUsingGPURenderer) {
189
193
  console.log('GPU-accelerated rendering enabled!')
190
194
  }
191
195
  ```
@@ -199,7 +203,7 @@ The default options are best, and automatically fallback to the next fastest opt
199
203
  | `video` | HTMLVideoElement | - | Video to use as target for rendering and event listeners |
200
204
  | `canvas` | HTMLCanvasElement | - | Canvas to use for manual handling (optional if video is provided) |
201
205
  | `blendMode` | `'js'` \| `'wasm'` | `'wasm'` | Image blending mode. WASM is better for low-end devices, JS for hardware acceleration |
202
- | `asyncRender` | boolean | `true` | Use async rendering with ImageBitmap for GPU offloading |
206
+ | `asyncRender` | boolean | auto | Render via ImageBitmap. Defaults to `true` on Canvas2D paths and `false` when a GPU renderer is active (raw buffers upload with fewer copies) or on WebKit |
203
207
  | `offscreenRender` | boolean | `true` | Render fully on the worker, greatly reduces CPU usage |
204
208
  | `onDemandRender` | boolean | `true` | Render subtitles as the video player renders frames |
205
209
  | `targetFps` | number | `24` | Target FPS when not using onDemandRender |
@@ -211,18 +215,20 @@ The default options are best, and automatically fallback to the next fastest opt
211
215
  | `dropAllAnimations` | boolean | `false` | Discard all animated tags for performance |
212
216
  | `dropAllBlur` | boolean | `false` | Drop all blur effects (~10x performance gain) |
213
217
  | `clampPos` | boolean | `false` | Clamp `\pos` values to script resolution |
218
+ | `renderAhead` | number | `0.008` | Extra seconds to render ahead, compensates pipeline latency |
214
219
  | `workerUrl` | string | `'akarisub-worker.js'` | URL to the worker script |
215
220
  | `wasmUrl` | string | `'akarisub-worker.wasm'` | URL to the WASM binary |
216
221
  | `subUrl` | string | - | URL of the subtitle file to play |
217
- | `subContent` | string | - | Content of the subtitle file to play |
222
+ | `subContent` | string \| Uint8Array \| ArrayBuffer | - | Content of the subtitle file to play |
223
+ | `encryptedSubContent` | EncryptedSubtitleContent | - | AES-GCM encrypted subtitle payload, decrypted inside the worker |
218
224
  | `fonts` | (string \| Uint8Array)[] | - | Array of font URLs or Uint8Arrays to force load |
219
225
  | `availableFonts` | Record<string, string \| Uint8Array> | `{'liberation sans': './default.woff2'}` | Available fonts map (lowercase name → URL/data) |
220
- | `fallbackFont` | string | `'liberation sans'` | Fallback font family key |
221
- | `useLocalFonts` | boolean | `false` | Use Local Font Access API if available |
222
- | `libassMemoryLimit` | number | - | libass bitmap cache memory limit in MiB |
223
- | `libassGlyphLimit` | number | - | libass glyph cache limit |
224
- | `preferWebGPU` | boolean | `true` | Prefer WebGPU renderer if available |
225
- | `onWebGPUFallback` | function | - | Callback when WebGPU is unavailable |
226
+ | `fallbackFonts` | string[] | `['liberation sans']` | Fallback font families in order, used for the fontconfig cascade |
227
+ | `useLocalFonts` | boolean | `true` | Use Local Font Access API if available |
228
+ | `libassMemoryLimit` | number | `128` | libass bitmap cache memory limit in MiB |
229
+ | `libassGlyphLimit` | number | `2048` | libass glyph cache limit |
230
+ | `fullTrackWarmup` | boolean | `false` | Pre-render early track windows after load to warm libass caches |
231
+ | `onCanvasFallback` | function | - | Callback when no GPU renderer is available (Canvas2D fallback) |
226
232
 
227
233
  ## Methods
228
234
 
@@ -231,7 +237,8 @@ The default options are best, and automatically fallback to the next fastest opt
231
237
  | Method | Parameters | Description |
232
238
  |--------|------------|-------------|
233
239
  | `setTrackByUrl(url)` | `url: string` | Load subtitle from URL |
234
- | `setTrack(content)` | `content: string` | Set subtitle from string content |
240
+ | `setTrack(content)` | `content: string \| Uint8Array \| ArrayBuffer` | Set subtitle from content |
241
+ | `setEncryptedTrack(content)` | `content: EncryptedSubtitleContent` | Set subtitle from an encrypted payload (decrypted in the worker) |
235
242
  | `freeTrack()` | - | Remove current subtitles |
236
243
 
237
244
  ### Playback Control
@@ -286,7 +293,6 @@ The default options are best, and automatically fallback to the next fastest opt
286
293
  | `resetStats()` | - | `Promise<void>` | Reset statistics counters |
287
294
  | `getEventCount()` | - | `Promise<number>` | Get event count (lightweight) |
288
295
  | `getStyleCount()` | - | `Promise<number>` | Get style count (lightweight) |
289
- | `runBenchmark()` | - | `void` | Run a benchmark on the worker |
290
296
 
291
297
  ### Lifecycle
292
298
 
@@ -304,8 +310,11 @@ The default options are best, and automatically fallback to the next fastest opt
304
310
  | `prescaleHeightLimit` | number | Height limit for prescaling |
305
311
  | `maxRenderHeight` | number | Maximum render height |
306
312
  | `timeOffset` | number | Subtitle time offset in seconds |
313
+ | `renderAhead` | number | Extra seconds to render ahead of the video clock |
307
314
  | `busy` | boolean | Whether the renderer is currently busy |
308
- | `isUsingWebGPU` | boolean | Whether WebGPU renderer is active (read-only) |
315
+ | `rendererType` | `'webgpu'` \| `'webgl2'` \| `'canvas2d'` | Active renderer backend (read-only) |
316
+ | `isUsingGPURenderer` | boolean | Whether a hardware-accelerated renderer is active (read-only) |
317
+ | `isUsingWebGPU` | boolean | *Deprecated* - use `rendererType === 'webgpu'` |
309
318
 
310
319
  ## Type Definitions
311
320
 
@@ -313,8 +322,8 @@ The default options are best, and automatically fallback to the next fastest opt
313
322
 
314
323
  | Property | Type | Description |
315
324
  |----------|------|-------------|
316
- | `Start` | number | Start time in seconds |
317
- | `Duration` | number | Duration in seconds |
325
+ | `Start` | number | Start time in milliseconds |
326
+ | `Duration` | number | Duration in milliseconds |
318
327
  | `Style` | string | Style name |
319
328
  | `Name` | string | Character name (informational) |
320
329
  | `MarginL` | number | Left margin override in pixels |
@@ -361,11 +370,11 @@ The default options are best, and automatically fallback to the next fastest opt
361
370
 
362
371
  ## Dependencies
363
372
 
373
+ [mise](https://mise.jdx.dev) manages the toolchain (emsdk, bun, cmake — see `mise.toml`). You additionally need the usual autotools build dependencies:
374
+
364
375
  - git
365
- - emscripten (Configure the enviroment)
366
376
  - make
367
377
  - python3
368
- - cmake
369
378
  - pkgconfig
370
379
  - patch
371
380
  - libtool
@@ -374,29 +383,22 @@ The default options are best, and automatically fallback to the next fastest opt
374
383
  - ragel - Required by Harfbuzz
375
384
  - itstool - Required by Fontconfig
376
385
  - gperf - Required by Fontconfig
377
- - licensecheck
378
386
 
379
387
  ## Get the Source
380
388
 
381
- Run git clone --recursive https://github.com/altqx/akarisub.git
382
-
383
- ## Build inside a Container
384
-
385
- ### Docker
386
-
387
- 1. Install Docker
388
- 2. ./run-docker-build.sh
389
- 3. Artifacts are in /dist/js
390
-
391
- ### Buildah
389
+ ```bash
390
+ git clone --recursive https://github.com/altqx/akarisub.git
391
+ ```
392
392
 
393
- 1. Install Buildah and a suitable backend for buildah run like crun or runc
394
- 2. ./run-buildah-build.sh
395
- 3. Artifacts are in /dist/js
393
+ ## Build
396
394
 
397
- ## Build without Containers
395
+ ```bash
396
+ mise install # installs emsdk, bun, cmake
397
+ bun install # JS dependencies
398
+ make # builds the static libs (fribidi, freetype, harfbuzz, fontconfig, libass, ...) and the WASM worker
399
+ bun run build # builds the WASM worker, TypeScript declarations and JS bundles
400
+ ```
398
401
 
399
- 1. Install the dependency packages listed above
400
- 2. make
401
- - If on macOS with libtool from brew, LIBTOOLIZE=glibtoolize make
402
- 3. Artifacts are in /dist/js
402
+ - If on macOS with libtool from brew, `LIBTOOLIZE=glibtoolize make`
403
+ - Incremental rebuilds of the worker only: `bun run build:wasm` (or `make worker`)
404
+ - Artifacts are in `dist/`