feat: add libass-wasm as ASS subtitles renderer (#121)

* feat: add `libass-wasm` as ASS subtitles renderer

* style: specification type definition

* chore: less font file size with better visual effect

* chore: update package.json
This commit is contained in:
Jad
2023-11-15 15:54:46 +08:00
committed by GitHub
parent 3951af983a
commit dce44631b7
11 changed files with 412 additions and 43 deletions

View File

@@ -4,3 +4,6 @@ pnpm-lock.yaml
.husky
.prettierignore
.gitignore
*.ttf
*.otf
*.woff2

View File

@@ -35,6 +35,7 @@
"license": "MIT",
"devDependencies": {
"@crowdin/cli": "^3.7.10",
"@hrgui/libass-wasm-ts": "^1.0.3",
"@types/mark.js": "^8.11.8",
"@types/node": "^18.7.5",
"@types/sha256": "^0.2.0",
@@ -43,6 +44,7 @@
"husky": "^8.0.2",
"lint-staged": "^13.0.4",
"prettier": "3.0.0",
"rollup-plugin-copy": "^3.5.0",
"terser": "^5.14.2",
"typescript": "^4.7.4",
"vite": "^3.0.8",
@@ -67,6 +69,7 @@
"flv.js": "^1.6.2",
"hls.js": "^1.2.1",
"just-once": "^2.2.0",
"libass-wasm": "^4.1.0",
"lightgallery": "^2.5.0",
"mark.js": "^8.11.1",
"mitt": "^3.0.0",

196
pnpm-lock.yaml generated
View File

@@ -56,6 +56,9 @@ dependencies:
just-once:
specifier: ^2.2.0
version: 2.2.0
libass-wasm:
specifier: ^4.1.0
version: 4.1.0
lightgallery:
specifier: ^2.5.0
version: 2.5.0
@@ -109,6 +112,9 @@ devDependencies:
'@crowdin/cli':
specifier: ^3.7.10
version: 3.7.10
'@hrgui/libass-wasm-ts':
specifier: ^1.0.3
version: 1.0.3
'@types/mark.js':
specifier: ^8.11.8
version: 8.11.8
@@ -133,6 +139,9 @@ devDependencies:
prettier:
specifier: 3.0.0
version: 3.0.0
rollup-plugin-copy:
specifier: ^3.5.0
version: 3.5.0
terser:
specifier: ^5.14.2
version: 5.14.2
@@ -520,6 +529,10 @@ packages:
solid-transition-group: 0.0.12(solid-js@1.4.8)
dev: false
/@hrgui/libass-wasm-ts@1.0.3:
resolution: {integrity: sha512-n8RbJLrhirfgDun88jVSs0/SeLC5PZz9iost9DXZ9dAXztDzpmjlEfu+k/viM37+EbaC9gWnRdUwcnptDkjtNw==}
dev: true
/@jridgewell/gen-mapping@0.1.1:
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
engines: {node: '>=6.0.0'}
@@ -633,6 +646,27 @@ packages:
tslib: 2.4.0
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: true
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: true
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
dev: true
/@solid-primitives/event-listener@2.3.0(solid-js@1.4.8):
resolution: {integrity: sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==}
peerDependencies:
@@ -713,6 +747,19 @@ packages:
'@types/ms': 0.7.31
dev: false
/@types/fs-extra@8.1.4:
resolution: {integrity: sha512-OMcQKnlrkrOI0TaZ/MgVDA8LYFl7CykzFsjMj9l5x3un2nFxCY20ZFlnqrM0lcqlbs0Yro2HbnZlmopyRaoJ5w==}
dependencies:
'@types/node': 18.7.5
dev: true
/@types/glob@7.2.0:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
'@types/minimatch': 5.1.2
'@types/node': 18.7.5
dev: true
/@types/hast@2.3.4:
resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
dependencies:
@@ -749,6 +796,10 @@ packages:
resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==}
dev: false
/@types/minimatch@5.1.2:
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
dev: true
/@types/ms@0.7.31:
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
dev: false
@@ -853,6 +904,11 @@ packages:
smoothscroll: 0.4.0
dev: false
/array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
dev: true
/artplayer-plugin-danmuku@4.4.11:
resolution: {integrity: sha512-/4F8IyB29Bdr1LV1RM3FM7CdiAMsVNOOJ/HY4jaJCXnMAKThQiGa++0PhCJ07nhyGvDcZGRL2/UWJRz9zZJFNw==}
dev: false
@@ -1036,6 +1092,10 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npm.taobao.org/color-name/-/color-name-1.1.4.tgz}
dev: true
/colorette@1.4.0:
resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
dev: true
/colorette@2.0.19:
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==, tarball: https://registry.npm.taobao.org/colorette/-/colorette-2.0.19.tgz}
dev: true
@@ -1159,6 +1219,13 @@ packages:
engines: {node: '>=0.3.1'}
dev: false
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
dependencies:
path-type: 4.0.0
dev: true
/dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
dependencies:
@@ -1458,6 +1525,23 @@ packages:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
/fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
dev: true
/fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
reusify: 1.0.4
dev: true
/fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
dependencies:
@@ -1503,6 +1587,15 @@ packages:
mime-types: 2.1.35
dev: false
/fs-extra@8.1.0:
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
engines: {node: '>=6 <7 || >=8'}
dependencies:
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
dev: true
/fs-minipass@1.2.7:
resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==}
dependencies:
@@ -1535,6 +1628,13 @@ packages:
engines: {node: '>=10'}
dev: true
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: true
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
@@ -1551,6 +1651,24 @@ packages:
engines: {node: '>=4'}
dev: true
/globby@10.0.1:
resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==}
engines: {node: '>=8'}
dependencies:
'@types/glob': 7.2.0
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.1
glob: 7.2.3
ignore: 5.2.4
merge2: 1.4.1
slash: 3.0.0
dev: true
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
dev: true
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
@@ -1705,6 +1823,11 @@ packages:
hasBin: true
dev: true
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
dev: true
/indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, tarball: https://registry.npm.taobao.org/indent-string/-/indent-string-4.0.0.tgz}
engines: {node: '>=8'}
@@ -1741,6 +1864,11 @@ packages:
has: 1.0.3
dev: true
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, tarball: https://registry.npm.taobao.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz}
engines: {node: '>=8'}
@@ -1751,6 +1879,13 @@ packages:
engines: {node: '>=12'}
dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: true
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, tarball: https://registry.npm.taobao.org/is-number/-/is-number-7.0.0.tgz}
engines: {node: '>=0.12.0'}
@@ -1761,6 +1896,11 @@ packages:
engines: {node: '>=12'}
dev: false
/is-plain-object@3.0.1:
resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==}
engines: {node: '>=0.10.0'}
dev: true
/is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==, tarball: https://registry.npm.taobao.org/is-stream/-/is-stream-3.0.0.tgz}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -1791,6 +1931,12 @@ packages:
hasBin: true
dev: true
/jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
optionalDependencies:
graceful-fs: 4.2.11
dev: true
/just-once@2.2.0:
resolution: {integrity: sha512-Wo547FgUOUZ98jbrZ1KX8nRezdEdtgIlC2NK1u1RvR1oZ/WoU++FjprP8J8hRbaox776MHyeMZZED4DvhhHVjg==}
dev: false
@@ -1812,6 +1958,10 @@ packages:
engines: {node: '>=6'}
dev: false
/libass-wasm@4.1.0:
resolution: {integrity: sha512-+RbYT/uuI6VHExCmGyUuMg3A2gQOaCRTzSn8GGDSf3q4cEoUNiINd9u4RGfZXA1UKafW+Hv8bmcKIX4FKbSh0Q==}
dev: false
/lightgallery@2.5.0:
resolution: {integrity: sha512-pzg5gwflLGlKaK1VqDKpb7yqQ/WSV/TxFaHRR7ld7G5iOI9gkJZ2qKKo2lyqvTvu8yAqNYXoU0w9O/Dll6POkw==}
engines: {node: '>=6.0.0'}
@@ -2043,6 +2193,11 @@ packages:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, tarball: https://registry.npm.taobao.org/merge-stream/-/merge-stream-2.0.0.tgz}
dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
dev: true
/micromark-core-commonmark@1.0.6:
resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==}
dependencies:
@@ -2505,6 +2660,11 @@ packages:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
dev: true
/pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
dev: true
@@ -2551,6 +2711,10 @@ packages:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/rechoir@0.6.2:
resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
engines: {node: '>= 0.10'}
@@ -2637,10 +2801,26 @@ packages:
signal-exit: 3.0.7
dev: true
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/rfdc@1.3.0:
resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==, tarball: https://registry.npm.taobao.org/rfdc/-/rfdc-1.3.0.tgz}
dev: true
/rollup-plugin-copy@3.5.0:
resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==}
engines: {node: '>=8.3'}
dependencies:
'@types/fs-extra': 8.1.4
colorette: 1.4.0
fs-extra: 8.1.0
globby: 10.0.1
is-plain-object: 3.0.1
dev: true
/rollup@2.77.3:
resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==}
engines: {node: '>=10.0.0'}
@@ -2649,6 +2829,12 @@ packages:
fsevents: 2.3.2
dev: true
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: true
/rxjs@7.5.7:
resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==, tarball: https://registry.npm.taobao.org/rxjs/-/rxjs-7.5.7.tgz}
dependencies:
@@ -2716,6 +2902,11 @@ packages:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, tarball: https://registry.npm.taobao.org/signal-exit/-/signal-exit-3.0.7.tgz}
dev: true
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
dev: true
/slice-ansi@3.0.0:
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==, tarball: https://registry.npm.taobao.org/slice-ansi/-/slice-ansi-3.0.0.tgz}
engines: {node: '>=8'}
@@ -3055,6 +3246,11 @@ packages:
unist-util-visit-parents: 5.1.0
dev: false
/universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
dev: true
/update-browserslist-db@1.0.5(browserslist@4.21.3):
resolution: {integrity: sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==}
hasBin: true

