哔哩哔哩 - 屏蔽指定内容

实现可分别按用户名、关键字或正则表达式对视频(或直播间/相薄)和评论(或回复)进行屏蔽; 将鼠标移至网页右下角弹出悬浮按钮

  1. // ==UserScript==
  2. // @name 哔哩哔哩 - 屏蔽指定内容
  3. // @namespace https://greasyfork.org/zh-CN/users/193133-pana
  4. // @homepage https://greasyfork.org/zh-CN/users/193133-pana
  5. // @version 4.8.0
  6. // @description 实现可分别按用户名、关键字或正则表达式对视频(或直播间/相薄)和评论(或回复)进行屏蔽; 将鼠标移至网页右下角弹出悬浮按钮
  7. // @author pana
  8. // @include *://www.bilibili.com/*
  9. // @include *://search.bilibili.com/*
  10. // @include *://live.bilibili.com/*
  11. // @include *://space.bilibili.com/*
  12. // @include *://t.bilibili.com/*
  13. // @include *://h.bilibili.com/*
  14. // @include *://manga.bilibili.com/*
  15. // @include *://message.bilibili.com/*
  16. // @require https://cdn.jsdelivr.net/npm/arrive@2.4.1/minified/arrive.min.js
  17. // @require https://greasyfork.org/scripts/407543-block-obj/code/Block_Obj.js?version=963893
  18. // @require https://unpkg.com/dayjs@1.8.21/dayjs.min.js
  19. // @license GNU General Public License v3.0 or later
  20. // @grant GM_getValue
  21. // @grant GM.getValue
  22. // @grant GM_setValue
  23. // @grant GM.setValue
  24. // @grant GM_setClipboard
  25. // @grant GM.setClipboard
  26. // @grant GM_registerMenuCommand
  27. // @grant GM_addValueChangeListener
  28. // @run-at document-start
  29. // @noframes
  30. // @note ----------------------------------------------------------------
  31. // @note 与"Bilibili 旧播放页"脚本(https://greasyfork.org/zh-CN/scripts/394296)的兼容问题:
  32. // @note 如果同时启用脚本后发现本脚本无法保存设置到存储中,请前往脚本管理器调整脚本执行顺序。
  33. // @note 具体方法可参考: https://greasyfork.org/zh-CN/scripts/397669
  34. // @note ----------------------------------------------------------------
  35. // @note 关于 "读取仅拥有标题的视频的用户名信息"
  36. // @note 原理是通过 API: "https://api.bilibili.com/x/web-interface/view"
  37. // @note 这个方法本质上是不可靠的,因为可能会由于快速大量进行请求从而导致被拦截 (如:频繁地在页面内刷新)
  38. // @note ----------------------------------------------------------------
  39. // @note 更新记录:
  40. // @note ver.4.8.0 优化关于动态的屏蔽功能
  41. // @note ver.4.7.0 支持在动态、视频播放等页面按粉丝勋章屏蔽评论
  42. // @note ver.4.6.4 补充覆盖视频播放页下部分内容
  43. // @note ver.4.6.3 修复添加正则表达式中存在逗号时录入出错的问题
  44. // @note ver.4.6.2 修复存在错误正则表达式时造成脚本失效的问题
  45. // @note ver.4.6.1 修复白名单效果未作用至动态上的问题
  46. // @note ver.4.6.0 支持用户白名单的功能
  47. // @note ver.4.5.0 支持按粉丝勋章屏蔽弹幕评论
  48. // @note ver.4.4.2 补充覆盖转发动态中的用户名
  49. // @note ver.4.4.1 修复上次更新导致屏蔽评论失效的问题
  50. // @note ver.4.4.0 优化脚本
  51. // @note ver.4.3.5 修复在视频关键字/正则表达式中添加单个空格时会导致所有视频被屏蔽的情况
  52. // @note ver.4.3.4 修复部分页面屏蔽失效的问题
  53. // @note ver.4.3.3 补充覆盖当前在线页面
  54. // @note ver.4.3.2 修复部分页面下按用户屏蔽失效的问题
  55. // @note ver.4.3.1 修复了由于上一版本的改动导致的脚本失效的问题
  56. // @note ver.4.3.0 兼容 Greasemonkey 4
  57. // @note ver.4.2.0 添加支持允许作用于动态的功能
  58. // @note ver.4.1.1 补充覆盖频道页面下内容
  59. // @note ver.4.1.0 允许在评论区显示屏蔽用户和"爆炸"按钮
  60. // @note ver.4.0.6 修复播放器网页全屏模式下的冲突问题
  61. // @note ver.4.0.4 尝试修复播放器网页全屏模式下可能的冲突问题
  62. // @note ver.4.0.3 修复已知的问题
  63. // @note ver.4.0.2 更换依赖库的 CDN
  64. // @note ver.4.0.0 整理并优化代码; 修复对于新添加的正则表达式,其无法在其他同步数据的标签页上生效的问题
  65. // @note ver.3.18.0 尝试通过 API 获取其他仅拥有标题的视频的用户名信息
  66. // @note ver.3.17.1 尝试通过 API 的方式读取专区热门列表里视频的用户名
  67. // @note ver.3.17.0 处理与"Bilibili 旧播放页"脚本不兼容的问题
  68. // @note ver.3.16.4 补充之前忘记匹配消息中心页面的问题; 补充覆盖番剧区页内的评论区; 修复了其他已知的问题
  69. // @note ver.3.16.0 增加 "消息中心 >> 回复我的" 的相关屏蔽,同时允许自动删除通知
  70. // @note ver.3.14.4 补充覆盖漫画页内的评论区
  71. // @note ver.3.14.3 增加相薄区的相关屏蔽; 完善部分未被覆盖的页面内容; 调整了使用关键字匹配表情的逻辑
  72. // @note ver.3.13.2 补充覆盖动态首页内的评论区
  73. // @note ver.3.13.1 修复可能无法匹配到用户动态页的问题
  74. // @note ver.3.13.0 实现多标签页同步数据; 调整取消按钮的行为; 覆盖视频播放完毕后的推荐视频; 兼容"Bilibili 旧播放页"脚本; 依旧存在的兼容问题: 在主页和视频播放页等页面下同时开启脚本时,本脚本无法保存设置到存储中
  75. // @note ver.3.11.0 增加直播区的相关屏蔽; 覆盖个人动态内的评论; 添加展开列表按钮
  76. // @note ver.3.7.1 添加删除按钮; 完善部分未被覆盖的页面内容
  77. // @note ver.3.5.3 修复部分页面下输入框内容看不清以及其他小问题
  78. // @note ver.3.5.0 优化代码; 完善部分未被覆盖的页面内容; 悬浮图标自动隐藏等
  79. // @note ver.2.2.0 添加允许将评论中的 b 站内置表情包转换成对应文字的功能
  80. // @note ver.2.1.2 修复储存正则表达式出错的问题; 优化代码
  81. // @note ver.2.1.0 添加允许按正则表达式进行屏蔽的功能
  82. // @note ver.2.0.0 调整了添加与删除关键字的方式,方便操作; 将评论与视频标题的关键词分开作用
  83. // @note ver.1.2.1 完善部分未被覆盖的页面内容
  84. // @note ver.1.2.0 添加屏蔽评论的功能
  85. // @note ver.1.1.2 调整屏蔽按钮的位置到右下角; 尝试处理脚本偶尔会失效的问题
  86. // @note ver.1.1.1 修复搜索页面以关键字屏蔽无效的问题
  87. // @note ver.1.1.0 匹配视频播放页面; 优化代码
  88. // ==/UserScript==
  89.  
  90. (async function () {
  91. 'use strict';
  92. const OLD_URL = location.href;
  93. const MODULE = {
  94. USERNAME: {
  95. className: 'li_username',
  96. },
  97. WHITELIST: {
  98. className: 'li_whitelist',
  99. },
  100. VIDEO_KEYWORD: {
  101. className: 'li_video_keyword',
  102. },
  103. COMMENT_KEYWORD: {
  104. className: 'li_comment_keyword',
  105. },
  106. };
  107. const BASIC_STYLE = `
  108. .player-mode-webfullscreen,
  109. .mode-webfullscreen,
  110. .webfullscreen,
  111. .player-module {
  112. z-index: 100001 !important;
  113. }
  114. .bilibili_reply_bang_button,
  115. .bilibili_comment_bang_button,
  116. .bilibili_reply_user_block_button,
  117. .bilibili_comment_user_block_button {
  118. display: inline-block;
  119. padding: 0px 5px;
  120. border-radius: 4px;
  121. cursor: pointer;
  122. }
  123. .bilibili_reply_bang_button:hover,
  124. .bilibili_comment_bang_button:hover,
  125. .bilibili_reply_user_block_button:hover,
  126. .bilibili_comment_user_block_button:hover {
  127. color: #00a1d6;
  128. background-color: #e5e9ef;
  129. }
  130. `;
  131. const handler = [
  132. {
  133. index: '.video-card-common',
  134. user: ['a.up', 'a.ex-up'],
  135. text: ['a.title', 'p.ex-title'],
  136. method: 1,
  137. },
  138. {
  139. clientInformation: 0,
  140. index: '.video-card-reco',
  141. user: 'p.up',
  142. text: 'p.title',
  143. },
  144. {
  145. index: '.van-slide div.item',
  146. user: null,
  147. text: 'p.title',
  148. },
  149. {
  150. index: '.rank-wrap',
  151. user: 'span.name',
  152. text: ['p.f-title', 'p.title', 'div.txt a.link p'],
  153. },
  154. {
  155. index: '.article-card',
  156. user: 'a.up',
  157. text: 'a.title',
  158. method: 1,
  159. },
  160. {
  161. index: '.live-card',
  162. user: 'p.name',
  163. text: 'p.desc',
  164. method: 1,
  165. type: {
  166. live: true,
  167. },
  168. },
  169. {
  170. index: '.card-live-module',
  171. user: '.auther',
  172. text: 'p.t',
  173. method: 1,
  174. type: {
  175. live: true,
  176. },
  177. },
  178. {
  179. index: '.live-rank-item',
  180. user: 'div.txt > p',
  181. text: 'p.p2',
  182. method: 0,
  183. type: {
  184. live: true,
  185. },
  186. },
  187. {
  188. index: '.manga-card',
  189. user: null,
  190. text: 'p.manga-title',
  191. method: 1,
  192. },
  193. {
  194. index: '.manga-spread-module',
  195. user: null,
  196. text: 'p.t',
  197. method: 1,
  198. },
  199. {
  200. c: 1,
  201. index: '.groom-module',
  202. user: 'p.author',
  203. userReg: /^up主:/,
  204. text: 'p.title',
  205. },
  206. {
  207. index: 'ul.vd-list li',
  208. user: 'a.v-author',
  209. text: 'a.title',
  210. },
  211. {
  212. index: '.video-page-card, .video-page-operator-card',
  213. user: 'div.up',
  214. text: '.title',
  215. },
  216. {
  217. index: '.rank-list li.item',
  218. user: null,
  219. text: '> a',
  220. },
  221. {
  222. c: 2,
  223. index: '.storey-box .spread-module',
  224. bv: 'a',
  225. text: 'p.t',
  226. },
  227. {
  228. index: '.ebox',
  229. user: '.author',
  230. text: '.etitle',
  231. url: ['www.bilibili.com/video/', 'www.bilibili.com/bangumi/'],
  232. comment: true,
  233. },
  234. {
  235. index: '.article-list li',
  236. user: '.nick-name',
  237. text: '.article-title',
  238. url: 'www.bilibili.com/read/ranking',
  239. },
  240. {
  241. index: '.rank-video-card, .video-card',
  242. user: '.up-name',
  243. text: '.video-name',
  244. url: ['www.bilibili.com/v/channel', 'www.bilibili.com/v/popular'],
  245. },
  246. {
  247. index: '.video-item',
  248. user: 'a.up-name',
  249. text: 'a.title',
  250. url: 'search.bilibili.com',
  251. },
  252. {
  253. index: '.live-user-item',
  254. user: '.uname',
  255. text: null,
  256. method: 0,
  257. type: {
  258. live: true,
  259. },
  260. url: 'search.bilibili.com',
  261. },
  262. {
  263. index: '.live-room-item',
  264. user: '.uname span',
  265. text: '.item-title',
  266. method: 0,
  267. type: {
  268. live: true,
  269. },
  270. url: 'search.bilibili.com',
  271. },
  272. {
  273. index: '.photo-item',
  274. user: '.up-name',
  275. text: '.title',
  276. method: 0,
  277. type: {
  278. pic: true,
  279. },
  280. url: 'search.bilibili.com',
  281. },
  282. {
  283. index: '.rank-item',
  284. user: '.room-anchor',
  285. text: '.room-title',
  286. method: 0,
  287. type: {
  288. live: true,
  289. },
  290. url: 'live.bilibili.com',
  291. comment: true,
  292. },
  293. {
  294. index: '.room-card-wrapper',
  295. user: '.room-anchor > span',
  296. text: '.room-title',
  297. method: 0,
  298. type: {
  299. live: true,
  300. },
  301. url: 'live.bilibili.com',
  302. },
  303. {
  304. index: '.ysly-room-ctnr li',
  305. user: '.uname',
  306. text: '.room-name',
  307. method: 0,
  308. type: {
  309. live: true,
  310. },
  311. url: 'live.bilibili.com',
  312. },
  313. {
  314. index: 'ul.list li',
  315. user: '.room-anchor > span',
  316. text: '.room-title',
  317. method: 0,
  318. type: {
  319. live: true,
  320. },
  321. url: 'live.bilibili.com',
  322. },
  323. {
  324. index: '.card-items li',
  325. user: '.uname',
  326. text: '.room-name',
  327. method: 0,
  328. type: {
  329. live: true,
  330. },
  331. },
  332. {
  333. index: '.content li',
  334. user: '.user-container a span',
  335. text: '.article-title a',
  336. method: 0,
  337. type: {
  338. pic: true,
  339. },
  340. url: 'h.bilibili.com',
  341. comment: true,
  342. },
  343. {
  344. index: '.rank-list > div',
  345. user: ['.name', '.user-name'],
  346. text: ['.title', '.work-name'],
  347. method: 0,
  348. type: {
  349. pic: true,
  350. },
  351. url: 'h.bilibili.com',
  352. },
  353. {
  354. index: '.canvas-card',
  355. user: '.user-container a span',
  356. text: '.article-title a',
  357. method: 1,
  358. type: {
  359. pic: true,
  360. },
  361. url: 'h.bilibili.com',
  362. },
  363. ];
  364. let bilibiliConfig = {
  365. functionEnable: true,
  366. usernameEnable: true,
  367. keywordEnable: true,
  368. whitelistEnable: false,
  369. commentEnable: false,
  370. commentKeywordEnable: false,
  371. commentFans: false,
  372. convertEmojiEnable: false,
  373. showBlockUserBtnEnable: false,
  374. showBangBtnEnable: false,
  375. liveEnable: false,
  376. picEnable: false,
  377. messageReplyEnable: false,
  378. messageReplyDelEnable: false,
  379. dynamicVideo: false,
  380. dynamicContent: false,
  381. usernameArray: [],
  382. keywordArray: [],
  383. commentArray: [],
  384. whitelistArray: [],
  385. };
  386. let infoRecord = [];
  387. const tempRecord = Block_Obj.GM.getValue('infoRecord', []);
  388. tempRecord.forEach(item => {
  389. if (dayjs().diff(item.time, 'd') <= 3) {
  390. infoRecord.push(item);
  391. }
  392. });
  393. let delNum = 0;
  394. let recordButton = [];
  395. let requestTotal = 0;
  396. let sendStatus = true;
  397. const INTERVAL_TIME = 100;
  398. if (typeof Block_Obj !== 'function') {
  399. alert('Block_Obj.js was not loaded successfully.');
  400. } else if (typeof Block_Obj.fn.compare !== 'function') {
  401. alert('The version of Block_Obj.js is too low.');
  402. }
  403. let blockObj = new Block_Obj('bilibili_config', [
  404. {
  405. key: 'keywordArray',
  406. ori: 'regArray',
  407. },
  408. {
  409. key: 'commentArray',
  410. ori: 'commentRegArray',
  411. },
  412. ]);
  413. await document.arrive('body', { fireOnAttributesModification: true, onceOnly: true, existing: true }, async function () {
  414. await blockObj.init({
  415. id: 'bilibiliConfig',
  416. menu: 'bilibili_屏蔽设置',
  417. style: BASIC_STYLE,
  418. field: [
  419. {
  420. id: 'functionEnable',
  421. label: '启用屏蔽功能',
  422. title: '总开关',
  423. type: 'c',
  424. default: true,
  425. },
  426. {
  427. id: 'whitelistEnable',
  428. label: '启用白名单',
  429. title: '白名单用户的视频(或直播间/相薄)以及评论(或回复)不会被屏蔽',
  430. type: 'c',
  431. default: false,
  432. move_right: true,
  433. },
  434. {
  435. label: '屏蔽视频(或直播间/相薄):',
  436. type: 's',
  437. },
  438. {
  439. id: 'usernameEnable',
  440. label: '按用户名',
  441. title: '屏蔽指定用户发布的视频(或直播间/相薄)',
  442. type: 'c',
  443. default: true,
  444. },
  445. {
  446. id: 'keywordEnable',
  447. label: '按关键字或正则',
  448. title: '屏蔽标题中包含指定关键字或匹配正则表达式的视频(或直播间/相薄)',
  449. type: 'c',
  450. default: true,
  451. move_right: true,
  452. },
  453. {
  454. id: 'liveEnable',
  455. label: '直播间',
  456. title: '扩展作用范围以同时允许屏蔽直播间',
  457. type: 'c',
  458. default: false,
  459. move_right: true,
  460. },
  461. {
  462. id: 'picEnable',
  463. label: '相薄',
  464. title: '扩展作用范围以同时允许屏蔽相薄',
  465. type: 'c',
  466. default: false,
  467. move_right: true,
  468. },
  469. {
  470. id: 'dynamicVideo',
  471. label: '动态',
  472. title: '允许屏蔽转发、分享指定用户的动态\n允许屏蔽视频标题匹配关键字或正则的动态',
  473. type: 'c',
  474. default: false,
  475. move_right: true,
  476. },
  477. {
  478. label: '屏蔽评论(或回复):',
  479. type: 's',
  480. },
  481. {
  482. id: 'commentEnable',
  483. label: '按用户名',
  484. title: '屏蔽指定用户发布的评论(或回复)',
  485. type: 'c',
  486. default: false,
  487. },
  488. {
  489. id: 'commentKeywordEnable',
  490. label: '按关键字或正则',
  491. title: '屏蔽内容中包含指定关键字或匹配正则表达式的评论(或回复)',
  492. type: 'c',
  493. default: false,
  494. move_right: true,
  495. },
  496. {
  497. id: 'commentFans',
  498. label: '按粉丝勋章',
  499. title: '屏蔽直播间中挂有指定粉丝勋章用户发布的弹幕评论\n屏蔽动态、视频播放等页面中挂有指定粉丝勋章用户发布的评论',
  500. type: 'c',
  501. default: false,
  502. move_right: true,
  503. },
  504. {
  505. id: 'dynamicContent',
  506. label: '动态',
  507. title: '允许屏蔽动态内容(包含转发、分享)匹配关键字或正则的动态',
  508. type: 'c',
  509. default: false,
  510. move_right: true,
  511. },
  512. {
  513. type: 'br',
  514. },
  515. {
  516. id: 'convertEmojiEnable',
  517. label: '表情转成文字',
  518. title:
  519. '判定时将表情包转换成对应的标识文字,例:[鸡腿]、[tv_白眼]等\n注意:使用关键字来匹配表情时,必须包含完整的中括号对;\n如 "鸡腿" 是无法匹配表情 [鸡腿] 的,需使用 "[鸡腿]" 进行匹配',
  520. type: 'c',
  521. default: false,
  522. },
  523. {
  524. id: 'showBlockUserBtnEnable',
  525. label: '显示屏蔽用户按钮',
  526. title: '在评论在底部显示一个屏蔽该用户的按钮',
  527. type: 'c',
  528. default: false,
  529. move_right: true,
  530. },
  531. {
  532. id: 'showBangBtnEnable',
  533. label: '显示"爆炸"按钮',
  534. title: '在评论底部显示一个可以拆分并选择文本内容的按钮',
  535. type: 'c',
  536. default: false,
  537. move_right: true,
  538. },
  539. {
  540. type: 'br',
  541. },
  542. {
  543. id: 'messageReplyEnable',
  544. label: '消息中心里的回复',
  545. title: '扩展作用范围以同时允许屏蔽消息中心里的回复',
  546. type: 'c',
  547. default: false,
  548. },
  549. {
  550. id: 'messageReplyDelEnable',
  551. label: '自动删除回复通知',
  552. title: '同时将屏蔽的回复通知自动删除\n删除的记录可在控制台中查看\n请谨慎启用该选项,因为删除操作是不可逆的!',
  553. type: 'c',
  554. default: false,
  555. move_right: true,
  556. },
  557. {
  558. type: 's',
  559. },
  560. {
  561. type: 's',
  562. label: '白名单 (用户名):',
  563. classname: MODULE.WHITELIST.className,
  564. },
  565. {
  566. id: 'whitelistInput',
  567. label: '输入:',
  568. placeholder: ' 同时输入多个时以半角逗号分隔 ',
  569. type: 'i',
  570. list_id: 'whitelistArray',
  571. classname: MODULE.WHITELIST.className,
  572. },
  573. {
  574. id: 'whitelistArray',
  575. type: 'l',
  576. default: [],
  577. classname: MODULE.WHITELIST.className,
  578. },
  579. {
  580. type: 's',
  581. },
  582. {
  583. type: 's',
  584. label: '黑名单 (用户名/粉丝勋章名):',
  585. classname: MODULE.USERNAME.className,
  586. },
  587. {
  588. id: 'usernameInput',
  589. label: '输入:',
  590. placeholder: ' 同时输入多个时以半角逗号分隔 ',
  591. type: 'i',
  592. list_id: 'usernameArray',
  593. classname: MODULE.USERNAME.className,
  594. },
  595. {
  596. id: 'usernameArray',
  597. type: 'l',
  598. default: [],
  599. classname: MODULE.USERNAME.className,
  600. },
  601. {
  602. type: 's',
  603. },
  604. {
  605. type: 's',
  606. label: '视频(或直播间/相薄)关键字或正则:',
  607. classname: MODULE.VIDEO_KEYWORD.className,
  608. },
  609. {
  610. id: 'videoKeywordInput',
  611. label: '输入:',
  612. placeholder: ' 正则表达式格式: /Pattern/Modifier ',
  613. type: 'i',
  614. list_id: 'keywordArray',
  615. classname: MODULE.VIDEO_KEYWORD.className,
  616. },
  617. {
  618. id: 'keywordArray',
  619. type: 'l',
  620. default: [],
  621. classname: MODULE.VIDEO_KEYWORD.className,
  622. },
  623. {
  624. type: 's',
  625. },
  626. {
  627. type: 's',
  628. label: '评论(或回复)关键字或正则:',
  629. classname: MODULE.COMMENT_KEYWORD.className,
  630. },
  631. {
  632. id: 'commentKeywordInput',
  633. label: '输入:',
  634. placeholder: ' 正则表达式格式: /Pattern/Modifier ',
  635. type: 'i',
  636. list_id: 'commentArray',
  637. classname: MODULE.COMMENT_KEYWORD.className,
  638. },
  639. {
  640. id: 'commentArray',
  641. type: 'l',
  642. default: [],
  643. classname: MODULE.COMMENT_KEYWORD.className,
  644. },
  645. {
  646. type: 's',
  647. },
  648. ],
  649. events: {
  650. save: config => {
  651. bilibiliConfig = config;
  652. hideEvent();
  653. },
  654. change: config => {
  655. bilibiliConfig = config;
  656. hideEvent();
  657. },
  658. },
  659. });
  660. bilibiliConfig = blockObj.getConfig();
  661. hideEvent();
  662. try {
  663. let observer = new MutationObserver(() => {
  664. hideEvent();
  665. });
  666. observer.observe(document.querySelector('body'), {
  667. childList: true,
  668. subtree: true,
  669. });
  670. } catch (e) {
  671. console.error(e);
  672. }
  673. if (/www\.bilibili\.com\/?(\/\?spm_id_from=.*)?$/.test(OLD_URL)) {
  674. document.querySelector('.btn.next') &&
  675. document.querySelector('.btn.next').addEventListener('click', () => {
  676. setTimeout(() => {
  677. hideEvent();
  678. }, 250);
  679. });
  680. document.querySelector('.btn.prev') &&
  681. document.querySelector('.btn.prev').addEventListener('click', () => {
  682. setTimeout(() => {
  683. hideEvent();
  684. }, 250);
  685. });
  686. document.body.arrive(
  687. '.manga-panel .btn-change',
  688. {
  689. fireOnAttributesModification: true,
  690. onceOnly: true,
  691. existing: true,
  692. },
  693. item => {
  694. item.addEventListener('click', () => {
  695. setTimeout(() => {
  696. hideEvent();
  697. }, 1000);
  698. });
  699. }
  700. );
  701. document.body.arrive(
  702. '.manga-panel .tab-switch-item',
  703. {
  704. fireOnAttributesModification: true,
  705. onceOnly: true,
  706. existing: true,
  707. },
  708. item => {
  709. item.addEventListener('click', () => {
  710. setTimeout(() => {
  711. hideEvent();
  712. }, 1000);
  713. });
  714. }
  715. );
  716. }
  717. if (/live\.bilibili\.com\/all/.test(OLD_URL)) {
  718. document.body.arrive(
  719. '.content-panel h1.title > span',
  720. {
  721. fireOnAttributesModification: true,
  722. onceOnly: true,
  723. existing: true,
  724. },
  725. item => {
  726. item.addEventListener('click', () => {
  727. setTimeout(() => {
  728. hideEvent();
  729. }, 1000);
  730. });
  731. }
  732. );
  733. }
  734. });
  735. function displayDel(panelId, num) {
  736. if (document.getElementById(panelId)) {
  737. document.getElementById(panelId).textContent = ' (自动删除了 ' + num + ' 条通知)';
  738. } else {
  739. const delPanel = document.createElement('span');
  740. delPanel.id = panelId;
  741. delPanel.textContent = ' (自动删除了 ' + num + ' 条通知)';
  742. document.querySelector('.space-right-top .title').appendChild(delPanel);
  743. }
  744. }
  745. function decideText(
  746. textValue,
  747. isComment = false,
  748. isLive = false,
  749. isPic = false,
  750. sourceText = null,
  751. isMessageReply = false,
  752. dynamicVideo = null,
  753. dynamic = null,
  754. repost = null
  755. ) {
  756. let isDecide = false;
  757. let isDecideComment = false;
  758. let isDecideDynamic = false;
  759. let isDecideDynamicTitle = false;
  760. let isDecideDynamicContent = false;
  761. let isDecideDynamicRepost = false;
  762. if (bilibiliConfig.functionEnable) {
  763. if (textValue) {
  764. if (isComment) {
  765. if (isMessageReply) {
  766. if (bilibiliConfig.messageReplyEnable) {
  767. isDecideComment = true;
  768. }
  769. } else {
  770. isDecideComment = true;
  771. }
  772. } else if (isLive) {
  773. if (bilibiliConfig.liveEnable) {
  774. isDecide = true;
  775. }
  776. } else if (isPic) {
  777. if (bilibiliConfig.picEnable) {
  778. isDecide = true;
  779. }
  780. } else {
  781. isDecide = true;
  782. }
  783. } else {
  784. if (bilibiliConfig.dynamicVideo && dynamicVideo) {
  785. isDecideDynamic = true;
  786. isDecideDynamicTitle = true;
  787. }
  788. if (bilibiliConfig.dynamicContent && dynamic) {
  789. isDecideDynamic = true;
  790. isDecideDynamicContent = true;
  791. }
  792. if (bilibiliConfig.dynamicContent && repost) {
  793. isDecideDynamic = true;
  794. isDecideDynamicRepost = true;
  795. }
  796. }
  797. }
  798. if (isDecide) {
  799. if (bilibiliConfig.keywordEnable) {
  800. for (let k of bilibiliConfig.keywordArray) {
  801. if (k) {
  802. if (typeof k === 'string' && textValue.includes(k)) {
  803. return true;
  804. } else {
  805. try {
  806. if (textValue.match(k)) {
  807. return true;
  808. }
  809. } catch (e) {
  810. console.error('存在错误的正则表达式: ', e);
  811. }
  812. }
  813. }
  814. }
  815. }
  816. } else if (isDecideComment) {
  817. if (bilibiliConfig.commentKeywordEnable) {
  818. for (let i of bilibiliConfig.commentArray) {
  819. if (i) {
  820. if (typeof i === 'string') {
  821. if (textValue.includes(i)) {
  822. if (sourceText) {
  823. if (sourceText.includes(i)) {
  824. return true;
  825. } else if (/\[.*\]/i.test(i)) {
  826. return true;
  827. }
  828. } else {
  829. return true;
  830. }
  831. } else if (sourceText && /\[.*\]/i.test(i)) {
  832. if (sourceText.includes(i)) {
  833. return true;
  834. }
  835. }
  836. } else {
  837. try {
  838. if (textValue.match(i)) {
  839. return true;
  840. } else if (sourceText.match(i)) {
  841. return true;
  842. }
  843. } catch (e) {
  844. console.error('存在错误的正则表达式: ', e);
  845. }
  846. }
  847. }
  848. }
  849. }
  850. } else if (isDecideDynamic) {
  851. let dynamicStatus = false;
  852. if (isDecideDynamicTitle) {
  853. if (bilibiliConfig.keywordEnable) {
  854. for (let o of bilibiliConfig.keywordArray) {
  855. if (o) {
  856. if (typeof o === 'string' && dynamicVideo.includes(o)) {
  857. dynamicStatus = true;
  858. break;
  859. } else {
  860. try {
  861. if (dynamicVideo.match(o)) {
  862. dynamicStatus = true;
  863. break;
  864. }
  865. } catch (e) {
  866. console.error('存在错误的正则表达式: ', e);
  867. }
  868. }
  869. }
  870. }
  871. }
  872. }
  873. if (!dynamicStatus && dynamic.content && isDecideDynamicContent) {
  874. if (bilibiliConfig.commentKeywordEnable) {
  875. for (const q of bilibiliConfig.commentArray) {
  876. if (q) {
  877. if (typeof q === 'string') {
  878. if (dynamic.content.includes(q)) {
  879. if (dynamic.sourceContent) {
  880. if (dynamic.sourceContent.includes(q)) {
  881. dynamicStatus = true;
  882. break;
  883. } else if (/\[.*\]/i.test(q)) {
  884. dynamicStatus = true;
  885. break;
  886. }
  887. } else {
  888. dynamicStatus = true;
  889. break;
  890. }
  891. } else if (dynamic.sourceContent && /\[.*\]/i.test(q)) {
  892. if (dynamic.sourceContent.includes(q)) {
  893. dynamicStatus = true;
  894. break;
  895. }
  896. }
  897. } else {
  898. try {
  899. if (dynamic.content.match(q)) {
  900. dynamicStatus = true;
  901. break;
  902. } else if (dynamic.sourceContent.match(q)) {
  903. dynamicStatus = true;
  904. break;
  905. }
  906. } catch (e) {
  907. console.error('存在错误的正则表达式: ', e);
  908. }
  909. }
  910. }
  911. }
  912. }
  913. }
  914. if (!dynamicStatus && repost.content && isDecideDynamicRepost) {
  915. if (bilibiliConfig.commentKeywordEnable) {
  916. for (const r of bilibiliConfig.commentArray) {
  917. if (r) {
  918. if (typeof r === 'string') {
  919. if (repost.content.includes(r)) {
  920. if (repost.sourceContent) {
  921. if (repost.sourceContent.includes(r)) {
  922. dynamicStatus = true;
  923. break;
  924. } else if (/\[.*\]/i.test(r)) {
  925. dynamicStatus = true;
  926. break;
  927. }
  928. } else {
  929. dynamicStatus = true;
  930. break;
  931. }
  932. } else if (repost.sourceContent && /\[.*\]/i.test(r)) {
  933. if (repost.sourceContent.includes(r)) {
  934. dynamicStatus = true;
  935. break;
  936. }
  937. }
  938. } else {
  939. try {
  940. if (repost.content.match(r)) {
  941. dynamicStatus = true;
  942. break;
  943. } else if (repost.sourceContent.match(r)) {
  944. dynamicStatus = true;
  945. break;
  946. }
  947. } catch (e) {
  948. console.error('存在错误的正则表达式: ', e);
  949. }
  950. }
  951. }
  952. }
  953. }
  954. }
  955. return dynamicStatus;
  956. }
  957. return false;
  958. }
  959. function decideUsername(
  960. username,
  961. isComment = false,
  962. isLive = false,
  963. isPic = false,
  964. isMessageReply = false,
  965. trueLove = null,
  966. repostUser = null
  967. ) {
  968. let isDecide = false;
  969. if (bilibiliConfig.functionEnable && username) {
  970. if (isComment) {
  971. if (bilibiliConfig.commentEnable) {
  972. if (isMessageReply) {
  973. if (bilibiliConfig.messageReplyEnable) {
  974. isDecide = true;
  975. }
  976. } else {
  977. isDecide = true;
  978. }
  979. }
  980. } else if (isLive) {
  981. if (bilibiliConfig.liveEnable) {
  982. if (bilibiliConfig.usernameEnable) {
  983. isDecide = true;
  984. }
  985. }
  986. } else if (isPic) {
  987. if (bilibiliConfig.picEnable) {
  988. if (bilibiliConfig.usernameEnable) {
  989. isDecide = true;
  990. }
  991. }
  992. } else {
  993. if (bilibiliConfig.usernameEnable) {
  994. isDecide = true;
  995. }
  996. }
  997. }
  998. if (isDecide) {
  999. if (bilibiliConfig.usernameArray.includes(username)) {
  1000. return true;
  1001. }
  1002. }
  1003. if (bilibiliConfig.functionEnable) {
  1004. if (bilibiliConfig.commentFans && trueLove) {
  1005. if (bilibiliConfig.usernameArray.includes(trueLove)) {
  1006. return true;
  1007. }
  1008. }
  1009. if (bilibiliConfig.dynamicVideo && repostUser) {
  1010. if (bilibiliConfig.usernameArray.includes(repostUser)) {
  1011. return true;
  1012. }
  1013. }
  1014. }
  1015. return false;
  1016. }
  1017. function isWhitelist(username) {
  1018. if (username && bilibiliConfig.functionEnable && bilibiliConfig.whitelistEnable) {
  1019. if (bilibiliConfig.whitelistArray.includes(username)) {
  1020. return true;
  1021. }
  1022. }
  1023. return false;
  1024. }
  1025. function hideHandler(itemNode, username, textValue, method = 0, type = {}) {
  1026. if (username) {
  1027. if (typeof username === 'object') {
  1028. username = username.textContent;
  1029. }
  1030. username = username.trim();
  1031. }
  1032. if (textValue) {
  1033. if (typeof textValue === 'object') {
  1034. textValue = textValue.textContent;
  1035. }
  1036. textValue = textValue.trim();
  1037. }
  1038. const isComment = type.comment ? true : false;
  1039. const isMessageReply = type.messageReply ? true : false;
  1040. const delButton = type.delButton ? type.delButton : null;
  1041. const isLive = type.live ? true : false;
  1042. const isPic = type.pic ? true : false;
  1043. const trueLove = type.trueLove ? type.trueLove.trim() : null;
  1044. const dynamic = type.dynamic != null && typeof type.dynamic === 'object' ? type.dynamic : null;
  1045. const dynamicVideo = type.dynamicVideo ? type.dynamicVideo.trim() : null;
  1046. const repost = type.repost != null && typeof type.repost === 'object' ? type.repost : null;
  1047. const repostUser = type.repostUser ? type.repostUser.trim() : null;
  1048. const sourceText = type.sourceText ? type.sourceText : null;
  1049. let hideStatus = false;
  1050. if (isWhitelist(username)) {
  1051. hideStatus = false;
  1052. } else if (decideUsername(username, isComment, isLive, isPic, isMessageReply, trueLove, repostUser)) {
  1053. hideStatus = true;
  1054. } else if (decideText(textValue, isComment, isLive, isPic, sourceText, isMessageReply, dynamicVideo, dynamic, repost)) {
  1055. hideStatus = true;
  1056. } else {
  1057. hideStatus = false;
  1058. }
  1059. if (itemNode.constructor == Array) {
  1060. for (let eleNode of itemNode) {
  1061. if (eleNode) {
  1062. Block_Obj.fn.hideOperation(eleNode, hideStatus, method);
  1063. }
  1064. }
  1065. } else {
  1066. Block_Obj.fn.hideOperation(itemNode, hideStatus, method);
  1067. }
  1068. if (hideStatus) {
  1069. if (delButton) {
  1070. if (bilibiliConfig.messageReplyDelEnable && !recordButton.includes(delButton)) {
  1071. recordButton.push(delButton);
  1072. delButton.click();
  1073. console.info('%c自动删除通知:', 'color: purple;', '\n用户名:', username, '\n评论内容:', textValue);
  1074. delNum++;
  1075. displayDel('messageDelPanel', delNum);
  1076. }
  1077. }
  1078. }
  1079. }
  1080. function extractEle(ele, selector) {
  1081. let result = null;
  1082. if (selector) {
  1083. if (Array.isArray(selector)) {
  1084. for (const e of selector) {
  1085. if (ele.querySelector(e)) {
  1086. result = ele.querySelector(e);
  1087. break;
  1088. }
  1089. }
  1090. } else {
  1091. result = ele.querySelector(selector);
  1092. }
  1093. }
  1094. return result;
  1095. }
  1096. function hideEvent() {
  1097. handler.forEach(item => {
  1098. const { c, index, user, text, method, type, userReg, url, comment, bv } = item;
  1099. let status = false;
  1100. if (url) {
  1101. if (Array.isArray(url)) {
  1102. for (let u of url) {
  1103. if (OLD_URL.indexOf(u) !== -1) {
  1104. status = true;
  1105. break;
  1106. }
  1107. }
  1108. } else {
  1109. status = OLD_URL.indexOf(url) !== -1;
  1110. }
  1111. } else {
  1112. status = OLD_URL.indexOf('www.bilibili.com') !== -1;
  1113. }
  1114. if (status) {
  1115. const all = document.querySelectorAll(index);
  1116. for (const ele of all) {
  1117. if (c == 1) {
  1118. hideHandler(ele, extractEle(ele, user).textContent.replace(userReg, ''));
  1119. } else if (c == 2) {
  1120. const bvNum = getBvNumber(ele.querySelector(bv).href);
  1121. asyncUsernameHandle(bvNum, ele, extractEle(ele, text));
  1122. } else {
  1123. hideHandler(ele, extractEle(ele, user), extractEle(ele, text), method, type);
  1124. }
  1125. }
  1126. if (comment) {
  1127. hideComment();
  1128. }
  1129. }
  1130. });
  1131. if (OLD_URL.indexOf('www.bilibili.com') !== -1) {
  1132. try {
  1133. const carouselModulePanel = document.querySelector('.carousel-module .panel');
  1134. if (carouselModulePanel) {
  1135. const carouselModulePanelTitle = carouselModulePanel.querySelectorAll('ul.title a');
  1136. const carouselModulePanelPic = carouselModulePanel.querySelectorAll('ul.pic li');
  1137. const carouselModulePanelTrig = carouselModulePanel.querySelectorAll('ul.trig span');
  1138. for (let panelIndex = 0; panelIndex < carouselModulePanelTitle.length; panelIndex++) {
  1139. hideHandler(
  1140. [carouselModulePanelTitle[panelIndex], carouselModulePanelPic[panelIndex], carouselModulePanelTrig[panelIndex]],
  1141. null,
  1142. carouselModulePanelTitle[panelIndex],
  1143. 3
  1144. );
  1145. }
  1146. }
  1147. } catch (e) {
  1148. console.error('bilibili_BLock: Variable carouselModulePanel is error.');
  1149. console.error(e);
  1150. }
  1151. const rankItem = document.getElementsByClassName('rank-item');
  1152. for (const rankItemEle of rankItem) {
  1153. let textValue = '';
  1154. if (rankItemEle.querySelector('p.ri-title')) {
  1155. textValue = rankItemEle.querySelector('p.ri-title');
  1156. }
  1157. if (rankItemEle.querySelector('a.title')) {
  1158. textValue = rankItemEle.querySelector('a.title');
  1159. }
  1160. if (rankItemEle.querySelector('.detail > a')) {
  1161. hideHandler(rankItemEle, rankItemEle.querySelector('.detail > a'), textValue);
  1162. } else if (rankItemEle.querySelector('a')) {
  1163. const linkA = rankItemEle.querySelector('a');
  1164. const bvNum = getBvNumber(linkA.href);
  1165. asyncUsernameHandle(bvNum, rankItemEle, textValue);
  1166. }
  1167. }
  1168. const recentHot = document.querySelectorAll('div#recent_hot li');
  1169. for (const recentHotItem of recentHot) {
  1170. const bvNum = getBvNumber(recentHotItem.querySelector('a').href);
  1171. asyncUsernameHandle(bvNum, recentHotItem, recentHotItem.title);
  1172. }
  1173. const bilibiliPlayerRecommendVideo = document.getElementsByClassName('bilibili-player-recommend-video');
  1174. for (const bilibiliPlayerRecommendVideoItem of bilibiliPlayerRecommendVideo) {
  1175. const bvNum = getBvNumber(bilibiliPlayerRecommendVideoItem.href);
  1176. asyncUsernameHandle(
  1177. bvNum,
  1178. bilibiliPlayerRecommendVideoItem,
  1179. bilibiliPlayerRecommendVideoItem.querySelector('.bilibili-player-recommend-title')
  1180. );
  1181. }
  1182. const bilibiliPlayerEndingPanelBoxRecommend = document.querySelectorAll('a.bilibili-player-ending-panel-box-recommend');
  1183. for (const bilibiliPlayerEndingPanelBoxRecommendItem of bilibiliPlayerEndingPanelBoxRecommend) {
  1184. let bvNum = '';
  1185. try {
  1186. bvNum = /(?:av|bv)(\w+)/i.exec(bilibiliPlayerEndingPanelBoxRecommendItem.getAttribute('data-bvid'))[1];
  1187. } catch (e) {
  1188. bvNum = null;
  1189. }
  1190. if (!bvNum) {
  1191. try {
  1192. bvNum = getBvNumber(bilibiliPlayerEndingPanelBoxRecommendItem.href);
  1193. } catch (e) {
  1194. bvNum = null;
  1195. }
  1196. }
  1197. asyncUsernameHandle(
  1198. bvNum,
  1199. bilibiliPlayerEndingPanelBoxRecommendItem,
  1200. bilibiliPlayerEndingPanelBoxRecommendItem.querySelector('.bilibili-player-ending-panel-box-recommend-cover-title')
  1201. );
  1202. }
  1203. } else if (/(t|manga|space)\.bilibili\.com/.test(OLD_URL)) {
  1204. const card = document.querySelectorAll('div.card');
  1205. for (const cardItem of card) {
  1206. const contentFull = cardItem.querySelector('.content-full');
  1207. let sourceContent = null;
  1208. let convertText = null;
  1209. if (contentFull && !contentFull.closest('.repost')) {
  1210. sourceContent = contentFull.textContent;
  1211. if (bilibiliConfig.convertEmojiEnable) {
  1212. convertText = getConvertText(contentFull.innerHTML);
  1213. }
  1214. }
  1215. const title = cardItem.querySelector('.title');
  1216. let titleText = null;
  1217. if (title) {
  1218. titleText = title.textContent;
  1219. }
  1220. let repostUser = cardItem.querySelector('.repost .username');
  1221. repostUser = repostUser ? repostUser.textContent : null;
  1222. let repostSourceText = null;
  1223. let repostConvertText = null;
  1224. const repostContent = cardItem.querySelector('.repost .content-full');
  1225. if (repostContent) {
  1226. repostSourceText = repostContent.textContent;
  1227. if (bilibiliConfig.convertEmojiEnable) {
  1228. repostConvertText = getConvertText(repostContent.innerHTML);
  1229. }
  1230. }
  1231. if (bilibiliConfig.convertEmojiEnable) {
  1232. hideHandler(cardItem, null, null, 0, {
  1233. dynamicVideo: titleText,
  1234. dynamic: {
  1235. content: convertText,
  1236. sourceContent: sourceContent,
  1237. },
  1238. repostUser,
  1239. repost: {
  1240. content: repostConvertText,
  1241. sourceContent: repostSourceText,
  1242. },
  1243. });
  1244. } else {
  1245. hideHandler(cardItem, null, null, 0, {
  1246. dynamicVideo: titleText,
  1247. dynamic: {
  1248. content: sourceContent,
  1249. },
  1250. repostUser,
  1251. repost: {
  1252. content: repostSourceText,
  1253. },
  1254. });
  1255. }
  1256. }
  1257. hideComment();
  1258. } else if (/message\.bilibili\.com\/#\/reply/.test(OLD_URL)) {
  1259. const replyItem = document.getElementsByClassName('reply-item');
  1260. for (const replyItemEle of replyItem) {
  1261. let nextNode = null;
  1262. if (replyItemEle.nextElementSibling) {
  1263. if (replyItemEle.nextElementSibling.classList.contains('divider')) {
  1264. nextNode = replyItemEle.nextElementSibling;
  1265. }
  1266. }
  1267. const sourceText = replyItemEle.querySelector('.text').textContent;
  1268. if (bilibiliConfig.convertEmojiEnable) {
  1269. const convertText = replyItemEle.querySelector('.text span').innerHTML.replace(/<img.*alt="(.*)".*>/g, '$1');
  1270. hideHandler([replyItemEle, nextNode], replyItemEle.querySelector('.name-field a'), convertText, 0, {
  1271. comment: true,
  1272. messageReply: true,
  1273. sourceText: sourceText,
  1274. delButton: replyItemEle.querySelector('.bl-button--primary'),
  1275. });
  1276. } else {
  1277. hideHandler([replyItemEle, nextNode], replyItemEle.querySelector('.name-field a'), sourceText, 0, {
  1278. comment: true,
  1279. messageReply: true,
  1280. delButton: replyItemEle.querySelector('.bl-button--primary'),
  1281. });
  1282. }
  1283. }
  1284. } else if (/live\.bilibili\.com\/\d+/.test(OLD_URL)) {
  1285. const chatItems = document.querySelectorAll('#chat-items .chat-item');
  1286. chatItems.forEach(item => {
  1287. const fansMedalContent = item.querySelector('.fans-medal-content');
  1288. hideHandler(item, null, null, 0, {
  1289. trueLove: fansMedalContent ? fansMedalContent.textContent : null,
  1290. });
  1291. });
  1292. }
  1293. }
  1294. function hideComment() {
  1295. const commentList = document.querySelectorAll('.comment-list .list-item');
  1296. for (const commentListItem of commentList) {
  1297. const sourceText = commentListItem.querySelector('.con > p.text').textContent;
  1298. let trueLove = commentListItem.querySelector('.true-love');
  1299. trueLove = trueLove ? trueLove.firstChild.textContent : null;
  1300. if (bilibiliConfig.convertEmojiEnable) {
  1301. const convertText = getConvertText(commentListItem.querySelector('.con > p.text').innerHTML);
  1302. hideHandler(commentListItem, commentListItem.querySelector('.con > .user a.name'), convertText, 0, {
  1303. comment: true,
  1304. sourceText: sourceText,
  1305. trueLove,
  1306. });
  1307. } else {
  1308. hideHandler(commentListItem, commentListItem.querySelector('.con > .user a.name'), sourceText, 0, {
  1309. comment: true,
  1310. trueLove,
  1311. });
  1312. }
  1313. const commentReplyBtn = commentListItem.querySelector('.reply.btn-hover');
  1314. if (bilibiliConfig.showBlockUserBtnEnable) {
  1315. commentReplyBtn &&
  1316. !commentListItem.querySelector('.bilibili_comment_user_block_button') &&
  1317. commentReplyBtn.after(
  1318. blockObj.createBlockBtn(
  1319. commentListItem.querySelector('.con > .user a.name').textContent,
  1320. 'usernameArray',
  1321. 'bilibili_comment_user_block_button',
  1322. 'span',
  1323. '屏蔽',
  1324. '屏蔽该用户'
  1325. )
  1326. );
  1327. } else {
  1328. commentListItem.querySelector('.bilibili_comment_user_block_button') &&
  1329. commentListItem.querySelector('.bilibili_comment_user_block_button').remove();
  1330. }
  1331. if (bilibiliConfig.showBangBtnEnable) {
  1332. const commentBtn = commentListItem.querySelector('.bilibili_comment_user_block_button') || commentReplyBtn;
  1333. commentBtn &&
  1334. !commentListItem.querySelector('.bilibili_comment_bang_button') &&
  1335. commentBtn.after(
  1336. blockObj.createBigBangBtn(
  1337. sourceText,
  1338. 'commentArray',
  1339. 'bilibili_comment_bang_button',
  1340. 'span',
  1341. '爆炸',
  1342. '拆分并选择文本内容进行屏蔽'
  1343. )
  1344. );
  1345. } else {
  1346. commentListItem.querySelector('.bilibili_comment_bang_button') &&
  1347. commentListItem.querySelector('.bilibili_comment_bang_button').remove();
  1348. }
  1349. }
  1350. const replyCommentList = document.querySelectorAll('.comment-list .reply-item');
  1351. for (const replyCommentListItem of replyCommentList) {
  1352. const replySourceText = replyCommentListItem.querySelector('.reply-con .text-con').textContent;
  1353. if (bilibiliConfig.convertEmojiEnable) {
  1354. const replyConvertText = getConvertText(replyCommentListItem.querySelector('.reply-con .text-con').innerHTML);
  1355. hideHandler(replyCommentListItem, replyCommentListItem.querySelector('.reply-con .user a.name'), replyConvertText, 0, {
  1356. comment: true,
  1357. sourceText: replySourceText,
  1358. });
  1359. } else {
  1360. hideHandler(replyCommentListItem, replyCommentListItem.querySelector('.reply-con .user a.name'), replySourceText, 0, {
  1361. comment: true,
  1362. });
  1363. }
  1364. const replyBtn = replyCommentListItem.querySelector('.reply.btn-hover');
  1365. if (bilibiliConfig.showBlockUserBtnEnable) {
  1366. replyBtn &&
  1367. !replyCommentListItem.querySelector('.bilibili_reply_user_block_button') &&
  1368. replyBtn.after(
  1369. blockObj.createBlockBtn(
  1370. replyCommentListItem.querySelector('.reply-con .user a.name').textContent,
  1371. 'usernameArray',
  1372. 'bilibili_reply_user_block_button',
  1373. 'span',
  1374. '屏蔽',
  1375. '屏蔽该用户'
  1376. )
  1377. );
  1378. } else {
  1379. replyCommentListItem.querySelector('.bilibili_reply_user_block_button') &&
  1380. replyCommentListItem.querySelector('.bilibili_reply_user_block_button').remove();
  1381. }
  1382. if (bilibiliConfig.showBangBtnEnable) {
  1383. const pBtn = replyCommentListItem.querySelector('.bilibili_reply_user_block_button') || replyBtn;
  1384. pBtn &&
  1385. !replyCommentListItem.querySelector('.bilibili_reply_bang_button') &&
  1386. pBtn.after(
  1387. blockObj.createBigBangBtn(
  1388. replySourceText,
  1389. 'commentArray',
  1390. 'bilibili_reply_bang_button',
  1391. 'span',
  1392. '爆炸',
  1393. '拆分并选择文本内容进行屏蔽'
  1394. )
  1395. );
  1396. } else {
  1397. replyCommentListItem.querySelector('.bilibili_reply_bang_button') &&
  1398. replyCommentListItem.querySelector('.bilibili_reply_bang_button').remove();
  1399. }
  1400. }
  1401. }
  1402. function getConvertText(text) {
  1403. return text
  1404. .replace(/<img.*?alt="(.*?)".*?>/g, '$1')
  1405. .replace(/<a.*?>(.*?)<\/\s*a>/g, '$1')
  1406. .replace(/&nbsp;/g, ' ');
  1407. }
  1408. function asyncUsernameHandle(bvNum, mainEle, textValue, hideMethod = 0, typeInfo = {}) {
  1409. let userName = '';
  1410. if (bvNum) {
  1411. let recordUser = false;
  1412. infoRecord.forEach(item => {
  1413. if (item.bv == bvNum) {
  1414. userName = item.user;
  1415. recordUser = true;
  1416. }
  1417. });
  1418. if (recordUser) {
  1419. hideHandler(mainEle, userName, textValue, hideMethod, typeInfo);
  1420. } else {
  1421. infoRecord.push({
  1422. bv: bvNum,
  1423. user: userName,
  1424. time: dayjs().format('YYYY-MM-DD'),
  1425. });
  1426. const apiUrl = bvNum.match(/^\d+$/)
  1427. ? 'https://api.bilibili.com/x/web-interface/view?aid='
  1428. : 'https://api.bilibili.com/x/web-interface/view?bvid=';
  1429. const xhr = new XMLHttpRequest();
  1430. xhr.open('GET', apiUrl + bvNum, true);
  1431. xhr.responseType = 'json';
  1432. xhr.onload = () => {
  1433. if (xhr.status == 200) {
  1434. if (xhr.response.data && xhr.response.data.owner && xhr.response.data.owner['name']) {
  1435. userName = xhr.response.data.owner['name'];
  1436. }
  1437. } else {
  1438. sendStatus = false;
  1439. console.info(apiUrl + bvNum + '\nresponse status: ' + xhr.status);
  1440. }
  1441. hideHandler(mainEle, userName, textValue, hideMethod, typeInfo);
  1442. infoRecord.forEach(item => {
  1443. if (item.bv == bvNum) {
  1444. item.user = userName;
  1445. }
  1446. });
  1447. Block_Obj.GM.setValue('infoRecord', infoRecord);
  1448. };
  1449. xhr.onerror = () => {
  1450. console.info(apiUrl + bvNum + '\nerror.');
  1451. hideHandler(mainEle, userName, textValue, hideMethod, typeInfo);
  1452. };
  1453. setTimeout(() => {
  1454. sendStatus && xhr.send();
  1455. }, INTERVAL_TIME * requestTotal);
  1456. requestTotal++;
  1457. }
  1458. } else {
  1459. hideHandler(mainEle, userName, textValue, hideMethod, typeInfo);
  1460. }
  1461. }
  1462. function getBvNumber(video_link) {
  1463. let bvNum = '';
  1464. try {
  1465. bvNum = /\/video\/(?:av|bv)(\w+)/i.exec(video_link)[1];
  1466. } catch (e) {
  1467. bvNum = null;
  1468. }
  1469. return bvNum;
  1470. }
  1471. })();