SteamPY 价格显示

显示 Steam 游戏在 SteamPY 的 CDKey 价格、余额购价格和代购价格

// ==UserScript==
// @name         SteamPY 价格显示
// @version      1.2
// @description  显示 Steam 游戏在 SteamPY 的 CDKey 价格、余额购价格和代购价格
// @author       Li
// @match        https://store.steampowered.com/app/*
// @grant        GM_xmlhttpRequest
// @connect      steampy.com
// @connect      steampowered.com
// @run-at       document-end
// @icon         https://steampy.com/m_logo.ico
// @license      MIT
// @supportURL   https://gf.qytechs.cn/zh-CN/scripts/518189-steampy-%E4%BB%B7%E6%A0%BC%E6%98%BE%E7%A4%BA/feedback
// @homepageURL  https://gf.qytechs.cn/zh-CN/scripts/518189-steampy-%E4%BB%B7%E6%A0%BC%E6%98%BE%E7%A4%BA
// @namespace https://gf.qytechs.cn/users/
// ==/UserScript==

(function () {
    'use strict';

    const BASE_URL = "https://steampy.com/";

    const API_ENDPOINTS = {
        gameInfo: (subId, appId, type) => `${BASE_URL}xboot/common/plugIn/getGame?subId=${subId}&appId=${appId}&type=${type}`,
        cdkDetail: (id) => `${BASE_URL}cdkDetail?name=cn&gameId=${id}`,
        balanceBuyDetail: (id) => `${BASE_URL}balanceBuyDetail?data=cn&gameId=${id}`,
        hotGameDetail: (id) => `${BASE_URL}hotGameDetail?gameId=${id}`,
    };

    const getAppId = () => {
        try {
            const link = document.querySelector('.apphub_OtherSiteInfo a');
            const appIdMatch = link?.href?.match(/\d+$/);
            return appIdMatch ? appIdMatch[0] : null;
        } catch (err) {
            console.error("获取 AppID 失败:", err);
            return null;
        }
    };

    const getSubIdElements = () => [...document.querySelectorAll('.game_area_purchase_game_wrapper')];

    const createPlaceholder = (parent) => {
        const placeholder = document.createElement('div');
        placeholder.className = 'price-box';
        placeholder.innerHTML = `<div class="loading-text">加载中...</div>`;
        parent.appendChild(placeholder);
        return placeholder;
    };

    const updatePlaceholder = (placeholder, content, isError = false) => {
        placeholder.innerHTML = isError
            ? `<div class="error-text">${content}</div>`
            : content;
    };

    const displayPrices = (res, placeholder) => {
        if (!res.success) {
            updatePlaceholder(placeholder, `加载失败:${res.message || "API 返回错误"}`, true);
            return;
        }
        const { keyPrice, marketPrice, daiPrice, id } = res.result;
        updatePlaceholder(
            placeholder,
            `
                <a href="${API_ENDPOINTS.cdkDetail(id)}" target="_blank" class="price-link">
                    CDKey 价格:¥${keyPrice || "未知"}
                </a>
                <a href="${API_ENDPOINTS.balanceBuyDetail(id)}" target="_blank" class="price-link">
                    余额购价格:¥${marketPrice || "未知"}
                </a>
                <a href="${API_ENDPOINTS.hotGameDetail(id)}" target="_blank" class="price-link">
                    代购价格:¥${daiPrice || "未知"}
                </a>
            `
        );
    };

    const appId = getAppId();
    if (!appId) {
        console.error("无法获取 AppID,页面结构可能已更改。");
        return;
    }

    const subIdElements = getSubIdElements();
    subIdElements.forEach((element) => {
        try {
            const input = element.querySelector('input[name="subid"], input[name="bundleid"]');
            if (!input) return;

            const subId = input.value;
            const type = input.name;
            const apiUrl = API_ENDPOINTS.gameInfo(subId, appId, type);

            const placeholder = createPlaceholder(element);

            GM_xmlhttpRequest({
                method: "GET",
                url: apiUrl,
                onload: (response) => {
                    try {
                        if (response.status !== 200) {
                            updatePlaceholder(placeholder, `加载失败:HTTP ${response.status} (${response.statusText || "无状态信息"})`, true);
                            return;
                        }
                        const responseText = response.responseText;
                        try {
                            const result = JSON.parse(responseText);
                            displayPrices(result, placeholder);
                        } catch (jsonErr) {
                            console.error("JSON 解析失败:", jsonErr, "响应文本:", responseText.slice(0, 200));
                            updatePlaceholder(placeholder, `加载失败:数据解析错误 (${jsonErr.message})`, true);
                        }
                    } catch (err) {
                        console.error("处理响应失败:", err);
                        updatePlaceholder(placeholder, `加载失败:内部错误 (${err.message})`, true);
                    }
                },
                onerror: (error) => {
                    console.error("请求失败:", error);
                    updatePlaceholder(placeholder, `加载失败:网络请求错误 (${error.status || "无状态信息"})`, true);
                }
            });
        } catch (err) {
            console.error("处理 SubID 失败:", err);
        }
    });

    const style = document.createElement('style');
    style.innerHTML = `
        .price-box {
            font-size: 14px;
            margin-top: 8px;
            padding: 8px;
            background-color: rgba(0, 0, 0, 0.3);
            border-radius: 4px;
            color: #f0f0f0;
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            box-sizing: border-box;
        }
        .price-link {
            color: #ffffff;
            text-decoration: none;
            font-size: 13px;
            white-space: nowrap;
        }
        .price-link:hover {
            color: #cccccc;
        }
        @media screen and (max-width: 767px) {
            .price-box {
                flex-direction: column;
                gap: 4px;
            }
        }
    `;
    document.head.appendChild(style);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址