我家在... 改

自动修改淘宝/天猫/京东等购物页面的"配送至"地址,在你分享商品截图的时候保护隐私。

// ==UserScript==
// @name         我家在... 改
// @namespace    https://114514.plus/
// @version      0.2.1
// @description  自动修改淘宝/天猫/京东等购物页面的"配送至"地址,在你分享商品截图的时候保护隐私。
// @author       jkfujr
// @match        https://www.jd.com/*
// @match        https://item.jd.com/*.html*
// @match        https://cart.jd.com/cart_index*
// @match        https://npcitem.jd.hk/*.html*
// @match        https://*.detail.tmall.com/item.htm*
// @match        https://*.detail.tmall.hk/hk/item.htm*
// @match        https://item.taobao.com/item.htm*
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @license      GNU GPLv3
// ==/UserScript==

(function () {
  "use strict";

  // 初始化
  if (GM_getValue("addressSpoofingEnabled") === undefined) {
    GM_setValue("addressSpoofingEnabled", true);
  }
  if (GM_getValue("fakeAddress1") === undefined) {
    GM_setValue("fakeAddress1", "日本");
  }
  if (GM_getValue("fakeAddress2") === undefined) {
    GM_setValue("fakeAddress2", "下北沢");
  }
  if (GM_getValue("addressSpoofingDelay") === undefined) {
    GM_setValue("addressSpoofingDelay", 2500);
  }

  // 获取设置
  var addressSpoofingEnabled = GM_getValue("addressSpoofingEnabled");
  var fakeAddress1 = GM_getValue("fakeAddress1");
  var fakeAddress2 = GM_getValue("fakeAddress2");
  var addressSpoofingDelay = GM_getValue("addressSpoofingDelay");

  // 菜单
  function registerMenu() {
    if (window.toggleMenuCommand)
      GM_unregisterMenuCommand(window.toggleMenuCommand);
    if (window.addressEditCommand)
      GM_unregisterMenuCommand(window.addressEditCommand);
    if (window.delayCommand) GM_unregisterMenuCommand(window.delayCommand);
    var menuText = (addressSpoofingEnabled ? "✅ " : "❌ ") + "地址伪装";
    window.toggleMenuCommand = GM_registerMenuCommand(menuText, function () {
      addressSpoofingEnabled = !addressSpoofingEnabled;
      GM_setValue("addressSpoofingEnabled", addressSpoofingEnabled);
      registerMenu();
      location.reload();
    });

    window.addressEditCommand = GM_registerMenuCommand(
      "✏️ 地址修改",
      function () {
        var address1 = prompt("请输入主要地址 (如省份/国家):", fakeAddress1);
        if (address1 !== null) {
          fakeAddress1 = address1 || "日本";
          GM_setValue("fakeAddress1", fakeAddress1);

          var address2 = prompt("请输入次要地址 (如城市/地区):", fakeAddress2);
          if (address2 !== null) {
            fakeAddress2 = address2 || "下北沢";
            GM_setValue("fakeAddress2", fakeAddress2);
            registerMenu();
            location.reload();
          }
        }
      }
    );

    window.delayCommand = GM_registerMenuCommand(`⏱️ 伪装延迟`, function () {
      var delay = prompt("请输入伪装延迟时间 (毫秒):", addressSpoofingDelay);
      if (delay !== null) {
        addressSpoofingDelay = parseInt(delay) || 2500;
        GM_setValue("addressSpoofingDelay", addressSpoofingDelay);
        registerMenu();
      }
    });
  }

  registerMenu();

  function replaceAddresses() {
    switch (window.location.host) {
      case "item.jd.com":
      case "npcitem.jd.hk":
      case "www.jd.com": {
        // 商品页
        var jdAddressElement = document.querySelector(".ui-area-text");
        if (jdAddressElement) {
          var replacementText = fakeAddress1 + " " + fakeAddress2;
          if (jdAddressElement.innerText !== replacementText) {
            jdAddressElement.innerText = replacementText;
            if (jdAddressElement.hasAttribute("title")) {
              jdAddressElement.title = replacementText;
            }
          }
        }

        // 导航栏地址(商品页和首页)
        var navSelectors = [".ui-areamini-text", ".ui-areamini-text-wrap .ui-areamini-text"];
        navSelectors.forEach(function(selector) {
          var navElement = document.querySelector(selector);
          if (navElement) {
            var navReplacementText = "京东全球版 - " + fakeAddress1;
            if (navElement.innerText !== navReplacementText) {
              navElement.innerText = navReplacementText;
              if (navElement.hasAttribute("title")) {
                navElement.title = navReplacementText;
              }
            }
          }
        });
        break;
      }
      case "cart.jd.com": {
        if (window.location.pathname === "/cart_index") {
          var jdCartAddressElement = document.querySelector(".ui-area-text");
          if (jdCartAddressElement) {
            var replacementText = fakeAddress1 + " " + fakeAddress2;
            if (jdCartAddressElement.innerText !== replacementText) {
              jdCartAddressElement.innerText = replacementText;
              if (jdCartAddressElement.hasAttribute("title")) {
                jdCartAddressElement.title = replacementText;
              }
            }
          }
        }
        break;
      }
      case "detail.tmall.com":
      case "detail.tmall.hk":
      case "chaoshi.detail.tmall.com":
      case "item.taobao.com": {
        var taobaoAddressElement = null;
        var addrWrap = document.querySelector("[class*='deliveryAddrWrap']");
        if (addrWrap) {
          var spanElement = addrWrap.querySelector("span");
          if (spanElement && spanElement.textContent.includes("至")) {
            taobaoAddressElement = spanElement;
          }
        }
        if (!taobaoAddressElement) {
          var allSpans = document.querySelectorAll("span");
          for (var i = 0; i < allSpans.length; i++) {
            var span = allSpans[i];
            var text = span.textContent.trim();
            if (text.includes("至") && text.length < 50) {
              taobaoAddressElement = span;
              break;
            }
          }
        }

        // 旧版本
        if (!taobaoAddressElement) {
          taobaoAddressElement = document.querySelector(
            "[class*='--select-trigger--']"
          );
        }

        if (taobaoAddressElement) {
          var originalText = taobaoAddressElement.textContent.trim();
          var replacementText;

          if (originalText.includes("至")) {
            var parts = originalText.split("至");
            if (parts.length > 1) {
              var targetAddr = parts[1].trim();
              if (targetAddr.includes(" ")) {
                replacementText =
                  parts[0].trim() + " 至 " + fakeAddress1 + " " + fakeAddress2;
              } else {
                replacementText = parts[0].trim() + " 至 " + fakeAddress1;
              }
            } else {
              replacementText = fakeAddress1;
            }
          } else {
            // 兼容
            if (originalText.includes(" ") || originalText.length > 3) {
              replacementText = fakeAddress1 + " " + fakeAddress2;
            } else {
              replacementText = fakeAddress1;
            }
          }

          if (taobaoAddressElement.textContent.trim() !== replacementText) {
            taobaoAddressElement.textContent = replacementText;
            if (taobaoAddressElement.hasAttribute("title")) {
              taobaoAddressElement.title = replacementText;
            }
          }
        }
        break;
      }
    }
  }

  if (addressSpoofingEnabled) {
    setTimeout(replaceAddresses, addressSpoofingDelay);

    // 监听DOM变化,处理地址
    var observer = new MutationObserver(function (mutations) {
      var shouldReplace = false;
      mutations.forEach(function (mutation) {
        if (
          mutation.type === "childList" ||
          mutation.type === "characterData"
        ) {
          var target = mutation.target;
          if (
            target.classList &&
            (target.classList.contains("ui-area-text") ||
              target.classList.contains("ui-areamini-text") ||
              target.className.includes("deliveryAddrWrap") ||
              target.className.includes("select-trigger"))
          ) {
            shouldReplace = true;
          }
          var parent = target.parentElement;
          if (
            parent &&
            parent.classList &&
            (parent.classList.contains("ui-area-text") ||
              parent.classList.contains("ui-areamini-text") ||
              parent.className.includes("deliveryAddrWrap"))
          ) {
            shouldReplace = true;
          }
        }
      });

      if (shouldReplace) {
        setTimeout(replaceAddresses, 100);
      }
    });

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