@nomercy-entertainment/nomercy-subtitle-octopus 0.1.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/COPYRIGHT +25 -0
- package/README.md +75 -0
- package/dist/canvas-geometry.d.ts +16 -0
- package/dist/default.ttf +0 -0
- package/dist/index.d.ts +6 -0
- package/dist/lifecycle.d.ts +31 -0
- package/dist/nomercy-subtitle-octopus.js +867 -0
- package/dist/octopus.d.ts +76 -0
- package/dist/subtitles-octopus-worker-legacy.data +0 -0
- package/dist/subtitles-octopus-worker-legacy.js +298866 -0
- package/dist/subtitles-octopus-worker.data +0 -0
- package/dist/subtitles-octopus-worker.js +9929 -0
- package/dist/subtitles-octopus-worker.wasm +0 -0
- package/dist/subtitles-octopus.d.ts +42 -0
- package/dist/subtitles-octopus.js +1149 -0
- package/dist/types.d.ts +91 -0
- package/dist/url-resolution.d.ts +18 -0
- package/dist/worker-bridge.d.ts +28 -0
- package/package.json +66 -0
package/COPYRIGHT
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
The WASM binaries in the public/ directory of this package are derived from
|
|
2
|
+
libass-wasm (SubtitleOctopus), originally authored by Dador and maintained by
|
|
3
|
+
the Jellyfin project contributors.
|
|
4
|
+
|
|
5
|
+
Source: https://github.com/jellyfin/jellyfin-web (libass-wasm integration)
|
|
6
|
+
https://github.com/libass/libass
|
|
7
|
+
|
|
8
|
+
License: GNU Lesser General Public License v2.1 (LGPL-2.1)
|
|
9
|
+
The full text of LGPL-2.1 is available at:
|
|
10
|
+
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
|
11
|
+
|
|
12
|
+
The TypeScript wrapper code in src/ is original work by NoMercy Entertainment
|
|
13
|
+
and is licensed under MIT.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
libass is Copyright (C) 2006-2022 libass contributors.
|
|
18
|
+
SubtitleOctopus WASM port is Copyright (C) Dador and contributors.
|
|
19
|
+
Jellyfin libass-wasm integration is Copyright (C) Jellyfin contributors.
|
|
20
|
+
|
|
21
|
+
This package distributes the compiled WASM output only. The wrapper does not
|
|
22
|
+
incorporate any source code from the upstream projects.
|
|
23
|
+
|
|
24
|
+
TODO(NME-octopus): Replace vendored WASM binaries with an in-house Emscripten
|
|
25
|
+
build that includes NoMercy-specific patches directly in the C layer.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @nomercy-entertainment/nomercy-subtitle-octopus
|
|
2
|
+
|
|
3
|
+
NoMercy-owned TypeScript wrapper around the libass-wasm (SubtitleOctopus) WASM renderer.
|
|
4
|
+
|
|
5
|
+
This package is **not** a fork of upstream — it's a thin consumer-side wrapper that adds the patches NoMercy needs without modifying the WASM worker. The actual fork of [libass/JavascriptSubtitlesOctopus](https://github.com/libass/JavascriptSubtitlesOctopus) lives at [`@nomercy-entertainment/libass-wasm`](../nomercy-libass-wasm/) — that package owns the C++ source, Emscripten build pipeline, and the binaries.
|
|
6
|
+
|
|
7
|
+
## Patches owned here (main-thread, TypeScript)
|
|
8
|
+
|
|
9
|
+
- **Bearer token auth** — pre-fetch subtitle + font files on the main thread with `Authorization: Bearer <token>`, hand the worker blob URLs. Worker stays unmodified, never makes auth-required calls. Custom request schemes (`nmsync:`, `cast:`, `data:`, `blob:`, `file:`, etc.) bypass the same-origin guard so the token never leaks onto requests that can't carry it.
|
|
10
|
+
- **Cross-origin worker instantiation** — Blob URL + `importScripts()` shim so workers load from a different origin (CDN deployments).
|
|
11
|
+
- **Canvas geometry sync** — `ResizeObserver` against a configurable `geometrySource` element; copies six CSS properties to `canvasParent` so the libass canvas tracks the player's overlay through fullscreen / theater / float transitions.
|
|
12
|
+
- **Lifecycle race guards** — `currentLoadedUrl` + race-token pattern, orphan canvas sweep, idempotent dispose.
|
|
13
|
+
- **URL resolution** — `basePath` prepend with proper RFC-3986 absolute-URL detection (any scheme, plus protocol-relative `//host/path`).
|
|
14
|
+
|
|
15
|
+
## Binaries
|
|
16
|
+
|
|
17
|
+
`public/subtitles-octopus-worker.{js,wasm}` and `public/default.ttf` are vendored from upstream `libass-wasm@4.1.0` pending a first NoMercy build out of the sister fork (`@nomercy-entertainment/libass-wasm`). License chain reproduced in `COPYRIGHT`.
|
|
18
|
+
|
|
19
|
+
## Worker files — copy to public
|
|
20
|
+
|
|
21
|
+
The libass WASM worker files ship inside this package's `dist/` directory. Your build tool must copy them into the public/static directory so the browser can load them:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// vite.config.ts
|
|
25
|
+
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
plugins: [
|
|
29
|
+
viteStaticCopy({
|
|
30
|
+
targets: [
|
|
31
|
+
{
|
|
32
|
+
src: 'node_modules/@nomercy-entertainment/nomercy-subtitle-octopus/dist/subtitles-octopus-worker*.{js,wasm,data}',
|
|
33
|
+
dest: 'static',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then pass the copied paths when registering the plugin:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
player.addPlugin(OctopusPlugin, {
|
|
45
|
+
workerUrl: '/static/subtitles-octopus-worker.js',
|
|
46
|
+
legacyWorkerUrl: '/static/subtitles-octopus-worker-legacy.js',
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { NMSubtitleOctopus } from '@nomercy-entertainment/nomercy-subtitle-octopus';
|
|
54
|
+
|
|
55
|
+
// Pre-fetch subtitle bytes and font binaries with whatever auth pipeline you use.
|
|
56
|
+
const trackContent = await fetchAuthedText('/episode-1.ass');
|
|
57
|
+
const availableFonts = await fetchAuthedFonts('/fonts/');
|
|
58
|
+
|
|
59
|
+
const octopus = new NMSubtitleOctopus({
|
|
60
|
+
video: videoElement,
|
|
61
|
+
trackContent,
|
|
62
|
+
availableFonts,
|
|
63
|
+
geometrySource: playerContainer,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
octopus.on('rendererReady', ({ url }) => console.log('renderer ready', url));
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The renderer never performs authenticated network I/O — your consumer (or the
|
|
70
|
+
NoMercy player kit) pre-fetches every byte the worker needs and passes it as
|
|
71
|
+
`trackContent` plus a `name → blob:URL` font map.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT — TypeScript wrapper code. The vendored WASM artefact carries the upstream license chain (LGPL-2.1 / FTL / GPL-2.0 / MIT / ISC / NTP / Zlib / BSL-1.0) reproduced in `COPYRIGHT`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch 3 — ResizeObserver-driven canvas geometry sync.
|
|
3
|
+
*
|
|
4
|
+
* v1 behaviour: on every window resize the wrapper copied six CSS properties
|
|
5
|
+
* from the player container onto the libass canvas parent so the subtitle
|
|
6
|
+
* overlay stayed pixel-locked to the video even when the layout shifted.
|
|
7
|
+
*/
|
|
8
|
+
export declare class CanvasGeometry {
|
|
9
|
+
private readonly source;
|
|
10
|
+
private readonly target;
|
|
11
|
+
private observer;
|
|
12
|
+
constructor(source: HTMLElement, target: HTMLElement);
|
|
13
|
+
attach(): void;
|
|
14
|
+
detach(): void;
|
|
15
|
+
private sync;
|
|
16
|
+
}
|
package/dist/default.ttf
ADDED
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CanvasGeometry } from './canvas-geometry';
|
|
2
|
+
export { isSupportedSubtitle, Lifecycle, RaceToken, sweepOrphanCanvases } from './lifecycle';
|
|
3
|
+
export { NMSubtitleOctopus } from './octopus';
|
|
4
|
+
export type { OctopusEvents, OctopusOptions, RenderMode } from './types';
|
|
5
|
+
export { resolveUrl } from './url-resolution';
|
|
6
|
+
export { createWorker, EventEmitter, WorkerBridge } from './worker-bridge';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch 4 — Worker reuse prevention and instance lifecycle race guards.
|
|
3
|
+
*
|
|
4
|
+
* v1 behaviour: rapid subtitle switches left stale worker instances alive
|
|
5
|
+
* and stale canvas elements in the DOM. The wrapper tracked the loaded URL
|
|
6
|
+
* and aborted in-flight loads if the URL changed during async operations.
|
|
7
|
+
* Orphan `.libassjs-canvas-parent` elements were swept before each new mount.
|
|
8
|
+
*/
|
|
9
|
+
/** True when the URL points to a supported subtitle format. */
|
|
10
|
+
export declare function isSupportedSubtitle(url: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Remove stale `.libassjs-canvas-parent` elements from `container`.
|
|
13
|
+
* Prevents ghost overlays after hot-reload or rapid plugin re-init.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sweepOrphanCanvases(container: HTMLElement): void;
|
|
16
|
+
/**
|
|
17
|
+
* Lightweight race token. Callers obtain a new token before each async
|
|
18
|
+
* operation and check `.cancelled` after every await to abort stale work.
|
|
19
|
+
*/
|
|
20
|
+
export declare class RaceToken {
|
|
21
|
+
cancelled: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Thin lifecycle wrapper around a disposable resource.
|
|
25
|
+
* Tracks cleanup callbacks added during setup and runs them in reverse on destroy.
|
|
26
|
+
*/
|
|
27
|
+
export declare class Lifecycle {
|
|
28
|
+
private cleanups;
|
|
29
|
+
addCleanup(fn: () => void): void;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|