Bilibili-Evolved/registry/lib/components/utils/ip-show/index.ts
2024-09-04 23:22:44 +08:00

336 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable no-underscore-dangle */
/* eslint-disable yoda */
import { defineComponentMetadata } from '@/components/define'
import { CommentItem, CommentReplyItem } from '@/components/utils/comment-apis'
import { select } from '@/core/spin-query'
// 新版评论区IP属地获取
const getIpLocation = (item: CommentReplyItem) => {
const reply = item.frameworkSpecificProps
return reply?.reply_control?.location ?? undefined
}
let version = 2
let bbComment: any
const marginLeft = 15
// 带IP属地显示的评论创建
const createListCon = function listCon(item, i, pos) {
const blCon = this._parentBlacklistDom(item, i, pos)
const con = [
`<div class="con ${pos === i ? 'no-border' : ''}">`,
`<div class="user">${this._createNickNameDom(item)}`,
this._createLevelLink(item),
this._identity(item.mid, item.assist, item.member.fans_detail),
`${this._createNameplate(item.member.nameplate) + this._createUserSailing(item)}</div>`,
this._createMsgContent(item),
this._createPerfectReply(item),
'<div class="info">',
this._createPlatformDom(item.content.plat),
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
item.lottery_id
? ''
: `<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
item.lottery_id ? '' : `<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
item.lottery_id ? '' : this._createReplyBtn(item.rcount),
item.lottery_id && item.mid !== bbComment.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(item)
? `<li class="set-top">${item.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(item.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(item.mid) && !item.isTop
? `<li class="del" data-mid="${item.mid}">删除</li>`
: ''
}</ul></div></div>`,
this._createLotteryContent(item.content),
this._createVoteContent(item.content),
this._createTags(item),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(
item.replies,
item.rcount,
false,
item.rpid,
item.folder && item.folder.has_folded,
item.reply_control,
),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return item.state === bbComment.blacklistCode ? blCon : con
}
// 带IP属地显示的回复创建
const createSubReplyItem = function subReply(item, i) {
const dom = [
`<div class="reply-item reply-wrap" data-id="${item.rpid}" data-index="${i}">`,
this._createSubReplyUserFace(item),
'<div class="reply-con">',
'<div class="user">',
this._createNickNameDom(item),
this._createLevelLink(item),
this._identity(item.mid),
this._createSubMsgContent(item),
'</div>',
'</div>',
'<div class="info">',
'<span class="time-location">',
'<span class="reply-time">'.concat(this._formateTime(item.ctime), '</span>'),
item?.reply_control?.location
? `<span class="reply-location" style="margin-left:${marginLeft}px;">${
item?.reply_control?.location || ''
}</span>`
: '',
'</span>',
`<span class="like ${item.action === 1 ? 'liked' : ''}"><i></i><span>${
item.like ? item.like : ''
}</span></span>`,
`<span class="hate ${item.action === 2 ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(item.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(item.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(item.mid) ? `<li class="del" data-mid="${item.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return dom
}
// 小黑屋专用带IP属地显示的评论创建
const blackroomCreateListCon = function listCon(e, n, t) {
const r = this._parentBlacklistDom(e, n, t)
const i = [
`<div class="con ${t === n ? 'no-border' : ''}">`,
`<div class="user">${this._identity(e.mid, e.assist, e.member.fans_detail)}`,
`<a data-usercard-mid="${e.mid}" href="//space.bilibili.com/${
e.mid
}" target="_blank" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(
e.member.uname,
)}</a><a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${
e.member.level_info.current_level
}"></i></a>${this._createNameplate(e.member.nameplate)}${this._createUserSailing(
(e.member && e.member.user_sailing) || {},
)}</div>`,
this._createMsgContent(e),
'<div class="info">',
e.floor ? `<span class="floor">#${e.floor}</span>` : '',
this._createPlatformDom(e.content.plat),
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${e?.reply_control?.location || ''}</span>`
: '',
e.lottery_id
? ''
: `<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
e.lottery_id ? '' : `<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
e.lottery_id ? '' : this._createReplyBtn(e.rcount),
e.lottery_id && e.mid !== this.userStatus.mid
? ''
: `<div class="operation more-operation"><div class="spot"></div><div class="opera-list"><ul>${
this._canSetTop(e)
? `<li class="set-top">${e.isUpTop ? '取消置顶' : '设为置顶'}</li>`
: ''
}${this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''}${
this._canReport(e.mid) ? '<li class="report">举报</li>' : ''
}${
this._canDel(e.mid) && !e.isTop ? `<li class="del" data-mid="${e.mid}">删除</li>` : ''
}</ul></div></div>`,
this._createLotteryContent(e.content),
this._createVoteContent(e.content),
this._createTags(e),
'</div>',
'<div class="reply-box">',
this._createSubReplyList(e.replies, e.rcount, !1, e.rpid, e.folder && e.folder.has_folded),
'</div>',
'<div class="paging-box">',
'</div>',
'</div>',
].join('')
return e.state === this.blacklistCode ? r : i
}
// 小黑屋专用带IP属地显示的回复创建
const blackroomCreateSubReplyItem = function subReply(e, n) {
const t = [
`<div class="reply-item reply-wrap" data-id="${e.rpid}" data-index="${n}">`,
`<a href="//space.bilibili.com/${e.mid}" data-usercard-mid="${e.mid}" target="_blank" class="reply-face">`,
`<img src="${this._trimHttpFix(
this._webpFix(e.member.avatar, {
w: 52,
h: 52,
}),
)}" alt="">`,
'</a>',
'<div class="reply-con">',
'<div class="user">',
`<a href="//space.bilibili.com/${e.mid}" target="_blank" data-usercard-mid="${
e.mid
}" class="name ${this._createVipClass(
e.member.vip.vipType,
e.member.vip.vipStatus,
e.member.vip.themeType,
)}">${this._unhtmlFix(e.member.uname)}</a>`,
`<a class="level-link" href="//www.bilibili.com/blackboard/help.html#%E4%BC%9A%E5%91%98%E7%AD%89%E7%BA%A7%E7%9B%B8%E5%85%B3" target="_blank"><i class="level l${e.member.level_info.current_level}"></i></a>`,
this._createSubMsgContent(e),
'</div>',
'</div>',
'<div class="info">',
`<span class="time">${this._formateTime(e.ctime)}</span>`,
e?.reply_control?.location
? `<span style="margin-left:${marginLeft - 15}px;">${e?.reply_control?.location || ''}</span>`
: '',
`<span class="like ${1 === e.action ? 'liked' : ''}"><i></i><span>${
e.like || ''
}</span></span>`,
`<span class="hate ${2 === e.action ? 'hated' : ''}"><i></i></span>`,
'<span class="reply btn-hover">回复</span>',
`<div class="operation btn-hover btn-hide-re"><div class="spot"></div><div class="opera-list"><ul>${
this._canBlackList(e.mid) ? '<li class="blacklist">加入黑名单</li>' : ''
}${this._canReport(e.mid) ? '<li class="report">举报</li>' : ''}${
this._canDel(e.mid) ? `<li class="del" data-mid="${e.mid}">删除</li>` : ''
}</ul></div></div>`,
'</div>',
'</div>',
].join('')
return t
}
const observer = new MutationObserver(mutations => {
mutations.forEach(() => {
// 监听旧版评论区全局变量
if (typeof unsafeWindow.bbComment !== 'undefined') {
// 评论创建函数替换
bbComment = unsafeWindow.bbComment
if (unsafeWindow.location.href.split('/')[3] === 'blackroom') {
// 小黑屋特判
// 三个谜之函数的polyfill不知为何无法直接调用会报错
bbComment.prototype._unhtmlFix = function unhtml(e, n) {
return e
? // eslint-disable-next-line @typescript-eslint/no-shadow
e.replace(n || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp|#\\d+);)?/g, function (e, n) {
return n ? e : { '<': '', '&': '', '"': '', '>': '', "'": '' }[e]
})
: ''
}
bbComment.prototype._trimHttpFix = function trimHttp(e) {
return e ? e.replace(/^http:/, '') : ''
}
bbComment.prototype._webpFix = function webp(e, n) {
if (!e) {
return e
}
const t = e.match(/(.*\\.(jpg|jpeg|gif|png|bmp))(\\?.*)?/)
let r = -1 !== e.indexOf('/bfs/')
if (!t || 'gif' === t[2] || 'bmp' === t[2] || !r) {
return e
}
r = n.w
e = n.h
e = r && e ? `@${r}w_${e}h` : '@'
n = t[3] || ''
return this.isWebp ? `${t[1] + e}.webp${n}` : `${t[1] + e}.${t[2]}${n}`
}
bbComment.prototype._createListCon = blackroomCreateListCon
bbComment.prototype._createSubReplyItem = blackroomCreateSubReplyItem
} else {
// 其他情况旧版评论区替换
bbComment.prototype._createListCon = createListCon
bbComment.prototype._createSubReplyItem = createSubReplyItem
}
version = 1
observer.disconnect()
}
})
})
observer.observe(document.head, { childList: true })
const processItems = (items: CommentReplyItem[]) => {
items.forEach(async item => {
const location = getIpLocation(item)
if (location === undefined) {
return
}
const replyTime = await (() => {
if (item.shadowDomEntry) {
return select(() => item.shadowDomEntry.querySelector('#pubdate'), {
queryInterval: 100,
maxRetry: 30,
})
}
return (
item.element.querySelector('.reply-info>.reply-time') ??
item.element.querySelector('.sub-reply-info>.sub-reply-time')
)
})()
if (replyTime === null) {
return
}
const existingLocation = replyTime.querySelector('.ip-location') as HTMLElement | null
if (existingLocation !== null) {
existingLocation.innerText = location
return
}
const replyLocation = document.createElement('span')
replyLocation.className = 'ip-location'
replyLocation.style.marginLeft = `${marginLeft}px`
replyLocation.innerText = location
replyTime.appendChild(replyLocation)
})
}
const entry = async () => {
const { forEachCommentItem } = await import('@/components/utils/comment-apis')
const addIpLocation = (comment: CommentItem) => {
if (version === 2) {
processItems([comment, ...comment.replies])
comment.addEventListener('repliesUpdate', replies => processItems(replies.detail))
}
}
forEachCommentItem({
added: addIpLocation,
})
}
export const component = defineComponentMetadata({
name: 'ipShow',
author: {
name: 'Light_Quanta',
link: 'https://github.com/LightQuanta',
},
displayName: '评论区IP属地显示',
tags: [componentsTags.utils],
entry,
description: {
'zh-CN': '在评论区显示评论的IP属地信息',
},
})