Merge tag 'v2.10.0-preview' into preview-fixes

This commit is contained in:
the1812 2025-04-09 07:46:21 +08:00
commit 494be26889
17 changed files with 333 additions and 19 deletions

View File

@ -51,6 +51,7 @@
"Fullscreen",
"githubusercontent",
"Greasemonkey",
"guochuang",
"haruna",
"hdslb",
"HEVC",

View File

@ -32,7 +32,7 @@
**注意事项**
- **⚠ 使用正式版 (GitHub 源) 和预览版须翻墙.**
- 默认不预装任何组件, 需要在按[设置](#设置)中的说明添加感兴趣的功能; 默认会屏蔽双击全屏, 如有需要可以安装 `双击全屏` 组件来恢复.
- 默认不预装任何组件, 需要在按[设置](#设置)中的说明添加感兴趣的功能.
- 这个是一个综合性的脚本, 如果只是想下载视频建议去 [GreasyFork](https://greasyfork.org/zh-CN/scripts/by-site/bilibili.com) 找个更专业的.
- 对性能有较大影响, 详见[配置要求](#配置).
- 默认不对未登录的状态做适配.

View File

@ -1056,6 +1056,14 @@
"fullRelativePath": "../../registry/dist/plugins/style/custom-navbar-dark-mode.js",
"fullAbsolutePath": "registry/dist/plugins/style/custom-navbar-dark-mode.js"
},
{
"type": "plugin",
"name": "customNavbar.items.pgc",
"displayName": "自定义顶栏 - 版权内容",
"description": "为自定义顶栏扩充版权内容相关的快速入口, 包括国创 / 电影 / 电视剧 /综艺 / 纪录片",
"fullRelativePath": "../../registry/dist/plugins/style/custom-navbar-pgc.js",
"fullAbsolutePath": "registry/dist/plugins/style/custom-navbar-pgc.js"
},
{
"type": "plugin",
"name": "keymap.actions.darkMode",

View File

@ -1472,6 +1472,15 @@ by FoundTheWOUT
为自定义顶栏添加一个夜间模式开关, 方便快速切换夜间模式.
### [自定义顶栏 - 版权内容](../../registry/dist/plugins/style/custom-navbar-pgc.js)
`customNavbar.items.pgc`
**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/plugins/style/custom-navbar-pgc.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/plugins/style/custom-navbar-pgc.js)
**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/plugins/style/custom-navbar-pgc.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/plugins/style/custom-navbar-pgc.js)
为自定义顶栏扩充版权内容相关的快速入口, 包括国创 / 电影 / 电视剧 /综艺 / 纪录片
### [快捷键扩展 - 夜间模式](../../registry/dist/plugins/utils/keymap-dark-mode.js)
`keymap.actions.darkMode`

View File

@ -74,6 +74,7 @@ export default Vue.extend({
<style lang="scss">
@import 'common';
@import './scroll-animation';
.van-message-box {
z-index: 10002 !important;
@ -121,7 +122,6 @@ body.fixed-navbar {
.custom-navbar *,
.custom-navbar {
transition: all 0.2s ease-out;
-webkit-tap-highlight-color: transparent;
outline: none !important;
}

View File

@ -170,12 +170,28 @@ export default Vue.extend({
<style lang="scss">
@import 'common';
@keyframes navbar-popup-in {
to {
pointer-events: initial;
}
}
// @keyframes navbar-popup-out {
// from {
// pointer-events: none;
// }
// to {
// pointer-events: none;
// opacity: 0;
// }
// }
.custom-navbar-item {
color: inherit;
position: relative;
height: 100%;
display: flex;
align-items: center;
transition: 0.2s background-color ease-out;
.active-bar {
position: absolute;
@ -241,7 +257,7 @@ export default Vue.extend({
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.05);
border: 1px solid #8882;
border-radius: 8px;
transition: all 0.2s ease-out 0.2s;
transition: opacity 0.2s ease-out 0.2s;
position: absolute;
top: 100%;
left: 50%;
@ -270,14 +286,17 @@ export default Vue.extend({
background-color: transparent !important;
box-shadow: none;
}
> * {
@include default-transition();
}
}
&:not(.disabled) .popup-container {
position: absolute;
top: calc(100% - 8px);
left: 50%;
transition: all 0.2s ease-out 0.2s;
pointer-events: none;
transition: all 0.2s ease-out 0.2s;
}
&:not(.disabled):hover,
@ -285,8 +304,7 @@ export default Vue.extend({
.popup-container {
top: 100%;
> .popup {
// transform: translateY(0) translateX(-50%);
pointer-events: initial;
animation: navbar-popup-in 0.2s ease-out 0.2s both;
opacity: 1;
}
}

View File

@ -0,0 +1,183 @@
@property --navbar-foreground {
syntax: '<color>';
inherits: true;
initial-value: transparent;
}
@property --navbar-background {
syntax: '<color>';
inherits: true;
initial-value: transparent;
}
@property --foreground-color-d {
syntax: '<color>';
inherits: true;
initial-value: transparent;
}
@property --theme-color {
syntax: '<color>';
inherits: true;
initial-value: transparent;
}
@property --theme-color-60 {
syntax: '<color>';
inherits: true;
initial-value: transparent;
}
@keyframes transparent-to-light {
to {
--navbar-foreground: #555;
--navbar-background: white;
}
}
@keyframes transparent-to-light-blur {
to {
--navbar-foreground: #555;
--navbar-background: #fffc;
backdrop-filter: blur(24px);
}
}
@keyframes transparent-to-dark {
to {
--navbar-foreground: #eee;
--navbar-background: #222;
}
}
@keyframes transparent-to-dark-blur {
to {
--navbar-foreground: #eee;
--navbar-background: #2228;
backdrop-filter: blur(24px);
}
}
@keyframes transparent-to-theme {
to {
--navbar-foreground: var(--foreground-color-d);
--navbar-background: var(--theme-color);
}
}
@keyframes transparent-to-theme-blur {
to {
--navbar-foreground: var(--foreground-color-d);
--navbar-background: var(--theme-color-60);
backdrop-filter: blur(24px);
}
}
@keyframes transparent-to-light-shadow {
to {
--navbar-foreground: #555;
--navbar-background: white;
box-shadow: #0002 0 1px 10px 1px;
}
}
@keyframes transparent-to-light-blur-shadow {
to {
--navbar-foreground: #555;
--navbar-background: #fffc;
backdrop-filter: blur(24px);
box-shadow: #0002 0 1px 10px 1px;
}
}
@keyframes transparent-to-dark-shadow {
to {
--navbar-foreground: #eee;
--navbar-background: #222;
box-shadow: #0004 0px 2px 10px 1px;
}
}
@keyframes transparent-to-dark-blur-shadow {
to {
--navbar-foreground: #eee;
--navbar-background: #2228;
backdrop-filter: blur(24px);
box-shadow: #0004 0px 2px 10px 1px;
}
}
@keyframes transparent-to-theme-shadow {
to {
--navbar-foreground: var(--foreground-color-d);
--navbar-background: var(--theme-color);
box-shadow: #0002 0 1px 10px 1px;
}
}
@keyframes transparent-to-theme-blur-shadow {
to {
--navbar-foreground: var(--foreground-color-d);
--navbar-background: var(--theme-color-60);
backdrop-filter: blur(24px);
box-shadow: #0002 0 1px 10px 1px;
}
}
@keyframes transparent-mask {
to {
opacity: 0;
}
}
@keyframes launch-bar-colors {
to {
background-color: #8883;
}
}
@keyframes launch-bar-colors-fill {
to {
background-color: #0002;
}
}
@supports (animation-timeline: scroll()) {
.custom-navbar.transparent {
--animation-range: clamp(116px, 7vw, 180px) clamp(155px, 9.375vw, 240px);
&::before {
animation: transparent-mask linear both;
animation-timeline: scroll();
animation-range: var(--animation-range);
}
body.fixed-navbar & {
animation: transparent-to-light linear both;
animation-timeline: scroll();
animation-range: var(--animation-range);
.launch-bar {
animation: launch-bar-colors linear both;
animation-timeline: scroll();
animation-range: var(--animation-range);
}
&.shadow {
animation-name: transparent-to-light-shadow;
}
&.blur:not(.fill) {
animation-name: transparent-to-light-blur;
&.shadow {
animation-name: transparent-to-light-blur-shadow;
}
}
&.fill {
animation-name: transparent-to-theme;
.launch-bar {
animation-name: launch-bar-colors-fill;
}
&.shadow {
animation-name: transparent-to-theme-shadow;
}
&.blur {
animation-name: transparent-to-theme-blur;
&.shadow {
animation-name: transparent-to-theme-blur-shadow;
}
}
}
}
body.fixed-navbar.dark &:not(.fill) {
animation-name: transparent-to-dark;
&.shadow {
animation-name: transparent-to-dark-shadow;
}
&.blur {
animation-name: transparent-to-dark-blur;
&.shadow {
animation-name: transparent-to-dark-blur-shadow;
}
}
}
}
}

View File

@ -102,6 +102,7 @@ export default Vue.extend({
cursor: pointer;
position: relative;
box-sizing: border-box;
transition: 0.2s background-color ease-out;
&.loading {
font-size: 10pt;
cursor: initial;

View File

@ -59,10 +59,11 @@ export default Vue.extend({
position: absolute;
width: 100%;
height: 100%;
transition: 0.2s all ease-out 0.2s;
opacity: 1;
z-index: 100;
.custom-navbar-item:hover & {
transform: scale(2) translateY(10px);
z-index: 100;
opacity: 1;
}
}
.user-face {

View File

@ -1,5 +1,18 @@
.search-panel {
> .trending {
display: none !important;
}
&:not(:has(.history)) {
padding: 0 !important;
border: none !important;
}
}
#nav-searchform.is-focus {
/* 搜索框 focusing 且有关键字列表 or 历史记录列表时不显示低边框*/
&:not(:has(+ .search-panel > .suggestions), :has(+ .search-panel > .history)) {
border-radius: 8px !important;
}
}

View File

@ -1,5 +1,13 @@
import { defineComponentMetadata } from '@/components/define'
import { allMutations } from '@/core/observer'
import { select } from '@/core/spin-query'
const DEFAULT_PLACEHOLDER = '搜索'
const resetPlaceholder = (input: HTMLInputElement) => {
input.placeholder = DEFAULT_PLACEHOLDER
input.title = DEFAULT_PLACEHOLDER
}
export const component = defineComponentMetadata({
name: 'hideTrendingSearch',
@ -12,14 +20,24 @@ export const component = defineComponentMetadata({
},
],
entry: async () => {
const input: HTMLInputElement = await select('input.nav-search-input', {
queryInterval: 500,
})
if (input) {
resetPlaceholder(input)
return
}
// Fallback to observer
allMutations(records => {
records.forEach(record => {
if (
record.target instanceof HTMLInputElement &&
record.target.classList.contains('nav-search-input') &&
record.target.placeholder !== '搜索'
record.target.placeholder !== DEFAULT_PLACEHOLDER
) {
record.target.placeholder = '搜索'
resetPlaceholder(record.target)
}
})
})

View File

@ -8,10 +8,16 @@ import desc from './desc.md'
import ScreenshotContainer from './VideoScreenshotContainer.vue'
export const VideoScreenshotDisabledClass = 'video-screenshot-disable'
const entry = async () => {
let screenShotsList: Vue & {
screenshots: Screenshot[]
let screenShotsList: Vue & {
screenshots: Screenshot[]
}
const exitConfirmHandler = (e: BeforeUnloadEvent) => {
if (screenShotsList?.screenshots.length > 0) {
e.preventDefault()
}
}
const entry = async () => {
addControlBarButton({
name: 'takeScreenshot',
displayName: '截图',
@ -35,6 +41,7 @@ const entry = async () => {
}
},
})
window.addEventListener('beforeunload', exitConfirmHandler)
}
export const component = defineComponentMetadata({
name: 'videoScreenshot',
@ -45,8 +52,14 @@ export const component = defineComponentMetadata({
'zh-CN': desc,
},
urlInclude: playerUrls,
reload: () => document.body.classList.remove(VideoScreenshotDisabledClass),
unload: () => document.body.classList.add(VideoScreenshotDisabledClass),
reload: () => {
document.body.classList.remove(VideoScreenshotDisabledClass)
window.addEventListener('beforeunload', exitConfirmHandler)
},
unload: () => {
document.body.classList.add(VideoScreenshotDisabledClass)
window.removeEventListener('beforeunload', exitConfirmHandler)
},
plugin: {
displayName: '视频截图 - 快捷键支持',
setup: ({ addData }) => {

View File

@ -0,0 +1,46 @@
import { PluginMetadata } from '@/plugins/plugin'
import type { CustomNavbarItemInit } from '../../../components/style/custom-navbar/custom-navbar-item'
export const plugin: PluginMetadata = {
name: 'customNavbar.items.pgc',
displayName: '自定义顶栏 - 版权内容',
description: '为自定义顶栏扩充版权内容相关的快速入口, 包括国创 / 电影 / 电视剧 /综艺 / 纪录片',
async setup({ addData }) {
addData('customNavbar.items', (items: CustomNavbarItemInit[]) => {
const pgcItems = [
{
name: 'guochuang',
displayName: '国创',
href: 'https://www.bilibili.com/guochuang/',
},
{
name: 'movie',
displayName: '电影',
href: 'https://www.bilibili.com/movie/',
},
{
name: 'tv',
displayName: '电视剧',
href: 'https://www.bilibili.com/tv/',
},
{
name: 'variety',
displayName: '综艺',
href: 'https://www.bilibili.com/variety/',
},
{
name: 'documentary',
displayName: '纪录片',
href: 'https://www.bilibili.com/documentary/',
},
]
items.push(
...pgcItems.map(item => ({
...item,
content: item.displayName,
active: document.URL.startsWith(item.href),
})),
)
})
},
}

View File

@ -2,7 +2,7 @@ import { DownloadPackage, PackageEntry } from '@/core/download'
import { meta } from '@/core/meta'
import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
import { formatPercent } from '@/core/utils/formatters'
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
import { title as pluginTitle } from '.'
import type { Options } from '../../../../components/video/download'
import { DownloadVideoAction } from '../../../../components/video/download/types'
@ -139,6 +139,10 @@ export async function run(action: DownloadVideoAction, muxWithMetadata: boolean)
throw new Error('仅支持 DASH 格式视频和音频')
}
if (video.size + audio.size > 4294967295) {
throw new Error(`仅支持合并 4GB 内的音视频(${formatFileSize(video.size + audio.size)}`)
}
await single(
video.title,
video.url,

View File

@ -19,7 +19,7 @@ export const plugin: PluginMetadata = {
outputs.push({
name: 'wasm',
displayName: 'WASM',
description: `${desc}。运行过程中请勿关闭页面,初次使用或清除缓存后需要加载约 30 MB 的 WASM 文件。`,
description: `${desc}。运行过程中请勿关闭页面,初次使用或清除缓存后需要加载约 30 MB 的 WASM 文件。由于浏览器限制,仅支持合并 4GB 以内的音视频。`,
runAction: async (action, instance) => {
try {
await run(action, instance.muxWithMetadata)

View File

@ -73,7 +73,6 @@ export default Vue.extend({
--color: #eee;
}
.launch-bar-suggest-list {
transition: 0.2s ease-out;
top: calc(100% + 8px);
max-height: calc(80vh - 16px - #{$barHeight});
@include no-scrollbar();

View File

@ -333,7 +333,7 @@ export default Vue.extend({
width: 100%;
transform: translateX(-50%) translateY(-4px);
pointer-events: none;
// transition: 0.2s ease-out;
transition: 0.2s all ease-out;
border: 1px solid #8882;
white-space: nowrap;
border-radius: 8px;