mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge branch 'preview-features' into preview
This commit is contained in:
commit
9f8ec17797
50
CHANGELOG.md
50
CHANGELOG.md
@ -1,5 +1,55 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
## v2.4.0
|
||||||
|
|
||||||
|
✨新增
|
||||||
|
<details>
|
||||||
|
<summary>正式版获得 v2.3.1 ~ v2.3.3 预览版的功能</summary>
|
||||||
|
|
||||||
|
- `清爽首页` 的热门视频支持显示弹幕数量.
|
||||||
|
- `极简首页` 初版已完成.
|
||||||
|
- 脚本的更新源配置默认值更换为 `GitHub`, 并添加了 `AltCdn`, 表示开发者自定义的其他 CDN 源. `jsDelivr` 将会删除.
|
||||||
|
- 在 `GitHub` 更新源下, MDI 图标库更换使用 GitHub Pages.
|
||||||
|
- 新增组件 `UP 主黑名单` by [snowraincloud](https://github.com/snowraincloud). (PR #3537)
|
||||||
|
- 在无限滚动的场景下, 点击那个 `加载中` 的标识 (ScrollTrigger) 可以手动触发加载下一页. 在遇到没有自动加载下一页的情况时会比较有用.
|
||||||
|
- `下载视频` 支持 `flac` 音源. (#3497)
|
||||||
|
- `自定义顶栏` 支持设置顶栏的高度, 设置为 64px 即为原版顶栏的高度. (#3136)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- `删除视频弹窗` 支持 3.x 播放器的 `关联视频` 和 `评分` 弹窗. (#3545)
|
||||||
|
- `展开弹幕列表` 支持设置 `最大弹幕数量`, 超过此数量不进行展开, 避免展开时卡死页面. (#2972)
|
||||||
|
- `图片批量导出` 在导出动态的图片时, 可以指定 `originalUser` 作为被转发用户名. (#1208)
|
||||||
|
- 新增插件 `自定义顶栏 - 频道`, 为自定义顶栏添加一个频道入口. (#3258)
|
||||||
|
- `自定义顶栏` 的历史弹窗中支持暂停/继续记录历史. (#3303)
|
||||||
|
|
||||||
|
🐛修复
|
||||||
|
- 修复 `默认播放器模式` 和 `播放器位置动作` 导致 `夜间模式跟随系统` 未生效. (#3157, PR #3636 by [ChsBuffer](https://github.com/chsbuffer))
|
||||||
|
- 修复个人空间中的动态无法使用动态相关功能. (#3191)
|
||||||
|
- 新版播放页 & 3.x 播放器适配: (#3187, #2615)
|
||||||
|
- 夜间模式 (#3647)
|
||||||
|
- 播放器投影
|
||||||
|
- 启用双击控制
|
||||||
|
- 控制栏触摸优化
|
||||||
|
- 三连触摸支持
|
||||||
|
- 隐藏视频标题层
|
||||||
|
- 展开视频简介
|
||||||
|
- 启用弹幕空降
|
||||||
|
- 播放器控制栏背景色
|
||||||
|
- 强制保留弹幕栏
|
||||||
|
- 快捷键扩展
|
||||||
|
- 外置稍后再看
|
||||||
|
- 启用快速收藏
|
||||||
|
- 传统连播模式
|
||||||
|
|
||||||
|
☕开发者相关 (来自预览版 v2.3.1)
|
||||||
|
- 重新整理了所有 CDN 调用, 并支持自定义 CDN 配置, 文档见 [doc/cdn.md](https://github.com/the1812/Bilibili-Evolved/blob/preview-features/doc/cdn.md).
|
||||||
|
- 拆分并整理了 `/src/core/settings` 的代码结构.
|
||||||
|
- 所有 webpack 配置更换为 TypeScript, 并启用 ESLint 检查.
|
||||||
|
- 重构了元数据注入功能, 新增了 i18n 和 description 注入, 详细用法可见 `webpack/inject-metadata/i18n.ts` 和 `webpack/inject-metadata/description.ts` 中的注释说明.
|
||||||
|
- 删除了用不到的包 `html-webpack-plugin`.
|
||||||
|
- 适配了 VSCode File Nesting 功能.
|
||||||
|
|
||||||
## v2.3.3-preview
|
## v2.3.3-preview
|
||||||
|
|
||||||
包含 v2.2.4 的所有更新内容.
|
包含 v2.2.4 的所有更新内容.
|
||||||
|
|||||||
@ -29,6 +29,9 @@ https://afdian.net/@the1812?tab=sponsor
|
|||||||
|
|
||||||
| 时间 | 用户名 | 单号后4位 | 金额 |
|
| 时间 | 用户名 | 单号后4位 | 金额 |
|
||||||
| ------------------- | ---------------- | --------- | ------- |
|
| ------------------- | ---------------- | --------- | ------- |
|
||||||
|
| 2022.08.31 16:28:40 | 匿名 | 1249 | ¥50.00 |
|
||||||
|
| 2022.08.28 14:13:22 | 匿名 | 4359 | ¥5.00 |
|
||||||
|
| 2022.08.27 09:33:37 | 匿名 | 3496 | ¥5.00 |
|
||||||
| 2022.08.23 20:21:47 | *I | 7157 | ¥10.00 |
|
| 2022.08.23 20:21:47 | *I | 7157 | ¥10.00 |
|
||||||
| 2022.08.16 01:11:59 | *生 | 3893 | ¥20.00 |
|
| 2022.08.16 01:11:59 | *生 | 3893 | ¥20.00 |
|
||||||
| 2022.08.09 22:42:25 | H*l | 0339 | ¥5.88 |
|
| 2022.08.09 22:42:25 | H*l | 0339 | ¥5.88 |
|
||||||
|
|||||||
@ -75,7 +75,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "badgeHelper",
|
"name": "badgeHelper",
|
||||||
"displayName": "直播勋章快速更换",
|
"displayName": "直播勋章快速更换",
|
||||||
"description": "在直播区中, 可从功能面板中直接切换勋章和头衔. 默认加载 256 个 (同时也是上限), 可在选项中修改.",
|
"description": "在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.",
|
||||||
"fullRelativePath": "../../registry/dist/components/live/badge-helper.js",
|
"fullRelativePath": "../../registry/dist/components/live/badge-helper.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/live/badge-helper.js"
|
"fullAbsolutePath": "registry/dist/components/live/badge-helper.js"
|
||||||
},
|
},
|
||||||
@ -163,7 +163,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "customNavbar",
|
"name": "customNavbar",
|
||||||
"displayName": "自定义顶栏",
|
"displayName": "自定义顶栏",
|
||||||
"description": "使用脚本提供的顶栏替换原版的主站顶栏 (非主站不替换), 启用后还可以在反广告插件 (例如 ABP) 中配置禁止原版顶栏的消息 iframe 以提升性能:\n- *://message.bilibili.com/pages/nav/index_new_pc_sync\n- *://message.bilibili.com/pages/nav/index_new_sync",
|
"description": "使用脚本提供的顶栏替换原版的主站顶栏 (非主站不替换), 启用后还可以在反广告插件 (例如 ABP) 中配置禁止原版顶栏的消息 iframe 以提升性能:\r\n- *://message.bilibili.com/pages/nav/index_new_pc_sync\r\n- *://message.bilibili.com/pages/nav/index_new_sync\r\n",
|
||||||
"fullRelativePath": "../../registry/dist/components/style/custom-navbar.js",
|
"fullRelativePath": "../../registry/dist/components/style/custom-navbar.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/style/custom-navbar.js"
|
"fullAbsolutePath": "registry/dist/components/style/custom-navbar.js"
|
||||||
},
|
},
|
||||||
@ -283,7 +283,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "sidebarOffset",
|
"name": "sidebarOffset",
|
||||||
"displayName": "侧栏垂直偏移",
|
"displayName": "侧栏垂直偏移",
|
||||||
"description": "给脚本的侧栏设置垂直偏移量, 范围为 -40% ~ 40%",
|
"description": "给脚本的侧栏设置垂直偏移量, 范围为 -35% ~ 40%",
|
||||||
"fullRelativePath": "../../registry/dist/components/style/sidebar-offset.js",
|
"fullRelativePath": "../../registry/dist/components/style/sidebar-offset.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/style/sidebar-offset.js"
|
"fullAbsolutePath": "registry/dist/components/style/sidebar-offset.js"
|
||||||
},
|
},
|
||||||
@ -371,7 +371,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "blackList",
|
"name": "blackList",
|
||||||
"displayName": "屏蔽黑名单up主",
|
"displayName": "屏蔽黑名单up主",
|
||||||
"description": "by [@snowraincloud](https://github.com/snowraincloud)\n\n屏蔽黑名单up主",
|
"description": "by [@snowraincloud](https://github.com/snowraincloud)\n\n屏蔽黑名单up主, 根据up主的名称进行匹配,支持精确匹配和正则匹配",
|
||||||
"fullRelativePath": "../../registry/dist/components/utils/black-list.js",
|
"fullRelativePath": "../../registry/dist/components/utils/black-list.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/utils/black-list.js"
|
"fullAbsolutePath": "registry/dist/components/utils/black-list.js"
|
||||||
},
|
},
|
||||||
@ -427,7 +427,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "imageExporter",
|
"name": "imageExporter",
|
||||||
"displayName": "图片批量导出",
|
"displayName": "图片批量导出",
|
||||||
"description": "可以批量导出某个地方的图片, 目前支持动态和专栏.\r\n\r\n动态文件名变量:\r\n- `user`: 用户名\r\n- `id`: 动态 ID\r\n- `n`: 第 n 张图\r\n\r\n专栏文件名变量:\r\n- `title`: 专栏标题\r\n- `n`: 第 n 张图",
|
"description": "可以批量导出某个地方的图片, 目前支持动态和专栏.\r\n\r\n动态文件名变量:\r\n- `user`: 用户名\r\n- `originalUser`: 被转发用户名, 如果不是转发类型的动态则等于 `user`\r\n- `id`: 动态 ID\r\n- `n`: 第 n 张图\r\n\r\n专栏文件名变量:\r\n- `title`: 专栏标题\r\n- `n`: 第 n 张图",
|
||||||
"fullRelativePath": "../../registry/dist/components/utils/image-exporter.js",
|
"fullRelativePath": "../../registry/dist/components/utils/image-exporter.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/utils/image-exporter.js"
|
"fullAbsolutePath": "registry/dist/components/utils/image-exporter.js"
|
||||||
},
|
},
|
||||||
@ -531,7 +531,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "expandDanmakuList",
|
"name": "expandDanmakuList",
|
||||||
"displayName": "展开弹幕列表",
|
"displayName": "展开弹幕列表",
|
||||||
"description": "每次加载视频时自动展开弹幕列表.",
|
"description": "每次加载视频时自动展开弹幕列表, 如果弹幕装载量超过 `最大弹幕数量`, 则不展开以免对页面造成卡顿.",
|
||||||
"fullRelativePath": "../../registry/dist/components/video/danmaku/expand.js",
|
"fullRelativePath": "../../registry/dist/components/video/danmaku/expand.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/video/danmaku/expand.js"
|
"fullAbsolutePath": "registry/dist/components/video/danmaku/expand.js"
|
||||||
},
|
},
|
||||||
@ -744,6 +744,14 @@
|
|||||||
"fullRelativePath": "../../registry/dist/plugins/settings-panel/recent-components.js",
|
"fullRelativePath": "../../registry/dist/plugins/settings-panel/recent-components.js",
|
||||||
"fullAbsolutePath": "registry/dist/plugins/settings-panel/recent-components.js"
|
"fullAbsolutePath": "registry/dist/plugins/settings-panel/recent-components.js"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "plugin",
|
||||||
|
"name": "customNavbar.items.channel",
|
||||||
|
"displayName": "自定义顶栏 - 频道",
|
||||||
|
"description": "为自定义顶栏添加一个频道入口.",
|
||||||
|
"fullRelativePath": "../../registry/dist/plugins/style/custom-navbar-channel.js",
|
||||||
|
"fullAbsolutePath": "registry/dist/plugins/style/custom-navbar-channel.js"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "plugin",
|
"type": "plugin",
|
||||||
"name": "customNavbar.items.darkMode",
|
"name": "customNavbar.items.darkMode",
|
||||||
|
|||||||
@ -96,7 +96,7 @@
|
|||||||
|
|
||||||
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/live/badge-helper.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/live/badge-helper.js)
|
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/live/badge-helper.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/live/badge-helper.js)
|
||||||
|
|
||||||
在直播区中, 可从功能面板中直接切换勋章和头衔. 默认加载 256 个 (同时也是上限), 可在选项中修改.
|
在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.
|
||||||
|
|
||||||
### [直播弹幕发送栏](../../registry/dist/components/live/danmaku-sendbar.js)
|
### [直播弹幕发送栏](../../registry/dist/components/live/danmaku-sendbar.js)
|
||||||
`liveDanmakuSendbar`
|
`liveDanmakuSendbar`
|
||||||
@ -344,7 +344,7 @@
|
|||||||
|
|
||||||
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/style/sidebar-offset.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/style/sidebar-offset.js)
|
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/style/sidebar-offset.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/style/sidebar-offset.js)
|
||||||
|
|
||||||
给脚本的侧栏设置垂直偏移量, 范围为 -40% ~ 40%
|
给脚本的侧栏设置垂直偏移量, 范围为 -35% ~ 40%
|
||||||
|
|
||||||
### [简化评论区](../../registry/dist/components/style/simplify/comments.js)
|
### [简化评论区](../../registry/dist/components/style/simplify/comments.js)
|
||||||
`simplifyComments`
|
`simplifyComments`
|
||||||
@ -460,7 +460,7 @@
|
|||||||
|
|
||||||
by [@snowraincloud](https://github.com/snowraincloud)
|
by [@snowraincloud](https://github.com/snowraincloud)
|
||||||
|
|
||||||
屏蔽黑名单up主
|
屏蔽黑名单up主, 根据up主的名称进行匹配,支持精确匹配和正则匹配
|
||||||
|
|
||||||
### [更新链接替换](../../registry/dist/components/utils/change-update-urls.js)
|
### [更新链接替换](../../registry/dist/components/utils/change-update-urls.js)
|
||||||
`changeUpdateUrls`
|
`changeUpdateUrls`
|
||||||
@ -541,6 +541,7 @@ by [@snowraincloud](https://github.com/snowraincloud)
|
|||||||
|
|
||||||
动态文件名变量:
|
动态文件名变量:
|
||||||
- `user`: 用户名
|
- `user`: 用户名
|
||||||
|
- `originalUser`: 被转发用户名, 如果不是转发类型的动态则等于 `user`
|
||||||
- `id`: 动态 ID
|
- `id`: 动态 ID
|
||||||
- `n`: 第 n 张图
|
- `n`: 第 n 张图
|
||||||
|
|
||||||
@ -668,7 +669,7 @@ by [@kdxcxs](https://github.com/kdxcxs)
|
|||||||
|
|
||||||
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/danmaku/expand.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/danmaku/expand.js)
|
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/video/danmaku/expand.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/video/danmaku/expand.js)
|
||||||
|
|
||||||
每次加载视频时自动展开弹幕列表.
|
每次加载视频时自动展开弹幕列表, 如果弹幕装载量超过 `最大弹幕数量`, 则不展开以免对页面造成卡顿.
|
||||||
|
|
||||||
### [视频页默认定位](../../registry/dist/components/video/default-location.js)
|
### [视频页默认定位](../../registry/dist/components/video/default-location.js)
|
||||||
`videoDefaultLocation`
|
`videoDefaultLocation`
|
||||||
@ -975,6 +976,15 @@ by FoundTheWOUT
|
|||||||
|
|
||||||
在设置面板中添加 "最近使用" 类别, 方便检索最近操作过的组件.
|
在设置面板中添加 "最近使用" 类别, 方便检索最近操作过的组件.
|
||||||
|
|
||||||
|
### [自定义顶栏 - 频道](../../registry/dist/plugins/style/custom-navbar-channel.js)
|
||||||
|
`customNavbar.items.channel`
|
||||||
|
|
||||||
|
**AltCdn:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/plugins/style/custom-navbar-channel.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/plugins/style/custom-navbar-channel.js)
|
||||||
|
|
||||||
|
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/plugins/style/custom-navbar-channel.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/plugins/style/custom-navbar-channel.js)
|
||||||
|
|
||||||
|
为自定义顶栏添加一个频道入口.
|
||||||
|
|
||||||
### [自定义顶栏 - 夜间模式开关](../../registry/dist/plugins/style/custom-navbar-dark-mode.js)
|
### [自定义顶栏 - 夜间模式开关](../../registry/dist/plugins/style/custom-navbar-dark-mode.js)
|
||||||
`customNavbar.items.darkMode`
|
`customNavbar.items.darkMode`
|
||||||
|
|
||||||
|
|||||||
@ -201,7 +201,7 @@
|
|||||||
"type": "component",
|
"type": "component",
|
||||||
"name": "customNavbar",
|
"name": "customNavbar",
|
||||||
"displayName": "自定义顶栏",
|
"displayName": "自定义顶栏",
|
||||||
"description": "使用脚本提供的顶栏替换原版的主站顶栏 (非主站不替换), 启用后还可以在反广告插件 (例如 ABP) 中配置禁止原版顶栏的消息 iframe 以提升性能:\n- *://message.bilibili.com/pages/nav/index_new_pc_sync\n- *://message.bilibili.com/pages/nav/index_new_sync",
|
"description": "使用脚本提供的顶栏替换原版的主站顶栏 (非主站不替换), 启用后还可以在反广告插件 (例如 ABP) 中配置禁止原版顶栏的消息 iframe 以提升性能:\r\n- *://message.bilibili.com/pages/nav/index_new_pc_sync\r\n- *://message.bilibili.com/pages/nav/index_new_sync\r\n",
|
||||||
"fullRelativePath": "../../registry/dist/components/style/custom-navbar.js",
|
"fullRelativePath": "../../registry/dist/components/style/custom-navbar.js",
|
||||||
"fullAbsolutePath": "registry/dist/components/style/custom-navbar.js"
|
"fullAbsolutePath": "registry/dist/components/style/custom-navbar.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,6 +6,17 @@
|
|||||||
<TextBox v-model="search" placeholder="搜索" linear></TextBox>
|
<TextBox v-model="search" placeholder="搜索" linear></TextBox>
|
||||||
</div>
|
</div>
|
||||||
<div class="operations">
|
<div class="operations">
|
||||||
|
<div
|
||||||
|
class="operation"
|
||||||
|
@click="toggleHistoryPause"
|
||||||
|
>
|
||||||
|
<VButton v-if="!paused" title="暂停记录历史" round>
|
||||||
|
<VIcon icon="mdi-pause" :size="14"></VIcon>
|
||||||
|
</VButton>
|
||||||
|
<VButton v-else title="继续记录历史" round>
|
||||||
|
<VIcon icon="mdi-play" :size="14"></VIcon>
|
||||||
|
</VButton>
|
||||||
|
</div>
|
||||||
<a
|
<a
|
||||||
class="operation"
|
class="operation"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@ -116,6 +127,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { bilibiliApi, getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
||||||
|
import { formData, getCsrf } from '@/core/utils'
|
||||||
import { descendingSort } from '@/core/utils/sort'
|
import { descendingSort } from '@/core/utils/sort'
|
||||||
import {
|
import {
|
||||||
VButton,
|
VButton,
|
||||||
@ -151,6 +164,7 @@ export default Vue.extend({
|
|||||||
groups: [],
|
groups: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
hasMorePage: true,
|
hasMorePage: true,
|
||||||
|
paused: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -170,7 +184,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
try {
|
try {
|
||||||
await this.nextPage()
|
await Promise.all([
|
||||||
|
this.nextPage(),
|
||||||
|
this.updateHistoryPauseState(),
|
||||||
|
])
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
@ -210,6 +227,29 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
this.hasMorePage = cards.length !== 0
|
this.hasMorePage = cards.length !== 0
|
||||||
},
|
},
|
||||||
|
async updateHistoryPauseState() {
|
||||||
|
const result = await bilibiliApi(getJsonWithCredentials('https://api.bilibili.com/x/v2/history/shadow'))
|
||||||
|
/*
|
||||||
|
result == true: 暂停
|
||||||
|
result == {}: 没暂停
|
||||||
|
*/
|
||||||
|
this.paused = result === true
|
||||||
|
},
|
||||||
|
async toggleHistoryPause() {
|
||||||
|
const targetState = !this.paused
|
||||||
|
try {
|
||||||
|
this.paused = targetState
|
||||||
|
await postTextWithCredentials(
|
||||||
|
'https://api.bilibili.com/x/v2/history/shadow/set',
|
||||||
|
formData({
|
||||||
|
csrf: getCsrf(),
|
||||||
|
switch: targetState,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
this.paused = !targetState
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@ -236,8 +276,9 @@ export default Vue.extend({
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@mixin round-button($width: 26px) {
|
@mixin round-button($size: 26px) {
|
||||||
width: $width;
|
width: $size;
|
||||||
|
height: $size;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
|
|||||||
@ -31,7 +31,10 @@ export const checkTransparentFill = async (vm: {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
).then(() => {
|
).then(banner => {
|
||||||
|
if (banner.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
addComponentListener('customNavbar.transparent', value => {
|
addComponentListener('customNavbar.transparent', value => {
|
||||||
if (!getComponentSettings('hideBanner').enabled) {
|
if (!getComponentSettings('hideBanner').enabled) {
|
||||||
vm.toggleStyle(value, 'transparent')
|
vm.toggleStyle(value, 'transparent')
|
||||||
|
|||||||
@ -222,6 +222,9 @@ blockquote {
|
|||||||
@include foreground-color();
|
@include foreground-color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#bilibili-player {
|
||||||
|
box-shadow: 0 4px 8px 0 #0004 !important;
|
||||||
|
}
|
||||||
#bilibiliPlayer {
|
#bilibiliPlayer {
|
||||||
box-shadow: 0 4px 8px 0 #0004;
|
box-shadow: 0 4px 8px 0 #0004;
|
||||||
@include background-color('2');
|
@include background-color('2');
|
||||||
|
|||||||
@ -182,6 +182,18 @@
|
|||||||
@include color("e");
|
@include color("e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#bilibili-player-placeholder-bottom {
|
||||||
|
@include background-color('3');
|
||||||
|
&-left,
|
||||||
|
&-right {
|
||||||
|
@include background-color('4');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#bpx-svg-sprite-danmu-on {
|
||||||
|
path:last-child {
|
||||||
|
@include theme-fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
.bpx-player-container {
|
.bpx-player-container {
|
||||||
box-shadow: 0 4px 8px 0 #0004 !important;
|
box-shadow: 0 4px 8px 0 #0004 !important;
|
||||||
.squirtle-controller {
|
.squirtle-controller {
|
||||||
@ -196,12 +208,16 @@
|
|||||||
@include background-color();
|
@include background-color();
|
||||||
}
|
}
|
||||||
.bpx-player-sending-bar {
|
.bpx-player-sending-bar {
|
||||||
@include background-color();
|
@include background-color('2');
|
||||||
.bpx-player-dm-setting:hover {
|
.bpx-player-video-btn-dm,
|
||||||
@include theme-fill();
|
.bpx-player-dm-setting,
|
||||||
|
.bpx-player-dm-switch {
|
||||||
|
@include fill('a');
|
||||||
}
|
}
|
||||||
|
.bpx-player-dm-switch:hover,
|
||||||
|
.bpx-player-dm-setting:hover,
|
||||||
.bpx-player-video-btn-dm:hover {
|
.bpx-player-video-btn-dm:hover {
|
||||||
@include theme-fill();
|
@include fill('e');
|
||||||
}
|
}
|
||||||
.bpx-player-dm-input {
|
.bpx-player-dm-input {
|
||||||
@include color("e");
|
@include color("e");
|
||||||
|
|||||||
@ -638,9 +638,21 @@
|
|||||||
}
|
}
|
||||||
.share_dropdown {
|
.share_dropdown {
|
||||||
@include color('e');
|
@include color('e');
|
||||||
|
@include background-color('3');
|
||||||
.box-right {
|
.box-right {
|
||||||
@include border-color('4');
|
@include border-color('4');
|
||||||
}
|
}
|
||||||
|
.capture-bar {
|
||||||
|
.bar-left {
|
||||||
|
@include color('a');
|
||||||
|
}
|
||||||
|
.bar-right {
|
||||||
|
.copy-link {
|
||||||
|
@include theme-background-color();
|
||||||
|
@include foreground-color();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.share-link {
|
.share-link {
|
||||||
@include background-color('4');
|
@include background-color('4');
|
||||||
#link_copy {
|
#link_copy {
|
||||||
@ -651,6 +663,12 @@
|
|||||||
@include theme-color();
|
@include theme-color();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.box-top-right {
|
||||||
|
box-shadow: -0.5px 0 0 #555 !important;
|
||||||
|
}
|
||||||
|
.box-bottom {
|
||||||
|
@include background-color('4');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-auxiliary-filter-playlist {
|
.player-auxiliary-filter-playlist {
|
||||||
@ -804,3 +822,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#bilibili-player-placeholder,
|
||||||
|
.bpx-player-container {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
import { defineComponentMetadata } from '@/components/define'
|
import { defineComponentMetadata } from '@/components/define'
|
||||||
import { toggleStyle } from '@/components/styled-component'
|
|
||||||
import { playerUrls } from '@/core/utils/urls'
|
import { playerUrls } from '@/core/utils/urls'
|
||||||
|
|
||||||
|
const name = 'hideVideoTopMask'
|
||||||
export const component = defineComponentMetadata({
|
export const component = defineComponentMetadata({
|
||||||
|
name,
|
||||||
displayName: '隐藏视频标题层',
|
displayName: '隐藏视频标题层',
|
||||||
...toggleStyle('hideVideoTopMask', () => import('./top-mask.scss')),
|
entry: none,
|
||||||
|
instantStyles: [
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
style: () => import('./top-mask.scss'),
|
||||||
|
},
|
||||||
|
],
|
||||||
tags: [
|
tags: [
|
||||||
componentsTags.style,
|
componentsTags.style,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
.bpx-player-top-wrap,
|
||||||
.bilibili-player-video-top {
|
.bilibili-player-video-top {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,3 +5,7 @@
|
|||||||
box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;
|
box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#bilibili-player-placeholder,
|
||||||
|
.bpx-player-container {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { videoUrls } from '@/core/utils/urls'
|
|||||||
|
|
||||||
const entry = async () => {
|
const entry = async () => {
|
||||||
const { select } = await import('@/core/spin-query')
|
const { select } = await import('@/core/spin-query')
|
||||||
const likeButton = await select('.ops span.like') as HTMLElement
|
const likeButton = await select(':is(.ops, .video-toolbar-v1) span.like') as HTMLElement
|
||||||
if (!likeButton) {
|
if (!likeButton) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
visibility: hidden !important;
|
visibility: hidden !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bpx-player-shadow-progress-area,
|
||||||
.bilibili-player-video-control-wrap {
|
.bilibili-player-video-control-wrap {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
@ -19,6 +20,9 @@
|
|||||||
bottom: -7px !important;
|
bottom: -7px !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
|
.bpx-player-control-top,
|
||||||
|
.bpx-player-control-mask,
|
||||||
|
.bpx-player-control-bottom,
|
||||||
.bpx-player-top-wrap {
|
.bpx-player-top-wrap {
|
||||||
opacity: 0 !important;
|
opacity: 0 !important;
|
||||||
visibility: hidden !important;
|
visibility: hidden !important;
|
||||||
|
|||||||
@ -12,7 +12,14 @@
|
|||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
bottom: 44px !important;
|
bottom: 44px !important;
|
||||||
}
|
}
|
||||||
.bpx-player-top-wrap {
|
.bpx-player-shadow-progress-area {
|
||||||
|
opacity: 0 !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
}
|
||||||
|
.bpx-player-top-wrap,
|
||||||
|
.bpx-player-control-mask,
|
||||||
|
.bpx-player-control-bottom,
|
||||||
|
.bpx-player-control-top {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bpx-player-pbp {
|
||||||
|
opacity: 0 !important;
|
||||||
|
bottom: 3px !important;
|
||||||
|
&.pin {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
.bpx-player-pbp-pin {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.touch-video-control-show .bpx-player-pbp {
|
||||||
|
opacity: 1 !important;
|
||||||
|
bottom: calc(100% - 1px) !important;
|
||||||
|
.bpx-player-pbp-pin {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.touch-video-control-show .bilibili-player-video-control {
|
&.touch-video-control-show .bilibili-player-video-control {
|
||||||
#bilibili_pbp,
|
#bilibili_pbp,
|
||||||
#bilibili_pbp_canvas {
|
#bilibili_pbp_canvas {
|
||||||
@ -60,6 +79,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.touch-video-control-show .bpx-player-pbp {
|
||||||
|
bottom: calc(100% + 5px) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
@import 'common';
|
||||||
|
|
||||||
@mixin subtitle {
|
@mixin subtitle {
|
||||||
&.bilibili-player-area .subtitle-position.subtitle-position {
|
&.bilibili-player-area .subtitle-position.subtitle-position {
|
||||||
&-bc,
|
&-bc,
|
||||||
@ -13,14 +15,30 @@
|
|||||||
bottom: 68px !important;
|
bottom: 68px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mode-webfullscreen &.touch-video-control-show,
|
.bpx-player-subtitle-panel-position {
|
||||||
.mode-fullscreen &.touch-video-control-show {
|
&[data-position='bottom'] {
|
||||||
.subtitle-position.subtitle-position {
|
bottom: 14px !important;
|
||||||
&-bc,
|
}
|
||||||
&-bl,
|
}
|
||||||
&-br {
|
&.touch-video-control-show .bpx-player-subtitle-panel-position {
|
||||||
bottom: 88px !important;
|
&[data-position='bottom'] {
|
||||||
|
bottom: 69px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include on-fullscreen {
|
||||||
|
&.touch-video-control-show {
|
||||||
|
.subtitle-position.subtitle-position {
|
||||||
|
&-bc,
|
||||||
|
&-bl,
|
||||||
|
&-br {
|
||||||
|
bottom: 88px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bpx-player-subtitle-panel-position {
|
||||||
|
&[data-position='bottom'] {
|
||||||
|
bottom: 88px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
@import "common";
|
@import 'common';
|
||||||
|
|
||||||
@mixin replace-with-icon() {
|
@mixin replace-with-icon() {
|
||||||
display: block;
|
display: block;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
color: #eee;
|
color: #eee;
|
||||||
font: normal normal normal 20px/1 "Material Design Icons";
|
font: normal normal normal 20px/1 'Material Design Icons';
|
||||||
text-rendering: auto;
|
text-rendering: auto;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
@ -35,7 +35,7 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
&::before {
|
&::before {
|
||||||
content: "\F0279";
|
content: '\F0279';
|
||||||
@include replace-with-icon();
|
@include replace-with-icon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
&::before {
|
&::before {
|
||||||
content: "\F08FF";
|
content: '\F08FF';
|
||||||
@include replace-with-icon();
|
@include replace-with-icon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include on-fullscreen(".touch-player-control") {
|
@include on-fullscreen('.touch-player-control') {
|
||||||
.bilibili-player-area {
|
.bilibili-player-area {
|
||||||
.bilibili-player-video-control-bottom-center {
|
.bilibili-player-video-control-bottom-center {
|
||||||
padding: 0 12px !important;
|
padding: 0 12px !important;
|
||||||
@ -100,7 +100,7 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.squirtle-video-pagelist::before {
|
.squirtle-video-pagelist::before {
|
||||||
content: "\F0279";
|
content: '\F0279';
|
||||||
@include replace-with-icon();
|
@include replace-with-icon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.squirtle-video-speed::before {
|
.squirtle-video-speed::before {
|
||||||
content: "\F08FF";
|
content: '\F08FF';
|
||||||
@include replace-with-icon();
|
@include replace-with-icon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,8 +127,28 @@
|
|||||||
right: 0 !important;
|
right: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bpx-player-control-top,
|
||||||
|
.bpx-player-control-bottom {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.bpx-player-pbp {
|
||||||
|
padding: 0 !important;
|
||||||
|
left: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.bpx-player-ctrl-btn {
|
||||||
|
height: 100% !important;
|
||||||
|
padding-left: 2px !important;
|
||||||
|
padding-right: 2px !important;
|
||||||
|
&.bpx-player-ctrl-play {
|
||||||
|
padding-left: 12px !important;
|
||||||
|
}
|
||||||
|
&.bpx-player-ctrl-full {
|
||||||
|
padding-right: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@include on-fullscreen(".touch-player-control") {
|
@include on-fullscreen('.touch-player-control') {
|
||||||
.squirtle-controller {
|
.squirtle-controller {
|
||||||
height: 72px !important;
|
height: 72px !important;
|
||||||
.squirtle-controller-wrap {
|
.squirtle-controller-wrap {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { FeedsCard, addMenuItem, forEachFeedsCard } from '@/components/feeds/api'
|
import { FeedsCard, addMenuItem, forEachFeedsCard, RepostFeedsCard } from '@/components/feeds/api'
|
||||||
import { ComponentEntry } from '@/components/types'
|
import { ComponentEntry } from '@/components/types'
|
||||||
import { getBlob } from '@/core/ajax'
|
import { getBlob } from '@/core/ajax'
|
||||||
import { DownloadPackage } from '@/core/download'
|
import { DownloadPackage } from '@/core/download'
|
||||||
@ -42,6 +42,7 @@ export const setupFeedImageExporter: ComponentEntry = async ({ settings: { optio
|
|||||||
const titleData = {
|
const titleData = {
|
||||||
user: card.username,
|
user: card.username,
|
||||||
id: card.id,
|
id: card.id,
|
||||||
|
originalUser: (card as RepostFeedsCard).repostUsername ?? card.username,
|
||||||
n: (index + 1).toString(),
|
n: (index + 1).toString(),
|
||||||
}
|
}
|
||||||
pack.add(`${formatTitle(feedFormat, false, titleData)}${imageUrls[index].extension}`, blob)
|
pack.add(`${formatTitle(feedFormat, false, titleData)}${imageUrls[index].extension}`, blob)
|
||||||
@ -50,6 +51,7 @@ export const setupFeedImageExporter: ComponentEntry = async ({ settings: { optio
|
|||||||
const packTitleData = {
|
const packTitleData = {
|
||||||
user: card.username,
|
user: card.username,
|
||||||
id: card.id,
|
id: card.id,
|
||||||
|
originalUser: (card as RepostFeedsCard).repostUsername ?? card.username,
|
||||||
n: '',
|
n: '',
|
||||||
}
|
}
|
||||||
await pack.emit(`${formatTitle(feedFormat, false, packTitleData)}.zip`)
|
await pack.emit(`${formatTitle(feedFormat, false, packTitleData)}.zip`)
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
动态文件名变量:
|
动态文件名变量:
|
||||||
- `user`: 用户名
|
- `user`: 用户名
|
||||||
|
- `originalUser`: 被转发用户名, 如果不是转发类型的动态则等于 `user`
|
||||||
- `id`: 动态 ID
|
- `id`: 动态 ID
|
||||||
- `n`: 第 n 张图
|
- `n`: 第 n 张图
|
||||||
|
|
||||||
@ -2,14 +2,10 @@ import { ComponentMetadata } from '@/components/types'
|
|||||||
import { matchUrlPattern } from '@/core/utils'
|
import { matchUrlPattern } from '@/core/utils'
|
||||||
import { columnUrls, feedsUrls } from '@/core/utils/urls'
|
import { columnUrls, feedsUrls } from '@/core/utils/urls'
|
||||||
import { setupFeedImageExporter } from './feed'
|
import { setupFeedImageExporter } from './feed'
|
||||||
import desc from './desc.md'
|
|
||||||
|
|
||||||
export const component: ComponentMetadata = {
|
export const component: ComponentMetadata = {
|
||||||
name: 'imageExporter',
|
name: 'imageExporter',
|
||||||
displayName: '图片批量导出',
|
displayName: '图片批量导出',
|
||||||
description: {
|
|
||||||
'zh-CN': desc,
|
|
||||||
},
|
|
||||||
tags: [
|
tags: [
|
||||||
componentsTags.feeds,
|
componentsTags.feeds,
|
||||||
componentsTags.utils,
|
componentsTags.utils,
|
||||||
|
|||||||
@ -126,11 +126,11 @@ export const builtInActions: Record<string, KeyBindingAction> = {
|
|||||||
},
|
},
|
||||||
coin: {
|
coin: {
|
||||||
displayName: '投币',
|
displayName: '投币',
|
||||||
run: useClickElement('.video-toolbar .coin,.tool-bar .coin-info, .video-toolbar-module .coin-box, .play-options-ul > li:nth-child(2)'),
|
run: useClickElement('.video-toolbar .coin, .tool-bar .coin-info, .video-toolbar-module .coin-box, .play-options-ul > li:nth-child(2), .video-toolbar-v1 .coin'),
|
||||||
},
|
},
|
||||||
favorite: {
|
favorite: {
|
||||||
displayName: '收藏',
|
displayName: '收藏',
|
||||||
run: useClickElement('.video-toolbar .collect, .video-toolbar-module .fav-box, .play-options-ul > li:nth-child(3)'),
|
run: useClickElement('.video-toolbar .collect, .video-toolbar-module .fav-box, .play-options-ul > li:nth-child(3), .video-toolbar-v1 .collect'),
|
||||||
},
|
},
|
||||||
pause: {
|
pause: {
|
||||||
displayName: '暂停/播放',
|
displayName: '暂停/播放',
|
||||||
@ -143,7 +143,7 @@ export const builtInActions: Record<string, KeyBindingAction> = {
|
|||||||
let likeClick = true
|
let likeClick = true
|
||||||
return ((context: KeyBindingActionContext) => {
|
return ((context: KeyBindingActionContext) => {
|
||||||
const { event } = context
|
const { event } = context
|
||||||
const likeButton = dq('.video-toolbar .like, .tool-bar .like-info') as HTMLSpanElement
|
const likeButton = dq('.video-toolbar .like, .tool-bar .like-info, .video-toolbar-v1 .like') as HTMLSpanElement
|
||||||
if (!likeButton) {
|
if (!likeButton) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
.bilibili-player-video-danmaku {
|
.b-danmaku {
|
||||||
.b-danmaku {
|
&.airborne {
|
||||||
&.airborne {
|
text-decoration: underline;
|
||||||
text-decoration: underline;
|
cursor: pointer;
|
||||||
cursor: pointer;
|
pointer-events: initial;
|
||||||
pointer-events: initial;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,39 @@ import { ComponentEntry, ComponentMetadata } from '@/components/types'
|
|||||||
import { videoChange } from '@/core/observer'
|
import { videoChange } from '@/core/observer'
|
||||||
import { select } from '@/core/spin-query'
|
import { select } from '@/core/spin-query'
|
||||||
import { matchUrlPattern } from '@/core/utils'
|
import { matchUrlPattern } from '@/core/utils'
|
||||||
|
import { useScopedConsole } from '@/core/utils/log'
|
||||||
import { mediaListUrls, videoAndBangumiUrls } from '@/core/utils/urls'
|
import { mediaListUrls, videoAndBangumiUrls } from '@/core/utils/urls'
|
||||||
|
|
||||||
|
const getDanmakuCount = async () => {
|
||||||
|
const countElement = await select('.bilibili-player-video-info-danmaku-number, .bpx-player-video-info-dm')
|
||||||
|
/*
|
||||||
|
3.x: 已装填 n 条弹幕
|
||||||
|
2.x: n
|
||||||
|
*/
|
||||||
|
const countText = countElement?.textContent ?? ''
|
||||||
|
const countMatch = countText.match(/\d+/)
|
||||||
|
if (!countMatch) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const count = parseInt(countMatch[0])
|
||||||
|
if (Number.isNaN(count)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
const entry: ComponentEntry = async ({ settings: { options } }) => {
|
const entry: ComponentEntry = async ({ settings: { options } }) => {
|
||||||
|
const console = useScopedConsole('展开弹幕列表')
|
||||||
videoChange(async () => {
|
videoChange(async () => {
|
||||||
if (mediaListUrls.some(url => matchUrlPattern(url)) && options.ignoreMediaList) {
|
if (mediaListUrls.some(url => matchUrlPattern(url)) && options.ignoreMediaList) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const danmakuCount = await getDanmakuCount()
|
||||||
|
console.log(`当前弹幕量: ${danmakuCount}`)
|
||||||
|
if (danmakuCount !== null && danmakuCount > options.maxDanmakuCount) {
|
||||||
|
console.log(`超过了最大弹幕数量 ${options.maxDanmakuCount}, 跳过展开`)
|
||||||
|
return
|
||||||
|
}
|
||||||
const danmakuBox = await select('.bui-collapse-wrap')
|
const danmakuBox = await select('.bui-collapse-wrap')
|
||||||
if (danmakuBox && danmakuBox.classList.contains('bui-collapse-wrap-folded')) {
|
if (danmakuBox && danmakuBox.classList.contains('bui-collapse-wrap-folded')) {
|
||||||
const button = await select('.bui-collapse-header') as HTMLDivElement
|
const button = await select('.bui-collapse-header') as HTMLDivElement
|
||||||
@ -23,13 +49,17 @@ export const component: ComponentMetadata = {
|
|||||||
entry,
|
entry,
|
||||||
tags: [componentsTags.video],
|
tags: [componentsTags.video],
|
||||||
description: {
|
description: {
|
||||||
'zh-CN': '每次加载视频时自动展开弹幕列表.',
|
'zh-CN': '每次加载视频时自动展开弹幕列表, 如果弹幕装载量超过 `最大弹幕数量`, 则不展开以免对页面造成卡顿.',
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
ignoreMediaList: {
|
ignoreMediaList: {
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
displayName: '合集类页面不自动展开',
|
displayName: '合集类页面不自动展开',
|
||||||
},
|
},
|
||||||
|
maxDanmakuCount: {
|
||||||
|
defaultValue: 500,
|
||||||
|
displayName: '最大弹幕数量',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
urlInclude: [
|
urlInclude: [
|
||||||
...videoAndBangumiUrls,
|
...videoAndBangumiUrls,
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
.video-desc .info,
|
.video-desc .info,
|
||||||
.video-desc .desc-info,
|
.video-desc .desc-info,
|
||||||
|
.video-desc-v1 .desc-info,
|
||||||
.play-up-info .play-up-self {
|
.play-up-info .play-up-self {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
.video-desc .btn,
|
.video-desc .btn,
|
||||||
.video-desc .toggle-btn,
|
.video-desc .toggle-btn,
|
||||||
|
.video-desc-v1 .toggle-btn,
|
||||||
.play-up-info .play-up-self-btn {
|
.play-up-info .play-up-self-btn {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { ComponentMetadata } from '@/components/types'
|
import { ComponentMetadata } from '@/components/types'
|
||||||
import { videoAndBangumiUrls } from '@/core/utils/urls'
|
import { videoAndBangumiUrls } from '@/core/utils/urls'
|
||||||
import { videoChange } from '@/core/observer'
|
import { videoChange } from '@/core/observer'
|
||||||
import { select } from '@/core/spin-query'
|
import { select, sq } from '@/core/spin-query'
|
||||||
import { addStyle, removeStyle } from '@/core/style'
|
import { addStyle, removeStyle } from '@/core/style'
|
||||||
import style from './full-description.scss'
|
import style from './full-description.scss'
|
||||||
|
|
||||||
@ -9,11 +9,14 @@ const name = 'fullVideoDescription'
|
|||||||
const entry = () => {
|
const entry = () => {
|
||||||
addStyle(style, name)
|
addStyle(style, name)
|
||||||
videoChange(async () => {
|
videoChange(async () => {
|
||||||
const desc = await select('.video-desc')
|
const desc = await select('.video-desc, .video-desc-v1')
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const expandButton = await select('.video-desc .btn[report-id="abstract_spread"], .video-desc .toggle-btn') as HTMLElement
|
const expandButton = await sq(
|
||||||
|
() => dq(desc, '[report-id="abstract_spread"], .toggle-btn') as HTMLElement,
|
||||||
|
it => it.style.display !== 'none',
|
||||||
|
)
|
||||||
expandButton?.click()
|
expandButton?.click()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<span title="稍后再看" class="watchlater" :class="{ on }" @click="toggle()">
|
<span title="稍后再看" class="watchlater be-outer-watchlater" :class="{ on }" @click="toggle()">
|
||||||
<VIcon class="icon" :size="28" icon="mdi-timetable"></VIcon>
|
<VIcon class="icon" :size="28" icon="mdi-timetable"></VIcon>
|
||||||
<span class="text">稍后再看</span>
|
<span class="text">稍后再看</span>
|
||||||
<div class="tip" :class="{ show: tipShowing }">{{ tipText }}</div>
|
<div class="tip" :class="{ show: tipShowing }">{{ tipText }}</div>
|
||||||
|
|||||||
@ -57,12 +57,12 @@ export const component = defineComponentMetadata({
|
|||||||
// urlExclude: watchlaterUrls,
|
// urlExclude: watchlaterUrls,
|
||||||
options,
|
options,
|
||||||
reload: () => {
|
reload: () => {
|
||||||
dqa('.ops .watchlater').forEach((it: HTMLElement) => {
|
dqa('.be-outer-watchlater').forEach((it: HTMLElement) => {
|
||||||
it.style.display = 'inline-block'
|
it.style.display = ''
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
unload: () => {
|
unload: () => {
|
||||||
dqa('.ops .watchlater').forEach((it: HTMLElement) => {
|
dqa('.be-outer-watchlater').forEach((it: HTMLElement) => {
|
||||||
it.style.display = 'none'
|
it.style.display = 'none'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -74,7 +74,7 @@ export const component = defineComponentMetadata({
|
|||||||
displayName: '稍后再看',
|
displayName: '稍后再看',
|
||||||
run: context => {
|
run: context => {
|
||||||
const { clickElement } = context
|
const { clickElement } = context
|
||||||
return clickElement('.video-toolbar .ops .watchlater, .more-ops-list .ops-watch-later, .video-toolbar-module .see-later-box', context)
|
return clickElement('.be-outer-watchlater', context)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,23 +1,57 @@
|
|||||||
@import "common";
|
@import 'common';
|
||||||
|
|
||||||
.bilibili-player-video-control {
|
.bilibili-player-video-control {
|
||||||
&-mask {
|
&-mask {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
.bilibili-player-video-control-bottom {
|
.bilibili-player-video-control-bottom {
|
||||||
background: rgba(0, 0, 0, var(--video-control-opacity)) !important;
|
&::before {
|
||||||
margin: 5px 0 0 0 !important;
|
content: '';
|
||||||
padding: 9px 0 0 !important;
|
position: absolute;
|
||||||
height: 30px !important;
|
bottom: 0;
|
||||||
@include on-fullscreen {
|
height: calc(100% - 5px);
|
||||||
margin: -2px 0 0 0 !important;
|
width: 100%;
|
||||||
padding: 13px 0 0 !important;
|
background-color: rgba(0, 0, 0, var(--video-control-opacity));
|
||||||
height: 45px !important;
|
z-index: -1;
|
||||||
|
@include on-fullscreen {
|
||||||
|
height: calc(100% + 2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bpx-player-control {
|
||||||
|
&-mask {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
&-bottom {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: calc(100% - 17px);
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, var(--video-control-opacity));
|
||||||
|
z-index: -1;
|
||||||
|
@include on-fullscreen {
|
||||||
|
height: calc(100% - 11px);
|
||||||
|
}
|
||||||
|
.video-container-v1 & {
|
||||||
|
height: calc(100% - 5px);
|
||||||
|
@include on-fullscreen {
|
||||||
|
height: calc(100% + 1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
&.video-control-progress-background {
|
&.video-control-progress-background {
|
||||||
|
.squirtle-progress-bar:not(.squirtle-progress-buffer):not(.squirtle-progress-timeline):not(.squirtle-progress-dot-container),
|
||||||
|
.bpx-player-progress-schedule {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
.bpx-player-progress,
|
||||||
|
.squirtle-progress-dot-container,
|
||||||
.bui-track-video-progress .bui-bar-wrap {
|
.bui-track-video-progress .bui-bar-wrap {
|
||||||
background: rgba(0, 0, 0, var(--video-control-opacity)) !important;
|
background: rgba(0, 0, 0, var(--video-control-opacity)) !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,48 +22,50 @@ const entry: ComponentEntry = async ({ settings: { options } }) => {
|
|||||||
} = playerAgent
|
} = playerAgent
|
||||||
|
|
||||||
await playerReady()
|
await playerReady()
|
||||||
const actions: Map<PlayerModes, () => void | Promise<void>> = new Map([
|
Promise.resolve().then(async () => {
|
||||||
[PlayerModes.Normal, none],
|
const actions: Map<PlayerModes, () => void | Promise<void>> = new Map([
|
||||||
[PlayerModes.Wide, async () => {
|
[PlayerModes.Normal, none],
|
||||||
await loadLazyPanel(buttons.widescreen.selector)
|
[PlayerModes.Wide, async () => {
|
||||||
disableWindowScroll(() => playerAgent.widescreen())
|
await loadLazyPanel(buttons.widescreen.selector)
|
||||||
}],
|
disableWindowScroll(() => playerAgent.widescreen())
|
||||||
[PlayerModes.WebFullscreen, async () => {
|
}],
|
||||||
await loadLazyPanel(buttons.webFullscreen.selector)
|
[PlayerModes.WebFullscreen, async () => {
|
||||||
playerAgent.webFullscreen()
|
await loadLazyPanel(buttons.webFullscreen.selector)
|
||||||
}],
|
playerAgent.webFullscreen()
|
||||||
[PlayerModes.Fullscreen, async () => {
|
}],
|
||||||
const video = await sq(
|
[PlayerModes.Fullscreen, async () => {
|
||||||
() => dq(playerAgent.query.video.element.selector),
|
const video = await sq(
|
||||||
(it: HTMLVideoElement) => it !== null && it.readyState === 4
|
() => dq(playerAgent.query.video.element.selector),
|
||||||
&& document.readyState === 'complete' && document.hasFocus(),
|
(it: HTMLVideoElement) => it !== null && it.readyState === 4
|
||||||
)
|
&& document.readyState === 'complete' && document.hasFocus(),
|
||||||
if (video === null) {
|
)
|
||||||
console.warn('[默认播放器模式] 未能应用全屏模式, 等待超时.')
|
if (video === null) {
|
||||||
return
|
console.warn('[默认播放器模式] 未能应用全屏模式, 等待超时.')
|
||||||
}
|
return
|
||||||
// await loadLazyPanel(buttons.fullscreen.selector)
|
}
|
||||||
playerAgent.fullscreen()
|
// await loadLazyPanel(buttons.fullscreen.selector)
|
||||||
}],
|
playerAgent.fullscreen()
|
||||||
])
|
}],
|
||||||
const video = await playerAgent.query.video.element() as HTMLVideoElement
|
])
|
||||||
if (!video) {
|
const video = await playerAgent.query.video.element() as HTMLVideoElement
|
||||||
return
|
if (!video) {
|
||||||
}
|
return
|
||||||
const action = actions.get(options.mode)
|
}
|
||||||
// https://github.com/the1812/Bilibili-Evolved/issues/2408
|
const action = actions.get(options.mode)
|
||||||
// 也许以前切P是会刷新页面,但现在(2.7+)的播放器切P是不刷新页面的,所以不需要判断
|
// https://github.com/the1812/Bilibili-Evolved/issues/2408
|
||||||
// const onplay = () => {
|
// 也许以前切P是会刷新页面,但现在(2.7+)的播放器切P是不刷新页面的,所以不需要判断
|
||||||
// const isNormalMode = !dq('body[class*=player-mode-]')
|
// const onplay = () => {
|
||||||
// if (isNormalMode) {
|
// const isNormalMode = !dq('body[class*=player-mode-]')
|
||||||
// action()
|
// if (isNormalMode) {
|
||||||
// }
|
// action()
|
||||||
// }
|
// }
|
||||||
if (options.applyOnPlay && !playerAgent.isAutoPlay()) {
|
// }
|
||||||
video.addEventListener('play', action, { once: true })
|
if (options.applyOnPlay && !playerAgent.isAutoPlay()) {
|
||||||
} else {
|
video.addEventListener('play', action, { once: true })
|
||||||
action()
|
} else {
|
||||||
}
|
action()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
export const component: ComponentMetadata = {
|
export const component: ComponentMetadata = {
|
||||||
name: 'defaultPlayerMode',
|
name: 'defaultPlayerMode',
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { playerAgent } from '@/components/video/player-agent'
|
|||||||
import { lightOff, lightOn } from '@/components/video/player-light'
|
import { lightOff, lightOn } from '@/components/video/player-light'
|
||||||
import { videoChange } from '@/core/observer'
|
import { videoChange } from '@/core/observer'
|
||||||
import { addComponentListener, getComponentSettings } from '@/core/settings'
|
import { addComponentListener, getComponentSettings } from '@/core/settings'
|
||||||
|
import { allVideoUrls } from '@/core/utils/urls'
|
||||||
|
|
||||||
enum IntersectionMode {
|
enum IntersectionMode {
|
||||||
Top = '视频顶部',
|
Top = '视频顶部',
|
||||||
@ -17,115 +18,118 @@ export const component: ComponentMetadata = {
|
|||||||
link: 'https://github.com/FoundTheWOUT',
|
link: 'https://github.com/FoundTheWOUT',
|
||||||
},
|
},
|
||||||
tags: [componentsTags.video],
|
tags: [componentsTags.video],
|
||||||
|
urlInclude: allVideoUrls,
|
||||||
entry: async ({ settings: { options }, metadata }) => {
|
entry: async ({ settings: { options }, metadata }) => {
|
||||||
const settings = options as {
|
const settings = options as {
|
||||||
triggerLocation: IntersectionMode
|
triggerLocation: IntersectionMode
|
||||||
pause: boolean
|
pause: boolean
|
||||||
light: boolean
|
light: boolean
|
||||||
}
|
}
|
||||||
const { query: { video } } = playerAgent
|
Promise.resolve().then(async () => {
|
||||||
|
const { query: { video } } = playerAgent
|
||||||
|
|
||||||
const videoEl = await video.element() as HTMLVideoElement
|
const videoEl = await video.element() as HTMLVideoElement
|
||||||
// const playerWrap = await video.wrap()
|
// const playerWrap = await video.wrap()
|
||||||
// 如果有 video-player 优先的使用该盒子
|
// 如果有 video-player 优先的使用该盒子
|
||||||
// 因为在稍后再看页面(medialist)视频也有 player-wrap
|
// 因为在稍后再看页面(medialist)视频也有 player-wrap
|
||||||
// 选择 player-wrap 会导致闪烁。
|
// 选择 player-wrap 会导致闪烁。
|
||||||
const playerWrap = (
|
const playerWrap = (
|
||||||
document.getElementById('video-player')
|
document.getElementById('video-player')
|
||||||
?? (dq('.player-wrap') || dq('.player-module'))
|
?? (dq('.player-wrap') || dq('.player-module'))
|
||||||
) as HTMLElement
|
) as HTMLElement
|
||||||
|
|
||||||
let observer: IntersectionObserver
|
let observer: IntersectionObserver
|
||||||
let intersectionLock = true // Lock intersection action
|
let intersectionLock = true // Lock intersection action
|
||||||
|
|
||||||
function getToTop(_mode: string): number {
|
function getToTop(_mode: string): number {
|
||||||
switch (_mode) {
|
switch (_mode) {
|
||||||
case IntersectionMode.Top:
|
case IntersectionMode.Top:
|
||||||
return 1
|
return 1
|
||||||
case IntersectionMode.Medium:
|
case IntersectionMode.Medium:
|
||||||
return 0.5
|
return 0.5
|
||||||
case IntersectionMode.Bottom:
|
case IntersectionMode.Bottom:
|
||||||
return 0
|
return 0
|
||||||
default:
|
default:
|
||||||
return 0.5
|
return 0.5
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPlayerOutEvent() {
|
|
||||||
// window.addEventListener('scroll', onPlayerOutEvent, { passive: true });
|
|
||||||
observer.observe(playerWrap)
|
|
||||||
}
|
|
||||||
|
|
||||||
function removePlayerOutEvent() {
|
|
||||||
// window.removeEventListener('scroll', onPlayerOutEvent);
|
|
||||||
observer.unobserve(playerWrap)
|
|
||||||
}
|
|
||||||
|
|
||||||
const intersectingCall = () => {
|
|
||||||
if (intersectionLock) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
intersectionLock = true // relock
|
|
||||||
if (settings.pause && videoEl.paused) {
|
|
||||||
videoEl.play()
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
settings.light
|
|
||||||
&& getComponentSettings('playerAutoLight').enabled
|
|
||||||
&& !settings.pause
|
|
||||||
&& !videoEl.paused
|
|
||||||
) {
|
|
||||||
lightOff()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const disIntersectingCall = () => {
|
|
||||||
// if video is playing, unlock intersecting action
|
|
||||||
if (!videoEl.paused) {
|
|
||||||
intersectionLock = false
|
|
||||||
}
|
|
||||||
if (settings.pause && !videoEl.paused) {
|
|
||||||
videoEl.pause()
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
settings.light
|
|
||||||
&& getComponentSettings('playerAutoLight').enabled
|
|
||||||
&& !settings.pause
|
|
||||||
) {
|
|
||||||
lightOn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createObserver = (mode?: string) => (
|
|
||||||
new IntersectionObserver(
|
|
||||||
([e]) => {
|
|
||||||
e.isIntersecting ? intersectingCall() : disIntersectingCall()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
threshold: getToTop(mode || settings.triggerLocation),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
function mountPlayListener() {
|
|
||||||
videoChange(async () => {
|
|
||||||
if (playerAgent.isAutoPlay()) {
|
|
||||||
addPlayerOutEvent()
|
|
||||||
}
|
}
|
||||||
videoEl.addEventListener('play', addPlayerOutEvent)
|
}
|
||||||
// videoEl.addEventListener('pause', removePlayerOutEvent);
|
|
||||||
videoEl.addEventListener('ended', removePlayerOutEvent)
|
function addPlayerOutEvent() {
|
||||||
|
// window.addEventListener('scroll', onPlayerOutEvent, { passive: true });
|
||||||
|
observer.observe(playerWrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePlayerOutEvent() {
|
||||||
|
// window.removeEventListener('scroll', onPlayerOutEvent);
|
||||||
|
observer.unobserve(playerWrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
const intersectingCall = () => {
|
||||||
|
if (intersectionLock) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
intersectionLock = true // relock
|
||||||
|
if (settings.pause && videoEl.paused) {
|
||||||
|
videoEl.play()
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
settings.light
|
||||||
|
&& getComponentSettings('playerAutoLight').enabled
|
||||||
|
&& !settings.pause
|
||||||
|
&& !videoEl.paused
|
||||||
|
) {
|
||||||
|
lightOff()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const disIntersectingCall = () => {
|
||||||
|
// if video is playing, unlock intersecting action
|
||||||
|
if (!videoEl.paused) {
|
||||||
|
intersectionLock = false
|
||||||
|
}
|
||||||
|
if (settings.pause && !videoEl.paused) {
|
||||||
|
videoEl.pause()
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
settings.light
|
||||||
|
&& getComponentSettings('playerAutoLight').enabled
|
||||||
|
&& !settings.pause
|
||||||
|
) {
|
||||||
|
lightOn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createObserver = (mode?: string) => (
|
||||||
|
new IntersectionObserver(
|
||||||
|
([e]) => {
|
||||||
|
e.isIntersecting ? intersectingCall() : disIntersectingCall()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
threshold: getToTop(mode || settings.triggerLocation),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
function mountPlayListener() {
|
||||||
|
videoChange(async () => {
|
||||||
|
if (playerAgent.isAutoPlay()) {
|
||||||
|
addPlayerOutEvent()
|
||||||
|
}
|
||||||
|
videoEl.addEventListener('play', addPlayerOutEvent)
|
||||||
|
// videoEl.addEventListener('pause', removePlayerOutEvent);
|
||||||
|
videoEl.addEventListener('ended', removePlayerOutEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponentListener(`${metadata.name}.triggerLocation`, (value: IntersectionMode) => {
|
||||||
|
removePlayerOutEvent()
|
||||||
|
observer = createObserver(value)
|
||||||
|
addPlayerOutEvent()
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
addComponentListener(`${metadata.name}.triggerLocation`, (value: IntersectionMode) => {
|
observer = createObserver()
|
||||||
removePlayerOutEvent()
|
mountPlayListener()
|
||||||
observer = createObserver(value)
|
|
||||||
addPlayerOutEvent()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
observer = createObserver()
|
|
||||||
mountPlayListener()
|
|
||||||
},
|
},
|
||||||
displayName: '播放器位置动作',
|
displayName: '播放器位置动作',
|
||||||
description: {
|
description: {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { ComponentMetadata } from '@/components/types'
|
import { ComponentMetadata } from '@/components/types'
|
||||||
|
import { playerAgent } from '@/components/video/player-agent'
|
||||||
import { videoChange } from '@/core/observer'
|
import { videoChange } from '@/core/observer'
|
||||||
import { select } from '@/core/spin-query'
|
import { select } from '@/core/spin-query'
|
||||||
import { playerReady } from '@/core/utils'
|
import { playerReady } from '@/core/utils'
|
||||||
@ -12,17 +13,19 @@ export const component: ComponentMetadata = {
|
|||||||
urlInclude: videoUrls,
|
urlInclude: videoUrls,
|
||||||
entry: async () => {
|
entry: async () => {
|
||||||
const autoPlayControls = {
|
const autoPlayControls = {
|
||||||
|
// 命中时应该打开连播: 传统分 P, 合集
|
||||||
enable: [
|
enable: [
|
||||||
'.base-video-sections .next-button',
|
':is(.base-video-sections, .base-video-sections-v1) .next-button',
|
||||||
'.multi-page .next-button',
|
':is(.multi-page, .multi-page-v1) .next-button',
|
||||||
'.player-auxiliary-autoplay-switch input',
|
'.player-auxiliary-autoplay-switch input',
|
||||||
],
|
],
|
||||||
disable: ['.recommend-list .next-button'],
|
// 命中时应该关闭连播: 关联视频推荐
|
||||||
|
disable: [':is(.recommend-list, .recommend-list-v1) .next-button'],
|
||||||
}
|
}
|
||||||
// 最后 1P 时不能开启连播
|
// 最后 1P 时不能开启连播
|
||||||
const disableConditions = [
|
const disableConditions = [
|
||||||
// 传统分 P
|
// 传统分 P
|
||||||
() => Boolean(dq('.multi-page .list-box li.on:last-child')),
|
() => Boolean(dq(':is(.multi-page, .multi-page-v1) .list-box li.on:last-child')),
|
||||||
// 替代分 P 的合集
|
// 替代分 P 的合集
|
||||||
// & 可分子合集的分 P 合集, 布局长得比下面那个丑一点
|
// & 可分子合集的分 P 合集, 布局长得比下面那个丑一点
|
||||||
() => Boolean(dq('.video-sections-item:last-child .video-episode-card:last-child .video-episode-card__info-playing')),
|
() => Boolean(dq('.video-sections-item:last-child .video-episode-card:last-child .video-episode-card__info-playing')),
|
||||||
@ -49,7 +52,7 @@ export const component: ComponentMetadata = {
|
|||||||
}
|
}
|
||||||
videoChange(async () => {
|
videoChange(async () => {
|
||||||
checkPlayMode()
|
checkPlayMode()
|
||||||
const video = await select('.bilibili-player-video video') as HTMLVideoElement
|
const video = await playerAgent.query.video.element() as HTMLVideoElement
|
||||||
video?.addEventListener('play', checkPlayMode, { once: true })
|
video?.addEventListener('play', checkPlayMode, { once: true })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
|
@import 'common';
|
||||||
|
|
||||||
@media screen and (max-width: 1200px) {
|
@media screen and (max-width: 1200px) {
|
||||||
.bilibili-player.mode-webfullscreen .bilibili-player-video-inputbar {
|
.bpx-player-video-inputbar,
|
||||||
display: flex !important;
|
.bilibili-player-video-inputbar {
|
||||||
|
@include on-fullscreen {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
import { ComponentMetadata } from '@/components/types'
|
import { ComponentMetadata } from '@/components/types'
|
||||||
import { toggleStyle } from '@/components/styled-component'
|
|
||||||
import { playerUrls } from '@/core/utils/urls'
|
import { playerUrls } from '@/core/utils/urls'
|
||||||
|
|
||||||
|
const name = 'preserveDanmakuInput'
|
||||||
export const component: ComponentMetadata = {
|
export const component: ComponentMetadata = {
|
||||||
...toggleStyle('preserveDanmakuInput', () => import('./danmaku-input.scss')),
|
name,
|
||||||
displayName: '强制保留弹幕发送栏',
|
displayName: '强制保留弹幕发送栏',
|
||||||
|
entry: none,
|
||||||
|
instantStyles: [
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
style: () => import('./danmaku-input.scss'),
|
||||||
|
},
|
||||||
|
],
|
||||||
tags: [
|
tags: [
|
||||||
componentsTags.style,
|
componentsTags.style,
|
||||||
componentsTags.video,
|
componentsTags.video,
|
||||||
|
|||||||
@ -14,7 +14,8 @@ body {
|
|||||||
}
|
}
|
||||||
&-related-videos {
|
&-related-videos {
|
||||||
.bilibili-player-video-link,
|
.bilibili-player-video-link,
|
||||||
.bilibili-player-link {
|
.bilibili-player-link,
|
||||||
|
.bpx-player-link {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,7 +28,10 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&-rates {
|
&-rates {
|
||||||
.bilibili-player-score {
|
.bilibili-player-score,
|
||||||
|
.bpx-player-popup-dm-close,
|
||||||
|
.bpx-player-score-summary-wrap,
|
||||||
|
.bpx-player-score {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<span
|
<span
|
||||||
class="quick-favorite"
|
class="quick-favorite be-quick-favorite"
|
||||||
title="快速收藏"
|
title="快速收藏"
|
||||||
:class="{ on: isFavorite }"
|
:class="{ on: isFavorite }"
|
||||||
@click.left.self="toggle()"
|
@click.left.self="toggle()"
|
||||||
|
|||||||
@ -61,10 +61,10 @@ export const component = defineComponentMetadata({
|
|||||||
},
|
},
|
||||||
entry,
|
entry,
|
||||||
unload: () => {
|
unload: () => {
|
||||||
dqa('.ops .quick-favorite').forEach((it: HTMLElement) => (it.style.display = 'none'))
|
dqa('.be-quick-favorite').forEach((it: HTMLElement) => (it.style.display = ''))
|
||||||
},
|
},
|
||||||
reload: () => {
|
reload: () => {
|
||||||
dqa('.ops .quick-favorite').forEach((it: HTMLElement) => (it.style.display = 'inline-block'))
|
dqa('.be-quick-favorite').forEach((it: HTMLElement) => (it.style.display = 'inline-block'))
|
||||||
},
|
},
|
||||||
urlInclude: videoUrls,
|
urlInclude: videoUrls,
|
||||||
// urlExclude: favoriteListUrls,
|
// urlExclude: favoriteListUrls,
|
||||||
@ -80,7 +80,7 @@ export const component = defineComponentMetadata({
|
|||||||
displayName: '快速收藏',
|
displayName: '快速收藏',
|
||||||
run: context => {
|
run: context => {
|
||||||
const { clickElement } = context
|
const { clickElement } = context
|
||||||
return clickElement('.quick-favorite', context)
|
return clickElement('.be-quick-favorite', context)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<div class="navbar-channel" :data-channel-id="channelId">频道</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax'
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
channelId: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
const { channel_id } = await bilibiliApi(getJsonWithCredentials(
|
||||||
|
'https://api.bilibili.com/x/web-interface/web/channel/red',
|
||||||
|
))
|
||||||
|
if (!channel_id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.channelId = channel_id
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
31
registry/lib/plugins/style/custom-navbar-channel/index.ts
Normal file
31
registry/lib/plugins/style/custom-navbar-channel/index.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { PluginMetadata } from '@/plugins/plugin'
|
||||||
|
import { getComponentSettings } from '@/core/settings'
|
||||||
|
import type { CustomNavbarItemInit } from '../../../components/style/custom-navbar/custom-navbar-item'
|
||||||
|
|
||||||
|
export const plugin: PluginMetadata = {
|
||||||
|
name: 'customNavbar.items.channel',
|
||||||
|
displayName: '自定义顶栏 - 频道',
|
||||||
|
description: '为自定义顶栏添加一个频道入口.',
|
||||||
|
async setup({ addData }) {
|
||||||
|
addData('customNavbar.items', (items: CustomNavbarItemInit[]) => {
|
||||||
|
const defaultLink = 'https://www.bilibili.com/v/channel/'
|
||||||
|
const name = 'channel'
|
||||||
|
const isOpenInNewTab = () => {
|
||||||
|
const { options } = getComponentSettings('customNavbar')
|
||||||
|
if (name in options.openInNewTabOverrides) {
|
||||||
|
return options.openInNewTabOverrides[name]
|
||||||
|
}
|
||||||
|
return options.openInNewTab
|
||||||
|
}
|
||||||
|
items.push({
|
||||||
|
name: 'channel',
|
||||||
|
displayName: '频道',
|
||||||
|
content: () => import('./NavbarChannel.vue'),
|
||||||
|
clickAction: () => {
|
||||||
|
const channelId = dq('.navbar-channel[data-channel-id]').getAttribute('data-channel-id')
|
||||||
|
window.open(channelId ? `${defaultLink}${channelId}` : defaultLink, isOpenInNewTab() ? '_blank' : '_self')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "2.3.3",
|
"version": "2.4.0",
|
||||||
"author": "Grant Howard, Coulomb-G",
|
"author": "Grant Howard, Coulomb-G",
|
||||||
"copyright": "[year], Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)",
|
"copyright": "[year], Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@ -5,9 +5,19 @@ import { FeedsCardsManagerV1 } from './v1'
|
|||||||
import { FeedsCardsManagerV2 } from './v2'
|
import { FeedsCardsManagerV2 } from './v2'
|
||||||
|
|
||||||
export * from './base'
|
export * from './base'
|
||||||
|
export const isV2Feeds = () => {
|
||||||
|
const hasCookieValue = parseInt(getCookieValue('hit-dyn-v2')) > 0
|
||||||
|
if (!hasCookieValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
't.bilibili.com',
|
||||||
|
'space.bilibili.com',
|
||||||
|
].some(host => location.host === host)
|
||||||
|
}
|
||||||
export const feedsCardsManager = (() => {
|
export const feedsCardsManager = (() => {
|
||||||
const isV2Feeds = parseInt(getCookieValue('hit-dyn-v2')) > 0 && location.host === 't.bilibili.com'
|
const isV2 = isV2Feeds()
|
||||||
if (isV2Feeds) {
|
if (isV2) {
|
||||||
return new FeedsCardsManagerV2()
|
return new FeedsCardsManagerV2()
|
||||||
}
|
}
|
||||||
return new FeedsCardsManagerV1()
|
return new FeedsCardsManagerV1()
|
||||||
|
|||||||
@ -3,7 +3,12 @@
|
|||||||
<div
|
<div
|
||||||
v-for="item of items"
|
v-for="item of items"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
class="be-video-control-bar-extend-item bilibili-player-video-btn squirtle-block-wrap"
|
class="
|
||||||
|
be-video-control-bar-extend-item
|
||||||
|
bilibili-player-video-btn
|
||||||
|
squirtle-block-wrap
|
||||||
|
bpx-player-ctrl-btn
|
||||||
|
"
|
||||||
:style="{ order: item.order.toString() }"
|
:style="{ order: item.order.toString() }"
|
||||||
:data-name="item.name"
|
:data-name="item.name"
|
||||||
@click="item.action($event)"
|
@click="item.action($event)"
|
||||||
@ -51,7 +56,7 @@ export default Vue.extend({
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
.be-icon {
|
.be-icon {
|
||||||
transition: transform .2s ease-out;
|
transition: transform 0.2s ease-out;
|
||||||
}
|
}
|
||||||
.be-icon svg,
|
.be-icon svg,
|
||||||
.be-icon {
|
.be-icon {
|
||||||
@ -93,7 +98,7 @@ export default Vue.extend({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
&:hover .be-video-control-tooltip {
|
&:hover .be-video-control-tooltip {
|
||||||
transition: all .3s ease-in-out .3s;
|
transition: all 0.3s ease-in-out 0.3s;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(-50%) translateY(calc(-100% - 19px));
|
transform: translateX(-50%) translateY(calc(-100% - 19px));
|
||||||
}
|
}
|
||||||
@ -113,4 +118,11 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bpx-player-control-wrap {
|
||||||
|
@include on-fullscreen {
|
||||||
|
& .be-video-control-bar-extend-item button {
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -45,7 +45,7 @@ const idPolyfill = async () => {
|
|||||||
})
|
})
|
||||||
loadPbpData()
|
loadPbpData()
|
||||||
}
|
}
|
||||||
/** 移除番剧的双击全屏, 和视频区保持一致.
|
/** 移除 3.x 的双击全屏.
|
||||||
* 如果以后视频区兼容了弹幕点赞层, 需要将双击全屏组件更换为阻止双击全屏, 并取消对此函数的使用.
|
* 如果以后视频区兼容了弹幕点赞层, 需要将双击全屏组件更换为阻止双击全屏, 并取消对此函数的使用.
|
||||||
*/
|
*/
|
||||||
const doubleClickPolyfill = async () => {
|
const doubleClickPolyfill = async () => {
|
||||||
@ -56,10 +56,11 @@ const doubleClickPolyfill = async () => {
|
|||||||
preventEvent(layer, 'dblclick')
|
preventEvent(layer, 'dblclick')
|
||||||
}
|
}
|
||||||
export const bpxPlayerPolyfill = lodash.once(async () => {
|
export const bpxPlayerPolyfill = lodash.once(async () => {
|
||||||
|
// 番剧 + 3.x 播放器通用
|
||||||
|
playerModePolyfill()
|
||||||
|
doubleClickPolyfill()
|
||||||
if (!document.URL.startsWith('https://www.bilibili.com/bangumi/play/')) {
|
if (!document.URL.startsWith('https://www.bilibili.com/bangumi/play/')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
playerModePolyfill()
|
|
||||||
idPolyfill()
|
idPolyfill()
|
||||||
doubleClickPolyfill()
|
|
||||||
})
|
})
|
||||||
|
|||||||
@ -250,12 +250,20 @@ export class VideoPlayerV2Agent extends PlayerAgent {
|
|||||||
if (!this.nativeApi) {
|
if (!this.nativeApi) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
if (this.nativeApi.isMuted) {
|
||||||
|
return this.nativeApi.isMuted()
|
||||||
|
}
|
||||||
return this.nativeApi.isMute()
|
return this.nativeApi.isMute()
|
||||||
}
|
}
|
||||||
changeVolume(change: number) {
|
changeVolume(change: number) {
|
||||||
if (!this.nativeApi) {
|
if (!this.nativeApi) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
if (this.nativeApi.getVolume) {
|
||||||
|
const current = this.nativeApi.getVolume()
|
||||||
|
this.nativeApi.setVolume(current + change / 100)
|
||||||
|
return Math.round(this.nativeApi.getVolume() * 100)
|
||||||
|
}
|
||||||
const current = this.nativeApi.volume()
|
const current = this.nativeApi.volume()
|
||||||
this.nativeApi.volume(current + change / 100)
|
this.nativeApi.volume(current + change / 100)
|
||||||
return Math.round(this.nativeApi.volume() * 100)
|
return Math.round(this.nativeApi.volume() * 100)
|
||||||
@ -389,54 +397,54 @@ export class BangumiPlayerAgent extends PlayerAgent {
|
|||||||
export class VideoPlayerMixedAgent extends VideoPlayerV2Agent {
|
export class VideoPlayerMixedAgent extends VideoPlayerV2Agent {
|
||||||
query = selectorWrap({
|
query = selectorWrap({
|
||||||
playerWrap: '.player-wrap',
|
playerWrap: '.player-wrap',
|
||||||
bilibiliPlayer: '.bilibili-player,#bilibili-player',
|
bilibiliPlayer: '.bilibili-player, #bilibili-player',
|
||||||
playerArea: '.bilibili-player-area,.bpx-player-primary-area',
|
playerArea: '.bilibili-player-area, .bpx-player-primary-area',
|
||||||
video: {
|
video: {
|
||||||
element: '.bilibili-player-video video,.bpx-player-video-wrap video',
|
element: '.bilibili-player-video video, .bpx-player-video-wrap video',
|
||||||
wrap: '.bilibili-player-video-wrap,.bpx-player-video-area',
|
wrap: '.bilibili-player-video-wrap, .bpx-player-video-area',
|
||||||
top: '.bilibili-player-video-top,.bpx-player-top-wrap',
|
top: '.bilibili-player-video-top, .bpx-player-top-wrap',
|
||||||
state: '.bilibili-player-video-state,.bpx-player-state-wrap',
|
state: '.bilibili-player-video-state, .bpx-player-state-wrap',
|
||||||
panel: '.bilibili-player-video-panel,.bpx-player-ending-panel',
|
panel: '.bilibili-player-video-panel, .bpx-player-ending-panel',
|
||||||
popup: '.bilibili-player-video-popup,.bpx-player-dialog-wrap',
|
popup: '.bilibili-player-video-popup, .bpx-player-dialog-wrap',
|
||||||
subtitle: '.bilibili-player-video-subtitle,.bpx-player-subtitle-wrap',
|
subtitle: '.bilibili-player-video-subtitle, .bpx-player-subtitle-wrap',
|
||||||
basDanmaku: '.bilibili-player-video-bas-danmaku,.bpx-player-bas-dm-wrap',
|
basDanmaku: '.bilibili-player-video-bas-danmaku, .bpx-player-bas-dm-wrap',
|
||||||
advDanmaku: '.bilibili-player-video-adv-danmaku,.bpx-player-adv-dm-wrap',
|
advDanmaku: '.bilibili-player-video-adv-danmaku, .bpx-player-adv-dm-wrap',
|
||||||
danmaku: '.bilibili-player-video-danmaku,.bpx-player-row-dm-wrap',
|
danmaku: '.bilibili-player-video-danmaku, .bpx-player-row-dm-wrap',
|
||||||
container: '.bilibili-player-video,.bpx-player-video-wrap',
|
container: '.bilibili-player-video, .bpx-player-video-perch',
|
||||||
},
|
},
|
||||||
control: {
|
control: {
|
||||||
element: '.bilibili-player-control,.bpx-player-control-entity',
|
element: '.bilibili-player-control, .bpx-player-control-entity',
|
||||||
wrap: '.bilibili-player-control-wrap,.bpx-player-control-wrap',
|
wrap: '.bilibili-player-control-wrap, .bpx-player-control-wrap',
|
||||||
mask: '.bilibili-player-control-mask,.bpx-player-control-mask',
|
mask: '.bilibili-player-control-mask, .bpx-player-control-mask',
|
||||||
top: '.bilibili-player-control-top,.bpx-player-control-top',
|
top: '.bilibili-player-control-top, .bpx-player-control-top',
|
||||||
progress: '.bilibili-player-video-progress,.bpx-player-progress',
|
progress: '.bilibili-player-video-progress, .bpx-player-progress',
|
||||||
bottom: '.bilibili-player-control-bottom,.bpx-player-control-bottom',
|
bottom: '.bilibili-player-control-bottom, .bpx-player-control-bottom',
|
||||||
bottomLeft: '.bilibili-player-control-bottom-left,,.bpx-player-control-bottom-left',
|
bottomLeft: '.bilibili-player-control-bottom-left, ,.bpx-player-control-bottom-left',
|
||||||
bottomCenter: '.bilibili-player-control-bottom-center,.bpx-player-control-bottom-center',
|
bottomCenter: '.bilibili-player-control-bottom-center, .bpx-player-control-bottom-center',
|
||||||
bottomRight: '.bilibili-player-control-bottom-right,.bpx-player-control-bottom-right',
|
bottomRight: '.bilibili-player-control-bottom-right, .bpx-player-control-bottom-right',
|
||||||
buttons: {
|
buttons: {
|
||||||
start: '.bilibili-player-video-btn-start,.bpx-player-ctrl-play',
|
start: '.bilibili-player-video-btn-start, .bpx-player-ctrl-play',
|
||||||
next: '.bilibili-player-video-btn-next,.bpx-player-ctrl-btn-next',
|
next: '.bilibili-player-video-btn-next, .bpx-player-ctrl-btn-next',
|
||||||
time: '.bilibili-player-video-time,.bpx-player-ctrl-time',
|
time: '.bilibili-player-video-time, .bpx-player-ctrl-time',
|
||||||
quality: '.bilibili-player-btn-quality,.bpx-player-ctrl-quality',
|
quality: '.bilibili-player-btn-quality, .bpx-player-ctrl-quality',
|
||||||
pageList: '.bilibili-player-video-btn-pagelist,.bpx-player-ctrl-eplist',
|
pageList: '.bilibili-player-video-btn-pagelist, .bpx-player-ctrl-eplist',
|
||||||
speed: '.bilibili-player-video-btn-speed,.bpx-player-ctrl-playbackrate',
|
speed: '.bilibili-player-video-btn-speed, .bpx-player-ctrl-playbackrate',
|
||||||
subtitle: '.bilibili-player-video-btn-subtitle,.bpx-player-ctrl-subtitle',
|
subtitle: '.bilibili-player-video-btn-subtitle, .bpx-player-ctrl-subtitle',
|
||||||
volume: '.bilibili-player-video-btn-volume .bilibili-player-iconfont-volume,.bpx-player-ctrl-volume .bpx-player-ctrl-volume-icon',
|
volume: '.bilibili-player-video-btn-volume .bilibili-player-iconfont-volume, .bpx-player-ctrl-volume .bpx-player-ctrl-volume-icon',
|
||||||
settings: '.bilibili-player-video-btn-setting,.bpx-player-ctrl-setting',
|
settings: '.bilibili-player-video-btn-setting, .bpx-player-ctrl-setting',
|
||||||
pip: '.bilibili-player-video-btn-pip,.bpx-player-ctrl-pip',
|
pip: '.bilibili-player-video-btn-pip, .bpx-player-ctrl-pip',
|
||||||
widescreen: '.bilibili-player-video-btn-widescreen,.bpx-player-ctrl-wide',
|
widescreen: '.bilibili-player-video-btn-widescreen, .bpx-player-ctrl-wide',
|
||||||
webFullscreen: '.bilibili-player-video-web-fullscreen,.bpx-player-ctrl-web',
|
webFullscreen: '.bilibili-player-video-web-fullscreen, .bpx-player-ctrl-web',
|
||||||
fullscreen: '.bilibili-player-video-btn-fullscreen,.bpx-player-ctrl-full',
|
fullscreen: '.bilibili-player-video-btn-fullscreen, .bpx-player-ctrl-full',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
wrap: '.bilibili-player-video-btn-setting-wrap,.bpx-player-ctrl-setting-box',
|
wrap: '.bilibili-player-video-btn-setting-wrap, .bpx-player-ctrl-setting-box',
|
||||||
lightOff: '.bilibili-player-video-btn-setting-right-others-content-lightoff .bui-checkbox-input,.bpx-player-ctrl-setting-lightoff .bui-checkbox-input',
|
lightOff: '.bilibili-player-video-btn-setting-right-others-content-lightoff .bui-checkbox-input, .bpx-player-ctrl-setting-lightoff .bui-checkbox-input',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
toastWrap: '.bilibili-player-video-toast-wrp,.bpx-player-dialog-wrap',
|
toastWrap: '.bilibili-player-video-toast-wrp, .bpx-player-dialog-wrap',
|
||||||
danmakuTipLayer: '.bilibili-player-dm-tip-wrap,.bpx-player-dm-tip',
|
danmakuTipLayer: '.bilibili-player-dm-tip-wrap, .bpx-player-dm-tip',
|
||||||
danmakuSwitch: '.bilibili-player-video-danmaku-switch input,.bpx-player-dm-switch input',
|
danmakuSwitch: '.bilibili-player-video-danmaku-switch input, .bpx-player-dm-switch input',
|
||||||
}) as PlayerQuery<ElementQuery>
|
}) as PlayerQuery<ElementQuery>
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@ -362,6 +362,9 @@ export class DoubleClickEvent {
|
|||||||
singleClickHandler: (e: MouseEvent) => void = none
|
singleClickHandler: (e: MouseEvent) => void = none
|
||||||
|
|
||||||
private clickedOnce = false
|
private clickedOnce = false
|
||||||
|
private readonly stopPropagationHandler = (e: MouseEvent) => {
|
||||||
|
e.stopImmediatePropagation()
|
||||||
|
}
|
||||||
private readonly doubleClickHandler = (e: MouseEvent) => {
|
private readonly doubleClickHandler = (e: MouseEvent) => {
|
||||||
if (!this.clickedOnce) {
|
if (!this.clickedOnce) {
|
||||||
this.clickedOnce = true
|
this.clickedOnce = true
|
||||||
@ -400,6 +403,7 @@ export class DoubleClickEvent {
|
|||||||
element.addEventListener('click', this.doubleClickHandler, {
|
element.addEventListener('click', this.doubleClickHandler, {
|
||||||
capture: true,
|
capture: true,
|
||||||
})
|
})
|
||||||
|
element.addEventListener('dblclick', this.stopPropagationHandler, { capture: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -415,6 +419,7 @@ export class DoubleClickEvent {
|
|||||||
element.removeEventListener('click', this.doubleClickHandler, {
|
element.removeEventListener('click', this.doubleClickHandler, {
|
||||||
capture: true,
|
capture: true,
|
||||||
})
|
})
|
||||||
|
element.removeEventListener('dblclick', this.stopPropagationHandler, { capture: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 等待播放器准备好, 如果过早注入 DOM 元素可能会导致爆炸
|
/** 等待播放器准备好, 如果过早注入 DOM 元素可能会导致爆炸
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user