// ==UserScript== // @name 仙家军成分查询Helper // @namespace www.bilibili.com // @version 1.4.1 // @description 用于标记仙家军和动态转发仙以及使用仙话术的b站用户。可能存在误伤,请注意辨别。脚本改自【糊狸-B站成分查询Helper】 // @author Darknights // @match https://*.bilibili.com/* // @exclude https://message.bilibili.com/* // @exclude https://www.bilibili.com/correspond/* // @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 // @downloadURL none // ==/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 xianRepostTag = ["转发仙:", "#1E971E"]; const favRepostTag = ["转发:", "#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(); var updateTime; const log = function (message) { return config.testLog ? console.log(message) : null; }; const spawnHtml = function (data) { return `<${data[0]}>`; } const spawnApiHtml = function (data) { return `<${data[0]}>`; } const spawnHtmlWithStrRef = function (data, word, link) { return `<${data[0]}${word}>`; } 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)); updateTime = json.updateTime; } 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()) { const 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 findRepost = function (items, isFav) { const usingList = isFav ? xianFavList : xianList; for (let i = 0; i < items.length; i++) { const item = items[i]; for (const key in item) { if (key == 'orig') { const origId = String(item.orig.modules.module_author.mid); if (usingList.indexOf(origId) > -1) { const origName = String(item.orig.modules.module_author.name); const link = String(item.id_str); return [origId, origName, link]; } } } } return null; } const hear = function (text) { for (const word of xianWordList) { const matchRes = text.match(word); if (matchRes != null) { let matchStr = matchRes[0]; if (matchStr == '') { for (const aidWord of aidList) { const matchAid = text.match(aidWord); if (matchAid != null) { matchStr = matchAid[0]; } } } return matchStr; } } return null; } const findWord = function (items) { for (let i = 0; i < items.length; i++) { const item = items[i]; let ownMatch; let 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 (const key in item) { let origMatch; let 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 findRecord = 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 = findRecord(uid, name); } else { uidSet.add(uid); } return oldTag; } log('isNew:' + isNew()); log("Loading... " + window.location.href); log("List update time:" + updateTime); setInterval(() => { const commentlist = getCommentList(); if (commentlist.length != 0) { commentlist.forEach(async htmlEntity => { if (htmlEntity.innerHTML.indexOf(``) == -1) { const uid = getUid(htmlEntity); const name = getName(htmlEntity); let oldTag = await findRecord(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) { let newTag = ''; if (xianList.indexOf(uid) > -1) { log('>>Find Target:' + name + '@UID-' + uid); newTag += spawnHtml(xianTag); } const dynamicJson = JSON.parse(res.response).data; if (dynamicJson) { if (dynamicJson.items) { const repostMatch = findRepost(dynamicJson.items, false); if (repostMatch != null) { log('>>Find Repost:' + name + '@UID-' + uid + '>>repost>>' + repostMatch[1] + '@UID-' + repostMatch[0]); newTag += spawnHtmlWithStrRef(xianRepostTag, repostMatch[1], repostMatch[2]); } const wordMatch = findWord(dynamicJson.items); if (wordMatch != null) { log('>>Find Word:' + name + '@UID-' + uid + '>>say>>' + wordMatch[0]); let fixedText = wordMatch[0]; if (fixedText.length > 15) { fixedText = fixedText.slice(0, 12) + '...'; } newTag += spawnHtmlWithStrRef(xianWordTag, fixedText, wordMatch[1]); } const favRepostMatch = findRepost(dynamicJson.items, true); if (favRepostMatch != null) { log('>>Find Fav:' + name + '@UID-' + uid + '>>repost>>' + favRepostMatch[1] + '@UID-' + favRepostMatch[0]); newTag += spawnHtmlWithStrRef(favRepostTag, favRepostMatch[1], favRepostMatch[2]); } } htmlEntity.innerHTML += newTag; recordMap.set(uid, newTag); } else { htmlEntity.innerHTML += spawnApiHtml(apiTag); } } else { log('Fail...'); log(res); } }, }); } htmlEntity.innerHTML += ``; } }); } }, config.times); } start();