chore: some typescript fixups and update vue and ts version

This commit is contained in:
CrazyboyQCD 2025-06-01 16:44:08 +08:00
parent 6ea9370c49
commit 32865edca5
73 changed files with 2011 additions and 1489 deletions

View File

@ -46,8 +46,6 @@ module.exports = {
format: ['PascalCase'],
},
],
'vue/multi-word-component-names': 'off',
'vue/max-attributes-per-line': 'off',
'vue/html-self-closing': 'off',
'vue/no-v-html': 'off',

View File

@ -60,9 +60,9 @@
"terser-webpack-plugin": "^5.0.1",
"to-string-loader": "^1.2.0",
"ts-node": "^10.7.0",
"typescript": "^4.9.5",
"typescript": "5.8.3",
"vue-loader": "^17.2.2",
"vue-tsc": "^1.8.1",
"vue-tsc": "^2.2.10",
"webpack": "^5.31.2",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.6.0",
@ -80,7 +80,7 @@
"protobufjs": "^6.11.2",
"streamsaver": "^2.0.6",
"tippy.js": "^6.3.1",
"vue": "^3.3.4"
"vue": "3.5.16"
},
"pnpm": {
"overrides": {

339
pnpm-lock.yaml generated
View File

@ -41,8 +41,8 @@ dependencies:
specifier: ^6.3.1
version: registry.npmmirror.com/tippy.js@6.3.7
vue:
specifier: ^3.3.4
version: registry.npmmirror.com/vue@3.5.13(typescript@4.9.5)
specifier: 3.5.16
version: registry.npmmirror.com/vue@3.5.16(typescript@5.8.3)
devDependencies:
'@babel/core':
@ -101,10 +101,10 @@ devDependencies:
version: registry.npmmirror.com/@types/ws@8.18.1
'@typescript-eslint/eslint-plugin':
specifier: ^5.50.0
version: registry.npmmirror.com/@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@4.9.5)
version: registry.npmmirror.com/@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@5.8.3)
'@typescript-eslint/parser':
specifier: ^5.50.0
version: registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5)
version: registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)
'@vue/tsconfig':
specifier: ^0.1.3
version: registry.npmmirror.com/@vue/tsconfig@0.1.3(@types/node@17.0.45)
@ -182,16 +182,16 @@ devDependencies:
version: registry.npmmirror.com/to-string-loader@1.2.0
ts-node:
specifier: ^10.7.0
version: registry.npmmirror.com/ts-node@10.9.2(@types/node@17.0.45)(typescript@4.9.5)
version: registry.npmmirror.com/ts-node@10.9.2(@types/node@17.0.45)(typescript@5.8.3)
typescript:
specifier: ^4.9.5
version: registry.npmmirror.com/typescript@4.9.5
specifier: 5.8.3
version: registry.npmmirror.com/typescript@5.8.3
vue-loader:
specifier: ^17.2.2
version: registry.npmmirror.com/vue-loader@17.4.2(vue@3.5.13)(webpack@5.99.7)
version: registry.npmmirror.com/vue-loader@17.4.2(vue@3.5.16)(webpack@5.99.7)
vue-tsc:
specifier: ^1.8.1
version: registry.npmmirror.com/vue-tsc@1.8.27(typescript@4.9.5)
specifier: ^2.2.10
version: registry.npmmirror.com/vue-tsc@2.2.10(typescript@5.8.3)
webpack:
specifier: ^5.31.2
version: registry.npmmirror.com/webpack@5.99.7(webpack-cli@4.10.0)
@ -285,7 +285,7 @@ packages:
version: 7.27.1
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
dev: true
registry.npmmirror.com/@babel/helper-compilation-targets@7.27.1:
@ -362,7 +362,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/traverse': registry.npmmirror.com/@babel/traverse@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
transitivePeerDependencies:
- supports-color
dev: true
@ -374,7 +374,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/traverse': registry.npmmirror.com/@babel/traverse@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
transitivePeerDependencies:
- supports-color
dev: true
@ -402,7 +402,7 @@ packages:
version: 7.27.1
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
dev: true
registry.npmmirror.com/@babel/helper-plugin-utils@7.27.1:
@ -453,7 +453,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/traverse': registry.npmmirror.com/@babel/traverse@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
transitivePeerDependencies:
- supports-color
dev: true
@ -485,7 +485,7 @@ packages:
dependencies:
'@babel/template': registry.npmmirror.com/@babel/template@7.27.1
'@babel/traverse': registry.npmmirror.com/@babel/traverse@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
transitivePeerDependencies:
- supports-color
dev: true
@ -508,6 +508,16 @@ packages:
hasBin: true
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.27.1
dev: true
registry.npmmirror.com/@babel/parser@7.27.4:
resolution: {integrity: sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/parser/-/parser-7.27.4.tgz}
name: '@babel/parser'
version: 7.27.4
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.27.3
registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.22.10):
resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz}
@ -1568,6 +1578,16 @@ packages:
dependencies:
'@babel/helper-string-parser': registry.npmmirror.com/@babel/helper-string-parser@7.27.1
'@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.27.1
dev: true
registry.npmmirror.com/@babel/types@7.27.3:
resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/types/-/types-7.27.3.tgz}
name: '@babel/types'
version: 7.27.3
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-string-parser': registry.npmmirror.com/@babel/helper-string-parser@7.27.1
'@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.27.1
registry.npmmirror.com/@cspotcode/source-map-support@0.8.1:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz}
@ -2297,7 +2317,7 @@ packages:
'@types/node': registry.npmmirror.com/@types/node@17.0.45
dev: true
registry.npmmirror.com/@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@4.9.5):
registry.npmmirror.com/@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@5.8.3):
resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz}
id: registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.62.0
name: '@typescript-eslint/eslint-plugin'
@ -2312,23 +2332,23 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': registry.npmmirror.com/@eslint-community/regexpp@4.12.1
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)
'@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@5.62.0
'@typescript-eslint/type-utils': registry.npmmirror.com/@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/type-utils': registry.npmmirror.com/@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)
'@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)
debug: registry.npmmirror.com/debug@4.4.0
eslint: registry.npmmirror.com/eslint@8.57.1
graphemer: registry.npmmirror.com/graphemer@1.4.0
ignore: registry.npmmirror.com/ignore@5.3.2
natural-compare-lite: registry.npmmirror.com/natural-compare-lite@1.4.0
semver: registry.npmmirror.com/semver@7.7.1
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@4.9.5)
typescript: registry.npmmirror.com/typescript@4.9.5
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@5.8.3)
typescript: registry.npmmirror.com/typescript@5.8.3
transitivePeerDependencies:
- supports-color
dev: true
registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5):
registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3):
resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.62.0.tgz}
id: registry.npmmirror.com/@typescript-eslint/parser/5.62.0
name: '@typescript-eslint/parser'
@ -2343,10 +2363,10 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@5.62.0
'@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@5.62.0
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5)
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)
debug: registry.npmmirror.com/debug@4.4.0
eslint: registry.npmmirror.com/eslint@8.57.1
typescript: registry.npmmirror.com/typescript@4.9.5
typescript: registry.npmmirror.com/typescript@5.8.3
transitivePeerDependencies:
- supports-color
dev: true
@ -2361,7 +2381,7 @@ packages:
'@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@5.62.0
dev: true
registry.npmmirror.com/@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.9.5):
registry.npmmirror.com/@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.3):
resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz}
id: registry.npmmirror.com/@typescript-eslint/type-utils/5.62.0
name: '@typescript-eslint/type-utils'
@ -2374,12 +2394,12 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5)
'@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)
'@typescript-eslint/utils': registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)
debug: registry.npmmirror.com/debug@4.4.0
eslint: registry.npmmirror.com/eslint@8.57.1
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@4.9.5)
typescript: registry.npmmirror.com/typescript@4.9.5
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@5.8.3)
typescript: registry.npmmirror.com/typescript@5.8.3
transitivePeerDependencies:
- supports-color
dev: true
@ -2391,7 +2411,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5):
registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3):
resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz}
id: registry.npmmirror.com/@typescript-eslint/typescript-estree/5.62.0
name: '@typescript-eslint/typescript-estree'
@ -2409,13 +2429,13 @@ packages:
globby: registry.npmmirror.com/globby@11.1.0
is-glob: registry.npmmirror.com/is-glob@4.0.3
semver: registry.npmmirror.com/semver@7.7.1
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@4.9.5)
typescript: registry.npmmirror.com/typescript@4.9.5
tsutils: registry.npmmirror.com/tsutils@3.21.0(typescript@5.8.3)
typescript: registry.npmmirror.com/typescript@5.8.3
transitivePeerDependencies:
- supports-color
dev: true
registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.9.5):
registry.npmmirror.com/@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.3):
resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.62.0.tgz}
id: registry.npmmirror.com/@typescript-eslint/utils/5.62.0
name: '@typescript-eslint/utils'
@ -2429,7 +2449,7 @@ packages:
'@types/semver': registry.npmmirror.com/@types/semver@7.7.0
'@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@5.62.0
'@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@5.62.0
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5)
'@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)
eslint: registry.npmmirror.com/eslint@8.57.1
eslint-scope: registry.npmmirror.com/eslint-scope@5.1.1
semver: registry.npmmirror.com/semver@7.7.1
@ -2454,137 +2474,144 @@ packages:
version: 1.3.0
dev: true
registry.npmmirror.com/@volar/language-core@1.11.1:
resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/language-core/-/language-core-1.11.1.tgz}
registry.npmmirror.com/@volar/language-core@2.4.14:
resolution: {integrity: sha512-X6beusV0DvuVseaOEy7GoagS4rYHgDHnTrdOj5jeUb49fW5ceQyP9Ej5rBhqgz2wJggl+2fDbbojq1XKaxDi6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.14.tgz}
name: '@volar/language-core'
version: 1.11.1
version: 2.4.14
dependencies:
'@volar/source-map': registry.npmmirror.com/@volar/source-map@1.11.1
'@volar/source-map': registry.npmmirror.com/@volar/source-map@2.4.14
dev: true
registry.npmmirror.com/@volar/source-map@1.11.1:
resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/source-map/-/source-map-1.11.1.tgz}
registry.npmmirror.com/@volar/source-map@2.4.14:
resolution: {integrity: sha512-5TeKKMh7Sfxo8021cJfmBzcjfY1SsXsPMMjMvjY7ivesdnybqqS+GxGAoXHAOUawQTwtdUxgP65Im+dEmvWtYQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.14.tgz}
name: '@volar/source-map'
version: 1.11.1
dependencies:
muggle-string: registry.npmmirror.com/muggle-string@0.3.1
version: 2.4.14
dev: true
registry.npmmirror.com/@volar/typescript@1.11.1:
resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/typescript/-/typescript-1.11.1.tgz}
registry.npmmirror.com/@volar/typescript@2.4.14:
resolution: {integrity: sha512-p8Z6f/bZM3/HyCdRNFZOEEzts51uV8WHeN8Tnfnm2EBv6FDB2TQLzfVx7aJvnl8ofKAOnS64B2O8bImBFaauRw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.14.tgz}
name: '@volar/typescript'
version: 1.11.1
version: 2.4.14
dependencies:
'@volar/language-core': registry.npmmirror.com/@volar/language-core@1.11.1
'@volar/language-core': registry.npmmirror.com/@volar/language-core@2.4.14
path-browserify: registry.npmmirror.com/path-browserify@1.0.1
vscode-uri: registry.npmmirror.com/vscode-uri@3.1.0
dev: true
registry.npmmirror.com/@vue/compiler-core@3.5.13:
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz}
registry.npmmirror.com/@vue/compiler-core@3.5.16:
resolution: {integrity: sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.16.tgz}
name: '@vue/compiler-core'
version: 3.5.13
version: 3.5.16
dependencies:
'@babel/parser': registry.npmmirror.com/@babel/parser@7.27.1
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@babel/parser': registry.npmmirror.com/@babel/parser@7.27.4
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
entities: registry.npmmirror.com/entities@4.5.0
estree-walker: registry.npmmirror.com/estree-walker@2.0.2
source-map-js: registry.npmmirror.com/source-map-js@1.2.1
registry.npmmirror.com/@vue/compiler-dom@3.5.13:
resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz}
registry.npmmirror.com/@vue/compiler-dom@3.5.16:
resolution: {integrity: sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz}
name: '@vue/compiler-dom'
version: 3.5.13
version: 3.5.16
dependencies:
'@vue/compiler-core': registry.npmmirror.com/@vue/compiler-core@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@vue/compiler-core': registry.npmmirror.com/@vue/compiler-core@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
registry.npmmirror.com/@vue/compiler-sfc@3.5.13:
resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz}
registry.npmmirror.com/@vue/compiler-sfc@3.5.16:
resolution: {integrity: sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz}
name: '@vue/compiler-sfc'
version: 3.5.13
version: 3.5.16
dependencies:
'@babel/parser': registry.npmmirror.com/@babel/parser@7.27.1
'@vue/compiler-core': registry.npmmirror.com/@vue/compiler-core@3.5.13
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.13
'@vue/compiler-ssr': registry.npmmirror.com/@vue/compiler-ssr@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@babel/parser': registry.npmmirror.com/@babel/parser@7.27.4
'@vue/compiler-core': registry.npmmirror.com/@vue/compiler-core@3.5.16
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.16
'@vue/compiler-ssr': registry.npmmirror.com/@vue/compiler-ssr@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
estree-walker: registry.npmmirror.com/estree-walker@2.0.2
magic-string: registry.npmmirror.com/magic-string@0.30.17
postcss: registry.npmmirror.com/postcss@8.5.3
source-map-js: registry.npmmirror.com/source-map-js@1.2.1
registry.npmmirror.com/@vue/compiler-ssr@3.5.13:
resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz}
registry.npmmirror.com/@vue/compiler-ssr@3.5.16:
resolution: {integrity: sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz}
name: '@vue/compiler-ssr'
version: 3.5.13
version: 3.5.16
dependencies:
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
registry.npmmirror.com/@vue/language-core@1.8.27(typescript@4.9.5):
resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/language-core/-/language-core-1.8.27.tgz}
id: registry.npmmirror.com/@vue/language-core/1.8.27
registry.npmmirror.com/@vue/compiler-vue2@2.7.16:
resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz}
name: '@vue/compiler-vue2'
version: 2.7.16
dependencies:
de-indent: registry.npmmirror.com/de-indent@1.0.2
he: registry.npmmirror.com/he@1.2.0
dev: true
registry.npmmirror.com/@vue/language-core@2.2.10(typescript@5.8.3):
resolution: {integrity: sha512-+yNoYx6XIKuAO8Mqh1vGytu8jkFEOH5C8iOv3i8Z/65A7x9iAOXA97Q+PqZ3nlm2lxf5rOJuIGI/wDtx/riNYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.10.tgz}
id: registry.npmmirror.com/@vue/language-core/2.2.10
name: '@vue/language-core'
version: 1.8.27
version: 2.2.10
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@volar/language-core': registry.npmmirror.com/@volar/language-core@1.11.1
'@volar/source-map': registry.npmmirror.com/@volar/source-map@1.11.1
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
computeds: registry.npmmirror.com/computeds@0.0.1
'@volar/language-core': registry.npmmirror.com/@volar/language-core@2.4.14
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.16
'@vue/compiler-vue2': registry.npmmirror.com/@vue/compiler-vue2@2.7.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
alien-signals: registry.npmmirror.com/alien-signals@1.0.13
minimatch: registry.npmmirror.com/minimatch@9.0.5
muggle-string: registry.npmmirror.com/muggle-string@0.3.1
muggle-string: registry.npmmirror.com/muggle-string@0.4.1
path-browserify: registry.npmmirror.com/path-browserify@1.0.1
typescript: registry.npmmirror.com/typescript@4.9.5
vue-template-compiler: registry.npmmirror.com/vue-template-compiler@2.7.16
typescript: registry.npmmirror.com/typescript@5.8.3
dev: true
registry.npmmirror.com/@vue/reactivity@3.5.13:
resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz}
registry.npmmirror.com/@vue/reactivity@3.5.16:
resolution: {integrity: sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.16.tgz}
name: '@vue/reactivity'
version: 3.5.13
version: 3.5.16
dependencies:
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
registry.npmmirror.com/@vue/runtime-core@3.5.13:
resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz}
registry.npmmirror.com/@vue/runtime-core@3.5.16:
resolution: {integrity: sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.16.tgz}
name: '@vue/runtime-core'
version: 3.5.13
version: 3.5.16
dependencies:
'@vue/reactivity': registry.npmmirror.com/@vue/reactivity@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@vue/reactivity': registry.npmmirror.com/@vue/reactivity@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
registry.npmmirror.com/@vue/runtime-dom@3.5.13:
resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz}
registry.npmmirror.com/@vue/runtime-dom@3.5.16:
resolution: {integrity: sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz}
name: '@vue/runtime-dom'
version: 3.5.13
version: 3.5.16
dependencies:
'@vue/reactivity': registry.npmmirror.com/@vue/reactivity@3.5.13
'@vue/runtime-core': registry.npmmirror.com/@vue/runtime-core@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
'@vue/reactivity': registry.npmmirror.com/@vue/reactivity@3.5.16
'@vue/runtime-core': registry.npmmirror.com/@vue/runtime-core@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
csstype: registry.npmmirror.com/csstype@3.1.3
registry.npmmirror.com/@vue/server-renderer@3.5.13(vue@3.5.13):
resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz}
id: registry.npmmirror.com/@vue/server-renderer/3.5.13
registry.npmmirror.com/@vue/server-renderer@3.5.16(vue@3.5.16):
resolution: {integrity: sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.16.tgz}
id: registry.npmmirror.com/@vue/server-renderer/3.5.16
name: '@vue/server-renderer'
version: 3.5.13
version: 3.5.16
peerDependencies:
vue: 3.5.13
vue: 3.5.16
dependencies:
'@vue/compiler-ssr': registry.npmmirror.com/@vue/compiler-ssr@3.5.13
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
vue: registry.npmmirror.com/vue@3.5.13(typescript@4.9.5)
'@vue/compiler-ssr': registry.npmmirror.com/@vue/compiler-ssr@3.5.16
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
vue: registry.npmmirror.com/vue@3.5.16(typescript@5.8.3)
registry.npmmirror.com/@vue/shared@3.5.13:
resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz}
registry.npmmirror.com/@vue/shared@3.5.16:
resolution: {integrity: sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/shared/-/shared-3.5.16.tgz}
name: '@vue/shared'
version: 3.5.13
version: 3.5.16
registry.npmmirror.com/@vue/tsconfig@0.1.3(@types/node@17.0.45):
resolution: {integrity: sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@vue/tsconfig/-/tsconfig-0.1.3.tgz}
@ -2891,6 +2918,12 @@ packages:
require-from-string: registry.npmmirror.com/require-from-string@2.0.2
dev: true
registry.npmmirror.com/alien-signals@1.0.13:
resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/alien-signals/-/alien-signals-1.0.13.tgz}
name: alien-signals
version: 1.0.13
dev: true
registry.npmmirror.com/ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-align/-/ansi-align-3.0.1.tgz}
name: ansi-align
@ -3531,12 +3564,6 @@ packages:
- supports-color
dev: true
registry.npmmirror.com/computeds@0.0.1:
resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/computeds/-/computeds-0.0.1.tgz}
name: computeds
version: 0.0.1
dev: true
registry.npmmirror.com/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz}
name: concat-map
@ -4157,7 +4184,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)
debug: registry.npmmirror.com/debug@3.2.7
eslint: registry.npmmirror.com/eslint@8.57.1
eslint-import-resolver-node: registry.npmmirror.com/eslint-import-resolver-node@0.3.9
@ -4179,7 +4206,7 @@ packages:
optional: true
dependencies:
'@rtsao/scc': registry.npmmirror.com/@rtsao/scc@1.1.0
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5)
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)
array-includes: registry.npmmirror.com/array-includes@3.1.8
array.prototype.findlastindex: registry.npmmirror.com/array.prototype.findlastindex@1.2.6
array.prototype.flat: registry.npmmirror.com/array.prototype.flat@1.3.3
@ -5819,10 +5846,10 @@ packages:
version: 2.1.3
dev: true
registry.npmmirror.com/muggle-string@0.3.1:
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/muggle-string/-/muggle-string-0.3.1.tgz}
registry.npmmirror.com/muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz}
name: muggle-string
version: 0.3.1
version: 0.4.1
dev: true
registry.npmmirror.com/nanoid@3.3.11:
@ -7748,7 +7775,7 @@ packages:
engines: {node: '>=6'}
dev: true
registry.npmmirror.com/ts-node@10.9.2(@types/node@17.0.45)(typescript@4.9.5):
registry.npmmirror.com/ts-node@10.9.2(@types/node@17.0.45)(typescript@5.8.3):
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ts-node/-/ts-node-10.9.2.tgz}
id: registry.npmmirror.com/ts-node/10.9.2
name: ts-node
@ -7777,7 +7804,7 @@ packages:
create-require: registry.npmmirror.com/create-require@1.1.1
diff: registry.npmmirror.com/diff@4.0.2
make-error: registry.npmmirror.com/make-error@1.3.6
typescript: registry.npmmirror.com/typescript@4.9.5
typescript: registry.npmmirror.com/typescript@5.8.3
v8-compile-cache-lib: registry.npmmirror.com/v8-compile-cache-lib@3.0.1
yn: registry.npmmirror.com/yn@3.1.1
dev: true
@ -7799,7 +7826,7 @@ packages:
version: 1.14.1
dev: true
registry.npmmirror.com/tsutils@3.21.0(typescript@4.9.5):
registry.npmmirror.com/tsutils@3.21.0(typescript@5.8.3):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz}
id: registry.npmmirror.com/tsutils/3.21.0
name: tsutils
@ -7809,7 +7836,7 @@ packages:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: registry.npmmirror.com/tslib@1.14.1
typescript: registry.npmmirror.com/typescript@4.9.5
typescript: registry.npmmirror.com/typescript@5.8.3
dev: true
registry.npmmirror.com/type-check@0.4.0:
@ -7881,11 +7908,11 @@ packages:
reflect.getprototypeof: registry.npmmirror.com/reflect.getprototypeof@1.0.10
dev: true
registry.npmmirror.com/typescript@4.9.5:
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz}
registry.npmmirror.com/typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz}
name: typescript
version: 4.9.5
engines: {node: '>=4.2.0'}
version: 5.8.3
engines: {node: '>=14.17'}
hasBin: true
registry.npmmirror.com/unbox-primitive@1.1.0:
@ -8000,6 +8027,12 @@ packages:
engines: {node: '>= 0.8'}
dev: true
registry.npmmirror.com/vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz}
name: vscode-uri
version: 3.1.0
dev: true
registry.npmmirror.com/vue-eslint-parser@9.4.3(eslint@8.57.1):
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz}
id: registry.npmmirror.com/vue-eslint-parser/9.4.3
@ -8021,7 +8054,7 @@ packages:
- supports-color
dev: true
registry.npmmirror.com/vue-loader@17.4.2(vue@3.5.13)(webpack@5.99.7):
registry.npmmirror.com/vue-loader@17.4.2(vue@3.5.16)(webpack@5.99.7):
resolution: {integrity: sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-loader/-/vue-loader-17.4.2.tgz}
id: registry.npmmirror.com/vue-loader/17.4.2
name: vue-loader
@ -8038,52 +8071,42 @@ packages:
dependencies:
chalk: registry.npmmirror.com/chalk@4.1.2
hash-sum: registry.npmmirror.com/hash-sum@2.0.0
vue: registry.npmmirror.com/vue@3.5.13(typescript@4.9.5)
vue: registry.npmmirror.com/vue@3.5.16(typescript@5.8.3)
watchpack: registry.npmmirror.com/watchpack@2.4.2
webpack: registry.npmmirror.com/webpack@5.99.7(webpack-cli@4.10.0)
dev: true
registry.npmmirror.com/vue-template-compiler@2.7.16:
resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz}
name: vue-template-compiler
version: 2.7.16
dependencies:
de-indent: registry.npmmirror.com/de-indent@1.0.2
he: registry.npmmirror.com/he@1.2.0
dev: true
registry.npmmirror.com/vue-tsc@1.8.27(typescript@4.9.5):
resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-tsc/-/vue-tsc-1.8.27.tgz}
id: registry.npmmirror.com/vue-tsc/1.8.27
registry.npmmirror.com/vue-tsc@2.2.10(typescript@5.8.3):
resolution: {integrity: sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.10.tgz}
id: registry.npmmirror.com/vue-tsc/2.2.10
name: vue-tsc
version: 1.8.27
version: 2.2.10
hasBin: true
peerDependencies:
typescript: '*'
typescript: '>=5.0.0'
dependencies:
'@volar/typescript': registry.npmmirror.com/@volar/typescript@1.11.1
'@vue/language-core': registry.npmmirror.com/@vue/language-core@1.8.27(typescript@4.9.5)
semver: registry.npmmirror.com/semver@7.7.1
typescript: registry.npmmirror.com/typescript@4.9.5
'@volar/typescript': registry.npmmirror.com/@volar/typescript@2.4.14
'@vue/language-core': registry.npmmirror.com/@vue/language-core@2.2.10(typescript@5.8.3)
typescript: registry.npmmirror.com/typescript@5.8.3
dev: true
registry.npmmirror.com/vue@3.5.13(typescript@4.9.5):
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz}
id: registry.npmmirror.com/vue/3.5.13
registry.npmmirror.com/vue@3.5.16(typescript@5.8.3):
resolution: {integrity: sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/vue/-/vue-3.5.16.tgz}
id: registry.npmmirror.com/vue/3.5.16
name: vue
version: 3.5.13
version: 3.5.16
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.13
'@vue/compiler-sfc': registry.npmmirror.com/@vue/compiler-sfc@3.5.13
'@vue/runtime-dom': registry.npmmirror.com/@vue/runtime-dom@3.5.13
'@vue/server-renderer': registry.npmmirror.com/@vue/server-renderer@3.5.13(vue@3.5.13)
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.13
typescript: registry.npmmirror.com/typescript@4.9.5
'@vue/compiler-dom': registry.npmmirror.com/@vue/compiler-dom@3.5.16
'@vue/compiler-sfc': registry.npmmirror.com/@vue/compiler-sfc@3.5.16
'@vue/runtime-dom': registry.npmmirror.com/@vue/runtime-dom@3.5.16
'@vue/server-renderer': registry.npmmirror.com/@vue/server-renderer@3.5.16(vue@3.5.16)
'@vue/shared': registry.npmmirror.com/@vue/shared@3.5.16
typescript: registry.npmmirror.com/typescript@5.8.3
registry.npmmirror.com/watchpack@2.4.2:
resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz}

