// ==UserScript== // @name Steam 创意工坊自动订阅 // @name:en Steamcommunity Auto Subscribe // @description Steam 创意工坊自动订阅 // @version 0.1.3 // @author Yiero // @namespace https://github.com/AliubYiero/TamperMonkeyScripts // @grant GM_getValue // @grant GM_notification // @grant window.close // @match https://steamcommunity.com/sharedfiles/filedetails/* // @license GPL-3 // ==/UserScript== /* ==UserConfig== 配置项: AppIds: title: "应用id (多个id通过逗号分隔)\n(打开商店页面, 地址栏中游戏/软件名前的纯数字)" description: "应用id" type: text default: "" autoClose: title: "订阅后, 自动关闭页面" description: "是否在订阅完成后, 自动关闭页面" type: checkbox default: false ==/UserConfig== */ var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); const getElement = (selector, parent = document.body, timeout = 0) => { return new Promise((resolve) => { let result = parent.querySelector(selector); if (result) { return resolve(result); } let timer; const observer = new window.MutationObserver((mutations) => { for (let mutation of mutations) { for (let addedNode of mutation.addedNodes) { if (addedNode instanceof Element) { result = addedNode.matches(selector) ? addedNode : addedNode.querySelector(selector); if (result) { observer.disconnect(); timer && clearTimeout(timer); setTimeout(() => resolve(result), 500); } } } } }); observer.observe(parent, { childList: true, subtree: true }); if (timeout > 0) { timer = setTimeout(() => { observer.disconnect(); return resolve(null); }, timeout); } }); }; const getPageInfo = () => { const getAppName = () => { var _a; return ((_a = document.querySelector(".apphub_AppName")) == null ? void 0 : _a.textContent) || ""; }; const getAppId = () => { const shopLinkSelector = '.apphub_OtherSiteInfo > a[href^="https://store.steampowered.com/app/"]'; const shopLink = document.querySelector(shopLinkSelector); if (!shopLink) { return -1; } const appId = Number(shopLink.dataset.appid); return appId; }; const getFileName = () => { var _a; return ((_a = document.querySelector(".workshopItemTitle")) == null ? void 0 : _a.textContent) || ""; }; const getUserName = () => { var _a; return ((_a = document.querySelector("#account_pulldown")) == null ? void 0 : _a.textContent) || "\u672A\u767B\u5F55\u7528\u6237"; }; return { appName: getAppName(), appId: getAppId(), fileName: getFileName(), userName: getUserName() }; }; const notify = (title, text = "") => { const steamImage = "https://steamcommunity.com/favicon.ico"; GM_notification({ title: `[Steam \u521B\u610F\u5DE5\u574A\u81EA\u52A8\u8BA2\u9605] ${title}`, text, image: steamImage, timeout: 1e3 }); }; const notifySubscribe = (info) => { const { appName = "", appId = -1, fileName = "", userName = "", subscribeAction = "add" } = info; const subscribeActionMapper = { add: "\u5DF2\u6DFB\u52A0\u81F3\u60A8\u7684\u8BA2\u9605\u5939", remove: "\u5DF2\u4ECE\u60A8\u7684\u8BA2\u9605\u5939\u4E2D\u79FB\u9664" }; const subscribeStatText = subscribeActionMapper[subscribeAction]; const notifyTitle = `\u8BA2\u9605\u60C5\u51B5\u53D8\u66F4`; const date = (/* @__PURE__ */ new Date()).toLocaleString(); notify( notifyTitle, [ `\u7269\u54C1\u300C${fileName}\u300D${subscribeStatText}. `, "", `\u5E94\u7528: ${appName}`, `\u7528\u6237: ${userName}`, `\u65E5\u671F: ${date}` ].join("\n") ); }; class Countdown { constructor(callback, delayPerMs) { __publicField(this, "timer", -1); __publicField(this, "delayPerMs", 2e4); __publicField(this, "callback"); this.callback = callback; this.delayPerMs = delayPerMs; } start() { this.timer = setTimeout(this.callback, this.delayPerMs); } stop() { clearTimeout(this.timer); } } const subscribeCountdown = () => { return new Countdown(() => { window.location.reload(); }, 15e3); }; const listenerNodeUpdate = (subscribeTextNode) => { const pageInfo = getPageInfo(); const autoClose = GM_getValue("\u914D\u7F6E\u9879.autoClose", false); const subscribeCountdownInstance = subscribeCountdown(); autoClose && subscribeCountdownInstance.start(); const observer = new MutationObserver((records) => { subscribeCountdownInstance.stop(); const subscribeButtonRecord = records.find((record) => record.target.id === "SubscribeItemOptionAdd"); const isOldSelected = subscribeButtonRecord.oldValue.includes("selected"); const isNewSelected = subscribeButtonRecord.target.classList.contains("selected"); if (!isOldSelected && isNewSelected) { notifySubscribe({ ...pageInfo, subscribeAction: "remove" }); observer.disconnect(); return; } notifySubscribe({ ...pageInfo, subscribeAction: "add" }); if (autoClose) { window.close(); } observer.disconnect(); }); observer.observe(subscribeTextNode, { attributeOldValue: true, subtree: true, attributeFilter: ["class"] }); return observer; }; const subscribeFile = () => { const subscribeTextSelector = ".subscribeText"; const subscribeTextNode = document.querySelector(subscribeTextSelector); subscribeTextNode.click(); listenerNodeUpdate(subscribeTextNode); }; const getUserLoginStat = () => { const notificationButtonSelector = "#header_notification_area"; return Boolean(document.querySelector(notificationButtonSelector)); }; class AppIdStorage { /** * 返回数组 * * @returns {number[]} */ static get() { const gameIdString = GM_getValue(this.key, ""); const gameIdList = gameIdString.split(/,\s*/).map((item) => Number(item)); return gameIdList; } } __publicField(AppIdStorage, "key", "\u914D\u7F6E\u9879.AppIds"); const containGame = () => { const { appId } = getPageInfo(); const appIdList = AppIdStorage.get(); return appIdList.includes(appId); }; const getSubscribeStat = () => { const selectedSubscribeOptionSelector = ".subscribeText > .selected"; const selectedMapper = { SubscribeItemOptionAdd: false, SubscribeItemOptionSubscribed: true }; const selectedSubscribeOption = document.querySelector(selectedSubscribeOptionSelector); if (!selectedSubscribeOption) { return true; } const selectedSubscribeOptionId = selectedSubscribeOption.id; if (!selectedSubscribeOptionId) { return true; } return selectedMapper[selectedSubscribeOptionId]; }; const judgeSubscribePossibility = () => { const isLogin = getUserLoginStat(); const isSelectApp = containGame(); const isSubscribe = getSubscribeStat(); if (!isLogin) { notify("Steam \u7528\u6237\u672A\u767B\u5F55", "\u7528\u6237\u672A\u767B\u5F55"); return false; } if (!isSelectApp) { return false; } if (isSubscribe) { notify("\u7269\u54C1\u5DF2\u8BA2\u9605", "\u5F53\u524D\u7269\u54C1\u5DF2\u8BA2\u9605, \u4E0D\u518D\u6267\u884C\u52A8\u4F5C. "); return false; } return true; }; (async () => { await getElement(".commentthread_header"); const subscribePossibility = judgeSubscribePossibility(); if (!subscribePossibility) { return; } subscribeFile(); })();