mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge branch 'preview-fixes' into preview-features
This commit is contained in:
commit
fba8849f46
@ -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 |
|
||||
|
||||
@ -675,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"
|
||||
},
|
||||
|
||||
@ -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)
|
||||
|
||||
by [@Light_Quanta](https://github.com/LightQuanta)
|
||||
by [@CNOCM](https://github.com/CNOCM)
|
||||
|
||||
在粉丝/关注列表显示关注的具体时间
|
||||
在粉丝/关注列表及用户主页显示关注的具体时间。
|
||||
|
||||
### [网址参数清理](../../registry/dist/components/utils/url-params-clean.js)
|
||||
`urlParamsClean`
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { defineComponentMetadata } from '@/components/define'
|
||||
import { useScopedConsole } from '@/core/utils/log'
|
||||
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 console = useScopedConsole(displayName)
|
||||
@ -22,20 +25,16 @@ type FollowTimeInfo = {
|
||||
const midMap: Record<number, FollowTimeInfo> = {}
|
||||
|
||||
const insertFollowTimeToCard = (mid: number, dateStr: string, label: string) => {
|
||||
const anchor = document.querySelector<HTMLAnchorElement>(
|
||||
`${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 +42,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<HTMLAnchorElement>(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<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)
|
||||
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 +86,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 +113,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 +185,7 @@ export const component = defineComponentMetadata({
|
||||
/https:\/\/space\.bilibili\.com\/\d+/,
|
||||
],
|
||||
entry,
|
||||
description: { 'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。' },
|
||||
description: {
|
||||
'zh-CN': '在粉丝/关注列表及用户主页显示关注的具体时间。',
|
||||
},
|
||||
})
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user