Merge branch 'preview-fixes' into preview-features

This commit is contained in:
the1812 2025-07-22 23:10:49 +08:00
commit fba8849f46
5 changed files with 95 additions and 105 deletions

View File

@ -30,6 +30,9 @@ https://afdian.com/a/the1812?tab=sponsor
| 时间 | 用户名 | 单号后4位 | 金额 | | 时间 | 用户名 | 单号后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.21 19:55:02 | mobmaster69 | 7644 | ¥5.00 |
| 2025.05.20 02:38:45 | Duane | 3937 | ¥5.00 | | 2025.05.20 02:38:45 | Duane | 3937 | ¥5.00 |
| 2025.05.15 22:12:22 | 匿名 | 3901 | ¥23.33 | | 2025.05.15 22:12:22 | 匿名 | 3901 | ¥23.33 |

View File

@ -675,7 +675,7 @@
"type": "component", "type": "component",
"name": "subscribeTimeShow", "name": "subscribeTimeShow",
"displayName": "关注时间显示", "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", "fullRelativePath": "../../registry/dist/components/utils/subscribe-time-show.js",
"fullAbsolutePath": "registry/dist/components/utils/subscribe-time-show.js" "fullAbsolutePath": "registry/dist/components/utils/subscribe-time-show.js"
}, },

View File

@ -946,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) **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) ### [网址参数清理](../../registry/dist/components/utils/url-params-clean.js)
`urlParamsClean` `urlParamsClean`

View File

