🏠 Home 

A畜3畜野狗大杂烩指示器

自动标注成分,初版默认包括a畜、3畜、4畜、e畜、OP、农狗、粥批、塔畜、罕见(東雪蓮)、T畜(星瞳)


Install this script?
  1. // ==UserScript==
  2. // @name A畜3畜野狗大杂烩指示器
  3. // @version 2.57
  4. // @author trychen,miayoshi
  5. // @namespace ACG3CGTCG
  6. // @license GPLv3
  7. // @description 自动标注成分,初版默认包括a畜、3畜、4畜、e畜、OP、农狗、粥批、塔畜、罕见(東雪蓮)、T畜(星瞳)
  8. // @match https://space.bilibili.com/*
  9. // @match https://www.bilibili.com/read/*
  10. // @match https://www.bilibili.com/video/*
  11. // @match https://t.bilibili.com/*
  12. // @icon https://static.hdslb.com/images/favicon.ico
  13. // @connect bilibili.com
  14. // @grant GM_xmlhttpRequest
  15. // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js
  16. // ==/UserScript==
  17. const blog = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?&host_mid='
  18. const followapi = 'https://api.bilibili.com/x/relation/followings?vmid='
  19. $(function () {
  20. 'use strict';
  21. const checkers = [
  22. {
  23. displayName: "A畜",
  24. displayIcon: "https://i2.hdslb.com/bfs/face/43b21998da8e7e210340333f46d4e2ae7ec046eb.jpg@240w_240h_1c_1s.jpg",
  25. keywords: ["想到晚的瞬间","晚晚","嘉晚饭","乃贝","贝极星空间站","乃琳夸夸群","顶碗人","皇珈骑士","贝极星","乃宝","嘉心糖的手账本","嘉心糖","拉姐","然然","asoul","A-SOUL","水母","来点然能量","奶淇琳","珈乐","贝拉拉的717片星空"],
  26. followings: [703007###,672342685,672328094,672353429,672346917,351609538]
  27. }
  28. ,
  29. {
  30. displayName: "4畜",
  31. displayIcon: "https://i2.hdslb.com/bfs/face/27258e94f32b724821ee16c4d020fa7b2042d489.jpg@240w_240h_1c_1s.jpg",
  32. keywords: ["啵刚","谭🐷","谭猪","衫之恶魔","枝江杀猪","9分美女","三畜","野狗","3畜","谭德安","孤珈者","一等骑士","谭女士",""],
  33. followings: [1529814632,17771572]
  34. }
  35. ,
  36. {
  37. displayName: "3畜",
  38. displayIcon: "https://i2.hdslb.com/bfs/face/26ad353c5dfa2319417e5bac84f876b9bd1b54a6.jpg@240w_240h_1c_1s.jpg",
  39. keywords: ["小狗说","玉桂幺幺340","三宝","3宝","巢友","巢畜","4畜","小狗生病","Pomelo不加糖","黛露#","啵啵伯仁","學無止境","藤枝薰official","小谷桔","巢楚","大事不好_Official","水无月雅Official","黛露#","王力口富贵","咩罗斯","量子观测Official","玉桂狗美图分享bot","锯沫","锯元素"]
  40. }
  41. ,
  42. {
  43. displayName: "塔畜",
  44. displayIcon: "https://i1.hdslb.com/bfs/face/4907464999fbf2f2a6f9cc8b7352fceb6b3bfec3.jpg@240w_240h_1c_1s.jpg",
  45. keywords: ["谢谢喵","taffy","雏草姬"],
  46. followings: [1265680561]
  47. }
  48. ,
  49. {
  50. displayName: "罕见",
  51. displayIcon: "https://i0.hdslb.com/bfs/face/ced15dc126348dc42bd5c8eefdd1de5e48bdd8e6.jpg@240w_240h_1c_1s.jpg",
  52. keywords: ["東雪蓮Official","东雪莲","莲宝"],
  53. followings: [1437582453]
  54. }
  55. ,
  56. {
  57. displayName: "T畜",
  58. displayIcon: "https://i0.hdslb.com/bfs/face/6be92dec2240b0593a40d2c696b37aa75c704ff6.jpg@240w_240h_1c_1s.jpg",
  59. keywords: ["小星星","瞳宝","瞳子","瞳瞳","瞳星结"],
  60. followings: [2122506217]
  61. }
  62. ,
  63. {
  64. displayName: "E畜",
  65. displayIcon: "https://i0.hdslb.com/bfs/face/f0ac506bbfa4e4ce09729d424d28d2383e721ade.jpg@240w_240h_1c_1s.jpg",
  66. keywords: ["虞莫","柚恩","露早","莞儿","米诺"],
  67. followings: [2018113152]
  68. }
  69. ,
  70. {
  71. displayName: "梓畜",
  72. displayIcon: "https://i2.hdslb.com/bfs/face/ba9ce36ef60a53e24a97f54429e62bdb951530a0.jpg@240w_240h_1c_1s.jpg",
  73. keywords: ["阿梓从小就很可爱","阿梓","小孩梓","达达","AME"],
  74. followings: [7706705]
  75. }
  76. ,
  77. {
  78. displayName: "量畜",
  79. displayIcon: "https://i1.hdslb.com/bfs/face/2f745d6ad1b703f9d972c6e628ad6bc5c756e94d.jpg@240w_240h_1c_1s.jpg",
  80. keywords: ["量子少年","慕宇","泽一","祥太","楚枫"],
  81. followings: [1895683714,1535525542,1461176910,1757836012,1230039261]
  82. }
  83. ,
  84. {
  85. displayName: "鲨畜",
  86. displayIcon: "https://i2.hdslb.com/bfs/face/254aedbf9dad0ed5e1117c2e435a6f36ed70c64d.jpg@240w_240h_1c_1s.jpg",
  87. keywords: ["脆鲨","娜娜米","海子姐"],
  88. followings: [434334701]
  89. }
  90. ,
  91. {
  92. displayName: "OP",
  93. displayIcon: "https://i2.hdslb.com/bfs/face/d2a95376140fb1e5efbcbed70ef62891a3e5284f.jpg@240w_240h_1c_1s.jpg",
  94. keywords: ["互动抽奖 #原神", "米哈游", "#米哈游#", "#miHoYo#","原神"],
  95. followings: [401742377]
  96. }
  97. ,
  98. {
  99. displayName: "农狗",
  100. displayIcon: "https://i2.hdslb.com/bfs/face/effbafff589a27f02148d15bca7e97031a31d772.jpg@240w_240h_1c_1s.jpg",
  101. keywords: ["互动抽奖 #王者荣耀","王者荣耀"]
  102. }
  103. ,
  104. {
  105. displayName: "粥批",
  106. displayIcon: "https://i0.hdslb.com/bfs/face/89154378c06a5ed332c40c2ca56f50cd641c0c90.jpg@240w_240h_1c_1s.jpg",
  107. keywords: ["互动抽奖 #明日方舟","危机合约","《明日方舟》"],
  108. followings: [161775300]
  109. }
  110. ]
  111. const checked = {}
  112. const checking = {}
  113. var printed = false
  114. // 监听用户ID元素出现
  115. listenKey(".user-name", addButton);
  116. listenKey(".sub-user-name", addButton);
  117. listenKey(".user .name", addButton);
  118. // 添加查成分按钮
  119. function addButton(element) {
  120. let node = $(`<div style="display: inline;" class="composition-checkable"><div class="iBadge">
  121. <a class="iName">查成分</a>
  122. </div></div>`)
  123. node.on('click', function () {
  124. node.find(".iName").text("检查中...")
  125. checktag(element, node.find(".iName"))
  126. })
  127. element.after(node)
  128. }
  129. // 添加标签
  130. function addtag(id, element, setting) {
  131. let node = $(`<div style="display: inline;"><div class="iBadge">
  132. <a class="iName">${setting.displayName}</a>
  133. <img src="${setting.displayIcon}" class="iIcon">
  134. </div></div>`)
  135. element.after(node)
  136. }
  137. // 检查标签
  138. function checktag(element, loadingElement) {
  139. // 用户ID
  140. let UID = element.attr("data-user-id") || element.attr("data-usercard-mid")
  141. // 用户名
  142. let name = element.text().charAt(0) == "@" ? element.text().substring(1) : element.text()
  143. if (checked[UID]) {
  144. // 已经缓存过了
  145. for(let setting of checked[UID]) {
  146. addtag(UID, element, setting)
  147. }
  148. } else if (checking[UID] != undefined) {
  149. // 检查中
  150. if (checking[UID].indexOf(element) < 0)
  151. checking[UID].push(element)
  152. } else {
  153. checking[UID] = [element]
  154. // 获取最近动态
  155. GM_xmlhttpRequest({
  156. method: "get",
  157. url: blog + UID,
  158. data: '',
  159. headers: {
  160. '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'
  161. },
  162. onload: res => {
  163. if(res.status === 200) {
  164. // 获取关注列表
  165. GM_xmlhttpRequest({
  166. method: "get",
  167. url: followapi + UID,
  168. data: '',
  169. headers: {
  170. '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'
  171. },
  172. onload: followingRes => {
  173. if(followingRes.status === 200) {
  174. // 查询关注列表
  175. let followingData = JSON.parse(followingRes.response)
  176. // 可能无权限
  177. let following = followingData.code == 0 ? followingData.data.list.map(it => it.mid) : []
  178. // 查询并拼接动态数据
  179. let st = JSON.stringify(JSON.parse(res.response).data.items)
  180. // 找到的匹配内容
  181. let found = []
  182. for(let setting of checkers) {
  183. // 检查动态内容
  184. if (setting.keywords)
  185. if (setting.keywords.find(keyword => st.includes(keyword))) {
  186. if (found.indexOf(setting) < 0)
  187. found.push(setting)
  188. continue;
  189. }
  190. // 检查关注列表
  191. if (setting.followings)
  192. for(let mid of setting.followings) {
  193. if (following.indexOf(mid) >= 0) {
  194. if (found.indexOf(setting) < 0)
  195. found.push(setting)
  196. continue;
  197. }
  198. }
  199. }
  200. // 添加标签
  201. if (found.length > 0) {
  202. if (!printed) {
  203. console.log(JSON.parse(res.response).data)
  204. printed = true
  205. }
  206. checked[UID] = found
  207. // 给所有用到的地方添加标签
  208. for (let element of checking[UID]) {
  209. for(let setting of found) {
  210. addtag(UID, element, setting)
  211. }
  212. }
  213. loadingElement.parent().remove()
  214. } else {
  215. loadingElement.text('无')
  216. }
  217. } else {
  218. loadingElement.text('失败')
  219. }
  220. delete checking[UID]
  221. },
  222. onerror: err => {
  223. loadingElement.text('失败')
  224. delete checking[UID]
  225. },
  226. })
  227. } else {
  228. loadingElement.text('失败')
  229. delete checking[UID]
  230. }
  231. },
  232. onerror: err => {
  233. loadingElement.text('失败')
  234. delete checking[UID]
  235. },
  236. });
  237. }
  238. }
  239. addGlobalStyle(`
  240. .iBadge {
  241. display: inline-flex;
  242. justify-content: center;
  243. align-items: center;
  244. width: fit-content;
  245. background: #07beff26;
  246. border-radius: 10px;
  247. margin: -6px 0;
  248. margin: 0 5px;
  249. font-family: PingFang SC, HarmonyOS_Regular, Helvetica Neue, Microsoft YaHei, sans-serif;
  250. }
  251. .iName {
  252. line-height: 13px;
  253. font-size: 13px;
  254. color: #07beff;
  255. padding: 2px 8px;
  256. }
  257. .iIcon {
  258. width: 25px;
  259. height: 25px;
  260. border-radius: 50%;
  261. border: 2px solid white;
  262. margin: -6px;
  263. margin-right: 5px;
  264. }
  265. `)
  266. function addGlobalStyle(css) {
  267. var head, style;
  268. head = document.getElementsByTagName('head')[0];
  269. if (!head) { return; }
  270. style = document.createElement('style');
  271. style.type = 'text/css';
  272. style.innerHTML = css;
  273. head.appendChild(style);
  274. }
  275. function listenKey(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
  276. var targetNodes, btargetsFound;
  277. if (typeof iframeSelector == "undefined")
  278. targetNodes = $(selectorTxt);
  279. else
  280. targetNodes = $(iframeSelector).contents ()
  281. .find (selectorTxt);
  282. if (targetNodes && targetNodes.length > 0) {
  283. btargetsFound = true;
  284. targetNodes.each ( function () {
  285. var jThis = $(this);
  286. var alreadyFound = jThis.data ('alreadyFound') || false;
  287. if (!alreadyFound) {
  288. //--- Call the payload function.
  289. var cancelFound = actionFunction (jThis);
  290. if (cancelFound) btargetsFound = false;
  291. else jThis.data ('alreadyFound', true);
  292. }
  293. } );
  294. } else {
  295. btargetsFound = false;
  296. }
  297. var controlObj = listenKey.controlObj || {};
  298. var controlKey = selectorTxt.replace (/[^\w]/g, "_");
  299. var timeControl = controlObj [controlKey];
  300. //--- Now set or clear the timer as appropriate.
  301. if (btargetsFound && bWaitOnce && timeControl) {
  302. clearInterval (timeControl);
  303. delete controlObj [controlKey]
  304. } else {
  305. //设置定时器
  306. if ( ! timeControl) {
  307. timeControl = setInterval ( function () {
  308. listenKey(selectorTxt,actionFunction,bWaitOnce,iframeSelector);
  309. }, 300);
  310. controlObj [controlKey] = timeControl;
  311. }
  312. }
  313. listenKey.controlObj = controlObj;
  314. }
  315. })