您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
快速移除Steam库中受限、正在了解和被Ban的游戏
// ==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> </span> <span class="remove_option_text"><input type="checkbox" id="chkShowLimited">显示受限</span><span> </span> <span class="remove_option_text"><input type="checkbox" id="chkShowLearning">显示了解中</span><span> </span> <span class="remove_option_text"><input type="checkbox" id="chkShowBanned">显示被Ban</span><span> </span> <span class="remove_option_text"><input type="checkbox" id="chkRemoveFree">选择免费</span><span> </span> <span class="remove_option_text"><input type="checkbox" id="chkRemoveCards">选择有卡</span><span> </span> <span class="remove_option_text"><input type="checkbox" id="chkRemoveAll">选择全部</span><span> </span> <span style="float:right"> <span class="remove_option_text" style=""><input type="checkbox" id="chkShowListed">仅显示已选择</span><span> </span> <span class="remove_option_text" style="">已选择<span id="removeCount">2</span>项</span><span style=""> </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); }) }) } })();