M3U8 Filter Ad Script

自用,拦截和过滤 m3u8(解析/采集资源) 的切片(插播)广告,同时在console打印过滤的行信息,不会误删。

当前为 2024-11-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name M3U8 Filter Ad Script
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.1
  5. // @description 自用,拦截和过滤 m3u8(解析/采集资源) 的切片(插播)广告,同时在console打印过滤的行信息,不会误删。
  6. // @author ltxlong
  7. // @match *://*/*
  8. // @run-at document-start
  9. // @grant unsafeWindow
  10. // @grant GM_getResourceText
  11. // @grant GM_addStyle
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_unregisterMenuCommand
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
  17. // @require https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.js
  18. // @resource Swal https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.css
  19. // @resource SwalDark https://unpkg.com/@sweetalert2/theme-dark@5/dark.min.css
  20. // @license MIT
  21. // ==/UserScript==
  22.  
  23. (function() {
  24. 'use strict';
  25.  
  26. let ts_name_len = 0; // ts前缀长度
  27.  
  28. let ts_name_len_extend = 1; // 容错
  29.  
  30. let first_extinf_row = '';
  31.  
  32. let the_extinf_judge_row_n = 0;
  33.  
  34. let the_same_extinf_name_n = 0;
  35.  
  36. let the_extinf_benchmark_n = 5; // 基准
  37.  
  38. let prev_ts_name_index = -1; // 上个ts序列号
  39.  
  40. let first_ts_name_index = -1; // 首个ts序列号
  41.  
  42. let ts_type = 0; // 0:xxxx000数字递增.ts模式0 ;1:xxxxxxxxxx.ts模式1;2:.ts模式2只能暴力拆解
  43.  
  44. let the_ext_x_mode = 0; // 0:ext_x_discontinuity判断模式0 ;1:ext_x_discontinuity判断模式1
  45.  
  46. let the_current_host = unsafeWindow.location.hostname;
  47.  
  48. let script_whitelist_mode_flag = false; // 是否启用白名单模式,默认否,默认是匹配所有的网站
  49.  
  50. let the_current_host_in_whitelist_flag = false; // 当前域名是否在白名单,默认否
  51.  
  52. let show_toast_tip_flag = false; // 是否启用弹窗提示,默认否
  53.  
  54. let violent_filter_mode_flag = false; // 是否启用暴力拆解模式,默认否-自动判断模式
  55.  
  56. function filter_log(...msg) {
  57. console.log('%c[m3u8_filter_ad]', 'font-weight: bold; color: white; background-color: #70b566b0; padding: 2px; border-radius: 2px;', ...msg);
  58. }
  59.  
  60. let the_swalcss_color = "#ff679a";
  61.  
  62. let swalcss = `
  63. .swal2-styled{transition: all 0.2s ease;}
  64. .swal2-loader{display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;-webkit-animation:swal2-rotate-loading 1.5s linear 0s infinite normal;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:${the_swalcss_color} transparent }
  65. .swal2-styled.swal2-confirm{border:0;border-radius:.25em;background:initial;background-color:${the_swalcss_color};color:#fff;font-size:1em}
  66. .swal2-styled.swal2-confirm:hover,.swal2-styled.swal2-deny:hover{opacity:0.8;background-image:none!important}
  67. .swal2-styled.swal2-confirm:focus{box-shadow:0 0 0 3px ${the_swalcss_color}80}
  68. .swal2-styled.swal2-deny:focus{box-shadow:0 0 0 3px #dc374180}
  69. .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto;overflow:hidden;border-bottom-right-radius:5px;border-bottom-left-radius:5px}
  70. .swal2-timer-progress-bar{width:100%;height:.25em;background:${the_swalcss_color}33 }
  71. .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:${the_swalcss_color};color:#fff;line-height:2em;text-align:center}
  72. .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:${the_swalcss_color} }
  73. .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:${the_swalcss_color}}
  74. .swal2-popup {padding:1.25em 0 1.25em;flex-direction:column}
  75. .swal2-close {position:absolute;top:1px;right:1px;transition: all 0.2s ease;}
  76. div:where(.swal2-container) .swal2-html-container{padding: 1.3em 1.3em 0.3em;}
  77. div:where(.swal2-container) button:where(.swal2-close):hover {color:${the_swalcss_color}!important;font-size:60px!important}
  78. div:where(.swal2-icon) .swal2-icon-content {font-family: sans-serif;}
  79. .swal2-container {z-index: 1145141919810;}
  80. `;
  81.  
  82. // 动态添加样式
  83. function addStyle(id, css, tag = 'style', element = 'body', position = 'before') {
  84. let styleDom = document.getElementById(id);
  85. if (styleDom) styleDom.remove();
  86. let style = document.createElement(tag);
  87. style.rel = 'stylesheet';
  88. style.id = id;
  89. tag === 'style' ? style.innerHTML = css : style.href = css;
  90. if (position === "before") {
  91. $(element).prepend($(style));
  92. } else {
  93. $(element).append($(style));
  94. }
  95. }
  96.  
  97. // 先监听颜色方案变化
  98. unsafeWindow.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  99. if (e.matches) {
  100. // 切换到暗色主题
  101. addStyle('swal-pub-style', GM_getResourceText('SwalDark'));
  102. } else {
  103. // 切换到浅色主题
  104. addStyle('swal-pub-style', GM_getResourceText('Swal'));
  105. }
  106.  
  107. addStyle('Panlinker-SweetAlert2-User', swalcss);
  108. });
  109. // 再修改主题
  110. if (unsafeWindow.matchMedia && unsafeWindow.matchMedia('(prefers-color-scheme: dark)').matches) {
  111. // 切换到暗色主题
  112. addStyle('swal-pub-style', GM_getResourceText('SwalDark'));
  113. } else {
  114. // 切换到浅色主题
  115. addStyle('swal-pub-style', GM_getResourceText('Swal'));
  116. }
  117.  
  118. addStyle('Panlinker-SweetAlert2-User', swalcss);
  119.  
  120. // Toast 提示配置
  121. let toast = Swal.mixin({
  122. toast: true,
  123. position: 'top-end',
  124. showConfirmButton: false,
  125. timer: 2000,
  126. timerProgressBar: true,
  127. showCloseButton: true,
  128. didOpen: function (toast) {
  129. toast.addEventListener('mouseenter', Swal.stopTimer);
  130. toast.addEventListener('mouseleave', Swal.resumeTimer);
  131. }
  132. });
  133.  
  134. // Toast 简易调用
  135. let message = {
  136. success: function (text) {
  137. toast.fire({ title: text, icon: 'success' });
  138. },
  139. error: function (text) {
  140. toast.fire({ title: text, icon: 'error' });
  141. },
  142. warning: function (text) {
  143. toast.fire({ title: text, icon: 'warning' });
  144. },
  145. info: function (text) {
  146. toast.fire({ title: text, icon: 'info' });
  147. },
  148. question: function (text) {
  149. toast.fire({ title: text, icon: 'question' });
  150. }
  151. };
  152.  
  153. function isM3U8File(url) {
  154. return /\.m3u8($|\?)/.test(url);
  155. }
  156.  
  157. function extractNumberBeforeTS(str) {
  158. // 匹配 .ts 前面的数字
  159. const match = str.match(/(\d+)\.ts/);
  160.  
  161. if (match) {
  162. // 使用 parseInt 去掉前导 0
  163. return parseInt(match[1], 10);
  164. }
  165.  
  166. return null; // 如果不匹配,返回 null
  167. }
  168.  
  169. function filterLines(lines) {
  170. let result = [];
  171.  
  172. if (violent_filter_mode_flag) {
  173. filter_log('----------------------------暴力拆解模式--------------------------');
  174.  
  175. ts_type = 2; // ts命名模式
  176. } else {
  177. filter_log('----------------------------自动判断模式--------------------------');
  178.  
  179. let the_normal_int_ts_n = 0;
  180. let the_diff_int_ts_n = 0;
  181.  
  182. let last_ts_name_len = 0;
  183.  
  184. // 初始化参数
  185. for (let i = 0; i < lines.length; i++) {
  186.  
  187. const line = lines[i];
  188.  
  189. // 初始化first_extinf_row
  190. if (the_extinf_judge_row_n === 0 && line.startsWith('#EXTINF')) {
  191. first_extinf_row = line;
  192.  
  193. the_extinf_judge_row_n++;
  194. } else if (the_extinf_judge_row_n === 1 && line.startsWith('#EXTINF')) {
  195. if (line !== first_extinf_row) {
  196. first_extinf_row = '';
  197. }
  198.  
  199. the_extinf_judge_row_n++;
  200. }
  201.  
  202. // 判断ts模式
  203. let the_ts_name_len = line.indexOf('.ts'); // ts前缀长度
  204.  
  205. if (the_ts_name_len > 0) {
  206.  
  207. if (the_extinf_judge_row_n === 1) {
  208. ts_name_len = the_ts_name_len;
  209. }
  210.  
  211. last_ts_name_len = the_ts_name_len;
  212.  
  213. let ts_name_index = extractNumberBeforeTS(line);
  214. if (ts_name_index === null) {
  215. if (the_extinf_judge_row_n === 1) {
  216. ts_type = 1; // ts命名模式
  217. } else if (the_extinf_judge_row_n === 2 && (ts_type === 1 || the_ts_name_len === ts_name_len)) {
  218. ts_type = 1; // ts命名模式
  219.  
  220. filter_log('----------------------------识别ts模式1---------------------------');
  221.  
  222. break;
  223. } else {
  224. the_diff_int_ts_n++;
  225. }
  226.  
  227. } else {
  228.  
  229. // 如果序号相隔等于1: 模式0
  230. // 如果序号相隔大于1,或其他:模式2(暴力拆解)
  231.  
  232. if (the_normal_int_ts_n === 0) {
  233. // 初始化ts序列号
  234. prev_ts_name_index = ts_name_index;
  235. first_ts_name_index = ts_name_index;
  236. prev_ts_name_index = first_ts_name_index - 1;
  237. }
  238.  
  239. if (the_ts_name_len !== ts_name_len) {
  240.  
  241. if (the_ts_name_len === last_ts_name_len + 1 && ts_name_index === prev_ts_name_index + 1) {
  242.  
  243. if (the_diff_int_ts_n) {
  244.  
  245. if (ts_name_index === prev_ts_name_index + 1) {
  246. ts_type = 0; // ts命名模式
  247. prev_ts_name_index = first_ts_name_index - 1;
  248.  
  249. filter_log('----------------------------识别ts模式0---------------------------')
  250.  
  251. break;
  252. } else {
  253. ts_type = 2; // ts命名模式
  254.  
  255. filter_log('----------------------------识别ts模式2---------------------------')
  256.  
  257. break;
  258. }
  259. }
  260.  
  261. the_normal_int_ts_n++;
  262. prev_ts_name_index = ts_name_index;
  263.  
  264. } else {
  265. the_diff_int_ts_n++;
  266. }
  267. } else {
  268.  
  269. if (the_diff_int_ts_n) {
  270.  
  271. if (ts_name_index === prev_ts_name_index + 1) {
  272. ts_type = 0; // ts命名模式
  273. prev_ts_name_index = first_ts_name_index - 1;
  274.  
  275. filter_log('----------------------------识别ts模式0---------------------------')
  276.  
  277. break;
  278. } else {
  279. ts_type = 2; // ts命名模式
  280.  
  281. filter_log('----------------------------识别ts模式2---------------------------')
  282.  
  283. break;
  284. }
  285. }
  286.  
  287. the_normal_int_ts_n++;
  288. prev_ts_name_index = ts_name_index;
  289. }
  290. }
  291. }
  292.  
  293. if (i === lines.length - 1) {
  294. // 后缀不是ts,而是jpeg等等,或者以上规则判断不了的,或者没有广告切片的:直接暴力拆解
  295.  
  296. ts_type = 2; // ts命名模式
  297.  
  298. filter_log('----------------------------进入暴力拆解模式---------------------------')
  299. }
  300. }
  301. }
  302.  
  303. // 开始遍历过滤
  304. for (let i = 0; i < lines.length; i++) {
  305.  
  306. let ts_index_check = false;
  307.  
  308. const line = lines[i];
  309.  
  310. if (ts_type === 0) {
  311.  
  312. if (line.startsWith('#EXT-X-DISCONTINUITY') && lines[i + 1] && lines[i + 2]) {
  313.  
  314. // 检查当前行是否跟 #EXT-X-PLAYLIST-TYPE相关
  315. if (i > 0 && lines[i - 1].startsWith('#EXT-X-PLAYLIST-TYPE')) {
  316. result.push(line);
  317.  
  318. continue;
  319. } else {
  320. let the_ts_name_len = lines[i + 2].indexOf('.ts'); // ts前缀长度
  321.  
  322. if (the_ts_name_len > 0) {
  323.  
  324. // 根据ts名字长度过滤
  325. if (the_ts_name_len - ts_name_len > ts_name_len_extend) {
  326. // 广告过滤
  327. if (lines[i + 3] && lines[i + 3].startsWith('#EXT-X-DISCONTINUITY')) {
  328. // 打印即将过滤的行
  329. filter_log('过滤规则: #EXT-X-DISCONTINUITY-ts文件名长度-');
  330. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2], "\n", lines[i + 3]);
  331. filter_log('------------------------------------------------------------------');
  332.  
  333. i += 3;
  334. } else {
  335. // 打印即将过滤的行
  336. filter_log('过滤规则: #EXT-X-DISCONTINUITY-ts文件名长度');
  337. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2]);
  338. filter_log('------------------------------------------------------------------');
  339.  
  340. i += 2;
  341. }
  342.  
  343. continue;
  344. } else {
  345. ts_name_len = the_ts_name_len;
  346. }
  347.  
  348. // 根据ts序列号过滤
  349. let the_ts_name_index = extractNumberBeforeTS(lines[i + 2]);
  350.  
  351. if (the_ts_name_index !== prev_ts_name_index + 1) {
  352.  
  353. // 广告过滤
  354. if (lines[i + 3] && lines[i + 3].startsWith('#EXT-X-DISCONTINUITY')) {
  355. // 打印即将过滤的行
  356. filter_log('过滤规则: #EXT-X-DISCONTINUITY-ts序列号-');
  357. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2], "\n", lines[i + 3]);
  358. filter_log('------------------------------------------------------------------');
  359.  
  360. i += 3;
  361. } else {
  362. // 打印即将过滤的行
  363. filter_log('过滤规则: #EXT-X-DISCONTINUITY-ts序列号');
  364. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2]);
  365. filter_log('------------------------------------------------------------------');
  366.  
  367. i += 2;
  368. }
  369.  
  370. continue;
  371. }
  372. }
  373. }
  374. }
  375.  
  376. if (line.startsWith('#EXTINF') && lines[i + 1]) {
  377.  
  378. let the_ts_name_len = lines[i + 1].indexOf('.ts'); // ts前缀长度
  379.  
  380. if (the_ts_name_len > 0) {
  381.  
  382. // 根据ts名字长度过滤
  383. if (the_ts_name_len - ts_name_len > ts_name_len_extend) {
  384. // 广告过滤
  385. if (lines[i + 2] && lines[i + 2].startsWith('#EXT-X-DISCONTINUITY')) {
  386. // 打印即将过滤的行
  387. filter_log('过滤规则: #EXTINF-ts文件名长度-');
  388. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2]);
  389. filter_log('------------------------------------------------------------------');
  390.  
  391. i += 2;
  392. } else {
  393. // 打印即将过滤的行
  394. filter_log('过滤规则: #EXTINF-ts文件名长度');
  395. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1]);
  396. filter_log('------------------------------------------------------------------');
  397.  
  398. i += 1;
  399. }
  400.  
  401. continue;
  402. } else {
  403. ts_name_len = the_ts_name_len;
  404. }
  405.  
  406. // 根据ts序列号过滤
  407. let the_ts_name_index = extractNumberBeforeTS(lines[i + 1]);
  408.  
  409. if (the_ts_name_index === prev_ts_name_index + 1) {
  410.  
  411. prev_ts_name_index++;
  412.  
  413. } else {
  414. // 广告过滤
  415. if (lines[i + 2].startsWith('#EXT-X-DISCONTINUITY')) {
  416. // 打印即将过滤的行
  417. filter_log('过滤规则: #EXTINF-ts序列号-');
  418. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2]);
  419. filter_log('------------------------------------------------------------------');
  420.  
  421. i += 2;
  422. } else {
  423. // 打印即将过滤的行
  424. filter_log('过滤规则: #EXTINF-ts序列号');
  425. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1]);
  426. filter_log('------------------------------------------------------------------');
  427.  
  428. i += 1;
  429. }
  430.  
  431. continue;
  432. }
  433. }
  434. }
  435. } else if (ts_type === 1) {
  436.  
  437. if (line.startsWith('#EXTINF')) {
  438. if (line === first_extinf_row && the_same_extinf_name_n <= the_extinf_benchmark_n && the_ext_x_mode === 0) {
  439. the_same_extinf_name_n++;
  440. } else {
  441. the_ext_x_mode = 1;
  442. }
  443.  
  444. if (the_same_extinf_name_n > the_extinf_benchmark_n) {
  445. the_ext_x_mode = 1;
  446. }
  447. }
  448.  
  449. if (line.startsWith('#EXT-X-DISCONTINUITY')) {
  450. // 检查当前行是否跟 #EXT-X-PLAYLIST-TYPE相关
  451. if (i > 0 && lines[i - 1].startsWith('#EXT-X-PLAYLIST-TYPE')) {
  452. result.push(line);
  453.  
  454. continue;
  455. } else {
  456.  
  457. // 如果第 i+2 行是 .ts 文件,跳过当前行和接下来的两行
  458. if (lines[i + 1] && lines[i + 1].startsWith('#EXTINF') && lines[i + 2] && lines[i + 2].indexOf('.ts') > 0) {
  459.  
  460. let the_ext_x_discontinuity_condition_flag = false;
  461.  
  462. if (the_ext_x_mode === 1) {
  463. the_ext_x_discontinuity_condition_flag = lines[i + 1] !== first_extinf_row && the_same_extinf_name_n > the_extinf_benchmark_n;
  464. }
  465.  
  466. // 进一步检测第 i+3 行是否也是 #EXT-X-DISCONTINUITY
  467. if (lines[i + 3] && lines[i + 3].startsWith('#EXT-X-DISCONTINUITY') && the_ext_x_discontinuity_condition_flag) {
  468. // 打印即将过滤的行
  469. filter_log('过滤规则: #EXT-X-DISCONTINUITY-广告-#EXT-X-DISCONTINUITY过滤');
  470. filter_log('过滤的行:', "\n", line, "\n", lines[i + 1], "\n", lines[i + 2], "\n", lines[i + 3]);
  471. filter_log('------------------------------------------------------------------');
  472.  
  473. i += 3; // 跳过当前行和接下来的三行
  474. } else {
  475. // 打印即将过滤的行
  476. filter_log('过滤规则: #EXT-X-DISCONTINUITY-单个标识过滤');
  477. filter_log('过滤的行:', "\n", line);
  478. filter_log('------------------------------------------------------------------');
  479. }
  480.  
  481. continue;
  482. }
  483. }
  484. }
  485. } else {
  486.  
  487. // 暴力拆解
  488. if (line.startsWith('#EXT-X-DISCONTINUITY')) {
  489. // 检查当前行是否跟 #EXT-X-PLAYLIST-TYPE相关
  490. if (i > 0 && lines[i - 1].startsWith('#EXT-X-PLAYLIST-TYPE')) {
  491. result.push(line);
  492.  
  493. continue;
  494. } else {
  495.  
  496. // 打印即将过滤的行
  497. filter_log('过滤规则: #EXT-X-DISCONTINUITY-单个标识过滤');
  498. filter_log('过滤的行:', "\n", line);
  499. filter_log('------------------------------------------------------------------');
  500.  
  501. continue;
  502. }
  503. }
  504. }
  505.  
  506. // 保留不需要过滤的行
  507. result.push(line);
  508. }
  509.  
  510. return result;
  511. }
  512.  
  513. async function safelyProcessM3U8(url, content) {
  514. try {
  515. const lines = content.split('\n');
  516. const newLines = filterLines(lines);
  517.  
  518. return newLines.join('\n');
  519. } catch (e) {
  520. filter_log(`处理 m3u8 文件时出错: ${url}`, e);
  521.  
  522. return content;
  523. }
  524. }
  525.  
  526. function hookXHR() {
  527. const OriginalXHR = unsafeWindow.XMLHttpRequest;
  528. unsafeWindow.XMLHttpRequest = class extends OriginalXHR {
  529. constructor() {
  530. super();
  531.  
  532. this.addEventListener('readystatechange', async function () {
  533. if (this.readyState === 4 && this.status === 200 && isM3U8File(this.responseURL)) {
  534.  
  535. filter_log('----------------------------hookXHR成功---------------------------');
  536.  
  537. const modifiedResponse = await safelyProcessM3U8(this.responseURL, this.responseText);
  538. Object.defineProperty(this, 'responseText', { value: modifiedResponse });
  539. Object.defineProperty(this, 'response', { value: modifiedResponse });
  540.  
  541. if (show_toast_tip_flag) {
  542. message.success('已成功过滤切片广告');
  543. }
  544.  
  545. GM_registerMenuCommand('提示:已成功过滤视频切片广告');
  546. }
  547. }, false);
  548. }
  549. };
  550. }
  551.  
  552. function initHook() {
  553. hookXHR();
  554. }
  555.  
  556. let menu_item_violent = null;
  557. let menu_item_mode = null;
  558. let menu_item_host_join = null;
  559. let menu_item_toast = null;
  560.  
  561. violent_filter_mode_flag = GM_getValue('violent_filter_mode_flag', false);
  562. script_whitelist_mode_flag = GM_getValue('script_whitelist_mode_flag', false);
  563. the_current_host_in_whitelist_flag = GM_getValue(the_current_host, false);
  564. show_toast_tip_flag = GM_getValue('show_toast_tip_flag', false);
  565.  
  566. function check_menu_item_violent() {
  567. if (violent_filter_mode_flag) {
  568. menu_item_violent = GM_registerMenuCommand('暴力拆解模式(可点击切换到自动判断过滤模式)', function() {
  569.  
  570. GM_setValue('violent_filter_mode_flag', false);
  571.  
  572. violent_filter_mode_flag = false;
  573.  
  574. message.success('已设置:<br><br>自动判断过滤模式!');
  575.  
  576. unsafeWindow.location.reload();
  577. });
  578. } else {
  579. menu_item_violent = GM_registerMenuCommand('自动判断过滤模式(可点击切换到暴力拆解模式)', function() {
  580.  
  581. GM_setValue('violent_filter_mode_flag', true);
  582.  
  583. violent_filter_mode_flag = true;
  584.  
  585. message.success('已设置:<br><br>暴力拆解模式!');
  586.  
  587. unsafeWindow.location.reload();
  588. });
  589. }
  590. }
  591.  
  592. function check_menu_item_mode() {
  593. if (script_whitelist_mode_flag) {
  594. menu_item_mode = GM_registerMenuCommand('现在是白名单模式(可点击切换到全匹配模式)', function() {
  595.  
  596. GM_setValue('script_whitelist_mode_flag', false);
  597.  
  598. script_whitelist_mode_flag = false;
  599.  
  600. message.success('已设置:<br><br>全匹配模式,即匹配所有网站!');
  601.  
  602. unsafeWindow.location.reload();
  603. });
  604. } else {
  605. menu_item_mode = GM_registerMenuCommand('现在是全匹配模式(可点击切换到白名单模式)', function() {
  606.  
  607. GM_setValue('script_whitelist_mode_flag', true);
  608.  
  609. script_whitelist_mode_flag = true;
  610.  
  611. message.success('已设置:<br><br>白名单模式,即需要单个网站设置加入过滤名单!');
  612.  
  613. unsafeWindow.location.reload();
  614. });
  615. }
  616. }
  617.  
  618. function check_menu_item_host_join() {
  619. if (script_whitelist_mode_flag) {
  620.  
  621. if (the_current_host_in_whitelist_flag) {
  622.  
  623. initHook();
  624.  
  625. if (unsafeWindow.self === unsafeWindow.top) {
  626.  
  627. if (menu_item_host_join === null) {
  628. filter_log('----------------------------脚本加载完成---------------------------');
  629. filter_log('----------------------------还没 hookXHR---------------------------');
  630. }
  631.  
  632. menu_item_host_join = GM_registerMenuCommand('本网站已开启过滤(可点击关闭广告过滤)', function() {
  633.  
  634. GM_setValue(the_current_host, false);
  635.  
  636. the_current_host_in_whitelist_flag = false;
  637.  
  638. message.success('已设置:<br><br>关闭本网站的广告过滤!');
  639.  
  640. unsafeWindow.location.reload();
  641. });
  642.  
  643. }
  644.  
  645. } else {
  646. if (unsafeWindow.self === unsafeWindow.top) {
  647.  
  648. if (menu_item_host_join === null) {
  649. filter_log('----------------------------还没开启过滤---------------------------');
  650. }
  651.  
  652. menu_item_host_join = GM_registerMenuCommand('本网站已关闭过滤(可点击开启广告过滤)', function() {
  653.  
  654. GM_setValue(the_current_host, true);
  655.  
  656. the_current_host_in_whitelist_flag = true;
  657.  
  658. message.success('已设置:<br><br>开启本网站的广告过滤!');
  659.  
  660. unsafeWindow.location.reload();
  661. });
  662.  
  663. }
  664. }
  665. } else {
  666.  
  667. if (menu_item_host_join === null) {
  668. filter_log('----------------------------脚本加载完成---------------------------');
  669. filter_log('----------------------------还没 hookXHR---------------------------');
  670.  
  671. initHook();
  672. }
  673.  
  674. }
  675. }
  676.  
  677. function check_menu_item_toast() {
  678. if (show_toast_tip_flag) {
  679. if (unsafeWindow.self === unsafeWindow.top) {
  680. menu_item_toast = GM_registerMenuCommand('已开启弹窗提示(可点击设置关闭)', function() {
  681.  
  682. GM_setValue('show_toast_tip_flag', false);
  683.  
  684. show_toast_tip_flag = false;
  685.  
  686. message.success('已设置:<br><br>关闭弹窗提示!');
  687.  
  688. add_menu_item_all();
  689. });
  690. }
  691.  
  692. } else {
  693. if (unsafeWindow.self === unsafeWindow.top) {
  694. menu_item_toast = GM_registerMenuCommand('已关闭弹窗提示(可点击设置开启)', function() {
  695.  
  696. GM_setValue('show_toast_tip_flag', true);
  697.  
  698. show_toast_tip_flag = true;
  699.  
  700. message.success('已设置:<br><br>开启弹窗提示!');
  701.  
  702. add_menu_item_all();
  703. });
  704. }
  705.  
  706. }
  707. }
  708.  
  709. function remove_menu_item_all() {
  710. GM_unregisterMenuCommand(menu_item_violent);
  711. GM_unregisterMenuCommand(menu_item_mode);
  712. GM_unregisterMenuCommand(menu_item_host_join);
  713. GM_unregisterMenuCommand(menu_item_toast);
  714. }
  715.  
  716. function add_menu_item_all() {
  717. remove_menu_item_all();
  718.  
  719. check_menu_item_violent();
  720. check_menu_item_mode();
  721. check_menu_item_host_join();
  722. check_menu_item_toast();
  723. }
  724.  
  725. add_menu_item_all();
  726.  
  727. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址