Greasy Fork is available in English.

steam价格转换

steam商店中的价格转换为人民币

// ==UserScript==
// @name         steam价格转换
// @namespace    https://github.com/marioplus/steam-price-converter
// @version      2.5.4
// @author       marioplus
// @description  steam商店中的价格转换为人民币
// @license      GPL-3.0-or-later
// @icon         https://vitejs.dev/logo.svg
// @homepage     https://github.com/marioplus
// @match        https://store.steampowered.com/*
// @match        https://steamcommunity.com/*
// @match        https://checkout.steampowered.com/checkout/*
// @require      https://cdn.jsdelivr.net/npm/mdui@2.1.1/mdui.global.min.js
// @require      https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js
// @resource     mdui/mdui.css  https://cdn.jsdelivr.net/npm/mdui@2.1.1/mdui.css
// @connect      api.augmentedsteam.com
// @connect      store.steampowered.com
// @connect      cdn.jsdelivr.net
// @grant        GM_addStyle
// @grant        GM_addValueChangeListener
// @grant        GM_cookie
// @grant        GM_deleteValue
// @grant        GM_getResourceText
// @grant        GM_getValue
// @grant        GM_info
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// ==/UserScript==

(e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const t=document.createElement("style");t.textContent=e,document.head.append(t)})(" div.home_tabs_content .tab_item_discount{width:185px}.search_result_row .col.search_name{width:240px}.search_result_row .col.search_released{width:105px}.search_result_row .col.search_discount_and_price .discount_block{width:165px}#popularItemsTable .market_listing_table_header .market_listing_their_price{width:130px}#popularItemsTable .market_listing_row_link>.market_listing_row .market_listing_right_cell.market_listing_their_price{width:130px}.setting-item[data-v-34f99f99]{color:rgb(var(--mdui-color-on-surface));padding:1em .75em;min-width:33em}.setting-item-title[data-v-34f99f99]{display:flex;align-items:center;padding:8px 0}.setting-item-title label[data-v-34f99f99]{display:inline-block;padding-right:.4em;font-size:var(--mdui-typescale-body-large-size);font-weight:var(--mdui-typescale-body-medium-weight);letter-spacing:var(--mdui-typescale-body-medium-tracking);line-height:var(--mdui-typescale-body-medium-line-height)}.setting-item-title .setting-region-title-icon[data-v-34f99f99]{font-size:var(--mdui-typescale-body-large-size)}mdui-select[data-v-34f99f99]::part(menu){max-height:256px;overflow:auto}mdui-text-field[data-v-34f99f99]::part(suffix){color:#00f} ");

