Greasy Fork

Greasy Fork is available in English.

SteamPY 价格显示

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

当前为 2024-11-20 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         SteamPY 价格显示
// @namespace    http://greasyfork.icu/users/
// @version      1.0
// @description  显示 Steam 游戏在 SteamPY 的 CDKey 价格、余额购价格和代购价格
// @author       Li
// @match        https://store.steampowered.com/app/*
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// @icon         https://steampy.com/m_logo.ico
// @license      MIT
// @supportURL   http://greasyfork.icu/zh-CN/scripts
// @homepageURL  http://greasyfork.icu/zh-CN/scripts
// ==/UserScript==

(function () {
    'use strict';

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

    // SteamPY的API
    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}`,
    };

    // 获取 AppID
    const getAppId = () => {
        const link = document.querySelector('.apphub_OtherSiteInfo a');
        const appIdMatch = link?.href?.match(/\d+$/);
        return appIdMatch ? appIdMatch[0] : null;
    };

    // 获取 SubID
    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 || "加载失败:未知错误", 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("未能获取 App ID,脚本终止!");
        return;
    }

    const subIdElements = getSubIdElements();
    subIdElements.forEach((element, index) => {
        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 {
                    const result = JSON.parse(response.responseText);
                    displayPrices(result, placeholder);
                } catch (err) {
                    console.error("解析响应失败:", err);
                    updatePlaceholder(placeholder, "加载失败:解析错误", true);
                }
            },
            onerror: () => updatePlaceholder(placeholder, "加载失败:网络错误", true),
        });
    });

    // 基本样式
    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;
        }
        .loading-text, .error-text {
            color: #ffcccc;
            font-size: 13px;
        }
        .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);
})();