diff --git a/package.json b/package.json index 3024c0b2c..9ccf2c449 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "license": "MIT", "devDependencies": { "@crowdin/cli": "^4.14.0", - "@hrgui/libass-wasm-ts": "^1.0.3", "@types/bencode": "^2.0.4", "@types/crypto-js": "^4.2.2", "@types/mark.js": "^8.11.12", @@ -92,9 +91,9 @@ "highlight.js": "^11.11.1", "hls.js": "^1.6.15", "ini": "^6.0.0", + "jassub": "^2.4.1", "just-once": "^2.2.0", "katex": "^0.16.28", - "libass-wasm": "^4.1.0", "libheif-js": "^1.19.8", "lightgallery": "^2.9.0", "mark.js": "^8.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3592466fd..a00e2e80d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,15 +95,15 @@ importers: ini: specifier: ^6.0.0 version: 6.0.0 + jassub: + specifier: ^2.4.1 + version: 2.4.1 just-once: specifier: ^2.2.0 version: 2.2.0 katex: specifier: ^0.16.28 version: 0.16.28 - libass-wasm: - specifier: ^4.1.0 - version: 4.1.0 libheif-js: specifier: ^1.19.8 version: 1.19.8 @@ -171,9 +171,6 @@ importers: '@crowdin/cli': specifier: ^4.14.0 version: 4.14.0 - '@hrgui/libass-wasm-ts': - specifier: ^1.0.3 - version: 1.0.3 '@types/bencode': specifier: ^2.0.4 version: 2.0.4 @@ -1212,10 +1209,6 @@ packages: solid-js: ^1.4.0 solid-transition-group: ^0.0.10 - '@hrgui/libass-wasm-ts@1.0.3': - resolution: {integrity: sha512-n8RbJLrhirfgDun88jVSs0/SeLC5PZz9iost9DXZ9dAXztDzpmjlEfu+k/viM37+EbaC9gWnRdUwcnptDkjtNw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -1766,6 +1759,9 @@ packages: '@vue/shared@3.5.26': resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} + abslink@1.1.6: + resolution: {integrity: sha512-8fQgnUoVSgc1IhOrYzdDY+wTDPktbuYjds2LKf9kWYWKwDnHgXU168gdV3sPei7vevFf5m2fPZ6IQSKZkSjHVg==} + acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -2622,6 +2618,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jassub@2.4.1: + resolution: {integrity: sha512-gwCy1hkDvgrPSIQpdBa8/LZe6Pp5/Jq508ZX4KK+ABnWAe31yD6LGBNJCDTyIaXwtxahDFkbZUin6pwvx1wtVA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2670,8 +2669,8 @@ packages: layout-base@2.0.1: resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} - libass-wasm@4.1.0: - resolution: {integrity: sha512-+RbYT/uuI6VHExCmGyUuMg3A2gQOaCRTzSn8GGDSf3q4cEoUNiINd9u4RGfZXA1UKafW+Hv8bmcKIX4FKbSh0Q==} + lfa-ponyfill@1.1.0: + resolution: {integrity: sha512-YS3/DmyDdywWwoEu1ZacAudqkJ4q7WtKE9+bWlaSuEoVrXva7ChIJHMJYs19zyVc1H198pzqAreQU0r/+YNeew==} libheif-js@1.19.8: resolution: {integrity: sha512-vQJWusIxO7wavpON1dusciL8Go9jsIQ+EUrckauFYAiSTjcmLAsuJh3SszLpvkwPci3JcL41ek2n+LUZGFpPIQ==} @@ -3275,6 +3274,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rvfc-polyfill@1.0.8: + resolution: {integrity: sha512-uA+0wwTkZ4OT8v45pfDfH+7Yq8mY6MvNngiF5Sq6VBgjJsvsfgt7Q18cyZqZjfAhW9rhkgXPX0cW0R9uw7yElA==} + rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} @@ -3462,6 +3464,9 @@ packages: engines: {node: '>=10'} hasBin: true + throughput@1.0.2: + resolution: {integrity: sha512-jvK1ZXuhsggjb3qYQjMiU/AVYYiTeqT5thWvYR2yuy2LGM84P5MSSyAinwHahGsdBYKR9m9HncVR/3f3nFKkxg==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -4995,8 +5000,6 @@ snapshots: solid-js: 1.9.11 solid-transition-group: 0.3.0(solid-js@1.9.11) - '@hrgui/libass-wasm-ts@1.0.3': {} - '@iconify/types@2.0.0': {} '@iconify/utils@3.0.2': @@ -5566,6 +5569,8 @@ snapshots: '@vue/shared@3.5.26': {} + abslink@1.1.6: {} + acorn@8.16.0: {} ansi-escapes@7.2.0: @@ -6448,6 +6453,13 @@ snapshots: isexe@2.0.0: {} + jassub@2.4.1: + dependencies: + abslink: 1.1.6 + lfa-ponyfill: 1.1.0 + rvfc-polyfill: 1.0.8 + throughput: 1.0.2 + js-tokens@4.0.0: {} jsesc@3.0.2: {} @@ -6487,7 +6499,7 @@ snapshots: layout-base@2.0.1: {} - libass-wasm@4.1.0: {} + lfa-ponyfill@1.1.0: {} libheif-js@1.19.8: {} @@ -7325,6 +7337,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rvfc-polyfill@1.0.8: {} + rw@1.3.3: {} safe-buffer@5.1.2: {} @@ -7520,6 +7534,8 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + throughput@1.0.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: diff --git a/src/components/artplayer-plugin-ass/fonts/SourceHanSansCN-Bold.woff2 b/src/components/artplayer-plugin-ass/fonts/SourceHanSansCN-Bold.woff2 deleted file mode 100644 index 28d1506fd..000000000 Binary files a/src/components/artplayer-plugin-ass/fonts/SourceHanSansCN-Bold.woff2 and /dev/null differ diff --git a/src/components/artplayer-plugin-ass/fonts/TimesNewRoman.ttf b/src/components/artplayer-plugin-ass/fonts/TimesNewRoman.ttf deleted file mode 100644 index eaf5e1164..000000000 Binary files a/src/components/artplayer-plugin-ass/fonts/TimesNewRoman.ttf and /dev/null differ diff --git a/src/components/artplayer-plugin-ass/index.d.ts b/src/components/artplayer-plugin-ass/index.d.ts deleted file mode 100644 index 4b51618c7..000000000 --- a/src/components/artplayer-plugin-ass/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type Artplayer from "artplayer" -import type SubtitlesOctopus from "libass-wasm" -import { type Options } from "libass-wasm" - -export = artplayerPluginAss -export as namespace artplayerPluginAss -type Ass = { - name: "artplayerPluginAss" - instance: SubtitlesOctopus -} - -declare const artplayerPluginAss: (options: Options) => (art: Artplayer) => Ass diff --git a/src/components/artplayer-plugin-ass/index.js b/src/components/artplayer-plugin-ass/index.js deleted file mode 100644 index d64dbc967..000000000 --- a/src/components/artplayer-plugin-ass/index.js +++ /dev/null @@ -1,110 +0,0 @@ -import SubtitlesOctopus from "libass-wasm" -// import workerUrl from "libass-wasm/dist/js/subtitles-octopus-worker.js?url" -// import wasmUrl from "libass-wasm/dist/js/subtitles-octopus-worker.wasm?url" - -// import TimesNewRomanFont from "./fonts/TimesNewRoman.ttf?url" -// import fallbackFont from "./fonts/SourceHanSansCN-Bold.woff2?url" - -import { useCDN } from "~/hooks" - -const { fontsPath, libAssPath } = useCDN() - -const workerUrl = `${libAssPath()}/subtitles-octopus-worker.js` -const wasmUrl = `${libAssPath()}/subtitles-octopus-worker.wasm` - -const TimesNewRomanFont = `${fontsPath()}/TimesNewRoman.ttf` -const fallbackFont = `${fontsPath()}/SourceHanSansCN-Bold.woff2` - -let instance = null - -function isAbsoluteUrl(url) { - return /^https?:\/\//.test(url) -} - -function toAbsoluteUrl(url) { - if (isAbsoluteUrl(url)) return url - - // handle absolute URL when the `Worker` of `BLOB` type loading network resources - return new URL(url, document.baseURI).toString() -} - -function loadWorker({ workerUrl, wasmUrl }) { - return new Promise((resolve) => { - fetch(workerUrl) - .then((res) => res.text()) - .then((text) => { - let workerScriptContent = text - - workerScriptContent = workerScriptContent.replace( - /wasmBinaryFile\s*=\s*"(subtitles-octopus-worker\.wasm)"/g, - (_match, wasm) => { - if (!wasmUrl) { - wasmUrl = new URL(wasm, toAbsoluteUrl(workerUrl)).toString() - } else { - wasmUrl = toAbsoluteUrl(wasmUrl) - } - - return `wasmBinaryFile = "${wasmUrl}"` - }, - ) - - const workerBlob = new Blob([workerScriptContent], { - type: "text/javascript", - }) - resolve(URL.createObjectURL(workerBlob)) - }) - }) -} - -function setVisible(visible) { - if (instance.canvasParent) - instance.canvasParent.style.display = visible ? "block" : "none" -} - -function artplayerPluginAss(options) { - return async (art) => { - instance = new SubtitlesOctopus({ - // TODO: load available fonts from manage panel - availableFonts: { - "times new roman": toAbsoluteUrl(TimesNewRomanFont), - }, - workerUrl: await loadWorker({ workerUrl, wasmUrl }), - fallbackFont: toAbsoluteUrl(fallbackFont), - video: art.template.$video, - ...options, - }) - - instance.canvasParent.className = "artplayer-plugin-ass" - instance.canvasParent.style.cssText = ` - position: absolute; - width: 100%; - height: 100%; - user-select: none; - pointer-events: none; - z-index: 20; - ` - // switch subtitle track - art.on("artplayer-plugin-ass:switch", (subtitle) => { - instance.freeTrack() - instance.setTrackByUrl(subtitle) - setVisible(true) - }) - - // set subtitle visible - art.on("subtitle", (visible) => setVisible(visible)) - art.on("artplayer-plugin-ass:visible", (visible) => setVisible(visible)) - - // set subtitle offset - art.on("subtitleOffset", (offset) => (instance.timeOffset = offset)) - - // when player destory - art.on("destroy", () => instance.dispose()) - - return { - name: "artplayerPluginAss", - instance: instance, - } - } -} - -export default artplayerPluginAss diff --git a/src/components/artplayer-plugin-ass/index.ts b/src/components/artplayer-plugin-ass/index.ts new file mode 100644 index 000000000..118fe38bc --- /dev/null +++ b/src/components/artplayer-plugin-ass/index.ts @@ -0,0 +1,37 @@ +import type Artplayer from "artplayer" +import type { JASSUBOptions } from "jassub" +import JASSUB from "jassub" +// import modernWasmUrl from "jassub/dist/wasm/jassub-worker-modern.wasm?url" +// import wasmUrl from "jassub/dist/wasm/jassub-worker.wasm?url" + +type SubtitleSourceOption = + | { subUrl: string; subContent?: string } + | { subUrl?: string; subContent: string } + +type ArtplayerPluginAssOptions = Omit< + JASSUBOptions, + "video" | "canvas" | "subUrl" | "subContent" +> & + SubtitleSourceOption + +export default function artplayerPluginAss(option: ArtplayerPluginAssOptions) { + return (art: Artplayer) => { + const instance = new JASSUB({ + video: art.video, + debug: import.meta.env.DEV, + ...option, + } satisfies JASSUBOptions) + + instance._canvasParent?.style && + (instance._canvasParent.style.zIndex = "20") + + art.on("destroy", () => { + instance.destroy() + }) + + return { + name: "artplayerPluginAss", + instance, + } + } +} diff --git a/src/hooks/useCDN.ts b/src/hooks/useCDN.ts index 793e06776..997ed2f1d 100644 --- a/src/hooks/useCDN.ts +++ b/src/hooks/useCDN.ts @@ -47,18 +47,6 @@ export const useCDN = () => { : `${static_path}/libheif` } - const libAssPath = () => { - return import.meta.env.VITE_LITE === "true" - ? npm(packageJson.name, packageJson.version, "dist/static/libass-wasm") - : `${static_path}/libass-wasm` - } - - const fontsPath = () => { - return import.meta.env.VITE_LITE === "true" - ? npm(packageJson.name, packageJson.version, "dist/static/fonts") - : `${static_path}/fonts` - } - return { npm, monacoPath, @@ -66,7 +54,5 @@ export const useCDN = () => { mermaidJSPath, ruffleJSPath, libHeifPath, - libAssPath, - fontsPath, } } diff --git a/src/pages/home/previews/aliyun_video.tsx b/src/pages/home/previews/aliyun_video.tsx index 414839249..12cfe7839 100644 --- a/src/pages/home/previews/aliyun_video.tsx +++ b/src/pages/home/previews/aliyun_video.tsx @@ -5,9 +5,9 @@ import { getMainColor, getSettingBool, objStore, password } from "~/store" import { ObjType, PResp } from "~/types" import { ext, handleResp, notify, r, pathDir, pathJoin } from "~/utils" import Artplayer from "artplayer" -import { type Option } from "artplayer/types/option" -import { type Setting } from "artplayer/types/setting" -import { type Events } from "artplayer/types/events" +import { type Option } from "artplayer" +import { type Setting } from "artplayer" +import { type Events } from "artplayer" import artplayerPluginDanmuku from "artplayer-plugin-danmuku" import { type Option as DanmukuOption } from "artplayer-plugin-danmuku" import artplayerPluginAss from "~/components/artplayer-plugin-ass" @@ -180,7 +180,6 @@ const Preview = () => { isEnhanceAssMode = true option.plugins?.push( artplayerPluginAss({ - // debug: true, subUrl: proxyLink(defaultSubtitle, true), }), ) diff --git a/src/pages/home/previews/video.tsx b/src/pages/home/previews/video.tsx index 396b55cf8..04e046b9a 100644 --- a/src/pages/home/previews/video.tsx +++ b/src/pages/home/previews/video.tsx @@ -5,9 +5,9 @@ import { getMainColor, getSettingBool, objStore } from "~/store" import { ObjType } from "~/types" import { ext, pathDir, pathJoin } from "~/utils" import Artplayer from "artplayer" -import { type Option } from "artplayer/types/option" -import { type Setting } from "artplayer/types/setting" -import { type Events } from "artplayer/types/events" +import { type Option } from "artplayer" +import { type Setting } from "artplayer" +import { type Events } from "artplayer" import artplayerPluginDanmuku from "artplayer-plugin-danmuku" import { type Option as DanmukuOption } from "artplayer-plugin-danmuku" import artplayerPluginAss from "~/components/artplayer-plugin-ass" @@ -170,7 +170,6 @@ const Preview = () => { isEnhanceAssMode = true option.plugins?.push( artplayerPluginAss({ - // debug: true, subUrl: proxyLink(defaultSubtitle, true), }), ) diff --git a/tsconfig.json b/tsconfig.json index 5ea8deafe..a4b260ed1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,7 @@ "esModuleInterop": true, "jsx": "preserve", "jsxImportSource": "solid-js", - "types": ["vite/client", "@hrgui/libass-wasm-ts"], + "types": ["vite/client"], "noEmit": true, "isolatedModules": false, "paths": { diff --git a/vite.config.ts b/vite.config.ts index 2c28be1c0..020e70647 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -81,14 +81,6 @@ export default defineConfig({ src: "node_modules/libheif-js/libheif-wasm/libheif.{js,wasm}", dest: "static/libheif", }, - { - src: "node_modules/libass-wasm/dist/js/subtitles-octopus-worker.{js,wasm}", - dest: "static/libass-wasm", - }, - { - src: "src/components/artplayer-plugin-ass/fonts/*", - dest: "static/fonts", - }, ], }) : null,