// ==UserScript==
// @name b站直播聊天室简化
// @namespace http://tampermonkey.net/
// @version 0.2.9
// @description 简化聊天室,就喜欢方方正正的
// @author Pronax
// @include /https:\/\/live\.bilibili\.com\/(blanc\/)?\d+/
// @run-at document-end
// @icon https://www.google.com/s2/favicons?domain=bilibili.com
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
let chatBox = document.querySelector("#chat-items");
if (!chatBox) { return; }
// 改为Falsy值就可以关闭滚动窗口信息添加到弹幕区
let infoPersistence = true;
// 改为Falsy值就可以关闭显示弹幕区底部滚动条
let displayBrushPrompt = false;
// 改为Falsy值就可以关闭显示弹幕中的头衔图片
let displayTitleLabel = false;
// 居中修复,改为任意Truthy值打开,用于在高分屏上修复粉丝牌、房管等文字没有居中的问题
let verticalAlign = 1;
let userId = getUserID();
let giftSendMap = new Map();
if (!displayBrushPrompt) {
// 隐藏滚动框
GM_addStyle(".chat-history-panel .brush-prompt {display:none;}");
GM_addStyle(".chat-history-panel .chat-history-list.with-brush-prompt {height: 100% !important}");
}
if (!displayTitleLabel) {
// 隐藏头衔
GM_addStyle(".chat-history-panel .chat-history-list .chat-item.danmaku-item .title-label {display:none;}");
}
// 区别自己发送的弹幕
if (userId) {
GM_addStyle(`.chat-item.danmaku-item:not(.superChat-card-detail)[data-uid="${userId}"] {border-color: #ccc !important;box-shadow: 0 0 3px 0px #ddd;}`);
}
// 居中修复
if (verticalAlign) {
GM_addStyle(`
/* 主播标志 房管标志 */
.chat-history-panel .chat-history-list .chat-item.danmaku-item .anchor-icon,
.chat-history-panel .chat-history-list .chat-item.danmaku-item .admin-icon {
/* 高分屏居中 */
display: flex;
align-items: center;
}
`);
}
// 标题栏
GM_addStyle(".live-room-app .app-content{padding-top:70px !important}");
GM_addStyle(".head-info-section{height:78px!important}.head-info-section>.header-info-ctnr{padding:6px}.head-info-section .right-ctnr{right:5px}");
// 礼物栏
GM_addStyle("#gift-control-vm{height: 120px;}.gift-control-panel {height: 110px!important;}");
// 弹幕部分
GM_addStyle(":root{--danmu_width:282px}.chat-history-panel .chat-history-list .last-danmu-timestamp,.chat-history-panel .chat-history-list .chat-item.convention-msg{padding:0 5px;margin:5px 0}.chat-history-panel .chat-history-list .last-danmu-timestamp>span{color:var(--success_green);margin-right:4px;line-height:20px}.chat-history-panel .chat-history-list{padding:5px 8px}.chat-history-panel .chat-history-list.with-brush-prompt{height:calc(100% - 25px);padding-bottom:0}.chat-history-panel .danmaku-buffer-prompt{bottom:60px;position:relative;border-radius:20px;width:130px;opacity:.85;margin:0 auto}.chat-history-panel .chat-history-list .chat-item.danmaku-item:not(.superChat-card-detail){border:1px solid #e8e8e8;display:block!important;width:var(--danmu_width)!important;box-sizing:border-box;border-radius:5px;margin:3px 0!important;padding:5px 0 3px 5px;background-color:#fdfdfd!important}.chat-history-panel .chat-history-list .chat-item.danmaku-item .danmaku-item-left{display:block;height:17px;}.chat-history-panel .chat-history-list .chat-item.danmaku-item .danmaku-item-left>.common-nickname-wrapper{display:block}.chat-history-panel .chat-history-list .chat-item.danmaku-item .user-name{float:left;position:relative;top:-4px;color:var(--text3)!important;height:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40%}.chat-history-panel .chat-history-list .chat-item.danmaku-item .user-name:hover{color:var(--brand_blue)!important}.chat-history-panel .chat-history-list .chat-item.danmaku-item .fans-medal-item-ctnr{float:right}.fans-medal-item .fans-medal-label{border-radius:0!important}.chat-history-panel .chat-history-list .chat-item.danmaku-item .fans-medal-item-ctnr:has(.medal-deco){float:right;margin-left:0}.chat-history-panel .chat-history-list .chat-item.danmaku-item .fans-medal-item-ctnr .fans-medal-item{line-height:15px;height:15px}.chat-history-panel .chat-history-list .chat-item .rank-icon{width:25px;height:17px;margin-right:5px;float:right}.chat-history-panel .chat-history-list .chat-item.danmaku-item .danmaku-item-left>:first-child{margin-left:0}.chat-history-panel .chat-history-list .chat-item.danmaku-item .anchor-icon,.chat-history-panel .chat-history-list .chat-item.danmaku-item .admin-icon{padding:0 2px;float:right}.chat-history-panel .chat-history-list .chat-item .vip-icon{float:right;width:17px;height:17px}.chat-history-panel .chat-history-list .chat-item.danmaku-item .title-label{float:right;bottom:-3px;height:15px;cursor:default}.chat-history-panel .chat-history-list .chat-item.danmaku-item .title-label .live-title-cntr{height:15px!important;opacity:.7}.chat-history-panel .chat-history-list .chat-item.danmaku-item .title-label .hover-panel{display:none!important}.chat-history-panel .chat-history-list .chat-item.danmaku-item .danmaku-item-right{font-size:14px;align-items:center}.chat-history-panel .chat-history-list .chat-item.danmaku-item.emoji .emoticon{height:25px}.chat-history-panel .chat-history-list .chat-item.danmaku-item .emoticon>img{height:16px;margin-bottom:-1px}.chat-history-panel .chat-history-list .chat-item.danmaku-item .emoticon.bulge{margin-left:0;height:40px}.chat-history-panel .chat-history-list .chat-item.danmaku-item .emoticon.bulge>img{height:40px;margin-top:-2px}.chat-history-panel .danmaku-menu{padding:6px 8px 5px!important;border-radius:6px!important;margin-top:-130px;margin-left:-5px;text-align:center}.chat-history-panel .chat-history-list .chat-item.top3-notice{box-sizing:border-box;width:var(--danmu_width);margin:5px 0;border-radius:3px;background-image:linear-gradient(134deg,#3023ae99 0,#6e6dd74d 100%)}.chat-history-panel .chat-history-list .chat-item.top3-notice span{line-height:18px}.chat-history-panel .chat-history-list .chat-item.system-msg{margin:10px 0;width:var(--danmu_width);box-sizing:border-box}.chat-history-panel .chat-history-list .chat-item.gift-item{width:var(--danmu_width);border:1px solid #ffdd7f;box-sizing:border-box;border-radius:5px;background-color:#fff5da;margin:5px 0;min-height:52px;display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;padding-left:49px}.chat-history-panel .chat-history-list .chat-item.gift-item .gift-img-div{left:4px;position:absolute}.chat-history-panel .chat-history-list .chat-item.gift-item .gift-fans-medal{position:absolute;right:1px;top:5px}.chat-history-panel .chat-history-list .chat-item.superChat-card-detail{width:var(--danmu_width)}.chat-history-panel .chat-history-list .chat-item.superChat-card-detail .card-item-middle-top{height:50px}.chat-history-panel .chat-history-list .chat-item.superChat-card-detail .card-item-middle-top .card-item-middle-top-right .name{display:block;height:16px;line-height:18px;width:135px;margin-left:0}.chat-history-panel .chat-history-list .chat-item.danmaku-item.superChat-card-detail .card-item-middle-top>.face{width:40px;height:40px;margin-right:5px;border-radius:50%}.chat-history-panel .chat-history-list .chat-item.superChat-card-detail .card-item-middle-top .card-item-middle-top-right .superChat-base{position:absolute;right:7px;top:10px}.chat-history-panel .chat-history-list .chat-item.danmaku-item.superChat-card-detail .card-item-middle-top-right .exp{color:var(--pay_yellow);line-height:16px;display:inline-block;vertical-align:middle}.chat-history-panel .chat-history-list .chat-item.danmaku-item.superChat-card-detail .card-item-middle-top-right .exp>i{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABDBJREFUaAXVWt1rFFcU/92Z3Z3sJiHRxBhNRe0ihSLSF20fBBWDL/og2Pf+A774IKGU0gXf2jcf/RMsQkXwg4IgVKxUUBB9SJssRtGQaLr52J1sZmduz93qujt752Nn713WE8jOPeeee36/O+d+zQzwiQtThZ8/K2QwZBxAzctGtmlhDVP4h7GCF1k3okIqwh7LzDmBL+Iv1NxDsRyqVKvIrtH/b2PVD6lkhNjimxaMw+A8HvgPrXJ+jhcLox+KSX/VEPC84UQA0hhK5NfkpIZAU4O9vow1Bji/auLN822B4KpsBOCB5kDDFrbz14VNqd3LcEx9v8IYC204dBbi85e+ANzLFOAo5XhOGkinkrES9ctNDOICmywsyUIFEuALl/Jw3CfUs13nqSxwRzrGijRaDrGJwobfLziFHPdnZeANC8hM+GO3l70twFmlsL6s4nw/1tlFcvjJ7xRMQKSNKjEHgaGD8Vuz54HyLNVvSX8pnpBZiMfosviYOqqZ/RzI7vO7SPGEEPD797icy8cK2L8EWBpgA5Ek+peAgG6Y/UHAfvMrSn8ew9bynUhAnVbQfgectafYXPkD3KvCeXe3U3yR9bUS4LV1VJZvNkAY1njjWtWFVgLlpRvw3I+LkpGZVIW70Y42Altrj+Fs/N0IJC4Ma2dLWUVBCwGvtorK0u02fIa1q03XrUIDAY7K4nUatLSv8ckncQeqq4/gVIo+6LQmMRMs0+eD2HNWYC//3gZeKAxLbGXU33CFLXKUF3+j1HHkBDTMQPWOkUZLoKz++wA1+2Wgp2GJKdSDV5mjFfk2PLs9zQKdQwxh54EQt1YTdzdgvw1fZZ3SQ5QeToO7lbozM3MYPXxL5FZrYx2WFBGw6cjsNkIbBIqLv6aZSIyPZmHikGPQjrNLUULAyOzA8GffQcz/qYHdMGi2WV+4gtrmYiC8XH6GbN0PQSUEBMpUbp/4aYgnzrYBYk2cQXqb9IQY4BGs7r4LZG1zh/ZAtsxS307k9l+Q2pIotRAI6n3xDGcw/wMg8l+RaCJQksKzJs8hNXpEakuq1EOABrNfzIEpZPee96u7LveEAAND7sCPlDrR7z46ZaSHgG8GssaOIzX8VafYYtXXTsCkNSE7cToWmCSV9BBw1+pYROoM7jqrZMUNIqeFQHroS4JOTwfHT8K0poJiK9ErW4mb0WTHp5EdO0GnmOgHU81+Sa613IE6EBXgefRbWH0EknRnsw9tR+jQ0KyRXvcvAcm5WsYghABbljn0RGe/AOw5fygpnrBBfJ9aoDlQgdTK9MbleXRD4gAktiHvT20tDgwCT5uEEZihZyGnlLyd5PRtgejVxMIWMIJfZO6BKcTyhVmk8DWRuEfzYftTKllrqnWMlSn+NZjpb9hY4f/V0ReD+crSYv1jjlepHVKjLiWvcezBYtQXLf8BGOoetC6LwK8AAAAASUVORK5CYII=);background-size:cover;background-position:center center;width:14px;height:14px;display:inline-block;position:relative;top:2px}.chat-history-panel .chat-history-list .chat-item.danmaku-item.superChat-card-detail .exp>span{font-size:12px;color:#999}.chat-history-panel .chat-history-list .chat-item.common-danmuku-msg{margin:8px auto;padding:0 6px!important}.chat-history-panel .chat-history-list .chat-item.important-prompt-item{padding:0 5px;margin:5px 0;width:var(--danmu_width);box-sizing:border-box;font-size:12px}.chat-history-panel .brush-prompt{bottom:1px;overflow-y:hidden;display:none}.chat-history-panel .brush-prompt .brush-prompt-item{padding:4px 13px;height:18px;line-height:18px}.chat-history-panel .chat-history-list .chat-item.important-prompt-item>.gift-frame-div{float:left}.chat-history-panel .chat-history-list .chat-item.important-prompt-item .gift-frame{margin-right:3px}.chat-history-panel .chat-history-list .important-prompt-item.red-pocket-prompt-item>div,.chat-history-panel .chat-history-list .important-prompt-item.luck-pocket-prompt-item>div{display:inline-block;vertical-align:middle}.chat-history-panel .chat-history-list .chat-item.important-prompt-item>.brush-aggregated-icon{float:left;height:16px;vertical-align:middle;padding:2px 0;padding-right:5px}.chat-history-panel .chat-history-list .chat-item.important-prompt-item .brush-aggregated-total-img{height:8px;vertical-align:middle;padding:2px 0}.chat-history-panel .chat-history-list .chat-item.important-prompt-item .brush-aggregated-number{display:inline-block;vertical-align:middle;font-size:14px;color:#ababab;font-weight:400;font-style:italic}.chat-history-panel .chat-history-list .important-prompt-item .rank-icon{width:24px;height:20px}.chat-history-panel .chat-history-list .important-prompt-item .fans-medal-item-ctnr,.chat-history-panel .chat-history-list .important-prompt-item.enter-prompt-item .fans-medal-item-ctnr{float:right;display:flex;height:20px;align-items:center;margin-right:0!important}.welcome-section-bottom{display:none}.margin-l5{margin-left:5px!important}");
// 荣耀等级
GM_addStyle(".wealth-medal{width: auto !important;height: 13px !important;}");
// 弹幕监听
const chatObserver = new MutationObserver(async function (mutationsList) {
for (const mutationDetail of mutationsList) {
// if (mutationDetail.type != "childList") { return; }
for (const node of mutationDetail.addedNodes) {
// console.log(node);
if (!node.classList) { continue; } // 过滤非dom
let tempVar = undefined;
switch (node.classList[1]) {
// 普通弹幕元素
case "danmaku-item":
// SC样式
if (node.classList.contains("superChat-card-detail")) {
// ID颜色对其
// node.querySelector(".name").style.color = node.querySelector(".card-item-middle-bottom").style.backgroundColor;
// 电池
let price = node.querySelector(".card-item-top-right");
let ele = document.createElement("i");
price.prepend(ele);
price.className = "exp";
// 价格标签移动到ID旁边
node.querySelector(".name").after(price);
// 头像
ele = document.createElement("div");
ele.className = "bg-cover face";
node.querySelector(".card-item-middle-top").prepend(ele);
setFaceUrl(ele, node.dataset.uid);
continue;
}
// 头衔位置
if (tempVar = node.querySelector(".title-label")) {
node.querySelector(".danmaku-item-right").append(tempVar);
}
// 高能榜图标
if (tempVar = node.querySelector(".rank-icon")) {
node.querySelector(".user-name").before(tempVar);
}
// 舰长图标边距
if (node.querySelector(".medal-deco")) {
node.querySelector(".fans-medal-item-ctnr").classList.add("margin-l5");
}
// 表情弹幕改高清
if (tempVar = node.querySelectorAll(".emoticon")) {
for (const emoji of tempVar) {
let img = emoji.querySelector("img");
if (img.alt.match(/^\[[^_]+\]$/)) {
continue; // 排除小emoji表情
} else if (img.offsetHeight != 40) {
console.log(img.offsetWidth, img.offsetHeight);
img.style.height = '25px'; // 官方图片表情
}
let index = img.src.lastIndexOf("@");
img.src = img.src.substr(0, index);
}
}
// 弹幕全行可触发菜单
if (tempVar = node.querySelector(".danmaku-item-right.pointer:not(.open-menu)")) {
tempVar.classList.add("open-menu");
tempVar.firstChild.classList && tempVar.firstChild.classList.add("open-menu");
}
// 自己发送的弹幕可以点开菜单(历史弹幕/非网页原始组件 发送的弹幕才有效)
if (tempVar = node.querySelector(".user-name.my-self")) {
if (node.dataset.ts == 0) {
node.querySelector(".danmaku-item-right").classList.remove("pointer");
} else {
// 用户名
tempVar.classList.remove("my-self");
tempVar.classList.add("pointer", "open-menu");
}
}
// 荣耀等级
if (tempVar = node.querySelector(".wealth-medal-ctnr")) {
tempVar.classList.remove("v-middle");
node.querySelector(".common-nickname-wrapper").append(tempVar);
}
break;
// 舰长开通
case "system-msg":
break;
// 通知提示
case "convention-msg":
// 显示最后一条弹幕发送时间
tempVar = document.querySelectorAll(".danmaku-item");
if (tempVar.length) {
showLastDanmaTime(tempVar[tempVar.length - 1]);
}
break;
// 互动提示
case "toast-msg":
console.log(node.innerText);
if (node.innerText.includes("结束了视频连线")) {
setTimeout(() => {
let msgList = document.querySelectorAll(".chat-item.toast-msg");
msgList.forEach(msg => {
if (msg.innerText.includes("视频连线")) {
msg.remove();
}
});
}, 6000);
}
break;
// 房间提示
case "misc-msg":
// 全员禁言
if (node.classList[2] == "room-silent") {
}
// 禁言
else if (node.innerText.includes("禁言")) {
// 用户名标红
node.querySelector("span>span").style.color = "var(--Re6)";
}
// 粉丝团勋章升级 恭喜 xxx 粉丝勋章刚刚升级至 Lv.x
else if (node.innerText.includes("升级")) {
}
// 加团 恭喜 xxx 成为粉丝团成员
else if (node.innerText.includes("成为粉丝团成员")) {
}
break;
// 礼物提示
case "gift-item":
// 礼物图片
if (tempVar = node.querySelector(".gift-frame")) {
tempVar = tempVar.parentElement;
tempVar.classList.add("gift-img-div");
node.querySelector("span.username").before(tempVar);
}
// 粉丝牌位置
if (tempVar = node.querySelector(".fans-medal-item-target")) {
let right = tempVar.offsetWidth + 5;
tempVar.querySelector(".medal-deco") && (right += 5);
node.style.paddingRight = right + "px";
}
break;
case "important-prompt-item":
// 高能榜图标
if (tempVar = node.querySelector(".rank-icon")) {
node.before(tempVar);
}
// 入场
if (node.classList[2] == "enter-prompt-item") {
}
// 红包
else if (node.classList[2] == "red-pocket-prompt-item") {
// 仅保留最新的一个
tempVar = document.querySelectorAll(".red-pocket-prompt-item");
if (tempVar.length > 1) {
tempVar[0].remove();
}
}
// 天选
else if (node.classList[2] == "luck-pocket-prompt-item") {
// 仅保留最新的一个
tempVar = document.querySelectorAll(".luck-pocket-prompt-item");
if (tempVar.length > 1) {
tempVar[0].remove();
}
}
// 免费礼物
else if (node.classList[2] == "gift-prompt-item") {
// 礼物数量叠加
let giftInfo = node.innerText.split("\n × ");
let key = giftInfo[0].replaceAll("\n", "");
// key存放gift文字说明,value存[dom对象,礼物数量,timeout]
if (tempVar = giftSendMap.get(key)) {
// 存在说明冷却未过,清除倒计时,刷新数量,重新插入到底部
clearTimeout(tempVar[2]);
giftInfo[1] = +giftInfo[1] + tempVar[1];
tempVar[0].remove();
node.querySelector(".count").innerText = ` × ${giftInfo[1]}`;
}
let timeout = setTimeout(() => {
giftSendMap.delete(key);
}, 5000);
giftSendMap.set(key, [node, +giftInfo[1], timeout]);
}
break;
}
}
}
});
chatObserver.observe(chatBox, {
attributes: false,
childList: true,
subtree: false
});
// 滚动条监听
let enterObserver = new MutationObserver(async function (mutationsList) {
for (const mutationDetail of mutationsList) {
// if (mutationDetail.type != "childList") { return; }
let tempVar = undefined;
for (const node of mutationDetail.addedNodes) {
let domType = undefined;
// 礼物
if (tempVar = node.querySelector(".count")) {
domType = "gift"
// 给礼物图片添加class
node.querySelector("div.dp-i-block.v-middle").classList.add("gift-frame-div");
// 礼物数量居中
tempVar.classList.add("v-middle");
// 礼物数量符号
tempVar.innerText = tempVar.innerText.replace("X", " ×");
} else if (tempVar = node.querySelector(".brush-aggregated-text")) {
// 红包
if (tempVar.innerText.includes("红包")) {
domType = "red-pocket";
}
// 天选
else {
domType = "luck-pocket";
}
}
// 入场
else if (node.querySelector(".interact-name")) {
domType = "enter";
}
// 插入到弹幕框内
let msgBox = document.createElement("div");
msgBox.className = "chat-item important-prompt-item";
domType && msgBox.classList.add(`${domType}-prompt-item`);
msgBox.innerHTML = node.innerHTML;
// 防止无限制增长
if (chatBox.childElementCount > 100) {
let chatHistory = document.querySelector("#chat-history-list");
// 判断滚动条位置决定是否添加
if (displayBrushPrompt || chatHistory.scrollTop > chatHistory.scrollHeight - 2 * chatHistory.offsetHeight) {
chatBox.querySelector(".chat-item.important-prompt-item").remove();
chatBox.append(msgBox);
}
} else {
chatBox.append(msgBox);
}
}
}
});
if (infoPersistence) {
enterObserver.observe(document.querySelector("#brush-prompt"), {
attributes: false,
childList: true,
subtree: false
});
}
// 弹幕弹框时间戳
let tsPanelStatus = false;
document.querySelector(".chat-items").addEventListener('click', function (e) {
if (e.target.className.includes("chat-emoticon") || e.target.className.includes("open-menu")) {
// 初始化时间界面
if (!tsPanelStatus) {
let ele = document.createElement("div");
ele.setAttribute("id", "send-ts");
document.querySelector(".danmaku-menu").append(ele);
tsPanelStatus = true;
}
setTimeout(() => { // 因为无法准确的确定窗口的状态,加延迟防止弹窗消失时时间突变
let ts = e.target.parentElement.getAttribute("data-ts") || e.target.parentElement.parentElement.getAttribute("data-ts");
ts = new Date(ts * 1000);
document.querySelector("#send-ts").innerText = ts.toLocaleString('chinese', { hour12: false });
document.querySelector("#send-ts").innerHTML += "<br/>" + toDescribeText(Math.floor((new Date() - ts) / 1000));
}, 50);
}
}, true);
function toDescribeText(sec) {
if (!(sec = sec && Math.abs(Math.round(sec)))) {
return "刚刚";
}
const unit = ["秒", "分", "小时", "天", "年"];
const weightArray = [60, 60, 24, 365, 0];
const suffix = sec < 0 ? "后" : "前";
let degitArray = new Array(5);
let weight = 1;
for (let index = 0; index < degitArray.length && sec > 0; index++) {
degitArray[index] = sec / weight % weightArray[index];
sec -= degitArray[index] * weight;
weight *= weightArray[index];
}
let str = "";
let prevDegit = 0;
for (let index = degitArray.length - 1; index >= 0; index--) {
if (degitArray[index]) {
if (prevDegit - index > 1) {
str += "零";
}
str += degitArray[index] + unit[index];
prevDegit = index;
}
}
return str.replace(/分$/, "分钟") + suffix;
}
async function setFaceUrl(ele, uid) {
const NO_FACE = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAC0ALQDAREAAhEBAxEB/8QAHAABAAMAAwEBAAAAAAAAAAAAAAUGBwECBAMJ/8QASBAAAQMCAgQHDQUHAgcAAAAAAQACAwQFBhEHEiExEyJBUWGR0RQVFjZVcXSBk5ShsdIyQlJUwVZicnOCkrMjQyQmM0VThLL/xAAYAQEBAQEBAAAAAAAAAAAAAAAAAQIDBP/EAB8RAQEAAgMAAwEBAAAAAAAAAAABAhESITEiMlFBQv/aAAwDAQACEQMRAD8A/RVetyEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQdBPAZTAJmGRozLA4awHmRHdFEBAQEHSKeGcF0EzJADkSxwOR5tiI7oogICAgICAgICAgICAgICDFrxT3rDd+fNNLIypEhljnB/6gJ39PSPUteuF3K0nCWLKbEdNwcmrFWxD/Uj5HfvN6Pks2OuOW1gRoQN20oM5xvjgzGSz2ab/T2tnnaftc7Wnm5zyqyOWWW+o76MLXco5pro8ujo5I+Da0/7rs946Bt29KUwl9aGo6iAgICAgICAgICAgIOHvZGwySPDWtGZcTkAEEPNjPDFO8xyXiEkHI6oLh1gFNM8o+fhzhXyuz2b+xDlEdfb5gfEFE6jrLowEbY5BG/WjdzjZ8E7S3Gs0jqJrXX8Pb6vjwSHg5mZgOyO/I8h5itOXjTLLpEs1XRNddqgUlS3ivbquLXdIyB2dCmnWZz+pDw5wr5XZ7N/YovKKnjPHja2N1ssczuAcMpZwCC8fhGe0DnVkYyy31Fdw1S2Oet4W/1zYKeLI6mq4mU82wbBzq1ma320yPGuEYY2xRXSNjGANa0RPAA5tyy68o7eHOFfK7PZv7EOUe633+y3V2pQXKGZ+WeoHZO6jtTSyyveiiAgICAgICAgIOHOaxpe9wa1ozJO4BBmdxuF2x9eHWq1yGKgiOZJ2N1R993PnyBXxytud1Es7R3he307X3S6TNPLI6VkbT5gR+qbXhJ6+Hgpo8Gzv+PfI+xN1OOP648FdHf7QN98j7E3Tjj+ngro7/aBvvkfYm6ccf08FtHf7QD3yPsTdXjj+uwwlo+O0X4e+R9ibqccf08EtH3l4e+R9ibpxx/TwS0fD/vw98j7E3Tjj+ngno98vj3yPsTdOOP65ZhHR/I4MZfQ5x3AVke34JunHH9dLvo2ZDB3bh2tlMsY12se4Eu/hcMsim1uH4kcC4rmuzH2q6O/42nGxx2GRo2HPpHKli45b6q3KNiAgICAgICAgr2Pa59BhmpMZIdOWwAjkDt/wBSM53URei2BjLPV1OqNaSo1S7lya0bPiVazh4k7Jbaa8R+EF2gZUz1JcYWyDWbDFmQ1rQdm7aTzlRZN91L957R5Ko/YN7Ea1DvPaPJVH7BvYhqHee0eSqP2DexDUO89o8lUfsG9iGod57R5Ko/YN7ENQ7z2jyVR+wb2Iah3ntHkqj9g3sQ1DvPaPJVH7BvYhqOr7JZpGlj7TRlrhkRwDexDUR1oidZr3NYonuNFJB3VTNcSeC42q5gPNmQR50SdXSk3SY2bSKZ4QGN7pjJA3ZPA1uvMq/xzvWTVFHYQEBAQEBAQEFT0m+LbfSWfJyRjPxxo0blhl5/FUSH4NVph4mcLZeD1Bl/4QpVx8SiNCAgICAgICAgipMvCmD0CT/IxGf8ATPccDLGpPOYD8AtRzy+zV1l2EBAQEBAQEBBU9Jvi230lnyckYz8ddGhPgzJnyVEn/wAtVqYeJnChzw5bzzwhStY+JVGnlr7rbbXHwlwrYYAd2u7InzDeUS2T1W6nSbh+GZscMdTOzPjPawAAdGZBKumecWuCeKphZUQPD45Gh7XDcQdyjXruiq/ijGFLhl8EL6d1RLNm4sa/V1W8+7n+SSbZyy4vhbdImHa4hk0slG88kzeL/cMx15JpJnKskE8FTGJqeZksbtzmODgfWEa9d0VESnLFdMOegl/yMRn/AEz7G5Jxs8czoAP7Wqzxzy+zWFHYQEBAQEBAQEFT0m+LbfSWfJyRjPxxo2GWGHnnnkPwCtMPEvhPxbt/8hqlXHxUMYY6u1NcZ7TbMqZkB1HSaub3Hoz3BWRjLK70pQbcLrVEgT1dRIdu97z+qrHdW2xaNK+r1Z7zL3LEdvBNyMh8/I34qbbmFvrSKOkgoaWKjpmlsULAxgJzyAUdJ0+qKgcT4QocStZJJK6CpiaWslaM8xzEcoSXTOWPJnl4wLf7SS8U3dUI/wByDjZedu8LW3O42I213q62OfhKCqkhOfGYdrXedp2IzLY1rCV8qMQWgV9VTCGQSGM6ueq/IDjDPk25epZrtjdx2m8bKX0Cb/IxD+s/xwAMakjlMB+AWo55fZq6y7CAgICAgICAgqek3xbb6Sz5OSMZ+ONHGzCzv50nyCtMPEvhPxbt38hqlXHxzcMLWG6Vnd9fQNlm1Q0kucAQN2YB2psuMvb30lDR0MfBUVLFAz8MbA0fBF1p9kV84KmnqWudTzslDHFjixwOThvBy5UQhqqapLxT1EcvBO1H6jgdV3MctxQ24gqqapMgp52SGJ5jk1XZ6rhvB6UH1RXir7JaLnn3fboJifvOZxusbUSyV6KWlpqKBlLSQMhiYMmsYMgEPEZN420voE3+RiJ/VBxz46ex+QWo55fZqyy7CAgICAgICAgqek3xbb6Sz5OSMZ+OdHLf+Vh+9NJ+itMPEthQauHLe3mhAUq4+JVGhAQVmfDN2oKueowvc4qSOrOtNBMzWYH/AIm78j0JtjjZ48lPgu82hp7xX/gnVEYbVGVmes/bxm8289qu042eVP2Cw01gozTQSPlfI4ySyvPGkeeVRqTSSRoQEERK3PFdM7P7NBL8ZGIz/VCx2MsZtPOIStRzy+zVFl2EBAQEBAQEBBVNJjScN5jkqGE9RVjGfjro0l4TDb4xvjqHt6wD+qUw8TGFXB2HqHnbHqnoIJBHWpVx8SqNCAgICAgICAgiHvDsWxRt2llveXdGcjcvkUZ/0oGNHGoxwImbS18EY8+Q7VqeOeX2assuwgICAgICAgIPBfrYLxaKq3HIOlZxCeRw2t+ICJZuaUXR7e4rPV1NhuZEBlkzYX7MpBsLT58h1K1zwuuquRttyt88stllpzDO4yPpp8w1rzvLHN3Z7yMiM1G9WeBmxXnsobXl6Q/6EPkcNiv8hbPeX/QnR8jhsWeT7X7y/wChOj5HDYs/IWv3l/0J0fJ2EuKeWitg/wDYf9CHZwuKPyds9u/6UOzhcU/krZ7w/wClDtxwuKvyVs94k+hDtwJcWO2dxWtmf3uHkdl6tUZofJxBFT4fpqq73mubJPLk6ect1RkPssYOYcg3klDzuqRhqCbFWMpb3JDq08MnDuzGwZbGN8+wdRV8Yx+V209R1EBAQEBAQEBAQVbFmBqe/PNdRSNp6zLJxI4knn5j0qysZY78VUWTSNbwKWnkrODZ9ngqkFvq2p0xrKORQ6TCcg+4+uoH1J0ayfCvGkG2U7quuq66KFmWbzUgjbu3FXovKPLbbljS7yPittxrp3xjWc1s+0Dn2lOknK+PZURaRqWCSpqJ7iyKJpe9xn2ADed6nS/KPFbrrjK7Tmmt1zrp5WtLy1s5zy59p6Qr0ktvj3S0+kiCJ8001xYyNpc5xqNgA3nep0uskbR33FdfUspKS71sk0hyY3hyMzzbSqm7UsaDSaNvCXH3kfUp0usnHcOkz8dy94H1J0ayfSDBmL79Mw3yrkiib96eXXcB0NB39Sbi8bfWhWez0VjomUNDHqsbtc4/ae7lJKjpJp7UUQEBAQEBAQEBAQEBBnOlC7l89PZYn8WMcNKB+I/ZHVmfWrHLO/xWcK3c2S+U9Y52URdwcv8AAdh6t/qVrON1WiaRLgKXDb4mP41W9sQy5R9o/AfFZjpnelDwLWdx4noyTk2YmE/1DIfHJarnjdVddJN67htLbZE/KWtOTst4jG/rOQ61I6Z3U0y6KWSCVk0Ty18bg5rhvBG4quTcMP3aO92inuLMg6RuUgH3XjY4day7y7m0giiAgICAgICAgICAgICAg6yyxwRPmlcGsjaXOJ5ABmSiMKu9wkutzqbjJnnPIXAczeQeoZBacLd3byIJi8Ygmu9rttDMSXUTHMcT97cGn+0BFt3EZSVDqSqhqmfahkbIPODmiJDFF6dfbzPXAnggeDhB5GDd17T60i27u0UiLxowvPAVs1mlfxKgcJFnyPA2j1j5KVvC96aUo6iAgICAgICAgICAgICAgrGkO6d78PSQMdlJWOEI/h3u+Ay9aRjO6jJFpyEBAQEBB6LdWy26vp6+E8eCRrx05HchLpu1NURVdPFVQu1o5mB7TzgjMLLv6+iKICAgICAgICAgICAgIMs0m3Luq9x0DHZso4wCP33bT8NVWOOd3VQVZEBAQEBAQato2ubq2xGjkOb6J+oP4DtH6j1KV1wvS2KNiAgICAgICAgICAgIOskjIo3SyHJrAXOPMAiMIuda+43Gprnk5zyuf5gTsHUtOF7eZAQEBAQEBBa9G9y7jv8A3I92UdYws/qG0fqPWpWsLqtXUdhAQEBAQEBAQEBAQEEViuV8GG7jJGcncA4Z+fZ+qRnLxiS04iAgICAgICD22SV8N4oZYzk5tRGQf6glJ63VZegQEBAQEBB//9k=";
ele.style.backgroundImage = `url(${NO_FACE})`;
if (!uid) { return NO_FACE; }
let res = await fetch(`https://api.bilibili.com/x/space/acc/info?mid=${uid}&jsonp=jsonp`, { credentials: "include" });
let json = await res.json();
if (json.code == json.message) {
await loadImage(json.data.face);
ele.style.backgroundImage = `url(${json.data.face})`;
} else {
throw new Error("头像加载失败", json);
}
return json.data.face;
}
function showLastDanmaTime(item) {
let ts = new Date(item.getAttribute("data-ts") * 1000);
let soFar = Math.floor((new Date() - ts) / 1000);
let ele = document.createElement("div");
ele.className = "last-danmu-timestamp";
ele.innerHTML = `
<span>
最后一条弹幕发送自:${toDescribeText(soFar)}
</span>
`;
item.after(ele);
}
function loadImage(src) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = function () {
resolve(img);
};
img.onerror = function () {
resolve(null);
};
img.src = src;
});
}
function getUserID() {
return document.cookie.match(/DedeUserID=(\w*); /) && document.cookie.match(/DedeUserID=(\w*); /)[1];
}
})();