1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Migrate back from JASSUB to JavascriptSubtitlesOctopus

JASSUB has some problems with non-Latin languages.

This reverts:
3560715f41
0b3d2d841f
93c4dbbe4c
478f81fecf
f0e8eb52bb
52c8cffc82
This commit is contained in:
Dmitry Lyzo 2024-03-17 17:18:23 +03:00
parent 2e3a8300d1
commit 8125c68d24
5 changed files with 76 additions and 138 deletions

48
package-lock.json generated
View file

@ -17,6 +17,7 @@
"@fontsource/noto-sans-kr": "5.0.17", "@fontsource/noto-sans-kr": "5.0.17",
"@fontsource/noto-sans-sc": "5.0.17", "@fontsource/noto-sans-sc": "5.0.17",
"@fontsource/noto-sans-tc": "5.0.17", "@fontsource/noto-sans-tc": "5.0.17",
"@jellyfin/libass-wasm": "4.1.1",
"@jellyfin/sdk": "0.0.0-unstable.202403240502", "@jellyfin/sdk": "0.0.0-unstable.202403240502",
"@loadable/component": "5.16.3", "@loadable/component": "5.16.3",
"@mui/icons-material": "5.15.11", "@mui/icons-material": "5.15.11",
@ -35,14 +36,12 @@
"dompurify": "3.0.1", "dompurify": "3.0.1",
"epubjs": "0.3.93", "epubjs": "0.3.93",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"event-target-polyfill": "github:ThaUnknown/event-target-polyfill",
"fast-text-encoding": "1.0.6", "fast-text-encoding": "1.0.6",
"flv.js": "1.6.2", "flv.js": "1.6.2",
"headroom.js": "0.12.0", "headroom.js": "0.12.0",
"history": "5.3.0", "history": "5.3.0",
"hls.js": "1.5.7", "hls.js": "1.5.7",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"jassub": "1.7.15",
"jellyfin-apiclient": "1.11.0", "jellyfin-apiclient": "1.11.0",
"jquery": "3.7.1", "jquery": "3.7.1",
"jstree": "3.3.16", "jstree": "3.3.16",
@ -3640,6 +3639,11 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true "dev": true
}, },
"node_modules/@jellyfin/libass-wasm": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@jellyfin/libass-wasm/-/libass-wasm-4.1.1.tgz",
"integrity": "sha512-xQVJw+lZUg4U1TmLS80reBECfPtpCgRF8hhUSvUUQM9g68OvINyUU3K2yqRH+8tomGpghiRaIcr/bUJ83e0veA=="
},
"node_modules/@jellyfin/sdk": { "node_modules/@jellyfin/sdk": {
"version": "0.0.0-unstable.202403240502", "version": "0.0.0-unstable.202403240502",
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202403240502.tgz", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202403240502.tgz",
@ -9306,11 +9310,6 @@
"es5-ext": "~0.10.14" "es5-ext": "~0.10.14"
} }
}, },
"node_modules/event-target-polyfill": {
"version": "0.0.3",
"resolved": "git+ssh://git@github.com/ThaUnknown/event-target-polyfill.git#5cb9a0ed6774af1b905b525964316911375726a7",
"license": "MIT"
},
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -12228,14 +12227,6 @@
"set-function-name": "^2.0.1" "set-function-name": "^2.0.1"
} }
}, },
"node_modules/jassub": {
"version": "1.7.15",
"resolved": "https://registry.npmjs.org/jassub/-/jassub-1.7.15.tgz",
"integrity": "sha512-8yKAJc++Y1gNfATOPRo3APk0JUhshKl5l7bRkT6WkJ8XP4RvYfVPb6ieH6WDxsMq523exwGzNvjjPEEWT+Z1nQ==",
"dependencies": {
"rvfc-polyfill": "^1.0.7"
}
},
"node_modules/jellyfin-apiclient": { "node_modules/jellyfin-apiclient": {
"version": "1.11.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.11.0.tgz", "resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.11.0.tgz",
@ -16900,11 +16891,6 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/rvfc-polyfill": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/rvfc-polyfill/-/rvfc-polyfill-1.0.7.tgz",
"integrity": "sha512-seBl7J1J3/k0LuzW2T9fG6JIOpni5AbU+/87LA+zTYKgTVhsfShmS8K/yOo1eeEjGJHnAdkVAUUM+PEjN9Mpkw=="
},
"node_modules/safe-array-concat": { "node_modules/safe-array-concat": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
@ -25267,6 +25253,11 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true "dev": true
}, },
"@jellyfin/libass-wasm": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@jellyfin/libass-wasm/-/libass-wasm-4.1.1.tgz",
"integrity": "sha512-xQVJw+lZUg4U1TmLS80reBECfPtpCgRF8hhUSvUUQM9g68OvINyUU3K2yqRH+8tomGpghiRaIcr/bUJ83e0veA=="
},
"@jellyfin/sdk": { "@jellyfin/sdk": {
"version": "0.0.0-unstable.202403240502", "version": "0.0.0-unstable.202403240502",
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202403240502.tgz", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202403240502.tgz",
@ -29419,10 +29410,6 @@
"es5-ext": "~0.10.14" "es5-ext": "~0.10.14"
} }
}, },
"event-target-polyfill": {
"version": "git+ssh://git@github.com/ThaUnknown/event-target-polyfill.git#5cb9a0ed6774af1b905b525964316911375726a7",
"from": "event-target-polyfill@github:ThaUnknown/event-target-polyfill"
},
"eventemitter3": { "eventemitter3": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -31548,14 +31535,6 @@
"set-function-name": "^2.0.1" "set-function-name": "^2.0.1"
} }
}, },
"jassub": {
"version": "1.7.15",
"resolved": "https://registry.npmjs.org/jassub/-/jassub-1.7.15.tgz",
"integrity": "sha512-8yKAJc++Y1gNfATOPRo3APk0JUhshKl5l7bRkT6WkJ8XP4RvYfVPb6ieH6WDxsMq523exwGzNvjjPEEWT+Z1nQ==",
"requires": {
"rvfc-polyfill": "^1.0.7"
}
},
"jellyfin-apiclient": { "jellyfin-apiclient": {
"version": "1.11.0", "version": "1.11.0",
"resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.11.0.tgz", "resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.11.0.tgz",
@ -34848,11 +34827,6 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"rvfc-polyfill": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/rvfc-polyfill/-/rvfc-polyfill-1.0.7.tgz",
"integrity": "sha512-seBl7J1J3/k0LuzW2T9fG6JIOpni5AbU+/87LA+zTYKgTVhsfShmS8K/yOo1eeEjGJHnAdkVAUUM+PEjN9Mpkw=="
},
"safe-array-concat": { "safe-array-concat": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",

View file

@ -78,6 +78,7 @@
"@fontsource/noto-sans-kr": "5.0.17", "@fontsource/noto-sans-kr": "5.0.17",
"@fontsource/noto-sans-sc": "5.0.17", "@fontsource/noto-sans-sc": "5.0.17",
"@fontsource/noto-sans-tc": "5.0.17", "@fontsource/noto-sans-tc": "5.0.17",
"@jellyfin/libass-wasm": "4.1.1",
"@jellyfin/sdk": "0.0.0-unstable.202403240502", "@jellyfin/sdk": "0.0.0-unstable.202403240502",
"@loadable/component": "5.16.3", "@loadable/component": "5.16.3",
"@mui/icons-material": "5.15.11", "@mui/icons-material": "5.15.11",
@ -96,14 +97,12 @@
"dompurify": "3.0.1", "dompurify": "3.0.1",
"epubjs": "0.3.93", "epubjs": "0.3.93",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"event-target-polyfill": "github:ThaUnknown/event-target-polyfill",
"fast-text-encoding": "1.0.6", "fast-text-encoding": "1.0.6",
"flv.js": "1.6.2", "flv.js": "1.6.2",
"headroom.js": "0.12.0", "headroom.js": "0.12.0",
"history": "5.3.0", "history": "5.3.0",
"hls.js": "1.5.7", "hls.js": "1.5.7",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"jassub": "1.7.15",
"jellyfin-apiclient": "1.11.0", "jellyfin-apiclient": "1.11.0",
"jquery": "3.7.1", "jquery": "3.7.1",
"jstree": "3.3.16", "jstree": "3.3.16",
@ -146,8 +145,8 @@
"start": "npm run serve", "start": "npm run serve",
"serve": "webpack serve --config webpack.dev.js", "serve": "webpack serve --config webpack.dev.js",
"build:analyze": "cross-env NODE_ENV=\"production\" webpack --config webpack.analyze.js", "build:analyze": "cross-env NODE_ENV=\"production\" webpack --config webpack.analyze.js",
"build:development": "cross-env NODE_OPTIONS=\"--max_old_space_size=6144\" webpack --config webpack.dev.js", "build:development": "webpack --config webpack.dev.js",
"build:production": "cross-env NODE_ENV=\"production\" NODE_OPTIONS=\"--max_old_space_size=6144\" webpack --config webpack.prod.js", "build:production": "cross-env NODE_ENV=\"production\" webpack --config webpack.prod.js",
"build:check": "tsc --noEmit", "build:check": "tsc --noEmit",
"escheck": "es-check", "escheck": "es-check",
"lint": "eslint \"./\"", "lint": "eslint \"./\"",

View file

@ -217,7 +217,7 @@ export class HtmlVideoPlayer {
*/ */
#currentAssRenderer; #currentAssRenderer;
/** /**
* @type {null | undefined} * @type {number | undefined}
*/ */
#customTrackIndex; #customTrackIndex;
/** /**
@ -983,6 +983,8 @@ export class HtmlVideoPlayer {
seekOnPlaybackStart(this, e.target, this._currentPlayOptions.playerStartPositionTicks, () => { seekOnPlaybackStart(this, e.target, this._currentPlayOptions.playerStartPositionTicks, () => {
if (this.#currentAssRenderer) { if (this.#currentAssRenderer) {
this.#currentAssRenderer.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + this.#currentTrackOffset; this.#currentAssRenderer.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + this.#currentTrackOffset;
this.#currentAssRenderer.resize();
this.#currentAssRenderer.resetRenderAheadCache(false);
} }
}); });
@ -1169,9 +1171,9 @@ export class HtmlVideoPlayer {
this.#currentClock = null; this.#currentClock = null;
this._currentAspectRatio = null; this._currentAspectRatio = null;
const jassub = this.#currentAssRenderer; const octopus = this.#currentAssRenderer;
if (jassub) { if (octopus) {
jassub.destroy(); octopus.dispose();
} }
this.#currentAssRenderer = null; this.#currentAssRenderer = null;
} }
@ -1260,76 +1262,60 @@ export class HtmlVideoPlayer {
const fallbackFontList = apiClient.getUrl('/FallbackFont/Fonts', { const fallbackFontList = apiClient.getUrl('/FallbackFont/Fonts', {
api_key: apiClient.accessToken() api_key: apiClient.accessToken()
}); });
// TODO: replace with `event-target-polyfill` once https://github.com/benlesh/event-target-polyfill/pull/12 or 11 is merged const htmlVideoPlayer = this;
import('event-target-polyfill').then(() => { import('@jellyfin/libass-wasm').then(({ default: SubtitlesOctopus }) => {
import('jassub').then(({ default: JASSUB }) => { const options = {
// test SIMD support video: videoElement,
JASSUB._test(); subUrl: getTextTrackUrl(track, item),
fonts: avaliableFonts,
workerUrl: `${appRouter.baseUrl()}/libraries/subtitles-octopus-worker.js`,
legacyWorkerUrl: `${appRouter.baseUrl()}/libraries/subtitles-octopus-worker-legacy.js`,
onError() {
// HACK: Clear JavascriptSubtitlesOctopus: it gets disposed when an error occurs
htmlVideoPlayer.#currentAssRenderer = null;
const options = { // HACK: Give JavascriptSubtitlesOctopus time to dispose itself
video: videoElement, setTimeout(() => {
subUrl: getTextTrackUrl(track, item), onErrorInternal(htmlVideoPlayer, 'mediadecodeerror');
fonts: avaliableFonts, }, 0);
fallbackFont: 'liberation sans', },
availableFonts: { 'liberation sans': `${appRouter.baseUrl()}/default.woff2` }, timeOffset: (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000,
// Disabled eslint compat, but is safe as corejs3 polyfills URL
// eslint-disable-next-line compat/compat
workerUrl: new URL('jassub/dist/jassub-worker.js', import.meta.url).href,
// eslint-disable-next-line compat/compat
wasmUrl: new URL('jassub/dist/jassub-worker.wasm', import.meta.url).href,
// eslint-disable-next-line compat/compat
legacyWasmUrl: new URL('jassub/dist/jassub-worker.wasm.js', import.meta.url).href,
// eslint-disable-next-line compat/compat
modernWasmUrl : new URL('jassub/dist/jassub-worker-modern.wasm', import.meta.url).href,
timeOffset: (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000,
// new jassub options; override all, even defaults
blendMode: 'js',
asyncRender: true,
offscreenRender: true,
// RVFC is polyfilled everywhere, but webOS 2 reports polyfill API's as functional even tho they aren't
onDemandRender: browser.web0sVersion !== 2,
useLocalFonts: true,
dropAllAnimations: false,
dropAllBlur: !JASSUB._supportsSIMD,
libassMemoryLimit: 40,
libassGlyphLimit: 40,
targetFps: 24,
prescaleFactor: 0.8,
prescaleHeightLimit: 1080,
maxRenderHeight: 2160
};
Promise.all([ // new octopus options; override all, even defaults
apiClient.getNamedConfiguration('encoding'), renderMode: 'wasm-blend',
// Worker in Tizen 5 doesn't resolve relative path with async request dropAllAnimations: false,
resolveUrl(options.workerUrl), libassMemoryLimit: 40,
resolveUrl(options.legacyWorkerUrl) libassGlyphLimit: 40,
]).then(([config, workerUrl, legacyWorkerUrl]) => { targetFps: 24,
options.workerUrl = workerUrl; prescaleFactor: 0.8,
options.legacyWorkerUrl = legacyWorkerUrl; prescaleHeightLimit: 1080,
maxRenderHeight: 2160,
resizeVariation: 0.2,
renderAhead: 90
};
const cleanup = () => { Promise.all([
this.#currentAssRenderer.destroy(); apiClient.getNamedConfiguration('encoding'),
this.#currentAssRenderer = null; // Worker in Tizen 5 doesn't resolve relative path with async request
onErrorInternal(this, 'mediadecodeerror'); resolveUrl(options.workerUrl),
}; resolveUrl(options.legacyWorkerUrl)
]).then(([config, workerUrl, legacyWorkerUrl]) => {
options.workerUrl = workerUrl;
options.legacyWorkerUrl = legacyWorkerUrl;
if (config.EnableFallbackFont) { if (config.EnableFallbackFont) {
apiClient.getJSON(fallbackFontList).then((fontFiles = []) => { apiClient.getJSON(fallbackFontList).then((fontFiles = []) => {
fontFiles.forEach(font => { fontFiles.forEach(font => {
const fontUrl = apiClient.getUrl(`/FallbackFont/Fonts/${font.Name}`, { const fontUrl = apiClient.getUrl(`/FallbackFont/Fonts/${font.Name}`, {
api_key: apiClient.accessToken() api_key: apiClient.accessToken()
});
avaliableFonts.push(fontUrl);
}); });
this.#currentAssRenderer = new JASSUB(options); avaliableFonts.push(fontUrl);
this.#currentAssRenderer.addEventListener('error', cleanup, { once: true });
}); });
} else { this.#currentAssRenderer = new SubtitlesOctopus(options);
this.#currentAssRenderer = new JASSUB(options); });
this.#currentAssRenderer.addEventListener('error', cleanup, { once: true }); } else {
} this.#currentAssRenderer = new SubtitlesOctopus(options);
}); }
}); });
}); });
} }

View file

@ -17,7 +17,7 @@
z-index: 1000; z-index: 1000;
} }
.videoPlayerContainer .JASSUB { .videoPlayerContainer .libassjs-canvas-parent {
order: -1; order: -1;
} }

View file

@ -10,13 +10,15 @@ const packageJson = require('./package.json');
const Assets = [ const Assets = [
'native-promise-only/npo.js', 'native-promise-only/npo.js',
'libarchive.js/dist/worker-bundle.js', 'libarchive.js/dist/worker-bundle.js',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker.js',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker.data',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker.wasm',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker-legacy.js',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker-legacy.data',
'@jellyfin/libass-wasm/dist/js/subtitles-octopus-worker-legacy.js.mem',
'pdfjs-dist/build/pdf.worker.js' 'pdfjs-dist/build/pdf.worker.js'
]; ];
const JassubWasm = [
'jassub/dist/default.woff2'
];
const LibarchiveWasm = [ const LibarchiveWasm = [
'libarchive.js/dist/wasm-gen/libarchive.js', 'libarchive.js/dist/wasm-gen/libarchive.js',
'libarchive.js/dist/wasm-gen/libarchive.wasm' 'libarchive.js/dist/wasm-gen/libarchive.wasm'
@ -102,14 +104,6 @@ const config = {
}; };
}) })
}), }),
new CopyPlugin({
patterns: JassubWasm.map(asset => {
return {
from: path.resolve(__dirname, `./node_modules/${asset}`),
to: path.resolve(__dirname, './dist')
};
})
}),
new ForkTsCheckerWebpackPlugin({ new ForkTsCheckerWebpackPlugin({
typescript: { typescript: {
configFile: path.resolve(__dirname, 'tsconfig.json') configFile: path.resolve(__dirname, 'tsconfig.json')
@ -182,8 +176,7 @@ const config = {
{ {
test: /\.(js|jsx|mjs)$/, test: /\.(js|jsx|mjs)$/,
include: [ include: [
path.resolve(__dirname, 'node_modules/event-target-polyfill'), path.resolve(__dirname, 'node_modules/@jellyfin/libass-wasm'),
path.resolve(__dirname, 'node_modules/rvfc-polyfill'),
path.resolve(__dirname, 'node_modules/@jellyfin/sdk'), path.resolve(__dirname, 'node_modules/@jellyfin/sdk'),
path.resolve(__dirname, 'node_modules/@react-hook/latest'), path.resolve(__dirname, 'node_modules/@react-hook/latest'),
path.resolve(__dirname, 'node_modules/@react-hook/passive-layout-effect'), path.resolve(__dirname, 'node_modules/@react-hook/passive-layout-effect'),
@ -224,20 +217,6 @@ const config = {
} }
}] }]
}, },
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'node_modules/jassub')
],
use: [{
loader: 'babel-loader',
options: {
cacheCompression: false,
cacheDirectory: true,
presets: ['@babel/preset-env']
}
}]
},
{ {
test: /\.worker\.ts$/, test: /\.worker\.ts$/,
exclude: /node_modules/, exclude: /node_modules/,