Steam CNY价格转换(商品界面)

Display Steam Market item price in CNY with dynamic exchange rate update interval

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Steam CNY价格转换(商品界面)
// @namespace    https://greasyfork.org/zh-CN/users/963647-moase
// @version      0.5
// @description  Display Steam Market item price in CNY with dynamic exchange rate update interval
// @author       MaoShiSanKe
// @match        https://steamcommunity.com/market/listings/*
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    const exchangeRateAPI = 'https://api.exchangerate-api.com/v4/latest/USD';
    const CACHE_EXPIRY_TIME = 30 * 60 * 1000; // 缓存过期时间:30分钟
    let lastExchangeRate = null;
    let lastExchangeRateTime = 0;
    let lastDataUpdateTime = 0;
    let isProcessing = false;  // 防止多次执行
    let isRateUpdating = false;  // 防止频繁的汇率请求
    let officialRefreshInterval = 5000;  // 默认5秒

    // 获取商品价格
    const getItemPrices = () => {
        let prices = [];
        document.querySelectorAll('.market_commodity_orders_table td').forEach((cell, index) => {
            if (index % 2 === 0) {
                const priceText = cell.textContent.trim();
                if (priceText.startsWith('$')) {
                    prices.push(parseFloat(priceText.substring(1)));
                }
            }
        });
        return prices;
    };

    // 获取汇率并缓存
    const getExchangeRate = () => {
        const currentTime = Date.now();

        // 如果缓存未过期,直接返回缓存的汇率
        if (lastExchangeRate && currentTime - lastExchangeRateTime < CACHE_EXPIRY_TIME) {
            return Promise.resolve(lastExchangeRate);
        }

        // 如果缓存过期,则重新请求API
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: exchangeRateAPI,
                onload: (response) => {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.rates && data.rates.CNY) {
                            // 缓存汇率并设置时间戳
                            lastExchangeRate = data.rates.CNY;
                            lastExchangeRateTime = currentTime;
                            resolve(lastExchangeRate);
                        } else {
                            reject('CNY汇率未找到');
                        }
                    } catch (e) {
                        reject('解析汇率数据失败');
                    }
                },
                onerror: (error) => {
                    reject('请求失败: ' + error);
                }
            });
        });
    };

    // 显示转换后的价格
    const displayPricesInCNY = async () => {
        if (isProcessing) return;  // 防止重复处理
        isProcessing = true;

        const prices = getItemPrices();
        if (prices.length > 0) {
            try {
                const exchangeRate = await getExchangeRate();
                prices.forEach(price => {
                    const priceInCNY = (price * exchangeRate).toFixed(2);
                    const priceElement = document.createElement('span');
                    priceElement.textContent = `(¥\ ${priceInCNY} CNY)`;
                    priceElement.classList.add('cny-price');

                    const priceNode = Array.from(document.querySelectorAll('.market_commodity_orders_table td')).find(node => node.textContent.includes(`$${price.toFixed(2)}`));
                    if (priceNode && !priceNode.querySelector('.cny-price')) {
                        priceNode.appendChild(priceElement);
                    }
                });
            } catch (error) {
                console.error('获取汇率失败:', error);
            }
        }
        isProcessing = false;
    };

    // 捕获官方刷新间隔(如果可以的话)
    const captureRefreshInterval = () => {
        const refreshTimeNode = document.querySelector('.market_commodity_orders_table');
        if (refreshTimeNode) {
            // 检测到页面内数据更新的时间间隔
            const refreshInterval = window.getComputedStyle(refreshTimeNode).getPropertyValue('animation-duration');
            if (refreshInterval) {
                const seconds = parseFloat(refreshInterval) * 1000;  // 将秒转为毫秒
                officialRefreshInterval = seconds;
                console.log(`检测到官方刷新间隔: ${officialRefreshInterval / 1000} 秒`);
            }
        }
    };

    // 检测数据是否刷新并更新汇率
    const checkForDataUpdate = () => {
        const currentTime = Date.now();

        // 如果数据已经刷新,并且距离上次汇率更新超过刷新间隔,则更新汇率
        if (currentTime - lastDataUpdateTime >= officialRefreshInterval && !isRateUpdating) {
            isRateUpdating = true;
            lastDataUpdateTime = currentTime;
            displayPricesInCNY().finally(() => {
                isRateUpdating = false;
            });
        }
    };

    // 使用 MutationObserver 监听价格更新
    const observePriceChanges = () => {
        const targetNode = document.querySelector('.market_commodity_orders_table');
        if (targetNode) {
            const observer = new MutationObserver(() => {
                checkForDataUpdate();  // 检查数据更新时间
            });
            observer.observe(targetNode, { childList: true, subtree: true });
        }
    };

    // 处理页面加载
    window.addEventListener('load', () => {
        captureRefreshInterval();  // 捕获官方刷新间隔
        displayPricesInCNY();
        observePriceChanges();
        // 定时检查数据更新时间并更新汇率
        setInterval(checkForDataUpdate, officialRefreshInterval);
    });
})();