Merge branch 'preview-fixes'

This commit is contained in:
the1812 2022-10-20 09:03:42 +08:00
commit 89a70bfd2b
482 changed files with 14141 additions and 11421 deletions

View File

@ -3,5 +3,4 @@ typings/
dist/
dev/
node_modules/
*.config.*
.eslintrc.*

View File

@ -7,6 +7,7 @@ module.exports = {
'plugin:vue/recommended',
'plugin:@typescript-eslint/recommended',
'airbnb-base',
'plugin:prettier/recommended',
],
globals: {
Atomics: 'readonly',
@ -18,8 +19,10 @@ module.exports = {
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: ['vue', '@typescript-eslint'],
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': 'error',
'import/no-unresolved': 'off',
'import/extensions': 'off',
'import/no-extraneous-dependencies': 'off',
@ -72,14 +75,13 @@ module.exports = {
'no-alert': 'off',
'no-restricted-globals': 'off',
'arrow-parens': ['error', 'as-needed'],
'arrow-body-style': 'off',
'prefer-arrow-callback': 'off',
'object-curly-newline': 'off',
semi: ['error', 'never'],
'linebreak-style': 'off',
camelcase: 'off',
'lines-between-class-members': 'off',
radix: ['error', 'as-needed'],
'max-len': 'error',
'max-classes-per-file': 'off',
'prefer-destructuring': [
'error',

View File

@ -25,20 +25,20 @@ jobs:
uses: bahmutov/npm-install@v1
- name: Type check
run: yarn type
run: pnpm run type
- name: ESLint check
run: yarn lint
run: pnpm run lint
- name: Build core
run: yarn build-core
run: pnpm run build-core
- name: Build features
run: |
cd registry
yarn
pnpm install
cd ../
yarn build-features
pnpm run build-features
- name: Git commit
id: commit

View File

@ -23,16 +23,20 @@ jobs:
uses: bahmutov/npm-install@v1
- name: Type check
run: yarn type
run: pnpm run type
- name: ESLint check
run: yarn lint-check
run: pnpm run lint-check
- name: Build core
run: yarn build-core
run: pnpm run build-core
- name: Build features
run: yarn build-features
run: |
cd registry
pnpm install
cd ../
pnpm run build-features
- name: Log
run: echo Check complete.

8
.prettierrc Normal file
View File

@ -0,0 +1,8 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"endOfLine": "auto",
"printWidth": 100
}

10
.vscode/settings.json vendored
View File

@ -68,6 +68,7 @@
"overscroll",
"pako",
"plusplus",
"pnpm",
"Popcap",
"popperjs",
"preload",
@ -106,10 +107,15 @@
"search.exclude": {
"**/dev": true,
"**/dist": true,
"**/yarn.lock": true
"**/pnpm-lock.yaml": true
},
"eslint.format.enable": true,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[vue]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"explorer.fileNesting.patterns": {
"*.ts": "${capture}.js",
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts",

32
.vscode/tasks.json vendored
View File

@ -5,112 +5,112 @@
"tasks": [
{
"type": "shell",
"command": "yarn ts-node ./dev-tools/dev-server/index.ts",
"command": "pnpm ts-node ./dev-tools/dev-server/index.ts",
"group": "build",
"problemMatcher": [],
"label": "启动开发服务 dev-server"
},
{
"type": "shell",
"command": "yarn webpack --config ./webpack/webpack.dev.ts --progress",
"command": "pnpm webpack --config ./webpack/webpack.dev.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "本体:编译开发版本 dev:build-core"
},
{
"type": "shell",
"command": "yarn webpack --watch --config ./webpack/webpack.dev.ts --progress",
"command": "pnpm webpack --watch --config ./webpack/webpack.dev.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "本体:监视开发版本 dev:watch-core"
},
{
"type": "shell",
"command": "yarn serve dist -p ${input:serverPort}",
"command": "pnpm serve dist -p ${input:serverPort}",
"group": "build",
"problemMatcher": [],
"label": "本体:启动服务器 dev:serve-core"
},
{
"type": "shell",
"command": "yarn serve registry/dist -p ${input:serverPort}",
"command": "pnpm serve registry/dist -p ${input:serverPort}",
"group": "build",
"problemMatcher": [],
"label": "功能:启动服务器 dev:serve-features"
},
{
"type": "shell",
"command": "yarn webpack --watch --config ./registry/webpack/components.ts --progress --mode=development",
"command": "pnpm webpack --watch --config ./registry/webpack/components.ts --progress --mode=development",
"group": "build",
"problemMatcher": [],
"label": "功能:监视组件 dev:watch-components"
},
{
"type": "shell",
"command": "yarn webpack --watch --config ./registry/webpack/plugins.ts --progress --mode=development",
"command": "pnpm webpack --watch --config ./registry/webpack/plugins.ts --progress --mode=development",
"group": "build",
"problemMatcher": [],
"label": "功能:监视插件 dev:watch-plugins"
},
{
"type": "shell",
"command": "yarn tsc -p tsconfig.type-check.json --noEmit",
"command": "pnpm tsc -p tsconfig.type-check.json --noEmit",
"group": "build",
"problemMatcher": [],
"label": "生产:类型检查 prod:type"
},
{
"type": "shell",
"command": "yarn --silent webpack --config ./webpack/webpack.prod.ts --profile --json > dist/profile.json && yarn webpack-bundle-analyzer dist/profile.json",
"command": "pnpm --silent webpack --config ./webpack/webpack.prod.ts --profile --json > dist/profile.json && pnpm webpack-bundle-analyzer dist/profile.json",
"group": "build",
"problemMatcher": [],
"label": "本体:打包分析 prod:analyze"
},
{
"type": "shell",
"command": "yarn eslint --cache --cache-location node_modules/.cache/eslint/ './**/*.@(js|ts|vue)'",
"command": "pnpm eslint --cache --cache-location node_modules/.cache/eslint/ './**/*.@(js|ts|vue)'",
"group": "build",
"problemMatcher": [],
"label": "生产:代码检查 prod:lint"
},
{
"type": "shell",
"command": "yarn eslint --cache --cache-location node_modules/.cache/eslint/ --fix './**/*.@(js|ts|vue)'",
"command": "pnpm eslint --cache --cache-location node_modules/.cache/eslint/ --fix './**/*.@(js|ts|vue)'",
"group": "build",
"problemMatcher": [],
"label": "生产:代码修复 prod:lint-fix"
},
{
"type": "shell",
"command": "yarn webpack --config ./webpack/webpack.prod.ts --progress",
"command": "pnpm webpack --config ./webpack/webpack.prod.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "本体:编译生产版本 prod:build-core"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/components.ts --progress",
"command": "pnpm webpack --config ./registry/webpack/components.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译组件 prod:build-components"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/plugins.ts --progress",
"command": "pnpm webpack --config ./registry/webpack/plugins.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译插件 prod:build-plugins"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/all.ts",
"command": "pnpm webpack --config ./registry/webpack/all.ts",
"group": "build",
"problemMatcher": [],
"label": "功能:编译所有 prod:build-features"
},
{
"type": "shell",
"command": "yarn webpack --config ./registry/webpack/docs.ts --progress",
"command": "pnpm webpack --config ./registry/webpack/docs.ts --progress",
"group": "build",
"problemMatcher": [],
"label": "功能:编译功能文档 prod:build-docs"

View File

@ -1,6 +1,40 @@
# 更新日志
## v2.5.0
`2022-10-20`
✨新增
- 新增功能 `隐藏动态评论预览`. (#3322)
> 隐藏动态评论按钮上方的精选评论预览.
- 新增功能 `显示视频投稿时间`. (PR #3727 by [wisokey](https://github.com/wisokey))
> 为视频播放页面的推荐列表中的视频添加显示视频投稿时间.
- 新增功能 `展开选集列表`. (#3380)
> 总是完全展开视频选集列表, 注意对番剧无效.
🐛修复
- 由于 Chrome / Firefox / Safari 均已支持自适应滚动条, `夜间模式` 不再覆盖默认滚动条样式, 设置的组件详情不再隐藏滚动条. (#3370)
- 修复 `下载字幕` 得到的 ASS 文件格式不正确. (#3688)
- 修复 `播放前显示封面` 在视频暂停时仍然显示封面. (#3698)
- `自定义顶栏` 的弹窗改为有焦点时不自动收起, 以防止在其中打字时意外收起. (#3703)
- 修复 `动态过滤器` 的关键词过滤在首页和顶栏中有时无法生效的问题, 以及对转发动态无效的问题.
- 修复 b 站消息会被 `自定义顶栏` 遮挡的问题. (#3702)
- 修复 `动态反折叠` 有时失效的问题.
- 修复 `极简首页` 中合作投稿样式的问题.
- 尝试修复 `document.body is null` 报错导致脚本无法加载的问题. (#3728)
- 修复 `下载弹幕` 无法读取 3.x 播放器的弹幕设置, 以及文件中的弹幕乱序的问题. (#3739)
- 修复 `自定义顶栏` 在搜索页没有正确隐藏原版顶栏. (#3731)
☕开发者相关
- 包管理器更换为 pnpm, **请删除 node_modules 并重新安装依赖 (`pnpm install`)**.
- ESLint 加入了 Prettier 规则. (#3729)
- 更多的组件更换为 define API 声明. (PR #3682, PR #3697 by [timongh](https://github.com/timongh))
- 改善了动态的 `addMenuItem` API 稳定性.
- 添加了 `createPostHook` API, 可以让原函数先执行再让钩子函数执行.
## v2.4.1-preview
`2022-09-18`
包含 v2.4.1 的所有更新内容.
@ -9,6 +43,7 @@
- 由于 Chrome / Firefox / Safari 均已支持自适应滚动条, `夜间模式` 不再覆盖默认滚动条样式, 设置的组件详情不再隐藏滚动条. (#3370)
## v2.4.1
`2022-09-18`
✨新增
- `删除视频弹窗` 支持删除预约弹窗. (#3670)
@ -22,6 +57,7 @@
- `删除广告` 适配新版首页. (#3585)
## v2.4.0
`2022-09-03`
✨新增
<details>
@ -72,6 +108,7 @@
- 适配了 VSCode File Nesting 功能.
## v2.3.3-preview
`2022-08-25`
包含 v2.2.4 的所有更新内容.
@ -79,6 +116,7 @@
- 修复 `UP 主黑名单` 无法添加 UP 主. (#3597, PR #3598 by [snowraincloud](https://github.com/snowraincloud))
## v2.2.4
`2022-08-25`
✨新增
- `自定义顶栏` 适配新版首页的分区栏. (#3585)
@ -96,6 +134,7 @@
- 修复设置中组件空菜单的显示异常. (#3610)
## v2.3.2-preview
`2022-08-14`
包含 v2.2.3 的所有更新内容.

View File

@ -2,15 +2,15 @@
## 搭建开发环境
- 需要安装 [Node.js](https://nodejs.org/en/download/) (>= 14.0), [Visual Studio Code](https://code.visualstudio.com/) 和 [yarn](https://yarnpkg.com/getting-started/install#global-install).
- 需要安装 [Node.js](https://nodejs.org/en/download/) (>= 14.0), [Visual Studio Code](https://code.visualstudio.com/) 和 [pnpm](https://pnpm.io/installation).
- 将项目 Fork 至自己账户后, 克隆至本地
- 分支视情况切换或新建, 新功能以 `preview-features` 为基础分支, 功能修复以 `preview-fixes` 为基础分支.
- 安装依赖:
```powershell
yarn
pnpm install
cd registry
yarn
pnpm install
```
### 本体
@ -142,7 +142,7 @@ yarn
全局变量, 无需 `import` 就可以直接使用. (Tampermonkey API 这里不再列出了, 可根据代码提示使用)
- `Vue`: Vue 库的主对象, 在创建 `.vue` 组件时, 其中的 `<script>` 可以直接使用 `Vue.extend()`
> 出于历史原因, 项目中用的还是 Vue 2, 由于其糟糕的 TypeScript 支持, 在 VS Code + Vetur 的环境下浏览 `.vue` 文件可能会报各种奇奇怪怪的类型错误, 无视就好. (类型是否正确以 `yarn type` 的结果为准)
> 出于历史原因, 项目中用的还是 Vue 2, 由于其糟糕的 TypeScript 支持, 在 VS Code + Vetur 的环境下浏览 `.vue` 文件可能会报各种奇奇怪怪的类型错误, 无视就好. (类型是否正确以 `pnpm run type` 的结果为准)
- `lodash`: 包含所有 Lodash 库提供的方法
- `dq` / `dqa`: `document.querySelector``document.querySelectorAll` 的简写, `dqa` 会返回真实数组

View File

@ -4,11 +4,8 @@ interface DevServerConfig {
port?: number
maxWatchers?: number
}
const configFile = (path: string) => () => (
existsSync(path)
? JSON.parse(readFileSync(path, { encoding: 'utf-8' }))
: {}
)
const configFile = (path: string) => () =>
existsSync(path) ? JSON.parse(readFileSync(path, { encoding: 'utf-8' })) : {}
const configSource: (() => DevServerConfig)[] = [
() => ({
port: 23333,
@ -16,6 +13,7 @@ const configSource: (() => DevServerConfig)[] = [
}),
configFile('dev/dev-server.json'),
]
export const devServerConfig = configSource.reduce((previous, current) => (
{ ...previous, ...current() }
), {} as DevServerConfig)
export const devServerConfig = configSource.reduce(
(previous, current) => ({ ...previous, ...current() }),
{} as DevServerConfig,
)

View File

@ -4,20 +4,26 @@ import webpackConfig from '../../webpack/webpack.dev'
import { sendMessage } from './web-socket-server'
import { defaultWatcherHandler } from './watcher-common'
export const startCoreWatcher = () => new Promise<void>(resolve => {
const compiler = webpack(webpackConfig as webpack.Configuration)
console.log('本体编译中...')
const instance = compiler.watch({}, defaultWatcherHandler(
() => resolve(),
result => {
console.log('本体已编译:', result.hash)
sendMessage({
type: 'coreUpdate',
})
},
))
exitHook(exit => instance.close(() => {
console.log('本体编译器已退出')
exit()
}))
})
export const startCoreWatcher = () =>
new Promise<void>(resolve => {
const compiler = webpack(webpackConfig as webpack.Configuration)
console.log('本体编译中...')
const instance = compiler.watch(
{},
defaultWatcherHandler(
() => resolve(),
result => {
console.log('本体已编译:', result.hash)
sendMessage({
type: 'coreUpdate',
})
},
),
)
exitHook(exit =>
instance.close(() => {
console.log('本体编译器已退出')
exit()
}),
)
})

View File

@ -18,14 +18,13 @@ export type QuerySessionsResponsePayload = PayloadBase<'querySessionsResponse'>
}
export type StopPayload = PayloadBase<'stop'>
export type Payload = (
StartPayload |
CoreUpdatePayload |
ItemUpdatePayload |
StopPayload |
ItemStopPayload |
QuerySessionsPayload |
QuerySessionsResponsePayload
)
export type Payload =
| StartPayload
| CoreUpdatePayload
| ItemUpdatePayload
| StopPayload
| ItemStopPayload
| QuerySessionsPayload
| QuerySessionsResponsePayload
export type MessageHandler<P extends Payload = Payload> = (payload: P) => void

View File

@ -34,24 +34,27 @@ export const stopInstance = (instance: Watching, onClose: () => void) => {
}
}
export const startRegistryWatcher = (url: string, config: Configuration) => new Promise<void>(
resolve => {
export const startRegistryWatcher = (url: string, config: Configuration) =>
new Promise<void>(resolve => {
console.log(`功能编译中... ${url}`)
const { maxWatchers } = devServerConfig
const watcher = webpack(config)
const instance = watcher.watch({}, defaultWatcherHandler(
() => {
resolve()
},
result => {
console.log('功能已编译:', result.hash, url)
sendMessage({
type: 'itemUpdate',
path: url,
sessions: watchers.map(it => it.url),
})
},
))
const instance = watcher.watch(
{},
defaultWatcherHandler(
() => {
resolve()
},
result => {
console.log('功能已编译:', result.hash, url)
sendMessage({
type: 'itemUpdate',
path: url,
sessions: watchers.map(it => it.url),
})
},
),
)
exitHook(exit => {
if (!instance.closed) {
instance.close(() => {
@ -63,9 +66,10 @@ export const startRegistryWatcher = (url: string, config: Configuration) => new
if (watchers.length >= maxWatchers) {
const oldInstance = watchers.shift()
stopInstance(oldInstance.instance, () => {
console.log(`已达到 maxWatchers 数量 (${maxWatchers}), 退出了功能编译器: ${oldInstance.url}`)
console.log(
`已达到 maxWatchers 数量 (${maxWatchers}), 退出了功能编译器: ${oldInstance.url}`,
)
})
}
watchers.push({ url, instance })
},
)
})

View File

@ -7,57 +7,54 @@ import { buildByEntry } from '../../registry/webpack/config'
import { exitWebSocketServer } from './web-socket-server'
import { watchers, parseRegistryUrl, startRegistryWatcher } from './registry-watcher'
export const startDevServer = () => new Promise<Server>(resolve => {
const { port } = devServerConfig
export const startDevServer = () =>
new Promise<Server>(resolve => {
const { port } = devServerConfig
const server = createServer((request, response) => {
const { url } = request
console.log('请求:', url)
const callHandler = () => {
handler(request, response, {
public: '.',
directoryListing: [
'/dist',
'/dist/**',
'/registry/dist',
'/registry/dist/**',
],
})
}
if (url.startsWith('/registry')) {
const existingWatcher = watchers.find(w => w.url === url)
const registryInfo = parseRegistryUrl(url)
if (existingWatcher && registryInfo) {
console.log(`已复用功能编译器: ${url}`)
const server = createServer((request, response) => {
const { url } = request
console.log('请求:', url)
const callHandler = () => {
handler(request, response, {
public: '.',
directoryListing: ['/dist', '/dist/**', '/registry/dist', '/registry/dist/**'],
})
}
if (existingWatcher || !registryInfo) {
callHandler()
if (url.startsWith('/registry')) {
const existingWatcher = watchers.find(w => w.url === url)
const registryInfo = parseRegistryUrl(url)
if (existingWatcher && registryInfo) {
console.log(`已复用功能编译器: ${url}`)
}
if (existingWatcher || !registryInfo) {
callHandler()
} else {
startRegistryWatcher(
url,
buildByEntry({
...registryInfo,
mode: 'development',
}) as Configuration,
).then(() => callHandler())
}
} else {
startRegistryWatcher(url, buildByEntry({
...registryInfo,
mode: 'development',
}) as Configuration).then(
() => callHandler(),
)
callHandler()
}
} else {
callHandler()
}
})
exitHook(exit => {
exitWebSocketServer()
server.close(error => {
if (error) {
console.error(error)
})
exitHook(exit => {
exitWebSocketServer()
server.close(error => {
if (error) {
console.error(error)
exit()
return
}
console.log('DevServer 已退出')
exit()
return
}
console.log('DevServer 已退出')
exit()
})
})
server.listen(port, () => {
console.log(`DevServer 已启动, 端口: ${port}`)
resolve(server)
})
})
server.listen(port, () => {
console.log(`DevServer 已启动, 端口: ${port}`)
resolve(server)
})
})

View File

@ -15,13 +15,15 @@ export const defaultWatcherHandler = (
}
const needLogging = result.hasErrors() || result.hasWarnings()
if (needLogging) {
console.log(result.toString({
hash: false,
assets: false,
modules: false,
chunks: false,
color: true,
}))
console.log(
result.toString({
hash: false,
assets: false,
modules: false,
chunks: false,
color: true,
}),
)
}
if (result.hasErrors()) {
lastHash = ''

View File

@ -22,45 +22,48 @@ export const exitWebSocketServer = () => {
sendMessage({ type: 'stop' })
server.clients.forEach(c => c.close())
}
export const startWebSocketServer = (httpServer: Server) => new Promise<void>(resolve => {
server = new WebSocketServer({ server: httpServer })
server.on('connection', client => {
sendMessage({ type: 'start', sessions: watchers.map(it => it.url) })
client.on('message', data => {
try {
const payload: Payload = JSON.parse(data.toString())
console.log('收到 DevClient 消息:', payload)
switch (payload.type) {
default: {
break
}
case 'itemStop': {
const { path } = payload
const watcherIndex = watchers.findIndex(it => it.url === path)
if (watcherIndex !== -1) {
const [watcher] = watchers.splice(watcherIndex, 1)
stopInstance(watcher.instance, () => {
console.log(`功能编译器已退出: ${watcher.url}`)
})
export const startWebSocketServer = (httpServer: Server) =>
new Promise<void>(resolve => {
server = new WebSocketServer({ server: httpServer })
server.on('connection', client => {
sendMessage({ type: 'start', sessions: watchers.map(it => it.url) })
client.on('message', data => {
try {
const payload: Payload = JSON.parse(data.toString())
console.log('收到 DevClient 消息:', payload)
switch (payload.type) {
default: {
break
}
case 'itemStop': {
const { path } = payload
const watcherIndex = watchers.findIndex(it => it.url === path)
if (watcherIndex !== -1) {
const [watcher] = watchers.splice(watcherIndex, 1)
stopInstance(watcher.instance, () => {
console.log(`功能编译器已退出: ${watcher.url}`)
})
}
break
}
case 'querySessions': {
sendMessage({ type: 'querySessionsResponse', sessions: watchers.map(it => it.url) })
break
}
break
}
case 'querySessions': {
sendMessage({ type: 'querySessionsResponse', sessions: watchers.map(it => it.url) })
break
}
} catch (error) {
console.error('无效信息', data)
}
} catch (error) {
console.error('无效信息', data)
}
})
})
server.on('error', error => console.error(error))
exitHook(exit =>
server.close(error => {
if (error) {
console.error(error)
}
exit()
}),
)
resolve()
})
server.on('error', error => console.error(error))
exitHook(exit => server.close(error => {
if (error) {
console.error(error)
}
exit()
}))
resolve()
})

View File

@ -11,44 +11,53 @@ const parseAliPay = (csv: Record<string, string>[]) => {
name += `${item.} `
}
name += `${item.} ${item.}`
return `| ${item..replace(/-/g, '.')} | ${name} | ${item..substring(item..length - 4)} | ¥${item['订单金额(元)']} |`
return `| ${item..replace(/-/g, '.')} | ${name} | ${item..substring(
item..length - 4,
)} | ¥${item['订单金额(元)']} |`
}
})
return csv
}
const parseWeChat = (csv: Record<string, string>[]) => {
const items = csv.filter(item => item. === '赞赏码').map(item => ({
...item,
sortKey: Number(new Date(item.)).toString(),
toString: () => {
let name = item.
if (name === '/') {
name = '匿名'
}
const noteMatch = item..match(/付款方留言:(.+)/)
if (noteMatch) {
name += ` ${noteMatch[1]}`
}
if (item..trim() !== '/') {
name += ` ${item.}`
}
item. = item..trim()
console.log(item, item.)
return `| ${item..replace(/-/g, '.')} | ${name} | ${item..substring(item..length - 4)} | ${item['金额(元)']} |`
},
}))
const items = csv
.filter(item => item. === '赞赏码')
.map(item => ({
...item,
sortKey: Number(new Date(item.)).toString(),
toString: () => {
let name = item.
if (name === '/') {
name = '匿名'
}
const noteMatch = item..match(/付款方留言:(.+)/)
if (noteMatch) {
name += ` ${noteMatch[1]}`
}
if (item..trim() !== '/') {
name += ` ${item.}`
}
item. = item..trim()
console.log(item, item.)
return `| ${item..replace(/-/g, '.')} | ${name} | ${item..substring(
item..length - 4,
)} | ${item['金额(元)']} |`
},
}))
return items
}
const items = files.map(file => {
const text = fs.readFileSync(file, { encoding: 'utf-8' })
const csv = parse(text, { columns: true })
if (file.includes('支付宝')) {
return parseAliPay(csv)
}
if (file.includes('微信')) {
return parseWeChat(csv)
}
console.warn(`not parse method for ${file}`)
return []
}).flat().sort((a, b) => parseInt(b.sortKey) - parseInt(a.sortKey))
const items = files
.map(file => {
const text = fs.readFileSync(file, { encoding: 'utf-8' })
const csv = parse(text, { columns: true })
if (file.includes('支付宝')) {
return parseAliPay(csv)
}
if (file.includes('微信')) {
return parseWeChat(csv)
}
console.warn(`not parse method for ${file}`)
return []
})
.flat()
.sort((a, b) => parseInt(b.sortKey) - parseInt(a.sortKey))
fs.outputFileSync('dist/output.md', items.join('\n'))

225
dev-tools/donate-table/pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,225 @@
lockfileVersion: 5.4
specifiers:
'@types/fs-extra': ^9.0.13
'@types/node': ^17.0.38
csv-parse: ^4.15.4
fs-extra: ^10.1.0
ts-node: ^10.8.0
typescript: ^4.7.2
dependencies:
csv-parse: registry.npmmirror.com/csv-parse/4.15.4
fs-extra: registry.npmmirror.com/fs-extra/10.1.0
devDependencies:
'@types/fs-extra': registry.npmmirror.com/@types/fs-extra/9.0.13
'@types/node': registry.npmmirror.com/@types/node/17.0.38
ts-node: registry.npmmirror.com/ts-node/10.8.0_h77muqpegcwcauif74p6js2ti4
typescript: registry.npmmirror.com/typescript/4.7.2
packages:
registry.npmmirror.com/@cspotcode/source-map-support/0.8.1:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz}
name: '@cspotcode/source-map-support'
version: 0.8.1
engines: {node: '>=12'}
dependencies:
'@jridgewell/trace-mapping': registry.npmmirror.com/@jridgewell/trace-mapping/0.3.9
dev: true
registry.npmmirror.com/@jridgewell/resolve-uri/3.0.7:
resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz}
name: '@jridgewell/resolve-uri'
version: 3.0.7
engines: {node: '>=6.0.0'}
dev: true
registry.npmmirror.com/@jridgewell/sourcemap-codec/1.4.13:
resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz}
name: '@jridgewell/sourcemap-codec'
version: 1.4.13
dev: true
registry.npmmirror.com/@jridgewell/trace-mapping/0.3.9:
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz}
name: '@jridgewell/trace-mapping'
version: 0.3.9
dependencies:
'@jridgewell/resolve-uri': registry.npmmirror.com/@jridgewell/resolve-uri/3.0.7
'@jridgewell/sourcemap-codec': registry.npmmirror.com/@jridgewell/sourcemap-codec/1.4.13
dev: true
registry.npmmirror.com/@tsconfig/node10/1.0.8:
resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.8.tgz}
name: '@tsconfig/node10'
version: 1.0.8
dev: true
registry.npmmirror.com/@tsconfig/node12/1.0.9:
resolution: {integrity: sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.9.tgz}
name: '@tsconfig/node12'
version: 1.0.9
dev: true
registry.npmmirror.com/@tsconfig/node14/1.0.1:
resolution: {integrity: sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.1.tgz}
name: '@tsconfig/node14'
version: 1.0.1
dev: true
registry.npmmirror.com/@tsconfig/node16/1.0.2:
resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.2.tgz}
name: '@tsconfig/node16'
version: 1.0.2
dev: true
registry.npmmirror.com/@types/fs-extra/9.0.13:
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz}
name: '@types/fs-extra'
version: 9.0.13
dependencies:
'@types/node': registry.npmmirror.com/@types/node/17.0.38
dev: true
registry.npmmirror.com/@types/node/17.0.38:
resolution: {integrity: sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-17.0.38.tgz}
name: '@types/node'
version: 17.0.38
dev: true
registry.npmmirror.com/acorn-walk/8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz}
name: acorn-walk
version: 8.2.0
engines: {node: '>=0.4.0'}
dev: true
registry.npmmirror.com/acorn/8.7.1:
resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn/-/acorn-8.7.1.tgz}
name: acorn
version: 8.7.1
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
registry.npmmirror.com/arg/4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz}
name: arg
version: 4.1.3
dev: true
registry.npmmirror.com/create-require/1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz}
name: create-require
version: 1.1.1
dev: true
registry.npmmirror.com/csv-parse/4.15.4:
resolution: {integrity: sha512-OdBbFc0yZhOm17lSxqkirrHlFFVpKRT0wp4DAGoJelsP3LbGzV9LNr7XmM/lrr0uGkCtaqac9UhP8PDHXOAbMg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/csv-parse/-/csv-parse-4.15.4.tgz}
name: csv-parse
version: 4.15.4
dev: false
registry.npmmirror.com/diff/4.0.2:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/diff/-/diff-4.0.2.tgz}
name: diff
version: 4.0.2
engines: {node: '>=0.3.1'}
dev: true
registry.npmmirror.com/fs-extra/10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz}
name: fs-extra
version: 10.1.0
engines: {node: '>=12'}
dependencies:
graceful-fs: registry.npmmirror.com/graceful-fs/4.2.10
jsonfile: registry.npmmirror.com/jsonfile/6.1.0
universalify: registry.npmmirror.com/universalify/2.0.0
dev: false
registry.npmmirror.com/graceful-fs/4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz}
name: graceful-fs
version: 4.2.10
dev: false
registry.npmmirror.com/jsonfile/6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz}
name: jsonfile
version: 6.1.0
dependencies:
universalify: registry.npmmirror.com/universalify/2.0.0
optionalDependencies:
graceful-fs: registry.npmmirror.com/graceful-fs/4.2.10
dev: false
registry.npmmirror.com/make-error/1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz}
name: make-error
version: 1.3.6
dev: true
registry.npmmirror.com/ts-node/10.8.0_h77muqpegcwcauif74p6js2ti4:
resolution: {integrity: sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ts-node/-/ts-node-10.8.0.tgz}
id: registry.npmmirror.com/ts-node/10.8.0
name: ts-node
version: 10.8.0
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
'@types/node': '*'
typescript: '>=2.7'
peerDependenciesMeta:
'@swc/core':
optional: true
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': registry.npmmirror.com/@cspotcode/source-map-support/0.8.1
'@tsconfig/node10': registry.npmmirror.com/@tsconfig/node10/1.0.8
'@tsconfig/node12': registry.npmmirror.com/@tsconfig/node12/1.0.9
'@tsconfig/node14': registry.npmmirror.com/@tsconfig/node14/1.0.1
'@tsconfig/node16': registry.npmmirror.com/@tsconfig/node16/1.0.2
'@types/node': registry.npmmirror.com/@types/node/17.0.38
acorn: registry.npmmirror.com/acorn/8.7.1
acorn-walk: registry.npmmirror.com/acorn-walk/8.2.0
arg: registry.npmmirror.com/arg/4.1.3
create-require: registry.npmmirror.com/create-require/1.1.1
diff: registry.npmmirror.com/diff/4.0.2
make-error: registry.npmmirror.com/make-error/1.3.6
typescript: registry.npmmirror.com/typescript/4.7.2
v8-compile-cache-lib: registry.npmmirror.com/v8-compile-cache-lib/3.0.1
yn: registry.npmmirror.com/yn/3.1.1
dev: true
registry.npmmirror.com/typescript/4.7.2:
resolution: {integrity: sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typescript/-/typescript-4.7.2.tgz}
name: typescript
version: 4.7.2
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
registry.npmmirror.com/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz}
name: universalify
version: 2.0.0
engines: {node: '>= 10.0.0'}
dev: false
registry.npmmirror.com/v8-compile-cache-lib/3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz}
name: v8-compile-cache-lib
version: 3.0.1
dev: true
registry.npmmirror.com/yn/3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz}
name: yn
version: 3.1.1
engines: {node: '>=6'}
dev: true

View File

@ -1,157 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.0.7"
resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe"
integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.13"
resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c"
integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@tsconfig/node10@^1.0.7":
version "1.0.8"
resolved "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
"@tsconfig/node12@^1.0.7":
version "1.0.9"
resolved "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
"@tsconfig/node14@^1.0.0":
version "1.0.1"
resolved "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
"@tsconfig/node16@^1.0.2":
version "1.0.2"
resolved "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
"@types/fs-extra@^9.0.13":
version "9.0.13"
resolved "https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45"
integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@^17.0.38":
version "17.0.38"
resolved "https://registry.npmmirror.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947"
integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^8.4.1:
version "8.7.1"
resolved "https://registry.npmmirror.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
csv-parse@^4.15.4:
version "4.15.4"
resolved "https://registry.npm.taobao.org/csv-parse/download/csv-parse-4.15.4.tgz#ad1ec62aaf71a642982dfcb81f1848184d691db5"
integrity sha1-rR7GKq9xpkKYLfy4HxhIGE1pHbU=
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.npmmirror.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
ts-node@^10.8.0:
version "10.8.0"
resolved "https://registry.npmmirror.com/ts-node/-/ts-node-10.8.0.tgz#3ceb5ac3e67ae8025c1950626aafbdecb55d82ce"
integrity sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
typescript@^4.7.2:
version "4.7.2"
resolved "https://registry.npmmirror.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4"
integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
yn@3.1.1:
version "3.1.1"
resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==

View File

@ -33,7 +33,7 @@ CDN 配置位于 `webpack/cdn/`, 可在目录下新建一个文件, 导出一个
## 编译
运行 `本体:编译生产版本` 任务 (`yarn webpack --config ./webpack/webpack.prod.ts --progress`).
运行 `本体:编译生产版本` 任务 (`pnpm webpack --config ./webpack/webpack.prod.ts --progress`).
会得到:
- 正式版: `dist\bilibili-evolved.user.js`

View File

@ -4,7 +4,6 @@
如需匿名或使用昵称请在备注中写明哦.
## 爱发电
> 之前的支付宝付款码有点问题, 现已弃用 (不必担心, 转账均已收到), 在爱发电中仍然可以选择支付宝作为付款方式.
<a href="https://afdian.net/@the1812" target="_blank">
<img alt="爱发电" src="../images/compressed/afdian.jpg" width="400">
@ -29,6 +28,11 @@ https://afdian.net/@the1812?tab=sponsor
| 时间 | 用户名 | 单号后4位 | 金额 |
| ------------------- | ---------------- | --------- | ------- |
| 2022.10.19 09:57:04 | 匿名 | 5144 | ¥10.00 |
| 2022.10.15 23:02:58 | *魁 | 3578 | ¥10.00 |
| 2022.09.29 22:59:20 | 匿名 | 8240 | ¥8.88 |
| 2022.09.21 19:31:43 | *笑 | 8884 | ¥5.00 |
| 2022.09.20 01:16:58 | *安 | 1905 | ¥10.00 |
| 2022.09.14 13:22:43 | 匿名 | 0778 | ¥5.00 |
| 2022.09.12 21:42:03 | 匿名 | 9234 | ¥5.00 |
| 2022.09.06 14:08:08 | *轩 | 6451 | ¥10.00 |

View File

@ -63,6 +63,14 @@
"fullRelativePath": "../../registry/dist/components/feeds/full-title.js",
"fullAbsolutePath": "registry/dist/components/feeds/full-title.js"
},
{
"type": "component",
"name": "hideFeedsCommentPreview",
"displayName": "隐藏动态评论预览",
"description": "隐藏动态评论按钮上方的精选评论预览. (详细可看 [#3322](https://github.com/the1812/Bilibili-Evolved/discussions/3322))\r\n",
"fullRelativePath": "../../registry/dist/components/feeds/hide-comment-preview.js",
"fullAbsolutePath": "registry/dist/components/feeds/hide-comment-preview.js"
},
{
"type": "component",
"name": "unfoldFeeds",
@ -547,7 +555,7 @@
"type": "component",
"name": "downloadVideo",
"displayName": "下载视频",
"description": "在功能面板中添加下载视频支持. 请注意不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.",
"description": "在功能面板中添加下载视频支持. 请注意:\r\n- 不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.\r\n- 请勿短时间进行大量下载, 以免遭到 b 站 IP 封禁.\r\n",
"fullRelativePath": "../../registry/dist/components/video/download.js",
"fullAbsolutePath": "registry/dist/components/video/download.js"
},
@ -559,6 +567,14 @@
"fullRelativePath": "../../registry/dist/components/video/full-description.js",
"fullAbsolutePath": "registry/dist/components/video/full-description.js"
},
{
"type": "component",
"name": "fullEpisodeTitle",
"displayName": "展开选集列表",
"description": "总是完全展开视频选集列表, 注意对番剧无效.\r\n",
"fullRelativePath": "../../registry/dist/components/video/full-episode-list.js",
"fullAbsolutePath": "registry/dist/components/video/full-episode-list.js"
},
{
"type": "component",
"name": "fullEpisodeTitle",
@ -687,6 +703,14 @@
"fullRelativePath": "../../registry/dist/components/video/player/show-cover.js",
"fullAbsolutePath": "registry/dist/components/video/player/show-cover.js"
},
{
"type": "component",
"name": "showUploadTime",
"displayName": "显示视频投稿时间",
"description": "by [@wisokey](https://github.com/wisokey)\n\n为视频播放页面的推荐列表中的视频添加显示视频投稿时间.",
"fullRelativePath": "../../registry/dist/components/video/player/show-upload-time.js",
"fullAbsolutePath": "registry/dist/components/video/player/show-upload-time.js"
},
{
"type": "component",
"name": "skipChargeList",

View File

@ -74,6 +74,15 @@
在顶栏的视频动态中, 无论标题多长总是完全展开.
### [隐藏动态评论预览](../../registry/dist/components/feeds/hide-comment-preview.js)
`hideFeedsCommentPreview`
**AltCdn:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/feeds/hide-comment-preview.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/feeds/hide-comment-preview.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/feeds/hide-comment-preview.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/feeds/hide-comment-preview.js)
隐藏动态评论按钮上方的精选评论预览. (详细可看 [#3322](https://github.com/the1812/Bilibili-Evolved/discussions/3322))
### [动态反折叠](../../registry/dist/components/feeds/unfold.js)
`unfoldFeeds`
@ -703,7 +712,9 @@ by [@kdxcxs](https://github.com/kdxcxs)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/download.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/download.js)
在功能面板中添加下载视频支持. 请注意不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.
在功能面板中添加下载视频支持. 请注意:
- 不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.
- 请勿短时间进行大量下载, 以免遭到 b 站 IP 封禁.
### [展开视频简介](../../registry/dist/components/video/full-description.js)
`fullVideoDescription`
@ -714,6 +725,15 @@ by [@kdxcxs](https://github.com/kdxcxs)
总是展开完整的视频简介.
### [展开选集列表](../../registry/dist/components/video/full-episode-list.js)
`fullEpisodeTitle`
**AltCdn:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/full-episode-list.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/full-episode-list.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/full-episode-list.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/full-episode-list.js)
总是完全展开视频选集列表, 注意对番剧无效.
### [展开选集标题](../../registry/dist/components/video/full-episode-title.js)
`fullEpisodeTitle`
@ -908,6 +928,17 @@ by [@JLoeve](https://github.com/LonelySteve)
在视频开始播放前, 在播放器中显示封面.
### [显示视频投稿时间](../../registry/dist/components/video/player/show-upload-time.js)
`showUploadTime`
**AltCdn:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/player/show-upload-time.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/player/show-upload-time.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/player/show-upload-time.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/player/show-upload-time.js)
by [@wisokey](https://github.com/wisokey)
为视频播放页面的推荐列表中的视频添加显示视频投稿时间.
### [跳过充电鸣谢](../../registry/dist/components/video/player/skip-charge-list.js)
`skipChargeList`

View File

@ -124,7 +124,7 @@
"type": "component",
"name": "downloadVideo",
"displayName": "下载视频",
"description": "在功能面板中添加下载视频支持. 请注意不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.",
"description": "在功能面板中添加下载视频支持. 请注意:\r\n- 不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的.\r\n- 请勿短时间进行大量下载, 以免遭到 b 站 IP 封禁.\r\n",
"fullRelativePath": "../../registry/dist/components/video/download.js",
"fullAbsolutePath": "registry/dist/components/video/download.js"
},

View File

@ -8,8 +8,8 @@
"scripts": {
"build-core": "webpack --config ./webpack/webpack.prod.ts --bail",
"build-features": "webpack --config ./registry/webpack/all.ts --bail",
"lint": "eslint --config ./.eslintrc.js --quiet --fix \"./**/*.@(js|ts|vue)\"",
"lint-check": "eslint --config ./.eslintrc.js \"./**/*.@(js|ts|vue)\"",
"lint": "eslint --quiet --fix . --ext .ts,.vue",
"lint-check": "eslint . --ext .ts,.vue",
"type": "tsc -p tsconfig.type-check.json --noEmit"
},
"devDependencies": {
@ -38,12 +38,15 @@
"css-loader": "^5.0.0",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "7.1.0",
"fast-sass-loader": "^2.0.0",
"postcss": "^8.1.0",
"postcss-loader": "^4.0.4",
"postcss-preset-env": "^7.5.0",
"prettier": "^2.7.1",
"sass": "^1.25.0",
"serve": "^13.0.2",
"serve-handler": "^6.1.3",

7489
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,194 @@
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["video/full-episode-list"] = factory();
else
root["video/full-episode-list"] = factory();
})(self, function() {
return /******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./registry/lib/components/video/full-episode-list/index.ts":
/*!******************************************************************!*\
!*** ./registry/lib/components/video/full-episode-list/index.ts ***!
\******************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"component\": function() { return /* binding */ component; }\n/* harmony export */ });\n/* harmony import */ var _components_define__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/components/define */ \"@/components/define\");\n/* harmony import */ var _components_define__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_components_define__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils/urls */ \"@/core/utils/urls\");\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils_urls__WEBPACK_IMPORTED_MODULE_1__);\n\n\nconst name = 'fullEpisodeTitle';\nconst component = (0,_components_define__WEBPACK_IMPORTED_MODULE_0__.defineComponentMetadata)({\n name,\n instantStyles: [{\n name,\n style: () => Promise.resolve(/*! import() */).then(__webpack_require__.t.bind(__webpack_require__, /*! ./full-episode-list.scss */ \"./registry/lib/components/video/full-episode-list/full-episode-list.scss\", 23))\n }],\n entry: none,\n displayName: '展开选集列表',\n description: {\n 'zh-CN': '总是完全展开视频选集列表, 注意对番剧无效.'\n },\n tags: [componentsTags.video, componentsTags.style],\n urlInclude: _core_utils_urls__WEBPACK_IMPORTED_MODULE_1__.videoUrls,\n commitHash: \"a6f5decfee70c9a5c8a1779f2c44362dc9ad8da0\",\n coreVersion: \"2.4.1\"\n});\n\n//# sourceURL=webpack://@bevo/core/./registry/lib/components/video/full-episode-list/index.ts?");
/***/ }),
/***/ "./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[1]!./node_modules/.pnpm/registry.npmmirror.com+postcss-loader@4.3.0_g4najheu5gwop3kphiif6aqpde/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[2]!./node_modules/.pnpm/registry.npmmirror.com+fast-sass-loader@2.0.1_sass@1.51.0+webpack@5.72.0/node_modules/fast-sass-loader/lib/index.js??clonedRuleSet-19[0].rules[0].use[3]!./registry/lib/components/video/full-episode-list/full-episode-list.scss":
/*!********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[1]!./node_modules/.pnpm/registry.npmmirror.com+postcss-loader@4.3.0_g4najheu5gwop3kphiif6aqpde/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[2]!./node_modules/.pnpm/registry.npmmirror.com+fast-sass-loader@2.0.1_sass@1.51.0+webpack@5.72.0/node_modules/fast-sass-loader/lib/index.js??clonedRuleSet-19[0].rules[0].use[3]!./registry/lib/components/video/full-episode-list/full-episode-list.scss ***!
\********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../../node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/runtime/api.js\");\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".video-sections-content-list {\\n max-height: unset !important;\\n height: auto !important;\\n}\\n.video-sections-content-list .video-section-list {\\n height: auto !important;\\n}\", \"\"]);\n// Exports\nmodule.exports = ___CSS_LOADER_EXPORT___;\n\n\n//# sourceURL=webpack://@bevo/core/./registry/lib/components/video/full-episode-list/full-episode-list.scss?./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/cjs.js??clonedRuleSet-19%5B0%5D.rules%5B0%5D.use%5B1%5D!./node_modules/.pnpm/registry.npmmirror.com+postcss-loader@4.3.0_g4najheu5gwop3kphiif6aqpde/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-19%5B0%5D.rules%5B0%5D.use%5B2%5D!./node_modules/.pnpm/registry.npmmirror.com+fast-sass-loader@2.0.1_sass@1.51.0+webpack@5.72.0/node_modules/fast-sass-loader/lib/index.js??clonedRuleSet-19%5B0%5D.rules%5B0%5D.use%5B3%5D");
/***/ }),
/***/ "./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/runtime/api.js":
/*!*******************************************************************************************************************************!*\
!*** ./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/runtime/api.js ***!
\*******************************************************************************************************************************/
/***/ (function(module) {
"use strict";
eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\n// eslint-disable-next-line func-names\nmodule.exports = function (cssWithMappingToString) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = cssWithMappingToString(item);\n\n if (item[2]) {\n return \"@media \".concat(item[2], \" {\").concat(content, \"}\");\n }\n\n return content;\n }).join(\"\");\n }; // import a list of modules into the list\n // eslint-disable-next-line func-names\n\n\n list.i = function (modules, mediaQuery, dedupe) {\n if (typeof modules === \"string\") {\n // eslint-disable-next-line no-param-reassign\n modules = [[null, modules, \"\"]];\n }\n\n var alreadyImportedModules = {};\n\n if (dedupe) {\n for (var i = 0; i < this.length; i++) {\n // eslint-disable-next-line prefer-destructuring\n var id = this[i][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n\n for (var _i = 0; _i < modules.length; _i++) {\n var item = [].concat(modules[_i]);\n\n if (dedupe && alreadyImportedModules[item[0]]) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n if (mediaQuery) {\n if (!item[2]) {\n item[2] = mediaQuery;\n } else {\n item[2] = \"\".concat(mediaQuery, \" and \").concat(item[2]);\n }\n }\n\n list.push(item);\n }\n };\n\n return list;\n};\n\n//# sourceURL=webpack://@bevo/core/./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/runtime/api.js?");
/***/ }),
/***/ "./registry/lib/components/video/full-episode-list/full-episode-list.scss":
/*!********************************************************************************!*\
!*** ./registry/lib/components/video/full-episode-list/full-episode-list.scss ***!
\********************************************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval("\n var result = __webpack_require__(/*! !!../../../../../node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[1]!../../../../../node_modules/.pnpm/registry.npmmirror.com+postcss-loader@4.3.0_g4najheu5gwop3kphiif6aqpde/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[2]!../../../../../node_modules/.pnpm/registry.npmmirror.com+fast-sass-loader@2.0.1_sass@1.51.0+webpack@5.72.0/node_modules/fast-sass-loader/lib/index.js??clonedRuleSet-19[0].rules[0].use[3]!./full-episode-list.scss */ \"./node_modules/.pnpm/registry.npmmirror.com+css-loader@5.2.7_webpack@5.72.0/node_modules/css-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[1]!./node_modules/.pnpm/registry.npmmirror.com+postcss-loader@4.3.0_g4najheu5gwop3kphiif6aqpde/node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-19[0].rules[0].use[2]!./node_modules/.pnpm/registry.npmmirror.com+fast-sass-loader@2.0.1_sass@1.51.0+webpack@5.72.0/node_modules/fast-sass-loader/lib/index.js??clonedRuleSet-19[0].rules[0].use[3]!./registry/lib/components/video/full-episode-list/full-episode-list.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n \n\n//# sourceURL=webpack://@bevo/core/./registry/lib/components/video/full-episode-list/full-episode-list.scss?");
/***/ }),
/***/ "@/components/define":
/*!******************************************************!*\
!*** external ["coreApis","componentApis","define"] ***!
\******************************************************/
/***/ (function(module) {
"use strict";
module.exports = coreApis.componentApis.define;
/***/ }),
/***/ "@/core/utils/urls":
/*!********************************************!*\
!*** external ["coreApis","utils","urls"] ***!
\********************************************/
/***/ (function(module) {
"use strict";
module.exports = coreApis.utils.urls;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ !function() {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function() { return module['default']; } :
/******/ function() { return module; };
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/create fake namespace object */
/******/ !function() {
/******/ var getProto = Object.getPrototypeOf ? function(obj) { return Object.getPrototypeOf(obj); } : function(obj) { return obj.__proto__; };
/******/ var leafPrototypes;
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 16: return value when it's Promise-like
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = this(value);
/******/ if(mode & 8) return value;
/******/ if(typeof value === 'object' && value) {
/******/ if((mode & 4) && value.__esModule) return value;
/******/ if((mode & 16) && typeof value.then === 'function') return value;
/******/ }
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ var def = {};
/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {
/******/ Object.getOwnPropertyNames(current).forEach(function(key) { def[key] = function() { return value[key]; }; });
/******/ }
/******/ def['default'] = function() { return value; };
/******/ __webpack_require__.d(ns, def);
/******/ return ns;
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ !function() {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = function(exports, definition) {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ !function() {
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ }();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ !function() {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ }();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = __webpack_require__("./registry/lib/components/video/full-episode-list/index.ts");
/******/ __webpack_exports__ = __webpack_exports__.component;
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});

View File

@ -1,10 +1,9 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["video/player/show-cover"]=t():e["video/player/show-cover"]=t()}(self,(function(){return function(){var e,t,o={33:function(e,t,o){var n=o(645)((function(e){return e[1]}));n.push([e.id,'.bpx-player-video-wrap::after,\n.bilibili-player-video::after {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: none;\n background: black var(--cover-url) center no-repeat;\n background-size: contain;\n pointer-events: none;\n z-index: 10;\n}\n\n.bpx-player-container.bpx-state-paused .bpx-player-video-wrap::after {\n display: block;\n}\n\n.bilibili-player-area.video-control-show.video-state-pause .bilibili-player-video::after {\n display: block;\n}',""]),e.exports=n},645:function(e){"use strict";
!function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports["video/player/show-cover"]=o():e["video/player/show-cover"]=o()}(self,(function(){return function(){var e,o,t={754:function(e,o,t){var n=t(355)((function(e){return e[1]}));n.push([e.id,'.bpx-player-video-wrap::after,\n.bilibili-player-video::after {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: none;\n background: black var(--cover-url) center no-repeat;\n background-size: contain;\n pointer-events: none;\n z-index: 10;\n}\n\n.bpx-player-container.bpx-state-paused .bpx-player-video-wrap::after {\n display: block;\n}\n\n.bilibili-player-area.video-state-pause .bilibili-player-video::after {\n display: block;\n}',""]),e.exports=n},355:function(e){"use strict";
// eslint-disable-next-line func-names
e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var o=e(t);return t[2]?"@media ".concat(t[2]," {").concat(o,"}"):o})).join("")},
e.exports=function(e){var o=[];return o.toString=function(){return this.map((function(o){var t=e(o);return o[2]?"@media ".concat(o[2]," {").concat(t,"}"):t})).join("")},
// eslint-disable-next-line func-names
t.i=function(e,o,n){"string"==typeof e&&(
o.i=function(e,t,n){"string"==typeof e&&(
// eslint-disable-next-line no-param-reassign
e=[[null,e,""]]);var r={};if(n)for(var i=0;i<this.length;i++){
// eslint-disable-next-line prefer-destructuring
var a=this[i][0];null!=a&&(r[a]=!0)}for(var c=0;c<e.length;c++){var u=[].concat(e[c]);n&&r[u[0]]||(o&&(u[2]?u[2]="".concat(o," and ").concat(u[2]):u[2]=o),t.push(u))}},t}},834:function(e,t,o){var n=o(33);n&&n.__esModule&&(n=n.default),e.exports="string"==typeof n?n:n.toString()},77:function(e){"use strict";e.exports=coreApis.componentApis.video.videoInfo}},n={};function r(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={id:e,exports:{}};return o[e](i,i.exports,r),i.exports}t=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},r.t=function(o,n){if(1&n&&(o=this(o)),8&n)return o;if("object"==typeof o&&o){if(4&n&&o.__esModule)return o;if(16&n&&"function"==typeof o.then)return o}var i=Object.create(null);r.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var c=2&n&&o;"object"==typeof c&&!~e.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((function(e){a[e]=function(){return o[e]}}));return a.default=function(){return o},r.d(i,a),i},r.d=function(e,t){for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var i={};return function(){"use strict";r.d(i,{component:function(){return o}});var e=coreApis.observer,t=coreApis.utils;const o={name:"showCoverBeforePlay",displayName:"播放前显示封面",urlInclude:coreApis.utils.urls.playerUrls,entry:async()=>{let o;// eslint-disable-next-line prefer-arrow-callback
(0,t.createHook)(await(0,t.isBwpVideo)()?BwpElement.prototype:HTMLVideoElement.prototype,"play",(function(){return document.body.style.removeProperty("--cover-url"),!0}));(0,e.videoChange)((async e=>{let{aid:t}=e;if(!t)return void console.warn("[播放前显示封面] 未找到av号");if(t===o)return;o=t;const{VideoInfo:n}=await Promise.resolve().then(r.t.bind(r,77,23)),i=new n(t);await i.fetchInfo(),document.body.style.setProperty("--cover-url",`url('${i.coverUrl}')`)}))},instantStyles:[{name:"showCoverBeforePlay",style:()=>Promise.resolve().then(r.t.bind(r,834,23))}],description:{"zh-CN":"在视频开始播放前, 在播放器中显示封面."},tags:[componentsTags.video],commitHash:"1def12660be1be05427fe717e844a6d1d5ef0e1e",coreVersion:"2.4.1"}}(),i=i.component}()}));
var a=this[i][0];null!=a&&(r[a]=!0)}for(var c=0;c<e.length;c++){var p=[].concat(e[c]);n&&r[p[0]]||(t&&(p[2]?p[2]="".concat(t," and ").concat(p[2]):p[2]=t),o.push(p))}},o}},179:function(e,o,t){var n=t(754);n&&n.__esModule&&(n=n.default),e.exports="string"==typeof n?n:n.toString()},77:function(e){"use strict";e.exports=coreApis.componentApis.video.videoInfo}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,exports:{}};return t[e](i,i.exports,r),i.exports}o=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},r.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var i=Object.create(null);r.r(i);var a={};e=e||[null,o({}),o([]),o(o)];for(var c=2&n&&t;"object"==typeof c&&!~e.indexOf(c);c=o(c))Object.getOwnPropertyNames(c).forEach((function(e){a[e]=function(){return t[e]}}));return a.default=function(){return t},r.d(i,a),i},r.d=function(e,o){for(var t in o)r.o(o,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},r.o=function(e,o){return Object.prototype.hasOwnProperty.call(e,o)},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var i={};return function(){"use strict";r.d(i,{component:function(){return a}});var e=coreApis.componentApis.define,o=coreApis.observer,t=coreApis.utils,n=coreApis.utils.urls;const a=(0,e.defineComponentMetadata)({name:"showCoverBeforePlay",displayName:"播放前显示封面",urlInclude:n.playerUrls,entry:async()=>{let e;const n=()=>document.body.style.removeProperty("--cover-url"),i=await(0,t.isBwpVideo)()?BwpElement.prototype:HTMLVideoElement.prototype,a=dq(".bpx-player-video-wrap"),c=Boolean(a);(0,t.createHook)(i,"play",(()=>(n(),!0))),c&&(0,o.videoChange)((()=>{console.debug("isBpxPlayer");const e=dq(".bpx-player-video-wrap video");e?(0,t.createHook)(e,"play",(()=>(n(),!0))):console.warn("bpx player not found")}));(0,o.videoChange)((async o=>{let{aid:t}=o;if(!t)return void console.warn("[播放前显示封面] 未找到av号");if(t===e)return;e=t;const{VideoInfo:n}=await Promise.resolve().then(r.t.bind(r,77,23)),i=new n(t);await i.fetchInfo(),document.body.style.setProperty("--cover-url",`url('${i.coverUrl}')`)}))},instantStyles:[{name:"showCoverBeforePlay",style:()=>Promise.resolve().then(r.t.bind(r,179,23))}],description:{"zh-CN":"在视频开始播放前, 在播放器中显示封面."},tags:[componentsTags.video],commitHash:"59c04ba07816fc5ab6aa55f6c54bd53c07136c35",coreVersion:"2.5.0"})}(),i=i.component}()}));

31
registry/dist/doc.js vendored

File diff suppressed because one or more lines are too long

View File

@ -25,8 +25,5 @@ export const component: ComponentMetadata = {
},
entry,
urlInclude: feedsUrls,
tags: [
componentsTags.feeds,
componentsTags.utils,
],
tags: [componentsTags.feeds, componentsTags.utils],
}

View File

@ -18,37 +18,50 @@ const entry = async () => {
addStyle()
const disableDetails = (card: FeedsCard) => {
const { element } = card
element.addEventListener('click', e => {
if (e.ctrlKey || !enabled) {
return
}
const contents = dqa(element, '.content, .bili-dyn-content [data-module="desc"] .bili-rich-text')
const target = e.target as HTMLElement
if (target.hasAttribute('click-title')) {
return
}
if ([
'bili-rich-text__action',
'bili-rich-text-topic',
'bili-rich-text-module',
'bili-rich-text-link',
].some(className => target.classList.contains(className))) {
return
}
const popups = dqa(element, '.im-popup')
if (popups.some(p => p.contains(target))) {
return
}
if (contents.some(c => c === target || c.contains(target))) {
e.stopImmediatePropagation()
}
}, { capture: true })
element.addEventListener(
'click',
e => {
if (e.ctrlKey || !enabled) {
return
}
const contents = dqa(
element,
'.content, .bili-dyn-content [data-module="desc"] .bili-rich-text',
)
const target = e.target as HTMLElement
if (target.hasAttribute('click-title')) {
return
}
if (
[
'bili-rich-text__action',
'bili-rich-text-topic',
'bili-rich-text-module',
'bili-rich-text-link',
].some(className => target.classList.contains(className))
) {
return
}
const popups = dqa(element, '.im-popup')
if (popups.some(p => p.contains(target))) {
return
}
if (contents.some(c => c === target || c.contains(target))) {
e.stopImmediatePropagation()
}
},
{ capture: true },
)
const postContent = dq(element, '.post-content, .bili-dyn-content')
if (!postContent) {
return
}
const hasCardContainer = ['.video-container', '.bangumi-container', '.media-list', '.article-container']
.some(type => dq(postContent, type))
const hasCardContainer = [
'.video-container',
'.bangumi-container',
'.media-list',
'.article-container',
].some(type => dq(postContent, type))
if (hasCardContainer) {
return
}
@ -63,7 +76,7 @@ const entry = async () => {
const details = document.createElement('div')
details.classList.add('details')
details.setAttribute('click-title', '详情')
details.innerHTML = /* html */`
details.innerHTML = /* html */ `
<i class="mdi mdi-chevron-right" click-title></i>
`
contents.insertAdjacentElement('beforeend', details)
@ -76,9 +89,7 @@ const entry = async () => {
export const component: ComponentMetadata = {
name: 'disableFeedsDetails',
displayName: '禁止跳转动态详情',
tags: [
componentsTags.feeds,
],
tags: [componentsTags.feeds],
urlInclude: feedsUrls,
description: {
'zh-CN': '禁止动态点击后跳转详情页, 方便选择其中的文字.',

View File

@ -13,14 +13,17 @@ interface LiveInfo {
}
const entry = async () => {
const { select } = await import('@/core/spin-query')
const liveList = await select('.live-up-list, .bili-dyn-live-users__body') as HTMLElement
const liveList = (await select('.live-up-list, .bili-dyn-live-users__body')) as HTMLElement
if (liveList === null) {
return
}
const pageSize = 24
const { getPages, getJsonWithCredentials } = await import('@/core/ajax')
const fullList: LiveInfo[] = await getPages({
api: page => getJsonWithCredentials(`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=${pageSize}`),
api: page =>
getJsonWithCredentials(
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=${pageSize}`,
),
getList: json => lodash.get(json, 'data.list', []),
getTotal: json => lodash.get(json, 'data.results', 0),
})
@ -46,7 +49,10 @@ const entry = async () => {
window.open(url, '_blank')
})
}
const face = dq(clone, '.live-up-img, .bili-dyn-live-users__item__face .bili-awesome-img') as HTMLElement
const face = dq(
clone,
'.live-up-img, .bili-dyn-live-users__item__face .bili-awesome-img',
) as HTMLElement
face.style.backgroundImage = `url(${it.face})`
const title = dq(clone, '.live-name, .bili-dyn-live-users__item__title') as HTMLElement
title.innerHTML = it.title
@ -70,11 +76,6 @@ export const component: ComponentMetadata = {
'zh-CN': '在动态的`正在直播`中, 为每一个直播间加上标题, 并且能够显示超过10个的直播间.',
},
entry: styledComponentEntry(() => import('./extend-feeds-live.scss'), entry),
tags: [
componentsTags.feeds,
componentsTags.live,
],
urlInclude: [
/^https:\/\/t\.bilibili\.com\/$/,
],
tags: [componentsTags.feeds, componentsTags.live],
urlInclude: [/^https:\/\/t\.bilibili\.com\/$/],
}

View File

@ -6,12 +6,7 @@
</div>
<h2>类型</h2>
<div class="filter-types">
<FilterTypeSwitch
v-for="[name, type] of allTypes"
:key="type.id"
:name="name"
:type="type"
/>
<FilterTypeSwitch v-for="[name, type] of allTypes" :key="type.id" :name="name" :type="type" />
</div>
<h2>关键词</h2>
<div class="filter-patterns">
@ -45,10 +40,7 @@
@click="toggleBlockSide(id)"
>
<label :class="{ disabled: sideDisabled(id) }">
<span
class="name"
:class="{ disabled: sideDisabled(id) }"
>{{ type.displayName }}</span>
<span class="name" :class="{ disabled: sideDisabled(id) }">{{ type.displayName }}</span>
<VIcon :size="16" class="disabled" icon="mdi-cancel"></VIcon>
<VIcon :size="16" icon="mdi-check"></VIcon>
</label>
@ -58,15 +50,11 @@
</template>
<script lang="ts">
import { FeedsCard, FeedsCardType } from '@/components/feeds/api'
import { FeedsCard, FeedsCardType, feedsCardTypes, forEachFeedsCard, RepostFeedsCard } from '@/components/feeds/api'
import { getComponentSettings } from '@/core/settings'
import { select } from '@/core/spin-query'
import { attributes } from '@/core/observer'
import {
VIcon,
TextBox,
VButton,
} from '@/ui'
import { VIcon, TextBox, VButton } from '@/ui'
import { FeedsFilterOptions } from '.'
import { hasBlockedPattern } from './pattern'
@ -140,7 +128,6 @@ export default Vue.extend({
console.error('tabBar not found')
return
}
const { forEachFeedsCard, feedsCardTypes } = await import('@/components/feeds/api')
document.body.classList.add('enable-feeds-filter')
const specialTypes = {
'self-repost': {
@ -158,14 +145,9 @@ export default Vue.extend({
},
})
if (cardsManager.managerType === 'v1') {
const tab = tabBar.querySelector(
'.tab:nth-child(1) .tab-text',
) as HTMLAnchorElement
const tab = tabBar.querySelector('.tab:nth-child(1) .tab-text') as HTMLAnchorElement
attributes(tab, () => {
document.body.classList.toggle(
'by-type',
!tab.classList.contains('selected'),
)
document.body.classList.toggle('by-type', !tab.classList.contains('selected'))
})
}
if (cardsManager.managerType === 'v2') {
@ -184,7 +166,13 @@ export default Vue.extend({
},
methods: {
updateCard(card: FeedsCard) {
const block = options.patterns.some(p => hasBlockedPattern(p, card))
const blockableCard = {
...card,
}
if (card.type === feedsCardTypes.repost) {
blockableCard.text += `\n${(card as RepostFeedsCard).repostText}`
}
const block = options.patterns.some(p => hasBlockedPattern(p, blockableCard))
if (block) {
card.element.classList.add('pattern-block')
} else {
@ -206,9 +194,7 @@ export default Vue.extend({
updateBlockSide() {
Object.entries(sideCards).forEach(([id, type]) => {
const name = sideBlock + type.className
document.body.classList[
this.blockSideCards.includes(id) ? 'add' : 'remove'
](name)
document.body.classList[this.blockSideCards.includes(id) ? 'add' : 'remove'](name)
})
},
toggleBlockSide(id: number) {
@ -231,8 +217,8 @@ export default Vue.extend({
</script>
<style lang="scss">
@import "common";
@import "./blocker";
@import 'common';
@import './blocker';
body.enable-feeds-filter:not(.disable-feeds-filter) {
@include type-block();

View File

@ -11,9 +11,7 @@
<script lang="ts">
import { getComponentSettings } from '@/core/settings'
import {
VIcon,
} from '@/ui'
import { VIcon } from '@/ui'
const { options } = getComponentSettings('feedsFilter')
export default Vue.extend({
@ -48,9 +46,7 @@ export default Vue.extend({
},
methods: {
setFilter(disabled: boolean, updateSettings = true) {
document.body.classList[disabled ? 'add' : 'remove'](
`feeds-filter-block-${this.name}`,
)
document.body.classList[disabled ? 'add' : 'remove'](`feeds-filter-block-${this.name}`)
if (!updateSettings) {
return
}

View File

@ -57,9 +57,7 @@ export const component: ComponentMetadata = {
'zh-CN': '按照类型或者关键词过滤动态首页的内容, 也可以移除动态页的一些侧边卡片.',
},
entry,
tags: [
componentsTags.feeds,
],
tags: [componentsTags.feeds],
options,
reload: () => document.body.classList.remove('disable-feeds-filter'),
unload: () => document.body.classList.add('disable-feeds-filter'),

View File

@ -15,10 +15,7 @@ export interface BlockableCard {
export const hasBlockedPattern = (pattern: string, card: BlockableCard) => {
const upNameMatch = pattern.match(/(.+) up:([^ ]+)/)
if (upNameMatch) {
return (
testPattern(upNameMatch[1], card.text)
&& testPattern(upNameMatch[2], card.username)
)
return testPattern(upNameMatch[1], card.text) && testPattern(upNameMatch[2], card.username)
}
return testPattern(pattern, card.text)
}

View File

@ -1,6 +1,7 @@
import { FeedsContentFilter } from '@/components/feeds/api'
import { getComponentSettings } from '@/core/settings'
import { PluginMetadata } from '@/plugins/plugin'
import { BlockableCard } from './pattern'
import { BlockableCard, hasBlockedPattern } from './pattern'
const bangumiFields = {
username: 'title',
@ -14,36 +15,36 @@ const feedField = {
username: ['username', 'repostUsername'],
text: ['text', 'repostText'],
}
const filterableFields = [
bangumiFields,
videoField,
feedField,
]
const filterableFields = [bangumiFields, videoField, feedField]
export const feedsFilterPlugin: PluginMetadata = {
name: 'feeds.contentFilters.patterns',
displayName: '动态关键词过滤',
setup: ({ addData }) => {
addData('feeds.contentFilters', async (filters: FeedsContentFilter[]) => {
const { getComponentSettings } = await import('@/core/settings')
const { hasBlockedPattern } = await import('./pattern')
addData('feeds.contentFilters', (filters: FeedsContentFilter[]) => {
filters.push({
filter: (items: any[]) => {
const { patterns } = getComponentSettings('feedsFilter').options as {
patterns: string[]
}
return items.filter(item => {
const field = filterableFields.find(it => (
const field = filterableFields.find(it =>
Object.values(it).every(fields => {
if (Array.isArray(fields)) {
return fields.some(f => f in item)
}
return fields in item
})
))
}),
)
const card = Object.fromEntries(
Object.entries(field).map(([key, value]) => {
if (Array.isArray(value)) {
return [key, value.map(v => item[v] ?? '').join('\n').trim()]
return [
key,
value
.map(v => item[v] ?? '')
.join('\n')
.trim(),
]
}
return [key, item[value].trim() as string]
}),

View File

@ -19,11 +19,7 @@ export const component: ComponentMetadata = {
description: {
'zh-CN': '强制固定动态主页的顶栏和所有侧栏.',
},
tags: [
componentsTags.feeds,
],
tags: [componentsTags.feeds],
entry,
urlInclude: [
/^https:\/\/t\.bilibili\.com\/$/,
],
urlInclude: [/^https:\/\/t\.bilibili\.com\/$/],
}

View File

@ -83,8 +83,6 @@ export const component: ComponentMetadata = {
'zh-CN': '动态里查看评论区时, 在底部添加一个`收起评论`按钮, 这样就不用再回到上面收起了.',
},
urlInclude: feedsUrlsWithoutDetail,
tags: [
componentsTags.feeds,
],
tags: [componentsTags.feeds],
entry: styledComponentEntry(() => import('./fold-comment.scss'), entry),
}

View File

@ -8,9 +8,6 @@ export const component: ComponentMetadata = {
description: {
'zh-CN': '不管内容多长, 总是完全展开动态的内容.',
},
tags: [
componentsTags.style,
componentsTags.feeds,
],
tags: [componentsTags.style, componentsTags.feeds],
urlInclude: feedsUrlsWithoutDetail,
}

View File

@ -0,0 +1,3 @@
.bili-dyn-item__interaction {
display: none !important;
}

View File

@ -0,0 +1 @@
隐藏动态评论按钮上方的精选评论预览. (详细可看 [#3322](https://github.com/the1812/Bilibili-Evolved/discussions/3322))

View File

@ -0,0 +1,15 @@
import { defineComponentMetadata } from '@/components/define'
const name = 'hideFeedsCommentPreview'
export const component = defineComponentMetadata({
name,
tags: [componentsTags.feeds, componentsTags.style],
displayName: '隐藏动态评论预览',
entry: none,
instantStyles: [
{
style: () => import('./hide-comment-preview.scss'),
name,
},
],
})

View File

@ -1,4 +1,5 @@
import { ComponentMetadata } from '@/components/types'
import { select } from '@/core/spin-query'
import { feedsUrlsWithoutDetail } from '@/core/utils/urls'
export const component: ComponentMetadata = {
@ -19,8 +20,8 @@ export const component: ComponentMetadata = {
entry: async () => {
const { forEachFeedsCard } = await import('@/components/feeds/api')
forEachFeedsCard({
added: card => {
const foldButton = dq(card.element, '.fold-hoverable, .bili-dyn-item-fold') as HTMLElement
added: async card => {
const foldButton = await select(() => dq(card.element, '.fold-hoverable, .bili-dyn-item-fold') as HTMLElement)
foldButton?.click()
},
})

View File

@ -22,11 +22,7 @@
</li>
</ul>
</VPopup>
<DefaultWidget
ref="medalButton"
icon="mdi-medal"
@click="medalOpen = !medalOpen"
>
<DefaultWidget ref="medalButton" icon="mdi-medal" @click="medalOpen = !medalOpen">
<span>更换勋章</span>
</DefaultWidget>
@ -48,11 +44,7 @@
</li>
</ul>
</VPopup>
<DefaultWidget
ref="titleButton"
icon="mdi-script-outline"
@click="titleOpen = !titleOpen"
>
<DefaultWidget ref="titleButton" icon="mdi-script-outline" @click="titleOpen = !titleOpen">
<span>更换头衔</span>
</DefaultWidget>
</div>
@ -61,13 +53,8 @@
<script lang="ts">
import { addComponentListener, getComponentSettings } from '@/core/settings'
import { descendingSort } from '@/core/utils/sort'
import {
DefaultWidget,
VPopup,
} from '@/ui'
import {
Medal, Title, Badge, getMedalList, getTitleList,
} from './badge'
import { DefaultWidget, VPopup } from '@/ui'
import { Medal, Title, Badge, getMedalList, getTitleList } from './badge'
const { options } = getComponentSettings('badgeHelper')
export default Vue.extend({
@ -85,9 +72,13 @@ export default Vue.extend({
}
},
async mounted() {
addComponentListener('badgeHelper.grayEffect', (enable: boolean) => {
this.grayEffect = enable
}, true)
addComponentListener(
'badgeHelper.grayEffect',
(enable: boolean) => {
this.grayEffect = enable
},
true,
)
const init = async () => {
const medal = this.loadMedalList()
await Title.getImageMap()
@ -142,7 +133,7 @@ export default Vue.extend({
</script>
<style lang="scss">
@import "common";
@import 'common';
.badge-popup {
top: 50%;
left: calc(100% + 8px);

View File

@ -1,4 +1,9 @@
import { getJsonWithCredentials, getPages, getTextWithCredentials, postTextWithCredentials } from '@/core/ajax'
import {
getJsonWithCredentials,
getPages,
getTextWithCredentials,
postTextWithCredentials,
} from '@/core/ajax'
import { formData, getCsrf } from '@/core/utils'
import { logError } from '@/core/utils/log'
@ -12,13 +17,16 @@ const validateJson = (json: any, errorMessage: string) => {
}
export abstract class Badge {
constructor(public isActive: boolean = false, public id: number = 0) { }
constructor(public isActive: boolean = false, public id: number = 0) {}
/** @deprecated */
static parseJson<T>(text: string, actions: {
successAction: (json: any) => T,
errorMessage: string,
errorAction: (json: any) => T
}) {
static parseJson<T>(
text: string,
actions: {
successAction: (json: any) => T
errorMessage: string
errorAction: (json: any) => T
},
) {
const json = JSON.parse(text)
if (json.code !== 0) {
logError(`${actions.errorMessage} 错误码:${json.code} ${json.message || ''}`)
@ -37,19 +45,9 @@ export class Medal extends Badge {
isLighted: boolean
constructor(json: any) {
const {
medal: {
medal_id,
level,
medal_name,
wearing_status,
is_lighted,
},
anchor_info: {
nick_name,
},
room_info: {
room_id,
},
medal: { medal_id, level, medal_name, wearing_status, is_lighted },
anchor_info: { nick_name },
room_info: { room_id },
} = json
super(wearing_status === 1, medal_id)
this.level = level
@ -59,20 +57,26 @@ export class Medal extends Badge {
this.isLighted = is_lighted
}
async activate() {
const text = await postTextWithCredentials('https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear', formData({
medal_id: this.id,
csrf_token: getCsrf(),
csrf: getCsrf(),
}))
const text = await postTextWithCredentials(
'https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear',
formData({
medal_id: this.id,
csrf_token: getCsrf(),
csrf: getCsrf(),
}),
)
const result = validateJson(JSON.parse(text), '佩戴勋章失败.')
this.isActive = true
return result
}
async deactivate() {
const text = await postTextWithCredentials('https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off', formData({
csrf_token: getCsrf(),
csrf: getCsrf(),
}))
const text = await postTextWithCredentials(
'https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off',
formData({
csrf_token: getCsrf(),
csrf: getCsrf(),
}),
)
const result = validateJson(JSON.parse(text), '卸下勋章失败.')
this.isActive = false
return result
@ -80,13 +84,13 @@ export class Medal extends Badge {
}
export const getMedalList = async () => {
const pages = await getPages({
api: page => getJsonWithCredentials(`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=${page}&page_size=50`),
api: page =>
getJsonWithCredentials(
`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=${page}&page_size=50`,
),
getList: json => {
validateJson(json, '无法获取勋章列表.')
return [
...lodash.get(json, 'data.list', []),
...lodash.get(json, 'data.special_list', []),
]
return [...lodash.get(json, 'data.list', []), ...lodash.get(json, 'data.special_list', [])]
},
getTotal: json => lodash.get(json, 'data.total_number', 0),
})
@ -100,9 +104,7 @@ export class Title extends Badge {
source: string
imageUrl: string
constructor(json: any) {
const {
id, cid, wear, css, name, source,
} = json
const { id, cid, wear, css, name, source } = json
super(wear, css)
this.tid = id
this.cid = cid
@ -134,7 +136,10 @@ export class Title extends Badge {
}
async activate() {
return Badge.parseJson(
await postTextWithCredentials('https://api.live.bilibili.com/i/ajaxWearTitle', `id=${this.tid}&cid=${this.cid}&csrf=${getCsrf()}&csrf_token=${getCsrf()}`),
await postTextWithCredentials(
'https://api.live.bilibili.com/i/ajaxWearTitle',
`id=${this.tid}&cid=${this.cid}&csrf=${getCsrf()}&csrf_token=${getCsrf()}`,
),
{
successAction: () => {
this.isActive = true
@ -147,8 +152,10 @@ export class Title extends Badge {
}
async deactivate() {
return Badge.parseJson(
await postTextWithCredentials('https://api.live.bilibili.com/i/ajaxCancelWearTitle',
`csrf=${getCsrf()}&csrf_token=${getCsrf()}`),
await postTextWithCredentials(
'https://api.live.bilibili.com/i/ajaxCancelWearTitle',
`csrf=${getCsrf()}&csrf_token=${getCsrf()}`,
),
{
successAction: () => {
this.isActive = false
@ -160,11 +167,15 @@ export class Title extends Badge {
)
}
}
export const getTitleList = async () => Badge.parseJson(
await getTextWithCredentials('https://api.live.bilibili.com/i/api/ajaxTitleInfo?page=1&pageSize=256&had=1'),
{
successAction: json => lodash.get(json, 'data.list', []).map((it: any) => new Title(it)) as Title[],
errorAction: () => [] as Title[],
errorMessage: '无法获取头衔列表.',
},
)
export const getTitleList = async () =>
Badge.parseJson(
await getTextWithCredentials(
'https://api.live.bilibili.com/i/api/ajaxTitleInfo?page=1&pageSize=256&had=1',
),
{
successAction: json =>
lodash.get(json, 'data.list', []).map((it: any) => new Title(it)) as Title[],
errorAction: () => [] as Title[],
errorMessage: '无法获取头衔列表.',
},
)

View File

@ -6,14 +6,13 @@ export const component = defineComponentMetadata({
name: 'badgeHelper',
displayName: '直播勋章快速更换',
description: {
'zh-CN': '在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.',
'zh-CN':
'在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.',
},
entry: () => autoMatchMedal(),
reload: none,
unload: none,
tags: [
componentsTags.live,
],
tags: [componentsTags.live],
widget: {
component: () => import('./BadgeHelper.vue').then(m => m.default),
condition: () => Boolean(getUID()),
@ -38,7 +37,5 @@ export const component = defineComponentMetadata({
defaultValue: true,
},
},
urlInclude: [
'//live.bilibili.com',
],
urlInclude: ['//live.bilibili.com'],
})

View File

@ -25,10 +25,14 @@ export default Vue.extend({
}
},
async mounted() {
const originalTextArea = await select(originalTextAreaSelector) as HTMLTextAreaElement
const sendButton = await select(sendButtonSelector) as HTMLButtonElement
const originalTextArea = (await select(originalTextAreaSelector)) as HTMLTextAreaElement
const sendButton = (await select(sendButtonSelector)) as HTMLButtonElement
if (!originalTextArea || !sendButton) {
throw new Error(`[danmakuSendBar] ref elements not found. originalTextArea = ${originalTextArea === null} sendButton = ${sendButton === null}`)
throw new Error(
`[danmakuSendBar] ref elements not found. originalTextArea = ${
originalTextArea === null
} sendButton = ${sendButton === null}`,
)
}
// console.log(originalTextArea, sendButton)
this.originalTextArea = originalTextArea
@ -37,9 +41,7 @@ export default Vue.extend({
originalTextArea.addEventListener('input', this.listenChange)
originalTextArea.addEventListener('change', this.listenChange)
if (!changeEventHook) {
const original = Object.getOwnPropertyDescriptors(
HTMLTextAreaElement.prototype,
).value
const original = Object.getOwnPropertyDescriptors(HTMLTextAreaElement.prototype).value
Object.defineProperty(originalTextArea, 'value', {
...original,
set(value: string) {

View File

@ -30,9 +30,7 @@ const entry = async () => {
export const component = defineComponentMetadata({
name: 'liveDanmakuSendbar',
displayName: '直播弹幕发送栏',
tags: [
componentsTags.live,
],
tags: [componentsTags.live],
description: {
'zh-CN': '在直播的网页全屏和全屏模式状态下, 在底部显示弹幕栏.',
},

View File

@ -1,3 +1,4 @@
export const originalTextAreaSelector = '.control-panel-ctnr .chat-input-ctnr .chat-input'
export const sendButtonSelector = '.control-panel-ctnr .chat-input-ctnr ~ .bottom-actions .bl-button--primary'
export const sendButtonSelector =
'.control-panel-ctnr .chat-input-ctnr ~ .bottom-actions .bl-button--primary'
export const leftControllerSelector = '.left-area'

View File

@ -43,7 +43,12 @@ export default Vue.extend({
return
}
const links: string[] = json.data.list.map((it: { url: string }) => it.url)
Toast.success(links.map(l => `<a class="download-link" target="_blank" href="${l}">${l}</a>`).join('\n'), '下载录像')
Toast.success(
links
.map(l => `<a class="download-link" target="_blank" href="${l}">${l}</a>`)
.join('\n'),
'下载录像',
)
} finally {
this.disabled = false
}

View File

@ -6,14 +6,10 @@ export const component = defineComponentMetadata({
description: {
'zh-CN': '在直播录像页面 `live.bilibili.com/record/` 中添加下载支持.',
},
tags: [
componentsTags.live,
],
tags: [componentsTags.live],
entry: none,
widget: {
component: () => import('./DownloadRecords.vue').then(m => m.default),
},
urlInclude: [
/^https:\/\/live\.bilibili\.com\/record\/(.+)/,
],
urlInclude: [/^https:\/\/live\.bilibili\.com\/record\/(.+)/],
})

View File

@ -46,7 +46,7 @@ let stopObservingMouseLeavePlayer: StopObservingCallback | null = null
interface FullWinToggleCallback {
(
// 标识监听到的动作是启动操作还是关闭操作
isStarted: boolean
isStarted: boolean,
): void
}
@ -75,9 +75,7 @@ function isFullWin(): boolean {
* @param callback
* @returns
*/
function observeFullWinToggle(
onToggle: FullWinToggleCallback,
): StopObservingCallback {
function observeFullWinToggle(onToggle: FullWinToggleCallback): StopObservingCallback {
/**
*
* @param {MutationRecord} mutation body
@ -113,10 +111,7 @@ function observeFullWinToggle(
}
// 将包裹按钮移动到控制条上
function moveGiftPackageToControlBar(
controlBar: Element,
giftBtn0: Element,
) {
function moveGiftPackageToControlBar(controlBar: Element, giftBtn0: Element) {
// console.debug(`[${componentName}] moving gift button to control bar...`)
const rightArea = dq(controlBar, '.right-area')
if (rightArea) {
@ -159,14 +154,9 @@ function onFullWinClose(giftBtn0: Element, originGiftBtnParent: Element) {
}
// 每当全屏模式切换时执行操作
function doOnFullWinToggle(
giftBtn0: Element,
originGiftBtnParent: Element,
): StopObservingCallback {
function doOnFullWinToggle(giftBtn0: Element, originGiftBtnParent: Element): StopObservingCallback {
return observeFullWinToggle(isStarted => {
isStarted
? onFullWinStart(giftBtn0)
: onFullWinClose(giftBtn0, originGiftBtnParent)
isStarted ? onFullWinStart(giftBtn0) : onFullWinClose(giftBtn0, originGiftBtnParent)
})
}
@ -195,7 +185,7 @@ async function reload() {
addStyle(componentStyle, componentName)
const giftBtnParent = await queryGiftBtnParent()
giftBtn = (giftBtnParent?.children[0])
giftBtn = giftBtnParent?.children[0]
if (giftBtnParent && giftBtn) {
stopObservingFullWinToggle = doOnFullWinToggle(giftBtn, giftBtnParent)

View File

@ -6,21 +6,23 @@ const liveHome = /^https:\/\/live\.bilibili\.com\/(index\.html)?$/
export const component = defineComponentMetadata({
name: 'liveHomeMute',
displayName: '直播首页静音',
tags: [
componentsTags.live,
],
tags: [componentsTags.live],
description: {
'zh-CN': '禁止直播首页的推荐直播间自动开始播放.',
},
entry: async ({ metadata }) => {
const styleID = 'hide-home-live'
addComponentListener(`${metadata.name}.hide`, (value: boolean) => {
if (value) {
addStyle('.player-area-ctnr,#player-header { display: none !important }', styleID)
} else {
removeStyle(styleID)
}
}, true)
addComponentListener(
`${metadata.name}.hide`,
(value: boolean) => {
if (value) {
addStyle('.player-area-ctnr,#player-header { display: none !important }', styleID)
} else {
removeStyle(styleID)
}
},
true,
)
},
options: {
hide: {
@ -28,9 +30,7 @@ export const component = defineComponentMetadata({
defaultValue: false,
},
},
urlInclude: [
liveHome,
],
urlInclude: [liveHome],
plugin: {
displayName: '直播首页静音 - 提前执行',
description: {

View File

@ -1,9 +1,6 @@
<template>
<a :href="href" tabindex="-1">
<DefaultWidget
name="返回原版直播间"
icon="mdi-arrow-left-circle-outline"
/>
<DefaultWidget name="返回原版直播间" icon="mdi-arrow-left-circle-outline" />
</a>
</template>
<script lang="ts">

View File

@ -4,7 +4,8 @@ import { matchUrlPattern } from '@/core/utils'
export const component = defineComponentMetadata({
name: 'originalLiveroom',
displayName: '返回原版直播间',
description: '在直播间中提供返回原版直播间的按钮, 原版直播间将无视活动皮肤, 强制使用标准的直播页面.',
description:
'在直播间中提供返回原版直播间的按钮, 原版直播间将无视活动皮肤, 强制使用标准的直播页面.',
tags: [componentsTags.live],
entry: none,
urlInclude: [

View File

@ -5,10 +5,7 @@ import { liveUrls } from '@/core/utils/urls'
export const component = defineComponentMetadata({
...toggleStyle('removeLiveWatermark', () => import('./remove-watermark.scss')),
displayName: '删除直播水印',
tags: [
componentsTags.live,
componentsTags.style,
],
tags: [componentsTags.live, componentsTags.style],
description: {
'zh-CN': '删除观看直播时角落的水印.',
},

View File

@ -5,13 +5,16 @@ const id = 'dpi-live-showgirl'
const entry = async () => {
const { addStyle } = await import('@/core/style')
if (document.getElementById(id) === null) {
addStyle(`
addStyle(
`
.haruna-ctnr,
.avatar-btn
{
transform: scale(${1 / window.devicePixelRatio}) !important;
}
`, id)
`,
id,
)
}
}
export const component = defineComponentMetadata({
@ -21,10 +24,7 @@ export const component = defineComponentMetadata({
description: {
'zh-CN': '根据屏幕 DPI 缩放直播看板娘的大小, 避免像素锯齿.',
},
tags: [
componentsTags.live,
componentsTags.style,
],
tags: [componentsTags.live, componentsTags.style],
entry,
reload: entry,
unload: () => {

View File

@ -12,9 +12,6 @@ export const component = defineComponentMetadata({
],
displayName: '自动收起直播侧栏',
description: '自动收起直播间右边偏下的侧栏. (上面有个 "关注" 的面板)',
tags: [
componentsTags.live,
componentsTags.style,
],
tags: [componentsTags.live, componentsTags.style],
urlInclude: liveUrls,
})

View File

@ -5,9 +5,13 @@ import { getNumberValidator } from '@/core/utils'
export const component = defineComponentMetadata({
name: 'autoHideSidebar',
entry: () => {
addComponentListener('autoHideSidebar.triggerWidth', (value: number) => {
document.documentElement.style.setProperty('--auto-hide-sidebar-width', `${value}px`)
}, true)
addComponentListener(
'autoHideSidebar.triggerWidth',
(value: number) => {
document.documentElement.style.setProperty('--auto-hide-sidebar-width', `${value}px`)
},
true,
)
},
displayName: '自动隐藏侧栏',
instantStyles: [
@ -26,6 +30,7 @@ export const component = defineComponentMetadata({
},
},
description: {
'zh-CN': '自动隐藏脚本的侧栏 (功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.',
'zh-CN':
'自动隐藏脚本的侧栏 (功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.',
},
})

View File

@ -2,11 +2,7 @@
<div class="custom-navbar" :class="styles" role="navigation">
<div class="left-pad padding"></div>
<div class="custom-navbar-items" role="list">
<NavbarItem
v-for="item of items"
:key="item.name"
:item="item"
></NavbarItem>
<NavbarItem v-for="item of items" :key="item.name" :item="item"></NavbarItem>
</div>
<div class="right-pad padding"></div>
</div>
@ -63,9 +59,13 @@ export default Vue.extend({
},
},
async mounted() {
addComponentListener('customNavbar.height', (value: number) => {
document.documentElement.style.setProperty('--navbar-height', `${value}px`)
}, true)
addComponentListener(
'customNavbar.height',
(value: number) => {
document.documentElement.style.setProperty('--navbar-height', `${value}px`)
},
true,
)
await checkTransparentFill(this)
},
methods: {
@ -83,6 +83,10 @@ export default Vue.extend({
<style lang="scss">
@import 'common';
.van-message-box {
z-index: 10002 !important;
}
html {
--navbar-height: 50px;
--navbar-foreground: #555;
@ -214,12 +218,7 @@ body.fixed-navbar {
left: 0;
width: 100%;
height: calc(2 * var(--navbar-height));
background-image: linear-gradient(
to bottom,
#000a 0,
#0004 65%,
transparent 100%
);
background-image: linear-gradient(to bottom, #000a 0, #0004 65%, transparent 100%);
pointer-events: none;
}
}

View File

@ -111,7 +111,10 @@ export default Vue.extend({
if (!popup) {
return
}
const allowRefresh = CustomNavbarItem.navbarOptions.refreshOnPopup && popup.popupRefresh && typeof popup.popupRefresh === 'function'
const allowRefresh =
CustomNavbarItem.navbarOptions.refreshOnPopup &&
popup.popupRefresh &&
typeof popup.popupRefresh === 'function'
if (!initialPopup && allowRefresh) {
popup.popupRefresh()
}
@ -262,12 +265,15 @@ export default Vue.extend({
pointer-events: none;
}
&:not(.disabled):hover .popup-container {
top: 100%;
> .popup {
// transform: translateY(0) translateX(-50%);
pointer-events: initial;
opacity: 1;
&:not(.disabled):hover,
&:not(.disabled):focus-within {
.popup-container {
top: 100%;
> .popup {
// transform: translateY(0) translateX(-50%);
pointer-events: initial;
opacity: 1;
}
}
}

View File

@ -1,9 +1,5 @@
<template>
<a
v-bind="$attrs"
:target="newTab ? '_blank' : null"
v-on="$listeners"
>
<a v-bind="$attrs" :target="newTab ? '_blank' : null" v-on="$listeners">
<slot />
</a>
</template>

View File

@ -4,19 +4,9 @@ import { ranking } from './ranking/ranking'
import { userInfo } from './user-info/user-info'
import { logo } from './logo/logo'
import { home } from './home/home'
import {
gamesIframe,
livesIframe,
mangaIframe,
} from './iframe/iframe'
import { gamesIframe, livesIframe, mangaIframe } from './iframe/iframe'
import { blanks } from './flexible-blank/flexible-blank'
import {
bangumi,
music,
drawing,
shop,
match,
} from './simple-links/simple-links'
import { bangumi, music, drawing, shop, match } from './simple-links/simple-links'
import { upload } from './upload/upload'
import { search } from './search/search'
import { feeds } from './feeds/feeds'

View File

@ -83,9 +83,13 @@ export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
throw new Error('Missing CustomNavbarItem content')
}
addComponentListener('customNavbar.touch', (value: boolean) => {
this.touch = value ? init.touch : false
}, true)
addComponentListener(
'customNavbar.touch',
(value: boolean) => {
this.touch = value ? init.touch : false
},
true,
)
this.hidden = CustomNavbarItem.navbarOptions.hidden.includes(this.name)
const orderMap = CustomNavbarItem.navbarOptions.order
this.order = orderMap[this.name] || 0

View File

@ -1,47 +1,46 @@
import { ComponentEntry } from '@/components/types'
import { addComponentListener } from '@/core/settings'
import {
isIframe,
isNotHtml,
matchUrlPattern,
mountVueComponent,
} from '@/core/utils'
import { isIframe, isNotHtml, matchUrlPattern, mountVueComponent } from '@/core/utils'
export const entry: ComponentEntry = async ({ metadata: { name } }) => {
// const url = document.URL.replace(location.search, '')
// const isHome = url === 'https://www.bilibili.com/' || url === 'https://www.bilibili.com/index.html'
if (
isIframe()
isIframe() ||
// (getComponentSettings('bilibiliSimpleNewHomeCompatible').enabled && isHome) ||
|| isNotHtml()
isNotHtml()
) {
return
}
addComponentListener(`${name}.padding`, value => {
document.documentElement.style.setProperty('--navbar-bounds-padding', `${value}%`)
}, true)
addComponentListener(
`${name}.padding`,
value => {
document.documentElement.style.setProperty('--navbar-bounds-padding', `${value}%`)
},
true,
)
const globalFixedExclude = [
'https://space.bilibili.com',
'https://www.bilibili.com/read',
'https://www.bilibili.com/account/history',
]
if (!globalFixedExclude.some(p => matchUrlPattern(p))) {
addComponentListener(`${name}.globalFixed`, value => {
document.body.classList.toggle('fixed-navbar', value)
}, true)
addComponentListener(
`${name}.globalFixed`,
value => {
document.body.classList.toggle('fixed-navbar', value)
},
true,
)
}
const CustomNavbar = await import('./CustomNavbar.vue')
const customNavbar: Vue & {
styles: string[]
toggleStyle: (value: boolean, style: string) => void
} = mountVueComponent(CustomNavbar)
document.body.insertAdjacentElement('beforeend', customNavbar.$el);
['fill', 'shadow', 'blur'].forEach(style => {
addComponentListener(
`${name}.${style}`,
value => customNavbar.toggleStyle(value, style),
true,
)
document.body.insertAdjacentElement('beforeend', customNavbar.$el)
;['fill', 'shadow', 'blur'].forEach(style => {
addComponentListener(`${name}.${style}`, value => customNavbar.toggleStyle(value, style), true)
})
}

View File

@ -13,9 +13,7 @@
</VDropdown>
</template>
<script lang="ts">
import {
VDropdown,
} from '@/ui'
import { VDropdown } from '@/ui'
import { getUID } from '@/core/utils'
import { getJsonWithCredentials } from '@/core/ajax'
import { getComponentSettings } from '@/core/settings'
@ -51,17 +49,14 @@ export default Vue.extend({
if (json.code !== 0) {
throw new Error(`获取收藏夹列表失败: ${json.message}`)
}
this.folders = lodash.get(json, 'data.list', []).map((item: {
id: number
title: string
media_count: number
}) => (
{
id: item.id,
name: item.title,
count: item.media_count,
} as FavoritesFolder
))
this.folders = lodash.get(json, 'data.list', []).map(
(item: { id: number; title: string; media_count: number }) =>
({
id: item.id,
name: item.title,
count: item.media_count,
} as FavoritesFolder),
)
if (this.folders.length > 0 && this.folder.id === notSelectedFolder.id) {
const { lastFavoriteFolder } = navbarOptions
const folder = this.folders.find((f: FavoritesFolder) => f.id === lastFavoriteFolder)

View File

@ -39,7 +39,8 @@
target="_blank"
:href="'https://www.bilibili.com/video/' + card.bvid"
:title="card.title"
>{{ card.title }}</a>
>{{ card.title }}</a
>
<a
v-if="card.upID"
class="up"
@ -47,18 +48,10 @@
:href="'https://space.bilibili.com/' + card.upID"
:title="card.upName"
>
<DpiImage
placeholder-image
class="face"
:src="card.upFaceUrl"
:size="20"
></DpiImage>
<DpiImage placeholder-image class="face" :src="card.upFaceUrl" :size="20"></DpiImage>
<div class="name">{{ card.upName }}</div>
</a>
<div
v-else
class="description"
>
<div v-else class="description">
{{ card.description }}
</div>
</div>
@ -72,15 +65,7 @@
</div>
</template>
<script lang="ts">
import {
VLoading,
VEmpty,
VIcon,
VButton,
TextBox,
DpiImage,
ScrollTrigger,
} from '@/ui'
import { VLoading, VEmpty, VIcon, VButton, TextBox, DpiImage, ScrollTrigger } from '@/ui'
import { formatDate, formatDuration } from '@/core/utils/formatters'
import { getUID } from '@/core/utils'
import { getJsonWithCredentials } from '@/core/ajax'
@ -131,8 +116,12 @@ async function searchAllList() {
}
try {
this.loading = true
const jsonCurrent = await getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=0&tid=0&platform=web`)
const jsonAll = await getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=1&tid=0&platform=web`)
const jsonCurrent = await getJsonWithCredentials(
`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=0&tid=0&platform=web`,
)
const jsonAll = await getJsonWithCredentials(
`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=1&tid=0&platform=web`,
)
if (jsonCurrent.code !== 0 && jsonAll.code !== 0) {
return
}
@ -222,8 +211,7 @@ export default Vue.extend({
this.hasMoreSearchPage = true
this.searchPage = 1
this.filteredCards = (this.cards as FavoritesItemInfo[]).filter(
it => it.title.toLowerCase().includes(keyword)
|| it.upName.toLowerCase().includes(keyword),
it => it.title.toLowerCase().includes(keyword) || it.upName.toLowerCase().includes(keyword),
)
},
},
@ -238,9 +226,7 @@ export default Vue.extend({
//
return []
}
return json.data.medias
.filter(favoriteItemFilter)
.map(favoriteItemMapper)
return json.data.medias.filter(favoriteItemFilter).map(favoriteItemMapper)
},
async changeList() {
if (this.folder.id === 0) {
@ -284,8 +270,8 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "common";
@import "../popup";
@import 'common';
@import '../popup';
.custom-navbar .favorites-list {
width: 380px;

View File

@ -1,10 +1,6 @@
<template>
<div class="navbar-feeds">
<TabControl
ref="tabControl"
:tabs="tabs"
more-link="https://t.bilibili.com/"
>
<TabControl ref="tabControl" :tabs="tabs" more-link="https://t.bilibili.com/">
<template #more-link>
所有动态
<VIcon icon="feeds" :size="18"></VIcon>
@ -13,10 +9,7 @@
</div>
</template>
<script lang="ts">
import {
TabControl,
VIcon,
} from '@/ui'
import { TabControl, VIcon } from '@/ui'
import { feedsCardTypes } from '@/components/feeds/api'
import { getNotifyCount } from '@/components/feeds/notify'
import { popperMixin } from '../mixins'
@ -61,7 +54,7 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "../popup";
@import '../popup';
.navbar-feeds {
width: 380px;

View File

@ -3,13 +3,7 @@
<VLoading v-if="loading"></VLoading>
<VEmpty v-else-if="!loading && cards.length === 0"></VEmpty>
<transition-group name="cards" tag="div" class="live-feeds-content">
<a
v-for="c of cards"
:key="c.id"
class="live-card"
target="_blank"
:href="c.url"
>
<a v-for="c of cards" :key="c.id" class="live-card" target="_blank" :href="c.url">
<div class="face-container">
<DpiImage class="face" :size="48" :src="c.upFaceUrl"></DpiImage>
</div>
@ -22,11 +16,7 @@
</div>
</template>
<script lang="ts">
import {
VLoading,
VEmpty,
DpiImage,
} from '@/ui'
import { VLoading, VEmpty, DpiImage } from '@/ui'
import { responsiveGetPages, getJsonWithCredentials } from '@/core/ajax'
import { LiveFeedItem } from './live-feed-item'
@ -57,9 +47,10 @@ export default Vue.extend({
},
async created() {
const [responsive] = responsiveGetPages({
api: page => getJsonWithCredentials(
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=24`,
),
api: page =>
getJsonWithCredentials(
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=24`,
),
getList: json => lodash.get(json, 'data.list', []),
getTotal: json => lodash.get(json, 'data.results', 0),
})
@ -69,7 +60,7 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "common";
@import 'common';
.live-feeds {
width: 100%;
@include v-center();
@ -121,7 +112,7 @@ export default Vue.extend({
}
.live-title {
font-size: 14px;
font-weight: bold;
@include semi-bold();
padding: 0 12px;
padding-bottom: 6px;
@include single-line();
@ -132,7 +123,7 @@ export default Vue.extend({
color: var(--theme-color);
}
.live-name {
opacity: .75;
opacity: 0.75;
padding: 0 12px;
@include single-line();
line-height: normal;

View File

@ -2,7 +2,8 @@
*
* ()
*/
export const getBangumiFeedsMockup = async () => JSON.parse(`{
export const getBangumiFeedsMockup = async () =>
JSON.parse(`{
"code": 0,
"msg": "",
"message": "",

View File

@ -7,11 +7,7 @@ import {
import { descendingStringSort } from '@/core/utils/sort'
import { logError } from '@/core/utils/log'
import { setLatestID } from '@/components/feeds/notify'
import {
VLoading,
VEmpty,
ScrollTrigger,
} from '@/ui'
import { VLoading, VEmpty, ScrollTrigger } from '@/ui'
/**
* Vue Mixin
@ -21,7 +17,8 @@ import {
export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
type: FeedsCardType,
jsonMapper: (obj: RawItem) => MappedItem,
) => (Vue.extend({
) =>
Vue.extend({
components: {
VLoading,
VEmpty,
@ -44,7 +41,7 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
const cards = this.sortedCards as MappedItem[]
if (cards.length > 0) {
setLatestID(cards[0].id)
// console.log('setLatestID', cards[0].id)
// console.log('setLatestID', cards[0].id)
}
},
methods: {
@ -77,7 +74,8 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
this.hasMorePage = false
return
}
this.hasMorePage = lastCardID === 0 ? true : Boolean(lodash.get(json, 'data.has_more', true))
this.hasMorePage =
lastCardID === 0 ? true : Boolean(lodash.get(json, 'data.has_more', true))
} catch (error) {
logError(error)
} finally {
@ -85,4 +83,4 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
}
},
},
}))
})

View File

@ -17,6 +17,7 @@ li.nav-item[report-id="playpage_dynamic"] .i-frame,
.van-popover {
z-index: 10002 !important;
}
.bili-header,
.international-header {
min-height: var(--navbar-height) !important;
}

View File

@ -6,10 +6,7 @@
<TextBox v-model="search" placeholder="搜索" linear></TextBox>
</div>
<div class="operations">
<div
class="operation"
@click="toggleHistoryPause"
>
<div class="operation" @click="toggleHistoryPause">
<VButton v-if="!paused" title="暂停记录历史" round>
<VIcon icon="mdi-pause" :size="14"></VIcon>
</VButton>
@ -17,11 +14,7 @@
<VIcon icon="mdi-play" :size="14"></VIcon>
</VButton>
</div>
<a
class="operation"
target="_blank"
href="https://www.bilibili.com/account/history"
>
<a class="operation" target="_blank" href="https://www.bilibili.com/account/history">
<VButton title="查看更多" round>
<VIcon icon="mdi-dots-horizontal" :size="18"></VIcon>
</VButton>
@ -29,9 +22,7 @@
</div>
</div>
<div class="header-row">
<div class="row-title">
过滤:
</div>
<div class="row-title">过滤:</div>
<div class="type-filters">
<div v-for="t of types" :key="t.name" class="type-filter">
<VButton
@ -55,11 +46,7 @@
<div class="time-group-name">
{{ g.name }}
</div>
<transition-group
name="time-group"
tag="div"
class="time-group-items"
>
<transition-group name="time-group" tag="div" class="time-group-items">
<div v-for="h of g.items" :key="h.id" class="time-group-item">
<a class="cover-container" target="_blank" :href="h.url">
<DpiImage
@ -73,26 +60,21 @@
class="progress"
:style="{ width: h.progress * 100 + '%' }"
></div>
<div
v-if="h.progressText"
class="floating progress-number"
>{{ h.progress >= 1 ? '已看完' : h.progressText }}</div>
<div v-if="h.progressText" class="floating progress-number">
{{ h.progress >= 1 ? '已看完' : h.progressText }}
</div>
<div
v-if="h.liveStatus !== undefined"
class="floating duration live-status"
:class="{ on: h.liveStatus === 1 }"
>{{ h.liveStatus === 1 ? '直播中': '未开播' }}</div>
<div
v-if="h.durationText"
class="floating duration"
>{{ h.durationText }}</div>
>
{{ h.liveStatus === 1 ? '直播中' : '未开播' }}
</div>
<div v-if="h.durationText" class="floating duration">{{ h.durationText }}</div>
</a>
<a
class="title"
target="_blank"
:href="h.url"
:title="h.title"
>{{ h.title || h.upName + '的直播间' }}</a>
<a class="title" target="_blank" :href="h.url" :title="h.title">{{
h.title || h.upName + '的直播间'
}}</a>
<a
class="up"
target="_blank"
@ -107,11 +89,7 @@
></DpiImage>
<div class="up-name">{{ h.upName }}</div>
</a>
<div
v-if="h.timeText"
class="time"
:title="new Date(h.viewAt).toLocaleString()"
>
<div v-if="h.timeText" class="time" :title="new Date(h.viewAt).toLocaleString()">
{{ h.timeText }}
</div>
</div>
@ -130,19 +108,9 @@
import { bilibiliApi, getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
import { formData, getCsrf } from '@/core/utils'
import { descendingSort } from '@/core/utils/sort'
import {
VButton,
VIcon,
TextBox,
VLoading,
VEmpty,
ScrollTrigger,
DpiImage,
} from '@/ui'
import { VButton, VIcon, TextBox, VLoading, VEmpty, ScrollTrigger, DpiImage } from '@/ui'
import { popperMixin } from '../mixins'
import {
types, TypeFilter, HistoryItem, getHistoryItems, group,
} from './types'
import { types, TypeFilter, HistoryItem, getHistoryItems, group } from './types'
export default Vue.extend({
components: {
@ -170,10 +138,10 @@ export default Vue.extend({
computed: {
canNextPage() {
return (
this.search === ''
&& !this.loading
&& this.hasMorePage
&& this.types.every((t: TypeFilter) => t.checked)
this.search === '' &&
!this.loading &&
this.hasMorePage &&
this.types.every((t: TypeFilter) => t.checked)
)
},
},
@ -184,10 +152,7 @@ export default Vue.extend({
},
async created() {
try {
await Promise.all([
this.nextPage(),
this.updateHistoryPauseState(),
])
await Promise.all([this.nextPage(), this.updateHistoryPauseState()])
} finally {
this.loading = false
}
@ -202,8 +167,8 @@ export default Vue.extend({
return false
}
if (
!item.title.toLowerCase().includes(this.search.toLowerCase())
&& !item.upName.toLowerCase().includes(this.search.toLowerCase())
!item.title.toLowerCase().includes(this.search.toLowerCase()) &&
!item.upName.toLowerCase().includes(this.search.toLowerCase())
) {
return false
}
@ -215,9 +180,7 @@ export default Vue.extend({
async nextPage() {
const items = await getHistoryItems(this.viewTime)
const cards: HistoryItem[] = lodash.uniqBy(
this.cards
.concat(items)
.sort(descendingSort((item: HistoryItem) => item.viewAt)),
this.cards.concat(items).sort(descendingSort((item: HistoryItem) => item.viewAt)),
item => item.id,
)
this.cards = cards
@ -228,7 +191,9 @@ export default Vue.extend({
this.hasMorePage = cards.length !== 0
},
async updateHistoryPauseState() {
const result = await bilibiliApi(getJsonWithCredentials('https://api.bilibili.com/x/v2/history/shadow'))
const result = await bilibiliApi(
getJsonWithCredentials('https://api.bilibili.com/x/v2/history/shadow'),
)
/*
result == true: 暂停
result == {}: 没暂停
@ -254,8 +219,8 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "common";
@import "../popup";
@import 'common';
@import '../popup';
.custom-navbar-history-list {
width: 350px;

View File

@ -95,9 +95,18 @@ const formatTime = (date: Date) => {
const { yesterday } = getTimeData()
const timestamp = Number(date)
if (timestamp >= yesterday) {
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
return `${date.getHours().toString().padStart(2, '0')}:${date
.getMinutes()
.toString()
.padStart(2, '0')}`
}
return `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
return `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
.getDate()
.toString()
.padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date
.getMinutes()
.toString()
.padStart(2, '0')}`
}
const parseHistoryItem = (item: any): HistoryItem => {
if (item.history.business === 'article') {
@ -110,7 +119,7 @@ const parseHistoryItem = (item: any): HistoryItem => {
oid, // 直播 房间号 / 专栏 cv 号
} = item.history
const progressParam = item.progress > 0 ? `t=${item.progress}` : 't=0'
const progress = item.progress === -1 ? 1 : (item.progress / item.duration)
const progress = item.progress === -1 ? 1 : item.progress / item.duration
const https = (url: string) => url.replace('http:', 'https:')
const time = new Date(item.view_at * 1000)
const cover = (() => {

View File

@ -9,10 +9,7 @@
>
<a :href="data.link" target="_blank">
<svg aria-hidden="true">
<use
:href="'#header-icon-' + data.icon"
:xlink:href="'#header-icon-' + data.icon"
/>
<use :href="'#header-icon-' + data.icon" :xlink:href="'#header-icon-' + data.icon" />
</svg>
<div class="name">{{ name }}</div>
<span class="count">
@ -26,7 +23,8 @@
class="sub-region"
:href="url"
target="_blank"
>{{ regionName }}</a>
>{{ regionName }}</a
>
</div>
</div>
</div>
@ -94,8 +92,8 @@ export default Vue.extend({
// 3. https://stackoverflow.com/a/33899301/13860169
flex-direction: row;
writing-mode: vertical-lr;
&>* {
writing-mode: horizontal-tb
& > * {
writing-mode: horizontal-tb;
}
.category-item {

View File

@ -1,10 +1,5 @@
<template>
<iframe
:src="item.src"
frameborder="0"
:width="item.width"
:height="item.height"
></iframe>
<iframe :src="item.src" frameborder="0" :width="item.width" :height="item.height"></iframe>
</template>
<script lang="ts">

View File

@ -1,4 +1,8 @@
import { defineComponentMetadata, defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
import {
defineComponentMetadata,
defineOptionsMetadata,
OptionsOfMetadata,
} from '@/components/define'
import { LaunchBarActionProvider } from '@/components/launch-bar/launch-bar-action'
import { urlInclude, urlExclude } from './urls'
import { entry } from './entry'
@ -77,10 +81,7 @@ export const component = defineComponentMetadata({
name: 'customNavbar',
displayName: '自定义顶栏',
entry,
tags: [
componentsTags.style,
componentsTags.general,
],
tags: [componentsTags.style, componentsTags.general],
options,
urlInclude,
urlExclude,
@ -110,15 +111,17 @@ export const component = defineComponentMetadata({
addData('launchBar.actions', (providers: LaunchBarActionProvider[]) => {
providers.push({
name: 'navbarSettings',
getActions: async () => [{
name: '自定义顶栏设置',
description: 'Custom Navbar Settings',
icon: 'mdi-sort',
action: async () => {
const { toggleNavbarSettings } = await import('./settings/vm')
toggleNavbarSettings()
getActions: async () => [
{
name: '自定义顶栏设置',
description: 'Custom Navbar Settings',
icon: 'mdi-sort',
action: async () => {
const { toggleNavbarSettings } = await import('./settings/vm')
toggleNavbarSettings()
},
},
}],
],
})
})
},

View File

@ -37,17 +37,12 @@ export default Vue.extend({
this.seasonLogoUrl = ''
return
}
const json = await getJson(
'https://api.bilibili.com/x/web-show/page/header?resource_id=1',
)
const json = await getJson('https://api.bilibili.com/x/web-show/page/header?resource_id=1')
if (json.code !== 0) {
this.seasonLogoUrl = ''
return
}
this.seasonLogoUrl = lodash.get(json, 'data.litpic', '').replace(
'http:',
'https:',
)
this.seasonLogoUrl = lodash.get(json, 'data.litpic', '').replace('http:', 'https:')
},
true,
)

View File

@ -7,7 +7,8 @@
:href="e.href"
:data-count="e.count || null"
@click="clearCount(e)"
>{{ e.name }}</a>
>{{ e.name }}</a
>
</div>
</div>
</template>
@ -99,9 +100,7 @@ export default Vue.extend({
return
}
const [mainJson, messageJson] = await Promise.all([
getJsonWithCredentials(
'https://api.bilibili.com/x/msgfeed/unread',
),
getJsonWithCredentials('https://api.bilibili.com/x/msgfeed/unread'),
getJsonWithCredentials(
'https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread',
),

View File

@ -1,10 +1,7 @@
<template>
<div class="ranking-popup" role="list">
<div v-for="e of entries" :key="e.name" class="ranking-entry" role="listitem">
<a
target="_blank"
:href="e.href"
>{{ e.name }}</a>
<a target="_blank" :href="e.href">{{ e.name }}</a>
</div>
</div>
</template>

View File

@ -17,7 +17,7 @@ export default Vue.extend({
// transparent mode / no fill
.launch-bar {
--color: var(--custom-navbar-foreground);
background-color: #000A;
background-color: #000a;
opacity: 0.5;
transition: opacity 0.2s ease-out;
padding: 2px 6px;

View File

@ -13,11 +13,7 @@
<script lang="ts">
import { getUID } from '@/core/utils'
import { VIcon, VButton } from '@/ui'
import {
setTriggerElement,
loadNavbarSettings,
toggleNavbarSettings,
} from './vm'
import { setTriggerElement, loadNavbarSettings, toggleNavbarSettings } from './vm'
export default Vue.extend({
components: {

View File

@ -9,9 +9,7 @@
>
<div class="navbar-settings-header">
<VIcon class="title-icon" icon="mdi-sort" :size="24"></VIcon>
<div class="title">
顶栏布局设置
</div>
<div class="title">顶栏布局设置</div>
<div class="grow"></div>
<div class="close" @click="open = false">
<VIcon icon="close" :size="18"></VIcon>
@ -19,9 +17,7 @@
</div>
<div class="navbar-settings-content">
<div class="navbar-settings-section">
<div class="navbar-settings-section-title">
边缘间距
</div>
<div class="navbar-settings-section-title">边缘间距</div>
<div class="navbar-settings-section-description">
设定两侧边缘处的间距, 单位为百分比, 100%为整个顶栏的宽度.
<br />空间不足时, 实际呈现的间距会自动缩小.
@ -32,18 +28,12 @@
@mouseout="peekPadding(false)"
>
<VSlider v-model="padding" :min="0" :max="40" :step="0.5"></VSlider>
<div class="padding-value">
{{ padding.toFixed(1) }}%
</div>
<div class="padding-value">{{ padding.toFixed(1) }}%</div>
</div>
</div>
<div class="navbar-settings-section">
<div class="navbar-settings-section-title">
元素呈现
</div>
<div
class="navbar-settings-section-description"
>
<div class="navbar-settings-section-title">元素呈现</div>
<div class="navbar-settings-section-description">
按住并拖动可以调整顺序, 点击眼睛图标可以切换隐藏/显示.
</div>
<VLoading v-if="!loaded" />
@ -67,11 +57,7 @@
<div class="toggle-visible">
<VIcon
:size="18"
:icon="
item.hidden
? 'mdi-eye-off-outline'
: 'mdi-eye-outline'
"
:icon="item.hidden ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
@click="toggleVisible(item)"
></VIcon>
</div>
@ -83,26 +69,20 @@
</template>
<script lang="ts">
import { SortableEvent } from 'sortablejs'
import {
VPopup,
VIcon,
VSlider,
VLoading,
} from '@/ui'
import { VPopup, VIcon, VSlider, VLoading } from '@/ui'
import { addComponentListener } from '@/core/settings'
import { dqa } from '@/core/utils'
import { SortableJSLibrary } from '@/core/runtime-library'
import { getData } from '@/plugins/data'
import {
CustomNavbarItem,
CustomNavbarRenderedItems,
} from '../custom-navbar-item'
import { CustomNavbarItem, CustomNavbarRenderedItems } from '../custom-navbar-item'
import { checkSequentialOrder, sortItems } from './orders'
const { navbarOptions } = CustomNavbarItem
const [rendered] = getData(CustomNavbarRenderedItems) as [{
items: CustomNavbarItem[]
}]
const [rendered] = getData(CustomNavbarRenderedItems) as [
{
items: CustomNavbarItem[]
},
]
export default Vue.extend({
components: {
VPopup,
@ -166,9 +146,9 @@ export default Vue.extend({
const container = this.$refs.navbarSortList as HTMLElement
const element = e.item
console.log(`${element.getAttribute('data-name')} ${e.oldIndex}->${e.newIndex}`)
const ordersMap = Object.fromEntries([...container.children].map((el, index) => (
[el.getAttribute('data-name') as string, index]
)))
const ordersMap = Object.fromEntries(
[...container.children].map((el, index) => [el.getAttribute('data-name') as string, index]),
)
this.rendered.items = sortItems(rendered.items, ordersMap)
},
toggleVisible(item: CustomNavbarItem) {
@ -186,7 +166,7 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "common";
@import 'common';
.custom-navbar-settings {
@include popup();
width: 400px;

View File

@ -7,7 +7,7 @@ const regenerateOrder = (items: CustomNavbarItem[]) => {
}
item.order = index
})
const orderMap = Object.fromEntries(items.map(it => ([it.name, it.order])))
const orderMap = Object.fromEntries(items.map(it => [it.name, it.order]))
CustomNavbarItem.navbarOptions.order = orderMap
}
export const checkSequentialOrder = (items: CustomNavbarItem[]) => {

View File

@ -38,7 +38,7 @@ export default Vue.extend({
})
</script>
<style lang="scss">
@import "../popup";
@import '../popup';
.navbar-subscriptions {
width: 380px;

View File

@ -17,27 +17,18 @@
<div class="card-info">
<h1 class="title" :title="card.title">{{ card.title }}</h1>
<div class="progress-row">
<div
v-if="card.status"
class="status"
:class="'status-' + card.status"
>{{ card.statusText }}</div>
<div v-if="card.status" class="status" :class="'status-' + card.status">
{{ card.statusText }}
</div>
<div
v-if="card.progress"
class="progress"
:title="card.progress + ' | ' + card.latest"
>{{ card.progress }} | {{ card.latest }}</div>
<div
v-else
class="progress"
:title="card.latest"
>{{ card.latest }}</div>
<a
class="info"
:href="card.mediaUrl"
target="_blank"
title="详细信息"
>
{{ card.progress }} | {{ card.latest }}
</div>
<div v-else class="progress" :title="card.latest">{{ card.latest }}</div>
<a class="info" :href="card.mediaUrl" target="_blank" title="详细信息">
<VIcon icon="mdi-information-outline" :size="16"></VIcon>
</a>
</div>
@ -52,13 +43,7 @@
<script lang="ts">
import { getUID } from '@/core/utils'
import { logError } from '@/core/utils/log'
import {
DpiImage,
VLoading,
VEmpty,
VIcon,
ScrollTrigger,
} from '@/ui'
import { DpiImage, VLoading, VEmpty, VIcon, ScrollTrigger } from '@/ui'
import { getJsonWithCredentials } from '@/core/ajax'
import { SubscriptionTypes } from './subscriptions'
@ -129,22 +114,24 @@ export default Vue.extend({
logError(`加载订阅信息失败: ${json.message}`)
return
}
const cards = lodash.uniqBy(
(this.cards as any[]).concat(
(lodash.get(json, 'data.list') as any[]).map(item => ({
title: item.title,
coverUrl: item.square_cover.replace('http:', 'https:'),
latest: item.new_ep.index_show,
progress: item.progress,
id: item.season_id,
status: item.follow_status,
statusText: getStatusText(item.follow_status),
playUrl: `https://www.bilibili.com/bangumi/play/ss${item.season_id}`,
mediaUrl: `https://www.bilibili.com/bangumi/media/md${item.media_id}`,
})),
),
card => card.id,
).sort(subscriptionSorter)
const cards = lodash
.uniqBy(
(this.cards as any[]).concat(
(lodash.get(json, 'data.list') as any[]).map(item => ({
title: item.title,
coverUrl: item.square_cover.replace('http:', 'https:'),
latest: item.new_ep.index_show,
progress: item.progress,
id: item.season_id,
status: item.follow_status,
statusText: getStatusText(item.follow_status),
playUrl: `https://www.bilibili.com/bangumi/play/ss${item.season_id}`,
mediaUrl: `https://www.bilibili.com/bangumi/media/md${item.media_id}`,
})),
),
card => card.id,
)
.sort(subscriptionSorter)
this.page++
this.cards = cards
this.hasMorePage = lodash.get(json, 'data.total', 0) > this.cards.length
@ -157,7 +144,7 @@ export default Vue.extend({
</script>
<style lang="scss">
@import "common";
@import 'common';
.subscription-list {
width: 100%;

View File

@ -12,7 +12,10 @@ export const checkTransparentFill = async (vm: {
return
}
sq(
() => dqa('.animated-banner video, .banner-img img, #banner_link, .international-header .bili-banner, .bili-header__banner'),
() =>
dqa(
'.animated-banner video, .banner-img img, #banner_link, .international-header .bili-banner, .bili-header__banner',
),
banners => {
if (banners.length === 0) {
return false
@ -35,11 +38,15 @@ export const checkTransparentFill = async (vm: {
if (banner.length === 0) {
return
}
addComponentListener('customNavbar.transparent', value => {
if (!getComponentSettings('hideBanner').enabled) {
vm.toggleStyle(value, 'transparent')
}
}, true)
addComponentListener(
'customNavbar.transparent',
value => {
if (!getComponentSettings('hideBanner').enabled) {
vm.toggleStyle(value, 'transparent')
}
},
true,
)
addComponentListener('hideBanner', value => {
if (getComponentSettings('customNavbar').options.transparent) {
vm.toggleStyle(!value, 'transparent')

View File

@ -1,9 +1,7 @@
<template>
<div class="navbar-upload">
<VIcon icon="upload" :size="18"></VIcon>
<div class="navbar-upload-name">
投稿
</div>
<div class="navbar-upload-name">投稿</div>
</div>
</template>
<script lang="ts">

View File

@ -1,34 +1,21 @@
<template>
<div role="list" class="upload-popup">
<div role="listitem">
<a
target="_blank"
href="https://member.bilibili.com/platform/upload/text/apply"
>专栏投稿</a>
<a target="_blank" href="https://member.bilibili.com/platform/upload/text/apply">专栏投稿</a>
</div>
<div role="listitem">
<a
target="_blank"
href="https://member.bilibili.com/platform/upload/audio/frame"
>音频投稿</a>
<a target="_blank" href="https://member.bilibili.com/platform/upload/audio/frame">音频投稿</a>
</div>
<div role="listitem">
<a
target="_blank"
href="https://member.bilibili.com/platform/upload/sticker"
>贴纸投稿</a>
<a target="_blank" href="https://member.bilibili.com/platform/upload/sticker">贴纸投稿</a>
</div>
<div role="listitem">
<a
target="_blank"
href="https://member.bilibili.com/platform/upload/video/frame"
>视频投稿</a>
<a target="_blank" href="https://member.bilibili.com/platform/upload/video/frame">视频投稿</a>
</div>
<div role="listitem">
<a
target="_blank"
href="https://member.bilibili.com/platform/upload-manager/article"
>投稿管理</a>
<a target="_blank" href="https://member.bilibili.com/platform/upload-manager/article"
>投稿管理</a
>
</div>
<div role="listitem">
<a target="_blank" href="https://member.bilibili.com/platform/home">创作中心</a>
@ -43,7 +30,7 @@ export default Vue.extend({
})
</script>
<style lang="scss" scoped>
@import "../nav-link";
@import '../nav-link';
.upload-popup {
width: max-content;
a {

View File

@ -1,16 +1,10 @@
<template>
<div class="user-info-panel">
<div v-if="isLogin && userInfo.isLogin === true" class="logged-in">
<a
class="name"
target="_blank"
href="https://space.bilibili.com/"
>{{ userInfo.uname }}</a>
<a
class="type"
target="_blank"
href="https://account.bilibili.com/account/big"
>{{ userType }}</a>
<a class="name" target="_blank" href="https://space.bilibili.com/">{{ userInfo.uname }}</a>
<a class="type" target="_blank" href="https://account.bilibili.com/account/big">{{
userType
}}</a>
<div v-if="userInfo.vipStatus === 1 && userInfo.vipType === 2" class="privileges row">
<div
class="b-coin"
@ -43,15 +37,11 @@
:size="30"
class="level-icon plus"
/>
<VIcon
v-else
:icon="'lv' + userInfo.level_info.current_level"
class="level-icon"
/>
<VIcon v-else :icon="'lv' + userInfo.level_info.current_level" class="level-icon" />
</a>
<span
class="level-progress-label"
>{{ userInfo.level_info.current_exp }} / {{ userInfo.level_info.next_exp }}</span>
<span class="level-progress-label"
>{{ userInfo.level_info.current_exp }} / {{ userInfo.level_info.next_exp }}</span
>
</div>
<div class="level-progress separator">
<div class="level-progress-thumb" :style="levelProgressStyle"></div>
@ -77,21 +67,11 @@
<VIcon v-if="userInfo.email_verified" icon="ok" :size="18"></VIcon>
<VIcon v-else icon="cancel" :size="18"></VIcon>
</a>
<a
class="item"
target="_blank"
href="https://account.bilibili.com/site/coin"
title="硬币"
>
<a class="item" target="_blank" href="https://account.bilibili.com/site/coin" title="硬币">
<VIcon icon="coin-outline" :size="20"></VIcon>
<span>{{ userInfo.money }}</span>
</a>
<a
class="item"
target="_blank"
href="https://pay.bilibili.com/bb_balance.html"
title="B币"
>
<a class="item" target="_blank" href="https://pay.bilibili.com/bb_balance.html" title="B币">
<VIcon icon="b-coin-outline" :size="20"></VIcon>
<span>{{ userInfo.wallet.bcoin_balance }}</span>
</a>
@ -103,21 +83,24 @@
:href="'https://space.bilibili.com/' + userInfo.mid + '/fans/follow'"
target="_blank"
>
<div class="stats-number">{{ stat.following | count }}</div>关注
<div class="stats-number">{{ stat.following | count }}</div>
关注
</a>
<a
class="stats-item"
:href="'https://space.bilibili.com/' + userInfo.mid + '/fans/fans'"
target="_blank"
>
<div class="stats-number">{{ stat.follower | count }}</div>粉丝
<div class="stats-number">{{ stat.follower | count }}</div>
粉丝
</a>
<a
class="stats-item"
:href="'https://space.bilibili.com/' + userInfo.mid + '/dynamic'"
target="_blank"
>
<div class="stats-number">{{ stat.dynamic_count | count }}</div>动态
<div class="stats-number">{{ stat.dynamic_count | count }}</div>
动态
</a>
</div>
<div class="separator"></div>
@ -159,25 +142,14 @@
>
<VIcon icon="course"></VIcon>我的课程
</a>
<div
class="logout grey-button"
@click="logout()"
>
退出登录
</div>
<div class="logout grey-button" @click="logout()">退出登录</div>
</div>
<div v-if="!isLogin" class="not-logged-in">
<h1 class="welcome">
欢迎来到 bilibili
</h1>
<a
href="https://passport.bilibili.com/register/phone.html"
class="signup grey-button"
>注册</a>
<a
href="https://passport.bilibili.com/login"
class="login theme-button"
>登录</a>
<h1 class="welcome">欢迎来到 bilibili</h1>
<a href="https://passport.bilibili.com/register/phone.html" class="signup grey-button"
>注册</a
>
<a href="https://passport.bilibili.com/login" class="login theme-button">登录</a>
</div>
</div>
</template>
@ -260,30 +232,18 @@ export default Vue.extend({
async created() {
const userInfo = await getUserInfo()
this.userInfo = userInfo
const json = await getJsonWithCredentials(
'https://api.bilibili.com/x/web-interface/nav/stat',
)
const json = await getJsonWithCredentials('https://api.bilibili.com/x/web-interface/nav/stat')
this.stat = json.data || {}
if (this.isLogin && this.userInfo.vipType === 2) {
//
const privileges = await getJsonWithCredentials(
'https://api.bilibili.com/x/vip/privilege/my',
)
const privileges = await getJsonWithCredentials('https://api.bilibili.com/x/vip/privilege/my')
if (privileges.code === 0) {
const bCoin = privileges.data.list.find(
(it: { type: PrivilegeType }) => it.type === 1,
)
const bCoin = privileges.data.list.find((it: { type: PrivilegeType }) => it.type === 1)
this.privileges.bCoin.received = bCoin.state === 1
this.privileges.bCoin.expire = new Date(
bCoin.expire_time * 1000,
).toLocaleDateString()
const coupons = privileges.data.list.find(
(it: { type: PrivilegeType }) => it.type === 2,
)
this.privileges.bCoin.expire = new Date(bCoin.expire_time * 1000).toLocaleDateString()
const coupons = privileges.data.list.find((it: { type: PrivilegeType }) => it.type === 2)
this.privileges.coupons.received = coupons.state === 1
this.privileges.coupons.expire = new Date(
coupons.expire_time * 1000,
).toLocaleDateString()
this.privileges.coupons.expire = new Date(coupons.expire_time * 1000).toLocaleDateString()
}
}
},

View File

@ -4,7 +4,11 @@
<div class="search">
<TextBox v-model="search" linear placeholder="搜索"></TextBox>
</div>
<a class="operation" target="_blank" href="https://www.bilibili.com/medialist/play/watchlater">
<a
class="operation"
target="_blank"
href="https://www.bilibili.com/medialist/play/watchlater"
>
<VButton class="round-button" title="播放全部" round>
<VIcon icon="mdi-play" :size="18"></VIcon>
</VButton>
@ -17,39 +21,21 @@
</div>
<VLoading v-if="loading"></VLoading>
<VEmpty v-else-if="!loading && cards.length === 0"></VEmpty>
<transition-group
v-else
name="cards"
tag="div"
class="watchlater-list-content"
>
<div
v-for="(card, index) of filteredCards"
:key="card.aid"
class="watchlater-card"
>
<transition-group v-else name="cards" tag="div" class="watchlater-list-content">
<div v-for="(card, index) of filteredCards" :key="card.aid" class="watchlater-card">
<a class="cover-container" target="_blank" :href="card.href">
<DpiImage
class="cover"
:src="card.coverUrl"
:size="{ width: 130, height: 85 }"
></DpiImage>
<div
class="floating remove"
title="移除"
@click.prevent="remove(card.aid, index)"
>
<div class="floating remove" title="移除" @click.prevent="remove(card.aid, index)">
<VIcon icon="mdi-close" :size="16"></VIcon>
</div>
<div class="floating duration">{{ card.durationText }}</div>
<div v-if="card.complete" class="floating viewed">已观看</div>
</a>
<a
class="title"
target="_blank"
:href="card.href"
:title="card.title"
>{{ card.title }}</a>
<a class="title" target="_blank" :href="card.href" :title="card.title">{{ card.title }}</a>
<a
class="up"
target="_blank"
@ -72,14 +58,7 @@ import {
RawWatchlaterItem,
toggleWatchlater,
} from '@/components/video/watchlater'
import {
VLoading,
VEmpty,
TextBox,
VButton,
VIcon,
DpiImage,
} from '@/ui'
import { VLoading, VEmpty, TextBox, VButton, VIcon, DpiImage } from '@/ui'
import { popperMixin } from '../mixins'
interface WatchlaterCard {
@ -191,17 +170,17 @@ export default Vue.extend({
const search = this.search.toLowerCase()
const cardsList = this.$el.querySelector('.watchlater-list-content') as HTMLElement
cardsList.scrollTo(0, 0)
this.filteredCards = (this.cards as WatchlaterCard[]).filter(card => (
card.title.toLowerCase().includes(search)
|| card.upName.toLowerCase().includes(search)
))
this.filteredCards = (this.cards as WatchlaterCard[]).filter(
card =>
card.title.toLowerCase().includes(search) || card.upName.toLowerCase().includes(search),
)
}, 100),
},
})
</script>
<style lang="scss">
@import "common";
@import "../popup";
@import 'common';
@import '../popup';
.custom-navbar .watchlater-list {
@include navbar-popup-height();

View File

@ -264,26 +264,26 @@ blockquote {
}
}
::-webkit-scrollbar {
width: 5px !important;
height: 5px !important;
}
::-webkit-scrollbar-corner,
::-webkit-scrollbar-track {
background: transparent !important;
}
::-webkit-resizer,
::-webkit-scrollbar-thumb {
background: #444 !important;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #555 !important;
}
* {
scrollbar-color: #444 transparent !important;
scrollbar-width: thin !important;
}
// ::-webkit-scrollbar {
// width: 5px !important;
// height: 5px !important;
// }
// ::-webkit-scrollbar-corner,
// ::-webkit-scrollbar-track {
// background: transparent !important;
// }
// ::-webkit-resizer,
// ::-webkit-scrollbar-thumb {
// background: #444 !important;
// border-radius: 3px;
// }
// ::-webkit-scrollbar-thumb:hover {
// background: #555 !important;
// }
// * {
// scrollbar-color: #444 transparent !important;
// scrollbar-width: thin !important;
// }
.members-info .avatar-name__container .is-vip,
.members-info .wide-members .avatar .is-vip,
.up-info .up-info_right .name .username.is-vip {

View File

@ -22,10 +22,7 @@ export const component: ComponentMetadata = {
})
},
urlExclude: darkExcludes,
tags: [
componentsTags.style,
componentsTags.general,
],
tags: [componentsTags.style, componentsTags.general],
description: {
'zh-CN': `
使 / , \`夜间模式计划时段\` 一同使用.

View File

@ -8,7 +8,10 @@ const add = async () => {
localStorage.setItem('pbp_theme_v4', 'b')
const meta = dq('meta[name="theme-color"]') as HTMLMetaElement
if (!meta) {
document.head.insertAdjacentHTML('beforeend', `<meta name="theme-color" content="${darkMetaColor}">`)
document.head.insertAdjacentHTML(
'beforeend',
`<meta name="theme-color" content="${darkMetaColor}">`,
)
} else {
meta.dataset.light = meta.content
meta.content = darkMetaColor
@ -40,10 +43,7 @@ export const component = defineComponentMetadata({
setTimeout(remove, changeDelay)
},
description: '启用夜间模式能更好地适应光线暗的环境, 并会大量应用主题颜色.',
tags: [
componentsTags.style,
componentsTags.general,
],
tags: [componentsTags.style, componentsTags.general],
instantStyles: [
{
name: 'dark-mode',

View File

@ -13,14 +13,14 @@ class ScheduleTime {
this.hour = now.getHours()
this.minute = now.getMinutes()
} else if (args.length === 1) {
const [text] = args;
[this.hour, this.minute] = text
const [text] = args
;[this.hour, this.minute] = text
.split(':')
.slice(0, 2)
.map(it => ScheduleTime.validatePart(it))
this.normalize()
} else if (args.length === 2) {
[this.hour, this.minute] = args
;[this.hour, this.minute] = args
}
}
normalize() {
@ -40,17 +40,13 @@ class ScheduleTime {
}
}
lessThan(other: ScheduleTime) {
if (this.hour < other.hour
|| (this.hour === other.hour && this.minute < other.minute)
) {
if (this.hour < other.hour || (this.hour === other.hour && this.minute < other.minute)) {
return true
}
return false
}
greaterThan(other: ScheduleTime) {
if (this.hour > other.hour
|| (this.hour === other.hour && this.minute > other.minute)
) {
if (this.hour > other.hour || (this.hour === other.hour && this.minute > other.minute)) {
return true
}
return false
@ -113,11 +109,9 @@ const checkTime = (settings: ComponentSettings) => {
export const component: ComponentMetadata = {
name: 'darkModeSchedule',
displayName: '夜间模式计划时段',
description: '设置一个使用夜间模式的时间段, 进入 / 离开此时间段时, 会自动开启 / 关闭夜间模式. 结束时间小于起始时间时将视为次日, 如 `18:00` 至 `6:00` 表示晚上 18:00 到次日 6:00. 请勿和 \`夜间模式跟随系统\` 一同使用.',
tags: [
componentsTags.style,
componentsTags.general,
],
description:
'设置一个使用夜间模式的时间段, 进入 / 离开此时间段时, 会自动开启 / 关闭夜间模式. 结束时间小于起始时间时将视为次日, 如 `18:00` 至 `6:00` 表示晚上 18:00 到次日 6:00. 请勿和 `夜间模式跟随系统` 一同使用.',
tags: [componentsTags.style, componentsTags.general],
entry: ({ settings }) => fullyLoaded(() => checkTime(settings)),
urlExclude: darkExcludes,
options: {

View File

@ -4,9 +4,7 @@ import { bangumiUrls } from '@/core/utils/urls'
export const component = defineComponentMetadata({
displayName: '隐藏番剧点评',
tags: [
componentsTags.style,
],
tags: [componentsTags.style],
...toggleStyle('hideBangumiReviews', () => import('./reviews.scss')),
urlInclude: bangumiUrls,
description: {

View File

@ -4,9 +4,7 @@ import { bangumiUrls } from '@/core/utils/urls'
export const component = defineComponentMetadata({
displayName: '隐藏番剧承包',
tags: [
componentsTags.style,
],
tags: [componentsTags.style],
...toggleStyle('hideBangumiSponsors', () => import('./sponsors.scss')),
urlInclude: bangumiUrls,
description: {

View File

@ -11,10 +11,7 @@ export const component = defineComponentMetadata({
},
],
displayName: '隐藏直播推荐',
tags: [
componentsTags.style,
componentsTags.video,
],
tags: [componentsTags.style, componentsTags.video],
description: {
'zh-CN': '隐藏视频页面右侧下方的直播推荐.',
},

View File

@ -11,12 +11,10 @@ export const component = defineComponentMetadata({
style: () => import('./related-videos.scss'),
},
],
tags: [
componentsTags.style,
componentsTags.video,
],
tags: [componentsTags.style, componentsTags.video],
description: {
'zh-CN': '隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播 (自动播放下一个推荐视频) 功能, 需要先取消隐藏视频推荐才能看到开关.',
'zh-CN':
'隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播 (自动播放下一个推荐视频) 功能, 需要先取消隐藏视频推荐才能看到开关.',
},
urlInclude: videoAndBangumiUrls,
})

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