// ==UserScript==
// @name 仙家军成分查询Helper
// @namespace www.bilibili.com
// @version 1.4
// @description 用于标记仙家军和动态转发仙以及使用仙话术的b站用户。可能存在误伤,请注意辨别。脚本改自【糊狸-B站成分查询Helper】
// @author Darknights
// @match https://*.bilibili.com/*
// @exclude https://message.bilibili.com/*
// @icon https://static.hdslb.com/images/favicon.ico
// @connect bilibili.com
// @connect fastly.jsdelivr.net
// @connect raw.githubusercontent.com
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @license MIT
// @run-at document-end
// ==/UserScript==
'use strict';
/* 配置区 */
const config = {
urlSource: 1, // 0:githubusercontent, 1:jsdelivr
times: 2500, // 标签处理间隔时间 单位:ms
testLog: 0 // 是否开启调试日志。0:不开启,1:开启
}
// 显示标签配置在👇面
var xianList;
var xianFavList;
var xianWordList;
//以下为本地名单,可以自行添加
// 大部分为仙,少部分为其他成分但也跑到别游评论区贩过剑,极少数可能有误判
const localXianList = [];
// 转发者常见仙的,包含且不限于米吹/被仙死缠烂打的人等等
const localXianFavList = [];
// 仙可能会用的词汇
const localXianWordList = [];
// 辅助,因为有些正则匹配返回值为空
const aidList = ['响指', '瘴'];
const xianTag = ["目标:仙", "#11DD77"];
const xianSmellTag = ["转发仙:", "#1E971E"];
const xianFavTag = ["转发:", "#2C9EFF"];
const xianWordTag = ["仙语:", "#04AEAB"];
const apiTag = ["出错,请点此验证", "#FF3434"];
const blog = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?&host_mid=';
const recordMap = new Map();
const uidSet = new Set();
const log = function (message) {
return config.testLog ? console.log(message) : null;
};
const spawnHtml = function (data) {
return `<a style='color: ${data[1]} !important' target='_blank'><${data[0]}></b>`;
}
const spawnApiHtml = function (data) {
return `<a style='color: ${data[1]} !important' href='https://space.bilibili.com/208259/dynamic' target='_blank'><${data[0]}></b>`;
}
const spawnHtmlWithStrRef = function (data, word, link) {
return `<a style='color: ${data[1]} !important' href='https://t.bilibili.com/${link}' target='_blank'><${data[0]}${word}></b>`;
}
const getxianListUrl = function () {
switch (config.urlSource) {
case 0:
return "https://raw.githubusercontent.com/Darknights1750/XianLists/main/xianLists.json";
case 1:
default:
return "https://fastly.jsdelivr.net/gh/Darknights1750/XianLists@main/xianLists.json";
}
};
// 检测是不是新版
const isNew = function () {
if (document.getElementsByClassName('item goback').length != 0) {
return true;
}
if (document.getElementsByClassName('app-v1').length != 0) {
return true;
}
if (document.getElementsByClassName('opus-detail').length != 0) {
return true;
}
return false;
};
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
function getXianListOnline() {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: getxianListUrl(),
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: res => {
if (res.status === 200) {
resolve(JSON.parse(res.responseText));
} else {
resolve(JSON.parse('{"xianList":[],"xianFavList":[],"xianWordList":[]}'));
}
}
});
});
}
async function fillLists() {
let json = await getXianListOnline();
xianList = [...localXianList, ...json.xianList];
xianFavList = [...localXianFavList, ...json.xianFavList];
let xianWordStrList = [...localXianWordList, ...json.xianWordList];
xianWordList = xianWordStrList.map((item) => new RegExp(item));
// log(xianWordList);
}
async function start() {
await fillLists();
runHelper();
}
function runHelper() {
/* Functions */
const getUid = function (htmlEntity) {
if (isNew()) {
return htmlEntity.children[0].dataset.userId;
} else {
return htmlEntity.children[0].href.replace(/[^\d]/g, "");
}
}
const getName = function (htmlEntity) {
if (isNew()) {
return htmlEntity.innerText;
} else {
return htmlEntity.children[0].innerText;
}
}
const getCommentList = function () {
if (isNew()) {
let lst = new Set();
for (let c of document.getElementsByClassName('user-info')) {
lst.add(c);
}
for (let c of document.getElementsByClassName('sub-user-info')) {
lst.add(c);
}
return lst;
} else {
return document.getElementsByClassName('user');
}
}
const smell = function (items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
for (var key in item) {
if (key == 'orig') {
var origId = String(item.orig.modules.module_author.mid);
if (xianList.indexOf(origId) > -1) {
var origName = String(item.orig.modules.module_author.name);
var link = String(item.id_str);
return [origId, origName, link];
}
}
}
}
return null;
}
const smellFav = function (items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
for (var key in item) {
if (key == 'orig') {
var origId = String(item.orig.modules.module_author.mid);
if (xianFavList.indexOf(origId) > -1) {
var origName = String(item.orig.modules.module_author.name);
var link = String(item.id_str);
return [origId, origName, link];
}
}
}
}
return null;
}
const hearAid = function (text) {
for (var word of aidList) {
var matchRes = text.match(word);
if (matchRes != null) {
return matchRes[0];
}
}
}
const hear = function (text) {
for (var word of xianWordList) {
var matchRes = text.match(word);
if (matchRes != null) {
var matchStr = matchRes[0];
if (matchStr == '') {
matchStr = hearAid(text);
}
return matchStr;
}
}
return null;
}
const hearWord = function (items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var ownMatch;
var ownFullText;
if (item.modules.module_dynamic.topic != null) {
ownFullText += item.modules.module_dynamic.topic.name;
}
if (item.modules.module_dynamic.desc != null) {
ownFullText += item.modules.module_dynamic.desc.text;
}
if (item.modules.module_dynamic.major != null && item.modules.module_dynamic.major.archive != null) {
ownFullText += item.modules.module_dynamic.major.archive.title;
ownFullText += item.modules.module_dynamic.major.archive.desc;
}
if (item.modules.module_dynamic.additional != null && item.modules.module_dynamic.additional.ugc != null) {
ownFullText += item.modules.module_dynamic.additional.ugc.title;
}
if (ownFullText != null) {
ownMatch = hear(ownFullText);
if (ownMatch != null) {
return [ownMatch, String(item.id_str)];
}
}
for (var key in item) {
var origMatch;
var origFullText;
if (key == 'orig') {
if (item.orig.modules.module_dynamic.topic != null) {
origFullText += item.orig.modules.module_dynamic.topic.name;
}
if (item.orig.modules.module_dynamic.desc != null) {
origFullText += item.orig.modules.module_dynamic.desc.text;
}
if (item.orig.modules.module_dynamic.major != null && item.orig.modules.module_dynamic.major.archive != null) {
origFullText += item.orig.modules.module_dynamic.major.archive.title;
origFullText += item.orig.modules.module_dynamic.major.archive.desc;
}
if (origFullText != null) {
origMatch = hear(origFullText);
if (origMatch != null) {
return [origMatch, String(item.id_str)];
}
}
}
}
}
return null;
}
const checkRecord = async function (uid, name) {
let oldTag;
if (recordMap.has(uid)) {
oldTag = recordMap.get(uid);
uidSet.delete(uid);
if (oldTag) {
log('>>record:' + name + '@UID' + uid + '_find:' + oldTag.replaceAll(/<\/?a.*?>/g, "").replaceAll(/></g, "、").replaceAll(/&.t;/g, ""));
}
} else if (uidSet.has(uid)) {
await sleep(500);
oldTag = checkRecord(uid, name);
} else {
uidSet.add(uid);
}
return oldTag;
}
log('isNew:' + isNew());
log("Loading...");
setInterval(() => {
const commentlist = getCommentList();
if (commentlist.length != 0) {
commentlist.forEach(async htmlEntity => {
if (htmlEntity.innerHTML.indexOf(`<span id="huli">`) == -1) {
htmlEntity.innerHTML += `<span id="huli">`;
const uid = getUid(htmlEntity);
const name = getName(htmlEntity);
let oldTag = await checkRecord(uid, name);
if (oldTag != null) {
htmlEntity.innerHTML += oldTag;
} else {
GM_xmlhttpRequest({
method: "get",
url: blog + uid,
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: res => {
if (res.status === 200) {
var newTag = '';
if (xianList.indexOf(uid) > -1) {
log('>>target:' + name + '@UID' + uid);
newTag += spawnHtml(xianTag);
}
const dynamicJson = JSON.parse(res.response).data;
if (dynamicJson) {
if (dynamicJson.items) {
var origMsg = smell(dynamicJson.items);
if (origMsg != null) {
log('>>smell:' + name + '@UID' + uid + '_repost:' + origMsg[1] + '@UID' + origMsg[0]);
newTag += spawnHtmlWithStrRef(xianSmellTag, origMsg[1], origMsg[2]);
}
var hearMatch = hearWord(dynamicJson.items);
if (hearMatch != null) {
log('>>hear:' + name + '@UID' + uid + '_say:' + hearMatch[0]);
var fixedText = hearMatch[0];
if (fixedText.length > 15) {
fixedText = fixedText.slice(0, 12) + '...';
}
newTag += spawnHtmlWithStrRef(xianWordTag, fixedText, hearMatch[1]);
}
var favOrigMsg = smellFav(dynamicJson.items);
if (favOrigMsg != null) {
log('>>tips:' + name + '@UID' + uid + '_repost:' + favOrigMsg[1] + '@UID' + favOrigMsg[0]);
newTag += spawnHtmlWithStrRef(xianFavTag, favOrigMsg[1], favOrigMsg[2]);
}
}
htmlEntity.innerHTML += newTag;
recordMap.set(uid, newTag);
} else {
htmlEntity.innerHTML += spawnApiHtml(apiTag);
}
} else {
log('Fail...');
log(res);
}
},
});
}
htmlEntity.innerHTML += `</span>`;
}
});
}
}, config.times);
}
start();