mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
123 lines
4.4 KiB
TypeScript
123 lines
4.4 KiB
TypeScript
import { ComponentMetadata } from '@/components/types'
|
|
import { CommentArea } from '@/components/utils/comment-apis'
|
|
import { getJson } from '@/core/ajax'
|
|
import { fullyLoaded } from '@/core/life-cycle'
|
|
import { childList } from '@/core/observer'
|
|
import { select } from '@/core/spin-query'
|
|
import { videoUrls } from '@/core/utils/urls'
|
|
|
|
enum CommentSortOrder {
|
|
Default = 1,
|
|
ByTime,
|
|
ByLikes,
|
|
}
|
|
const getComments = (oid: number | string, mode: CommentSortOrder, page = 1) => {
|
|
if (mode === CommentSortOrder.ByTime) {
|
|
return getJson(`https://api.bilibili.com/x/v2/reply/main?oid=${oid}&type=1&mode=${mode}`)
|
|
}
|
|
return getJson(`https://api.bilibili.com/x/v2/reply/main?oid=${oid}&type=1&mode=${mode}&next=${page}`)
|
|
}
|
|
const getOid = async (commentContainer: HTMLElement) => {
|
|
if (document.URL.match(/\/\/www\.bilibili\.com\/(video|bangumi)/)) {
|
|
return select(() => unsafeWindow.aid)
|
|
}
|
|
console.error('commentContainer = ', commentContainer)
|
|
throw new Error('No oid extract method for current context.')
|
|
}
|
|
const restore = async (commentContainer: HTMLElement) => {
|
|
const oid = await getOid(commentContainer)
|
|
if (!oid) {
|
|
return
|
|
}
|
|
const mode = dq(commentContainer, '.hot-sort.on') !== null ? CommentSortOrder.ByLikes : CommentSortOrder.ByTime
|
|
let page = 1
|
|
const pagesElement = dq(commentContainer, '.paging-box .current')
|
|
if (pagesElement !== null) {
|
|
page = parseInt(pagesElement.textContent)
|
|
}
|
|
const json = await getComments(oid, mode, page)
|
|
if (json.code !== 0) {
|
|
console.error('Comment API failed: ', json.message)
|
|
return
|
|
}
|
|
const getFloorInfo = (item: any) => {
|
|
const result = [{
|
|
id: item.rpid_str as string,
|
|
floor: item.floor as number,
|
|
}]
|
|
if (item.replies !== null) {
|
|
result.push(...item.replies.map((it: any) => ({
|
|
id: it.rpid_str as string,
|
|
floor: it.floor as number,
|
|
})))
|
|
}
|
|
return result
|
|
}
|
|
const replies = lodash.flatMap(lodash.get(json, 'data.replies', []), getFloorInfo)
|
|
const top = lodash.get(json, 'data.top.upper')
|
|
if (top) {
|
|
replies.push(...getFloorInfo(top))
|
|
}
|
|
// console.log(replies)
|
|
const commentItems = dqa(commentContainer, '.reply-wrap[data-id]')
|
|
const commentInfos = commentItems.map(item => dq(item, '.reply-wrap > .con > .info, .reply-wrap > .info') as HTMLElement)
|
|
commentItems.forEach((item, index) => {
|
|
const id = item.getAttribute('data-id') as string
|
|
const reply = replies.find(r => r.id === id)
|
|
if (reply !== undefined) {
|
|
const info = commentInfos[index]
|
|
if (info.getAttribute('data-restore-floor') === null) {
|
|
info.insertAdjacentHTML('afterbegin', /* html */`<span class="floor">#${reply.floor}</span>`)
|
|
info.setAttribute('data-restore-floor', reply.floor.toString())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
const prepareRestore = (commentContainer: HTMLElement) => {
|
|
const commentLoading = 'comment-loading'
|
|
const isCommentLoading = Array.prototype.some.call(
|
|
commentContainer.children,
|
|
(it: HTMLElement) => it.classList.contains(commentLoading),
|
|
)
|
|
if (isCommentLoading) {
|
|
const [observer] = childList(commentContainer, records => {
|
|
const isCommentLoaded = records.some(r => Array.prototype.some.call(
|
|
r.removedNodes,
|
|
(node: Node) => node.nodeType === Node.ELEMENT_NODE
|
|
&& (node as HTMLElement).classList.contains(commentLoading),
|
|
))
|
|
if (isCommentLoaded) {
|
|
observer.disconnect()
|
|
prepareRestore(commentContainer)
|
|
}
|
|
})
|
|
} else if (commentContainer.getAttribute('data-restore-floor') === null) {
|
|
commentContainer.setAttribute('data-restore-floor', 'true')
|
|
const list = dq(commentContainer, '.comment-list') as HTMLElement
|
|
childList(list, lodash.debounce(records => {
|
|
console.log(records)
|
|
restore(commentContainer)
|
|
}, 100))
|
|
}
|
|
}
|
|
export const component: ComponentMetadata = {
|
|
name: 'restoreFloors',
|
|
displayName: '评论楼层显示',
|
|
urlInclude: [
|
|
...videoUrls,
|
|
// '//www.bilibili.com/bangumi',
|
|
// '//t.bilibili.com/',
|
|
],
|
|
description: {
|
|
'zh-CN': '恢复按热度排序时评论楼层, 按时间排序只能恢复第一页, 仅对普通视频页有效.',
|
|
},
|
|
tags: [componentsTags.utils],
|
|
entry: () => {
|
|
fullyLoaded(async () => {
|
|
const { forEachCommentArea } = await import('@/components/utils/comment-apis')
|
|
const callback = (area: CommentArea) => prepareRestore(area.element)
|
|
forEachCommentArea(callback)
|
|
})
|
|
},
|
|
}
|