@ -1,6 +1,9 @@
import { defineComponentMetadata } from '@/components/define' import { defineComponentMetadata } from '@/components/define'
import { useScopedConsole } from '@/core/utils/log' import { useScopedConsole } from '@/core/utils/log'
import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax' import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax'
import { select } from '@/core/spin-query'
import { allMutations } from '@/core/observer'
import { getUserInfo } from '@/core/user-info'
const displayName = '关注时间显示' const displayName = '关注时间显示'
const console = useScopedConsole(displayName) const console = useScopedConsole(displayName)
@ -22,20 +25,16 @@ type FollowTimeInfo = {
const midMap: Record<number, FollowTimeInfo> = {} const midMap: Record<number, FollowTimeInfo> = {}
const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => { const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => {
const anchor = document.querySelector<HTMLAnchorElement>( const anchor = dq(`${SELECTORS.relationCardAnchor}[href*="/${mid}"]`)
`${SELECTORS.relationCardAnchor}[href*="/${mid}"]`,
)
const card = anchor?.closest(SELECTORS.relationCardContainer) const card = anchor?.closest(SELECTORS.relationCardContainer)
if (!card) { if (!card || card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) {
return
}
if (card.querySelector(`.${SELECTORS.relationCardTimeClass}`)) {
return return
} }
const div = document.createElement('div') const div = document.createElement('div')
div.className = SELECTORS.relationCardTimeClass div.className = SELECTORS.relationCardTimeClass
div.textContent = `${label}${dateStr}` div.textContent = `${label}${dateStr}`
div.dataset.mid = mid.toString()
const sign = card.querySelector(SELECTORS.relationCardSign) const sign = card.querySelector(SELECTORS.relationCardSign)
if (sign?.parentNode) { if (sign?.parentNode) {
@ -43,24 +42,24 @@ const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) =>
} }
} }
let fetchWrapped = false const updateCards = (() => {
let pendingUpdate = false let scheduled = false
return () => {
const updateCards = () => { if (scheduled) {
if (pendingUpdate) {
return return
} }
pendingUpdate = true scheduled = true
requestAnimationFrame(() => { requestAnimationFrame(() => {
pendingUpdate = false scheduled = false
const mids = Array.from( dqa(SELECTORS.relationCardAnchor).forEach(el => {
document.querySelectorAll<HTMLAnchorElement>(SELECTORS.relationCardAnchor), const match = (el as HTMLAnchorElement).href.match(/\/(\d+)/)
) if (!match) {
.map(el => el.href.match(/\/(\d+)/)?.[1]) return
.filter(Boolean) }
.map(Number) const mid = Number(match[1])
if (Number.isNaN(mid)) {
mids.forEach(mid => { return
}
const data = midMap[mid] const data = midMap[mid]
if (data) { if (data) {
const dateStr = new Date(data.mtime * 1000).toLocaleString() const dateStr = new Date(data.mtime * 1000).toLocaleString()
@ -69,31 +68,11 @@ const updateCards = () => {
}) })
}) })
} }
})()
const waitForProfileContainer = () =>
new Promise<Element>(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)
}
})
observer.observe(document.body, { childList: true, subtree: true })
}
})
const insertSubscribeTime = (followTimeStr: string) => { const insertSubscribeTime = (followTimeStr: string) => {
const container = document.querySelector(SELECTORS.profileFollowContainer) const container = dq(SELECTORS.profileFollowContainer)
if (!container) { if (!container || container.querySelector(`.${SELECTORS.profileTextClass}`)) {
return
}
if (container.querySelector(`.${SELECTORS.profileTextClass}`)) {
return return
} }
@ -107,25 +86,22 @@ const insertSubscribeTime = (followTimeStr: string) => {
container.appendChild(infoEl) container.appendChild(infoEl)
} }
const entry = async () => { if (!(unsafeWindow as any).subscribeTimeHooked) {
try { ;(unsafeWindow as any).subscribeTimeHooked = true
const { addImportantStyle } = await import('@/core/style')
const { default: style } = await import('./subscribe-time.scss')
addImportantStyle(style, 'subscribe-time-style')
} catch (e) {
console.error('样式加载失败:', e)
}
new MutationObserver(updateCards).observe(document.body, { childList: true, subtree: true })
if (!fetchWrapped) {
fetchWrapped = true
const originalFetch = unsafeWindow.fetch const originalFetch = unsafeWindow.fetch
unsafeWindow.fetch = new Proxy(originalFetch, { unsafeWindow.fetch = new Proxy(originalFetch, {
apply(target, thisArg, args) { apply(target, thisArg, args) {
const url = typeof args[0] === 'string' ? args[0] : args[0].url const url = typeof args[0] === 'string' ? args[0] : args[0].url
if (url.includes('/x/relation/fans') || url.includes('/x/relation/followings')) { const urlObj = new URL(url, location.origin)
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 res
.clone() .clone()
.json() .json()
@ -137,54 +113,63 @@ const entry = async () => {
} }
list.forEach(user => { list.forEach(user => {
if (typeof user.mid === 'number' && typeof user.mtime === 'number') { if (typeof user.mid === 'number' && typeof user.mtime === 'number') {
const label = url.includes('/x/relation/fans') const label = url.includes('/fans') ? 'Ta 关注你的时间' : '你关注 Ta 的时间'
? 'Ta 关注你的时间'
: '你关注 Ta 的时间'
midMap[user.mid] = { mtime: user.mtime, label } midMap[user.mid] = { mtime: user.mtime, label }
insertFollowTimeToCard( const dateStr = new Date(user.mtime * 1000).toLocaleString()
user.mid, insertFollowTimeToCard(user.mid, dateStr, label)
new Date(user.mtime * 1000).toLocaleString(),
label,
)
} }
}) })
}) })
.catch(err => console.warn('JSON 解析失败:', err)) .catch(err => {
console.warn('JSON 解析失败:', err)
})
return res return res
}) })
.catch(err => {
console.warn('fetch 请求失败:', err)
throw err
})
} }
return target.apply(thisArg, args) 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+)/) const match = location.href.match(/space\.bilibili\.com\/(\d+)/)
if (!match) { if (!match) {
console.warn('无法提取 mid')
return return
} }
const mid = Number(match[1]) const mid = Number(match[1])
if (mid === userMid) {
console.log('当前为本人空间,跳过关注时间显示')
return
}
const info = await bilibiliApi( const info = await bilibiliApi(
getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/relation?mid=${mid}`), getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/relation?mid=${mid}`),
) )
if (!info?.relation) {
console.warn('未获取到 relation 信息') const mtime = info?.relation?.mtime
return if (!mtime) {
}
if (!info.relation.mtime) {
console.log('当前未关注或关注时间无效')
return return
} }
try { await select(SELECTORS.profileFollowContainer)
await waitForProfileContainer() insertSubscribeTime(new Date(mtime * 1000).toLocaleString())
} catch (e) {
console.warn('等待关注容器超时,跳过插入关注时间')
return
}
insertSubscribeTime(new Date(info.relation.mtime * 1000).toLocaleString())
} }
export const component = defineComponentMetadata({ export const component = defineComponentMetadata({
@ -200,5 +185,7 @@ export const component = defineComponentMetadata({
/https:\/\/space\.bilibili\.com\/\d+/, /https:\/\/space\.bilibili\.com\/\d+/,
], ],
entry, entry,
description: { 'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。' }, description: {
'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。',
},
}) })

View File

@ -1,5 +1,5 @@
{ {
"version": "2.10.2", "version": "2.10.3",
"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",