From 527b45e299a524f5f63659c97f51f45db7b08e35 Mon Sep 17 00:00:00 2001 From: CNOCM <2436432930@qq.com> Date: Mon, 30 Jun 2025 11:31:17 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor(subscribeTimeShow):=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/subscribe-time-show/index.ts | 190 ++++++++---------- 1 file changed, 89 insertions(+), 101 deletions(-) diff --git a/registry/lib/components/utils/subscribe-time-show/index.ts b/registry/lib/components/utils/subscribe-time-show/index.ts index 2743ec93a..95151cf9b 100644 --- a/registry/lib/components/utils/subscribe-time-show/index.ts +++ b/registry/lib/components/utils/subscribe-time-show/index.ts @@ -1,6 +1,10 @@ import { defineComponentMetadata } from '@/components/define' import { useScopedConsole } from '@/core/utils/log' import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax' +import { dqa, dq } from '@/core/utils' +import { select } from '@/core/spin-query' +import { allMutations } from '@/core/observer' +import { getUserInfo } from '@/core/user-info' const displayName = '关注时间显示' const console = useScopedConsole(displayName) @@ -22,20 +26,16 @@ type FollowTimeInfo = { const midMap: Record = {} const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => { - const anchor = document.querySelector( - `${SELECTORS.relationCardAnchor}[href*="/${mid}"]`, - ) + const anchor = dq(`${SELECTORS.relationCardAnchor}[href*="/${mid}"]`) const card = anchor?.closest(SELECTORS.relationCardContainer) - if (!card) { - return - } - if (card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) { + if (!card || card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) { return } const div = document.createElement('div') div.className = SELECTORS.relationCardTimeClass div.textContent = `${label}:${dateStr}` + div.dataset.mid = mid.toString() const sign = card.querySelector(SELECTORS.relationCardSign) if (sign?.parentNode) { @@ -43,57 +43,37 @@ const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => } } -let fetchWrapped = false -let pendingUpdate = false - -const updateCards = () => { - if (pendingUpdate) { - return - } - pendingUpdate = true - requestAnimationFrame(() => { - pendingUpdate = false - const mids = Array.from( - document.querySelectorAll(SELECTORS.relationCardAnchor), - ) - .map(el => el.href.match(/\/(\d+)/)?.[1]) - .filter(Boolean) - .map(Number) - - mids.forEach(mid => { - const data = midMap[mid] - if (data) { - const dateStr = new Date(data.mtime * 1000).toLocaleString() - insertFollowTimeToCard(mid, dateStr, data.label) - } - }) - }) -} - -const waitForProfileContainer = () => - new Promise(resolve => { - const check = () => document.querySelector(SELECTORS.profileFollowContainer) - let container = check() - if (container) { - resolve(container) - } else { - const observer = new MutationObserver(() => { - container = check() - if (container) { - observer.disconnect() - resolve(container) +const updateCards = (() => { + let scheduled = false + return () => { + if (scheduled) { + return + } + scheduled = true + requestAnimationFrame(() => { + scheduled = false + dqa(SELECTORS.relationCardAnchor).forEach(el => { + const match = (el as HTMLAnchorElement).href.match(/\/(\d+)/) + if (!match) { + return + } + const mid = Number(match[1]) + if (Number.isNaN(mid)) { + return + } + const data = midMap[mid] + if (data) { + const dateStr = new Date(data.mtime * 1000).toLocaleString() + insertFollowTimeToCard(mid, dateStr, data.label) } }) - observer.observe(document.body, { childList: true, subtree: true }) - } - }) + }) + } +})() const insertSubscribeTime = (followTimeStr: string) => { - const container = document.querySelector(SELECTORS.profileFollowContainer) - if (!container) { - return - } - if (container.querySelector(`.${SELECTORS.profileTextClass}`)) { + const container = dq(SELECTORS.profileFollowContainer) + if (!container || container.querySelector(`.${SELECTORS.profileTextClass}`)) { return } @@ -107,25 +87,22 @@ const insertSubscribeTime = (followTimeStr: string) => { container.appendChild(infoEl) } -const entry = async () => { - try { - const { addImportantStyle } = await import('@/core/style') - const { default: style } = await import('./subscribe-time.scss') - addImportantStyle(style, 'subscribe-time-style') - } catch (e) { - console.error('样式加载失败:', e) - } +if (!(unsafeWindow as any).subscribeTimeHooked) { + ;(unsafeWindow as any).subscribeTimeHooked = true + const originalFetch = unsafeWindow.fetch + unsafeWindow.fetch = new Proxy(originalFetch, { + apply(target, thisArg, args) { + const url = typeof args[0] === 'string' ? args[0] : args[0].url + const urlObj = new URL(url, location.origin) - new MutationObserver(updateCards).observe(document.body, { childList: true, subtree: true }) - - if (!fetchWrapped) { - fetchWrapped = true - const originalFetch = unsafeWindow.fetch - unsafeWindow.fetch = new Proxy(originalFetch, { - apply(target, thisArg, args) { - const url = typeof args[0] === 'string' ? args[0] : args[0].url - if (url.includes('/x/relation/fans') || url.includes('/x/relation/followings')) { - return target.apply(thisArg, args).then(res => { + if ( + urlObj.hostname === 'api.bilibili.com' && + (urlObj.pathname.includes('/x/relation/fans') || + urlObj.pathname.includes('/x/relation/followings')) + ) { + return target + .apply(thisArg, args) + .then(res => { res .clone() .json() @@ -137,54 +114,63 @@ const entry = async () => { } list.forEach(user => { if (typeof user.mid === 'number' && typeof user.mtime === 'number') { - const label = url.includes('/x/relation/fans') - ? 'Ta 关注你的时间' - : '你关注 Ta 的时间' + const label = url.includes('/fans') ? 'Ta 关注你的时间' : '你关注 Ta 的时间' midMap[user.mid] = { mtime: user.mtime, label } - insertFollowTimeToCard( - user.mid, - new Date(user.mtime * 1000).toLocaleString(), - label, - ) + const dateStr = new Date(user.mtime * 1000).toLocaleString() + insertFollowTimeToCard(user.mid, dateStr, label) } }) }) - .catch(err => console.warn('JSON 解析失败:', err)) + .catch(err => { + console.warn('JSON 解析失败:', err) + }) return res }) - } - return target.apply(thisArg, args) - }, - }) + .catch(err => { + console.warn('fetch 请求失败:', err) + throw err + }) + } + + return target.apply(thisArg, args) + }, + }) +} + +const entry = async () => { + try { + const { addImportantStyle } = await import('@/core/style') + const { default: style } = await import('./subscribe-time.scss') + addImportantStyle(style, 'subscribe-time-style') + } catch (e) { + console.error('样式加载失败:', e) } + allMutations(updateCards) + + const userMid = (await getUserInfo()).mid const match = location.href.match(/space\.bilibili\.com\/(\d+)/) if (!match) { - console.warn('无法提取 mid') return } + const mid = Number(match[1]) + if (mid === userMid) { + console.log('当前为本人空间,跳过关注时间显示') + return + } const info = await bilibiliApi( getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/relation?mid=${mid}`), ) - if (!info?.relation) { - console.warn('未获取到 relation 信息') - return - } - if (!info.relation.mtime) { - console.log('当前未关注或关注时间无效') + + const mtime = info?.relation?.mtime + if (!mtime) { return } - try { - await waitForProfileContainer() - } catch (e) { - console.warn('等待关注容器超时,跳过插入关注时间') - return - } - - insertSubscribeTime(new Date(info.relation.mtime * 1000).toLocaleString()) + await select(SELECTORS.profileFollowContainer) + insertSubscribeTime(new Date(mtime * 1000).toLocaleString()) } export const component = defineComponentMetadata({ @@ -200,5 +186,7 @@ export const component = defineComponentMetadata({ /https:\/\/space\.bilibili\.com\/\d+/, ], entry, - description: { 'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。' }, + description: { + 'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。', + }, }) From b8c8485671fd2a8182913329af22b4a92590a536 Mon Sep 17 00:00:00 2001 From: CNOCM <80609142+CNOCM@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:42:34 +0800 Subject: [PATCH 2/6] Update index.ts --- registry/lib/components/utils/subscribe-time-show/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/registry/lib/components/utils/subscribe-time-show/index.ts b/registry/lib/components/utils/subscribe-time-show/index.ts index 95151cf9b..b90497ddf 100644 --- a/registry/lib/components/utils/subscribe-time-show/index.ts +++ b/registry/lib/components/utils/subscribe-time-show/index.ts @@ -1,7 +1,6 @@ import { defineComponentMetadata } from '@/components/define' import { useScopedConsole } from '@/core/utils/log' import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax' -import { dqa, dq } from '@/core/utils' import { select } from '@/core/spin-query' import { allMutations } from '@/core/observer' import { getUserInfo } from '@/core/user-info' From 3cba41aec68104ce14a104b63eafcfa8cdbd1843 Mon Sep 17 00:00:00 2001 From: the1812 Date: Tue, 22 Jul 2025 09:21:00 +0800 Subject: [PATCH 3/6] Update changelog --- CHANGELOG.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9669352c..2ad13c2ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,69 @@ # 更新日志 +## v2.10.3-preview + +包含 [v2.10.3](https://github.com/the1812/Bilibili-Evolved/releases/tag/v2.10.3) 的所有更新内容. + +- 新增 `深色模式` 组件, 用于跟随 b 站官方的内测深色模式. (#5272) +> 脚本自身的元素配色也会逐步适配官方的配色, 目前仅适配设置面板、自定义顶栏和动态首页中的元素 + +- `插件 - 下载视频 - WASM 混流输出` 修正下载限制为 2GB, 新增下载速度和剩余时间显示. (#5102, PR #5233 by [WakelessSloth56](https://github.com/WakelessSloth56)) +- `弹幕空降` 支持识别中文数字, 修复对特殊弹幕未触发的问题. (PR #5265 by [fixfeat](https://github.com/fixfeat)) +- 新增 `视频预览放大` 组件. (PR #5281 by [wsgh0202](https://github.com/wsgh0202)) +> 放大鼠标悬停于视频卡片时播放的 5 分钟预览 +> +> - 点击放大镜图标放大预览 +> - 点击缩小图标或者预览框外空白处关闭预览 + +- 修复 `隐藏首页轮播图` 失效, 并增加了一些局部元素控制功能. (PR #5287 [wsgh0202](https://github.com/wsgh0202)) + + +## v2.10.3 +`2025-07-22` + +
+正式版用户将获得 v2.10.1-preview ~ v2.10.2-preview 的所有改动, 点击展开查看 + +- 新增 `稍后再看页面-重定向` 组件. (PR #5205 by [undefined](https://github.com/magicFeirl)) +> 重定向**稍后再看页面**到普通视频页面,和`稍后再看重定向`组件的区别在于,该组件是在进入稍后再看的视频页面后进行重定向,而非直接替换链接到普通视频的链接,用于补充`稍后再看重定向`组件的功能。 + +- `隐藏热搜` 支持隐藏直播间搜索框的热搜. (PR #5207 by [undefined](https://github.com/magicFeirl)) +- 修复 `视频链接增强` 对 niconico 链接的处理. (PR #5215 by [Alan Ye](https://github.com/at-wr)) +- 新增 `动态分组过滤` 组件. (PR #5217 by [Rinne](https://github.com/OharaRinneY)) +> 按照关注分组筛选动态 + +- `直播信息扩充` 支持配置置顶和隐藏的关注列表. (#5183) +- 新增组件 `一键点亮直播间粉丝勋章`. (PR #5171 by [undefined](https://github.com/magicFeirl)) +> 在直播间页面的功能面板添加一键点亮粉丝勋章功能,仅适用于有粉丝勋章且正在直播的直播间。原理:发送一个 300 次点赞的请求点亮粉丝勋章。 + +- 新增组件 `下载表情`. (PR #5176 by [Pencil](https://github.com/pencilqaq)) +> 支持下载 up 主专属表情包,处于任意直播间页面时,下载按钮会在 `功能` 面板显示,以压缩包形式保存。 + +- 新增组件 `视频链接增强`. (PR #5197 by [Alan Ye](https://github.com/at-wr)) +> 这个组件会将视频简介中的普通网址转换为可点击的链接,并将被 Bilibili 抛弃已失效的 `acg.tv` 跳转链接修复为 `nicovideo.jp` 链接。 +> +> 例如: `https://acg.tv/sm37507315` → `https://www.nicovideo.jp/watch/sm37507315` +> +> 本组件不会保证目标链接的安全性,因此在点击前请自行验证其是否可信 + +- `自定义顶栏` 新增 `使用主题色 Logo` 选项, 关闭时可以使用黑白纯色的 Logo. (#4996) +- `自定义顶栏` 更新 `游戏中心`, `漫画`, `赛事` 的弹窗, 废弃 `直播` 的弹窗. (#5055) + +
+ +(以下其实都是 6 月就更新了, 只要你的 `自动更新器` 正常使用, 应该早已收到更新了, 这些改动无需更新本体) + +✨新增 +- `显示视频投稿时间` 支持在合集类页面显示. (#5247, PR #5266 by [呼乎户](https://github.com/wisokey)) +- `动态过滤` 支持过滤新出现的热搜面板. (#5273, PR #5276 by [Whalko](https://github.com/RtYkk)) + +🐛修复 +- 修复 `夜间模式` 在首页 svg 图标的颜色. (PR #5240 by [hyrious](https://github.com/hyrious)) +- 修复 `自动移出稍后再看` 重复调用接口的 bug. (PR #5241 by [sunfkny](https://github.com/sunfkny)) +- 修复 `关注时间显示` 失效. (#5096, #5212, PR 5282 by [CNOCM](https://github.com/CNOCM)) + + ## v2.10.2-preview `2025-05-30` From 993b726d97c11fa2a97491d44b6fdbfc47e14441 Mon Sep 17 00:00:00 2001 From: the1812 Date: Tue, 22 Jul 2025 09:34:40 +0800 Subject: [PATCH 4/6] Update version number --- src/client/common.meta.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/common.meta.json b/src/client/common.meta.json index 8fdbfc24e..9db4499e9 100644 --- a/src/client/common.meta.json +++ b/src/client/common.meta.json @@ -1,5 +1,5 @@ { - "version": "2.10.2", + "version": "2.10.3", "author": "Grant Howard, Coulomb-G", "copyright": "[year], Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)", "license": "MIT", From 076dc47b5548234a286e993b90b2b109335d168c Mon Sep 17 00:00:00 2001 From: the1812 Date: Tue, 22 Jul 2025 23:08:59 +0800 Subject: [PATCH 5/6] Update donate history --- doc/donate.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/donate.md b/doc/donate.md index d04af99e4..0ff109007 100644 --- a/doc/donate.md +++ b/doc/donate.md @@ -30,6 +30,9 @@ https://afdian.com/a/the1812?tab=sponsor | 时间 | 用户名 | 单号后4位 | 金额 | | ------------------- | --------------------- | --------- | ------- | +| 2025.07.12 16:44:24 | 爱音allin | 3957 | ¥5.00 | +| 2025.06.29 10:53:44 | f*x | 9352 | ¥10.00 | +| 2025.06.10 01:22:23 | *匆 | 5332 | ¥5.00 | | 2025.05.21 19:55:02 | mobmaster69 | 7644 | ¥5.00 | | 2025.05.20 02:38:45 | Duane | 3937 | ¥5.00 | | 2025.05.15 22:12:22 | 匿名 | 3901 | ¥23.33 | From c85fc06e5134e3034220b3080d0bba5ea86771d2 Mon Sep 17 00:00:00 2001 From: the1812 Date: Tue, 22 Jul 2025 23:10:14 +0800 Subject: [PATCH 6/6] Update docs --- doc/features/features.json | 18 +++++++++++++++++- doc/features/features.md | 26 ++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/doc/features/features.json b/doc/features/features.json index e5d85ee94..f26ced8f4 100644 --- a/doc/features/features.json +++ b/doc/features/features.json @@ -71,6 +71,14 @@ "fullRelativePath": "../../registry/dist/components/feeds/full-title.js", "fullAbsolutePath": "registry/dist/components/feeds/full-title.js" }, + { + "type": "component", + "name": "feedsGroupFilter", + "displayName": "动态分组过滤", + "description": "by [@Rinne](https://github.com/OharaRinneY)\n\n按照关注分组筛选动态\r\n", + "fullRelativePath": "../../registry/dist/components/feeds/group-filter.js", + "fullAbsolutePath": "registry/dist/components/feeds/group-filter.js" + }, { "type": "component", "name": "hideFeedsCommentPreview", @@ -667,7 +675,7 @@ "type": "component", "name": "subscribeTimeShow", "displayName": "关注时间显示", - "description": "by [@Light_Quanta](https://github.com/LightQuanta)\n\n在粉丝/关注列表显示关注的具体时间", + "description": "by [@CNOCM](https://github.com/CNOCM)\n\n在粉丝/关注列表及用户主页显示关注的具体时间。", "fullRelativePath": "../../registry/dist/components/utils/subscribe-time-show.js", "fullAbsolutePath": "registry/dist/components/utils/subscribe-time-show.js" }, @@ -695,6 +703,14 @@ "fullRelativePath": "../../registry/dist/components/utils/view-cover.js", "fullAbsolutePath": "registry/dist/components/utils/view-cover.js" }, + { + "type": "component", + "name": "watchlaterPageRedirect", + "displayName": "稍后再看页面-重定向", + "description": "by [@magicFeirl](https://github.com/magicFeirl)\n\n重定向**稍后再看页面**到普通视频页面,和`稍后再看重定向`组件的区别在于,该组件是在进入稍后再看的视频页面后进行重定向,而非直接替换链接到普通视频的链接,用于补充`稍后再看重定向`组件的功能。\r\n", + "fullRelativePath": "../../registry/dist/components/utils/watchlater-page-redirect.js", + "fullAbsolutePath": "registry/dist/components/utils/watchlater-page-redirect.js" + }, { "type": "component", "name": "watchlaterRedirect", diff --git a/doc/features/features.md b/doc/features/features.md index 92dde7f34..b1b3a6759 100644 --- a/doc/features/features.md +++ b/doc/features/features.md @@ -85,6 +85,17 @@ 在顶栏的视频动态中, 无论标题多长总是完全展开. +### [动态分组过滤](../../registry/dist/components/feeds/group-filter.js) +`feedsGroupFilter` + +**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/components/feeds/group-filter.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/feeds/group-filter.js) + +**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/feeds/group-filter.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/feeds/group-filter.js) + +by [@Rinne](https://github.com/OharaRinneY) + +按照关注分组筛选动态 + ### [隐藏动态评论预览](../../registry/dist/components/feeds/hide-comment-preview.js) `hideFeedsCommentPreview` @@ -935,9 +946,9 @@ by [@Light_Quanta](https://github.com/LightQuanta) **GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/utils/subscribe-time-show.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/utils/subscribe-time-show.js) -by [@Light_Quanta](https://github.com/LightQuanta) +by [@CNOCM](https://github.com/CNOCM) -在粉丝/关注列表显示关注的具体时间 +在粉丝/关注列表及用户主页显示关注的具体时间。 ### [网址参数清理](../../registry/dist/components/utils/url-params-clean.js) `urlParamsClean` @@ -966,6 +977,17 @@ by [@Light_Quanta](https://github.com/LightQuanta) 在视频页面中, 可从功能面板中查看封面. +### [稍后再看页面-重定向](../../registry/dist/components/utils/watchlater-page-redirect.js) +`watchlaterPageRedirect` + +**jsDelivr:** [`Stable`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/registry/dist/components/utils/watchlater-page-redirect.js) / [`Preview`](https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/registry/dist/components/utils/watchlater-page-redirect.js) + +**GitHub:** [`Stable`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/registry/dist/components/utils/watchlater-page-redirect.js) / [`Preview`](https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/registry/dist/components/utils/watchlater-page-redirect.js) + +by [@magicFeirl](https://github.com/magicFeirl) + +重定向**稍后再看页面**到普通视频页面,和`稍后再看重定向`组件的区别在于,该组件是在进入稍后再看的视频页面后进行重定向,而非直接替换链接到普通视频的链接,用于补充`稍后再看重定向`组件的功能。 + ### [稍后再看重定向](../../registry/dist/components/utils/watchlater-redirect.js) `watchlaterRedirect`