Move v2 files

This commit is contained in:
the1812 2021-10-26 13:16:35 +08:00
parent 31b173401d
commit 9f452209fe
1278 changed files with 51746 additions and 43111 deletions

View File

@ -1,17 +0,0 @@
{
"presets": [
// "@babel/preset-env",
[
"@babel/preset-typescript",
{
"allExtensions": true
}
]
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
"./builder/node/@babel/plugin-top-level-return"
]
}

63
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,63 @@
# This is a basic workflow to help you get started with Actions
name: Build
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the v2 branch
on:
push:
branches: [ v2 ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
with:
fetch-depth: '0'
- name: Install dependencies
uses: bahmutov/npm-install@v1
- name: Type check
run: yarn type
- name: ESLint check
run: yarn lint
- name: Build core
run: yarn build-core
- name: Build features
run: |
cd registry
yarn
cd ../
yarn build-features
- name: Git commit
id: commit
run: |
git config --local user.email "the1812@outlook.com"
git config --local user.name "the1812"
git config --global core.autocrlf true
git config --global core.safecrlf false
git commit -m "CI build" -a
continue-on-error: true
- name: Git push
uses: ad-m/github-push-action@master
if: ${{ steps.commit.outcome == 'success' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: 'v2'
- name: Log
if: ${{ steps.commit.outcome != 'success' }}
run: echo Nothing to commit.

View File

@ -0,0 +1,37 @@
# This is a basic workflow to help you get started with Actions
name: Pull Request Check
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the v2 branch
on: [pull_request]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
check:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Install dependencies
uses: bahmutov/npm-install@v1
- name: Type check
run: yarn type
- name: ESLint check
run: yarn lint
- name: Build core
run: yarn build-core
- name: Build features
run: yarn build-features
- name: Log
run: echo Check complete.

280
.gitignore vendored
View File

@ -1,277 +1,7 @@
bilibili-evolved.dev.js
.DS_Store
builder/dotnet/Properties
dist/
.node_modules/
.ts-output/
.sass-output/
package-lock.json
dark.css
dark-template.css
_dark-template.scss
min/dark-slice-*.min.scss
min/dark-slice-*.min.css
doc/roadmap.*
*.csx
*.backup.*
*.vue.ts
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
*.backup.*
dev/
*.log
dist/stats.html
dist/bilibili-evolved.dev.user.js

24
.vscode/dynamic-import.code-snippets vendored Normal file
View File

@ -0,0 +1,24 @@
{
// Place your Bilibili Evolved workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Dynamic import": {
"scope": "javascript, typescript",
"prefix": "import",
"body": "const { $2 } = await import('$1')$0",
"description": "Dynamic import"
}
}

View File

@ -1,7 +0,0 @@
{
"recommendations": [
"ms-dotnettools.csharp",
"octref.vetur",
"editorconfig.editorconfig"
]
}

View File

@ -1,5 +1,5 @@
{
// Place your Bilibili Evo workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// Place your Bilibili Evolved workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:

23
.vscode/launch.json vendored
View File

@ -4,28 +4,5 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "重新编译 rebuild",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/builder/dotnet/bin/Debug/netcoreapp3.1/build.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "internalConsole",
"preLaunchTask": "构建编译器 (Debug模式) compile builder"
},
{
"name": "监视 watch",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/builder/dotnet/bin/Debug/netcoreapp3.1/build.dll",
"args": ["watch"],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"internalConsoleOptions": "neverOpen",
"console": "integratedTerminal",
"preLaunchTask": "构建编译器 (Debug模式) compile builder"
}
]
}

56
.vscode/settings.json vendored
View File

@ -14,26 +14,36 @@
"**/build-scripts/**"
],
"cSpell.words": [
"BVID",
"Bangumi",
"Biliplus",
"Bing",
"Blockable",
"Danmaku",
"Doujin",
"Fullscreen",
"Greasemonkey",
"HEVC",
"Iframes",
"Interop",
"Liveroom",
"Otaku",
"Muuri",
"Popcap",
"Roadmap",
"Sendbar",
"Swiper",
"Tampermonkey",
"Touhou",
"Violentmonkey",
"Vuex",
"WASD",
"Watchlater",
"Wasm",
"afterbegin",
"afterend",
"bevo",
"bili",
"bilibili",
"bofqi",
"btns",
"bvid",
"camelcase",
"clipboardy",
"cntr",
"compositionend",
@ -42,41 +52,61 @@
"ctnr",
"danmakus",
"debounced",
"devtools",
"downloaders",
"dpis",
"durl",
"epid",
"esbuild",
"githubusercontent",
"gridview",
"haruna",
"hdslb",
"iconfont",
"imgleft",
"jinkela",
"jsdelivr",
"jszip",
"kanban",
"kichiku",
"linebreak",
"materialdesignicons",
"medialist",
"mimetype",
"minmax",
"mixins",
"overscroll",
"pako",
"plusplus",
"popperjs",
"preload",
"protobuf",
"qrcode",
"rcmd",
"reimu",
"reloadable",
"reloadables",
"remd",
"repo",
"repost",
"reposts",
"squirtle",
"roomid",
"saturationv",
"superchat",
"tabindex",
"truetype",
"uname",
"woff",
"xmlhttp"
],
"javascript.validate.enable": true,
"svg.preview.background": "transparent",
"prettier.semi": false,
"typescript.format.semicolons": "remove",
"javascript.format.semicolons": "remove",
"files.associations": {
"*.user.js": "plain",
"*.dev.js": "plain"
// don't highlight generated files
"*.user.js": "plaintext",
"**/dist/**/*.js": "plaintext"
},
"search.exclude": {
"**/dev": true,
"**/dist": true,
"**/yarn.lock": true
}
}

192
.vscode/tasks.json vendored
View File

@ -4,122 +4,128 @@
"version": "2.0.0",
"tasks": [
{
"label": "生产编译 production",
"type": "shell",
"command": "dotnet builder/dotnet/publish/build.dll production",
"options": {
"cwd": "./"
},
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "重新编译 rebuild",
"type": "shell",
"command": "dotnet builder/dotnet/publish/build.dll",
"options": {
"cwd": "./"
},
"command": "yarn webpack --config ./webpack/webpack.dev.js --progress",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
"problemMatcher": [],
"label": "本体:编译开发版本 dev:build-core"
},
{
"label": "监视 watch",
"type": "shell",
"command": "dotnet builder/dotnet/publish/build.dll watch",
"options": {
"cwd": "./"
},
"command": "yarn webpack --watch --config ./webpack/webpack.dev.js --progress",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
"problemMatcher": [],
"label": "本体:监视开发版本 dev:watch-core"
},
{
"label": "生产监视 production-watch",
"type": "shell",
"command": "dotnet builder/dotnet/publish/build.dll watch production",
"options": {
"cwd": "./"
},
"command": "yarn serve dist -p ${input:serverPort}",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
"problemMatcher": [],
"label": "本体:启动服务器 dev:serve-core"
},
{
"label": "构建编译器 compile builder",
"type": "shell",
"command": "dotnet publish -c Release -o publish/",
"options": {
"cwd": "./builder/dotnet/"
},
"command": "yarn serve registry/dist -p ${input:serverPort}",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
"problemMatcher": [],
"label": "功能:启动服务器 dev:serve-features"
},
{
"label": "构建编译器 (Debug模式) compile builder",
"type": "shell",
"command": "dotnet build",
"options": {
"cwd": "./builder/dotnet/"
},
"command": "yarn webpack --watch --config ./registry/webpack/components.js --progress",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": [],
"label": "功能:监视组件 dev:watch-components"
},
{
"type": "shell",
"command": "yarn webpack --watch --config ./registry/webpack/plugins.js --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:监视插件 dev:watch-plugins"
},
// {
// "type": "shell",
// "command": "yarn webpack --config ./webpack/webpack.measure.js --progress",
// "problemMatcher": [],
// "label": "打包分析 dev:measure"
// },
// {
// "type": "shell",
// "command": "./dist/stats.html",
// "problemMatcher": [],
// "dependsOn": "打包分析 dev:measure",
// "label": "查看打包分析 dev:stats"
// },
{
"type": "shell",
"command": "yarn eslint -f html -o dev/eslint.html --cache --cache-location node_modules/.cache/eslint/ 'src/**/*.@(js|ts|vue)' 'registry/lib/**/*.@(js|ts|vue)'",
"group": "build",
"problemMatcher": [],
"label": "生产:代码检查 prod:lint"
},
{
"type": "shell",
"command": "yarn eslint -f html -o dev/eslint.html --cache --cache-location node_modules/.cache/eslint/ --fix 'src/**/*.@(js|ts|vue)' 'registry/lib/**/*.@(js|ts|vue)'",
"group": "build",
"problemMatcher": [],
"label": "生产:代码修复 prod:lint-fix"
},
{
"type": "shell",
"command": "yarn webpack --config ./webpack/webpack.prod.js --progress",
"group": "build",
"problemMatcher": [],
"label": "本体:编译生产版本 prod:build-core"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/components.js --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译组件 prod:bulid-components"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/plugins.js --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译插件 prod:build-plugins"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/all.js",
"group": "build",
"problemMatcher": [],
"label": "功能:编译所有 prod:build-features"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/docs.js --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译功能文档 prod:build-docs"
},
{
"type": "shell",
"command": "rm -r ./node_modules/.cache/webpack/",
"label": "缓存:清除webpack cache:clean-webpack",
"problemMatcher": []
},
{
"label": "同步i18n数据 sync i18n",
"type": "shell",
"command": "node ./builder/node/i18n-sync/i18n-sync.js",
"presentation": {
"echo": false,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": false
},
"command": "rm -r ./node_modules/.cache/",
"label": "缓存:清除全部 cache:clear-all",
"problemMatcher": []
}
],
"inputs": [
{
"id": "serverPort",
"type": "promptString",
"description": "监听端口",
"default": "5000"
}
]
}

24
.vscode/ui-import.code-snippets vendored Normal file
View File

@ -0,0 +1,24 @@
{
// Place your Bilibili Evolved workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"UI import": {
"scope": "javascript, typescript",
"prefix": "ui",
"body": "import {\n $0\n} from '@/ui'",
"description": "UI import"
},
}

24
.vscode/vue-import.code-snippets vendored Normal file
View File

@ -0,0 +1,24 @@
{
// Place your Bilibili Evolved workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Vue import": {
"scope": "javascript, typescript",
"prefix": "vue",
"body": "() => import('$1').then(m => m.default)$0",
"description": "Vue import"
}
}

285
CHANGELOG.md Normal file
View File