View File

@ -1,5 +1,5 @@
<template>
<div class="multiple-widgets">
<div ref="el" class="multiple-widgets">
<DefaultWidget
v-for="item in items"
:key="item.name"
@ -13,30 +13,22 @@
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { DefaultWidget } from '@/ui'
import { CheckInItem, checkInItems } from './check-in-item'
import { type CheckInItem, checkInItems } from './check-in-item'
export default Vue.extend({
components: {
DefaultWidget,
},
data() {
return {
items: checkInItems,
}
},
methods: {
async runItemAction(item: CheckInItem, event: MouseEvent) {
try {
// undefined
this.$set(item, 'disabled', true)
const button = this.$el.querySelector(`[data-name='${item.name}']`) as HTMLDivElement
await item.action(button, event)
} finally {
item.disabled = false
}
},
},
})
const el = ref<HTMLDivElement>(null)
const items = reactive(checkInItems)
const runItemAction = async (item: CheckInItem, event: MouseEvent) => {
try {
// undefined
item.disabled = true
const button = el.value.querySelector(`[data-name='${item.name}']`) as HTMLDivElement
await item.action(button, event)
} finally {
item.disabled = false
}
}
</script>

View File

@ -2,9 +2,9 @@
<div ref="element" class="multiple-widgets">
<VPopup
ref="medalPopup"
v-model:open="medalOpen"
v-model="medalOpen"
class="badge-popup widgets-popup medal"
:trigger-element="medalButton"
:trigger-element="$refs.medalButton"
>
<ul>
<li
@ -28,9 +28,9 @@
<VPopup
ref="titlePopup"
v-model:open="titleOpen"
v-model="titleOpen"
class="badge-popup widgets-popup title"
:trigger-element="titleButton"
:trigger-element="$refs.titleButton"
>
<ul>
<li

View File

