您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
复制网页中的Steamkey后自动激活,3.0+版本为Beta版
// ==UserScript== // @name AuTo Redeem Steamkey // @namespace HCLonely // @author HCLonely // @description 复制网页中的Steamkey后自动激活,3.0+版本为Beta版 // @version 3.4.1 // @supportURL https://keylol.com/t344489-1-1 // @homepage https://blog.hclonely.com/posts/71381355/ // @iconURL https://blog.hclonely.com/img/avatar.jpg // @include *://*/* // @exclude *store.steampowered.com/widget/* // @exclude *googleads* // @grant GM_setClipboard // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @run-at document-idle // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert.min.js // @connect * // @compatible chrome 没有测试其他浏览器的兼容性 // ==/UserScript== "use strict"; // asfCmd.ts var asfCommands = ` <table class="hclonely"> <thead> <tr> <th>命令</th> <th>权限</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td><code>2fa [Bots]</code></td> <td><code>Master</code></td> <td>为指定机器人生成临时的<strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN">两步验证</a></strong>令牌。</td> </tr> <tr> <td><code>2fafinalize [Bots] <ActivationCode></code></td> <td><code>Master</code></td> <td>使用短信或邮件验证码,完成为指定机器人绑定新<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN#%E5%88%9B%E5%BB%BA"><strong>两步验证</strong></a>凭据的流程。</td> </tr> <tr> <td><code>2fafinalized [Bots] <ActivationCode></code></td> <td><code>Master</code></td> <td>为指定机器人导入已创建完成的<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN#%E5%88%9B%E5%BB%BA"><strong>两步验证</strong></a>凭据,并用两步验证令牌代码验证。</td> </tr> <tr> <td><code>2fafinalizedforce [Bots]</code></td> <td><code>Master</code></td> <td>为指定机器人导入已创建完成的<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN#%E5%88%9B%E5%BB%BA"><strong>两步验证</strong></a>凭据,并跳过两步验证令牌代码验证。</td> </tr> <tr> <td><code>2fainit [Bots]</code></td> <td><code>Master</code></td> <td>开始为指定机器人绑定新<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN#%E5%88%9B%E5%BB%BA"><strong>两步验证</strong></a>凭据的流程。</td> </tr> <tr> <td><code>2fano [Bots]</code></td> <td><code>Master</code></td> <td>为指定机器人拒绝所有等待操作的<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN"><strong>两步验证</strong></a>交易确认。</td> </tr> <tr> <td><code>2faok [Bots]</code></td> <td><code>Master</code></td> <td>为指定机器人接受所有等待操作的<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Two-factor-authentication-zh-CN"><strong>两步验证</strong></a>交易确认。</td> </tr> <tr> <td><code>addlicense [Bots] <Licenses></code></td> <td><code>Operator</code></td> <td>为指定机器人激活给定的 <code>Licenses </code>(许可),该参数解释详见<a href="#addlicense-%E5%91%BD%E4%BB%A4%E7%9A%84-licenses-%E5%8F%82%E6%95%B0"><strong>下文</strong></a>。</td> </tr> <tr> <td><code>balance [Bots]</code></td> <td><code>Master</code></td> <td>显示指定机器人的 Steam 钱包余额。</td> </tr> <tr> <td><code>bgr [Bots]</code></td> <td><code>Master</code></td> <td>显示指定机器人的 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Background-games-redeemer-zh-CN">BGR</a></strong>(后台游戏激活器)队列信息。</td> </tr> <tr> <td><code>bgrclear [Bots]</code></td> <td><code>Master</code></td> <td>清除指定机器人的<a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Background-games-redeemer-zh-CN"><strong>后台游戏激活器</strong></a>队列。</td> </tr> <tr> <td><code>encrypt <encryptionMethod> <stringToEncrypt></code></td> <td><code>Owner</code></td> <td>以给定的加密方式加密字符串——详见<a href="#encrypt-%E5%91%BD%E4%BB%A4"><strong>下文的解释</strong></a>。</td> </tr> <tr> <td><code>exit</code></td> <td><code>Owner</code></td> <td>完全停止 ASF 进程。</td> </tr> <tr> <td><code>farm [Bots]</code></td> <td><code>Master</code></td> <td>重新启动指定机器人的挂卡模块。</td> </tr> <tr> <td><code>fb [Bots]</code></td> <td><code>Master</code></td> <td>列出指定机器人的自动挂卡黑名单。</td> </tr> <tr> <td><code>fbadd [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 加入指定机器人的自动挂卡黑名单。</td> </tr> <tr> <td><code>fbrm [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 从指定机器人的自动挂卡黑名单中移除。</td> </tr> <tr> <td><code>fq [Bots]</code></td> <td><code>Master</code></td> <td>列出指定机器人的优先挂卡队列。</td> </tr> <tr> <td><code>fqadd [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 加入指定机器人的优先挂卡队列。</td> </tr> <tr> <td><code>fqrm [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 从指定机器人的优先挂卡队列中移除。</td> </tr> <tr> <td><code>hash <hashingMethod> <stringToHash></code></td> <td><code>Owner</code></td> <td>以指定的加密方式生成给定字符串的哈希值——详见<a href="#hash-%E5%91%BD%E4%BB%A4"><strong>下文的解释</strong></a>。</td> </tr> <tr> <td><code>help</code></td> <td><code>FamilySharing</code></td> <td>显示帮助(指向此页面的链接)。</td> </tr> <tr> <td><code>input [Bots] <Type> <Value></code></td> <td><code>Master</code></td> <td>为指定机器人填写给定的输入值,仅在 <code>Headless</code> 模式中可用——详见<a href="#input-%E5%91%BD%E4%BB%A4"><strong>下文的解释</strong></a>。</td> </tr> <tr> <td><code>inventory [Bots]</code></td> <td><code>Operator</code></td> <td>显示指定机器人的库存摘要。</td> </tr> <tr> <td><code>level [Bots]</code></td> <td><code>Master</code></td> <td>显示指定机器人的 Steam 帐户等级。</td> </tr> <tr> <td><code>loot [Bots]</code></td> <td><code>Master</code></td> <td>将指定机器人的所有 <code>LootableTypes</code> 社区物品拾取到其 <code>SteamUserPermissions</code> 属性中设置的 <code>Master</code> 用户(如果有多个则取 steamID 最小的)。</td> </tr> <tr> <td><code>loot@ [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将指定机器人的所有符合给定 <code>AppIDs</code> 的 <code>LootableTypes</code> 社区物品拾取到其 <code>SteamUserPermissions</code> 属性中设置的 <code>Master</code> 用户(如果有多个则取 steamID 最小的)。 此命令与 <code>loot%</code> 相反。</td> </tr> <tr> <td><code>loot% [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将指定机器人的所有不符合给定 <code>AppIDs</code> 的 <code>LootableTypes</code> 社区物品拾取到其 <code>SteamUserPermissions</code> 属性中设置的 <code>Master</code> 用户(如果有多个则取 steamID 最小的)。 此命令与 <code>loot@</code> 相反。</td> </tr> <tr> <td><code>loot^ [Bots] <AppID> <ContextID></code></td> <td><code>Master</code></td> <td>将指定机器人的 <code>ContextID</code> 库存分类中符合给定 <code>AppID</code> 的物品拾取到其 <code>SteamUserPermissions</code> 属性中设置的 <code>Master</code> 用户(如果有多个则取 steamID 最小的)。</td> </tr> <tr> <td><code>loot& [Bots] <AppID> <ContextID> <Rarities></code></td> <td><code>Master</code></td> <td>将指定机器人的 <code>ContextID</code> 库存分类中符合给定 <code>AppID</code> 并且符合给定 <strong><a href="#%E5%B7%B2%E7%9F%A5%E7%9A%84%E7%A8%80%E6%9C%89%E5%BA%A6"><code>Rarities</code></a></strong> 的物品拾取到其 <code>SteamUserPermissions</code> 属性中设置的 <code>Master</code> 用户(如果有多个则取 steamID 最小的)。</td> </tr> <tr> <td><code>mab [Bots]</code></td> <td><code>Master</code></td> <td>列出 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/ItemsMatcherPlugin-zh-CN#matchactively%E4%B8%BB%E5%8A%A8%E5%8C%B9%E9%85%8D"><code>MatchActively</code></a></strong> 自动交易的 App 黑名单。</td> </tr> <tr> <td><code>mabadd [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 加入到 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/ItemsMatcherPlugin-zh-CN#matchactively%E4%B8%BB%E5%8A%A8%E5%8C%B9%E9%85%8D"><code>MatchActively</code></a></strong> 自动交易的 App 黑名单。</td> </tr> <tr> <td><code>mabrm [Bots] <AppIDs></code></td> <td><code>Master</code></td> <td>将给定的 <code>AppIDs</code> 从 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/ItemsMatcherPlugin-zh-CN#matchactively%E4%B8%BB%E5%8A%A8%E5%8C%B9%E9%85%8D"><code>MatchActively</code></a></strong> 自动交易的 App 黑名单中移除。</td> </tr> <tr> <td><code>match [Bots]</code></td> <td><code>Master</code></td> <td>控制 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/ItemsMatcherPlugin-zh-CN#matchactively%E4%B8%BB%E5%8A%A8%E5%8C%B9%E9%85%8D"><code>ItemsMatcherPlugin</code></a></strong> 的特殊命令,用于立即触发 <code>MatchActively</code> 流程。</td> </tr> <tr> <td><code>nickname [Bots] <Nickname></code></td> <td><code>Master</code></td> <td>将指定机器人的昵称更改为 <code>Nickname</code>。</td> </tr> <tr> <td><code>owns [Bots] <Games></code></td> <td><code>Operator</code></td> <td>检查指定机器人是否已拥有 <code>Games</code>,该参数解释详见<a href="#owns-%E5%91%BD%E4%BB%A4%E7%9A%84-games-%E5%8F%82%E6%95%B0"><strong>下文</strong></a>。</td> </tr> <tr> <td><code>pause [Bots]</code></td> <td><code>Operator</code></td> <td>永久暂停指定机器人的自动挂卡模块。 ASF 在本次会话中将不会再尝试对此帐户进行挂卡,除非您手动 <code>resume</code> 或者重启 ASF。</td> </tr> <tr> <td><code>pause~ [Bots]</code></td> <td><code>FamilySharing</code></td> <td>临时暂停指定机器人的自动挂卡模块。 挂卡进程将会在下次游戏事件或者机器人断开连接时自动恢复。 您可以 <code>resume</code> 以恢复挂卡。</td> </tr> <tr> <td><code>pause& [Bots] <Seconds></code></td> <td><code>Operator</code></td> <td>临时暂停指定机器人的自动挂卡模块 <code>Seconds</code> 秒。 之后,挂卡模块会自动恢复。</td> </tr> <tr> <td><code>play [Bots] <AppIDs,GameName></code></td> <td><code>Master</code></td> <td>切换到手动挂卡——使指定机器人运行给定的 <code>AppIDs</code>,并且可选自定义 <code>GameName</code> 为游戏名称。 若要此功能正常工作,您的 Steam 帐户<strong>必须</strong>拥有所有您指定的 <code>AppIDs</code> 的有效许可,包括免费游戏。 使用 <code>reset</code> 或 <code>resume</code> 命令恢复。</td> </tr> <tr> <td><code>points [Bots]</code></td> <td><code>Master</code></td> <td>显示指定机器人的 <a href="https://store.steampowered.com/points/shop" rel="nofollow"><strong>Steam 点数商店</strong></a>点数余额。</td> </tr> <tr> <td><code>privacy [Bots] <Settings></code></td> <td><code>Master</code></td> <td>更改指定机器人的 <strong><a href="https://steamcommunity.com/my/edit/settings" rel="nofollow">Steam 隐私设置</a></strong>,可用选项见<a href="#privacy-%E8%AE%BE%E7%BD%AE"><strong>下文</strong></a>。</td> </tr> <tr> <td><code>redeem [Bots] <Keys></code></td> <td><code>Operator</code></td> <td>为指定机器人激活给定的游戏序列号或钱包充值码。</td> </tr> <tr> <td><code>redeem^ [Bots] <Modes> <Keys></code></td> <td><code>Operator</code></td> <td>以 <code>Modes</code> 模式为指定机器人激活给定的游戏序列号或钱包充值码,模式详见下文的<a href="#redeem-%E6%A8%A1%E5%BC%8F"><strong>解释</strong></a>。</td> </tr> <tr> <td><code>redeempoints [Bots] <DefinitionIDs></code></td> <td><code>Operator</code></td> <td>为指定机器人以 <a href="https://store.steampowered.com/points/shop" rel="nofollow"><strong>Steam 点数</strong></a>兑换给定物品。 默认只允许免费物品,如果要无条件兑换物品,包括付费物品,则需要在每个符合条件的物品 <code>DefinitionID</code> 结尾添加 <code>!</code> 符号。</td> </tr> <tr> <td><code>reset [Bots]</code></td> <td><code>Master</code></td> <td>重置为原始(之前的)游玩状态,用来配合 <code>play</code> 命令的手动挂卡模式使用。</td> </tr> <tr> <td><code>restart</code></td> <td><code>Owner</code></td> <td>重新启动 ASF 进程。</td> </tr> <tr> <td><code>resume [Bots]</code></td> <td><code>FamilySharing</code></td> <td>恢复指定机器人的自动挂卡进程。</td> </tr> <tr> <td><code>start [Bots]</code></td> <td><code>Master</code></td> <td>启动指定机器人。</td> </tr> <tr> <td><code>stats</code></td> <td><code>Owner</code></td> <td>显示进程统计信息,例如托管内存用量。</td> </tr> <tr> <td><code>status [Bots]</code></td> <td><code>FamilySharing</code></td> <td>显示指定机器人的状态。</td> </tr> <tr> <td><code>std [Bots]</code></td> <td><code>Master</code></td> <td>控制 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/SteamTokenDumperPlugin-zh-CN"><code>SteamTokenDumperPlugin</code></a></strong> 的特殊命令,用于触发刷新指定的机器人并立即提交数据。</td> </tr> <tr> <td><code>stop [Bots]</code></td> <td><code>Master</code></td> <td>停止指定机器人。</td> </tr> <tr> <td><code>tb [Bots]</code></td> <td><code>Master</code></td> <td>列出指定机器人的交易黑名单用户。</td> </tr> <tr> <td><code>tbadd [Bots] <SteamIDs64></code></td> <td><code>Master</code></td> <td>将给定的 <code>SteamIDs</code> 加入指定机器人的交易黑名单。</td> </tr> <tr> <td><code>tbrm [Bots] <SteamIDs64></code></td> <td><code>Master</code></td> <td>将给定的 <code>SteamIDs</code> 从指定机器人的交易黑名单中移除。</td> </tr> <tr> <td><code>transfer [Bots] <TargetBot></code></td> <td><code>Master</code></td> <td>将指定机器人的所有 <code>TransferableTypes</code> 社区物品转移到一个目标机器人。</td> </tr> <tr> <td><code>transfer@ [Bots] <AppIDs> <TargetBot></code></td> <td><code>Master</code></td> <td>将指定机器人的所有符合给定 <code>AppIDs</code> 的 <code>TransferableTypes</code> 社区物品转移到一个目标机器人。 此命令与 <code>transfer%</code> 相反。</td> </tr> <tr> <td><code>transfer% [Bots] <AppIDs> <TargetBot></code></td> <td><code>Master</code></td> <td>将指定机器人的所有不符合给定 <code>AppIDs</code> 的 <code>TransferableTypes</code> 社区物品转移到一个目标机器人。 此命令与 <code>transfer@</code> 相反。</td> </tr> <tr> <td><code>transfer^ [Bots] <AppID> <ContextID> <TargetBot></code></td> <td><code>Master</code></td> <td>将指定机器人的 <code>ContextID</code> 库存分类中符合给定 <code>AppID</code> 的物品转移到一个目标机器人。</td> </tr> <tr> <td><code>transfer& [Bots] <AppID> <ContextID> <TargetBot> <Rarities></code></td> <td><code>Master</code></td> <td>将指定机器人的 <code>ContextID</code> 库存分类中符合给定 <code>AppID</code> 并且符合给定 <strong><a href="#%E5%B7%B2%E7%9F%A5%E7%9A%84%E7%A8%80%E6%9C%89%E5%BA%A6"><code>Rarities</code></a></strong> 的物品转移到一个目标机器人。</td> </tr> <tr> <td><code>unpack [Bots]</code></td> <td><code>Master</code></td> <td>拆开指定机器人库存中的所有补充包。</td> </tr> <tr> <td><code>update [Channel]</code></td> <td><code>Owner</code></td> <td>在 GitHub 上检查 ASF 新版本,如果可用则更新。 通常这会每隔 <code>UpdatePeriod</code> 自动执行一次。 可选的 <code>Channel</code> 参数指定 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration-zh-CN#updatechannel"><code>UpdateChannel</code></a></strong>,如果未提供,则默认使用全局设置中的值。 <code>Channel</code> 可以用 <code>!</code> 字符结尾,这会强制在指定频道上更新——包括降级等操作。</td> </tr> <tr> <td><code>updateplugins [Channel] [Plugins]</code></td> <td><code>Owner</code></td> <td>更新指定的插件。 如果插件支持多个更新频道,可选的 <code>Channel</code> 参数允许您选择不同的 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration-zh-CN#updatechannel"><code>UpdateChannel</code></a></strong> 进行更新。 <code>Channel</code> 可以用 <code>!</code> 字符结尾,这会强制在指定频道上更新——包括降级等操作,但具体的功能取决于插件自身。 如果不指定 <code>Plugins</code>,则所有由 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration-zh-CN#pluginsupdatelist"><code>PluginsUpdateList</code></a></strong> 和 <strong><a href="https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration-zh-CN#pluginsupdatemode"><code>PluginsUpdateMode</code></a></strong> 配置判断为允许自动更新的插件都会被更新。 如果您要更新指定插件,特别是已经默认禁用自动更新的,则需要同时提供 <code>Channel</code> 和 <code>Plugins</code> 参数,这样 ASF 就会忽略其自动更新设置,强行更新它们。</td> </tr> <tr> <td><code>version</code></td> <td><code>FamilySharing</code></td> <td>显示 ASF 的版本号。</td> </tr> </tbody> </table> `; // asf.ts var getASFConfig = (setting) => ({ protocol: setting.asfProtocol, host: setting.asfHost, port: setting.asfPort, password: setting.asfPassword }); var getASFHeaders = (setting) => { const { protocol, host, port } = getASFConfig(setting); return { accept: "application/json", "Content-Type": "application/json", Authentication: setting.asfPassword, Host: `${host}:${port}`, Origin: `${protocol}://${host}:${port}`, Referer: `${protocol}://${host}:${port}/page/commands` }; }; var getASFUrl = (setting) => { const { protocol, host, port } = getASFConfig(setting); return `${protocol}://${host}:${port}/Api/Command`; }; function asfSend(command = "") { const setting = GM_getValue("setting") || globalThis.defaultSetting; if (!setting?.asf) { swal({ closeOnClickOutside: false, className: "swal-user", icon: "warning", title: "此功能需要在设置中配置ASF IPC并开启ASF功能!", //@ts-ignore buttons: { confirm: "确定" } }); return; } swal({ closeOnClickOutside: false, className: "swal-user", text: "请在下方输入要执行的ASF指令:", content: { element: "input", attributes: { placeholder: "输入ASF指令" } }, //@ts-ignore buttons: { test: "连接测试", redeem: "激活key", pause: "暂停挂卡", resume: "恢复挂卡", "2fa": "获取令牌", "2faok": "2faok", more: "更多ASF指令", confirm: "确定", cancel: "取消" } }).then((value) => { switch (value) { case "redeem": swalRedeem(); break; case "pause": case "resume": case "2fa": case "2faok": asfRedeem(`!${value}`); break; case "test": asfTest(); break; case "more": swal({ closeOnClickOutside: false, className: "swal-user", text: "ASF指令", //@ts-ignore content: $(asfCommands)[0], //@ts-ignore buttons: { confirm: "返回", cancel: "关闭" } }).then((value2) => { if (value2) asfSend(); }); $("table.hclonely button.swal-button").on("click", function() { const command2 = setting.asfBot ? $(this).parent().next().text().trim().replace(/<Bots>/gim, setting.asfBot) : $(this).parent().next().text().trim(); asfSend(command2); }); break; case null: break; default: const inputValue = $(".swal-content__input").val()?.toString()?.trim(); if (!inputValue) { swal({ closeOnClickOutside: false, title: "ASF指令不能为空!", icon: "warning", //@ts-ignore buttons: { confirm: "确定" } }).then(() => { asfSend(command); }); } else { const finalCommand = value || inputValue; if (finalCommand) asfRedeem(finalCommand); } break; } }); if (command) { $(".swal-content__input").val(`!${command}`); } } function swalRedeem() { swal({ closeOnClickOutside: false, className: "swal-user", title: "请输入要激活的key:", //@ts-ignore content: $('<textarea id="keyText" class="asf-output"></textarea>')[0], //@ts-ignore buttons: { confirm: "激活", cancel: "返回" } }).then((value) => { if (value) { const key = getKeysByRE($("#keyText").val()?.toString()?.trim() || ""); if (key.length > 0) { const setting = GM_getValue("setting") || globalThis.defaultSetting; const asfBot = setting.asfBot ? `${setting.asfBot} ` : ""; asfRedeem(`!redeem ${asfBot}${key.join(",")}`); } else { swal({ closeOnClickOutside: false, title: "steam key不能为空!", icon: "error", //@ts-ignore buttons: { confirm: "返回", cancel: "关闭" } }).then((value2) => { if (value2) { swalRedeem(); } }); } } else { asfSend(); } }); } function asfTest() { const setting = GM_getValue("setting") || globalThis.defaultSetting; if (!setting.asf) { swal({ closeOnClickOutside: false, title: "请先在设置中开启ASF功能", icon: "warning", //@ts-ignore buttons: { confirm: "确定" } }); return; } const apiUrl = getASFUrl(setting); swal({ closeOnClickOutside: false, title: "ASF连接测试", text: `正在尝试连接 "${apiUrl}"`, //@ts-ignore buttons: { confirm: "确定" } }); GM_xmlhttpRequest({ method: "POST", url: apiUrl, data: '{"Command":"!stats"}', responseType: "json", headers: getASFHeaders(setting), onload(data) { const response = data.response; if (data.status === 200) { if (response?.Success === true && response.Message === "OK" && response.Result) { swal({ closeOnClickOutside: false, title: "ASF连接成功!", icon: "success", text: `连接地址 "${apiUrl}" 返回内容 "${response.Result.trim()}"`, //@ts-ignore buttons: { confirm: "确定" } }); } else if (response?.Message) { swal({ closeOnClickOutside: false, title: "ASF连接成功?", icon: "info", text: `连接地址 "${apiUrl}" 返回内容 "${response.Message.trim()}"`, //@ts-ignore buttons: { confirm: "确定" } }); } else { swal({ closeOnClickOutside: false, title: "ASF连接失败!", icon: "error", text: `连接地址 "${apiUrl}" 返回内容 "${data.responseText}"`, //@ts-ignore buttons: { confirm: "确定" } }); } } else { swal({ closeOnClickOutside: false, title: `ASF连接失败:${data.status}`, icon: "error", text: `连接地址 "${apiUrl}"`, //@ts-ignore buttons: { confirm: "确定" } }); } }, onabort() { showErrorDialog("ASF连接失败:aborted", apiUrl); }, onerror() { showErrorDialog("ASF连接失败:error", apiUrl); }, ontimeout() { showErrorDialog("ASF连接失败:timeout", apiUrl); } }); } function showErrorDialog(title, apiUrl) { swal({ closeOnClickOutside: false, title, icon: "error", text: `连接地址 "${apiUrl}"`, //@ts-ignore buttons: { confirm: "确定" } }); } function asfRedeem(command) { const setting = GM_getValue("setting") || globalThis.defaultSetting; const apiUrl = getASFUrl(setting); const textarea = document.createElement("textarea"); textarea.setAttribute("class", "asf-output"); textarea.setAttribute("readonly", "readonly"); const btn = /!redeem/gim.test(command) ? { confirm: "提取未使用key", cancel: "关闭" } : { confirm: "确定" }; swal({ closeOnClickOutside: false, className: "swal-user", text: `正在执行ASF指令:${command}`, //@ts-ignore content: textarea, //@ts-ignore buttons: btn }).then((v) => { if (/!redeem/gim.test(command)) { let value = ""; const textareaElement = $(".swal-content textarea"); if (textareaElement.length > 0) { value = textareaElement.val()?.toString() || ""; } GM_setValue("history", [$(".swal-content").html() || "", value]); if (v) { const unUseKey = textareaElement.val()?.toString()?.split(/[(\r\n)\r\n]+/).filter((e) => /未使用/gim.test(e || "")).join(","); if (unUseKey) { GM_setClipboard(arr(getKeysByRE(unUseKey)).join(",")); swal({ title: "复制成功!", icon: "success" }); } } } }); GM_xmlhttpRequest({ method: "POST", url: apiUrl, data: JSON.stringify({ Command: command }), responseType: "json", headers: getASFHeaders(setting), onload(data) { console.log(data); console.log(command); if (data.status === 200) { if (data.response?.Success && data.response.Message === "OK" && data.response.Result) { textarea.value += `${data.response.Result.trim()} `; } else if (data.response?.Message) { textarea.value += `${data.response.Message.trim()} `; } else { textarea.value += data.responseText || ""; } } else { swal({ closeOnClickOutside: false, className: "swal-user", title: `执行ASF指令(${command})失败!请检查ASF配置是否正确!`, text: data.responseText || data.status.toString(), icon: "error", //@ts-ignore buttons: { confirm: "关闭" } }); } }, onabort() { swal({ closeOnClickOutside: false, className: "swal-user", title: `执行ASF指令(${command})失败!请检查网络!`, text: "aborted", icon: "error", //@ts-ignore buttons: { confirm: "关闭" } }); }, onerror(error) { console.error(error); swal({ closeOnClickOutside: false, className: "swal-user", title: `执行ASF指令(${command})失败!请检查控制台日志!`, text: "error", icon: "error", //@ts-ignore buttons: { confirm: "关闭" } }); }, ontimeout() { swal({ closeOnClickOutside: false, className: "swal-user", title: `执行ASF指令(${command})失败!请检查网络!`, text: "连接超时", icon: "error", //@ts-ignore buttons: { confirm: "关闭" } }); } }); } // utils.ts function mouseClick($2, e) { const $i = $2("<span/>").text("Steam Key"); const x = e.pageX; const y = e.pageY; $i.css({ "z-index": 999999999999999, top: y - 20, left: x, position: "absolute", "font-weight": "bold", color: "#ff6651" }); $2("body").append($i); $i.animate({ top: y - 180, opacity: 0 }, 1500, () => { $i.remove(); }); } function addBtn() { const div = $('<div id="keyDiv" style="position:fixed;left:5px;bottom:5px"></div>'); const btn = $('<button id="allKey" class="btn btn-default" key="" style="display:none;z-index:9999">激活本页面所有key(共0个)</button>')[0]; btn.onclick = function() { const setting = GM_getValue("setting") || {}; const keys = getKeysByRE($(this).attr("key") || ""); if (setting.asf) { asfRedeem(`!redeem ${setting.asfBot} ${keys.join(",")}`); } else if (setting.newTab) { window.open(`https://store.steampowered.com/account/registerkey?key=${keys.join(",")}`, "_blank"); } else { webRedeem(keys.join(",")); } }; div.append(btn); $("body").append(div); return btn; } function redeemAllKey() { let len = 0; let keyList = ""; let hasKey = []; const btn = addBtn(); setInterval(() => { const allSteamKey = arr(getKeysByRE($("body").text() || "")) || []; len = allSteamKey.length; if (len > 0) { hasKey.push(...allSteamKey); hasKey = arr(hasKey); keyList = hasKey.join(","); if ($(btn).attr("key") !== keyList) { $(btn).attr("key", keyList).text(`激活本页面所有key(共${hasKey.length}个)`).show(); } } else if (document.getElementById("allKey")?.style?.display === "block") { $(btn).hide().text("激活本页面所有key(共0个)"); } }, 1e3); } function arr(arr2) { return [...new Set(arr2)]; } async function httpRequest(options, times = 0) { if (window.TRACE) { console.trace("%cAuto-Task[Debug]:", "color:blue"); } try { const result = await new Promise((resolve) => { if (options.dataType) { options.responseType = options.dataType; } const requestObj = { timeout: 3e4, ontimeout(data) { resolve({ result: "Error", statusText: "Timeout", status: 601, data, options }); }, onabort(data) { resolve({ result: "Error", statusText: "Aborted", status: 602, data, options }); }, onerror(data) { resolve({ result: "Error", statusText: "Error", status: 603, data, options }); }, onload(data) { if (options.responseType === "json" && data?.responseText && typeof data.response !== "object") { try { data.response = JSON.parse(data.responseText); } catch (error) { } } resolve({ result: "Success", statusText: "Load", status: 600, data, options }); }, ...options }; GM_xmlhttpRequest(requestObj); }); if (window.DEBUG) { console.log("%cAuto-Task[httpRequest]:", "color:blue", JSON.stringify(result)); } if (result.status !== 600 && times < 2) { return await httpRequest(options, times + 1); } return result; } catch (error) { console.log("%cAuto-Task[httpRequest]:", "color:red", JSON.stringify({ errorMsg: error, options })); return { result: "JsError", statusText: "Error", status: 604, error, options }; } } function settingChange() { const setting = GM_getValue("setting") || globalThis.defaultSetting; const div = $(` <div id="hclonely-asf"> <input type="checkbox" name="newTab" ${setting.newTab ? "checked=checked" : ""} title="开启ASF激活后此功能无效"/> <span title="开启ASF激活后此功能无效">新标签页激活</span> <br/> <input type="checkbox" name="copyListen" ${setting.copyListen ? "checked=checked" : ""} title="复制key时询问是否激活"/> <span title="复制key时询问是否激活">开启复制捕捉</span> <input type="checkbox" name="selectListen" ${setting.selectListen ? "checked=checked" : ""} title="选中key时显示激活图标"/> <span title="选中key时显示激活图标">开启选中捕捉</span> <input type="checkbox" name="clickListen" ${setting.clickListen ? "checked=checked" : ""} title="点击key时添加激活链接"/> <span title="点击key时添加激活链接">开启点击捕捉</span><br/> <input type="checkbox" name="allKeyListen" ${setting.allKeyListen ? "checked=checked" : ""} title="匹配页面内所有符合steam key格式的内容"/> <span title="匹配页面内所有符合steam key格式的内容">捕捉页面内所有key</span> <div class="swal-title">ASF IPC设置</div> <span>ASF IPC协议</span><input type="text" name="asfProtocol" value='${setting.asfProtocol}' placeholder="http或https,默认为http"/> <br/> <span>ASF IPC地址</span><input type="text" name="asfHost" value='${setting.asfHost}' placeholder="ip地址或域名,默认为127.0.0.1"/> <br/> <span>ASF IPC端口</span><input type="text" name="asfPort" value='${setting.asfPort}' placeholder="默认1242"/> <br/> <span>ASF IPC密码</span><input type="text" name="asfPassword" value='${setting.asfPassword}' placeholder="ASF IPC密码"/> <br/> <span>ASF Bot名字</span><input type="text" name="asfBot" value='${setting.asfBot}' placeholder="ASF Bot name,可留空"/> <br/> <input type="checkbox" name="asf" ${setting.asf ? "checked=checked" : ""} title="此功能默认关闭新标签页激活"/> <span title="此功能默认关闭新标签页激活">开启ASF激活</span> </div>`)[0]; swal({ closeOnClickOutside: false, className: "asf-class", title: "全局设置", content: div, buttons: { save: "保存", showHistory: "上次激活记录", showSwitchKey: "Key格式转换", cancel: "取消" } }).then((value) => { if (value === "save") { const newSetting = {}; $("#hclonely-asf input").each(function(index, element) { const name = $(element).attr("name"); if (name) { newSetting[name] = element.type === "checkbox" ? element.checked : element.value; } }); GM_setValue("setting", newSetting); swal({ closeOnClickOutside: false, icon: "success", title: "保存成功!", text: "刷新页面后生效!", buttons: { confirm: "确定" } }); } else if (value === "showHistory") { showHistory(); } else if (value === "showSwitchKey") { showSwitchKey(); } }); } function showHistory() { const history = GM_getValue("history"); if (Array.isArray(history)) { swal({ closeOnClickOutside: false, className: "swal-user", title: "上次激活记录:", content: $(history[0])[0], buttons: { confirm: "确定" } }); if (history[1]) { $(".swal-content textarea").val(history[1]); } } else { swal({ closeOnClickOutside: false, title: "没有操作记录!", icon: "error", buttons: { cancel: "关闭" } }); } } function showSwitchKey() { swal({ closeOnClickOutside: false, title: "请选择要转换成什么格式:", buttons: { confirm: "确定", cancel: "关闭" }, content: $('<div class="switch-key"><div class="switch-key-left"><p>key</p><p>key</p><p>key</p><input name="keyType" type="radio" value="1"/></div><div class="switch-key-right"><p> </p><p>key,key,key</p><p> </p><input name="keyType" type="radio" value="2"/></div></div>')[0] }).then((value) => { if (value) { const selectedValue = $("input:radio:checked").val(); if (selectedValue) { showSwitchArea(selectedValue); } else { swal({ closeOnClickOutside: false, title: "请选择要将key转换成什么格式!", icon: "warning" }).then(() => showSwitchKey()); } } }); $(".switch-key div").each(function() { $(this).on("click", function() { $(this).find("input")[0].click(); }); }); } function showSwitchArea(type) { swal({ closeOnClickOutside: false, title: "请输入要转换的key:", content: $('<textarea style="width: 80%;height: 100px;"></textarea>')[0], buttons: { confirm: "转换", back: "返回", cancel: "关闭" } }).then((value) => { if (value === "back") { showSwitchKey(); } else if (value) { const inputKey = $(".swal-content textarea").val(); if (inputKey) { switchKey(inputKey, type); } } }); } function switchKey(key, type) { switch (type) { case "1": showKey(getKeysByRE(key).join("\n"), type); break; case "2": showKey(getKeysByRE(key).join(","), type); break; default: break; } } function showKey(key, type) { swal({ closeOnClickOutside: false, icon: "success", title: "转换成功!", content: $(`<textarea style="width: 80%;height: 100px;" readonly="readonly">${key}</textarea>`)[0], buttons: { confirm: "返回", cancel: "关闭" } }).then((value) => { if (value) { showSwitchArea(type); } }); $(".swal-content textarea").on("click", function() { this.select(); }); } function getKeysByRE(text) { text = text.trim().toUpperCase(); const reg = new RegExp("([0-9A-Z]{5}-){2,4}[0-9A-Z]{5}", "g"); const keys = []; let result; while (result = reg.exec(text)) { keys.push(result[0]); } return keys; } // steamWeb.ts var STEAM_HOSTS = { STORE: "store.steampowered.com", LOGIN: "login.steampowered.com" }; var handleError = (error, message) => { console.error(`${message}:`, error); return false; }; async function refreshToken() { try { const formData = new FormData(); formData.append("redir", `https://${STEAM_HOSTS.STORE}/`); const response = await httpRequest({ url: `https://${STEAM_HOSTS.LOGIN}/jwt/ajaxrefresh`, method: "POST", responseType: "json", headers: { Host: STEAM_HOSTS.LOGIN, Origin: `https://${STEAM_HOSTS.STORE}`, Referer: `https://${STEAM_HOSTS.STORE}/` }, data: formData }); if (response.result === "Success" && response.data?.response?.success) { return await setStoreToken(response.data.response); } return false; } catch (error) { return handleError(error, "Failed to refresh token"); } } async function setStoreToken(param) { try { const host = "store.steampowered.com"; const formData = new FormData(); formData.append("steamID", param.steamID); formData.append("nonce", param.nonce); formData.append("redir", param.redir); formData.append("auth", param.auth); const { result, statusText, status, data } = await httpRequest({ url: `https://${host}/login/settoken`, method: "POST", headers: { Accept: "application/json, text/plain, */*", Host: host, Origin: `https://${host}` // Referer: `https://${host}/login` }, data: formData }); if (result === "Success") { if (data?.status === 200) { return true; } return false; } return false; } catch (error) { console.error(error); return false; } } async function updateStoreAuth(retry = false) { try { const { result, statusText, status, data } = await httpRequest({ url: "https://store.steampowered.com/", method: "GET", headers: { Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Cache-Control": "max-age=0", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Upgrade-Insecure-Requests": "1" }, fetch: false, redirect: "manual" }); if (data?.status === 200) { if (!data.responseText.includes("data-miniprofile=")) { if (await refreshToken()) { if (retry) { return false; } return updateStoreAuth(true); } return false; } const storeSessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1]; if (storeSessionID) { globalThis.sessionID = storeSessionID; return true; } return false; } if ([301, 302].includes(data?.status)) { if (await refreshToken()) { if (retry) { return false; } return updateStoreAuth(true); } return false; } return false; } catch (error) { console.error(error); return false; } } var showSwalMessage = (options) => { return swal({ className: "swal-user", closeOnClickOutside: false, ...options }); }; function webRedeem(key) { const redeemContent = createRedeemContent(); showSwalMessage({ title: "正在获取sessionID...", buttons: { confirm: "关闭" } }); if (!globalThis.sessionID) { handleNoSession(key, redeemContent); return; } showRedeemDialog(key, redeemContent); } function createRedeemContent() { return $(` <div id="registerkey_examples_text"> <div class="notice_box_content" id="unusedKeyArea"> <b>未使用的Key:</b><br> <div><ol id="unusedKeys" align="left"></ol></div> </div> <div class="table-responsive table-condensed"> <table class="table table-hover hclonely"> <caption><h2>激活记录</h2></caption> <thead> <th>No.</th><th>Key</th><th>结果</th><th>详情</th><th>Sub</th> </thead> <tbody></tbody> </table> </div> <br> </div> `)[0]; } function handleNoSession(key, redeemContent) { GM_xmlhttpRequest({ method: "GET", url: "https://store.steampowered.com/account/registerkey", onload: async (data) => { if (data.finalUrl.includes("login") && !await updateStoreAuth()) { showSwalMessage({ title: "请先登录(不可用)steam!", icon: "warning", buttons: { confirm: "登录(不可用)", cancel: "关闭" } }).then((value) => { if (value) window.open("https://store.steampowered.com/login/", "_blank"); }); } else { if (data.status === 200) { globalThis.sessionID = data.responseText?.match(/g_sessionID = "(.+?)";/)?.[1] || ""; showRedeemDialog(key, redeemContent); } else { showSwalMessage({ title: "获取sessionID失败!", icon: "error", buttons: { confirm: "关闭" } }); } } } }); } function showRedeemDialog(key, redeemContent) { showSwalMessage({ title: "正在激活steam key...", content: redeemContent, buttons: { confirm: "提取未使用key", cancel: "关闭" } }).then((v) => { let value = ""; const textarea = $(".swal-content textarea"); if (textarea.length > 0) { value = textarea.val()?.toString() || ""; } GM_setValue("history", [$(".swal-content").html() || "", value]); if (v) { GM_setClipboard(arr(getKeysByRE($("#unusedKeys").text() || "")).join(",")); showSwalMessage({ title: "复制成功!", icon: "success" }); } }); redeemKeys(key); } function redeemSub(e) { const subText = e || $("#gameSub").val(); if (subText) { const ownedPackages = {}; $(".account_table a").each((i, el) => { const match = el.href.match(/javascript:RemoveFreeLicense\( ([0-9]+), '/); if (match !== null) { ownedPackages[+match[1]] = true; } }); const freePackages = subText.match(/[\d]{2,}/g) || []; let loaded = 0; const total = freePackages.length; swal("正在执行…", "请等待所有请求完成。 忽略所有错误,让它完成。"); freePackages.forEach((packae) => { const packageId = parseInt(packae, 10); if (ownedPackages[packageId]) { loaded++; return; } $.post("//store.steampowered.com/checkout/addfreelicense", { action: "add_to_cart", sessionid: g_sessionID, subid: packageId }).always(() => { loaded++; if (loaded >= total) { if (window.location.href.includes("licenses")) { window.open("https://store.steampowered.com/account/licenses/", "_self"); } else { swal("全部激活完成,是否前往账户页面查看结果?", { //@ts-ignore buttons: { cancel: "取消", 确定: true } }).then((value) => { if (value) { window.open("https://store.steampowered.com/account/licenses/", "_blank"); } }); } } else { swal("正在激活…", `进度:${loaded}/${total}.`); } }); }); } } function redeemSubs() { const key = $("#inputKey").val()?.trim(); if (key) { redeemSub(key); } } async function cc() { try { showSwalMessage({ title: "正在获取当前国家/地区...", icon: "info" }); const cartData = await fetchCartData(); const { cartConfig, userInfo } = parseCartData(cartData); if (!isValidCartConfig(cartConfig, userInfo)) { showSwalMessage({ title: "需要挂相应地区的梯子!", icon: "warning" }); return; } showCountryChangeDialog(cartConfig, userInfo, cartData); } catch (error) { showSwalMessage({ title: "获取当前国家/地区失败!", icon: "error" }); } } function fetchCartData() { return new Promise((resolve, reject) => { $.ajax({ url: "//store.steampowered.com/cart/", type: "get", success: (data) => resolve(data), error: reject }); }); } function parseCartData(data) { const cartConfigRaw = data.match(/data-cart_config="(.*?)"/)?.[1]; const temp = document.createElement("div"); temp.innerHTML = cartConfigRaw || ""; const cartConfigStr = temp.textContent || temp.innerText || ""; try { const cartConfig = JSON.parse(cartConfigStr); if (!cartConfig || !cartConfig.rgUserCountryOptions) { throw new Error("Invalid cartConfig format"); } const userInfoRaw = data.match(/data-userinfo="(.*?)"/)?.[1]; const temp1 = document.createElement("div"); temp1.innerHTML = userInfoRaw || ""; const userInfoStr = temp1.textContent || temp1.innerText || ""; const userInfo = JSON.parse(userInfoStr); if (!userInfo || !userInfo.country_code) { throw new Error("Invalid userInfo format"); } return { cartConfig, userInfo }; } catch (e) { throw new Error("Failed to parse Steam data"); } } function isValidCartConfig(cartConfig, userInfo) { return cartConfig && userInfo && Object.keys(cartConfig.rgUserCountryOptions).length > 2; } function bindCurrencyChangeOption() { const checkElement = () => { const $currencyChangeOptions = $(".currency_change_option"); if ($currencyChangeOptions.length > 0) { $currencyChangeOptions.click(function() { const newCountry = $(this).attr("data-country"); if (newCountry) { changeCountry(newCountry); } }); return true; } return false; }; const intervalId = setInterval(() => { if (checkElement()) { clearInterval(intervalId); } }, 500); setTimeout(() => { clearInterval(intervalId); }, 1e4); } function showCountryChangeDialog(cartConfig, userInfo, cartData) { const divContent = cartData.match(/<div class="currency_change_options">([\w\W]*?)<p/i)?.[1]?.trim(); const div = `${divContent || ""}</div>`; showSwalMessage({ closeOnClickOutside: false, title: `当前国家/地区:${cartConfig.rgUserCountryOptions[userInfo.country_code] || userInfo.country_code}`, //@ts-ignore content: $(`<div>${div}</div>`)[0] }); bindCurrencyChangeOption(); } function changeCountry(country) { showSwalMessage({ closeOnClickOutside: false, icon: "info", title: "正在更换国家/地区..." }); $.ajax({ url: "//store.steampowered.com/country/setcountry", type: "post", data: { sessionid: g_sessionID, cc: country }, complete() { $.ajax({ url: "//store.steampowered.com/cart/", type: "get", success(data) { const cartConfigRaw = data.match(/data-cart_config="(.*?)"/)?.[1]; const temp = document.createElement("div"); temp.innerHTML = cartConfigRaw || ""; const cartConfigStr = temp.textContent || temp.innerText || ""; let cartConfig; try { cartConfig = JSON.parse(cartConfigStr); } catch (e) { console.error(e); showSwalMessage({ title: "获取当前国家/地区失败!", icon: "error" }); return; } const userInfoRaw = data.match(/data-userinfo="(.*?)"/)?.[1]; const temp1 = document.createElement("div"); temp1.innerHTML = userInfoRaw || ""; const userInfoStr = temp1.textContent || temp1.innerText || ""; let userInfo; try { userInfo = JSON.parse(userInfoStr); } catch (e) { console.error(e); showSwalMessage({ title: "获取当前国家/地区失败!", icon: "error" }); return; } const divContent = data.match(/<div class="currency_change_options">([\w\W]*?)<p/i)?.[1]?.trim(); const div = `${divContent || ""}</div>`; if (userInfo?.country_code === country) { showSwalMessage({ title: "更换成功!", icon: "success" }).then(() => { showSwalMessage({ closeOnClickOutside: false, title: `当前国家/地区:${cartConfig?.rgUserCountryOptions[userInfo.country_code] || userInfo.country_code}`, //@ts-ignore content: $(`<div>${div}</div>`)[0] }); bindCurrencyChangeOption(); }); } else { showSwalMessage({ title: "更换失败!", icon: "error" }); } }, error: () => { showSwalMessage({ title: "获取当前国家/地区失败!", icon: "error" }); } }); } }); } // redeem.ts var FAILURE_DETAILS = { 14: "无效激活码", 15: "重复激活", 53: "次数上限", 13: "地区限制", 9: "已拥有", 24: "缺少主游戏", 36: "需要PS3?", 50: "这是充值码" }; var UNUSED_KEY_REASONS = [ "次数上限", "地区限制", "已拥有", "缺少主游戏", "其他错误", "未知错误", "网络错误或超时" ]; function redeemKey(key) { GM_xmlhttpRequest({ url: "https://store.steampowered.com/account/ajaxregisterkey/", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", Origin: "https://store.steampowered.com", Referer: "https://store.steampowered.com/account/registerkey" }, data: `product_key=${key}&sessionid=${globalThis.sessionID}`, method: "POST", responseType: "json", onloadstart() { if ($(globalThis.selecter + "table").is(":hidden")) { $(globalThis.selecter + "table").fadeIn(); } }, onload(response) { if (response.status === 200 && response.response) { const data = response.response; if (data.success === 1 && data.purchase_receipt_info?.line_items[0]) { const item = data.purchase_receipt_info.line_items[0]; tableUpdateKey( key, globalThis.myTexts.success, globalThis.myTexts.line, item.packageid, item.line_item_description ); return; } else if (data.purchase_result_details !== void 0 && data.purchase_receipt_info) { const item = data.purchase_receipt_info.line_items[0]; const failureReason = FAILURE_DETAILS[data.purchase_result_details] || globalThis.myTexts.others; if (!item) { tableUpdateKey( key, globalThis.myTexts.fail, failureReason, 0, globalThis.myTexts.nothing ); } else { tableUpdateKey( key, globalThis.myTexts.fail, failureReason, item.packageid, item.line_item_description ); } return; } tableUpdateKey(key, globalThis.myTexts.fail, globalThis.myTexts.nothing, 0, globalThis.myTexts.nothing); } else { tableUpdateKey(key, globalThis.myTexts.fail, globalThis.myTexts.network, 0, globalThis.myTexts.nothing); } }, ontimeout: () => { tableUpdateKey(key, globalThis.myTexts.fail, globalThis.myTexts.network, 0, globalThis.myTexts.nothing); }, onerror: () => { tableUpdateKey(key, globalThis.myTexts.fail, globalThis.myTexts.network, 0, globalThis.myTexts.nothing); }, onabort: () => { tableUpdateKey(key, globalThis.myTexts.fail, globalThis.myTexts.network, 0, globalThis.myTexts.nothing); } }); } function setUnusedKeys(key, success, reason, subId, subName) { if (success && globalThis.allUnusedKeys.includes(key)) { let listObject; globalThis.allUnusedKeys = globalThis.allUnusedKeys.filter((keyItem) => keyItem !== key); $(`${globalThis.selecter}li`).each((i, e) => { if ($(e).html()?.includes(key)) { listObject = $(e); listObject.remove(); } }); } else if (!success && !globalThis.allUnusedKeys.includes(key) && UNUSED_KEY_REASONS.includes(reason)) { const listObject = $("<li></li>"); listObject.html( `${key} (${reason}${subId !== 0 ? `: <code>${subId}</code> ${subName}` : ""})` ); $("#unusedKeys").append(listObject); globalThis.allUnusedKeys.push(key); } } function tableInsertKey(key) { globalThis.keyCount++; const row = $("<tr></tr>"); row.append(`<td class="nobr">${globalThis.keyCount}</td>`); row.append(`<td class="nobr"><code>${key}</code></td>`); row.append(`<td colspan="3">${globalThis.myTexts.redeeming}...</td>`); $(`${globalThis.selecter}tbody`).prepend(row); } function tableWaitKey(key) { globalThis.keyCount++; const row = $("<tr></tr>"); row.append(`<td class="nobr">${globalThis.keyCount}</td>`); row.append(`<td class="nobr"><code>${key}</code></td>`); row.append(`<td colspan="3">${globalThis.myTexts.waiting} (${globalThis.waitingSeconds}秒)...</td>`); $(`${globalThis.selecter}tbody`).prepend(row); } function tableUpdateKey(key, result, detail, subId, subName) { setUnusedKeys(key, result === globalThis.myTexts.success, detail, subId, subName); globalThis.recvCount++; if (!globalThis.selecter && globalThis.recvCount === globalThis.keyCount) { $("#buttonRedeem").fadeIn(); $("#inputKey").removeAttr("disabled"); } const rowObjects = $(`${globalThis.selecter}tr`); for (let i = 1; i < rowObjects.length; i++) { const rowElement = rowObjects[i]; const rowObject = $(rowElement); if (rowObject.children()[1].innerHTML.includes(key) && rowObject.children()[2].innerHTML.includes(globalThis.myTexts.redeeming)) { rowObject.children()[2].remove(); if (result === globalThis.myTexts.fail) { rowObject.append(`<td class="nobr" style="color:red">${result}</td>`); } else { rowObject.append(`<td class="nobr" style="color:green">${result}</td>`); } rowObject.append(`<td class="nobr">${detail}</td>`); if (subId === 0) { rowObject.append("<td>——</td>"); } else { rowObject.append( `<td><code>${subId}</code> <a href="https://steamdb.info/sub/${subId}/" target="_blank">${subName}</a></td>` ); } break; } } } function startTimer() { const timer = setInterval(() => { let flag = false; let nowKey = 0; const rowObjects = $(`${globalThis.selecter}tr`); for (let i = rowObjects.length - 1; i >= 1; i--) { const rowElement = rowObjects[i]; const rowObject = $(rowElement); const cellContent = rowObject.children()[2]?.innerHTML; if (cellContent?.includes(globalThis.myTexts.waiting)) { nowKey++; if (nowKey <= globalThis.autoDivideNum) { let key = rowObject.children()[1]?.innerHTML.substring(6); key = key?.substring(0, key.indexOf("</code>")) || ""; rowObject.children()[2].innerHTML = `<td colspan="3">${globalThis.myTexts.redeeming}...</td>`; redeemKey(key); } else { flag = true; break; } } } if (!flag) { clearInterval(timer); } }, 1e3 * globalThis.waitingSeconds); } function redeem(keys) { if (keys.length <= 0) { return; } if (!globalThis.selecter) { $("#buttonRedeem").hide(); $("#inputKey").attr("disabled", "disabled"); } let nowKey = 0; keys.forEach((key) => { nowKey++; if (nowKey <= globalThis.autoDivideNum) { tableInsertKey(key); redeemKey(key); } else { tableWaitKey(key); } }); if (nowKey > globalThis.autoDivideNum) { startTimer(); } } function redeemKeys(key) { const keys = key ? key.split(",") : getKeysByRE($("#inputKey").val()?.toString()?.trim() || ""); redeem(keys); } function toggleUnusedKeyArea() { if (!globalThis.selecter) { const unusedKeyArea = $("#unusedKeyArea"); if (unusedKeyArea.is(":hidden")) { unusedKeyArea.show(); } else { unusedKeyArea.hide(); } } } function registerkey(key) { const setting = GM_getValue("setting"); const keys = getKeysByRE(key); if (setting?.asf) { const asfCommand = `!redeem ${setting.asfBot ? `${setting.asfBot} ` : ""}${keys.join(",")}`; asfRedeem(asfCommand); } else if (setting?.newTab) { const url = `https://store.steampowered.com/account/registerkey?key=${keys.join(",")}`; window.open(url, "_blank"); } else { webRedeem(keys.join(",")); } } // css.ts var css = `table.hclonely { font-family: verdana,arial,sans-serif; font-size: 11px; color: #333333; border-width: 1px; border-color: #999999; border-collapse: collapse; } table.hclonely th { background-color: #c3dde0; border-width: 1px; padding: 8px; border-style: solid; border-color: #a9c6c9; } table.hclonely tr { background-color: #d4e3e5; } table.hclonely td { border-width: 1px; padding: 8px; border-style: solid; border-color: #a9c6c9; } table.hclonely caption { padding-top: 8px; color: #808294; text-align: center; caption-side: top; background-color: #94d7df; } table.hclonely h2 { margin: 0; font-size: 25px; } .swal-user { width: 80%; } table.hclonely a { color: #2196F3; } table.hclonely .swal-button { padding: 5px; } #unusedKeyArea code { padding: 2px 4px; font-size: 90%; color: #c7254e; background-color: #f9f2f4; border-radius: 3px; } .notice_box_content { border: 1px solid #a25024; border-radius: 3px; color: #acb2b8; font-size: 14px; font-family: "Motiva Sans", Sans-serif; font-weight: normal; padding: 15px 15px; margin-bottom: 15px; } .notice_box_content b { font-weight: normal; color: #f47b20; float: left; } #unusedKeys { margin:0 15px; } #copyUnuseKey span { font-size: 15px; line-height: 20px; } #unusedKeyArea li { white-space: nowrap; color: #007fff; } .currency_change_option_ctn { vertical-align: top; margin: 0 6%; } .currency_change_option_ctn:first-child { margin-bottom: 12px; } .currency_change_option_ctn > p { font-size: 12px; margin: 8px 8px 0 8px; } .currency_change_option_ctn { vertical-align: top; margin: 0 6%; } .currency_change_option_ctn:first-child { margin-bottom: 12px; } .currency_change_option { font-family: "Motiva Sans", Sans-serif; font-weight: 300; /* light */ display: block; } .currency_change_option > span { display: block; padding: 9px 19px; } .currency_change_option .country { font-size: 20px; } .currency_change_option .notes { font-size: 13px; line-height: 18px; } .currency_change_option_ctn > p { font-size: 12px; margin: 8px 8px 0 8px; } .asf-class input[type="text"]{ border: 1px solid #c2e9ee; width:180px; } .asf-output{ width:90%; min-height:150px; } .switch-key { margin:0 15%; height:100px; } .switch-key-left { float:left; } .switch-key-right { float:right; } .switch-key div { width: 50%; position: relative; cursor:default; } .switch-key input { margin:10px 0; } .switch-key p { font-size:25px; height:25px; color:black; margin:0; } .swal-content *{ color:#000; } .swal-content textarea{ background: #fff; } #allKey{ display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: 400; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; -ms-touch-action: manipulation; touch-action: manipulation; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 4px;color: #333; background-color: #fff; border-color: #ccc; } #allKey:hover{ color: #333; background-color: #e6e6e6; border-color: #adadad; text-decoration: none; } #allKey:focus{ color: #333; background-color: #e6e6e6; border-color: #8c8c8c; text-decoration: none; } #allKey:active{ background-image: none; outline: 0; -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.125); box-shadow: inset 0 3px 5px rgba(0,0,0,.125);color: #333; background-color: #e6e6e6; border-color: #adadad; } .icon-img { position: absolute; width: 32px; height: 32px; margin: 0px!important; } .icon-div { width: 32px!important; height: 32px!important; display: none; background: #fff!important; border-radius: 16px!important; box-shadow: 4px 4px 8px #888!important; position: absolute!important; z-index: 2147483647!important; cursor: pointer; } `; // main.ts globalThis.url = window.location.href; globalThis.defaultSetting = { newTab: false, copyListen: true, selectListen: true, clickListen: true, allKeyListen: false, asf: false, asfProtocol: "http", asfHost: "127.0.0.1", asfPort: 1242, asfPassword: "", asfBot: "" }; globalThis.sessionID = ""; try { globalThis.sessionID = g_sessionID; } catch (e) { globalThis.sessionID = ""; } globalThis.allUnusedKeys = []; globalThis.selecter = globalThis.url.includes("/account/registerkey") ? "" : ".hclonely "; globalThis.myTexts = { fail: "失败", success: "成功", network: "网络错误或超时", line: "——", nothing: "", others: "其他错误", unknown: "未知错误", redeeming: "激活中", waiting: "等待中", showUnusedKey: "显示未使用的Key", hideUnusedKey: "隐藏未使用的Key" }; globalThis.autoDivideNum = 9; globalThis.waitingSeconds = 20; globalThis.keyCount = 0; globalThis.recvCount = 0; try { const setting = GM_getValue("setting"); if (Object.prototype.toString.call(setting) !== "[object Object]") { GM_setValue("setting", globalThis.defaultSetting); } if (setting?.selectListen) { const icon = document.createElement("div"); icon.className = "icon-div"; icon.title = "激活"; icon.innerHTML = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABsFBMVEVHcEz9/f3+/v8Tdaf///8LGTP+/v4NPWX+/v8GGDj8/f4OGzX///////////8ZJ1ALJ0oNGzf+/v4mOGXX2+T8/f3z9vkPH0UjMFj5+fr///8NGzMJG0ERHS8SKEgXW40Ubp8WY5Ula5ePnrb3+PlnhKUfQ3Q3R3C2vMvt8PRcZH7///8TgrMTgbITfa4YNmcPHDT///8JGj0HGT2rucxGWYJ0g6H///9aZYbGy9jFyNQhL1TO0dp5lbOTma39/f7///+Sl6br7O6SlqT///////8UY5UUY5UJGTgTc6QThLUTfa8VToETdKYQK1sRK1sUWowUY5X///+mq7tlc5MzWX7Mztl5gZuytcJPV3AjL08iLlEUTYAUPXATK10Tfa4FO3IVToHEz9wAL2fj5+5GUG4JFz1mbIC8wMsFFzYFGDwHGkILGTIJG0cLHUoFGD8RJFMUU4YUN2kOIE4TSHsUYJMUbqAUQnUVTYAQLWEUWowUPG8SKFoTZ5kRHDATfq8Tdqf///8IIFQUaJkeWYrA0N4JMmgHQndAc5wJTYIIVooGXpNllrdchanT3ui2xtaZV9eJAAAAaXRSTlMAj/j97/vmAtD8xzncwJvwJay59uHd/ObqgnBtlpgLPfz8Femx+/7s0vitXqVLf53k3VmE9fDr59vaxLSY/qmGRnxeXjI/lGy5MLbr+8A/cPuiqLzgfLHJhJfN17bjr6z8xfmu9cH4cHitMXlOAAACjUlEQVQ4y2XTh1faQBgA8IMGQqCiGPaQAgUE3OLeFTfurR120SYkAQSrQUABUSyOf7l3kQC+/i7JfXff9/Ly4DsAXuA4AG0qi02jsVlUbS/rRnCpsvXkqnpsKmGrnsZBy2KOyTGyHBrooWlpeAkMLAzDyBiRDIayvloFnKwMJSOoKgJGsghD9YsVOLASBEE3pKtz/8t34MBCEXQddbQ7O/trjKAiVB96BY630I2ow1BobjoUmjXQdAR+KRyL0Ug0VhWlD+c+jBkMxzNzM3BXgwrWog1oYyBgODr47adnpv2xSBT+HkDDRlgxz9H+wM/jgNkc8BvNBzGWtQLgNLAcy8JbGLFJs3HSZDJNmQzjpmaWM7SBviRXk2SbxyXGSQkCI1jAqUB/Mp6sYbfV6mGvWq2W7JOSPQ7urIPuJBsXccNbkNG7t7cf397aQQkrMLUPZLh4JoMushV5P0yS3vatUbSV+QwkytaRQbJQ4DOFwqiySQnBR1PTKAnTPCyY0ikUSoVrgPcOjihE2vYdPnPK8yTfDczytwKtbsQVhHOvTqcd4Hn+VMCvg2lM3itHMK3LMyiXD/UGPbeXkFBwuQacrh8Yhg1hiM8TxHxu/vT8UvQJtud3j/ubVKCXTrix8O15Xaob/hf21MlJOZiX5qXSvHvi+Tacqgmn7Kgfvl6E7+58ped8vpTyTdwlLkThi49CP9gTiZv7R/1juXxTerpPNEINA6/d9Eb6/kH/VNKXbtJ1G+kFsSk3zxyOv46Hh3KlclbjOJsHYleDzWKxmK1UskUkixSzxfnGc9f1DvkjQvHCq6OHL61eX1+/qYLR6tKrw4lKOr+sXFWtdNj/O99wiTs7uzqWlzu6Op14Pf0P2PD9NrHDeWsAAAAASUVORK5CYII=" class="icon-img" alt="激活图标">`; const $icon = $(icon); $("html").append(icon); $(document).mousedown((e) => { if (e.target === icon || e.target?.parentNode === icon || e.target?.parentNode?.parentNode === icon) { e.preventDefault(); } }); document.addEventListener("selectionchange", () => { if (!window.getSelection()?.toString()?.trim()) { $icon.hide(); } }); $(document).mouseup((e) => { if (e.target === icon || e.target?.parentNode === icon || e.target?.parentNode?.parentNode === icon) { e.preventDefault(); return false; } const text = window.getSelection()?.toString()?.trim(); const productKey = text || e.target?.value; if (/[\d\w]{5}(-[\d\w]{5}){2}/.test(productKey) && text && $icon.is(":hidden")) { $icon.css({ top: e.pageY + 12, left: e.pageX + 18 }).show(); } else if (!text) { $icon.hide(); } }); $icon.click((e) => { const productKey = window.getSelection()?.toString()?.trim() || e.target?.value; registerkey(productKey); }); } if (!/https?:\/\/store\.steampowered\.com\/account\/registerkey[\w\W]{0,}/.test(globalThis.url) && setting?.copyListen) { const activateProduct = async function(e) { const productKey = window.getSelection()?.toString()?.trim() || e.target?.value; const clipboardSuccess = await navigator.clipboard.writeText(productKey).then(() => true, () => false); if (/^([\w\W]*)?([\d\w]{5}(-[\d\w]{5}){2}(\r||,||,)?){1,}/.test(productKey)) { if (!$("div.swal-overlay").hasClass("swal-overlay--show-modal")) { swal({ title: "检测到神秘key,是否激活?", icon: "success", //@ts-ignore buttons: { confirm: "激活", cancel: "取消" } }).then((value) => { if (value) registerkey(productKey); }); } } else if (/^![\w\d]+\s+asf\s+.+/gi.test(productKey)) { if (setting?.asf && !$("div.swal-overlay").hasClass("swal-overlay--show-modal")) { swal({ closeOnClickOutside: false, className: "swal-user", title: "检测到您复制了以下ASF指令,是否执行?", text: productKey, //@ts-ignore buttons: { confirm: "执行", cancel: "取消" } }).then((value) => { if (value) asfRedeem(productKey); }); } } }; window.addEventListener("copy", activateProduct, false); } if (/^https?:\/\/store\.steampowered\.com\/account\/registerkey*/.test(globalThis.url)) { $("#registerkey_examples_text").html(` <div class="notice_box_content" id="unusedKeyArea" style="display: none"> <b>未使用的Key:</b> <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" id="copyUnuseKey"> <span>提取未使用key</span> </a> <br> <div><ol id="unusedKeys"></ol></div> </div> <div class="table-responsive table-condensed"> <table class="table table-hover" style="display: none"> <caption><h2>激活记录</h2></caption> <thead> <tr> <th>No.</th> <th>Key</th> <th>结果</th> <th>详情</th> <th>Sub</th> </tr> </thead> <tbody></tbody> </table> </div> <br>`); $("#copyUnuseKey").click(() => { const unusedKeys = $("#unusedKeys").text(); GM_setClipboard(arr(getKeysByRE(unusedKeys)).join(",")); swal({ title: "复制成功!", icon: "success" }); }); $(".registerkey_input_box_text").parent().css("float", "none").append(` <textarea class="form-control" rows="3" id="inputKey" placeholder="支持批量激活,可以把整个网页文字复制过来 若一次激活的Key的数量超过9个则会自动分批激活(等待20秒) 激活多个SUB时每个SUB之间用英文逗号隔开" style="margin: 3px 0px 0px; width: 525px; height: 102px;"></textarea><br>`); if (/^https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=.+/.test(globalThis.url)) { $("#inputKey").val(globalThis.url.replace(/https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=/i, "")); } $(".registerkey_input_box_text,#purchase_confirm_ssa").hide(); $("#register_btn").parent().css("margin", "10px 0").append(` <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0" id="redeemKey"> <span>激活key</span> </a> <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0" id="redeemSub"> <span>激活sub</span> </a> <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0" id="changeCountry"> <span>更换国家/地区</span> </a> `); $("#register_btn").remove(); if (/^https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=.+/.test(globalThis.url)) { redeem(getKeysByRE(globalThis.url.replace(/https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=/i, "").trim())); } $("#redeemKey").click(() => { redeemKeys(); }); $("#redeemSub").click(redeemSubs); $("#changeCountry").click(cc); toggleUnusedKeyArea(); } else if (/https?:\/\/steamdb\.info\/freepackages\//.test(globalThis.url)) { const activateConsole = () => { const sub = []; $("#freepackages span:visible").each(function() { const subId = $(this).attr("data-subid"); if (subId) sub.push(subId); }); const freePackages = sub.join(","); window.open(`https://store.steampowered.com/account/licenses/?sub=${freePackages}`, "_self"); }; const fp = setInterval(() => { if ($("#freepackages").length > 0) { $("#freepackages").click(activateConsole); clearInterval(fp); } }, 1e3); } else if (/https?:\/\/store\.steampowered\.com\/account\/licenses\/(\?sub=[\w\W]{0,})?/.test(globalThis.url)) { $("h2.pageheader").parent().append(` <div style="float: left;"> <textarea class="registerkey_input_box_text" rows="1" name="product_key" id="gameSub" placeholder="输入SUB,多个SUB之间用英文逗号连接" value="" style="margin: 3px 0px 0px; width: 400px; height: 15px;background-color:#102634; padding: 6px 18px 6px 18px; font-weight:bold; color:#fff;"></textarea> </div> <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="width: 95px; height: 30px;" id="buttonSUB"> <span>激活SUB</span> </a> <a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="width: 125px; height: 30px;margin-left:5px" id="changeCountry-account"> <span>更改国家/地区</span> </a>`); $("#buttonSUB").click(() => { redeemSub(); }); $("#changeCountry-account").click(cc); if (/https?:\/\/store\.steampowered\.com\/account\/licenses\/\?sub=([\d]+,)+/.test(globalThis.url)) { setTimeout(() => { redeemSub(globalThis.url); }, 2e3); } } else if (setting?.clickListen) { let htmlEl = null; if ($("body").length > 0) { $("body").click((event) => { htmlEl = event.target; if ($(htmlEl).parents(".swal-overlay").length === 0 && !["A", "BUTTON", "TEXTAREA"].includes(htmlEl.tagName) && !["button", "text"].includes(htmlEl.getAttribute("type") || "") && ($(htmlEl).children().length === 0 || !/([0-9,A-Z]{5}-){2,4}[0-9,A-Z]{5}/gim.test($.makeArray($(htmlEl).children().map(function() { return $(this).text(); })).join(""))) && /([0-9,A-Z]{5}-){2,4}[0-9,A-Z]{5}/gim.test($(htmlEl).text())) { mouseClick($, event); arr($(htmlEl).text().match(/[\w\d]{5}(-[\w\d]{5}){2}/gim) || []).map((e) => { $(htmlEl).html($(htmlEl).html()?.replace(new RegExp(e, "gi"), `<a class="redee-key" href='javascript:void(0)' target="_self" key='${e}'>${e}</a>`)); }); $(".redee-key").click(function() { registerkey($(this).attr("key") || ""); }); } }); } } if (/https?:\/\/store\.steampowered\.com\//.test(globalThis.url)) { $("#account_pulldown").before('<span id="changeCountry" style="cursor:pointer;display:inline-block;padding-left:4px;line-height:25px" class="global_action_link persona_name_text_content">更改国家/地区 |</span>'); $("#changeCountry").click(cc); } if (setting?.allKeyListen) { redeemAllKey(); } GM_addStyle(css); GM_registerMenuCommand("⚙设置", settingChange); GM_registerMenuCommand("执行ASF指令", () => { asfSend(); }); } catch (e) { swal("AuTo Redeem Steamkey脚本执行出错,详情请查看控制台!", e.stack, "error"); console.error(e); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址