// ==UserScript==
// @name B站用户成分标签
// @namespace lycoris
// @version 1.0
// @description B站评论区根据用户动态成分添加标签(根据 新·三相之力指示器,原神指示器 修改制作)
// @author Lyzoris
// @match https://www.bilibili.com/video/*
// @icon https://static.hdslb.com/images/favicon.ico
// @connect bilibili.com
// @grant GM_xmlhttpRequest
// @license MIT
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 脚本刷新时间(推荐在10s左右) 单位:ms
const refreshTime = 10000;
// 作者不针对任何玩家或群体,不表达任何倾向,对于因为打标签行为而造成不愉快的用户,作者在此道歉
// 设置成分标签,可自定义 标签(tag),内容(text),关键词筛选正则(reg),标签颜色(color),隐藏评论(hide)
// 关键词正则 reg,可自定义(增加关键词用 | 分隔),关键词不要缩写和省略,防止误伤
const tag = [
{ tag: '游戏', text: '原神', reg: '原神|米哈游', color: '#6600CC', hide: false },
{ tag: '游戏', text: '方舟', reg: '明日方舟', color: '#6600CC', hide: false },
{ tag: '游戏', text: '农药', reg: '王者荣耀', color: '#6600CC', hide: false },
{ tag: 'Vtuber', text: '嘉心糖', reg: '嘉然', color: '#946845', hide: false },
{ tag: 'Vtuber', text: '雏草姬', reg: '塔菲', color: '#946845', hide: false },
{ tag: 'Vtuber', text: '杰尼', reg: '七海', color: '#946845', hide: false },
{ tag: 'Vtuber', text: '喵喵露', reg: '猫雷', color: '#946845', hide: false }
];
const blog = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?&host_mid=';
const is_new = document.getElementsByClassName('item goback').length != 0; // 检测是不是新版
// 网页头部插入标签样式
const tag_style = document.createElement('style');
tag_style.innerHTML = `.op-tag{
border-color:rgba(169, 195, 233, 0.1803921568627451);
color:rgba(87, 127, 184, 1);
background-image: linear-gradient(90deg, rgba(158, 186, 232, 0.2), rgba(158, 186, 232, 0.2));
float: left;
text-align: center;
height: 12px;
line-height: 12px;
border-width: 0.5px;
border-style: solid;
border-bottom-left-radius: 1px;
border-top-left-radius: 1px;
}
.tag-font{
width: 200%;
height: 200%;
font-weight: 400;
transform-origin: center;
transform: scale(0.5) translate(-50%, -50%);
font-size: 20px;
line-height: 24px;
}`;
document.querySelector('head').appendChild(tag_style);
// 标签
class Tag {
constructor(tag_dic) {
this.tag = tag_dic.tag;
this.text = tag_dic.text;
this.tagReg = new RegExp(tag_dic.text);
this.reg = new RegExp(tag_dic.reg);
this.hide = tag_dic.hide;
this.color = tag_dic.color;
this.width = tag_dic.text.length * 10 + 5;
this.tag_width = RegExp('[A-Za-z0-9]').test(this.tag) ? this.tag.length * 5 + 5 : this.tag.length * 10 + 5;
this.list = new Set();
this.nolist = new Set();
this.inner = `<div class='medal'><div class='medal-level' style='border-color:#8da8e8;color:#5e80c4; width:${this.tag_width}px'><div class='tag-font'>${this.tag}</div></div>
<div class='op-tag' style='color: ${this.color}; width:${this.width}px;'><div class='tag-font'>${this.text}</div></div></div>`;
};
// 检查列表中是否存在该用户 pid
check(pid, c) {
if (this.list.has(pid)) {
if (this.hide) {
if (c.querySelector('.text-con')) {
c.querySelector('.text-con').innerText = '评论已屏蔽';
} else {
c.nextSibling.innerText = '评论已屏蔽';
}
}
if (!this.tagReg.test(c.textContent)) {
c.innerHTML += this.inner;
}
return true;
} else if (this.nolist.has(pid)) {
// do nothing
return true;
}
};
// 检测用户标签
detect(st, c, pid) {
//添加标签
if (this.reg.test(st)) {
if (this.hide) {
if (c.querySelector('.text-con')) {
c.querySelector('.text-con').innerText = '评论已屏蔽';
} else {
c.nextSibling.innerText = '评论已屏蔽';
}
}
c.innerHTML += this.inner;
this.list.add(pid);
} else {
this.nolist.add(pid);
}
};
}
// 标签列表
class TagList {
constructor() {
this.list = [];
}
push(tag) {
this.list.push(tag);
}
check(pid, c) {
for (let i of this.list) {
let a = i.check(pid, c);
if (a) {
return true;
}
}
}
detect(st, c, pid) {
this.list.map(i => i.detect(st, c, pid));
}
}
// 获取用户 id
const get_pid = (c) => {
if (is_new) {
return c.dataset.userId;
} else {
return c.querySelector('.name').getAttribute('data-usercard-mid') || c.children[0].href.replace(/[^\d]/g, "");
}
};
// 获取评论列表
const get_comment_list = () => {
if (is_new) {
let lst = new Set();
for (let c of document.querySelectorAll('.user-name')) {
lst.add(c);
}
for (let c of document.querySelectorAll('.sub-user-name')) {
lst.add(c);
}
return lst;
} else {
return document.querySelectorAll('.user');
}
};
// 成分检测(刷新评论,检测、屏蔽标签)
const IngredientDetection = () => {
let commentlist = get_comment_list();
if (commentlist.length != 0) {
commentlist.forEach(c => {
// 检测标签列表中是否含有该用户id
let pid = get_pid(c);
let a = tag_list.check(pid, c);
if (a) {
return;
}
// 标签列表中不含该用户 id
// 获取该用户近期动态内容
let blogurl = blog + pid;
GM_xmlhttpRequest({
method: "get",
url: blogurl,
data: '',
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
},
onload: function(res) {
if (res.status === 200) {
let st = JSON.stringify(JSON.parse(res.response).data);
tag_list.detect(st, c, pid)
} else {
console.log('加载用户信息失败');
console.log(res);
}
},
});
});
}
};
// 初始化标签列表
const tag_list = new TagList();
tag.map(i => tag_list.push(new Tag(i)));
IngredientDetection();
// 设置定时检测
setInterval(() => {
let btns = document.querySelectorAll('.btn-more,.paging-box');
for (let btn of btns) {
btn.onclick = () => {
setTimeout(() => {
IngredientDetection();
}, 800);
}
}
IngredientDetection();
}, refreshTime);
console.log('%c成分查询脚本已加载', 'color: #43bb88; font-size: 12px; font-weight: bolder');
})();