diff --git a/package-lock.json b/package-lock.json index c4fb4ec7ec..a2a98ed104 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "@fontsource/noto-sans-kr": "4.5.12", "@fontsource/noto-sans-sc": "4.5.12", "@fontsource/noto-sans-tc": "4.5.12", - "@jellyfin/libass-wasm": "4.1.1", "@jellyfin/sdk": "unstable", "@loadable/component": "5.15.3", "blurhash": "2.0.4", @@ -32,6 +31,7 @@ "history": "5.3.0", "hls.js": "0.14.17", "intersection-observer": "0.12.2", + "jassub": "1.4.0", "jellyfin-apiclient": "1.10.0", "jquery": "3.6.3", "jstree": "3.3.14", @@ -2580,11 +2580,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "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": { "version": "0.0.0-unstable.202302070552", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202302070552.tgz", @@ -9629,6 +9624,14 @@ "node": ">=0.10.0" } }, + "node_modules/jassub": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jassub/-/jassub-1.4.0.tgz", + "integrity": "sha512-cqUKGUCho/MgJoloMP8b/+q3IQpFBmUK/hvneFKyEruHEEEXUYWP9ksQcDX1wewF5WNvUqGGLhnvZJRZt01+Kg==", + "dependencies": { + "rvfc-polyfill": "^1.0.4" + } + }, "node_modules/jellyfin-apiclient": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.10.0.tgz", @@ -13628,6 +13631,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rvfc-polyfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rvfc-polyfill/-/rvfc-polyfill-1.0.4.tgz", + "integrity": "sha512-BemRbBDZiLB8pxoPT+2q6R30ykY1e75XBE/L1A0Ubd/3KdUoCQLqI/z4v4oNFNlN3/Rs93d3b6WoybnXhdebkw==" + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -20825,11 +20833,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "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": { "version": "0.0.0-unstable.202302070552", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202302070552.tgz", @@ -26153,6 +26156,14 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "jassub": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jassub/-/jassub-1.4.0.tgz", + "integrity": "sha512-cqUKGUCho/MgJoloMP8b/+q3IQpFBmUK/hvneFKyEruHEEEXUYWP9ksQcDX1wewF5WNvUqGGLhnvZJRZt01+Kg==", + "requires": { + "rvfc-polyfill": "^1.0.4" + } + }, "jellyfin-apiclient": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/jellyfin-apiclient/-/jellyfin-apiclient-1.10.0.tgz", @@ -29030,6 +29041,11 @@ "queue-microtask": "^1.2.2" } }, + "rvfc-polyfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rvfc-polyfill/-/rvfc-polyfill-1.0.4.tgz", + "integrity": "sha512-BemRbBDZiLB8pxoPT+2q6R30ykY1e75XBE/L1A0Ubd/3KdUoCQLqI/z4v4oNFNlN3/Rs93d3b6WoybnXhdebkw==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", diff --git a/package.json b/package.json index bafc4ff4bc..80a7d85983 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "@fontsource/noto-sans-kr": "4.5.12", "@fontsource/noto-sans-sc": "4.5.12", "@fontsource/noto-sans-tc": "4.5.12", - "@jellyfin/libass-wasm": "4.1.1", "@jellyfin/sdk": "unstable", "@loadable/component": "5.15.3", "blurhash": "2.0.4", @@ -91,6 +90,7 @@ "history": "5.3.0", "hls.js": "0.14.17", "intersection-observer": "0.12.2", + "jassub": "1.4.0", "jellyfin-apiclient": "1.10.0", "jquery": "3.6.3", "jstree": "3.3.14", diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index af136e9185..d64478005f 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -198,7 +198,7 @@ function tryRemoveElement(elem) { /** * @type {any | null | undefined} */ - #currentSubtitlesOctopus; + #currentJASSUB; /** * @type {null | undefined} */ @@ -530,9 +530,9 @@ function tryRemoveElement(elem) { const offsetValue = parseFloat(offset); // if .ass currently rendering - if (this.#currentSubtitlesOctopus) { + if (this.#currentJASSUB) { this.updateCurrentTrackOffset(offsetValue); - this.#currentSubtitlesOctopus.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue; + this.#currentJASSUB.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue; } else { const trackElement = this.getTextTrack(); // if .vtt currently rendering @@ -837,10 +837,8 @@ function tryRemoveElement(elem) { loading.hide(); seekOnPlaybackStart(this, e.target, this._currentPlayOptions.playerStartPositionTicks, () => { - if (this.#currentSubtitlesOctopus) { - this.#currentSubtitlesOctopus.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + this.#currentTrackOffset; - this.#currentSubtitlesOctopus.resize(); - this.#currentSubtitlesOctopus.resetRenderAheadCache(false); + if (this.#currentJASSUB) { + this.#currentJASSUB.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + this.#currentTrackOffset; } }); @@ -980,11 +978,11 @@ function tryRemoveElement(elem) { this.#currentClock = null; this._currentAspectRatio = null; - const octopus = this.#currentSubtitlesOctopus; - if (octopus) { - octopus.dispose(); + const jassub = this.#currentJASSUB; + if (jassub) { + jassub.destroy(); } - this.#currentSubtitlesOctopus = null; + this.#currentJASSUB = null; const renderer = this.#currentAssRenderer; if (renderer) { @@ -1066,37 +1064,30 @@ function tryRemoveElement(elem) { const fallbackFontList = apiClient.getUrl('/FallbackFont/Fonts', { api_key: apiClient.accessToken() }); - const htmlVideoPlayer = this; const options = { video: videoElement, 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.#currentSubtitlesOctopus = null; - - // HACK: Give JavascriptSubtitlesOctopus time to dispose itself - setTimeout(() => { - onErrorInternal(htmlVideoPlayer, 'mediadecodeerror'); - }, 0); - }, + workerUrl: `${appRouter.baseUrl()}/libraries/jassub-worker.js`, + legacyWorkerUrl: `${appRouter.baseUrl()}/libraries/jassub-worker-legacy.js`, timeOffset: (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000, - // new octopus options; override all, even defaults - renderMode: 'wasm-blend', + // new jassub options; override all, even defaults + blendMode: 'js', + asyncRender: true, + // firefox implements offscreen canvas, but not according to spec which causes errors + offscreenRender: !browser.firefox, + onDemandRender: true, + useLocalFonts: true, dropAllAnimations: false, libassMemoryLimit: 40, libassGlyphLimit: 40, targetFps: 24, prescaleFactor: 0.8, prescaleHeightLimit: 1080, - maxRenderHeight: 2160, - resizeVariation: 0.2, - renderAhead: 90 + maxRenderHeight: 2160 }; - import('@jellyfin/libass-wasm').then(({default: SubtitlesOctopus}) => { + import('jassub').then(({ default: JASSUB }) => { Promise.all([ apiClient.getNamedConfiguration('encoding'), // Worker in Tizen 5 doesn't resolve relative path with async request @@ -1114,11 +1105,17 @@ function tryRemoveElement(elem) { }); avaliableFonts.push(fontUrl); }); - this.#currentSubtitlesOctopus = new SubtitlesOctopus(options); + this.#currentJASSUB = new JASSUB(options); }); } else { - this.#currentSubtitlesOctopus = new SubtitlesOctopus(options); + this.#currentJASSUB = new JASSUB(options); } + + this.#currentJASSUB.addEventListener('error', ()=>{ + this.#currentJASSUB.destroy(); + this.#currentJASSUB = null; + onErrorInternal(this, 'mediadecodeerror'); + }, { once: true }); }); }); } diff --git a/webpack.common.js b/webpack.common.js index 14826c9f0b..b42f34c398 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -8,12 +8,10 @@ const { DefinePlugin } = require('webpack'); const Assets = [ 'native-promise-only/npo.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', + 'jassub/dist/jassub-worker.js', + 'jassub/dist/jassub-worker.wasm', + 'jassub/dist/jassub-worker-legacy.js', + 'jassub/dist/jassub-worker-legacy.mem', 'pdfjs-dist/build/pdf.worker.js' ];