View File

@@ -0,0 +1,12 @@
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

View File

@@ -0,0 +1,62 @@
import SubtitlesOctopus from "libass-wasm"
import legacyWorkerUrl from "libass-wasm/dist/js/subtitles-octopus-worker-legacy.js?url"
import workerUrl from "libass-wasm/dist/js/subtitles-octopus-worker.js?url"
import TimesNewRomanFont from "./fonts/TimesNewRoman.ttf?url"
import fallbackFont from "./fonts/SourceHanSansCN-Bold.woff2?url"
let instance = null
function setVisible(visible) {
if (instance.canvasParent)
instance.canvasParent.style.display = visible ? "block" : "none"
}
function artplayerPluginAss(options) {
return (art) => {
instance = new SubtitlesOctopus({
// TODO: load available fonts from manage panel
availableFonts: {
"times new roman": TimesNewRomanFont,
},
fallbackFont,
legacyWorkerUrl,
workerUrl,
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

View File

@@ -58,3 +58,16 @@ export function VscodeIconsFileTypeAi2(props: IconProps) {
props,
)
}
export function ArtPlayerIconsSubtitle(props: IconProps) {
return IconTemplate(
{
a: {
viewBox: "0 0 48 48",
},
c: `<path d="M0 0h48v48H0z" fill="none"/>
<path fill="#ffffff" d="M40 8H8c-2.21 0-4 1.79-4 4v24c0 2.21 1.79 4 4 4h32c2.21 0 4-1.79 4-4V12c0-2.21-1.79-4-4-4zM8 24h8v4H8v-4zm20 12H8v-4h20v4zm12 0h-8v-4h8v4zm0-8H20v-4h20v4z"/>`,
},
props,
)
}

View File

@@ -6,11 +6,15 @@ import { ObjType } from "~/types"
import { ext } 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 artplayerPluginDanmuku from "artplayer-plugin-danmuku"
import artplayerPluginAss from "~/components/artplayer-plugin-ass"
import flvjs from "flv.js"
import Hls from "hls.js"
import { currentLang } from "~/app/i18n"
import { VideoBox } from "./video_box"
import { ArtPlayerIconsSubtitle } from "~/components/icons"
const Preview = () => {
const { replace, pathname } = useRouter()
@@ -80,7 +84,7 @@ const Preview = () => {
},
},
lang: ["en", "zh-cn", "zh-tw"].includes(currentLang().toLowerCase())
? (currentLang().toLowerCase() as any)
? (currentLang().toLowerCase() as string)
: "en",
lock: true,
fastForward: true,
@@ -104,51 +108,120 @@ const Preview = () => {
}
return false
})
// TODO: add a switch in manage panel to choose whether to enable `libass-wasm`
const enableEnhanceAss = true
if (subtitle.length != 0) {
option.subtitle = {
url: proxyLink(subtitle[0], true),
type: ext(subtitle[0].name) as any,
let isEnhanceAssMode = false
// set default subtitle
const defaultSubtitle = subtitle[0]
if (enableEnhanceAss && ext(defaultSubtitle.name).toLowerCase() === "ass") {
isEnhanceAssMode = true
option.plugins?.push(
artplayerPluginAss({
// debug: true,
subUrl: proxyLink(defaultSubtitle, true),
}),
)
} else {
option.subtitle = {
url: proxyLink(defaultSubtitle, true),
type: ext(defaultSubtitle.name),
}
}
// render subtitle toggle menu
const innerMenu: Setting[] = [
{
id: "setting_subtitle_display",
html: "Display",
tooltip: "Show",
switch: true,
onSwitch: function (item: Setting) {
item.tooltip = item.switch ? "Hide" : "Show"
setSubtitleVisible(!item.switch)
// sync menu subtitle tooltip
const menu_sub = option.settings?.find(
(_) => _.id === "setting_subtitle",
)
menu_sub && (menu_sub.tooltip = item.tooltip)
return !item.switch
},
},
]
subtitle.forEach((item, i) => {
innerMenu.push({
default: i === 0,
html: (
<span
title={item.name}
style={{
display: "inline-block",
"max-width": "15em",
"text-overflow": "ellipsis",
overflow: "hidden",
}}
>
{item.name}
</span>
) as HTMLElement,
name: item.name,
url: proxyLink(item, true),
})
})
option.settings?.push({
id: "setting_subtitle",
html: "Subtitle",
tooltip: "Show",
icon: ArtPlayerIconsSubtitle({ size: 24 }) as HTMLElement,
selector: innerMenu,
onSelect: function (item: Setting) {
if (enableEnhanceAss && ext(item.name).toLowerCase() === "ass") {
isEnhanceAssMode = true
this.emit("artplayer-plugin-ass:switch" as keyof Events, item.url)
setSubtitleVisible(true)
} else {
isEnhanceAssMode = false
this.subtitle.switch(item.url, { name: item.name })
this.once("subtitleLoad", setSubtitleVisible.bind(this, true))
}
const switcher = innerMenu.find(
(_) => _.id === "setting_subtitle_display",
)
if (switcher && !switcher.switch) switcher.$html?.click?.()
// sync from display switcher
return switcher?.tooltip
},
})
function setSubtitleVisible(visible: boolean) {
const type = isEnhanceAssMode ? "ass" : "webvtt"
switch (type) {
case "ass":
player.subtitle.show = false
player.emit("artplayer-plugin-ass:visible" as keyof Events, visible)
break
case "webvtt":
default:
player.subtitle.show = visible
player.emit("artplayer-plugin-ass:visible" as keyof Events, false)
break
}
}
}
if (subtitle.length != 0) {
const selector = []
selector.push({
html: "Display",
tooltip: "Show",
switch: true,
onSwitch: function (item: Setting) {
item.tooltip = item.switch ? "Hide" : "Show"
this.subtitle.show = !item.switch
return !item.switch
},
})
subtitle.map((subtitleOne, i) => {
selector.push({
default: i == 0 ? true : false,
html:
subtitleOne.name.length < 30
? subtitleOne.name
: subtitleOne.name.substr(-30, 30),
url: proxyLink(subtitleOne, true),
})
})
option.settings.push({
html: "Subtitle",
tooltip: subtitle[0].name,
icon: '<img width="22" heigth="22" src="https://www.artplayer.org/assets/img/subtitle.svg">',
selector: selector,
onSelect: function (item: Setting) {
this.subtitle.switch(item.url, {
name: item.html,
})
return item.html
},
})
}
if (danmu) {
option.plugins = [
option.plugins?.push(
artplayerPluginDanmuku({
danmuku: proxyLink(danmu, true),
speed: 5,
@@ -166,7 +239,7 @@ const Preview = () => {
maxWidth: 400,
theme: "dark",
}),
]
)
}
onMount(() => {
player = new Artplayer(option)

View File

@@ -8,7 +8,7 @@
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"types": ["vite/client", "@hrgui/libass-wasm-ts"],
"noEmit": true,
"isolatedModules": false,
"paths": {

View File

@@ -3,6 +3,7 @@ import { defineConfig } from "vite"
import solidPlugin from "vite-plugin-solid"
import legacy from "@vitejs/plugin-legacy"
import { dynamicBase } from "vite-plugin-dynamic-base"
import copyPlugin from "rollup-plugin-copy"
export default defineConfig({
resolve: {
@@ -16,6 +17,12 @@ export default defineConfig({
legacy({
targets: ["defaults"],
}),
copyPlugin({
targets: [
{ src: "node_modules/libass-wasm/**/*.wasm", dest: "dist/assets" },
],
hook: "writeBundle",
}),
dynamicBase({
// dynamic public path var string, default window.__dynamic_base__
publicPath: " window.__dynamic_base__",