Greasy Fork is available in English.
修复评论区评论的楼层号,包括视频、动态、专栏、话题、活动……
当前为
// ==UserScript==
// @name 修复B站评论区楼层
// @namespace MotooriKashin
// @version 0.0.2
// @description 修复评论区评论的楼层号,包括视频、动态、专栏、话题、活动……
// @author MotooriKashin
// @match *://*.bilibili.com/*
// @grant none
// @license MIT License
// ==/UserScript==
(function() {
'use strict';
let src, timer, mode, type;
const url = {
reply : "https://api.bilibili.com/x/v2/reply",
replymain : "https://api.bilibili.com/x/v2/reply/main",
replycursor : "https://api.bilibili.com/x/v2/reply/reply/cursor"
}
const xhr = {
"true" : (url) => {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.withCredentials = true;
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) resolve(xhr.response)
else reject({status: xhr.status, statusText: xhr.statusText})
};
xhr.onerror = () => reject({status: xhr.status, statusText: xhr.statusText})
xhr.send();
});
}
}
const deliver = {
obj2search : (url, obj) =>{
if (obj) {
let arr = [],i = 0;
for (let key in obj) {
if(obj[key] !== "" && obj[key] !== "undefined" && obj[key] !== null) {
arr[i] = key + "=" + obj[key];
i++;
}
}
url = url + "?" + arr.join("&");
}
return url;
},
setReplyFloor : async (src) => {
try {
let oid, sort, pn, data;
src = src.split('?')[1].split('&');
for (let i = 0; i < src.length; i++) {
let key = src[i].split('=');
if (key[0] == "oid") oid = key[1]; // oid是评论号,视频播放页似与aid相关
if (key[0] == "sort") sort = key[1]; // 评论排序方式
if (key[0] == "pn") pn = key[1]; // 评论页码
if (key[0] == "type") type = key[1]; // 评论类型:区分视频、专栏、话题……
}
// sort与mode对应转化
if (sort == 0) mode = 1;
if (sort == 1) return; // 当前无法处理按回复量排序的情形,直接退出
if (sort == 2) mode = 3;
// 热门:sort=2 mode=3 时间:sort=0 mode=2 回复:sort=1 默认(热门+时间) mode=1
if (sort == 2) data = await xhr.true(deliver.obj2search(url.replymain, {"oid": oid,"next": pn,"type": type,"mode": mode})); // 获取热门评论首页数据
else {
if (pn == 1) data = await xhr.true(deliver.obj2search(url.replymain, {"oid": oid,"type": type,"mode": mode})); // 获取最新评论首页数据
else{
pn = pn - 1;
data = await xhr.true(deliver.obj2search(url.reply, {"type": type,"sort": sort,"oid": oid,"pn": pn}));// 获取最新评论其他页的上一页数据
data = JSON.parse(data).data;
let i = data.replies.length - 1;
oid = data.replies[0].oid;
let root = data.replies[i].rpid; // 获取上一页最后一条评论的rpid并对应到root
data = await xhr.true(deliver.obj2search(url.replycursor, {"oid": oid,"root": root,"type": type})); // 根据上一页最后一条评论的root请求该评论数据
data = JSON.parse(data).data;
oid = data.root.oid;
let next = data.root.floor; // 获取上一页最后一条评论楼层并对应到next
data = await xhr.true(deliver.obj2search(url.replymain, {"oid": oid,"next": next,"type": type,"mode": mode})); // 获取当前页评论数据
}
}
data = JSON.parse(data).data;
let floor = {}, top = data.top, hots = data.hots, replies = data.replies;
let list_item = document.getElementsByClassName("list-item");
let main_floor = document.getElementsByClassName("main-floor");
if (hots && hots[0]) for (let i = 0; i < hots.length; i++) floor[hots[i].rpid] = hots[i].floor; // 获取热门评论数据
if (replies && replies[0]) for (let i = 0;i < replies.length; i++) floor[replies[i].rpid] = replies[i].floor; // 获取一般评论数据
// 获取三种置顶类型评论数据
if (top && top.admin) floor[top.admin.rpid] = top.admin.floor;
if (top && top.upper) floor[top.upper.rpid] = top.upper.floor;
if (top && top.vote) floor[top.vote.rpid] = top.vote.floor;
if (main_floor[0]) { // 判断旧版评论
for (let i = 0; i < main_floor.length; i++) {
let rpid = main_floor[i].getAttribute("id").split('_')[2]; // 获取旧版评论rpid
if (rpid in floor) main_floor[i].getElementsByClassName("floor-num")[0].innerText = "#" + floor[rpid]; // 旧版评论直接写入楼层
}
}
if (list_item[0]) { // 判断新版评论
for (let i = 0; i<list_item.length; i++) {
let rpid = list_item[i].getAttribute("data-id"); // 获取新版评论rpid
if (rpid in floor) {
let node = list_item[i].getElementsByClassName("info")[0];
// 新版评论需另外创建floor
let span = document.createElement("span");
span.setAttribute("class", "floor");
span.innerText = "#" + floor[rpid];
node.insertBefore(span,node.firstChild);
}
}
}
} catch(e) {console.error(e)}
}
}
document.addEventListener("DOMNodeInserted",(msg) => {
if (msg.target.src && msg.target.src.startsWith('https://api.bilibili.com/x/v2/reply?')) src = msg.target.src;
if (src) {
if (msg.target.className && (msg.target.className == "main-floor" || msg.target.className == "list-item reply-wrap ")){
window.clearTimeout(timer);
timer = window.setTimeout(() => {deliver.setReplyFloor(src)},1000);
}
}
});
})();