🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

Steam库移除助手

快速移除Steam库中受限、正在了解和被Ban的游戏

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         Steam库移除助手
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  快速移除Steam库中受限、正在了解和被Ban的游戏
// @author       lyzlyslyc
// @match        http*://steamcommunity.com/*/games/*
// @match        http*://help.steampowered.com/*
// @icon         https://store.steampowered.com/favicon.ico
// @resource     data https://cdn.jsdelivr.net/gh/lyzlyslyc/Scripts/SteamLimitedGames.json
// @grant        GM_getResourceText
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      help.steampowered.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...
    let removeList = GM_getValue("removeList");
    if(removeList===undefined)removeList={};
    if(document.domain=="help.steampowered.com"){
        let applist = [];
        let success = 0;
        let fail = 0;
        let div;
        let rows = {};
        let currentThread = 0;
        let maxThread = 5;
        let removeInterval_ms = 1000;
        let thread = null;
        initializeDiv();
        let table = document.getElementById("gameRemoveTable");
        for(let appid in removeList){
            if(removeList[appid].remove==true){
                applist.push(appid);
                rows[appid] = addGame(appid,removeList[appid].name);
            }
        }
        if(applist.length>0){
            document.getElementById("remove_gamecount").innerText=applist.length;
            div.style.display = "";
        }

        function initializeDiv(){
            div = document.createElement("div");
            div.id="gameRemoveDiv";
            div.innerHTML = `<h2 style="text-align:center; margin-bottom: 5px">检测到需要移除的游戏</h2><div style="overflow: auto;"><span>共<span id="remove_gamecount">0</span>项</span><table style="width: 100%;text-align: center;" id="gameRemoveTable"><thead><tr><th>appid</th><th>游戏名</th><th>状态</th></tr></thead><tbody></tbody></table></div><div id="btnStartRemove" class="btn_green_white_innerfade" style="margin-top: 10px;width: 100%;text-align: center;line-height: 30px;">开始移除</div>`;
            div.style.display = "none";
            document.body.append(div);
            $J('<style type="text/css">#gameRemoveDiv{padding: 10px;position: fixed;top: 20%;right: 0;background: rgb(30, 45, 64);max-height: 40%;display: flex;flex-direction: column;max-width: 30%;z-index: 999;}#gameRemoveTable,#gameRemoveTable tr th,#gameRemoveTable tr td{border:1px solid;padding: 5px;}</style>').appendTo($J("head"));
            let btnStart = document.getElementById("btnStartRemove");
            btnStart.addEventListener("click",()=>{
                if(thread!=null){
                    btnStart.innerText="开始移除";
                    clearInterval(thread);
                    thread=null;
                    return;
                }
                btnStart.innerText="停止移除";
                thread = setInterval(removeLoop,removeInterval_ms);
            })

        }

        function addGame(appid,name){
            let row = table.tBodies[0].insertRow(0);
            let appidCell=row.insertCell(0);
            let nameCell=row.insertCell(1);
            let statusCell = row.insertCell(2);
            //let deleteCell = row.insertCell(3);
            appidCell.innerText=appid;
            nameCell.innerText=name;
            statusCell.innerText="未开始";
            //deleteCell.innerText="×";
            return row;
        }

        function removeLoop(){
            while(currentThread<maxThread){
                let appid = applist.pop();
                if(appid===undefined&&thread!=null){
                    clearInterval(thread);
                    thread=null;
                    document.getElementById("btnStartRemove").innerText="移除完毕";
                    console.log("Removing stopped.");
                    return;
                }
                removeOne(appid);
            }
        }

        function removeOne(appid){
            currentThread++;
            rows[appid].style.background="#ff8c00";
            rows[appid].cells[2].innerText="请求中";
            getAjaxParams(appid).then(params=>doRemovePackage(params)).then(res=>{
                if(res.success==true){
                    rows[appid].style.background="green";
                    rows[appid].cells[2].innerText="成功";
                    delete removeList[appid];
                    GM_setValue("removeList",removeList);
                }
                else {
                    rows[appid].style.background="red";
                    rows[appid].cells[2].innerText="失败";
                    delete removeList[appid];
                    GM_setValue("removeList",removeList);
                }
            }).catch(err=>{
                console.log(err);
                rows[appid].style.background="red";
                rows[appid].cells[2].innerText=err;
            }).finally(()=>{currentThread--;})
        }
    }
    else{
        let data;
        try{
            data = JSON.parse(GM_getResourceText("data"));
        }
        catch(e){
            alert("Steam库移除助手:获取受限游戏数据失败,请刷新重试!");
            console.log(e);
        }

        //添加筛选面板
        $J(`<style type="text/css">.filtered{display:none !important}.remove_options_label{display:inline;}.remove_option_text{color:#fff}.remove_options input {vertical-align: middle;}</style>`).appendTo("head");
        $J("#gameslist_controls").after($J(`<div class="remove_options sort_options">
            <div class="remove_options_label">移除筛选</div><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkShowLimited">显示受限</span><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkShowLearning">显示了解中</span><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkShowBanned">显示被Ban</span><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkRemoveFree">选择免费</span><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkRemoveCards">选择有卡</span><span>&nbsp;</span>
            <span class="remove_option_text"><input type="checkbox" id="chkRemoveAll">选择全部</span><span>&nbsp;</span>
            <span style="float:right">
                <span class="remove_option_text" style=""><input type="checkbox" id="chkShowListed">仅显示已选择</span><span>&nbsp;</span>
                <span class="remove_option_text" style="">已选择<span id="removeCount">2</span>项</span><span style="">&nbsp;</span>
                <a style="" target="_blank" href="https://help.steampowered.com/">前往客服页面移除</a>
            </span>
        </div>`));
        let chkShowLimited = document.querySelector("#chkShowLimited");
        let chkShowLearning = document.querySelector("#chkShowLearning");
        let chkShowBanned = document.querySelector("#chkShowBanned");
        let chkShowListed = document.querySelector("#chkShowListed");
        chkShowLimited.addEventListener("click",()=>handleFilterClick());
        chkShowLearning.addEventListener("click",()=>handleFilterClick());
        chkShowListed.addEventListener("click",()=>handleFilterClick());
        chkShowBanned.addEventListener("click",()=>handleFilterClick());
        //移除免费
        document.querySelector("#chkRemoveFree").addEventListener("click",(e)=>{
            document.querySelector("#games_list_row_container").style.display = "none";
            if(e.currentTarget.checked){
                document.querySelectorAll("#games_list_rows .gameListRow:not(.filtered)").forEach(row=>{
                    //如果没显示,且是勾选事件,则不显示的不会被加入列表
                    if(row.style.display=="none")return;
                    if(data.FOD[row.appid]){
                        handleRemoveButtonClick(row.btn,row.appid,row.name,true);
                    }
                })
            }
            else{
                document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                    if(data.FOD[row.appid]){
                        if(row.btn.isOnList!=e.currentTarget.checked)handleRemoveButtonClick(row.btn,row.appid,row.name,false);
                    }
                });
            }
            document.querySelector("#games_list_row_container").style.display = "";
            GM_setValue("removeList",removeList);
            handleFilterClick();
            countSelectedGames();
        })
        //移除有卡
        document.querySelector("#chkRemoveCards").addEventListener("click",(e)=>{
            document.querySelector("#games_list_row_container").style.display = "none";
            if(e.currentTarget.checked){
                document.querySelectorAll("#games_list_rows .gameListRow:not(.filtered)").forEach(row=>{
                    //如果没显示,且是勾选事件,则不显示的不会被加入列表
                    if(row.style.display=="none")return;
                    if(data.cards[row.appid]){
                        handleRemoveButtonClick(row.btn,row.appid,row.name,true);
                    }
                })
            }
            else{
                document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                    if(data.cards[row.appid]){
                        if(row.btn.isOnList!=e.currentTarget.checked)handleRemoveButtonClick(row.btn,row.appid,row.name,false);
                    }
                });
            }
            document.querySelector("#games_list_row_container").style.display = "";
            GM_setValue("removeList",removeList);
            handleFilterClick();
            countSelectedGames();
        })
        //移除全部
        document.querySelector("#chkRemoveAll").addEventListener("click",(e)=>{
            document.querySelector("#games_list_row_container").style.display = "none";
            if(e.currentTarget.checked){
                document.querySelectorAll("#games_list_rows .gameListRow:not(.filtered)").forEach(row=>{
                    if(row.style.display=="none")return;
                    handleRemoveButtonClick(row.btn,row.appid,row.name,true);
                })
            }
            else{
                document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                    //如果列表状态和勾选状态不一致,就点击按钮
                    if(row.btn.isOnList!=e.currentTarget.checked)handleRemoveButtonClick(row.btn,row.appid,row.name,false);
                });
            }
            GM_setValue("removeList",removeList);
            document.querySelector("#games_list_row_container").style.display = "";
            handleFilterClick();
            countSelectedGames();
        })
        //添加移除按钮
        addButtons();
        //添加表格变化监视
        let observer = new MutationObserver((mutations)=>{
            console.log(mutations);
            handleFilterClick();
            countSelectedGames();
        });
        observer.observe(document.querySelector("#games_list_rows"),{attributes:true,attributeFilter: ['style'],subtree:true });
        countSelectedGames();

        function toggleText(btn){
            if(btn.isOnList)btn.innerText = "移出移除列表";
            else btn.innerText = "加入移除列表";
        }

        async function addButtons(){
            let limitedCount = 0;
            let learningCount = 0;
            let bannedCount = 0;
            let fodCount = 0;
            document.querySelector("#games_list_row_container").style.display = "none";
            document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                //提取游戏appid和游戏名
                row.appid = row.id.match(/\d+/)[0];
                row.name = row.querySelector(".gameListRowItemName").innerText;
                //创建按钮
                let btn = document.createElement("a");
                btn.className = "pullup_item remove_item";
                btn.href = `javascript:void(0);`;
                btn.style = "padding:3px;";
                btn.isOnList = (removeList[row.appid]&&removeList[row.appid].remove==true);
                toggleText(btn);
                btn.addEventListener("click",()=>{handleRemoveButtonClick(btn,row.appid,row.name);GM_setValue("removeList",removeList);countSelectedGames();})
                row.querySelector(".bottom_controls").append(btn);
                row.btn=btn;

                if(data.limited[row.appid])limitedCount++;
                if(data.learning[row.appid])learningCount++;
                if(data.banned[row.appid])bannedCount++;

                let tags = $J("<span></span>");
                if(data.FOD[row.appid]){
                    tags[0].innerText+="免费 ";
                    $J(row.querySelector(".gameListRowItemName")).after(tags);
                    if(data.limited[row.appid]||data.learning[row.appid]||data.banned[row.appid])fodCount++;
                }
                if(data.cards[row.appid]){
                    tags[0].innerText+="有卡 ";
                    $J(row.querySelector(".gameListRowItemName")).after(tags);
                }
            })
            document.querySelector("#games_list_row_container").style.display = "";
            console.log(`共${limitedCount}个受限游戏,${learningCount}个正在了解游戏,${bannedCount}被Ban游戏,这些游戏中有${fodCount}个免费游戏。`);
        }

        async function handleRemoveButtonClick(btn,appid,name,isOnList){
            if(isOnList)btn.isOnList=isOnList;
            else btn.isOnList=!btn.isOnList;
            if(removeList[appid])removeList[appid].remove=btn.isOnList;
            else removeList[appid] = {name:name,remove:btn.isOnList};
            toggleText(btn,btn.isOnList);
        }

        async function handleFilterClick(){
            document.querySelector("#games_list_row_container").style.display = "none";
            document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                let appid = row.id.match(/\d+/)[0];
                let name = row.querySelector(".gameListRowItemName").innerText;
                let filtered = false;
                //仅显示已选择
                if(chkShowListed.checked)filtered = !row.querySelector(".remove_item").isOnList;
                //如果都没有选择,就都不筛选
                if((!chkShowLimited.checked)&&(!chkShowLearning.checked)&&(!chkShowBanned.checked))filtered||=false;
                //如果选择至少一个,且不游戏在相应名单中,就将游戏筛选
                else filtered ||=!((chkShowLimited.checked&&data.limited[appid])||(chkShowLearning.checked&&data.learning[appid])||(chkShowBanned.checked&&data.banned[appid]));
                $J(row).toggleClass("filtered",filtered);
            });
            document.querySelector("#games_list_row_container").style.display = "";
        }

        function countSelectedGames(){
            let count = 0;
            document.querySelectorAll("#games_list_rows .gameListRow").forEach(row=>{
                if(row.btn.isOnList)count++;
            });
            document.getElementById("removeCount").innerText=count;
        }
    }

    function getAjaxParams(appid){
        return new Promise((resolve,reject)=>{
            GM_xmlhttpRequest({
                url:`https://help.steampowered.com/zh-cn/wizard/HelpWithGameIssue/?appid=${appid}&issueid=123`,
                method:"GET",
                timeout:5000,
                onload:(res)=>{
                    let text = res.responseText;
                    if(text.search("m_steamid")==-1){
                        reject("Steam客服页面未登录");
                        return;
                    }
                    let match = text.match(/g_sessionID = "([0-9a-zA-Z]+)";/);
                    if(match==null){
                        reject("未获取到Steam客服页面SessionID");
                        return;
                    }
                    let parser = new DOMParser();
                    let doc = parser.parseFromString(text,"text/html");
                    let packageid = doc.querySelector("#packageid").value;
                    resolve({ appid:appid, packageid:packageid, sessionid: match[1], wizard_ajax: 1, gamepad: 0 });
                },
                ontimeout:()=>{reject(`获取参数超时`)},
                onerror:(err)=>{reject(`获取参数出错:`+JSON.stringify(err))}
            })
        })
    }

    function doRemovePackage(ajaxParams){
        return new Promise((resolve,reject)=>{
            $J.ajax({
                type: 'POST',
                url: 'https://help.steampowered.com/zh-cn/wizard/AjaxDoPackageRemove',
                data: `packageid=${ajaxParams.packageid}&appid=${ajaxParams.appid}&sessionid=${ajaxParams.sessionid}&wizard_ajax=1&gamepad=0`
            }).fail((xhr)=>reject(`移除出错`))
            .done((res)=>{
                resolve(res);
            })
        })
    }

})();