🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

苹方字体网页替换脚本

将网页字体替换为苹方字体,资源使用外部注入

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name 苹方字体网页替换脚本
// @namespace http://tampermonkey.net/
// @version 1.0
// @author Wolfe
// @description 将网页字体替换为苹方字体,资源使用外部注入
// @match *://*/*
// @run-at document-start
// @grant none
// @license MIT
// ==/UserScript==

(function () {
  "use strict";

  // ======================
  // 配置
  // ======================
  const PROTECTED_TAGS = new Set([
    "script",
    "style",
    "link",
    "meta",
    "noscript",
    "svg",
    "path",
  ]);
  const CODE_TAGS = new Set(["code", "pre", "kbd", "samp", "tt"]);
  const processed = new WeakSet();

  // 字体栈配置 (来自v13.3)
  // [MODIFIED v3] 完整实现 Inter -> PingFang (SC/TC/HK) -> Noto (CJK) 栈
  const UNIFIED_STACK =
    'Inter, "PingFang SC", "PingFang TC", "PingFang HK", "Noto Sans SC", "Noto Sans TC", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR"';

  // [MODIFIED v4] 遵照用户要求:代码字体使用 Maple Mono -> Noto Sans Mono (思源等宽)
  const MONO_STACK = '"Maple Mono", "Noto Sans Mono", "SF Mono"';

  const FONTS = {
    latin: UNIFIED_STACK,
    cjk: UNIFIED_STACK,
    mixed: UNIFIED_STACK,
    mono: MONO_STACK, // <--- MODIFIED
  };

  // CDN配置 (来自v9.7)
  const CONFIG = {
    CDN: {
      PINGFANG: "https://cdn.jsdelivr.net/gh/ZWolken/PingFang/",
      GOOGLE_FONTS: "https://fonts.googleapis.com/css2",
    },
  };

  // ======================
  // FontLoader(来自v9.7 - 字体注入系统)
  // ======================
  class FontLoader {
    constructor() {
      this.loaded = false;
    }

    loadFonts() {
      if (this.loaded) return;
      const style = document.createElement("style");
      style.id = "font-replacement-loader";

      // [INFO] Noto Sans 字体在这里被 @import
      style.textContent = `
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Inter:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Roboto:wght@100;300;400;500;700;900&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Open+Sans:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Lato:wght@100;300;400;700;900&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+SC:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+TC:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+HK:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+JP:[email protected]&display=swap');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+KR:[email protected]&display=swap');

/* [MODIFIED v4] 注入 Maple Mono 和 Noto Sans Mono (思源等宽) */
@import url('https://cdn.jsdelivr.net/npm/maple-mono/maple.css');
@import url('${
        CONFIG.CDN.GOOGLE_FONTS
      }?family=Noto+Sans+Mono:[email protected]&display=swap');

${this.generatePingFangFontFaces()}
`;
      (document.head || document.documentElement).appendChild(style);
      this.loaded = true;
    }

    generatePingFangFontFaces() {
      // [INFO] PingFang SC, TC, HK 字体在这里被 @font-face 注入
      const variants = ["SC", "TC", "HK"];
      const weights = [
        { name: "Thin", weight: 100 },
        { name: "Ultralight", weight: 200 },
        { name: "Light", weight: 300 },
        { name: "Regular", weight: 400 },
        { name: "Medium", weight: 500 },
        { name: "Semibold", weight: 600 },
        { name: "Semibold", weight: 700 },
        { name: "Heavy", weight: 800 },
        { name: "Heavy", weight: 900 },
      ];
      const cjkUnicodeRange =
        "U+2E80-2EFF, U+3000-303F, U+3040-309F, U+30A0-30FF, U+3100-312F, U+3130-318F, U+3190-319F, U+31A0-31BF, U+31C0-31EF, U+31F0-31FF, U+3200-32FF, U+3300-33FF, U+3400-4DBF, U+4DC0-4DFF, U+4E00-9FFF, U+A000-A48F, U+A490-A4CF, U+AC00-D7AF, U+F900-FAFF, U+FE30-FE4F, U+FF00-FFEF, U+20000-2A6DF, U+2A700-2B73F, U+2B740-2B81F, U+2B820-2CEAF, U+2CEB0-2EBEF, U+30000-3134F";
      let css = "";
      variants.forEach((variant) => {
        weights.forEach((style) => {
          css += `
@font-face {
    font-family: 'PingFang ${variant}';
    src: url('${CONFIG.CDN.PINGFANG}PingFang${variant}-${style.name}.otf') format('opentype');
    font-weight: ${style.weight};
    font-style: normal;
    font-display: swap;
    unicode-range: ${cjkUnicodeRange};
}
`;
        });
      });
      return css;
    }
  }

  // ======================
  // 快速文本类型检测(保留,但逻辑中已不再依赖其区分cjk/latin)
  // ======================
  function getTextType(text) {
    if (!text || text.length === 0) return "empty";
    const sample = text.substring(0, 30);
    const hasLatin = /[a-zA-Z]/.test(sample);
    const hasCJK =
      /[\u4e00-\u9fff\u3000-\u303f\u3040-\u309f\u30a0-\u30ff]/.test(sample);

    if (!hasLatin && !hasCJK) return "empty";
    if (hasLatin && !hasCJK) return "latin";
    if (!hasLatin && hasCJK) return "cjk";

    const latinCount = (sample.match(/[a-zA-Z]/g) || []).length;
    const cjkCount = (sample.match(/[\u4e00-\u9fff]/g) || []).length;
    if (cjkCount < latinCount * 0.3) return "latin";

    return "mixed";
  }

  // ======================
  // 处理元素(核心函数)
  // ======================
  function processElement(el) {
    if (processed.has(el)) return;

    const tag = el.tagName?.toLowerCase();
    if (!tag || PROTECTED_TAGS.has(tag)) {
      processed.add(el);
      return;
    }

    if (tag === "i") {
      processed.add(el);
      return;
    }

    const className = el.className;
    if (className && typeof className === "string") {
      if (/icon|fa-|fa\s|glyph|emoji|symbol/i.test(className)) {
        processed.add(el);
        return;
      }
    }

    const text = el.textContent?.trim();
    if (text && text.length <= 2) {
      const code = text.charCodeAt(0);
      if (
        (code >= 0xe000 && code <= 0xf8ff) ||
        (code >= 0x2600 && code <= 0x27bf) ||
        code >= 0x1f000
      ) {
        processed.add(el);
        return;
      }
    }

    // 确定字体类型
    let fontStack;

    // [INFO] 统一使用 FONTS.mixed (指向 UNIFIED_STACK)
    if (CODE_TAGS.has(tag)) {
      fontStack = FONTS.mono; // <--- MODIFIED: 将使用新的 MONO_STACK
    } else {
      fontStack = FONTS.mixed;
    }

    // 直接应用样式
    if (fontStack) {
      // [INFO] 保留 !important 强制覆盖
      el.style.setProperty("font-family", fontStack, "important");
      el.style.setProperty("text-rendering", "optimizeLegibility", "important");
      el.style.setProperty(
        "-webkit-font-smoothing",
        "antialiased",
        "important"
      );
    }
    processed.add(el);
  }

  // ======================
  // 处理所有元素
  // ======================
  function processAll() {
    const elements = document.getElementsByTagName("*");
    for (let i = 0; i < elements.length; i++) {
      processElement(elements[i]);
    }
    processShadowRoots();
  }

  // ======================
  // 处理Shadow DOM
  // ======================
  function processShadowRoots() {
    const elements = document.querySelectorAll("*");
    for (let el of elements) {
      if (el.shadowRoot) {
        const shadowElements = el.shadowRoot.querySelectorAll("*");
        for (let shadowEl of shadowElements) {
          processElement(shadowEl);
        }
      }
    }
  }

  // ======================
  // MutationObserver
  // ======================
  function setupObserver() {
    let pending = [];
    let scheduled = false;

    const processPending = () => {
      scheduled = false;
      processShadowRoots();
      for (let el of pending) {
        processElement(el);
      }
      pending = [];
    };

    const observer = new MutationObserver((mutations) => {
      for (let mutation of mutations) {
        if (mutation.addedNodes.length) {
          for (let node of mutation.addedNodes) {
            if (node.nodeType === 1) {
              pending.push(node);
              const children = node.getElementsByTagName?.("*");
              if (children) {
                for (let child of children) {
                  pending.push(child);
                }
              }
            }
          }
        }
      }

      if (pending.length && !scheduled) {
        scheduled = true;
        if (window.requestIdleCallback) {
          requestIdleCallback(processPending, { timeout: 50 });
        } else {
          setTimeout(processPending, 0);
        }
      }
    });

    observer.observe(document.documentElement, {
      childList: true,
      subtree: true,
    });
  }

  // ======================
  // 初始化
  // ======================
  const fontLoader = new FontLoader();

  function init() {
    fontLoader.loadFonts();
    processAll();
    setupObserver();

    setInterval(processAll, 5000);

    setInterval(() => {
      const iframes = document.querySelectorAll("iframe");
      for (let iframe of iframes) {
        try {
          const doc = iframe.contentDocument || iframe.contentWindow?.document;
          if (doc && !doc.__fontPatched) {
            doc.__fontPatched = true;
            const elements = doc.getElementsByTagName("*");
            for (let el of elements) {
              processElement(el);
            }
          }
        } catch (e) {
          // 跨域
        }
      }
    }, 3000);
  }

  if (document.body || document.documentElement) {
    init();
  } else {
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", init);
    } else {
      init();
    }
  }

  window.__fontEngine = {
    processAll: processAll,
    processElement: processElement,
    reload: () => {
      processed.clear();
      processAll();
    },
  };

  console.log(
    "[Font v13.3.4-Modified] Initialized with full font stack (Inter -> PingFang -> Noto) and Code (Maple -> Noto Mono)."
  );
})();