(function (mdui, vue) {
  'use strict';

  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => {
    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
    return value;
  };
  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("mdui/mdui.css");
  const STORAGE_KEY_PREFIX = "Storage:";
  const STORAGE_KEY_RATE_CACHES = STORAGE_KEY_PREFIX + "RateCache";
  const STORAGE_KEY_SETTING = STORAGE_KEY_PREFIX + "Setting";
  const IM_MENU_SETTING = "设置";
  class Attrs {
  }
  __publicField(Attrs, "STATUS_KEY", "data-spc-status");
  __publicField(Attrs, "STATUS_CONVERTED", "converted");
  class AbstractConverter {
    /**
     * 匹配到的元素,是否匹配这个 exchanger
     * @param elementSnap 选择器选择到的元素快照
     */
    match(elementSnap) {
      if (!elementSnap || !elementSnap.element) {
        return false;
      }
      const status = elementSnap.element.getAttribute(Attrs.STATUS_KEY);
      const converted = Attrs.STATUS_CONVERTED === status;
      if (converted) {
        return false;
      }
      const content = elementSnap.textContext;
      if (!content) {
        return false;
      }
      if (content.match(/\d/) === null) {
        return false;
      }
      if (/^[,.\d\s]+$/.test(content)) {
        return false;
      }
      const parent = elementSnap.element.parentElement;
      if (!parent) {
        return false;
      }
      for (const selector of this.getCssSelectors()) {
        const element = parent.querySelector(selector);
        if (element && element === elementSnap.element) {
          elementSnap.selector = selector;
          return true;
        }
      }
      return false;
    }
    /**
     * 替换之后的操作
     * @param elementSnap 选择器选择到的元素快照
     */
    // @ts-ignore
    afterConvert(elementSnap) {
      elementSnap.element.setAttribute(Attrs.STATUS_KEY, Attrs.STATUS_CONVERTED);
    }
  }
  class Setting {
    constructor() {
      /**
       * 目标国家代码,默认CN
       */
      __publicField(this, "countyCode", "CN");
      /**
       * 目标货币符号,默认 ¥
       */
      __publicField(this, "currencySymbol", "¥");
      /**
       * 符号位置在首
       */
      __publicField(this, "currencySymbolBeforeValue", true);
      /**
       * 汇率获取时间,默认1小时
       */
      __publicField(this, "rateCacheExpired", 1e3 * 60 * 60);
      /**
       * 使用自定义汇率
       */
      __publicField(this, "useCustomRate", false);
      /**
       * 自定义汇率
       */
      __publicField(this, "customRate", 1);
      /**
       * 前一个版本
       */
      __publicField(this, "oldVersion", "0.0.0");
      /**
       * 当前版本
       */
      __publicField(this, "currVersion", "0.0.0");
      /**
       * 日志级别
       */
      __publicField(this, "logLevel", "info");
    }
  }
  const countyObjs = [
    {
      code: "AE",
      currencyCode: "AED",
      name: "阿联酋",
      nameEn: "United Arab Emirates"
    },
    {
      code: "AU",
      currencyCode: "AUD",
      name: "澳大利亚",
      nameEn: "Australia"
    },
    {
      code: "BR",
      currencyCode: "BRL",
      name: "巴西",
      nameEn: "Brazil"
    },
    {
      code: "CA",
      currencyCode: "CAD",
      name: "加拿大",
      nameEn: "Canada"
    },
    {
      code: "CH",
      currencyCode: "CHF",
      name: "瑞士",
      nameEn: "Switzerland"
    },
    {
      code: "CL",
      currencyCode: "CLP",
      name: "智利",
      nameEn: "Chile"
    },
    {
      code: "CN",
      currencyCode: "CNY",
      name: "中国",
      nameEn: "China"
    },
    {
      code: "CO",
      currencyCode: "COP",
      name: "哥伦比亚",
      nameEn: "Colombia"
    },
    {
      code: "CR",
      currencyCode: "CRC",
      name: "哥斯达黎加",
      nameEn: "Costa Rica"
    },
    {
      code: "AD",
      currencyCode: "EUR",
      name: "安道尔",
      nameEn: "Andorra"
    },
    {
      code: "DE",
      currencyCode: "EUR",
      name: "德国",
      nameEn: "Germany"
    },
    {
      code: "EE",
      currencyCode: "EUR",
      name: "爱沙尼亚",
      nameEn: "Estonia"
    },
    {
      code: "ES",
      currencyCode: "EUR",
      name: "西班牙",
      nameEn: "Spain"
    },
    {
      code: "FR",
      currencyCode: "EUR",
      name: "法国",
      nameEn: "France"
    },
    {
      code: "IT",
      currencyCode: "EUR",
      name: "意大利",
      nameEn: "Italy"
    },
    {
      code: "LT",
      currencyCode: "EUR",
      name: "立陶宛",
      nameEn: "Lithuania"
    },
    {
      code: "LU",
      currencyCode: "EUR",
      name: "卢森堡",
      nameEn: "Luxembourg"
    },
    {
      code: "LV",
      currencyCode: "EUR",
      name: "拉脱维亚",
      nameEn: "Latvia"
    },
    {
      code: "MC",
      currencyCode: "EUR",
      name: "摩纳哥",
      nameEn: "Monaco"
    },
    {
      code: "ME",
      currencyCode: "EUR",
      name: "黑山",
      nameEn: "Montenegro"
    },
    {
      code: "SI",
      currencyCode: "EUR",
      name: "斯洛文尼亚",
      nameEn: "Slovenia"
    },
    {
      code: "SK",
      currencyCode: "EUR",
      name: "斯洛伐克",
      nameEn: "Slovakia"
    },
    {
      code: "SM",
      currencyCode: "EUR",
      name: "圣马力诺",
      nameEn: "San Marino"
    },
    {
      code: "VA",
      currencyCode: "EUR",
      name: "梵蒂冈",
      nameEn: "Holy See"
    },
    {
      code: "GB",
      currencyCode: "GBP",
      name: "英国",
      nameEn: "United Kingdom"
    },
    {
      code: "HK",
      currencyCode: "HKD",
      name: "中国香港",
      nameEn: "Hong Kong"
    },
    {
      code: "ID",
      currencyCode: "IDR",
      name: "印度尼西亚",
      nameEn: "Indonesia"
    },
    {
      code: "IL",
      currencyCode: "ILS",
      name: "以色列",
      nameEn: "Israel"
    },
    {
      code: "IN",
      currencyCode: "INR",
      name: "印度",
      nameEn: "India"
    },
    {
      code: "JP",
      currencyCode: "JPY",
      name: "日本",
      nameEn: "Japan"
    },
    {
      code: "KR",
      currencyCode: "KRW",
      name: "韩国",
      nameEn: "South Korea"
    },
    {
      code: "KW",
      currencyCode: "KWD",
      name: "科威特",
      nameEn: "Kuwait"
    },
    {
      code: "KZ",
      currencyCode: "KZT",
      name: "哈萨克斯坦",
      nameEn: "Kazakhstan"
    },
    {
      code: "MX",
      currencyCode: "MXN",
      name: "墨西哥",
      nameEn: "Mexico"
    },
    {
      code: "MY",
      currencyCode: "MYR",
      name: "马来西亚",
      nameEn: "Malaysia"
    },
    {
      code: "NO",
      currencyCode: "NOK",
      name: "挪威",
      nameEn: "Norway"
    },
    {
      code: "NZ",
      currencyCode: "NZD",
      name: "新西兰",
      nameEn: "New Zealand"
    },
    {
      code: "PE",
      currencyCode: "PEN",
      name: "秘鲁",
      nameEn: "Peru"
    },
    {
      code: "PH",
      currencyCode: "PHP",
      name: "菲律宾",
      nameEn: "Philippines"
    },
    {
      code: "PL",
      currencyCode: "PLN",
      name: "波兰",
      nameEn: "Poland"
    },
    {
      code: "QA",
      currencyCode: "QAR",
      name: "卡塔尔",
      nameEn: "Qatar"
    },
    {
      code: "RU",
      currencyCode: "RUB",
      name: "俄罗斯",
      nameEn: "Russia"
    },
    {
      code: "SA",
      currencyCode: "SAR",
      name: "沙特阿拉伯",
      nameEn: "Saudi Arabia"
    },
    {
      code: "SG",
      currencyCode: "SGD",
      name: "新加坡",
      nameEn: "Singapore"
    },
    {
      code: "TH",
      currencyCode: "THB",
      name: "泰国",
      nameEn: "Thailand"
    },
    {
      code: "TW",
      currencyCode: "TWD",
      name: "中国台湾",
      nameEn: "Taiwan"
    },
    {
      code: "UA",
      currencyCode: "UAH",
      name: "乌克兰",
      nameEn: "Ukraine"
    },
    {
      code: "AR",
      currencyCode: "USD",
      name: "阿根廷",
      nameEn: "Argentina"
    },
    {
      code: "AZ",
      currencyCode: "USD",
      name: "阿塞拜疆",
      nameEn: "Azerbaijan"
    },
    {
      code: "PK",
      currencyCode: "USD",
      name: "巴基斯坦",
      nameEn: "Pakistan"
    },
    {
      code: "TR",
      currencyCode: "USD",
      name: "土耳其",
      nameEn: "Turkey"
    },
    {
      code: "US",
      currencyCode: "USD",
      name: "美国",
      nameEn: "United States"
    },
    {
      code: "ZA",
      currencyCode: "USD",
      name: "南非",
      nameEn: "South Africa"
    },
    {
      code: "UY",
      currencyCode: "UYU",
      name: "乌拉圭",
      nameEn: "Uruguay"
    },
    {
      code: "VN",
      currencyCode: "VND",
      name: "越南",
      nameEn: "Vietnam"
    }
  ];
  class Jsons {
    /**
     * 将对象转换为普通 JSON 对象
     */
    static toJson(obj) {
      return { ...obj };
    }
    /**
     * 将对象转换为 JSON 字符串
     */
    static toString(obj) {
      return JSON.stringify(this.toJson(obj));
    }
    /**
     * 将普通 JSON 对象解析为指定类型,支持嵌套处理,包括 Map 和 Record 中的 class
     */
    static readJson(json, cls) {
      if (!cls) {
        if (typeof json !== "object" || json === null) {
          throw new Error("Invalid JSON input");
        }
        return json;
      }
      const instance = new cls();
      if (instance instanceof Map) {
        return this.handleMap(json, instance);
      }
      for (const key of Reflect.ownKeys(json)) {
        const value = json[key];
        if (value === null || value === void 0) {
          instance[key] = value;
          continue;
        }
        const fieldValue = instance[key];
        if (fieldValue !== null && typeof fieldValue === "object" && !(fieldValue instanceof Array)) {
          if (fieldValue instanceof Map) {
            instance[key] = this.handleMap(value, fieldValue);
          } else if (fieldValue instanceof Object) {
            instance[key] = this.readJson(value, fieldValue.constructor);
          }
        } else if (Array.isArray(fieldValue)) {
          instance[key] = value.map(
            (item) => {
              var _a;
              return typeof item === "object" ? this.readJson(item, (_a = fieldValue[0]) == null ? void 0 : _a.constructor) : item;
            }
          );
        } else {
          instance[key] = value;
        }
      }
      return instance;
    }
    /**
     * 处理 Map 类型的转换,其中 V 可以是一个 class
     */
    static handleMap(value, mapInstance) {
      const map = /* @__PURE__ */ new Map();
      if (value && typeof value === "object") {
        for (const key of Object.keys(value)) {
          const mapValue = value[key];
          if (mapValue === null || mapValue === void 0) {
            map.set(key, mapValue);
            continue;
          }
          const existingValue = mapInstance.get(key);
          if (this.isObject(mapValue) && existingValue) {
            map.set(key, this.readJson(mapValue, existingValue.constructor));
          } else {
            map.set(key, mapValue);
          }
        }
      }
      return map;
    }
    static isObject(value) {
      return value !== null && typeof value === "object";
    }
    /**
     * 将 JSON 字符串解析为指定类型,支持嵌套处理,包括 Map 和 Record 中的 class
     */
    static readString(jsonString, cls) {
      const json = JSON.parse(jsonString);
      return this.readJson(json, cls);
    }
  }
  const countyInfos = Jsons.readJson(countyObjs, Array);
  const countyCode2Info = new Map(countyInfos.map((v) => [v.code, v]));
  var _GM_addValueChangeListener = /* @__PURE__ */ (() => typeof GM_addValueChangeListener != "undefined" ? GM_addValueChangeListener : void 0)();
  var _GM_cookie = /* @__PURE__ */ (() => typeof GM_cookie != "undefined" ? GM_cookie : void 0)();
  var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
  var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  function initializeLogTitle() {
    const isInIFrame = window.parent !== window || window.frames.length > 0;
    return isInIFrame ? `steam-price-convertor iframe(${(/* @__PURE__ */ new Date()).getMilliseconds()})` : "steam-price-convertor";
  }
  function createLogStyle(color) {
    return `
            background: ${color};
            color: white;
            padding: 1px 3px;
            border-radius: 2px;
        `;
  }
  function composeLogHint() {
    return `%c${initializeLogTitle()}`;
  }
  const LogDefinitions = {
    debug: {
      index: 0,
      color: "#009688",
      label: "debug",
      bindMethod: console.info
    },
    info: {
      index: 1,
      color: "#2196f3",
      label: "info",
      bindMethod: console.info
    },
    warn: {
      index: 2,
      color: "#ffc107",
      label: "warn",
      bindMethod: console.warn
    },
    error: {
      index: 3,
      color: "#e91e63",
      label: "error",
      bindMethod: console.error
    },
    off: {
      index: 4,
      color: "",
      label: "off",
      bindMethod: () => {
      }
    }
  };
  const Logger = {
    debug: noopLog.bind(null),
    info: noopLog.bind(null),
    warn: noopLog.bind(null),
    error: noopLog.bind(null)
  };
  function noopLog() {
  }
  let currLogLevel = LogDefinitions.info;
  function refreshBinding() {
    const hint = composeLogHint();
    Object.entries(LogDefinitions).forEach(([label, def]) => {
      if (def.index >= currLogLevel.index) {
        const logStyle = createLogStyle(def.color);
        Logger[label.toLowerCase()] = def.bindMethod.bind(console, hint, logStyle);
      } else {
        Logger[label.toLowerCase()] = noopLog.bind(null);
      }
    });
  }
  function setLogLevel(levelLabel) {
    const newLevel = LogDefinitions[levelLabel];
    if (newLevel) {
      currLogLevel = newLevel;
      refreshBinding();
    } else {
      console.error(`Invalid log level: ${levelLabel}`);
    }
  }
  refreshBinding();
  class Strings {
    static format(format, ...args) {
      args = args || [];
      let message = format;
      for (let arg of args) {
        message = message.replace("%s", arg);
      }
      return message;
    }
  }
  class GmUtils {
    static getValue(cls, key, defaultValue) {
      const value = _GM_getValue(key);
      return value ? Jsons.readString(value, cls) : defaultValue;
    }
    static setValue(key, value) {
      _GM_setValue(key, Jsons.toString(value));
    }
    static deleteValue(key) {
      _GM_deleteValue(key);
    }
    static registerMenuCommand(caption, onClick, accessKey) {
      const key = `GM_registerMenuCommand@${caption}`;
      _GM_registerMenuCommand(
        caption,
        (event) => {
          this.setValue(key, true);
          Logger.debug("点击菜单:" + caption);
          this.setValue(key, false);
          if (onClick) {
            onClick(event);
          }
        },
        accessKey
      );
    }
    static addMenuClickEventListener(caption, onClick) {
      const key = `GM_registerMenuCommand@${caption}`;
      _GM_addValueChangeListener(key, (name, oldValue, newValue) => {
        if (newValue) {
          onClick();
        }
      });
    }
  }
  const _SettingManager = class _SettingManager {
    constructor() {
      __publicField(this, "setting");
      this.setting = this.loadSetting();
    }
    loadSetting() {
      const setting = GmUtils.getValue(Setting, STORAGE_KEY_SETTING, new Setting());
      setting.oldVersion = setting.currVersion;
      setting.currVersion = _GM_info.script.version;
      if (setting.oldVersion === setting.currVersion) {
        Logger.info("读取设置", setting);
      } else {
        Logger.debug(Strings.format(`版本更新重置设置:%s -> %s`, setting.oldVersion, setting.currVersion));
        this.saveSetting(setting);
      }
      return setting;
    }
    /**
     * 保存设置
     * @param setting  设置
     */
    saveSetting(setting) {
      Logger.info("保存设置", setting);
      this.setting = setting;
      GmUtils.setValue(STORAGE_KEY_SETTING, setting);
    }
    setCountyCode(countyCode) {
      const county = countyCode2Info.get(countyCode);
      if (!county) {
        throw Error(`国家代码不存在:${countyCode}`);
      }
      this.setting.countyCode = countyCode;
      this.saveSetting(this.setting);
    }
    setCurrencySymbol(currencySymbol) {
      this.setting.currencySymbol = currencySymbol;
      this.saveSetting(this.setting);
    }
    setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue) {
      this.setting.currencySymbolBeforeValue = isCurrencySymbolBeforeValue;
      this.saveSetting(this.setting);
    }
    reset() {
      this.saveSetting(new Setting());
    }
    setRateCacheExpired(rateCacheExpired) {
      this.setting.rateCacheExpired = rateCacheExpired;
      this.saveSetting(this.setting);
    }
    setUseCustomRate(isUseCustomRate) {
      this.setting.useCustomRate = isUseCustomRate;
      this.saveSetting(this.setting);
    }
    setCustomRate(customRate) {
      this.setting.customRate = customRate;
      this.saveSetting(this.setting);
    }
  };
  __publicField(_SettingManager, "instance", new _SettingManager());
  let SettingManager = _SettingManager;
  function parsePrice(content) {
    let priceStr = content.replace(/руб\./g, "").replace(/pуб\./g, "").replace(/\s/g, "").replace(/^[^0-9]+/, "").replace(/[^0-9,.]+$/, "").replace(/,(?=\d\d\d)/g, "");
    const numberStr = priceStr.replace(/\D/g, "");
    let price = Number.parseInt(numberStr) ?? 0;
    if (priceStr.match(/\D/)) {
      price = price / 100;
    }
    return price;
  }
  function convertPrice(price, rate) {
    return Number.parseFloat((price / rate).toFixed(2));
  }
  function convertPriceContent(originalContent, rate) {
    const safeContent = originalContent.trim().replaceAll(/\(.+$/g, "").trim();
    const price = parsePrice(safeContent);
    const convertedPrice = convertPrice(price, rate);
    const setting = SettingManager.instance.setting;
    let finalContent = setting.currencySymbolBeforeValue ? `${safeContent}(${setting.currencySymbol}${convertedPrice})` : `${safeContent}(${convertedPrice}${setting.currencySymbol})`;
    const message = `转换前文本:${safeContent}; 提取到的价格:${price}; 转换后的价格:${convertedPrice}; 转换后文本:${finalContent}`;
    Logger.debug(message);
    return finalContent;
  }
  class ElementConverter extends AbstractConverter {
    getCssSelectors() {
      const home = [
        // 大图
        ".discount_prices > .discount_final_price"
      ];
      const category = [
        // 原价
        ".Wh0L8EnwsPV_8VAu8TOYr",
        "._3j4dI1yA7cRfCvK8h406OB",
        // 折扣价
        "._1EKGZBnKFWOr3RqVdnLMRN",
        "._3fFFsvII7Y2KXNLDk_krOW"
      ];
      const account = [
        "div.accountData.price a"
      ];
      const wishlist = [
        // 右上角钱包
        "div.Hxi-pnf9Xlw- > div._79DIT7RUQ5g-",
        // 当前价格
        "div.ME2eMO7C1Tk- > div.DOnsaVcV0Is-",
        // 原价
        "div.ME2eMO7C1Tk- > div.ywNldZ-YzEE-"
      ];
      const inventory = [
        '#iteminfo1_item_market_actions  div[id^="market_item_action_buyback_at_price_"]'
      ];
      const cart = [
        // 原价
        ".Panel.Focusable ._3-o3G9jt3lqcvbRXt8epsn.StoreOriginalPrice",
        // 折扣价
        ".Panel.Focusable .pk-LoKoNmmPK4GBiC9DR8",
        // 总额
        "._2WLaY5TxjBGVyuWe_6KS3N"
      ];
      const cartCheckout = [
        // 列表
        "#checkout_review_cart_area .checkout_review_item_price > .price",
        // 小计
        "#review_subtotal_value.price",
        // 合计
        "#review_total_value.price"
      ];
      const selectors = [
        // 商店
        // 首页
        ".discount_original_price",
        ".discount_final_price",
        ".col.search_price.responsive_secondrow strike",
        // 头像旁边
        "#header_wallet_balance > span.tooltip",
        // 愿望单总价值
        ".esi-wishlist-stat > .num",
        // 新版卡片
        ".salepreviewwidgets_StoreOriginalPrice_1EKGZ",
        ".salepreviewwidgets_StoreSalePriceBox_Wh0L8",
        // 分类查看游戏
        ".contenthubshared_OriginalPrice_3hBh3",
        ".contenthubshared_FinalPrice_F_tGv",
        ".salepreviewwidgets_StoreSalePriceBox_Wh0L8:not(.salepreviewwidgets_StoreSalePrepurchaseLabel_Wxeyn)",
        // 市场
        // 总余额
        "#marketWalletBalanceAmount",
        // 列表
        "span.normal_price[data-price]",
        "span.sale_price",
        // 求购、求售统计
        ".market_commodity_orders_header_promote:nth-child(even)",
        // 求购、求售列表
        ".market_commodity_orders_table td:nth-child(odd)",
        // 详情列表
        ".market_table_value > span",
        ".jqplot-highlighter-tooltip",
        // 消费记录
        "tr.wallet_table_row > td.wht_total",
        "tr.wallet_table_row > td.wht_wallet_change.wallet_column",
        "tr.wallet_table_row > td.wht_wallet_balance.wallet_column",
        // 捆绑包
        ".package_totals_row > .price:not(.bundle_discount)",
        "#package_savings_bar > .savings.bundle_savings",
        // 低于xxx 分类标题
        ".home_page_content_title a.btn_small_tall > span"
      ];
      selectors.push(...home);
      selectors.push(...category);
      selectors.push(...account);
      selectors.push(...wishlist);
      selectors.push(...inventory);
      selectors.push(...cart);
      selectors.push(...cartCheckout);
      return selectors;
    }
    convert(elementSnap, rate) {
      elementSnap.element.textContent = convertPriceContent(elementSnap.textContext, rate);
      return true;
    }
  }
  class TextNodeConverter extends AbstractConverter {
    constructor() {
      super(...arguments);
      // @ts-ignore
      __publicField(this, "parseFirstChildTextNodeFn", (el) => el.firstChild);
      // 购物车
      __publicField(this, "cart", /* @__PURE__ */ new Map([
        // 卡牌获取进度
        [
          ".Panel.Focusable ._18eO4-XadW5jmTpgdATkSz",
          [(el) => el.childNodes[1]]
        ]
      ]));
      // @ts-ignore
      __publicField(this, "targets", new Map([
        [
          ".col.search_price.responsive_secondrow",
          [
            // @ts-ignore
            (el) => el.firstChild.nextSibling.nextSibling.nextSibling,
            this.parseFirstChildTextNodeFn
          ]
        ],
        ["#header_wallet_balance", [this.parseFirstChildTextNodeFn]],
        // iframe
        [".game_purchase_price.price", [this.parseFirstChildTextNodeFn]],
        // 低于xxx 分类标题
        [".home_page_content_title", [this.parseFirstChildTextNodeFn]],
        // dlc 中没有折扣
        [".game_area_dlc_row > .game_area_dlc_price", [
          (el) => el,
          this.parseFirstChildTextNodeFn
        ]],
        ...this.cart
      ]));
    }
    getCssSelectors() {
      return [...this.targets.keys()];
    }
    convert(elementSnap, rate) {
      const selector = elementSnap.selector;
      this.targets.get(selector);
      const parseNodeFns = this.targets.get(selector) || [];
      if (!parseNodeFns) {
        return false;
      }
      const textNode = this.safeParseNode(selector, elementSnap.element, parseNodeFns);
      if (!textNode) {
        return false;
      }
      const content = textNode.nodeValue;
      if (!content || content.trim().length === 0) {
        return false;
      }
      textNode.nodeValue = convertPriceContent(content, rate);
      return true;
    }
    safeParseNode(selector, el, fns) {
      for (let fn of fns) {
        try {
          const node = fn(el);
          if (node.nodeName === "#text" && node.nodeValue && node.nodeValue.length > 0) {
            return node;
          }
        } catch (e) {
          console.debug("获取文本节点失败,但不确定该节点是否一定会出现。selector:" + selector);
        }
      }
      return null;
    }
  }
  const _ConverterManager = class _ConverterManager {
    constructor() {
      __publicField(this, "converters");
      this.converters = [
        new ElementConverter(),
        new TextNodeConverter()
      ];
    }
    getSelector() {
      return this.converters.map((exchanger) => exchanger.getCssSelectors()).flat(1).join(", ");
    }
    convert(elements, rate) {
      if (!elements) {
        return;
      }
      elements.forEach((element) => {
        const elementSnap = {
          element,
          textContext: element.textContent,
          classList: element.classList,
          attributes: element.attributes
        };
        this.converters.filter((converter) => converter.match(elementSnap)).forEach((converter) => {
          try {
            const exchanged = converter.convert(elementSnap, rate);
            if (exchanged) {
              converter.afterConvert(elementSnap);
            }
          } catch (e) {
            console.group("转换失败");
            console.error(e);
            console.error("转换失败请将下列内容反馈给开发者,右键 > 复制(copy) > 复制元素(copy element)");
            console.error("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
            console.error(element);
            console.error("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
            console.groupEnd();
          }
        });
      });
    }
  };
  __publicField(_ConverterManager, "instance", new _ConverterManager());
  let ConverterManager = _ConverterManager;
  class RateCache {
    constructor(from, to, rate, createdAt) {
      __publicField(this, "from");
      __publicField(this, "to");
      __publicField(this, "createdAt");
      __publicField(this, "rate");
      this.from = from;
      this.to = to;
      this.createdAt = createdAt || 0;
      this.rate = rate || 0;
    }
  }
  class RateCaches {
    constructor() {
      __publicField(this, "caches", /* @__PURE__ */ new Map());
    }
    getCache(from, to) {
      return this.caches.get(this.buildCacheKey(from, to));
    }
    setCache(cache) {
      this.caches.set(this.buildCacheKey(cache.from, cache.to), cache);
    }
    buildCacheKey(from, to) {
      return `${from}:${to}`;
    }
  }
  class Http {
    static get(cls, url, details) {
      if (!details) {
        details = { url };
      }
      details.method = "GET";
      return this.request(cls, details);
    }
    static post(url, cls, details) {
      if (!details) {
        details = { url };
      }
      details.method = "POST";
      return this.request(cls, details);
    }
    static request(cls, details) {
      return new Promise((resolve, reject) => {
        details.onload = (response) => {
          if (cls.name === String.name) {
            resolve(response.response);
          } else {
            const json = JSON.parse(response.response);
            resolve(Jsons.readJson(json, cls));
          }
        };
        details.onerror = (error) => reject(error);
        _GM_xmlhttpRequest(details);
      });
    }
  }
  class SpcContext {
    constructor(setting, targetCountyInfo, targetCountyCode) {
      __publicField(this, "_setting");
      __publicField(this, "_targetCountyInfo");
      __publicField(this, "_currentCountyInfo");
      this._setting = setting;
      this._targetCountyInfo = targetCountyInfo;
      this._currentCountyInfo = targetCountyCode;
    }
    static getContext() {
      return _unsafeWindow.spcContext;
    }
    get setting() {
      return this._setting;
    }
    get targetCountyInfo() {
      return this._targetCountyInfo;
    }
    get currentCountyInfo() {
      return this._currentCountyInfo;
    }
  }
  class AugmentedSteamRateApi {
    getName() {
      return "AugmentedSteamRateApi";
    }
    async getRate() {
      const context = SpcContext.getContext();
      Logger.info(Strings.format(
        "通过 AugmentedSteam 获取汇率 %s(%s) -> %s(%s)...",
        context.currentCountyInfo.currencyCode,
        context.currentCountyInfo.name,
        context.targetCountyInfo.currencyCode,
        context.targetCountyInfo.name
      ));
      const url = `https://api.augmentedsteam.com/rates/v1?to=${context.currentCountyInfo.currencyCode}`;
      let rate = await Http.get(Map, url).then((res) => res.get(context.targetCountyInfo.currencyCode)[context.currentCountyInfo.currencyCode]).catch((err) => Logger.error("通过 AugmentedSteam 获取汇率失败", err));
      if (rate) {
        return rate;
      }
      throw new Error(`通过 ${this.getName()} 获取汇率失败。`);
    }
  }
  const _RateManager = class _RateManager {
    constructor() {
      __publicField(this, "rateApis");
      __publicField(this, "rateCaches", new RateCaches());
      this.rateApis = [
        new AugmentedSteamRateApi()
      ];
    }
    getName() {
      return "RateManager";
    }
    async getRate4Remote() {
      Logger.info("远程获取汇率...");
      let rate;
      for (let rateApi of this.rateApis) {
        try {
          rate = await rateApi.getRate();
        } catch (e) {
          Logger.error(`使用实现(${rateApi.getName()})获取汇率失败`);
        }
        if (rate) {
          return rate;
        }
      }
      throw Error("所有汇率获取实现获取汇率均失败");
    }
    async getRate() {
      const context = SpcContext.getContext();
      if (context.setting.useCustomRate) {
        Logger.info("使用自定义汇率");
        return context.setting.customRate;
      }
      this.rateCaches = this.loadRateCache();
      let cache = this.rateCaches.getCache(context.currentCountyInfo.code, context.targetCountyInfo.code);
      const now = (/* @__PURE__ */ new Date()).getTime();
      const expired = context.setting.rateCacheExpired;
      if (!cache || !cache.rate || now > cache.createdAt + expired) {
        Logger.info(`本地缓存已过期`);
        cache = new RateCache(context.currentCountyInfo.code, context.targetCountyInfo.code);
        cache.rate = await this.getRate4Remote();
        cache.createdAt = (/* @__PURE__ */ new Date()).getTime();
        this.rateCaches.setCache(cache);
        this.saveRateCache();
      }
      return cache.rate;
    }
    loadRateCache() {
      const setting = SpcContext.getContext().setting;
      if (setting.oldVersion !== setting.currVersion) {
        Logger.info(`脚本版本发生变化需要刷新汇率缓存`);
        this.clear();
        return new RateCaches();
      }
      Logger.info(`读取汇率缓存`);
      return GmUtils.getValue(RateCaches, STORAGE_KEY_RATE_CACHES, new RateCaches());
    }
    saveRateCache() {
      Logger.info("保存汇率缓存", this.rateCaches);
      GmUtils.setValue(STORAGE_KEY_RATE_CACHES, this.rateCaches);
    }
    clear() {
      GmUtils.deleteValue(STORAGE_KEY_RATE_CACHES);
    }
  };
  __publicField(_RateManager, "instance", new _RateManager());
  let RateManager = _RateManager;
  async function main() {
    const context = SpcContext.getContext();
    if (context.currentCountyInfo.code === context.targetCountyInfo.code) {
      Logger.info(`${context.currentCountyInfo.name}无需转换`);
      return;
    }
    const rate = await RateManager.instance.getRate();
    if (!rate) {
      throw Error("获取汇率失败");
    }
    Logger.info(Strings.format(`汇率 %s -> %s:%s`, context.currentCountyInfo.currencyCode, context.targetCountyInfo.currencyCode, rate));
    await convert(rate);
  }
  async function convert(rate) {
    const exchangerManager = ConverterManager.instance;
    const elements = document.querySelectorAll(exchangerManager.getSelector());
    exchangerManager.convert(elements, rate);
    const selector = exchangerManager.getSelector();
    const priceObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        const target = mutation.target;
        let priceEls = target.querySelectorAll(selector);
        if (!priceEls || priceEls.length === 0) {
          return;
        }
        exchangerManager.convert(priceEls, rate);
      });
    });
    priceObserver.observe(document.body, {
      childList: true,
      subtree: true
    });
  }
  const _withScopeId = (n) => (vue.pushScopeId("data-v-34f99f99"), n = n(), vue.popScopeId(), n);
  const _hoisted_1 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("link", {
    href: "https://fonts.googleapis.com/icon?family=Material+Icons",
    rel: "stylesheet"
  }, null, -1));
  const _hoisted_2 = {
    "close-on-overlay-click": "",
    class: "setting"
  };
  const _hoisted_3 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { slot: "headline" }, "设置", -1));
  const _hoisted_4 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", { slot: "description" }, "随心所欲设置 steam-price-converter", -1));
  const _hoisted_5 = { class: "setting-item" };
  const _hoisted_6 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "目标区域"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "将价格转换为此区域的货币",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_7 = { class: "setting-item-content" };
  const _hoisted_8 = ["value"];
  const _hoisted_9 = ["value"];
  const _hoisted_10 = { class: "setting-item" };
  const _hoisted_11 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "货币符号"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "转换后的价格的货币符号",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_12 = { class: "setting-item-content" };
  const _hoisted_13 = ["value"];
  const _hoisted_14 = { class: "setting-item" };
  const _hoisted_15 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "货币符号展示位置"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "控制转换后的价格货币符号的位置",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_16 = { class: "setting-item-content" };
  const _hoisted_17 = ["value"];
  const _hoisted_18 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-menu-item", { value: "true" }, "价格之前", -1));
  const _hoisted_19 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-menu-item", { value: "false" }, "价格之后", -1));
  const _hoisted_20 = [
    _hoisted_18,
    _hoisted_19
  ];
  const _hoisted_21 = { class: "setting-item" };
  const _hoisted_22 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "汇率缓存有效期"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "获取汇率后进行缓存,在此时间内将使用缓存汇率",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_23 = { class: "setting-item-content" };
  const _hoisted_24 = ["value"];
  const _hoisted_25 = { class: "setting-item" };
  const _hoisted_26 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "使用自定义汇率"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "使用自定义汇率进行价格转换,不再获取区域,不再根据区域获取汇率",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_27 = { class: "setting-item-content" };
  const _hoisted_28 = ["value"];
  const _hoisted_29 = { class: "setting-item" };
  const _hoisted_30 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "自定义汇率"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "开启“使用自定义汇率”后使用此汇率进行转换",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_31 = { class: "setting-item-content" };
  const _hoisted_32 = ["value"];
  const _hoisted_33 = { class: "setting-item" };
  const _hoisted_34 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "setting-item-title" }, [
    /* @__PURE__ */ vue.createElementVNode("label", null, "日志等级"),
    /* @__PURE__ */ vue.createElementVNode("mdui-tooltip", {
      content: "日志等级 debug > info > warn > error > off",
      placement: "right"
    }, [
      /* @__PURE__ */ vue.createElementVNode("mdui-icon", {
        name: "error",
        class: "setting-region-title-icon"
      })
    ])
  ], -1));
  const _hoisted_35 = { class: "setting-item-content" };
  const _hoisted_36 = ["value"];
  const _hoisted_37 = ["value"];
  const _hoisted_38 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-button", {
    class: "setting-btn-canal",
    slot: "action",
    variant: "text"
  }, "取消", -1));
  const _hoisted_39 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("mdui-button", {
    class: "setting-btn-save",
    slot: "action",
    variant: "tonal"
  }, "保存", -1));
  const _sfc_main = /* @__PURE__ */ vue.defineComponent({
    __name: "App",
    setup(__props) {
      const vueCountyInfos = countyInfos;
      const setting = Object.assign({}, SettingManager.instance.setting);
      vue.onMounted(() => {
        var _a, _b;
        const dialog = document.querySelector(".setting");
        (_a = dialog.querySelector(".setting-btn-canal")) == null ? void 0 : _a.addEventListener("click", () => dialog.open = false);
        (_b = dialog.querySelector(".setting-btn-save")) == null ? void 0 : _b.addEventListener("click", () => {
          SettingManager.instance.saveSetting(setting);
          dialog.open = false;
        });
        GmUtils.addMenuClickEventListener(IM_MENU_SETTING, () => dialog.open = true);
      });
      function getSelected(target) {
        var _a;
        return (_a = target.querySelector("*[selected]")) == null ? void 0 : _a.value;
      }
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          _hoisted_1,
          vue.createElementVNode("mdui-dialog", _hoisted_2, [
            _hoisted_3,
            _hoisted_4,
            vue.createElementVNode("div", _hoisted_5, [
              _hoisted_6,
              vue.createElementVNode("div", _hoisted_7, [
                vue.createElementVNode("mdui-select", {
                  value: vue.unref(setting).countyCode,
                  placement: "bottom",
                  onChange: _cache[0] || (_cache[0] = ($event) => vue.unref(setting).countyCode = getSelected($event.target))
                }, [
                  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(vueCountyInfos), (countyInfo) => {
                    return vue.openBlock(), vue.createElementBlock("mdui-menu-item", {
                      value: countyInfo.code
                    }, vue.toDisplayString(countyInfo.name) + " (" + vue.toDisplayString(countyInfo.code) + ") ", 9, _hoisted_9);
                  }), 256))
                ], 40, _hoisted_8)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_10, [
              _hoisted_11,
              vue.createElementVNode("div", _hoisted_12, [
                vue.createElementVNode("mdui-text-field", {
                  value: vue.unref(setting).currencySymbol,
                  onChange: _cache[1] || (_cache[1] = ($event) => vue.unref(setting).currencySymbol = $event.target.value)
                }, null, 40, _hoisted_13)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_14, [
              _hoisted_15,
              vue.createElementVNode("div", _hoisted_16, [
                vue.createElementVNode("mdui-select", {
                  value: vue.unref(setting).currencySymbolBeforeValue.toString(),
                  placement: "bottom",
                  onChange: _cache[2] || (_cache[2] = ($event) => vue.unref(setting).currencySymbolBeforeValue = getSelected($event.target) === "true")
                }, _hoisted_20, 40, _hoisted_17)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_21, [
              _hoisted_22,
              vue.createElementVNode("div", _hoisted_23, [
                vue.createElementVNode("mdui-text-field", {
                  type: "number",
                  value: vue.unref(setting).rateCacheExpired / (60 * 60 * 1e3),
                  suffix: "h",
                  onChange: _cache[3] || (_cache[3] = ($event) => vue.unref(setting).rateCacheExpired = $event.target.value * (60 * 60 * 1e3))
                }, null, 40, _hoisted_24)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_25, [
              _hoisted_26,
              vue.createElementVNode("div", _hoisted_27, [
                vue.createElementVNode("mdui-switch", {
                  slot: "end-icon",
                  value: vue.unref(setting).useCustomRate,
                  onChange: _cache[4] || (_cache[4] = ($event) => vue.unref(setting).useCustomRate = $event.target.checked)
                }, null, 40, _hoisted_28)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_29, [
              _hoisted_30,
              vue.createElementVNode("div", _hoisted_31, [
                vue.createElementVNode("mdui-text-field", {
                  type: "number",
                  value: vue.unref(setting).customRate,
                  onChange: _cache[5] || (_cache[5] = ($event) => vue.unref(setting).customRate = $event.target.value)
                }, null, 40, _hoisted_32)
              ])
            ]),
            vue.createElementVNode("div", _hoisted_33, [
              _hoisted_34,
              vue.createElementVNode("div", _hoisted_35, [
                vue.createElementVNode("mdui-select", {
                  value: vue.unref(setting).logLevel,
                  onChange: _cache[6] || (_cache[6] = ($event) => vue.unref(setting).logLevel = getSelected($event.target))
                }, [
                  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(LogDefinitions), (def) => {
                    return vue.openBlock(), vue.createElementBlock("mdui-menu-item", {
                      value: def.label
                    }, vue.toDisplayString(def.label), 9, _hoisted_37);
                  }), 256))
                ], 40, _hoisted_36)
              ])
            ]),
            _hoisted_38,
            _hoisted_39
          ])
        ], 64);
      };
    }
  });
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-34f99f99"]]);
  class CookieCountyInfoGetter {
    name() {
      return "cookie";
    }
    match() {
      return true;
    }
    async getCountyCode() {
      return new Promise(async (resolve, reject) => {
        const cookies = await _GM_cookie.list({ name: "steamCountry" });
        if (cookies && cookies.length > 0) {
          const match = cookies[0].value.match(/^[a-zA-Z][a-zA-Z]/);
          if (match) {
            resolve(match[0]);
          }
        }
        reject();
      });
    }
  }
  class RequestStorePageCountyCodeGetter {
    name() {
      return "请求商店页面";
    }
    match() {
      return !window.location.href.includes("store.steampowered.com");
    }
    async getCountyCode() {
      return new Promise(async (resolve, reject) => {
        try {
          const storeHtml = await Http.get(String, "https://store.steampowered.com/");
          const match = storeHtml.match(new RegExp("(?<=GDynamicStore.Init\\(.+')[A-Z][A-Z](?=',)"));
          if (match) {
            return resolve(match[0]);
          }
        } catch (err) {
          Logger.error(err);
        }
        reject();
      });
    }
  }
  class StorePageCountyCodeGetter {
    name() {
      return "商店页面";
    }
    match() {
      return window.location.href.includes("store.steampowered.com");
    }
    getCountyCode() {
      return new Promise((resolve, reject) => {
        var _a, _b;
        try {
          let countyCode = (_b = (_a = GStoreItemData == null ? void 0 : GStoreItemData.rgNavParams) == null ? void 0 : _a.__page_default_obj) == null ? void 0 : _b.countrycode;
          if (countyCode) {
            resolve(countyCode);
          }
        } catch (e) {
          Logger.warn("读取商店页面区域代码变量失败: " + e.message);
        }
        document.querySelectorAll("script").forEach((scriptEl) => {
          const scriptInnerText = scriptEl.innerText;
          if (scriptInnerText.includes("$J( InitMiniprofileHovers );") || scriptInnerText.includes(`$J( InitMiniprofileHovers( 'https%3A%2F%2Fstore.steampowered.com%2F' ) );`)) {
            const matcher = new RegExp("(?<=')[A-Z]{2}(?!=')", "g");
            const match = scriptInnerText.match(matcher);
            if (match) {
              const countyCode = match.toString();
              resolve(countyCode);
            }
          }
        });
        reject();
      });
    }
  }
  class MarketPageCountyCodeGetter {
    name() {
      return "市场页面";
    }
    match() {
      return window.location.href.includes("steamcommunity.com");
    }
    getCountyCode() {
      return new Promise((resolve, reject) => {
        try {
          const code = g_strCountryCode;
          if (code)
            return resolve(code);
        } catch (err) {
          Logger.error(err);
        }
        reject();
      });
    }
  }
  class UserConfigCountyInfoGetter {
    async getCountyCode() {
      return new Promise(async (resolve, reject) => {
        var _a;
        const code = _unsafeWindow.userConfig ? (_a = _unsafeWindow.userConfig) == null ? void 0 : _a.country_code : await this.getCountyCodeForDev();
        if (code) {
          resolve(code);
        } else {
          reject();
        }
      });
    }
    match() {
      return true;
    }
    name() {
      return "window.UserConfig";
    }
    async getCountyCodeForDev() {
      const html = await Http.get(String, window.location.href);
      const match = html.match(/,"country_code":"([A-Z]{2})"/);
      if (match) {
        return match[1];
      }
      return void 0;
    }
  }
  const _CountyCodeGetterManager = class _CountyCodeGetterManager {
    constructor() {
      __publicField(this, "getters");
      this.getters = [
        new UserConfigCountyInfoGetter(),
        new StorePageCountyCodeGetter(),
        new MarketPageCountyCodeGetter(),
        new RequestStorePageCountyCodeGetter(),
        new CookieCountyInfoGetter()
      ];
    }
    match() {
      return true;
    }
    async getCountyCode() {
      Logger.info("尝试获取区域代码");
      for (let getter of this.getters) {
        if (!getter.match()) {
          continue;
        }
        Logger.debug(`尝试通过[${getter.name()}]获取区域代码`);
        try {
          const countyCode = await getter.getCountyCode();
          Logger.info(`通过[${getter.name()}]获取区域代码成功`);
          return countyCode;
        } catch (e) {
          Logger.error(`通过[${getter.name()}]获取区域代码失败`);
        }
      }
      throw new Error("所有获取区域代码策略都获取失败");
    }
  };
  __publicField(_CountyCodeGetterManager, "instance", new _CountyCodeGetterManager());
  let CountyCodeGetterManager = _CountyCodeGetterManager;
  const _SpcManager = class _SpcManager {
    constructor() {
    }
    setCountyCode(code) {
      SettingManager.instance.setCountyCode(code);
    }
    setCurrencySymbol(symbol) {
      SettingManager.instance.setCurrencySymbol(symbol);
    }
    setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue) {
      SettingManager.instance.setCurrencySymbolBeforeValue(isCurrencySymbolBeforeValue);
    }
    setRateCacheExpired(expired) {
      SettingManager.instance.setRateCacheExpired(expired);
    }
    resetSetting() {
      SettingManager.instance.reset();
    }
    clearCache() {
      RateManager.instance.clear();
    }
    setUseCustomRate(isUseCustomRate) {
      SettingManager.instance.setUseCustomRate(isUseCustomRate);
    }
    setCustomRate(customRate) {
      SettingManager.instance.setCustomRate(customRate);
    }
  };
  __publicField(_SpcManager, "instance", new _SpcManager());
  let SpcManager = _SpcManager;
  class ReactUtils {
    static waitForReactInit(callback, checkInterval = 500, timeout = 1e4) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const interval = setInterval(() => {
          const root = document.documentElement;
          for (const prop in root) {
            if (prop.startsWith("__react")) {
              clearInterval(interval);
              console.log(`React initialized with property: ${prop}`);
              Promise.resolve(callback(root, prop)).then(() => resolve()).catch(reject);
              return;
            }
          }
          if (Date.now() - start > timeout) {
            clearInterval(interval);
            reject(new Error("React initialization timeout exceeded."));
          }
        }, checkInterval);
      });
    }
    static useReact() {
      return !!document.querySelector("div[data-react-nav-root]");
    }
  }
  (async () => {
    if (ReactUtils.useReact()) {
      await ReactUtils.waitForReactInit(async (root, reactProp) => {
        console.log("React is ready!", { root, reactProp });
        await initContext();
        initApp();
        registerMenu();
        await main();
      });
    } else {
      console.log("React is not detected!");
      await initContext();
      initApp();
      registerMenu();
      await main();
    }
  })();
  function initApp() {
    vue.createApp(App).mount(
      (() => {
        const app = document.createElement("div");
        app.setAttribute("id", "spc-menu");
        document.body.append(app);
        return app;
      })()
    );
  }
  function registerMenu() {
    GmUtils.registerMenuCommand(IM_MENU_SETTING);
  }
  async function initContext() {
    const setting = SettingManager.instance.setting;
    setLogLevel(setting.logLevel);
    let targetCountyInfo = countyCode2Info.get(setting.countyCode);
    if (!targetCountyInfo) {
      Logger.warn(`获取转换后的国家(${setting.countyCode})信息失败,默认为美国:` + setting.countyCode);
      targetCountyInfo = countyCode2Info.get("US");
    }
    Logger.info("目标区域:", targetCountyInfo);
    const currCountyCode = await CountyCodeGetterManager.instance.getCountyCode();
    const currCountInfo = countyCode2Info.get(currCountyCode);
    if (!currCountyCode) {
      throw Error("缺少当前国家的信息映射:county: " + currCountyCode);
    }
    Logger.info("当前区域:", currCountInfo);
    _unsafeWindow.SpcManager = SpcManager.instance;
    _unsafeWindow.spcContext = new SpcContext(setting, targetCountyInfo, currCountInfo);
  }

})(mdui, Vue);