Steam、Epic历史价格查询

跳转到SteamDB、EpicGamesDB,兼容via和x浏览器

// ==UserScript==
// @name                Steam、Epic历史价格查询
// @name:zh-TW          Steam、Epic歷史價格查詢
// @name:en             Steam and Epic Historical Price Lookup
// @name:ja             Steam and Epic Historical Price Lookup
// @name:ko             Steam and Epic Historical Price Lookup
// @name:ru             Steam and Epic Historical Price Lookup
// @description         跳转到SteamDB、EpicGamesDB,兼容via和x浏览器
// @description:zh-TW   跳轉到 SteamDB、EpicGamesDB,兼容via和x瀏覽器
// @description:en      Navigate to SteamDB, EpicGamesDB, compatible with Via and X browsers
// @description:ja      Navigate to SteamDB, EpicGamesDB, compatible with Via and X browsers
// @description:ko      Navigate to SteamDB, EpicGamesDB, compatible with Via and X browsers
// @description:ru      Navigate to SteamDB, EpicGamesDB, compatible with Via and X browsers
// @author       shopkeeperV
// @namespace    https://greasyfork.org/zh-CN/users/150069
// @version      1.1.2
// @run-at       document-end
// @match        https://store.steampowered.com/*
// @match        https://store.epicgames.com/*
// @grant        GM_info
// @grant        window.onurlchange
// ==/UserScript==

(function () {
    'use strict';
    let host = location.host;
    let path = location.pathname;
    let db_url;
    if (/steampowered/.test(host)) {
        let page_type;
        let title_eles;
        let page_id = path.match(/\/([0-9]*?)\//i)[1];
        if (/app/.test(path)) {
            page_type = "app";
            //@run-at声明在各浏览器中表现不一致,所以为了兼容麻烦得要死
            let wait = function () {
                title_eles = document.getElementsByClassName("apphub_AppName");
                let wrappers = document.getElementsByClassName("game_area_purchase_game_wrapper");
                if (title_eles.length > 0 && wrappers.length > 0) {
                    for (let wrapper of wrappers) {
                        let item_type;
                        let item_id;
                        let form = wrapper.getElementsByTagName("form")[0];
                        let inputs = form.getElementsByTagName("input");
                        for (let input of inputs) {
                            if (/subid|bundleid/.test(input.name)) {
                                if (/subid/.test(input.name)) {
                                    item_type = "sub";
                                } else if (/bundleid/.test(input.name)) {
                                    item_type = "bundle";
                                }
                                item_id = input.value;
                                break;
                            }
                        }
                        db_url = "https://steamdb.info/" + item_type + "/" + item_id + "/#pricehistory";
                        wrapper.getElementsByTagName("h1")[0].appendChild(createASpan(db_url));
                    }
                    set();
                } else {
                    setTimeout(wait, 500);
                }
            }
            wait();
        } else {
            if (/sub/.test(path)) {
                page_type = "sub";
            } else if (/bundle/.test(path)) {
                page_type = "bundle";
            } else return;
            let wait = function () {
                title_eles = document.getElementsByClassName("pageheader");
                if (title_eles.length > 0) {
                    set();
                } else {
                    setTimeout(wait, 500);
                }
            }
            wait();
        }

        function set() {
            for (let title_ele of title_eles) {
                db_url = "https://steamdb.info/" + page_type + "/" + page_id + "/#pricehistory";
                title_ele.appendChild(createASpan(db_url));
            }
        }
    }
    if (/epicgames/.test(host)) {
        let loop_times = 0;
        handler();
        //尽量用原生api
        if (/xmonkey|tampermonkey/i.test(GM_info.scriptHandler)) {
            window.addEventListener('urlchange', handler);
        } else {
            const originalPushState = history.pushState;
            const originalReplaceState = history.replaceState;
            //popstate事件监听不到,可以拦截相应方法达到同样的效果
            history.pushState = function (state) {
                originalPushState.apply(history, arguments);
                console.log("Epic历史价格查询:监听到地址变化。pushState()调用。");
                handler();
            };
            //此方法只是备用,epic并不是用这个
            history.replaceState = function (state) {
                originalReplaceState.apply(history, arguments);
                console.log("Epic历史价格查询:监听到地址变化,replaceState()调用。");
                handler();
            };
        }

        function handler() {
            if (loop_times >= 30) {
                loop_times = 0;
                console.log("Epic历史价格查询:取消循环。");
                return;
            }
            if (/\/p\//.test(location.pathname)) {
                console.log("Epic历史价格查询:正在获取页面id...");
                let ele1 = document.getElementById("_schemaOrgMarkup-Product");
                let ele2 = document.getElementById("btn_age_continue");
                if (ele1 && !ele2 && !ele1.getAttribute("price_db")) {
                    ele1.setAttribute("price_db", "price_db");
                    loop_times = 0;
                    console.log("Epic历史价格查询:已添加查询按钮。");
                    let content = ele1.textContent;
                    let id = content.match(/"sku":"([^"]*):([^"]*)"/)[2];
                    db_url = "https://epicgamesdb.info/p/" + id + "/" + location.pathname.split("/").pop();
                    document.getElementsByTagName("h1")[0].appendChild(createASpan(db_url));
                } else {
                    loop_times++;
                    setTimeout(handler, 500);
                }
            }
        }
    }

    function createASpan(url) {
        let span = document.createElement("span");
        span.setAttribute("class", "history_price");
        span.textContent = "查价";
        span.style.cssText = "display:inline-block;margin-left:10px;color:yellow;cursor:pointer;";
        span.onclick = (e) => {
            window.open(url);
        };
        return span;
    }
})();