@ -1,4 +1,4 @@
import { OptionsOfMetadata, defineOptionsMetadata } from '@/components/define'
import { type OptionsOfMetadata, defineOptionsMetadata } from '@/components/define'
import { getNumberValidator } from '@/core/utils'
export const badgeHelperOptions = defineOptionsMetadata({

View File

@ -19,7 +19,7 @@
<script setup lang="ts">
import { computed, reactive, ref, onBeforeMount } from 'vue'
import { getComponentSettings } from '@/core/settings'
import { ChatPanelFitOptions, ChatPanelFitOptionsMinWidth } from './options'
import { type ChatPanelFitOptions, ChatPanelFitOptionsMinWidth } from './options'
const options = reactive(getComponentSettings<ChatPanelFitOptions>('liveChatPanelFit').options)
onBeforeMount(() => {

View File

@ -1,3 +1,4 @@
import type { App } from 'vue'
import { defineComponentMetadata } from '@/components/define'
import {
addComponentListener,
@ -8,7 +9,12 @@ import { select, sq } from '@/core/spin-query'
import { mountVueComponent } from '@/core/utils'
import { useScopedConsole } from '@/core/utils/log'
import { liveUrls } from '@/core/utils/urls'
import { ChatPanelFitOptions, ChatPanelFitOptionsMinWidth, chatPanelFitOptions } from './options'
import {
type ChatPanelFitOptions,
ChatPanelFitOptionsMinWidth,
chatPanelFitOptions,
} from './options'
import type ChatPanelFitDraggerVue from './ChatPanelFitDragger.vue'
const name = 'liveChatPanelFit'
const console = useScopedConsole(name)
@ -37,7 +43,8 @@ const calcPanelWidth = () => {
}
const debounceCalcPanelWidth = lodash.debounce(calcPanelWidth, 200)
let draggerInstance: Vue
let draggerInstance: InstanceType<typeof ChatPanelFitDraggerVue> | undefined
let draggerApp: App<HTMLDivElement> | undefined
const load = async () => {
addComponentListener(`${name}.targetRatio`, calcPanelWidth)
addComponentListener(`${name}.maxWidth`, calcPanelWidth)
@ -59,8 +66,10 @@ const load = async () => {
return
}
const { default: ChatPanelFitDragger } = await import('./ChatPanelFitDragger.vue')
draggerInstance = mountVueComponent(ChatPanelFitDragger)
asideToggleButton.insertAdjacentElement('afterend', draggerInstance.$el)
const [el, vm, app] = mountVueComponent(ChatPanelFitDragger)
draggerInstance = vm
draggerApp = app
asideToggleButton.insertAdjacentElement('afterend', el)
}
const unload = () => {
removeComponentListener(`${name}.targetRatio`, calcPanelWidth)
@ -70,8 +79,9 @@ const unload = () => {
document.documentElement.style.removeProperty('--live-chat-panel-width')
if (draggerInstance) {
draggerInstance.$el.remove()
draggerInstance.$destroy()
draggerApp.unmount()
draggerInstance = undefined
draggerApp = undefined
}
}

View File

@ -1,4 +1,4 @@
import { OptionsOfMetadata, defineOptionsMetadata } from '@/components/define'
import { type OptionsOfMetadata, defineOptionsMetadata } from '@/components/define'
import { getNumberValidator } from '@/core/utils'
export const ChatPanelFitOptionsMinWidth = 190

View File

@ -15,18 +15,18 @@
</ExtraOptionsPanel>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, watch, onMounted, useTemplateRef } from 'vue'
import { TextArea } from '@/ui'
import SwitchOptionsMin from './SwitchOptionsMin.vue'
import { SwitchMetadataOption } from '@/components/switch-options'
import type { SwitchMetadataOption } from '@/components/switch-options'
import ExtraOptionsPanel from './ExtraOptionsPanel.vue'
import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
import { delay } from '@/core/utils'
import { useScopedConsole } from '@/core/utils/log'
import { fontFamilyDefaultValue, coverOptionsName, coverOptionsDefaultValue } from '../data'
import { ExtraOptionsPanelInitData } from './extra-options-panel'
import type { ExtraOptionsPanelInitData } from './extra-options-panel'
const initData: ExtraOptionsPanelInitData = {
header: {
@ -89,91 +89,80 @@ for (const coverOptionName of coverOptionsName) {
const console = useScopedConsole('自定义字体')
export default defineComponent({
components: {
ExtraOptionsPanel,
TextArea,
SwitchOptionsMin,
},
const extraOptionsPanel =
useTemplateRef<InstanceType<typeof ExtraOptionsPanel>>('extraOptionsPanel')
const isPeeking = ref(false)
const isMouseOverPeekIcon = ref(false)
const inputFontFamily = ref(getComponentSettings('customFontFamily').options.fontFamily)
data() {
return {
isPeeking: false,
isMouseOverPeekIcon: false,
initData,
// inputFontFamily fontFamily
inputFontFamily: getComponentSettings('customFontFamily').options.fontFamily,
switchOptionsComponentOptions,
}
},
watch(
() => inputFontFamily.value,
lodash.debounce((value: string) => {
getComponentSettings('customFontFamily').options.fontFamily = value
}, 1000),
)
watch: {
// inputFontFamily fontFamily inputFontFamily 1000ms
inputFontFamily: lodash.debounce(value => {
getComponentSettings('customFontFamily').options.fontFamily = value
}, 1000),
watch(isMouseOverPeekIcon, async (value: boolean) => {
if (!value) {
isPeeking.value = false
return
}
if (value) {
await delay(200)
}
if (isMouseOverPeekIcon.value) {
isPeeking.value = true
}
})
async isMouseOverPeekIcon(value: boolean) {
if (!value) {
this.isPeeking = false
return
}
if (value) {
await delay(200)
}
if (this.isMouseOverPeekIcon) {
this.isPeeking = true
}
},
},
const toggleDisplay = () => {
extraOptionsPanel.value.popupOpen = !extraOptionsPanel.value.popupOpen
}
mounted() {
// v-for 使
// ref
// https://cn.vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
const setIsMouseOverPeekIconToTrue = () => {
isMouseOverPeekIcon.value = true
}
const action0Reset = this.$refs.extraOptionsPanel.$refs.action0[0].$el as HTMLElement
action0Reset.addEventListener('click', this.confirmResetOptions)
const setIsMouseOverPeekIconToFalse = () => {
isMouseOverPeekIcon.value = false
}
const action1Peek = this.$refs.extraOptionsPanel.$refs.action1[0].$el as HTMLElement
action1Peek.addEventListener('mouseover', this.setIsMouseOverPeekIconToTrue)
action1Peek.addEventListener('mouseout', this.setIsMouseOverPeekIconToFalse)
},
const resetOptions = () => {
//
getComponentSettings('customFontFamily').options.fontFamily = fontFamilyDefaultValue
inputFontFamily.value = fontFamilyDefaultValue
methods: {
toggleDisplay() {
this.$refs.extraOptionsPanel.popupOpen = !this.$refs.extraOptionsPanel.popupOpen
},
//
for (const coverOptionName of coverOptionsName) {
const defaultValue = coverOptionsDefaultValue[coverOptionName.camel]
getComponentSettings('customFontFamily').options[coverOptionName.camel] = defaultValue
}
setIsMouseOverPeekIconToTrue() {
this.isMouseOverPeekIcon = true
},
Toast.success('更多选项面板中的所有选项已成功被重置为默认值', '自定义字体', 2000)
console.log('更多选项面板中的所有选项已成功被重置为默认值')
}
setIsMouseOverPeekIconToFalse() {
this.isMouseOverPeekIcon = false
},
const confirmResetOptions = () => {
if (confirm('确定将面板中的所有选项重置为默认值吗?')) {
resetOptions()
}
}
onMounted(() => {
// v-for 使
// ref
// https://cn.vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
confirmResetOptions() {
if (confirm('确定将面板中的所有选项重置为默认值吗?')) {
this.resetOptions()
}
},
const panel = extraOptionsPanel.value
const action0Reset = panel.$refs.action0[0].$el as HTMLElement
action0Reset.addEventListener('click', confirmResetOptions)
resetOptions() {
//
getComponentSettings('customFontFamily').options.fontFamily = fontFamilyDefaultValue
this.inputFontFamily = fontFamilyDefaultValue
const action1Peek = panel.$refs.action1[0].$el as HTMLElement
action1Peek.addEventListener('mouseover', setIsMouseOverPeekIconToTrue)
action1Peek.addEventListener('mouseout', setIsMouseOverPeekIconToFalse)
})
//
for (const coverOptionName of coverOptionsName) {
const defaultValue = coverOptionsDefaultValue[coverOptionName.camel]
getComponentSettings('customFontFamily').options[coverOptionName.camel] = defaultValue
}
Toast.success('更多选项面板中的所有选项已成功被重置为默认值', '自定义字体', 2000)
console.log('更多选项面板中的所有选项已成功被重置为默认值')
},
},
defineExpose({
toggleDisplay,
})
</script>

View File

@ -1,17 +1,17 @@
import { mountVueComponent } from '@/core/utils'
import type PanelVue from './Panel.vue'
let panelVm: Vue & {
toggleDisplay: () => void
}
let panelVm: InstanceType<typeof PanelVue> | null = null
const getPanelLoadState = () => {
return Boolean(panelVm)
}
const mountPanel = async () => {
const panel = await import('./Panel.vue').then(m => m.default)
panelVm = mountVueComponent(panel)
document.body.insertAdjacentElement('beforeend', panelVm.$el)
const panel = await import('./Panel.vue')
const [el, vm] = mountVueComponent(panel)
panelVm = vm
document.body.insertAdjacentElement('beforeend', el)
}
export const loadPanel = async () => {
@ -22,5 +22,5 @@ export const loadPanel = async () => {
}
export const togglePanelDisplay = async () => {
panelVm.toggleDisplay()
panelVm?.toggleDisplay()
}

View File

@ -135,7 +135,7 @@ import {
import { popupProps, usePopup } from '../mixins'
import type { HistoryItem, TypeFilter } from './types'
import { getHistoryItems, group, HistoryType } from './types'
import { getHistoryItems, group, HistoryType, navbarFilterTypes } from './types'
function search(this: InstanceType<typeof ThisComponent>) {
this.reloadHistoryItems()

View File

@ -6,19 +6,7 @@
@click="toggleNavbarSettings()"
/>
</template>
<script lang="ts">
<script lang="ts" setup>
import { DefaultWidget } from '@/ui'
import { loadNavbarSettings, toggleNavbarSettings } from './vm'
export default Vue.extend({
components: {
DefaultWidget,
},
methods: {
async loadNavbarSettings() {
await loadNavbarSettings()
},
toggleNavbarSettings,
},
})
</script>

View File

@ -1,7 +1,8 @@
<template>
<div class="">{{ content }}</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import {
addComponentListener,
getComponentSettings,
@ -9,34 +10,19 @@ import {
} from '@/core/settings'
import type { CustomNavbarOptions } from '..'
export default Vue.extend({
data() {
return {
isBangumiLinkHidden:
getComponentSettings<CustomNavbarOptions>('customNavbar').options.hidden.includes(
'bangumi',
),
}
},
computed: {
content() {
if (this.isBangumiLinkHidden) {
return '番剧'
}
return '追番追剧'
},
},
mounted() {
addComponentListener('customNavbar.hidden', this.updateBangumiLinkStatus)
},
beforeDestroy() {
removeComponentListener('customNavbar.hidden', this.updateBangumiLinkStatus)
},
methods: {
updateBangumiLinkStatus(hiddenItems: string[]) {
const isBangumiLinkHidden = hiddenItems.includes('bangumi')
this.isBangumiLinkHidden = isBangumiLinkHidden
},
},
const isBangumiLinkHidden = ref(
getComponentSettings<CustomNavbarOptions>('customNavbar').options.hidden.includes('bangumi'),
)
const content = computed(() => (isBangumiLinkHidden.value ? '番剧' : '追番追剧'))
const updateBangumiLinkStatus = (hiddenItems: string[]) => {
isBangumiLinkHidden.value = hiddenItems.includes('bangumi')
}
onMounted(() => {
addComponentListener('customNavbar.hidden', updateBangumiLinkStatus)
})
onBeforeUnmount(() => {
removeComponentListener('customNavbar.hidden', updateBangumiLinkStatus)
})
</script>

View File

@ -8,63 +8,54 @@
<MinimalHomeOperations v-if="cards.length > 0" @refresh="refresh" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script lang="ts" setup>
import { ref, computed, useTemplateRef } from 'vue'
import { getVideoFeeds } from '@/components/feeds/api'
import type { VideoCard } from '@/components/feeds/video-card'
import VideoCardComponent from '@/components/feeds/VideoCard.vue'
import type { VideoCard as VideoCardType } from '@/components/feeds/video-card'
import VideoCard from '@/components/feeds/VideoCard.vue'
import { logError } from '@/core/utils/log'
import { ascendingStringSort } from '@/core/utils/sort'
import { ScrollTrigger, VEmpty } from '@/ui'
import type { ScrollTrigger as ScrollTriggerType } from '@/ui'
import MinimalHomeOperations from '../MinimalHomeOperations.vue'
export default defineComponent({
components: { ScrollTrigger, VEmpty, VideoCard: VideoCardComponent, MinimalHomeOperations },
data() {
return {
loading: true,
cards: [] as VideoCard[],
error: false,
}
},
computed: {
loaded(): boolean {
return !this.loading && !this.error
},
lastID(): string | null {
if (!this.cards.length) {
return null
}
const cards: VideoCard[] = [...this.cards]
return cards.sort(ascendingStringSort(c => c.id))[0].id
},
},
methods: {
async loadCards() {
try {
this.error = false
this.loading = true
this.$refs.scrollTrigger.setLoadState('loading')
this.cards = lodash.uniqBy(
[...this.cards, ...(await getVideoFeeds('video', this.lastID))],
it => it.id,
)
} catch (error) {
logError(error)
this.error = true
this.$refs.scrollTrigger.setLoadState('error')
} finally {
this.loading = false
if (this.loaded) {
this.$refs.scrollTrigger.setLoadState('loaded')
}
}
},
async refresh() {
this.cards = []
this.$refs.scrollTrigger.resetIsFirstLoad()
},
},
const loading = ref(true)
const cards = ref<VideoCardType[]>([])
const error = ref(false)
const scrollTrigger = useTemplateRef<InstanceType<typeof ScrollTriggerType>>('scrollTrigger')
const loaded = computed(() => !loading.value && !error.value)
const lastID = computed(() => {
if (!cards.value.length) {
return null
}
const sorted = [...cards.value].sort(ascendingStringSort(c => c.id))
return sorted[0].id
})
const loadCards = async () => {
try {
error.value = false
loading.value = true
scrollTrigger.value.setLoadState('loading')
const newCards = await getVideoFeeds('video', lastID.value)
cards.value = lodash.uniqBy([...cards.value, ...newCards], it => it.id)
} catch (e) {
logError(e)
error.value = true
scrollTrigger.value.setLoadState('error')
} finally {
loading.value = false
if (loaded.value) {
scrollTrigger.value.setLoadState('loaded')
}
}
}
const refresh = async () => {
cards.value = []
scrollTrigger.value.resetIsFirstLoad()
}
</script>

View File

@ -1,6 +1,5 @@
<template>
<VPopup
ref="popup"
v-model="isOpen"
class="like-black-list"
fixed
@ -44,59 +43,47 @@
</div>
</VPopup>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref, defineProps, defineEmits, watch, useTemplateRef } from 'vue'
import { VPopup, TextBox, VIcon, VButton } from '@/ui'
export default Vue.extend({
components: {
VPopup,
TextBox,
VIcon,
VButton,
},
props: {
triggerElement: {
type: HTMLElement,
default: null,
},
list: {
type: Array,
default: null,
},
titleName: {
type: String,
default: '',
},
},
data() {
return {
isOpen: false,
isLoaded: false,
name: '',
}
},
async mounted() {
this.isLoaded = true
},
methods: {
toggle() {
this.$refs.popup.toggle()
},
changeName(val: string) {
this.name = val
},
add() {
if (this.name.length && !this.list.includes(this.name)) {
// eslint-disable-next-line vue/no-mutating-props
this.list.push(this.name)
}
this.name = ''
},
toggleVisible(item: string) {
// eslint-disable-next-line vue/no-mutating-props
this.list.splice(this.list.indexOf(item), 1)
},
},
const props = defineProps<{
triggerElement?: HTMLElement | null
list?: string[]
titleName?: string
}>()
const emit = defineEmits(['update:list'])
const isOpen = ref(false)
const isLoaded = ref(false)
const name = ref('')
const list = ref<string[]>(props.list ? [...props.list] : [])
const changeName = (val: string) => {
name.value = val
}
const add = () => {
if (name.value.length && !list.value.includes(name.value)) {
list.value.push(name.value)
emit('update:list', [...list.value])
}
name.value = ''
}
function toggleVisible(item: string) {
const idx = list.value.indexOf(item)
if (idx !== -1) {
list.value.splice(idx, 1)
emit('update:list', [...list.value])
}
}
isLoaded.value = true
defineExpose({
isOpen,
})
</script>

View File

@ -2,7 +2,7 @@ import { defineComponentMetadata } from '@/components/define'
import { select } from '@/core/spin-query'
import { matchUrlPattern, playerReady } from '@/core/utils'
import { feedsUrls, videoAndBangumiUrls } from '@/core/utils/urls'
import { KeyBindingAction } from '../keymap/bindings'
import type { KeyBindingAction } from '../keymap/bindings'
import { forEachFeedsCard } from '@/components/feeds/api'
import { BlackListDataKey, loadlikeButton } from './vm'
import { getData, registerData } from '@/plugins/data'

View File

@ -5,66 +5,53 @@
</VButton>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref } from 'vue'
import { VButton, VIcon } from '@/ui'
import { getData } from '@/plugins/data'
import { BlackListDataKey } from './vm'
export default Vue.extend({
components: {
VButton,
VIcon,
},
props: {
list: {
type: Array,
default: null,
},
},
data() {
return {
isClick: false,
isLike: false,
totalLikeCnt: 0,
curLikeCnt: 0,
feedsLikeQueue: [] as HTMLElement[],
const isClick = ref(false)
const isLike = ref(false)
const totalLikeCnt = ref(0)
const curLikeCnt = ref(0)
const feedsLikeQueue = ref([] as HTMLElement[])
const like = () => {
if (isClick.value) {
return
}
isClick.value = true
const list = getData(BlackListDataKey)[0].users as string[]
// forEachFeedsCarddqa
const likeButtons = (
Array.from(document.getElementsByClassName('bili-dyn-title__text')) as HTMLElement[]
).reduce((buttons, e) => {
if (list.includes(e.textContent.trim())) {
return buttons
}
},
methods: {
like() {
if (this.isClick) {
return
}
this.isClick = true
// forEachFeedsCarddqa
const likeButtons = (
Array.from(document.getElementsByClassName('bili-dyn-title__text')) as HTMLElement[]
).reduce((buttons, e) => {
if (this.list.includes(e.textContent.trim())) {
return buttons
}
const likeButton = e.closest('.bili-dyn-item__main').querySelector('.bili-dyn-action.like')
if (likeButton && !likeButton.classList.contains('active')) {
buttons.push(likeButton as HTMLElement)
}
return buttons
}, [] as HTMLElement[])
this.feedsLikeQueue.push(...likeButtons)
this.totalLikeCnt = this.feedsLikeQueue.length
this.curLikeCnt = 0
this.isLike = true
const t = window.setInterval(() => {
if (this.feedsLikeQueue.length === 0) {
this.isLike = false
this.isClick = false
clearInterval(t)
return
}
const button = this.feedsLikeQueue.shift()
button?.click()
this.curLikeCnt++
}, 1200)
},
},
})
const likeButton = e.closest('.bili-dyn-item__main').querySelector('.bili-dyn-action.like')
if (likeButton && !likeButton.classList.contains('active')) {
buttons.push(likeButton as HTMLElement)
}
return buttons
}, [] as HTMLElement[])
feedsLikeQueue.value.push(...likeButtons)
totalLikeCnt.value = feedsLikeQueue.value.length
curLikeCnt.value = 0
isLike.value = true
const t = window.setInterval(() => {
if (feedsLikeQueue.value.length === 0) {
isLike.value = false
isClick.value = false
clearInterval(t)
return
}
const button = feedsLikeQueue.value.shift()
button?.click()
curLikeCnt.value++
}, 1200)
}
</script>
<style lang="scss">

View File

@ -1,44 +1,23 @@
<template>
<div>
<div class="custom-black-list-extra-options">
<VButton ref="button" @mouseover="setBlackListProps" @click="toggleBlackList">
<VButton ref="button" @mouseover="setBlackListPropsWrapper" @click="toggleBlackList">
黑名单
<VIcon icon="right-arrow" :size="16" />
</VButton>
</div>
</div>
</template>
<script lang="ts">
import { VIcon, VButton } from '@/ui'
import { loadBlackList, setBlackListProps, toggleBlackList } from './vm'
<script lang="ts" setup>
import { useTemplateRef } from 'vue'
import { VIcon, type VButton } from '@/ui'
import { loadBlackList, toggleBlackList } from './vm'
export default Vue.extend({
components: {
VIcon,
VButton,
},
data() {
return {
isFirstLoad: false,
}
},
methods: {
toggle() {
this.$refs.popup.toggle()
},
async setBlackListProps() {
if (this.isFirstLoad) {
return
}
this.isFirstLoad = await loadBlackList()
if (this.isFirstLoad) {
const triggerButton = this.$refs.button.$el as HTMLElement
setBlackListProps(triggerButton)
}
},
toggleBlackList,
},
})
const button = useTemplateRef<InstanceType<typeof VButton>>('button')
const setBlackListPropsWrapper = async () => {
await loadBlackList(button.value.$el as HTMLElement)
}
</script>
<style lang="scss">
.custom-black-list-extra-options {

View File

@ -2,47 +2,34 @@ import { select } from '@/core/spin-query'
import { mountVueComponent } from '@/core/utils'
import { getData } from '@/plugins/data'
import type blackListVue from './blackList.vue'
export const BlackListDataKey = 'like-black-List.data'
let blacklistVM: InstanceType<typeof blackListVue> | null = null
type SettingsVmType = Vue & {
toggle: () => void
triggerElement: HTMLElement
list: string[]
titleName: string
export const loadlikeButton = async () => {
const LikeButton = await import('./like.vue')
const [el] = mountVueComponent(LikeButton)
const bg = (await select('#app')) as HTMLElement
bg.insertAdjacentElement('afterbegin', el)
}
let blacklistVM: SettingsVmType = null
export const setBlackListProps = (element: HTMLElement) => {
if (!blacklistVM) {
export const loadBlackList = async (element: HTMLElement) => {
if (blacklistVM) {
return
}
blacklistVM.triggerElement = element
const blackList = getData(BlackListDataKey)
blacklistVM.list = blackList[0].users
blacklistVM.titleName = '黑名单'
}
export const loadlikeButton = async () => {
const LikeButton = await import('./like.vue').then(m => m.default)
const blackList = getData(BlackListDataKey)
const likebuttonVM: Vue & { list: string[] } = mountVueComponent(LikeButton)
likebuttonVM.list = blackList[0].users
const bg = (await select('#app')) as HTMLElement
bg.insertAdjacentElement('afterbegin', likebuttonVM.$el)
}
export const loadBlackList = async () => {
if (blacklistVM) {
return false
}
const blackList = await import('./blackList.vue').then(m => m.default)
blacklistVM = mountVueComponent(blackList)
document.body.insertAdjacentElement('beforeend', blacklistVM.$el)
return true
const blackList = await import('./blackList.vue')
const [el, vm] = mountVueComponent(blackList, {
triggerElement: element,
list: getData(BlackListDataKey)[0].users,
titleName: '黑名单',
})
blacklistVM = vm
document.body.insertAdjacentElement('beforeend', el)
}
export const toggleBlackList = async () => {
if (!blacklistVM) {
await loadBlackList()
if (blacklistVM) {
blacklistVM.isOpen = false
}
blacklistVM?.toggle()
}

View File

@ -1,8 +1,8 @@
import { registerAndGetData } from '@/plugins/data'
import { getComponentSettings } from '@/core/settings'
import { CommentContentReplaceHandler } from './types'
import { CommentContentReplaceOptions } from '../options'
import { NodeContentReplacer } from './node-content-replacer'
import type { CommentContentReplaceHandler } from './types'
import type { CommentContentReplaceOptions } from '../options'
import type { NodeContentReplacer } from './node-content-replacer'
import { EmoticonToEmoticonReplacer } from './emoticon-to-emoticon'
import { EmoticonToTextReplacer } from './emoticon-to-text'
import { RecursiveReplacer } from './recursive'

View File

@ -1,4 +1,4 @@
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import { defineOptionsMetadata, type OptionsOfMetadata } from '@/components/define'
export const commentContentReplaceOptions = defineOptionsMetadata({
replaceMap: {

View File

@ -29,31 +29,23 @@
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { VButton, TextBox, VIcon } from '@/ui'
import { CommentContentReplaceRow } from './row'
export default Vue.extend({
components: {
VButton,
VIcon,
TextBox,
},
props: {
row: {
required: true,
type: CommentContentReplaceRow,
},
},
methods: {
emitChange(event: { from: string; to: string }) {
this.$emit('change', event)
},
emitDelete() {
this.$emit('delete')
},
const { row } = defineProps({
row: {
required: true,
type: CommentContentReplaceRow,
},
})
const emits = defineEmits(['change', 'delete'])
const emitChange = (event: { from: string; to: string }) => {
emits('change', event)
}
const emitDelete = () => {
emits('delete')
}
</script>
<style lang="scss">
@import 'common';

View File

@ -1,9 +1,8 @@
<template>
<div class="comment-content-replace-extra-options">
<div class="comment-content-replace-rows">
<template v-for="(row, index) of rows">
<template v-for="(row, index) of rows" :key="row.key">
<ContentReplaceRow
:key="row.key"
:row="row"
@change="handleRowChange(row, $event)"
@delete="handleRowDelete(row)"
@ -21,52 +20,38 @@
</VButton>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { reactive } from 'vue'
import { getComponentSettings } from '@/core/settings'
import { deleteValue } from '@/core/utils'
import { VButton, VIcon } from '@/ui'
import { CommentContentReplaceOptions } from '../options'
import type { CommentContentReplaceOptions } from '../options'
import { CommentContentReplaceRow } from './row'
import ContentReplaceRow from './ContentReplaceRow.vue'
const { options } = getComponentSettings<CommentContentReplaceOptions>('commentContentReplace')
export default Vue.extend({
components: {
ContentReplaceRow,
VButton,
VIcon,
},
data() {
const { replaceMap } = options
const rows = Object.entries(replaceMap).map(
([from, to]) => new CommentContentReplaceRow(from, to),
)
return {
rows,
}
},
methods: {
saveSettings() {
const validRows = (this.rows as CommentContentReplaceRow[])
.map(row => [row.from, row.to])
.filter(([from]) => Boolean(from))
options.replaceMap = Object.fromEntries(validRows)
},
handleRowChange(row: CommentContentReplaceRow, event: { from: string; to: string }) {
row.from = event.from
row.to = event.to
this.saveSettings()
},
handleRowDelete(row: CommentContentReplaceRow) {
deleteValue(this.rows, it => it === row)
this.saveSettings()
},
handleRowAdd() {
this.rows.push(new CommentContentReplaceRow())
},
},
})
const { replaceMap } = options
const rows = reactive(
Object.entries(replaceMap).map(([from, to]) => new CommentContentReplaceRow(from, to)),
)
const saveSettings = () => {
const validRows = rows.map(row => [row.from, row.to]).filter(([from]) => Boolean(from))
options.replaceMap = Object.fromEntries(validRows)
}
const handleRowChange = (row: CommentContentReplaceRow, event: { from: string; to: string }) => {
row.from = event.from
row.to = event.to
saveSettings()
}
const handleRowDelete = (row: CommentContentReplaceRow) => {
deleteValue(rows, it => it === row)
saveSettings()
}
const handleRowAdd = () => {
rows.push(new CommentContentReplaceRow())
}
</script>
<style lang="scss">
@import 'common';

View File

@ -1,7 +1,7 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable yoda */
import { defineComponentMetadata } from '@/components/define'
import { CommentItem, CommentReplyItem } from '@/components/utils/comment-apis'
import type { CommentItem, CommentReplyItem } from '@/components/utils/comment-apis'
import { select } from '@/core/spin-query'
// 新版评论区IP属地获取
@ -15,212 +15,6 @@ let bbComment: any
const marginLeft = 15
// 带IP属地显示的评论创建
const createListCon = function listCon(item, i, pos) {
const blCon = this._parentBlacklistDom(item, i, pos)
const con = [
`<div class="con ${pos === i ? 'no-border' : ''}">`,
`<div class="user">${this._createNickNameDom(item)}`,
this._createLevelLink(item),
this._identity(item.mid, item.assist, item.member.fans_detail),
`${this._createNameplate(item.member.nameplate) + this._createUserSailing(item)}</div>`,
this._createMsgContent(item),
this._createPerfectReply(item),
'<div class="info">',
this._createPlatformDom(item.content.plat),
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
item.lottery_id
? ''
: `<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
item.lottery_id ? '' : `<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
item.lottery_id ? '' : this._createReplyBtn(item.rcount),
item.lottery_id && item.mid !== bbComment.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(item)
? `<li class="set-top">${item.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(item.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(item.mid) && !item.isTop
? `<li class="del" data-mid="${item.mid}">删除</li>`
: ''
}</ul></div></div>`,
this._createLotteryContent(item.content),
this._createVoteContent(item.content),
this._createTags(item),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(
item.replies,
item.rcount,
false,
item.rpid,
item.folder && item.folder.has_folded,
item.reply_control,
),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return item.state === bbComment.blacklistCode ? blCon : con
}
// 带IP属地显示的回复创建
const createSubReplyItem = function subReply(item, i) {
const dom = [
`<div class="reply-item reply-wrap" data-id="${item.rpid}" data-index="${i}">`,
this._createSubReplyUserFace(item),
'<div class="reply-con">',
'<div class="user">',
this._createNickNameDom(item),
this._createLevelLink(item),
this._identity(item.mid),
this._createSubMsgContent(item),
'</div>',
'</div>',
'<div class="info">',
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
`<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
`<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(item.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(item.mid) ? `<li class="del" data-mid="${item.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return dom
}
// 小黑屋专用带IP属地显示的评论创建
const blackroomCreateListCon = function listCon(e, n, t) {
const r = this._parentBlacklistDom(e, n, t)
const i = [
`<div class="con ${t === n ? 'no-border' : ''}">`,
`<div class="user">${this._identity(e.mid, e.assist, e.member.fans_detail)}`,
`<a data-usercard-mid="${e.mid}" href="//space.bilibili.com/${
e.mid
}" target="_blank" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(
e.member.uname,
)}</a><a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${
e.member.level_info.current_level
}"></i></a>${this._createNameplate(e.member.nameplate)}${this._createUserSailing(
(e.member && e.member.user_sailing) || {},
)}</div>`,
this._createMsgContent(e),
'<div class="info">',
e.floor ? `<span class="floor">#${e.floor}</span>` : '',
this._createPlatformDom(e.content.plat),
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${e?.reply_control?.location || ''}</span>`
: '',
e.lottery_id
? ''
: `<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
e.lottery_id ? '' : `<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
e.lottery_id ? '' : this._createReplyBtn(e.rcount),
e.lottery_id && e.mid !== this.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(e)
? `<li class="set-top">${e.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(e.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(e.mid) && !e.isTop ? `<li class="del" data-mid="${e.mid}">删除</li>` : ''
}</ul></div></div>`,
this._createLotteryContent(e.content),
this._createVoteContent(e.content),
this._createTags(e),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(e.replies, e.rcount, !1, e.rpid, e.folder && e.folder.has_folded),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return e.state === this.blacklistCode ? r : i
}
// 小黑屋专用带IP属地显示的回复创建
const blackroomCreateSubReplyItem = function subReply(e, n) {
const t = [
`<div class="reply-item reply-wrap" data-id="${e.rpid}" data-index="${n}">`,
`<a href="//space.bilibili.com/${e.mid}" data-usercard-mid="${e.mid}" target="_blank" class="reply-face">`,
`<img src="${this._trimHttpFix(
this._webpFix(e.member.avatar, {
w: 52,
h: 52,
}),
)}" alt="">`,
'</a>',
'<div class="reply-con">',
'<div class="user">',
`<a href="//space.bilibili.com/${e.mid}" target="_blank" data-usercard-mid="${
e.mid
}" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(e.member.uname)}</a>`,
`<a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${e.member.level_info.current_level}"></i></a>`,
this._createSubMsgContent(e),
'</div>',
'</div>',
'<div class="info">',
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${e?.reply_control?.location || ''}</span>`
: '',
`<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
`<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(e.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(e.mid) ? `<li class="del" data-mid="${e.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return t
}
const observer = new MutationObserver(mutations => {
mutations.forEach(() => {
// 监听旧版评论区全局变量
@ -257,12 +51,232 @@ const observer = new MutationObserver(mutations => {
return this.isWebp ? `${t[1] + e}.webp${n}` : `${t[1] + e}.${t[2]}${n}`
}
bbComment.prototype._createListCon = blackroomCreateListCon
bbComment.prototype._createSubReplyItem = blackroomCreateSubReplyItem
bbComment.prototype._createListCon =
// 小黑屋专用带IP属地显示的评论创建
function blackRoomListCon(e, n, t) {
const r = this._parentBlacklistDom(e, n, t)
const i = [
`<div class="con ${t === n ? 'no-border' : ''}">`,
`<div class="user">${this._identity(e.mid, e.assist, e.member.fans_detail)}`,
`<a data-usercard-mid="${e.mid}" href="//space.bilibili.com/${
e.mid
}" target="_blank" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(
e.member.uname,
)}</a><a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${
e.member.level_info.current_level
}"></i></a>${this._createNameplate(e.member.nameplate)}${this._createUserSailing(
(e.member && e.member.user_sailing) || {},
)}</div>`,
this._createMsgContent(e),
'<div class="info">',
e.floor ? `<span class="floor">#${e.floor}</span>` : '',
this._createPlatformDom(e.content.plat),
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${
e?.reply_control?.location || ''
}</span>`
: '',
e.lottery_id
? ''
: `<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
e.lottery_id
? ''
: `<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
e.lottery_id ? '' : this._createReplyBtn(e.rcount),
e.lottery_id && e.mid !== this.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(e)
? `<li class="set-top">${e.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(e.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(e.mid) && !e.isTop
? `<li class="del" data-mid="${e.mid}">删除</li>`
: ''
}</ul></div></div>`,
this._createLotteryContent(e.content),
this._createVoteContent(e.content),
this._createTags(e),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(
e.replies,
e.rcount,
!1,
e.rpid,
e.folder && e.folder.has_folded,
),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return e.state === this.blacklistCode ? r : i
}
bbComment.prototype._createSubReplyItem =
// 小黑屋专用带IP属地显示的回复创建
function blackRoomSubReply(e, n) {
const t = [
`<div class="reply-item reply-wrap" data-id="${e.rpid}" data-index="${n}">`,
`<a href="//space.bilibili.com/${e.mid}" data-usercard-mid="${e.mid}" target="_blank" class="reply-face">`,
`<img src="${this._trimHttpFix(
this._webpFix(e.member.avatar, {
w: 52,
h: 52,
}),
)}" alt="">`,
'</a>',
'<div class="reply-con">',
'<div class="user">',
`<a href="//space.bilibili.com/${e.mid}" target="_blank" data-usercard-mid="${
e.mid
}" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(e.member.uname)}</a>`,
`<a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${e.member.level_info.current_level}"></i></a>`,
this._createSubMsgContent(e),
'</div>',
'</div>',
'<div class="info">',
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${
e?.reply_control?.location || ''
}</span>`
: '',
`<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
`<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(e.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(e.mid) ? `<li class="del" data-mid="${e.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return t
}
} else {
// 其他情况旧版评论区替换
bbComment.prototype._createListCon = createListCon
bbComment.prototype._createSubReplyItem = createSubReplyItem
bbComment.prototype._createListCon =
// 带IP属地显示的评论创建
function listIcon(item, i, pos) {
const blCon = this._parentBlacklistDom(item, i, pos)
const con = [
`<div class="con ${pos === i ? 'no-border' : ''}">`,
`<div class="user">${this._createNickNameDom(item)}`,
this._createLevelLink(item),
this._identity(item.mid, item.assist, item.member.fans_detail),
`${
this._createNameplate(item.member.nameplate) + this._createUserSailing(item)
}</div>`,
this._createMsgContent(item),
this._createPerfectReply(item),
'<div class="info">',
this._createPlatformDom(item.content.plat),
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
item.lottery_id
? ''
: `<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
item.lottery_id
? ''
: `<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
item.lottery_id ? '' : this._createReplyBtn(item.rcount),
item.lottery_id && item.mid !== bbComment.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(item)
? `<li class="set-top">${item.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(item.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(item.mid) && !item.isTop
? `<li class="del" data-mid="${item.mid}">删除</li>`
: ''
}</ul></div></div>`,
this._createLotteryContent(item.content),
this._createVoteContent(item.content),
this._createTags(item),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(
item.replies,
item.rcount,
false,
item.rpid,
item.folder && item.folder.has_folded,
item.reply_control,
),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return item.state === bbComment.blacklistCode ? blCon : con
}
bbComment.prototype._createSubReplyItem =
// 带IP属地显示的回复创建
function subReply(item, i) {
const dom = [
`<div class="reply-item reply-wrap" data-id="${item.rpid}" data-index="${i}">`,
this._createSubReplyUserFace(item),
'<div class="reply-con">',
'<div class="user">',
this._createNickNameDom(item),
this._createLevelLink(item),
this._identity(item.mid),
this._createSubMsgContent(item),
'</div>',
'</div>',
'<div class="info">',
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
`<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
`<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(item.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(item.mid) ? `<li class="del" data-mid="${item.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return dom
}
}
version = 1
observer.disconnect()

View File

@ -2,7 +2,7 @@
<div class="download-cover-config download-video-config-section">
<div class="download-video-config-item">
<div class="download-video-config-title">封面:</div>
<VDropdown v-model="type" :items="items">
<VDropdown v-model:value="type" :items="items">
<template #item="{ item }">
{{ item }}
</template>
@ -10,37 +10,22 @@
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { getComponentSettings } from '@/core/settings'
import { UnknownOptions } from '@/components/component'
import type { UnknownOptions } from '@/components/component'
import { VDropdown } from '@/ui'
import { CoverDownloadType } from './types'
import type { CoverDownloadType } from './types'
interface Options extends UnknownOptions {
CoverType: CoverDownloadType | '无'
}
const { options } = getComponentSettings<Options>('downloadVideo')
export default Vue.extend({
components: {
VDropdown,
},
data() {
return {
type: options.CoverType ?? '无',
items: ['无', 'jpg'],
}
},
computed: {
enabled() {
return this.type !== '无'
},
},
watch: {
type(newValue: CoverDownloadType) {
options.CoverType = newValue
},
},
const type = ref(options.CoverType ?? '无')
const items = ['无', 'jpg']
watch(type, newValue => {
options.CoverType = newValue
})
</script>
<style lang="scss">

View File

@ -2,11 +2,11 @@ import { defineAsyncComponent } from 'vue'
import { defineComponentMetadata } from '@/components/define'
import { getVideoCoverUrlByAid, getBlobByAid } from '@/components/video/video-cover'
import { PackageEntry } from '@/core/download'
import type { PackageEntry } from '@/core/download'
import { videoAndBangumiUrls } from '@/core/utils/urls'
import { Toast } from '@/core/toast'
import { DownloadVideoAssets } from '../../video/download/types'
import { CoverDownloadType } from './types'
import type { DownloadVideoAssets } from '../../video/download/types'
import type { CoverDownloadType } from './types'
export const component = defineComponentMetadata({
name: 'viewCover',

View File

@ -1,4 +1,5 @@
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import type { OptionsOfMetadata } from '@/components/define'
import { defineOptionsMetadata } from '@/components/define'
export const downloadDanmakuOptions = defineOptionsMetadata({
speed: {

View File

@ -9,7 +9,7 @@ import type { DanmakuType } from '../converter/danmaku-type'
import { XmlDanmaku } from '../converter/xml-danmaku'
import { playerAgent } from '@/components/video/player-agent'
import { getComponentSettings } from '@/core/settings'
import { DownloadDanmakuOptions } from './options'
import type { DownloadDanmakuOptions } from './options'
export class JsonDanmaku {
// static SegmentSize = 6 * 60

View File

@ -3,7 +3,7 @@
class="video-default-location-extend-box"
:class="{ 'video-default-location-extend-box-hidden': realHidden }"
>
<div class="video-default-location-extend-box-bar" @click="setRealHidden">
<div class="video-default-location-extend-box-bar" @click="setRealHidden(!realHidden)">
<div class="video-default-location-extend-box-bar-text">位置测试</div>
<div
class="video-default-location-extend-box-bar-btn"

View File

@ -79,16 +79,16 @@
class="run-download"
type="primary"
:disabled="!canStartDownload"
@click="startDownload(outputOptions, selectedOutput)"
@click="startDownload()"
>
开始
</VButton>
</div>
</VPopup>
</template>
<script lang="ts">
<script lang="ts" setup>
import type { Ref, ComponentPublicInstance } from 'vue'
import { ref, defineComponent, reactive } from 'vue'
import { ref, reactive, computed, watch, onMounted, useTemplateRef } from 'vue'
import type { VideoQuality } from '@/components/video/video-quality'
import { allQualities } from '@/components/video/video-quality'
import type { TestPattern } from '@/core/common-types'
@ -116,13 +116,13 @@ import type {
} from './types'
import { DownloadVideoAction } from './types'
const [inputs] = registerAndGetData('downloadVideo.inputs', [
const [inputsRaw] = registerAndGetData('downloadVideo.inputs', [
videoSingleInput,
videoBatchInput,
videoSeasonBatchInput,
bangumiBatchInput,
] as DownloadVideoInput[])
const [apis] = registerAndGetData('downloadVideo.apis', [
const [apisRaw] = registerAndGetData('downloadVideo.apis', [
videoFlv,
videoDashAvc,
videoDashHevc,
@ -130,7 +130,7 @@ const [apis] = registerAndGetData('downloadVideo.apis', [
videoAudioDash,
] as DownloadVideoApi[])
const [assets] = registerAndGetData('downloadVideo.assets', [] as DownloadVideoAssets[])
const [outputs] = registerAndGetData('downloadVideo.outputs', [
const [outputsRaw] = registerAndGetData('downloadVideo.outputs', [
streamSaverOutput,
] as DownloadVideoOutput[])
const { basicConfig } = getComponentSettings('downloadVideo').options as {
@ -152,215 +152,196 @@ const getFallbackTestVideoInfo = () =>
title: getFriendlyTitle(true),
} as DownloadVideoInputItem)
export default defineComponent({
components: {
VPopup,
VButton,
VDropdown,
VIcon,
SwitchBox,
},
props: {
triggerElement: {
required: true,
},
},
setup: () => ({
inputOptions: ref(null) as Ref<ComponentPublicInstance | null>,
assetsOptions: ref(null) as Ref<ComponentPublicInstance[] | null>,
outputOptions: ref(null) as Ref<ComponentPublicInstance | null>,
}),
data() {
const lastOutput = basicConfig.output
const lastUseBackupUrls = basicConfig.useBackupUrls
return {
open: false,
busy: false,
// videoInfo,
testData: {
// undefined: ; null: ;
videoInfo: null,
// P
multiple: false,
},
assets,
qualities: [] as VideoQuality[],
selectedQuality: undefined,
inputs: [] as DownloadVideoInput[],
selectedInput: undefined,
apis: [] as DownloadVideoApi[],
selectedApi: undefined,
outputs,
selectedOutput: outputs.find(it => it.name === lastOutput) || outputs[0],
useBackupUrls: lastUseBackupUrls || false,
}
},
computed: {
assetsWithOptions(): DownloadVideoAssets[] {
return (this.assets as DownloadVideoAssets[]).filter(a => a.component)
},
filteredQualities(): VideoQuality[] {
if (this.qualities.length === 0) {
return allQualities
}
return this.qualities
},
canStartDownload(): boolean {
if (this.busy || !this.open) {
return false
}
const isAnySelectionEmpty = [
'selectedQuality',
'selectedInput',
'selectedApi',
'selectedOutput',
].some(prop => !this[prop])
if (isAnySelectionEmpty) {
return false
}
return true
},
},
watch: {
selectedInput(input: DownloadVideoInput) {
if (input === undefined) {
return
}
this.updateTestVideoInfo()
},
selectedApi(api: DownloadVideoApi) {
if (api === undefined) {
return
}
this.updateTestVideoInfo()
basicConfig.api = api.name
},
selectedOutput(output: DownloadVideoOutput) {
if (output === undefined) {
return
}
basicConfig.output = output.name
},
useBackupUrls(useBackupUrls: boolean) {
if (useBackupUrls === undefined) {
return
}
basicConfig.useBackupUrls = useBackupUrls
},
},
mounted() {
coreApis.observer.videoChange(() => {
this.selectedInput = undefined
this.selectedApi = undefined
const inputOptions = useTemplateRef('inputOptions')
const assetsOptions = useTemplateRef<ComponentPublicInstance[]>('assetsOptions')
const outputOptions = useTemplateRef('outputOptions')
const matchedInputs = filterData(inputs)
this.inputs = matchedInputs
this.selectedInput = matchedInputs[0]
const matchedApis = filterData(apis)
this.apis = matchedApis
const lastApi = matchedApis.find(api => api.name === basicConfig.api)
if (lastApi) {
this.selectedApi = lastApi
} else {
this.selectedApi = matchedApis[0]
const { triggerElement } = defineProps<{ triggerElement: HTMLElement }>()
const open = ref(false)
const busy = ref(false)
const testData = reactive({
// undefined: ; null: ;
videoInfo: null,
// P
multiple: false,
})
const qualities = ref<VideoQuality[]>([])
const selectedQuality = ref<VideoQuality | undefined>(undefined)
const inputs = ref<DownloadVideoInput[]>([])
const selectedInput = ref<DownloadVideoInput | undefined>(undefined)
const apis = ref<DownloadVideoApi[]>([])
const selectedApi = ref<DownloadVideoApi | undefined>(undefined)
const outputs = ref<DownloadVideoOutput[]>(outputsRaw)
const selectedOutput = ref<DownloadVideoOutput>(
outputsRaw.find(it => it.name === basicConfig.output) || outputsRaw[0],
)
const useBackupUrls = ref<boolean>(basicConfig.useBackupUrls || false)
const assetsWithOptions = computed(() => (assets as DownloadVideoAssets[]).filter(a => a.component))
const filteredQualities = computed(() =>
qualities.value.length === 0 ? allQualities : qualities.value,
)
const canStartDownload = computed(() => {
if (busy.value || !open.value) {
return false
}
const isAnySelectionEmpty = [
selectedQuality.value,
selectedInput.value,
selectedApi.value,
selectedOutput.value,
].some(v => !v)
if (isAnySelectionEmpty) {
return false
}
return true
})
const updateTestVideoInfo = async () => {
if (!selectedInput.value || !selectedApi.value) {
return
}
testData.videoInfo = null
const input = selectedInput.value as DownloadVideoInput
const testItem = input.getTestInput?.() ?? getFallbackTestVideoInfo()
console.log('[updateTestVideoInfo]', testItem)
testData.multiple = input.batch
const api = selectedApi.value as DownloadVideoApi
try {
const videoInfo = await api.downloadVideoInfo(testItem)
qualities.value = videoInfo.qualities
const isSelectedQualityOutdated =
!selectedQuality.value ||
!videoInfo.qualities.some(q => q.value === selectedQuality.value?.value)
if (isSelectedQualityOutdated) {
selectedQuality.value = videoInfo.qualities[0]
if (basicConfig.quality) {
const [matchedQuality] = videoInfo.qualities.filter(q => q.value <= basicConfig.quality)
if (matchedQuality) {
selectedQuality.value = matchedQuality
}
}
}
// quality quality
testItem.quality = selectedQuality.value
const qualityVideoInfo = await api.downloadVideoInfo(testItem)
testData.videoInfo = qualityVideoInfo
} catch (error) {
console.error('[updateTestVideoInfo] failed', error)
testData.videoInfo = undefined
}
}
watch(selectedInput, input => {
if (input === undefined) {
return
}
updateTestVideoInfo()
})
watch(selectedApi, api => {
if (api === undefined) {
return
}
updateTestVideoInfo()
basicConfig.api = api.name
})
watch(selectedOutput, output => {
if (output === undefined) {
return
}
basicConfig.output = output.name
})
watch(useBackupUrls, val => {
if (val === undefined) {
return
}
basicConfig.useBackupUrls = val
})
// , watch
const saveSelectedQuality = () => {
const quality = selectedQuality.value
if (quality === undefined) {
return
}
basicConfig.quality = quality.value
updateTestVideoInfo()
}
// const getVideoItems = async () => {
// const input = selectedInput.value as DownloadVideoInput
// const videoItems = await input.getInputs(inputOptions)
// return videoItems
// }
const startDownload = async () => {
const instance = outputOptions.value as ComponentPublicInstance
const output = selectedOutput.value
try {
busy.value = true
const input = selectedInput.value as DownloadVideoInput
const api = selectedApi.value as DownloadVideoApi
const videoInputs = await input.getInputs(inputOptions)
if (videoInputs.length === 0) {
Toast.info('未接收到视频, 如果输入源支持批量, 请至少选择一个视频.', '下载视频', 3000)
return
}
videoInputs.forEach(item => {
item.quality = selectedQuality.value
})
},
methods: {
formatFileSize,
// , watch
saveSelectedQuality() {
const quality: VideoQuality = this.selectedQuality
if (quality === undefined) {
return
}
basicConfig.quality = quality.value
this.updateTestVideoInfo()
},
async getVideoItems() {
const input = this.selectedInput as DownloadVideoInput
const videoItems = await input.getInputs(this.inputOptions)
return videoItems
},
async updateTestVideoInfo() {
if (!this.selectedInput || !this.selectedApi) {
return
}
this.testData.videoInfo = null
const input = this.selectedInput as DownloadVideoInput
const testItem = input.getTestInput?.() ?? getFallbackTestVideoInfo()
console.log('[updateTestVideoInfo]', testItem)
this.testData.multiple = input.batch
const api = this.selectedApi as DownloadVideoApi
try {
const videoInfo = await api.downloadVideoInfo(testItem)
this.qualities = videoInfo.qualities
const isSelectedQualityOutdated =
!this.selectedQuality ||
!videoInfo.qualities.some(q => q.value === this.selectedQuality.value)
if (isSelectedQualityOutdated) {
this.selectedQuality = videoInfo.qualities[0]
if (basicConfig.quality) {
const [matchedQuality] = videoInfo.qualities.filter(q => q.value <= basicConfig.quality)
if (matchedQuality) {
this.selectedQuality = matchedQuality
}
}
}
// quality quality
testItem.quality = this.selectedQuality
const qualityVideoInfo = await api.downloadVideoInfo(testItem)
this.testData.videoInfo = qualityVideoInfo
} catch (error) {
console.error('[updateTestVideoInfo] failed', error)
this.testData.videoInfo = undefined
}
},
async startDownload(instance: ComponentPublicInstance, output: DownloadVideoOutput) {
try {
this.busy = true
const input = this.selectedInput as DownloadVideoInput
const api = this.selectedApi as DownloadVideoApi
const videoInputs = await input.getInputs(this.inputOptions)
if (videoInputs.length === 0) {
Toast.info('未接收到视频, 如果输入源支持批量, 请至少选择一个视频.', '下载视频', 3000)
return
}
videoInputs.forEach(item => {
item.quality = this.selectedQuality
const videoInfos = await Promise.all(videoInputs.map(i => api.downloadVideoInfo(i)))
if (videoInfos.length === 0 || lodash.sumBy(videoInfos, it => it.fragments.length) === 0) {
Toast.info('未接收到可下载数据, 请检查输入源和格式是否适用于当前视频.', '下载视频', 3000)
return
}
if (useBackupUrls.value) {
videoInfos.forEach(videoInfo => {
videoInfo.fragments.forEach(fragment => {
fragment.url =
fragment.backupUrls && fragment.backupUrls.length !== 0
? fragment.backupUrls.at(0)
: fragment.url
})
const videoInfos = await Promise.all(videoInputs.map(i => api.downloadVideoInfo(i)))
if (videoInfos.length === 0 || lodash.sumBy(videoInfos, it => it.fragments.length) === 0) {
Toast.info('未接收到可下载数据, 请检查输入源和格式是否适用于当前视频.', '下载视频', 3000)
return
}
if (this.useBackupUrls) {
videoInfos.forEach(videoInfo => {
videoInfo.fragments.forEach(fragment => {
fragment.url =
fragment.backupUrls && fragment.backupUrls.length !== 0
? fragment.backupUrls.at(0)
: fragment.url
})
})
}
const action = new DownloadVideoAction(videoInfos)
assets.forEach(a => {
const assetsType = a?.getUrls ? action.extraOnlineAssets : action.extraAssets
assetsType.push({
asset: a,
instance: this.$refs.assetsOptions.find((c: any) => c.$attrs.name === a.name),
})
})
await output.runAction(action, instance)
await action.downloadExtraAssets()
} catch (error) {
logError(error)
} finally {
this.busy = false
}
},
},
})
}
const action = new DownloadVideoAction(videoInfos)
for (const a of assets) {
const assetsType = a?.getUrls ? action.extraOnlineAssets : action.extraAssets
assetsType.push({
asset: a,
instance: assetsOptions.value.find(c => (c.$attrs.name as string) === a.name),
})
}
await output.runAction(action, instance)
await action.downloadExtraAssets()
} catch (error) {
logError(error)
} finally {
busy.value = false
}
}
onMounted(() => {
coreApis.observer.videoChange(() => {
selectedInput.value = undefined
selectedApi.value = undefined
const matchedInputs = filterData(inputsRaw)
inputs.value = matchedInputs
selectedInput.value = matchedInputs[0]
const matchedApis = filterData(apisRaw)
apis.value = matchedApis
const lastApi = matchedApis.find(api => api.name === basicConfig.api)
if (lastApi) {
selectedApi.value = lastApi
} else {
selectedApi.value = matchedApis[0]
}
})
})
defineExpose({
open,
})
</script>
<style lang="scss">

View File

@ -9,7 +9,7 @@ import { compareQuality } from '../error'
import type { DownloadVideoApi, DownloadVideoFragment, DownloadVideoInputItem } from '../types'
import { DownloadVideoInfo } from '../types'
import { bangumiApi, videoApi } from './url'
import { Options } from '..'
import type { Options } from '..'
import { getComponentSettings } from '@/core/settings'
/** dash 格式更明确的扩展名 */

View File

@ -5,7 +5,8 @@ import { formatDuration, formatNumber } from '@/core/utils/formatters'
import { logError } from '@/core/utils/log'
import { formatTitle, getTitleVariablesFromDate } from '@/core/utils/title'
import { videoUrls } from '@/core/utils/urls'
import type { BiliBiliQueryAidAndBvidResponse } from './types/aid-bvid-response'
import type { BiliBiliQueryAidData } from './types/aid-response'
import type { DownloadVideoInput } from '../../types'
import type { EpisodeItem } from '../episode-item'
import { createEpisodesPicker } from '../episode-item'
@ -25,17 +26,17 @@ export const videoBatchInput: DownloadVideoInput = {
logError(`获取视频选集列表失败, message = ${json.message}`)
return []
}
const { pages, owner, pubdate } = json.data
const { pages, owner, pubdate } = json.data as BiliBiliQueryAidData
if (pages === undefined) {
logError('获取视频选集列表失败, 没有找到选集信息.')
return []
}
const date = getTitleVariablesFromDate(new Date(pubdate * 1000))
return pages.map((page: any, index: number) => {
const key = page.cid
return pages.map((page, index: number) => {
const cidString = page.cid.toString()
const title = `P${page.page} ${page.part}`
return {
key,
key: cidString,
title,
isChecked: index < instance.maxCheckedItems,
durationText: formatDuration(page.duration),
@ -43,7 +44,7 @@ export const videoBatchInput: DownloadVideoInput = {
allowQualityDrop: true,
title: formatTitle(getGeneralSettings().batchFilenameFormat, false, {
n: formatNumber(page.page, pages.length),
cid: page.cid,
cid: cidString,
ep: page.part,
user: owner?.name,
userID: owner?.mid?.toString(),
@ -55,7 +56,7 @@ export const videoBatchInput: DownloadVideoInput = {
publishSecond: date.second,
publishMillisecond: date.millisecond,
}),
cid: page.cid,
cid: cidString,
aid,
},
} as EpisodeItem
@ -73,13 +74,13 @@ export const videoSeasonBatchInput: DownloadVideoInput = {
createEpisodesPicker(async instance => {
const { aid, bvid } = unsafeWindow
const api = `https://api.bilibili.com/x/web-interface/wbi/view/detail?bvid=${bvid}&aid=${aid}`
const json = await getJsonWithCredentials(api)
const json = await getJsonWithCredentials<BiliBiliQueryAidAndBvidResponse>(api)
if (json.code !== 0) {
logError(`获取视频合集列表失败, message = ${json.message}`)
return []
}
const owner = lodash.get(json, 'data.View.owner', {})
const sections: { episodes: any[] }[] = lodash.get(json, 'data.View.ugc_season.sections', [])
const owner = json.data?.View?.owner || { name: '未知用户', mid: 0 }
const sections = json.data?.View?.ugc_season?.sections || []
if (sections.length === 0) {
return []
}
@ -89,12 +90,12 @@ export const videoSeasonBatchInput: DownloadVideoInput = {
return episodes.map((episode, episodeIndex) => {
const currentIndex =
episodeIndex + lodash.sumBy(sections.slice(0, sectionIndex), it => it.episodes.length)
const key = episode.cid
const cidString = episode.cid.toString()
const page = currentIndex + 1
const title = `P${page} ${episode.title}`
const date = getTitleVariablesFromDate(new Date(episode.arc.pubdate * 1000))
return {
key,
key: cidString,
title,
isChecked: currentIndex < instance.maxCheckedItems,
durationText: formatDuration(episode.arc.duration),
@ -103,9 +104,9 @@ export const videoSeasonBatchInput: DownloadVideoInput = {
title: formatTitle(getGeneralSettings().batchFilenameFormat, false, {
n: formatNumber(page, totalEpisodesLength),
title: episode.page.part,
cid: episode.cid,
aid: episode.aid,
bvid: episode.bvid,
cid: cidString,
aid: episode.aid.toString(),
bvid: episode.bvid.toString(),
ep: episode.title,
user: owner.name,
userID: owner.mid?.toString(),
@ -117,8 +118,8 @@ export const videoSeasonBatchInput: DownloadVideoInput = {
publishSecond: date.second,
publishMillisecond: date.millisecond,
}),
cid: episode.cid,
aid: episode.aid,
cid: cidString,
aid: episode.aid.toString(),
},
} as EpisodeItem
})

View File

@ -0,0 +1,571 @@
export interface BiliBiliQueryAidAndBvidResponse {
code: number
message: string
ttl: number
data: BiliBiliQueryAidAndBvidData
}
export interface BiliBiliQueryAidAndBvidData {
View: View
Card: Card2
Tags: Tag[]
Reply: Reply2
Related: Related[]
Spec: null
hot_share: Hotshare
elec: null
emergency: Emergency
view_addit: Viewaddit
guide: null
query_tags: null
participle: null
module_ctrl: null
replace_recommend: boolean
is_hit_labour_day_activity: boolean
}
interface Viewaddit {
'63': boolean
'64': boolean
'69': boolean
'71': boolean
'72': boolean
}
interface Emergency {
no_like: boolean
no_coin: boolean
no_fav: boolean
no_share: boolean
}
interface Hotshare {
show: boolean
list: any[]
}
interface Related {
aid: number
videos: number
tid: number
tname: string
copyright: number
pic: string
title: string
pubdate: number
ctime: number
desc: string
state: number
duration: number
rights: Rights3
owner: Owner
stat: Stat4
dynamic: string
cid: number
dimension: Dimension
short_link_v2: string
first_frame: string
pub_location: string
cover43: string
tidv2: number
tnamev2: string
pid_v2: number
pid_name_v2: string
bvid: string
season_type: number
is_ogv: boolean
ogv_info: null
rcmd_reason: string
enable_vt: number
ai_rcmd: Aircmd
season_id?: number
mission_id?: number
up_from_v2?: number
}
interface Aircmd {
id: number
goto: string
trackid: string
uniq_id: string
}
interface Stat4 {
aid: number
view: number
danmaku: number
reply: number
favorite: number
coin: number
share: number
now_rank: number
his_rank: number
like: number
dislike: number
vt: number
vv: number
fav_g: number
like_g: number
}
interface Rights3 {
bp: number
elec: number
download: number
movie: number
pay: number
hd5: number
no_reprint: number
autoplay: number
ugc_pay: number
is_cooperation: number
ugc_pay_preview: number
no_background: number
arc_pay: number
pay_free_watch: number
}
interface Reply2 {
page: null
replies: Reply[]
}
interface Reply {
rpid: number
oid: number
type: number
mid: number
root: number
parent: number
dialog: number
count: number
rcount: number
state: number
fansgrade: number
attr: number
ctime: number
like: number
action: number
content: null
replies: null
assist: number
show_follow: boolean
}
interface Tag {
tag_id: number
tag_name: string
music_id: string
tag_type: string
jump_url: string
}
interface Card2 {
card: Card
space: Space
following: boolean
archive_count: number
article_count: number
follower: number
like_num: number
}
interface Space {
s_img: string
l_img: string
}
interface Card {
mid: string
name: string
approve: boolean
sex: string
rank: string
face: string
face_nft: number
face_nft_type: number
DisplayRank: string
regtime: number
spacesta: number
birthday: string
place: string
description: string
article: number
attentions: any[]
fans: number
friend: number
attention: number
sign: string
level_info: Levelinfo
pendant: Pendant
nameplate: Nameplate
Official: Official
official_verify: Officialverify
vip: Vip
is_senior_member: number
name_render: null
}
interface Vip {
type: number
status: number
due_date: number
vip_pay_type: number
theme_type: number
label: Label
avatar_subscript: number
nickname_color: string
role: number
avatar_subscript_url: string
tv_vip_status: number
tv_vip_pay_type: number
tv_due_date: number
avatar_icon: Avataricon
vipType: number
vipStatus: number
}
interface Avataricon {
icon_resource: Honorreply
}
interface Label {
path: string
text: string
label_theme: string
text_color: string
bg_style: number
bg_color: string
border_color: string
use_img_label: boolean
img_label_uri_hans: string
img_label_uri_hant: string
img_label_uri_hans_static: string
img_label_uri_hant_static: string
}
interface Officialverify {
type: number
desc: string
}
interface Official {
role: number
title: string
desc: string
type: number
}
interface Nameplate {
nid: number
name: string
image: string
image_small: string
level: string
condition: string
}
interface Pendant {
pid: number
name: string
image: string
expire: number
image_enhance: string
image_enhance_frame: string
n_pid: number
}
interface Levelinfo {
current_level: number
current_min: number
current_exp: number
next_exp: number
}
interface View {
bvid: string
aid: number
videos: number
tid: number
tid_v2: number
tname: string
tname_v2: string
copyright: number
pic: string
title: string
pubdate: number
ctime: number
desc: string
desc_v2: Descv2[]
state: number
duration: number
rights: Rights
owner: Owner
stat: Stat
argue_info: Argueinfo
dynamic: string
cid: number
dimension: Dimension
season_id: number
premiere: null
teenage_mode: number
is_chargeable_season: boolean
is_story: boolean
is_upower_exclusive: boolean
is_upower_play: boolean
is_upower_preview: boolean
enable_vt: number
vt_display: string
is_upower_exclusive_with_qa: boolean
no_cache: boolean
pages: Page[]
subtitle: Subtitle
ugc_season: Ugcseason
is_season_display: boolean
user_garb: Usergarb
honor_reply: Honorreply
like_icon: string
need_jump_bv: boolean
disable_show_up_info: boolean
is_story_play: number
is_view_self: boolean
}
interface Honorreply {}
interface Usergarb {
url_image_ani_cut: string
}
interface Ugcseason {
id: number
title: string
cover: string
mid: number
intro: string
sign_state: number
attribute: number
sections: Section[]
stat: Stat3
ep_count: number
season_type: number
is_pay_season: boolean
enable_vt: number
}
interface Stat3 {
season_id: number
view: number
danmaku: number
reply: number
fav: number
coin: number
share: number
now_rank: number
his_rank: number
like: number
vt: number
vv: number
}
interface Section {
season_id: number
id: number
title: string
type: number
episodes: Episode[]
}
interface Episode {
season_id: number
section_id: number
id: number
aid: number
cid: number
title: string
attribute: number
arc: Arc
page: Page2
bvid: string
pages: Page2[]
}
interface Page2 {
cid: number
page: number
from: string
part: string
duration: number
vid: string
weblink: string
dimension: Dimension
}
interface Arc {
aid: number
videos: number
type_id: number
type_name: string
copyright: number
pic: string
title: string
pubdate: number
ctime: number
desc: string
state: number
duration: number
rights: Rights2
author: Owner
stat: Stat2
dynamic: string
dimension: Dimension
desc_v2: null
is_chargeable_season: boolean
is_blooper: boolean
enable_vt: number
vt_display: string
type_id_v2: number
type_name_v2: string
is_lesson_video: number
}
interface Stat2 {
aid: number
view: number
danmaku: number
reply: number
fav: number
coin: number
share: number
now_rank: number
his_rank: number
like: number
dislike: number
evaluation: string
argue_msg: string
vt: number
vv: number
}
interface Rights2 {
bp: number
elec: number
download: number
movie: number
pay: number
hd5: number
no_reprint: number
autoplay: number
ugc_pay: number
is_cooperation: number
ugc_pay_preview: number
arc_pay: number
free_watch: number
}
interface Subtitle {
allow_submit: boolean
list: List[]
}
interface List {
id: number
lan: string
lan_doc: string
is_lock: boolean
subtitle_url: string
type: number
id_str: string
ai_type: number
ai_status: number
author: Author
}
interface Author {
mid: number
name: string
sex: string
face: string
sign: string
rank: number
birthday: number
is_fake_account: number
is_deleted: number
in_reg_audit: number
is_senior_member: number
name_render: null
}
interface Page {
cid: number
page: number
from: string
part: string
duration: number
vid: string
weblink: string
dimension: Dimension
first_frame: string
ctime: number
}
interface Dimension {
width: number
height: number
rotate: number
}
interface Argueinfo {
argue_msg: string
argue_type: number
argue_link: string
}
interface Stat {
aid: number
view: number
danmaku: number
reply: number
favorite: number
coin: number
share: number
now_rank: number
his_rank: number
like: number
dislike: number
evaluation: string
vt: number
}
interface Owner {
mid: number
name: string
face: string
}
interface Rights {
bp: number
elec: number
download: number
movie: number
pay: number
hd5: number
no_reprint: number
autoplay: number
ugc_pay: number
is_cooperation: number
ugc_pay_preview: number
no_background: number
clean_mode: number
is_stein_gate: number
is_360: number
no_share: number
arc_pay: number
free_watch: number
}
interface Descv2 {
raw_text: string
type: number
biz_id: number
}

View File

@ -0,0 +1,165 @@
export interface BiliBiliQueryAidResponse {
code: number
message: string
ttl: number
data: BiliBiliQueryAidData
}
export interface BiliBiliQueryAidData {
bvid: string
aid: number
videos: number
tid: number
tid_v2: number
tname: string
tname_v2: string
copyright: number
pic: string
title: string
pubdate: number
ctime: number
desc: string
desc_v2: Descv2[]
state: number
duration: number
rights: Rights
owner: Owner
stat: Stat
argue_info: Argueinfo
dynamic: string
cid: number
dimension: Dimension
premiere: null
teenage_mode: number
is_chargeable_season: boolean
is_story: boolean
is_upower_exclusive: boolean
is_upower_play: boolean
is_upower_preview: boolean
enable_vt: number
vt_display: string
is_upower_exclusive_with_qa: boolean
no_cache: boolean
pages: Page[]
subtitle: Subtitle
is_season_display: boolean
user_garb: Usergarb
honor_reply: Honorreply
like_icon: string
need_jump_bv: boolean
disable_show_up_info: boolean
is_story_play: number
is_view_self: boolean
}
interface Honorreply {}
interface Usergarb {
url_image_ani_cut: string
}
interface Subtitle {
allow_submit: boolean
list: List[]
}
interface List {
id: number
lan: string
lan_doc: string
is_lock: boolean
subtitle_url: string
type: number
id_str: string
ai_type: number
ai_status: number
author: Author
}
interface Author {
mid: number
name: string
sex: string
face: string
sign: string
rank: number
birthday: number
is_fake_account: number
is_deleted: number
in_reg_audit: number
is_senior_member: number
name_render: null
}
interface Page {
cid: number
page: number
from: string
part: string
duration: number
vid: string
weblink: string
dimension: Dimension
ctime: number
}
interface Dimension {
width: number
height: number
rotate: number
}
interface Argueinfo {
argue_msg: string
argue_type: number
argue_link: string
}
interface Stat {
aid: number
view: number
danmaku: number
reply: number
favorite: number
coin: number
share: number
now_rank: number
his_rank: number
like: number
dislike: number
evaluation: string
vt: number
}
interface Owner {
mid: number
name: string
face: string
}
interface Rights {
bp: number
elec: number
download: number
movie: number
pay: number
hd5: number
no_reprint: number
autoplay: number
ugc_pay: number
is_cooperation: number
ugc_pay_preview: number
no_background: number
clean_mode: number
is_stein_gate: number
is_360: number
no_share: number
arc_pay: number
free_watch: number
}
interface Descv2 {
raw_text: string
type: number
biz_id: number
}

View File

@ -2,7 +2,7 @@
<div class="download-video-config-section">
<div class="download-video-config-item">
<div>元数据</div>
<VDropdown v-model="type" :items="items">
<VDropdown v-model:value="type" :items="items">
<template #item="{ item }">
{{ item }}
</template>
@ -10,35 +10,21 @@
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { VDropdown } from '@/ui'
import { getComponentSettings } from '@/core/settings'
import { MetadataType } from './metadata'
import type { MetadataType } from './metadata'
interface Options {
type Options = {
metadataType: MetadataType | '无'
}
const options = getComponentSettings('downloadVideo').options as Options
const { options } = getComponentSettings<Options>('downloadVideo')
export default Vue.extend({
components: {
VDropdown,
},
data() {
return {
type: options.metadataType ?? '无',
items: ['无', 'ffmetadata', 'ogm'],
}
},
computed: {
enabled() {
return this.type !== '无'
},
},
watch: {
type(value: MetadataType) {
options.metadataType = value
},
},
const type = ref(options.metadataType ?? '无')
const items = ['无', 'ffmetadata', 'ogm']
watch(type, newValue => {
options.metadataType = newValue
})
</script>

View File

@ -16,33 +16,23 @@
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref } from 'vue'
import { DefaultWidget } from '@/ui'
import { logError } from '@/core/utils/log'
import { DownloadPackage } from '@/core/download'
import { getFriendlyTitle } from '@/core/utils/title'
import { MetadataType, generateByType } from './metadata'
import { type MetadataType, generateByType } from './metadata'
export default Vue.extend({
components: {
DefaultWidget,
},
data() {
return {
disabled: false,
}
},
methods: {
async run(type: MetadataType) {
try {
this.disabled = true
DownloadPackage.single(`${getFriendlyTitle(true)}.${type}.txt`, await generateByType(type))
} catch (error) {
logError(error)
} finally {
this.disabled = false
}
},
},
})
const disabled = ref(false)
const run = async (type: MetadataType) => {
try {
disabled.value = true
DownloadPackage.single(`${getFriendlyTitle(true)}.${type}.txt`, await generateByType(type))
} catch (error) {
logError(error)
} finally {
disabled.value = false
}
}
</script>

View File

@ -1,10 +1,11 @@
import { defineComponentMetadata } from '@/components/define'
import { PackageEntry } from '@/core/download'
import type { PackageEntry } from '@/core/download'
import { hasVideo } from '@/core/spin-query'
import { Toast } from '@/core/toast'
import { videoUrls } from '@/core/utils/urls'
import { DownloadVideoAssets } from '../download/types'
import { generateByType, MetadataType } from './metadata'
import type { DownloadVideoAssets } from '../download/types'
import type { MetadataType } from './metadata'
import { generateByType } from './metadata'
import { options } from './options'
export const title = '保存视频元数据'

View File

@ -1,15 +1,17 @@
import { VideoInfo, VideoPageInfo } from '@/components/video/video-info'
import { VideoQuality } from '@/components/video/video-quality'
import type { VideoPageInfo } from '@/components/video/video-info'
import { VideoInfo } from '@/components/video/video-info'
import type { VideoQuality } from '@/components/video/video-quality'
import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax'
import { meta } from '@/core/meta'
import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
import { name as componentName, title as pluginTitle } from '.'
import { FieldsMode, Options } from './options'
import type { Options } from './options'
import { FieldsMode } from './options'
export type MetadataType = 'ffmetadata' | 'ogm'
function escape(s: string) {
function mescape(s: string) {
return s.replace(/[=;#\\\n]/g, r => `\\${r}`)
}
@ -57,7 +59,7 @@ async function fetchMetadata(aid: string = unsafeWindow.aid, cid: string = unsaf
}
function ff(key: string, value: any, prefix = true) {
return `${prefix ? 'bilibili_' : ''}${key}=${escape(lodash.toString(value))}`
return `${prefix ? 'bilibili_' : ''}${key}=${mescape(lodash.toString(value))}`
}
async function generateFFMetadata(aid: string = unsafeWindow.aid, cid: string = unsafeWindow.cid) {

View File

@ -1,4 +1,5 @@
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import type { OptionsOfMetadata } from '@/components/define'
import { defineOptionsMetadata } from '@/components/define'
export enum FieldsMode {
ALL = '全部',

View File

@ -1,4 +1,4 @@
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import { defineOptionsMetadata, type OptionsOfMetadata } from '@/components/define'
export enum DisplayMode {
Auto = '自动',

View File

@ -18,9 +18,9 @@
<div class="lists">
选择快速收藏夹:
<VDropdown
v-model="selectedFavoriteList"
v-model:value="selectedFavoriteList"
:items="list"
:key-mapper="it => it.id"
:key-mapper="it => (it as DisplayItem).id"
@change="saveFavoriteList"
/>
</div>
@ -40,6 +40,7 @@ import { logError } from '@/core/utils/log'
import { VDropdown } from '@/ui'
import { DisplayMode, type Options } from './options'
type DisplayItem = { displayName: string; id: number }
const { options } = getComponentSettings('quickFavorite')
interface RawFavoriteListItem {
id: number
@ -70,7 +71,7 @@ export default defineComponent({
tipText: '',
tipShowing: false,
tipHandle: 0,
list: [] as { displayName: string; id: number }[],
list: [] as DisplayItem[],
selectedFavoriteList: EmptyFavoriteList,
listShowing: false,
displayMode,

View File

@ -1,4 +1,4 @@
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import { defineOptionsMetadata, type OptionsOfMetadata } from '@/components/define'
export enum DisplayMode {
Auto = '自动',

View File

@ -1,4 +1,4 @@
import { PluginMetadata } from '@/plugins/plugin'
import type { PluginMetadata } from '@/plugins/plugin'
import type { CustomNavbarItemInit } from '../../../components/style/custom-navbar/custom-navbar-item'
export const plugin: PluginMetadata = {

View File

@ -1,5 +1,5 @@
import { PluginMetadata } from '@/plugins/plugin'
import { DownloadVideoOutput } from '../../../../components/video/download/types'
import type { PluginMetadata } from '@/plugins/plugin'
import type { DownloadVideoOutput } from '../../../../components/video/download/types'
export const plugin: PluginMetadata = {
name: 'downloadVideo.outputs.empty',

View File

@ -10,27 +10,22 @@
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref } from 'vue'
import { getComponentSettings } from '@/core/settings'
import { TextBox } from '@/ui'
const { options } = getComponentSettings<ConfigDataType>('downloadVideo')
export default Vue.extend<ConfigDataType>({
components: {
TextBox,
},
data() {
return {
...lodash.pick(options, ['api_dev_key', 'api_user_key']),
}
},
methods: {
onChange() {
Object.assign(options, lodash.pick(this, ['api_dev_key', 'api_user_key']))
},
},
})
const api_dev_key = ref(options.api_dev_key || '')
const api_user_key = ref(options.api_user_key || '')
const onChange = () => {
Object.assign(options, {
api_dev_key: api_dev_key.value,
api_user_key: api_user_key.value,
})
}
</script>
<style lang="scss">
@import 'common';
@ -40,8 +35,6 @@ export default Vue.extend<ConfigDataType>({
@include v-stretch(12px);
> .config-item {
@include h-center(8px);
> .item-name {
}
}
}
</style>

View File

@ -1,10 +1,9 @@
import { monkey } from '@/core/ajax'
import { logError } from '@/core/utils/log'
import { DownloadVideoOutput } from '../../../../components/video/download/types'
import type { DownloadVideoOutput } from '../../../../components/video/download/types'
const getPastebinUrl = async (str: string, config: ConfigDataType) => {
const sp = new URLSearchParams()
Object.entries({
const sp = new URLSearchParams({
api_dev_key: config.api_dev_key,
api_user_key: config.api_user_key, // ! 必须绑定一个账号,否则链接可能被吞
api_folder_key: 'm3u',
@ -12,7 +11,7 @@ const getPastebinUrl = async (str: string, config: ConfigDataType) => {
api_paste_code: str,
api_paste_private: '1',
api_paste_expire_date: '10M',
}).forEach(([key, value]) => sp.append(key, value))
})
const response = await monkey<string>({
url: 'https://pastebin.com/api/api_post.php',
method: 'POST',
@ -24,7 +23,7 @@ const getPastebinUrl = async (str: string, config: ConfigDataType) => {
responseType: 'text',
fetch: true,
})
if (/^Bad API request,/.test(response)) {
if (response.startsWith('Bad API request,')) {
throw response
}

View File

@ -1,5 +1,5 @@
import { PluginMetadata } from '@/plugins/plugin'
import { DownloadVideoOutput } from '../../../../components/video/download/types'
import type { PluginMetadata } from '@/plugins/plugin'
import type { DownloadVideoOutput } from '../../../../components/video/download/types'
import { MPV_Ex } from './handler'
export const plugin: PluginMetadata = {

View File

@ -8,7 +8,8 @@
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import { ref } from 'vue'
import { SwitchBox } from '@/ui'
import { isComponentEnabled, getComponentSettings } from '@/core/settings'
@ -20,22 +21,11 @@ const defaultOptions: Options = {
}
const { options: storedOptions } = getComponentSettings('downloadVideo')
const options: Options = { ...defaultOptions, ...storedOptions }
export default Vue.extend({
components: {
SwitchBox,
},
data() {
const shouldShow = isComponentEnabled('saveVideoMetadata')
return {
shouldShow,
muxWithMetadata: shouldShow && options.muxWithMetadata,
}
},
methods: {
saveOptions() {
options.muxWithMetadata = this.muxWithMetadata
Object.assign(storedOptions, options)
},
},
})
const shouldShow = isComponentEnabled('saveVideoMetadata')
const muxWithMetadata = ref(shouldShow && options.muxWithMetadata)
const saveOptions = () => {
options.muxWithMetadata = muxWithMetadata.value
Object.assign(storedOptions, options)
}
</script>

View File

@ -1,11 +1,11 @@
import { DownloadPackage, PackageEntry } from '@/core/download'
import { DownloadPackage, type PackageEntry } from '@/core/download'
import { meta } from '@/core/meta'
import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
import { title as pluginTitle } from '.'
import type { Options } from '../../../../components/video/download'
import { DownloadVideoAction } from '../../../../components/video/download/types'
import type { DownloadVideoAction } from '../../../../components/video/download/types'
import { FFmpeg } from './ffmpeg'
import { getCacheOrFetch, httpGet, toastProgress, toBlobUrl } from './utils'

View File

@ -1,6 +1,6 @@
import { Toast } from '@/core/toast'
import { PluginMetadata } from '@/plugins/plugin'
import { DownloadVideoOutput } from '../../../../components/video/download/types'
import type { PluginMetadata } from '@/plugins/plugin'
import type { DownloadVideoOutput } from '../../../../components/video/download/types'
import { run } from './handler'
export const title = 'WASM 混流输出'

View File

@ -1,7 +1,8 @@
import { Toast } from '@/core/toast'
import type { Toast } from '@/core/toast'
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
import { getOrLoad, storeNames } from './database'
import { RuntimeLibraryDefinition, RuntimeLibrary } from '@/core/runtime-library'
import type { RuntimeLibraryDefinition } from '@/core/runtime-library'
import { RuntimeLibrary } from '@/core/runtime-library'
type OnProgress = (received: number, total: number) => void

View File

@ -112,9 +112,7 @@ const parseCard = async (element: HTMLElement): Promise<FeedsCard> => {
return [currentText, currentTitle].filter(it => Boolean(it)).join('\n')
}
const getNumber = async (selector: string) => {
const result = Number.parseIntarseIntarseIntarseIntarseIntarseIntarseIntarseIntarseIntarseInt(
await getSimpleText(selector),
)
const result = Number.parseInt(await getSimpleText(selector))
if (isNaN(result)) {
return 0
}

View File

@ -166,7 +166,7 @@ export class FeedsCardsManagerV2 extends FeedsCardsManager {
if (!isNodeValid(node)) {
return
}
const vueData = getVue2Data(node)
const vueData = getVueData(node)
if (!vueData) {
return
}

View File

@ -41,11 +41,11 @@ export class BingTranslate extends MachineTranslateProvider {
const response = await monkey({
url: 'https://cn.bing.com/ttranslatev3',
method: 'POST',
data: formData({
data: new URLSearchParams({
fromLang: 'auto-detect',
to: targetLanguage,
text,
}),
}).toString(),
headers: {
'User-Agent': UserAgent,
'Content-Type': 'application/x-www-form-urlencoded',

View File

@ -10,7 +10,7 @@ export interface LanguagePack {
map?: [string, Translation][]
regex?: RegexTranslation
}
export interface Options {
export type Options = {
language: string
translator: string
}

View File

@ -7,8 +7,8 @@
@click.self="performAction($event)"
@keydown.enter.prevent.stop="performAction($event)"
@keydown.shift.delete.prevent.stop="performDelete($event)"
@keydown.up.prevent.stop="$emit('previous-item', $event.currentTarget)"
@keydown.down.prevent.stop="$emit('next-item', $event.currentTarget)"
@keydown.up.prevent.stop="emits('previous-item')"
@keydown.down.prevent.stop="emits('next-item')"
>
<div class="be-launch-bar-suggest-item-content">
<div
@ -47,42 +47,35 @@
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script lang="ts" setup>
import type { PropType } from 'vue'
import type { LaunchBarAction } from '@/components/launch-bar/launch-bar-action'
import { VIcon } from '@/ui'
export default defineComponent({
components: {
VIcon,
},
props: {
action: {
type: Object as PropType<LaunchBarAction>,
required: true,
},
},
emits: {
action: null as (e: KeyboardEvent | MouseEvent) => true,
'delete-item': null as (e: KeyboardEvent | MouseEvent) => true,
'previous-item': null as (e: KeyboardEvent) => true,
'next-item': null as (e: KeyboardEvent) => true,
},
methods: {
async performAction(event: KeyboardEvent | MouseEvent) {
await this.action.action()
this.$emit('action', event)
},
async performDelete(event: KeyboardEvent | MouseEvent) {
if (!this.action.deleteAction) {
return
}
await this.action.deleteAction()
this.$emit('delete-item', event)
},
const { action } = defineProps({
action: {
type: Object as PropType<LaunchBarAction>,
required: true,
},
})
const emits = defineEmits<{
(e: 'action', event: KeyboardEvent | MouseEvent): void
(e: 'delete-item', event: KeyboardEvent | MouseEvent): void
(e: 'previous-item'): void
(e: 'next-item'): void
}>()
const performAction = async (event: KeyboardEvent | MouseEvent) => {
await action.action()
emits('action', event)
}
const performDelete = async (event: KeyboardEvent | MouseEvent) => {
if (!action.deleteAction) {
return
}
await action.deleteAction()
emits('delete-item', event)
}
</script>
<style lang="scss">
@import 'common';

View File

@ -9,49 +9,36 @@
<LaunchBar ref="launchBar" @close="close()" />
</VPopup>
</template>
<script lang="ts">
import type { Ref } from 'vue'
import { defineComponent, ref } from 'vue'
<script lang="ts" setup>
import { watch, onMounted, ref, useTemplateRef } from 'vue'
import LaunchBar from './LaunchBar.vue'
import type launchBarVue from './LaunchBar.vue'
import VPopup from '@/ui/VPopup.vue'
import LaunchBar from './LaunchBar.vue'
const launchBar = useTemplateRef<InstanceType<typeof launchBarVue>>('launchBar')
const show = ref(true)
export default defineComponent({
components: {
LaunchBar,
VPopup,
},
setup: () => ({
launchBar: ref(null) as Ref<InstanceType<typeof LaunchBar> | null>,
}),
data() {
return {
show: true,
}
},
watch: {
show(value: boolean) {
if (value) {
this.focus()
}
},
},
async mounted() {
await this.$nextTick()
this.focus()
},
methods: {
focus() {
const input = this.launchBar?.input
input?.focus()
input?.select()
},
close() {
this.show = false
const input = this.launchBar?.input
input?.blur()
},
},
const focus = () => {
const { input } = launchBar.value
input.focus()
input.select()
}
const close = () => {
show.value = false
const { input } = launchBar.value
input.blur()
}
watch(show, (value: boolean) => {
if (value) {
focus()
}
})
onMounted(() => {
focus()
})
defineExpose({
show,
})
</script>
<style lang="scss">

View File

@ -37,7 +37,7 @@
@delete-item="onDeleteItem(index)"
@action="
index === actions.length - 1 && onClearHistory()
onAction(a)
onAction()
"
/>
</div>
@ -59,16 +59,15 @@
@previous-item="previousItem()"
@next-item="nextItem()"
@delete-item="onDeleteItem(index)"
@action="onAction(a)"
@action="onAction()"
/>
</div>
</div>
</div>
</template>
<script lang="ts">
<script lang="ts" setup>
import Fuse from 'fuse.js'
import type { Ref } from 'vue'
import { defineComponent, ref } from 'vue'
import { computed, onMounted, reactive, ref, useTemplateRef, watch } from 'vue'
import { VIcon, VLoading, VEmpty } from '@/ui'
import { registerAndGetData } from '@/plugins/data'
import { select } from '@/core/spin-query'
@ -90,8 +89,8 @@ const [actionProviders] = registerAndGetData(LaunchBarActionProviders, [
historyProvider,
]) as [LaunchBarActionProvider[]]
const sortActions = (actions: LaunchBarAction[]) => {
return [...actions].sort(ascendingSort(it => it.order ?? Infinity))
const sortActions = (actions: SearchAction[]) => {
return [...actions].sort(ascendingSort(it => it.order ?? Number.POSITIVE_INFINITY))
}
const generateKeys = (
provider: LaunchBarActionProvider,
@ -108,15 +107,32 @@ const generateKeys = (
provider,
}
})
async function getOnlineActions(this: InstanceType<typeof ThisComponent>) {
const [recommended] = registerAndGetData('launchBar.recommended', {
word: '搜索',
href: 'https://search.bilibili.com/',
})
type SearchAction = {
key: string
provider: LaunchBarActionProvider
} & LaunchBarAction
const emits = defineEmits(['close'])
const input = useTemplateRef('input')
const list = useTemplateRef('list')
const focusTarget = reactive(new FocusTarget(0))
const keyword = ref('')
const noActions = ref(false)
const actions = ref<SearchAction[]>([])
const isHistory = computed(() => keyword.value.length === 0)
const getOnlineActions = lodash.debounce(async () => {
const onlineActions = (
await Promise.all(
actionProviders.map(async provider =>
generateKeys(provider, await provider.getActions(this.keyword)),
generateKeys(provider, await provider.getActions(keyword.value)),
),
)
).flat()
if (this.isHistory) {
if (isHistory.value) {
return
}
const fuse = new Fuse(onlineActions, {
@ -124,163 +140,130 @@ async function getOnlineActions(this: InstanceType<typeof ThisComponent>) {
includeScore: true,
threshold: 0.1,
})
const fuseResult = fuse.search(this.keyword)
console.log(fuseResult)
this.actions = sortActions(fuseResult.map(it => it.item).slice(0, 13))
this.noActions = this.actions.length === 0
}
async function getActions(this: InstanceType<typeof ThisComponent>) {
this.noActions = false
if (this.isHistory) {
this.actions = sortActions(
generateKeys(historyProvider, await historyProvider.getActions(this.keyword)),
const fuseResult = fuse.search(keyword.value)
// console.log(fuseResult)
actions.value = sortActions(fuseResult.map(it => it.item).slice(0, 13))
noActions.value = actions.value.length === 0
}, 200)
const getActions = async () => {
noActions.value = false
if (isHistory.value) {
actions.value = sortActions(
generateKeys(historyProvider, await historyProvider.getActions(keyword.value)),
)
return
}
const actions: LaunchBarAction[] = []
this.actions = actions
this.getOnlineActions()
actions.value = []
getOnlineActions()
}
const [recommended] = registerAndGetData('launchBar.recommended', {
word: '搜索',
href: 'https://search.bilibili.com/',
watch(keyword, () => {
getActions()
})
const ThisComponent = defineComponent({
components: {
VIcon,
VLoading,
VEmpty,
ActionItem,
},
emits: ['close'],
setup: () => ({
input: ref(null) as Ref<HTMLInputElement | null>,
list: ref(null) as Ref<HTMLDivElement | null>,
}),
data() {
const focusTarget = new FocusTarget(0)
return {
recommended,
actions: [] as LaunchBarAction[],
keyword: '',
focusTarget,
noActions: false,
}
},
computed: {
isHistory(): boolean {
return this.keyword.length === 0
},
},
watch: {
keyword() {
this.getActions()
},
actions() {
this.focusTarget.reset(this.actions.length)
},
},
async mounted() {
await this.getActions()
if (matchUrlPattern(/^https?:\/\/search\.bilibili\.com/)) {
await this.setupSearchPageSync()
}
this.focusTarget.addEventListener('index-change', () => {
this.handleIndexUpdate()
})
},
methods: {
getOnlineActions: lodash.debounce(getOnlineActions, 200),
getActions,
async setupSearchPageSync() {
const selector = '#search-keyword, .search-input-el'
const input = (await select(selector)) as HTMLInputElement
if (!input) {
return
}
urlChange(url => {
const params = new URLSearchParams(url)
const keywordFromParam = params.get('keyword')
if (keywordFromParam !== null) {
this.keyword = params.get('keyword')
}
})
await this.$nextTick()
},
handleSelect() {
this.$emit('close')
this.getActions()
},
async handleEnter(e: KeyboardEvent) {
if (e.isComposing) {
return
}
if (this.actions.length > 0 && !this.isHistory) {
const [first] = this.actions as LaunchBarAction[]
if (first.explicitSelect !== true) {
first.action()
return
}
}
if (this.keyword) {
search(this.keyword)
this.handleSelect()
return
}
window.open(this.recommended.href, '_blank')
this.handleSelect()
},
handleUp(e: KeyboardEvent) {
if (e.isComposing) {
return
}
this.focusTarget.previous()
e.preventDefault()
},
handleDown(e: KeyboardEvent) {
if (e.isComposing) {
return
}
this.focusTarget.next()
e.preventDefault()
},
async handleIndexUpdate() {
await this.$nextTick()
if (!this.focusTarget.hasFocus) {
this.focusInput()
return
}
this.focusSuggestItem(this.focusTarget.index + 1)
},
previousItem() {
this.focusTarget.previous()
},
nextItem() {
this.focusTarget.next()
},
search,
onDeleteItem(index: number) {
this.focusTarget.setFocus(index)
this.focusTarget.previous()
this.getActions()
},
onClearHistory() {
this.focusInput()
this.getActions()
},
onAction() {
this.handleSelect()
},
focusInput() {
this.input.focus()
},
focusSuggestItem(nth: number) {
this.list.querySelector(`.be-launch-bar-suggest-item:nth-child(${nth})`)?.focus()
},
},
watch(actions, () => {
focusTarget.reset(actions.value.length)
})
const setupSearchPageSync = async () => {
const selector = '#search-keyword, .search-input-el'
const searchInput = (await select(selector)) as HTMLInputElement
if (!searchInput) {
return
}
urlChange(url => {
const params = new URLSearchParams(url)
const keywordFromParam = params.get('keyword')
if (keywordFromParam !== null) {
keyword.value = keywordFromParam
}
})
// await this.$nextTick()
}
const focusInput = () => {
input.value.focus()
}
const handleSelect = () => {
emits('close')
getActions()
}
const handleEnter = async (e: KeyboardEvent | MouseEvent) => {
if ((e as KeyboardEvent).isComposing) {
return
}
if (actions.value.length > 0 && !isHistory.value) {
const [first] = actions.value as LaunchBarAction[]
if (first.explicitSelect !== true) {
first.action()
return
}
}
if (keyword.value) {
search(keyword.value)
handleSelect()
return
}
window.open(recommended.href, '_blank')
handleSelect()
}
const focusSuggestItem = (nth: number) => {
;(
list.value.querySelector(`.be-launch-bar-suggest-item:nth-child(${nth})`) as HTMLDivElement
)?.focus()
}
const handleUp = (e: KeyboardEvent) => {
if (e.isComposing) {
return
}
focusTarget.previous()
e.preventDefault()
}
const handleDown = (e: KeyboardEvent) => {
if (e.isComposing) {
return
}
focusTarget.next()
e.preventDefault()
}
const handleIndexUpdate = async () => {
// await this.$nextTick()
if (!focusTarget.hasFocus) {
focusInput()
return
}
focusSuggestItem(focusTarget.index + 1)
}
const previousItem = () => {
focusTarget.previous()
}
const nextItem = () => {
focusTarget.next()
}
const onDeleteItem = (index: number) => {
focusTarget.setFocus(index)
focusTarget.previous()
getActions()
}
const onClearHistory = () => {
focusInput()
getActions()
}
const onAction = () => {
handleSelect()
}
onMounted(async () => {
await getActions()
if (matchUrlPattern(/^https?:\/\/search\.bilibili\.com/)) {
await setupSearchPageSync()
}
focusTarget.addEventListener('index-change', () => {
handleIndexUpdate()
})
})
defineExpose({
input,
})
export default ThisComponent
</script>
<style lang="scss">
@import 'common';

View File

@ -224,8 +224,8 @@ export class LiveSocket extends EventTarget {
}
if (
this.webSocket &&
[WebSocket.CONNECTING, WebSocket.OPEN].includes(this.webSocket.readyState)
(this.webSocket && this.webSocket.readyState === WebSocket.OPEN) ||
this.webSocket.readyState === WebSocket.CONNECTING
) {
this.stop()
}

View File

@ -3,7 +3,8 @@ import { childList } from '@/core/observer'
import { CommentItem } from '../comment-item'
import { DomCommentArea } from './dom'
import { CommentReplyItem } from '../reply-item'
import { HTMLElementWithVue, VNodeManager } from '../vnode-manager'
import type { HTMLElementWithVue } from '../vnode-manager'
import { VNodeManager } from '../vnode-manager'
export class CommentAreaV2 extends DomCommentArea {
private vnodeManager: VNodeManager

View File

@ -1,7 +1,8 @@
import { ShadowDomObserver, shadowDomObserver, ShadowRootEvents } from '@/core/shadow-root'
import type { ShadowDomObserver } from '@/core/shadow-root'
import { shadowDomObserver, ShadowRootEvents } from '@/core/shadow-root'
import { CommentReplyItem } from '../reply-item'
import { CommentArea } from './base'
import { ShadowDomEntry } from '@/core/shadow-root/dom-entry'
import type { ShadowDomEntry } from '@/core/shadow-root/dom-entry'
import { CommentItem } from '../comment-item'
import { deleteValue } from '@/core/utils'
import { select } from '@/core/spin-query'

View File

@ -1,6 +1,6 @@
import { allMutations, childList } from '@/core/observer'
import { getCommentArea } from './comment-area'
import {
import type {
CommentAreaCallback,
CommentCallbackInput,
CommentCallbackPair,

View File

@ -1,5 +1,5 @@
import { CommentReplyItem } from './reply-item'
import { RepliesUpdateEventCallback, RepliesUpdateEventType } from './types'
import { type RepliesUpdateEventCallback, RepliesUpdateEventType } from './types'
const createRepliesUpdateEvent = (replies: CommentReplyItem[]) => {
return new CustomEvent(RepliesUpdateEventType, {

View File

@ -1,6 +1,6 @@
import { PlayerAgent, selectorWrap } from './base'
import { bpxSelectors } from './bpx'
import { AgentType, PlayerQuery, ElementQuery } from './types'
import type { AgentType, PlayerQuery, ElementQuery } from './types'
export class BangumiPlayerAgent extends PlayerAgent {
type: AgentType = 'bangumi'
@ -11,10 +11,6 @@ export class BangumiPlayerAgent extends PlayerAgent {
...bpxSelectors,
}) as PlayerQuery<ElementQuery>
constructor() {
super()
}
seek(time: number) {
const seekResult = super.seek(time)
if (seekResult === null) {

View File

@ -1,6 +1,6 @@
import { isBwpVideo } from '@/core/utils'
import { PlayerAgent, selectorWrap } from './base'
import { PlayerQuery, ElementQuery, AgentType } from './types'
import type { PlayerQuery, ElementQuery, AgentType } from './types'
import { select } from '@/core/spin-query'
import { bpxSelectors } from './bpx'

View File

@ -39,7 +39,7 @@ export const addControlBarButton = async (button: VideoControlBarItem) => {
if (!controlBarInstance) {
controlBarInstance = initControlBar()
}
const created = (await controlBarInstance) as ControlBarComponent
const created = await controlBarInstance
if (!created) {
return
}

View File

@ -1,7 +1,8 @@
import { contentLoaded } from '../life-cycle'
import { childListSubtree } from '../observer'
import { deleteValue } from '../utils'
import { ShadowDomCallback, ShadowDomEntry } from './dom-entry'
import type { ShadowDomCallback } from './dom-entry'
import { ShadowDomEntry } from './dom-entry'
import { ShadowRootObserver } from './root-observer'
import { ShadowRootEvents } from './types'

View File

@ -1,4 +1,4 @@
import { ShadowRootEvents } from './types'
import type { ShadowRootEvents } from './types'
export abstract class ShadowRootObserver extends EventTarget {
static queryAllShadowRoots(

View File

@ -1,7 +1,8 @@
import { addComponentListener, removeComponentListener } from '../settings'
import { deleteValue, getRandomId } from '../utils'
import { ShadowDomEntry } from './dom-entry'
import { ShadowDomObserver, shadowDomObserver } from './dom-observer'
import type { ShadowDomEntry } from './dom-entry'
import type { ShadowDomObserver } from './dom-observer'
import { shadowDomObserver } from './dom-observer'
export interface ShadowRootStyleEntry {
id: string

View File

@ -4,22 +4,13 @@
<template v-if="typeof config.content === 'string' && config.content.length > 0">
{{ config.content }}
</template>
<component :is="config.content" v-if="typeof config.content !== 'string'"></component>
<component :is="config.content as Component" v-if="typeof config.content !== 'string'" />
</slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { emptyContent } from './v-empty'
export default defineComponent({
name: 'VEmpty',
data() {
return {
config: emptyContent,
}
},
})
<script lang="ts" setup>
import type { Component } from 'vue'
import { emptyContent as config } from './v-empty'
</script>
<style lang="scss">
@import 'common';

View File

@ -4,22 +4,13 @@
<template v-if="typeof config.content === 'string' && config.content.length > 0">
{{ config.content }}
</template>
<component :is="config.content" v-if="typeof config.content !== 'string'"></component>
<component :is="config.content as Component" v-if="typeof config.content !== 'string'" />
</slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { loadingContent } from './v-loading'
export default defineComponent({
name: 'VLoading',
data() {
return {
config: loadingContent,
}
},
})
<script lang="ts" setup>
import type { Component } from 'vue'
import { loadingContent as config } from './v-loading'
</script>
<style lang="scss">
@import 'common';

View File

@ -1,6 +1,9 @@
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"compilerOptions": {
"compilerOptions": {
"importsNotUsedAsValues": "remove",
"preserveValueImports": false,
"verbatimModuleSyntax": true,
"strict": false,
"sourceMap": true,
"baseUrl": ".",
@ -13,7 +16,7 @@
}
},
"vueCompilerOptions": {
"target": 2.7
"target": 3.5,
},
"include": [
"src/**/*",