@ -0,0 +1,285 @@
# 更新日志
## v2.0.0-tp9
`v2.0.0 Technical Preview ⑨` `2021-10-17`
**功能:**
- 组件与 `v1.12.20` 同步更新.
- 自定义顶栏:
- 新增`新标签页打开`选项
- 改善了拖动排列顶栏元素顺序时的性能.
- `收藏`弹窗中修复了一些搜索相关的 bug.
- 暂时禁止了`动态`上定时刷新的数字提醒, 因为弹窗里还没做完实时刷新. (#2303)
- 番剧区:
- 修复宽屏模式 + mini 播放器出现的布局错乱. (PR #2371 by [FoundTheWOUT](https://github.com/FoundTheWOUT))
- 恢复`默认播放器模式`, `启用双击控制`和`控制栏触摸优化`的支持.
- 夜间模式更新. (PR #2296 by [FoundTheWOUT](https://github.com/FoundTheWOUT))
- 修复 Firefox 下无法加载. (#2308)
- 下载视频中支持仅下载音频. (#2325)
- 更新了直播间勋章的 API.
- 修复夜间模式下部分 iframe 弹窗背景没有变透明.
- 修复组件没超过更新间隔期时, 选项里点检查更新不执行.
**开发:**
- 修复 `VSlider` 上使用方向键没有阻止默认行为.
- 修复 `MiniToast` 加载过早时获取不到 `body`.
- `addControlBarButton` 支持番剧区.
## v2.0.0-tp8
`v2.0.0 Technical Preview 8` `2021-09-15`
**功能:**
- 组件与 `v1.12.18` 同步更新.
- 使用在线仓库时, 连接到 `github.com` 时无需再设置跨域.
- 修复搜索栏建议的文本过长时溢出.
- 快捷键设置也能从搜索栏中唤起了.
- 修复播放器控制栏的扩展按钮(截图, 逐帧调整等)颜色不对.
- 在组件详情的菜单中, 鼠标停留在 `检查更新` 上时可以显示安装的来源 URL, 如果是来自 `localhost`, 还会显示特定的图标作为区分. (#2278)
- 快捷键支持 <kbd>Ctrl</kbd>+<kbd>Enter</kbd> 发送评论. (#1015)
**开发:**
- 新增 `RuntimeLibrary API` (`src/core/runtime-library.ts`), 可以在运行时动态载入第三方库, 可以避免在每次载入页面时都加载了不常用的库. 以下原先内置于脚本的库现已转换为运行时库:
- protobufjs
- JSZip
- Sortable
- 重新整理了 `task.json` 中任务的命名.
- 功能也和本体一样能参与 CI 构建流程了.
- 支持记录第三方功能并在在线仓库中显示.
- 在 `CONTRIBUTING.md` 中补充了一些 API 说明.
- 主题颜色除了 10 级不同透明度 `var(--theme-color-XX)`, 也支持了 10 级不同明亮度 `var(--theme-color-lightness-XX)`.
- `Toast``duration` 即使在 Toast 已发出后也能响应更改了.
- 同 v1 一样, 按住 <kbd>Shift</kbd> 点击侧栏的功能将会执行 `debugger` 语句, 在开发者工具打开时能够立即停止页面运行.
- 清理了一些无用文件, `widgets` 文件夹中的代码移动到 `ui``components` 中对应的文件夹.
- `observer` 新增 `urlChange`, 可以检测 URL 变动.
## v2.0.0-tp7
`v2.0.0 Technical Preview 7` `2021-08-23`
**功能:**
- 组件与 `v1.12.16` 同步更新.
- 新增组件 `v1 风格设置面板`.
- 在功能的管理面板中, 支持在线安装新功能.
- 搜索栏支持提供自定义选项, 目前实现的有:
- 切换在线仓库
- 自定义顶栏设置
- 修复 `observer.allMutations` 只处理第一个调用者.
- 修复高能进度条未固定时的样式.
- 尝试为 `bwp-video` 适配 `播放前显示封面`.
- `播放器控制栏背景色` 的不透明度选项使用 `0% ~ 100%` 做范围, 之前保存的值默认是 `0.64`, 如果你之前使用过, 更新后记得去改成 `64`.
**开发:**
- `Toast` API 支持 `Toast.mini` 并提供对应组件 `MiniToast` (基于 [tippy.js](https://atomiks.github.io/tippyjs/)), 用于在特定元素旁边弹出小提示.
- 插件允许提供描述 `PluginMetadata.description`
- 组件允许提供多语言配置和作者 `ComponentMetadata.i18n` / `ComponentMetadata.author`
- 删除所有的非必要 `eslint-disable`
- 统一内置组件的 UI 导入方式.
- Vue 内置于脚本, 不再由 `// @require` 提供.
- 组件选项支持使用滑动条提供带范围的数字选择 `ComponentOption.slider`, 例子可以参考 `registry/lib/components/video/player/control-background/index.ts`.
- 组件详情中支持扩展动作, 并内置了 `卸载` 动作.
## v2.0.0-tp6
`v2.0.0 Technical Preview 6` `2021-08-01`
- 搜索栏可以使用 <kbd>/</kbd> 全局唤起了. (安装了`快捷键扩展`时)
- 自定义顶栏功能同步至 `v1.12.13`.
- 新增组件 `v1 设置迁移`, 可以导入 v1 设置了, README 中有使用说明.
- 支持[合集包](https://github.com/the1812/Bilibili-Evolved/blob/v2/doc/features/pack/pack.md)安装, 设置面板中的批量安装可以接受任意类型的功能.
- `关于`面板中有了更多的链接, 并显示更详细的版本信息.
## v2.0.0-tp5
`v2.0.0 Technical Preview 5` `2021-07-24`
- 元数据中添加了 `@connect localhost`, 解决 Tampermonkey BETA 中不能从本地安装组件的问题.
- 修复 `LifeCycleEventTypes.ComponentsLoaded` 在组件运行完成前就触发的问题.
- 动态 API 支持自定义内容过滤器. (`动态过滤器`基于此 API 实现了对顶栏动态的过滤)
- 搜索栏的历史同步 b 站的搜索历史 (同 v1), 之前产生的历史数据可以通过运行以下代码来删除.
```js
delete bilibiliEvolved.settingsApis.getComponentSettings('launchBar').options.searchHistory
```
- 支持设置 `文件下载模式`.
**插件新增:**
- 下载视频 - IDM导出
- 搜索栏 - 搜索推荐
**组件迁移:**
所有常用组件已迁移完成, 剩余未迁移的还有:
- 工作量过大 (Coming S∞n)
- 清爽首页
- 极简首页
- 隐藏功能 (有一定缺陷所以未公开)
- 网址AV号转换
- 评论楼层显示
- 废弃功能 (被 b 站官方实现)
- 默认视频画质
- 解除音量上限
另外一部分组件功能还未更新到 v1.12.12 的进度:
- 下载视频
- 不支持 ffmpeg 相关导出
- 不支持课程 / 番剧 / 电影
- 自定义顶栏
- 分区未更新
- 搜索栏在搜索页没有同步搜索词
- 历史面板中的直播没有状态显示
- 收藏面板还不能记住上次选择的收藏夹
- 收藏面板还不能显示已失效视频
- 视频动态还不能显示发布时间
- `排行`还没有子菜单
- UI 样式未统一
## v2.0.0-tp4
`v2.0.0 Technical Preview 4` `2021-07-18`
**组件迁移:**
- 自动展开弹幕列表
- BiliPlus跳转支持
- 强制保留弹幕栏
- 隐藏推荐直播/视频推荐
- 直播间自动抽奖
- 直播首页静音/隐藏推荐直播
- 直播全屏弹幕栏/包裹
- 复制动态/评论链接
- 动态/评论翻译
> 移除了 Bing 翻译 (接口挂了), 翻译后可以实时更换翻译器 (#993)
- 动态/专栏图片导出
> 支持分别自定义命名格式, 不过具体说明还没写 (#1208)
- 启用细滚动条
- 高分辨率图片
- 简化首页
> 注意这个是 v1 中的 `首页过滤`, 更换为这个名字是为了和其他几个 `简化xxx` 功能保持一致. (都是移除某个页面中不需要的元素) 原 v1 中的 `简化首页` 会更换为 `清爽首页` 之类的名字.
**插件新增:**
- 设置面板 - '最近使用'类别
> 记录点开组件详情的时间, 让最近点开过的组件排序在上面
**其他:**
- `关于`页面中将显示本体的 commit hash
- `自动更新器`将自动跳过无在线链接(通过本地浏览安装)的功能.
**API 变更:**
- 组件不再必需填写 `enabledByDefault`, 默认就为 `true`.
- 组件的 `instantStyles` 会在开启/关闭时自动添加/移除了.
- 设置面板的标签分类使用自定义过滤函数. (上面那个'最近使用'类别的插件就是基于此)
## v2.0.0-tp3
`v2.0.0 Technical Preview 3` `2021-07-09`
- 设置面板更新:
- 修复高度过小时侧栏图标溢出面板
- 支持批量安装功能
- 支持设置导入/导出 (在关于面板中, 与 v1 不同的是导入后会自动刷新页面)
- 组件迁移:
- 展开动态内容
- 简化直播间
- 直播勋章快速更换
- 直播看板娘高DPI适配
- 自动收起直播侧栏
- 倍速记忆
- 删除视频弹窗
- 展开视频简介
- 外置稍后再看
- 启用快速收藏
- 快捷键扩展
- 插件新增:
- 下载视频 - aria2 输出支持
- 修复无法更新现有样式.
- 引入了 CSS `gap` 属性, 浏览器版本要求提高至 Chrome 84 / Firefox 80 / Safari 14.1
- 主脚本名称变动 (`Bilibili Evolved II`变为`Bilibili Evolved (v2)`), 更新时请多加注意.
- 生成了[功能列表文档](https://github.com/the1812/Bilibili-Evolved/blob/v2/doc/features/features.md).
> 好像只能装 GitHub 源的, jsDelivr 不知道为啥 Failed to fetch 了. 另外目前只能用 Stable 的版本, Preview 分支上还没有 v2 的文件.
## v2.0.0-tp2
`v2.0.0 Technical Preview 2` `2021-06-28`
- 设置面板更新:
- 支持右侧停靠
- 修复组件列表溢出面板
- 动画效果调整
- 更新了动态 API (`src/components/feeds/api`)
- 组件迁移:
- 禁止跳转动态详情
- 直播信息扩充
- 快速收起评论区
- 展开动态标题
- 动态反折叠
- 删除直播水印
- 专栏文字选择
- 网址参数清理
- 稍后再看重定向
- 启用弹幕空降
- 跳过充电鸣谢
- 自定义顶栏中的搜索改为默认不显示推荐词
- 样式输入格式改为与组件和插件一致 (使用 `.js` 文件), 修复样式无法卸载
## v2.0.0-tp1
`v2.0.0 Technical Preview 1` `2021-06-11`
此次 Release 为 v2.0.0 Technical Preview 1 (技术预览版), 请注意:
- 技术预览版仅供开发者或对此项目非常熟悉的用户体验, 如果你只对日常使用感兴趣, 请继续等待 v1 的后续更新.
- 主要是本体方面的换新, 功能模块尚未迁移完成, 因此还不能替代 v1 作为日常使用.
- 不保证稳定性, 可能有大量神秘 bug 潜伏.
欢迎来到 Bilibili Evolved v2 的第一个版本, 为了更长远的发展, 我完全重写了整个项目:
- 引入现代化前端工具 (webpack, Babel, PostCSS 等)
- 源代码 TypeScript 全覆盖 (webpack 等配置文件除外)
- 自带 UI 组件库 (基于 Vue)
- 移除对 jQuery 和 Vuex 的依赖
- 全新的架构设计, 本体大小可减小至 300+KB
- 不再有离线版, 你可以自行控制组件的更新
安装文件位于 [./dist/bilibili-evolved.user.js](./dist/bilibili-evolved.user.js) 或 [./dist/bilibili-evolved.preview.user.js](./dist/bilibili-evolved.user.js) , 虽然分了个预览版但目前还没有区别(
使用方法见 [README.md](./README.md#设置).
关于技术上的更详细的信息, 请参见[代码贡献指南](./CONTRIBUTING.md).
### 已完成功能
- 下载弹幕
- 夜间模式
- 跟随系统 / 计划时段
- 删除广告
- 查看封面
- 简化评论区
### 待完成功能 (近期)
- 下载视频, 已支持普通视频源 + flv / dash 格式 + 显示链接 / aria2 输出, 待实现番剧 / 课程 / 手动输入源, 纯音频格式 + IDM 输出.
- 自定义顶栏, 目前仅实现至 v1.10.20 (commit 855bb6f)
- 视频卡片联合投稿显示支持
- 简化直播间
- 设置面板
- 组件/插件/样式管理 - 文本 / 批量输入支持
- "关于"页面
- 停靠位置
### 你可能想问的其他问题
**v1 还会更新吗?**
在 v2 正式版发布前会保持更新, 只是频率可能慢些.
**v2 正式版何时发布?**
在功能迁移完成后, 会发布 v2 的预览版, 测试没有问题后就会发布正式版.
**是否会涵盖 v1 的所有功能?**
尽量会, 有些特别复杂的功能可能会在正式版发布之后再完成开发, 目前确定的有`简化首页`.
**本体体积缩小后, 还会在 GreasyFork 上发布吗?**
我拒绝.
**可以为 v2 开发组件了吗?**
可以弄些简单的玩玩, 复杂的组件建议等预览版发布后(接口基本稳定)再开发.

View File

@ -1,242 +1,37 @@
# 代码贡献指南 Pull Request Guide
# 代码贡献指南
## 环境需求
- [.NET Core 3.1+](https://dotnet.microsoft.com/download)
- [Node.js](https://nodejs.org/en/download/)
- [全局安装 yarn](https://yarnpkg.com/getting-started/install#global-install)
## 搭建开发环境
## 下载项目代码
将项目 Fork 至自己账户
- 需要安装 [Node.js](https://nodejs.org/en/download/), [Visual Studio Code](https://code.visualstudio.com/) 和 [yarn](https://yarnpkg.com/getting-started/install#global-install).
- 将项目 Fork 至自己账户后, 克隆至本地
然后克隆至本地
```powershell
git clone --single-branch -b preview https://github.com/{{your-name}}/Bilibili-Evolved.git
git clone https://github.com/{{your-name}}/Bilibili-Evolved.git -b v2 --single-branch
cd Bilibili-Evolved
```
- 安装依赖
## 安装依赖
```powershell
yarn
cd registry
yarn
```
## 修改代码
### 修改现有功能
- 启动[监视模式](##构建/监视)
- 确认功能对应的代码文件, 通常根据目录结构就可以找到, 实在找不到可以在设置中可以通过检查元素查看到某项功能对应的 `data-key`, 这个 key 对应的是 `src/client/resource-manifest.js` 中的 key, 从而可以得知相应的代码文件名称 (`path` 属性)
- 修改代码, 保存后会自动编译
### 本体
需要说明的是, 脚本本体和功能是分开的两个项目, 因此编译时也是分开的. 脚本本体的编译通常使用 `监视开发版 dev:watch` 任务, 会产生 `dist/bilibili-evolved.dev.user.js` 文件.
> 如果不使用 Visual Studio Code, 则需要根据 `.vscode/tasks.json` 中各个任务定义的命令手动在终端执行. (npm scripts 仅用于 CI)
#### 夜间模式修改
如果要改的是夜间模式, 改原有样式就原地改, 添加样式就进入数字最大的那个 `dark-slice-xxx.scss` 文件修改即可
然后配置本地调试环境:
> 你可能会发现, 旧的 slice 风格以多个不同地方的选择器 + 尽量少的样式声明组成; 新的 slice 里是按照修改的地方分开存放, 因为有 Sass 的 Mixin, 所以可以放心地随时添加样式声明, Mixin 列表见 `src/style/dark/_dark-definitions.scss`
附一些要点:
- 尽可能遵照 b 站白天原有的元素风格, 除非原版实在太丑
- 颜色相关的 Mixin 参数含义:
- 0个字符 `transparent`
- 1个字符 `e` -> `#eee`
- 2个字符 `e8` -> `#e8e8e8`
- 3/6个字符 `eee` -> `#eee`
- theme-color 相关的 Mixin 可以对各种属性应用主题色
- foreground-color 相关的 Mixin 仅用于主题色做背景时的前景色 (对应设置中的 `文本颜色`)
- 避免写入名字过于宽泛的选择器, 比如 `.card`, 夜间模式作用于所有页面, 要尽可能避免选择器误伤. 遇到这种情况可以向上寻找元素的父级 class, 组成一个 `.xxx .card` 就比较好
- 遇到纯色图片可以用 `@to-theme('pink')` / `@to-theme('blue')` 转换为主题色 (参数是原来的颜色, 目前就这两种, 放在 filter 上)
- 旧的 slice 基本都不符合这些要点, 不过我们也懒得改了(
### 添加新功能
- 在 `src/client/settings.js` 中的 `settings` 对象上添加新的 key, 作为新功能的默认值
> key 的名称尽量具体, 避免撞车, 因为所有选项都是平铺的, 如果是作为子选项, 也建议添加固定的前缀. 找参考的话别看文件里太上面的 key (都是些老功能), 命名不少都有问题, 为了兼容性就不改了.
- 在 `src/global.d.ts` 添加对应的类型声明
- 在 `src` 下对应的文件夹分类中创建代码文件, 如果只有一个 `.js` / `.ts` 文件, 可以不建子文件夹, 带有样式等建议放在同名的子文件夹
> ⚠️ 由于历史原因, 即便是分在不同的文件夹, 这些功能组件的文件名也不能重名
>
> ⚠️ 未来的 v2.0 架构已确定不兼容 v1.x, 请勿再为 v1.x 开发复杂功能
- 在 `src/client/resource-manifest.js` 中添加声明, 类型大致如下:
```ts
// 大部分可以参考文件里上方类似的写法
// 早期组件可能还会有一些这里没列出来的已弃用属性, 不建议使用
interface ResourceDefinition {
[key: string]: {
/** 代码文件的 js 文件名, 中间要插入一个 `.min.` 例如 abc.ts -> abc.min.js
* v1.11.17 的版本后, 如果功能 key 转为短横线分割正好就是文件名, 则可以省略这一项
* 比如 fooBar 功能使用 foo-bar.ts 作为文件名就不需要填写 path 了
*/
path?: string
/** 在设置面板中的展示名称, 包括子选项
* 如果不需要在设置面板中展示可以省略
* 如果当前功能的 path 可以省略, displayNames 里也只有对应其本身 key 的一条, 则可以把整个 ResourceDefinition 定义省略为这一条展示名称的字符串, 可以在 resource-manifest.js 找到不少这样的例子
*/
displayNames?: {
[key: string]: string
},
/** 样式定义
* true 会自动取同目录下同名的 `.css` / `.scss` 生成资源定义, 代码中可以用 `${key}Style` 作为样式的 key 导入
* important 会自动注入到 body 末尾, 不需要再在代码里导入
* instant 会优先于代码运行前注入到 head 里, 不需要再在代码里导入
*/
style?: boolean | 'important' | 'instant'
/** HTML 定义, 为 true 时类似 style, 可以在代码中作为字符串导入, 生成的 key 为 `${key}Html` */
html? boolean
/** 为 true 时表示可实时重载, 无需刷新生效, 会调用相应的 unload / reload 方法, 下述 */
reloadable?: boolean
/** 定义下拉框数据 */
dropdown?: {
/** 需要下拉框的选项 key */
key: string
/** 下拉框数据列表 */
items: string[]
}
}
}
```
- 写好代码后可以进行[编译](##编译), 调试时需要多次改动代码也可以使用监视模式
- 在 `src/utils/gui-settings/gui-settings.html` 中添加对应的设置项, 可以使用 `<checkbox>``<dropdown>` 元素, 子选项需要增加 `indent` 值, 并在 `dependencies` 中指定父级的 key.
### 多文件
将重复逻辑提出一个单独文件是很好的做法, 但可惜本项目对多文件的支持十分有限.
例子: 假设 `a.ts` `b.ts` 都想使用 `lib.ts` 中的函数 `foo`, 那么 `lib.ts` 需要写成这样:
```ts
// lib.ts
// 导出函数本身, 这样 VSCode 才能提供代码补全, 且通过 TypeScript 编译
export const foo = () => console.log('foo')
// 导出一个默认对象, 对象上声明一个固定的 export 属性, 值为一个对象, 包含当前文件所有要导出的内容
// 这个是运行时实际获取导出内容的地方, 所以 export 这个名字不能更换
export default {
export: { foo }
}
```
> `export `(后面带一个空格) 会被编译器识别为导出, 并在最后生成的代码中删除, 因此你不能在其他任何地方使用 `export `, 包括字符串里也不行. 例如 `const html = '<a class="export link">link</a>'` 会变成 `const html = '<a class="link">link</a>'`, 需要改成 `const html = '<a class="link export">link</a>'` 才行.
然后使用的时候, **必须**通过动态导入方式导入 `lib.ts` 中的功能 (`interface` 之类的运行时不存在的东西没有这个限制)
```ts
// a.ts / b.ts
(async () => {
const { foo } = await import('./lib')
foo()
})()
```
`a.ts` 如果作为一项功能, 需要在 `src/client/resource-manifest.js` 中声明, `lib.ts` 只导出一些可重用的功能, 不需要声明.
如果 `lib.ts` 即是一项功能, 又导出函数给其他功能使用, 那么仍然需要声明.
### Vue SFC 支持 (Vue 单文件组件)
Vue 的支持仅限内置的几种标签: `<template>`, `<script>`, `<style>`. 语言可选用 `ts`, `js`, `css`, `scss`, `html`.
在脚本中也**必须**使用动态导入:
```ts
// xxx.ts
(async () => {
const ComponentA = await import('./a.vue')
new Vue({
el: '.container',
components: { ComponentA },
// ...
})
const ComponentB = await import('./b.vue')
const vm = new (Vue.extend(ComponentB))().$mount()
document.body.appendChild(vm.$el)
vm.xxx = xxx
// ...
})()
```
### 创建附加功能
可以在功能组件中声明附加功能, 添加按钮到脚本的`附加功能`面板:
```ts
export default {
widget: {
// ...
}
}
```
`widget` 是一个对象, 类型如下:
```ts
interface Widget {
/** 插入到附加功能面板的 HTML, 一般可以带上 class="gui-settings-flat-button" 获得与其他附加功能按钮一致的外观 */
content: string
/** 附加功能面板打开时, 会调用这个判断当前页面是否适用此附加功能
* 得到 false 的话不会插入 content, 也不会执行 success
*/
condition: () => boolean | Promise<boolean>
/** content 插入后运行的函数 */
success: () => void | Promise<void>
}
```
关于例子可以查看 `src/live/download-live-records.ts`
### 可重载功能
如果你设计的功能不需要刷新页面也能切换开启/关闭状态, 可以将其写为可重载功能:
```ts
// 初次运行功能时, 直接执行文件内容, setup 将会调用, 当然用其他名字也行
const setup = () => {
// ...
}
setup()
// 上面那些内容只会运行一次
export default {
// 重新开启功能时, reload 会调用, setup 不调用
reload: () => {
// ...
},
// 关闭功能时, unload 会调用
unload: () => {
// ...
},
}
```
然后在 `src/client/resource-manifest.js` 中添加 `reloadable: true`, 例如:
```ts
disableFeedsDetails: {
reloadable: true,
displayNames: {
disableFeedsDetails: '禁止跳转动态详情',
},
},
```
关于例子可查看 `src/activity/disable-feeds-details.ts`
更进一步, 如果你的功能只是简单切换一下样式, 还可以这么写:
```ts
// 样式内容, 样式 id, 网址匹配模式(可选, 填入字符串或正则表达式)
export default resources.toggleStyle('a { color: red }', 'my-style', {
include: [ 'https://www.bilibili.com/video/xxxxx' ],
exclude: [ /\/abcd$/ ],
})
```
关于例子可查看 `src/style/player-on-top.js`
## 编译
编译代码 (有时候要跑两次才能真正编译完成, 玄学bug)
(VSCode 对应任务: `生产编译 production`)
```powershell
dotnet builder/dotnet/publish/build.dll production
```
监视代码改动 (Vue构建偶尔会出bug假死, 关掉重启下就行)
(VSCode 对应任务: `监视 watch`)
```powershell
dotnet builder/dotnet/publish/build.dll watch
```
如果需要清理编译器的缓存, 强制 clean build, 删除目录下的 `dev.cache`即可.
### 本地调试方式
1. 必须使用 Chrome / 基于 Chrome 内核的浏览器
2. Chrome 插件管理 `chrome://extensions/` > Tampermonkey > 详细信息
3. 打开`允许访问文件网址`
4. 新建脚本
5. 粘贴内容:
**如果使用的是基于 Chromium 的浏览器**
1. Chrome 插件管理 `chrome://extensions/` > Tampermonkey > 详细信息
2. 打开`允许访问文件网址`
3. 新建脚本
4. 粘贴内容:
```js
// ==UserScript==
// @name Bilibili Evolved (Local preview offline)
// @description Bilibili Evolved 预览离线版 (本地)
// @name Bilibili Evolved (Local)
// @description Bilibili Evolved (本地)
// @version 300.0
// @author Grant Howard, Coulomb-G
// @copyright 2021, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)
@ -253,45 +48,200 @@ dotnet builder/dotnet/publish/build.dll watch
// @exclude *://member.bilibili.com/studio/bs-editor/*
// @exclude *://www.bilibili.com/h5/*
// @exclude *://www.bilibili.com/*/h5/*
// @exclude *://message.bilibili.com/pages/nav/index_new_sync
// @exclude *://message.bilibili.com/pages/nav/index_new_pc_sync
// @exclude *://t.bilibili.com/h5/dynamic/specification
// @exclude *://bbq.bilibili.com/*
// @run-at document-start
// @grant unsafeWindow
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_setClipboard
// @grant GM_info
// @grant GM_xmlhttpRequest
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.setClipboard
// @grant GM.info
// @grant GM.xmlHttpRequest
// @connect raw.githubusercontent.com
// @connect cdn.jsdelivr.net
// @connect cn.bing.com
// @connect www.bing.com
// @connect translate.google.cn
// @connect translate.google.com
// @connect localhost
// @connect *
// @require https://cdn.jsdelivr.net/npm/jquery@3.4.0/dist/jquery.min.js
// @require https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js
// @require https://cdn.jsdelivr.net/npm/jszip@3.1.5/dist/jszip.min.js
// @require https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js
// @require https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js
// @icon https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/logo-small.png
// @icon64 https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/logo.png
// ==/UserScript==
```
6. 在那些 `@require` 下面再添加一行 `@require file://{{ bilibili-evolved.dev.js的绝对路径 }}`
> Windows 例子: `@require file://C:/xxx/Bilibili-Evolved/bilibili-evolved.dev.js`
6. 在那些 `@require` 下面再添加一行 `@require file://{{ bilibili-evolved.dev.user.js的绝对路径 }}`
> Windows 例子: `@require file://C:/xxx/Bilibili-Evolved/bilibili-evolved.dev.user.js`
> macOS 例子: `@require file:///Users/xxx/Documents/Bilibili-Evolved/bilibili-evolved.dev.js`
> macOS 例子: `@require file:///Users/xxx/Documents/Bilibili-Evolved/bilibili-evolved.dev.user.js`
7. 保存脚本, 监视模式下保存文件构建完成后, 刷新即可生效
> 上面那些其他的 @require`src/client/bilibili-evolved.js` 里的保持一致就行, 偶尔这些依赖项会变动导致这个本地调试脚本失效, 到时候照着改一下就行.
> 上面那些其他的 @require`src/client/common.meta.json` 里的保持一致就行, 偶尔这些依赖项会变动导致这个本地调试脚本失效, 到时候照着改一下就行.
**如果使用 Firefox 或 Safari**
1. 运行 `启动服务器(本体) dev:serve` 任务, 假设得到的服务链接为`http://localhost:5000/`
2. 继续 Chromium 指南中的第 3~6 步, 但在第 6 步时 `@require` 的链接使用 `http://localhost:5000/bilibili-evolved.dev.user.js`.
3. 保存脚本, 监视模式下保存文件构建完成后, 在 Tampermonkey 中编辑脚本 - 外部, 删除 `localhost` 的缓存文件后生效.
### 组件
组件除了本体内置的几个(内置的按照本体的调试方法就行), 其他都是和本体分离的, 本节包括这些组件的编译和调试方法, 同样适用于插件. 组件的源代码和产物均位于 `registry` 文件夹中.
1. 运行任务 `监视组件 dev:components`, (插件运行 `监视插件 dev:plugins`), 任务会询问要编译的组件是哪个, 从列表中选择即可.
2. 然后运行 `启动服务器(组件) dev:serve components`, 就得到了组件在 `localhost` 下的链接.
3. 进入网站, 打开脚本的设置面板 - 组件管理, (确保`自动更新器`功能开启) 粘贴组件的链接并安装.
4. 监视模式下保存文件构建完成后, 在控制台中运行
```js
bilibiliEvolved.componentApis.importComponent('autoUpdate').checkUpdatesAndReload()
```
会自动更新所有 `localhost` 加载的组件并刷新页面.
## 修改
找到对应的代码文件修改, 可以搜索组件的 `name``displayName` 定位文件, 修改后运行对应的编译任务即可.
## 新增
### 本体
本体内容的新增, 可以在 `src/` 中进行, v2 中不再有 v1 的奇怪限制, 你可以直接增加文件, 在代码中使用 `import` / `export` 等.
### 组件
`registry/lib/components` 中是所有组件的源代码.
> 你可能还发现 `src/components` 中也有大量组件, 除了几个内置组件, 其他是在 v1.10.20 (commit `855bb6f`) 时做的迁移测试留下的, 我以后会迁移到 `registry/lib/components` 中, 所以就当没看见好了.
1. 根据类别进入对应的子文件夹, 如样式修改的功能就是 `style/`
2. 新建文件夹, 名称为组件名, 单词短横线分隔
3. 新建文件 `index.ts` 作为组件入口点
> 此名称不可更改, webpack 配置中将搜索所有 index.ts 作为组件编译入口
4. 在 `index.ts` 中导出 `component` 对象, 实现 `ComponentMetadata` 接口
```ts
import { ComponentMetadata } from '@/components/types'
export const component: ComponentMetadata = {
// ...
}
```
> 在 `ComponentMetadata` 的源码中有各属性的说明
> `author` 字段记得填, 这个因为我自己写的组件不需要所以就不是 required 的
5. 根据组件的复杂度, 可以自行在文件夹中创建其他文件来组织代码, 下方还列出了一些可用资源可以帮助你加快开发.
6. 编译并调试组件.
### 插件
`registry/lib/plugins` 中是所有插件的源代码, 步骤和组件基本一致, 只有在第 4 步中, 导出的是 `plugin` 对象, 实现 `PluginMetadata` 接口.
## 可用资源
本体提供了大量 API 供组件 / 插件使用.
### 全局
全局变量, 无需 `import` 就可以直接使用. (Tampermonkey API 这里不再列出了, 可根据代码提示使用)
- `Vue`: Vue 库的主对象, 在创建 `.vue` 组件时, 其中的 `<script>` 可以直接使用 `Vue.extend()`
- `lodash`: 包含所有 Lodash 库提供的方法
- `dq` / `dqa`: `document.querySelector``document.querySelectorAll` 的简写, `dqa` 会返回真实数组
> 在 `bwp-video` 出现后, 这两个查询函数还会自动将对 `video` 的查询扩展到 `bwp-video`
- `none`: 什么都不做的空函数
- `componentTags`: 预置的一些组件标签, 实现 `ComponentMetadata.tags` 时常用
### 本体 API
仅介绍常用 API, 其他可以翻阅源代码了解, 代码中均带有文档.
- `core/ajax`: 封装 `XMLHttpRequest` 常见操作, 以及 `bilibiliApi` 作为 b 站 API 的响应处理 (`fetch` 可以直接用)
- `core/download`: `DownloadPackage` 类封装了下载文件的逻辑, 可以添加单个或多个文件, 多个文件时自动打包为 `.zip`, 确定是单个文件时也可以直接调用静态方法 `single`
- `core/file-picker`: 打开系统的文件选择对话框
- `core/life-cycle`: 控制在网页的不同生命周期执行代码
- `core/meta`: 获取脚本的自身元数据, 如名称, 版本等/
- `core/observer`: 封装各种监视器, 包括元素增删, 进入/离开视图, 大小变化, 以及当前页面视频的更换
- `core/spin-query`: 轮询器, 等待页面上异步加载的元素, 也可以自定义查询条件
- `core/runtime-library`: 运行时代码库, 目前支持导入 protobufjs 和 JSZip 使用
- `core/user-info`: 获取当前用户的登录信息
- `core/version`: 版本比较
- `core/settings`: 脚本设置 API, 可监听设置变更, 获取组件设置, 判断组件是否开启等
- `core/toast`: 通知 API, 能够在左下角显示通知
- `core/utils`: 工具集, 包含各种常量, 格式化函数, 排序工具, 标题获取, 日志等
### 组件 API
- `components/types`: 组件相关接口定义
- `components/styled-components`: 包含样式的组件 entry 简化包装函数
- `components/user-component`: 用户组件的安装/卸载 API
- `components/description`: 获取组件或插件的描述, 会自动匹配语言并插入作者标记, 支持 HTML, Markdown 和纯文本形式
- `components/feeds/`:
- `api`: 动态相关 API 封装, 获取动态流, 对每一个动态卡片执行操作等
- `BangumiCard.vue`: 番剧卡片
- `VideoCard.vue`: 视频卡片
- `ColumnCard.vue`: 专栏卡片
- `notify`: 获取未读动态数目, 最后阅读的动态 ID 等
- `components/video/`:
- `ass-utils`: ASS 字幕工具函数
- `player-light`: 控制播放器开关灯
- `video-danmaku`: 对每一条视频弹幕执行操作
- `video-info`: 根据 av 号查询视频信息
- `video-quality`: 视频清晰度列表
- `video-context-menu`: 向播放器右键菜单插入内容
- `video-control-bar`: 向播放器控制栏插入内容
- `watchlater`: 稍后再看列表获取, 添加/移除稍后再看等
- `components/live/`:
- `live-control-bar`: 向直播控制栏插入内容
- `live-socket`: 直播间弹幕的 WebSocket 封装
- `components/utils/`:
- `comment-apis`: 对每条评论执行操作
- `categories/data`: 主站分区数据
- `components/i18n/machine-translator/MachineTranslator.vue`: 机器翻译器组件
- `components/switch-options`: SwitchOptions API, 方便创建含有多个独立开闭的子选项的功能
- `components/launch-bar/LaunchBar.vue`: 搜索栏组件
### 插件 API
- `plugins/data`: 数据注入 API
持有数据的一方使用特定的 `key` 调用 `registerAndGetData` 注册并获取数据, 在这之前或之后所有的 `addData` 调用都能修改这些数据. 两方通过使用相同的 `key` 交换数据, 可以有效降低代码耦合.
例如, 自定义顶栏功能的顶栏元素列表就是合适的数据, 夜间模式的插件可以向其中添加一个快速切换夜间模式的开关, 而不需要修改自定义顶栏的代码.
> 有时候需要分开数据的注册和获取, 可以分别调用 `registerData``getData`
> 从设计上考虑好你的数据是否适合此 API, `addData` 做出的数据修改是单向累加式的, 不能够撤销.
- `plugins/hook`: 钩子函数 API
对于某种特定时机发生的事件, 可以调用 `getHook` 允许其他地方注入钩子提高扩展性, 其他地方可以嗲用 `addHook` 进行注入.
例如, 自动更新器在组件管理面板注入了钩子, 在新组件安装时记录安装来源, 实现自动更新. 组件管理面板没有任何更新相关代码.
- `plugins/style`: 提供简单的自定义样式增删 API (复杂样式请考虑组件或者 Stylus)
### UI
所有的 UI 组件建议使用 `'@/ui'` 导入, 大部分看名字就知道是什么, 这里只列几个特殊的.
- `ui/icon/VIcon.vue`: 图标组件, 自带 MDI 图标集, b 站图标集, 支持自定义图标注入
- `ui/_common.scss`: 一些通用的 Sass Mixin, 在代码中可以直接使用 `@import "common"` 导入
- `ui/_markdown.scss`: 提供一个 Markdown Mixin, 导入这个 Mixin 的地方将获得为各种 HTML 元素适配的 Markdown 样式. 在代码中可以直接使用 `@import "markdown"` 导入
- `ui/ScrollTrigger.vue`: 进入视图时触发事件, 通常用于实现无限滚动
- `ui/VEmpty.vue`: 表示无数据, 界面可被插件更改
- `ui/VLoading.vue`: 表示数据加载中, 界面可被插件更改
## 代码风格检查
项目中含有 ESLint, 不通过 ESLint 可能无法发起 Pull Request. 配置基于 `airbnb-base`, `typescript-eslint/recommended`, `vue/recommended` 修改而来, 几个比较特殊的规则如下:
### 强制性
- 除了 Vue 单文件组件, 禁止使用 `export default`, 所有导出必须命名.
- 参数列表, 数组, 对象等的尾随逗号必须添加.
- 如非必要禁止在末尾添加分号.
- 任何控制流语句主体必须添加大括号.
### 建议性
- 一行代码最长 80 字符.
- 不需要使用 `this` 特性的函数, 均使用箭头函数.
## 提交 commit
- 调试过程中会产生编译后的文件 (`min` 文件夹里的东西), 建议提交前放弃这些文件的更改, 只提交对源代码的修改, 以免 PR 的时候冲突
- commit message 只需写明改动点, 中英文随意, 也不强求类似 [commit-lint](https://github.com/conventional-changelog/commitlint) 的格式
commit message 只需写明改动点, 中英文随意, 也不强求类似 [commit-lint](https://github.com/conventional-changelog/commitlint) 的格式.
## 发起 PR (合并请求)
将 preview 分支往主仓库的 preview 分支合并就行
将你的分支往主仓库的 `preview` 分支合并就行.
> 目前 Technical Preview 阶段应该是往 `v2` 分支
## 自行保留
你可以选择不将功能代码合并到主仓库, 因此也没有 ESLint 的限制. PR 时仅添加指向你的仓库中的组件信息即可, 具体来说, 是在 `registry/lib/docs/third-party.ts` 中, 往对应数组中添加你的功能的相关信息, 当然别忘了把 `owner` 设为你的 GitHub 用户名.

View File

@ -1,20 +1,16 @@
<div align="center"><img id="Bilibili-Evolved" width="500" alt="Bilibili Evolved" src="https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/bilibili-evolved-wide-color.svg"></div>
<br>
<div align="center">
# Bilibili Evolved II
「 强大的哔哩哔哩增强脚本 」
</div>
[📦 安装](#安装) / [Install](doc/install-tutorial.en-US.md) / [インストール](doc/install-tutorial.ja-JP.md)
[📦 安装](#安装)
[⚙ 设置](#设置)
[📚 功能](doc/features.md)
[📚 功能](doc/features/features.md)
[👻 兼容性](#兼容性)
[🐛 版本历史与更新日志](https://github.com/the1812/Bilibili-Evolved/releases)
[🐛 版本历史与更新日志](CHANGELOG.md)
[📖 参与开发](CONTRIBUTING.md)
@ -24,35 +20,18 @@
需要浏览器拥有 [Tampermonkey](https://tampermonkey.net/) 插件.
**注意事项**
- 近期番剧区改版, 大部分视频功能都不支持番剧.
- 港澳台等地区限定内容一概不支持.
- 如果你只是来下载视频的, 不需要其他功能, 建议找个专门支持下载的软件/插件. 本脚本的下载视频就是凑合用用的, 如果下载失败我可懒得管.
- 做好觉悟, 脚本开启后不能使用弹幕点赞和举报, 全景视频不能用鼠标拖拽视角(只能用键盘操作), 对性能也有较大影响.
- 某些破坏性的大更新会使旧版脚本**完全**无法运行, 请及时检查更新.
- 使用 aria2 RPC 时脚本管理器可能会提示"脚本试图访问跨域资源", 请选择"始终允许".
- 新版本一旦正式发布, 就不再对旧版本做任何技术支持.
- 使用外部网站的链接时(如将下载任务发送到自己的服务器 / 使用链接安装组件等)可能会提示"脚本试图访问跨域资源", 请选择"始终允许".
点击名称即可安装👇
| [正式版](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.user.js) | [预览版](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/bilibili-evolved.preview.user.js) | [离线版](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js) | [预览离线版](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/bilibili-evolved.preview-offline.user.js) |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| 正式发布的版本, 最稳定, 更新频率较低. | 新增内容测试的地方, 更新频率高, 但功能不稳定. | 内置所有依赖项, 体积较大, 更新频率高于正式版. | 兼备预览版和离线版的特点. |
## 备用安装源
如果默认的安装链接无法使用, 可以尝试以下的备用安装源.
| | 更新延迟 | 下载速度 | 正式版 | 预览版 | 离线版 | 预览离线版 |
| -------- | -------- | -------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| jsDelivr | 24h | 快 | [安装](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.user.js) | [安装](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/bilibili-evolved.preview.user.js) | [安装](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js) | [安装](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/bilibili-evolved.preview-offline.user.js) |
| GitHub | <1h | 需要梯子 | [安装](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.user.js) | [安装](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview.user.js) | [安装](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.offline.user.js) | [安装](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview-offline.user.js) |
### 关于换源
上面的更换安装源能够以不同的来源安装脚本**本体**, 但脚本还有个热更新机制, 会自动下载脚本**功能**的更新. 如果你想完全更换为 GitHub 源 (例如希望尽快得到刚发布的更新), 除了从上面的 GitHub 安装源安装脚本以外, 安装完还需要在脚本的设置里将 `其他 - 更新源` 从默认的 `jsDelivr` 更换为 `GitHub`.
- [jsDelivr 源](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/bilibili-evolved.user.js)
- [GitHub 源](./dist/bilibili-evolved.user.js)
## 推荐配置
- 操作系统: 64-bit Windows 10 / macOS 10.15+
- 分辨率: 2K+ / 192ppi
- 浏览器: Chrome 80+ / Firefox 65+ / Edge 80+ / Safari 14+
- 浏览器: Chrome 84+ / Firefox 80+ / Edge 84+ / Safari 14.1+
- 处理器: Intel Core i7 / AMD Ryzen 5
- 内存: 8GB
- 脚本管理器: Tampermonkey 4.11 / Violentmonkey 2.12
@ -60,40 +39,35 @@
- 网络: 10MB/s
# 设置
脚本启用后, 在网页左侧中央会有一个齿轮图标, 点击即可打开设置. 默认只启用了一部分功能, 您可以根据需要自由调整设置.
脚本启用后, 在网页左侧中央会有功能面板和设置面板的入口. 功能面板中包含适用于当前页面的一些功能入口, 设置面板中可以管理组件的开启/关闭, 修改组件选项, 以及安装/卸载组件和插件等.
可以在[功能列表](doc/features.md)页中查看每项功能的详细说明, 在网页中通过鼠标停留在某一项也可以查看简要说明.
全新安装的脚本实际上没有任何功能, 你需要去[功能列表](doc/features/features.md)中挑选你感兴趣的功能并安装, 在设置面板的左下角可以打开组件/插件/样式管理, 界面基本差不多, 在里面粘贴要安装的链接点添加就可以了, 这个脚本能发挥出怎样的作用完全取决于你的选择.
大部分功能可通过设置面板开启, 有一些功能会以`附加功能`的形式生效, 或者是可以在`附加功能`做进一步设置. `附加功能`可从网页左侧中央的功能按钮进入.
> 安装需要对应文件的直链, GitHub Raw 或 jsDelivr 都可以. 批量安装时逐行粘贴链接即可.
**绝大部分设置保存后, 需要刷新网页才能生效. 仅有一些样式设置可以立即生效.**
<img alt="设置" height="500" src="https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/compressed/gui-settings.jpg">
如果你曾经使用过 v1 版, 可以利用 `v1 设置迁移` 组件将旧设置导入到 v2 中, 该工具将自动把里面开启的设置对应的组件下载并安装, 使用方法可以参考[这个文档](./doc/v1-migrate.md).
> ⚠️ 目前的 Technical Preview 阶段中, 只有 GitHub Stable 源可以用, 在使用 `v1 设置迁移` 时, 也需要在通用设置中把更新源设为 `GitHub`.
# 兼容性
## 脚本管理器
### [Tampermonkey](https://tampermonkey.net/) / [Violentmonkey](https://violentmonkey.github.io/)
完全兼容, 但在较旧的浏览器中 Violentmonkey 可能无法运行此脚本.
兼容, 但在较旧的浏览器中 Violentmonkey 可能无法运行此脚本.
### [Greasemonkey](https://www.greasespot.net/)
不兼容.
### [AdGuard](https://adguard.com/zh_cn/adguard-windows/overview.html)
~~不兼容~~
部分兼容, 加载模式仅可为`延迟(自动)`且无法更改. 经测试, Adguard 在最新7.5.3版本中已支持复杂数据储存.
部分兼容, 加载模式仅可为`延迟(自动)`且无法更改. 经测试, AdGuard 在最新7.5.3版本中已支持复杂数据储存.
## 浏览器
支持**最新版** Chrome, Edge (Chromium 内核), Firefox, Safari, 不保证脚本能在["套壳类浏览器"](https://www.jianshu.com/p/67d790a8f221)或者较长时间没更新的浏览器中完美运行.
UWP 版 Edge 已经不再支持了(就是 Windows 10 自带的那个), 请使用以上列出的浏览器, 或换用 [Chromium 内核的 Edge](https://www.microsoft.com/en-us/edge).
> Windows 10 20H2 更新中好像完全替换掉了 UWP 版 Edge (R.I.P.) 自带浏览器变成了 Chromium 内核 Edge.
# 开发者
见 https://github.com/the1812/Bilibili-Evolved/graphs/contributors (之前用的 Contributors Badge 挂了)
TODO (之前那个 contributors badge 抽风了)
## 文案翻译贡献者
- [PleiadeSubaru](https://github.com/Etherrrr)
@ -101,25 +75,28 @@ UWP 版 Edge 已经不再支持了(就是 Windows 10 自带的那个), 请使用
- Joshuaふみひる
## 参与项目
欢迎参考[代码贡献指南](CONTRIBUTING.md)来为项目添砖加瓦~
> v2.0 正在开发中, 请暂时不要为此仓库开发新功能, 以免增加不必要的迁移成本. (其他一些维护性的工作是可以的)
# 隐私声明
本脚本以及本仓库中提供的组件/插件, 是完全匿名的. 用户数据的使用均在本地完成, 不会存储到任何服务器, 也不会有所谓的"用户体验改善计划"来收集统计数据.
欢迎参考[代码贡献指南](CONTRIBUTING.md)来为项目添砖加瓦~ (小心编译器的神秘 bug / 小心被祖传代码闪瞎)
但是, 任何组件/插件都对用户数据有着完全的访问能力, 对于其他来源(非本仓库提供)的组件/插件, 请自行甄别其安全性.
# 第三方开源组件
👍感谢这些组件帮助我们极大地提升了开发效率.
- [Vue.js](https://cn.vuejs.org/index.html)
- [Vuex](https://vuex.vuejs.org/zh/)
- [JSZip](https://stuk.github.io/jszip/)
- [Slip.js](https://github.com/kornelski/slip)
- [bilibili API collect](https://github.com/SocialSisterYi/bilibili-API-collect)
- [popper-core](https://github.com/popperjs/popper-core)
- [Tippy.js](https://github.com/atomiks/tippyjs)
- [Sortable](https://github.com/SortableJS/Sortable)
- [color](https://github.com/Qix-/color)
- [Lodash](https://lodash.com/)
- [jQuery](http://jquery.com/)
- [marked](https://github.com/markedjs/marked)
- [MDI](https://materialdesignicons.com)
# 已知问题
- 和`解除B站区域限制`一同使用时, 两个脚本功能互相没有任何问题, 但有的人会遇到没弹幕的状况. 单独使用各脚本时正常, 目前未找到原因.
- 4K视频只能导出下载, 不能直接下载.
- 可能无法很好地适应窄屏幕, 请尽量以1400px以上的宽度使用此脚本.
- ASS弹幕下载不能包含高级弹幕, 字幕弹幕等.

View File

@ -1,12 +0,0 @@
{
"preview": "bilibili-evolved.preview.user.js",
"offline": "bilibili-evolved.offline.user.js",
"previewOffline": "bilibili-evolved.preview-offline.user.js",
"master": "bilibili-evolved.user.js",
"dev": "bilibili-evolved.dev.js",
"smallLogoPath": "images/logo-small.png",
"logoPath": "images/logo.png",
"owner": "the1812",
"copyOnBuild": false,
"bundle": "dist/bundle"
}

View File

@ -1,35 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "构建编译器 compile builder",
"type": "shell",
"command": "dotnet publish -c Release -o publish/",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "构建编译器 (Debug模式) compile builder",
"type": "shell",
"command": "dotnet build",
"group": "build",
"presentation": {
"echo": false,
"reveal": "always",
"focus": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
namespace BilibiliEvolved.Build
{
public class BuildCache : IDisposable
{
public static string CacheFilename => ProjectBuilder.ProductionMode ? "build.cache" : "dev.cache";
private readonly string fileName;
private readonly ConcurrentDictionary<string, string> sha1Cache = new ConcurrentDictionary<string, string>();
private readonly DirectoryInfo cacheDirectory;
private readonly SHA1Managed sha1;
public BuildCache() : this(Environment.CurrentDirectory) { }
public BuildCache(string path) : this(new DirectoryInfo(path)) { }
public BuildCache(DirectoryInfo path)
{
cacheDirectory = path;
fileName = Path.Combine(cacheDirectory.FullName, CacheFilename);
sha1 = new SHA1Managed();
LoadCache();
}
private string hashToString(byte[] hash)
{
return string.Join("", hash.Select(b => b.ToString("X2")).ToArray());
}
private string getFileHashString(string path)
{
var bytes = File.ReadAllBytes(path);
return hashToString(sha1.ComputeHash(bytes));
}
public void LoadCache()
{
if (File.Exists(fileName))
{
var lines = File.ReadAllText(fileName)
.Split(Environment.NewLine)
.Where(l => !string.IsNullOrWhiteSpace(l));
lines.ForEach(line =>
{
var data = line.Split("|");
var fileName = data[0];
var sha1Text = data[1];
sha1Cache.TryAdd(fileName, sha1Text);
});
}
}
public void SaveCache()
{
var builder = new StringBuilder();
sha1Cache.OrderBy(pair => pair.Key).ForEach(pair =>
{
builder
.Append(pair.Key)
.Append("|")
.Append(pair.Value)
.Append(Environment.NewLine);
});
File.WriteAllText(fileName, builder.ToString().Trim());
}
public void AddCache(string file)
{
var hashText = getFileHashString(file);
sha1Cache.AddOrUpdate(file, hashText, (k, v) => hashText);
}
public bool Contains(string file)
{
var hashText = getFileHashString(file);
if (sha1Cache.ContainsKey(file))
{
return sha1Cache[file] == hashText;
}
else
{
return false;
}
}
public void Dispose()
{
sha1?.Dispose();
}
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BilibiliEvolved.Build
{
public class BuilderConfig
{
public string Master { get; set; }
public string Preview { get; set; }
public string Offline { get; set; }
public string PreviewOffline { get; set; }
public string Dev { get; set; }
public string LogoPath { get; set; }
public string SmallLogoPath { get; set; }
public string Owner { get; set; }
public bool CopyOnBuild { get; set; }
public string Bundle { get; set; }
}
}

View File

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.IO.Compression;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
// private IEnumerable<string> changedBundleFiles;
public ProjectBuilder GetBundleFiles() {
// using (var cache = new BuildCache())
// {
// var extensions = new string[] {
// ".ts", ".js", ".css", ".scss", ".sass", ".vue", ".html", ".htm"
// };
// var files = ResourceMinifier.GetFiles(file =>
// extensions.Contains(file.Extension) &&
// !file.Name.EndsWith(".vue.ts") &&
// !file.Name.EndsWith(".d.ts") &&
// !file.FullName.Contains("client" + Path.DirectorySeparatorChar)
// );
// changedBundleFiles = files.Where(file => !cache.Contains(file)).ToArray();
// }
return this;
}
public ProjectBuilder BuildBundle()
{
if (ProductionMode)
{
// var urlList = from file in Directory.GetFiles("min")
// where !file.Contains("dark-slice") && !Path.GetFileName(file).StartsWith("bundle.")
// select file.Replace(@"\", "/");
var hashDict = new Dictionary<string, string>();
var zipName = "min/bundle.zip";
if (File.Exists(zipName))
{
File.Delete(zipName);
}
using (var sha256 = new SHA256Managed())
using (var zip = ZipFile.Open(zipName, ZipArchiveMode.Update))
{
foreach (var (url, text) in CachedMinFiles.OrderBy(p => p.Key))
{
var filename = Path.GetFileName(url);
var hash = string.Join("", sha256.ComputeHash(Encoding.UTF8.GetBytes(text)).Select(b => b.ToString("X2")).ToArray());
zip.CreateEntryFromFile(url, filename, CompressionLevel.NoCompression);
hashDict.Add(filename, hash);
}
zip.CreateEntryFromFile("version.txt", "version.txt", CompressionLevel.NoCompression);
}
File.WriteAllText("min/bundle.json", JsonConvert.SerializeObject(hashDict, Formatting.Indented));
WriteSuccess("Bundle build complete.");
}
else
{
WriteSuccess("Skipped bundle build.");
}
return this;
}
}
}

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
public ProjectBuilder BuildClient()
{
var source = File.ReadAllText("src/client/bilibili-evolved.js");
source = RegexReplacer.Replace(source, @"import (.*) from [""'](.*)[""']", match =>
{
var module = File.ReadAllText("src/client/" + match.Groups[2].Value.Replace("./", "") + ".js").Replace("export ", "");
return module;
});
// File.WriteAllText(SourcePath, source);
Source = source;
WriteSuccess("Client Build complete.");
return this;
}
}
}

View File

@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
public ProjectBuilder BuildDarkStyles()
{
var files = new DirectoryInfo("min")
.EnumerateFiles()
.OrderBy(f => f.FullName)
.Where(f => f.FullName.Contains("dark-slice"));
var fullStyle = files
.Select(f => File.ReadAllText(f.FullName))
.Aggregate((acc, s) => acc + s);
var filename = "min/dark.min.css";
File.WriteAllText(filename, fullStyle);
var otherStyle = File.ReadAllText("min/dark-important.min.css") + File.ReadAllText("min/dark-navbar.min.css") + File.ReadAllText("min/scrollbar.min.css");
if (string.IsNullOrWhiteSpace(offlineVersion)) {
generateVersion();
}
var userStyleFilename = "min/dark.user.css";
void writeUserStyle() {
File.WriteAllText(userStyleFilename, $@"
/* ==UserStyle==
@name Bilibili Evolved -
@namespace Bilibili-Evolved
@homepageURL https://github.com/the1812/Bilibili-Evolved
@updateURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/min/dark.user.css
@version {offlineVersion}.0
@license MIT
@author Grant Howard (https://github.com/the1812), Coulomb-G (https://github.com/Coulomb-G)
==/UserStyle== */
@-moz-document domain(""bilibili.com"") {{
{fullStyle}
{otherStyle}
}}
".Trim());
}
if (File.Exists(userStyleFilename)) {
var userStyle = File.ReadAllText(userStyleFilename);
var changed = !userStyle.EndsWith($@"
@-moz-document domain(""bilibili.com"") {{
{fullStyle}
{otherStyle}
}}
".Trim());
if (changed) {
writeUserStyle();
}
} else {
writeUserStyle();
}
UpdateCachedMinFile(filename);
WriteSuccess("Dark style build complete.");
return this;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace BilibiliEvolved.Build
{
static class Description
{
public static readonly string Master = "强大的哔哩哔哩增强脚本: 下载视频, 音乐, 封面, 弹幕 / 简化直播间, 评论区, 首页 / 自定义顶栏, 删除广告, 夜间模式 / 触屏设备支持";
public static readonly string Preview = "Bilibili Evolved 的预览版, 可以抢先体验新功能.";
public static readonly string Offline = "Bilibili Evolved 的离线版, 所有功能都已内置于脚本中.";
public static readonly string PreviewOffline = "Bilibili Evolved 的预览离线版, 可以抢先体验新功能, 并且所有功能都已内置于脚本中.";
}
}

View File

@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
static class Extensions
{
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
{
action(item);
}
}
public static Action<T> Debounce<T>(Action<T> action, int waitTime)
{
var queue = new ConcurrentQueue<Action<T>>();
return async (T arg) =>
{
queue.Enqueue(action);
await Task.Delay(waitTime);
lock (queue) {
if (queue.TryDequeue(out var a))
{
if (queue.Count == 0)
{
a?.Invoke(arg);
}
}
}
};
}
public static Action Debounce(Action action, int waitTime)
{
var queue = new ConcurrentQueue<Action>();
return async () =>
{
queue.Enqueue(action);
await Task.Delay(waitTime);
if (queue.TryDequeue(out var a))
{
if (queue.Count == 0)
{
a?.Invoke();
}
}
};
}
}
}

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
private readonly Regex ownerRegex = new Regex(@"(github\.com/)(.+)(/Bilibili-Evolved)");
public ProjectBuilder BuildMaster()
{
var master = Source;
master = ownerRegex.Replace(master, "${1}" + config.Owner + "${3}");
var replaceMap = new Dictionary<string, string>
{
{ @"Bilibili-Evolved/preview", @"Bilibili-Evolved/master" },
{ @"Bilibili-Evolved/raw/preview", @"Bilibili-Evolved/raw/master" },
{ @"Bilibili-Evolved@preview", @"Bilibili-Evolved@master" },
{ SourcePath, OutputPath },
{ @"Bilibili Evolved (Preview)", @"Bilibili Evolved" },
{ Description.Preview, Description.Master },
};
replaceMap.ForEach(item => master = master.Replace(item.Key, item.Value));
Output = master;
WriteSuccess("Master build complete.");
return this;
}
}
}

View File

@ -1,134 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
public abstract class NodeInteract
{
public static readonly string LocalModulePath = @"node_modules/";
public static readonly string GlobalModulePath = Environment.GetEnvironmentVariable("AppData") + @"/npm/node_modules/";
protected abstract string ExecutablePath { get; }
protected abstract string Arguments { get; }
public Process Run() {
var filename = "";
if (File.Exists(LocalModulePath + ExecutablePath))
{
filename = LocalModulePath + ExecutablePath;
}
else if (File.Exists(GlobalModulePath + ExecutablePath))
{
filename = GlobalModulePath + ExecutablePath;
}
else
{
throw new FileNotFoundException($"Binary file not found: {ExecutablePath}");
}
var processInfo = new ProcessStartInfo
{
FileName = "node",
Arguments = filename + " " + Arguments,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
return Process.Start(processInfo);
}
public string Run(string input)
{
var process = Run();
using (var writer = new StreamWriter(process.StandardInput.BaseStream, Encoding.UTF8))
{
writer.Write(input);
writer.Flush();
writer.Close();
using (var outputReader = new StreamReader(process.StandardOutput.BaseStream, Encoding.UTF8))
using (var errorReader = new StreamReader(process.StandardError.BaseStream, Encoding.UTF8))
{
return outputReader.ReadToEnd().Trim() + errorReader.ReadToEnd().Trim();
}
}
}
}
sealed class UglifyJs : NodeInteract
{
protected override string ExecutablePath => "terser/bin/terser";
protected override string Arguments => "-m";
}
sealed class UserScriptTerser : NodeInteract
{
public string Filename { get; private set; }
public UserScriptTerser(string filename) => Filename = filename;
protected override string ExecutablePath => "terser/bin/terser";
protected override string Arguments => $"{Filename} -m --comments \"/^[ ]*(==|@)|eslint-|spell-checker:/\"";
public static Task WaitForExit(string filename) {
return Task.Run(() => {
var process = new UserScriptTerser(filename).Run();
var result = "";
using (var outputReader = new StreamReader(process.StandardOutput.BaseStream, Encoding.UTF8))
using (var errorReader = new StreamReader(process.StandardError.BaseStream, Encoding.UTF8))
{
result = outputReader.ReadToEnd().Trim() + errorReader.ReadToEnd().Trim();
}
File.WriteAllText(filename, result);
});
}
}
sealed class UglifyCss : NodeInteract
{
protected override string ExecutablePath => "clean-css-cli/bin/cleancss";
protected override string Arguments => "-O2";
}
sealed class UglifyHtml : NodeInteract
{
protected override string ExecutablePath => "html-minifier/cli.js";
protected override string Arguments => "--collapse-whitespace --collapse-inline-tag-whitespace --remove-comments --remove-attribute-quotes --remove-tag-whitespace --use-short-doctype";
}
sealed class TypeScriptCompiler : NodeInteract
{
protected override string ExecutablePath => "typescript/bin/tsc";
protected override string Arguments => "";
}
sealed class TypeScriptWatchCompiler : NodeInteract
{
protected override string ExecutablePath => "typescript/bin/tsc";
protected override string Arguments => "--watch";
}
sealed class BabelCompiler : NodeInteract
{
protected override string ExecutablePath => "@babel/cli/bin/babel.js";
protected override string Arguments => "src --out-dir .ts-output --quiet --extensions .ts";
}
sealed class BabelWatchCompiler : NodeInteract
{
protected override string ExecutablePath => "@babel/cli/bin/babel.js";
protected override string Arguments => "src --out-dir .ts-output --quiet --extensions .ts --watch";
}
sealed class BabelSingleCompiler : NodeInteract
{
private string filename;
public BabelSingleCompiler(string filename) { this.filename = filename; }
protected override string ExecutablePath => "@babel/cli/bin/babel.js";
protected override string Arguments => $"-f {filename}";
}
sealed class SassCompiler : NodeInteract
{
protected override string ExecutablePath => "sass/sass.js";
protected override string Arguments => "--quiet --no-source-map src:.sass-output";
}
sealed class SassWatchCompiler : NodeInteract
{
protected override string ExecutablePath => "sass/sass.js";
protected override string Arguments => "--watch --quiet --no-source-map src:.sass-output";
}
sealed class SassSingleCompiler : NodeInteract
{
protected override string ExecutablePath => "sass/sass.js";
protected override string Arguments => "--quiet --no-source-map --stdin";
}
}

View File

@ -1,130 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
private string offlineText = "";
private string offlineVersion = "";
private string readAsBase64Image(string path)
{
var bytes = File.ReadAllBytes(path);
return $"data:image/png;base64,{Convert.ToBase64String(bytes)}";
}
private void replaceInfo(Dictionary<string, string> map)
{
map.ForEach(item => offlineText = offlineText.Replace(item.Key, item.Value));
offlineText = ownerRegex.Replace(offlineText, "${1}" + config.Owner + "${3}");
offlineText = offlineText.Replace(
$"@icon https://raw.githubusercontent.com/{config.Owner}/Bilibili-Evolved/master/{config.SmallLogoPath}",
$"@icon {readAsBase64Image(config.SmallLogoPath)}");
offlineText = offlineText.Replace(
$"@icon64 https://raw.githubusercontent.com/{config.Owner}/Bilibili-Evolved/master/{config.LogoPath}",
$"@icon64 {readAsBase64Image(config.LogoPath)}");
}
private void generateVersion()
{
var startDate = new DateTime(2018, 7, 16, 15, 46, 53);
var versionRegex = new Regex(@"(@version[ ]*)[\d\.]*");
var version = DateTime.Now.ToOADate() - startDate.ToOADate();
offlineVersion = version.ToString("0.00");
offlineText = versionRegex.Replace(offlineText, "${1}" + offlineVersion);
}
private void compileOfflineData()
{
var onlineRoot = $"https://raw.githubusercontent.com/{config.Owner}/Bilibili-Evolved/master/";
// var urlList = (from match in new Regex(@"path:\s*""(.*)""").Matches(offlineText)
// as IEnumerable<Match>
// select "min/" + match.Groups[1].Value.Trim()
// ).ToList();
// var urlList = from file in Directory.GetFiles("min")
// where !file.Contains("dark-slice") && !Path.GetFileName(file).StartsWith("bundle.")
// select file.Replace(@"\", "/");
var downloadCodeStart = @"// \+#Offline build placeholder";
var downloadCodeEnd = @"// \-#Offline build placeholder";
var downloadCodes = new Regex($"({downloadCodeStart}([^\0]*){downloadCodeEnd})").Match(offlineText).Groups[0].Value;
var offlineData = "const offlineData = {};" + Environment.NewLine;
foreach (var (url, text) in CachedMinFiles.OrderBy(p => p.Key))
{
if (url.EndsWith(".js"))
{
offlineData = offlineData + $"offlineData[\"{onlineRoot + url}\"] = {text}" + Environment.NewLine;
}
else
{
offlineData = offlineData + $"offlineData[\"{onlineRoot + url}\"] = `{text.Replace("\\", "\\\\")}`;" + Environment.NewLine;
}
}
offlineText = offlineText
.Replace(@"// [Offline build placeholder]", offlineData)
.Replace(downloadCodes, "this.text=this.type.preprocessor(offlineData[this.url]);resolve(this.text);");
}
private void buildFile(string path)
{
// if (File.Exists(path))
// {
// var offlineFileText = File.ReadAllText(path);
// var noVersion = new Regex(@"// @version[ ]*(.*)" + Environment.NewLine);
// var originalOffline = noVersion.Replace(offlineFileText, "");
// var currentOffline = noVersion.Replace(offlineText, "");
// if (currentOffline == originalOffline)
// {
// offlineVersion = noVersion.Match(offlineFileText).Groups[1].Value.Trim();
// return;
// }
// }
if (ProductionMode) {
File.WriteAllText(path, offlineText);
}
if (path == config.PreviewOffline && !ProductionMode) {
File.WriteAllText(config.Dev, offlineText);
}
}
private ProjectBuilder build(Dictionary<string, string> replaceMap, string outputPath, string successMessage)
{
offlineText = Output;
replaceInfo(replaceMap);
generateVersion();
compileOfflineData();
buildFile(outputPath);
WriteSuccess(successMessage);
return this;
}
public ProjectBuilder BuildOffline()
{
var replaceMap = new Dictionary<string, string>
{
{ "Bilibili Evolved", "Bilibili Evolved (Offline)" },
{ Description.Master, Description.Offline },
{ $"master/{config.Master}", $"master/{config.Offline}" },
// { $"// ==/UserScript==", $"// ==/UserScript=={Environment.NewLine}/* eslint-disable */ /* spell-checker: disable */"},
};
return build(replaceMap, config.Offline, "Offline build complete.");
}
public ProjectBuilder BuildPreviewOffline()
{
var replaceMap = new Dictionary<string, string>
{
{ "Bilibili Evolved", "Bilibili Evolved (Preview Offline)" },
{ Description.Master, Description.PreviewOffline },
{ $"master/{config.Master}", $"preview/{config.PreviewOffline}" },
// { $"// ==/UserScript==", $"// ==/UserScript=={Environment.NewLine}/* eslint-disable */ /* spell-checker: disable */"},
};
return build(replaceMap, config.PreviewOffline, "Preview Offline build complete.");
}
}
}

View File

@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
private string onlineVersion;
private string compileOnlineData()
{
var onlineRoot = $"https://raw.githubusercontent.com/{config.Owner}/Bilibili-Evolved/preview/";
// var urlList = from file in Directory.GetFiles("min")
// where !file.Contains("dark-slice") && !Path.GetFileName(file).StartsWith("bundle.")
// select file.Replace(@"\", "/");
var onlineData = "const onlineData = {};" + Environment.NewLine;
foreach (var (url, text) in CachedMinFiles.OrderBy(p => p.Key))
{
if (url.EndsWith(".js"))
{
onlineData = onlineData + $"onlineData[\"{onlineRoot + url}\"] = {text}" + Environment.NewLine;
}
else
{
onlineData = onlineData + $"onlineData[\"{onlineRoot + url}\"] = `{text.Replace("\\", "\\\\")}`;" + Environment.NewLine;
}
}
return onlineData;
}
public ProjectBuilder BuildVersions()
{
var version = new Regex(@"//[ ]*@version[ ]*(.+)").Match(Source).Groups[1].Value.Trim();
Source = ownerRegex
.Replace(Source, "${1}" + config.Owner + "${3}");
// File.WriteAllText(SourcePath, Source);
File.WriteAllText("version.txt", version);
onlineVersion = version;
return this;
}
public ProjectBuilder BuildPreviewData()
{
if (ProductionMode) {
File.WriteAllText(SourcePath, Source.Replace(@"// [Offline build placeholder]", compileOnlineData()));
}
return this;
}
}
}

View File

@ -1,60 +0,0 @@
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using BilibiliEvolved.Build.Watcher;
namespace BilibiliEvolved.Build
{
class Program
{
public static void Main(string[] arguments)
{
try
{
var args = arguments.Select(a => a.ToLowerInvariant());
ProjectBuilder.ProductionMode = args.Any(a => a == "production");
if (args.Any(a => a == "watch")) {
if (!File.Exists(BuildCache.CacheFilename)) {
Console.WriteLine("No build cache found, running full build...");
RunFullBuild();
}
var watchBuilder = new WatchBuilder();
watchBuilder.StartWatching();
} else {
RunFullBuild();
}
}
catch (Exception ex)
{
var lastColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"Unexpected Error: {ex.Message}");
Console.ForegroundColor = lastColor;
throw;
}
}
public static void RunFullBuild() {
var builder = ProjectBuilder.CreateBuilder();
builder
.BuildClient() // inject client files
.BuildVersions() // preview file, versions
.BuildMaster() // stable source code
.GetBundleFiles() // detect if bundle needs rebuild or can skip
.PrebuildVue() // generate vue.ts files from vue files
.BuildTypeScripts() // build ts files
.BuildSass() // build sass files
.BuildVue() // build vue files (js, sass, css, html)
.BuildResources() // build js, css, html files
.BuildPreviewOffline() // preview-offline file + offline data
.BuildOffline() // offline file + offline data
.BuildBundle() // bundle file
.BuildPreviewData() // preview online data
.BuildFinalOutput(); // stable file + online data
}
}
}

View File

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Configuration;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
public partial class ProjectBuilder
{
public static bool ProductionMode { get; set; }
public static ProjectBuilder CreateBuilder()
{
var configFile = new ConfigurationBuilder()
.AddJsonFile(
Path.Combine(Environment.CurrentDirectory, "builder/builder-config.json"),
optional: false,
reloadOnChange: false)
.Build();
var config = new BuilderConfig();
configFile.Bind(config);
return new ProjectBuilder(config);
}
public ProjectBuilder(BuilderConfig config)
{
this.config = config;
SourcePath = config.Preview;
// Source = File.ReadAllText(SourcePath);
WriteInfo("[Bilibili Evolved] Project builder started.");
WriteInfo($"Mode = {(ProductionMode ? "Production" : "Development")}");
WriteInfo($"Working directory: {Environment.CurrentDirectory}");
Console.WriteLine();
var urlList = from file in Directory.GetFiles("min")
where !file.Contains("dark-slice") && !Path.GetFileName(file).StartsWith("bundle.")
select file.Replace(@"\", "/");
Parallel.ForEach(urlList, url =>
{
CachedMinFiles[url] = File.ReadAllText(url);
});
}
private BuilderConfig config;
// public double MinimizedResourceLength { get; set; }
// public double OriginalResourceLength { get; set; }
public string Source { get; private set; }
public string Output { get; private set; }
public string SourcePath { get; private set; }
public string OutputPath { get; set; } = "bilibili-evolved.user.js";
public DateTime StartTime { get; private set; } = DateTime.Now;
public void ResetBuildTime() => StartTime = DateTime.Now;
public void BuildFinalOutput()
{
// var ratio = 100.0 * MinimizedResourceLength / OriginalResourceLength;
if (ProductionMode) {
var masterOutput = Output.Replace(@"// [Offline build placeholder]", compileOnlineData().Replace("Bilibili-Evolved/preview/", "Bilibili-Evolved/master/"));
File.WriteAllText(OutputPath, masterOutput);
Task.WaitAll(
UserScriptTerser.WaitForExit(config.Master),
UserScriptTerser.WaitForExit(config.Preview),
UserScriptTerser.WaitForExit(config.Offline),
UserScriptTerser.WaitForExit(config.PreviewOffline)
);
}
Console.WriteLine();
// WriteHint($"External resource size -{(100.0 - ratio):0.##}%");
var elapsed = DateTime.Now - StartTime;
WriteInfo($"Build complete in {elapsed:hh\\:mm\\:ss\\.ff}", ConsoleColor.Green);
if (config.CopyOnBuild)
{
var text = File.ReadAllText(config.PreviewOffline);
TextCopy.Clipboard.SetText(text);
WriteHint($"Copied {text.Length} characters");
}
}
public void WriteInfo(string message = "", ConsoleColor color = ConsoleColor.Gray)
{
if (string.IsNullOrWhiteSpace(message)) {
return;
}
lock (this)
{
var lastColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = lastColor;
}
}
public void WriteSuccess(string message) => WriteInfo(message, ConsoleColor.Blue);
public void WriteError(string message) => WriteInfo(message, ConsoleColor.Red);
public void WriteHint(string message) => WriteInfo(message, ConsoleColor.DarkGray);
public ConcurrentDictionary<string, string> CachedMinFiles { get; private set; } = new ConcurrentDictionary<string, string>();
public void UpdateCachedMinFile(string url)
{
url = url.Replace(@"\", "/");
// Console.WriteLine($"Update min url: {url}");
CachedMinFiles[url] = File.ReadAllText(url);
}
}
}

View File

@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
static class RegexReplacer
{
public static string Replace(string text, string regexText, Func<Match, string> func)
{
var regex = new Regex(regexText, RegexOptions.Compiled | RegexOptions.IgnoreCase);
while (true)
{
var match = regex.Match(text);
if (!match.Success)
{
break;
}
text = text.Replace(match.Value, func(match));
}
return text;
}
}
}

View File

@ -1,248 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
public ProjectBuilder BuildResources()
{
new CssMinifier().Build(this);
new HtmlMinifier().Build(this);
new JavascriptMinifier().Build(this);
return this;
}
}
public abstract class ResourceMinifier
{
public abstract Predicate<FileInfo> FileFilter { get; }
public abstract string ResourceType { get; }
public abstract string Minify(string input);
public static string GetMinimizedFileName(string path)
{
var filename = Path.GetFileName(path);
return "min/" + filename.Insert(filename.LastIndexOf("."), ".min");
}
public static IEnumerable<string> GetFiles(Predicate<FileInfo> filter)
{
string getRelativePath(string fullPath)
{
var currentFolder = Environment.CurrentDirectory;
var path = fullPath.Replace(currentFolder, "");
if (path.StartsWith(Path.DirectorySeparatorChar))
{
return path.Remove(path.IndexOf(Path.DirectorySeparatorChar), 1);
}
else
{
return path;
}
}
IEnumerable<string> getFiles(Predicate<FileInfo> predicate, string path)
{
var list = new List<string>();
var currentDirectory = new DirectoryInfo(path);
list.AddRange(currentDirectory.EnumerateFiles()
.Where(file =>
{
var fullName = file.FullName;
return predicate(file) && !fullName.Contains($".backup.");
})
.Select(file => getRelativePath(file.FullName)));
foreach (var subDir in currentDirectory.EnumerateDirectories())
{
list.AddRange(getFiles(filter, subDir.FullName));
}
return list;
}
var directory = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}src";
if (!directory.EndsWith(Path.DirectorySeparatorChar))
{
directory = directory + Path.DirectorySeparatorChar;
}
return getFiles(filter, directory);
}
public virtual ProjectBuilder Build(ProjectBuilder builder)
{
var files = GetFiles(FileFilter);
using (var cache = new BuildCache())
{
var changedFiles = files.Where(file => !cache.Contains(file));
Parallel.ForEach(changedFiles, path =>
{
builder.WriteInfo($"{ResourceType} minify: {path}");
var text = File.ReadAllText(path);
var result = Minify(text);
var outputPath = GetMinimizedFileName(path);
File.WriteAllText(outputPath, result);
cache.AddCache(path);
// builder.WriteHint($"\t=> {outputPath}");
// builder.WriteHint($"\t=> {outputPath.PadRight(48)}{(100.0 * result.Length / text.Length):0.##}%");
});
cache.SaveCache();
}
// files.ForEach(file =>
// {
// builder.OriginalResourceLength += new FileInfo(file).Length;
// builder.MinimizedResourceLength += new FileInfo(GetMinimizedFileName(file)).Length;
// });
builder.WriteSuccess($"{ResourceType} minify complete.");
return builder;
}
}
sealed class CssMinifier : ResourceMinifier
{
public override Predicate<FileInfo> FileFilter { get; } = file =>
{
return !file.FullName.Contains(".min.")
&& file.Name != "dark.css"
&& file.Name != "dark-template.css"
&& file.Extension == ".css"
&& !file.Name.EndsWith(".p.css");
};
public override string ResourceType { get; } = "CSS";
public override string Minify(string input)
{
return new UglifyCss().Run(input);
}
public override ProjectBuilder Build(ProjectBuilder builder)
{
base.Build(builder);
return builder.BuildDarkStyles();
}
}
sealed class JavascriptMinifier : ResourceMinifier
{
public override Predicate<FileInfo> FileFilter { get; } = file =>
{
return !file.FullName.Contains("client" + Path.DirectorySeparatorChar) &&
file.Extension == ".js" && !file.Name.EndsWith(".vue.js");
};
public override string ResourceType { get; } = "JavaScript";
public override string Minify(string input)
{
if (!input.StartsWith("(() =>"))
{
Func<string, string> convertToRuntimeSource = source =>
{
var index = source.LastIndexOf("/");
if (index != -1)
{
source = source.Remove(1, index);
}
return source;
};
input = RegexReplacer.Replace(input, @"import (.*) from ([^\r\n;]*)", match =>
{
var imported = match.Groups[1].Value.Replace(" as ", ":");
var source = convertToRuntimeSource(match.Groups[2].Value);
return $"const {imported} = resources.import({source})";
});
input = RegexReplacer.Replace(input, @" import\((.+?)\)", match =>
{
var source = convertToRuntimeSource(match.Groups[1].Value);
return $" resources.importAsync({source})";
});
var exportMatches = new Regex(@"export[\s]+[a-zA-Z]+[\s]+([\w]+)").Matches(input);
if (exportMatches.Count > 0)
{
var exports = exportMatches
.Select(m => m.Groups[1].Value)
.Aggregate((acc, m) => acc + ", " + m);
if (!input.Contains("export default "))
{
input += $"return {{ export: {{ {exports} }} }}";
// Console.WriteLine("Auto export: " + $"return {{ export: {{ {exports} }} }}");
}
// TODO: insert exports into existing block
// else if (input.Contains("export default ") && input.Contains(""))
}
input = @"(() =>
{
return (settings, resources) =>
{
" + input.Replace("export default ", "return ").Replace("export ", "") + @"
};
})();";
}
// Console.WriteLine(input);
return new Regex(@"\\n( )+([<`])").Replace(new UglifyJs().Run(input), @"\n$2");
}
}
sealed class HtmlMinifier : ResourceMinifier
{
public override Predicate<FileInfo> FileFilter { get; } = file =>
{
return !file.FullName.Contains(".min.") && file.Extension == ".html";
};
public override string ResourceType { get; } = "HTML";
static HtmlMinifier()
{
var patterns = new string[] {
@"<category\s*?icon=""?(.+?)""?>([^\0]*?)<\/category>",
@"<checkbox\s*?indent=""?(.+?)""?\s*?key=""?(.+?)""?\s*?dependencies=""?(.*?)""?>([^\0]*?)<\/checkbox>",
@"<dropdown\s*?indent=""?(.+?)""?\s*?key=""?(.+?)""?\s*?dependencies=""?(.*?)""?>([^\0]*?)<\/dropdown>",
@"<textbox\s*?indent=""?(.+?)""?\s*key=""?(.+?)""?\s*?dependencies=""?(.*?)""?>([^\0]*?)<\/textbox>",
};
var replacements = new string[] {
@"<li class='indent-center category folded'>
<i class='icon-$1' style='margin-right:8px'></i>
<span class='settings-category'>$2</span>
<i class='icon-arrow' style='margin-left:8px'></i>
</li>",
@"<li class='indent-$1 folded' data-indent='$1' data-key='$2' data-dependencies='$3'>
<label class='gui-settings-checkbox-container'>
<input key='$2' type='checkbox' dependencies='$3' checked/>
<div class='gui-settings-checkbox'></div>
<span>$4</span>
</label>
</li>",
@"<li class='indent-$1 folded' data-indent='$1' data-key='$2' data-dependencies='$3'>
<label class='gui-settings-dropdown-container'>
<span class='gui-settings-dropdown-span'>$4</span>
<div class='gui-settings-dropdown popup'>
<input readonly type='text' spellcheck='false' key='$2' dependencies='$3'>
<ul></ul>
<i class='icon-arrow'></i>
</div>
</label>
</li>",
@"<li class='indent-$1 folded' data-indent='$1' data-key='$2' data-dependencies='$3'>
<label class='gui-settings-textbox-container'>
<span>$4</span>
<input key='$2' dependencies='$3' spellcheck='false' type='text' />
</label>
</li>",
};
regices = patterns.Zip(replacements, (pattern, replacement) =>
{
return (new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase), replacement);
});
}
private static readonly IEnumerable<(Regex, string)> regices;
public override string Minify(string input)
{
foreach (var (regex, replacement) in regices)
{
input = regex.Replace(input, replacement);
}
return new UglifyHtml().Run(input);
}
}
}

View File

@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
public ProjectBuilder BuildSass()
{
var sass = new SassCompiler();
var cleancss = new CssMinifier();
var files = ResourceMinifier.GetFiles(file =>
file.Extension == ".scss"
);
using (var cache = new BuildCache())
{
var changedFiles = files.Where(file => !cache.Contains(file)).ToArray();
if (changedFiles.Any())
{
string getOutputCacheFilename(string f)
{
return ".sass-output/" + f
.Replace(".scss", ".css")
.Replace($"src{Path.DirectorySeparatorChar}", "");
}
changedFiles.ForEach(file => {
cache.AddCache(file);
WriteInfo($"Sass build: {file}");
});
WriteInfo(sass.Run("").Trim());
Parallel.ForEach(changedFiles
.Where(f => !Path.GetFileName(f).StartsWith("_")),
f => {
// var sass = new SassSingleCompiler();
// var css = sass.Run(File.ReadAllText(file));
// File.WriteAllText(getOutputCacheFilename(file), css);
var file = getOutputCacheFilename(f);
var min = cleancss.Minify(File.ReadAllText(file).Replace("@charset \"UTF-8\";", ""));
var minFile = ResourceMinifier.GetMinimizedFileName(file);
File.WriteAllText(minFile, min);
UpdateCachedMinFile(minFile);
// WriteHint($"\t=> {minFile}");
});
// var results = ResourceMinifier.GetFiles(f => f.FullName.Contains(".sass-output" + Path.DirectorySeparatorChar));
// Parallel.ForEach(results, file =>
// {
// var min = cleancss.Minify(File.ReadAllText(file).Replace("@charset \"UTF-8\";", ""));
// var minFile = ResourceMinifier.GetMinimizedFileName(file);
// File.WriteAllText(minFile, min);
// });
}
cache.SaveCache();
}
WriteSuccess("Sass build complete.");
return this;
}
}
}

View File

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
partial class ProjectBuilder
{
public ProjectBuilder BuildTypeScripts()
{
var tsc = new BabelCompiler();
var uglifyJs = new JavascriptMinifier();
var files = ResourceMinifier.GetFiles(file =>
file.Extension == ".ts" &&
!file.Name.EndsWith(".d.ts")
);
using (var cache = new BuildCache())
{
var changedFiles = files.Where(file => !cache.Contains(file)).ToArray();
if (changedFiles.Any())
{
string getOutputCacheFilename(string f)
{
return ".ts-output/" + f
.Replace(".ts", ".js")
.Replace($"src{Path.DirectorySeparatorChar}", "");
}
changedFiles.ForEach(file => {
cache.AddCache(file);
WriteInfo($"TypeScript build: {file}");
});
WriteInfo(tsc.Run("").Trim());
Parallel.ForEach(changedFiles
.Where(f => !f.EndsWith(".vue.ts")),
f => {
// var tsc = new BabelSingleCompiler(file);
// var js = tsc.Run(File.ReadAllText(file));
// File.WriteAllText(getOutputCacheFilename(file), js);
var file = getOutputCacheFilename(f);
var text = RegexReplacer.Replace(File.ReadAllText(file), @"import\(\(\(\)\s*=>\s*(.*)\)\(\)\)", match =>
{
return $"import({match.Groups[1].Value})";
});
var min = uglifyJs.Minify(text);
var minFile = ResourceMinifier.GetMinimizedFileName(file);
File.WriteAllText(minFile, min);
UpdateCachedMinFile(minFile);
// WriteHint($"\t=> {minFile}");
});
}
cache.SaveCache();
}
WriteSuccess("TypeScript build complete.");
return this;
}
}
}

View File

@ -1,206 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build
{
public sealed class VueFile
{
public string TamplateLang { get; private set; }
public string Tamplate { get; private set; }
public string ScriptLang { get; private set; }
public string Script { get; private set; }
public string StyleLang { get; private set; }
public string Style { get; private set; }
public VueFile(string text)
{
parseTamplate(text);
parseScript(text);
parseStyle(text);
}
private void parseTamplate(string text)
{
var regex = @"<template\s*(lang=""(.+)"")?\s*>([^\0]*)</template>";
var match = new Regex(regex, RegexOptions.Multiline).Match(text);
if (!match.Success)
{
TamplateLang = null;
Tamplate = null;
return;
}
Tamplate = match.Groups[3].Value.Trim().Replace("`", "\\`");
TamplateLang = match.Groups[2].Value.Trim();
if (TamplateLang == "")
{
TamplateLang = "html";
}
}
private void parseScript(string text)
{
var regex = @"<script\s*(lang=""(.+)"")?\s*>([^\0]*)</script>";
var match = new Regex(regex, RegexOptions.Multiline).Match(text);
if (!match.Success)
{
ScriptLang = null;
Script = null;
return;
}
Script = match.Groups[3].Value.Trim();
ScriptLang = match.Groups[2].Value.Trim();
if (ScriptLang == "")
{
ScriptLang = "js";
}
}
private void parseStyle(string text)
{
var regex = @"<style\s*(lang=""(.+)"")?\s*>([^\0]*)</style>";
var match = new Regex(regex, RegexOptions.Multiline).Match(text);
if (!match.Success)
{
StyleLang = null;
Style = null;
return;
}
Style = match.Groups[3].Value.Trim().Trim('\ufeff');
StyleLang = match.Groups[2].Value.Trim();
if (StyleLang == "")
{
StyleLang = "css";
}
}
}
public sealed class VueBuildException : Exception
{
public VueBuildException(string message) : base(message) { }
}
partial class ProjectBuilder
{
public ProjectBuilder PrebuildVue()
{
var files = ResourceMinifier.GetFiles(file =>
file.Extension == ".vue"
);
using (var cache = new BuildCache())
{
var changedFiles = files.Where(file => !cache.Contains(file)).ToArray();
if (changedFiles.Any())
{
Parallel.ForEach(changedFiles, file =>
{
var source = File.ReadAllText(file);
var vueFile = new VueFile(source);
if (vueFile.Script is null)
{
return;
}
if (vueFile.ScriptLang == "ts" || vueFile.ScriptLang == "typescript")
{
File.WriteAllText(file + ".ts", vueFile.Script);
}
});
}
}
return this;
}
public ProjectBuilder BuildVue()
{
var files = ResourceMinifier.GetFiles(file =>
file.Extension == ".vue"
);
using (var cache = new BuildCache())
{
var changedFiles = files.Where(file => !cache.Contains(file)).ToArray();
if (changedFiles.Any())
{
Parallel.ForEach(changedFiles, file =>
{
cache.AddCache(file);
WriteInfo($"Vue build: {file}");
var source = File.ReadAllText(file);
var vueFile = new VueFile(source);
var compiledText = new StringBuilder("");
if (vueFile.Tamplate is null)
{
throw new VueBuildException($"{file}: Missing <tamplate>");
}
else
{
var uglifyHtml = new UglifyHtml();
if (vueFile.TamplateLang == "html")
{
compiledText.Append($"const template = /*html*/`{uglifyHtml.Run(vueFile.Tamplate)}`;");
}
else
{
throw new VueBuildException($"{file}: Unsupported <template> lang '{vueFile.TamplateLang}'");
}
}
if (vueFile.Style != null)
{
var styleID = Path.ChangeExtension(Path.GetFileName(file), null).Replace(".", "-") + "-style";
var uglifyCss = new UglifyCss();
if (vueFile.StyleLang == "css")
{
compiledText.Append($"resources.applyStyleFromText(`{uglifyCss.Run(vueFile.Style)}`,'{styleID}');");
}
else if (vueFile.StyleLang == "scss")
{
var sass = new SassSingleCompiler();
var css = uglifyCss.Run(sass.Run(vueFile.Style).Replace("@charset \"UTF-8\";", ""));
compiledText.Append($"resources.applyStyleFromText(`{css}`,'{styleID}');");
}
else
{
throw new VueBuildException($"{file}: Unsupported <style> lang '{vueFile.StyleLang}'");
}
}
if (vueFile.Script is null)
{
throw new VueBuildException($"{file}: Missing <script>");
}
else
{
if (vueFile.ScriptLang == "js" || vueFile.ScriptLang == "javascript")
{
var script = vueFile.Script.Replace("export default ", "return {export:Object.assign({template},").Trim().TrimEnd(';');
compiledText.Append($"{script})}}");
}
else if (vueFile.ScriptLang == "ts" || vueFile.ScriptLang == "typescript")
{
// var tsFile = file + ".ts";
// var jsFile = ".ts-output" + Path.DirectorySeparatorChar + file.Replace("src" + Path.DirectorySeparatorChar, "") + ".js";
// var script = File.ReadAllText(jsFile).Replace("export default ", "return {export:Object.assign({template},").Trim().TrimEnd(';');
// compiledText.Append($"{script})}}");
// File.Delete(tsFile);
// File.Delete(jsFile);
var tsc = new BabelSingleCompiler(file + ".ts");
var script = tsc.Run(vueFile.Script).Replace("export default ", "return {export:Object.assign({template},").Trim().TrimEnd(';');
compiledText.Append($"{script})}}");
}
else
{
throw new VueBuildException($"{file}: Unsupported <script> lang '{vueFile.ScriptLang}'");
}
}
// compiledText.Append("}})()");
var minFile = "min" + Path.DirectorySeparatorChar + Path.GetFileName(file) + ".min.js";
var jsc = new JavascriptMinifier();
File.WriteAllText(minFile, jsc.Minify(compiledText.ToString()));
UpdateCachedMinFile(minFile);
// WriteHint($"\t=> {minFile}");
});
}
cache.SaveCache();
}
WriteSuccess("Vue build complete.");
return this;
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build.Watcher
{
public class ClientWatcher : Watcher
{
public ClientWatcher() : base($"src{Path.DirectorySeparatorChar}client")
{
GenericFilter = "*.js";
}
protected override void OnFileChanged(FileSystemEventArgs e)
{
builder.WriteInfo($"[Client] {e.Name} changed.");
builder
.BuildClient()
.BuildVersions()
.BuildMaster();
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BilibiliEvolved.Build.Watcher
{
public class DarkStyleWatcher : Watcher
{
public DarkStyleWatcher() : base("min")
{
GenericFilter = "*.min.css";
FileFilter = file => {
return file.Contains("dark-slice");
};
}
protected override void OnFileChanged(FileSystemEventArgs e)
{
var sliceID = Convert.ToInt32(Path.GetFileNameWithoutExtension(e.Name).Replace("dark-slice-", "").Replace(".min", ""));
builder.WriteInfo($"[Dark Style] Slice {sliceID} changed.");
builder.BuildDarkStyles();
}
}
}

View File

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BilibiliEvolved.Build.Watcher
{
public abstract class PreprocessorWatcher : Watcher
{
private Process externalWatcherProcess;
private bool exitRequested = false;
private string originalExtension;
protected abstract ResourceMinifier Minifier { get; }
protected abstract NodeInteract WatcherComplier { get; }
protected abstract string Name { get; }
protected abstract string PostBuild(string content);
private string GetOriginalFilePath(string path)
{
return Path.ChangeExtension(path, originalExtension).Replace(WatcherPath, "src");
}
public void RestartCompiler() {
Console.WriteLine($"Unexpected exit of {Name} watcher, restarting...");
externalWatcherProcess.Start();
Console.WriteLine($"Restarted {Name} watcher.");
}
public PreprocessorWatcher(string originalExtension, string compliedExtension, string watcherPath) : base(watcherPath)
{
this.originalExtension = originalExtension;
externalWatcherProcess = WatcherComplier.Run();
externalWatcherProcess.Exited += (s, e) => {
if (!exitRequested) {
RestartCompiler();
}
};
GenericFilter = $"*{compliedExtension}";
FileFilter = file =>
{
var originalFile = GetOriginalFilePath(file);
if (originalExtension == ".scss") {
return true;
}
if (originalFile.EndsWith(".d.ts")) {
return false;
}
return !cache.Contains(originalFile);
};
}
private void KillExternalWatcher()
{
if (!externalWatcherProcess.HasExited)
{
exitRequested = true;
externalWatcherProcess.Kill();
}
}
public override void Stop()
{
KillExternalWatcher();
base.Stop();
}
public override void Dispose()
{
KillExternalWatcher();
base.Dispose();
}
protected override sealed void OnFileChanged(FileSystemEventArgs e)
{
// if (Path.GetExtension(e.FullPath) == ".js") {
// Console.WriteLine($"ts watcher changed: {e.FullPath}");
// }
if (!Path.GetFileNameWithoutExtension(e.FullPath).EndsWith(".vue"))
{
var originalFile = GetOriginalFilePath(e.FullPath);
if (!File.Exists(originalFile))
{
return;
}
builder.WriteInfo($"[{Name}] {Path.GetFileName(originalFile)} changed.");
var content = File.ReadAllText(e.FullPath);
cache.AddCache(originalFile);
cache.SaveCache();
var minFile = ResourceMinifier.GetMinimizedFileName(e.FullPath);
File.WriteAllText(minFile, Minifier.Minify(PostBuild(content)));
builder.UpdateCachedMinFile(minFile);
if (e.Name.Contains("dark-slice"))
{
builder.BuildDarkStyles();
}
}
}
protected override void OnFileDeleted(FileSystemEventArgs e)
{
if (!Path.GetFileNameWithoutExtension(e.FullPath).EndsWith(".vue"))
{
base.OnFileDeleted(e);
}
}
}
}

View File

@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build.Watcher
{
public abstract class ResourceWatcher : Watcher
{
public ResourceWatcher(string genericFilter, Predicate<string> fileFilter = null) : base($"src{Path.DirectorySeparatorChar}")
{
GenericFilter = genericFilter;
FileFilter = path => (fileFilter?.Invoke(path) ?? true) && !path.Contains($"src{Path.DirectorySeparatorChar}client");
}
protected abstract ResourceMinifier Minifier { get; }
protected abstract string Name { get; }
protected override sealed void OnFileChanged(FileSystemEventArgs e)
{
builder.WriteInfo($"[{Name}] {e.Name} changed.");
cache.AddCache(e.FullPath);
cache.SaveCache();
string minFile = ResourceMinifier.GetMinimizedFileName(e.FullPath);
File.WriteAllText(minFile, Minifier.Minify(File.ReadAllText(e.FullPath)));
builder.UpdateCachedMinFile(minFile);
if (e.Name.Contains("dark-slice")) {
builder.BuildDarkStyles();
}
}
}
public class JavaScriptWatcher : ResourceWatcher
{
public JavaScriptWatcher() : base("*.js", path => !path.EndsWith(".vue.js")) { }
protected override ResourceMinifier Minifier { get; } = new JavascriptMinifier();
protected override string Name { get; } = "JavaScript";
}
public class HtmlWatcher : ResourceWatcher
{
public HtmlWatcher() : base("*.html") { }
protected override ResourceMinifier Minifier { get; } = new HtmlMinifier();
protected override string Name { get; } = "HTML";
}
public class CssWatcher : ResourceWatcher
{
public CssWatcher() : base("*.css", file =>
{
return Path.GetFileName(file) != "dark.css"
&& Path.GetFileName(file) != "dark-template.css"
&& Path.GetExtension(file) == ".css"
&& !file.EndsWith(".p.css");
})
{ }
protected override ResourceMinifier Minifier { get; } = new CssMinifier();
protected override string Name { get; } = "CSS";
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BilibiliEvolved.Build.Watcher
{
public class SassWatcher : PreprocessorWatcher
{
public SassWatcher() : base(".scss", ".css", $".sass-output") { }
protected override ResourceMinifier Minifier { get; } = new CssMinifier();
protected override NodeInteract WatcherComplier { get; } = new SassWatchCompiler();
protected override string Name { get; } = "Sass";
protected override string PostBuild(string content) => content.Replace("@charset \"UTF-8\";", "");
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BilibiliEvolved.Build.Watcher
{
public class TypeScriptWatcher : PreprocessorWatcher
{
public TypeScriptWatcher() : base(".ts", ".js", $".ts-output") { }
protected override ResourceMinifier Minifier { get; } = new JavascriptMinifier();
protected override NodeInteract WatcherComplier { get; } = new BabelWatchCompiler();
protected override string Name { get; } = "TypeScript";
protected override string PostBuild(string content) => content;
}
}

View File

@ -1,152 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BilibiliEvolved.Build.Watcher
{
public class VueTypeScriptWatcher : Watcher
{
public VueTypeScriptWatcher() : base($".ts-output")
{
GenericFilter = "*.vue.js";
}
private Dictionary<string, TaskCompletionSource<string>> waitRequests = new Dictionary<string, TaskCompletionSource<string>>();
public Task<string> WaitForBuild(string path)
{
var tcs = new TaskCompletionSource<string>();
// Console.WriteLine($"add request: {path}");
waitRequests[path] = tcs;
return tcs.Task;
}
protected override void OnFileChanged(FileSystemEventArgs e)
{
var originalFilename = Path.ChangeExtension(e.FullPath, ".ts").Replace(WatcherPath, "src");
// Console.WriteLine($"test filename: {originalFilename}");
if (waitRequests.ContainsKey(originalFilename))
{
// Console.WriteLine($"set result for: {originalFilename}");
waitRequests[originalFilename].SetResult(File.ReadAllText(e.FullPath));
if (File.Exists(originalFilename))
{
File.Delete(originalFilename);
}
waitRequests.Remove(originalFilename);
}
}
}
public class VueWatcher : Watcher
{
// private VueTypeScriptWatcher tsWatcher = new VueTypeScriptWatcher();
public VueWatcher() : base($"src{Path.DirectorySeparatorChar}")
{
GenericFilter = "*.vue";
}
// public override void Start(ProjectBuilder builder)
// {
// tsWatcher.Start(builder);
// base.Start(builder);
// }
// public override void Stop()
// {
// base.Stop();
// tsWatcher.Stop();
// }
protected override void OnFileChanged(FileSystemEventArgs e)
{
builder.WriteInfo($"[Vue] {e.Name} changed.");
var source = File.ReadAllText(e.FullPath);
var vueFile = new VueFile(source);
var compiledText = new StringBuilder("");
BuildTemplate(e.FullPath, vueFile, compiledText);
BuildStyle(e.FullPath, vueFile, compiledText);
BuildScript(e.FullPath, vueFile, compiledText);
var minFile = $"min{Path.DirectorySeparatorChar + Path.GetFileName(e.FullPath)}.min.js";
var minifier = new JavascriptMinifier();
File.WriteAllText(minFile, minifier.Minify(compiledText.ToString()));
builder.UpdateCachedMinFile(minFile);
cache.AddCache(e.FullPath);
cache.SaveCache();
}
private void BuildTemplate(string path, VueFile vueFile, StringBuilder compiledText)
{
if (vueFile.Tamplate is null)
{
throw new VueBuildException($"{path}: Missing <tamplate>");
}
else
{
var uglifyHtml = new UglifyHtml();
if (vueFile.TamplateLang == "html")
{
compiledText.Append($"const template = /*html*/`{uglifyHtml.Run(vueFile.Tamplate)}`;");
}
else
{
throw new VueBuildException($"{path}: Unsupported <template> lang '{vueFile.TamplateLang}'");
}
}
}
private void BuildStyle(string path, VueFile vueFile, StringBuilder compiledText)
{
if (vueFile.Style != null)
{
var styleID = Path.ChangeExtension(Path.GetFileName(path), null).Replace(".", "-") + "-style";
var uglifyCss = new UglifyCss();
if (vueFile.StyleLang == "css")
{
compiledText.Append($"resources.applyStyleFromText(`{uglifyCss.Run(vueFile.Style)}`,'{styleID}');");
}
else if (vueFile.StyleLang == "scss")
{
var sass = new SassSingleCompiler();
var css = uglifyCss.Run(sass.Run(vueFile.Style).Replace("@charset \"UTF-8\";", ""));
compiledText.Append($"resources.applyStyleFromText(`{css}`,'{styleID}');");
}
else
{
throw new VueBuildException($"{path}: Unsupported <style> lang '{vueFile.StyleLang}'");
}
}
}
private void BuildScript(string path, VueFile vueFile, StringBuilder compiledText)
{
if (vueFile.Script is null)
{
throw new VueBuildException($"{path}: Missing <script>");
}
else
{
if (vueFile.ScriptLang == "js" || vueFile.ScriptLang == "javascript")
{
var script = vueFile.Script.Replace("export default ", "return {export:Object.assign({template},").Trim().TrimEnd(';');
compiledText.Append($"{script})}}");
}
else if (vueFile.ScriptLang == "ts" || vueFile.ScriptLang == "typescript")
{
// var tsFile = path + ".ts";
// var task = tsWatcher.WaitForBuild(tsFile);
// if (File.Exists(tsFile)) {
// File.Delete(tsFile);
// }
// Console.WriteLine($"writing file {tsFile}");
// File.WriteAllText(tsFile, vueFile.Script);
// Console.WriteLine($"waiting for tsc...");
var tsc = new BabelSingleCompiler(path + ".ts");
var script = tsc.Run(vueFile.Script).Replace("export default ", "return {export:Object.assign({template},").Trim().TrimEnd(';');
compiledText.Append($"{script})}}");
}
else
{
throw new VueBuildException($"{path}: Unsupported <script> lang '{vueFile.ScriptLang}'");
}
}
}
}
}

View File

@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build.Watcher
{
public class WatchBuilder
{
private List<Watcher> watchers = new List<Watcher>{
new ClientWatcher(),
new JavaScriptWatcher(),
new CssWatcher(),
new HtmlWatcher(),
new TypeScriptWatcher(),
new SassWatcher(),
new VueWatcher(),
};
private ProjectBuilder builder = ProjectBuilder.CreateBuilder();
public bool IsWatching => watchers.All(w => w.IsWatching);
public void StartWatching()
{
builder
.BuildClient()
.BuildVersions()
.BuildMaster();
var queue = new Queue<FileSystemEventArgs>();
async void rebuild()
{
await Task.Run(() =>
{
lock (builder)
{
builder.ResetBuildTime();
builder
.BuildBundle()
.BuildPreviewOffline()
.BuildOffline()
.BuildPreviewData()
.BuildFinalOutput();
}
});
lock (queue)
{
if (queue.Count > 1)
{
while (queue.Count > 1)
{
queue.TryDequeue(out var e);
// Console.WriteLine($"dequeued {e.FullPath}");
}
// Console.WriteLine($"restarting rebuild");
rebuild();
}
else if (queue.Count == 1)
{
queue.Clear();
// Console.WriteLine($"rebuild complete with clean queue");
return;
}
else
{
throw new Exception("Invalid state of queue!");
}
}
}
var notifyRebuild = Extensions.Debounce((FileSystemEventArgs e) =>
{
if (!Path.GetFileNameWithoutExtension(e.FullPath).EndsWith(".vue"))
{
lock (queue)
{
queue.Enqueue(e);
// Console.WriteLine($"enqueue to {queue.Count}");
if (queue.Count == 1)
{
rebuild();
}
}
}
}, Watcher.HandleFileChangesPeriod);
watchers.ForEach(w =>
{
w.Start(builder);
w.FileChanged += notifyRebuild;
w.FileDeleted += notifyRebuild;
});
builder.WriteInfo("Watcher started, input 'q' or press 'Ctrl + C' to exit.");
var input = "";
Console.CancelKeyPress += (s, e) =>
{
StopWatching();
};
while (input != null && input.ToLowerInvariant() != "q")
{
input = Console.ReadLine();
}
if (input != null)
{
StopWatching();
}
}
private void StopWatching()
{
watchers.Where(w => w.IsWatching).ForEach(w => w.Stop());
builder.WriteInfo("Watcher stopped.");
Environment.Exit(0);
}
}
}

View File

@ -1,179 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
namespace BilibiliEvolved.Build.Watcher
{
public abstract class Watcher : IDisposable
{
public Watcher(string path)
{
WatcherPath = path;
}
public bool IsWatching { get; private set; } = false;
public string WatcherPath { get; private set; }
public string GenericFilter { get; set; } = "";
public Predicate<string> FileFilter { get; set; } = s => true;
public ConcurrentBag<string> ChangedFilesHistory { get; } = new ConcurrentBag<string>();
public event Action<FileSystemEventArgs> FileChanged;
public event Action<FileSystemEventArgs> FileDeleted;
protected abstract void OnFileChanged(FileSystemEventArgs e);
protected virtual void OnFileDeleted(FileSystemEventArgs e)
{
// var minimizedFilename = ResourceMinifier.GetMinimizedFileName(e.FullPath);
// if (File.Exists(minimizedFilename))
// {
// File.Delete(minimizedFilename);
// }
builder.GetBundleFiles();
// builder
// .GetBundleFiles()
// .BuildBundle();
// RebuildOutputs();
}
// protected void RebuildBundle()
// {
// builder
// .GetBundleFiles()
// .BuildBundle();
// }
protected void RebuildOutputs()
{
builder
.BuildPreviewOffline()
.BuildOffline()
.BuildPreviewData()
.BuildFinalOutput();
}
protected BuildCache cache = new BuildCache();
protected ProjectBuilder builder;
private FileSystemWatcher watcher;
// https://github.com/dotnet/corefx/issues/25117
private ConcurrentBag<FileSystemEventArgs> changedFiles = new ConcurrentBag<FileSystemEventArgs>();
public const int HandleFileChangesPeriod = 200;
private void HandleFileChange(FileSystemEventArgs e)
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Changed:
case WatcherChangeTypes.Created:
// Console.WriteLine($"OnChange {e.Name}");
OnFileChanged(e);
FileChanged?.Invoke(e);
break;
case WatcherChangeTypes.Deleted:
// Console.WriteLine($"delete {e.Name} {e.ChangeType}");
OnFileDeleted(e);
FileDeleted?.Invoke(e);
break;
default:
break;
}
}
// private string GetRelativePath(string fullPath)
// {
// var cwd = Environment.CurrentDirectory;
// if (!cwd.EndsWith(Path.DirectorySeparatorChar))
// {
// cwd += Path.DirectorySeparatorChar;
// }
// if (fullPath.StartsWith(cwd))
// {
// return fullPath.Substring(0, cwd.Length);
// }
// else
// {
// throw new ArgumentException($"The path is not relative to cwd. {nameof(fullPath)}={fullPath}, {nameof(cwd)}={cwd}", nameof(fullPath));
// }
// }
public virtual void Start(ProjectBuilder builder)
{
if (IsWatching)
{
return;
}
IsWatching = true;
if (builder is null) {
throw new NullReferenceException("Project Builder cannot be null");
}
this.builder = builder;
if (watcher == null)
{
watcher = new FileSystemWatcher();
var fileChange = Extensions.Debounce((FileSystemEventArgs e) =>
{
builder.GetBundleFiles();
HandleFileChange(e);
// builder.UpdateCachedMinFile(ResourceMinifier.GetMinimizedFileName(e.FullPath));
ChangedFilesHistory.Add(e.FullPath);
}, HandleFileChangesPeriod);
FileSystemEventHandler handler = (s, e) =>
{
if (!FileFilter(e.FullPath))
{
return;
}
// if (e.FullPath.Contains("simple-home.vue.js")) {
// Console.WriteLine("simple-home.vue.js changed");
// }
fileChange(e);
// changedFiles.Add(e);
};
watcher.Changed += handler;
// watcher.Created += handler;
watcher.Deleted += handler;
watcher.IncludeSubdirectories = true;
}
watcher.Path = WatcherPath;
watcher.Filter = GenericFilter;
watcher.EnableRaisingEvents = true;
// Task.Run(async () =>
// {
// while (watcher.EnableRaisingEvents)
// {
// // watcher.WaitForChanged(WatcherChangeTypes.All);
// await Task.Delay(HandleFileChangesPeriod);
// if (changedFiles.IsEmpty)
// {
// continue;
// }
// lock (changedFiles)
// {
// builder.GetBundleFiles();
// var distinctChanges = changedFiles
// .GroupBy(e => e.FullPath)
// .Select(g => g.First())
// .ToArray();
// distinctChanges.ForEach(e =>
// {
// HandleFileChange(e);
// builder.UpdateCachedMinFile(e.FullPath);
// ChangedFilesHistory.Add(e.FullPath);
// });
// changedFiles.Clear();
// // builder.BuildBundle();
// // RebuildOutputs();
// }
// }
// });
}
public virtual void Stop()
{
watcher.EnableRaisingEvents = false;
IsWatching = false;
}
public virtual void Dispose()
{
cache?.Dispose();
watcher?.Dispose();
}
}
}

View File

@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Authors>Grant Howard</Authors>
<Product>Bilibili-Evolved Project Builder</Product>
<StartupObject>BilibiliEvolved.Build.Program</StartupObject>
<AssemblyName>build</AssemblyName>
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
<ApplicationIcon>Bilibili-Evolved.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.1" />
<PackageReference Include="TextCopy" Version="1.5.1" />
</ItemGroup>
</Project>

Binary file not shown.

View File

@ -1,239 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v3.1",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v3.1": {
"build/1.0.0": {
"dependencies": {
"Microsoft.Extensions.Configuration": "2.1.1",
"Microsoft.Extensions.Configuration.Binder": "2.1.1",
"Microsoft.Extensions.Configuration.Json": "2.1.1",
"TextCopy": "1.5.1"
},
"runtime": {
"build.dll": {}
}
},
"Microsoft.Extensions.Configuration/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.Configuration.Abstractions/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Primitives": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.Configuration.Binder/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Configuration": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Binder.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.Configuration.FileExtensions/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Configuration": "2.1.1",
"Microsoft.Extensions.FileProviders.Physical": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.FileExtensions.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.Configuration.Json/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Configuration": "2.1.1",
"Microsoft.Extensions.Configuration.FileExtensions": "2.1.1",
"Newtonsoft.Json": "11.0.2"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Json.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.FileProviders.Abstractions/2.1.1": {
"dependencies": {
"Microsoft.Extensions.Primitives": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Abstractions.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.FileProviders.Physical/2.1.1": {
"dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "2.1.1",
"Microsoft.Extensions.FileSystemGlobbing": "2.1.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.FileProviders.Physical.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.FileSystemGlobbing/2.1.1": {
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.FileSystemGlobbing.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Microsoft.Extensions.Primitives/2.1.1": {
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
},
"runtime": {
"lib/netstandard2.0/Microsoft.Extensions.Primitives.dll": {
"assemblyVersion": "2.1.1.0",
"fileVersion": "2.1.1.18157"
}
}
},
"Newtonsoft.Json/11.0.2": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
"assemblyVersion": "11.0.0.0",
"fileVersion": "11.0.2.21924"
}
}
},
"System.Memory/4.5.1": {},
"System.Runtime.CompilerServices.Unsafe/4.5.1": {},
"TextCopy/1.5.1": {
"runtime": {
"lib/netstandard2.0/TextCopy.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
}
}
},
"libraries": {
"build/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Microsoft.Extensions.Configuration/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-LjVKO6P2y52c5ZhTLX/w8zc5H4Y3J/LJsgqTBj49TtFq/hAtVNue/WA0F6/7GMY90xhD7K0MDZ4qpOeWXbLvzg==",
"path": "microsoft.extensions.configuration/2.1.1",
"hashPath": "microsoft.extensions.configuration.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.Abstractions/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-VfuZJNa0WUshZ/+8BFZAhwFKiKuu/qOUCFntfdLpHj7vcRnsGHqd3G2Hse78DM+pgozczGM63lGPRLmy+uhUOA==",
"path": "microsoft.extensions.configuration.abstractions/2.1.1",
"hashPath": "microsoft.extensions.configuration.abstractions.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.Binder/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-fcLCTS03poWE4v9tSNBr3pWn0QwGgAn1vzqHXlXgvqZeOc7LvQNzaWcKRQZTdEc3+YhQKwMsOtm3VKSA2aWQ8w==",
"path": "microsoft.extensions.configuration.binder/2.1.1",
"hashPath": "microsoft.extensions.configuration.binder.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.FileExtensions/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-CDk5CwG0YzlRgvl65J0iK6ahrX12yMRrEat3yVTXjWC+GN9Jg9zHZu2IE4cQIPAMA/IiAI5KjgL08fhP3fPCkw==",
"path": "microsoft.extensions.configuration.fileextensions/2.1.1",
"hashPath": "microsoft.extensions.configuration.fileextensions.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.Configuration.Json/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-IFpONpvdhVEE3S3F4fTYkpT/GyIHtumy2m0HniQanJ80Pj/pUF3Z4wjrHEp1G78rPD+WTo5fRlhdJfuU1Tv2GQ==",
"path": "microsoft.extensions.configuration.json/2.1.1",
"hashPath": "microsoft.extensions.configuration.json.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.FileProviders.Abstractions/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-UEQB5/QPuLYaCvScZQ9llhcks5xyEUKh41D615FoehRAF9UgGVmXHcCSOH8idHHLRoKm+OJJjEy1oywvuaL33w==",
"path": "microsoft.extensions.fileproviders.abstractions/2.1.1",
"hashPath": "microsoft.extensions.fileproviders.abstractions.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.FileProviders.Physical/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kVCvLm1ePchUgRrQZrno07Mn6knDAzR7vl6eRaI/fem0u6ODg+RTwOYLs4XL39Ttuu+BzEwqzHu3DtDgXT8+vQ==",
"path": "microsoft.extensions.fileproviders.physical/2.1.1",
"hashPath": "microsoft.extensions.fileproviders.physical.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.FileSystemGlobbing/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-4QDzyCN8cJnThY6mK9SnzovyCZ8KCG9jmC9KqHfFGtazJvmNZP1gcyBkPmqMjP0qwbmEUUyqyA9LLn3FrYXTGw==",
"path": "microsoft.extensions.filesystemglobbing/2.1.1",
"hashPath": "microsoft.extensions.filesystemglobbing.2.1.1.nupkg.sha512"
},
"Microsoft.Extensions.Primitives/2.1.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-scJ1GZNIxMmjpENh0UZ8XCQ6vzr/LzeF9WvEA51Ix2OQGAs9WPgPu8ABVUdvpKPLuor/t05gm6menJK3PwqOXg==",
"path": "microsoft.extensions.primitives/2.1.1",
"hashPath": "microsoft.extensions.primitives.2.1.1.nupkg.sha512"
},
"Newtonsoft.Json/11.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-IvJe1pj7JHEsP8B8J8DwlMEx8UInrs/x+9oVY+oCD13jpLu4JbJU2WCIsMRn5C4yW9+DgkaO8uiVE5VHKjpmdQ==",
"path": "newtonsoft.json/11.0.2",
"hashPath": "newtonsoft.json.11.0.2.nupkg.sha512"
},
"System.Memory/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-sDJYJpGtTgx+23Ayu5euxG5mAXWdkDb4+b0rD0Cab0M1oQS9H0HXGPriKcqpXuiJDTV7fTp/d+fMDJmnr6sNvA==",
"path": "system.memory/4.5.1",
"hashPath": "system.memory.4.5.1.nupkg.sha512"
},
"System.Runtime.CompilerServices.Unsafe/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==",
"path": "system.runtime.compilerservices.unsafe/4.5.1",
"hashPath": "system.runtime.compilerservices.unsafe.4.5.1.nupkg.sha512"
},
"TextCopy/1.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-iDgG90XFIllX8KAdzeyYk6S5oeVLzQU68gk5zqGT8X9WxJZQv6LgWu9ph4vbp6sRxP7+rmwJQwTEghojJiIADg==",
"path": "textcopy/1.5.1",
"hashPath": "textcopy.1.5.1.nupkg.sha512"
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +0,0 @@
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
}
}
}

View File

@ -1,13 +0,0 @@
const { declare } = require('@babel/helper-plugin-utils')
module.exports = declare(api => {
api.assertVersion(7)
return {
name: 'syntax-top-level-return',
manipulateOptions (opts, parserOpts) {
parserOpts.allowReturnOutsideFunction = true
},
}
})

View File

@ -0,0 +1,11 @@
| 2021.09.23 15:46:45 | **涛 evolved真的太好用啦谢谢 | 6217 | ¥1.00 |
| 2021.09.16 22:38:31 | *俊 支持一波bilibili-evolved | 9954 | ¥10.00 |
| 2021.09.12 05:04:22 | **羽 Damokles | 0826 | ¥10.00 |
| 2021.09.11 04:03:50 | **强 匿名 | 5617 | ¥8.88 |
| 2021.09.08 11:01:34 | *锐 | 2023 | ¥1.00 |
| 2021.09.06 23:37:57 | **培 匿名 | 7988 | ¥5.00 |
| 2021.09.01 00:15:50 | **沅 | 3822 | ¥2.00 |
| 2021.09.01 00:09:40 | **申 | 7942 | ¥10.00 |
| 2021.08.26 16:00:53 | **毅 | 5904 | ¥10.00 |
| 2021.08.23 12:24:30 | **锋 | 5739 | ¥1.50 |
| 2021.08.22 23:03:13 | *涛 | 4972 | ¥66.00 |

View File

@ -1,45 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const path_1 = require("path");
class LanguageKeys {
constructor(mapKeys, regexKeys) {
this.mapKeys = mapKeys;
this.regexKeys = regexKeys;
}
diff(other) {
return new LanguageKeys(this.mapKeys.filter(it => !other.mapKeys.includes(it)), this.regexKeys.filter(it => !other.regexKeys.includes(it)));
}
}
const readFile = (filename) => fs_1.readFileSync(filename, { encoding: 'utf-8' });
const config = JSON.parse(readFile('i18n-sync.json'));
const extractKeys = (language) => {
let temp = null;
const mapKeys = [];
const mapRegex = /\[`(.+?)`,/g;
while (temp = mapRegex.exec(language)) {
mapKeys.push(temp[1]);
}
const regexKeys = [];
const regexRegex = /\[(\/.*\/[a-z]*),/g;
while (temp = regexRegex.exec(language)) {
regexKeys.push(temp[1]);
}
return new LanguageKeys(mapKeys, regexKeys);
};
const mainLanguageKey = extractKeys(readFile(path_1.join(config.folder, `i18n.${config.mainLanguage}.js`)));
const targetLanguages = config.targetLanguages.map(name => {
const path = path_1.join(config.folder, `i18n.${name}.js`);
return {
name,
path,
text: readFile(path)
};
});
targetLanguages.forEach(language => {
const diff = mainLanguageKey.diff(extractKeys(language.text));
const output = language.text
.replace(/([\s\n]*\[`\*`)/, `\n ${diff.mapKeys.map(k => '[`' + k + '`, `TODO:`],').join('\n ')}$1`)
.replace(/(\]\);?[\s\n]*export default)/, ` ${diff.regexKeys.map(k => '[' + k + ', `TODO:`],').join('\n ')}\n$1`);
fs_1.writeFileSync(language.path, output, { encoding: 'utf-8' });
});

View File

@ -1,55 +0,0 @@
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
interface Config {
folder: string
mainLanguage: string
targetLanguages: string[]
}
class LanguageKeys {
constructor(
public mapKeys: string[],
public regexKeys: string[]
) { }
diff(other: LanguageKeys) {
return new LanguageKeys(
this.mapKeys.filter(it => !other.mapKeys.includes(it)),
this.regexKeys.filter(it => !other.regexKeys.includes(it))
)
}
}
const readFile = (filename: string) => readFileSync(filename, { encoding: 'utf-8' })
const config = JSON.parse(readFile('i18n-sync.json')) as Config
const extractKeys = (language: string) => {
let temp = null
const mapKeys = []
const mapRegex = /\[`(.+?)`,/g
while (temp = mapRegex.exec(language)) {
mapKeys.push(temp[1])
}
const regexKeys = []
const regexRegex = /\[(\/.*\/[a-z]*),/g
while (temp = regexRegex.exec(language)) {
regexKeys.push(temp[1])
}
return new LanguageKeys(mapKeys, regexKeys)
}
const mainLanguageKey = extractKeys(readFile(join(config.folder, `i18n.${config.mainLanguage}.js`)))
const targetLanguages = config.targetLanguages.map(name => {
const path = join(config.folder, `i18n.${name}.js`)
return {
name,
path,
text: readFile(path)
}
})
targetLanguages.forEach(language => {
const diff = mainLanguageKey.diff(extractKeys(language.text))
const output = language.text
.replace(/([\s\n]*\[`\*`)/, `\n ${diff.mapKeys.map(k => '[`' + k + '`, `TODO:`],').join('\n ')}$1`)
.replace(/(\]\);?[\s\n]*export default)/, ` ${diff.regexKeys.map(k => '[' + k + ', `TODO:`],').join('\n ')}\n$1`)
writeFileSync(language.path, output, { encoding: 'utf-8' })
})

View File

@ -1,9 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "commonjs",
"noImplicitAny": true,
"strictNullChecks": true,
"sourceMap": false,
}
}

730
doc/features/features.json Normal file
View File

@ -0,0 +1,730 @@
[
{
"type": "component",
"name": "copyFeedsLink",
"displayName": "复制动态链接",
"description": "开启后, 可在每条动态的菜单中选择复制链接.",
"fullRelativePath": "../../registry/dist/components/feeds/copy-link.js",
"fullAbsolutePath": "registry/dist/components/feeds/copy-link.js"
},
{
"type": "component",
"name": "disableFeedsDetails",
"displayName": "禁止跳转动态详情",
"description": "禁止动态点击后跳转详情页, 方便选择其中的文字.",
"fullRelativePath": "../../registry/dist/components/feeds/disable-details.js",
"fullAbsolutePath": "registry/dist/components/feeds/disable-details.js"
},
{
"type": "component",
"name": "extendFeedsLive",
"displayName": "直播信息扩充",
"description": "在动态的`正在直播`中, 为每一个直播间加上标题, 并且能够显示超过10个的直播间.",
"fullRelativePath": "../../registry/dist/components/feeds/extend-live.js",
"fullAbsolutePath": "registry/dist/components/feeds/extend-live.js"
},
{
"type": "component",
"name": "feedsFilter",
"displayName": "动态过滤器",
"description": "按照类型或者关键词过滤动态首页的内容, 也可以移除动态页的一些侧边卡片.",
"fullRelativePath": "../../registry/dist/components/feeds/filter.js",
"fullAbsolutePath": "registry/dist/components/feeds/filter.js"
},
{
"type": "component",
"name": "fixedFeedsSidebars",
"displayName": "强制固定动态侧栏",
"description": "强制固定动态主页的顶栏和所有侧栏.",
"fullRelativePath": "../../registry/dist/components/feeds/fixed-sidebars.js",
"fullAbsolutePath": "registry/dist/components/feeds/fixed-sidebars.js"
},
{
"type": "component",
"name": "foldComments",
"displayName": "快速收起评论",
"description": "动态里查看评论区时, 在底部添加一个`收起评论`按钮, 这样就不用再回到上面收起了.",
"fullRelativePath": "../../registry/dist/components/feeds/fold-comments.js",
"fullAbsolutePath": "registry/dist/components/feeds/fold-comments.js"
},
{
"type": "component",
"name": "fullFeedsContent",
"displayName": "展开动态内容",
"description": "不管内容多长, 总是完全展开动态的内容.",
"fullRelativePath": "../../registry/dist/components/feeds/full-content.js",
"fullAbsolutePath": "registry/dist/components/feeds/full-content.js"
},
{
"type": "component",
"name": "fullFeedsTitle",
"displayName": "展开动态标题",
"description": "在顶栏的视频动态中, 无论标题多长总是完全展开.",
"fullRelativePath": "../../registry/dist/components/feeds/full-title.js",
"fullAbsolutePath": "registry/dist/components/feeds/full-title.js"
},
{
"type": "component",
"name": "unfoldFeeds",
"displayName": "动态反折叠",
"description": "自动展开被折叠的动态.",
"fullRelativePath": "../../registry/dist/components/feeds/unfold.js",
"fullAbsolutePath": "registry/dist/components/feeds/unfold.js"
},
{
"type": "component",
"name": "liveAutoDraw",
"displayName": "直播间自动抽奖",
"description": "在当前直播间有抽奖活动时, 自动点击抽奖按钮. 注意只适用于少量抽奖, 那种99+限量抽奖可能跟不上其他人的手速(",
"fullRelativePath": "../../registry/dist/components/live/auto-draw.js",
"fullAbsolutePath": "registry/dist/components/live/auto-draw.js"
},
{
"type": "component",
"name": "badgeHelper",
"displayName": "直播勋章快速更换",
"description": "在直播区中, 可从功能面板中直接切换勋章和头衔.",
"fullRelativePath": "../../registry/dist/components/live/badge-helper.js",
"fullAbsolutePath": "registry/dist/components/live/badge-helper.js"
},
{
"type": "component",
"name": "liveDanmakuSendbar",
"displayName": "直播弹幕发送栏",
"description": "在直播的网页全屏和全屏模式状态下, 在底部显示弹幕栏.",
"fullRelativePath": "../../registry/dist/components/live/danmaku-sendbar.js",
"fullAbsolutePath": "registry/dist/components/live/danmaku-sendbar.js"
},
{
"type": "component",
"name": "downloadLiveRecords",
"displayName": "直播录像下载",
"description": "在直播录像页面 `live.bilibili.com/record/` 中添加下载支持.",
"fullRelativePath": "../../registry/dist/components/live/download-records.js",
"fullAbsolutePath": "registry/dist/components/live/download-records.js"
},
{
"type": "component",
"name": "liveGiftBox",
"displayName": "直播全屏包裹",
"description": "在直播的网页全屏(不能是全屏)模式下往控制栏添加包裹按钮",
"fullRelativePath": "../../registry/dist/components/live/gift-box.js",
"fullAbsolutePath": "registry/dist/components/live/gift-box.js"
},
{
"type": "component",
"name": "liveHomeMute",
"displayName": "直播首页静音",
"description": "禁止直播首页的推荐直播间自动开始播放.",
"fullRelativePath": "../../registry/dist/components/live/home-mute.js",
"fullAbsolutePath": "registry/dist/components/live/home-mute.js"
},
{
"type": "component",
"name": "livePip",
"displayName": "直播画中画",
"description": "在直播间的功能中启用画中画支持.",
"fullRelativePath": "../../registry/dist/components/live/pip.js",
"fullAbsolutePath": "registry/dist/components/live/pip.js"
},
{
"type": "component",
"name": "removeLiveWatermark",
"displayName": "删除直播水印",
"description": "删除观看直播时角落的水印.",
"fullRelativePath": "../../registry/dist/components/live/remove-watermark.js",
"fullAbsolutePath": "registry/dist/components/live/remove-watermark.js"
},
{
"type": "component",
"name": "dpiLiveShowgirl",
"displayName": "直播看板娘高DPI适配",
"description": "根据屏幕DPI缩放直播看板娘的大小, 避免像素锯齿.",
"fullRelativePath": "../../registry/dist/components/live/showgirl.js",
"fullAbsolutePath": "registry/dist/components/live/showgirl.js"
},
{
"type": "component",
"name": "collapseLiveSideBar",
"displayName": "自动收起直播侧栏",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/live/side-bar.js",
"fullAbsolutePath": "registry/dist/components/live/side-bar.js"
},
{
"type": "component",
"name": "alwaysShowDuration",
"displayName": "总是显示视频时长",
"description": "使脚本展示的各种视频卡片中的时长无需鼠标经过也能一直显示.",
"fullRelativePath": "../../registry/dist/components/style/always-show-duration.js",
"fullAbsolutePath": "registry/dist/components/style/always-show-duration.js"
},
{
"type": "component",
"name": "autoHideSidebar",
"displayName": "自动隐藏侧栏",
"description": "自动隐藏脚本的侧栏(功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.",
"fullRelativePath": "../../registry/dist/components/style/auto-hide-sidebar.js",
"fullAbsolutePath": "registry/dist/components/style/auto-hide-sidebar.js"
},
{
"type": "component",
"name": "customNavbar",
"displayName": "自定义顶栏",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/style/custom-navbar.js",
"fullAbsolutePath": "registry/dist/components/style/custom-navbar.js"
},
{
"type": "component",
"name": "darkModeFollowSystem",
"displayName": "夜间模式跟随系统",
"description": "使夜间模式同步系统设置的亮/暗主题.",
"fullRelativePath": "../../registry/dist/components/style/dark-mode/follow-system.js",
"fullAbsolutePath": "registry/dist/components/style/dark-mode/follow-system.js"
},
{
"type": "component",
"name": "darkMode",
"displayName": "夜间模式",
"description": "启用夜间模式能更好地适应光线暗的环境, 并会大量应用主题颜色.",
"fullRelativePath": "../../registry/dist/components/style/dark-mode.js",
"fullAbsolutePath": "registry/dist/components/style/dark-mode.js"
},
{
"type": "component",
"name": "darkModeSchedule",
"displayName": "夜间模式计划时段",
"description": "设置一个使用夜间模式的时间段, 进入/离开此时间段时, 会自动开启/关闭夜间模式. 结束时间小于起始时间时将视为次日, 如`18:00`至`6:00`表示晚上18:00到次日6:00.",
"fullRelativePath": "../../registry/dist/components/style/dark-mode/schedule.js",
"fullAbsolutePath": "registry/dist/components/style/dark-mode/schedule.js"
},
{
"type": "component",
"name": "hideBangumiReviews",
"displayName": "隐藏番剧点评",
"description": "隐藏番剧播放页面里的点评板块.",
"fullRelativePath": "../../registry/dist/components/style/hide/bangumi/reviews.js",
"fullAbsolutePath": "registry/dist/components/style/hide/bangumi/reviews.js"
},
{
"type": "component",
"name": "hideBangumiSponsors",
"displayName": "隐藏番剧承包",
"description": "隐藏番剧页面下方的承包榜, 以及右边的承包按钮.",
"fullRelativePath": "../../registry/dist/components/style/hide/bangumi/sponsors.js",
"fullAbsolutePath": "registry/dist/components/style/hide/bangumi/sponsors.js"
},
{
"type": "component",
"name": "hideBanner",
"displayName": "隐藏顶部横幅",
"description": "隐藏首页顶部横幅.",
"fullRelativePath": "../../registry/dist/components/style/hide/banner.js",
"fullAbsolutePath": "registry/dist/components/style/hide/banner.js"
},
{
"type": "component",
"name": "hideRecommendedLive",
"displayName": "隐藏推荐直播",
"description": "隐藏视频页面右侧下方的推荐直播.",
"fullRelativePath": "../../registry/dist/components/style/hide/video/recommended-live.js",
"fullAbsolutePath": "registry/dist/components/style/hide/video/recommended-live.js"
},
{
"type": "component",
"name": "hideRelatedVideos",
"displayName": "隐藏视频推荐",
"description": "隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播(自动播放下一个推荐视频)功能, 需要先取消隐藏视频推荐才能看到开关.",
"fullRelativePath": "../../registry/dist/components/style/hide/video/related-videos.js",
"fullAbsolutePath": "registry/dist/components/style/hide/video/related-videos.js"
},
{
"type": "component",
"name": "hideVideoTopMask",
"displayName": "隐藏视频标题层",
"description": "隐藏视频里鼠标经过时出现在右上角的覆盖层.",
"fullRelativePath": "../../registry/dist/components/style/hide/video/top-mask.js",
"fullAbsolutePath": "registry/dist/components/style/hide/video/top-mask.js"
},
{
"type": "component",
"name": "playerOnTop",
"displayName": "播放器置顶",
"description": "在视频页面中将播放器放在页面最上方.",
"fullRelativePath": "../../registry/dist/components/style/player-on-top.js",
"fullAbsolutePath": "registry/dist/components/style/player-on-top.js"
},
{
"type": "component",
"name": "playerShadow",
"displayName": "播放器投影",
"description": "为播放器添加主题色投影.",
"fullRelativePath": "../../registry/dist/components/style/player-shadow.js",
"fullAbsolutePath": "registry/dist/components/style/player-shadow.js"
},
{
"type": "component",
"name": "elegantScrollbar",
"displayName": "使用细滚动条",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/style/scrollbar.js",
"fullAbsolutePath": "registry/dist/components/style/scrollbar.js"
},
{
"type": "component",
"name": "sidebarOffset",
"displayName": "侧栏垂直偏移",
"description": "给脚本的侧栏设置垂直偏移量, 范围为 -40% ~ 40%",
"fullRelativePath": "../../registry/dist/components/style/sidebar-offset.js",
"fullAbsolutePath": "registry/dist/components/style/sidebar-offset.js"
},
{
"type": "component",
"name": "simplifyComments",
"displayName": "简化评论区",
"description": "- 删除热评头像下方的关注按钮\n- 删除用户的等级标识\n- 删除发送源信息(`来自安卓客户端`这种)\n- 删除用户名右边的勋章\n- 删除评论区顶部的横幅\n- 发送时间移动到右上角\n- 位图图标全部换用矢量图标, 高分屏不会模糊\n- 投票仅显示链接, 隐藏下面的大框.\n\n> 注: 关注和等级可以通过鼠标停留在头像上, 在弹出的资料卡小窗中查看.",
"fullRelativePath": "../../registry/dist/components/style/simplify/comments.js",
"fullAbsolutePath": "registry/dist/components/style/simplify/comments.js"
},
{
"type": "component",
"name": "simplifyHome",
"displayName": "简化首页",
"description": "隐藏原版首页不需要的元素/分区.",
"fullRelativePath": "../../registry/dist/components/style/simplify/home.js",
"fullAbsolutePath": "registry/dist/components/style/simplify/home.js"
},
{
"type": "component",
"name": "simplifyLiveroom",
"displayName": "简化直播间",
"description": "隐藏直播间中各种不需要的内容.",
"fullRelativePath": "../../registry/dist/components/style/simplify/live.js",
"fullAbsolutePath": "registry/dist/components/style/simplify/live.js"
},
{
"type": "component",
"name": "disableSpecialDanmaku",
"displayName": "禁用特殊弹幕样式",
"description": "移除高赞弹幕或UP主弹幕的特殊样式, 弹幕内容不会移除.",
"fullRelativePath": "../../registry/dist/components/style/special-danmaku.js",
"fullAbsolutePath": "registry/dist/components/style/special-danmaku.js"
},
{
"type": "component",
"name": "v1PanelStyle",
"displayName": "v1 风格设置面板",
"description": "使用 v1 风格的设置面板样式",
"fullRelativePath": "../../registry/dist/components/style/v1-panel.js",
"fullAbsolutePath": "registry/dist/components/style/v1-panel.js"
},
{
"type": "component",
"name": "touchComboLike",
"displayName": "三连触摸支持",
"description": "为视频页面中的三连操作(长按点赞)启用触摸支持.",
"fullRelativePath": "../../registry/dist/components/touch/combo-like.js",
"fullAbsolutePath": "registry/dist/components/touch/combo-like.js"
},
{
"type": "component",
"name": "doubleClickControl",
"displayName": "启用双击控制",
"description": "将操作方式更改为: 单击显示/隐藏控制栏, 双击播放/暂停.",
"fullRelativePath": "../../registry/dist/components/touch/double-click-control.js",
"fullAbsolutePath": "registry/dist/components/touch/double-click-control.js"
},
{
"type": "component",
"name": "touchMiniPlayer",
"displayName": "迷你播放器触摸拖动",
"description": "使迷你播放器的拖动条可以触摸拖动.",
"fullRelativePath": "../../registry/dist/components/touch/mini-player.js",
"fullAbsolutePath": "registry/dist/components/touch/mini-player.js"
},
{
"type": "component",
"name": "touchPlayerControl",
"displayName": "控制栏触摸优化",
"description": "增大播放器控制栏里按钮的间距, 方便触屏使用.",
"fullRelativePath": "../../registry/dist/components/touch/player-control.js",
"fullAbsolutePath": "registry/dist/components/touch/player-control.js"
},
{
"type": "component",
"name": "touchPlayerGestures",
"displayName": "播放器触摸手势",
"description": "为播放器启用触摸手势支持:\r\n- 左右滑动可调整进度\r\n- 上下滑动可调整音量\r\n- 进度调整可在左上角和右上角取消\r\n- 进度调整时在不同位置滑动, 可以使用3档不同的灵敏度.",
"fullRelativePath": "../../registry/dist/components/touch/player-gestures.js",
"fullAbsolutePath": "registry/dist/components/touch/player-gestures.js"
},
{
"type": "component",
"name": "checkInCenter",
"displayName": "签到助手",
"description": "在功能面板中提供一些可以每日进行的操作.",
"fullRelativePath": "../../registry/dist/components/utils/check-in-center.js",
"fullAbsolutePath": "registry/dist/components/utils/check-in-center.js"
},
{
"type": "component",
"name": "columnUnlock",
"displayName": "专栏文字选择",
"description": "使专栏的文字可以选择.",
"fullRelativePath": "../../registry/dist/components/utils/column-unlock.js",
"fullAbsolutePath": "registry/dist/components/utils/column-unlock.js"
},
{
"type": "component",
"name": "copyCommentsLink",
"displayName": "复制评论链接",
"description": "开启后, 可在每条评论的菜单中选择复制链接.",
"fullRelativePath": "../../registry/dist/components/utils/comments/copy-link.js",
"fullAbsolutePath": "registry/dist/components/utils/comments/copy-link.js"
},
{
"type": "component",
"name": "downloadAudio",
"displayName": "下载音频",
"description": "开启音频下载支持, 音频页面中可以在功能面板中下载当前音频.\n\n> 需要进入音频的详细信息页面才能下载, 在其他页面中此按钮将不可点击.",
"fullRelativePath": "../../registry/dist/components/utils/download-audio.js",
"fullAbsolutePath": "registry/dist/components/utils/download-audio.js"
},
{
"type": "component",
"name": "imageExporter",
"displayName": "图片批量导出",
"description": "可以批量导出某个地方的图片, 目前支持动态和专栏.\r\n\r\n动态文件名变量:\r\n`user`: 用户名\r\n`id`: 动态 ID\r\n`n`: 第 n 张图\r\n\r\n专栏文件名变量:\r\n`title`: 专栏标题\r\n`n`: 第 n 张图",
"fullRelativePath": "../../registry/dist/components/utils/image-exporter.js",
"fullAbsolutePath": "registry/dist/components/utils/image-exporter.js"
},
{
"type": "component",
"name": "imageResolution",
"displayName": "高分辨率图片",
"description": "根据屏幕 DPI 请求更高分辨率的图片, 例如 DPI 缩放 200% 则请求 2 倍的分辨率, 加载时间也会相应变长一些.",
"fullRelativePath": "../../registry/dist/components/utils/image-resolution.js",
"fullAbsolutePath": "registry/dist/components/utils/image-resolution.js"
},
{
"type": "component",
"name": "keymap",
"displayName": "快捷键扩展",
"description": "为视频播放器启用更多的快捷键, 快捷键列表可在`快捷键设置`中查看和配置.",
"fullRelativePath": "../../registry/dist/components/utils/keymap.js",
"fullAbsolutePath": "registry/dist/components/utils/keymap.js"
},
{
"type": "component",
"name": "removePromotions",
"displayName": "删除广告",
"description": "删除站内的各种广告. 包括首页的推广模块, 手机app推荐, 视频页面右侧的广告等.\n\n- `占位文本`: 删除首页推广模块的广告后显示\"🚫已屏蔽广告\"来替代空白区域.\n- `保留活动横幅`: 保留视频页面的活动横幅.",
"fullRelativePath": "../../registry/dist/components/utils/remove-promotions.js",
"fullAbsolutePath": "registry/dist/components/utils/remove-promotions.js"
},
{
"type": "component",
"name": "urlParamsClean",
"displayName": "网址参数清理",
"description": "自动删除网址中的多余跟踪参数.",
"fullRelativePath": "../../registry/dist/components/utils/url-params-clean.js",
"fullAbsolutePath": "registry/dist/components/utils/url-params-clean.js"
},
{
"type": "component",
"name": "v1Migrate",
"displayName": "v1 设置迁移",
"description": "在设置的 `关于` 面板中添加 `导入 v1 设置` 按钮, 点击导入可以导入 v1 的设置, 并根据打开的选项自动下载安装 v2 中对应的功能.",
"fullRelativePath": "../../registry/dist/components/utils/v1-migrate.js",
"fullAbsolutePath": "registry/dist/components/utils/v1-migrate.js"
},
{
"type": "component",
"name": "viewCover",
"displayName": "查看封面",
"description": "在视频和直播页面中, 可从功能面板中查看封面.",
"fullRelativePath": "../../registry/dist/components/utils/view-cover.js",
"fullAbsolutePath": "registry/dist/components/utils/view-cover.js"
},
{
"type": "component",
"name": "watchlaterRedirect",
"displayName": "稍后再看重定向",
"description": "将稍后再看的链接重定向为普通播放网址, 以使用新版播放页面.",
"fullRelativePath": "../../registry/dist/components/utils/watchlater-redirect.js",
"fullAbsolutePath": "registry/dist/components/utils/watchlater-redirect.js"
},
{
"type": "component",
"name": "biliplusRedirect",
"displayName": "BiliPlus跳转支持",
"description": "在视频/番剧/空间中, 可以从功能中的按钮点击转到BiliPlus上对应的页面.",
"fullRelativePath": "../../registry/dist/components/video/biliplus-redirect.js",
"fullAbsolutePath": "registry/dist/components/video/biliplus-redirect.js"
},
{
"type": "component",
"name": "bvidConvert",
"displayName": "BV号转换",
"description": "在功能面板中显示视频的AV号和BV号.",
"fullRelativePath": "../../registry/dist/components/video/bvid-convert.js",
"fullAbsolutePath": "registry/dist/components/video/bvid-convert.js"
},
{
"type": "component",
"name": "danmakuAirborne",
"displayName": "启用弹幕空降",
"description": "by [@kdxcxs](https://github.com/kdxcxs)\n\n为可能含有时间点的弹幕添加下划线, 点击可以跳到视频对应时间.",
"fullRelativePath": "../../registry/dist/components/video/danmaku/airborne.js",
"fullAbsolutePath": "registry/dist/components/video/danmaku/airborne.js"
},
{
"type": "component",
"name": "downloadDanmaku",
"displayName": "下载弹幕",
"description": "启用下载弹幕支持, 在视频和番剧页面中可从功能面板里下载弹幕.",
"fullRelativePath": "../../registry/dist/components/video/danmaku/download.js",
"fullAbsolutePath": "registry/dist/components/video/danmaku/download.js"
},
{
"type": "component",
"name": "expandDanmakuList",
"displayName": "展开弹幕列表",
"description": "每次加载视频时自动展开弹幕列表.",
"fullRelativePath": "../../registry/dist/components/video/danmaku/expand.js",
"fullAbsolutePath": "registry/dist/components/video/danmaku/expand.js"
},
{
"type": "component",
"name": "downloadVideo",
"displayName": "下载视频",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/video/download.js",
"fullAbsolutePath": "registry/dist/components/video/download.js"
},
{
"type": "component",
"name": "fullVideoDescription",
"displayName": "展开视频简介",
"description": "总是展开完整的视频简介.",
"fullRelativePath": "../../registry/dist/components/video/full-description.js",
"fullAbsolutePath": "registry/dist/components/video/full-description.js"
},
{
"type": "component",
"name": "fullEpisodeTitle",
"displayName": "展开选集标题",
"description": "总是完全展开视频选集列表的标题, 注意对番剧无效.",
"fullRelativePath": "../../registry/dist/components/video/full-episode-title.js",
"fullAbsolutePath": "registry/dist/components/video/full-episode-title.js"
},
{
"type": "component",
"name": "outerWatchlater",
"displayName": "外置稍后再看",
"description": "将视频页面菜单里的`稍后再看`移到外面.",
"fullRelativePath": "../../registry/dist/components/video/outer-watchlater.js",
"fullAbsolutePath": "registry/dist/components/video/outer-watchlater.js"
},
{
"type": "component",
"name": "playerAutoLight",
"displayName": "播放时自动关灯",
"description": "在视频播放时自动关灯, 暂停或结束时再自动打开.",
"fullRelativePath": "../../registry/dist/components/video/player/auto-light.js",
"fullAbsolutePath": "registry/dist/components/video/player/auto-light.js"
},
{
"type": "component",
"name": "playerControlBackground",
"displayName": "播放器控制栏背景色",
"description": "给视频播放器控制栏附上半透明的黑色, 代替原来的阴影.",
"fullRelativePath": "../../registry/dist/components/video/player/control-background.js",
"fullAbsolutePath": "registry/dist/components/video/player/control-background.js"
},
{
"type": "component",
"name": "defaultPlayerMode",
"displayName": "默认播放器模式",
"description": "控制是否使用默认播放器模式, 可以为`常规`, `宽屏`, `网页全屏`或`全屏`.",
"fullRelativePath": "../../registry/dist/components/video/player/default-mode.js",
"fullAbsolutePath": "registry/dist/components/video/player/default-mode.js"
},
{
"type": "component",
"name": "doubleClickFullscreen",
"displayName": "双击全屏",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/video/player/double-click-fullscreen.js",
"fullAbsolutePath": "registry/dist/components/video/player/double-click-fullscreen.js"
},
{
"type": "component",
"name": "playerFocus",
"displayName": "播放器定位",
"description": "进入视频/番剧页面时, 自动定位到播放器.\r\n\r\n可设置定位时的竖直偏移量, 单位为像素(px).",
"fullRelativePath": "../../registry/dist/components/video/player/focus.js",
"fullAbsolutePath": "registry/dist/components/video/player/focus.js"
},
{
"type": "component",
"name": "playerIntersectionActions",
"displayName": "播放器位置动作",
"description": "by [@FoundTheWOUT](https://github.com/FoundTheWOUT)\n\n设置当播放器移出视图的位置变化时执行的动作.",
"fullRelativePath": "../../registry/dist/components/video/player/intersection-actions.js",
"fullAbsolutePath": "registry/dist/components/video/player/intersection-actions.js"
},
{
"type": "component",
"name": "legacyAutoPlay",
"displayName": "传统连播模式",
"description": "暂无描述.",
"fullRelativePath": "../../registry/dist/components/video/player/legacy-auto-play.js",
"fullAbsolutePath": "registry/dist/components/video/player/legacy-auto-play.js"
},
{
"type": "component",
"name": "preserveDanmakuInput",
"displayName": "强制保留弹幕发送栏",
"description": "在网页全屏时, 即使宽度过小也强制保留弹幕发送栏, 注意这可能导致右侧的功能按钮挤出边界.",
"fullRelativePath": "../../registry/dist/components/video/player/preserve-danmaku-input.js",
"fullAbsolutePath": "registry/dist/components/video/player/preserve-danmaku-input.js"
},
{
"type": "component",
"name": "rememberVideoSpeed",
"displayName": "倍速记忆",
"description": "by [@JLoeve](https://github.com/LonelySteve)\n\n记忆上次选择的视频播放速度, 还可以使用更多倍速来扩展原生倍速菜单.",
"fullRelativePath": "../../registry/dist/components/video/player/remember-speed.js",
"fullAbsolutePath": "registry/dist/components/video/player/remember-speed.js"
},
{
"type": "component",
"name": "removePlayerPopup",
"displayName": "删除视频弹窗",
"description": "删除视频播放器中出现的各种弹窗, 类别可在选项中分别选择.",
"fullRelativePath": "../../registry/dist/components/video/player/remove-popup.js",
"fullAbsolutePath": "registry/dist/components/video/player/remove-popup.js"
},
{
"type": "component",
"name": "videoScreenshot",
"displayName": "启用视频截图",
"description": "启用视频快速截图, 将在播放器的时间右边增加一个截图按钮. 支持键盘快捷键<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>.\r\n\r\n如果弹幕渲染类型选择了Canvas, 则可以再按住<kbd>Shift</kbd>键来截取带弹幕的截图. 也就是鼠标操作为\"按住<kbd>Shift</kbd>点击截图按钮\", 键盘操作为\"<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>\".",
"fullRelativePath": "../../registry/dist/components/video/player/screenshot.js",
"fullAbsolutePath": "registry/dist/components/video/player/screenshot.js"
},
{
"type": "component",
"name": "seekByFrames",
"displayName": "启用逐帧调整",
"description": "在播放器的时间右边增加两个按钮, 用于**较精细**调整视频时间. 支持键盘快捷键<kbd>Shift</kbd>+<kbd>←</kbd>/<kbd>→</kbd>.\r\n\r\n> 注: `视频的实际播放帧率`跟`视频本身的帧率`和`显示器的刷新率`有关, 很难计算一个精准的数值, 部分视频仍然会有暂停不到那种一闪而过的图的情况.",
"fullRelativePath": "../../registry/dist/components/video/player/seek-by-frames.js",
"fullAbsolutePath": "registry/dist/components/video/player/seek-by-frames.js"
},
{
"type": "component",
"name": "showCoverBeforePlay",
"displayName": "播放前显示封面",
"description": "在视频开始播放前, 在播放器中显示封面.",
"fullRelativePath": "../../registry/dist/components/video/player/show-cover.js",
"fullAbsolutePath": "registry/dist/components/video/player/show-cover.js"
},
{
"type": "component",
"name": "skipChargeList",
"displayName": "跳过充电鸣谢",
"description": "自动跳过视频结尾的充电鸣谢.",
"fullRelativePath": "../../registry/dist/components/video/player/skip-charge-list.js",
"fullAbsolutePath": "registry/dist/components/video/player/skip-charge-list.js"
},
{
"type": "component",
"name": "quickFavorite",
"displayName": "启用快速收藏",
"description": "启用快速收藏, 在视频页面可以一键收藏到设定的某个收藏夹.",
"fullRelativePath": "../../registry/dist/components/video/quick-favorite.js",
"fullAbsolutePath": "registry/dist/components/video/quick-favorite.js"
},
{
"type": "component",
"name": "seoRedirect",
"displayName": "SEO页面重定向",
"description": "进入SEO视频页面时 (`https://www.bilibili.com/s/video/`) 自动跳转到原视频页面.",
"fullRelativePath": "../../registry/dist/components/video/seo-redirect.js",
"fullAbsolutePath": "registry/dist/components/video/seo-redirect.js"
},
{
"type": "component",
"name": "downloadSubtitle",
"displayName": "下载字幕",
"description": "启用下载字幕支持, 在视频页面中可从功能面板里下载字幕.",
"fullRelativePath": "../../registry/dist/components/video/subtitle/download.js",
"fullAbsolutePath": "registry/dist/components/video/subtitle/download.js"
},
{
"type": "component",
"name": "videoCurTime",
"displayName": "视频内显示时间",
"fullRelativePath": "../../registry/dist/components/video/player/localtime.js",
"fullAbsolutePath": "registry/dist/components/video/player/localtime.js",
"owner": "FoundTheWOUT"
},
{
"type": "plugin",
"name": "i18n.language.english",
"displayName": "英语语言包",
"fullRelativePath": "../../registry/dist/plugins/i18n/en-US.js",
"fullAbsolutePath": "registry/dist/plugins/i18n/en-US.js"
},
{
"type": "plugin",
"name": "i18n.language.japanese",
"displayName": "日语语言包",
"fullRelativePath": "../../registry/dist/plugins/i18n/ja-JP.js",
"fullAbsolutePath": "registry/dist/plugins/i18n/ja-JP.js"
},
{
"type": "plugin",
"name": "launchBar.trendingSearch",
"displayName": "搜索栏 - 搜索推荐",
"fullRelativePath": "../../registry/dist/plugins/launch-bar/trending-search.js",
"fullAbsolutePath": "registry/dist/plugins/launch-bar/trending-search.js"
},
{
"type": "plugin",
"name": "settingsPanel.tagFilters.recentComponents",
"displayName": "设置面板 - \"最近使用\"类别",
"fullRelativePath": "../../registry/dist/plugins/settings-panel/recent-components.js",
"fullAbsolutePath": "registry/dist/plugins/settings-panel/recent-components.js"
},
{
"type": "plugin",
"name": "customNavbar.items.darkMode",
"displayName": "自定义顶栏 - 夜间模式开关",
"fullRelativePath": "../../registry/dist/plugins/style/custom-navbar-dark-mode.js",
"fullAbsolutePath": "registry/dist/plugins/style/custom-navbar-dark-mode.js"
},
{
"type": "plugin",
"name": "vLoading.reimu",
"displayName": "加载提示 - 灵梦油库里",
"fullRelativePath": "../../registry/dist/plugins/v-loading/reimu.js",
"fullAbsolutePath": "registry/dist/plugins/v-loading/reimu.js"
},
{
"type": "plugin",
"name": "downloadVideo.outputs.aria2",
"displayName": "下载视频 - aria2 输出支持",
"fullRelativePath": "../../registry/dist/plugins/video/download/aria2-output.js",
"fullAbsolutePath": "registry/dist/plugins/video/download/aria2-output.js"
},
{
"type": "plugin",
"name": "downloadVideo.outputs.idm",
"displayName": "下载视频 - IDM 输出支持",
"fullRelativePath": "../../registry/dist/plugins/video/download/idm-output.js",
"fullAbsolutePath": "registry/dist/plugins/video/download/idm-output.js"
}
]

853
doc/features/features.md Normal file
View File

@ -0,0 +1,853 @@
# 可安装功能
## 组件
### [复制动态链接](../../registry/dist/components/feeds/copy-link.js)
`copyFeedsLink`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/copy-link.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/copy-link.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/copy-link.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/copy-link.js)
开启后, 可在每条动态的菜单中选择复制链接.
### [禁止跳转动态详情](../../registry/dist/components/feeds/disable-details.js)
`disableFeedsDetails`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/disable-details.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/disable-details.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/disable-details.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/disable-details.js)
禁止动态点击后跳转详情页, 方便选择其中的文字.
### [直播信息扩充](../../registry/dist/components/feeds/extend-live.js)
`extendFeedsLive`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/extend-live.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/extend-live.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/extend-live.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/extend-live.js)
在动态的`正在直播`中, 为每一个直播间加上标题, 并且能够显示超过10个的直播间.
### [动态过滤器](../../registry/dist/components/feeds/filter.js)
`feedsFilter`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/filter.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/filter.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/filter.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/filter.js)
按照类型或者关键词过滤动态首页的内容, 也可以移除动态页的一些侧边卡片.
### [强制固定动态侧栏](../../registry/dist/components/feeds/fixed-sidebars.js)
`fixedFeedsSidebars`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/fixed-sidebars.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/fixed-sidebars.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/fixed-sidebars.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/fixed-sidebars.js)
强制固定动态主页的顶栏和所有侧栏.
### [快速收起评论](../../registry/dist/components/feeds/fold-comments.js)
`foldComments`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/fold-comments.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/fold-comments.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/fold-comments.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/fold-comments.js)
动态里查看评论区时, 在底部添加一个`收起评论`按钮, 这样就不用再回到上面收起了.
### [展开动态内容](../../registry/dist/components/feeds/full-content.js)
`fullFeedsContent`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/full-content.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/full-content.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/full-content.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/full-content.js)
不管内容多长, 总是完全展开动态的内容.
### [展开动态标题](../../registry/dist/components/feeds/full-title.js)
`fullFeedsTitle`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/full-title.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/full-title.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/full-title.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/full-title.js)
在顶栏的视频动态中, 无论标题多长总是完全展开.
### [动态反折叠](../../registry/dist/components/feeds/unfold.js)
`unfoldFeeds`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/unfold.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/unfold.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/unfold.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/unfold.js)
自动展开被折叠的动态.
### [直播间自动抽奖](../../registry/dist/components/live/auto-draw.js)
`liveAutoDraw`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/auto-draw.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/auto-draw.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/auto-draw.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/auto-draw.js)
在当前直播间有抽奖活动时, 自动点击抽奖按钮. 注意只适用于少量抽奖, 那种99+限量抽奖可能跟不上其他人的手速(
### [直播勋章快速更换](../../registry/dist/components/live/badge-helper.js)
`badgeHelper`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/badge-helper.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/badge-helper.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/badge-helper.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/badge-helper.js)
在直播区中, 可从功能面板中直接切换勋章和头衔.
### [直播弹幕发送栏](../../registry/dist/components/live/danmaku-sendbar.js)
`liveDanmakuSendbar`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/danmaku-sendbar.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/danmaku-sendbar.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/danmaku-sendbar.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/danmaku-sendbar.js)
在直播的网页全屏和全屏模式状态下, 在底部显示弹幕栏.
### [直播录像下载](../../registry/dist/components/live/download-records.js)
`downloadLiveRecords`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/download-records.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/download-records.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/download-records.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/download-records.js)
在直播录像页面 `live.bilibili.com/record/` 中添加下载支持.
### [直播全屏包裹](../../registry/dist/components/live/gift-box.js)
`liveGiftBox`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/gift-box.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/gift-box.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/gift-box.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/gift-box.js)
在直播的网页全屏(不能是全屏)模式下往控制栏添加包裹按钮
### [直播首页静音](../../registry/dist/components/live/home-mute.js)
`liveHomeMute`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/home-mute.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/home-mute.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/home-mute.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/home-mute.js)
禁止直播首页的推荐直播间自动开始播放.
### [直播画中画](../../registry/dist/components/live/pip.js)
`livePip`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/pip.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/pip.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/pip.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/pip.js)
在直播间的功能中启用画中画支持.
### [删除直播水印](../../registry/dist/components/live/remove-watermark.js)
`removeLiveWatermark`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/remove-watermark.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/remove-watermark.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/remove-watermark.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/remove-watermark.js)
删除观看直播时角落的水印.
### [直播看板娘高DPI适配](../../registry/dist/components/live/showgirl.js)
`dpiLiveShowgirl`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/showgirl.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/showgirl.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/showgirl.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/showgirl.js)
根据屏幕DPI缩放直播看板娘的大小, 避免像素锯齿.
### [自动收起直播侧栏](../../registry/dist/components/live/side-bar.js)
`collapseLiveSideBar`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/side-bar.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/side-bar.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/side-bar.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/side-bar.js)
暂无描述.
### [总是显示视频时长](../../registry/dist/components/style/always-show-duration.js)
`alwaysShowDuration`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/always-show-duration.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/always-show-duration.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/always-show-duration.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/always-show-duration.js)
使脚本展示的各种视频卡片中的时长无需鼠标经过也能一直显示.
### [自动隐藏侧栏](../../registry/dist/components/style/auto-hide-sidebar.js)
`autoHideSidebar`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/auto-hide-sidebar.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/auto-hide-sidebar.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/auto-hide-sidebar.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/auto-hide-sidebar.js)
自动隐藏脚本的侧栏(功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.
### [自定义顶栏](../../registry/dist/components/style/custom-navbar.js)
`customNavbar`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/custom-navbar.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/custom-navbar.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/custom-navbar.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/custom-navbar.js)
暂无描述.
### [夜间模式跟随系统](../../registry/dist/components/style/dark-mode/follow-system.js)
`darkModeFollowSystem`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode/follow-system.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode/follow-system.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode/follow-system.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode/follow-system.js)
使夜间模式同步系统设置的亮/暗主题.
### [夜间模式](../../registry/dist/components/style/dark-mode.js)
`darkMode`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode.js)
启用夜间模式能更好地适应光线暗的环境, 并会大量应用主题颜色.
### [夜间模式计划时段](../../registry/dist/components/style/dark-mode/schedule.js)
`darkModeSchedule`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode/schedule.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode/schedule.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode/schedule.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode/schedule.js)
设置一个使用夜间模式的时间段, 进入/离开此时间段时, 会自动开启/关闭夜间模式. 结束时间小于起始时间时将视为次日, 如`18:00`至`6:00`表示晚上18:00到次日6:00.
### [隐藏番剧点评](../../registry/dist/components/style/hide/bangumi/reviews.js)
`hideBangumiReviews`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/bangumi/reviews.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/bangumi/reviews.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/bangumi/reviews.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/bangumi/reviews.js)
隐藏番剧播放页面里的点评板块.
### [隐藏番剧承包](../../registry/dist/components/style/hide/bangumi/sponsors.js)
`hideBangumiSponsors`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/bangumi/sponsors.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/bangumi/sponsors.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/bangumi/sponsors.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/bangumi/sponsors.js)
隐藏番剧页面下方的承包榜, 以及右边的承包按钮.
### [隐藏顶部横幅](../../registry/dist/components/style/hide/banner.js)
`hideBanner`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/banner.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/banner.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/banner.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/banner.js)
隐藏首页顶部横幅.
### [隐藏推荐直播](../../registry/dist/components/style/hide/video/recommended-live.js)
`hideRecommendedLive`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/recommended-live.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/recommended-live.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/recommended-live.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/recommended-live.js)
隐藏视频页面右侧下方的推荐直播.
### [隐藏视频推荐](../../registry/dist/components/style/hide/video/related-videos.js)
`hideRelatedVideos`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/related-videos.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/related-videos.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/related-videos.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/related-videos.js)
隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播(自动播放下一个推荐视频)功能, 需要先取消隐藏视频推荐才能看到开关.
### [隐藏视频标题层](../../registry/dist/components/style/hide/video/top-mask.js)
`hideVideoTopMask`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/top-mask.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/top-mask.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/top-mask.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/top-mask.js)
隐藏视频里鼠标经过时出现在右上角的覆盖层.
### [播放器置顶](../../registry/dist/components/style/player-on-top.js)
`playerOnTop`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/player-on-top.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/player-on-top.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/player-on-top.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/player-on-top.js)
在视频页面中将播放器放在页面最上方.
### [播放器投影](../../registry/dist/components/style/player-shadow.js)
`playerShadow`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/player-shadow.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/player-shadow.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/player-shadow.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/player-shadow.js)
为播放器添加主题色投影.
### [使用细滚动条](../../registry/dist/components/style/scrollbar.js)
`elegantScrollbar`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/scrollbar.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/scrollbar.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/scrollbar.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/scrollbar.js)
暂无描述.
### [侧栏垂直偏移](../../registry/dist/components/style/sidebar-offset.js)
`sidebarOffset`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/sidebar-offset.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/sidebar-offset.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/sidebar-offset.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/sidebar-offset.js)
给脚本的侧栏设置垂直偏移量, 范围为 -40% ~ 40%
### [简化评论区](../../registry/dist/components/style/simplify/comments.js)
`simplifyComments`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/comments.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/comments.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/comments.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/comments.js)
- 删除热评头像下方的关注按钮
- 删除用户的等级标识
- 删除发送源信息(`来自安卓客户端`这种)
- 删除用户名右边的勋章
- 删除评论区顶部的横幅
- 发送时间移动到右上角
- 位图图标全部换用矢量图标, 高分屏不会模糊
- 投票仅显示链接, 隐藏下面的大框.
> 注: 关注和等级可以通过鼠标停留在头像上, 在弹出的资料卡小窗中查看.
### [简化首页](../../registry/dist/components/style/simplify/home.js)
`simplifyHome`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/home.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/home.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/home.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/home.js)
隐藏原版首页不需要的元素/分区.
### [简化直播间](../../registry/dist/components/style/simplify/live.js)
`simplifyLiveroom`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/live.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/live.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/live.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/live.js)
隐藏直播间中各种不需要的内容.
### [禁用特殊弹幕样式](../../registry/dist/components/style/special-danmaku.js)
`disableSpecialDanmaku`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/special-danmaku.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/special-danmaku.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/special-danmaku.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/special-danmaku.js)
移除高赞弹幕或UP主弹幕的特殊样式, 弹幕内容不会移除.
### [v1 风格设置面板](../../registry/dist/components/style/v1-panel.js)
`v1PanelStyle`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/v1-panel.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/v1-panel.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/v1-panel.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/v1-panel.js)
使用 v1 风格的设置面板样式
### [三连触摸支持](../../registry/dist/components/touch/combo-like.js)
`touchComboLike`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/combo-like.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/combo-like.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/combo-like.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/combo-like.js)
为视频页面中的三连操作(长按点赞)启用触摸支持.
### [启用双击控制](../../registry/dist/components/touch/double-click-control.js)
`doubleClickControl`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/double-click-control.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/double-click-control.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/double-click-control.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/double-click-control.js)
将操作方式更改为: 单击显示/隐藏控制栏, 双击播放/暂停.
### [迷你播放器触摸拖动](../../registry/dist/components/touch/mini-player.js)
`touchMiniPlayer`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/mini-player.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/mini-player.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/mini-player.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/mini-player.js)
使迷你播放器的拖动条可以触摸拖动.
### [控制栏触摸优化](../../registry/dist/components/touch/player-control.js)
`touchPlayerControl`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/player-control.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/player-control.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/player-control.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/player-control.js)
增大播放器控制栏里按钮的间距, 方便触屏使用.
### [播放器触摸手势](../../registry/dist/components/touch/player-gestures.js)
`touchPlayerGestures`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/player-gestures.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/player-gestures.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/player-gestures.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/player-gestures.js)
为播放器启用触摸手势支持:
- 左右滑动可调整进度
- 上下滑动可调整音量
- 进度调整可在左上角和右上角取消
- 进度调整时在不同位置滑动, 可以使用3档不同的灵敏度.
### [签到助手](../../registry/dist/components/utils/check-in-center.js)
`checkInCenter`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/check-in-center.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/check-in-center.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/check-in-center.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/check-in-center.js)
在功能面板中提供一些可以每日进行的操作.
### [专栏文字选择](../../registry/dist/components/utils/column-unlock.js)
`columnUnlock`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/column-unlock.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/column-unlock.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/column-unlock.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/column-unlock.js)
使专栏的文字可以选择.
### [复制评论链接](../../registry/dist/components/utils/comments/copy-link.js)
`copyCommentsLink`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/comments/copy-link.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/comments/copy-link.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/comments/copy-link.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/comments/copy-link.js)
开启后, 可在每条评论的菜单中选择复制链接.
### [下载音频](../../registry/dist/components/utils/download-audio.js)
`downloadAudio`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/download-audio.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/download-audio.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/download-audio.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/download-audio.js)
开启音频下载支持, 音频页面中可以在功能面板中下载当前音频.
> 需要进入音频的详细信息页面才能下载, 在其他页面中此按钮将不可点击.
### [图片批量导出](../../registry/dist/components/utils/image-exporter.js)
`imageExporter`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/image-exporter.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/image-exporter.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/image-exporter.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/image-exporter.js)
可以批量导出某个地方的图片, 目前支持动态和专栏.
动态文件名变量:
`user`: 用户名
`id`: 动态 ID
`n`: 第 n 张图
专栏文件名变量:
`title`: 专栏标题
`n`: 第 n 张图
### [高分辨率图片](../../registry/dist/components/utils/image-resolution.js)
`imageResolution`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/image-resolution.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/image-resolution.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/image-resolution.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/image-resolution.js)
根据屏幕 DPI 请求更高分辨率的图片, 例如 DPI 缩放 200% 则请求 2 倍的分辨率, 加载时间也会相应变长一些.
### [快捷键扩展](../../registry/dist/components/utils/keymap.js)
`keymap`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/keymap.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/keymap.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/keymap.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/keymap.js)
为视频播放器启用更多的快捷键, 快捷键列表可在`快捷键设置`中查看和配置.
### [删除广告](../../registry/dist/components/utils/remove-promotions.js)
`removePromotions`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/remove-promotions.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/remove-promotions.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/remove-promotions.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/remove-promotions.js)
删除站内的各种广告. 包括首页的推广模块, 手机app推荐, 视频页面右侧的广告等.
- `占位文本`: 删除首页推广模块的广告后显示"🚫已屏蔽广告"来替代空白区域.
- `保留活动横幅`: 保留视频页面的活动横幅.
### [网址参数清理](../../registry/dist/components/utils/url-params-clean.js)
`urlParamsClean`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/url-params-clean.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/url-params-clean.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/url-params-clean.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/url-params-clean.js)
自动删除网址中的多余跟踪参数.
### [v1 设置迁移](../../registry/dist/components/utils/v1-migrate.js)
`v1Migrate`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/v1-migrate.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/v1-migrate.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/v1-migrate.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/v1-migrate.js)
在设置的 `关于` 面板中添加 `导入 v1 设置` 按钮, 点击导入可以导入 v1 的设置, 并根据打开的选项自动下载安装 v2 中对应的功能.
### [查看封面](../../registry/dist/components/utils/view-cover.js)
`viewCover`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/view-cover.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/view-cover.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/view-cover.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/view-cover.js)
在视频和直播页面中, 可从功能面板中查看封面.
### [稍后再看重定向](../../registry/dist/components/utils/watchlater-redirect.js)
`watchlaterRedirect`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/watchlater-redirect.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/watchlater-redirect.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/watchlater-redirect.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/watchlater-redirect.js)
将稍后再看的链接重定向为普通播放网址, 以使用新版播放页面.
### [BiliPlus跳转支持](../../registry/dist/components/video/biliplus-redirect.js)
`biliplusRedirect`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/biliplus-redirect.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/biliplus-redirect.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/biliplus-redirect.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/biliplus-redirect.js)
在视频/番剧/空间中, 可以从功能中的按钮点击转到BiliPlus上对应的页面.
### [BV号转换](../../registry/dist/components/video/bvid-convert.js)
`bvidConvert`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/bvid-convert.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/bvid-convert.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/bvid-convert.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/bvid-convert.js)
在功能面板中显示视频的AV号和BV号.
### [启用弹幕空降](../../registry/dist/components/video/danmaku/airborne.js)
`danmakuAirborne`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/airborne.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/airborne.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/airborne.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/airborne.js)
by [@kdxcxs](https://github.com/kdxcxs)
为可能含有时间点的弹幕添加下划线, 点击可以跳到视频对应时间.
### [下载弹幕](../../registry/dist/components/video/danmaku/download.js)
`downloadDanmaku`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/download.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/download.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/download.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/download.js)
启用下载弹幕支持, 在视频和番剧页面中可从功能面板里下载弹幕.
### [展开弹幕列表](../../registry/dist/components/video/danmaku/expand.js)
`expandDanmakuList`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/expand.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/expand.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/expand.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/expand.js)
每次加载视频时自动展开弹幕列表.
### [下载视频](../../registry/dist/components/video/download.js)
`downloadVideo`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/download.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/download.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/download.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/download.js)
暂无描述.
### [展开视频简介](../../registry/dist/components/video/full-description.js)
`fullVideoDescription`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/full-description.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/full-description.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/full-description.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/full-description.js)
总是展开完整的视频简介.
### [展开选集标题](../../registry/dist/components/video/full-episode-title.js)
`fullEpisodeTitle`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/full-episode-title.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/full-episode-title.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/full-episode-title.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/full-episode-title.js)
总是完全展开视频选集列表的标题, 注意对番剧无效.
### [外置稍后再看](../../registry/dist/components/video/outer-watchlater.js)
`outerWatchlater`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/outer-watchlater.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/outer-watchlater.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/outer-watchlater.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/outer-watchlater.js)
将视频页面菜单里的`稍后再看`移到外面.
### [播放时自动关灯](../../registry/dist/components/video/player/auto-light.js)
`playerAutoLight`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/auto-light.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/auto-light.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/auto-light.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/auto-light.js)
在视频播放时自动关灯, 暂停或结束时再自动打开.
### [播放器控制栏背景色](../../registry/dist/components/video/player/control-background.js)
`playerControlBackground`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/control-background.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/control-background.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/control-background.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/control-background.js)
给视频播放器控制栏附上半透明的黑色, 代替原来的阴影.
### [默认播放器模式](../../registry/dist/components/video/player/default-mode.js)
`defaultPlayerMode`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/default-mode.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/default-mode.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/default-mode.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/default-mode.js)
控制是否使用默认播放器模式, 可以为`常规`, `宽屏`, `网页全屏`或`全屏`.
### [双击全屏](../../registry/dist/components/video/player/double-click-fullscreen.js)
`doubleClickFullscreen`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/double-click-fullscreen.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/double-click-fullscreen.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/double-click-fullscreen.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/double-click-fullscreen.js)
暂无描述.
### [播放器定位](../../registry/dist/components/video/player/focus.js)
`playerFocus`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/focus.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/focus.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/focus.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/focus.js)
进入视频/番剧页面时, 自动定位到播放器.
可设置定位时的竖直偏移量, 单位为像素(px).
### [播放器位置动作](../../registry/dist/components/video/player/intersection-actions.js)
`playerIntersectionActions`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/intersection-actions.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/intersection-actions.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/intersection-actions.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/intersection-actions.js)
by [@FoundTheWOUT](https://github.com/FoundTheWOUT)
设置当播放器移出视图的位置变化时执行的动作.
### [传统连播模式](../../registry/dist/components/video/player/legacy-auto-play.js)
`legacyAutoPlay`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/legacy-auto-play.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/legacy-auto-play.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/legacy-auto-play.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/legacy-auto-play.js)
暂无描述.
### [强制保留弹幕发送栏](../../registry/dist/components/video/player/preserve-danmaku-input.js)
`preserveDanmakuInput`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/preserve-danmaku-input.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/preserve-danmaku-input.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/preserve-danmaku-input.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/preserve-danmaku-input.js)
在网页全屏时, 即使宽度过小也强制保留弹幕发送栏, 注意这可能导致右侧的功能按钮挤出边界.
### [倍速记忆](../../registry/dist/components/video/player/remember-speed.js)
`rememberVideoSpeed`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/remember-speed.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/remember-speed.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/remember-speed.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/remember-speed.js)
by [@JLoeve](https://github.com/LonelySteve)
记忆上次选择的视频播放速度, 还可以使用更多倍速来扩展原生倍速菜单.
### [删除视频弹窗](../../registry/dist/components/video/player/remove-popup.js)
`removePlayerPopup`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/remove-popup.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/remove-popup.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/remove-popup.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/remove-popup.js)
删除视频播放器中出现的各种弹窗, 类别可在选项中分别选择.
### [启用视频截图](../../registry/dist/components/video/player/screenshot.js)
`videoScreenshot`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/screenshot.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/screenshot.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/screenshot.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/screenshot.js)
启用视频快速截图, 将在播放器的时间右边增加一个截图按钮. 支持键盘快捷键<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>.
如果弹幕渲染类型选择了Canvas, 则可以再按住<kbd>Shift</kbd>键来截取带弹幕的截图. 也就是鼠标操作为"按住<kbd>Shift</kbd>点击截图按钮", 键盘操作为"<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd>".
### [启用逐帧调整](../../registry/dist/components/video/player/seek-by-frames.js)
`seekByFrames`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/seek-by-frames.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/seek-by-frames.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/seek-by-frames.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/seek-by-frames.js)
在播放器的时间右边增加两个按钮, 用于**较精细**调整视频时间. 支持键盘快捷键<kbd>Shift</kbd>+<kbd></kbd>/<kbd></kbd>.
> 注: `视频的实际播放帧率`跟`视频本身的帧率`和`显示器的刷新率`有关, 很难计算一个精准的数值, 部分视频仍然会有暂停不到那种一闪而过的图的情况.
### [播放前显示封面](../../registry/dist/components/video/player/show-cover.js)
`showCoverBeforePlay`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/show-cover.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/show-cover.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/show-cover.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/show-cover.js)
在视频开始播放前, 在播放器中显示封面.
### [跳过充电鸣谢](../../registry/dist/components/video/player/skip-charge-list.js)
`skipChargeList`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/skip-charge-list.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/skip-charge-list.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/skip-charge-list.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/skip-charge-list.js)
自动跳过视频结尾的充电鸣谢.
### [启用快速收藏](../../registry/dist/components/video/quick-favorite.js)
`quickFavorite`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/quick-favorite.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/quick-favorite.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/quick-favorite.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/quick-favorite.js)
启用快速收藏, 在视频页面可以一键收藏到设定的某个收藏夹.
### [SEO页面重定向](../../registry/dist/components/video/seo-redirect.js)
`seoRedirect`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/seo-redirect.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/seo-redirect.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/seo-redirect.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/seo-redirect.js)
进入SEO视频页面时 (`https://www.bilibili.com/s/video/`) 自动跳转到原视频页面.
### [下载字幕](../../registry/dist/components/video/subtitle/download.js)
`downloadSubtitle`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/subtitle/download.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/subtitle/download.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/subtitle/download.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/subtitle/download.js)
启用下载字幕支持, 在视频页面中可从功能面板里下载字幕.
### [视频内显示时间](../../registry/dist/components/video/player/localtime.js)
`videoCurTime`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/FoundTheWOUT/Bilibili-Evolved@v2/registry/dist/components/video/player/localtime.js) / [`Preview`](https://cdn.jsdelivr.net/gh/FoundTheWOUT/Bilibili-Evolved@preview/registry/dist/components/video/player/localtime.js)
**GitHub:** [`Stable`](https://github.com/FoundTheWOUT/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/localtime.js) / [`Preview`](https://github.com/FoundTheWOUT/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/localtime.js)
## 插件
### [英语语言包](../../registry/dist/plugins/i18n/en-US.js)
`i18n.language.english`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/i18n/en-US.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/i18n/en-US.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/i18n/en-US.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/i18n/en-US.js)
### [日语语言包](../../registry/dist/plugins/i18n/ja-JP.js)
`i18n.language.japanese`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/i18n/ja-JP.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/i18n/ja-JP.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/i18n/ja-JP.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/i18n/ja-JP.js)
### [搜索栏 - 搜索推荐](../../registry/dist/plugins/launch-bar/trending-search.js)
`launchBar.trendingSearch`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/launch-bar/trending-search.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/launch-bar/trending-search.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/launch-bar/trending-search.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/launch-bar/trending-search.js)
### [设置面板 - "最近使用"类别](../../registry/dist/plugins/settings-panel/recent-components.js)
`settingsPanel.tagFilters.recentComponents`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/settings-panel/recent-components.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/settings-panel/recent-components.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/settings-panel/recent-components.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/settings-panel/recent-components.js)
### [自定义顶栏 - 夜间模式开关](../../registry/dist/plugins/style/custom-navbar-dark-mode.js)
`customNavbar.items.darkMode`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/style/custom-navbar-dark-mode.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/style/custom-navbar-dark-mode.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/style/custom-navbar-dark-mode.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/style/custom-navbar-dark-mode.js)
### [加载提示 - 灵梦油库里](../../registry/dist/plugins/v-loading/reimu.js)
`vLoading.reimu`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/v-loading/reimu.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/v-loading/reimu.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/v-loading/reimu.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/v-loading/reimu.js)
### [下载视频 - aria2 输出支持](../../registry/dist/plugins/video/download/aria2-output.js)
`downloadVideo.outputs.aria2`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/video/download/aria2-output.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/video/download/aria2-output.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/video/download/aria2-output.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/video/download/aria2-output.js)
### [下载视频 - IDM 输出支持](../../registry/dist/plugins/video/download/idm-output.js)
`downloadVideo.outputs.idm`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/video/download/idm-output.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/video/download/idm-output.js)
**GitHub:** [`Stable`](https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/video/download/idm-output.js) / [`Preview`](https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/video/download/idm-output.js)

