mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-09-26 22:49:14 +08:00
Merge branch 'preview-fixes' into preview-features
This commit is contained in:
commit
24714b77a7
@ -28,7 +28,6 @@
|
||||
"name": "Install dependencies",
|
||||
"uses": "pnpm/action-setup@v4",
|
||||
"with": {
|
||||
"version": "8.12.1",
|
||||
"run_install": true
|
||||
}
|
||||
},
|
||||
|
@ -17,7 +17,6 @@
|
||||
"name": "Install dependencies",
|
||||
"uses": "pnpm/action-setup@v4",
|
||||
"with": {
|
||||
"version": "8.12.1",
|
||||
"run_install": true
|
||||
}
|
||||
},
|
||||
|
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -22,7 +22,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8.12.1
|
||||
run_install: true
|
||||
- name: Type check
|
||||
run: pnpm run type
|
||||
|
1
.github/workflows/pull-request-check.yml
vendored
1
.github/workflows/pull-request-check.yml
vendored
@ -11,7 +11,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8.12.1
|
||||
run_install: true
|
||||
- name: Type check
|
||||
run: pnpm run type
|
||||
|
12
package.json
12
package.json
@ -51,7 +51,7 @@
|
||||
"postcss-loader": "^4.0.4",
|
||||
"postcss-preset-env": "^7.5.0",
|
||||
"prettier": "^2.8.3",
|
||||
"sass": "^1.25.0",
|
||||
"sass": "1.25.0",
|
||||
"serve": "^13.0.2",
|
||||
"serve-handler": "^6.1.3",
|
||||
"style-loader": "^2.0.0",
|
||||
@ -60,6 +60,7 @@
|
||||
"to-string-loader": "^1.2.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.9.5",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-loader": "^15.10.1",
|
||||
"webpack": "^5.31.2",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
@ -84,7 +85,11 @@
|
||||
"overrides": {
|
||||
"caniuse-lite": "1.0.30001668",
|
||||
"consolidate": "1.0.1"
|
||||
}
|
||||
},
|
||||
"onlyBuiltDependencies": [
|
||||
"@parcel/watcher",
|
||||
"protobufjs"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"userscript",
|
||||
@ -92,5 +97,6 @@
|
||||
"dark-theme",
|
||||
"touchscreen",
|
||||
"tampermonkey"
|
||||
]
|
||||
],
|
||||
"packageManager": "pnpm@10.3.0+sha512.ee592eda8815a8a293c206bb0917c4bb0ff274c50def7cbc17be05ec641fc2d1b02490ce660061356bd0d126a4d7eb2ec8830e6959fb8a447571c631d5a2442d"
|
||||
}
|
||||
|
10450
pnpm-lock.yaml
generated
10450
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { addComponentListener } from '@/core/settings'
|
||||
import { getUID } from '@/core/utils'
|
||||
import { ascendingSort } from '@/core/utils/sort'
|
||||
import { registerAndGetData } from '@/plugins/data'
|
||||
import { getBuiltInItems } from './built-in-items'
|
||||
@ -28,14 +27,7 @@ const [renderedItems] = registerAndGetData(CustomNavbarRenderedItems, {
|
||||
items: [] as CustomNavbarItem[],
|
||||
})
|
||||
const getItems = () => {
|
||||
const isLogin = Boolean(getUID())
|
||||
const items = (initItems as CustomNavbarItemInit[])
|
||||
.filter(it => {
|
||||
if (it.loginRequired && !isLogin) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
.map(it => new CustomNavbarItem(it))
|
||||
.sort(ascendingSort(it => it.order))
|
||||
renderedItems.items = items
|
||||
|
@ -2,6 +2,7 @@ import { createPopper, Instance as Popper } from '@popperjs/core'
|
||||
import { VueModule, Executable } from '@/core/common-types'
|
||||
import { getComponentSettings, addComponentListener } from '@/core/settings'
|
||||
import type { CustomNavbarOptions } from '.'
|
||||
import { getUID } from '@/core/utils'
|
||||
|
||||
export const CustomNavbarItems = 'customNavbar.items'
|
||||
export const CustomNavbarRenderedItems = 'customNavbar.renderedItems'
|
||||
@ -90,7 +91,8 @@ export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
|
||||
},
|
||||
true,
|
||||
)
|
||||
this.hidden = CustomNavbarItem.navbarOptions.hidden.includes(this.name)
|
||||
this.hidden =
|
||||
CustomNavbarItem.navbarOptions.hidden.includes(this.name) || (!getUID() && init.loginRequired)
|
||||
const orderMap = CustomNavbarItem.navbarOptions.order
|
||||
this.order = orderMap[this.name] || 0
|
||||
this.requestedPopup = !this.lazy
|
||||
|
@ -35,6 +35,7 @@ export const entry: ComponentEntry = async ({ metadata: { name } }) => {
|
||||
'https://www.bilibili.com/opus',
|
||||
'https://www.bilibili.com/account/history',
|
||||
'https://www.bilibili.com/v/topic/detail',
|
||||
'https://www.bilibili.com/watchlater/list',
|
||||
]
|
||||
if (!globalFixedExclude.some(p => matchUrlPattern(p))) {
|
||||
addComponentListener(
|
||||
|
@ -118,20 +118,18 @@ export default Vue.extend({
|
||||
}
|
||||
})
|
||||
const list: HTMLElement = this.$refs.navbarSortList
|
||||
const Sortable = await SortableJSLibrary
|
||||
Sortable.create(list, {
|
||||
delay: 100,
|
||||
forceFallback: true,
|
||||
onEnd: (e: SortableEvent) => {
|
||||
this.onSort(e)
|
||||
},
|
||||
})
|
||||
checkSequentialOrder(rendered.items)
|
||||
if (list) {
|
||||
const Sortable = await SortableJSLibrary
|
||||
Sortable.create(list, {
|
||||
delay: 100,
|
||||
forceFallback: true,
|
||||
onEnd: (e: SortableEvent) => {
|
||||
this.onSort(e)
|
||||
},
|
||||
})
|
||||
checkSequentialOrder(rendered.items)
|
||||
}
|
||||
this.loaded = true
|
||||
// unsafeWindow.nsTest = {
|
||||
// list,
|
||||
// Sortable,
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
|
@ -4,11 +4,11 @@ interface SimpleLinkConfig {
|
||||
name: string
|
||||
displayName: string
|
||||
href: string
|
||||
content?: string
|
||||
}
|
||||
const getSimpleLinkItem = (config: SimpleLinkConfig): SimpleLinkConfig & CustomNavbarItemInit => ({
|
||||
...config,
|
||||
content: config.displayName,
|
||||
|
||||
...config,
|
||||
active: document.URL.startsWith(config.href),
|
||||
})
|
||||
export const ranking = getSimpleLinkItem({
|
||||
@ -18,7 +18,8 @@ export const ranking = getSimpleLinkItem({
|
||||
})
|
||||
export const bangumi = getSimpleLinkItem({
|
||||
name: 'bangumi',
|
||||
displayName: '番剧',
|
||||
displayName: '番剧 (链接)',
|
||||
content: '番剧',
|
||||
href: 'https://www.bilibili.com/anime/',
|
||||
})
|
||||
export const music = getSimpleLinkItem({
|
||||
|
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="">{{ content }}</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
addComponentListener,
|
||||
getComponentSettings,
|
||||
removeComponentListener,
|
||||
} from '@/core/settings'
|
||||
import type { CustomNavbarOptions } from '..'
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
isBangumiLinkHidden:
|
||||
getComponentSettings<CustomNavbarOptions>('customNavbar').options.hidden.includes(
|
||||
'bangumi',
|
||||
),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
content() {
|
||||
if (this.isBangumiLinkHidden) {
|
||||
return '番剧'
|
||||
}
|
||||
return '追番追剧'
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
addComponentListener('customNavbar.hidden', this.updateBangumiLinkStatus)
|
||||
},
|
||||
beforeDestroy() {
|
||||
removeComponentListener('customNavbar.hidden', this.updateBangumiLinkStatus)
|
||||
},
|
||||
methods: {
|
||||
updateBangumiLinkStatus(hiddenItems: string[]) {
|
||||
const isBangumiLinkHidden = hiddenItems.includes('bangumi')
|
||||
this.isBangumiLinkHidden = isBangumiLinkHidden
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
@ -8,8 +8,8 @@ export enum SubscriptionTypes {
|
||||
const uid = getUID()
|
||||
export const subscriptions: CustomNavbarItemInit = {
|
||||
name: 'subscriptions',
|
||||
displayName: '番剧',
|
||||
content: '番剧',
|
||||
displayName: '番剧 (弹窗)',
|
||||
content: () => import('./Content.vue').then(m => m.default),
|
||||
|
||||
href: `https://space.bilibili.com/${uid}/bangumi`,
|
||||
touch: true,
|
||||
|
@ -40,7 +40,7 @@
|
||||
<div v-if="card.percent" class="progress" :style="{ width: card.percent * 100 + '%' }" />
|
||||
</a>
|
||||
<a class="title" target="_blank" :href="card.href" :title="card.title">{{ card.title }}</a>
|
||||
<div class="info">
|
||||
<div class="info-row">
|
||||
<a
|
||||
class="up"
|
||||
target="_blank"
|
||||
@ -352,7 +352,7 @@ export default Vue.extend({
|
||||
color: var(--theme-color) !important;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
|
@ -16,5 +16,6 @@
|
||||
@import "./dark-slice-16.scss";
|
||||
@import "./dark-slice-17.scss";
|
||||
@import "./dark-slice-18.scss";
|
||||
@import "./dark-slice-19.scss";
|
||||
@import "./dark-navbar.scss";
|
||||
@import "./dark-variables.scss";
|
||||
|
@ -619,7 +619,7 @@ html {
|
||||
&:not(.iframe) {
|
||||
&,
|
||||
body {
|
||||
@include background-color('2');
|
||||
background-color: var(--bg1, #222) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
@import './dark-definitions';
|
||||
@import 'common';
|
||||
|
||||
.relation-card-info-option {
|
||||
.follow-btn {
|
||||
@include background-color();
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { postTextWithCredentials, getJsonWithCredentials } from '@/core/ajax'
|
||||
import { postTextWithCredentials } from '@/core/ajax'
|
||||
import { Toast } from '@/core/toast'
|
||||
import { formData, getCsrf } from '@/core/utils'
|
||||
import { getCsrf } from '@/core/utils'
|
||||
import { registerAndGetData } from '@/plugins/data'
|
||||
|
||||
export interface CheckInItem {
|
||||
@ -19,7 +19,7 @@ const builtInItems: CheckInItem[] = [
|
||||
const seedsToCoinsApi = 'https://api.live.bilibili.com/xlive/revenue/v1/wallet/silver2coin'
|
||||
const text = await postTextWithCredentials(
|
||||
seedsToCoinsApi,
|
||||
formData({
|
||||
new URLSearchParams({
|
||||
csrf: getCsrf(),
|
||||
csrf_token: getCsrf(),
|
||||
}),
|
||||
@ -40,31 +40,5 @@ const builtInItems: CheckInItem[] = [
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'live-check-in',
|
||||
displayName: '直播间签到',
|
||||
icon: 'mdi-calendar-check',
|
||||
action: async () => {
|
||||
const liveCheckInApi = 'https://api.live.bilibili.com/xlive/web-ucenter/v1/sign/DoSign'
|
||||
const json = (await getJsonWithCredentials(liveCheckInApi)) as {
|
||||
code: number
|
||||
message: string
|
||||
data: {
|
||||
text: string
|
||||
specialText: string
|
||||
allDays: number
|
||||
hadSignDays: number
|
||||
isBonusDay: number
|
||||
}
|
||||
}
|
||||
if (json.code !== 0) {
|
||||
Toast.info(json.message, '直播间签到', 3000)
|
||||
} else {
|
||||
const { text, specialText, allDays, hadSignDays } = json.data
|
||||
const message = `签到成功, 获得了${text} ${specialText}\n本月进度: ${hadSignDays} / ${allDays}`
|
||||
Toast.success(message, '直播间签到', 3000)
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
export const [checkInItems] = registerAndGetData('checkInCenter.items', builtInItems)
|
||||
|
@ -23,7 +23,7 @@ export const setupFeedImageExporter: ComponentEntry<Options> = async ({
|
||||
const imageUrls: { url: string; extension: string }[] = []
|
||||
dqa(
|
||||
card.element,
|
||||
'.main-content .img-content, .bili-album__preview__picture__img, .bili-album .preview__picture__img, .bili-dyn-gallery__image img',
|
||||
'.main-content .img-content, .bili-album__preview__picture__img, .bili-album .preview__picture__img, .bili-dyn-gallery__image img, .bili-album__watch__track__item img',
|
||||
).forEach((img: HTMLImageElement | HTMLDivElement) => {
|
||||
const urlData = retrieveImageUrl(img)
|
||||
if (urlData && !imageUrls.some(({ url }) => url === urlData.url)) {
|
||||
|
7
registry/lib/components/utils/image-resolution/index.md
Normal file
7
registry/lib/components/utils/image-resolution/index.md
Normal file
@ -0,0 +1,7 @@
|
||||
对 200% 以上的屏幕 DPI 缩放请求更高分辨率的图片, 加载时间也会相应变长一些. (也会导致某些浏览器里出现图片闪动, 因为本质上是更换了图片源)
|
||||
|
||||
由于 b 站在很多地方没有设置图片维持原比例, 如果计算后的图片尺寸超出原图尺寸则会产生错误的比例, 可以考虑在选项中手动降低缩放级别.
|
||||
|
||||
`缩放级别` 选项:
|
||||
- `auto`: 根据 DPI 缩放超出 200% 的比例自动计算, 例如 250% 的缩放下会请求 1.5 倍尺寸的图片.
|
||||
- `数字`: 自定义尺寸的缩放倍率.
|
@ -9,7 +9,6 @@ const options = defineOptionsMetadata({
|
||||
scale: {
|
||||
displayName: '缩放级别',
|
||||
defaultValue: 'auto',
|
||||
hidden: true,
|
||||
},
|
||||
originalImageInArticles: {
|
||||
displayName: '在专栏中请求原图',
|
||||
@ -25,9 +24,5 @@ export const component = defineComponentMetadata({
|
||||
tags: [componentsTags.utils],
|
||||
enabledByDefault: window.devicePixelRatio > 1,
|
||||
entry: startResolution,
|
||||
description: {
|
||||
'zh-CN':
|
||||
'根据屏幕 DPI 请求更高分辨率的图片, 例如 DPI 缩放 200% 则请求 2 倍的分辨率, 加载时间也会相应变长一些. (也会导致某些浏览器里出现图片闪动, 因为本质上是更换了图片源)',
|
||||
},
|
||||
options,
|
||||
})
|
||||
|
@ -19,6 +19,13 @@ const widthAndHeightSelectors = [
|
||||
]
|
||||
const originalImageInArticlesSelectors = ['.article-detail .article-content img']
|
||||
|
||||
const getAutoScale = () => {
|
||||
if (window.devicePixelRatio <= 2) {
|
||||
return 1
|
||||
}
|
||||
return window.devicePixelRatio / 2
|
||||
}
|
||||
|
||||
const walk = (rootElement: Node, action: (node: HTMLElement) => void) => {
|
||||
const walker = document.createNodeIterator(rootElement, NodeFilter.SHOW_ELEMENT)
|
||||
let node = walker.nextNode()
|
||||
@ -123,10 +130,11 @@ export const startResolution = styledComponentEntry<Options>(
|
||||
() => import('./fix.scss'),
|
||||
async ({ settings }) => {
|
||||
const { allMutations } = await import('@/core/observer')
|
||||
const dpi =
|
||||
settings.options.scale === 'auto'
|
||||
? window.devicePixelRatio
|
||||
: parseFloat(settings.options.scale)
|
||||
const scale =
|
||||
settings.options.scale === 'auto' ? getAutoScale() : parseFloat(settings.options.scale)
|
||||
if (scale === 1) {
|
||||
return
|
||||
}
|
||||
const handleResolution: ImageResolutionHandler = {
|
||||
getWidth: (currentWidth, element) => {
|
||||
if (
|
||||
@ -135,7 +143,7 @@ export const startResolution = styledComponentEntry<Options>(
|
||||
) {
|
||||
return Infinity
|
||||
}
|
||||
return Math.round(dpi * currentWidth)
|
||||
return Math.round(scale * currentWidth)
|
||||
},
|
||||
getHeight: (currentHeight, element) => {
|
||||
if (
|
||||
@ -144,7 +152,7 @@ export const startResolution = styledComponentEntry<Options>(
|
||||
) {
|
||||
return Infinity
|
||||
}
|
||||
return Math.round(dpi * currentHeight)
|
||||
return Math.round(scale * currentHeight)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isTyping, matchUrlPattern } from '@/core/utils'
|
||||
import { getActiveElement, isTyping, matchUrlPattern } from '@/core/utils'
|
||||
import { mediaListUrls, watchlaterUrls } from '@/core/utils/urls'
|
||||
import { clickElement, changeVideoTime, showTip } from './actions'
|
||||
import { shadowDomObserver } from '@/core/shadow-root'
|
||||
@ -17,6 +17,7 @@ export interface KeyBindingAction {
|
||||
run: (context: KeyBindingActionContext) => unknown
|
||||
prevent?: boolean
|
||||
ignoreTyping?: boolean
|
||||
ignoreFocus?: boolean
|
||||
}
|
||||
export interface KeyBinding {
|
||||
keys: string[]
|
||||
@ -43,6 +44,15 @@ export const loadKeyBindings = lodash.once((bindings: KeyBinding[]) => {
|
||||
if (binding.action.ignoreTyping !== false && isTyping()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 忽略其他可聚焦元素
|
||||
const hasElementFocus = !([document.body, null] as (Element | null)[]).includes(
|
||||
getActiveElement(),
|
||||
)
|
||||
if (binding.action.ignoreFocus !== false && hasElementFocus) {
|
||||
return
|
||||
}
|
||||
|
||||
const key = e.key.toLowerCase()
|
||||
|
||||
// 全景视频禁用 WASD 快捷键
|
||||
|
@ -36,7 +36,8 @@ body:not(.preserve-feed-goods) .dyn-goods,
|
||||
.desktop-download-tip,
|
||||
.adcard,
|
||||
.palette-button-adcard,
|
||||
.palette-button-wrap .adcard-content {
|
||||
.palette-button-wrap .adcard-content,
|
||||
.video-card-ad-small {
|
||||
display: none !important;
|
||||
}
|
||||
.recommend-list .rec-list > :not(.video-page-card) + .video-page-card {
|
||||
|
@ -1,53 +1,87 @@
|
||||
import { ComponentEntry } from '@/components/types'
|
||||
import { defineComponentMetadata } from '@/components/define'
|
||||
import type { RawWatchlaterItem } from '@/components/video/watchlater'
|
||||
|
||||
const entry: ComponentEntry = async ({ settings }) => {
|
||||
if (settings.options.page) {
|
||||
const { select } = await import('@/core/spin-query')
|
||||
const { childList } = await import('@/core/observer')
|
||||
const { getWatchlaterList } = await import('@/components/video/watchlater')
|
||||
const list = await getWatchlaterList(true)
|
||||
const listBox = await select('.watch-later-list .list-box > span')
|
||||
if (!listBox) {
|
||||
return
|
||||
}
|
||||
const redirect = (item: Element, index: number) => {
|
||||
try {
|
||||
const watchlaterItem = list[index]
|
||||
const { bvid, cid, pages } = watchlaterItem
|
||||
const page = pages.find(p => p.cid === cid)?.page ?? 1
|
||||
const url =
|
||||
page > 1
|
||||
? `https://www.bilibili.com/video/${bvid}?p=${page}`
|
||||
: `https://www.bilibili.com/video/${bvid}`
|
||||
const pic = item.querySelector('.av-pic') as HTMLAnchorElement
|
||||
pic.target = '_blank'
|
||||
pic.href = url
|
||||
const title = item.querySelector('.av-about .t') as HTMLAnchorElement
|
||||
title.target = '_blank'
|
||||
title.href = url
|
||||
} catch (error) {
|
||||
console.error(`[watchlater redirect] error at index ${index}`, item, error)
|
||||
}
|
||||
}
|
||||
const runRedirect = () => {
|
||||
const avItems = listBox.querySelectorAll('.av-item')
|
||||
avItems.forEach(redirect)
|
||||
}
|
||||
childList(listBox, records => {
|
||||
records.forEach(record => {
|
||||
record.removedNodes.forEach(node => {
|
||||
if (node instanceof HTMLElement && !node.classList.contains('itemlist-move')) {
|
||||
const index = parseInt(dq(node, '.key').textContent) - 1
|
||||
console.log('remove index', index)
|
||||
list.splice(index, 1)
|
||||
}
|
||||
})
|
||||
})
|
||||
runRedirect()
|
||||
})
|
||||
const getBvidFromElement = (element: Element) => {
|
||||
const pic = element.querySelector('.av-pic, .bili-cover-card') as HTMLAnchorElement
|
||||
const bvid = pic.href.match(/bvid=([^&]+)/)?.[1]
|
||||
return bvid
|
||||
}
|
||||
|
||||
const redirect = (element: Element, watchlaterItem: RawWatchlaterItem) => {
|
||||
try {
|
||||
const { bvid, cid, pages } = watchlaterItem
|
||||
const page = pages.find(p => p.cid === cid)?.page ?? 1
|
||||
const url =
|
||||
page > 1
|
||||
? `https://www.bilibili.com/video/${bvid}?p=${page}`
|
||||
: `https://www.bilibili.com/video/${bvid}`
|
||||
const pic = element.querySelector('.av-pic, .bili-cover-card') as HTMLAnchorElement
|
||||
pic.target = '_blank'
|
||||
pic.href = url
|
||||
const title = element.querySelector(
|
||||
'.av-about .t, .bili-video-card__title a, .video-card__right .title',
|
||||
) as HTMLAnchorElement
|
||||
title.target = '_blank'
|
||||
title.href = url
|
||||
} catch (error) {
|
||||
console.error(`[watchlater redirect] error at ${watchlaterItem.bvid}`, element, error)
|
||||
}
|
||||
}
|
||||
|
||||
const entry: ComponentEntry = async ({ settings }) => {
|
||||
if (!settings.options.page) {
|
||||
return
|
||||
}
|
||||
const { select } = await import('@/core/spin-query')
|
||||
const { childListSubtree } = await import('@/core/observer')
|
||||
const { getWatchlaterList } = await import('@/components/video/watchlater')
|
||||
const { useScopedConsole } = await import('@/core/utils/log')
|
||||
const console = useScopedConsole('稍后再看重定向')
|
||||
const list: RawWatchlaterItem[] = await getWatchlaterList(true)
|
||||
const listContainer = await select('.watch-later-list .list-box > span, .watchlater-list')
|
||||
if (!listContainer) {
|
||||
return
|
||||
}
|
||||
|
||||
const tryRedirect = (element: Element) => {
|
||||
const bvid = getBvidFromElement(element)
|
||||
if (bvid === undefined) {
|
||||
console.warn('bvid not found for', element)
|
||||
return
|
||||
}
|
||||
const listItem = list.find(it => it.bvid === bvid)
|
||||
if (listItem === undefined) {
|
||||
console.warn('bvid no match for', bvid)
|
||||
return
|
||||
}
|
||||
redirect(element, listItem)
|
||||
}
|
||||
|
||||
const runRedirect = lodash.debounce(() => {
|
||||
const videoCards = listContainer.querySelectorAll('.av-item, .video-card')
|
||||
console.log('run redirect, length =', videoCards.length)
|
||||
videoCards.forEach(card => {
|
||||
tryRedirect(card)
|
||||
})
|
||||
}, 200)
|
||||
|
||||
runRedirect()
|
||||
childListSubtree(listContainer, async records => {
|
||||
records.forEach(r => {
|
||||
const hasVideoCardChange = [...r.addedNodes].some(
|
||||
node =>
|
||||
node instanceof HTMLElement &&
|
||||
(node.classList.contains('bili-video-card__wrap') ||
|
||||
node.classList.contains('watchlater-list-container')),
|
||||
)
|
||||
if (hasVideoCardChange) {
|
||||
runRedirect()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const component = defineComponentMetadata({
|
||||
name: 'watchlaterRedirect',
|
||||
displayName: '稍后再看重定向',
|
||||
@ -62,6 +96,9 @@ export const component = defineComponentMetadata({
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
urlInclude: ['https://www.bilibili.com/watchlater/#/list'],
|
||||
urlInclude: [
|
||||
'https://www.bilibili.com/watchlater/#/list',
|
||||
'https://www.bilibili.com/watchlater/list#/list',
|
||||
],
|
||||
tags: [componentsTags.utils, componentsTags.video],
|
||||
})
|
||||
|
@ -263,7 +263,7 @@ export const addMenuItem = (
|
||||
if (isCascader) {
|
||||
;(async () => {
|
||||
const cascader = await select(() => dq(morePanel, '.bili-cascader'))
|
||||
const [observer] = childList(cascader, () => {
|
||||
childList(cascader, (_, observer) => {
|
||||
const cascaderOptions = dq(cascader, '.bili-cascader-options')
|
||||
if (cascaderOptions === null) {
|
||||
return
|
||||
|
@ -49,7 +49,7 @@ addData(ListAdaptorKey, (adaptors: FeedsCardsListAdaptor[]) => {
|
||||
name: 'space',
|
||||
match: ['https://space.bilibili.com/'],
|
||||
watchCardsList: async manager => {
|
||||
const container = (await select('.s-space')) as HTMLDivElement
|
||||
const container = (await select('.s-space, .space-main')) as HTMLDivElement
|
||||
if (!container) {
|
||||
return false
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
@import 'common';
|
||||
@mixin markdown {
|
||||
line-height: normal;
|
||||
> * {
|
||||
font-size: inherit;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
|
Loading…
Reference in New Issue
Block a user