Via Css 检验

用于检验Via的Adblock规则中的Css隐藏规则是否有错误的规则,支持自动运行和菜单操作。

目前为 2025-03-09 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Via Css 检验
  3. // @namespace https://viayoo.com/
  4. // @version 2.6
  5. // @license MIT
  6. // @description 用于检验Via的Adblock规则中的Css隐藏规则是否有错误的规则,支持自动运行和菜单操作。
  7. // @author Copilot
  8. // @run-at document-end
  9. // @match *://*/*
  10. // @grant GM_registerMenuCommand
  11. // @require https://cdn.jsdelivr.net/npm/js-beautify@1.14.0/js/lib/beautify-css.js
  12. // @require https://cdn.jsdelivr.net/npm/css-tree@2.3.1/dist/csstree.min.js
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // 获取CSS文件URL
  19. function getCssFileUrl() {
  20. const currentHost = window.location.hostname;
  21. return `https://${currentHost}/via_inject_blocker.css`;
  22. }
  23.  
  24. // 使用 js-beautify 格式化CSS内容
  25. function formatCssWithJsBeautify(rawCss) {
  26. try {
  27. return css_beautify(rawCss, {
  28. indent_size: 2,
  29. selector_separator_newline: true
  30. });
  31. } catch (error) {
  32. console.error(`CSS格式化失败:${error.message}`);
  33. return null;
  34. }
  35. }
  36.  
  37. // 截断错误行以限制字符数
  38. function truncateErrorLine(errorLine, maxLength = 150) {
  39. if (errorLine.length > maxLength) {
  40. return errorLine.substring(0, maxLength) + "..."; // 添加省略号表示截断
  41. }
  42. return errorLine;
  43. }
  44.  
  45. // 读取并格式化CSS内容
  46. async function fetchAndFormatCss() {
  47. const url = getCssFileUrl();
  48. try {
  49. const response = await fetch(url);
  50. if (!response.ok) {
  51. throw new Error(`无法获取CSS文件:${response.statusText}`);
  52. }
  53. const rawCss = await response.text();
  54. return formatCssWithJsBeautify(rawCss);
  55. } catch (error) {
  56. console.error(`无法获取或格式化CSS文件:${error.message}`);
  57. return null;
  58. }
  59. }
  60.  
  61. // 翻译错误信息为中文
  62. function translateErrorMessage(englishMessage) {
  63. const translations = {
  64. "Identifier is expected": "需要标识符",
  65. "Unexpected end of input": "输入意外结束",
  66. "Selector is expected": "需要选择器",
  67. "Invalid character": "无效字符",
  68. "Unexpected token": "意外的标记",
  69. '"]" is expected': '需要 "]"',
  70. '"{" is expected': '需要 "{"',
  71. 'Unclosed block': '未闭合的块',
  72. 'Unclosed string': '未闭合的字符串',
  73. 'Property is expected': '需要属性名',
  74. 'Value is expected': '需要属性值',
  75. "Percent sign is expected": "需要百分号 (%)",
  76. 'Attribute selector (=, ~=, ^=, $=, *=, |=) is expected': '需要属性选择器运算符(=、~=、^=、$=、*=、|=)',
  77. 'Semicolon is expected': '需要分号 ";"',
  78. 'Number is expected': '需要数字',
  79. 'Colon is expected': '需要冒号 ":"'
  80. };
  81. return translations[englishMessage] || `${englishMessage}`;
  82. }
  83.  
  84. // 验证格式化后的CSS内容
  85. function validateCss(formattedCss, isAutoRun = false) {
  86. if (!formattedCss) return;
  87.  
  88. let hasError = false;
  89. const errors = [];
  90. const lines = formattedCss.split('\n'); // 将格式化的CSS按行分割
  91.  
  92. try {
  93. csstree.parse(formattedCss, {
  94. onParseError(error) {
  95. hasError = true;
  96.  
  97. // 获取并截断错误的具体片段
  98. const errorLine = lines[error.line - 1] || "无法提取错误行";
  99. const truncatedErrorLine = truncateErrorLine(errorLine);
  100.  
  101. // 翻译错误信息
  102. const translatedMessage = translateErrorMessage(error.message);
  103.  
  104. const errorMessage = `
  105. CSS 解析错误:
  106. - 位置:第 ${error.line}
  107. - 错误信息:${translatedMessage}
  108. - 错误片段:${truncatedErrorLine}
  109. `.trim();
  110. errors.push(errorMessage);
  111. }
  112. });
  113.  
  114. if (hasError) {
  115. if (isAutoRun) {
  116. alert(errors.join('\n\n'));
  117. }
  118. } else if (!isAutoRun) {
  119. alert("CSS验证通过:未发现错误。");
  120. }
  121. } catch (error) {
  122. const translatedMessage = translateErrorMessage(error.message);
  123. if (isAutoRun) {
  124. console.error(`自动运行时CSS验证失败:${translatedMessage}`);
  125. } else {
  126. alert(`CSS验证失败:${translatedMessage}`);
  127. }
  128. }
  129. }
  130.  
  131. // 自动运行逻辑
  132. async function autoRunCssValidation() {
  133. const formattedCss = await fetchAndFormatCss();
  134. if (formattedCss) {
  135. validateCss(formattedCss, true); // 自动运行时传递 true
  136. }
  137. }
  138.  
  139. // 注册菜单
  140. GM_registerMenuCommand("验证CSS文件", async () => {
  141. const formattedCss = await fetchAndFormatCss();
  142. if (formattedCss) {
  143. validateCss(formattedCss, false); // 手动运行时传递 false
  144. }
  145. });
  146.  
  147. // 触发自动运行
  148. autoRunCssValidation();
  149.  
  150. })();