您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。
当前为
// ==UserScript== // @name auto-task-v4 // @namespace auto-task-v4 // @version 4.7.8 // @description 自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。 // @description:en Automatically complete the tasks of FreeAnyWhere, GiveawaySu, GiveeClub, Givekey, Gleam, Indiedb, keyhub, OpiumPulses, Opquests, SweepWidget websites. // @author HCLonely // @license MIT // @run-at document-start // @homepage https://auto-task-doc.js.org/ // @supportURL https://github.com/HCLonely/auto-task-v4/issues // @icon https://auto-task-v4.hclonely.com/favicon.ico // @include *://freeanywhere.net/* // @include *://giveaway.su/giveaway/view/* // @include *://givee.club/*/event/* // @include *://givekey.ru/giveaway/* // @include *://www.indiedb.com/giveaways* // @include *://key-hub.eu/giveaway/* // @include *://keylol.com/* // @include *://www.opiumpulses.com/giveaways // @include *://prys.revadike.com/giveaway/?id=* // @include *://opquests.com/quests/* // @include *://gleam.io/* // @include *://sweepwidget.com/view/* // @include *://giveawayhopper.com/c/* // @include *://discord.com/* // @include *://www.twitch.tv/* // @include *://www.youtube.com/* // @include *://*.reddit.com/* // @include *://twitter.com/settings/account?k* // @include *://x.com/settings/account* // @include *://steamcommunity.com/* // @include *://store.steampowered.com/* // @include https://auto-task-v4.hclonely.com/setting.html // @include https://auto-task-v4.hclonely.com/history.html // @grant GM_setValue // @grant GM_getValue // @grant GM_listValues // @grant GM_deleteValue // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_info // @grant GM_openInTab // @grant GM_setClipboard // @grant GM_getResourceText // @grant GM_cookie // @grant GM_addValueChangeListener // @grant GM_removeValueChangeListener // @grant unsafeWindow // @grant window.close // @grant window.localStorage // @grant window.sessionStorage // @grant window.focus // @connect cdn.jsdelivr.net // @connect store.steampowered.com // @connect steamcommunity.com // @connect login.steampowered.com // @connect twitter.com // @connect x.com // @connect abs.twimg.com // @connect api.twitter.com // @connect youtube.com // @connect www.youtube.com // @connect facebook.com // @connect instagram.com // @connect vk.com // @connect twitch.tv // @connect www.twitch.tv // @connect gql.twitch.tv // @connect github.com // @connect discordapp.com // @connect discord.gg // @connect discord.com // @connect www.reddit.com // @connect oauth.reddit.com // @connect raw.githubusercontent.com // @connect t.me // @connect bit.ly // @connect giveaway.su // @connect google.com // @connect www.vloot.io // @connect givee.club // @connect gleam.io // @connect www.indiedb.com // @connect key-hub.eu // @connect opquests.com // @connect itch.io // @connect auto-task-v4.hclonely.com // @connect giveawayhopper.com // @connect * // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/js.cookie.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/runtime.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/src/sha1.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/src/sha256.min.js // @require https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js // @resource style https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.min.css // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/keyboard.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dayjs.min.js // @require https://bundle.run/[email protected] // @noframes // ==/UserScript== console.log('%c%s', 'color:blue', 'Auto-Task[Load]: 脚本开始加载'); (function() { var __webpack_modules__ = { 243: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { decodeBase64: function() { return decodeBase64; }, encodeBase64: function() { return encodeBase64; }, generateTransactionId: function() { return generateTransactionId; } }); const encodeSha256 = async data => { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); return Array.from(new Uint8Array(hashBuffer)); }; const encodeBase64 = data => { let binary = ''; const bytes = new Uint8Array(data); const len = bytes.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary).replace(/=/g, ''); }; const decodeBase64 = data => { const binaryString = atob(data); const len = binaryString.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i); } return Array.from(bytes); }; const generateTransactionId = async (method, path, key, animationKey) => { const DEFAULT_KEYWORD = 'obfiowerehiring'; const ADDITIONAL_RANDOM_NUMBER = 3; const timeNow = Math.floor((Date.now() - 1682924400 * 1e3) / 1e3); const timeNowBytes = [ timeNow & 255, timeNow >> 8 & 255, timeNow >> 16 & 255, timeNow >> 24 & 255 ]; const data = `${method}!${path}!${timeNow}${DEFAULT_KEYWORD}${animationKey}`; const hashBytes = await encodeSha256(data); const keyBytes = decodeBase64(key); const randomNum = Math.floor(Math.random() * 256); const bytesArr = [ ...keyBytes, ...timeNowBytes, ...hashBytes.slice(0, 16), ADDITIONAL_RANDOM_NUMBER ]; const out = new Uint8Array(bytesArr.length + 1); out[0] = randomNum; bytesArr.forEach((item, index) => { out[index + 1] = item ^ randomNum; }); return encodeBase64(out); }; }, 314: function(module) { 'use strict'; module.exports = function(cssWithMappingToString) { var list = []; list.toString = function toString() { return this.map(function(item) { var content = ''; var needLayer = typeof item[5] !== 'undefined'; if (item[4]) { content += '@supports ('.concat(item[4], ') {'); } if (item[2]) { content += '@media '.concat(item[2], ' {'); } if (needLayer) { content += '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {'); } content += cssWithMappingToString(item); if (needLayer) { content += '}'; } if (item[2]) { content += '}'; } if (item[4]) { content += '}'; } return content; }).join(''); }; list.i = function i(modules, media, dedupe, supports, layer) { if (typeof modules === 'string') { modules = [ [ null, modules, undefined ] ]; } var alreadyImportedModules = {}; if (dedupe) { for (var k = 0; k < this.length; k++) { var id = this[k][0]; if (id != null) { alreadyImportedModules[id] = true; } } } for (var _k = 0; _k < modules.length; _k++) { var item = [].concat(modules[_k]); if (dedupe && alreadyImportedModules[item[0]]) { continue; } if (typeof layer !== 'undefined') { if (typeof item[5] === 'undefined') { item[5] = layer; } else { item[1] = '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {').concat(item[1], '}'); item[5] = layer; } } if (media) { if (!item[2]) { item[2] = media; } else { item[1] = '@media '.concat(item[2], ' {').concat(item[1], '}'); item[2] = media; } } if (supports) { if (!item[4]) { item[4] = ''.concat(supports); } else { item[1] = '@supports ('.concat(item[4], ') {').concat(item[1], '}'); item[4] = supports; } } list.push(item); } }; return list; }; }, 356: function(module, __unused_webpack_exports, __webpack_require__) { const { axiosGM } = __webpack_require__(945); const { getIndices, getAnimationKey } = __webpack_require__(702); const { generateTransactionId } = __webpack_require__(243); const { decodeBase64 } = __webpack_require__(243); const { never } = __webpack_require__(727); const { decodeTransactionId } = __webpack_require__(791); const createSession = async () => { const raw = await axiosGM({ url: 'https://x.com', method: 'GET', responseType: 'text' }); const html = raw.data; const root = $.parseHTML(`<div>${html}</div>`)[0]; const content = root.querySelector('[name^=tw]')?.getAttribute('content') ?? never('No content'); const verification = decodeBase64(content); const frames = root.querySelectorAll('[id^=\'loading-x-anim\']'); const svgArray = svgKey(verification, frames); const indexKey = await getIndices(html); const animationKey = getAnimationKey(svgArray, verification, indexKey); return { get: (method, path) => generateTransactionId(method, path, content, animationKey.join('')) }; }; const svgKey = (verification, frames) => { const index = verification[5] % 4; const path = frames[index].children[0].children[1]; const d = path.getAttribute('d') ?? never('No d'); const sub = d.substring(9).split('C'); const res = sub.map(item => { return item.replace(/[^\d]+/g, ' ').trim().split(' ').map(Number); }); return res; }; module.exports = { createSession: createSession, generateTransactionId: generateTransactionId, decodeTransactionId: decodeTransactionId }; }, 601: function(module) { 'use strict'; module.exports = function(i) { return i[1]; }; }, 675: function(module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.d(__webpack_exports__, { A: function() { return __WEBPACK_DEFAULT_EXPORT__; } }); var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(601); var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(314); var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()); ___CSS_LOADER_EXPORT___.push([ module.id, `.colorful-button,#auto-task-buttons a.auto-task-website-btn,.show-button-div a.auto-task-website-btn,body.auto-task-options .auto-task-form table button{position:relative;padding:5px 10px;text-align:center;color:#fff;-webkit-text-decoration:none;text-decoration:none;background:linear-gradient(90deg, #03a9f4, #f441a5, #ffeb3b, #03a9f4);border-radius:30px;background-size:400%;text-transform:capitalize}.colorful-button:hover,#auto-task-buttons a.auto-task-website-btn:hover,.show-button-div a.auto-task-website-btn:hover,body.auto-task-options .auto-task-form table button:hover{transform:scale(1.05);box-shadow:0 6px 20px rgba(0,0,0,.3);cursor:pointer}.colorful-button:hover::before,#auto-task-buttons a.auto-task-website-btn:hover::before,.show-button-div a.auto-task-website-btn:hover::before,body.auto-task-options .auto-task-form table button:hover::before{filter:blur(10px);opacity:1}.colorful-button::before,#auto-task-buttons a.auto-task-website-btn::before,.show-button-div a.auto-task-website-btn::before,body.auto-task-options .auto-task-form table button::before{content:"";position:absolute;top:-5px;left:-5px;right:-5px;bottom:-5px;z-index:-1;background:linear-gradient(90deg, #03a9f4, #f441a5, #ffeb3b, #03a9f4);border-radius:40px;background-size:400%;opacity:-1}#auto-task-info{position:fixed;bottom:10px;right:10px;width:60%;max-width:500px;max-height:60%;overflow-y:auto;color:#000;background-color:#fff;padding-left:5px;z-index:999999999 !important;border:solid 2px #add8e6;border-radius:10px}#auto-task-info li{text-align:left}#auto-task-info li a.high-light{color:#00aeff;font-weight:bold}#auto-task-info .success{color:green}#auto-task-info .error{color:red}#auto-task-info .warning{color:blue}#auto-task-info .info{color:#ff0}#auto-task-info .update-text{color:green;border:solid 2px #8dcb69;margin:5px 10px 5px 20px;border-radius:10px;padding:5px 20px}.auto-task-keylol{display:inline-block;text-transform:capitalize;margin-left:10px;-webkit-text-decoration:none !important;text-decoration:none !important;border:solid 1px;border-radius:5px;padding:0 2px}.auto-task-keylol[selected=selected]{background-color:blue !important;color:#fff !important}.auto-task-form table{font-family:verdana,arial,sans-serif;font-size:11px;color:#333;border-width:1px;border-color:#999;border-collapse:collapse;width:100%}.auto-task-form table thead td{border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9;font-weight:bold;background-color:#fff}.auto-task-form table tbody tr{background-color:#d4e3e5}.auto-task-form table tbody tr:hover{background-color:#ff6 !important}.auto-task-form table tbody tr th{background-color:#c3dde0;border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9;text-transform:capitalize}.auto-task-form table tbody tr td{border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9}.swal2-modal{width:70% !important;max-width:1000px !important}body.auto-task-options{padding-top:10px;text-align:center}body.auto-task-options .auto-task-form{width:80%;max-width:1000px;margin:0 auto;padding-bottom:20px}body.auto-task-options .auto-task-form table input.editOption{width:80%}body.auto-task-options .auto-task-form table #getTwitterUserId,body.auto-task-options .auto-task-form table #getYoutubeChannelId{margin-top:5px}body.auto-task-options .auto-task-form table button{z-index:1}body.auto-task-options .auto-task-form table input[type=text]{outline-style:none;border:1px solid #ccc;border-radius:3px;padding:5px 10px;font-size:14px}body.auto-task-options .auto-task-form table input[type=text]:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}body.auto-task-options .auto-task-form table label{position:relative;width:160px;height:80px;cursor:pointer;transform:scale(0.25);margin:-25% 0;top:-30px;display:inline-block}body.auto-task-options .auto-task-form table label input{position:relative;z-index:1;appearance:none}body.auto-task-options .auto-task-form table label input:checked~span{background:#05be05;box-shadow:0 15px 25px rgba(5,190,5,.4)}body.auto-task-options .auto-task-form table label input:checked~span i{left:84px}body.auto-task-options .auto-task-form table label input:checked~span i::before{background:#05be05;box-shadow:35px 0 0 #05be05}body.auto-task-options .auto-task-form table label input:checked~span i::after{bottom:12px;height:15px;border-bottom-left-radius:15px;border-bottom-right-radius:15px;background:#05be05}body.auto-task-options .auto-task-form table label span{position:absolute;top:0;left:0;width:100%;height:100%;background:#fe0000;border-radius:80px;transition:.5s;box-shadow:0 15px 25px rgba(254,0,0,.4)}body.auto-task-options .auto-task-form table label span i{position:absolute;top:4px;left:4px;width:72px;height:72px;background:#fff;border-radius:50%}body.auto-task-options .auto-task-form table label span i::before{content:"";position:absolute;top:22px;left:12px;width:12px;height:12px;border-radius:50%;background:#fe0000;box-shadow:35px 0 0 #fe0000;transition:.5s}body.auto-task-options .auto-task-form table label span i::after{content:"";position:absolute;bottom:15px;left:calc(50% - 15px);width:30px;height:6px;border-radius:6px;background:#fe0000;transition:.5s}body.auto-task-history{font-size:15px;font-weight:400;line-height:1.5}body.auto-task-history .container a{color:#007bff;-webkit-text-decoration:none;text-decoration:none;background-color:rgba(0,0,0,0)}body.auto-task-history .container .card{width:80%;max-width:800px;border-radius:10px;background:rgba(118,118,118,.1019607843);border-top:1px solid hsla(0,0%,100%,.5019607843);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);box-shadow:0 15px 25px rgba(0,0,0,.1019607843);margin:20px auto;position:relative;display:flex;flex-direction:column;word-wrap:break-word;-webkit-background-clip:border-box;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}body.auto-task-history .container .card .title{text-align:center;font-size:30px;font-weight:bold;margin:5px 0}body.auto-task-history .container .card .title a:hover{-webkit-text-decoration:none;text-decoration:none;background:#93e1ff;border-radius:10px;padding:3px}body.auto-task-history .container .card ul{margin-bottom:25px}body.auto-task-history .container .card ul li{margin-bottom:5px;line-height:20px}body.auto-task-history .container .card ul a:hover{-webkit-text-decoration:underline;text-decoration:underline}body.auto-task-history .container .card .delete-task{right:10px;width:38px;height:35px;position:absolute;font-size:24px;cursor:pointer;border-radius:10px}body.auto-task-history .container .card .delete-task:hover{background:#fff}body.auto-task-history .container .card .time{right:5px;position:absolute;bottom:0;color:#e83e8c;font-family:'SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace';font-size:15px}#auto-task-buttons,.show-button-div{position:fixed;top:30px;right:15px;width:124px;z-index:999999999 !important;transform:scale(0.85)}#auto-task-buttons p,.show-button-div p{line-height:30px;height:40px;text-align:center;margin:5px !important}#auto-task-buttons a.auto-task-website-btn,.show-button-div a.auto-task-website-btn{width:105px;line-height:27px;font-size:20px;display:block}.show-button-div{width:20px}.auto-task-capitalize{text-transform:capitalize !important}.swal2-file:focus,.swal2-input:focus,.swal2-textarea:focus{box-shadow:inset 0px 0px 4px 1px rgba(100,150,200,.5) !important}.swal2-checkbox-custom{align-items:center;justify-content:center;background:#fff;color:inherit;margin:1em auto}.swal2-checkbox-custom input{flex-shrink:0;margin:0 .4em}.giveaway-actions #getKey{display:none !important}.auto-task-giveaway-status{color:#fff;border-radius:10px;padding:0 5px;margin-left:5px}.auto-task-giveaway-status.active{background-color:#5cb85c}.auto-task-giveaway-status.not-active{background-color:#d9534f}`, '' ]); const __WEBPACK_DEFAULT_EXPORT__ = ___CSS_LOADER_EXPORT___.toString(); }, 702: function(module, __unused_webpack_exports, __webpack_require__) { const { axiosGM } = __webpack_require__(945); const totalTime = 4096; const calculateScaledValue = (scalingFactor, baseValue, targetValue, roundToInteger) => { const result = scalingFactor * (targetValue - baseValue) / 255 + baseValue; return roundToInteger ? Math.floor(result) : Number(result.toFixed(2)); }; function interpolate(from, to, value) { const out = Array.from(from.length); for (let i = 0; i < from.length; i++) { out[i] = interpolateNum(from[i], to[i], value); } return out; } function interpolateNum(from, to, value) { return from * (1 - value) + to * value; } function convertRotationToMatrix(degrees) { const radians = degrees * Math.PI / 180; const c = Math.cos(radians).toFixed(6); const s = Math.sin(radians).toFixed(6); return [ c, s, -s, c, 0, 0 ]; } function cubic(a, b, c, d) { if (a < 0 || a > 1 || c < 0 || c > 1) { return function(x) { return x; }; } return function(x) { if (x <= 0) { var start_gradient = 0; if (a > 0) { start_gradient = b / a; } else if (!b && c > 0) { start_gradient = d / c; } return start_gradient * x; } if (x >= 1) { var end_gradient = 0; if (c < 1) { end_gradient = (d - 1) / (c - 1); } else if (c == 1 && a < 1) { end_gradient = (b - 1) / (a - 1); } return 1 + end_gradient * (x - 1); } var start = 0, end = 1; function f(a, b, m) { const _1_m = 1 - m; return 3 * a * _1_m * _1_m * m + 3 * b * _1_m * m * m + m * m * m; } while (start < end) { var mid = start + (end - start) / 2; var xEst = f(a, c, mid); if (Math.abs(x - xEst) < 1e-6) { return f(b, d, mid); } if (xEst < x) { start = mid; } else { end = mid; } } return f(b, d, mid); }; } function doAnimation(numArr, frameTime) { const _cubic = cubic(...numArr.slice(7).map((n, W) => calculateScaledValue(n, W % 2 ? -1 : 0, 1, false))); const currentTime = Math.round(frameTime / 10) * 10; const cubicValue = _cubic(currentTime / totalTime); const frameColor = interpolate([ numArr[0], numArr[1], numArr[2] ], [ numArr[3], numArr[4], numArr[5] ], cubicValue); const frameRotate = interpolate([ 0 ], [ calculateScaledValue(numArr[6], 60, 360, !0) ], cubicValue); const frameMatrix = convertRotationToMatrix(frameRotate); return { color: frameColor.map(c => Math.round(c)), transform: frameMatrix.slice(0, 4).map(m => Number(Number(m).toFixed(2))) }; } const getAnimationKey = (svgArray, verification, indexKey) => { const index = verification[indexKey[0]] % 16; const frameTime = verification[indexKey[1]] % 16 * (verification[indexKey[2]] % 16) * (verification[indexKey[3]] % 16); const style = doAnimation(svgArray[index], frameTime); const hexIntArray = Array.from([ style.color.length + style.transform.length + 2 ]); const hexArray = hexIntArray.map(i => i.toString(16)); hexArray[7] = hexArray[8] = '0'; for (let i = 0; i < 3; i++) { const numColorValue = style.color[i]; if (numColorValue >= 0 && numColorValue <= 255) { hexArray[i] = numColorValue.toString(16); } if (numColorValue < 0) { hexArray[i] = '0'; } else { hexArray[i] = 'ff'; } } for (let i = 0; i < 4; i++) { let numMatrixValue = style.transform[i]; if (numMatrixValue < 0) { numMatrixValue = -numMatrixValue; } if (numMatrixValue > 0 && numMatrixValue < 1) { hexArray[i + 3] = numMatrixValue.toString(16).replace('.', ''); } else if (numMatrixValue <= 0) { hexArray[i + 3] = '0'; } else { hexArray[i + 3] = '1'; } } return hexArray; }; const getIndices = async html => { const ON_DEMAND_FILE_REGEX = /['"](ondemand\.s)['"]:\s*['"]([\w]*)['"]/gim; const INDICES_REGEX = /\(\w\[(\d{1,2})\],\s*16\)/gim; const onDemandMatch = ON_DEMAND_FILE_REGEX.exec(html); const keyByteIndices = []; if (onDemandMatch) { const url = `https://abs.twimg.com/responsive-web/client-web/ondemand.s.${onDemandMatch[2]}a.js`; try { const { data } = await axiosGM.get(url); const matches = data.matchAll(INDICES_REGEX); for (const match of matches) { keyByteIndices.push(parseInt(match[1], 10)); } } catch (error) { console.error('Failed to fetch ondemand file:', error); } } if (keyByteIndices.length < 4) { throw new Error('Couldn\'t get KEY_BYTE indices'); } return keyByteIndices; }; module.exports = { getIndices: getIndices, getAnimationKey: getAnimationKey }; }, 727: function(module) { const never = (...args) => { throw new Error(...args); }; module.exports = { never: never }; }, 791: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { decodeTransactionId: function() { return decodeTransactionId; } }); const decodeTimeFromBytes = timeBytes => { const reversed = [ ...timeBytes ].reverse(); const timeValue = reversed.reduce((acc, value) => acc << 8 | value, 0); const baseTime = 1682924400; return new Date((timeValue + baseTime) * 1e3); }; const decodeTransactionId = transactionId => { const padded = transactionId + '='.repeat((4 - transactionId.length % 4) % 4); const binaryString = atob(padded); const decoded = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { decoded[i] = binaryString.charCodeAt(i); } const rand = decoded[0]; const dataSection = Array.from(decoded.subarray(1)).reverse().map(byte => byte ^ rand).reverse(); const keyBytes = dataSection.slice(0, 48); const timeNowBytes = dataSection.slice(48, 52); const hashBytes = dataSection.slice(52, 68); const additional = dataSection[68]; return { keyBytes: keyBytes, time: decodeTimeFromBytes(timeNowBytes), hashBytes: hashBytes, additional: additional }; }; }, 945: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { 'use strict'; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { axiosGM: function() { return axiosGM; } }); const parseResponseHeaders = headerStr => { const headers = {}; if (!headerStr) { return headers; } headerStr.split('\r\n').forEach(line => { if (line) { const parts = line.split(':'); const key = parts.shift()?.trim(); const value = parts.join(':').trim(); if (key) { if (key.toLowerCase() === 'set-cookie') { if (headers[key]) { if (Array.isArray(headers[key])) { headers[key].push(value); } else { headers[key] = [ headers[key], value ]; } } else { headers[key] = value; } } else { headers[key] = value; } } } }); return headers; }; const axiosGM = function(config) { const finalConfig = { ...axiosGM.defaults, ...config }; const retries = finalConfig.retry ?? 0; const retryDelay = finalConfig.retryDelay ?? 0; const requestAttempt = attempt => new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: finalConfig.method ? finalConfig.method.toUpperCase() : 'GET', url: finalConfig.url, headers: finalConfig.headers, data: finalConfig.data, responseType: finalConfig.responseType || 'json', timeout: finalConfig.timeout, fetch: finalConfig.fetch ?? true, onload(response) { const axiosResponse = { data: response.response || response.responseText, status: response.status, statusText: response.statusText, headers: parseResponseHeaders(response.responseHeaders), config: finalConfig, request: response }; resolve(axiosResponse); }, onerror(error) { if (attempt < retries) { setTimeout(() => { requestAttempt(attempt + 1).then(resolve).catch(reject); }, retryDelay); } else { reject(error); } }, ontimeout() { if (attempt < retries) { setTimeout(() => { requestAttempt(attempt + 1).then(resolve).catch(reject); }, retryDelay); } else { reject('Error: timeout'); } } }); }); return requestAttempt(0); }; axiosGM.defaults = {}; axiosGM.get = function(url, config = {}) { return axiosGM({ ...config, url: url, method: 'GET' }); }; axiosGM.post = function(url, data, config = {}) { return axiosGM({ ...config, url: url, data: data, method: 'POST' }); }; axiosGM.head = function(url, config = {}) { return axiosGM({ ...config, url: url, method: 'HEAD' }); }; axiosGM.create = function(instanceDefaults = {}) { const instance = config => { const mergedConfig = { ...axiosGM.defaults, ...instanceDefaults, ...config }; return axiosGM(mergedConfig); }; instance.defaults = { ...axiosGM.defaults, ...instanceDefaults }; instance.get = function(url, config = {}) { return instance({ ...config, url: url, method: 'GET' }); }; instance.post = function(url, data, config = {}) { return instance({ ...config, url: url, data: data, method: 'POST' }); }; instance.head = function(url, config = {}) { return instance({ ...config, url: url, method: 'HEAD' }); }; instance.create = axiosGM.create; return instance; }; }, 991: function(__unused_webpack_module, exports) { !function(e, n) { true ? n(exports) : 0; }(this, function(e) { 'use strict'; function l(e) { return '[object Object]' === o(e); } function n(e) { return /^\d+$/.test(e + ''); } function t(e) { return /^\d+\.\d+$/.test(e + ''); } var o = function(e) { return Object.prototype.toString.call(e); }; var r = function() { return (r = Object.assign || function(e) { for (var n, t = 1, o = arguments.length; t < o; t++) { for (var r in n = arguments[t]) { Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r]); } } return e; }).apply(this, arguments); }; function i(e, n, t) { if (t || 2 === arguments.length) { for (var o, r = 0, i = n.length; r < i; r++) { !o && r in n || ((o = o || Array.prototype.slice.call(n, 0, r))[r] = n[r]); } } return e.concat(o || Array.prototype.slice.call(n)); } a.prototype.init = function() { try { this.getSystemName(), this.getBrowserName(); } catch (e) { console.warn('[UA formatter error] '.concat(e)); } }, a.prototype.getEngine = function() { var e = this.agent; return -1 !== e.indexOf('Trident') ? 'Trident' : -1 !== e.indexOf('Firefox') ? 'Gecko' : -1 !== e.indexOf('Presto') ? 'Presto' : 'WebKit'; }, a.prototype.getSystemName = function() { var e, n = (this.agent.match(/^[a-z]+\/\d+\.\d+\s?\(([a-z\d\s:;./_-]+)\)/i) || [])[1]; try { var t, o = ''; if (/Windows/i.test(n)) { var r = (n.match(/NT\s(\d+\.\d+)/) || [])[1]; switch (this.info.os = 'Windows', r) { case '6.3': o = '8.1'; break; case '6.2': o = '8'; break; case '6.1': o = '7'; break; case '5.2': case '5.1': o = 'XP'; break; default: o = r; } this.info.device = 'PC', this.info.osVersion = o; } else { /^Macintosh/i.test(n) ? (o = (n.match(/X\s((\d+(_|\.))+\d+)/) || [])[1], this.info.os = 'Macintosh', this.info.device = 'PC', this.info.osVersion = null != (e = null == o ? void 0 : o.replace(/_/g, '.')) ? e : 'Unknown') : /^iPad/i.test(n) ? (o = (n.match(/((\d+_)+\d+)/) || [])[1], this.info.os = 'iPad', this.info.device = 'Tablet', this.info.osVersion = o.replace(/_/g, '.')) : /^iPhone/i.test(n) ? (o = (n.match(/((\d+_)+\d+)/) || [])[1], this.info.os = 'iPhone', this.info.device = 'Mobile', this.info.osVersion = o.replace(/_/g, '.')) : -1 !== n.indexOf('Android') ? (t = (n.match(/Android\s((\d+\.?)+\d?)/) || [])[1], this.info.device = 'Mobile', this.info.os = 'Android', this.info.osVersion = t) : (/Linux\s[a-z\d_]+/.test(n) ? this.info.os = 'Linux' : this.info.os = 'Unknown', this.info.osVersion = 'Unknown'); } } catch (e) { this.info.os = 'Unknown', this.info.osVersion = 'Unknown'; } }, a.prototype.getBrowserName = function() { var e = Object.keys(this.browserNameMap).map(function(e) { return new RegExp(''.concat(e, '(\\/|\\s)(\\d+\\.)+\\d+')); }), n = 1 < (n = (this.agent.match(/[a-z\d]+(\/|\s)(\d+\.)+\d+/gi) || []).filter(function(n) { return -1 !== e.findIndex(function(e) { return e.test(n); }); })).length && !/^Safari/.test(n[n.length - 1]) ? n.reverse() : n; this.info = r(r({}, this.info), this._formatBrowserVersion(n[0])); }, a.prototype._formatBrowserVersion = function(e) { var n, t, o, r; try { for (var i = null != (t = null == (n = e.match(/(?<name>[a-z\d]+)(\/|\s)(?<version>(\d+\.)+\d+)/i)) ? void 0 : n.groups) ? t : {}, s = i.name, a = i.version, c = {}, u = 0, f = Object.entries(this.browserNameMap); u < f.length; u++) { var l = f[u], d = l[0], h = l[1]; if (new RegExp(d).test(s)) { c = h; break; } } var p = { browserVersion: null != a ? a : 'Unknown', browser: null != (o = c.en) ? o : 'Unknown', browserZH: null != (r = (null == c ? void 0 : c.zh) || c.en) ? r : 'Unknown' }; return 'Trident' === s && (p.browserVersion = { '4.0': 8, '5.0': 9, '6.0': 10, '7.0': 11 }[a]), p; } catch (e) { return console.warn('[UA formatter error] '.concat(e)), { browser: 'Unknown', browserVersion: 'Unknown' }; } }; var s = a; function a(e) { this.agent = '', this.info = { browser: '', browserZH: '', browserVersion: '', os: '', osVersion: '', device: 'Unknown', engine: 'WebKit' }, this.browserNameMap = { MicroMessenger: { en: 'MicroMessenger', zh: '微信' }, MetaSr: { en: 'MetaSr', zh: '搜狗浏览器' }, 'QQ(Browser)?': { en: 'QQBrowser', zh: 'QQ浏览器' }, UCBrowser: { en: 'UCBrowser', zh: 'UC浏览器' }, '2345Explorer': { en: '2345Explorer', zh: '2345极速浏览器' }, Mb2345Browser: { en: 'Mb2345Browser', zh: '2345手机浏览器' }, Trident: { en: 'Internet Explorer' }, 'Edge?': { en: 'Edge' }, OPR: { en: 'Opera' }, Vivaldi: { en: 'Vivaldi' }, Firefox: { en: 'Firefox' }, Chrome: { en: 'Chrome' }, Safari: { en: 'Safari' } }, this.agent = e, this.init(); var e = this.info, n = e.browser, t = e.browserVersion, e = e.osVersion; this.info = r(r({}, this.info), { engine: this.getEngine(), browserVersion: 'Safari' === n ? e : t }); } u.prototype.init = function() { var t; 'undefined' != typeof window && (t = {}, document.cookie.split(/;\s/).forEach(function(e) { var e = e.split(/=/), n = e[0], e = e[1]; t[n] = e; }), this.cookies = t); }, u.prototype.getItem = function(e) { return this.cookies[e]; }, u.prototype.getAllItems = function() { return this.cookies; }, u.prototype.setItem = function(e, n, t, o, r, i) { document.cookie = ''.concat(e, '=').concat(n).concat(t ? '; expires='.concat(t) : '').concat(o ? '; path='.concat(o) : '').concat(r ? '; domain='.concat(r) : '').concat(i ? '; secure' : ''); }; var c = u; function u() { this.cookies = {}, this.init(); } function d(e, n) { var t = i(i([], n || [], !0), [ '_' ], !1).join('|'); return e.replace(new RegExp('(('.concat(t, ')[a-z])+'), 'g'), function(e, n) { return n.replace(new RegExp(t), '').toLocaleUpperCase(); }); } function f(e) { return e.replace(/(-\w)/g, function(e) { return e.substr(1, 1).toUpperCase(); }).replace(/^(\w)/, function(e) { return e.toUpperCase(); }); } e.countDown = function e(n, t, o, r) { if (!window) { throw new Error('window is not defined.'); } if (0 < n) { return r && r(), n--, window[t] = window.setTimeout(function() { e(n, t, o, r); }, 1e3), function() { return clearTimeout(window[t]); }; } clearTimeout(window[t]), o && o(); }, e.createRandomID = function(e) { void 0 === e && (e = 12); for (var n = [], t = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), o = t.length, r = 0; r < e; r++) { n.push(t[Math.round(Math.random() * o)]); } return n.join(''); }, e.dCookie = function() { return new c(); }, e.debounce = function(o, r, i) { var s; return void 0 === r && (r = 0), void 0 === i && (i = !1), function() { for (var e = this, n = [], t = 0; t < arguments.length; t++) { n[t] = arguments[t]; } i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() { o.apply(e, n); }, r)); }; }, e.debounceDecorator = function(r, i) { var s; return function(e, n, t) { var o = t.value; return t.value = function() { for (var e = this, n = [], t = 0; t < arguments.length; t++) { n[t] = arguments[t]; } i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() { o.apply(e, n); }, r)); }, t; }; }, e.debugWarn = function(e, n) { console.warn('['.concat(e, ']: ').concat(n)); }, e.deepCopy = function e(n) { if (l(n) || Array.isArray(n)) { var t, o = Array.isArray(n) ? [] : {}; for (t in n) { o[t] = e(n[t]); } return o; } return n; }, e.deleteArrayItems = function(n, e, t) { return 'object' == typeof e[0] ? e.filter(function(e) { return !n.includes(e[t]); }) : e.filter(function(e) { return !n.includes(e); }); }, e.formatQueryParams = function(e) { e = null == (e = /\?(?<params>(.*)=.+)/.exec(decodeURIComponent(e))) ? void 0 : e.groups; if (!e) { return {}; } for (var n = e.params.split('&'), o = {}, t = 0; t < n.length; t++) { n[t].replace(/([^?&]*)=([^?&]*)/, function(e, n, t) { return o[n] = t, e; }); } return o; }, e.formatThousandth = function(e) { var e = ''.concat(e).split('.'), n = e[0], e = e[1], e = void 0 === e ? '' : e, n = n.replace(/\d{1,3}(?=(\d{3})+$)/g, '$&,'); return ''.concat(n).concat(e ? '.'.concat(e) : ''); }, e.generateTree = function e(n, t, o, r) { for (var i = [], s = 0; s < n.length; s++) { var a = n[s]; a[o] === t && (i.push(a), a.children = e(n, a[null != r ? r : 'id'], o, r)); } return i; }, e.isBoolean = function(e) { return 'boolean' == typeof e; }, e.isEmpty = function(e) { return Array.isArray(e) ? 0 === e.length : l(e) ? 0 === Object.keys(e).length : [ '[object Set]', '[object Map]' ].includes(o(e)) ? 0 === e.size : [ null, void 0, '' ].includes(e); }, e.isFloatNumber = t, e.isFunction = function(e) { return '[object Function]' === o(e); }, e.isImageUrl = function(e) { return /\.((png)|(jpe?g)|(gif)|(svg)|(webp))$/gi.test(e); }, e.isInteger = n, e.isNumber = function(e) { return n(e) || t(e); }, e.isObject = l, e.isPromise = function(e) { return '[object Promise]' === o(e); }, e.isRegexp = function(e) { return '[object RegExp]' === o(e); }, e.objectKeyToCamelCase = function e(n, t, o) { if (Array.isArray(n)) { for (var r = [], i = 0; i < n.length; i++) { r[i] = e(t && n[i][t] ? n[i][t] : n[i], t, o); } } else if (l(n)) { r = {}; for (var s = t && n[t] ? n[t] : n, a = 0, c = Object.entries(s); a < c.length; a++) { var u = (f = c[a])[0], f = f[1]; Array.isArray(f) || l(s) ? r[d(u, o)] = e(f, t, o) : r[d(u, o)] = f; } } else { r = n; } return r; }, e.pickLastItem = function(e) { return e[e.length - 1]; }, e.realType = o, e.searchParams = function(e, n) { return void 0 === e && (e = null === location || void 0 === location ? void 0 : location.search), new URLSearchParams(e).get(n); }, e.throwError = function(e, n) { throw '['.concat(f(e), ']: ').concat(n); }, e.toBoolean = function(e) { return 'true' === e || 'false' !== e && Boolean(e); }, e.toLowerCamelCase = d, e.toPascalCase = f, e.toUnderline = function(e) { return e.replace(/([A-Z])/g, function(e) { return '_'.concat(e.toLocaleLowerCase()); }); }, e.ua = function(e) { return void 0 === e && (e = navigator.userAgent), new s(e).info; }; }); } }; var __webpack_module_cache__ = {}; function __webpack_require__(moduleId) { var cachedModule = __webpack_module_cache__[moduleId]; if (cachedModule !== undefined) { return cachedModule.exports; } var module = __webpack_module_cache__[moduleId] = { id: moduleId, exports: {} }; __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); return module.exports; } !function() { __webpack_require__.n = function(module) { var getter = module && module.__esModule ? function() { return module['default']; } : function() { return module; }; __webpack_require__.d(getter, { a: getter }); return getter; }; }(); !function() { __webpack_require__.d = function(exports, definition) { for (var key in definition) { if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; }(); !function() { __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; }(); !function() { __webpack_require__.r = function(exports) { if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; }(); var __webpack_exports__ = {}; !function() { 'use strict'; const external_Swal_namespaceObject = Swal; var external_Swal_default = __webpack_require__.n(external_Swal_namespaceObject); const external_Cookies_namespaceObject = Cookies; var external_Cookies_default = __webpack_require__.n(external_Cookies_namespaceObject); var auto_task = __webpack_require__(675); var javascript_utils_umd_min = __webpack_require__(991); const httpRequest = async (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: data, options: options }); }, onabort() { resolve({ result: 'Error', statusText: 'Aborted', status: 602, data: undefined, options: options }); }, onerror(data) { resolve({ result: 'Error', statusText: 'Error', status: 603, data: data, options: options }); }, onload(data) { const headers = {}; data.responseHeaders?.split('\n').forEach(header => { const headerArr = header.trim().split(':'); const name = headerArr.shift()?.trim() || ''; const value = headerArr.join(':').trim(); if (name && value) { if (headers[name]) { if (Array.isArray(headers[name])) { headers[name].push(value); } else { headers[name] = [ headers[name], value ]; } } else { headers[name] = value; } } }); if (headers['set-cookie'] && !Array.isArray(headers['set-cookie'])) { headers['set-cookie'] = [ headers['set-cookie'] ]; } data.responseHeadersText = data.responseHeaders; data.responseHeaders = headers; data.finalUrl = data.responseHeaders?.location || data.finalUrl; if (options.responseType === 'json' && data?.response && typeof data.response !== 'object') { try { data.response = JSON.parse(data.responseText); } catch (error) {} } resolve({ result: 'Success', statusText: 'Load', status: 600, data: data, options: 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: options })); throwError(error, 'httpRequest'); return { result: 'JsError', statusText: 'Error', status: 604, error: error, options: options }; } }; const tools_httpRequest = httpRequest; const echoLog = ({ type, text, html, id }) => { const emptyStatus = { success: () => emptyStatus, error: () => emptyStatus, warning: () => emptyStatus, info: () => emptyStatus, view: () => emptyStatus }; try { let ele; if (type) { switch (type) { case 'joiningSteamGroup': case 'leavingSteamGroup': case 'gettingSteamGroupId': ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/groups/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'joiningSteamOfficialGroup': case 'leavingSteamOfficialGroup': case 'gettingSteamOfficialGroupId': ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/games/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'subscribingForum': case 'unsubscribingForum': case 'gettingForumId': ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/app/${text}/discussions/" target="_blank">${text}</a>]...<font></font></li>`); break; case 'followingCurator': case 'unfollowingCurator': case 'gettingCuratorId': ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/${text?.includes('/') ? text : `curator/${text}`}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'addingToWishlist': case 'removingFromWishlist': case 'followingGame': case 'unfollowingGame': case 'gettingSubid': case 'addingFreeLicense': case 'requestingPlayTestAccess': ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/app/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'addingFreeLicenseSubid': ele = $(`<li>${i18n('addingFreeLicense')}[<a href="https://steamdb.info/sub/${text}/" target="_blank">${text}</a>]...<font></font></li>`); break; case 'favoritingWorkshop': case 'unfavoritingWorkshop': case 'gettingWorkshopAppId': case 'votingUpWorkshop': ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=${text}" target="_blank"> ${text}</a>]...<font></font></li>`); break; case 'gettingAnnouncementParams': case 'likingAnnouncement': ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/news/app/${text}/view/${id}" target="_blank"> ${id}</a>]...<font></font></li>`); break; case 'joiningDiscordServer': case 'gettingDiscordGuild': ele = $(`<li>${i18n(type)}[<a href="https://discord.com/invite/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'leavingDiscordServer': ele = $(`<li>${i18n(type)}[<a href="https://discord.com/channels/@me/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'updateDiscordAuth': ele = $(`<li style="color:red;">${i18n('updateDiscordAuth')}</li>`); break; case 'followingTwitchChannel': case 'unfollowingTwitchChannel': case 'gettingTwitchChannelId': ele = $(`<li>${i18n(type)}[<a href="https://www.twitch.tv/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'gettingInsUserId': case 'followingIns': case 'unfollowingIns': ele = $(`<li>${i18n(type)}[<a href="https://www.instagram.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`); break; case 'gettingTwitterUserId': case 'followingTwitterUser': case 'unfollowingTwitterUser': ele = $(`<li>${i18n(type)}[<a href="https://x.com/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'retweetting': case 'unretweetting': ele = $(`<li>${i18n(type)}${text}...<font></font></li>`); break; case 'joiningReddit': case 'leavingReddit': ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/r/${text}/" target="_blank">${text}</a>]...<font></font></li>`); break; case 'followingRedditUser': case 'unfollowingRedditUser': ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/user/${text?.replace('u_', '')}" target="_blank"> ${text?.replace('u_', '')}</a>]...<font></font></li>`); break; case 'followingYtbChannel': case 'unfollowingYtbChannel': ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/channel/${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'likingYtbVideo': case 'unlikingYtbVideo': ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/watch?v=${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'gettingVkId': case 'joiningVkGroup': case 'leavingVkGroup': case 'joiningVkPublic': case 'leavingVkPublic': case 'sendingVkWall': case 'deletingVkWall': ele = $(`<li>${i18n(type)}[<a href="https://vk.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`); break; case 'visitingLink': ele = $(`<li>${i18n('visitingLink')}[<a href="${text}" target="_blank">${text}</a>]...<font></font></li>`); break; case 'verifyingInsAuth': case 'text': ele = $(`<li>${i18n(text)}<font></font></li>`); break; case 'html': ele = $(text || html); break; case 'whiteList': ele = $(`<li><font class="warning">${i18n('skipTask')}[${text}(${id})](${i18n('whiteList')})</font></li>`); break; case 'globalOptionsSkip': ele = $(`<li>${i18n('skipTaskOption')}<font class="warning">${text}</font></li>`); break; default: ele = $(`<li>${i18n('unKnown')}:${type}(${text})...<font></font></li>`); break; } } else if (text) { ele = $(`<li>${i18n(text)}<font></font></li>`); } else if (html) { ele = $(html); } else { ele = $('<li><font></font></li>'); } ele.addClass('card-text'); $('#auto-task-info').append(ele); ele[0]?.scrollIntoView(); const font = ele.find('font'); const status = { font: font, success(text = 'Success', html = false) { this.font?.attr('class', '').addClass('success'); html ? this.font?.html(text) : this.font?.text(text); return this; }, error(text = 'Error', html = false) { this.font?.attr('class', '').addClass('error'); html ? this.font?.html(text) : this.font?.text(text); return this; }, warning(text = 'Warning', html = false) { this.font?.attr('class', '').addClass('warning'); html ? this.font?.html(text) : this.font?.text(text); return this; }, info(text = 'Info', html = false) { this.font?.attr('class', '').addClass('info'); html ? this.font?.html(text) : this.font?.text(text); return this; }, view() { this.font?.[0].scrollIntoView(); return this; } }; return status; } catch (error) { throwError(error, 'echoLog'); return emptyStatus; } }; const scripts_echoLog = echoLog; const unique = array => { try { return [ ...new Set(array) ]; } catch (error) { throwError(error, 'unique'); return []; } }; const delay = (time = 1e3) => new Promise(resolve => { setTimeout(() => { resolve(true); }, time); }); const getRedirectLink = async (link, redirectOnce = false) => { try { if (!link) { return null; } const redirectLinksCache = GM_getValue('redirectLinks') || {}; if (redirectLinksCache[link]) { redirectLinksCache[link]; } return await tools_httpRequest({ url: link, method: 'GET', redirect: redirectOnce ? 'manual' : 'follow' }).then(({ data }) => { if (data?.finalUrl) { redirectLinksCache[link] = data.finalUrl; GM_setValue('redirectLinks', redirectLinksCache); return data.finalUrl; } return null; }); } catch (error) { throwError(error, 'getRedirectLink'); return null; } }; const visitLink = async (link, options) => { try { const logStatus = scripts_echoLog({ type: 'visitLink', text: link }); return await tools_httpRequest({ url: link, method: 'GET', ...options }).then(({ result, statusText, status }) => { if (result === 'Success') { logStatus.success(); return true; } logStatus.error(`${result}:${statusText}(${status})`); return false; }); } catch (error) { throwError(error, 'visitLink'); return false; } }; const getUrlQuery = url => { try { const query = {}; if (url) { if (url.includes('?')) { url.split('?')[1].replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => { query[key] = value; return str; }); } } else { window.location.search.replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => { query[key] = value; return str; }); } return query; } catch (error) { throwError(error, 'getUrlQuery'); return {}; } }; const getUuid = () => { const uuidUrl = URL.createObjectURL(new Blob()).toString(); return uuidUrl.slice(uuidUrl.lastIndexOf('/') + 1); }; const stringToColour = str => { try { let hash = 0; for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } let colour = '#'; for (let i = 0; i < 3; i++) { const value = hash >> i * 8 & 255; colour += `00${value.toString(16)}`.slice(-2); } return colour; } catch (error) { throwError(error, 'stringToColour'); return '#fff'; } }; const debug = (log, data) => { if (!window.DEBUG) { return; } console.log('%c%s', 'color:#a7a7a7', `Auto-Task[Debug]: ${log}`); if (data) { console.log('%c%s', 'color:#a7a7a7', 'Auto-Task[Debug]: ', data); } }; const defaultGlobalOptions = { doTask: { discord: { servers: true }, instagram: { users: true }, twitch: { channels: true }, twitter: { users: true, retweets: true }, vk: { names: true }, youtube: { channels: true, likes: true }, reddit: { reddits: true }, steam: { groups: true, officialGroups: true, wishlists: true, follows: true, forums: true, workshops: true, curators: true, workshopVotes: true, announcements: true, licenses: true, playtests: true } }, undoTask: { discord: { servers: true }, instagram: { users: true }, twitch: { channels: true }, twitter: { users: true, retweets: true }, vk: { names: true }, youtube: { channels: true, likes: true }, reddit: { reddits: true }, steam: { groups: true, officialGroups: true, wishlists: true, follows: true, forums: true, workshops: true, curators: true } }, ASF: { AsfEnabled: false, AsfIpcUrl: '', AsfIpcPassword: '', AsfBotname: 'asf' }, position: { buttonSideX: 'right', buttonSideY: 'top', buttonDistance: '15,30', showButtonSideX: 'right', showButtonSideY: 'top', showButtonDistance: '15,30', logSideX: 'right', logSideY: 'bottom', logDistance: '10,10' }, hotKey: { doTaskKey: 'alt + d', undoTaskKey: 'alt + u', toggleLogKey: 'alt + l' }, other: { twitterVerifyId: '783214', youtubeVerifyChannel: 'UCrXUsMBcfTVqwAS7DKg9C0Q', autoUpdateSource: 'jsdelivr', language: 'zh', checkLogin: true, checkLeftKey: true, defaultShowButton: true, defaultShowLog: true, debug: false, receivePreview: true } }; const userDefinedGlobalOptions = GM_getValue('globalOptions') || {}; const assignObject = (obj1, obj2) => { try { const newObj = {}; for (const [ key, value ] of Object.entries(obj1)) { if (Object.prototype.toString.call(value) === '[object Object]' && Object.prototype.toString.call(obj2[key]) === '[object Object]') { newObj[key] = assignObject(value, obj2[key]); } else { newObj[key] = obj2[key] ?? value; } } return newObj; } catch (error) { throwError(error, 'assignObject'); return defaultGlobalOptions; } }; const globalOptions = assignObject(defaultGlobalOptions, userDefinedGlobalOptions); const saveData = () => { try { const data = {}; $('#globalOptionsForm').serializeArray().map(value => { data[value.name] = value.value; return value; }); $.makeArray($('#globalOptionsForm input')).map(element => { const name = $(element).attr('name'); const keys = name.split('.'); if (keys.length === 3) { globalOptions[keys[0]][keys[1]][keys[2]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false; } else if (keys.length === 2) { globalOptions[keys[0]][keys[1]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false; } return element; }); GM_setValue('globalOptions', globalOptions); external_Swal_default().fire({ title: i18n('changeGlobalOptionsSuccess'), icon: 'success' }); } catch (error) { throwError(error, 'saveData'); } }; const changeGlobalOptions = showType => { try { let globalOptionsForm = `<form id="globalOptionsForm" class="auto-task-form"> <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`; for (const [ type, data1 ] of Object.entries(globalOptions)) { for (const [ option, data2 ] of Object.entries(data1)) { if ([ 'other', 'position', 'hotKey', 'ASF' ].includes(type)) { if (typeof data2 === 'boolean') { globalOptionsForm += `<tr style="background-color: ${stringToColour(type)}44">${Object.keys(data1).indexOf(option) === 0 ? `<th rowspan="${Object.keys(data1).length}">${i18n(type)}</th>` : ''}<td>${i18n(option)}</td><td><label><input type="checkbox" name="${type}.${option}"${data2 ? ' checked="checked"' : ''}/><span><i></i></span></label></td></tr>`; } else { globalOptionsForm += `<tr style="background-color: ${stringToColour(type)}44">${Object.keys(data1).indexOf(option) === 0 ? `<th rowspan="${Object.keys(data1).length}" style="background-color: ${stringToColour(type)}66">${i18n(type)}</th>` : ''}<td>${i18n(option)}</td><td><input class="editOption" type="text" name="${type}.${option}" value="${data2}"/></td></tr>`; } } else { for (const [ socialType, data3 ] of Object.entries(data2)) { globalOptionsForm += `<tr style="background-color: ${stringToColour(option)}66">${Object.keys(data1).indexOf(option) === 0 ? `<th rowspan="${Object.keys(data1).map(key => Object.keys(data1[key]).length).reduce((acr, cur) => acr + cur)}" style="background-color: ${stringToColour(type)}66">${i18n(type)}</th>` : ''}<td>${option}.${i18n(socialType)}</td><td><label><input type="checkbox" name="${type}.${option}.${socialType}"${data3 ? ' checked="checked"' : ''}/><span><i></i></span></label></td></tr>`; } } } } globalOptionsForm += '</tbody></table></form>'; if (showType === 'swal') { external_Swal_default().fire({ title: i18n('globalOptions'), html: globalOptionsForm, showConfirmButton: true, confirmButtonText: i18n('save'), showCancelButton: true, cancelButtonText: i18n('close') }).then(({ isConfirmed }) => { if (isConfirmed) { saveData(); } }); } else { $('body').append(`<h2>${i18n('globalOptions')}</h2>${globalOptionsForm}`); } } catch (error) { throwError(error, 'changeGlobalOptions'); } }; const data = { website: '网站', type: '类型', edit: '编辑', whiteList: '白名单', skipTask: '跳过撤销任务', whiteListOptions: '白名单设置', changeWhiteListOption: '设置白名单(%0)', whiteListNotFound: '找不到此项白名单: %0', changeWhiteListSuccess: '白名单修改成功,刷新生效!', changeWebsiteOptions: '网站设置', changeGlobalOptions: '全局设置', ok: '是', save: '保存', close: '关闭', return: '返回', option: '选项', value: '值', websiteOptions: '当前网站设置', changeWebsiteOptionsSuccess: '更改当前网站设置成功,刷新生效!', changeGlobalOptionsSuccess: '更改全局设置成功,刷新生效!', needLogin: '请先登录!', getTasksInfo: '正在获取并处理任务信息...', gettingKey: '正在获取Key...', verifyingTask: '正在验证任务', notice: '自动任务脚本提醒', noKeysLeft: '此页面已经没有剩余key了,是否关闭?', giveawayEnded: '此活动已结束,是否关闭?', giveawayNotWork: '此活动因某些原因(已结束/暂停/未开始...)不可用(如果是脚本误判请及时反馈),是否关闭?', confirm: '确定', cancel: '取消', unKnown: '未知', unKnownTaskType: '未识别的任务', doing: '正在做任务', allTasksComplete: '所有任务已完成!', getTaskIdFailed: '获取任务Id失败!', initSuccess: '%0 初始化成功!', initFailed: '%0 初始化失败!', errorLink: '链接错误: %0', needInit: '请先初始化', verifyingAuth: '正在验证%0凭证...', updatingAuth: '正在更新%0凭证...', refreshingToken: '正在刷新%0凭证...', settingToken: '正在设置%0凭证...', steamStoreTab: 'Steam商店(弹窗)', steamCommunityTab: 'Steam社区(弹窗)', initing: '正在初始化...', getFailed: '获取%0失败!', checkLoginFailed: '检测登录状态失败!', checkLeftKeyFailed: '检测剩余Key失败!', userId: '用户Id', joiningGiveaway: '正在加入赠Key', needJoinGiveaway: '需要先加入赠Key', cannotUndo: '此网站不支持取消任务', verifyAuth: '正在验证 %0 凭证...', closePageNotice: '如果此页面没有自动关闭,请自行关闭本页面。', errorReport: '检测到脚本报错,是否前往反馈BUG?', visitingLink: '正在访问链接...', doTask: '做任务', undoTask: '撤销任务', verifyTask: '验证任务', getKey: '获取Key', selectAll: '全选', selectNone: '全不选', invertSelect: '反选', doFreeTask: '加入免费赠品', doPointTask: '加入点数赠品', skipTaskOption: '设置中已配置跳过任务', other: '其他', globalOptions: '全局设置', checkLogin: '登录检测</br>需要登录的网站自动登录,部分网站支持', checkLeftKey: '剩余Key检测</br>赠Key活动结束提示是否关闭,部分网站支持', twitterVerifyId: '通过尝试关注该账号验证Twitter凭证</br>默认为Twitter官方帐号 783214</br>不想关注官方账号可以改为自己的帐号', youtubeVerifyChannel: '通过尝试订阅该频道验证YouTube凭证</br>默认为YouTube官方频道 UCrXUsMBcfTVqwAS7DKg9C0Q</br>不想关注官方频道可以改为自己的频道', autoUpdateSource: '更新源</br>github: 需代理,实时更新</br>jsdelivr: 可不用代理,更新有延迟</br>standby: 备用</br>auto: 依次使用github, jsdelivr, standby源进行尝试更新', saveGlobalOptions: '保存设置', settingPage: '设置页面', name: '名称', version: '版本', scriptManager: '脚本管理器', script: '脚本', environment: '环境', os: '系统', browser: '浏览器', getId: '获取 %0 id', getTwitterUserId: '获取Twitter用户id(获取id功能仅在设置页面可用)', getYoutubeChannelId: '获取Youtube频道id(获取id功能仅在设置页面可用)', showButton: '显示按钮', hideButton: '隐藏按钮', showLog: '显示日志', hideLog: '隐藏日志', defaultShowButton: '默认显示按钮', defaultShowLog: '默认显示日志', debug: '输出调试日志,不要开启此选项!', receivePreview: '接收预览版更新', position: '组件位置', buttonSideX: '按钮区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右', buttonSideY: '按钮区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下', buttonDistance: '按钮区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离', showButtonSideX: '显示按钮水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右', showButtonSideY: '显示按钮垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下', showButtonDistance: '显示按钮距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离', logSideX: '日志区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右', logSideY: '日志区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下', logDistance: '日志区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离', hotKey: '快捷键', doTaskKey: '做任务快捷键</br>(实时预览功能仅在设置页面可用)', undoTaskKey: '撤销任务快捷键</br>(实时预览功能仅在设置页面可用)', toggleLogKey: '显示/隐藏日志快捷键</br>(实时预览功能仅在设置页面可用)', tasksHistory: '任务历史', clearHistory: '清空历史', clearHistoryFinished: '已清空任务历史!', deleteTask: '删除任务', lastChangeTime: '最后一次修改时间', clearTaskFinished: '删除以下任务完成!', clearTaskFailed: '删除任务失败,没有找到任务名!', syncData: '数据同步', settingData: '正在上传数据...', gettingData: '正在获取数据...', help: '帮助', fileName: '文件名', upload2gist: '同步到Gist', downloadFromGist: '从Gist同步', saveAndTest: '保存配置并测试', testSuccess: '测试成功!', testFailed: '测试失败!', saveAndTestNotice: '请先保存配置并测试!', processingData: '正在处理数据...', updatingData: '正在上传数据...', syncDataSuccess: '同步数据成功!', syncDataFailed: '同步数据失败,请在控制台查看错误信息!', downloadingData: '正在下载数据...', checkedNoData: '没有检测到远程数据,请确认配置是否正确!', savingData: '正在保存数据...', syncHistory: '同步任务历史', checkUpdateFailed: '检测更新失败', newVersionNotice: '检测到新版本V%0, <a class="high-light" href="%1" target="_blank">点此更新</a>', language: '语言</br>目前仅支持zh: 中文, en: 英文', gistOptions: 'Gist 设置', swalNotice: '检测到您第一次安装V4版本脚本,请前往阅读用前必读内容!', echoNotice: '检测到您第一次安装V4版本脚本,请<a class="high-light" href="%0" target="_blank">点此前往</a>阅读用前必读内容!', noticeLink: 'https://auto-task-doc.js.org/guide/#用前必读', toGithub: '前往Github反馈', toKeylol: '前往其乐论坛反馈', copySuccess: '错误信息已复制到剪切板,是否前往其乐论坛反馈?', copyFailed: '请复制下方错误信息后前往Keylol论坛反馈!', updateText: '%0 版本更新内容:', Active: '进行中', Ended: '已结束', Banned: '已封禁', Paused: '已暂停', notStart: '未开始', noRemoteData: '检测到远程无数据', errorRemoteDataFormat: '远程数据格式错误', updateHistory: '历史更新记录<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">点此查看</a>', AsfEnabled: '使用ASF做Steam相关任务(需<a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a>插件)', AsfIpcUrl: 'ASF IPC 地址', AsfIpcPassword: 'ASF IPC 密码', versionNotMatched: '脚本管理器版本过低,需TamperMonkey >= 5.2.0或TamperMonkey Beta >= 5.2.6196', groups: '组', officialGroups: '官方组', wishlists: '愿望单', follows: '游戏关注', forums: '论坛', workshops: '创意工坊收藏', curators: '鉴赏家', workshopVotes: '创意工坊点赞', announcements: '社区通知', steamCommunity: 'Steam社区', steamStore: 'Steam商店', licenses: '入库免费游戏', playtests: '请求访问权限', needLoginSteamStore: '请先<a href="https://store.steampowered.com/login/" target="_blank">登录Steam商店</a>', needLoginSteamCommunity: '请先<a href="https://steamcommunity.com/login/home/" target="_blank">登录Steam社区</a>', joiningSteamGroup: '正在加入Steam组', leavingSteamGroup: '正在退出Steam组', gettingSteamGroupId: '正在获取Steam组Id', joiningSteamOfficialGroup: '正在加入Steam官方组', leavingSteamOfficialGroup: '正在退出Steam官方组', gettingSteamOfficialGroupId: '正在获取Steam官方组Id', subscribingForum: '正在订阅Steam论坛', unsubscribingForum: '正在取消订阅Steam论坛', gettingForumId: '正在获取Steam论坛Id', followingCurator: '正在关注Steam鉴赏家', unfollowingCurator: '正在取关Steam鉴赏家', gettingCuratorId: '正在获取Steam鉴赏家Id', addingToWishlist: '正在添加游戏到Steam愿望单', removingFromWishlist: '正在从Steam愿望单移除游戏', followingGame: '正在关注Steam游戏', unfollowingGame: '正在取关Steam游戏', favoritingWorkshop: '正在收藏Steam创意工坊物品', unfavoritingWorkshop: '正在取消收藏Steam创意工坊物品', gettingWorkshopAppId: '正在获取Steam创意工坊物品Id', votingUpWorkshop: '正在点赞Steam创意工坊物品', gettingAnnouncementParams: '正在获取Steam通知信息', likingAnnouncement: '正在点赞Steam通知', changingArea: '正在更换Steam地区: %0...', notNeededChangeArea: '当前地区不需要更换', noAnotherArea: '请检测是否开启正确开启代理', gettingAreaInfo: '正在获取Steam地区信息...', changeAreaNotice: '疑似锁区游戏,尝试换区执行', steamFinishNotice: 'Steam任务完成,尝试将购物车地区换回', gettingSubid: '正在获取游戏subid', addingFreeLicense: '正在入库', missParams: '缺少参数', gettingLicenses: '正在获取Licenses...', requestingPlayTestAccess: '正在请求访问权限', tryChangeAreaNotice: '此功能无法检测游戏是否限区,因此会尝试换区后再入库,换区失败也不影响后续入库', gettingUserLink: '正在获取Steam用户社区链接...', retry: '重试', owned: '已拥有', redirect: '重定向', noSubid: '无法获取,跳过', initingASF: '正在初始化ASF...', servers: '服务器', joiningDiscordServer: '正在加入Discord服务器', leavingDiscordServer: '正在退出Discord服务器', gettingDiscordGuild: '正在获取Discord服务器Id', getDiscordAuthFailed: '获取Discord凭证失败,请检测Discord帐号是否已登录', discordImportantNotice: '重要提醒!!!', discordImportantNoticeText: '由于Discord网站后台更新,目前使用此脚本加组后可能会导致Discord帐号被强制退出,且需要两步验证才能正常登录,请谨慎使用!!!', continue: '继续', skipDiscordTask: '跳过Discord任务', continueAndDontRemindAgain: '继续且不再提醒', users: '用户', loginIns: '请先<a href="https://www.instagram.com/accounts/login/" target="_blank">登录Instagram</a>', insBanned: '您的Instagram账户已被封禁', verifyingInsAuth: '正在验证Instagram凭证...', gettingInsUserId: '正在获取Instagram用户Id', followingIns: '正在关注Instagram用户', unfollowingIns: '正在取关Instagram用户', reddits: '社区/用户', loginReddit: '请先<a href="https://www.reddit.com/login/" target="_blank">登录Reddit</a>', changingRedditVersion: '正在切换Reddit为新版页面...', joiningReddit: '正在加入Reddit社区', leavingReddit: '正在退出Reddit社区', followingRedditUser: '正在关注Reddit用户', unfollowingRedditUser: '正在取关Reddit用户', channels: '频道', followingTwitchChannel: '正在关注Twitch频道', unfollowingTwitchChannel: '正在取关Twitch频道', gettingTwitchChannelId: '正在获取Twitch频道Id', checkingTwitchIntegrity: '正在检查Twitch完整性...', twitterUser: '推特用户', retweets: '转推', gettingTwitterUserId: '正在获取推特用户Id', followingTwitterUser: '正在关注推特用户', unfollowingTwitterUser: '正在取关推特用户', retweetting: '正在转推', unretweetting: '正在撤销转推', names: '组/社区/动态', loginVk: '请先<a href="https://vk.com/login/" target="_blank">登录Vk</a>', gettingVkId: '正在获取Vk任务Id', joiningVkGroup: '正在加入Vk组', leavingVkGroup: '正在退出Vk组', joiningVkPublic: '正在加入Vk社区', leavingVkPublic: '正在退出Vk社区', sendingVkWall: '正在转发Vk动态', deletingVkWall: '正在撤销转发Vk动态', youtubeChannel: 'YouTube频道', likes: '点赞', loginYtb: '请先<a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">登录YouTube</a>', tryUpdateYtbAuth: '请尝试<a href="https://www.youtube.com/#auth" target="_blank">更新YouTube凭证</a>', gettingYtbToken: '正在获取YouTube Token...', followingYtbChannel: '正在订阅YouTube频道', unfollowingYtbChannel: '正在退订YouTube频道', likingYtbVideo: '正在点赞YouTube视频', unlikingYtbVideo: '正在取消点赞YouTube视频', giveKeyNoticeBefore: '每次验证间隔15s', giveKeyNoticeAfter: '如果没有key, 请在<a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>查看', noPoints: '点数不够,跳过抽奖', getNeedPointsFailed: '获取所需点数失败,跳过抽奖', joiningLottery: '正在加入抽奖', doingGleamTask: '正在做Gleam任务...', gettingGleamLink: '正在获取Gleam任务链接...', gleamTaskNotice: '如果此页面长时间未关闭,请完成任一任务后自行关闭!', verifiedGleamTasks: '已尝试验证所有任务,验证失败的任务请尝试手动验证或完成!', campaign: '检测到人机验证,请完成验证后重新验证任务!', gsNotice: '为避免得到"0000-0000-0000"key, 已自动屏蔽"Grab Key"按钮,获取key时请关闭脚本!', giveeClubVerifyNotice: '正在验证任务...', giveeClubVerifyFinished: '请等待验证完成后自行加入赠Key', doingKeyhubTask: '正在做Keyhub任务...', SweepWidgetNotice: '正在处理并验证任务,每次验证任务有1~3s间隔防止触发验证过快警告...', tasksNotCompleted: '任务未完成', notConnect: '社交平台未连接,跳过任务', tgTaskNotice: '检测到Telegram任务,需要手动完成', confirmingTask: '正在跳过警告页面...', unSupporttedTaskType: '不支持的任务类型' }; const zh_CN = data; const en_US_data = { website: 'Website', type: 'Type', edit: 'Edit', whiteList: 'Whitelist', skipTask: 'Skip undo task', whiteListOptions: 'Whitelist options', changeWhiteListOption: 'Whitelist option(%0)', whiteListNotFound: 'Cannot find this whitelist: %0', changeWhiteListSuccess: 'The whitelist is successfully modified, and the page refresh will take effect!', changeWebsiteOptions: 'Website options', changeGlobalOptions: 'Global options', ok: 'OK', save: 'Save', close: 'Close', return: 'Return', option: 'Option', value: 'Value', websiteOptions: 'Current website settings', changeWebsiteOptionsSuccess: 'The current website setting is changed successfully, and the page refresh will take effect!', changeGlobalOptionsSuccess: 'The global setting is changed successfully, and the refresh will take effect!', needLogin: 'Please log in first!', getTasksInfo: 'Obtaining and processing task information...', gettingKey: 'Getting Key...', verifyingTask: 'Verifying task', notice: 'Automatic task script notice', noKeysLeft: 'There are no more keys left on this page. Do you want to close it?', giveawayEnded: 'This event has ended, do you want to close it?', giveawayNotWork: 'This activity is unavailable for some reasons (banned/ended/paused/not started...)' + ' (if it is a script misjudgment, please give us feedback in time), is it closed?', confirm: 'Confirm', cancel: 'Cancel', unKnown: 'Unknown', unKnownTaskType: 'Unrecognized task', doing: 'Doing a task', allTasksComplete: 'All tasks have been completed!', getTaskIdFailed: 'Failed to obtain task Id!', initSuccess: '%0 was initialized successfully!', initFailed: '%0 initialization failed!', errorLink: 'Link error: %0', needInit: 'Please initialize first', verifyingAuth: 'Verifying %0 token...', updatingAuth: 'Update %0 token...', refreshingToken: 'Refreshing %0 token...', settingToken: 'Setting %0 token...', steamStoreTab: 'Steam store (new tab)', steamCommunityTab: 'Steam community(new tab)', initing: 'Initializing...', getFailed: 'Failed to get %0!', checkLoginFailed: 'Failed to detect login status!', checkLeftKeyFailed: 'Failed to detect the remaining keys!', userId: 'User Id', joiningGiveaway: 'Joining giveaway', needJoinGiveaway: 'Need to join the giveaway first', cannotUndo: 'This website does not support canceling tasks', verifyAuth: 'Verifying %0 token...', closePageNotice: 'f this page does not close automatically, please close this page yourself.', errorReport: 'A script error is detected, do you want to report the BUG?', visitingLink: 'Visiting link ...', doTask: 'DoTask', undoTask: 'UndoTask', verifyTask: 'Verify', getKey: 'GetKey', selectAll: 'SelectAll', selectNone: 'SelectNone', invertSelect: 'InvertSelect', doFreeTask: 'FreeTask', doPointTask: 'PointTask', skipTaskOption: 'Skip task has been configured in the settings', other: 'Other', globalOptions: 'Global Options', checkLogin: 'Login detection</br>Need to log in to the website automatically log in, part of this website supports.', checkLeftKey: 'Key remaining detection</br>The end of the giveaway event prompts whether to close or not, part of this website supports.', twitterVerifyId: 'Verify Twitter token by trying to follow the account.</br>The default is the official Twitter account 783214.</br>' + 'If you don\'t want to follow the official account, you can change it to your own account.', youtubeVerifyChannel: 'Verify YouTube token by trying to subscribe to the channel.</br>' + 'The default is the official YouTube channel UCrXUsMBcfTVqwAS7DKg9C0Q.</br>' + 'If you don\'t want to follow the official channel, you can change it to your own channel.', autoUpdateSource: 'The source to update</br>github: Fast update.</br>jsdelivr: Update is delayed.</br>' + 'standby: Standby source.</br>auto: Try to update using github, jsdelivr, standby sources in turn.', saveGlobalOptions: 'SaveSettings', settingPage: 'Setting Page', name: 'Name', version: 'Version', scriptManager: 'Script Manager', script: 'Script', environment: 'Environment', os: 'OS', browser: 'Browser', getId: 'Get %0 id', getTwitterUserId: 'Get Twitter user id (Get id function is only available on the settings page).', getYoutubeChannelId: 'Get Youtube channel id (Get id function is only available on the settings page).', showButton: 'ShowButton', hideButton: 'HideButton', showLog: 'ShowLog', hideLog: 'HideLog', defaultShowButton: 'Default display button', defaultShowLog: 'Display log by default', debug: 'Output debug log, do not enable this option!', receivePreview: 'Receive preview updates', position: 'Component position', buttonSideX: 'Horizontal positioning of the button area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right', buttonSideY: 'The button area is positioned in the vertical direction (real-time preview function is only available on the settings page).' + '</br>top: top | bottom: bottom', buttonDistance: 'The distance between the button area and the edge (the real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance', showButtonSideX: 'ShowButton horizontal positioning (real-time preview function is only available on the setting page).' + '</br>left: left | right: right', showButtonSideY: 'ShowButton vertical positioning (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom', showButtonDistance: 'The distance between the ShowButton and the edge (real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance', logSideX: 'Horizontal positioning of the log area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right', logSideY: 'Vertical positioning of the log area (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom', logDistance: 'The distance between the log area and the edge (the real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance', hotKey: 'Shortcut key', doTaskKey: 'DoTask shortcut keys</br> (real-time preview function is only available on the settings page).', undoTaskKey: 'UndoTask shortcut keys</br> (real-time preview function is only available on the settings page).', toggleLogKey: 'ShowLog/HideLog shortcut keys</br> (real-time preview function is only available on the settings page).', tasksHistory: 'TasksHistory', clearHistory: 'Clear history', clearHistoryFinished: 'The mission history has been cleared!', deleteTask: 'Delete task', lastChangeTime: 'Last Change Time', clearTaskFinished: 'Delete the following tasks completed!', clearTaskFailed: 'Failed to delete the task, the task name was not found!', syncData: 'DataSync', settingData: 'Uploading data...', gettingData: 'Getting data...', help: 'Help', fileName: 'Filename', upload2gist: 'Sync to Gist', downloadFromGist: 'Sync from Gist', saveAndTest: 'Save configuration and test', testSuccess: 'Test success!', testFailed: 'Test failed!', saveAndTestNotice: 'Please save the configuration and test first!', processingData: 'Processing data...', updatingData: 'Uploading data...', syncDataSuccess: 'Synchronized data successfully!', syncDataFailed: 'Failed to synchronize data, please check the error message on the console!', downloadingData: 'Downloading data...', checkedNoData: 'No remote data is detected, please confirm whether the configuration is correct!', savingData: 'Saving data...', syncHistory: 'Synchronize tasks history', checkUpdateFailed: 'Check update failed', newVersionNotice: 'Checked a new version V%0, <a class="high-light" href="%1" target="_blank">click to update</a>', language: 'Language</br> Currently only supports zh: Chinese, en: English', gistOptions: 'Gist Settings', swalNotice: 'It is detected that you are installing the V4 version script for the first time' + ', please go to read the READ ME FIRST content before use!', echoNotice: 'It is detected that you are installing the V4 version script for the first time' + ', please <a class="high-light" href="%0" target="_blank">click here</a> to read the READ ME FIRST content before use!', noticeLink: 'https://auto-task-doc.js.org/en/guide/#read-me-first', toGithub: 'Feedback(Github)', toKeylol: 'Feedback(Keylol)', copySuccess: 'The error message has been copied to the clipboard. Do you want to go to the Keylol forum to give feedback?', copyFailed: 'Please copy the error information below and report back to the Keylol forum!', updateText: 'Updates in version %0:', Active: 'Active', Ended: 'Ended', Banned: 'Banned', Paused: 'Paused', notStart: 'notStart', noRemoteData: 'No data remotely', errorRemoteDataFormat: 'Remote data has wrong format', updateHistory: '<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">Click here</a>' + ' to view the historical update record.', AsfEnabled: 'Use ASF to do Steam related tasks (requires <a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a> plugin)', AsfIpcUrl: 'ASF IPC URL', AsfIpcPassword: 'ASF IPC Password', groups: 'Group', officialGroups: 'Official Group', wishlists: 'Wishlist', follows: 'Follow Game', forums: 'Forum', workshops: 'Favorite Workshop', curators: 'Curator', workshopVotes: 'Voteup Workshop', announcements: 'Announcement', steamCommunity: 'Steam Community', steamStore: 'Steam Store', licenses: 'Add License', playtests: 'Playtest Access', needLoginSteamStore: 'Please <a href="https://store.steampowered.com/login/" target="_blank">log in to the Steam Store</a>', needLoginSteamCommunity: 'Please <a href="https://steamcommunity.com/login/home/" target="_blank">log in to the Steam Community</a>', joiningSteamGroup: 'Joining Steam Group', leavingSteamGroup: 'Leaving Steam Group', gettingSteamGroupId: 'Getting Steam Group Id', joiningSteamOfficialGroup: 'Joining Steam Official Group', leavingSteamOfficialGroup: 'Leaving Steam Official Group', gettingSteamOfficialGroupId: 'Getting Steam Official Group Id', subscribingForum: 'Subscribing the Steam Forum', unsubscribingForum: 'Unsubscribing the Steam Forum', gettingForumId: 'Getting Steam Forum Id', followingCurator: 'Following Steam Curator', unfollowingCurator: 'Unfollowing Steam Curator', gettingCuratorId: 'Getting Steam Curator Id', addingToWishlist: 'Adding the game to the Steam wishlist', removingFromWishlist: 'Removing the game from the Steam wishlist', followingGame: 'Following Steam games', unfollowingGame: 'Unfollowing Steam games', favoritingWorkshop: 'Favouring Steam Workshop Items', unfavoritingWorkshop: 'Unfavoriting Steam Workshop Items', gettingWorkshopAppId: 'Getting Steam Workshop Item Id', votingUpWorkshop: 'Liking Steam workshop items', gettingAnnouncementParams: 'Getting Steam announcement information', likingAnnouncement: 'Liking Steam announcement', changingArea: 'Changing Steam area: %0...', notNeededChangeArea: 'The current area does not need to be changed', noAnotherArea: 'Please check whether the proxy is turned on correctly', gettingAreaInfo: 'Getting Steam area information...', changeAreaNotice: 'Suspected of a locked zone game, try to change the zone to execute', steamFinishNotice: 'Steam task completed, try to change the shopping cart area back to ', gettingSubid: 'Getting subid', addingFreeLicense: 'Adding free license', missParams: 'Missing parameters', gettingLicenses: 'Getting licenses...', requestingPlayTestAccess: 'Requesting play test access', tryChangeAreaNotice: 'This function cannot detect whether the game is limited, so it will try to change the area before entering the library' + '. Failure to change the area will not affect the subsequent storage.', versionNotMatched: 'The script manager version is too low, requiring TamperMonkey >= 5.2.0 or TamperMonkey Beta >= 5.2.6196', gettingUserLink: 'Getting steam user community link...', retry: 'Retry', owned: 'Owned', redirect: 'Redirect', noSubid: 'skip due to unrecognized', initingASF: 'Initing ASF...', servers: 'Server', joiningDiscordServer: 'Joining Discord Server', leavingDiscordServer: 'Leaving Discord Server', gettingDiscordGuild: 'Getting Discord server Id', getDiscordAuthFailed: 'Failed to get Discord token, please check whether the Discord account is logged in', discordImportantNotice: 'Important Reminder! ! !', discordImportantNoticeText: 'Due to the background update of the Discord website, currently using this script to join a group may cause the Discord account to be forcibly logged out, and two-step verification is required to log in normally, please use it with caution! ! !', continue: 'Continue', skipDiscordTask: 'Skip', continueAndDontRemindAgain: 'Continue without Reminders', users: 'User', loginIns: 'Please <a href="https://www.instagram.com/accounts/login/" target="_blank">log in to Instagram</a>', insBanned: 'Your Instagram account has been banned', verifyingInsAuth: 'Verifying Instagram token...', gettingInsUserId: 'Getting Instagram user Id', followingIns: 'Following Instagram user', unfollowingIns: 'Unfollowing Instagram user', reddits: 'Reddit/User', loginReddit: 'Please <a href="https://www.reddit.com/login/" target="_blank">log in to Reddit</a>', changingRedditVersion: 'Switching Reddit to a new version page...', joiningReddit: 'Joining the Reddit', leavingReddit: 'Leaving the Reddit', followingRedditUser: 'Following Reddit User', unfollowingRedditUser: 'Unfollowing Reddit User', channels: 'Channel', followingTwitchChannel: 'Following Twitch Channel', unfollowingTwitchChannel: 'Unfollowing Twitch Channel', gettingTwitchChannelId: 'Getting Twitch Channel Id', checkingTwitchIntegrity: 'Checking Twitch integrity...', twitterUser: 'Twitter User', retweets: 'Retweet', gettingTwitterUserId: 'Getting Twitter User Id', followingTwitterUser: 'Following Twitter User', unfollowingTwitterUser: 'Unfollowing Twitter User', retweetting: 'Retweetting', unretweetting: 'Unretweetting', names: 'Group/Public/Wall', loginVk: 'Please <a href="https://vk.com/login/" target="_blank">log in to Vk</a>', gettingVkId: 'Getting Vk task Id', joiningVkGroup: 'Joining Vk Group', leavingVkGroup: 'Leaving Vk Group', joiningVkPublic: 'Joining Vk Public', leavingVkPublic: 'Leaving Vk Public', sendingVkWall: 'Sending Vk Wall', deletingVkWall: 'Deleting Vk Wall', youtubeChannel: 'YouTube Channel', likes: 'Like', loginYtb: 'Please <a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">log in to YouTube</a>', tryUpdateYtbAuth: 'Please try to <a href="https://www.youtube.com/#auth" target="_blank">update YouTube token</a>', gettingYtbToken: 'Getting YouTube Token...', followingYtbChannel: 'Subscribing to YouTube channel', unfollowingYtbChannel: 'Unsubscribing to YouTube channel', likingYtbVideo: 'Liking YouTube video', unlikingYtbVideo: 'Unliking YouTube video', giveKeyNoticeBefore: 'Each verification interval is 15s', giveKeyNoticeAfter: 'If there is no key, please check at <a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>', noPoints: 'Not enough points, skip the lottery', getNeedPointsFailed: 'ailed to obtain the required points, skip the lottery', joiningLottery: 'Joining the lottery', doingGleamTask: 'Doing Gleam Task...', gettingGleamLink: 'Getting Gleam task link...', gleamTaskNotice: 'If this page has not been closed for a long time, please close it yourself after completing any task!', verifiedGleamTasks: 'Attempted to verify all tasks. If the verification fails, please try to verify manually or complete it!', campaign: 'ReCAPTCHA detected, please complete it and re-verify the tasks!', gsNotice: 'In order to avoid getting the "0000-0000-0000" key, the "Grab Key" button has been hidden,' + ' please close the script when obtaining the key!', giveeClubVerifyNotice: 'Verifying task...', giveeClubVerifyFinished: 'Wait for the verification to complete and join it by yourself', doingKeyhubTask: 'Doing Keyhub Task...', SweepWidgetNotice: 'The task is being processed and verified. ' + 'There is an interval of 1~3s for each verification task to prevent the triggering of too fast verification warning...', tasksNotCompleted: 'Tasks Not Completed', notConnect: 'Social platform is not connectted, skip', tgTaskNotice: 'The telegram task is checked, need to do it yourself!', confirmingTask: 'Confirming task...', unSupporttedTaskType: 'Unsupportted task type' }; const en_US = en_US_data; const languages = { zh: zh_CN, en: en_US }; const language = [ 'zh', 'en' ].includes(globalOptions.other.language) ? globalOptions.other.language : 'en'; const I18n = (key, ...argvs) => { if (!languages[language]?.[key]) { return key; } return languages[language][key].replace(/%([\d]+)/g, (match, index) => argvs[parseInt(index, 10)]); }; const i18n = I18n; function throwError(error, name) { if (window.TRACE) { console.trace('%cAuto-Task[Debug]:', 'color:blue'); } external_Swal_default().fire({ title: i18n('errorReport'), icon: 'error', showCancelButton: true, confirmButtonText: i18n('toGithub'), showDenyButton: true, denyButtonText: i18n('toKeylol'), cancelButtonText: i18n('close') }).then(({ isDenied, isConfirmed }) => { if (isConfirmed) { GM_openInTab(`https://github.com/HCLonely/auto-task-v4/issues/new?title=${encodeURIComponent(`[BUG] 脚本报错: ${name}`)}&labels=bug&template=bug_report.yml&website=${encodeURIComponent(window.location.href)}&browser=${encodeURIComponent(JSON.stringify((0, javascript_utils_umd_min.ua)(), null, 4))}&manager=${encodeURIComponent(`${GM_info.scriptHandler} ${GM_info.version}`)}&user-script=${encodeURIComponent(GM_info.script.version)}&logs=${encodeURIComponent(error.stack || 'null')}&run-logs=${encodeURIComponent($.makeArray($('#auto-task-info>li')).map(element => element.innerText).join('\n'))}`, { active: true }); } else if (isDenied) { const text = `错误链接: [url=${window.location.href}]${window.location.href}[/url] 环境: [code]${JSON.stringify((0, javascript_utils_umd_min.ua)(), null, 4)}[/code] 脚本管理器: ${GM_info.scriptHandler} ${GM_info.version} 脚本版本: ${GM_info.script.version} 报错信息: [code]${error.stack}[/code] 执行日志: [code]${$.makeArray($('#auto-task-info>li')).map(element => element.innerText).join('\n')}[/code]`; GM_setClipboard(text); external_Swal_default().fire({ title: i18n('copySuccess'), icon: 'success', confirmButtonText: i18n('ok') }).then(() => { GM_openInTab('https://keylol.com/forum.php?mod=post&action=reply&fid=319&tid=777450', { active: true }); }); } }); console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: ${name}\n${error.stack}`); } class Social { tasks; getRealParams(name, links, doTask, link2param) { try { let realParams = []; if (links.length > 0) { realParams = [ ...realParams, ...links.map(link => link2param(link)).filter(link => link) ]; } if (!doTask && this.tasks[name].length > 0) { realParams = [ ...realParams, ...this.tasks[name] ]; } return unique(realParams); } catch (error) { throwError(error, 'Social.getRealParams'); return []; } } } const social_Social = Social; class Discord extends social_Social { tasks; whiteList; #auth = GM_getValue('discordAuth') || {}; #cache = GM_getValue('discordCache') || {}; #initialized = false; constructor() { super(); const defaultTasksTemplate = { servers: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.discord || {} }; } async init(action) { try { if (!GM_getValue('dontRemindDiscordAgain')) { const result = await external_Swal_default().fire({ title: i18n('discordImportantNotice'), text: i18n('discordImportantNoticeText'), showCancelButton: true, showDenyButton: true, confirmButtonText: i18n('continue'), cancelButtonText: i18n('skipDiscordTask'), denyButtonText: i18n('continueAndDontRemindAgain') }).then(({ isConfirmed, isDenied }) => { if (isConfirmed) { return true; } if (isDenied) { GM_setValue('dontRemindDiscordAgain', true); return true; } return false; }); if (!result) { this.#initialized = false; return 'skip'; } } if (GM_getValue('dontRemindDiscordAgain') || action === 'do' && !globalOptions.doTask.discord.servers || action === 'undo' && !globalOptions.undoTask.discord.servers) { this.#initialized = false; return 'skip'; } if (this.#initialized) { return true; } if (!this.#auth.auth) { if (await this.#updateAuth()) { this.#initialized = true; return true; } return false; } const isVerified = await this.#verifyAuth(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Discord')); this.#initialized = true; return true; } GM_setValue('discordAuth', { auth: null }); if (await this.#updateAuth()) { scripts_echoLog({}).success(i18n('initSuccess', 'Discord')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Discord')); return false; } catch (error) { throwError(error, 'Discord.init'); return false; } } async #verifyAuth() { try { const logStatus = scripts_echoLog({ text: i18n('verifyingAuth', 'Discord') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://discord.com/api/v6/users/@me', method: 'HEAD', headers: { authorization: this.#auth.auth } }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Discord.verifyAuth'); return false; } } async #updateAuth() { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', 'Discord') }); return await new Promise(resolve => { const newTab = GM_openInTab('https://discord.com/channels/@me', { active: true, insert: true, setParent: true }); newTab.name = 'ATv4_discordAuth'; newTab.onclose = async () => { const auth = GM_getValue('discordAuth')?.auth; if (auth) { this.#auth = { auth: auth }; logStatus.success(); resolve(await this.#verifyAuth()); } else { logStatus.error('Error: Update discord auth failed!'); resolve(false); } }; }); } catch (error) { throwError(error, 'Discord.updateAuth'); return false; } } async #joinServer(inviteId) { try { const logStatus = scripts_echoLog({ type: 'joiningDiscordServer', text: inviteId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://discord.com/api/v9/invites/${inviteId}`, method: 'POST', dataType: 'json', headers: { authorization: this.#auth.auth, origin: 'https://discord.com', referer: `https://discord.com/invite/${inviteId}` } }); if (result === 'Success' && data?.status === 200) { logStatus.success(); const guild = String(data.response?.guild?.id); if (guild) { this.#setCache(inviteId, guild); this.tasks.servers = unique([ ...this.tasks.servers, inviteId ]); } return true; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Discord.joinServer'); return false; } } async #leaveServer(inviteId) { try { if (this.whiteList.servers.includes(inviteId)) { scripts_echoLog({ type: 'whiteList', text: 'Discord.leaveServer', id: inviteId }); return true; } const guild = await this.#getGuild(inviteId); if (!guild) { return false; } const logStatus = scripts_echoLog({ type: 'leavingDiscordServer', text: guild }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://discord.com/api/v9/users/@me/guilds/${guild}`, method: 'DELETE', headers: { authorization: this.#auth.auth } }); if (result === 'Success' && data?.status === 204) { logStatus.success(); return true; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Discord.leaveServer'); return false; } } async #getGuild(inviteId) { try { const logStatus = scripts_echoLog({ type: 'gettingDiscordGuild', text: inviteId }); const guild = this.#cache[inviteId]; if (guild) { logStatus.success(); return guild; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://discord.com/api/v9/invites/${inviteId}`, responseType: 'json', method: 'GET' }); if (result === 'Success' && data?.status === 200) { const guild = data.response?.guild?.id; if (guild) { logStatus.success(); this.#setCache(inviteId, guild); return guild; } logStatus.error(`${result}:${statusText}(${status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Discord.getGuild'); return false; } } async toggle({ doTask = true, serverLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.discord.servers || !doTask && !globalOptions.undoTask.discord.servers) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'discord.servers' }); } else { const realServers = this.getRealParams('servers', serverLinks, doTask, link => link.match(/invite\/(.+)/)?.[1]); if (realServers.length > 0) { for (const server of realServers) { if (doTask) { prom.push(this.#joinServer(server)); } else { prom.push(this.#leaveServer(server)); } await delay(1e3); } } } return await Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Discord.toggleServers'); return false; } } #setCache(inviteId, guild) { try { this.#cache[inviteId] = guild; GM_setValue('discordCache', this.#cache); } catch (error) { throwError(error, 'Discord.setCache'); } } } const social_Discord = Discord; class Instagram extends social_Social { tasks; whiteList; #cache = GM_getValue('instagramCache') || {}; #auth = {}; #initialized = false; constructor() { super(); const defaultTasksTemplate = { users: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.instagram || {} }; } async init() { try { if (this.#initialized) { return true; } const isVerified = await this.#getUserInfo(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Instagram')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Instagram')); return false; } catch (error) { throwError(error, 'Instagram.init'); return false; } } async #getUserInfo(name = 'instagram') { try { const logStatus = scripts_echoLog({ type: name === 'instagram' ? 'verifyingInsAuth' : 'gettingInsUserId', text: name }); const userId = this.#cache[name]; if (userId && name !== 'instagram') { logStatus.success(); return userId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://www.instagram.com/${name}/`, method: 'GET' }); if (result === 'Success') { if (data?.finalUrl.includes('accounts/login')) { logStatus.error(`Error:${i18n('loginIns')}`, true); return false; } else if (data?.finalUrl.includes('www.instagram.com/challenge')) { logStatus.error(`Error:${i18n('insBanned')}`); return false; } if (data?.status === 200) { const csrftoken = data.responseText.match(/"csrf_token":"(.+?)"/)?.[1]; const hash = data.responseText.match(/"rollout_hash":"(.+?)"/)?.[1]; if (name === 'instagram') { if (csrftoken && hash) { this.#auth = { csrftoken: csrftoken, hash: hash }; return true; } return false; } const id = data.responseText.match(/"profilePage_([\d]+?)"/)?.[1]; if (id) { this.#setCache(name, id); logStatus.success(); return id; } logStatus.error('Error: Get ins data error!'); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } return false; } catch (error) { throwError(error, 'Instagram.getUserInfo'); return false; } } async #followUser(name) { try { const id = await this.#getUserInfo(name); if (!id) { return false; } const logStatus = scripts_echoLog({ type: 'followingIns', text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://www.instagram.com/web/friendships/${id}/follow/`, method: 'POST', dataType: 'json', headers: { 'x-csrftoken': this.#auth.csrftoken, origin: 'https://www.instagram.com', referer: `https://www.instagram.com/${name}/`, 'content-type': 'application/x-www-form-urlencoded', 'sec-fetch-site': 'same-origin', 'x-instagram-ajax': this.#auth.hash } }); if (result === 'Success') { if (data?.status === 200 && data.response?.result === 'following') { logStatus.success(); this.tasks.users = unique([ ...this.tasks.users, name ]); return true; } logStatus.error(`Error:${data?.response?.feedback_message || `${data?.statusText}(${data?.status})`}`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Instagram.followUser'); return false; } } async #unfollowUser(name) { try { if (this.whiteList.users.includes(name)) { scripts_echoLog({ type: 'whiteList', text: 'Instagram.unfollowUser', id: name }); return true; } const id = await this.#getUserInfo(name); if (!id) { return false; } const logStatus = scripts_echoLog({ type: 'unfollowingIns', text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://www.instagram.com/web/friendships/${id}/unfollow/`, method: 'POST', dataType: 'json', headers: { 'x-csrftoken': this.#auth.csrftoken, origin: 'https://www.instagram.com', referer: `https://www.instagram.com/${name}/`, 'content-type': 'application/x-www-form-urlencoded', 'sec-fetch-site': 'same-origin', 'x-instagram-ajax': this.#auth.hash } }); if (result === 'Success') { if (data?.status === 200 && data.response?.status === 'ok') { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Instagram.unfollowUser'); return false; } } async toggle({ doTask = true, userLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.instagram.users || !doTask && !globalOptions.undoTask.instagram.users) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'instagram.users' }); } else { const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1]); if (realUsers.length > 0) { for (const username of realUsers) { if (doTask) { prom.push(this.#followUser(username)); } else { prom.push(this.#unfollowUser(username)); } await delay(1e3); } } } return await Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Instagram.toggleUsers'); return false; } } #setCache(name, id) { try { this.#cache[name] = id; GM_setValue('instagramCache', this.#cache); } catch (error) { throwError(error, 'Instagram.setCache'); } } } const social_Instagram = Instagram; class Reddit extends social_Social { tasks; whiteList; #auth; #initialized = false; constructor() { super(); const defaultTasksTemplate = { reddits: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.reddit || {} }; } async init() { try { if (this.#initialized) { return true; } const isVerified = await this.#updateAuth(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Reddit')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Reddit')); return false; } catch (error) { throwError(error, 'Reddit.init'); return false; } } async #useBeta() { try { const logStatus = scripts_echoLog({ text: i18n('changingRedditVersion') }); return await new Promise(resolve => { const newTab = GM_openInTab('https://www.reddit.com/', { active: true, insert: true, setParent: true }); newTab.name = 'ATv4_redditAuth'; newTab.onclose = async () => { logStatus.success(); resolve(await this.#updateAuth(true)); }; }); } catch (error) { throwError(error, 'Reddit.useBeta'); return false; } } async #updateAuth(beta = false) { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', 'Reddit') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://www.reddit.com/', method: 'GET', nochche: true, headers: { 'Cache-Control': 'no-cache' } }); if (result === 'Success') { if (data?.responseText.includes('www.reddit.com/login/')) { logStatus.error(`Error:${i18n('loginReddit')}`, true); return false; } if (data?.status === 200) { if (data.responseText.includes('redesign-beta-optin-btn') && !beta) { return await this.#useBeta(); } const accessToken = data.responseText.match(/"accessToken":"(.*?)","expires":"(.*?)"/)?.[1]; if (accessToken) { this.#auth = { token: accessToken }; logStatus.success(); return true; } logStatus.error('Error: Parameter "accessToken" not found!'); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Reddit.updateAuth'); return false; } } async #toggleTask({ name, doTask = true }) { try { if (!doTask && this.whiteList.reddits.includes(name)) { scripts_echoLog({ type: 'whiteList', text: 'Reddit.undoTask', id: name }); return true; } let type = doTask ? 'joiningReddit' : 'leavingReddit'; if (/^u_/.test(name)) { type = doTask ? 'followingRedditUser' : 'unfollowingRedditUser'; } const logStatus = scripts_echoLog({ type: type, text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://oauth.reddit.com/api/subscribe?redditWebClient=desktop2x&app=desktop2x-client-production&raw_json=1&gilding_detail=1', method: 'POST', headers: { authorization: `Bearer ${this.#auth.token}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param({ action: doTask ? 'sub' : 'unsub', sr_name: name, api_type: 'json' }) }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); if (doTask) { this.tasks.reddits = unique([ ...this.tasks.reddits, name ]); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Reddit.toggleTask'); return false; } } async toggle({ doTask = true, redditLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.reddit.reddits || !doTask && !globalOptions.undoTask.reddit.reddits) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'reddit.reddits' }); } else { const realReddits = this.getRealParams('reddits', redditLinks, doTask, link => { const name = link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1]; const userName = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1]; if (userName) { return name || userName; } return name; }); if (realReddits.length > 0) { for (const name of realReddits) { prom.push(this.#toggleTask({ name: name, doTask: doTask })); await delay(1e3); } } } return await Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Reddit.toggle'); return false; } } } const social_Reddit = Reddit; class Twitch extends social_Social { tasks; whiteList; #auth = GM_getValue('twitchAuth') || {}; #cache = GM_getValue('twitchCache') || {}; #initialized = false; #integrityToken; constructor() { super(); const defaultTasksTemplate = { channels: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.twitch || {} }; } async init() { try { if (this.#initialized) { return true; } if (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId) { if (await this.#updateAuth()) { this.#initialized = true; return true; } return false; } const isVerified = await this.#verifyAuth(true); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Twitch')); this.#initialized = true; return true; } GM_setValue('twitchAuth', null); if (await this.#updateAuth()) { scripts_echoLog({}).success(i18n('initSuccess', 'Twitch')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Twitch')); return false; } catch (error) { throwError(error, 'Twitch.init'); return false; } } async #verifyAuth(isFirst) { try { const logStatus = scripts_echoLog({ text: i18n('verifyingAuth', 'Twitch') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://gql.twitch.tv/gql', method: 'POST', dataType: 'json', headers: { Authorization: `OAuth ${this.#auth.authToken}`, 'Client-Id': this.#auth.clientId }, data: '[{"operationName":"FrontPageNew_User","variables":{"limit":1},"extensions":{"persistedQuery":{"version":1,' + '"sha256Hash":"64bd07a2cbaca80699d62636d966cf6395a5d14a1f0a14282067dcb28b13eb11"}}}]' }); if (result === 'Success') { if (data?.status === 200 && data.response?.[0]?.data?.currentUser) { await this.#integrity(isFirst); logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitch.verifyAuth'); return false; } } async #integrity(isFirst = true, ct = '') { try { const logStatus = scripts_echoLog({ text: i18n('checkingTwitchIntegrity') }); if (isFirst && (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId)) { return await this.#updateAuth(false); } const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://gql.twitch.tv/integrity', method: 'POST', dataType: 'json', anonymous: true, headers: { Origin: 'https://www.twitch.tv', Referer: 'https://www.twitch.tv/', Authorization: `OAuth ${this.#auth.authToken}`, 'Client-Id': this.#auth.clientId, 'Client-Version': this.#auth.clientVersion, 'X-Device-Id': this.#auth.deviceId, 'Client-Session-Id': this.#auth.clientSessionId, 'x-kpsdk-ct': ct } }); if (result === 'Success') { if (!ct && data?.responseHeaders?.['x-kpsdk-ct']) { return await this.#integrity(isFirst, data.responseHeaders['x-kpsdk-ct']); } if (data?.status === 200 && data.response?.token) { this.#integrityToken = data.response.token; logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitch.integrity'); return false; } } async #updateAuth(isFirst = true) { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', 'Twitch') }); return await new Promise(resolve => { const newTab = GM_openInTab('https://www.twitch.tv/', { active: true, insert: true, setParent: true }); newTab.name = 'ATv4_twitchAuth'; newTab.onclose = async () => { const auth = GM_getValue('twitchAuth'); if (auth) { this.#auth = auth; logStatus.success(); resolve(await this.#verifyAuth(isFirst)); } else { logStatus.error('Error: Update twitch auth failed!'); resolve(false); } }; }); } catch (error) { throwError(error, 'Twitch.updateAuth'); return false; } } async #toggleChannel({ name, doTask = true }) { try { if (!doTask && this.whiteList.channels.includes(name)) { scripts_echoLog({ type: 'whiteList', text: 'Twitch.unfollowChannel', id: name }); return true; } const channelId = await this.#getChannelId(name); if (!channelId) { return false; } const logStatus = scripts_echoLog({ type: `${doTask ? '' : 'un'}followingTwitchChannel`, text: name }); const followData = `[{"operationName":"FollowButton_FollowUser","variables":{"input":{"disableNotifications":false,"targetID":"${channelId}` + '"}},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"800e7346bdf7e5278a3c1d3f21b2b56e2639928f86815677a7126b093b2fdd08"}}}]'; const unfollowData = `[{"operationName":"FollowButton_UnfollowUser","variables":{"input":{"targetID":"${channelId}"}},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"f7dae976ebf41c755ae2d758546bfd176b4eeb856656098bb40e0a672ca0d880"}}}]'; const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://gql.twitch.tv/gql', method: 'POST', dataType: 'json', anonymous: true, headers: { Origin: 'https://www.twitch.tv', Referer: 'https://www.twitch.tv/', Authorization: `OAuth ${this.#auth.authToken}`, 'Client-Id': this.#auth.clientId, 'Client-Version': this.#auth.clientVersion, 'X-Device-Id': this.#auth.deviceId, 'Client-Session-Id': this.#auth.clientSessionId, 'Client-Integrity': this.#integrityToken }, data: doTask ? followData : unfollowData }); if (result === 'Success') { if (data?.status === 200 && data.response?.[0] && !data.response[0].errors) { logStatus.success(); if (doTask) { this.tasks.channels = unique([ ...this.tasks.channels, name ]); } return true; } logStatus.error(`Error:${data?.response?.[0].errors?.[0]?.message || `${data?.statusText}(${data?.status})`}`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitch.toggleChannel'); return false; } } async #getChannelId(name) { try { const logStatus = scripts_echoLog({ type: 'gettingTwitchChannelId', text: name }); const channelId = this.#cache[name]; if (channelId) { logStatus.success(); return channelId; } const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://gql.twitch.tv/gql', method: 'POST', headers: { Authorization: `OAuth ${this.#auth.authToken}`, 'Client-Id': this.#auth.clientId }, responseType: 'json', data: `[{"operationName":"ActiveWatchParty","variables":{"channelLogin":"${name}"},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"4a8156c97b19e3a36e081cf6d6ddb5dbf9f9b02ae60e4d2ff26ed70aebc80a30"}}}]' }); if (result === 'Success') { if (data?.status === 200) { const channelId = data.response?.[0]?.data?.user?.id; if (channelId) { this.#setCache(name, String(channelId)); logStatus.success(); return channelId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitch.getChannelId'); return false; } } async toggle({ doTask = true, channelLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.twitch.channels || !doTask && !globalOptions.undoTask.twitch.channels) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'twitch.channels' }); } else { const realChannels = this.getRealParams('channels', channelLinks, doTask, link => link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2]); if (realChannels.length > 0) { for (const channel of realChannels) { prom.push(this.#toggleChannel({ name: channel, doTask: doTask })); await delay(1e3); } } } return Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Twitch.toggle'); return false; } } #setCache(name, id) { try { this.#cache[name] = id; GM_setValue('twitchCache', this.#cache); } catch (error) { throwError(error, 'Twitch.setCache'); } } } const social_Twitch = Twitch; var main = __webpack_require__(356); class Twitter extends social_Social { tasks; whiteList; #verifyId = globalOptions.other.twitterVerifyId; #auth = GM_getValue('twitterAuth') || {}; #cache = GM_getValue('twitterCache') || {}; #initialized = false; #session; constructor() { super(); const defaultTasksTemplate = { users: [], retweets: [], likes: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.twitter || {} }; } async init() { try { if (this.#initialized) { return true; } if (!this.#auth.ct0) { if (await this.#updateAuth()) { this.#initialized = true; return true; } return false; } this.#session = await (0, main.createSession)(); const isVerified = await this.#verifyAuth(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Twitter')); this.#initialized = true; return true; } GM_setValue('twitterAuth', null); if (await this.#updateAuth()) { scripts_echoLog({}).success(i18n('initSuccess', 'Twitter')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Twitter')); return false; } catch (error) { throwError(error, 'Twitter.init'); return false; } } async #verifyAuth() { try { return await this.#toggleUser({ name: 'verify', doTask: true, verify: true }); } catch (error) { throwError(error, 'Twitter.verifyAuth'); return false; } } async #updateAuth() { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', 'Twitter') }); return await new Promise(resolve => { GM_cookie.list({ url: 'https://x.com/settings/account' }, async (cookies, error) => { if (!error) { const [ ct0, isLogin ] = cookies.map(cookie => [ 'ct0', 'twid' ].includes(cookie.name) ? cookie.value : null).filter(cookie => cookie); if (isLogin && ct0) { GM_setValue('twitterAuth', { ct0: ct0 }); this.#auth = { ct0: ct0 }; logStatus.success(); resolve(await this.#verifyAuth()); } else { logStatus.error(i18n('needLogin')); resolve(false); } } else { logStatus.error('Error: Update twitter auth failed!'); resolve(false); } }); }); } catch (error) { throwError(error, 'Twitter.updateToken'); return false; } } async #toggleUser({ name, doTask = true, verify = false, retry = false }) { try { if (!doTask && !verify && this.whiteList.users.includes(name)) { scripts_echoLog({ type: 'whiteList', text: 'Twitter.unfollowUser', id: name }); return true; } const userId = verify ? this.#verifyId : await this.userName2id(name); if (!userId) { return false; } const logStatus = verify ? scripts_echoLog({ text: i18n('verifyingAuth', 'Twitter') }) : scripts_echoLog({ type: `${doTask ? '' : 'un'}followingTwitterUser`, text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://x.com/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`, method: 'POST', headers: { authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 'Content-Type': 'application/x-www-form-urlencoded', 'x-csrf-token': this.#auth.ct0, 'X-Twitter-Auth-Type': 'OAuth2Session', 'X-Twitter-Active-User': 'yes', 'x-client-transaction-id': await this.#session.get('POST', `/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`) }, responseType: 'json', data: $.param({ include_profile_interstitial_type: 1, include_blocking: 1, include_blocked_by: 1, include_followed_by: 1, include_want_retweets: 1, include_mute_edge: 1, include_can_dm: 1, include_can_media_tag: 1, skip_status: 1, id: userId }) }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); if (doTask && !verify) { this.tasks.users = unique([ ...this.tasks.users, name ]); } return true; } if (verify && data?.status === 403) { if (data.response?.errors?.[0]?.code === 158) { logStatus.success(); return true; } if (data.response?.errors?.[0]?.code === 353 && !retry && data.responseHeaders?.['set-cookie']) { this.#auth.ct0 = data.responseHeaders['set-cookie']?.find(cookie => cookie.includes('ct0='))?.split(';')?.at(0)?.split('=')?.at(-1) || this.#auth.ct0; logStatus.warning(i18n('retry')); return this.#toggleUser({ name: name, doTask: doTask, verify: verify, retry: true }); } } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitter.toggleUser'); return false; } } async userName2id(name) { try { const logStatus = scripts_echoLog({ type: 'gettingTwitterUserId', text: name }); const userId = this.#cache[name]; if (userId) { logStatus.success(); return userId; } const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://x.com/i/api/graphql/mCbpQvZAw6zu_4PvuAUVVQ/UserByScreenName' + `?variables=%7B%22screen_name%22%3A%22${name}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D`, method: 'GET', headers: { authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 'content-type': 'application/json', referer: `https://x.com/${name}`, 'x-csrf-token': this.#auth.ct0, 'X-Twitter-Auth-Type': 'OAuth2Session', 'X-Twitter-Active-User': 'yes', 'x-client-transaction-id': await this.#session.get('GET', '/i/api/graphql/mCbpQvZAw6zu_4PvuAUVVQ/UserByScreenName' + `?variables=%7B%22screen_name%22%3A%22${name}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D`) }, responseType: 'json' }); if (result === 'Success') { if (data?.status === 200) { let response = data.response || (typeof data.responseText === 'object' ? data.responseText : null); if (!response) { try { response = JSON.parse(data.responseText); } catch (error) { response = null; } } const userId = String(response?.data?.user?.result?.rest_id); if (userId) { this.#setCache(name, userId); logStatus.success(); return userId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitter.getUserId'); return false; } } async #toggleRetweet({ retweetId, doTask = true }) { try { if (!doTask && this.whiteList.retweets.includes(retweetId)) { scripts_echoLog({ type: 'whiteList', text: 'Twitter.unretweet', id: retweetId }); return true; } const logStatus = scripts_echoLog({ type: `${doTask ? '' : 'un'}retweetting`, text: retweetId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://x.com/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`, method: 'POST', headers: { authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 'Content-Type': 'application/json', origin: 'https://x.com', referer: 'https://x.com/home', 'x-csrf-token': this.#auth.ct0, 'X-Twitter-Auth-Type': 'OAuth2Session', 'X-Twitter-Active-User': 'yes', 'x-client-transaction-id': await this.#session.get('POST', `/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`) }, data: `{"variables":{"${doTask ? '' : 'source_'}tweet_id":"${retweetId}","dark_request":false},"queryId":"${doTask ? 'ojPdsZsimiJrUGLR1sjUtA' : 'iQtK4dl5hBmXewYZuEOKVw'}"}`, responseType: 'json' }); if (result === 'Success') { if (data?.status === 200 || data?.status === 403 && data.response?.errors?.[0]?.code === 327) { if (data.response?.errors && data.response?.errors?.[0]?.code !== 327) { logStatus.error(`Error:${data.response?.errors?.[0]?.message}`); return false; } logStatus.success(); if (doTask) { this.tasks.retweets = unique([ ...this.tasks.retweets, retweetId ]); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Twitter.toggleRetweet'); return false; } } async toggle({ doTask = true, userLinks = [], retweetLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.twitter.users || !doTask && !globalOptions.undoTask.twitter.users) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'twitter.users' }); } else { const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/x\.com\/(.+)/)?.[1] || link.match(/https:\/\/twitter\.com\/(.+)/)?.[1]); if (realUsers.length > 0) { for (const user of realUsers) { prom.push(this.#toggleUser({ name: user, doTask: doTask })); await delay(1e3); } } } if (doTask && !globalOptions.doTask.twitter.retweets || !doTask && !globalOptions.undoTask.twitter.retweets) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'twitter.retweets' }); } else { const realRetweets = this.getRealParams('retweets', retweetLinks, doTask, link => link.match(/https:\/\/x\.com\/.*?\/status\/([\d]+)/)?.[1] || link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1]); if (realRetweets.length > 0) { for (const retweet of realRetweets) { prom.push(this.#toggleRetweet({ retweetId: retweet, doTask: doTask })); await delay(1e3); } } } return Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Twitter.toggle'); return false; } } #setCache(name, id) { try { this.#cache[name] = id; GM_setValue('twitterCache', this.#cache); } catch (error) { throwError(error, 'Twitter.setCache'); } } } const social_Twitter = Twitter; class Vk extends social_Social { tasks; whiteList; #username = ''; #cache = GM_getValue('vkCache') || {}; #initialized = false; constructor() { super(); const defaultTasksTemplate = { names: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.vk || {} }; } async init() { try { if (this.#initialized) { return true; } const isVerified = await this.#verifyAuth(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Vk')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Vk')); return false; } catch (error) { throwError(error, 'Vk.init'); return false; } } async #verifyAuth() { try { const logStatus = scripts_echoLog({ text: i18n('verifyAuth', 'Vk') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://vk.com/im', method: 'GET' }); if (result === 'Success') { if (data?.finalUrl.includes('vk.com/login')) { logStatus.error(`Error:${i18n('loginVk')}`, true); return false; } if (data?.status === 200) { this.#username = data.responseText.match(/TopNavBtn__profileLink" href="\/(.*?)"/)?.[1] || ''; logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.verifyAuth'); return false; } } async #toggleGroup(name, dataParam, doTask = true) { try { const logStatus = scripts_echoLog({ type: doTask ? 'joiningVkGroup' : 'leavingVkGroup', text: name }); if (dataParam.groupAct === 'enter' && !doTask || dataParam.groupAct === 'leave' && doTask) { logStatus.success(); return true; } const reqData = { act: doTask ? 'enter' : 'leave', al: 1, gid: dataParam.groupId, hash: dataParam.groupHash }; if (doTask) { reqData.context = '_'; } const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://vk.com/al_groups.php', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${name}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param(reqData) }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); if (doTask) { this.tasks.names = unique([ ...this.tasks.names, name ]); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.toggleGroup'); return false; } } async #togglePublic(name, dataParam, doTask = true) { try { const logStatus = scripts_echoLog({ type: doTask ? 'joiningVkPublic' : 'leavingVkPublic', text: name }); if (dataParam.publicJoined && doTask || !dataParam.publicJoined && !doTask) { logStatus.success(); return true; } const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://vk.com/al_public.php', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${name}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param({ act: doTask ? 'a_enter' : 'a_leave', al: 1, pid: dataParam.publicPid, hash: dataParam.publicHash }) }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); if (doTask) { this.tasks.names = unique([ ...this.tasks.names, name ]); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.togglePublic'); return false; } } async #toggleLikeWall(name, dataParam, doTask = true) { try { const logStatus = scripts_echoLog({ type: doTask ? 'likingVkPublic' : 'unlikingVkPublic', text: name }); const postData = { act: 'a_set_reaction', al: 1, event_subtype: 'post_modal', from: 'wall_page', hash: dataParam.hash, object: dataParam.object, track_code: dataParam.trackCode, wall: 2 }; if (doTask) { postData.reaction_id = 0; } const { result: resultR, statusText: statusTextR, status: statusR, data: dataR } = await tools_httpRequest({ url: 'https://vk.com/like.php?act=a_set_reaction', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${name}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param(postData) }); if (resultR === 'Success') { if (dataR?.status === 200) { if (dataR.response?.payload?.[1]?.[1]?.like_my === true) { logStatus.success(); return true; } } logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`); return false; } logStatus.error(`${resultR}:${statusTextR}(${statusR})`); return false; } catch (error) { throwError(error, 'Vk.sendWall'); return false; } } async #sendWall(name) { try { const logStatus = scripts_echoLog({ type: 'sendingVkWall', text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://vk.com/like.php', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${name}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param({ act: 'publish_box', al: 1, object: name }) }); if (result === 'Success') { if (data?.status === 200) { const hash = data.responseText.match(/shHash:[\s]*'(.*?)'/)?.[1]; if (hash) { const { result: resultR, statusText: statusTextR, status: statusR, data: dataR } = await tools_httpRequest({ url: 'https://vk.com/like.php', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${name}`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param({ Message: '', act: 'a_do_publish', al: 1, close_comments: 0, friends_only: 0, from: 'box', hash: hash, list: '', mark_as_ads: 0, mute_notifications: 0, object: name, ret_data: 1, to: 0 }) }); if (resultR === 'Success') { if (dataR?.status === 200) { const jsonData = JSON.parse(dataR.responseText?.replace('\x3c!--', '') || '{}'); if (jsonData?.payload?.[1]?.[1]?.share_my === true) { logStatus.success(); const postId = String(jsonData?.payload?.[1]?.[1]?.post_id); const ownerId = String(jsonData?.payload?.[1]?.[1]?.owner_id); if (postId && ownerId) { this.#setCache(name, `${ownerId}_${postId}`); } this.tasks.names = unique([ ...this.tasks.names, name ]); return true; } } logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`); return false; } logStatus.error(`${resultR}:${statusTextR}(${statusR})`); return false; } logStatus.error('Error: Get "hash" failed'); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.sendWall'); return false; } } async #deleteWall(name, dataParams) { try { const logStatus = scripts_echoLog({ type: 'deletingVkWall', text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://vk.com/al_wall.php?act=delete', method: 'POST', headers: { origin: 'https://vk.com', referer: `https://vk.com/${this.#username}?w=wall${this.#cache[name]}%2Fall`, 'content-type': 'application/x-www-form-urlencoded' }, data: $.param({ act: 'delete', al: 1, confirm: 0, from: 'wkview', hash: dataParams.wallHash, post: this.#cache[name] }) }); if (result === 'Success') { if (data?.status === 200) { const jsonData = JSON.parse(data.responseText?.replace('\x3c!--', '') || '{}'); if (jsonData?.payload?.[1]?.[1]) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.deleteWall'); return false; } } async #getId(name, doTask) { try { let url = `https://vk.com/${name}`; if (/^wall-/.test(name)) { if (doTask) { return { type: 'sendWall' }; } if (!this.#cache[name]) { return { type: 'unSupport' }; } url = `https://vk.com/${this.#username}?w=wall${this.#cache[name]}`; } const logStatus = scripts_echoLog({ type: 'gettingVkId', text: name }); const { result, statusText, status, data } = await tools_httpRequest({ url: url, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { const [ , groupAct, groupId, , groupHash ] = data.responseText.match(/Groups.(enter|leave)\(.*?,.*?([\d]+?), ('|')(.*?)('|')/) || []; const publicHash = data.responseText.match(/"enterHash":"(.*?)"/)?.[1]; const publicPid = data.responseText.match(/"public_id":([\d]+?),/)?.[1]; const publicJoined = !data.responseText.includes('Public.subscribe'); if (groupAct && groupId && groupHash) { logStatus.success(); return { groupAct: groupAct, groupId: groupId, groupHash: groupHash, type: 'group' }; } else if (publicHash && publicPid) { logStatus.success(); return { publicHash: publicHash, publicPid: publicPid, publicJoined: publicJoined, type: 'public' }; } else if (name.includes('action=like')) { const hash = data.responseText.match(/data-reaction-hash="(.*?)"/)?.[1]; const trackCode = data.responseText.match(/data-post-track-code="(.*?)"/)?.[1]; const object = name.match(/wall-[\w_]+/)?.[0]; if (hash && trackCode && object) { logStatus.success(); return { type: 'likeWall', hash: hash, trackCode: trackCode, object: object }; } } else if (data.responseText.includes('wall.deletePost') && !doTask) { const wallHash = data.responseText.match(/wall\.deletePost\(this, '.*?', '(.*?)'\)/)?.[1]; if (wallHash) { logStatus.success(); return { type: 'deleteWall', wallHash: wallHash }; } } else if (name.includes('wall') && doTask) { logStatus.success(); return { type: 'sendWall' }; } logStatus.error('Error: Parameters not found!'); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Vk.getId'); return false; } } async #toggleVk({ name, doTask = true }) { try { if (!doTask && this.whiteList.names.includes(name)) { scripts_echoLog({ type: 'whiteList', text: 'Vk.undoTask', id: name }); return true; } const formatName = name.replace(/\/$/, ''); const data = await this.#getId(formatName, doTask); if (!data) { return false; } switch (data.type) { case 'group': return await this.#toggleGroup(formatName, data, doTask); case 'public': return await this.#togglePublic(formatName, data, doTask); case 'likeWall': return await this.#toggleLikeWall(formatName, data, doTask); case 'sendWall': return doTask ? await this.#sendWall(formatName) : true; case 'deleteWall': return doTask ? true : await this.#deleteWall(formatName, data); default: return false; } } catch (error) { throwError(error, 'Vk.toggleVk'); return false; } } async toggle({ doTask = true, nameLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.vk.names || !doTask && !globalOptions.undoTask.vk.names) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'vk.names' }); } else { const realNames = this.getRealParams('names', nameLinks, doTask, link => link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1]); if (realNames.length > 0) { for (const name of realNames) { prom.push(this.#toggleVk({ name: name, doTask: doTask })); await delay(1e3); } } } return Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Vk.toggle'); return false; } } #setCache(name, postId) { try { this.#cache[name] = postId; GM_setValue('vkCache', this.#cache); } catch (error) { throwError(error, 'Vk.setCache'); } } } const social_Vk = Vk; const getInfo = async function(link, type) { try { const logStatus = scripts_echoLog({ text: i18n('gettingYtbToken') }); const { result, statusText, status, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { if (data.responseText.includes('accounts.google.com/ServiceLogin?service=youtube')) { logStatus.error(`Error:${i18n('loginYtb')}`, true); return { needLogin: true }; } const apiKey = data.responseText.match(/"INNERTUBE_API_KEY":"(.*?)"/)?.[1]; const context = (data.responseText.match(/\(\{"INNERTUBE_CONTEXT":([\w\W]*?)\}\)/) || data.responseText.match(/"INNERTUBE_CONTEXT":([\w\W]*?\}),"INNERTUBE/))?.[1] || '{}'; const { client, request } = JSON.parse(context); if (apiKey && client && request) { client.hl = 'en'; if (type === 'channel') { const channelId = data.responseText.match(/"channelId":"(.+?)"/)?.[1]; if (channelId) { logStatus.success(); return { params: { apiKey: apiKey, client: client, request: request, channelId: channelId } }; } logStatus.error('Error: Get "channelId" failed!'); return {}; } else if (type === 'likeVideo') { const videoId = data.responseText.match(/<link rel="shortlinkUrl" href="https:\/\/youtu\.be\/(.*?)">/)?.[1]; const likeParams = data.responseText.match(/"likeParams":"(.*?)"/)?.[1]; if (videoId) { logStatus.success(); return { params: { apiKey: apiKey, client: client, request: request, videoId: videoId, likeParams: likeParams } }; } logStatus.error('Error: Get "videoId" failed!'); return {}; } logStatus.error('Error: Unknown type'); return {}; } logStatus.error('Error: Parameter "apiKey" not found!'); return {}; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return {}; } logStatus.error(`${result}:${statusText}(${status})`); return {}; } catch (error) { throwError(error, 'Youtube.getInfo'); return {}; } }; class Youtube extends social_Social { tasks; whiteList; #auth = GM_getValue('youtubeAuth') || {}; #initialized = false; #verifyChannel = `https://www.youtube.com/channel/${globalOptions.other.youtubeVerifyChannel}`; constructor() { super(); const defaultTasksTemplate = { channels: [], likes: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.youtube || {} }; } async init() { try { if (this.#initialized) { return true; } if (!this.#auth.PAPISID) { if (await this.#updateAuth()) { this.#initialized = true; return true; } return false; } const isVerified = await this.#verifyAuth(); if (isVerified) { scripts_echoLog({}).success(i18n('initSuccess', 'Youtube')); this.#initialized = true; return true; } GM_setValue('youtubeAuth', null); if (await this.#updateAuth()) { scripts_echoLog({}).success(i18n('initSuccess', 'Youtube')); this.#initialized = true; return true; } scripts_echoLog({}).error(i18n('initFailed', 'Youtube')); return false; } catch (error) { throwError(error, 'Youtube.init'); return false; } } async #verifyAuth() { try { return await this.#toggleChannel({ link: this.#verifyChannel, doTask: true, verify: true }); } catch (error) { throwError(error, 'Youtube.verifyAuth'); return false; } } async #updateAuth() { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', 'Youtube') }); return await new Promise(resolve => { GM_cookie.list({ url: 'https://www.youtube.com/@YouTube' }, async (cookies, error) => { if (!error) { const PAPISID = cookies.find(cookie => cookie.name === '__Secure-3PAPISID')?.value; if (PAPISID) { GM_setValue('youtubeAuth', { PAPISID: PAPISID }); this.#auth = { PAPISID: PAPISID }; logStatus.success(); resolve(await this.#verifyAuth()); } else { logStatus.error(i18n('needLogin')); resolve(false); } } else { logStatus.error('Error: Update youtube auth failed!'); resolve(false); } }); }); } catch (error) { throwError(error, 'Youtube.updateAuth'); return false; } } #getInfo(link, type) { return getInfo(link, type); } async #toggleChannel({ link, doTask = true, verify = false }) { try { const { params, needLogin } = await this.#getInfo(link, 'channel'); const { apiKey, client, request, channelId } = params || {}; if (needLogin) { scripts_echoLog({ html: i18n('loginYtb') }); return false; } if (!(apiKey && client && request && channelId)) { scripts_echoLog({ text: '"getYtbToken" failed' }); return false; } if (!doTask && !verify && this.whiteList.channels.includes(channelId)) { scripts_echoLog({ type: 'whiteList', text: 'Youtube.unfollowChannel', id: channelId }); return true; } const logStatus = verify ? scripts_echoLog({ text: i18n('verifyingAuth', 'Youtube') }) : scripts_echoLog({ type: doTask ? 'followingYtbChannel' : 'unfollowingYtbChannel', text: channelId }); const nowTime = parseInt(String(new Date().getTime() / 1e3), 10); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://www.youtube.com/youtubei/v1/subscription/${doTask ? '' : 'un'}subscribe?key=${apiKey}&prettyPrint=false`, method: 'POST', headers: { origin: 'https://www.youtube.com', referer: `https://www.youtube.com/channel/${channelId}`, 'content-type': 'application/json', 'x-goog-authuser': '0', 'x-goog-visitor-id': client?.visitorData, 'x-origin': 'https://www.youtube.com', authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}` }, data: JSON.stringify({ context: { client: client, request: { sessionId: request?.sessionId, internalExperimentFlags: [], consistencyTokenJars: [] }, user: {} }, channelIds: [ channelId ], params: doTask ? 'EgIIAhgA' : 'CgIIAhgA' }) }); if (result === 'Success') { if (data?.status === 200) { if (doTask && (/"subscribed":true/.test(data.responseText) || data.responseText.includes('The subscription already exists')) || !doTask && /"subscribed":false/.test(data.responseText)) { logStatus.success(); if (doTask && !verify) { this.tasks.channels = unique([ ...this.tasks.channels, link ]); } return true; } if (verify && data.responseText.includes('You may not subscribe to yourself')) { logStatus.success(); return true; } logStatus.error(i18n('tryUpdateYtbAuth'), true); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Youtube.toggleChannel'); return false; } } async #toggleLikeVideo({ link, doTask = true }) { try { const { params, needLogin } = await this.#getInfo(link, 'likeVideo'); const { apiKey, client, request, videoId, likeParams } = params || {}; if (needLogin) { scripts_echoLog({ html: `${i18n('loginYtb')}` }); return false; } if (!(apiKey && client && request && videoId && likeParams)) { scripts_echoLog({ text: '"getYtbToken" failed' }); return false; } if (!doTask && this.whiteList.likes.includes(videoId)) { scripts_echoLog({ type: 'whiteList', text: 'Youtube.unlikeVideo', id: videoId }); return true; } const logStatus = scripts_echoLog({ type: doTask ? 'likingYtbVideo' : 'unlikingYtbVideo', text: videoId }); const nowTime = parseInt(String(new Date().getTime() / 1e3), 10); const likeVideoData = { context: { client: client, request: { sessionId: request.sessionId, internalExperimentFlags: [], consistencyTokenJars: [] }, user: {} }, target: { videoId: videoId } }; if (doTask) { if (likeParams) { likeVideoData.params = likeParams; } else { logStatus.error('Empty likeParams'); return false; } } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://www.youtube.com/youtubei/v1/like/${doTask ? '' : 'remove'}like?key=${apiKey}`, method: 'POST', headers: { origin: 'https://www.youtube.com', referer: `https://www.youtube.com/watch?v=${videoId}`, 'content-type': 'application/json', 'x-goog-authuser': '0', 'x-goog-visitor-id': client.visitorData, 'x-origin': 'https://www.youtube.com', authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}` }, data: JSON.stringify(likeVideoData) }); if (result === 'Success') { if (data?.status === 200) { if (doTask && data.responseText.includes('Added to Liked videos') || !doTask && (data.responseText.includes('Removed from Liked videos') || data.responseText.includes('Dislike removed'))) { logStatus.success(); if (doTask) { this.tasks.likes = unique([ ...this.tasks.likes, link ]); } return true; } logStatus.error(i18n('tryUpdateYtbAuth'), true); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Youtube.toggleLikeVideo'); return false; } } async toggle({ doTask = true, channelLinks = [], videoLinks = [] }) { try { if (!this.#initialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.youtube.channels || !doTask && !globalOptions.undoTask.youtube.channels) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'youtube.channels' }); } else { const realChannels = this.getRealParams('channels', channelLinks, doTask, link => { if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) { return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1]; } return link; }); if (realChannels.length > 0) { for (const channel of realChannels) { prom.push(this.#toggleChannel({ link: channel, doTask: doTask })); await delay(1e3); } } } if (doTask && !globalOptions.doTask.youtube.likes || !doTask && !globalOptions.undoTask.youtube.likes) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'youtube.likes' }); } else { const realLikes = this.getRealParams('likes', videoLinks, doTask, link => { if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) { return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1]; } return link; }); if (realLikes.length > 0) { for (const video of realLikes) { prom.push(this.#toggleLikeVideo({ link: video, doTask: doTask })); await delay(1e3); } } } return Promise.all(prom).then(() => true); } catch (error) { throwError(error, 'Youtube.toggle'); return false; } } } class SteamASF { #asfOptions; #botName = 'asf'; #groupInfo; async init() { try { const asfCommandsUrl = new URL('/Api/Command/', globalOptions.ASF.AsfIpcUrl); this.#asfOptions = { url: asfCommandsUrl.href, method: 'POST', responseType: 'json', headers: { accept: 'application/json', 'Content-Type': 'application/json', Host: asfCommandsUrl.host, Origin: asfCommandsUrl.origin, Referer: asfCommandsUrl.href, Authentication: globalOptions.ASF.AsfIpcPassword } }; if (globalOptions.ASF.AsfBotname) { this.#botName = globalOptions.ASF.AsfBotname; } const logStatus = scripts_echoLog({ text: i18n('initingASF') }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: '{"Command":"!stats"}' }); if (result === 'Success') { if (data?.response?.Success === true && data.response.Message === 'OK' && data.response.Result) { logStatus.success(); return true; } if (data?.response?.Result || data?.response?.Message) { logStatus.error(data?.response?.Result || data.response.Message); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.init'); return false; } } async joinGroup(groupName) { try { const logStatus = scripts_echoLog({ type: 'joiningSteamGroup', text: groupName }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!JOINGROUP ${this.#botName} ${groupName}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '已加入', '已申请', 'Joined', 'Applied', 'Присоединился', 'costs' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.joinGroup'); return false; } } async leaveGroup(groupName) { try { if (!this.#groupInfo) { if (!await this.#getGroupId()) { return false; } } const groupId = await this.#groupInfo[groupName]; if (!groupId) { return false; } const logStatus = scripts_echoLog({ type: 'leavingSteamGroup', text: groupName }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!LEAVEGROUP ${this.#botName} ${groupId}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.leaveGroup'); return false; } } async #getGroupId() { try { const logStatus = scripts_echoLog({ type: 'gettingSteamGroupId', text: 'All' }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!GROUPLIST ${this.#botName}` }) }); if (result === 'Success') { if (data?.status === 200 && data.response?.Result?.includes('|')) { this.#groupInfo = Object.fromEntries(data.response.Result.split('\n').map(line => { const [ , name, id ] = line.trim().split('|'); if (name && id) { return [ name, id ]; } return null; }).filter(ele => ele)); logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.getGroupID'); return false; } } async addToWishlist(gameId) { try { const logStatus = scripts_echoLog({ type: 'addingToWishlist', text: gameId }); if ((await this.#checkGame(gameId)).wishlist === true) { logStatus.success(); return true; } const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!ADDWISHLIST ${this.#botName} ${gameId}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.addToWishlist'); return false; } } async removeFromWishlist(gameId) { try { const logStatus = scripts_echoLog({ type: 'removingFromWishlist', text: gameId }); if ((await this.#checkGame(gameId)).wishlist === false) { logStatus.success(); return true; } const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!REMOVEWISHLIST ${this.#botName} ${gameId}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.removeFromWishlist'); return false; } } async toggleFollowGame(gameId, doTask) { try { const logStatus = scripts_echoLog({ type: `${doTask ? '' : 'un'}followingGame`, text: gameId }); if (doTask && (await this.#checkGame(gameId)).followed === true || !doTask && (await this.#checkGame(gameId)).followed === false) { logStatus.success(); return true; } const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!${doTask ? '' : 'UN'}FOLLOWGAME ${this.#botName} ${gameId}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'SteamASF.toggleFollowGame'); return false; } } async #checkGame(gameId) { try { const { result, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!CHECK ${this.#botName} ${gameId}` }) }); if (result === 'Success') { if (data?.status === 200 && data.response?.Result?.includes(gameId)) { const matchedResult = data.response.Result.split('\n').find(result => result.includes(gameId))?.split('|'); if (matchedResult?.length > 3) { return { wishlist: matchedResult.at(-3).trim() === '√' || matchedResult.at(-2).trim() === '√', followed: matchedResult.at(-1).trim() === '√' }; } return {}; } return {}; } return {}; } catch (error) { throwError(error, 'SteamASF.checkGame'); return {}; } } async toggleCurator(curatorId, doTask = true) { try { const logStatus = scripts_echoLog({ type: doTask ? 'followingCurator' : 'unfollowingCurator', text: curatorId }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!${doTask ? '' : 'UN'}FOLLOWCURATOR ${this.#botName} ${curatorId}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.toggleCurator'); return false; } } async addLicense(id) { try { const [ type, ids ] = id.split('-'); if (type === 'appid') { const logStatus = scripts_echoLog({ type: 'addingFreeLicense', text: ids }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!addlicense ${this.#botName} app/${ids}` }) }); if (result === 'Success') { if (data?.status === 200 && [ 'AlreadyPurchased', 'OK' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } else if (type === 'subid') { const idsArr = ids.split(','); const logStatus = scripts_echoLog({ type: 'addingFreeLicenseSubid', text: ids }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!addlicense ${this.#botName} ${idsArr.map(id => `sub/${id}`).join(',')}` }) }); if (result === 'Success') { if (data?.status === 200 && data.response?.Result) { const resultLines = data.response.Result.split('\n'); idsArr.forEach(subid => { const targetLine = resultLines.find(text => text.includes(subid)); if (targetLine && [ '成功', 'Success', 'Успех' ].find(text => targetLine.includes(text))) { scripts_echoLog({}).success(targetLine); } else { scripts_echoLog({}).error(targetLine); } }); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } return false; } catch (error) { throwError(error, 'SteamASF.addLicense'); return false; } } async requestPlayTestAccess(id) { try { const logStatus = scripts_echoLog({ type: 'requestingPlayTestAccess', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ ...this.#asfOptions, data: JSON.stringify({ Command: `!REQUESTACCESS ${this.#botName} ${id}` }) }); if (result === 'Success') { if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) { logStatus.success(); return true; } logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.requestPlayTestAccess'); return false; } } } const social_SteamASF = SteamASF; class Steam extends social_Social { tasks; whiteList; #cache = { ...{ group: {}, officialGroup: {}, forum: {}, workshop: {}, curator: {} }, ...GM_getValue('steamCache') }; #auth = {}; #storeInitialized = false; #communityInitialized = false; #area = 'CN'; #oldArea; #areaStatus = 'end'; #ASF; constructor() { super(); const defaultTasksTemplate = { groups: [], officialGroups: [], wishlists: [], follows: [], forums: [], workshops: [], workshopVotes: [], curators: [], curatorLikes: [], announcements: [], licenses: [], playtests: [] }; this.tasks = defaultTasksTemplate; this.whiteList = { ...defaultTasksTemplate, ...GM_getValue('whiteList')?.steam || {} }; } async init(type = 'all') { try { if (globalOptions.ASF.AsfEnabled && globalOptions.ASF.AsfIpcUrl && globalOptions.ASF.AsfIpcPassword) { this.#ASF = new social_SteamASF(); if (await this.#ASF.init()) { this.#storeInitialized = true; this.#communityInitialized = true; return true; } return false; } if (type === 'store') { if (this.#storeInitialized) { return true; } let storeInitialized = await this.#updateStoreAuth(); if (!storeInitialized) { storeInitialized = await this.#updateStoreAuthTab(); } this.#storeInitialized = storeInitialized; if (!this.#storeInitialized) { scripts_echoLog({}).error(i18n('initFailed', 'Steam')); return false; } scripts_echoLog({}).success(i18n('initSuccess', 'SteamStore')); return true; } if (type === 'community') { if (this.#communityInitialized) { return true; } let communityInitialized = await this.#updateCommunityAuth(); if (!communityInitialized) { communityInitialized = await this.#updateCommunityAuthTab(); GM_setValue('steamCommunityAuth', null); } this.#communityInitialized = communityInitialized; if (!this.#communityInitialized) { scripts_echoLog({}).error(i18n('initFailed', 'Steam')); return false; } scripts_echoLog({}).success(i18n('initSuccess', 'SteamCommunity')); return true; } if (this.#storeInitialized && this.#communityInitialized) { scripts_echoLog({}).success(i18n('initSuccess', 'Steam')); return true; } scripts_echoLog({}).error(i18n('initFailed', 'Steam')); return false; } catch (error) { throwError(error, 'Steam.init'); return false; } } async #refreshToken(type = 'steamStore') { try { const host = { steamStore: 'store.steampowered.com', steamCommunity: 'steamcommunity.com' }; const logStatus = scripts_echoLog({ text: i18n('refreshingToken', i18n(type)) }); const formData = new FormData(); formData.append('redir', `https://${host[type]}/`); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://login.steampowered.com/jwt/ajaxrefresh', method: 'POST', responseType: 'json', headers: { Host: 'login.steampowered.com', Origin: `https://${host[type]}`, Referer: `https://${host[type]}/` }, data: formData }); if (result === 'Success') { if (data?.response?.success) { if (await this.#setStoreToken(data.response, type)) { logStatus.success(); return true; } logStatus.error('Error'); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.refreshToken'); return false; } } async #setStoreToken(param, type) { try { const host = { steamStore: 'store.steampowered.com', steamCommunity: 'steamcommunity.com' }; const logStatus = scripts_echoLog({ text: i18n('settingToken', i18n(type)) }); 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 tools_httpRequest({ url: `https://${host[type]}/login/settoken`, method: 'POST', headers: { Accept: 'application/json, text/plain, */*', Host: host[type], Origin: `https://${host[type]}` }, data: formData }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.setStoreToken'); return false; } } async #updateStoreAuth(retry = false) { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', i18n('steamStore')) }); const { result, statusText, status, data } = await tools_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', '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 this.#refreshToken('steamStore')) { logStatus.warning(i18n('retry')); if (retry) { logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true); return false; } return this.#updateStoreAuth(true); } logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true); return false; } const storeSessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1]; if (storeSessionID) { this.#auth.storeSessionID = storeSessionID; logStatus.success(); return true; } logStatus.error('Error: Get "sessionID" failed'); return false; } if ([ 301, 302 ].includes(data?.status)) { if (await this.#refreshToken('steamStore')) { logStatus.warning(i18n('retry')); if (retry) { logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true); return false; } return this.#updateStoreAuth(true); } logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.updateStoreAuth'); return false; } } async #updateStoreAuthTab() { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', i18n('steamStoreTab')) }); return await new Promise(resolve => { GM_deleteValue('steamStoreAuth'); GM_setValue('ATv4_updateStoreAuth', true); const newTab = GM_openInTab('https://store.steampowered.com/', { active: true, setParent: true }); newTab.name = 'ATv4_updateStoreAuth'; const listenerId = GM_addValueChangeListener('steamStoreAuth', (key, oldValue, newValue) => { GM_removeValueChangeListener(listenerId); GM_deleteValue('ATv4_updateStoreAuth'); newTab?.close(); window.focus(); if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) { this.#auth.storeSessionID = newValue.storeSessionID; logStatus.success(); resolve(true); return; } logStatus.error('Failed'); resolve(false); }); newTab.onclose = () => { GM_deleteValue('ATv4_updateStoreAuth'); }; }); } catch (error) { throwError(error, 'Steam.updateStoreAuthTab'); return false; } } async #updateCommunityAuthTab() { try { const logStatus = scripts_echoLog({ text: i18n('updatingAuth', i18n('steamCommunityTab')) }); return await new Promise(resolve => { GM_deleteValue('steamCommunityAuth'); GM_setValue('ATv4_updateCommunityAuth', true); const newTab = GM_openInTab('https://steamcommunity.com/my', { active: true, setParent: true }); newTab.name = 'ATv4_updateCommunityAuth'; const listenerId = GM_addValueChangeListener('steamCommunityAuth', (key, oldValue, newValue) => { GM_removeValueChangeListener(listenerId); GM_deleteValue('ATv4_updateCommunityAuth'); newTab?.close(); window.focus(); if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) { this.#auth.steam64Id = newValue.steam64Id; this.#auth.communitySessionID = newValue.communitySessionID; logStatus.success(); resolve(true); return; } logStatus.error('Failed'); resolve(false); }); newTab.onclose = () => { GM_deleteValue('ATv4_updateCommunityAuth'); }; }); } catch (error) { throwError(error, 'Steam.updateCommunityAuthTab'); return false; } } async #updateCommunityAuth() { try { const logStatus = scripts_echoLog({ text: i18n('gettingUserLink') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://steamcommunity.com/my', method: 'GET', headers: { Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', Host: 'steamcommunity.com', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate' }, fetch: false }); if (data?.status === 200) { if (data.finalUrl.includes('https://steamcommunity.com/login/home')) { logStatus.error(`Error:${i18n('needLoginSteamCommunity')}`, true); return false; } const steam64Id = data.responseText.match(/g_steamID = "(.+?)";/)?.[1]; const communitySessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1]; if (steam64Id && communitySessionID) { this.#auth.steam64Id = steam64Id; this.#auth.communitySessionID = communitySessionID; logStatus.success(); return true; } logStatus.error('Error: Get "sessionID" failed'); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.updateCommunityAuth'); return false; } } async #getAreaInfo() { try { const logStatus = scripts_echoLog({ text: i18n('gettingAreaInfo') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/cart/', method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { const cartConfigRaw = data.responseText.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 (error) { logStatus.error('Error: get country info filed'); console.error(error); return {}; } if (!cartConfig.rgUserCountryOptions) { logStatus.warning('Warning: Area cannot be changed'); return {}; } const userInfoRaw = data.responseText.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 (error) { logStatus.error('Error: get country info filed'); console.error(error); return {}; } const currentArea = userInfo.country_code; const areas = Object.keys(cartConfig.rgUserCountryOptions).filter(area => area !== 'help'); if (currentArea && areas.length > 0) { this.#area = currentArea; logStatus.success(); return { currentArea: currentArea, areas: areas }; } logStatus.error('Error: get country info filed'); return {}; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return {}; } logStatus.error(`${result}:${statusText}(${status})`); return {}; } catch (error) { throwError(error, 'Steam.getAreaInfo'); return {}; } } async #changeArea(area) { try { if (this.#areaStatus === 'waiting') { await new Promise(resolve => { const checker = setInterval(() => { if (this.#areaStatus !== 'waiting') { clearInterval(checker); resolve(true); } }); }); } if (this.#area === area || !area && this.#area !== 'CN') { return true; } this.#areaStatus = 'waiting'; let aimedArea = area; if (!aimedArea) { const { currentArea, areas } = await this.#getAreaInfo(); if (!currentArea || !areas) { this.#areaStatus = 'error'; return false; } if (currentArea !== 'CN') { this.#areaStatus = 'skip'; scripts_echoLog({ text: 'notNeededChangeArea' }); return 'skip'; } const anotherArea = areas.filter(area => area && area !== 'CN'); if (!anotherArea || anotherArea.length === 0) { this.#areaStatus = 'noAnotherArea'; scripts_echoLog({ text: 'noAnotherArea' }); return false; } [ aimedArea ] = anotherArea; } const logStatus = scripts_echoLog({ text: i18n('changingArea', aimedArea) }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/country/setcountry', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ cc: aimedArea, sessionid: this.#auth.storeSessionID }) }); if (result === 'Success') { if (data?.status === 200 && data.responseText === 'true') { const { currentArea } = await this.#getAreaInfo(); if (currentArea) { this.#area = currentArea; if (!this.#oldArea) { this.#oldArea = currentArea; } } if (currentArea === aimedArea) { this.#areaStatus = 'success'; logStatus.success(); return currentArea; } this.#areaStatus = 'error'; logStatus.error('Error: change country filed'); return 'CN'; } this.#areaStatus = 'error'; logStatus.error(`Error:${data?.statusText}(${data?.status})`); return 'CN'; } this.#areaStatus = 'error'; logStatus.error(`${result}:${statusText}(${status})`); return 'CN'; } catch (error) { this.#areaStatus = 'error'; throwError(error, 'Steam.changeArea'); return false; } } async #joinGroup(groupName) { try { if (this.#ASF) { if (await this.#ASF.joinGroup(groupName)) { this.tasks.groups = unique([ ...this.tasks.groups, groupName ]); return true; } return false; } const logStatus = scripts_echoLog({ type: 'joiningSteamGroup', text: groupName }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/groups/${groupName}`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ action: 'join', sessionID: this.#auth.communitySessionID }) }); if (result === 'Success') { if (data?.status === 200 && !data.responseText.includes('grouppage_join_area')) { logStatus.success(); this.tasks.groups = unique([ ...this.tasks.groups, groupName ]); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.joinGroup'); return false; } } async #leaveGroup(groupName) { try { if (this.whiteList.groups.includes(groupName)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.leaveGroup', id: groupName }); return true; } if (this.#ASF) { return await this.#ASF.leaveGroup(groupName); } const groupId = await this.#getGroupId(groupName); if (!groupId) { return false; } const logStatus = scripts_echoLog({ type: 'leavingSteamGroup', text: groupName }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ sessionID: this.#auth.communitySessionID, action: 'leaveGroup', groupId: groupId }) }); if (result === 'Success') { if (data?.status === 200 && data.finalUrl.includes('groups') && $(data.responseText.replace(/<img.*?>/g, '').toLowerCase()).find(`a[href='https://steamcommunity.com/groups/${groupName.toLowerCase()}']`).length === 0) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.leaveGroup'); return false; } } async #getGroupId(groupName) { try { const logStatus = scripts_echoLog({ type: 'gettingSteamGroupId', text: groupName }); const groupId = this.#cache.group[groupName]; if (groupId) { logStatus.success(); return groupId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/groups/${groupName}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (result === 'Success') { if (data?.status === 200) { const groupId = data.responseText.match(/OpenGroupChat\( '([0-9]+)'/)?.[1]; if (groupId) { this.#setCache('group', groupName, groupId); logStatus.success(); return groupId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getGroupID'); return false; } } async #joinOfficialGroup(gameId) { try { if (this.#ASF) { if (await this.#ASF.joinGroup(gameId)) { this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]); return true; } return false; } const logStatus = scripts_echoLog({ type: 'joiningSteamOfficialGroup', text: gameId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/games/${gameId}?action=join&sessionID=${this.#auth.communitySessionID}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (result === 'Success') { if (data?.status === 200 && !data.responseText.includes('id="publicGroupJoin"')) { logStatus.success(); this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]); const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1]; if (groupId) { this.#setCache('officialGroup', gameId, groupId); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.joinOfficialGroup'); return false; } } async #leaveOfficialGroup(gameId) { try { if (this.whiteList.officialGroups.includes(gameId)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.leaveOfficialGroup', id: gameId }); return true; } if (this.#ASF) { return await this.#ASF.leaveGroup(gameId); } const groupId = await this.#getOfficialGroupId(gameId); if (!groupId) { return false; } const logStatus = scripts_echoLog({ type: 'leavingSteamOfficialGroup', text: gameId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ sessionID: this.#auth.communitySessionID, action: 'leaveGroup', groupId: groupId }) }); if (result === 'Success') { if (data?.status === 200) { const { result: resultR, statusText: statusTextR, status: statusR, data: dataR } = await tools_httpRequest({ url: `https://steamcommunity.com/games/${gameId}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (resultR === 'Success') { if (dataR?.status === 200 && dataR.responseText.includes('id="publicGroupJoin"')) { logStatus.success(); return true; } logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`); return false; } logStatus.error(`${resultR}:${statusTextR}(${statusR})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.leaveOfficialGroup'); return false; } } async #getOfficialGroupId(gameId) { try { const logStatus = scripts_echoLog({ type: 'gettingSteamOfficialGroupId', text: gameId }); const groupId = this.#cache.officialGroup[gameId]; if (groupId) { logStatus.success(); return groupId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/games/${gameId}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (result === 'Success') { if (data?.status === 200) { const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1]; if (groupId) { this.#setCache('officialGroup', gameId, groupId); logStatus.success(); return groupId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getGroupID'); return false; } } async #addToWishlist(gameId) { try { if (this.#ASF) { if (await this.#ASF.addToWishlist(gameId)) { this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]); return true; } return false; } const logStatus = scripts_echoLog({ type: 'addingToWishlist', text: gameId }); const { result, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/api/addtowishlist', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ sessionid: this.#auth.storeSessionID, appid: gameId }), dataType: 'json' }); if (result === 'Success' && data?.status === 200 && data.response?.success === true) { logStatus.success(); this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]); return true; } const { result: resultR, statusText: statusTextR, status: statusR, data: dataR } = await tools_httpRequest({ url: `https://store.steampowered.com/app/${gameId}`, method: 'GET' }); if (resultR === 'Success') { if (dataR?.status === 200) { if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) { logStatus.warning(i18n('changeAreaNotice')); if (!await this.#changeArea()) { return false; } return await this.#addToWishlist(gameId); } if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('class="already_in_library"')) { logStatus.success(); this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]); return true; } else if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('id="add_to_wishlist_area_success" style="display: none;') || !dataR.responseText.includes('class="queue_actions_ctn"')) { logStatus.error(`Error:${dataR.statusText}(${dataR.status})`); return false; } logStatus.success(); this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]); return true; } logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`); return false; } logStatus.error(`${resultR}:${statusTextR}(${statusR})`); return false; } catch (error) { throwError(error, 'Steam.addToWishlist'); return false; } } async #removeFromWishlist(gameId) { try { if (this.whiteList.wishlists.includes(gameId)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.removeFromWishlist', id: gameId }); return true; } if (this.#ASF) { return await this.#ASF.removeFromWishlist(gameId); } const logStatus = scripts_echoLog({ type: 'removingFromWishlist', text: gameId }); const { result, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/api/removefromwishlist', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ sessionid: this.#auth.storeSessionID, appid: gameId }), dataType: 'json' }); if (result === 'Success' && data?.status === 200 && data.response?.success === true) { logStatus.success(); return true; } const { result: resultR, statusText: statusTextR, status: statusR, data: dataR } = await tools_httpRequest({ url: `https://store.steampowered.com/app/${gameId}`, method: 'GET' }); if (resultR === 'Success') { if (dataR?.status === 200) { if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) { logStatus.warning(i18n('changeAreaNotice')); const result = await this.#changeArea(); if (!result || result === 'CN' || result === 'skip') { return false; } return await this.#removeFromWishlist(gameId); } if (dataR.responseText.includes('class="queue_actions_ctn"') && (dataR.responseText.includes('ds_owned_flag ds_flag') || dataR.responseText.includes('add_to_wishlist_area'))) { logStatus.success(); return true; } logStatus.error(`Error:${dataR.statusText}(${dataR.status})`); return false; } logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`); return false; } logStatus.error(`${resultR}:${statusTextR}(${statusR})`); return false; } catch (error) { throwError(error, 'Steam.removeFromWishlist'); return false; } } async #toggleFollowGame(gameId, doTask) { try { if (!doTask && this.whiteList.follows.includes(gameId)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.unfollowGame', id: gameId }); return true; } if (this.#ASF) { if (await this.#ASF.toggleFollowGame(gameId, doTask)) { if (doTask) { this.tasks.follows = unique([ ...this.tasks.follows, gameId ]); } return true; } return false; } const logStatus = scripts_echoLog({ type: `${doTask ? '' : 'un'}followingGame`, text: gameId }); const requestData = { sessionid: this.#auth.storeSessionID, appid: gameId }; if (!doTask) { requestData.unfollow = '1'; } const { result, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/explore/followgame/', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param(requestData) }); if (result === 'Success' && data?.status === 200 && data.responseText === 'true') { logStatus.success(); return true; } const followed = await this.#isFollowedGame(gameId); if (this.#area === 'CN' && followed === 'areaLocked') { logStatus.warning(i18n('changeAreaNotice')); if (!await this.#changeArea()) { return false; } return await this.#toggleFollowGame(gameId, doTask); } if (doTask === followed) { logStatus.success(); if (doTask) { this.tasks.follows = unique([ ...this.tasks.follows, gameId ]); } return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } catch (error) { throwError(error, 'Steam.toggleFollowGame'); return false; } } async #isFollowedGame(gameId) { try { const { result, data } = await tools_httpRequest({ url: `https://store.steampowered.com/app/${gameId}`, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) { return 'areaLocked'; } if ($(data.responseText.replace(/<img.*?>/g, '')).find('.queue_control_button.queue_btn_follow>.btnv6_blue_hoverfade.btn_medium.queue_btn_active').css('display') !== 'none') { return true; } return false; } return false; } return false; } catch (error) { throwError(error, 'Steam.isFollowedGame'); return false; } } async #toggleForum(gameId, doTask = true) { try { if (!doTask && this.whiteList.forums.includes(gameId)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.unsubscribeForum', id: gameId }); return true; } const forumId = await this.#getForumId(gameId); if (!forumId) { return false; } const logStatus = scripts_echoLog({ type: `${doTask ? '' : 'un'}subscribingForum`, text: gameId }); const [ id, feature ] = forumId.split('_'); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/forum/${id}/General/${doTask ? '' : 'un'}subscribe/${feature || '0'}/`, method: 'POST', responseType: 'json', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ sessionid: this.#auth.communitySessionID }) }); if (result === 'Success') { if (data?.status === 200 && (data.response?.success === 1 || data.response?.success === 29)) { if (doTask) { this.tasks.forums = unique([ ...this.tasks.forums, gameId ]); } logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return true; } logStatus.error(`${result}:${statusText}(${status})`); return true; } catch (error) { throwError(error, 'Steam.toggleForum'); return true; } } async #getForumId(gameId) { try { const logStatus = scripts_echoLog({ type: 'gettingForumId', text: gameId }); const forumId = this.#cache.forum[gameId]; if (forumId) { logStatus.success(); return forumId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/app/${gameId}/discussions/`, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { const forumId = data.responseText?.match(/General_([\d]+(_[\d]+)?)/)?.[1]; if (forumId) { this.#setCache('forum', gameId, forumId); logStatus.success(); return forumId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getForumId'); return false; } } async #toggleFavoriteWorkshop(id, doTask = true) { try { if (!doTask && this.whiteList.workshops.includes(id)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.unfavoriteWorkshop', id: id }); return true; } const appid = await this.#getWorkshopAppId(id); if (!appid) { return false; } const logStatus = scripts_echoLog({ type: doTask ? 'favoritingWorkshop' : 'unfavoritingWorkshop', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/sharedfiles/${doTask ? '' : 'un'}favorite`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ id: id, appid: appid, sessionid: this.#auth.communitySessionID }) }); if (result === 'Success') { if (data?.status === 200 && !data.responseText) { if (doTask) { this.tasks.workshops = unique([ ...this.tasks.workshops, id ]); } logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.toggleFavoriteWorkshop'); return false; } } async #getWorkshopAppId(id) { try { const logStatus = scripts_echoLog({ type: 'gettingWorkshopAppId', text: id }); const appId = this.#cache.workshop[id]; if (appId) { logStatus.success(); return appId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${id}`, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { const appId = data.responseText.match(/<input type="hidden" name="appid" value="([\d]+?)" \/>/)?.[1]; if (appId) { this.#setCache('workshop', id, appId); logStatus.success(); return appId; } logStatus.error('Error: getWorkshopAppId failed'); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getWorkshopAppId'); return false; } } async #voteUpWorkshop(id) { try { const logStatus = scripts_echoLog({ type: 'votingUpWorkshop', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://steamcommunity.com/sharedfiles/voteup', method: 'POST', responseType: 'json', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ id: id, sessionid: this.#auth.communitySessionID }) }); if (result === 'Success') { if (data?.status === 200 && data.response?.success === 1) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return true; } logStatus.error(`${result}:${statusText}(${status})`); return true; } catch (error) { throwError(error, 'Steam.voteupWorkshop'); return true; } } async #toggleCurator(curatorId, doTask = true) { try { if (!doTask && this.whiteList.curators.includes(curatorId)) { scripts_echoLog({ type: 'whiteList', text: 'Steam.unfollowCurator', id: curatorId }); return true; } if (this.#ASF) { return await this.#ASF.toggleCurator(curatorId, doTask); } const logStatus = scripts_echoLog({ type: doTask ? 'followingCurator' : 'unfollowingCurator', text: curatorId }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://store.steampowered.com/curators/ajaxfollow', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: $.param({ clanid: curatorId, sessionid: this.#auth.storeSessionID, follow: doTask }), dataType: 'json' }); if (result === 'Success') { if (data?.status === 200 && data.response?.success?.success === 1) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.response?.success}` || `${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.toggleCurator'); return false; } } async getCuratorId(path, name) { try { const logStatus = scripts_echoLog({ type: 'gettingCuratorId', text: `${path}/${name}` }); const curatorId = this.#cache.curator[`${path}/${name}`]; if (curatorId) { logStatus.success(); return curatorId; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/${path}/${name}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (result === 'Success') { if (data?.status === 200) { const curatorId = data.responseText.match(/g_pagingData.*?"clanid":([\d]+)/)?.[1]; if (curatorId) { this.#setCache('curator', `${path}/${name}`, curatorId); logStatus.success(); return curatorId; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getCuratorID'); return false; } } async #toggleCuratorLike(link, doTask = true) { try { const [ path, name ] = link.split('/'); if (!(path && name)) { scripts_echoLog({ text: i18n('errorLink', link) }); return false; } const curatorId = await this.getCuratorId(path, name); if (curatorId) { return await this.#toggleCurator(curatorId, doTask); } return false; } catch (error) { throwError(error, 'Steam.toggleCuratorLike'); return false; } } async #getAnnouncementParams(appId, viewId) { try { const logStatus = scripts_echoLog({ type: 'gettingAnnouncementParams', text: appId, id: viewId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/events/ajaxgetpartnerevent?appid=${appId}&announcement_gid=${viewId}&lang_list=6_0&last_modified_time=0&origin=https:%2F%2Fstore.steampowered.com&for_edit=false`, method: 'GET', responseType: 'json', headers: { Host: 'store.steampowered.com', Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}` } }); if (result === 'Success') { if (data?.status === 200 && data?.response?.success === 1) { const { clanid, gid } = data.response.event?.announcement_body || {}; if (clanid) { logStatus.success(); return { clanId: clanid, gid: gid }; } logStatus.error(`Error:${data.statusText}(${data.status})`); return {}; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return {}; } logStatus.error(`${result}:${statusText}(${status})`); return {}; } catch (error) { throwError(error, 'Steam.likeAnnouncement'); return {}; } } async #likeAnnouncement(id) { try { const [ appId, viewId ] = id.split('/'); if (!(appId && viewId)) { scripts_echoLog({}).error(`${i18n('missParams')}(id)`); return false; } const { clanId, gid } = await this.#getAnnouncementParams(appId, viewId); if (!clanId) { return false; } const logStatus = scripts_echoLog({ type: 'likingAnnouncement', text: appId, id: viewId }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/updated/ajaxrateupdate/${gid || viewId}`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Host: 'store.steampowered.com', Origin: 'https://store.steampowered.com', Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}` }, data: $.param({ sessionid: this.#auth.storeSessionID, voteup: 1, clanid: clanId, ajax: 1 }), dataType: 'json' }); if (result === 'Success') { if (data?.status === 200 && data.response.success === 1) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.likeAnnouncement'); return false; } } async #appid2subid(id) { try { const logStatus = scripts_echoLog({ type: 'gettingSubid', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/app/${id}`, method: 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }); if (result === 'Success') { if (data?.status === 200) { if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) { logStatus.success(i18n('owned')); return false; } if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) { logStatus.warning(i18n('changeAreaNotice')); const result = await this.#changeArea(); if (!result || result === 'CN' || result === 'skip') { return false; } return await this.#appid2subid(id); } let subid = data.responseText.match(/name="subid" value="([\d]+?)"/)?.[1]; if (subid) { logStatus.success(); return subid; } subid = data.responseText.match(/AddFreeLicense\(\s*(\d+)/)?.[1]; if (subid) { logStatus.success(); return subid; } logStatus.error(`Error:${i18n('noSubid')}`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.appid2subid'); return false; } } async #getLicenses() { try { const logStatus = scripts_echoLog({ text: i18n('gettingLicenses') }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/dynamicstore/userdata/?t=${new Date().getTime()}`, method: 'GET', responseType: 'json' }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); return data.response?.rgOwnedPackages; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.getLicenses'); return false; } } async #addLicense(id) { try { if (this.#ASF) { return await this.#ASF.addLicense(id); } const [ type, ids ] = id.split('-'); if (type === 'appid') { const subid = await this.#appid2subid(ids); if (!subid) { return false; } const logStatus = scripts_echoLog({ type: 'addingFreeLicense', text: ids }); if (!await this.#addFreeLicense(subid, logStatus)) { return false; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/app/${ids}`, method: 'GET' }); if (result === 'Success') { if (data?.status === 200) { if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) { logStatus.success(); return true; } logStatus.error(`Error:${data.statusText}(${data.status})`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } else if (type === 'subid') { if (this.#area === 'CN') { scripts_echoLog({}).success(i18n('tryChangeAreaNotice')); await this.#changeArea(); } const logStatusArr = {}; const idsArr = ids.split(','); for (const subid of idsArr) { const logStatus = scripts_echoLog({ type: 'addingFreeLicenseSubid', text: subid }); if (!await this.#addFreeLicense(subid, logStatus)) { return false; } logStatusArr[subid] = logStatus; } const licenses = await this.#getLicenses(); if (!licenses) { return false; } for (const subid of idsArr) { if (licenses.includes(parseInt(subid, 10))) { logStatusArr[subid].success(); } else { logStatusArr[subid].error(); } } return true; } return false; } catch (error) { throwError(error, 'Steam.addLicense'); return false; } } async #addFreeLicense(id, logStatusPre) { try { const logStatus = logStatusPre || scripts_echoLog({ type: 'addingFreeLicenseSubid', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/freelicense/addfreelicense/${id}`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Host: 'store.steampowered.com', Origin: 'https://store.steampowered.com', Referer: 'https://store.steampowered.com/account/licenses/' }, data: $.param({ ajax: true, sessionid: this.#auth.storeSessionID }), dataType: 'json' }); if (result === 'Success') { if (data?.status === 200) { if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) { logStatus.warning(i18n('changeAreaNotice')); const result = await this.#changeArea(); if (!result || [ 'CN', 'skip' ].includes(result)) { return false; } return await this.#addFreeLicense(id); } logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.addFreeLicense'); return false; } } async #requestPlayTestAccess(id) { try { if (this.#ASF) { return await this.#ASF.requestPlayTestAccess(id); } const logStatus = scripts_echoLog({ type: 'requestingPlayTestAccess', text: id }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://store.steampowered.com/ajaxrequestplaytestaccess/${id}`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Host: 'store.steampowered.com', Origin: 'https://store.steampowered.com', Referer: `https://store.steampowered.com/app/${id}` }, data: $.param({ sessionid: this.#auth.storeSessionID }), dataType: 'json' }); if (result === 'Success') { if (data?.status === 200 && data?.response?.success === 1) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Steam.requestPlayTestAccess'); return false; } } async toggle({ doTask = true, groupLinks = [], officialGroupLinks = [], wishlistLinks = [], followLinks = [], forumLinks = [], workshopLinks = [], workshopVoteLinks = [], curatorLinks = [], curatorLikeLinks = [], announcementLinks = [], licenseLinks = [], playtestLinks = [] }) { try { if ([ ...groupLinks, ...officialGroupLinks, ...forumLinks, ...workshopLinks, ...workshopVoteLinks ].length > 0 && !this.#communityInitialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } if ([ ...wishlistLinks, ...followLinks, ...curatorLinks, ...curatorLikeLinks, ...announcementLinks, ...licenseLinks, ...playtestLinks ].length > 0 && !this.#storeInitialized) { scripts_echoLog({ text: i18n('needInit') }); return false; } const prom = []; if (doTask && !globalOptions.doTask.steam.groups || !doTask && !globalOptions.undoTask.steam.groups) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.groups' }); } else { const realGroups = this.getRealParams('groups', groupLinks, doTask, link => link.match(/groups\/(.+)\/?/)?.[1]?.split('/')?.[0]); if (realGroups.length > 0) { for (const group of realGroups) { if (doTask) { prom.push(this.#joinGroup(group)); } else { prom.push(this.#leaveGroup(group)); } await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.officialGroups || !doTask && !globalOptions.undoTask.steam.officialGroups) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.officialGroups' }); } else { const realOfficialGroups = this.getRealParams('officialGroups', officialGroupLinks, doTask, link => link.match(/games\/(.+)\/?/)?.[1]); if (realOfficialGroups.length > 0) { for (const officialGroup of realOfficialGroups) { if (doTask) { prom.push(this.#joinOfficialGroup(officialGroup)); } else { prom.push(this.#leaveOfficialGroup(officialGroup)); } await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.wishlists || !doTask && !globalOptions.undoTask.steam.wishlists) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.wishlists' }); } else { const realWishlists = this.getRealParams('wishlists', wishlistLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]); if (realWishlists.length > 0) { for (const game of realWishlists) { if (doTask) { prom.push(this.#addToWishlist(game)); } else { prom.push(this.#removeFromWishlist(game)); } await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.follows || !doTask && !globalOptions.undoTask.steam.follows) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.follows' }); } else { const realFollows = this.getRealParams('follows', followLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]); if (realFollows.length > 0) { for (const game of realFollows) { prom.push(this.#toggleFollowGame(game, doTask)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.forums || !doTask && !globalOptions.undoTask.steam.forums) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.forums' }); } else { const realForums = this.getRealParams('forums', forumLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]); if (realForums.length > 0) { for (const forum of realForums) { prom.push(this.#toggleForum(forum, doTask)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.workshops || !doTask && !globalOptions.undoTask.steam.workshops) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.workshops' }); } else { const realWorkshops = this.getRealParams('workshops', workshopLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]); if (realWorkshops.length > 0) { for (const workshop of realWorkshops) { prom.push(this.#toggleFavoriteWorkshop(workshop, doTask)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.workshopVotes) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.workshopVotes' }); } else { const realworkshopVotes = this.getRealParams('workshopVotes', workshopVoteLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]); if (doTask && realworkshopVotes.length > 0) { for (const workshop of realworkshopVotes) { prom.push(this.#voteUpWorkshop(workshop)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.curators || !doTask && !globalOptions.undoTask.steam.curators) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.curators' }); } else { const realCurators = this.getRealParams('curators', curatorLinks, doTask, link => link.match(/curator\/([\d]+)/)?.[1]); const realCuratorLikes = this.getRealParams('curatorLikes', curatorLikeLinks, doTask, link => link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3).join('/')); if (realCurators.length > 0) { for (const curator of realCurators) { prom.push(this.#toggleCurator(curator, doTask)); await delay(1e3); } } if (realCuratorLikes.length > 0) { for (const curatorLike of realCuratorLikes) { prom.push(this.#toggleCuratorLike(curatorLike, doTask)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.announcements) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.announcements' }); } else { const realAnnouncements = this.getRealParams('announcements', announcementLinks, doTask, link => { if (link.includes('store.steampowered.com')) { return link.match(/store\.steampowered\.com\/news\/app\/([\d]+)\/view\/([\d]+)/)?.slice(1, 3).join('/'); } return link.match(/steamcommunity\.com\/games\/([\d]+)\/announcements\/detail\/([\d]+)/)?.slice(1, 3).join('/'); }); if (doTask && realAnnouncements.length > 0) { for (const id of realAnnouncements) { prom.push(this.#likeAnnouncement(id)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.licenses) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.licenses' }); } else if (doTask && globalOptions.doTask.steam.licenses && licenseLinks.length > 0) { for (const ids of licenseLinks) { const [ type, idsStr ] = ids.split('-'); const idsArr = idsStr.split(','); for (const id of idsArr) { prom.push(this.#addLicense(`${type}-${id}`)); await delay(1e3); } } } if (doTask && !globalOptions.doTask.steam.playtests) { scripts_echoLog({ type: 'globalOptionsSkip', text: 'steam.playtests' }); } else { const realPlaytests = this.getRealParams('playtests', playtestLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]); if (doTask && globalOptions.doTask.steam.playtests && realPlaytests.length > 0) { for (const id of realPlaytests) { prom.push(this.#requestPlayTestAccess(id)); await delay(1e3); } } } return Promise.all(prom).then(async () => { if (this.#oldArea && this.#area !== this.#oldArea) { scripts_echoLog({}).warning(i18n('steamFinishNotice') + this.#oldArea); await this.#changeArea(this.#oldArea); } return true; }); } catch (error) { throwError(error, 'Steam.toggle'); return false; } } #setCache(type, name, id) { try { this.#cache[type][name] = id; GM_setValue('steamCache', this.#cache); } catch (error) { throwError(error, 'Steam.setCache'); } } } const social_Steam = Steam; class Website { undoneTasks; socialTasks; giveawayId; socialInitialized = { discord: false, instagram: false, reddit: false, twitch: false, twitter: false, vk: false, youtube: false, steamStore: false, steamCommunity: false }; initialized = false; steamTaskType = { steamStore: false, steamCommunity: false }; social = {}; async #bind(name, init) { try { return { name: name, result: await init }; } catch (error) { throwError(error, 'Website.bind'); return { name: name, result: false }; } } async initSocial(action) { try { const pro = []; const tasks = action === 'do' ? this.undoneTasks : this.socialTasks; if (tasks.discord) { const hasDiscord = Object.values(tasks.discord).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasDiscord && (!this.socialInitialized.discord || !this.social.discord)) { this.social.discord = new social_Discord(); pro.push(this.#bind('discord', this.social.discord.init(action))); } } if (tasks.instagram) { const hasInstagram = Object.values(tasks.instagram).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasInstagram && (!this.socialInitialized.instagram || !this.social.instagram)) { this.social.instagram = new social_Instagram(); pro.push(this.#bind('instagram', this.social.instagram.init())); } } if (tasks.reddit) { const hasReddit = Object.values(tasks.reddit).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasReddit && (!this.socialInitialized.reddit || !this.social.reddit)) { this.social.reddit = new social_Reddit(); pro.push(this.#bind('reddit', this.social.reddit.init())); } } if (tasks.twitch) { const hasTwitch = Object.values(tasks.twitch).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasTwitch && (!this.socialInitialized.twitch || !this.social.twitch)) { this.social.twitch = new social_Twitch(); pro.push(this.#bind('twitch', this.social.twitch.init())); } } if (tasks.twitter) { const hasTwitter = Object.values(tasks.twitter).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasTwitter && (!this.socialInitialized.twitter || !this.social.twitter)) { this.social.twitter = new social_Twitter(); pro.push(this.#bind('twitter', this.social.twitter.init())); } } if (tasks.vk) { const hasVk = Object.values(tasks.vk).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasVk && (!this.socialInitialized.vk || !this.social.vk)) { this.social.vk = new social_Vk(); pro.push(this.#bind('vk', this.social.vk.init())); } } if (tasks.youtube) { const hasYoutube = Object.values(tasks.youtube).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasYoutube && (!this.socialInitialized.youtube || !this.social.youtube)) { this.social.youtube = new Youtube(); pro.push(this.#bind('youtube', this.social.youtube.init())); } } if (tasks.steam) { const steamLength = Object.values(tasks.steam).reduce((total, arr) => [ ...total, ...arr ]).length; if (steamLength > 0) { if (!this.social.steam) { this.social.steam = new social_Steam(); } const steamCommunityLength = Object.keys(tasks.steam).map(type => [ 'groupLinks', 'officialGroupLinks', 'forumLinks', 'workshopLinks', 'workshopVoteLinks' ].includes(type) ? tasks.steam?.[type]?.length || 0 : 0).reduce((total, number) => total + number, 0); if (steamLength - steamCommunityLength > 0) { this.steamTaskType.steamStore = true; if (!this.socialInitialized.steamStore) { pro.push(this.#bind('steamStore', this.social.steam.init('store'))); } } if (steamCommunityLength > 0) { if (!this.socialInitialized.steamCommunity) { this.steamTaskType.steamCommunity = true; pro.push(this.#bind('steamCommunity', this.social.steam.init('community'))); } } } } if (tasks.links && tasks.links.length > 0) { this.social.visitLink = visitLink; } return await Promise.all(pro).then(result => { let checked = true; for (const data of result) { if (data.result) { this.socialInitialized[data.name] = data.result; } else { checked = false; } } return checked; }); } catch (error) { throwError(error, 'Website.initSocial'); return false; } } uniqueTasks(allTasks) { try { const result = {}; for (const [ social, types ] of Object.entries(allTasks)) { result[social] = {}; for (const [ type, tasks ] of Object.entries(types)) { result[social][type] = unique(tasks); } } return result; } catch (error) { throwError(error, 'Website.uniqueTasks'); return allTasks; } } async toggleTask(action) { try { if (!this.initialized && !this.init()) { return false; } if (!await this.classifyTask(action)) { return false; } await this.initSocial(action); const pro = []; const doTask = action === 'do'; const tasks = doTask ? this.undoneTasks : this.socialTasks; if (this.socialInitialized.discord === true && this.social.discord) { pro.push(this.social.discord.toggle({ doTask: doTask, ...tasks.discord })); } if (this.socialInitialized.instagram === true && this.social.instagram) { pro.push(this.social.instagram.toggle({ doTask: doTask, ...tasks.instagram })); } if (this.socialInitialized.reddit === true && this.social.reddit) { pro.push(this.social.reddit.toggle({ doTask: doTask, ...tasks.reddit })); } if (this.socialInitialized.twitch === true && this.social.twitch) { pro.push(this.social.twitch.toggle({ doTask: doTask, ...tasks.twitch })); } if (this.socialInitialized.twitter === true && this.social.twitter) { pro.push(this.social.twitter.toggle({ doTask: doTask, ...tasks.twitter })); } if (this.socialInitialized.vk === true && this.social.vk) { pro.push(this.social.vk.toggle({ doTask: doTask, ...tasks.vk })); } if (this.socialInitialized.youtube === true && this.social.youtube) { pro.push(this.social.youtube.toggle({ doTask: doTask, ...tasks.youtube })); } if ((this.steamTaskType.steamCommunity ? this.socialInitialized.steamCommunity === true : true) && (this.steamTaskType.steamStore ? this.socialInitialized.steamStore === true : true) && this.social.steam) { pro.push(this.social.steam.toggle({ doTask: doTask, ...tasks.steam })); } if (this.social.visitLink && tasks.links && doTask) { for (const link of tasks.links) { pro.push(this.social.visitLink(link)); } } if (doTask && tasks.extra && this.extraDoTask) { const hasExtra = Object.values(tasks.extra).reduce((total, arr) => [ ...total, ...arr ]).length > 0; if (hasExtra) { pro.push(this.extraDoTask(tasks.extra)); } } await Promise.all(pro); scripts_echoLog({}).success(i18n('allTasksComplete')); return true; } catch (error) { throwError(error, 'Website.toggleTask'); return false; } } async doTask() { try { return await this.toggleTask('do'); } catch (error) { throwError(error, 'Website.doTask'); return false; } } async undoTask() { try { return await this.toggleTask('undo'); } catch (error) { throwError(error, 'Website.undoTask'); return false; } } } const website_Website = Website; const defaultTasksTemplate = { steam: { groupLinks: [], wishlistLinks: [], curatorLinks: [], followLinks: [] }, discord: { serverLinks: [] }, vk: { nameLinks: [] }, extra: { website: [] } }; const defaultTasks = JSON.stringify(defaultTasksTemplate); class FreeAnyWhere extends website_Website { name = 'FreeAnyWhere'; tasks = []; socialTasks = JSON.parse(defaultTasks); undoneTasks = JSON.parse(defaultTasks); buttons = [ 'doTask', 'undoTask', 'verifyTask', 'getKey' ]; static test() { return window.location.host === 'freeanywhere.net'; } async init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); debug('检测登录按钮'); if ($('div.header__login a[href*=logout]').length === 0) { window.open('https://freeanywhere.net/game.php?steam_login', '_self'); logStatus.warning(i18n('needLogin')); return false; } debug('检测是否为登录页面'); if (window.location.href.includes('/login')) { logStatus.warning(i18n('needLogin')); return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Freeanywhere.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`fawTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks); } const tasks = $('div.game__content-tasks__task').map((index, element) => ({ id: $(element).attr('data-id'), social: $(element).find('div.task-img img').attr('alt'), link: $(element).find('div.task-link a').attr('href'), title: $(element).find('div.task-link').text().trim(), type: $(element).attr('data-type'), isSuccess: $(element).hasClass('done') })).toArray(); if (tasks.length === 0) { logStatus.success(); return false; } if (action === 'verify') { this.tasks = []; } for (const task of tasks) { debug('任务分类', task); const { id, social, title, type, link, isSuccess } = task; const taskInfo = { id: id, title: title, social: social, type: type }; if (action === 'verify' && !isSuccess) { this.tasks.push(taskInfo); continue; } switch (type) { case 'steam_account_verify': break; case 'steam_game_wishlist': if (action === 'undo' && link) { this.socialTasks.steam.wishlistLinks.push(link); } if (action === 'do' && !isSuccess && link) { this.undoneTasks.steam.wishlistLinks.push(link); } break; case 'steam_group_sub': if (action === 'undo' && link) { this.socialTasks.steam.groupLinks.push(link); } if (action === 'do' && !isSuccess && link) { this.undoneTasks.steam.groupLinks.push(link); } break; case 'site_visit': if (action === 'do' && !isSuccess) { this.undoneTasks.extra.website.push(`id=${id}&type=${type}&task=true`); } break; case 'vk_community_sub': if (action === 'undo' && link) { this.socialTasks.vk.nameLinks.push(link); } if (action === 'do' && !isSuccess && link) { this.undoneTasks.vk.nameLinks.push(link); } break; case 'vk_post_like': if (action === 'undo' && link) { this.socialTasks.vk.nameLinks.push(`${link}&action=like`); } if (action === 'do' && !isSuccess && link) { this.undoneTasks.vk.nameLinks.push(`${link}&action=like`); } break; case 'discord_server_sub': if (action === 'undo' && link) { this.socialTasks.discord.serverLinks.push(link); } if (action === 'do' && !isSuccess && link) { this.undoneTasks.discord.serverLinks.push(link); } break; case 'telegram_channel_sub': scripts_echoLog({}).warning(`${i18n('tgTaskNotice')}`); break; case 'none': scripts_echoLog({}).warning(`${i18n('notConnect')}`); break; default: scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${type}`); break; } } logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`fawTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'Freeanywhere.classifyTask'); return false; } } async verifyTask() { try { if (!this.initialized && !this.init()) { debug('未初始化'); return false; } if (this.tasks.length === 0 && !await this.classifyTask('verify')) { debug('任务列表为空', this.tasks); return false; } const pro = []; for (const task of this.tasks) { pro.push(this.#verify(task)); await delay(1e3); } await Promise.all(pro); scripts_echoLog({}).success(i18n('allTasksComplete')); return !!await this.getKey(true); } catch (error) { throwError(error, 'Freeanywhere.verifyTask'); return false; } } async extraDoTask({ website }) { try { const pro = []; for (const link of website) { pro.push(this.#doVisitWebsite(link)); } return Promise.all(pro).then(() => true); } catch (error) { throwError(error, 'FreeAnyWhere.extraDoTask'); return false; } } async #doVisitWebsite(link) { try { const logStatus = scripts_echoLog({ text: i18n('visitingLink') }); const { result, statusText, status } = await tools_httpRequest({ url: 'https://freeanywhere.net/php/task_site_visit_done.php', method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: link }); if (result === 'Success') { logStatus.success(); return true; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'FreeAnyWhere.doVisitWebsite'); return false; } } async getKey(initialized) { try { if (!initialized && !this.initialized && !this.init()) { debug('未初始化'); return false; } const logStatus = scripts_echoLog({ text: i18n('gettingKey') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://freeanywhere.net/php/user_get_key.php', method: 'POST' }); if (result === 'Success') { if (data?.responseText.indexOf('bad') !== -1 || data?.responseText.length > 50) { logStatus.error(data?.responseText); return false; } logStatus.success(); scripts_echoLog({}).success(data.responseText); return data.responseText; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'FreeAnyWhere.getGiveawayId'); return false; } } async #verify(task) { try { const logStatus = scripts_echoLog({ html: `<li>${i18n('verifyingTask')}${task.title.trim()}...<font></font></li>` }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://freeanywhere.net/php/user_task_update.php', method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: `id=${task.id}&type=${task.type}` }); if (result === 'Success') { if (data?.responseText.trim() === 'good') { logStatus.success(); return true; } debug('任务验证结果', data?.response); logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Freeanywhere.verify'); return false; } } } const Freeanywhere = FreeAnyWhere; const Giveawaysu_defaultTasks = { steam: { groupLinks: [], wishlistLinks: [], curatorLinks: [], curatorLikeLinks: [], followLinks: [], forumLinks: [], announcementLinks: [], workshopVoteLinks: [], playtestLinks: [] }, discord: { serverLinks: [] }, instagram: { userLinks: [] }, vk: { nameLinks: [] }, twitch: { channelLinks: [] }, reddit: { redditLinks: [] }, youtube: { channelLinks: [], likeLinks: [] }, twitter: { userLinks: [], retweetLinks: [] } }; class GiveawaySu extends website_Website { name = 'GiveawaySu'; socialTasks = Giveawaysu_defaultTasks; undoneTasks = Giveawaysu_defaultTasks; buttons = [ 'doTask', 'undoTask' ]; static test() { return /^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(window.location.href); } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } scripts_echoLog({}).warning(i18n('gsNotice')); } catch (error) { throwError(error, 'Giveawaysu.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if ($('a.steam-login').length > 0) { window.open('/steam/redirect', '_self'); logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Giveawaysu.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`gasTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks; return true; } const pro = []; const tasks = $('#actions tr'); if ($('div.bind-discord').is(':visible')) { $('div.bind-discord a')[0].click(); } if ($('div.bind-twitch').is(':visible')) { $('div.bind-twitch a')[0].click(); } for (const task of tasks) { pro.push(new Promise(resolve => { const td = $(task).find('td:not(".hidden")'); const colorfulTask = td.eq(1).find('a:not([data-trigger="link"])'); const colorlessTask = td.eq(2).find('a:not([data-trigger="link"])'); const taskDes = colorfulTask.length > 0 ? colorfulTask : colorlessTask; const taskIcon = td.eq(0).find('i').attr('class') || ''; const taskName = taskDes.text().trim(); if (taskIcon.includes('ban') || /disable adblock/gi.test(taskName)) { return resolve(true); } getRedirectLink(taskDes.attr('href')).then(taskLink => { if (!taskLink) { return resolve(false); } if (taskIcon.includes('steam') && /join/gi.test(taskName)) { this.undoneTasks.steam.groupLinks.push(taskLink); } else if (/like.*announcement/gi.test(taskName)) { this.undoneTasks.steam.announcementLinks.push(taskLink); } else if (/(follow|subscribe).*curator/gim.test(taskName) && /^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) { this.undoneTasks.steam.curatorLinks.push(taskLink); } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) { this.undoneTasks.steam.curatorLikeLinks.push(taskLink); } else if (/subscribe.*steam.*forum/gim.test(taskName)) { this.undoneTasks.steam.forumLinks.push(taskLink); } else if (taskIcon.includes('thumbs-up') && /^https?:\/\/steamcommunity\.com\/sharedfiles\/filedetails\/\?id=[\d]+/.test(taskLink)) { this.undoneTasks.steam.workshopVoteLinks.push(taskLink); } else if (taskIcon.includes('plus') && /request.*playtest/gim.test(taskName)) { this.undoneTasks.steam.playtestLinks.push(taskLink); } else if (taskIcon.includes('discord') || /join.*discord/gim.test(taskName)) { this.undoneTasks.discord.serverLinks.push(taskLink); } else if (taskIcon.includes('instagram') || /follow.*instagram/gim.test(taskName)) { this.undoneTasks.instagram.userLinks.push(taskLink); } else if (taskIcon.includes('twitch') || /follow.*twitch.*channel/gim.test(taskName)) { this.undoneTasks.twitch.channelLinks.push(taskLink); } else if (taskIcon.includes('reddit') || /subscribe.*subreddit/gim.test(taskName) || /follow.*reddit/gim.test(taskName)) { this.undoneTasks.reddit.redditLinks.push(taskLink); } else if (/watch.*art/gim.test(taskName)) { this.undoneTasks.steam.workshopVoteLinks.push(taskLink); } else if (/subscribe.*youtube.*channel/gim.test(taskName)) { this.undoneTasks.youtube.channelLinks.push(taskLink); } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) { this.undoneTasks.youtube.likeLinks.push(taskLink); } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) { this.undoneTasks.vk.nameLinks.push(taskLink); } else { if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else { if (/wishlist.*game|add.*wishlist/gim.test(taskName)) { this.undoneTasks.steam.wishlistLinks.push(taskLink); } if (/follow.*button/gim.test(taskName)) { this.undoneTasks.steam.followLinks.push(taskLink); } } } resolve(true); }).catch(error => { throwError(error, 'Giveawaysu.classifyTask->getRedirectLink'); return false; }); })); } await Promise.all(pro); logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.undoneTasks; if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`gasTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'Giveawaysu.classifyTask'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a.steam-login').length > 0) { window.open('/steam/redirect', '_self'); } return true; } catch (error) { throwError(error, 'Giveawaysu.checkLogin'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } if ($('.giveaway-ended').length > 0 && $('.giveaway-key').length === 0) { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('noKeysLeft'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Giveawaysu.checkLeftKey'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } catch (error) { throwError(error, 'Giveawaysu.getGiveawayId'); return false; } } } class Indiedb { name = 'Indiedb'; buttons = [ 'doTask' ]; static test() { return window.location.host === 'www.indiedb.com'; } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } } catch (error) { throwError(error, 'Indiedb.after'); } } async doTask() { try { if (!await this.#join()) { return false; } return await this.#do(); } catch (error) { throwError(error, 'Indiedb.doTask'); return false; } } async #join() { try { if ($('a.buttonenter:contains(Register to join)').length > 0) { scripts_echoLog({}).error(i18n('needLogin')); return false; } const currentoption = $('a.buttonenter.buttongiveaway'); if (/join giveaway/gim.test(currentoption.text())) { const logStatus = scripts_echoLog({ text: `${i18n('joiningGiveaway')}...` }); const { result, statusText, status, data } = await tools_httpRequest({ url: currentoption.attr('href'), method: 'POST', data: 'ajax=t', dataType: 'json', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Accept: 'application/json, text/javascript, */*; q=0.01', Origin: window.location.origin, referer: window.location.href } }); if (result === 'Success') { if (data?.status === 200) { if (data.response?.success) { currentoption.addClass('buttonentered').text('Success - Giveaway joined'); $('#giveawaysjoined').slideDown(); $('#giveawaysrecommend').slideDown(); logStatus.success(`Success${data.response?.text ? `:${data.response?.text}` : ''}`); return true; } logStatus.error(`Error${data.response?.text ? `:${data.response?.text}` : ''}`); return false; } if (await this.#join2()) { logStatus.success('Success'); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } else if (/success/gim.test($('a.buttonenter.buttongiveaway').text())) { return true; } scripts_echoLog({}).warning(i18n('needJoinGiveaway')); return false; } catch (error) { throwError(error, 'Indiedb.join'); return false; } } async #join2() { try { return await new Promise(resolve => { const targetNode = document.getElementById('giveawaysjoined'); const config = { attributes: true }; const observer = new MutationObserver(() => { if ($('#giveawaysjoined').is(':visible')) { resolve(true); observer.disconnect(); } }); observer.observe(targetNode, config); $('a.buttonenter.buttongiveaway')[0]?.click(); setTimeout(() => { resolve(false); observer.disconnect(); }, 3e4); }); } catch (error) { throwError(error, 'Indiedb.join2'); return false; } } async #do() { try { const id = $('script').map((index, script) => { if (/\$\(document\)/gim.test(script.innerHTML)) { return [ script.innerHTML.match(/"\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0], script.innerHTML.match(/"\/newsletter\/ajax\/subscribeprofile\/optin\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0] ]; } return null; }); if (id.length === 2) { const pro = []; const tasks = $('#giveawaysjoined a[class*=promo]'); for (const task of tasks) { const promo = $(task); if (!promo.hasClass('buttonentered')) { const status = scripts_echoLog({ text: `${i18n('doing')}:${promo.parents('p').text()}...` }); if (/facebookpromo|twitterpromo|visitpromo/gim.test(task.className)) { let text = ''; if (promo.hasClass('facebookpromo')) { text = 'facebookpromo'; } else if (promo.hasClass('twitterpromo')) { text = 'twitterpromo'; } else { text = 'visitpromo'; } pro.push(new Promise(resolve => { $.ajax({ type: 'POST', url: urlPath(`/giveaways/ajax/${text}/${id[0]}`), timeout: 6e4, dataType: 'json', data: { ajax: 't' }, error(response, error, exception) { if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:red', { response: response, error: error, exception: exception }); } status.error('Error:An error has occurred performing the action requested. Please try again shortly.'); resolve(true); }, success(response) { if (response.success) { status.success(`Success:${response.text}`); promo.addClass('buttonentered').closest('p').html(promo.closest('p').find('span').html()); resolve(true); } else { status.error(`Error:${response.text}`); resolve(true); } } }); })); } else if (promo.hasClass('emailoptinpromo')) { pro.push(new Promise(resolve => { $.ajax({ type: 'POST', url: urlPath(`/newsletter/ajax/subscribeprofile/optin/${id[1]}`), timeout: 6e4, dataType: 'json', data: { ajax: 't', emailsystoggle: 4 }, error(response, error, exception) { if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:red', { response: response, error: error, exception: exception }); } status.error('Error:An error has occurred performing the action requested. Please try again shortly.'); resolve(true); }, success(response) { if (response.success) { status.success(`Success:${response.text}`); promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html()); resolve(true); } else { status.error(`Error:${response.text}`); resolve(true); } } }); })); } else if (promo.hasClass('watchingpromo')) { pro.push(new Promise(resolve => { const data = getUrlQuery(promo.attr('href')); data.ajax = 't'; $.ajax({ type: 'POST', url: urlPath(promo.attr('href')?.split(/[?#]/)[0]), timeout: 6e4, dataType: 'json', data: data, error(response, error, exception) { if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:red', { response: response, error: error, exception: exception }); } status.error('Error:An error has occurred performing the action requested. Please try again shortly.'); resolve(true); }, success(response) { if (response.success) { status.success(`Success:${response.text}`); promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html()); resolve(true); } else { status.error(`Error:${response.text}`); resolve(true); } } }); })); } else if (!/the-challenge-of-adblock/gim.test(promo.attr('href'))) { pro.push(new Promise(resolve => { $.ajax({ type: 'POST', url: urlPath(promo.attr('href')), timeout: 6e4, dataType: 'json', data: { ajax: 't' }, error(response, error, exception) { if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:red', { response: response, error: error, exception: exception }); } status.error('Error:An error has occurred performing the action requested. Please try again shortly.'); resolve(true); }, success(response) { if (response.success) { status.success(`Success:${response.text}`); promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html()); resolve(true); } else { status.error(`Error:${response.text}`); resolve(true); } } }); })); } else { status.error(`Error:${i18n('unKnownTaskType')}`); } } } await Promise.all(pro); scripts_echoLog({}).success(i18n('allTasksComplete')); return true; } scripts_echoLog({}).error(i18n('getFailed', 'TaskId')); return false; } catch (error) { throwError(error, 'Indiedb.classifyTask'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a.buttonenter:contains(Register to join)').length > 0) { window.open('/members/login', '_self'); } return true; } catch (error) { throwError(error, 'Indiedb.checkLogin'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } if ($('a.buttonenter:contains("next time"), a.buttonenter:contains("Giveaway is closed")').length > 0) { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('giveawayEnded'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Indiedb.checkLeftKey'); return false; } } } const website_Indiedb = Indiedb; const Keyhub_defaultTasksTemplate = { steam: { groupLinks: [], officialGroupLinks: [], wishlistLinks: [], curatorLinks: [] }, discord: { serverLinks: [] }, extra: { videoTasks: [] }, links: [] }; const Keyhub_defaultTasks = JSON.stringify(Keyhub_defaultTasksTemplate); class Keyhub extends website_Website { name = 'Keyhub'; socialTasks = JSON.parse(Keyhub_defaultTasks); undoneTasks = JSON.parse(Keyhub_defaultTasks); buttons = [ 'doTask', 'undoTask' ]; static test() { return window.location.host === 'key-hub.eu'; } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } $('.NSFW').hide(); } catch (error) { throwError(error, 'Keyhub.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if ($('a[href*="/connect/steam"]').length > 0) { window.open('/connect/steam', '_self'); logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } $('#VPNoverlay').hide(); $('#mainArticleSection').show(); this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Keyhub.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`khTasks-${this.giveawayId}`)?.tasks || JSON.parse(Keyhub_defaultTasks); } const tasks = $('.task:not(".googleads")').filter((index, element) => action === 'do' ? $(element).find('i.fa-check-circle:visible').length === 0 : true).find('a'); for (const task of tasks) { let link = $(task).attr('href'); const taskDes = $(task).text().trim(); if (!link) { continue; } if (/\/away\?data=/.test(link) || /steamcommunity\.com\/gid\//.test(link)) { link = await getRedirectLink(link) || link; } if (/https?:\/\/key-hub\.eu\/connect\/discord/.test(link)) { GM_openInTab(link, { active: true }); } else if (/steamcommunity\.com\/groups\//.test(link)) { if (action === 'undo') { this.socialTasks.steam.groupLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.groupLinks.push(link); } } else if (/steamcommunity\.com\/games\/[\d]+/.test(link)) { if (action === 'undo') { this.socialTasks.steam.officialGroupLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.officialGroupLinks.push(link); } } else if (/store\.steampowered\.com\/app\//.test(link) && /wishlist/gim.test(taskDes)) { if (action === 'undo') { this.socialTasks.steam.wishlistLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.wishlistLinks.push(link); } } else if (/store\.steampowered\.com\/curator\//.test(link)) { if (action === 'undo') { this.socialTasks.steam.curatorLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.curatorLinks.push(link); } } else if (/^https?:\/\/discord\.com\/invite\//.test(link)) { if (action === 'undo') { this.socialTasks.discord.serverLinks.push(link); } if (action === 'do') { this.undoneTasks.discord.serverLinks.push(link); } } else if (/^javascript:videoTask.+/.test(link)) { if (action === 'do') { const taskData = link.match(/javascript:videoTask\('.+?','(.+?)'/)?.[1]; if (taskData) { this.undoneTasks.extra.videoTasks.push(taskData); } } } else if (/^https?:\/\/www\.instagram\.com\/.*/.test(link) || /^https?:\/\/twitter\.com\/.*/.test(link) || /^https?:\/\/www\.twitch\.tv\/.*/.test(link) || /^https?:\/\/www\.facebook\.com\/.*/.test(link) || /^https?:\/\/www\.youtube\.com\/.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/developer\//.test(link) || /^https?:\/\/.*?\.itch\.io\/.*/.test(link) || /^https?:\/\/key-hub\.eu.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/app\/.*/.test(link) || /^https?:\/\/qr\.streamelements\.com\/.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/news\/app\/.*/.test(link)) {} else { scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`); } } logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`khTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'Keyhub.classifyTask'); return false; } } async #doScriptTask(data) { try { const logStatus = scripts_echoLog({ text: i18n('doingKeyhubTask') }); const { result, statusText, status, data: response } = await tools_httpRequest({ url: `/away?data=${data}`, method: 'GET', headers: { origin: 'https://key-hub.eu', referer: 'https://key-hub.eu/' } }); if (result === 'Success') { if (response?.status === 200) { logStatus.success(); return true; } logStatus.error(`Error:${response?.statusText}(${response?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Keyhub.doScriptTask'); return false; } } async extraDoTask({ videoTasks }) { try { const pro = []; for (const data of videoTasks) { pro.push(this.#doScriptTask(data)); } return Promise.all(pro).then(() => true); } catch (error) { throwError(error, 'Keyhub.extraDoTask'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId')); return false; } catch (error) { throwError(error, 'Keyhub.getGiveawayId'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } const leftKey = $('#keysleft').text().trim(); if (leftKey === '0') { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('noKeysLeft'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Keyhub.checkLeftKey'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a[href*="/connect/steam"]').length > 0) { window.open('/connect/steam', '_self'); } return true; } catch (error) { throwError(error, 'Keyhub.checkLogin'); return false; } } } const website_Keyhub = Keyhub; const Givekey_defaultTasksTemplate = { steam: { groupLinks: [], wishlistLinks: [], curatorLinks: [], curatorLikeLinks: [] }, twitter: { userLinks: [] }, vk: { nameLinks: [] }, discord: { serverLinks: [] } }; const Givekey_defaultTasks = JSON.stringify(Givekey_defaultTasksTemplate); class Givekey extends website_Website { name = 'Givekey'; tasks = []; socialTasks = JSON.parse(Givekey_defaultTasks); undoneTasks = JSON.parse(Givekey_defaultTasks); userId; buttons = [ 'doTask', 'undoTask', 'verifyTask' ]; static test() { return window.location.host === 'givekey.ru'; } async after() { try { await new Promise(resolve => { const checker = setInterval(() => { if ($('#navbarDropdown').length > 0) { clearInterval(checker); resolve(true); } }, 500); }); if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } } catch (error) { throwError(error, 'Givekey.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if ($('a[href*="/auth/steam"]').length > 0) { window.open('/auth/steam', '_self'); logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } const userId = $('meta[name="user-id"]').attr('content'); if (!userId) { logStatus.error(i18n('getFailed', i18n('userId'))); return false; } this.userId = userId; this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Givekey.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`gkTasks-${this.giveawayId}`)?.tasks || JSON.parse(Givekey_defaultTasks); } const tasks = $('.card-body:has("button") .row'); for (const task of tasks) { const taskEle = $(task); const isSuccess = /Complete/i.test(taskEle.find('button').text().trim()); if (isSuccess && action !== 'undo') { continue; } const checkButton = taskEle.find('#task_check'); const taskId = checkButton.attr('data-id'); if (taskId) { this.tasks.push(taskId); } if (action === 'verify') { continue; } let href = taskEle.find('a').attr('href') || null; const text = taskEle.find('a').text().trim(); const icon = taskEle.find('i'); if (!href || !text) { continue; } if (/^https?:\/\/givekey\.ru\/giveaway\/[\d]+\/execution_task/.test(href)) { href = await getRedirectLink(href); } if (!href) { continue; } if (/^https?:\/\/vk\.com\//.test(href)) { this.socialTasks.vk.nameLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.vk.nameLinks.push(href); } } else if (/^https?:\/\/steamcommunity\.com\/groups/.test(href)) { this.socialTasks.steam.groupLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.steam.groupLinks.push(href); } } else if (/^https?:\/\/store\.steampowered\.com\/app\//.test(href)) { this.socialTasks.steam.wishlistLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.steam.wishlistLinks.push(href); } } else if (/Subscribe/gi.test(text) && icon.hasClass('fa-steam-square')) { if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(href)) { this.socialTasks.steam.curatorLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.steam.curatorLinks.push(href); } } else { this.socialTasks.steam.curatorLikeLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.steam.curatorLikeLinks.push(href); } } } else if (/^https?:\/\/twitter\.com\//.test(href) && /Subscribe/gi.test(text)) { this.socialTasks.twitter.userLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.twitter.userLinks.push(href); } } else if (icon.hasClass('fa-discord') || /^https?:\/\/discord\.com\/invite\//.test(href)) { this.socialTasks.discord.serverLinks.push(href); if (action === 'do' && !isSuccess) { this.undoneTasks.discord.serverLinks.push(href); } } else { scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${text}(${href})`); } } logStatus.success(); this.tasks = unique(this.tasks); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`gkTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'Givekey.classifyTask'); return false; } } async verifyTask() { try { if (!this.initialized && !this.init()) { return false; } if (this.tasks.length === 0 && !await this.classifyTask('verify')) { return false; } scripts_echoLog({}).warning(i18n('giveKeyNoticeBefore')); const taskLength = this.tasks.length; for (let i = 0; i < taskLength; i++) { await this.#verify(this.tasks[i]); if (i < taskLength - 1) { await delay(15e3); } } scripts_echoLog({}).success(i18n('allTasksComplete')); scripts_echoLog({ html: `<li><font class="warning">${i18n('giveKeyNoticeAfter')}</font></li>` }); return true; } catch (error) { throwError(error, 'Givekey.verifyTask'); return false; } } async #verify(task) { try { const logStatus = scripts_echoLog({ html: `<li>${i18n('verifyingTask')}${task}...<font></font></li>` }); return await new Promise(resolve => { $.ajax({ url: 'https://givekey.ru/giveaway/task', method: 'POST', data: `id=${task}&user_id=${this.userId}`, dataType: 'json', headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, success: data => { if (data.btn) { $(`button[data-id=${this.userId}]`).html(data.btn); } if (data.status === 'ok') { $(`.task_check_${data.id}`).html(`<button class="btn btn-success mb-2 btn-block" disabled>${data.btn}</button>`); logStatus.success(); resolve(true); } else if (data.status === 'end') { logStatus.success(); scripts_echoLog({}).success(data.key); resolve(true); } else { logStatus.error(`Error:${data.msg}`); resolve(false); } }, error: xhr => { logStatus.error(`Error:${xhr.statusText}(${xhr.status})`); resolve(false); } }); }); } catch (error) { throwError(error, 'Givekey.verify'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } catch (error) { throwError(error, 'Givekey.getGiveawayId'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } if (!$('#keys_count').text()) { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('noKeysLeft'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Givekey.checkLeftKey'); return false; } } } const website_Givekey = Givekey; class GiveeClub extends GiveawaySu { name = 'GiveeClub'; buttons = [ 'doTask', 'undoTask', 'verifyTask' ]; static test() { return /^https?:\/\/givee\.club\/.*?\/event\/[\d]+/.test(window.location.href); } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } } catch (error) { throwError(error, 'GiveeClub.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if (!this.#checkLogin()) { logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'GiveeClub.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`gcTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks; return true; } this.undoneTasks = Giveawaysu_defaultTasks; const pro = []; const tasks = $('.event-actions tr'); for (const task of tasks) { pro.push(new Promise(resolve => { const taskDes = $(task).find('.event-action-label a'); const taskIcon = $(task).find('.event-action-icon i').attr('class') || ''; const taskName = taskDes.text().trim(); const taskType = $(task).find('button[data-type]')?.attr('data-type'); const taskFinished = $(task).find('.event-action-buttons .btn-success')?.length; if (taskIcon.includes('ban') || /AdBlock/i.test(taskName) || taskIcon.includes('envelope') || taskFinished) { return resolve(true); } getRedirectLink(taskDes.attr('href'), true).then(taskLink => { if (!taskLink) { return resolve(false); } if (taskType === 'steam.group.join' && /^https?:\/\/steamcommunity\.com\/groups/.test(taskLink)) { this.undoneTasks.steam.groupLinks.push(taskLink); } else if (/like.*announcement/gi.test(taskName)) { this.undoneTasks.steam.announcementLinks.push(taskLink); } else if (taskType === 'steam.game.wishlist' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) { this.undoneTasks.steam.wishlistLinks.push(taskLink); } else if (taskType === 'steam.game.wishlist' && taskDes.attr('data-steam-wishlist-appid')) { this.undoneTasks.steam.wishlistLinks.push(`https://store.steampowered.com/app/${taskDes.attr('data-steam-wishlist-appid')}`); } else if (taskType === 'steam.game.follow' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) { this.undoneTasks.steam.followLinks.push(taskLink); } else if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) { this.undoneTasks.steam.curatorLinks.push(taskLink); } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) { this.undoneTasks.steam.curatorLikeLinks.push(taskLink); } else if (/subscribe.*steam.*forum/gim.test(taskName)) { this.undoneTasks.steam.forumLinks.push(taskLink); } else if (taskIcon.includes('discord')) { this.undoneTasks.discord.serverLinks.push(taskLink); } else if (taskIcon.includes('instagram')) { this.undoneTasks.instagram.userLinks.push(taskLink); } else if (taskIcon.includes('twitch')) { this.undoneTasks.twitch.channelLinks.push(taskLink); } else if (taskIcon.includes('reddit')) { this.undoneTasks.reddit.redditLinks.push(taskLink); } else if (/watch.*art/gim.test(taskName)) { this.undoneTasks.steam.workshopVoteLinks.push(taskLink); } else if (/subscribe.*youtube.*channel/gim.test(taskName)) { this.undoneTasks.youtube.channelLinks.push(taskLink); } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) { this.undoneTasks.youtube.likeLinks.push(taskLink); } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) { this.undoneTasks.vk.nameLinks.push(taskLink); } else if (taskIcon.includes('twitter')) { if (/https?:\/\/(twitter|x)\.com\/[^/]+\/?$/gim.test(taskLink)) { this.undoneTasks.twitter.userLinks.push(taskLink); } else if (/https?:\/\/(twitter|x)\.com\/[^/]+?\/status\/[\d]+/gim.test(taskLink)) { this.undoneTasks.twitter.retweetLinks.push(taskLink); } } else { if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else { if (/follow.*button/gim.test(taskName)) { this.undoneTasks.steam.followLinks.push(taskLink); } } } resolve(true); }).catch(error => { throwError(error, 'GiveeClub.classifyTask->getRedirectLink'); return false; }); })); } await Promise.all(pro); logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.undoneTasks; if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`gcTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'GiveeClub.classifyTask'); return false; } } async verifyTask() { try { const logStatus = scripts_echoLog({ text: i18n('giveeClubVerifyNotice') }); const taskButtons = $('.event-actions tr button').has('i.glyphicon-refresh').not('[data-type="user.adblock"]'); for (const button of taskButtons) { button.click(); if ($(button).attr('data-type') !== 'steam.game.wishlist') { await delay(1e3); } } logStatus.warning(i18n('giveeClubVerifyFinished')); return true; } catch (error) { throwError(error, 'Givekey.verifyTask'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a[href*="/account/auth"]').length > 0) { window.open($('a[href*="/account/auth"]').attr('href'), '_self'); } return true; } catch (error) { throwError(error, 'GiveeClub.checkLogin'); return false; } } #getGiveawayId() { const giveawayId = window.location.href.match(/\/event\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } if ($('.event-ended').length > 0 && $('.event-winner').length === 0) { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('giveawayEnded'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Giveawaysu.checkLeftKey'); return false; } } } const website_GiveeClub = GiveeClub; const defaultOptions = { maxPoint: '99999999' }; class OpiumPulses { name = 'OpiumPulses'; options = { ...defaultOptions, ...GM_getValue('OpiumPulsesOptions') }; maxPoints = 99999999; myPoints = 0; buttons = [ 'doFreeTask', 'doPointTask' ]; static test() { return window.location.host === 'www.opiumpulses.com'; } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } this.maxPoints = parseInt(this.options.maxPoint, 10); } catch (error) { throwError(error, 'OpiumPulses.after'); } } async doFreeTask() { try { this.#toggleTask('FREE'); } catch (error) { throwError(error, 'OpiumPulses.doFreeTask'); } } async doPointTask() { try { this.myPoints = parseInt($('.page-header__nav-func-user-nav-items.points-items').text().match(/[\d]+/gim)?.[0] || '0', 10); this.#toggleTask('points'); } catch (error) { throwError(error, 'OpiumPulses.doPointTask'); } } async #toggleTask(type) { try { const items = $(`.giveaways-page-item:contains('${type}'):not(:contains('ENTERED'))`); for (const item of items) { const needPoints = parseInt($(item).find('.giveaways-page-item-header-points').text().match(/[\d]+/gim)?.[0] || '999999', 10); const name = $(item).find('.giveaways-page-item-footer-name').text().trim(); if (type === 'points' && needPoints > this.myPoints) { scripts_echoLog({}).warning(`${i18n('noPoints')}: ${name}`); } else if (type === 'points' && !needPoints) { scripts_echoLog({}).warning(`${i18n('getNeedPointsFailed')}: ${name}`); } else if (!(type === 'points' && needPoints > this.maxPoints)) { const logStatus = scripts_echoLog({ text: `${i18n('joiningLottery')}<a href="${$(item).find('a.giveaways-page-item-img-btn-more').attr('href')}" target="_blank">${name}</a>...` }); const aElement = $(item).find('a.giveaways-page-item-img-btn-enter:contains(\'enter\')'); if (aElement?.attr('onclick')?.includes('checkUser')) { const giveawayId = aElement.attr('onclick')?.match(/[\d]+/)?.[0]; if (giveawayId) { checkUser(giveawayId); } } if (!aElement.attr('href')) { logStatus.error('Error: No "href".'); continue; } const { result, statusText, status, data } = await tools_httpRequest({ url: aElement.attr('href'), method: 'GET' }); if (result === 'Success') { const { result: result0, statusText: statusText0, status: status0, data: data0 } = await tools_httpRequest({ url: data?.finalUrl, method: 'GET' }); if (data0?.responseText && /You've entered this giveaway/gim.test(data0.responseText)) { logStatus.success(); const points = data0.responseText.match(/Points:[\s]*?([\d]+)/)?.[1]; if (type === 'points' && points) { this.myPoints = parseInt(points, 10); } } else if (data0?.responseText && /You're not eligible to enter/gim.test(data0.responseText)) { logStatus.error('You\'re not eligible to enter'); } else { logStatus.error(`${result0}:${statusText0}(${status0})`); } } else { logStatus.error(`${result}:${statusText}(${status})`); } } } scripts_echoLog({ text: '-----END-----' }); } catch (error) { throwError(error, 'OpiumPulses.toggleTask'); } } init() { return true; } classifyTask() { return true; } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a[href*="/site/login"]').length > 1) { window.open('/site/login', '_self'); } return true; } catch (error) { throwError(error, 'OpiumPulses.checkLogin'); return false; } } } const website_OpiumPulses = OpiumPulses; const external_dayjs_namespaceObject = dayjs; var external_dayjs_default = __webpack_require__.n(external_dayjs_namespaceObject); const leftKeyChecker = { async classify(link) { try { if (/^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(link)) { return await this.giveawaySu(link); } if (/^https?:\/\/givee\.club\/[\w]+?\/event\/[\d]+/.test(link)) { return await this.giveeClub(link); } if (/^https?:\/\/gleam\.io\/.+?\/.+/.test(link)) { return await this.gleam(link); } if (/^https?:\/\/www\.indiedb\.com\/giveaways\/.+/.test(link)) { return await this.indieDb(link); } if (/^https?:\/\/key-hub\.eu\/giveaway\/[\d]+/.test(link)) { return await this.keyhub(link); } if (/^https?:\/\/opquests\.com\/quests\/[\d]+/.test(link)) { return await this.opquests(link); } if (/^https?:\/\/itch\.io\/s\/[\d]+?\/.*/.test(link)) { return await this.itch(link); } return false; } catch (error) { throwError(error, 'leftKeyChecker.classify'); return false; } }, async giveawaySu(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { if (data.responseText.includes('class="steam-login"')) { return false; } if (data.responseText.includes('class="giveaway-ended"')) { return 'Ended'; } return 'Active'; } return false; } catch (error) { throwError(error, 'leftKeyChecker.giveawaySu'); return false; } }, async giveeClub(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { if (data.responseText.includes('class="event-winner"')) { return 'Won'; } if (data.responseText.includes('class="event-ended"')) { return 'Ended'; } return 'Active'; } return false; } catch (error) { throwError(error, 'leftKeyChecker.giveeClub'); return false; } }, async gleam(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { if (/incentives":{"[\d]+?":\[".+?"\]/.test(data.responseText)) { return 'Won'; } const campaignDiv = data.responseText.match(/<div class='popup-blocks-container'[\w\W]+?'>/)?.[0]; if (!campaignDiv) { return false; } const campaignString = $(campaignDiv).attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1]; if (!campaignString) { return false; } const { campaign } = JSON.parse(campaignString); if (campaign.banned) { return 'Banned'; } if (campaign.finished) { return 'Ended'; } if (campaign.paused) { return 'Paused'; } if (new Date().getTime() < campaign.starts_at * 1e3) { return 'NotStart'; } return 'Active'; } return false; } catch (error) { throwError(error, 'leftKeyChecker.gleam'); return false; } }, async indieDb(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { if (data.responseText.includes('Congrats you WON')) { return 'Won'; } if (data.responseText.includes('Giveaway is closed') || data.responseText.includes('next time')) { return 'Ended'; } return 'Active'; } return false; } catch (error) { throwError(error, 'leftKeyChecker.indieDb'); return false; } }, async keyhub(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { const keysleft = data.responseText.match(/<span id="keysleft">([\d]+?)<\/span>/)?.[1]; if (!keysleft) { return false; } if (keysleft === '0') { return 'Ended'; } return `Active(${keysleft})`; } return false; } catch (error) { throwError(error, 'leftKeyChecker.keyhub'); return false; } }, async opquests(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { const keysleft = data.responseText.match(/<div class="">[\s]*?([\d]+?)[\s]*?of/)?.[1]; if (!keysleft) { return false; } if (keysleft === '0') { return 'Ended'; } return `Active(${keysleft})`; } else if (data?.status === 404) { return 'Ended'; } return false; } catch (error) { throwError(error, 'leftKeyChecker.opquests'); return false; } }, async itch(link) { try { const { result, data } = await tools_httpRequest({ url: link, method: 'GET' }); if (result === 'Success' && data?.status === 200) { const endDate = data.responseText.match(/{"start_date":"[0-9A-Z-:]+?".*?"end_date":"([0-9A-Z-:]+?)".*?}/)?.[1]; if (!endDate) { return false; } if (new Date().getTime() > new Date(endDate).getTime()) { return 'Ended'; } return `Active(${external_dayjs_default()(endDate).format('YYYY-MM-DD HH:mm:ss')})`; } return false; } catch (error) { throwError(error, 'leftKeyChecker.itch'); return false; } } }; const website_leftKeyChecker = leftKeyChecker; const Keylol_defaultTasksTemplate = { steam: { groupLinks: [], wishlistLinks: [], curatorLinks: [], curatorLikeLinks: [], followLinks: [], forumLinks: [], announcementLinks: [], workshopVoteLinks: [], licenseLinks: [] }, discord: { serverLinks: [] }, instagram: { userLinks: [] }, vk: { nameLinks: [] }, twitch: { channelLinks: [] }, reddit: { redditLinks: [] }, twitter: { userLinks: [], retweetLinks: [] }, youtube: { channelLinks: [], likeLinks: [] } }; const Keylol_defaultTasks = JSON.stringify(Keylol_defaultTasksTemplate); class Keylol extends website_Website { name = 'Keylol'; socialTasks = JSON.parse(Keylol_defaultTasks); undoneTasks = JSON.parse(Keylol_defaultTasks); buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect' ]; static test() { return window.location.host === 'keylol.com' && (!!$('.subforum_left_title_left_up a').eq(3).attr('href')?.includes('319') || !!$('.subforum_left_title_left_up a').eq(3).attr('href')?.includes('234')); } init() { return true; } after() { try { const selector = this.name === 'Keylol' ? '#postlist>div[id^="post_"]:first' : 'div.container'; const mainPost = $(selector); const discordLinks = mainPost.find('a[href*="discord.com"]:visible'); const redditLinks = mainPost.find('a[href*="reddit.com"]:visible'); const insLinks = mainPost.find('a[href*="instagram.com"]:visible'); const twitterLinks = mainPost.find('a[href*="twitter.com"]:visible,a[href*="x.com"]:visible'); const twitchLinks = mainPost.find('a[href*="twitch.tv"]:visible'); const vkLinks = mainPost.find('a[href*="vk.com"]:visible'); const steamStoreLinks = mainPost.find('a[href*="store.steampowered.com"]:visible'); const steamCommunityLinks = mainPost.find('a[href*="steamcommunity.com"]:visible'); const ytbLinks = mainPost.find('a[href*="youtube.com"]:visible'); if (discordLinks.length > 0) { for (const discordLink of discordLinks) { const link = $(discordLink).attr('href'); if (!(link && /^https?:\/\/discord\.com\/invite\/.+/.test(link))) { continue; } this.#addBtn(discordLink, 'discord', 'serverLinks', link); } } if (redditLinks.length > 0) { for (const redditLink of redditLinks) { const link = $(redditLink).attr('href'); if (!(link && /^https?:\/\/www\.reddit\.com\/(r|user)\/.+/.test(link))) { continue; } this.#addBtn(redditLink, 'reddit', 'redditLinks', link); } } if (insLinks.length > 0) { for (const insLink of insLinks) { const link = $(insLink).attr('href'); if (!(link && /^https:\/\/www\.instagram\.com\/.+/.test(link))) { continue; } this.#addBtn(insLink, 'instagram', 'userLinks', link); } } if (twitterLinks.length > 0) { for (const twitterLink of twitterLinks) { const link = $(twitterLink).attr('href'); if (!(link && /^https:\/\/twitter\.com\/.+/.test(link))) { continue; } if (/https:\/\/twitter\.com\/.*?\/status\/[\d]+/.test(link)) { this.#addBtn(twitterLink, 'twitter', 'retweetLinks', link); } else { this.#addBtn(twitterLink, 'twitter', 'userLinks', link); } } } if (twitchLinks.length > 0) { for (const twitchLink of twitchLinks) { const link = $(twitchLink).attr('href'); if (!(link && /^https:\/\/(www\.)?twitch\.tv\/.+/.test(link))) { continue; } this.#addBtn(twitchLink, 'twitch', 'channelLinks', link); } } if (vkLinks.length > 0) { for (const vkLink of vkLinks) { const link = $(vkLink).attr('href'); if (!(link && /^https:\/\/vk\.com\/.+/.test(link))) { continue; } this.#addBtn(vkLink, 'vk', 'nameLinks', link); } } if (steamStoreLinks.length > 0) { for (const steamStoreLink of steamStoreLinks) { const link = $(steamStoreLink).attr('href'); if (!link) { continue; } if (/curator\/[\d]+/.test(link)) { this.#addBtn(steamStoreLink, 'steam', 'curatorLinks', link); } else if (/(publisher|developer|franchise)\/.+/.test(link)) { this.#addBtn(steamStoreLink, 'steam', 'curatorLikeLinks', link); } else if (/news(hub)?\/app\/[\d]+\/view\/[\d]+/.test(link)) { this.#addBtn(steamStoreLink, 'steam', 'announcementLinks', link); } else if (/app\/[\d]+/.test(link)) { this.#addBtn(steamStoreLink, 'steam', 'followLinks', link); this.#addBtn(steamStoreLink, 'steam', 'wishlistLinks', link); } } } if (steamCommunityLinks.length > 0) { for (const steamCommunityLink of steamCommunityLinks) { const link = $(steamCommunityLink).attr('href'); if (!link) { continue; } if (/groups\/.+/.test(link)) { this.#addBtn(steamCommunityLink, 'steam', 'groupLinks', link); } else if (/announcements\/detail\/[\d]+/.test(link)) { this.#addBtn(steamCommunityLink, 'steam', 'announcementLinks', link); } } } if (ytbLinks.length > 0) { for (const ytbLink of ytbLinks) { const link = $(ytbLink).attr('href'); if (!link) { continue; } this.#addBtn(ytbLink, 'youtube', 'channelLinks', link); this.#addBtn(ytbLink, 'youtube', 'likeLinks', link); } } const giveawayLinks = mainPost.find('a[href*="giveaway.su/giveaway/view/"]:visible,a[href*="givee.club/"]:visible,a[href*="gleam.io/"]:visible,a[href*="www.indiedb.com/giveaways/"]:visible,a[href*="key-hub.eu/giveaway/"]:visible,a[href*="opquests.com/quests/"]:visible,a[href*="itch.io/s/"]:visible'); if (giveawayLinks.length > 0) { for (const giveawayLink of giveawayLinks) { const link = $(giveawayLink).attr('href'); if (!link) { continue; } website_leftKeyChecker.classify(link).then(status => { if (!status) { return; } if (/^Active/.test(status)) { $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status active" title="${i18n('Active')}">${status}</font>`); return; } $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status not-active" title="${i18n(status)}">${status}</font>`); }).catch(error => { throwError(error, 'keylol.after -> leftKeyChecker'); }); } } if (this.name === 'Keylol') { const asfLinks = mainPost.find('a[href^="#asf"]:visible'); if (asfLinks.length > 0) { for (const asfLink of asfLinks) { const link = $(asfLink).attr('href'); if (!link) { continue; } this.#addBtn($(`a[href="${link}"]`).after('<span style="color: #ccc; margin: 0 -5px 0 5px"> | </span>').next()[0], 'steam', 'licenseLinks', `appid-${link.replace('#asf', '')}`); } } const subLinks = mainPost.find('a[href*="steamdb.info/sub/"]:visible'); if (subLinks.length > 0) { for (const subLink of subLinks) { const link = $(subLink).attr('href'); if (!link) { continue; } const subid = link.match(/^https:\/\/steamdb\.info\/sub\/([\d]+)/)?.[1]; if (!subid) { continue; } this.#addBtn(subLink, 'steam', 'licenseLinks', `subid-${subid}`); } } const asfLinks2 = mainPost.find('.blockcode:contains("addlicense"):visible'); if (asfLinks2.length > 0) { for (const asfLink of asfLinks2) { const appid = [ ...asfLink.innerText.matchAll(/a(pp)?\/([\d]+)/g) ].map(matched => matched?.[2]).filter(id => id) || []; if (appid.length > 0) { this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `appid-${appid.join(',')}`); } const subid = asfLink.innerText.match(/[\d]+/g)?.filter(matched => !appid.includes(matched)); if (!subid || subid.length === 0) { continue; } this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `subid-${subid.join(',')}`); } } } if ($('#threadindex').length > 0) { const [ targetNode ] = $('#postlist').children('div[id^="post_"]'); const config = { childList: true }; const observer = new MutationObserver(() => { observer.disconnect(); this.after(); }); observer.observe(targetNode, config); } } catch (error) { throwError(error, 'keylol.after'); } } classifyTask(action) { try { this.socialTasks = JSON.parse(Keylol_defaultTasks); this.undoneTasks = JSON.parse(Keylol_defaultTasks); const selectedBtns = $('.auto-task-keylol[selected="selected"]:visible'); for (const btn of selectedBtns) { const button = $(btn); const social = button.attr('data-social'); const type = button.attr('data-type'); const link = button.attr('data-link'); if (!(social && type && link)) { continue; } if (action === 'do') { this.undoneTasks[social][type].push(link); } if (action === 'undo') { this.socialTasks[social][type].push(link); } } this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } return true; } catch (error) { throwError(error, 'Keylol.classifyTask'); return false; } } selectAll() { try { $('.auto-task-keylol:visible').attr('selected', 'selected'); } catch (error) { throwError(error, 'Keylol.selectAll'); } } selectNone() { try { $('.auto-task-keylol:visible').removeAttr('selected'); } catch (error) { throwError(error, 'Keylol.selectNone'); } } invertSelect() { try { $('.auto-task-keylol:visible').each((index, element) => { element.getAttribute('selected') ? element.removeAttribute('selected') : element.setAttribute('selected', 'selected'); }); } catch (error) { throwError(error, 'Keylol.invertSelect'); } } #addBtn(before, social, linkType, link) { try { $(before).after('<a href="javascript:void(0);" class="auto-task-keylol" target="_self"' + ' onclick="this.getAttribute(\'selected\') ? this.removeAttribute(\'selected\') : this.setAttribute(\'selected\', \'selected\')"' + ` data-social="${social}" data-type="${linkType}" data-link="${link}">${linkType.replace('Links', '')}</a>`); } catch (error) { throwError(error, 'keylol.addBtn'); } } } const website_Keylol = Keylol; const Opquests_defaultTasks = { steam: { groupLinks: [], wishlistLinks: [], followLinks: [], curatorLikeLinks: [] }, twitter: { userLinks: [], retweetLinks: [] } }; class Opquests extends website_Website { name = 'Opquests'; undoneTasks = { ...Opquests_defaultTasks }; buttons = [ 'doTask', 'verifyTask', 'getKey' ]; static test() { return window.location.host === 'opquests.com'; } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } const opquestsVerifyTasks = GM_getValue('opquestsVerifyTasks') || []; if (opquestsVerifyTasks.length > 0) { const taskId = opquestsVerifyTasks.pop(); GM_setValue('opquestsVerifyTasks', opquestsVerifyTasks); const [ verifyBtn ] = $(`#task_id[value="${taskId}"]`).parent().find('button[type="button"]').has('i.fa-check'); if (verifyBtn) { verifyBtn.click(); return; } this.after(); return; } if (GM_getValue('opquestsVerifyTasks')) { GM_deleteValue('opquestsVerifyTasks'); } } catch (error) { throwError(error, 'Opquests.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if ($('a[href*="/auth/redirect"]').length > 0) { window.open('/auth/redirect', '_self'); logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Opquests.init'); return false; } } async classifyTask(action) { try { if (action === 'undo') { scripts_echoLog({ text: i18n('cannotUndo') }); return false; } const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); const tasks = $('.w-full:contains("Validate") .items-center'); for (const task of tasks) { const link = $(task).find('a:contains("Open")').attr('href'); const taskDes = $(task).find('div').eq(1).text().trim(); if (!link) { continue; } if (/steamcommunity\.com\/groups\//.test(link)) { this.undoneTasks.steam.groupLinks.push(link); } else if (/store\.steampowered\.com\/app\//.test(link)) { if (/wishlist/gim.test(taskDes)) { this.undoneTasks.steam.wishlistLinks.push(link); } else if (/follow/gim.test(taskDes)) { this.undoneTasks.steam.followLinks.push(link); } } else if (/store\.steampowered\.com\/(publisher|developer|curator)\//.test(link) && /follow/gim.test(taskDes)) { this.undoneTasks.steam.curatorLikeLinks.push(link); } else if (link.includes('//x.com/') && /follow/gim.test(taskDes)) { this.undoneTasks.twitter.userLinks.push(link); } else if (link.includes('//x.com/') && link.includes('status') && /Repost/gim.test(taskDes)) { this.undoneTasks.twitter.retweetLinks.push(link); } else if (/clash\.gg/.test(link)) { scripts_echoLog({}).warning(`${i18n('unSupporttedTaskType')}: ${taskDes}(${link})`); } else { scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`); } } logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } return true; } catch (error) { throwError(error, 'Opquests.classifyTask'); return false; } } async verifyTask() { try { if (!this.initialized) { this.init(); } const tasks = $.makeArray($('.items-center').has('input[name="task_id"]')).map(ele => $(ele).find('input[name="task_id"]').val()); GM_setValue('opquestsVerifyTasks', tasks); await this.#confirm(); this.after(); return true; } catch (error) { throwError(error, 'Opquests.verifyTask'); return false; } } async #confirm() { try { const logStatus = scripts_echoLog({ html: `<li>${i18n('confirmingTask')}...<font></font></li>` }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://opquests.com/quests/${this.giveawayId}?confirm=1`, method: 'GET', nochche: true, headers: { origin: 'https://opquests.com', referer: `https://opquests.com/warning?id=${this.giveawayId}` } }); if (result === 'Success') { if (data?.status === 200) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Opquests.confirm'); return false; } } async getKey(isButton) { try { const logStatus = scripts_echoLog({ text: i18n('gettingKey') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://opquests.com/keys', method: 'GET' }); if (result === 'Success') { if (data?.responseText) { const key = $(data?.responseText).find(`div.items-center:contains("${$('h1.font-bold').text().trim().replace(' Quest', '')}")`).find('div.font-bold').next().text(); if (!key) { logStatus.error('Error: Key was not found'); if (isButton) { window.open('https://opquests.com/keys', '_self'); } return false; } logStatus.success(); scripts_echoLog({}).success(key); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Opquests.getGiveawayId'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.href.match(/quests\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId')); return false; } catch (error) { throwError(error, 'Opquests.getGiveawayId'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('a[href*="/auth/redirect"]').length > 0) { window.open('/auth/redirect', '_self'); } return true; } catch (error) { throwError(error, 'Opquests.checkLogin'); return false; } } } const website_Opquests = Opquests; const Gleam_defaultTasksTemplate = { steam: { groupLinks: [], wishlistLinks: [], followLinks: [], curatorLinks: [], curatorLikeLinks: [] }, twitter: { userLinks: [], retweetLinks: [] }, twitch: { channelLinks: [] }, discord: { serverLinks: [] }, youtube: { channelLinks: [] }, extra: { gleam: [] } }; const Gleam_defaultTasks = JSON.stringify(Gleam_defaultTasksTemplate); class Gleam extends website_Website { name = 'Gleam'; undoneTasks = JSON.parse(Gleam_defaultTasks); socialTasks = JSON.parse(Gleam_defaultTasks); buttons = [ 'doTask', 'undoTask', 'verifyTask' ]; static test() { return window.location.host === 'gleam.io'; } before() { try { unsafeWindow.confirm = () => {}; unsafeWindow.alert = () => {}; unsafeWindow.prompt = () => {}; } catch (error) { throwError(error, 'Gleam.before'); } } async after() { try { if (window.location.search.includes('8b07d23f4bfa65f9')) { const checkComplete = setInterval(() => { if ($('.entry-content .entry-method i.fa-check').length > 0) { clearInterval(checkComplete); window.close(); } }); for (const task of $('.entry-content .entry-method')) { const taskInfo = $(task).find('.user-links'); const expandInfo = $(task).find('.expandable'); const aElements = expandInfo.find('a.btn,a:contains(Continue),button:contains(Continue)'); if (aElements.length > 0) { for (const element of aElements) { const $element = $(element); const href = $element.attr('href'); $element.removeAttr('href')[0].click(); $element.attr('href', href); await delay(1e3); } } taskInfo[0].click(); await delay(1e3); } scripts_echoLog({}).warning(i18n('gleamTaskNotice')); } else if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } } catch (error) { throwError(error, 'Gleam.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if (!this.#getGiveawayId()) { return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'Gleam.init'); return false; } } async classifyTask(action) { try { const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`gleamTasks-${this.giveawayId}`)?.tasks || JSON.parse(Gleam_defaultTasks); } const tasks = $('.entry-content .entry-method'); for (const task of tasks) { const $task = $(task); if (action === 'do' && $task.find('i.fa-question').length === 0) { continue; } const socialIcon = $task.find('.icon-wrapper i'); const taskInfo = $task.find('.user-links'); const taskText = taskInfo.text().trim(); const expandInfo = $task.find('.expandable'); const aElements = expandInfo.find('a.btn'); if (aElements.length > 0) { for (const element of aElements) { const $element = $(element); const href = $element.attr('href'); $element.removeAttr('href')[0].click(); $element.attr('href', href); } } if (socialIcon.hasClass('fa-twitter') || socialIcon.hasClass('fa-x-twitter')) { const link = $task.find('a[href^="https://twitter.com/"],a[href^="https://x.com/"]').attr('href'); if (!link) { continue; } if (/follow/gi.test(taskText)) { if (action === 'undo') { this.socialTasks.twitter.userLinks.push(link); } if (action === 'do') { this.undoneTasks.twitter.userLinks.push(link); } } else if (/retweet/gim.test(taskText)) { if (action === 'undo') { this.socialTasks.twitter.retweetLinks.push(link); } if (action === 'do') { this.undoneTasks.twitter.retweetLinks.push(link); } } } else if (socialIcon.hasClass('fa-twitch')) { if (/follow/gim.test(taskText)) { const link = $task.find('a[href^="https://twitch.tv/"]').attr('href'); if (!link) { continue; } if (action === 'undo') { this.socialTasks.twitch.channelLinks.push(link); } if (action === 'do') { this.undoneTasks.twitch.channelLinks.push(link); } } } else if (socialIcon.hasClass('fa-discord')) { if (/join/gim.test(taskText)) { let link = $task.find('a[href^="https://discord.com/invite/"]').attr('href'); if (!link) { const ggLink = $task.find('a[href^="https://discord.gg/"]').attr('href')?.match(/discord\.gg\/([^/]+)/)?.[1]; if (!ggLink) { continue; } link = `https://discord.com/invite/${ggLink}`; } if (action === 'undo') { this.socialTasks.discord.serverLinks.push(link); } if (action === 'do') { this.undoneTasks.discord.serverLinks.push(link); } } } else if (socialIcon.hasClass('fa-external-link-square-alt')) { continue; } else if (socialIcon.hasClass('fa-youtube')) { if (/subscribe/gim.test(taskText)) { const link = $task.find('a[href^="https://www.youtube.com/channel/"]').attr('href'); if (!link) { continue; } if (action === 'undo') { this.socialTasks.youtube.channelLinks.push(link); } if (action === 'do') { this.undoneTasks.youtube.channelLinks.push(link); } } } else if (socialIcon.attr('class')?.includes('steam')) { if (/join.*group/gi.test(taskText)) { const link = $task.find('a[href^="https://steamcommunity.com/groups/"]').attr('href'); if (!link) { continue; } if (action === 'undo') { this.socialTasks.steam.groupLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.groupLinks.push(link); } } else if (/follow.*curator/gi.test(taskText)) { const link = $task.find('a[href^="https://store.steampowered.com/curator/"]').attr('href'); if (!link) { continue; } if (action === 'undo') { this.socialTasks.steam.curatorLinks.push(link); } if (action === 'do') { this.undoneTasks.steam.curatorLinks.push(link); } } } else if (socialIcon.hasClass('fa-bullhorn') && /Complete|Increase/gi.test(taskText)) { if (action !== 'do') { continue; } const gleamLink = await this.#getGleamLink(taskText); if (!gleamLink) { continue; } this.undoneTasks.extra.gleam.push(gleamLink); } else if (socialIcon.hasClass('fa-question') || socialIcon.hasClass('fa-reddit') || socialIcon.hasClass('fa-instagram') || socialIcon.hasClass('fa-facebook-f') || socialIcon.hasClass('fa-telegram-plane') || socialIcon.hasClass('fa-telegram') || socialIcon.hasClass('fa-vk') || socialIcon.hasClass('fa-envelope') || socialIcon.hasClass('fa-gift') || socialIcon.hasClass('fa-square-up-right') || socialIcon.hasClass('fa-gamepad-modern') || socialIcon.hasClass('fa-dollar-sign') || socialIcon.hasClass('fa-tiktok') || socialIcon.hasClass('fa-gamepad-alt') || socialIcon.hasClass('fa-shield') && taskText.includes('one of our giveaways') || socialIcon.hasClass('fa-shield') && taskText.includes('Check out') || socialIcon.hasClass('fa-shield') && taskText.includes('vloot.io')) {} else { scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskText}`); } } logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`gleamTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } catch (error) { throwError(error, 'Gleam.classifyTask'); return false; } } async extraDoTask({ gleam }) { try { const pro = []; for (const link of gleam) { pro.push(this.#doGleamTask(link)); } return Promise.all(pro).then(() => true); } catch (error) { throwError(error, 'Gleam.extraDoTask'); return false; } } async verifyTask() { try { scripts_echoLog({ text: `${i18n('verifyingTask')}...` }); const tasks = $('.entry-content .entry-method'); unsafeWindow._OxA = '_OxA'; for (const task of tasks) { if ($('[campaign-key="campaign.key"]').length > 0) { return scripts_echoLog({ text: i18n('campaign') }); } const $task = $(task); if ($task.find('i.fa-question').length === 0) { continue; } const taskInfo = $task.find('.user-links'); taskInfo[0].click(); const aElements = $task.find('.expandable').find('a.btn'); if (aElements.length > 0) { for (const element of aElements) { const $element = $(element); const href = $element.attr('href'); $element.removeAttr('href')[0].click(); $element.attr('href', href); } } unsafeWindow.$hookTimer?.setSpeed(1e3); const visitBtn = $task.find('.expandable').find('span:contains(more seconds),button:contains(more seconds)').filter(':visible'); if (visitBtn.length > 0 && unsafeWindow.$hookTimer) { const newTab = GM_openInTab('', { active: true }); await delay(1e3); newTab?.close(); window.focus(); } await delay(3e3); unsafeWindow.$hookTimer?.setSpeed(1); const expandInfo = $task.find('.expandable'); const [ input ] = expandInfo.find('input'); if (input) { const evt = new Event('input', { bubbles: true, cancelable: true, composed: true }); const valuelimit = [ ...expandInfo.text().matchAll(/"(.+?)"/g) ].at(-1)?.[1]; input.value = valuelimit || 'vloot'; input.dispatchEvent(evt); await delay(1e3); } await this.#checkSync(); const continueBtn = $task.find('.expandable').find('span:contains(Continue),button:contains(Continue)'); for (const button of continueBtn) { button.click(); await delay(500); await this.#checkSync(); } } scripts_echoLog({ text: i18n('verifiedGleamTasks') }); } catch (error) { throwError(error, 'Gleam.verifyTask'); return false; } } async #checkSync() { try { return await new Promise(resolve => { const checker = setInterval(() => { if ($('.entry-content .entry-method i.fa-sync').length === 0) { clearInterval(checker); resolve(true); } }, 500); }); } catch (error) { throwError(error, 'Gleam.checkSync'); return false; } } async #doGleamTask(link) { try { const logStatus = scripts_echoLog({ text: i18n('doingGleamTask') }); return await new Promise(resolve => { GM_openInTab(`${link}?8b07d23f4bfa65f9`, { active: true, insert: true, setParent: true }).onclose = () => { logStatus.success(); resolve(true); }; }); } catch (error) { throwError(error, 'Gleam.doGleamTask'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.pathname; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } catch (error) { throwError(error, 'Gleam.getGiveawayId'); return false; } } async #getGleamLink(title) { try { const logStatus = scripts_echoLog({ text: i18n('gettingGleamLink') }); const { result, statusText, status, data } = await tools_httpRequest({ url: 'https://www.vloot.io/api/v1/giveaways', method: 'GET', responseType: 'json' }); if (result === 'Success') { if (data?.status === 200 && data?.response?.Success === true && data?.response?.Data) { const { link } = data.response.Data.find(giveaway => title.replace(/[\s]/g, '').toLowerCase().includes(giveaway.title.replace(/[\s]/g, '').toLowerCase())) || {}; if (link) { logStatus.success(); return link; } logStatus.error(`Error:${i18n('getLinkFailed')}`); return false; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'Gleam.getGleamLink'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } const campaignString = $('div.popup-blocks-container').attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1]; if (!campaignString) { return false; } const { campaign, incentive } = JSON.parse(campaignString); const controllerString = $('div.campaign.reward').attr('ng-init')?.match(/initContestant\(([\w\W]+?)\);/)?.[1]; let ownedKey = false; if (controllerString) { if (JSON.parse(controllerString).contestant?.claims?.incentives?.[incentive.id]?.length) { ownedKey = true; } } if (campaign.banned || campaign.finished && !ownedKey || campaign.paused || new Date().getTime() < campaign.starts_at * 1e3) { await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('giveawayNotWork'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); } return true; } catch (error) { throwError(error, 'Gleam.checkLeftKey'); return false; } } } const website_Gleam = Gleam; const SweepWidget_defaultOptions = { username: '', email: '' }; class SweepWidget extends website_Website { name = 'SweepWidget'; options = { ...SweepWidget_defaultOptions, ...GM_getValue('SweepWidgetOptions') }; buttons = [ 'doTask' ]; static test() { return /^https?:\/\/sweepwidget\.com\/view\/[\d]+/.test(window.location.href); } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } } catch (error) { throwError(error, 'SweepWidget.after'); } } init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if (!this.#checkLogin()) { logStatus.warning(i18n('needLogin')); return false; } if (!this.#getGiveawayId()) { return false; } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'SweepWidget.init'); return false; } } classifyTask() { return true; } async doTask() { try { if ($('#unlock_rewards_main_wrapper').length === 0) { if ($('input[name="sw__login_name"]:visible').length > 0) { $('input[name="sw__login_name"]').val(this.options.username); } if ($('input[name="sw__login_email"]:visible').length > 0) { $('input[name="sw__login_email"]').val(this.options.email); } if ($('#sw_login_button:visible').length > 0) { $('#sw_login_button')[0].click(); } if (!await this.#checkEnter()) { return false; } } const logStatus = scripts_echoLog({ text: i18n('SweepWidgetNotice') }); const tasks = $('#sw_inner_entry_methods_l2_wrapper>div.sw_entry'); for (const task of tasks) { const $task = $(task); if ($task.find('i.fa-check:visible').length > 0) { continue; } const title = $task.find('.sw_text_inner'); title[0].click(); const aElement = $task.find('a.sw_link'); const link = aElement.attr('href'); aElement.attr('href', '#a').attr('target', '_self'); aElement[0]?.click(); await delay(300); aElement.attr('href', link).attr('target', '_blank'); $task.find('input[type="text"]').val('test'); const verifyBtn = $task.find('input.sw_verify'); if (verifyBtn.prop('disabled') === true) { title[0].click(); await delay(300); title[0].click(); await delay(300); } $task.find('input.sw_verify').removeAttr('disabled')[0]?.click(); await this.#checkFinish($task); await delay(parseInt(`${Math.random() * (3e3 - 1e3 + 1) + 1e3}`, 10)); } logStatus.success(); return true; } catch (error) { throwError(error, 'SweepWidget.doTask'); return false; } } #checkLogin() { try { if ($('#twitter_login_button').length > 0) { $('#twitter_login_button')[0].click(); } return true; } catch (error) { throwError(error, 'SweepWidget.checkLogin'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1]; if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } catch (error) { throwError(error, 'SweepWidget.getGiveawayId'); return false; } } async #checkEnter() { try { return new Promise(resolve => { const checker = setInterval(() => { if ($('#unlock_rewards_main_wrapper').length > 0) { clearInterval(checker); resolve(true); } }, 500); }); } catch (error) { throwError(error, 'SweepWidget.checkEnter'); return false; } } async #checkFinish($task) { try { return new Promise(resolve => { const checker = setInterval(() => { if ($task.find('i.fa-check:visible').length > 0 || $task.find('.sw_entry_input:visible').length === 0) { clearInterval(checker); resolve(true); } }, 500); }); } catch (error) { throwError(error, 'SweepWidget.checkFinish'); return false; } } } const website_SweepWidget = SweepWidget; const defaultWhiteList = { discord: { servers: [] }, instagram: { users: [] }, twitch: { channels: [] }, twitter: { users: [], retweets: [], likes: [] }, vk: { names: [] }, youtube: { channels: [], likes: [] }, reddit: { reddits: [] }, steam: { groups: [], officialGroups: [], wishlists: [], follows: [], forums: [], workshops: [], curators: [], workshopVotes: [], curatorLikes: [], announcements: [], licenses: [], playtests: [] } }; const link2id = async function(type) { try { const link = $('#socialLink').val(); let id = ''; switch (type) { case 'discord.servers': id = link.match(/invite\/(.+)/)?.[1] || ''; break; case 'instagram.users': id = link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1] || ''; break; case 'twitch.channels': id = link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2] || ''; break; case 'twitter.users': id = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || ''; break; case 'twitter.retweets': id = link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1] || ''; break; case 'vk.names': id = link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1] || ''; break; case 'youtube.channels': id = (await getInfo(link, 'channel'))?.params?.channelId || ''; break; case 'youtube.likes': id = (await getInfo(link, 'likeVideo'))?.params?.videoId || ''; break; case 'reddit.reddits': id = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1] || link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1] || ''; break; case 'steam.groups': id = link.match(/groups\/(.+)\/?/)?.[1] || ''; break; case 'steam.wishlists': case 'steam.follows': case 'steam.forums': id = link.match(/app\/([\d]+)/)?.[1] || ''; break; case 'steam.workshops': id = link.match(/\?id=([\d]+)/)?.[1] || ''; break; case 'steam.curators': { if (link.includes('curator')) { id = link.match(/curator\/([\d]+)/)?.[1] || ''; } else { const param = link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3); if (!param || param.length !== 2) { break; } const steam = new social_Steam(); if (await steam.init()) { id = await steam.getCuratorId(param[0], param[1]) || ''; } } } break; } return id; } catch (error) { throwError(error, 'link2id'); return i18n('getFailed', 'id'); } }; const disabledType = { steam: [ 'workshopVotes', 'curatorLikes', 'announcements' ], twitter: [ 'likes' ] }; const assignWhiteList = whiteList => { try { const newWhiteList = {}; for (const [ key, value ] of Object.entries(defaultWhiteList)) { newWhiteList[key] = { ...value, ...whiteList[key] }; } return newWhiteList; } catch (error) { throwError(error, 'assignWhiteList'); return defaultWhiteList; } }; const whiteListOptions = function(showType) { try { const whiteList = assignWhiteList(GM_getValue('whiteList') || {}); let whiteListOptionsForm = `<form id="whiteListForm" class="auto-task-form"> <table class="auto-task-table"><thead><tr><td>${i18n('website')}</td><td>${i18n('type')}</td><td>${i18n('edit')}</td></tr></thead><tbody>`; for (const [ social, types ] of Object.entries(whiteList)) { whiteListOptionsForm += Object.keys(types).map((type, index) => disabledType[social]?.includes(type) ? '' : `<tr style="background-color: ${stringToColour(social)}66">${index === 0 ? `<th rowspan="${Object.keys(types).length - (disabledType[social] || []).length}" style="background-color: ${stringToColour(social)}66">${social}</th>` : ''}<td>${i18n(type)}</td><td><button type="button" class="editWhiteList" data-value="${social}.${type}">${i18n('edit')}</button></td></tr>`).join(''); } whiteListOptionsForm += '</tbody></table></form>'; if (showType === 'swal') { external_Swal_default().fire({ title: i18n('whiteListOptions'), html: whiteListOptionsForm, showConfirmButton: false, showCloseButton: true }); } else { $('body').append(`<h2>${i18n('whiteList')}</h2>${whiteListOptionsForm}`); } $('.editWhiteList').on('click', function() { const value = $(this).attr('data-value'); if (!value) { return; } const [ social, type ] = value.split('.'); if (!whiteList?.[social]?.[type]) { scripts_echoLog({}).warning(i18n('whiteListNotFound', value)); return; } external_Swal_default().fire({ title: i18n('changeWhiteListOption', value), input: 'textarea', html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id"> <button id="link2id" data-type="${value}" class="swal2-confirm swal2-styled">获取id</button> <p style="margin-bottom:0 !important;">在下方填写白名单,每行一个</p>`, inputValue: whiteList[social][type].join('\n'), showConfirmButton: true, confirmButtonText: i18n('save'), showCancelButton: true, cancelButtonText: i18n('close'), showDenyButton: true, denyButtonText: i18n('return') }).then(({ isDenied, isConfirmed, value }) => { if (isDenied) { if (showType === 'swal') { whiteListOptions(showType); } return; } else if (isConfirmed) { whiteList[social][type] = value.split('\n'); GM_setValue('whiteList', whiteList); external_Swal_default().fire({ title: i18n('changeWhiteListSuccess'), icon: 'success' }); } }); $('#link2id').on('click', async function() { const type = $(this).attr('data-type'); $('#socialLink').val(await link2id(type)); }); }); } catch (error) { throwError(error, 'whiteListOptions'); } }; const whiteList = whiteListOptions; const setGistData = async (token, gistId, fileName, content) => { try { const logStatus = scripts_echoLog({ text: i18n('settingData') }); const contentData = JSON.stringify({ files: { [fileName]: { content: JSON.stringify(content) } } }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://api.github.com/gists/${gistId}`, headers: { Accept: 'application/vnd.github.v3+json', Authorization: `token ${token}` }, data: contentData, responseType: 'json', method: 'POST', timeout: 3e4 }); if (result === 'Success') { if (data?.status === 200 && data.response.files?.[fileName]?.content === JSON.stringify(content)) { logStatus.success(); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'setGistData'); return false; } }; const getGistData = async (token, gistId, fileName, test = false) => { try { const logStatus = scripts_echoLog({ text: i18n('gettingData') }); const { result, statusText, status, data } = await tools_httpRequest({ url: `https://api.github.com/gists/${gistId}`, headers: { Accept: 'application/vnd.github.v3+json', Authorization: `token ${token}` }, responseType: 'json', method: 'GET', timeout: 3e4 }); if (result === 'Success') { if (data?.status === 200) { const content = data.response?.files?.[fileName]?.content; let formatedContent; if (!content) { logStatus.error(`Error:${i18n('noRemoteData')}`); return false; } if (test) { logStatus.success(); return true; } try { formatedContent = JSON.parse(content); } catch (error) { logStatus.error(`Error:${i18n('errorRemoteDataFormat')}`); return false; } logStatus.success(); return formatedContent; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'getGistData'); return false; } }; const syncOptions = () => { try { const { TOKEN, GIST_ID, FILE_NAME, SYNC_HISTORY } = GM_getValue('gistOptions') || { TOKEN: '', GIST_ID: '', FILE_NAME: '', SYNC_HISTORY: true }; external_Swal_default().fire({ title: i18n('gistOptions'), html: `<p>Github Token<input id="github-token" class="swal2-input" placeholder="Github Token" value="${TOKEN}"></p>` + `<p>Gist ID<input id="gist-id" class="swal2-input" placeholder="Gist ID" value="${GIST_ID}"></p>` + `<p>${i18n('fileName')}<input id="file-name" class="swal2-input" placeholder="${i18n('fileName')}" value="${FILE_NAME}"></p>` + '<p><label for="sync-history" class="swal2-checkbox-custom" style="display: flex;">' + `<input id="sync-history" type="checkbox"${SYNC_HISTORY ? ' checked="checked"' : ''}/>` + `<span class="swal2-label">${i18n('syncHistory')}</span></label></p>` + `<p><button id="upload-data" type="button" class="swal2-confirm swal2-styled" style="display: inline-block;"> ${i18n('upload2gist')}</button>` + `<button id="download-data" type="button" class="swal2-confirm swal2-styled" style="display: inline-block;"> ${i18n('downloadFromGist')}</button></p>`, focusConfirm: false, showLoaderOnConfirm: true, footer: `<a href="https://auto-task-doc.js.org/guide/#%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5" target="_blank">${i18n('help')}</a>`, preConfirm: async () => { const token = $('#github-token').val(); const gistId = $('#gist-id').val(); const fileName = $('#file-name').val(); const syncHistory = $('#sync-history').prop('checked'); GM_setValue('gistOptions', { TOKEN: token, GIST_ID: gistId, FILE_NAME: fileName, SYNC_HISTORY: syncHistory }); return await getGistData(token, gistId, fileName, true); }, allowOutsideClick: () => !external_Swal_default().isLoading(), confirmButtonText: i18n('saveAndTest'), showCancelButton: true, cancelButtonText: i18n('close') }).then(({ value }) => { if (value) { external_Swal_default().fire({ icon: 'success', title: i18n('testSuccess') }).then(syncOptions); } else if (value !== undefined) { external_Swal_default().fire({ icon: 'error', title: i18n('testFailed') }).then(syncOptions); } }); $('#upload-data').on('click', async () => { const { TOKEN, GIST_ID, FILE_NAME } = GM_getValue('gistOptions') || {}; if (!(TOKEN && GIST_ID && FILE_NAME)) { return external_Swal_default().fire({ icon: 'error', title: i18n('saveAndTestNotice') }).then(syncOptions); } external_Swal_default().fire({ icon: 'info', title: i18n('processingData') }); const data = {}; const names = GM_listValues(); const SYNC_HISTORY = $('#sync-history').prop('checked'); for (const name of names) { if (name === 'gistOptions' || /^[\w]+?Auth$/.test(name)) { continue; } if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) { continue; } data[name] = GM_getValue(name); } external_Swal_default().update({ icon: 'info', title: i18n('updatingData') }); if (await setGistData(TOKEN, GIST_ID, FILE_NAME, data)) { external_Swal_default().fire({ icon: 'success', title: i18n('syncDataSuccess') }); } else { external_Swal_default().fire({ icon: 'error', title: i18n('syncDataFailed') }); } }); $('#download-data').on('click', async () => { const { TOKEN, GIST_ID, FILE_NAME } = GM_getValue('gistOptions') || {}; if (!(TOKEN && GIST_ID && FILE_NAME)) { return external_Swal_default().fire({ icon: 'error', title: i18n('saveAndTestNotice') }).then(syncOptions); } external_Swal_default().fire({ icon: 'info', title: i18n('downloadingData') }); const data = await getGistData(TOKEN, GIST_ID, FILE_NAME); if (!data) { return external_Swal_default().fire({ icon: 'error', title: i18n('checkedNoData') }).then(syncOptions); } external_Swal_default().update({ icon: 'info', title: i18n('savingData') }); const SYNC_HISTORY = $('#sync-history').prop('checked'); for (const [ name, value ] of Object.entries(data)) { if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) { continue; } GM_setValue(name, value); } external_Swal_default().fire({ icon: 'success', title: i18n('syncDataSuccess') }); }); } catch (error) { throwError(error, 'syncOptions'); } }; const dataSync = syncOptions; class Setting { name = 'Setting'; buttons = [ 'saveGlobalOptions', 'syncData', 'tasksHistory' ]; syncData = dataSync; tasksHistory() { GM_openInTab('https://auto-task-v4.hclonely.com/history.html', { active: true }); } static test() { return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/setting.html'; } before() { try { $('body').html('').addClass('auto-task-options'); } catch (error) { throwError(error, 'Setting.before'); } } after() { try { this.#environment(); changeGlobalOptions('page'); whiteList('page'); $('input[name="other.twitterVerifyId"]').after(`<button id="getTwitterUserId" type="button">${i18n('getTwitterUserId')}</button>`); $('#getTwitterUserId').on('click', () => { this.#getId('twitterUser'); }); $('input[name="other.youtubeVerifyChannel"]').after(`<button id="getYoutubeChannelId" type="button">${i18n('getYoutubeChannelId')}</button>`); $('#getYoutubeChannelId').on('click', () => { this.#getId('youtubeChannel'); }); $('input[name^="position"]').on('input', function() { const type = $(this).attr('name').replace('position.', ''); const xLabel = 'rightleft'; const yLabel = 'topbottpm'; switch (type) { case 'buttonSideX': case 'buttonSideY': case 'buttonDistance': { const distance = $('input[name="position.buttonDistance"]').val(); const sideX = $('input[name="position.buttonSideX"]').val(); const sideY = $('input[name="position.buttonSideY"]').val(); if (![ 'right', 'left' ].includes(sideX)) { break; } if (![ 'top', 'bottom' ].includes(sideY)) { break; } if (!/^[\d]+?,[\d]+$/.test(distance)) { break; } const distanceArr = distance.split(','); $('#auto-task-buttons').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), ''); break; } case 'showButtonSideX': case 'showButtonSideY': case 'showButtonDistance': { const distance = $('input[name="position.showButtonDistance"]').val(); const sideX = $('input[name="position.showButtonSideX"]').val(); const sideY = $('input[name="position.showButtonSideY"]').val(); if (![ 'right', 'left' ].includes(sideX)) { break; } if (![ 'top', 'bottom' ].includes(sideY)) { break; } if (!/^[\d]+?,[\d]+$/.test(distance)) { break; } const distanceArr = distance.split(','); $('div.show-button-div').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), ''); break; } case 'logSideX': case 'logSideY': case 'logDistance': { const distance = $('input[name="position.logDistance"]').val(); const sideX = $('input[name="position.logSideX"]').val(); const sideY = $('input[name="position.logSideY"]').val(); if (![ 'right', 'left' ].includes(sideX)) { break; } if (![ 'top', 'bottom' ].includes(sideY)) { break; } if (!/^[\d]+?,[\d]+$/.test(distance)) { break; } const distanceArr = distance.split(','); $('#auto-task-info').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), ''); break; } default: break; } }); $('input[name^="hotKey"]').attr('readonly', 'readonly').off('keydown').on('keydown', function(event) { let functionKey = ''; if (event.altKey) { functionKey += 'alt + '; } else if (event.ctrlKey) { functionKey += 'ctrl + '; } else if (event.shiftKey) { functionKey += 'shift + '; } $(this).val(functionKey + (event.key.length === 1 ? event.key.toLowerCase() : '')); }); } catch (error) { throwError(error, 'Setting.after'); } } saveGlobalOptions() { try { saveData(); } catch (error) { throwError(error, 'Setting.saveGlobalOptions'); } } #getId(social) { try { external_Swal_default().fire({ title: i18n('getId', i18n(social)), html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id"> <button id="link2id" data-type="${social}" class="swal2-confirm swal2-styled">获取id</button>`, showCancelButton: true, cancelButtonText: i18n('close'), showConfirmButton: false }); $('#link2id').on('click', async function() { const link = $('#socialLink').val(); if (!link) { return; } const type = $(this).attr('data-type'); if (type === 'twitterUser') { const name = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || link; $('#socialLink').val(await new social_Twitter().userName2id(name) || ''); } else if (type === 'youtubeChannel') { const name = /^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www.youtube.com\/.*/.test(link) ? link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1] : link; $('#socialLink').val((await getInfo(name, 'channel'))?.params?.channelId || ''); } }); } catch (error) { throwError(error, 'Setting.getId'); } } #environment() { try { const userAgent = (0, javascript_utils_umd_min.ua)(); const environmentForm = `<form id="environmentForm" class="auto-task-form"> <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('name')}</td><td>${i18n('version')}</td></tr></thead><tbody> <tr><td>${i18n('os')}</td><td>${userAgent.os}</td><td>${userAgent.osVersion}</td></tr> <tr><td>${i18n('browser')}</td><td>${userAgent.browserZH}</td><td>${userAgent.browserVersion}</td></tr> <tr><td>${i18n('scriptManager')}</td><td>${GM_info.scriptHandler}</td><td>${GM_info.version}</td></tr> <tr><td>${i18n('script')}</td><td>${GM_info.script.name}</td><td>${GM_info.script.version}</td></tr> </tbody></table></form>`; $('body').append(`<h2>${i18n('environment')}</h2>${environmentForm}`); } catch (error) { throwError(error, 'Setting.environment'); } } } const website_Setting = Setting; class History extends website_Keylol { name = 'History'; buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect', 'clearHistory' ]; static test() { return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/history.html'; } before() { try { $('body').html('<div class="container"></div>').addClass('auto-task-history'); const data = GM_listValues() || []; const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value); for (const item of tasksHistory) { this.#addItem(item); } } catch (error) { throwError(error, 'History.before'); } } clearHistory() { try { const data = GM_listValues() || []; const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value); for (const item of tasksHistory) { GM_deleteValue(item); } external_Swal_default().fire({ title: i18n('clearHistoryFinished'), icon: 'success' }); } catch (error) { throwError(error, 'History.clearHistory'); } } #addItem(item) { try { const tasksData = GM_getValue(item); if (!tasksData?.tasks) { return; } let html = ''; let title = ''; let link = ''; const [ website, id ] = item.split('-'); switch (website) { case 'fawTasks': title = `Freeanywhere[${id}]`; link = `https://freeanywhere.net/#/giveaway/${id}`; break; case 'gasTasks': title = `Giveawaysu[${id}]`; link = `https://giveaway.su/giveaway/view/${id}`; break; case 'gcTasks': title = `GiveeClub[${id}]`; link = `https://givee.club/event/${id}`; break; case 'gkTasks': title = `Givekey[${id}]`; link = `https://givekey.ru/giveaway/${id}`; break; case 'gleamTasks': title = `Gleam[${id}]`; link = `https://gleam.io${id}`; break; case 'khTasks': title = `keyhub[${id}]`; link = `https://key-hub.eu/giveaway/${id}`; break; case 'prysTasks': title = `Prys[${id}]`; link = `https://prys.revadike.com/giveaway/?id=${id}`; break; default: return; } for (const [ social, types ] of Object.entries(tasksData.tasks)) { for (const [ type, tasks ] of Object.entries(types)) { for (const task of tasks) { html += `<li><font class="auto-task-capitalize">${social}.${i18n(type.replace('Link', ''))}: </font><a href="${task}" target="_blank">${task.length > 55 ? `${task.slice(0, 55)}...` : task}</a></li>`; } } } $('.container').append(`<div class="card" data-name="${item}"><div class="title"><a href="${link}" target="_blank">${title}</a><span class="delete-task" data-name="${item}" title="${i18n('deleteTask')}"><svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2734" width="32" height="32"><path d="M607.897867 768.043004c-17.717453 0-31.994625-14.277171-31.994625-31.994625L575.903242 383.935495c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 351.94087C639.892491 753.593818 625.61532 768.043004 607.897867 768.043004z" p-id="2735" fill="#d81e06"></path><path d="M415.930119 768.043004c-17.717453 0-31.994625-14.277171-31.994625-31.994625L383.935495 383.935495c0-17.717453 14.277171-31.994625 31.994625-31.994625 17.717453 0 31.994625 14.277171 31.994625 31.994625l0 351.94087C447.924744 753.593818 433.647573 768.043004 415.930119 768.043004z" p-id="2736" fill="#d81e06"></path><path d="M928.016126 223.962372l-159.973123 0L768.043004 159.973123c0-52.980346-42.659499-95.983874-95.295817-95.983874L351.94087 63.989249c-52.980346 0-95.983874 43.003528-95.983874 95.983874l0 63.989249-159.973123 0c-17.717453 0-31.994625 14.277171-31.994625 31.994625s14.277171 31.994625 31.994625 31.994625l832.032253 0c17.717453 0 31.994625-14.277171 31.994625-31.994625S945.73358 223.962372 928.016126 223.962372zM319.946246 159.973123c0-17.545439 14.449185-31.994625 31.994625-31.994625l320.806316 0c17.545439 0 31.306568 14.105157 31.306568 31.994625l0 63.989249L319.946246 223.962372 319.946246 159.973123 319.946246 159.973123z" p-id="2737" fill="#d81e06"></path><path d="M736.048379 960.010751 288.123635 960.010751c-52.980346 0-95.983874-43.003528-95.983874-95.983874L192.139761 383.591466c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 480.435411c0 17.717453 14.449185 31.994625 31.994625 31.994625l448.096758 0c17.717453 0 31.994625-14.277171 31.994625-31.994625L768.215018 384.795565c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 479.231312C832.032253 916.835209 789.028725 960.010751 736.048379 960.010751z" p-id="2738" fill="#d81e06"></path></svg></span></div><ul>${html}</ul><span class="time">${i18n('lastChangeTime')}: ${external_dayjs_namespaceObject(tasksData.time).format('YYYY-MM-DD HH:mm:ss')}</span></div>`); $('span.delete-task').on('click', function() { const itemName = $(this).attr('data-name'); if (itemName) { GM_deleteValue(itemName); $(`div.card[data-name="${itemName}"]`).remove(); external_Swal_default().fire({ title: i18n('clearTaskFinished'), text: itemName, icon: 'success' }); } else { external_Swal_default().fire({ title: i18n('clearTaskFailed'), icon: 'error' }); } }); } catch (error) { throwError(error, 'History.addItem'); } } } const website_History = History; const GiveawayHopper_defaultTasksTemplate = { steam: { groupLinks: [], wishlistLinks: [], followLinks: [], curatorLinks: [], curatorLikeLinks: [] }, twitter: { userLinks: [], retweetLinks: [] }, twitch: { channelLinks: [] }, discord: { serverLinks: [] }, youtube: { channelLinks: [] }, extra: { giveawayHopper: [] } }; const GiveawayHopper_defaultTasks = JSON.stringify(GiveawayHopper_defaultTasksTemplate); class GiveawayHopper extends website_Website { name = 'GiveawayHopper'; undoneTasks = JSON.parse(GiveawayHopper_defaultTasks); socialTasks = JSON.parse(GiveawayHopper_defaultTasks); tasks = []; buttons = [ 'doTask', 'undoTask', 'verifyTask' ]; static test() { return window.location.host === 'giveawayhopper.com'; } async after() { try { if (!this.#checkLogin()) { scripts_echoLog({}).warning(i18n('checkLoginFailed')); } this.#getGiveawayId(); } catch (error) { throwError(error, 'GiveawayHopper.after'); } } async init() { try { const logStatus = scripts_echoLog({ text: i18n('initing') }); if (!await this.#checkLeftKey()) { scripts_echoLog({}).warning(i18n('checkLeftKeyFailed')); } this.initialized = true; logStatus.success(); return true; } catch (error) { throwError(error, 'GiveawayHopper.init'); return false; } } async classifyTask(action) { try { if (!this.giveawayId) { await this.#getGiveawayId(); } const logStatus = scripts_echoLog({ text: i18n('getTasksInfo') }); if (action === 'undo') { this.socialTasks = GM_getValue(`giveawayHopperTasks-${this.giveawayId}`)?.tasks || JSON.parse(GiveawayHopper_defaultTasks); } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/with-auth`, method: 'GET', responseType: 'json', fetch: true, headers: { authorization: `Bearer ${window.sessionStorage.gw_auth}`, 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]) } }); if (result === 'Success') { if (data?.status === 200 && data?.response?.tasks) { this.tasks = data.response.tasks; for (const task of data.response.tasks) { if (task.isDone) { continue; } await tools_httpRequest({ url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/visited`, method: 'GET', responseType: 'json', fetch: true, headers: { authorization: `Bearer ${window.sessionStorage.gw_auth}`, 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]) } }); if (task.category === 'Steam' && task.type === 'JoinGroup') { const steamGroupLink = await getRedirectLink(`https://steamcommunity.com/gid/${task.group_id}`); if (!steamGroupLink) { continue; } if (action === 'undo') { this.socialTasks.steam.groupLinks.push(steamGroupLink); } if (action === 'do') { this.undoneTasks.steam.groupLinks.push(steamGroupLink); } continue; } if (task.category === 'Discord' && task.type === 'JoinServer') { if (action === 'undo') { this.socialTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`); } if (action === 'do') { this.undoneTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`); } continue; } if ([ 'TikTok', 'YouTube', 'General' ].includes(task.category)) { continue; } scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${task.category}-${task.type}`); } logStatus.success(); this.undoneTasks = this.uniqueTasks(this.undoneTasks); this.socialTasks = this.uniqueTasks(this.socialTasks); if (window.DEBUG) { console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this)); } GM_setValue(`giveawayHopperTasks-${this.giveawayId}`, { tasks: this.socialTasks, time: new Date().getTime() }); return true; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); return false; } logStatus.error(`${result}:${statusText}(${status})`); return false; } catch (error) { throwError(error, 'GiveawayHopper.classifyTask'); return false; } } async verifyTask() { try { for (const task of this.tasks) { if (task.isDone) { continue; } const logStatus = scripts_echoLog({ text: `${i18n('verifyingTask')}[${task.displayName?.replace(':target', task.targetName) || task.name}]...` }); if (!task.link) { if (task.category === 'YouTube' && task.type === 'FollowAccount') { task.link = `https://www.youtube.com/@${task.targetName}`; } else if (task.category === 'TikTok' && task.type === 'FollowAccount') { task.link = `https://www.tiktok.com/@${task.targetName}`; } else if (task.category === 'Steam' && task.type === 'JoinGroup') { task.link = ''; } else if (task.category === 'Discord' && task.type === 'JoinServer') { task.link = ''; } } if (task.link) { await tools_httpRequest({ url: `https://giveawayhopper.com/fw?url=${encodeURIComponent(task.link)}&src=campaign&src_id=${this.giveawayId}&ref=task&ref_id=${task.id}&token=${window.sessionStorage.gw_auth}`, method: 'GET', fetch: true, headers: { authorization: `Bearer ${window.sessionStorage.gw_auth}`, 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]) } }); } await delay(1e3); const postData = { taskcategory: task.category, taskname: task.type }; if ([ 'YouTube', 'TikTok' ].includes(task.category)) { postData.username = '1'; } const { result, statusText, status, data } = await tools_httpRequest({ url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/complete`, method: 'POST', fetch: true, headers: { authorization: `Bearer ${window.sessionStorage.gw_auth}`, 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]), 'content-type': 'application/json' }, dataType: 'json', data: JSON.stringify(postData) }); if (result === 'Success') { if (data?.status === 200 && data?.response?.completed) { logStatus.success(); continue; } logStatus.error(`Error:${data?.statusText}(${data?.status})`); continue; } logStatus.error(`${result}:${statusText}(${status})`); continue; } } catch (error) { throwError(error, 'GiveawayHopper.verifyTask'); return false; } } #getGiveawayId() { try { const giveawayId = window.location.pathname.split('/').at(-1); if (giveawayId) { this.giveawayId = giveawayId; return true; } scripts_echoLog({ text: i18n('getFailed', 'GiveawayId') }); return false; } catch (error) { throwError(error, 'GiveawayHopper.getGiveawayId'); return false; } } #checkLogin() { try { if (!globalOptions.other.checkLogin) { return true; } if ($('div.widget-connections-edit:contains("Log in")').length > 0) { $('div.widget-connections-edit:contains("Log in") a')[0].click(); } return true; } catch (error) { throwError(error, 'GiveawayHopper.checkLogin'); return false; } } async #checkLeftKey() { try { if (!globalOptions.other.checkLeftKey) { return true; } if ($('p.widget-single-prize span').length > 0 && parseInt($('p.widget-single-prize span').text()?.match(/\d+/)?.[0] || '0', 10) > 0) { return true; } await external_Swal_default().fire({ icon: 'warning', title: i18n('notice'), text: i18n('noKeysLeft'), confirmButtonText: i18n('confirm'), cancelButtonText: i18n('cancel'), showCancelButton: true }).then(({ value }) => { if (value) { window.close(); } }); return true; } catch (error) { throwError(error, 'GiveawayHopper.checkLeftKey'); return false; } } } const website_GiveawayHopper = GiveawayHopper; const Websites = [ Freeanywhere, GiveawaySu, website_Indiedb, website_Keyhub, website_Givekey, website_GiveeClub, website_OpiumPulses, website_Keylol, website_Opquests, website_Gleam, website_SweepWidget, website_Setting, website_History, website_GiveawayHopper ]; const websiteOptions = function(website, options) { try { let websiteOptionsForm = `<form id="websiteOptionsForm" class="auto-task-form"> <table class="auto-task-table"><thead><tr><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`; for (const [ option, value ] of Object.entries(options)) { websiteOptionsForm += `<tr><td>${option}</td><td><input class="editOption" type="text" name="${option}" value="${value}"/></td></tr>`; } websiteOptionsForm += '</tbody></table></form>'; external_Swal_default().fire({ title: i18n('websiteOptions'), html: websiteOptionsForm, showConfirmButton: true, confirmButtonText: i18n('save'), showCancelButton: true, cancelButtonText: i18n('close') }).then(({ isConfirmed }) => { if (isConfirmed) { $('#websiteOptionsForm').serializeArray().map(value => { options[value.name] = value.value; return value; }); GM_setValue(`${website}Options`, options); external_Swal_default().fire({ title: i18n('changeWebsiteOptionsSuccess'), icon: 'success' }); } }); } catch (error) { throwError(error, 'websiteOptions'); } }; const options = websiteOptions; const external_keyboardJS_namespaceObject = keyboardJS; var external_keyboardJS_default = __webpack_require__.n(external_keyboardJS_namespaceObject); const checkUpdate = async (updateLink, auto) => { try { const checkUrl = `${updateLink}package.json?time=${new Date().getTime()}`; const { result, statusText, status, data } = await tools_httpRequest({ url: checkUrl, responseType: 'json', method: 'GET', timeout: 3e4 }); if (result === 'Success') { if (data?.response?.version) { return data.response; } if (!auto) { scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${data?.statusText}(${data?.status})]`); } return false; } if (!auto) { scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${result}:${statusText}(${status})]`); } return false; } catch (error) { throwError(error, 'checkUpdate'); return false; } }; const hasNewVersion = (currentVersion, remoteVersion) => { try { const [ currentRealVersion ] = currentVersion.split('-'); const [ remoteRealVersion, isPreview ] = remoteVersion.split('-'); if (isPreview && !globalOptions.other.receivePreview) { return false; } const [ currentVersion1, currentVersion2, currentVersion3 ] = currentRealVersion.split('.').map(value => parseInt(value, 10)); const [ remoteVersion1, remoteVersion2, remoteVersion3 ] = remoteRealVersion.split('.').map(value => parseInt(value, 10)); if (remoteVersion1 > currentVersion1) { return true; } if (remoteVersion1 < currentVersion1) { return false; } if (remoteVersion2 > currentVersion2) { return true; } if (remoteVersion2 < currentVersion2) { return false; } if (remoteVersion3 > currentVersion3) { return true; } return false; } catch (error) { throwError(error, 'compareVersion'); return false; } }; const updateChecker = async () => { try { const currentVersion = GM_info.script.version; const updateSource = globalOptions.other.autoUpdateSource.toLowerCase(); const updateLinks = { github: 'https://github.com/HCLonely/auto-task-new/raw/main/', jsdelivr: 'https://cdn.jsdelivr.net/gh/HCLonely/auto-task-v4@main/', standby: 'https://auto-task-v4.hclonely.com/' }; let version; let updateLink = ''; let packageData; if ([ 'github', 'jsdelivr', 'standby' ].includes(updateSource)) { updateLink = updateLinks[updateSource]; packageData = await checkUpdate(updateLink, false); } else { updateLink = updateLinks.github; packageData = await checkUpdate(updateLink, true); if (!packageData) { updateLink = updateLinks.jsdelivr; packageData = await checkUpdate(updateLink, true); if (!packageData) { updateLink = updateLinks.standby; packageData = await checkUpdate(updateLink, true); } } } if (packageData) { version = packageData.version || currentVersion; } else { version = currentVersion; scripts_echoLog({}).error(i18n('checkUpdateFailed')); } if (packageData && hasNewVersion(currentVersion, version)) { scripts_echoLog({ html: `<li><font>${i18n('newVersionNotice', version, `${updateLink}dist/${GM_info.script.name}.user.js`)}</font></li>` }); scripts_echoLog({ html: `<li>${i18n('updateText', version)}</li><ol class="update-text">${packageData.change?.map(change => `<li>${change}</li>`).join('')}<li>${i18n('updateHistory')}</li></ol>` }); } } catch (error) { throwError(error, 'updateChecker'); } }; const scripts_updateChecker = updateChecker; window.STYLE = GM_addStyle(auto_task.A + GM_getResourceText('style')); window.DEBUG = !!globalOptions.other?.debug; window.TRACE = !!globalOptions.other?.debug && typeof console.trace === 'function'; const loadScript = async () => { if (window.name === 'ATv4_twitchAuth' && window.location.hostname === 'www.twitch.tv') { const authToken = external_Cookies_default().get('auth-token'); const isLogin = !!external_Cookies_default().get('login'); if (isLogin) { GM_setValue('twitchAuth', { authToken: authToken, clientVersion: __twilightBuildID, clientId: commonOptions?.headers?.['Client-ID'], deviceId: commonOptions?.headers?.['Device-ID'], clientSessionId: window.localStorage.local_storage_app_session_id.replace(/"/g, '') }); window.close(); external_Swal_default().fire('', i18n('closePageNotice')); } else { external_Swal_default().fire('', i18n('needLogin')); } return; } if (window.name === 'ATv4_redditAuth' && window.location.hostname === 'www.reddit.com') { const betaButton = $('#redesign-beta-optin-btn'); if (betaButton.length > 0) { return betaButton[0].click(); } window.close(); external_Swal_default().fire('', i18n('closePageNotice')); return; } let website; for (const Website of Websites) { if (Website.test()) { website = new Website(); break; } } if (!website) { console.log('%c%s', 'color:#ff0000', 'Auto-Task[Warning]: 脚本停止加载,当前网站不支持!'); return; } if (website?.before) { await website?.before(); } $('body').append(` <div id="auto-task-info" style="display:${globalOptions.other.defaultShowLog ? 'block' : 'none'}; ${globalOptions.position.logSideX}:${globalOptions.position.logDistance.split(',')[0]}px; ${globalOptions.position.logSideY}:${globalOptions.position.logDistance.split(',')[1]}px;"> </div> <div id="auto-task-buttons" style="display:${globalOptions.other.defaultShowButton ? 'block' : 'none'}; ${globalOptions.position.buttonSideX}:${globalOptions.position.buttonDistance.split(',')[0]}px; ${globalOptions.position.buttonSideY}:${globalOptions.position.buttonDistance.split(',')[1]}px;"> </div> <div class="show-button-div" style="display:${globalOptions.other.defaultShowButton ? 'none' : 'block'}; ${globalOptions.position.showButtonSideX}:${globalOptions.position.showButtonDistance.split(',')[0]}px; ${globalOptions.position.showButtonSideY}:${globalOptions.position.showButtonDistance.split(',')[1]}px;"> <a class="auto-task-website-btn" href="javascript:void(0);" target="_self" title="${i18n('showButton')}"> </a> </div> `); $('div.show-button-div').on('click', () => { $('#auto-task-buttons').show(); $('div.show-button-div').hide(); }); const toggleLog = () => { const $this = $('#toggle-log'); const status = $this.attr('data-status'); if (status === 'show') { $('#auto-task-info').hide(); $this.attr('data-status', 'hide').text(i18n('showLog')); } else { $('#auto-task-info').show(); $this.attr('data-status', 'show').text(i18n('hideLog')); } }; external_keyboardJS_default().bind(globalOptions.hotKey.doTaskKey, () => { if (website.doTask) { website.doTask(); } }); external_keyboardJS_default().bind(globalOptions.hotKey.undoTaskKey, () => { if (website.undoTask) { website.undoTask(); } }); external_keyboardJS_default().bind(globalOptions.hotKey.toggleLogKey, toggleLog); if (website?.after) { await website?.after(); } if (website?.buttons && $('#auto-task-buttons').children().length === 0) { $('#auto-task-buttons').addClass(`${website.name}-buttons`); for (const button of website.buttons) { if (website[button]) { const btnElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">${i18n(button)}</a></p>`); btnElement.find('a.auto-task-website-btn').on('click', () => { website[button](); }); $('#auto-task-buttons').append(btnElement); } } } const hideButtonElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self"> ${i18n('hideButton')}</a></p>`); hideButtonElement.find('a.auto-task-website-btn').on('click', () => { $('#auto-task-buttons').hide(); $('div.show-button-div').show(); }); const toggleLogElement = $(`<p><a id="toggle-log" class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self" data-status="${globalOptions.other.defaultShowLog ? 'show' : 'hide'}"> ${globalOptions.other.defaultShowLog ? i18n('hideLog') : i18n('showLog')}</a></p>`); toggleLogElement.find('a.auto-task-website-btn').on('click', toggleLog); $('#auto-task-buttons').append(hideButtonElement).append(toggleLogElement); if (website?.options) { GM_registerMenuCommand(i18n('changeWebsiteOptions'), () => { options(website.name, website.options); }); } if (website.name !== 'Setting') { GM_registerMenuCommand(i18n('changeGlobalOptions'), () => { changeGlobalOptions('swal'); }); GM_registerMenuCommand(i18n('settingPage'), () => { GM_openInTab('https://auto-task-v4.hclonely.com/setting.html', { active: true }); }); } console.log('%c%s', 'color:#1bbe1a', 'Auto-Task[Load]: 脚本加载完成'); const [ v1, v2 ] = GM_info.version?.split('.') || []; if (!(parseInt(v1, 10) >= 5 && parseInt(v2, 10) >= 2)) { scripts_echoLog({}).error(i18n('versionNotMatched')); } if (!GM_getValue('notice')) { external_Swal_default().fire({ title: i18n('swalNotice'), icon: 'warning' }).then(() => { GM_openInTab(i18n('noticeLink'), { active: true }); GM_setValue('notice', new Date().getTime()); }); scripts_echoLog({ html: `<li><font class="warning">${i18n('echoNotice', i18n('noticeLink'))}</font></li>` }).font?.find('a').on('click', () => { GM_setValue('notice', new Date().getTime()); }); } scripts_updateChecker(); }; if (window.location.hostname === 'discord.com') { const LocalStorage = window.localStorage; if (window.name === 'ATv4_discordAuth') { window.localStorage.removeItem = () => true; const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, ''); if (discordAuth && discordAuth.length > 0) { GM_setValue('discordAuth', { auth: discordAuth }); window.close(); external_Swal_default().fire('', i18n('closePageNotice')); } else { external_Swal_default().fire({ text: i18n('getDiscordAuthFailed'), icon: 'error' }); } } else { const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, ''); if (discordAuth && discordAuth.length > 0) { GM_setValue('discordAuth', { auth: discordAuth }); } } } else if (window.location.hostname === 'opquests.com') { loadScript(); } else if ((window.name === 'ATv4_updateStoreAuth' || GM_getValue('ATv4_updateStoreAuth')) && window.location.host === 'store.steampowered.com') { $(() => { if ($('[data-miniprofile]').length === 0) { return; } const storeSessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1]; if (storeSessionID) { GM_deleteValue('ATv4_updateStoreAuth'); GM_setValue('steamStoreAuth', { storeSessionID: storeSessionID }); window.close(); external_Swal_default().fire('', i18n('closePageNotice')); } else { external_Swal_default().fire({ title: 'Error: Get "sessionID" failed', icon: 'error' }); } }); } else if ((window.name === 'ATv4_updateCommunityAuth' || GM_getValue('ATv4_updateCommunityAuth')) && window.location.host === 'steamcommunity.com') { $(() => { const steam64Id = document.body.innerHTML.match(/g_steamID = "(.+?)";/)?.[1]; const communitySessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1]; if (steam64Id && communitySessionID) { GM_deleteValue('ATv4_updateCommunityAuth'); GM_setValue('steamCommunityAuth', { steam64Id: steam64Id, communitySessionID: communitySessionID }); window.close(); external_Swal_default().fire('', i18n('closePageNotice')); } else { setTimeout(() => { external_Swal_default().fire({ title: 'Error: Get "sessionID" failed', icon: 'error' }); }, 3e3); } }); } else { if (window.location.hostname === 'key-hub.eu') { unsafeWindow.keyhubtracker = 1; unsafeWindow.gaData = {}; } $(loadScript); } }(); })();