1169
doc/features/pack/pack.json Normal file

File diff suppressed because it is too large Load Diff

634
doc/features/pack/pack.md Normal file
View File

@ -0,0 +1,634 @@
# 合集包
合集包提供了批量的功能安装链接, 方便一次性安装大量功能.
### 我全都要
安装所有功能 (互斥的和个人私货不算), 请注意会耗费大量性能.
<details>
<summary><strong>jsDelivr Stable</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/copy-link.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/disable-details.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/extend-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/filter.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/fixed-sidebars.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/fold-comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/full-content.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/full-title.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/unfold.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/auto-draw.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/badge-helper.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/danmaku-sendbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/download-records.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/gift-box.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/home-mute.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/pip.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/showgirl.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/side-bar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/always-show-duration.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/auto-hide-sidebar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/custom-navbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode/follow-system.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/dark-mode/schedule.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/bangumi/reviews.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/bangumi/sponsors.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/banner.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/recommended-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/related-videos.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/top-mask.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/player-on-top.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/player-shadow.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/scrollbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/sidebar-offset.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/home.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/special-danmaku.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/v1-panel.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/combo-like.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/double-click-control.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/mini-player.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/player-control.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/touch/player-gestures.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/check-in-center.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/column-unlock.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/comments/copy-link.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/download-audio.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/image-exporter.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/image-resolution.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/keymap.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/url-params-clean.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/v1-migrate.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/view-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/watchlater-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/biliplus-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/bvid-convert.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/airborne.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/expand.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/full-description.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/full-episode-title.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/outer-watchlater.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/auto-light.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/control-background.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/default-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/double-click-fullscreen.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/focus.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/intersection-actions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/legacy-auto-play.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/preserve-danmaku-input.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/remember-speed.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/remove-popup.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/screenshot.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/seek-by-frames.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/show-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/skip-charge-list.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/quick-favorite.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/seo-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/subtitle/download.js
https://cdn.jsdelivr.net/gh/FoundTheWOUT/Bilibili-Evolved@v2/registry/dist/components/video/player/localtime.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/i18n/en-US.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/i18n/ja-JP.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/launch-bar/trending-search.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/settings-panel/recent-components.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/style/custom-navbar-dark-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/v-loading/reimu.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/video/download/aria2-output.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/video/download/idm-output.js
```
</details>
<details>
<summary><strong>jsDelivr Preview</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/copy-link.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/disable-details.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/extend-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/filter.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/fixed-sidebars.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/fold-comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/full-content.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/full-title.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/unfold.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/auto-draw.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/badge-helper.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/danmaku-sendbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/download-records.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/gift-box.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/home-mute.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/pip.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/showgirl.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/side-bar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/always-show-duration.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/auto-hide-sidebar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/custom-navbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode/follow-system.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/dark-mode/schedule.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/bangumi/reviews.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/bangumi/sponsors.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/banner.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/recommended-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/related-videos.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/top-mask.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/player-on-top.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/player-shadow.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/scrollbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/sidebar-offset.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/home.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/special-danmaku.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/v1-panel.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/combo-like.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/double-click-control.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/mini-player.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/player-control.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/touch/player-gestures.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/check-in-center.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/column-unlock.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/comments/copy-link.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/download-audio.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/image-exporter.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/image-resolution.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/keymap.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/url-params-clean.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/v1-migrate.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/view-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/watchlater-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/biliplus-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/bvid-convert.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/airborne.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/expand.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/full-description.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/full-episode-title.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/outer-watchlater.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/auto-light.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/control-background.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/default-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/double-click-fullscreen.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/focus.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/intersection-actions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/legacy-auto-play.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/preserve-danmaku-input.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/remember-speed.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/remove-popup.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/screenshot.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/seek-by-frames.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/show-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/skip-charge-list.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/quick-favorite.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/seo-redirect.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/subtitle/download.js
https://cdn.jsdelivr.net/gh/FoundTheWOUT/Bilibili-Evolved@preview/registry/dist/components/video/player/localtime.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/i18n/en-US.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/i18n/ja-JP.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/launch-bar/trending-search.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/settings-panel/recent-components.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/style/custom-navbar-dark-mode.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/v-loading/reimu.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/video/download/aria2-output.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/video/download/idm-output.js
```
</details>
<details>
<summary><strong>GitHub Stable</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/copy-link.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/disable-details.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/extend-live.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/filter.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/fixed-sidebars.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/fold-comments.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/full-content.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/full-title.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/unfold.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/auto-draw.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/badge-helper.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/danmaku-sendbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/download-records.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/gift-box.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/home-mute.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/pip.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/showgirl.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/side-bar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/always-show-duration.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/auto-hide-sidebar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/custom-navbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode/follow-system.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/dark-mode/schedule.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/bangumi/reviews.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/bangumi/sponsors.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/banner.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/recommended-live.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/related-videos.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/top-mask.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/player-on-top.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/player-shadow.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/scrollbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/sidebar-offset.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/comments.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/home.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/live.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/special-danmaku.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/v1-panel.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/combo-like.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/double-click-control.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/mini-player.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/player-control.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/touch/player-gestures.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/check-in-center.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/column-unlock.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/comments/copy-link.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/download-audio.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/image-exporter.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/image-resolution.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/keymap.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/url-params-clean.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/v1-migrate.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/view-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/watchlater-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/biliplus-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/bvid-convert.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/airborne.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/download.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/expand.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/download.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/full-description.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/full-episode-title.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/outer-watchlater.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/auto-light.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/control-background.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/default-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/double-click-fullscreen.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/focus.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/intersection-actions.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/legacy-auto-play.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/preserve-danmaku-input.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/remember-speed.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/remove-popup.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/screenshot.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/seek-by-frames.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/show-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/skip-charge-list.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/quick-favorite.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/seo-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/subtitle/download.js
https://github.com/FoundTheWOUT/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/localtime.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/i18n/en-US.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/i18n/ja-JP.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/launch-bar/trending-search.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/settings-panel/recent-components.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/style/custom-navbar-dark-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/v-loading/reimu.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/video/download/aria2-output.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/video/download/idm-output.js
```
</details>
<details>
<summary><strong>GitHub Preview</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/copy-link.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/disable-details.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/extend-live.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/filter.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/fixed-sidebars.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/fold-comments.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/full-content.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/full-title.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/unfold.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/auto-draw.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/badge-helper.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/danmaku-sendbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/download-records.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/gift-box.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/home-mute.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/pip.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/showgirl.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/side-bar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/always-show-duration.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/auto-hide-sidebar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/custom-navbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode/follow-system.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/dark-mode/schedule.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/bangumi/reviews.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/bangumi/sponsors.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/banner.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/recommended-live.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/related-videos.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/top-mask.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/player-on-top.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/player-shadow.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/scrollbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/sidebar-offset.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/comments.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/home.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/live.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/special-danmaku.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/v1-panel.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/combo-like.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/double-click-control.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/mini-player.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/player-control.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/touch/player-gestures.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/check-in-center.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/column-unlock.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/comments/copy-link.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/download-audio.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/image-exporter.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/image-resolution.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/keymap.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/url-params-clean.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/v1-migrate.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/view-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/watchlater-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/biliplus-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/bvid-convert.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/airborne.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/download.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/expand.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/download.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/full-description.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/full-episode-title.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/outer-watchlater.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/auto-light.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/control-background.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/default-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/double-click-fullscreen.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/focus.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/intersection-actions.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/legacy-auto-play.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/preserve-danmaku-input.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/remember-speed.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/remove-popup.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/screenshot.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/seek-by-frames.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/show-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/skip-charge-list.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/quick-favorite.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/seo-redirect.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/subtitle/download.js
https://github.com/FoundTheWOUT/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/localtime.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/i18n/en-US.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/i18n/ja-JP.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/launch-bar/trending-search.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/settings-panel/recent-components.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/style/custom-navbar-dark-mode.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/v-loading/reimu.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/video/download/aria2-output.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/video/download/idm-output.js
```
</details>
### 简洁至上
简化各种多余界面元素, 专注于内容本身.
<details>
<summary><strong>jsDelivr Stable</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/player/remove-popup.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/special-danmaku.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/simplify/home.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/side-bar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/related-videos.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/recommended-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/hide/video/top-mask.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/auto-hide-sidebar.js
```
</details>
<details>
<summary><strong>jsDelivr Preview</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/player/remove-popup.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/special-danmaku.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/simplify/home.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/side-bar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/related-videos.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/recommended-live.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/hide/video/top-mask.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/auto-hide-sidebar.js
```
</details>
<details>
<summary><strong>GitHub Stable</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/player/remove-popup.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/special-danmaku.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/comments.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/live.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/simplify/home.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/side-bar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/related-videos.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/recommended-live.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/hide/video/top-mask.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/auto-hide-sidebar.js
```
</details>
<details>
<summary><strong>GitHub Preview</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/player/remove-popup.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/special-danmaku.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/comments.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/live.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/simplify/home.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/side-bar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/related-videos.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/recommended-live.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/hide/video/top-mask.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/auto-hide-sidebar.js
```
</details>
### 下载器
包含下载各种内容的功能.
<details>
<summary><strong>jsDelivr Stable</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/subtitle/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/danmaku/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/download-audio.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/download-records.js
```
</details>
<details>
<summary><strong>jsDelivr Preview</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/subtitle/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/danmaku/download.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/download-audio.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/download-records.js
```
</details>
<details>
<summary><strong>GitHub Stable</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/download.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/subtitle/download.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/danmaku/download.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/download-audio.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/download-records.js
```
</details>
<details>
<summary><strong>GitHub Preview</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/download.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/subtitle/download.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/danmaku/download.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/download-audio.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/download-records.js
```
</details>
### 常用功能包
包含一些常用功能.
<details>
<summary><strong>jsDelivr Stable</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/scrollbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/style/custom-navbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/column-unlock.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/url-params-clean.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/keymap.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/utils/view-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/bvid-convert.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/danmaku-sendbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/live/gift-box.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/full-content.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/unfold.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/fold-comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/feeds/disable-details.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/components/video/full-description.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@v2/registry/dist/plugins/settings-panel/recent-components.js
```
</details>
<details>
<summary><strong>jsDelivr Preview</strong></summary>
```
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/scrollbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/style/custom-navbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/remove-promotions.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/column-unlock.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/url-params-clean.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/keymap.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/view-cover.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/bvid-convert.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/remove-watermark.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/danmaku-sendbar.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/live/gift-box.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/full-content.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/unfold.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/fold-comments.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/disable-details.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/video/full-description.js
https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/settings-panel/recent-components.js
```
</details>
<details>
<summary><strong>GitHub Stable</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/scrollbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/style/custom-navbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/column-unlock.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/url-params-clean.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/keymap.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/utils/view-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/bvid-convert.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/danmaku-sendbar.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/live/gift-box.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/full-content.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/unfold.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/fold-comments.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/feeds/disable-details.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/components/video/full-description.js
https://github.com/the1812/Bilibili-Evolved/raw/v2/registry/dist/plugins/settings-panel/recent-components.js
```
</details>
<details>
<summary><strong>GitHub Preview</strong></summary>
```
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/scrollbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/style/custom-navbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/remove-promotions.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/column-unlock.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/url-params-clean.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/keymap.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/utils/view-cover.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/bvid-convert.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/remove-watermark.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/danmaku-sendbar.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/live/gift-box.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/full-content.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/unfold.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/fold-comments.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/feeds/disable-details.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/components/video/full-description.js
https://github.com/the1812/Bilibili-Evolved/raw/preview/registry/dist/plugins/settings-panel/recent-components.js
```
</details>

35
doc/v1-migrate.md Normal file
View File

@ -0,0 +1,35 @@
# 从 v1 (旧版) 迁移设置
在 v2 的组件库中, 提供了 `v1 设置迁移` 的功能, 可以将 v1 中使用的功能自动安装到 v2 中来.
本文档将说明迁移的步骤, 从还没有安装 v2 的脚本开始:
## 1. 导出 v1 设置
打开脚本设置面板, 在搜索框旁边的菜单中选择导出设置, 得到文件 `settings.json`
![image](https://user-images.githubusercontent.com/26504152/127772561-96410454-45eb-4a08-9223-6a97c1850abb.png)
## 2. 安装 v2 脚本
前往 [README](../README.md#安装) 安装 v2 脚本, 并禁用 v1 脚本.
## 3. 安装 v1 设置迁移
前往 [功能列表](./features/features.md), 搜索 `v1 设置迁移`, 根据自身网络情况选择合适的安装链接并复制.
![image](https://user-images.githubusercontent.com/26504152/127772680-9e227748-6685-4bb4-9afb-4e0b1e96b282.png)
刷新之前的 b 站页面, v2 脚本应该已经生效, 设置面板依然默认在页面左侧中央.
打开设置面板, 进入左下角的 `组件`, 在 `添加组件` 那里的输入框粘贴链接, 点击添加, 安装完成后刷新页面.
![image](https://user-images.githubusercontent.com/26504152/127772811-bc1ac97f-ecaa-4823-b694-c393d688ad35.png)
## 4. 开始迁移
再次打开设置面板, 进入左下角的 `关于`, 上一步成功的话这里会多出一个 `导入 v1 设置` 的按钮.
> 目前的 Technical Preview 版中, 在使用 `v1 设置迁移` 时, 也需要在通用设置中把更新源设为 `GitHub`.
![image](https://user-images.githubusercontent.com/26504152/127772852-4594d882-9ce7-4059-a34c-366725ce36ff.png)
点击这个按钮, 选择一开始导出的 `settings.json` 文件, 脚本将会开始下载所有在 v1 中开启的功能并安装.
等待安装完成后, 刷新页面就完成迁移了. v1 脚本可以先不卸载, 免得这设置迁移有啥 bug 把数据搞丢了就不好了(

3
docs/README.md Normal file
View File

@ -0,0 +1,3 @@
**预留给 Github Pages 的文件夹**
文档请放至`doc`文件夹

View File

@ -1,19 +0,0 @@
// ==UserScript==
// @name Live Keymap
// @version 1.0.0
// @description 直播间快捷键扩展
// @author Grant Howard
// @license MIT
// @match *://live.bilibili.com/*
// @match *://live.bilibili.com
// @run-at document-body
// @grant unsafeWindow
// ==/UserScript==
document.addEventListener('keydown', e => {
if (document.activeElement && ['input', 'textarea'].includes(document.activeElement.nodeName.toLowerCase())) {
return
}
if (e.key.toLowerCase() === 'm' && !e.ctrlKey && !e.shiftKey && !e.altKey) {
document.querySelector('.blpui-volume-btn .blpui-btn').click()
}
})

View File

@ -1,11 +0,0 @@
// ==UserScript==
// @name <name>
// @version 1.0.0
// @description <description>
// @author <author>
// @license MIT
// @match *://*.bilibili.com/*
// @run-at document-body
// @grant unsafeWindow
// ==/UserScript==
Object.assign(window, unsafeWindow.bilibiliEvolved)

View File

@ -1,64 +0,0 @@
// ==UserScript==
// @name 拜年祭火锅连点
// @version 1.0.0
// @author Grant Howard
// @license MIT
// @match https://www.bilibili.com/blackboard/xianxing2020bnj.html*
// @run-at document-start
// @grant unsafeWindow
// ==/UserScript==
window.addEventListener('load', async () => {
Object.assign(window, unsafeWindow.bilibiliEvolved)
const Toast = await unsafeWindow.bilibiliEvolved.resources.importAsync('toast')
const log = (...args) => {
console.log(...args)
Toast.info(args.join(' '), '拜年祭火锅连点', 6000)
}
unsafeWindow.startAutoClick = true
addons.push({
content: /*html*/`
<button id="dish-click" class="gui-settings-flat-button">
<i class="mdi mdi-24px mdi-cursor-default-click-outline"></i>
关闭火锅连点
</button>`,
success: () => {
const button = document.getElementById('dish-click')
const textNode = [...button.childNodes].find(it => it.nodeType === Node.TEXT_NODE && it.textContent.trim() !== '')
button.addEventListener('click', () => {
if (unsafeWindow.startAutoClick === true) {
textNode.textContent = '启动火锅连点'
} else {
textNode.textContent = '关闭火锅连点'
}
unsafeWindow.startAutoClick = !unsafeWindow.startAutoClick
})
}
})
let nextTime = 3000
const dishClick = async () => {
if (unsafeWindow.startAutoClick !== true) {
return
}
const count = Math.floor(Math.random() * (30 - 2)) + 2
const response = await (await fetch('https://api.bilibili.com/x/activity/bnj2020/hotpot/increase', {
credentials: 'include',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: `count=${count}&csrf=${getCsrf()}`,
method: 'POST'
}
)).json()
if (response.code === 0) {
log('完成了一次连点, 次数: ', count)
if (response.data) {
log(`触发了特殊事件: `, response.data.name)
}
} else {
log('连点失败! ', response.message)
}
nextTime = Math.floor(Math.random() * (3000 - 500)) + 500
setTimeout(dishClick, nextTime)
}
dishClick()
})

View File

@ -1,6 +0,0 @@
*.flv
*.part*
*.xml
*.ass
test.*
test/

View File

@ -1,5 +0,0 @@
.vscode/
test.*
test/
*.xml
*.ass

View File

@ -1,50 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const danmaku_1 = require("./danmaku");
class AssDanmaku extends danmaku_1.Danmaku {
constructor({ content, time, type, fontSize, color, typeTag, colorTag, endTime }) {
super({ content, time, type, fontSize, color });
this.typeTag = typeTag;
this.colorTag = colorTag;
this.endTime = endTime;
}
text(fontStyles) {
const styleName = fontStyles[this.fontSize].match(/Style:(.*?),/)[1].trim();
return `Dialogue: 0,${this.time},${this.endTime},${styleName},,0,0,0,,{${this.typeTag}${this.colorTag}}${this.content}`;
}
}
exports.AssDanmaku = AssDanmaku;
class AssDanmakuDocument {
constructor(danmakus, title, fontStyles, blockTypes, resolution) {
this.danmakus = danmakus;
this.title = title;
this.fontStyles = fontStyles;
this.blockTypes = blockTypes;
this.resolution = resolution;
}
generateAss() {
const meta = `
[Script Info]
; Script generated by Bilibili Evolved Danmaku Converter
; https://github.com/the1812/Bilibili-Evolved/
Title: ${this.title}
ScriptType: v4.00+
PlayResX: ${this.resolution.x}
PlayResY: ${this.resolution.y}
Timer: 10.0000
WrapStyle: 2
ScaledBorderAndShadow: no
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
${Object.values(this.fontStyles).join('\n')}
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
`.trim();
return meta + '\n' + this.danmakus
.map(it => it.text(this.fontStyles))
.filter(it => it !== '').join('\n');
}
}
exports.AssDanmakuDocument = AssDanmakuDocument;

View File

@ -1,132 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const xml_danmaku_1 = require("./xml-danmaku");
const ass_danmaku_1 = require("./ass-danmaku");
const danmaku_stack_1 = require("./danmaku-stack");
const danmaku_1 = require("./danmaku");
exports.getDefaultDanmakuConverterConfig = (title) => {
return {
title,
font: "微软雅黑",
alpha: 0.6,
duration: (danmaku) => {
switch (danmaku.type) {
case danmaku_1.DanmakuType.Bottom:
case danmaku_1.DanmakuType.Top:
return 4;
default:
return 6;
}
},
blockTypes: [danmaku_1.DanmakuType.Special, danmaku_1.DanmakuType.Special2],
resolution: {
x: 1920,
y: 1080,
},
bottomMarginPercent: 0.15,
bold: false,
};
};
class DanmakuConverter {
constructor({ title, font, alpha, duration, blockTypes, resolution, bottomMarginPercent, bold }) {
this.title = title;
this.font = font;
this.alpha = Math.round(alpha * 100).toString(16).toUpperCase();
this.duration = duration;
this.blockTypes = blockTypes;
this.resolution = resolution;
this.bold = bold;
this.danmakuStack = new danmaku_stack_1.DanmakuStack(font, resolution, duration, bottomMarginPercent);
}
get fontStyles() {
return {
30: `Style: Large,${this.font},64,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`,
25: `Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`,
18: `Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`
};
}
convertToAssDocument(xml) {
const xmlDanmakuDocument = new xml_danmaku_1.XmlDanmakuDocument(xml);
const assDanmakus = [];
for (const xmlDanmaku of xmlDanmakuDocument.danmakus.sort((a, b) => a.startTime - b.startTime)) {
// 跳过设置为屏蔽的弹幕类型
if (this.blockTypes.indexOf(xmlDanmaku.type) !== -1 ||
this.blockTypes.indexOf('color') !== -1 && xmlDanmaku.color !== DanmakuConverter.white) {
continue;
}
const [startTime, endTime] = this.convertTime(xmlDanmaku.startTime, this.duration(xmlDanmaku));
assDanmakus.push(new ass_danmaku_1.AssDanmaku({
content: this.convertText(xmlDanmaku.content),
time: startTime,
endTime: endTime,
type: xmlDanmaku.type.valueOf().toString(),
fontSize: xmlDanmaku.fontSize.toString(),
color: xmlDanmaku.color.toString(),
typeTag: this.convertType(xmlDanmaku),
colorTag: this.convertColor(xmlDanmaku.color)
}));
}
return new ass_danmaku_1.AssDanmakuDocument(assDanmakus, this.title, this.fontStyles, this.blockTypes, this.resolution);
}
convertText(text) {
const map = {
'{': '',
'}': '',
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&apos;': "'"
};
for (const [key, value] of Object.entries(map)) {
text = text.replace(new RegExp(key, 'g'), value);
}
return text;
}
convertType(danmaku) {
return this.danmakuStack.push(danmaku).tags;
}
convertColor(decColor) {
if (decColor === DanmakuConverter.white) {
return '';
}
const hex = decColor.toString(16);
const red = hex.substring(0, 2);
const green = hex.substring(2, 4);
const blue = hex.substring(4, 6);
return `\\c&H${blue}${green}${red}&`;
}
convertTime(startTime, duration) {
function round(number) {
const [integer, decimal = '00'] = String(number).split('.');
return `${integer.padStart(2, '0')}.${decimal.substr(0, 2).padEnd(2, '0')}`;
}
function secondsToTime(seconds) {
let hours = 0;
let minutes = 0;
while (seconds >= 60) {
seconds -= 60;
minutes++;
}
while (minutes >= 60) {
minutes -= 60;
hours++;
}
return `${hours}:${String(minutes).padStart(2, '0')}:${round(seconds)}`;
}
return [secondsToTime(startTime), secondsToTime(startTime + duration)];
}
}
DanmakuConverter.white = 16777215; // Dec color of white danmaku
exports.DanmakuConverter = DanmakuConverter;
exports.default = {
export: {
AssDanmaku: ass_danmaku_1.AssDanmaku,
AssDanmakuDocument: ass_danmaku_1.AssDanmakuDocument,
Danmaku: danmaku_1.Danmaku,
DanmakuConverter,
DanmakuStack: danmaku_stack_1.DanmakuStack,
XmlDanmaku: xml_danmaku_1.XmlDanmaku,
XmlDanmakuDocument: xml_danmaku_1.XmlDanmakuDocument
}
};

View File

@ -1,2 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -1,186 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const danmaku_1 = require("./danmaku");
// interface MeasureText {
// width(text: string, options: {
// 'font-family': string
// }): number
// }
const measureText = require("bezoerb-measure-text");
class DanmakuStack {
constructor(font, resolution, duration, bottomMarginPercent) {
this.horizontalStack = [];
this.horizontalTrack = [];
this.verticalStack = [];
this.verticalTrack = [];
this.resolution = resolution;
this.duration = duration;
// XML字体大小到实际大小的表
this.fontSizes = {
30: `64px ${font}`,
25: `52px ${font}`,
18: `36px ${font}`
};
this.bottomMarginPercent = bottomMarginPercent;
this.generateTracks();
}
generateTracks() {
const height = 52;
this.danmakuHeight = height;
this.trackHeight = DanmakuStack.margin * 2 + height;
this.trackCount = parseInt(fixed(this.resolution.y * (1 - this.bottomMarginPercent) / this.trackHeight, 0));
}
getTextSize(danmaku) {
const font = this.fontSizes[danmaku.fontSize];
const width = measureText.width(danmaku.content, { 'font-family': font });
const x = width / 2;
return [x, this.danmakuHeight / 2];
}
getTags(danmaku, { targetTrack, initTrackNumber, nextTrackNumber, willOverlay, getTrackItem, getTag }) {
const [x, y] = this.getTextSize(danmaku);
const width = x * 2;
/*
x = this.resolution.x = 屏幕宽度
d = this.duration(danmaku) = 当前弹幕总持续时长(从出现到完全消失)
w = width = 当前弹幕的宽度
delay = DanmakuStack.nextDanmakuDelay = 相邻弹幕间最小的时间间隔
当前弹幕的速度 v = (x + w) / d
完全进入屏幕所需时间 = visibleTime = delay + w / v = delay + wd / (x + w)
*/
const visibleTime = this.duration(danmaku) * width / (this.resolution.x + width) + DanmakuStack.nextDanmakuDelay;
let trackNumber = initTrackNumber;
let overlayDanmaku = null;
// 寻找前面已发送的弹幕中可能重叠的
do {
overlayDanmaku = targetTrack.find(it => willOverlay(it, trackNumber, width));
trackNumber += nextTrackNumber;
} while (overlayDanmaku && trackNumber <= this.trackCount && trackNumber >= 0);
// 如果弹幕过多, 此条就不显示了
if (trackNumber > this.trackCount || trackNumber < 0) {
return `\\pos(0,-999)`;
}
trackNumber -= nextTrackNumber; // 减回最后的自增
targetTrack.push(getTrackItem(trackNumber, width, visibleTime));
return getTag({ trackNumber, x, y });
}
getHorizontalTags(danmaku) {
return this.getTags(danmaku, {
targetTrack: this.horizontalTrack,
initTrackNumber: 0,
nextTrackNumber: 1,
willOverlay: (it, trackNumber, width) => {
if (it.trackNumber !== trackNumber) { // 不同轨道当然不会重叠
return false;
}
if (it.width < width) { // 弹幕比前面的弹幕长, 必须等前面弹幕走完
/*
x = this.resolution.x = 屏幕宽度
d = this.duration(danmaku) = 当前弹幕总持续时长(从出现到完全消失)
w = width = 当前弹幕的宽度
end = it.end = 前面的弹幕结束时间点
start = danmaku.startTime = 当前弹幕的开始时间点
当前弹幕的速度 v = (x + w) / d
当前弹幕碰到左侧边缘需要的时间 t = x / v = dx / (x + w)
当前弹幕碰到左侧边缘的时间点 t = t + start
如果会重叠, 则当前弹幕碰到左边缘时, 前面的弹幕还未结束
t <= end
也就是 start + dx / (x + w) <= end dx / (x + w) <= end - start
*/
return this.duration(danmaku) * this.resolution.x / (this.resolution.x + width) <= it.end - danmaku.startTime;
}
else { // 前面弹幕完全进入屏幕的时间点晚于当前弹幕的开始时间, 就一定会重叠
return it.visible > danmaku.startTime;
}
},
getTrackItem: (trackNumber, width, visibleTime) => {
return {
width: width,
start: danmaku.startTime,
visible: danmaku.startTime + visibleTime,
end: danmaku.startTime + this.duration(danmaku),
trackNumber
};
},
getTag: ({ trackNumber, x, y }) => {
return `\\move(${this.resolution.x + x},${trackNumber * this.trackHeight + DanmakuStack.margin + y},${-x},${trackNumber * this.trackHeight + DanmakuStack.margin + y},0,${this.duration(danmaku) * 1000})`;
}
});
}
getVerticalTags(danmaku) {
const isTop = DanmakuStack.danmakuType[danmaku.type] === 'top';
return this.getTags(danmaku, {
targetTrack: this.verticalTrack,
initTrackNumber: isTop ? 0 : this.trackCount - 1,
nextTrackNumber: isTop ? 1 : -1,
willOverlay: (it, trackNumber) => {
if (it.trackNumber !== trackNumber) {
return false;
}
return it.end > danmaku.startTime;
},
getTrackItem: (trackNumber) => {
return {
start: danmaku.startTime,
end: danmaku.startTime + this.duration(danmaku),
trackNumber
};
},
getTag: ({ trackNumber, y }) => {
if (isTop) {
return `\\pos(${this.resolution.x / 2},${trackNumber * this.trackHeight + DanmakuStack.margin + y})`;
}
else {
return `\\pos(${this.resolution.x / 2},${this.resolution.y - DanmakuStack.margin - y - (this.trackCount - 1 - trackNumber) * this.trackHeight})`;
}
}
});
}
push(danmaku) {
let tags = '';
let stack = [];
switch (DanmakuStack.danmakuType[danmaku.type]) {
case 'normal':
case 'reversed': // 反向先鸽了, 直接当正向了
{
tags = this.getHorizontalTags(danmaku);
stack = this.horizontalStack;
break;
}
case 'top':
case 'bottom':
{
tags = this.getVerticalTags(danmaku);
stack = this.verticalStack;
break;
}
case 'special': // 高级弹幕也鸽了先
default:
{
return {
tags: `\\pos(0,-999)`
};
}
}
const info = {
tags
};
stack.push(info);
return info;
}
}
DanmakuStack.danmakuType = {
[danmaku_1.DanmakuType.Normal]: 'normal',
[danmaku_1.DanmakuType.Normal2]: 'normal',
[danmaku_1.DanmakuType.Normal3]: 'normal',
[danmaku_1.DanmakuType.Bottom]: 'bottom',
[danmaku_1.DanmakuType.Top]: 'top',
[danmaku_1.DanmakuType.Reversed]: 'reversed',
[danmaku_1.DanmakuType.Special]: 'special',
[danmaku_1.DanmakuType.Special2]: 'special'
};
DanmakuStack.margin = 4;
DanmakuStack.nextDanmakuDelay = 0.05;
exports.DanmakuStack = DanmakuStack;

View File

@ -1,24 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DanmakuType;
(function (DanmakuType) {
DanmakuType[DanmakuType["Normal"] = 1] = "Normal";
DanmakuType[DanmakuType["Normal2"] = 2] = "Normal2";
DanmakuType[DanmakuType["Normal3"] = 3] = "Normal3";
DanmakuType[DanmakuType["Bottom"] = 4] = "Bottom";
DanmakuType[DanmakuType["Top"] = 5] = "Top";
DanmakuType[DanmakuType["Reversed"] = 6] = "Reversed";
DanmakuType[DanmakuType["Special"] = 7] = "Special";
DanmakuType[DanmakuType["Special2"] = 8] = "Special2";
})(DanmakuType = exports.DanmakuType || (exports.DanmakuType = {}));
class Danmaku {
constructor({ content, time, type, fontSize, color }) {
this.content = content;
this.time = time;
this.startTime = parseFloat(time);
this.type = parseInt(type);
this.fontSize = parseFloat(fontSize);
this.color = parseInt(color);
}
}
exports.Danmaku = Danmaku;

View File

@ -1,11 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const danmaku_converter_1 = require("./danmaku-converter");
const fs_1 = require("fs");
const config = danmaku_converter_1.getDefaultDanmakuConverterConfig('test');
const input = 'test.xml';
const output = 'test.ass';
const converter = new danmaku_converter_1.DanmakuConverter(config);
const xml = fs_1.readFileSync(input, { encoding: 'utf8' });
const ass = converter.convertToAssDocument(xml).generateAss();
fs_1.writeFileSync(output, ass);

View File

@ -1,30 +0,0 @@
{
"name": "danmaku-converter",
"version": "1.8.0",
"description": "将 bilibili 的 XML 弹幕转换为 ASS 弹幕",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/the1812/Bilibili-Evolved.git"
},
"keywords": [
"danmaku",
"bilibili",
"converter",
"ass",
"xml"
],
"author": "Grant Howard",
"license": "MIT",
"bugs": {
"url": "https://github.com/the1812/Bilibili-Evolved/issues"
},
"homepage": "https://github.com/the1812/Bilibili-Evolved#readme",
"dependencies": {
"@types/node": "^12.0.12",
"text-metrics": "^1.0.1"
}
}

View File

@ -1,154 +0,0 @@
import { XmlDanmaku, XmlDanmakuDocument } from './xml-danmaku'
import { Duration, BlockTypes, Resolution, AssDanmaku, AssDanmakuDocument } from './ass-danmaku'
import { DanmakuStack } from './danmaku-stack'
import { Danmaku, DanmakuType } from './danmaku'
export interface DanmakuConverterConfig {
title: string
font: string
alpha: number
bold: boolean
duration: Duration
blockTypes: BlockTypes
resolution: Resolution
bottomMarginPercent: number
}
export const getDefaultDanmakuConverterConfig = (title: string): DanmakuConverterConfig => {
return {
title,
font: "微软雅黑",
alpha: 0.6,
duration: (danmaku: Danmaku) => {
switch (danmaku.type) {
case DanmakuType.Bottom:
case DanmakuType.Top:
return 4;
default:
return 6;
}
},
blockTypes: [DanmakuType.Special, DanmakuType.Special2],
resolution: {
x: 1920,
y: 1080,
},
bottomMarginPercent: 0.15,
bold: false,
}
}
export class DanmakuConverter {
static white = 16777215 // Dec color of white danmaku
title: string
font: string
alpha: string
duration: Duration
blockTypes: BlockTypes
resolution: Resolution
bold: boolean
danmakuStack: DanmakuStack
constructor({ title, font, alpha, duration, blockTypes, resolution, bottomMarginPercent, bold }: DanmakuConverterConfig) {
this.title = title
this.font = font
this.alpha = Math.round(alpha * 100).toString(16).toUpperCase()
this.duration = duration
this.blockTypes = blockTypes
this.resolution = resolution
this.bold = bold
this.danmakuStack = new DanmakuStack(font, resolution, duration, bottomMarginPercent)
}
get fontStyles() {
return {
30: `Style: Large,${this.font},64,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`,
25: `Style: Medium,${this.font},52,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`,
18: `Style: Small,${this.font},36,&H${this.alpha}FFFFFF,&H${this.alpha}FFFFFF,&H${this.alpha}000000,&H${this.alpha}000000,${this.bold ? '1' : '0'},0,0,0,100,100,0,0,1,1.2,0,5,0,0,0,0`
}
}
convertToAssDocument(xml: string) {
const xmlDanmakuDocument = new XmlDanmakuDocument(xml)
const assDanmakus = []
for (const xmlDanmaku of xmlDanmakuDocument.danmakus.sort((a, b) => a.startTime - b.startTime)) {
// 跳过设置为屏蔽的弹幕类型
if (this.blockTypes.indexOf(xmlDanmaku.type) !== -1 ||
this.blockTypes.indexOf('color') !== -1 && xmlDanmaku.color !== DanmakuConverter.white) {
continue
}
const [startTime, endTime] = this.convertTime(xmlDanmaku.startTime, this.duration(xmlDanmaku))
assDanmakus.push(new AssDanmaku({
content: this.convertText(xmlDanmaku.content),
time: startTime,
endTime: endTime,
type: xmlDanmaku.type.valueOf().toString(),
fontSize: xmlDanmaku.fontSize.toString(),
color: xmlDanmaku.color.toString(),
typeTag: this.convertType(xmlDanmaku),
colorTag: this.convertColor(xmlDanmaku.color)
}))
}
return new AssDanmakuDocument(
assDanmakus,
this.title,
this.fontStyles,
this.blockTypes,
this.resolution
)
}
convertText(text: string) {
const map = {
'{': '',
'}': '',
'&amp;': '&',
'&lt;': '<',
'&gt;': '>',
'&quot;': '"',
'&apos;': "'"
}
for (const [key, value] of Object.entries(map)) {
text = text.replace(new RegExp(key, 'g'), value)
}
return text
}
convertType(danmaku: Danmaku) {
return this.danmakuStack.push(danmaku).tags
}
convertColor(decColor: number) {
if (decColor === DanmakuConverter.white) {
return ''
}
const hex = decColor.toString(16)
const red = hex.substring(0, 2)
const green = hex.substring(2, 4)
const blue = hex.substring(4, 6)
return `\\c&H${blue}${green}${red}&`
}
convertTime(startTime: number, duration: number) {
function round(number: number) {
const [integer, decimal = '00'] = String(number).split('.')
return `${integer.padStart(2, '0')}.${decimal.substr(0, 2).padEnd(2, '0')}`
}
function secondsToTime(seconds: number) {
let hours = 0
let minutes = 0
while (seconds >= 60) {
seconds -= 60
minutes++
}
while (minutes >= 60) {
minutes -= 60
hours++
}
return `${hours}:${String(minutes).padStart(2, '0')}:${round(seconds)}`
}
return [secondsToTime(startTime), secondsToTime(startTime + duration)]
}
}
export default {
export: {
AssDanmaku,
AssDanmakuDocument,
Danmaku,
DanmakuConverter,
DanmakuStack,
XmlDanmaku,
XmlDanmakuDocument
}
}

View File

@ -1,19 +0,0 @@
export interface BasicDanmakuData {
content: string
time: string
type: string
fontSize: string
color: string
}
export interface XmlDanmakuData extends BasicDanmakuData {
timeStamp: string
pool: string
userHash: string
rowId: string
time: string
}
export interface AssDanmakuData extends BasicDanmakuData {
typeTag: string
colorTag: string
endTime: string
}

View File

@ -1,11 +0,0 @@
import { getDefaultDanmakuConverterConfig, DanmakuConverter } from './danmaku-converter'
import { readFileSync, writeFileSync } from 'fs';
const config = getDefaultDanmakuConverterConfig('test')
const input = 'test.xml'
const output = 'test.ass'
const converter = new DanmakuConverter(config)
const xml = readFileSync(input, { encoding: 'utf8' })
const ass = converter.convertToAssDocument(xml).generateAss()
writeFileSync(output, ass)

View File

@ -1,14 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "commonjs",
"noImplicitAny": true,
"strictNullChecks": true,
"sourceMap": false,
"outDir": "./"
},
"include": [
"src/*.ts"
],
"exclude": []
}

View File

@ -1,32 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const danmaku_1 = require("./danmaku");
class XmlDanmaku extends danmaku_1.Danmaku {
constructor({ content, time, type, fontSize, color, timeStamp, pool, userHash, rowId }) {
super({ content, time, type, fontSize, color });
this.timeStamp = parseInt(timeStamp);
this.pool = parseInt(pool);
this.userHash = userHash;
this.rowId = parseInt(rowId);
this.pDataArray = [time, type, fontSize, color, timeStamp, pool, userHash, rowId];
}
text() {
const pData = this.pDataArray.join(',');
return `<d p="${pData}">${this.content}</d>`;
}
static parse(element) {
const pData = element.getAttribute('p');
const [time, type, fontSize, color, timeStamp, pool, userHash, rowId] = pData.split(',');
const content = element.innerHTML;
return new XmlDanmaku({ content, time, type, fontSize, color, timeStamp, pool, userHash, rowId });
}
}
exports.XmlDanmaku = XmlDanmaku;
class XmlDanmakuDocument {
constructor(xml) {
this.xml = xml;
const document = new DOMParser().parseFromString(xml, 'application/xml').documentElement;
this.danmakus = [...document.querySelectorAll('d[p]')].map(it => XmlDanmaku.parse(it));
}
}
exports.XmlDanmakuDocument = XmlDanmakuDocument;

View File

@ -1,17 +0,0 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}\\video-link-downloader.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}

View File

@ -1,5 +0,0 @@
{
"cSpell.words": [
"clipboardy"
]
}

View File

@ -1,3 +0,0 @@
//@ts-check
const colors = require("colors");
console.log("sss".red);

View File

@ -1,20 +0,0 @@
{
"fragments": [
{
"length": 353268,
"size": 143745381,
"url": "https://upos-hz-mirrorcosu.acgvideo.com/upgcxcode/38/59/34625938/34625938-1-80.flv?e=ig8euxZM2rNcNbRVhWUVhwdlhWd17WdVhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEVEuxTEto8i8o859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859r1qXg8gNEVE5XREto8z5JZC2X2gkX5L5F1eTX1jkXlsTXHeux_f2o859IB_&deadline=1556351987&gen=playurl&nbs=1&oi=1879750068&os=cosu&platform=pc&trid=e9e758d7a9714f098e9af07bcbc0ed11&uipk=5&upsig=664c3df7cf72102598d8ece868036d83&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk",
"backupUrls": null
},
{
"length": 468741,
"size": 183172072,
"url": "https://upos-hz-mirrorbsyu.acgvideo.com/upgcxcode/38/59/34625938/34625938-2-80.flv?e=ig8euxZM2rNcNbea7WdVhoMH7zUVhwdEto8g5X10ugNcXBlqNxHxNEVE5XREto8KqJZHUa6m5J0SqE85tZvEuENvNC8xNEVE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==&deadline=1556351987&gen=playurl&nbs=1&oi=1879750068&os=bsyu&platform=pc&trid=e9e758d7a9714f098e9af07bcbc0ed11&uipk=5&upsig=f3c1add5bc4cfc826ee1d75570981725&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk",
"backupUrls": [
"https://upos-hz-mirrorcosu.acgvideo.com/upgcxcode/38/59/34625938/34625938-2-80.flv?e=ig8euxZM2rNcNbea7WdVhoMH7zUVhwdEto8g5X10ugNcXBlqNxHxNEVE5XREto8KqJZHUa6m5J0SqE85tZvEuENvNC8xNEVE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==&deadline=1556351987&gen=playurl&nbs=1&oi=1879750068&os=cosu&platform=pc&trid=e9e758d7a9714f098e9af07bcbc0ed11&uipk=5&upsig=5b0a9b5c35d72eb6c0143add2cc17c8b&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk"
]
}
],
"title": "【3D东方】Subterranean Stars - 正片",
"totalSize": 326917453
}

View File

@ -1,7 +0,0 @@
{
"folder": "src/utils/i18n",
"mainLanguage": "ja-JP",
"targetLanguages": [
"en-US"
]
}

1
min/about.min.css vendored
View File

@ -1 +0,0 @@
.bilibili-evolved-about{height:100%;width:450px;background:#fff;color:#000;position:fixed;top:0;left:0;z-index:100000;transform:translateX(-101%);transition:.3s cubic-bezier(0,.86,.58,1);display:flex;flex-direction:column;box-shadow:4px 0 16px 0 #0000;user-select:none}.gui-settings-dock-right .bilibili-evolved-about{right:0;left:unset;transform:translateX(101%)}body.dark .bilibili-evolved-about{background:#222;color:#eee}.bilibili-evolved-about.opened,.gui-settings-dock-right .bilibili-evolved-about.opened{transform:translateX(0);box-shadow:4px 0 16px 0 #0005}.about-header{padding:32px;display:flex;align-items:center;justify-content:flex-start}.about-header i{margin-right:8px;display:flex}.about-title{font-size:16pt}.about-content{padding:16px 36px 0;margin-bottom:36px;display:flex;flex-direction:column;overflow:auto}.about-content .name{font-size:24pt;display:none;align-items:center}.about-content .name svg{width:100%}body.dark .about-content .name.dark,body:not(.dark) .about-content .name.light{display:flex}.about-content .version{font-size:10pt;font-weight:700;opacity:.6;margin-top:6px;margin-bottom:6px;align-self:center}.about-content .love{font-size:10pt;margin-bottom:24px;align-self:center}.about-content .love a{color:inherit!important}.about-content section{font-size:10pt;margin-top:16px}.about-content section .title{display:flex;justify-content:center;text-transform:uppercase;font-weight:700;font-size:13pt;letter-spacing:3px;margin:8px 0 16px}.about-content section .supporter,.about-content section a{color:var(--theme-color)!important;margin-right:8px;display:inline-flex}.about-content section .supporter{user-select:none}.about-content section .supporter:not(:last-child)::after,.about-content section a:not(:last-child)::after{content:","}@keyframes spinner{to{transform:translate(-50%,-50%) rotate(360deg)}}.about-content section.participants .fetching{margin-right:8px;position:relative;display:inline-flex}.about-content section.participants .fetching::before{content:"Loading..."}

View File

@ -1 +0,0 @@
<div class=bilibili-evolved-about><div class=about-header><i class="mdi mdi-information-outline mdi-24px"></i><span class=about-title>关于</span></div><div class=about-content><p v-if=branch class="name light"v-html=logoImage></p><p v-if=branch class="name dark"v-html=logoImageDark></p><p class=version>v{{version}} · {{clientType}}</p><p class=love><a target=_blank href=https://github.com/the1812/Bilibili-Evolved/ >Made with ❤  </a><a target=_blank href=https://github.com/the1812/Bilibili-Evolved/blob/preview/doc/donate.md>Buy me a coffee ☕</a></p><section class=authors><span class=title>Authors</span><a class=author target=_blank v-for="author of authors"v-bind:href=author.link>{{author.name}}</a></section><section class=contributors><span class=title>Contributors</span><a class=contributor target=_blank v-for="contributor of contributors"v-bind:href=contributor.link>{{contributor.name}}</a></section><section class=supporters><a class=title target=_blank href=https://github.com/the1812/Bilibili-Evolved/blob/preview/doc/donate.md#历史>View Supporters</a></section><section class=participants><span class=title>Community Power</span><span class=fetching v-if=fetching></span><a class=participant target=_blank v-for="participant of participants"v-bind:href=participant.link>{{participant.name}}</a></section><section class=websites><span class=title>Websites</span><a class=website target=_blank v-for="website of websites"v-bind:href=website.link>{{website.name}}</a></section><section class=components><span class=title>Components</span><a class=component target=_blank v-for="component of components"v-bind:href=component.link>{{component.name}}</a></section></div></div>

1
min/about.min.js vendored
View File

@ -1 +0,0 @@
(()=>(e,t)=>{(async()=>{const i=await t.importAsync("aboutHtml");document.body.insertAdjacentHTML("beforeend",i);dq(".bilibili-evolved-about").addEventListener("be:about-load",(()=>{const t=(e,t)=>e.charCodeAt(0)-t.charCodeAt(0);const i=(e,i)=>t(e.name,i.name);const n=GM.info.script.name.match(/Bilibili Evolved \((.*)\)/);const o=n?n[1]:"Stable";new Vue({el:".bilibili-evolved-about",data:{version:e.currentVersion,clientType:o,logoImage:null,logoImageDark:null,branch:null,authors:[{name:"Grant Howard",link:"https://github.com/the1812"},{name:"Coulomb-G",link:"https://github.com/Coulomb-G"}],contributors:[{name:"PleiadeSubaru",link:"https://github.com/Etherrrr"},{name:"Lets-Halloween",link:"https://github.com/Lets-Halloween"},{name:"shugen002",link:"https://github.com/shugen002"},{name:"Joshuaふみひる",link:""},{name:"kdxcxs",link:"https://github.com/kdxcxs"},{name:"JLoeve",link:"https://github.com/LonelySteve"}].sort(i),fetching:true,participants:[],websites:[{name:"GitHub",link:"https://github.com/the1812/Bilibili-Evolved/"},{name:"Greasy Fork",link:"https://greasyfork.org/zh-CN/scripts/373563-bilibili-evolved"}],components:[{name:"Vue.js",link:"https://cn.vuejs.org/index.html"},{name:"Vuex",link:"https://vuex.vuejs.org/zh/"},{name:"JSZip",link:"https://stuk.github.io/jszip/"},{name:"jQuery",link:"http://jquery.com/"},{name:"debounce",link:"https://github.com/component/debounce/"},{name:"Slip.js",link:"https://github.com/kornelski/slip"},{name:"MDI",link:"https://materialdesignicons.com"},{name:"Lodash",link:"https://lodash.com/"}]},mounted(){dq(".bilibili-evolved-about").addEventListener("be:about-load-community",(()=>{this.init()}),{once:true})},methods:{async getLogos(){this.logoImage=await Ajax.getText(`https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/images/bilibili-evolved-wide.svg`);this.logoImageDark=await Ajax.getText(`https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/images/bilibili-evolved-wide-dark.svg`)},async init(){this.branch=/Preview|Local/.test(o)?"preview":"master";this.getLogos();const e=new Set;let t=[];let n=1;do{t=await Ajax.getJson(`https://api.github.com/repos/the1812/Bilibili-Evolved/issues?state=all&direction=asc&per_page=100&page=${n}`).catch((()=>{t=[{name:"电波无法到达(´・_・`)",link:null}]}));n++;for(const i of t){e.add(i.user.login)}}while(t.length>0);this.participants=[...e].map((e=>({name:e,link:`https://github.com/${e}`}))).filter((({link:e})=>!this.authors.some((t=>t.link===e))&&!this.contributors.some((t=>t.link===e)))).sort(i);this.fetching=false}}})}),{once:true})})()})();

View File

@ -1 +0,0 @@
(()=>{return(t,e)=>{class s extends EventTarget{constructor(){super(...arguments);this.cards=[]}addCard(t){if(t instanceof Element&&t.classList.contains("card")){if(t.querySelector(".skeleton")!==null){const e=Observer.childList(t,()=>{if(t.querySelector(".skeleton")===null){e.forEach(t=>t.stop());this.addCard(t)}})}else{const e=this.parseCard(t);this.cards.push(e);const s=new CustomEvent("addCard",{detail:e});this.dispatchEvent(s)}}}removeCard(t){if(t instanceof Element&&t.classList.contains("card")){const e=this.parseCard(t).id;const s=this.cards.findIndex(t=>t.id===e);const r=this.cards[s];this.cards.splice(s,1);const n=new CustomEvent("removeCard",{detail:r});this.dispatchEvent(n)}}parseCard(t){const e=e=>{if(t.querySelector(e)===null){return""}return t.querySelector(e).innerText};const s=t=>{const s=parseInt(e(t));if(isNaN(s)){return 0}return s};const r={id:t.getAttribute("data-did"),username:e(".main-content .user-name"),text:e(".card-content .text.description"),reposts:s(".button-bar .single-button:nth-child(1) .text-offset"),comments:s(".button-bar .single-button:nth-child(2) .text-offset"),likes:s(".button-bar .single-button:nth-child(3) .text-offset")};return r}async startWatching(){const t=await SpinQuery.select(".card-list .content");if(!t){return false}const e=[...t.querySelectorAll(".content>.card")];e.forEach(t=>this.addCard(t));Observer.childList(t,t=>{t.forEach(t=>{t.addedNodes.forEach(t=>this.addCard(t));t.removedNodes.forEach(t=>this.removeCard(t))})});return true}}const r=new s;return{export:{activityCardsManager:r}}}})();

View File

@ -1 +0,0 @@
(()=>(t,e)=>{(async()=>{if(!document.URL.startsWith("https://t.bilibili.com")&&!document.URL.startsWith("space.bilibili.com")){return}const t=t=>{const e=t.querySelector(".image-viewer");if(e===null){console.log(t)}else{e.addEventListener("contextmenu",(()=>{setTimeout((()=>{const t=dq(".pop-message .toast-text");if(t&&t.innerHTML.includes("作者设置了禁止保存")){Toast.success(`<img src="${e.src}" width="200">`,"解除动态存图限制")}}),200)}))}};[...document.body.children].filter((t=>t.classList.contains("photo-imager-container"))).forEach(t);Observer.childList(document.body,(e=>{e.forEach((e=>{const s=[...e.addedNodes].filter((t=>t instanceof Element&&t.classList.contains("photo-imager-container")));s.forEach(t)}))}))})()})();

Some files were not shown because too many files have changed in this diff Show More