auto-task-v4

自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。

  1. // ==UserScript==
  2. // @name auto-task-v4
  3. // @namespace auto-task-v4
  4. // @version 4.7.8
  5. // @description 自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。
  6. // @description:en Automatically complete the tasks of FreeAnyWhere, GiveawaySu, GiveeClub, Givekey, Gleam, Indiedb, keyhub, OpiumPulses, Opquests, SweepWidget websites.
  7. // @author HCLonely
  8. // @license MIT
  9. // @run-at document-start
  10. // @homepage https://auto-task-doc.js.org/
  11. // @supportURL https://github.com/HCLonely/auto-task-v4/issues
  12. // @icon https://auto-task-v4.hclonely.com/favicon.ico
  13.  
  14. // @include *://freeanywhere.net/*
  15. // @include *://giveaway.su/giveaway/view/*
  16. // @include *://givee.club/*/event/*
  17. // @include *://givekey.ru/giveaway/*
  18. // @include *://www.indiedb.com/giveaways*
  19. // @include *://key-hub.eu/giveaway/*
  20. // @include *://keylol.com/*
  21. // @include *://www.opiumpulses.com/giveaways
  22. // @include *://prys.revadike.com/giveaway/?id=*
  23. // @include *://opquests.com/quests/*
  24. // @include *://gleam.io/*
  25. // @include *://sweepwidget.com/view/*
  26. // @include *://giveawayhopper.com/c/*
  27.  
  28. // @include *://discord.com/*
  29. // @include *://www.twitch.tv/*
  30. // @include *://www.youtube.com/*
  31. // @include *://*.reddit.com/*
  32. // @include *://twitter.com/settings/account?k*
  33. // @include *://x.com/settings/account*
  34. // @include *://steamcommunity.com/*
  35. // @include *://store.steampowered.com/*
  36. // @include https://auto-task-v4.hclonely.com/setting.html
  37. // @include https://auto-task-v4.hclonely.com/history.html
  38.  
  39. // @grant GM_setValue
  40. // @grant GM_getValue
  41. // @grant GM_listValues
  42. // @grant GM_deleteValue
  43. // @grant GM_addStyle
  44. // @grant GM_xmlhttpRequest
  45. // @grant GM_registerMenuCommand
  46. // @grant GM_info
  47. // @grant GM_openInTab
  48. // @grant GM_setClipboard
  49. // @grant GM_getResourceText
  50. // @grant GM_cookie
  51. // @grant GM_addValueChangeListener
  52. // @grant GM_removeValueChangeListener
  53. // @grant unsafeWindow
  54. // @grant window.close
  55. // @grant window.localStorage
  56. // @grant window.sessionStorage
  57. // @grant window.focus
  58.  
  59. // @connect cdn.jsdelivr.net
  60. // @connect store.steampowered.com
  61. // @connect steamcommunity.com
  62. // @connect login.steampowered.com
  63. // @connect twitter.com
  64. // @connect x.com
  65. // @connect abs.twimg.com
  66. // @connect api.twitter.com
  67. // @connect youtube.com
  68. // @connect www.youtube.com
  69. // @connect facebook.com
  70. // @connect instagram.com
  71. // @connect vk.com
  72. // @connect twitch.tv
  73. // @connect www.twitch.tv
  74. // @connect gql.twitch.tv
  75. // @connect github.com
  76. // @connect discordapp.com
  77. // @connect discord.gg
  78. // @connect discord.com
  79. // @connect www.reddit.com
  80. // @connect oauth.reddit.com
  81. // @connect raw.githubusercontent.com
  82. // @connect t.me
  83. // @connect bit.ly
  84. // @connect giveaway.su
  85. // @connect google.com
  86. // @connect www.vloot.io
  87. // @connect givee.club
  88. // @connect gleam.io
  89. // @connect www.indiedb.com
  90. // @connect key-hub.eu
  91. // @connect opquests.com
  92. // @connect itch.io
  93. // @connect auto-task-v4.hclonely.com
  94. // @connect giveawayhopper.com
  95. // @connect *
  96. // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
  97. // @require https://cdn.jsdelivr.net/npm/js-cookie@3.0.1/dist/js.cookie.min.js
  98. // @require https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.5/runtime.min.js
  99. // @require https://cdn.jsdelivr.net/npm/js-sha1@0.6.0/src/sha1.min.js
  100. // @require https://cdn.jsdelivr.net/npm/js-sha256@0.11.0/src/sha256.min.js
  101. // @require https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js
  102. // @resource style https://cdn.jsdelivr.net/npm/sweetalert2@11.3.5/dist/sweetalert2.min.css
  103. // @require https://cdn.jsdelivr.net/npm/keyboardjs@2.6.4/dist/keyboard.min.js
  104. // @require https://cdn.jsdelivr.net/npm/dayjs@1.10.7/dayjs.min.js
  105. // @require https://bundle.run/buffer@6.0.3
  106.  
  107. // @noframes
  108. // ==/UserScript==
  109.  
  110. console.log('%c%s', 'color:blue', 'Auto-Task[Load]: 脚本开始加载');
  111. (function() {
  112. var __webpack_modules__ = {
  113. 243: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  114. 'use strict';
  115. __webpack_require__.r(__webpack_exports__);
  116. __webpack_require__.d(__webpack_exports__, {
  117. decodeBase64: function() {
  118. return decodeBase64;
  119. },
  120. encodeBase64: function() {
  121. return encodeBase64;
  122. },
  123. generateTransactionId: function() {
  124. return generateTransactionId;
  125. }
  126. });
  127. const encodeSha256 = async data => {
  128. const encoder = new TextEncoder();
  129. const dataBuffer = encoder.encode(data);
  130. const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
  131. return Array.from(new Uint8Array(hashBuffer));
  132. };
  133. const encodeBase64 = data => {
  134. let binary = '';
  135. const bytes = new Uint8Array(data);
  136. const len = bytes.byteLength;
  137. for (let i = 0; i < len; i++) {
  138. binary += String.fromCharCode(bytes[i]);
  139. }
  140. return btoa(binary).replace(/=/g, '');
  141. };
  142. const decodeBase64 = data => {
  143. const binaryString = atob(data);
  144. const len = binaryString.length;
  145. const bytes = new Uint8Array(len);
  146. for (let i = 0; i < len; i++) {
  147. bytes[i] = binaryString.charCodeAt(i);
  148. }
  149. return Array.from(bytes);
  150. };
  151. const generateTransactionId = async (method, path, key, animationKey) => {
  152. const DEFAULT_KEYWORD = 'obfiowerehiring';
  153. const ADDITIONAL_RANDOM_NUMBER = 3;
  154. const timeNow = Math.floor((Date.now() - 1682924400 * 1e3) / 1e3);
  155. const timeNowBytes = [ timeNow & 255, timeNow >> 8 & 255, timeNow >> 16 & 255, timeNow >> 24 & 255 ];
  156. const data = `${method}!${path}!${timeNow}${DEFAULT_KEYWORD}${animationKey}`;
  157. const hashBytes = await encodeSha256(data);
  158. const keyBytes = decodeBase64(key);
  159. const randomNum = Math.floor(Math.random() * 256);
  160. const bytesArr = [ ...keyBytes, ...timeNowBytes, ...hashBytes.slice(0, 16), ADDITIONAL_RANDOM_NUMBER ];
  161. const out = new Uint8Array(bytesArr.length + 1);
  162. out[0] = randomNum;
  163. bytesArr.forEach((item, index) => {
  164. out[index + 1] = item ^ randomNum;
  165. });
  166. return encodeBase64(out);
  167. };
  168. },
  169. 314: function(module) {
  170. 'use strict';
  171. module.exports = function(cssWithMappingToString) {
  172. var list = [];
  173. list.toString = function toString() {
  174. return this.map(function(item) {
  175. var content = '';
  176. var needLayer = typeof item[5] !== 'undefined';
  177. if (item[4]) {
  178. content += '@supports ('.concat(item[4], ') {');
  179. }
  180. if (item[2]) {
  181. content += '@media '.concat(item[2], ' {');
  182. }
  183. if (needLayer) {
  184. content += '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {');
  185. }
  186. content += cssWithMappingToString(item);
  187. if (needLayer) {
  188. content += '}';
  189. }
  190. if (item[2]) {
  191. content += '}';
  192. }
  193. if (item[4]) {
  194. content += '}';
  195. }
  196. return content;
  197. }).join('');
  198. };
  199. list.i = function i(modules, media, dedupe, supports, layer) {
  200. if (typeof modules === 'string') {
  201. modules = [ [ null, modules, undefined ] ];
  202. }
  203. var alreadyImportedModules = {};
  204. if (dedupe) {
  205. for (var k = 0; k < this.length; k++) {
  206. var id = this[k][0];
  207. if (id != null) {
  208. alreadyImportedModules[id] = true;
  209. }
  210. }
  211. }
  212. for (var _k = 0; _k < modules.length; _k++) {
  213. var item = [].concat(modules[_k]);
  214. if (dedupe && alreadyImportedModules[item[0]]) {
  215. continue;
  216. }
  217. if (typeof layer !== 'undefined') {
  218. if (typeof item[5] === 'undefined') {
  219. item[5] = layer;
  220. } else {
  221. item[1] = '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {').concat(item[1], '}');
  222. item[5] = layer;
  223. }
  224. }
  225. if (media) {
  226. if (!item[2]) {
  227. item[2] = media;
  228. } else {
  229. item[1] = '@media '.concat(item[2], ' {').concat(item[1], '}');
  230. item[2] = media;
  231. }
  232. }
  233. if (supports) {
  234. if (!item[4]) {
  235. item[4] = ''.concat(supports);
  236. } else {
  237. item[1] = '@supports ('.concat(item[4], ') {').concat(item[1], '}');
  238. item[4] = supports;
  239. }
  240. }
  241. list.push(item);
  242. }
  243. };
  244. return list;
  245. };
  246. },
  247. 356: function(module, __unused_webpack_exports, __webpack_require__) {
  248. const {
  249. axiosGM
  250. } = __webpack_require__(945);
  251. const {
  252. getIndices,
  253. getAnimationKey
  254. } = __webpack_require__(702);
  255. const {
  256. generateTransactionId
  257. } = __webpack_require__(243);
  258. const {
  259. decodeBase64
  260. } = __webpack_require__(243);
  261. const {
  262. never
  263. } = __webpack_require__(727);
  264. const {
  265. decodeTransactionId
  266. } = __webpack_require__(791);
  267. const createSession = async () => {
  268. const raw = await axiosGM({
  269. url: 'https://x.com',
  270. method: 'GET',
  271. responseType: 'text'
  272. });
  273. const html = raw.data;
  274. const root = $.parseHTML(`<div>${html}</div>`)[0];
  275. const content = root.querySelector('[name^=tw]')?.getAttribute('content') ?? never('No content');
  276. const verification = decodeBase64(content);
  277. const frames = root.querySelectorAll('[id^=\'loading-x-anim\']');
  278. const svgArray = svgKey(verification, frames);
  279. const indexKey = await getIndices(html);
  280. const animationKey = getAnimationKey(svgArray, verification, indexKey);
  281. return {
  282. get: (method, path) => generateTransactionId(method, path, content, animationKey.join(''))
  283. };
  284. };
  285. const svgKey = (verification, frames) => {
  286. const index = verification[5] % 4;
  287. const path = frames[index].children[0].children[1];
  288. const d = path.getAttribute('d') ?? never('No d');
  289. const sub = d.substring(9).split('C');
  290. const res = sub.map(item => {
  291. return item.replace(/[^\d]+/g, ' ').trim().split(' ').map(Number);
  292. });
  293. return res;
  294. };
  295. module.exports = {
  296. createSession: createSession,
  297. generateTransactionId: generateTransactionId,
  298. decodeTransactionId: decodeTransactionId
  299. };
  300. },
  301. 601: function(module) {
  302. 'use strict';
  303. module.exports = function(i) {
  304. return i[1];
  305. };
  306. },
  307. 675: function(module, __webpack_exports__, __webpack_require__) {
  308. 'use strict';
  309. __webpack_require__.d(__webpack_exports__, {
  310. A: function() {
  311. return __WEBPACK_DEFAULT_EXPORT__;
  312. }
  313. });
  314. var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(601);
  315. 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__);
  316. var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(314);
  317. 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__);
  318. 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());
  319. ___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}`, '' ]);
  320. const __WEBPACK_DEFAULT_EXPORT__ = ___CSS_LOADER_EXPORT___.toString();
  321. },
  322. 702: function(module, __unused_webpack_exports, __webpack_require__) {
  323. const {
  324. axiosGM
  325. } = __webpack_require__(945);
  326. const totalTime = 4096;
  327. const calculateScaledValue = (scalingFactor, baseValue, targetValue, roundToInteger) => {
  328. const result = scalingFactor * (targetValue - baseValue) / 255 + baseValue;
  329. return roundToInteger ? Math.floor(result) : Number(result.toFixed(2));
  330. };
  331. function interpolate(from, to, value) {
  332. const out = Array.from(from.length);
  333. for (let i = 0; i < from.length; i++) {
  334. out[i] = interpolateNum(from[i], to[i], value);
  335. }
  336. return out;
  337. }
  338. function interpolateNum(from, to, value) {
  339. return from * (1 - value) + to * value;
  340. }
  341. function convertRotationToMatrix(degrees) {
  342. const radians = degrees * Math.PI / 180;
  343. const c = Math.cos(radians).toFixed(6);
  344. const s = Math.sin(radians).toFixed(6);
  345. return [ c, s, -s, c, 0, 0 ];
  346. }
  347. function cubic(a, b, c, d) {
  348. if (a < 0 || a > 1 || c < 0 || c > 1) {
  349. return function(x) {
  350. return x;
  351. };
  352. }
  353. return function(x) {
  354. if (x <= 0) {
  355. var start_gradient = 0;
  356. if (a > 0) {
  357. start_gradient = b / a;
  358. } else if (!b && c > 0) {
  359. start_gradient = d / c;
  360. }
  361. return start_gradient * x;
  362. }
  363. if (x >= 1) {
  364. var end_gradient = 0;
  365. if (c < 1) {
  366. end_gradient = (d - 1) / (c - 1);
  367. } else if (c == 1 && a < 1) {
  368. end_gradient = (b - 1) / (a - 1);
  369. }
  370. return 1 + end_gradient * (x - 1);
  371. }
  372. var start = 0, end = 1;
  373. function f(a, b, m) {
  374. const _1_m = 1 - m;
  375. return 3 * a * _1_m * _1_m * m + 3 * b * _1_m * m * m + m * m * m;
  376. }
  377. while (start < end) {
  378. var mid = start + (end - start) / 2;
  379. var xEst = f(a, c, mid);
  380. if (Math.abs(x - xEst) < 1e-6) {
  381. return f(b, d, mid);
  382. }
  383. if (xEst < x) {
  384. start = mid;
  385. } else {
  386. end = mid;
  387. }
  388. }
  389. return f(b, d, mid);
  390. };
  391. }
  392. function doAnimation(numArr, frameTime) {
  393. const _cubic = cubic(...numArr.slice(7).map((n, W) => calculateScaledValue(n, W % 2 ? -1 : 0, 1, false)));
  394. const currentTime = Math.round(frameTime / 10) * 10;
  395. const cubicValue = _cubic(currentTime / totalTime);
  396. const frameColor = interpolate([ numArr[0], numArr[1], numArr[2] ], [ numArr[3], numArr[4], numArr[5] ], cubicValue);
  397. const frameRotate = interpolate([ 0 ], [ calculateScaledValue(numArr[6], 60, 360, !0) ], cubicValue);
  398. const frameMatrix = convertRotationToMatrix(frameRotate);
  399. return {
  400. color: frameColor.map(c => Math.round(c)),
  401. transform: frameMatrix.slice(0, 4).map(m => Number(Number(m).toFixed(2)))
  402. };
  403. }
  404. const getAnimationKey = (svgArray, verification, indexKey) => {
  405. const index = verification[indexKey[0]] % 16;
  406. const frameTime = verification[indexKey[1]] % 16 * (verification[indexKey[2]] % 16) * (verification[indexKey[3]] % 16);
  407. const style = doAnimation(svgArray[index], frameTime);
  408. const hexIntArray = Array.from([ style.color.length + style.transform.length + 2 ]);
  409. const hexArray = hexIntArray.map(i => i.toString(16));
  410. hexArray[7] = hexArray[8] = '0';
  411. for (let i = 0; i < 3; i++) {
  412. const numColorValue = style.color[i];
  413. if (numColorValue >= 0 && numColorValue <= 255) {
  414. hexArray[i] = numColorValue.toString(16);
  415. }
  416. if (numColorValue < 0) {
  417. hexArray[i] = '0';
  418. } else {
  419. hexArray[i] = 'ff';
  420. }
  421. }
  422. for (let i = 0; i < 4; i++) {
  423. let numMatrixValue = style.transform[i];
  424. if (numMatrixValue < 0) {
  425. numMatrixValue = -numMatrixValue;
  426. }
  427. if (numMatrixValue > 0 && numMatrixValue < 1) {
  428. hexArray[i + 3] = numMatrixValue.toString(16).replace('.', '');
  429. } else if (numMatrixValue <= 0) {
  430. hexArray[i + 3] = '0';
  431. } else {
  432. hexArray[i + 3] = '1';
  433. }
  434. }
  435. return hexArray;
  436. };
  437. const getIndices = async html => {
  438. const ON_DEMAND_FILE_REGEX = /['"](ondemand\.s)['"]:\s*['"]([\w]*)['"]/gim;
  439. const INDICES_REGEX = /\(\w\[(\d{1,2})\],\s*16\)/gim;
  440. const onDemandMatch = ON_DEMAND_FILE_REGEX.exec(html);
  441. const keyByteIndices = [];
  442. if (onDemandMatch) {
  443. const url = `https://abs.twimg.com/responsive-web/client-web/ondemand.s.${onDemandMatch[2]}a.js`;
  444. try {
  445. const {
  446. data
  447. } = await axiosGM.get(url);
  448. const matches = data.matchAll(INDICES_REGEX);
  449. for (const match of matches) {
  450. keyByteIndices.push(parseInt(match[1], 10));
  451. }
  452. } catch (error) {
  453. console.error('Failed to fetch ondemand file:', error);
  454. }
  455. }
  456. if (keyByteIndices.length < 4) {
  457. throw new Error('Couldn\'t get KEY_BYTE indices');
  458. }
  459. return keyByteIndices;
  460. };
  461. module.exports = {
  462. getIndices: getIndices,
  463. getAnimationKey: getAnimationKey
  464. };
  465. },
  466. 727: function(module) {
  467. const never = (...args) => {
  468. throw new Error(...args);
  469. };
  470. module.exports = {
  471. never: never
  472. };
  473. },
  474. 791: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  475. 'use strict';
  476. __webpack_require__.r(__webpack_exports__);
  477. __webpack_require__.d(__webpack_exports__, {
  478. decodeTransactionId: function() {
  479. return decodeTransactionId;
  480. }
  481. });
  482. const decodeTimeFromBytes = timeBytes => {
  483. const reversed = [ ...timeBytes ].reverse();
  484. const timeValue = reversed.reduce((acc, value) => acc << 8 | value, 0);
  485. const baseTime = 1682924400;
  486. return new Date((timeValue + baseTime) * 1e3);
  487. };
  488. const decodeTransactionId = transactionId => {
  489. const padded = transactionId + '='.repeat((4 - transactionId.length % 4) % 4);
  490. const binaryString = atob(padded);
  491. const decoded = new Uint8Array(binaryString.length);
  492. for (let i = 0; i < binaryString.length; i++) {
  493. decoded[i] = binaryString.charCodeAt(i);
  494. }
  495. const rand = decoded[0];
  496. const dataSection = Array.from(decoded.subarray(1)).reverse().map(byte => byte ^ rand).reverse();
  497. const keyBytes = dataSection.slice(0, 48);
  498. const timeNowBytes = dataSection.slice(48, 52);
  499. const hashBytes = dataSection.slice(52, 68);
  500. const additional = dataSection[68];
  501. return {
  502. keyBytes: keyBytes,
  503. time: decodeTimeFromBytes(timeNowBytes),
  504. hashBytes: hashBytes,
  505. additional: additional
  506. };
  507. };
  508. },
  509. 945: function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  510. 'use strict';
  511. __webpack_require__.r(__webpack_exports__);
  512. __webpack_require__.d(__webpack_exports__, {
  513. axiosGM: function() {
  514. return axiosGM;
  515. }
  516. });
  517. const parseResponseHeaders = headerStr => {
  518. const headers = {};
  519. if (!headerStr) {
  520. return headers;
  521. }
  522. headerStr.split('\r\n').forEach(line => {
  523. if (line) {
  524. const parts = line.split(':');
  525. const key = parts.shift()?.trim();
  526. const value = parts.join(':').trim();
  527. if (key) {
  528. if (key.toLowerCase() === 'set-cookie') {
  529. if (headers[key]) {
  530. if (Array.isArray(headers[key])) {
  531. headers[key].push(value);
  532. } else {
  533. headers[key] = [ headers[key], value ];
  534. }
  535. } else {
  536. headers[key] = value;
  537. }
  538. } else {
  539. headers[key] = value;
  540. }
  541. }
  542. }
  543. });
  544. return headers;
  545. };
  546. const axiosGM = function(config) {
  547. const finalConfig = {
  548. ...axiosGM.defaults,
  549. ...config
  550. };
  551. const retries = finalConfig.retry ?? 0;
  552. const retryDelay = finalConfig.retryDelay ?? 0;
  553. const requestAttempt = attempt => new Promise((resolve, reject) => {
  554. GM_xmlhttpRequest({
  555. method: finalConfig.method ? finalConfig.method.toUpperCase() : 'GET',
  556. url: finalConfig.url,
  557. headers: finalConfig.headers,
  558. data: finalConfig.data,
  559. responseType: finalConfig.responseType || 'json',
  560. timeout: finalConfig.timeout,
  561. fetch: finalConfig.fetch ?? true,
  562. onload(response) {
  563. const axiosResponse = {
  564. data: response.response || response.responseText,
  565. status: response.status,
  566. statusText: response.statusText,
  567. headers: parseResponseHeaders(response.responseHeaders),
  568. config: finalConfig,
  569. request: response
  570. };
  571. resolve(axiosResponse);
  572. },
  573. onerror(error) {
  574. if (attempt < retries) {
  575. setTimeout(() => {
  576. requestAttempt(attempt + 1).then(resolve).catch(reject);
  577. }, retryDelay);
  578. } else {
  579. reject(error);
  580. }
  581. },
  582. ontimeout() {
  583. if (attempt < retries) {
  584. setTimeout(() => {
  585. requestAttempt(attempt + 1).then(resolve).catch(reject);
  586. }, retryDelay);
  587. } else {
  588. reject('Error: timeout');
  589. }
  590. }
  591. });
  592. });
  593. return requestAttempt(0);
  594. };
  595. axiosGM.defaults = {};
  596. axiosGM.get = function(url, config = {}) {
  597. return axiosGM({
  598. ...config,
  599. url: url,
  600. method: 'GET'
  601. });
  602. };
  603. axiosGM.post = function(url, data, config = {}) {
  604. return axiosGM({
  605. ...config,
  606. url: url,
  607. data: data,
  608. method: 'POST'
  609. });
  610. };
  611. axiosGM.head = function(url, config = {}) {
  612. return axiosGM({
  613. ...config,
  614. url: url,
  615. method: 'HEAD'
  616. });
  617. };
  618. axiosGM.create = function(instanceDefaults = {}) {
  619. const instance = config => {
  620. const mergedConfig = {
  621. ...axiosGM.defaults,
  622. ...instanceDefaults,
  623. ...config
  624. };
  625. return axiosGM(mergedConfig);
  626. };
  627. instance.defaults = {
  628. ...axiosGM.defaults,
  629. ...instanceDefaults
  630. };
  631. instance.get = function(url, config = {}) {
  632. return instance({
  633. ...config,
  634. url: url,
  635. method: 'GET'
  636. });
  637. };
  638. instance.post = function(url, data, config = {}) {
  639. return instance({
  640. ...config,
  641. url: url,
  642. data: data,
  643. method: 'POST'
  644. });
  645. };
  646. instance.head = function(url, config = {}) {
  647. return instance({
  648. ...config,
  649. url: url,
  650. method: 'HEAD'
  651. });
  652. };
  653. instance.create = axiosGM.create;
  654. return instance;
  655. };
  656. },
  657. 991: function(__unused_webpack_module, exports) {
  658. !function(e, n) {
  659. true ? n(exports) : 0;
  660. }(this, function(e) {
  661. 'use strict';
  662. function l(e) {
  663. return '[object Object]' === o(e);
  664. }
  665. function n(e) {
  666. return /^\d+$/.test(e + '');
  667. }
  668. function t(e) {
  669. return /^\d+\.\d+$/.test(e + '');
  670. }
  671. var o = function(e) {
  672. return Object.prototype.toString.call(e);
  673. };
  674. var r = function() {
  675. return (r = Object.assign || function(e) {
  676. for (var n, t = 1, o = arguments.length; t < o; t++) {
  677. for (var r in n = arguments[t]) {
  678. Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r]);
  679. }
  680. }
  681. return e;
  682. }).apply(this, arguments);
  683. };
  684. function i(e, n, t) {
  685. if (t || 2 === arguments.length) {
  686. for (var o, r = 0, i = n.length; r < i; r++) {
  687. !o && r in n || ((o = o || Array.prototype.slice.call(n, 0, r))[r] = n[r]);
  688. }
  689. }
  690. return e.concat(o || Array.prototype.slice.call(n));
  691. }
  692. a.prototype.init = function() {
  693. try {
  694. this.getSystemName(), this.getBrowserName();
  695. } catch (e) {
  696. console.warn('[UA formatter error] '.concat(e));
  697. }
  698. }, a.prototype.getEngine = function() {
  699. var e = this.agent;
  700. return -1 !== e.indexOf('Trident') ? 'Trident' : -1 !== e.indexOf('Firefox') ? 'Gecko' : -1 !== e.indexOf('Presto') ? 'Presto' : 'WebKit';
  701. }, a.prototype.getSystemName = function() {
  702. var e, n = (this.agent.match(/^[a-z]+\/\d+\.\d+\s?\(([a-z\d\s:;./_-]+)\)/i) || [])[1];
  703. try {
  704. var t, o = '';
  705. if (/Windows/i.test(n)) {
  706. var r = (n.match(/NT\s(\d+\.\d+)/) || [])[1];
  707. switch (this.info.os = 'Windows', r) {
  708. case '6.3':
  709. o = '8.1';
  710. break;
  711.  
  712. case '6.2':
  713. o = '8';
  714. break;
  715.  
  716. case '6.1':
  717. o = '7';
  718. break;
  719.  
  720. case '5.2':
  721. case '5.1':
  722. o = 'XP';
  723. break;
  724.  
  725. default:
  726. o = r;
  727. }
  728. this.info.device = 'PC', this.info.osVersion = o;
  729. } else {
  730. /^Macintosh/i.test(n) ? (o = (n.match(/X\s((\d+(_|\.))+\d+)/) || [])[1],
  731. 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],
  732. this.info.os = 'iPad', this.info.device = 'Tablet', this.info.osVersion = o.replace(/_/g, '.')) : /^iPhone/i.test(n) ? (o = (n.match(/((\d+_)+\d+)/) || [])[1],
  733. 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],
  734. 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',
  735. this.info.osVersion = 'Unknown');
  736. }
  737. } catch (e) {
  738. this.info.os = 'Unknown', this.info.osVersion = 'Unknown';
  739. }
  740. }, a.prototype.getBrowserName = function() {
  741. var e = Object.keys(this.browserNameMap).map(function(e) {
  742. return new RegExp(''.concat(e, '(\\/|\\s)(\\d+\\.)+\\d+'));
  743. }), n = 1 < (n = (this.agent.match(/[a-z\d]+(\/|\s)(\d+\.)+\d+/gi) || []).filter(function(n) {
  744. return -1 !== e.findIndex(function(e) {
  745. return e.test(n);
  746. });
  747. })).length && !/^Safari/.test(n[n.length - 1]) ? n.reverse() : n;
  748. this.info = r(r({}, this.info), this._formatBrowserVersion(n[0]));
  749. }, a.prototype._formatBrowserVersion = function(e) {
  750. var n, t, o, r;
  751. try {
  752. 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++) {
  753. var l = f[u], d = l[0], h = l[1];
  754. if (new RegExp(d).test(s)) {
  755. c = h;
  756. break;
  757. }
  758. }
  759. var p = {
  760. browserVersion: null != a ? a : 'Unknown',
  761. browser: null != (o = c.en) ? o : 'Unknown',
  762. browserZH: null != (r = (null == c ? void 0 : c.zh) || c.en) ? r : 'Unknown'
  763. };
  764. return 'Trident' === s && (p.browserVersion = {
  765. '4.0': 8,
  766. '5.0': 9,
  767. '6.0': 10,
  768. '7.0': 11
  769. }[a]), p;
  770. } catch (e) {
  771. return console.warn('[UA formatter error] '.concat(e)), {
  772. browser: 'Unknown',
  773. browserVersion: 'Unknown'
  774. };
  775. }
  776. };
  777. var s = a;
  778. function a(e) {
  779. this.agent = '', this.info = {
  780. browser: '',
  781. browserZH: '',
  782. browserVersion: '',
  783. os: '',
  784. osVersion: '',
  785. device: 'Unknown',
  786. engine: 'WebKit'
  787. }, this.browserNameMap = {
  788. MicroMessenger: {
  789. en: 'MicroMessenger',
  790. zh: '微信'
  791. },
  792. MetaSr: {
  793. en: 'MetaSr',
  794. zh: '搜狗浏览器'
  795. },
  796. 'QQ(Browser)?': {
  797. en: 'QQBrowser',
  798. zh: 'QQ浏览器'
  799. },
  800. UCBrowser: {
  801. en: 'UCBrowser',
  802. zh: 'UC浏览器'
  803. },
  804. '2345Explorer': {
  805. en: '2345Explorer',
  806. zh: '2345极速浏览器'
  807. },
  808. Mb2345Browser: {
  809. en: 'Mb2345Browser',
  810. zh: '2345手机浏览器'
  811. },
  812. Trident: {
  813. en: 'Internet Explorer'
  814. },
  815. 'Edge?': {
  816. en: 'Edge'
  817. },
  818. OPR: {
  819. en: 'Opera'
  820. },
  821. Vivaldi: {
  822. en: 'Vivaldi'
  823. },
  824. Firefox: {
  825. en: 'Firefox'
  826. },
  827. Chrome: {
  828. en: 'Chrome'
  829. },
  830. Safari: {
  831. en: 'Safari'
  832. }
  833. }, this.agent = e, this.init();
  834. var e = this.info, n = e.browser, t = e.browserVersion, e = e.osVersion;
  835. this.info = r(r({}, this.info), {
  836. engine: this.getEngine(),
  837. browserVersion: 'Safari' === n ? e : t
  838. });
  839. }
  840. u.prototype.init = function() {
  841. var t;
  842. 'undefined' != typeof window && (t = {}, document.cookie.split(/;\s/).forEach(function(e) {
  843. var e = e.split(/=/), n = e[0], e = e[1];
  844. t[n] = e;
  845. }), this.cookies = t);
  846. }, u.prototype.getItem = function(e) {
  847. return this.cookies[e];
  848. }, u.prototype.getAllItems = function() {
  849. return this.cookies;
  850. }, u.prototype.setItem = function(e, n, t, o, r, i) {
  851. document.cookie = ''.concat(e, '=').concat(n).concat(t ? '; expires='.concat(t) : '').concat(o ? '; path='.concat(o) : '').concat(r ? '; domain='.concat(r) : '').concat(i ? '; secure' : '');
  852. };
  853. var c = u;
  854. function u() {
  855. this.cookies = {}, this.init();
  856. }
  857. function d(e, n) {
  858. var t = i(i([], n || [], !0), [ '_' ], !1).join('|');
  859. return e.replace(new RegExp('(('.concat(t, ')[a-z])+'), 'g'), function(e, n) {
  860. return n.replace(new RegExp(t), '').toLocaleUpperCase();
  861. });
  862. }
  863. function f(e) {
  864. return e.replace(/(-\w)/g, function(e) {
  865. return e.substr(1, 1).toUpperCase();
  866. }).replace(/^(\w)/, function(e) {
  867. return e.toUpperCase();
  868. });
  869. }
  870. e.countDown = function e(n, t, o, r) {
  871. if (!window) {
  872. throw new Error('window is not defined.');
  873. }
  874. if (0 < n) {
  875. return r && r(), n--, window[t] = window.setTimeout(function() {
  876. e(n, t, o, r);
  877. }, 1e3), function() {
  878. return clearTimeout(window[t]);
  879. };
  880. }
  881. clearTimeout(window[t]), o && o();
  882. }, e.createRandomID = function(e) {
  883. void 0 === e && (e = 12);
  884. for (var n = [], t = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), o = t.length, r = 0; r < e; r++) {
  885. n.push(t[Math.round(Math.random() * o)]);
  886. }
  887. return n.join('');
  888. }, e.dCookie = function() {
  889. return new c();
  890. }, e.debounce = function(o, r, i) {
  891. var s;
  892. return void 0 === r && (r = 0), void 0 === i && (i = !1), function() {
  893. for (var e = this, n = [], t = 0; t < arguments.length; t++) {
  894. n[t] = arguments[t];
  895. }
  896. i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() {
  897. o.apply(e, n);
  898. }, r));
  899. };
  900. }, e.debounceDecorator = function(r, i) {
  901. var s;
  902. return function(e, n, t) {
  903. var o = t.value;
  904. return t.value = function() {
  905. for (var e = this, n = [], t = 0; t < arguments.length; t++) {
  906. n[t] = arguments[t];
  907. }
  908. i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() {
  909. o.apply(e, n);
  910. }, r));
  911. }, t;
  912. };
  913. }, e.debugWarn = function(e, n) {
  914. console.warn('['.concat(e, ']: ').concat(n));
  915. }, e.deepCopy = function e(n) {
  916. if (l(n) || Array.isArray(n)) {
  917. var t, o = Array.isArray(n) ? [] : {};
  918. for (t in n) {
  919. o[t] = e(n[t]);
  920. }
  921. return o;
  922. }
  923. return n;
  924. }, e.deleteArrayItems = function(n, e, t) {
  925. return 'object' == typeof e[0] ? e.filter(function(e) {
  926. return !n.includes(e[t]);
  927. }) : e.filter(function(e) {
  928. return !n.includes(e);
  929. });
  930. }, e.formatQueryParams = function(e) {
  931. e = null == (e = /\?(?<params>(.*)=.+)/.exec(decodeURIComponent(e))) ? void 0 : e.groups;
  932. if (!e) {
  933. return {};
  934. }
  935. for (var n = e.params.split('&'), o = {}, t = 0; t < n.length; t++) {
  936. n[t].replace(/([^?&]*)=([^?&]*)/, function(e, n, t) {
  937. return o[n] = t, e;
  938. });
  939. }
  940. return o;
  941. }, e.formatThousandth = function(e) {
  942. 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, '$&,');
  943. return ''.concat(n).concat(e ? '.'.concat(e) : '');
  944. }, e.generateTree = function e(n, t, o, r) {
  945. for (var i = [], s = 0; s < n.length; s++) {
  946. var a = n[s];
  947. a[o] === t && (i.push(a), a.children = e(n, a[null != r ? r : 'id'], o, r));
  948. }
  949. return i;
  950. }, e.isBoolean = function(e) {
  951. return 'boolean' == typeof e;
  952. }, e.isEmpty = function(e) {
  953. 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);
  954. }, e.isFloatNumber = t, e.isFunction = function(e) {
  955. return '[object Function]' === o(e);
  956. }, e.isImageUrl = function(e) {
  957. return /\.((png)|(jpe?g)|(gif)|(svg)|(webp))$/gi.test(e);
  958. }, e.isInteger = n, e.isNumber = function(e) {
  959. return n(e) || t(e);
  960. }, e.isObject = l, e.isPromise = function(e) {
  961. return '[object Promise]' === o(e);
  962. }, e.isRegexp = function(e) {
  963. return '[object RegExp]' === o(e);
  964. }, e.objectKeyToCamelCase = function e(n, t, o) {
  965. if (Array.isArray(n)) {
  966. for (var r = [], i = 0; i < n.length; i++) {
  967. r[i] = e(t && n[i][t] ? n[i][t] : n[i], t, o);
  968. }
  969. } else if (l(n)) {
  970. r = {};
  971. for (var s = t && n[t] ? n[t] : n, a = 0, c = Object.entries(s); a < c.length; a++) {
  972. var u = (f = c[a])[0], f = f[1];
  973. Array.isArray(f) || l(s) ? r[d(u, o)] = e(f, t, o) : r[d(u, o)] = f;
  974. }
  975. } else {
  976. r = n;
  977. }
  978. return r;
  979. }, e.pickLastItem = function(e) {
  980. return e[e.length - 1];
  981. }, e.realType = o, e.searchParams = function(e, n) {
  982. return void 0 === e && (e = null === location || void 0 === location ? void 0 : location.search),
  983. new URLSearchParams(e).get(n);
  984. }, e.throwError = function(e, n) {
  985. throw '['.concat(f(e), ']: ').concat(n);
  986. }, e.toBoolean = function(e) {
  987. return 'true' === e || 'false' !== e && Boolean(e);
  988. }, e.toLowerCamelCase = d, e.toPascalCase = f, e.toUnderline = function(e) {
  989. return e.replace(/([A-Z])/g, function(e) {
  990. return '_'.concat(e.toLocaleLowerCase());
  991. });
  992. }, e.ua = function(e) {
  993. return void 0 === e && (e = navigator.userAgent), new s(e).info;
  994. };
  995. });
  996. }
  997. };
  998. var __webpack_module_cache__ = {};
  999. function __webpack_require__(moduleId) {
  1000. var cachedModule = __webpack_module_cache__[moduleId];
  1001. if (cachedModule !== undefined) {
  1002. return cachedModule.exports;
  1003. }
  1004. var module = __webpack_module_cache__[moduleId] = {
  1005. id: moduleId,
  1006. exports: {}
  1007. };
  1008. __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  1009. return module.exports;
  1010. }
  1011. !function() {
  1012. __webpack_require__.n = function(module) {
  1013. var getter = module && module.__esModule ? function() {
  1014. return module['default'];
  1015. } : function() {
  1016. return module;
  1017. };
  1018. __webpack_require__.d(getter, {
  1019. a: getter
  1020. });
  1021. return getter;
  1022. };
  1023. }();
  1024. !function() {
  1025. __webpack_require__.d = function(exports, definition) {
  1026. for (var key in definition) {
  1027. if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  1028. Object.defineProperty(exports, key, {
  1029. enumerable: true,
  1030. get: definition[key]
  1031. });
  1032. }
  1033. }
  1034. };
  1035. }();
  1036. !function() {
  1037. __webpack_require__.o = function(obj, prop) {
  1038. return Object.prototype.hasOwnProperty.call(obj, prop);
  1039. };
  1040. }();
  1041. !function() {
  1042. __webpack_require__.r = function(exports) {
  1043. if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  1044. Object.defineProperty(exports, Symbol.toStringTag, {
  1045. value: 'Module'
  1046. });
  1047. }
  1048. Object.defineProperty(exports, '__esModule', {
  1049. value: true
  1050. });
  1051. };
  1052. }();
  1053. var __webpack_exports__ = {};
  1054. !function() {
  1055. 'use strict';
  1056. const external_Swal_namespaceObject = Swal;
  1057. var external_Swal_default = __webpack_require__.n(external_Swal_namespaceObject);
  1058. const external_Cookies_namespaceObject = Cookies;
  1059. var external_Cookies_default = __webpack_require__.n(external_Cookies_namespaceObject);
  1060. var auto_task = __webpack_require__(675);
  1061. var javascript_utils_umd_min = __webpack_require__(991);
  1062. const httpRequest = async (options, times = 0) => {
  1063. if (window.TRACE) {
  1064. console.trace('%cAuto-Task[Debug]:', 'color:blue');
  1065. }
  1066. try {
  1067. const result = await new Promise(resolve => {
  1068. if (options.dataType) {
  1069. options.responseType = options.dataType;
  1070. }
  1071. const requestObj = {
  1072. ...{
  1073. timeout: 3e4,
  1074. ontimeout(data) {
  1075. resolve({
  1076. result: 'Error',
  1077. statusText: 'Timeout',
  1078. status: 601,
  1079. data: data,
  1080. options: options
  1081. });
  1082. },
  1083. onabort() {
  1084. resolve({
  1085. result: 'Error',
  1086. statusText: 'Aborted',
  1087. status: 602,
  1088. data: undefined,
  1089. options: options
  1090. });
  1091. },
  1092. onerror(data) {
  1093. resolve({
  1094. result: 'Error',
  1095. statusText: 'Error',
  1096. status: 603,
  1097. data: data,
  1098. options: options
  1099. });
  1100. },
  1101. onload(data) {
  1102. const headers = {};
  1103. data.responseHeaders?.split('\n').forEach(header => {
  1104. const headerArr = header.trim().split(':');
  1105. const name = headerArr.shift()?.trim() || '';
  1106. const value = headerArr.join(':').trim();
  1107. if (name && value) {
  1108. if (headers[name]) {
  1109. if (Array.isArray(headers[name])) {
  1110. headers[name].push(value);
  1111. } else {
  1112. headers[name] = [ headers[name], value ];
  1113. }
  1114. } else {
  1115. headers[name] = value;
  1116. }
  1117. }
  1118. });
  1119. if (headers['set-cookie'] && !Array.isArray(headers['set-cookie'])) {
  1120. headers['set-cookie'] = [ headers['set-cookie'] ];
  1121. }
  1122. data.responseHeadersText = data.responseHeaders;
  1123. data.responseHeaders = headers;
  1124. data.finalUrl = data.responseHeaders?.location || data.finalUrl;
  1125. if (options.responseType === 'json' && data?.response && typeof data.response !== 'object') {
  1126. try {
  1127. data.response = JSON.parse(data.responseText);
  1128. } catch (error) {}
  1129. }
  1130. resolve({
  1131. result: 'Success',
  1132. statusText: 'Load',
  1133. status: 600,
  1134. data: data,
  1135. options: options
  1136. });
  1137. }
  1138. },
  1139. ...options
  1140. };
  1141. GM_xmlhttpRequest(requestObj);
  1142. });
  1143. if (window.DEBUG) {
  1144. console.log('%cAuto-Task[httpRequest]:', 'color:blue', JSON.stringify(result));
  1145. }
  1146. if (result.status !== 600 && times < 2) {
  1147. return await httpRequest(options, times + 1);
  1148. }
  1149. return result;
  1150. } catch (error) {
  1151. console.log('%cAuto-Task[httpRequest]:', 'color:red', JSON.stringify({
  1152. errorMsg: error,
  1153. options: options
  1154. }));
  1155. throwError(error, 'httpRequest');
  1156. return {
  1157. result: 'JsError',
  1158. statusText: 'Error',
  1159. status: 604,
  1160. error: error,
  1161. options: options
  1162. };
  1163. }
  1164. };
  1165. const tools_httpRequest = httpRequest;
  1166. const echoLog = ({
  1167. type,
  1168. text,
  1169. html,
  1170. id
  1171. }) => {
  1172. const emptyStatus = {
  1173. success: () => emptyStatus,
  1174. error: () => emptyStatus,
  1175. warning: () => emptyStatus,
  1176. info: () => emptyStatus,
  1177. view: () => emptyStatus
  1178. };
  1179. try {
  1180. let ele;
  1181. if (type) {
  1182. switch (type) {
  1183. case 'joiningSteamGroup':
  1184. case 'leavingSteamGroup':
  1185. case 'gettingSteamGroupId':
  1186. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/groups/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1187. break;
  1188.  
  1189. case 'joiningSteamOfficialGroup':
  1190. case 'leavingSteamOfficialGroup':
  1191. case 'gettingSteamOfficialGroupId':
  1192. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/games/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1193. break;
  1194.  
  1195. case 'subscribingForum':
  1196. case 'unsubscribingForum':
  1197. case 'gettingForumId':
  1198. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/app/${text}/discussions/" target="_blank">${text}</a>]...<font></font></li>`);
  1199. break;
  1200.  
  1201. case 'followingCurator':
  1202. case 'unfollowingCurator':
  1203. case 'gettingCuratorId':
  1204. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/${text?.includes('/') ? text : `curator/${text}`}" target="_blank">${text}</a>]...<font></font></li>`);
  1205. break;
  1206.  
  1207. case 'addingToWishlist':
  1208. case 'removingFromWishlist':
  1209. case 'followingGame':
  1210. case 'unfollowingGame':
  1211. case 'gettingSubid':
  1212. case 'addingFreeLicense':
  1213. case 'requestingPlayTestAccess':
  1214. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/app/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1215. break;
  1216.  
  1217. case 'addingFreeLicenseSubid':
  1218. ele = $(`<li>${i18n('addingFreeLicense')}[<a href="https://steamdb.info/sub/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  1219. break;
  1220.  
  1221. case 'favoritingWorkshop':
  1222. case 'unfavoritingWorkshop':
  1223. case 'gettingWorkshopAppId':
  1224. case 'votingUpWorkshop':
  1225. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=${text}" target="_blank">
  1226. ${text}</a>]...<font></font></li>`);
  1227. break;
  1228.  
  1229. case 'gettingAnnouncementParams':
  1230. case 'likingAnnouncement':
  1231. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/news/app/${text}/view/${id}" target="_blank">
  1232. ${id}</a>]...<font></font></li>`);
  1233. break;
  1234.  
  1235. case 'joiningDiscordServer':
  1236. case 'gettingDiscordGuild':
  1237. ele = $(`<li>${i18n(type)}[<a href="https://discord.com/invite/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1238. break;
  1239.  
  1240. case 'leavingDiscordServer':
  1241. ele = $(`<li>${i18n(type)}[<a href="https://discord.com/channels/@me/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1242. break;
  1243.  
  1244. case 'updateDiscordAuth':
  1245. ele = $(`<li style="color:red;">${i18n('updateDiscordAuth')}</li>`);
  1246. break;
  1247.  
  1248. case 'followingTwitchChannel':
  1249. case 'unfollowingTwitchChannel':
  1250. case 'gettingTwitchChannelId':
  1251. ele = $(`<li>${i18n(type)}[<a href="https://www.twitch.tv/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1252. break;
  1253.  
  1254. case 'gettingInsUserId':
  1255. case 'followingIns':
  1256. case 'unfollowingIns':
  1257. ele = $(`<li>${i18n(type)}[<a href="https://www.instagram.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  1258. break;
  1259.  
  1260. case 'gettingTwitterUserId':
  1261. case 'followingTwitterUser':
  1262. case 'unfollowingTwitterUser':
  1263. ele = $(`<li>${i18n(type)}[<a href="https://x.com/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1264. break;
  1265.  
  1266. case 'retweetting':
  1267. case 'unretweetting':
  1268. ele = $(`<li>${i18n(type)}${text}...<font></font></li>`);
  1269. break;
  1270.  
  1271. case 'joiningReddit':
  1272. case 'leavingReddit':
  1273. ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/r/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  1274. break;
  1275.  
  1276. case 'followingRedditUser':
  1277. case 'unfollowingRedditUser':
  1278. ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/user/${text?.replace('u_', '')}" target="_blank">
  1279. ${text?.replace('u_', '')}</a>]...<font></font></li>`);
  1280. break;
  1281.  
  1282. case 'followingYtbChannel':
  1283. case 'unfollowingYtbChannel':
  1284. ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/channel/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1285. break;
  1286.  
  1287. case 'likingYtbVideo':
  1288. case 'unlikingYtbVideo':
  1289. ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/watch?v=${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1290. break;
  1291.  
  1292. case 'gettingVkId':
  1293. case 'joiningVkGroup':
  1294. case 'leavingVkGroup':
  1295. case 'joiningVkPublic':
  1296. case 'leavingVkPublic':
  1297. case 'sendingVkWall':
  1298. case 'deletingVkWall':
  1299. ele = $(`<li>${i18n(type)}[<a href="https://vk.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  1300. break;
  1301.  
  1302. case 'visitingLink':
  1303. ele = $(`<li>${i18n('visitingLink')}[<a href="${text}" target="_blank">${text}</a>]...<font></font></li>`);
  1304. break;
  1305.  
  1306. case 'verifyingInsAuth':
  1307. case 'text':
  1308. ele = $(`<li>${i18n(text)}<font></font></li>`);
  1309. break;
  1310.  
  1311. case 'html':
  1312. ele = $(text || html);
  1313. break;
  1314.  
  1315. case 'whiteList':
  1316. ele = $(`<li><font class="warning">${i18n('skipTask')}[${text}(${id})](${i18n('whiteList')})</font></li>`);
  1317. break;
  1318.  
  1319. case 'globalOptionsSkip':
  1320. ele = $(`<li>${i18n('skipTaskOption')}<font class="warning">${text}</font></li>`);
  1321. break;
  1322.  
  1323. default:
  1324. ele = $(`<li>${i18n('unKnown')}:${type}(${text})...<font></font></li>`);
  1325. break;
  1326. }
  1327. } else if (text) {
  1328. ele = $(`<li>${i18n(text)}<font></font></li>`);
  1329. } else if (html) {
  1330. ele = $(html);
  1331. } else {
  1332. ele = $('<li><font></font></li>');
  1333. }
  1334. ele.addClass('card-text');
  1335. $('#auto-task-info').append(ele);
  1336. ele[0]?.scrollIntoView();
  1337. const font = ele.find('font');
  1338. const status = {
  1339. font: font,
  1340. success(text = 'Success', html = false) {
  1341. this.font?.attr('class', '').addClass('success');
  1342. html ? this.font?.html(text) : this.font?.text(text);
  1343. return this;
  1344. },
  1345. error(text = 'Error', html = false) {
  1346. this.font?.attr('class', '').addClass('error');
  1347. html ? this.font?.html(text) : this.font?.text(text);
  1348. return this;
  1349. },
  1350. warning(text = 'Warning', html = false) {
  1351. this.font?.attr('class', '').addClass('warning');
  1352. html ? this.font?.html(text) : this.font?.text(text);
  1353. return this;
  1354. },
  1355. info(text = 'Info', html = false) {
  1356. this.font?.attr('class', '').addClass('info');
  1357. html ? this.font?.html(text) : this.font?.text(text);
  1358. return this;
  1359. },
  1360. view() {
  1361. this.font?.[0].scrollIntoView();
  1362. return this;
  1363. }
  1364. };
  1365. return status;
  1366. } catch (error) {
  1367. throwError(error, 'echoLog');
  1368. return emptyStatus;
  1369. }
  1370. };
  1371. const scripts_echoLog = echoLog;
  1372. const unique = array => {
  1373. try {
  1374. return [ ...new Set(array) ];
  1375. } catch (error) {
  1376. throwError(error, 'unique');
  1377. return [];
  1378. }
  1379. };
  1380. const delay = (time = 1e3) => new Promise(resolve => {
  1381. setTimeout(() => {
  1382. resolve(true);
  1383. }, time);
  1384. });
  1385. const getRedirectLink = async (link, redirectOnce = false) => {
  1386. try {
  1387. if (!link) {
  1388. return null;
  1389. }
  1390. const redirectLinksCache = GM_getValue('redirectLinks') || {};
  1391. if (redirectLinksCache[link]) {
  1392. redirectLinksCache[link];
  1393. }
  1394. return await tools_httpRequest({
  1395. url: link,
  1396. method: 'GET',
  1397. redirect: redirectOnce ? 'manual' : 'follow'
  1398. }).then(({
  1399. data
  1400. }) => {
  1401. if (data?.finalUrl) {
  1402. redirectLinksCache[link] = data.finalUrl;
  1403. GM_setValue('redirectLinks', redirectLinksCache);
  1404. return data.finalUrl;
  1405. }
  1406. return null;
  1407. });
  1408. } catch (error) {
  1409. throwError(error, 'getRedirectLink');
  1410. return null;
  1411. }
  1412. };
  1413. const visitLink = async (link, options) => {
  1414. try {
  1415. const logStatus = scripts_echoLog({
  1416. type: 'visitLink',
  1417. text: link
  1418. });
  1419. return await tools_httpRequest({
  1420. url: link,
  1421. method: 'GET',
  1422. ...options
  1423. }).then(({
  1424. result,
  1425. statusText,
  1426. status
  1427. }) => {
  1428. if (result === 'Success') {
  1429. logStatus.success();
  1430. return true;
  1431. }
  1432. logStatus.error(`${result}:${statusText}(${status})`);
  1433. return false;
  1434. });
  1435. } catch (error) {
  1436. throwError(error, 'visitLink');
  1437. return false;
  1438. }
  1439. };
  1440. const getUrlQuery = url => {
  1441. try {
  1442. const query = {};
  1443. if (url) {
  1444. if (url.includes('?')) {
  1445. url.split('?')[1].replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => {
  1446. query[key] = value;
  1447. return str;
  1448. });
  1449. }
  1450. } else {
  1451. window.location.search.replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => {
  1452. query[key] = value;
  1453. return str;
  1454. });
  1455. }
  1456. return query;
  1457. } catch (error) {
  1458. throwError(error, 'getUrlQuery');
  1459. return {};
  1460. }
  1461. };
  1462. const getUuid = () => {
  1463. const uuidUrl = URL.createObjectURL(new Blob()).toString();
  1464. return uuidUrl.slice(uuidUrl.lastIndexOf('/') + 1);
  1465. };
  1466. const stringToColour = str => {
  1467. try {
  1468. let hash = 0;
  1469. for (let i = 0; i < str.length; i++) {
  1470. hash = str.charCodeAt(i) + ((hash << 5) - hash);
  1471. }
  1472. let colour = '#';
  1473. for (let i = 0; i < 3; i++) {
  1474. const value = hash >> i * 8 & 255;
  1475. colour += `00${value.toString(16)}`.slice(-2);
  1476. }
  1477. return colour;
  1478. } catch (error) {
  1479. throwError(error, 'stringToColour');
  1480. return '#fff';
  1481. }
  1482. };
  1483. const debug = (log, data) => {
  1484. if (!window.DEBUG) {
  1485. return;
  1486. }
  1487. console.log('%c%s', 'color:#a7a7a7', `Auto-Task[Debug]: ${log}`);
  1488. if (data) {
  1489. console.log('%c%s', 'color:#a7a7a7', 'Auto-Task[Debug]: ', data);
  1490. }
  1491. };
  1492. const defaultGlobalOptions = {
  1493. doTask: {
  1494. discord: {
  1495. servers: true
  1496. },
  1497. instagram: {
  1498. users: true
  1499. },
  1500. twitch: {
  1501. channels: true
  1502. },
  1503. twitter: {
  1504. users: true,
  1505. retweets: true
  1506. },
  1507. vk: {
  1508. names: true
  1509. },
  1510. youtube: {
  1511. channels: true,
  1512. likes: true
  1513. },
  1514. reddit: {
  1515. reddits: true
  1516. },
  1517. steam: {
  1518. groups: true,
  1519. officialGroups: true,
  1520. wishlists: true,
  1521. follows: true,
  1522. forums: true,
  1523. workshops: true,
  1524. curators: true,
  1525. workshopVotes: true,
  1526. announcements: true,
  1527. licenses: true,
  1528. playtests: true
  1529. }
  1530. },
  1531. undoTask: {
  1532. discord: {
  1533. servers: true
  1534. },
  1535. instagram: {
  1536. users: true
  1537. },
  1538. twitch: {
  1539. channels: true
  1540. },
  1541. twitter: {
  1542. users: true,
  1543. retweets: true
  1544. },
  1545. vk: {
  1546. names: true
  1547. },
  1548. youtube: {
  1549. channels: true,
  1550. likes: true
  1551. },
  1552. reddit: {
  1553. reddits: true
  1554. },
  1555. steam: {
  1556. groups: true,
  1557. officialGroups: true,
  1558. wishlists: true,
  1559. follows: true,
  1560. forums: true,
  1561. workshops: true,
  1562. curators: true
  1563. }
  1564. },
  1565. ASF: {
  1566. AsfEnabled: false,
  1567. AsfIpcUrl: '',
  1568. AsfIpcPassword: '',
  1569. AsfBotname: 'asf'
  1570. },
  1571. position: {
  1572. buttonSideX: 'right',
  1573. buttonSideY: 'top',
  1574. buttonDistance: '15,30',
  1575. showButtonSideX: 'right',
  1576. showButtonSideY: 'top',
  1577. showButtonDistance: '15,30',
  1578. logSideX: 'right',
  1579. logSideY: 'bottom',
  1580. logDistance: '10,10'
  1581. },
  1582. hotKey: {
  1583. doTaskKey: 'alt + d',
  1584. undoTaskKey: 'alt + u',
  1585. toggleLogKey: 'alt + l'
  1586. },
  1587. other: {
  1588. twitterVerifyId: '783214',
  1589. youtubeVerifyChannel: 'UCrXUsMBcfTVqwAS7DKg9C0Q',
  1590. autoUpdateSource: 'jsdelivr',
  1591. language: 'zh',
  1592. checkLogin: true,
  1593. checkLeftKey: true,
  1594. defaultShowButton: true,
  1595. defaultShowLog: true,
  1596. debug: false,
  1597. receivePreview: true
  1598. }
  1599. };
  1600. const userDefinedGlobalOptions = GM_getValue('globalOptions') || {};
  1601. const assignObject = (obj1, obj2) => {
  1602. try {
  1603. const newObj = {};
  1604. for (const [ key, value ] of Object.entries(obj1)) {
  1605. if (Object.prototype.toString.call(value) === '[object Object]' && Object.prototype.toString.call(obj2[key]) === '[object Object]') {
  1606. newObj[key] = assignObject(value, obj2[key]);
  1607. } else {
  1608. newObj[key] = obj2[key] ?? value;
  1609. }
  1610. }
  1611. return newObj;
  1612. } catch (error) {
  1613. throwError(error, 'assignObject');
  1614. return defaultGlobalOptions;
  1615. }
  1616. };
  1617. const globalOptions = assignObject(defaultGlobalOptions, userDefinedGlobalOptions);
  1618. const saveData = () => {
  1619. try {
  1620. const data = {};
  1621. $('#globalOptionsForm').serializeArray().map(value => {
  1622. data[value.name] = value.value;
  1623. return value;
  1624. });
  1625. $.makeArray($('#globalOptionsForm input')).map(element => {
  1626. const name = $(element).attr('name');
  1627. const keys = name.split('.');
  1628. if (keys.length === 3) {
  1629. globalOptions[keys[0]][keys[1]][keys[2]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false;
  1630. } else if (keys.length === 2) {
  1631. globalOptions[keys[0]][keys[1]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false;
  1632. }
  1633. return element;
  1634. });
  1635. GM_setValue('globalOptions', globalOptions);
  1636. external_Swal_default().fire({
  1637. title: i18n('changeGlobalOptionsSuccess'),
  1638. icon: 'success'
  1639. });
  1640. } catch (error) {
  1641. throwError(error, 'saveData');
  1642. }
  1643. };
  1644. const changeGlobalOptions = showType => {
  1645. try {
  1646. let globalOptionsForm = `<form id="globalOptionsForm" class="auto-task-form">
  1647. <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`;
  1648. for (const [ type, data1 ] of Object.entries(globalOptions)) {
  1649. for (const [ option, data2 ] of Object.entries(data1)) {
  1650. if ([ 'other', 'position', 'hotKey', 'ASF' ].includes(type)) {
  1651. if (typeof data2 === 'boolean') {
  1652. 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>`;
  1653. } else {
  1654. 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>`;
  1655. }
  1656. } else {
  1657. for (const [ socialType, data3 ] of Object.entries(data2)) {
  1658. 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>`;
  1659. }
  1660. }
  1661. }
  1662. }
  1663. globalOptionsForm += '</tbody></table></form>';
  1664. if (showType === 'swal') {
  1665. external_Swal_default().fire({
  1666. title: i18n('globalOptions'),
  1667. html: globalOptionsForm,
  1668. showConfirmButton: true,
  1669. confirmButtonText: i18n('save'),
  1670. showCancelButton: true,
  1671. cancelButtonText: i18n('close')
  1672. }).then(({
  1673. isConfirmed
  1674. }) => {
  1675. if (isConfirmed) {
  1676. saveData();
  1677. }
  1678. });
  1679. } else {
  1680. $('body').append(`<h2>${i18n('globalOptions')}</h2>${globalOptionsForm}`);
  1681. }
  1682. } catch (error) {
  1683. throwError(error, 'changeGlobalOptions');
  1684. }
  1685. };
  1686. const data = {
  1687. website: '网站',
  1688. type: '类型',
  1689. edit: '编辑',
  1690. whiteList: '白名单',
  1691. skipTask: '跳过撤销任务',
  1692. whiteListOptions: '白名单设置',
  1693. changeWhiteListOption: '设置白名单(%0)',
  1694. whiteListNotFound: '找不到此项白名单: %0',
  1695. changeWhiteListSuccess: '白名单修改成功,刷新生效!',
  1696. changeWebsiteOptions: '网站设置',
  1697. changeGlobalOptions: '全局设置',
  1698. ok: '是',
  1699. save: '保存',
  1700. close: '关闭',
  1701. return: '返回',
  1702. option: '选项',
  1703. value: '值',
  1704. websiteOptions: '当前网站设置',
  1705. changeWebsiteOptionsSuccess: '更改当前网站设置成功,刷新生效!',
  1706. changeGlobalOptionsSuccess: '更改全局设置成功,刷新生效!',
  1707. needLogin: '请先登录!',
  1708. getTasksInfo: '正在获取并处理任务信息...',
  1709. gettingKey: '正在获取Key...',
  1710. verifyingTask: '正在验证任务',
  1711. notice: '自动任务脚本提醒',
  1712. noKeysLeft: '此页面已经没有剩余key了,是否关闭?',
  1713. giveawayEnded: '此活动已结束,是否关闭?',
  1714. giveawayNotWork: '此活动因某些原因(已结束/暂停/未开始...)不可用(如果是脚本误判请及时反馈),是否关闭?',
  1715. confirm: '确定',
  1716. cancel: '取消',
  1717. unKnown: '未知',
  1718. unKnownTaskType: '未识别的任务',
  1719. doing: '正在做任务',
  1720. allTasksComplete: '所有任务已完成!',
  1721. getTaskIdFailed: '获取任务Id失败!',
  1722. initSuccess: '%0 初始化成功!',
  1723. initFailed: '%0 初始化失败!',
  1724. errorLink: '链接错误: %0',
  1725. needInit: '请先初始化',
  1726. verifyingAuth: '正在验证%0凭证...',
  1727. updatingAuth: '正在更新%0凭证...',
  1728. refreshingToken: '正在刷新%0凭证...',
  1729. settingToken: '正在设置%0凭证...',
  1730. steamStoreTab: 'Steam商店(弹窗)',
  1731. steamCommunityTab: 'Steam社区(弹窗)',
  1732. initing: '正在初始化...',
  1733. getFailed: '获取%0失败!',
  1734. checkLoginFailed: '检测登录状态失败!',
  1735. checkLeftKeyFailed: '检测剩余Key失败!',
  1736. userId: '用户Id',
  1737. joiningGiveaway: '正在加入赠Key',
  1738. needJoinGiveaway: '需要先加入赠Key',
  1739. cannotUndo: '此网站不支持取消任务',
  1740. verifyAuth: '正在验证 %0 凭证...',
  1741. closePageNotice: '如果此页面没有自动关闭,请自行关闭本页面。',
  1742. errorReport: '检测到脚本报错,是否前往反馈BUG?',
  1743. visitingLink: '正在访问链接...',
  1744. doTask: '做任务',
  1745. undoTask: '撤销任务',
  1746. verifyTask: '验证任务',
  1747. getKey: '获取Key',
  1748. selectAll: '全选',
  1749. selectNone: '全不选',
  1750. invertSelect: '反选',
  1751. doFreeTask: '加入免费赠品',
  1752. doPointTask: '加入点数赠品',
  1753. skipTaskOption: '设置中已配置跳过任务',
  1754. other: '其他',
  1755. globalOptions: '全局设置',
  1756. checkLogin: '登录检测</br>需要登录的网站自动登录,部分网站支持',
  1757. checkLeftKey: '剩余Key检测</br>赠Key活动结束提示是否关闭,部分网站支持',
  1758. twitterVerifyId: '通过尝试关注该账号验证Twitter凭证</br>默认为Twitter官方帐号 783214</br>不想关注官方账号可以改为自己的帐号',
  1759. youtubeVerifyChannel: '通过尝试订阅该频道验证YouTube凭证</br>默认为YouTube官方频道 UCrXUsMBcfTVqwAS7DKg9C0Q</br>不想关注官方频道可以改为自己的频道',
  1760. autoUpdateSource: '更新源</br>github: 需代理,实时更新</br>jsdelivr: 可不用代理,更新有延迟</br>standby: 备用</br>auto: 依次使用github, jsdelivr, standby源进行尝试更新',
  1761. saveGlobalOptions: '保存设置',
  1762. settingPage: '设置页面',
  1763. name: '名称',
  1764. version: '版本',
  1765. scriptManager: '脚本管理器',
  1766. script: '脚本',
  1767. environment: '环境',
  1768. os: '系统',
  1769. browser: '浏览器',
  1770. getId: '获取 %0 id',
  1771. getTwitterUserId: '获取Twitter用户id(获取id功能仅在设置页面可用)',
  1772. getYoutubeChannelId: '获取Youtube频道id(获取id功能仅在设置页面可用)',
  1773. showButton: '显示按钮',
  1774. hideButton: '隐藏按钮',
  1775. showLog: '显示日志',
  1776. hideLog: '隐藏日志',
  1777. defaultShowButton: '默认显示按钮',
  1778. defaultShowLog: '默认显示日志',
  1779. debug: '输出调试日志,不要开启此选项!',
  1780. receivePreview: '接收预览版更新',
  1781. position: '组件位置',
  1782. buttonSideX: '按钮区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1783. buttonSideY: '按钮区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1784. buttonDistance: '按钮区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1785. showButtonSideX: '显示按钮水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1786. showButtonSideY: '显示按钮垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1787. showButtonDistance: '显示按钮距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1788. logSideX: '日志区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1789. logSideY: '日志区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1790. logDistance: '日志区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1791. hotKey: '快捷键',
  1792. doTaskKey: '做任务快捷键</br>(实时预览功能仅在设置页面可用)',
  1793. undoTaskKey: '撤销任务快捷键</br>(实时预览功能仅在设置页面可用)',
  1794. toggleLogKey: '显示/隐藏日志快捷键</br>(实时预览功能仅在设置页面可用)',
  1795. tasksHistory: '任务历史',
  1796. clearHistory: '清空历史',
  1797. clearHistoryFinished: '已清空任务历史!',
  1798. deleteTask: '删除任务',
  1799. lastChangeTime: '最后一次修改时间',
  1800. clearTaskFinished: '删除以下任务完成!',
  1801. clearTaskFailed: '删除任务失败,没有找到任务名!',
  1802. syncData: '数据同步',
  1803. settingData: '正在上传数据...',
  1804. gettingData: '正在获取数据...',
  1805. help: '帮助',
  1806. fileName: '文件名',
  1807. upload2gist: '同步到Gist',
  1808. downloadFromGist: '从Gist同步',
  1809. saveAndTest: '保存配置并测试',
  1810. testSuccess: '测试成功!',
  1811. testFailed: '测试失败!',
  1812. saveAndTestNotice: '请先保存配置并测试!',
  1813. processingData: '正在处理数据...',
  1814. updatingData: '正在上传数据...',
  1815. syncDataSuccess: '同步数据成功!',
  1816. syncDataFailed: '同步数据失败,请在控制台查看错误信息!',
  1817. downloadingData: '正在下载数据...',
  1818. checkedNoData: '没有检测到远程数据,请确认配置是否正确!',
  1819. savingData: '正在保存数据...',
  1820. syncHistory: '同步任务历史',
  1821. checkUpdateFailed: '检测更新失败',
  1822. newVersionNotice: '检测到新版本V%0, <a class="high-light" href="%1" target="_blank">点此更新</a>',
  1823. language: '语言</br>目前仅支持zh: 中文, en: 英文',
  1824. gistOptions: 'Gist 设置',
  1825. swalNotice: '检测到您第一次安装V4版本脚本,请前往阅读用前必读内容!',
  1826. echoNotice: '检测到您第一次安装V4版本脚本,请<a class="high-light" href="%0" target="_blank">点此前往</a>阅读用前必读内容!',
  1827. noticeLink: 'https://auto-task-doc.js.org/guide/#用前必读',
  1828. toGithub: '前往Github反馈',
  1829. toKeylol: '前往其乐论坛反馈',
  1830. copySuccess: '错误信息已复制到剪切板,是否前往其乐论坛反馈?',
  1831. copyFailed: '请复制下方错误信息后前往Keylol论坛反馈!',
  1832. updateText: '%0 版本更新内容:',
  1833. Active: '进行中',
  1834. Ended: '已结束',
  1835. Banned: '已封禁',
  1836. Paused: '已暂停',
  1837. notStart: '未开始',
  1838. noRemoteData: '检测到远程无数据',
  1839. errorRemoteDataFormat: '远程数据格式错误',
  1840. updateHistory: '历史更新记录<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">点此查看</a>',
  1841. AsfEnabled: '使用ASF做Steam相关任务(需<a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a>插件)',
  1842. AsfIpcUrl: 'ASF IPC 地址',
  1843. AsfIpcPassword: 'ASF IPC 密码',
  1844. versionNotMatched: '脚本管理器版本过低,需TamperMonkey >= 5.2.0或TamperMonkey Beta >= 5.2.6196',
  1845. groups: '组',
  1846. officialGroups: '官方组',
  1847. wishlists: '愿望单',
  1848. follows: '游戏关注',
  1849. forums: '论坛',
  1850. workshops: '创意工坊收藏',
  1851. curators: '鉴赏家',
  1852. workshopVotes: '创意工坊点赞',
  1853. announcements: '社区通知',
  1854. steamCommunity: 'Steam社区',
  1855. steamStore: 'Steam商店',
  1856. licenses: '入库免费游戏',
  1857. playtests: '请求访问权限',
  1858. needLoginSteamStore: '请先<a href="https://store.steampowered.com/login/" target="_blank">登录Steam商店</a>',
  1859. needLoginSteamCommunity: '请先<a href="https://steamcommunity.com/login/home/" target="_blank">登录Steam社区</a>',
  1860. joiningSteamGroup: '正在加入Steam组',
  1861. leavingSteamGroup: '正在退出Steam组',
  1862. gettingSteamGroupId: '正在获取Steam组Id',
  1863. joiningSteamOfficialGroup: '正在加入Steam官方组',
  1864. leavingSteamOfficialGroup: '正在退出Steam官方组',
  1865. gettingSteamOfficialGroupId: '正在获取Steam官方组Id',
  1866. subscribingForum: '正在订阅Steam论坛',
  1867. unsubscribingForum: '正在取消订阅Steam论坛',
  1868. gettingForumId: '正在获取Steam论坛Id',
  1869. followingCurator: '正在关注Steam鉴赏家',
  1870. unfollowingCurator: '正在取关Steam鉴赏家',
  1871. gettingCuratorId: '正在获取Steam鉴赏家Id',
  1872. addingToWishlist: '正在添加游戏到Steam愿望单',
  1873. removingFromWishlist: '正在从Steam愿望单移除游戏',
  1874. followingGame: '正在关注Steam游戏',
  1875. unfollowingGame: '正在取关Steam游戏',
  1876. favoritingWorkshop: '正在收藏Steam创意工坊物品',
  1877. unfavoritingWorkshop: '正在取消收藏Steam创意工坊物品',
  1878. gettingWorkshopAppId: '正在获取Steam创意工坊物品Id',
  1879. votingUpWorkshop: '正在点赞Steam创意工坊物品',
  1880. gettingAnnouncementParams: '正在获取Steam通知信息',
  1881. likingAnnouncement: '正在点赞Steam通知',
  1882. changingArea: '正在更换Steam地区: %0...',
  1883. notNeededChangeArea: '当前地区不需要更换',
  1884. noAnotherArea: '请检测是否开启正确开启代理',
  1885. gettingAreaInfo: '正在获取Steam地区信息...',
  1886. changeAreaNotice: '疑似锁区游戏,尝试换区执行',
  1887. steamFinishNotice: 'Steam任务完成,尝试将购物车地区换回',
  1888. gettingSubid: '正在获取游戏subid',
  1889. addingFreeLicense: '正在入库',
  1890. missParams: '缺少参数',
  1891. gettingLicenses: '正在获取Licenses...',
  1892. requestingPlayTestAccess: '正在请求访问权限',
  1893. tryChangeAreaNotice: '此功能无法检测游戏是否限区,因此会尝试换区后再入库,换区失败也不影响后续入库',
  1894. gettingUserLink: '正在获取Steam用户社区链接...',
  1895. retry: '重试',
  1896. owned: '已拥有',
  1897. redirect: '重定向',
  1898. noSubid: '无法获取,跳过',
  1899. initingASF: '正在初始化ASF...',
  1900. servers: '服务器',
  1901. joiningDiscordServer: '正在加入Discord服务器',
  1902. leavingDiscordServer: '正在退出Discord服务器',
  1903. gettingDiscordGuild: '正在获取Discord服务器Id',
  1904. getDiscordAuthFailed: '获取Discord凭证失败,请检测Discord帐号是否已登录',
  1905. discordImportantNotice: '重要提醒!!!',
  1906. discordImportantNoticeText: '由于Discord网站后台更新,目前使用此脚本加组后可能会导致Discord帐号被强制退出,且需要两步验证才能正常登录,请谨慎使用!!!',
  1907. continue: '继续',
  1908. skipDiscordTask: '跳过Discord任务',
  1909. continueAndDontRemindAgain: '继续且不再提醒',
  1910. users: '用户',
  1911. loginIns: '请先<a href="https://www.instagram.com/accounts/login/" target="_blank">登录Instagram</a>',
  1912. insBanned: '您的Instagram账户已被封禁',
  1913. verifyingInsAuth: '正在验证Instagram凭证...',
  1914. gettingInsUserId: '正在获取Instagram用户Id',
  1915. followingIns: '正在关注Instagram用户',
  1916. unfollowingIns: '正在取关Instagram用户',
  1917. reddits: '社区/用户',
  1918. loginReddit: '请先<a href="https://www.reddit.com/login/" target="_blank">登录Reddit</a>',
  1919. changingRedditVersion: '正在切换Reddit为新版页面...',
  1920. joiningReddit: '正在加入Reddit社区',
  1921. leavingReddit: '正在退出Reddit社区',
  1922. followingRedditUser: '正在关注Reddit用户',
  1923. unfollowingRedditUser: '正在取关Reddit用户',
  1924. channels: '频道',
  1925. followingTwitchChannel: '正在关注Twitch频道',
  1926. unfollowingTwitchChannel: '正在取关Twitch频道',
  1927. gettingTwitchChannelId: '正在获取Twitch频道Id',
  1928. checkingTwitchIntegrity: '正在检查Twitch完整性...',
  1929. twitterUser: '推特用户',
  1930. retweets: '转推',
  1931. gettingTwitterUserId: '正在获取推特用户Id',
  1932. followingTwitterUser: '正在关注推特用户',
  1933. unfollowingTwitterUser: '正在取关推特用户',
  1934. retweetting: '正在转推',
  1935. unretweetting: '正在撤销转推',
  1936. names: '组/社区/动态',
  1937. loginVk: '请先<a href="https://vk.com/login/" target="_blank">登录Vk</a>',
  1938. gettingVkId: '正在获取Vk任务Id',
  1939. joiningVkGroup: '正在加入Vk组',
  1940. leavingVkGroup: '正在退出Vk组',
  1941. joiningVkPublic: '正在加入Vk社区',
  1942. leavingVkPublic: '正在退出Vk社区',
  1943. sendingVkWall: '正在转发Vk动态',
  1944. deletingVkWall: '正在撤销转发Vk动态',
  1945. youtubeChannel: 'YouTube频道',
  1946. likes: '点赞',
  1947. loginYtb: '请先<a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">登录YouTube</a>',
  1948. tryUpdateYtbAuth: '请尝试<a href="https://www.youtube.com/#auth" target="_blank">更新YouTube凭证</a>',
  1949. gettingYtbToken: '正在获取YouTube Token...',
  1950. followingYtbChannel: '正在订阅YouTube频道',
  1951. unfollowingYtbChannel: '正在退订YouTube频道',
  1952. likingYtbVideo: '正在点赞YouTube视频',
  1953. unlikingYtbVideo: '正在取消点赞YouTube视频',
  1954. giveKeyNoticeBefore: '每次验证间隔15s',
  1955. giveKeyNoticeAfter: '如果没有key, 请在<a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>查看',
  1956. noPoints: '点数不够,跳过抽奖',
  1957. getNeedPointsFailed: '获取所需点数失败,跳过抽奖',
  1958. joiningLottery: '正在加入抽奖',
  1959. doingGleamTask: '正在做Gleam任务...',
  1960. gettingGleamLink: '正在获取Gleam任务链接...',
  1961. gleamTaskNotice: '如果此页面长时间未关闭,请完成任一任务后自行关闭!',
  1962. verifiedGleamTasks: '已尝试验证所有任务,验证失败的任务请尝试手动验证或完成!',
  1963. campaign: '检测到人机验证,请完成验证后重新验证任务!',
  1964. gsNotice: '为避免得到"0000-0000-0000"key, 已自动屏蔽"Grab Key"按钮,获取key时请关闭脚本!',
  1965. giveeClubVerifyNotice: '正在验证任务...',
  1966. giveeClubVerifyFinished: '请等待验证完成后自行加入赠Key',
  1967. doingKeyhubTask: '正在做Keyhub任务...',
  1968. SweepWidgetNotice: '正在处理并验证任务,每次验证任务有1~3s间隔防止触发验证过快警告...',
  1969. tasksNotCompleted: '任务未完成',
  1970. notConnect: '社交平台未连接,跳过任务',
  1971. tgTaskNotice: '检测到Telegram任务,需要手动完成',
  1972. confirmingTask: '正在跳过警告页面...',
  1973. unSupporttedTaskType: '不支持的任务类型'
  1974. };
  1975. const zh_CN = data;
  1976. const en_US_data = {
  1977. website: 'Website',
  1978. type: 'Type',
  1979. edit: 'Edit',
  1980. whiteList: 'Whitelist',
  1981. skipTask: 'Skip undo task',
  1982. whiteListOptions: 'Whitelist options',
  1983. changeWhiteListOption: 'Whitelist option(%0)',
  1984. whiteListNotFound: 'Cannot find this whitelist: %0',
  1985. changeWhiteListSuccess: 'The whitelist is successfully modified, and the page refresh will take effect!',
  1986. changeWebsiteOptions: 'Website options',
  1987. changeGlobalOptions: 'Global options',
  1988. ok: 'OK',
  1989. save: 'Save',
  1990. close: 'Close',
  1991. return: 'Return',
  1992. option: 'Option',
  1993. value: 'Value',
  1994. websiteOptions: 'Current website settings',
  1995. changeWebsiteOptionsSuccess: 'The current website setting is changed successfully, and the page refresh will take effect!',
  1996. changeGlobalOptionsSuccess: 'The global setting is changed successfully, and the refresh will take effect!',
  1997. needLogin: 'Please log in first!',
  1998. getTasksInfo: 'Obtaining and processing task information...',
  1999. gettingKey: 'Getting Key...',
  2000. verifyingTask: 'Verifying task',
  2001. notice: 'Automatic task script notice',
  2002. noKeysLeft: 'There are no more keys left on this page. Do you want to close it?',
  2003. giveawayEnded: 'This event has ended, do you want to close it?',
  2004. 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?',
  2005. confirm: 'Confirm',
  2006. cancel: 'Cancel',
  2007. unKnown: 'Unknown',
  2008. unKnownTaskType: 'Unrecognized task',
  2009. doing: 'Doing a task',
  2010. allTasksComplete: 'All tasks have been completed!',
  2011. getTaskIdFailed: 'Failed to obtain task Id!',
  2012. initSuccess: '%0 was initialized successfully!',
  2013. initFailed: '%0 initialization failed!',
  2014. errorLink: 'Link error: %0',
  2015. needInit: 'Please initialize first',
  2016. verifyingAuth: 'Verifying %0 token...',
  2017. updatingAuth: 'Update %0 token...',
  2018. refreshingToken: 'Refreshing %0 token...',
  2019. settingToken: 'Setting %0 token...',
  2020. steamStoreTab: 'Steam store (new tab)',
  2021. steamCommunityTab: 'Steam community(new tab)',
  2022. initing: 'Initializing...',
  2023. getFailed: 'Failed to get %0!',
  2024. checkLoginFailed: 'Failed to detect login status!',
  2025. checkLeftKeyFailed: 'Failed to detect the remaining keys!',
  2026. userId: 'User Id',
  2027. joiningGiveaway: 'Joining giveaway',
  2028. needJoinGiveaway: 'Need to join the giveaway first',
  2029. cannotUndo: 'This website does not support canceling tasks',
  2030. verifyAuth: 'Verifying %0 token...',
  2031. closePageNotice: 'f this page does not close automatically, please close this page yourself.',
  2032. errorReport: 'A script error is detected, do you want to report the BUG?',
  2033. visitingLink: 'Visiting link ...',
  2034. doTask: 'DoTask',
  2035. undoTask: 'UndoTask',
  2036. verifyTask: 'Verify',
  2037. getKey: 'GetKey',
  2038. selectAll: 'SelectAll',
  2039. selectNone: 'SelectNone',
  2040. invertSelect: 'InvertSelect',
  2041. doFreeTask: 'FreeTask',
  2042. doPointTask: 'PointTask',
  2043. skipTaskOption: 'Skip task has been configured in the settings',
  2044. other: 'Other',
  2045. globalOptions: 'Global Options',
  2046. checkLogin: 'Login detection</br>Need to log in to the website automatically log in, part of this website supports.',
  2047. checkLeftKey: 'Key remaining detection</br>The end of the giveaway event prompts whether to close or not, part of this website supports.',
  2048. 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.',
  2049. 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.',
  2050. 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.',
  2051. saveGlobalOptions: 'SaveSettings',
  2052. settingPage: 'Setting Page',
  2053. name: 'Name',
  2054. version: 'Version',
  2055. scriptManager: 'Script Manager',
  2056. script: 'Script',
  2057. environment: 'Environment',
  2058. os: 'OS',
  2059. browser: 'Browser',
  2060. getId: 'Get %0 id',
  2061. getTwitterUserId: 'Get Twitter user id (Get id function is only available on the settings page).',
  2062. getYoutubeChannelId: 'Get Youtube channel id (Get id function is only available on the settings page).',
  2063. showButton: 'ShowButton',
  2064. hideButton: 'HideButton',
  2065. showLog: 'ShowLog',
  2066. hideLog: 'HideLog',
  2067. defaultShowButton: 'Default display button',
  2068. defaultShowLog: 'Display log by default',
  2069. debug: 'Output debug log, do not enable this option!',
  2070. receivePreview: 'Receive preview updates',
  2071. position: 'Component position',
  2072. buttonSideX: 'Horizontal positioning of the button area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  2073. 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',
  2074. 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',
  2075. showButtonSideX: 'ShowButton horizontal positioning (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  2076. showButtonSideY: 'ShowButton vertical positioning (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
  2077. 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',
  2078. logSideX: 'Horizontal positioning of the log area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  2079. logSideY: 'Vertical positioning of the log area (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
  2080. 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',
  2081. hotKey: 'Shortcut key',
  2082. doTaskKey: 'DoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
  2083. undoTaskKey: 'UndoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
  2084. toggleLogKey: 'ShowLog/HideLog shortcut keys</br> (real-time preview function is only available on the settings page).',
  2085. tasksHistory: 'TasksHistory',
  2086. clearHistory: 'Clear history',
  2087. clearHistoryFinished: 'The mission history has been cleared!',
  2088. deleteTask: 'Delete task',
  2089. lastChangeTime: 'Last Change Time',
  2090. clearTaskFinished: 'Delete the following tasks completed!',
  2091. clearTaskFailed: 'Failed to delete the task, the task name was not found!',
  2092. syncData: 'DataSync',
  2093. settingData: 'Uploading data...',
  2094. gettingData: 'Getting data...',
  2095. help: 'Help',
  2096. fileName: 'Filename',
  2097. upload2gist: 'Sync to Gist',
  2098. downloadFromGist: 'Sync from Gist',
  2099. saveAndTest: 'Save configuration and test',
  2100. testSuccess: 'Test success!',
  2101. testFailed: 'Test failed!',
  2102. saveAndTestNotice: 'Please save the configuration and test first!',
  2103. processingData: 'Processing data...',
  2104. updatingData: 'Uploading data...',
  2105. syncDataSuccess: 'Synchronized data successfully!',
  2106. syncDataFailed: 'Failed to synchronize data, please check the error message on the console!',
  2107. downloadingData: 'Downloading data...',
  2108. checkedNoData: 'No remote data is detected, please confirm whether the configuration is correct!',
  2109. savingData: 'Saving data...',
  2110. syncHistory: 'Synchronize tasks history',
  2111. checkUpdateFailed: 'Check update failed',
  2112. newVersionNotice: 'Checked a new version V%0, <a class="high-light" href="%1" target="_blank">click to update</a>',
  2113. language: 'Language</br> Currently only supports zh: Chinese, en: English',
  2114. gistOptions: 'Gist Settings',
  2115. 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!',
  2116. 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!',
  2117. noticeLink: 'https://auto-task-doc.js.org/en/guide/#read-me-first',
  2118. toGithub: 'Feedback(Github)',
  2119. toKeylol: 'Feedback(Keylol)',
  2120. copySuccess: 'The error message has been copied to the clipboard. Do you want to go to the Keylol forum to give feedback?',
  2121. copyFailed: 'Please copy the error information below and report back to the Keylol forum!',
  2122. updateText: 'Updates in version %0:',
  2123. Active: 'Active',
  2124. Ended: 'Ended',
  2125. Banned: 'Banned',
  2126. Paused: 'Paused',
  2127. notStart: 'notStart',
  2128. noRemoteData: 'No data remotely',
  2129. errorRemoteDataFormat: 'Remote data has wrong format',
  2130. updateHistory: '<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">Click here</a>' + ' to view the historical update record.',
  2131. AsfEnabled: 'Use ASF to do Steam related tasks (requires <a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a> plugin)',
  2132. AsfIpcUrl: 'ASF IPC URL',
  2133. AsfIpcPassword: 'ASF IPC Password',
  2134. groups: 'Group',
  2135. officialGroups: 'Official Group',
  2136. wishlists: 'Wishlist',
  2137. follows: 'Follow Game',
  2138. forums: 'Forum',
  2139. workshops: 'Favorite Workshop',
  2140. curators: 'Curator',
  2141. workshopVotes: 'Voteup Workshop',
  2142. announcements: 'Announcement',
  2143. steamCommunity: 'Steam Community',
  2144. steamStore: 'Steam Store',
  2145. licenses: 'Add License',
  2146. playtests: 'Playtest Access',
  2147. needLoginSteamStore: 'Please <a href="https://store.steampowered.com/login/" target="_blank">log in to the Steam Store</a>',
  2148. needLoginSteamCommunity: 'Please <a href="https://steamcommunity.com/login/home/" target="_blank">log in to the Steam Community</a>',
  2149. joiningSteamGroup: 'Joining Steam Group',
  2150. leavingSteamGroup: 'Leaving Steam Group',
  2151. gettingSteamGroupId: 'Getting Steam Group Id',
  2152. joiningSteamOfficialGroup: 'Joining Steam Official Group',
  2153. leavingSteamOfficialGroup: 'Leaving Steam Official Group',
  2154. gettingSteamOfficialGroupId: 'Getting Steam Official Group Id',
  2155. subscribingForum: 'Subscribing the Steam Forum',
  2156. unsubscribingForum: 'Unsubscribing the Steam Forum',
  2157. gettingForumId: 'Getting Steam Forum Id',
  2158. followingCurator: 'Following Steam Curator',
  2159. unfollowingCurator: 'Unfollowing Steam Curator',
  2160. gettingCuratorId: 'Getting Steam Curator Id',
  2161. addingToWishlist: 'Adding the game to the Steam wishlist',
  2162. removingFromWishlist: 'Removing the game from the Steam wishlist',
  2163. followingGame: 'Following Steam games',
  2164. unfollowingGame: 'Unfollowing Steam games',
  2165. favoritingWorkshop: 'Favouring Steam Workshop Items',
  2166. unfavoritingWorkshop: 'Unfavoriting Steam Workshop Items',
  2167. gettingWorkshopAppId: 'Getting Steam Workshop Item Id',
  2168. votingUpWorkshop: 'Liking Steam workshop items',
  2169. gettingAnnouncementParams: 'Getting Steam announcement information',
  2170. likingAnnouncement: 'Liking Steam announcement',
  2171. changingArea: 'Changing Steam area: %0...',
  2172. notNeededChangeArea: 'The current area does not need to be changed',
  2173. noAnotherArea: 'Please check whether the proxy is turned on correctly',
  2174. gettingAreaInfo: 'Getting Steam area information...',
  2175. changeAreaNotice: 'Suspected of a locked zone game, try to change the zone to execute',
  2176. steamFinishNotice: 'Steam task completed, try to change the shopping cart area back to ',
  2177. gettingSubid: 'Getting subid',
  2178. addingFreeLicense: 'Adding free license',
  2179. missParams: 'Missing parameters',
  2180. gettingLicenses: 'Getting licenses...',
  2181. requestingPlayTestAccess: 'Requesting play test access',
  2182. 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.',
  2183. versionNotMatched: 'The script manager version is too low, requiring TamperMonkey >= 5.2.0 or TamperMonkey Beta >= 5.2.6196',
  2184. gettingUserLink: 'Getting steam user community link...',
  2185. retry: 'Retry',
  2186. owned: 'Owned',
  2187. redirect: 'Redirect',
  2188. noSubid: 'skip due to unrecognized',
  2189. initingASF: 'Initing ASF...',
  2190. servers: 'Server',
  2191. joiningDiscordServer: 'Joining Discord Server',
  2192. leavingDiscordServer: 'Leaving Discord Server',
  2193. gettingDiscordGuild: 'Getting Discord server Id',
  2194. getDiscordAuthFailed: 'Failed to get Discord token, please check whether the Discord account is logged in',
  2195. discordImportantNotice: 'Important Reminder! ! !',
  2196. 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! ! !',
  2197. continue: 'Continue',
  2198. skipDiscordTask: 'Skip',
  2199. continueAndDontRemindAgain: 'Continue without Reminders',
  2200. users: 'User',
  2201. loginIns: 'Please <a href="https://www.instagram.com/accounts/login/" target="_blank">log in to Instagram</a>',
  2202. insBanned: 'Your Instagram account has been banned',
  2203. verifyingInsAuth: 'Verifying Instagram token...',
  2204. gettingInsUserId: 'Getting Instagram user Id',
  2205. followingIns: 'Following Instagram user',
  2206. unfollowingIns: 'Unfollowing Instagram user',
  2207. reddits: 'Reddit/User',
  2208. loginReddit: 'Please <a href="https://www.reddit.com/login/" target="_blank">log in to Reddit</a>',
  2209. changingRedditVersion: 'Switching Reddit to a new version page...',
  2210. joiningReddit: 'Joining the Reddit',
  2211. leavingReddit: 'Leaving the Reddit',
  2212. followingRedditUser: 'Following Reddit User',
  2213. unfollowingRedditUser: 'Unfollowing Reddit User',
  2214. channels: 'Channel',
  2215. followingTwitchChannel: 'Following Twitch Channel',
  2216. unfollowingTwitchChannel: 'Unfollowing Twitch Channel',
  2217. gettingTwitchChannelId: 'Getting Twitch Channel Id',
  2218. checkingTwitchIntegrity: 'Checking Twitch integrity...',
  2219. twitterUser: 'Twitter User',
  2220. retweets: 'Retweet',
  2221. gettingTwitterUserId: 'Getting Twitter User Id',
  2222. followingTwitterUser: 'Following Twitter User',
  2223. unfollowingTwitterUser: 'Unfollowing Twitter User',
  2224. retweetting: 'Retweetting',
  2225. unretweetting: 'Unretweetting',
  2226. names: 'Group/Public/Wall',
  2227. loginVk: 'Please <a href="https://vk.com/login/" target="_blank">log in to Vk</a>',
  2228. gettingVkId: 'Getting Vk task Id',
  2229. joiningVkGroup: 'Joining Vk Group',
  2230. leavingVkGroup: 'Leaving Vk Group',
  2231. joiningVkPublic: 'Joining Vk Public',
  2232. leavingVkPublic: 'Leaving Vk Public',
  2233. sendingVkWall: 'Sending Vk Wall',
  2234. deletingVkWall: 'Deleting Vk Wall',
  2235. youtubeChannel: 'YouTube Channel',
  2236. likes: 'Like',
  2237. loginYtb: 'Please <a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">log in to YouTube</a>',
  2238. tryUpdateYtbAuth: 'Please try to <a href="https://www.youtube.com/#auth" target="_blank">update YouTube token</a>',
  2239. gettingYtbToken: 'Getting YouTube Token...',
  2240. followingYtbChannel: 'Subscribing to YouTube channel',
  2241. unfollowingYtbChannel: 'Unsubscribing to YouTube channel',
  2242. likingYtbVideo: 'Liking YouTube video',
  2243. unlikingYtbVideo: 'Unliking YouTube video',
  2244. giveKeyNoticeBefore: 'Each verification interval is 15s',
  2245. giveKeyNoticeAfter: 'If there is no key, please check at <a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>',
  2246. noPoints: 'Not enough points, skip the lottery',
  2247. getNeedPointsFailed: 'ailed to obtain the required points, skip the lottery',
  2248. joiningLottery: 'Joining the lottery',
  2249. doingGleamTask: 'Doing Gleam Task...',
  2250. gettingGleamLink: 'Getting Gleam task link...',
  2251. gleamTaskNotice: 'If this page has not been closed for a long time, please close it yourself after completing any task!',
  2252. verifiedGleamTasks: 'Attempted to verify all tasks. If the verification fails, please try to verify manually or complete it!',
  2253. campaign: 'ReCAPTCHA detected, please complete it and re-verify the tasks!',
  2254. 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!',
  2255. giveeClubVerifyNotice: 'Verifying task...',
  2256. giveeClubVerifyFinished: 'Wait for the verification to complete and join it by yourself',
  2257. doingKeyhubTask: 'Doing Keyhub Task...',
  2258. 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...',
  2259. tasksNotCompleted: 'Tasks Not Completed',
  2260. notConnect: 'Social platform is not connectted, skip',
  2261. tgTaskNotice: 'The telegram task is checked, need to do it yourself!',
  2262. confirmingTask: 'Confirming task...',
  2263. unSupporttedTaskType: 'Unsupportted task type'
  2264. };
  2265. const en_US = en_US_data;
  2266. const languages = {
  2267. zh: zh_CN,
  2268. en: en_US
  2269. };
  2270. const language = [ 'zh', 'en' ].includes(globalOptions.other.language) ? globalOptions.other.language : 'en';
  2271. const I18n = (key, ...argvs) => {
  2272. if (!languages[language]?.[key]) {
  2273. return key;
  2274. }
  2275. return languages[language][key].replace(/%([\d]+)/g, (match, index) => argvs[parseInt(index, 10)]);
  2276. };
  2277. const i18n = I18n;
  2278. function throwError(error, name) {
  2279. if (window.TRACE) {
  2280. console.trace('%cAuto-Task[Debug]:', 'color:blue');
  2281. }
  2282. external_Swal_default().fire({
  2283. title: i18n('errorReport'),
  2284. icon: 'error',
  2285. showCancelButton: true,
  2286. confirmButtonText: i18n('toGithub'),
  2287. showDenyButton: true,
  2288. denyButtonText: i18n('toKeylol'),
  2289. cancelButtonText: i18n('close')
  2290. }).then(({
  2291. isDenied,
  2292. isConfirmed
  2293. }) => {
  2294. if (isConfirmed) {
  2295. 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,
  2296. 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'))}`, {
  2297. active: true
  2298. });
  2299. } else if (isDenied) {
  2300. const text = `错误链接: [url=${window.location.href}]${window.location.href}[/url]
  2301.  
  2302. 环境:
  2303.  
  2304. [code]${JSON.stringify((0, javascript_utils_umd_min.ua)(), null, 4)}[/code]
  2305.  
  2306. 脚本管理器: ${GM_info.scriptHandler} ${GM_info.version}
  2307. 脚本版本: ${GM_info.script.version}
  2308.  
  2309. 报错信息:
  2310. [code]${error.stack}[/code]
  2311.  
  2312. 执行日志:
  2313. [code]${$.makeArray($('#auto-task-info>li')).map(element => element.innerText).join('\n')}[/code]`;
  2314. GM_setClipboard(text);
  2315. external_Swal_default().fire({
  2316. title: i18n('copySuccess'),
  2317. icon: 'success',
  2318. confirmButtonText: i18n('ok')
  2319. }).then(() => {
  2320. GM_openInTab('https://keylol.com/forum.php?mod=post&action=reply&fid=319&tid=777450', {
  2321. active: true
  2322. });
  2323. });
  2324. }
  2325. });
  2326. console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: ${name}\n${error.stack}`);
  2327. }
  2328. class Social {
  2329. tasks;
  2330. getRealParams(name, links, doTask, link2param) {
  2331. try {
  2332. let realParams = [];
  2333. if (links.length > 0) {
  2334. realParams = [ ...realParams, ...links.map(link => link2param(link)).filter(link => link) ];
  2335. }
  2336. if (!doTask && this.tasks[name].length > 0) {
  2337. realParams = [ ...realParams, ...this.tasks[name] ];
  2338. }
  2339. return unique(realParams);
  2340. } catch (error) {
  2341. throwError(error, 'Social.getRealParams');
  2342. return [];
  2343. }
  2344. }
  2345. }
  2346. const social_Social = Social;
  2347. class Discord extends social_Social {
  2348. tasks;
  2349. whiteList;
  2350. #auth = GM_getValue('discordAuth') || {};
  2351. #cache = GM_getValue('discordCache') || {};
  2352. #initialized = false;
  2353. constructor() {
  2354. super();
  2355. const defaultTasksTemplate = {
  2356. servers: []
  2357. };
  2358. this.tasks = defaultTasksTemplate;
  2359. this.whiteList = {
  2360. ...defaultTasksTemplate,
  2361. ...GM_getValue('whiteList')?.discord || {}
  2362. };
  2363. }
  2364. async init(action) {
  2365. try {
  2366. if (!GM_getValue('dontRemindDiscordAgain')) {
  2367. const result = await external_Swal_default().fire({
  2368. title: i18n('discordImportantNotice'),
  2369. text: i18n('discordImportantNoticeText'),
  2370. showCancelButton: true,
  2371. showDenyButton: true,
  2372. confirmButtonText: i18n('continue'),
  2373. cancelButtonText: i18n('skipDiscordTask'),
  2374. denyButtonText: i18n('continueAndDontRemindAgain')
  2375. }).then(({
  2376. isConfirmed,
  2377. isDenied
  2378. }) => {
  2379. if (isConfirmed) {
  2380. return true;
  2381. }
  2382. if (isDenied) {
  2383. GM_setValue('dontRemindDiscordAgain', true);
  2384. return true;
  2385. }
  2386. return false;
  2387. });
  2388. if (!result) {
  2389. this.#initialized = false;
  2390. return 'skip';
  2391. }
  2392. }
  2393. if (GM_getValue('dontRemindDiscordAgain') || action === 'do' && !globalOptions.doTask.discord.servers || action === 'undo' && !globalOptions.undoTask.discord.servers) {
  2394. this.#initialized = false;
  2395. return 'skip';
  2396. }
  2397. if (this.#initialized) {
  2398. return true;
  2399. }
  2400. if (!this.#auth.auth) {
  2401. if (await this.#updateAuth()) {
  2402. this.#initialized = true;
  2403. return true;
  2404. }
  2405. return false;
  2406. }
  2407. const isVerified = await this.#verifyAuth();
  2408. if (isVerified) {
  2409. scripts_echoLog({}).success(i18n('initSuccess', 'Discord'));
  2410. this.#initialized = true;
  2411. return true;
  2412. }
  2413. GM_setValue('discordAuth', {
  2414. auth: null
  2415. });
  2416. if (await this.#updateAuth()) {
  2417. scripts_echoLog({}).success(i18n('initSuccess', 'Discord'));
  2418. this.#initialized = true;
  2419. return true;
  2420. }
  2421. scripts_echoLog({}).error(i18n('initFailed', 'Discord'));
  2422. return false;
  2423. } catch (error) {
  2424. throwError(error, 'Discord.init');
  2425. return false;
  2426. }
  2427. }
  2428. async #verifyAuth() {
  2429. try {
  2430. const logStatus = scripts_echoLog({
  2431. text: i18n('verifyingAuth', 'Discord')
  2432. });
  2433. const {
  2434. result,
  2435. statusText,
  2436. status,
  2437. data
  2438. } = await tools_httpRequest({
  2439. url: 'https://discord.com/api/v6/users/@me',
  2440. method: 'HEAD',
  2441. headers: {
  2442. authorization: this.#auth.auth
  2443. }
  2444. });
  2445. if (result === 'Success') {
  2446. if (data?.status === 200) {
  2447. logStatus.success();
  2448. return true;
  2449. }
  2450. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2451. return false;
  2452. }
  2453. logStatus.error(`${result}:${statusText}(${status})`);
  2454. return false;
  2455. } catch (error) {
  2456. throwError(error, 'Discord.verifyAuth');
  2457. return false;
  2458. }
  2459. }
  2460. async #updateAuth() {
  2461. try {
  2462. const logStatus = scripts_echoLog({
  2463. text: i18n('updatingAuth', 'Discord')
  2464. });
  2465. return await new Promise(resolve => {
  2466. const newTab = GM_openInTab('https://discord.com/channels/@me', {
  2467. active: true,
  2468. insert: true,
  2469. setParent: true
  2470. });
  2471. newTab.name = 'ATv4_discordAuth';
  2472. newTab.onclose = async () => {
  2473. const auth = GM_getValue('discordAuth')?.auth;
  2474. if (auth) {
  2475. this.#auth = {
  2476. auth: auth
  2477. };
  2478. logStatus.success();
  2479. resolve(await this.#verifyAuth());
  2480. } else {
  2481. logStatus.error('Error: Update discord auth failed!');
  2482. resolve(false);
  2483. }
  2484. };
  2485. });
  2486. } catch (error) {
  2487. throwError(error, 'Discord.updateAuth');
  2488. return false;
  2489. }
  2490. }
  2491. async #joinServer(inviteId) {
  2492. try {
  2493. const logStatus = scripts_echoLog({
  2494. type: 'joiningDiscordServer',
  2495. text: inviteId
  2496. });
  2497. const {
  2498. result,
  2499. statusText,
  2500. status,
  2501. data
  2502. } = await tools_httpRequest({
  2503. url: `https://discord.com/api/v9/invites/${inviteId}`,
  2504. method: 'POST',
  2505. dataType: 'json',
  2506. headers: {
  2507. authorization: this.#auth.auth,
  2508. origin: 'https://discord.com',
  2509. referer: `https://discord.com/invite/${inviteId}`
  2510. }
  2511. });
  2512. if (result === 'Success' && data?.status === 200) {
  2513. logStatus.success();
  2514. const guild = String(data.response?.guild?.id);
  2515. if (guild) {
  2516. this.#setCache(inviteId, guild);
  2517. this.tasks.servers = unique([ ...this.tasks.servers, inviteId ]);
  2518. }
  2519. return true;
  2520. }
  2521. logStatus.error(`${result}:${statusText}(${status})`);
  2522. return false;
  2523. } catch (error) {
  2524. throwError(error, 'Discord.joinServer');
  2525. return false;
  2526. }
  2527. }
  2528. async #leaveServer(inviteId) {
  2529. try {
  2530. if (this.whiteList.servers.includes(inviteId)) {
  2531. scripts_echoLog({
  2532. type: 'whiteList',
  2533. text: 'Discord.leaveServer',
  2534. id: inviteId
  2535. });
  2536. return true;
  2537. }
  2538. const guild = await this.#getGuild(inviteId);
  2539. if (!guild) {
  2540. return false;
  2541. }
  2542. const logStatus = scripts_echoLog({
  2543. type: 'leavingDiscordServer',
  2544. text: guild
  2545. });
  2546. const {
  2547. result,
  2548. statusText,
  2549. status,
  2550. data
  2551. } = await tools_httpRequest({
  2552. url: `https://discord.com/api/v9/users/@me/guilds/${guild}`,
  2553. method: 'DELETE',
  2554. headers: {
  2555. authorization: this.#auth.auth
  2556. }
  2557. });
  2558. if (result === 'Success' && data?.status === 204) {
  2559. logStatus.success();
  2560. return true;
  2561. }
  2562. logStatus.error(`${result}:${statusText}(${status})`);
  2563. return false;
  2564. } catch (error) {
  2565. throwError(error, 'Discord.leaveServer');
  2566. return false;
  2567. }
  2568. }
  2569. async #getGuild(inviteId) {
  2570. try {
  2571. const logStatus = scripts_echoLog({
  2572. type: 'gettingDiscordGuild',
  2573. text: inviteId
  2574. });
  2575. const guild = this.#cache[inviteId];
  2576. if (guild) {
  2577. logStatus.success();
  2578. return guild;
  2579. }
  2580. const {
  2581. result,
  2582. statusText,
  2583. status,
  2584. data
  2585. } = await tools_httpRequest({
  2586. url: `https://discord.com/api/v9/invites/${inviteId}`,
  2587. responseType: 'json',
  2588. method: 'GET'
  2589. });
  2590. if (result === 'Success' && data?.status === 200) {
  2591. const guild = data.response?.guild?.id;
  2592. if (guild) {
  2593. logStatus.success();
  2594. this.#setCache(inviteId, guild);
  2595. return guild;
  2596. }
  2597. logStatus.error(`${result}:${statusText}(${status})`);
  2598. return false;
  2599. }
  2600. logStatus.error(`${result}:${statusText}(${status})`);
  2601. return false;
  2602. } catch (error) {
  2603. throwError(error, 'Discord.getGuild');
  2604. return false;
  2605. }
  2606. }
  2607. async toggle({
  2608. doTask = true,
  2609. serverLinks = []
  2610. }) {
  2611. try {
  2612. if (!this.#initialized) {
  2613. scripts_echoLog({
  2614. text: i18n('needInit')
  2615. });
  2616. return false;
  2617. }
  2618. const prom = [];
  2619. if (doTask && !globalOptions.doTask.discord.servers || !doTask && !globalOptions.undoTask.discord.servers) {
  2620. scripts_echoLog({
  2621. type: 'globalOptionsSkip',
  2622. text: 'discord.servers'
  2623. });
  2624. } else {
  2625. const realServers = this.getRealParams('servers', serverLinks, doTask, link => link.match(/invite\/(.+)/)?.[1]);
  2626. if (realServers.length > 0) {
  2627. for (const server of realServers) {
  2628. if (doTask) {
  2629. prom.push(this.#joinServer(server));
  2630. } else {
  2631. prom.push(this.#leaveServer(server));
  2632. }
  2633. await delay(1e3);
  2634. }
  2635. }
  2636. }
  2637. return await Promise.all(prom).then(() => true);
  2638. } catch (error) {
  2639. throwError(error, 'Discord.toggleServers');
  2640. return false;
  2641. }
  2642. }
  2643. #setCache(inviteId, guild) {
  2644. try {
  2645. this.#cache[inviteId] = guild;
  2646. GM_setValue('discordCache', this.#cache);
  2647. } catch (error) {
  2648. throwError(error, 'Discord.setCache');
  2649. }
  2650. }
  2651. }
  2652. const social_Discord = Discord;
  2653. class Instagram extends social_Social {
  2654. tasks;
  2655. whiteList;
  2656. #cache = GM_getValue('instagramCache') || {};
  2657. #auth = {};
  2658. #initialized = false;
  2659. constructor() {
  2660. super();
  2661. const defaultTasksTemplate = {
  2662. users: []
  2663. };
  2664. this.tasks = defaultTasksTemplate;
  2665. this.whiteList = {
  2666. ...defaultTasksTemplate,
  2667. ...GM_getValue('whiteList')?.instagram || {}
  2668. };
  2669. }
  2670. async init() {
  2671. try {
  2672. if (this.#initialized) {
  2673. return true;
  2674. }
  2675. const isVerified = await this.#getUserInfo();
  2676. if (isVerified) {
  2677. scripts_echoLog({}).success(i18n('initSuccess', 'Instagram'));
  2678. this.#initialized = true;
  2679. return true;
  2680. }
  2681. scripts_echoLog({}).error(i18n('initFailed', 'Instagram'));
  2682. return false;
  2683. } catch (error) {
  2684. throwError(error, 'Instagram.init');
  2685. return false;
  2686. }
  2687. }
  2688. async #getUserInfo(name = 'instagram') {
  2689. try {
  2690. const logStatus = scripts_echoLog({
  2691. type: name === 'instagram' ? 'verifyingInsAuth' : 'gettingInsUserId',
  2692. text: name
  2693. });
  2694. const userId = this.#cache[name];
  2695. if (userId && name !== 'instagram') {
  2696. logStatus.success();
  2697. return userId;
  2698. }
  2699. const {
  2700. result,
  2701. statusText,
  2702. status,
  2703. data
  2704. } = await tools_httpRequest({
  2705. url: `https://www.instagram.com/${name}/`,
  2706. method: 'GET'
  2707. });
  2708. if (result === 'Success') {
  2709. if (data?.finalUrl.includes('accounts/login')) {
  2710. logStatus.error(`Error:${i18n('loginIns')}`, true);
  2711. return false;
  2712. } else if (data?.finalUrl.includes('www.instagram.com/challenge')) {
  2713. logStatus.error(`Error:${i18n('insBanned')}`);
  2714. return false;
  2715. }
  2716. if (data?.status === 200) {
  2717. const csrftoken = data.responseText.match(/"csrf_token":"(.+?)"/)?.[1];
  2718. const hash = data.responseText.match(/"rollout_hash":"(.+?)"/)?.[1];
  2719. if (name === 'instagram') {
  2720. if (csrftoken && hash) {
  2721. this.#auth = {
  2722. csrftoken: csrftoken,
  2723. hash: hash
  2724. };
  2725. return true;
  2726. }
  2727. return false;
  2728. }
  2729. const id = data.responseText.match(/"profilePage_([\d]+?)"/)?.[1];
  2730. if (id) {
  2731. this.#setCache(name, id);
  2732. logStatus.success();
  2733. return id;
  2734. }
  2735. logStatus.error('Error: Get ins data error!');
  2736. return false;
  2737. }
  2738. logStatus.error(`${result}:${statusText}(${status})`);
  2739. return false;
  2740. }
  2741. return false;
  2742. } catch (error) {
  2743. throwError(error, 'Instagram.getUserInfo');
  2744. return false;
  2745. }
  2746. }
  2747. async #followUser(name) {
  2748. try {
  2749. const id = await this.#getUserInfo(name);
  2750. if (!id) {
  2751. return false;
  2752. }
  2753. const logStatus = scripts_echoLog({
  2754. type: 'followingIns',
  2755. text: name
  2756. });
  2757. const {
  2758. result,
  2759. statusText,
  2760. status,
  2761. data
  2762. } = await tools_httpRequest({
  2763. url: `https://www.instagram.com/web/friendships/${id}/follow/`,
  2764. method: 'POST',
  2765. dataType: 'json',
  2766. headers: {
  2767. 'x-csrftoken': this.#auth.csrftoken,
  2768. origin: 'https://www.instagram.com',
  2769. referer: `https://www.instagram.com/${name}/`,
  2770. 'content-type': 'application/x-www-form-urlencoded',
  2771. 'sec-fetch-site': 'same-origin',
  2772. 'x-instagram-ajax': this.#auth.hash
  2773. }
  2774. });
  2775. if (result === 'Success') {
  2776. if (data?.status === 200 && data.response?.result === 'following') {
  2777. logStatus.success();
  2778. this.tasks.users = unique([ ...this.tasks.users, name ]);
  2779. return true;
  2780. }
  2781. logStatus.error(`Error:${data?.response?.feedback_message || `${data?.statusText}(${data?.status})`}`);
  2782. return false;
  2783. }
  2784. logStatus.error(`${result}:${statusText}(${status})`);
  2785. return false;
  2786. } catch (error) {
  2787. throwError(error, 'Instagram.followUser');
  2788. return false;
  2789. }
  2790. }
  2791. async #unfollowUser(name) {
  2792. try {
  2793. if (this.whiteList.users.includes(name)) {
  2794. scripts_echoLog({
  2795. type: 'whiteList',
  2796. text: 'Instagram.unfollowUser',
  2797. id: name
  2798. });
  2799. return true;
  2800. }
  2801. const id = await this.#getUserInfo(name);
  2802. if (!id) {
  2803. return false;
  2804. }
  2805. const logStatus = scripts_echoLog({
  2806. type: 'unfollowingIns',
  2807. text: name
  2808. });
  2809. const {
  2810. result,
  2811. statusText,
  2812. status,
  2813. data
  2814. } = await tools_httpRequest({
  2815. url: `https://www.instagram.com/web/friendships/${id}/unfollow/`,
  2816. method: 'POST',
  2817. dataType: 'json',
  2818. headers: {
  2819. 'x-csrftoken': this.#auth.csrftoken,
  2820. origin: 'https://www.instagram.com',
  2821. referer: `https://www.instagram.com/${name}/`,
  2822. 'content-type': 'application/x-www-form-urlencoded',
  2823. 'sec-fetch-site': 'same-origin',
  2824. 'x-instagram-ajax': this.#auth.hash
  2825. }
  2826. });
  2827. if (result === 'Success') {
  2828. if (data?.status === 200 && data.response?.status === 'ok') {
  2829. logStatus.success();
  2830. return true;
  2831. }
  2832. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2833. return false;
  2834. }
  2835. logStatus.error(`${result}:${statusText}(${status})`);
  2836. return false;
  2837. } catch (error) {
  2838. throwError(error, 'Instagram.unfollowUser');
  2839. return false;
  2840. }
  2841. }
  2842. async toggle({
  2843. doTask = true,
  2844. userLinks = []
  2845. }) {
  2846. try {
  2847. if (!this.#initialized) {
  2848. scripts_echoLog({
  2849. text: i18n('needInit')
  2850. });
  2851. return false;
  2852. }
  2853. const prom = [];
  2854. if (doTask && !globalOptions.doTask.instagram.users || !doTask && !globalOptions.undoTask.instagram.users) {
  2855. scripts_echoLog({
  2856. type: 'globalOptionsSkip',
  2857. text: 'instagram.users'
  2858. });
  2859. } else {
  2860. const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1]);
  2861. if (realUsers.length > 0) {
  2862. for (const username of realUsers) {
  2863. if (doTask) {
  2864. prom.push(this.#followUser(username));
  2865. } else {
  2866. prom.push(this.#unfollowUser(username));
  2867. }
  2868. await delay(1e3);
  2869. }
  2870. }
  2871. }
  2872. return await Promise.all(prom).then(() => true);
  2873. } catch (error) {
  2874. throwError(error, 'Instagram.toggleUsers');
  2875. return false;
  2876. }
  2877. }
  2878. #setCache(name, id) {
  2879. try {
  2880. this.#cache[name] = id;
  2881. GM_setValue('instagramCache', this.#cache);
  2882. } catch (error) {
  2883. throwError(error, 'Instagram.setCache');
  2884. }
  2885. }
  2886. }
  2887. const social_Instagram = Instagram;
  2888. class Reddit extends social_Social {
  2889. tasks;
  2890. whiteList;
  2891. #auth;
  2892. #initialized = false;
  2893. constructor() {
  2894. super();
  2895. const defaultTasksTemplate = {
  2896. reddits: []
  2897. };
  2898. this.tasks = defaultTasksTemplate;
  2899. this.whiteList = {
  2900. ...defaultTasksTemplate,
  2901. ...GM_getValue('whiteList')?.reddit || {}
  2902. };
  2903. }
  2904. async init() {
  2905. try {
  2906. if (this.#initialized) {
  2907. return true;
  2908. }
  2909. const isVerified = await this.#updateAuth();
  2910. if (isVerified) {
  2911. scripts_echoLog({}).success(i18n('initSuccess', 'Reddit'));
  2912. this.#initialized = true;
  2913. return true;
  2914. }
  2915. scripts_echoLog({}).error(i18n('initFailed', 'Reddit'));
  2916. return false;
  2917. } catch (error) {
  2918. throwError(error, 'Reddit.init');
  2919. return false;
  2920. }
  2921. }
  2922. async #useBeta() {
  2923. try {
  2924. const logStatus = scripts_echoLog({
  2925. text: i18n('changingRedditVersion')
  2926. });
  2927. return await new Promise(resolve => {
  2928. const newTab = GM_openInTab('https://www.reddit.com/', {
  2929. active: true,
  2930. insert: true,
  2931. setParent: true
  2932. });
  2933. newTab.name = 'ATv4_redditAuth';
  2934. newTab.onclose = async () => {
  2935. logStatus.success();
  2936. resolve(await this.#updateAuth(true));
  2937. };
  2938. });
  2939. } catch (error) {
  2940. throwError(error, 'Reddit.useBeta');
  2941. return false;
  2942. }
  2943. }
  2944. async #updateAuth(beta = false) {
  2945. try {
  2946. const logStatus = scripts_echoLog({
  2947. text: i18n('updatingAuth', 'Reddit')
  2948. });
  2949. const {
  2950. result,
  2951. statusText,
  2952. status,
  2953. data
  2954. } = await tools_httpRequest({
  2955. url: 'https://www.reddit.com/',
  2956. method: 'GET',
  2957. nochche: true,
  2958. headers: {
  2959. 'Cache-Control': 'no-cache'
  2960. }
  2961. });
  2962. if (result === 'Success') {
  2963. if (data?.responseText.includes('www.reddit.com/login/')) {
  2964. logStatus.error(`Error:${i18n('loginReddit')}`, true);
  2965. return false;
  2966. }
  2967. if (data?.status === 200) {
  2968. if (data.responseText.includes('redesign-beta-optin-btn') && !beta) {
  2969. return await this.#useBeta();
  2970. }
  2971. const accessToken = data.responseText.match(/"accessToken":"(.*?)","expires":"(.*?)"/)?.[1];
  2972. if (accessToken) {
  2973. this.#auth = {
  2974. token: accessToken
  2975. };
  2976. logStatus.success();
  2977. return true;
  2978. }
  2979. logStatus.error('Error: Parameter "accessToken" not found!');
  2980. return false;
  2981. }
  2982. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2983. return false;
  2984. }
  2985. logStatus.error(`${result}:${statusText}(${status})`);
  2986. return false;
  2987. } catch (error) {
  2988. throwError(error, 'Reddit.updateAuth');
  2989. return false;
  2990. }
  2991. }
  2992. async #toggleTask({
  2993. name,
  2994. doTask = true
  2995. }) {
  2996. try {
  2997. if (!doTask && this.whiteList.reddits.includes(name)) {
  2998. scripts_echoLog({
  2999. type: 'whiteList',
  3000. text: 'Reddit.undoTask',
  3001. id: name
  3002. });
  3003. return true;
  3004. }
  3005. let type = doTask ? 'joiningReddit' : 'leavingReddit';
  3006. if (/^u_/.test(name)) {
  3007. type = doTask ? 'followingRedditUser' : 'unfollowingRedditUser';
  3008. }
  3009. const logStatus = scripts_echoLog({
  3010. type: type,
  3011. text: name
  3012. });
  3013. const {
  3014. result,
  3015. statusText,
  3016. status,
  3017. data
  3018. } = await tools_httpRequest({
  3019. url: 'https://oauth.reddit.com/api/subscribe?redditWebClient=desktop2x&app=desktop2x-client-production&raw_json=1&gilding_detail=1',
  3020. method: 'POST',
  3021. headers: {
  3022. authorization: `Bearer ${this.#auth.token}`,
  3023. 'content-type': 'application/x-www-form-urlencoded'
  3024. },
  3025. data: $.param({
  3026. action: doTask ? 'sub' : 'unsub',
  3027. sr_name: name,
  3028. api_type: 'json'
  3029. })
  3030. });
  3031. if (result === 'Success') {
  3032. if (data?.status === 200) {
  3033. logStatus.success();
  3034. if (doTask) {
  3035. this.tasks.reddits = unique([ ...this.tasks.reddits, name ]);
  3036. }
  3037. return true;
  3038. }
  3039. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3040. return false;
  3041. }
  3042. logStatus.error(`${result}:${statusText}(${status})`);
  3043. return false;
  3044. } catch (error) {
  3045. throwError(error, 'Reddit.toggleTask');
  3046. return false;
  3047. }
  3048. }
  3049. async toggle({
  3050. doTask = true,
  3051. redditLinks = []
  3052. }) {
  3053. try {
  3054. if (!this.#initialized) {
  3055. scripts_echoLog({
  3056. text: i18n('needInit')
  3057. });
  3058. return false;
  3059. }
  3060. const prom = [];
  3061. if (doTask && !globalOptions.doTask.reddit.reddits || !doTask && !globalOptions.undoTask.reddit.reddits) {
  3062. scripts_echoLog({
  3063. type: 'globalOptionsSkip',
  3064. text: 'reddit.reddits'
  3065. });
  3066. } else {
  3067. const realReddits = this.getRealParams('reddits', redditLinks, doTask, link => {
  3068. const name = link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1];
  3069. const userName = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1];
  3070. if (userName) {
  3071. return name || userName;
  3072. }
  3073. return name;
  3074. });
  3075. if (realReddits.length > 0) {
  3076. for (const name of realReddits) {
  3077. prom.push(this.#toggleTask({
  3078. name: name,
  3079. doTask: doTask
  3080. }));
  3081. await delay(1e3);
  3082. }
  3083. }
  3084. }
  3085. return await Promise.all(prom).then(() => true);
  3086. } catch (error) {
  3087. throwError(error, 'Reddit.toggle');
  3088. return false;
  3089. }
  3090. }
  3091. }
  3092. const social_Reddit = Reddit;
  3093. class Twitch extends social_Social {
  3094. tasks;
  3095. whiteList;
  3096. #auth = GM_getValue('twitchAuth') || {};
  3097. #cache = GM_getValue('twitchCache') || {};
  3098. #initialized = false;
  3099. #integrityToken;
  3100. constructor() {
  3101. super();
  3102. const defaultTasksTemplate = {
  3103. channels: []
  3104. };
  3105. this.tasks = defaultTasksTemplate;
  3106. this.whiteList = {
  3107. ...defaultTasksTemplate,
  3108. ...GM_getValue('whiteList')?.twitch || {}
  3109. };
  3110. }
  3111. async init() {
  3112. try {
  3113. if (this.#initialized) {
  3114. return true;
  3115. }
  3116. if (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId) {
  3117. if (await this.#updateAuth()) {
  3118. this.#initialized = true;
  3119. return true;
  3120. }
  3121. return false;
  3122. }
  3123. const isVerified = await this.#verifyAuth(true);
  3124. if (isVerified) {
  3125. scripts_echoLog({}).success(i18n('initSuccess', 'Twitch'));
  3126. this.#initialized = true;
  3127. return true;
  3128. }
  3129. GM_setValue('twitchAuth', null);
  3130. if (await this.#updateAuth()) {
  3131. scripts_echoLog({}).success(i18n('initSuccess', 'Twitch'));
  3132. this.#initialized = true;
  3133. return true;
  3134. }
  3135. scripts_echoLog({}).error(i18n('initFailed', 'Twitch'));
  3136. return false;
  3137. } catch (error) {
  3138. throwError(error, 'Twitch.init');
  3139. return false;
  3140. }
  3141. }
  3142. async #verifyAuth(isFirst) {
  3143. try {
  3144. const logStatus = scripts_echoLog({
  3145. text: i18n('verifyingAuth', 'Twitch')
  3146. });
  3147. const {
  3148. result,
  3149. statusText,
  3150. status,
  3151. data
  3152. } = await tools_httpRequest({
  3153. url: 'https://gql.twitch.tv/gql',
  3154. method: 'POST',
  3155. dataType: 'json',
  3156. headers: {
  3157. Authorization: `OAuth ${this.#auth.authToken}`,
  3158. 'Client-Id': this.#auth.clientId
  3159. },
  3160. data: '[{"operationName":"FrontPageNew_User","variables":{"limit":1},"extensions":{"persistedQuery":{"version":1,' + '"sha256Hash":"64bd07a2cbaca80699d62636d966cf6395a5d14a1f0a14282067dcb28b13eb11"}}}]'
  3161. });
  3162. if (result === 'Success') {
  3163. if (data?.status === 200 && data.response?.[0]?.data?.currentUser) {
  3164. await this.#integrity(isFirst);
  3165. logStatus.success();
  3166. return true;
  3167. }
  3168. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3169. return false;
  3170. }
  3171. logStatus.error(`${result}:${statusText}(${status})`);
  3172. return false;
  3173. } catch (error) {
  3174. throwError(error, 'Twitch.verifyAuth');
  3175. return false;
  3176. }
  3177. }
  3178. async #integrity(isFirst = true, ct = '') {
  3179. try {
  3180. const logStatus = scripts_echoLog({
  3181. text: i18n('checkingTwitchIntegrity')
  3182. });
  3183. if (isFirst && (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId)) {
  3184. return await this.#updateAuth(false);
  3185. }
  3186. const {
  3187. result,
  3188. statusText,
  3189. status,
  3190. data
  3191. } = await tools_httpRequest({
  3192. url: 'https://gql.twitch.tv/integrity',
  3193. method: 'POST',
  3194. dataType: 'json',
  3195. anonymous: true,
  3196. headers: {
  3197. Origin: 'https://www.twitch.tv',
  3198. Referer: 'https://www.twitch.tv/',
  3199. Authorization: `OAuth ${this.#auth.authToken}`,
  3200. 'Client-Id': this.#auth.clientId,
  3201. 'Client-Version': this.#auth.clientVersion,
  3202. 'X-Device-Id': this.#auth.deviceId,
  3203. 'Client-Session-Id': this.#auth.clientSessionId,
  3204. 'x-kpsdk-ct': ct
  3205. }
  3206. });
  3207. if (result === 'Success') {
  3208. if (!ct && data?.responseHeaders?.['x-kpsdk-ct']) {
  3209. return await this.#integrity(isFirst, data.responseHeaders['x-kpsdk-ct']);
  3210. }
  3211. if (data?.status === 200 && data.response?.token) {
  3212. this.#integrityToken = data.response.token;
  3213. logStatus.success();
  3214. return true;
  3215. }
  3216. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3217. return false;
  3218. }
  3219. logStatus.error(`${result}:${statusText}(${status})`);
  3220. return false;
  3221. } catch (error) {
  3222. throwError(error, 'Twitch.integrity');
  3223. return false;
  3224. }
  3225. }
  3226. async #updateAuth(isFirst = true) {
  3227. try {
  3228. const logStatus = scripts_echoLog({
  3229. text: i18n('updatingAuth', 'Twitch')
  3230. });
  3231. return await new Promise(resolve => {
  3232. const newTab = GM_openInTab('https://www.twitch.tv/', {
  3233. active: true,
  3234. insert: true,
  3235. setParent: true
  3236. });
  3237. newTab.name = 'ATv4_twitchAuth';
  3238. newTab.onclose = async () => {
  3239. const auth = GM_getValue('twitchAuth');
  3240. if (auth) {
  3241. this.#auth = auth;
  3242. logStatus.success();
  3243. resolve(await this.#verifyAuth(isFirst));
  3244. } else {
  3245. logStatus.error('Error: Update twitch auth failed!');
  3246. resolve(false);
  3247. }
  3248. };
  3249. });
  3250. } catch (error) {
  3251. throwError(error, 'Twitch.updateAuth');
  3252. return false;
  3253. }
  3254. }
  3255. async #toggleChannel({
  3256. name,
  3257. doTask = true
  3258. }) {
  3259. try {
  3260. if (!doTask && this.whiteList.channels.includes(name)) {
  3261. scripts_echoLog({
  3262. type: 'whiteList',
  3263. text: 'Twitch.unfollowChannel',
  3264. id: name
  3265. });
  3266. return true;
  3267. }
  3268. const channelId = await this.#getChannelId(name);
  3269. if (!channelId) {
  3270. return false;
  3271. }
  3272. const logStatus = scripts_echoLog({
  3273. type: `${doTask ? '' : 'un'}followingTwitchChannel`,
  3274. text: name
  3275. });
  3276. const followData = `[{"operationName":"FollowButton_FollowUser","variables":{"input":{"disableNotifications":false,"targetID":"${channelId}` + '"}},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"800e7346bdf7e5278a3c1d3f21b2b56e2639928f86815677a7126b093b2fdd08"}}}]';
  3277. const unfollowData = `[{"operationName":"FollowButton_UnfollowUser","variables":{"input":{"targetID":"${channelId}"}},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"f7dae976ebf41c755ae2d758546bfd176b4eeb856656098bb40e0a672ca0d880"}}}]';
  3278. const {
  3279. result,
  3280. statusText,
  3281. status,
  3282. data
  3283. } = await tools_httpRequest({
  3284. url: 'https://gql.twitch.tv/gql',
  3285. method: 'POST',
  3286. dataType: 'json',
  3287. anonymous: true,
  3288. headers: {
  3289. Origin: 'https://www.twitch.tv',
  3290. Referer: 'https://www.twitch.tv/',
  3291. Authorization: `OAuth ${this.#auth.authToken}`,
  3292. 'Client-Id': this.#auth.clientId,
  3293. 'Client-Version': this.#auth.clientVersion,
  3294. 'X-Device-Id': this.#auth.deviceId,
  3295. 'Client-Session-Id': this.#auth.clientSessionId,
  3296. 'Client-Integrity': this.#integrityToken
  3297. },
  3298. data: doTask ? followData : unfollowData
  3299. });
  3300. if (result === 'Success') {
  3301. if (data?.status === 200 && data.response?.[0] && !data.response[0].errors) {
  3302. logStatus.success();
  3303. if (doTask) {
  3304. this.tasks.channels = unique([ ...this.tasks.channels, name ]);
  3305. }
  3306. return true;
  3307. }
  3308. logStatus.error(`Error:${data?.response?.[0].errors?.[0]?.message || `${data?.statusText}(${data?.status})`}`);
  3309. return false;
  3310. }
  3311. logStatus.error(`${result}:${statusText}(${status})`);
  3312. return false;
  3313. } catch (error) {
  3314. throwError(error, 'Twitch.toggleChannel');
  3315. return false;
  3316. }
  3317. }
  3318. async #getChannelId(name) {
  3319. try {
  3320. const logStatus = scripts_echoLog({
  3321. type: 'gettingTwitchChannelId',
  3322. text: name
  3323. });
  3324. const channelId = this.#cache[name];
  3325. if (channelId) {
  3326. logStatus.success();
  3327. return channelId;
  3328. }
  3329. const {
  3330. result,
  3331. statusText,
  3332. status,
  3333. data
  3334. } = await tools_httpRequest({
  3335. url: 'https://gql.twitch.tv/gql',
  3336. method: 'POST',
  3337. headers: {
  3338. Authorization: `OAuth ${this.#auth.authToken}`,
  3339. 'Client-Id': this.#auth.clientId
  3340. },
  3341. responseType: 'json',
  3342. data: `[{"operationName":"ActiveWatchParty","variables":{"channelLogin":"${name}"},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"4a8156c97b19e3a36e081cf6d6ddb5dbf9f9b02ae60e4d2ff26ed70aebc80a30"}}}]'
  3343. });
  3344. if (result === 'Success') {
  3345. if (data?.status === 200) {
  3346. const channelId = data.response?.[0]?.data?.user?.id;
  3347. if (channelId) {
  3348. this.#setCache(name, String(channelId));
  3349. logStatus.success();
  3350. return channelId;
  3351. }
  3352. logStatus.error(`Error:${data.statusText}(${data.status})`);
  3353. return false;
  3354. }
  3355. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3356. return false;
  3357. }
  3358. logStatus.error(`${result}:${statusText}(${status})`);
  3359. return false;
  3360. } catch (error) {
  3361. throwError(error, 'Twitch.getChannelId');
  3362. return false;
  3363. }
  3364. }
  3365. async toggle({
  3366. doTask = true,
  3367. channelLinks = []
  3368. }) {
  3369. try {
  3370. if (!this.#initialized) {
  3371. scripts_echoLog({
  3372. text: i18n('needInit')
  3373. });
  3374. return false;
  3375. }
  3376. const prom = [];
  3377. if (doTask && !globalOptions.doTask.twitch.channels || !doTask && !globalOptions.undoTask.twitch.channels) {
  3378. scripts_echoLog({
  3379. type: 'globalOptionsSkip',
  3380. text: 'twitch.channels'
  3381. });
  3382. } else {
  3383. const realChannels = this.getRealParams('channels', channelLinks, doTask, link => link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2]);
  3384. if (realChannels.length > 0) {
  3385. for (const channel of realChannels) {
  3386. prom.push(this.#toggleChannel({
  3387. name: channel,
  3388. doTask: doTask
  3389. }));
  3390. await delay(1e3);
  3391. }
  3392. }
  3393. }
  3394. return Promise.all(prom).then(() => true);
  3395. } catch (error) {
  3396. throwError(error, 'Twitch.toggle');
  3397. return false;
  3398. }
  3399. }
  3400. #setCache(name, id) {
  3401. try {
  3402. this.#cache[name] = id;
  3403. GM_setValue('twitchCache', this.#cache);
  3404. } catch (error) {
  3405. throwError(error, 'Twitch.setCache');
  3406. }
  3407. }
  3408. }
  3409. const social_Twitch = Twitch;
  3410. var main = __webpack_require__(356);
  3411. class Twitter extends social_Social {
  3412. tasks;
  3413. whiteList;
  3414. #verifyId = globalOptions.other.twitterVerifyId;
  3415. #auth = GM_getValue('twitterAuth') || {};
  3416. #cache = GM_getValue('twitterCache') || {};
  3417. #initialized = false;
  3418. #session;
  3419. constructor() {
  3420. super();
  3421. const defaultTasksTemplate = {
  3422. users: [],
  3423. retweets: [],
  3424. likes: []
  3425. };
  3426. this.tasks = defaultTasksTemplate;
  3427. this.whiteList = {
  3428. ...defaultTasksTemplate,
  3429. ...GM_getValue('whiteList')?.twitter || {}
  3430. };
  3431. }
  3432. async init() {
  3433. try {
  3434. if (this.#initialized) {
  3435. return true;
  3436. }
  3437. if (!this.#auth.ct0) {
  3438. if (await this.#updateAuth()) {
  3439. this.#initialized = true;
  3440. return true;
  3441. }
  3442. return false;
  3443. }
  3444. this.#session = await (0, main.createSession)();
  3445. const isVerified = await this.#verifyAuth();
  3446. if (isVerified) {
  3447. scripts_echoLog({}).success(i18n('initSuccess', 'Twitter'));
  3448. this.#initialized = true;
  3449. return true;
  3450. }
  3451. GM_setValue('twitterAuth', null);
  3452. if (await this.#updateAuth()) {
  3453. scripts_echoLog({}).success(i18n('initSuccess', 'Twitter'));
  3454. this.#initialized = true;
  3455. return true;
  3456. }
  3457. scripts_echoLog({}).error(i18n('initFailed', 'Twitter'));
  3458. return false;
  3459. } catch (error) {
  3460. throwError(error, 'Twitter.init');
  3461. return false;
  3462. }
  3463. }
  3464. async #verifyAuth() {
  3465. try {
  3466. return await this.#toggleUser({
  3467. name: 'verify',
  3468. doTask: true,
  3469. verify: true
  3470. });
  3471. } catch (error) {
  3472. throwError(error, 'Twitter.verifyAuth');
  3473. return false;
  3474. }
  3475. }
  3476. async #updateAuth() {
  3477. try {
  3478. const logStatus = scripts_echoLog({
  3479. text: i18n('updatingAuth', 'Twitter')
  3480. });
  3481. return await new Promise(resolve => {
  3482. GM_cookie.list({
  3483. url: 'https://x.com/settings/account'
  3484. }, async (cookies, error) => {
  3485. if (!error) {
  3486. const [ ct0, isLogin ] = cookies.map(cookie => [ 'ct0', 'twid' ].includes(cookie.name) ? cookie.value : null).filter(cookie => cookie);
  3487. if (isLogin && ct0) {
  3488. GM_setValue('twitterAuth', {
  3489. ct0: ct0
  3490. });
  3491. this.#auth = {
  3492. ct0: ct0
  3493. };
  3494. logStatus.success();
  3495. resolve(await this.#verifyAuth());
  3496. } else {
  3497. logStatus.error(i18n('needLogin'));
  3498. resolve(false);
  3499. }
  3500. } else {
  3501. logStatus.error('Error: Update twitter auth failed!');
  3502. resolve(false);
  3503. }
  3504. });
  3505. });
  3506. } catch (error) {
  3507. throwError(error, 'Twitter.updateToken');
  3508. return false;
  3509. }
  3510. }
  3511. async #toggleUser({
  3512. name,
  3513. doTask = true,
  3514. verify = false,
  3515. retry = false
  3516. }) {
  3517. try {
  3518. if (!doTask && !verify && this.whiteList.users.includes(name)) {
  3519. scripts_echoLog({
  3520. type: 'whiteList',
  3521. text: 'Twitter.unfollowUser',
  3522. id: name
  3523. });
  3524. return true;
  3525. }
  3526. const userId = verify ? this.#verifyId : await this.userName2id(name);
  3527. if (!userId) {
  3528. return false;
  3529. }
  3530. const logStatus = verify ? scripts_echoLog({
  3531. text: i18n('verifyingAuth', 'Twitter')
  3532. }) : scripts_echoLog({
  3533. type: `${doTask ? '' : 'un'}followingTwitterUser`,
  3534. text: name
  3535. });
  3536. const {
  3537. result,
  3538. statusText,
  3539. status,
  3540. data
  3541. } = await tools_httpRequest({
  3542. url: `https://x.com/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`,
  3543. method: 'POST',
  3544. headers: {
  3545. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3546. 'Content-Type': 'application/x-www-form-urlencoded',
  3547. 'x-csrf-token': this.#auth.ct0,
  3548. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3549. 'X-Twitter-Active-User': 'yes',
  3550. 'x-client-transaction-id': await this.#session.get('POST', `/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`)
  3551. },
  3552. responseType: 'json',
  3553. data: $.param({
  3554. include_profile_interstitial_type: 1,
  3555. include_blocking: 1,
  3556. include_blocked_by: 1,
  3557. include_followed_by: 1,
  3558. include_want_retweets: 1,
  3559. include_mute_edge: 1,
  3560. include_can_dm: 1,
  3561. include_can_media_tag: 1,
  3562. skip_status: 1,
  3563. id: userId
  3564. })
  3565. });
  3566. if (result === 'Success') {
  3567. if (data?.status === 200) {
  3568. logStatus.success();
  3569. if (doTask && !verify) {
  3570. this.tasks.users = unique([ ...this.tasks.users, name ]);
  3571. }
  3572. return true;
  3573. }
  3574. if (verify && data?.status === 403) {
  3575. if (data.response?.errors?.[0]?.code === 158) {
  3576. logStatus.success();
  3577. return true;
  3578. }
  3579. if (data.response?.errors?.[0]?.code === 353 && !retry && data.responseHeaders?.['set-cookie']) {
  3580. this.#auth.ct0 = data.responseHeaders['set-cookie']?.find(cookie => cookie.includes('ct0='))?.split(';')?.at(0)?.split('=')?.at(-1) || this.#auth.ct0;
  3581. logStatus.warning(i18n('retry'));
  3582. return this.#toggleUser({
  3583. name: name,
  3584. doTask: doTask,
  3585. verify: verify,
  3586. retry: true
  3587. });
  3588. }
  3589. }
  3590. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3591. return false;
  3592. }
  3593. logStatus.error(`${result}:${statusText}(${status})`);
  3594. return false;
  3595. } catch (error) {
  3596. throwError(error, 'Twitter.toggleUser');
  3597. return false;
  3598. }
  3599. }
  3600. async userName2id(name) {
  3601. try {
  3602. const logStatus = scripts_echoLog({
  3603. type: 'gettingTwitterUserId',
  3604. text: name
  3605. });
  3606. const userId = this.#cache[name];
  3607. if (userId) {
  3608. logStatus.success();
  3609. return userId;
  3610. }
  3611. const {
  3612. result,
  3613. statusText,
  3614. status,
  3615. data
  3616. } = await tools_httpRequest({
  3617. 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`,
  3618. method: 'GET',
  3619. headers: {
  3620. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3621. 'content-type': 'application/json',
  3622. referer: `https://x.com/${name}`,
  3623. 'x-csrf-token': this.#auth.ct0,
  3624. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3625. 'X-Twitter-Active-User': 'yes',
  3626. '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`)
  3627. },
  3628. responseType: 'json'
  3629. });
  3630. if (result === 'Success') {
  3631. if (data?.status === 200) {
  3632. let response = data.response || (typeof data.responseText === 'object' ? data.responseText : null);
  3633. if (!response) {
  3634. try {
  3635. response = JSON.parse(data.responseText);
  3636. } catch (error) {
  3637. response = null;
  3638. }
  3639. }
  3640. const userId = String(response?.data?.user?.result?.rest_id);
  3641. if (userId) {
  3642. this.#setCache(name, userId);
  3643. logStatus.success();
  3644. return userId;
  3645. }
  3646. logStatus.error(`Error:${data.statusText}(${data.status})`);
  3647. return false;
  3648. }
  3649. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3650. return false;
  3651. }
  3652. logStatus.error(`${result}:${statusText}(${status})`);
  3653. return false;
  3654. } catch (error) {
  3655. throwError(error, 'Twitter.getUserId');
  3656. return false;
  3657. }
  3658. }
  3659. async #toggleRetweet({
  3660. retweetId,
  3661. doTask = true
  3662. }) {
  3663. try {
  3664. if (!doTask && this.whiteList.retweets.includes(retweetId)) {
  3665. scripts_echoLog({
  3666. type: 'whiteList',
  3667. text: 'Twitter.unretweet',
  3668. id: retweetId
  3669. });
  3670. return true;
  3671. }
  3672. const logStatus = scripts_echoLog({
  3673. type: `${doTask ? '' : 'un'}retweetting`,
  3674. text: retweetId
  3675. });
  3676. const {
  3677. result,
  3678. statusText,
  3679. status,
  3680. data
  3681. } = await tools_httpRequest({
  3682. url: `https://x.com/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`,
  3683. method: 'POST',
  3684. headers: {
  3685. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3686. 'Content-Type': 'application/json',
  3687. origin: 'https://x.com',
  3688. referer: 'https://x.com/home',
  3689. 'x-csrf-token': this.#auth.ct0,
  3690. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3691. 'X-Twitter-Active-User': 'yes',
  3692. 'x-client-transaction-id': await this.#session.get('POST', `/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`)
  3693. },
  3694. data: `{"variables":{"${doTask ? '' : 'source_'}tweet_id":"${retweetId}","dark_request":false},"queryId":"${doTask ? 'ojPdsZsimiJrUGLR1sjUtA' : 'iQtK4dl5hBmXewYZuEOKVw'}"}`,
  3695. responseType: 'json'
  3696. });
  3697. if (result === 'Success') {
  3698. if (data?.status === 200 || data?.status === 403 && data.response?.errors?.[0]?.code === 327) {
  3699. if (data.response?.errors && data.response?.errors?.[0]?.code !== 327) {
  3700. logStatus.error(`Error:${data.response?.errors?.[0]?.message}`);
  3701. return false;
  3702. }
  3703. logStatus.success();
  3704. if (doTask) {
  3705. this.tasks.retweets = unique([ ...this.tasks.retweets, retweetId ]);
  3706. }
  3707. return true;
  3708. }
  3709. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3710. return false;
  3711. }
  3712. logStatus.error(`${result}:${statusText}(${status})`);
  3713. return false;
  3714. } catch (error) {
  3715. throwError(error, 'Twitter.toggleRetweet');
  3716. return false;
  3717. }
  3718. }
  3719. async toggle({
  3720. doTask = true,
  3721. userLinks = [],
  3722. retweetLinks = []
  3723. }) {
  3724. try {
  3725. if (!this.#initialized) {
  3726. scripts_echoLog({
  3727. text: i18n('needInit')
  3728. });
  3729. return false;
  3730. }
  3731. const prom = [];
  3732. if (doTask && !globalOptions.doTask.twitter.users || !doTask && !globalOptions.undoTask.twitter.users) {
  3733. scripts_echoLog({
  3734. type: 'globalOptionsSkip',
  3735. text: 'twitter.users'
  3736. });
  3737. } else {
  3738. const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/x\.com\/(.+)/)?.[1] || link.match(/https:\/\/twitter\.com\/(.+)/)?.[1]);
  3739. if (realUsers.length > 0) {
  3740. for (const user of realUsers) {
  3741. prom.push(this.#toggleUser({
  3742. name: user,
  3743. doTask: doTask
  3744. }));
  3745. await delay(1e3);
  3746. }
  3747. }
  3748. }
  3749. if (doTask && !globalOptions.doTask.twitter.retweets || !doTask && !globalOptions.undoTask.twitter.retweets) {
  3750. scripts_echoLog({
  3751. type: 'globalOptionsSkip',
  3752. text: 'twitter.retweets'
  3753. });
  3754. } else {
  3755. const realRetweets = this.getRealParams('retweets', retweetLinks, doTask, link => link.match(/https:\/\/x\.com\/.*?\/status\/([\d]+)/)?.[1] || link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1]);
  3756. if (realRetweets.length > 0) {
  3757. for (const retweet of realRetweets) {
  3758. prom.push(this.#toggleRetweet({
  3759. retweetId: retweet,
  3760. doTask: doTask
  3761. }));
  3762. await delay(1e3);
  3763. }
  3764. }
  3765. }
  3766. return Promise.all(prom).then(() => true);
  3767. } catch (error) {
  3768. throwError(error, 'Twitter.toggle');
  3769. return false;
  3770. }
  3771. }
  3772. #setCache(name, id) {
  3773. try {
  3774. this.#cache[name] = id;
  3775. GM_setValue('twitterCache', this.#cache);
  3776. } catch (error) {
  3777. throwError(error, 'Twitter.setCache');
  3778. }
  3779. }
  3780. }
  3781. const social_Twitter = Twitter;
  3782. class Vk extends social_Social {
  3783. tasks;
  3784. whiteList;
  3785. #username = '';
  3786. #cache = GM_getValue('vkCache') || {};
  3787. #initialized = false;
  3788. constructor() {
  3789. super();
  3790. const defaultTasksTemplate = {
  3791. names: []
  3792. };
  3793. this.tasks = defaultTasksTemplate;
  3794. this.whiteList = {
  3795. ...defaultTasksTemplate,
  3796. ...GM_getValue('whiteList')?.vk || {}
  3797. };
  3798. }
  3799. async init() {
  3800. try {
  3801. if (this.#initialized) {
  3802. return true;
  3803. }
  3804. const isVerified = await this.#verifyAuth();
  3805. if (isVerified) {
  3806. scripts_echoLog({}).success(i18n('initSuccess', 'Vk'));
  3807. this.#initialized = true;
  3808. return true;
  3809. }
  3810. scripts_echoLog({}).error(i18n('initFailed', 'Vk'));
  3811. return false;
  3812. } catch (error) {
  3813. throwError(error, 'Vk.init');
  3814. return false;
  3815. }
  3816. }
  3817. async #verifyAuth() {
  3818. try {
  3819. const logStatus = scripts_echoLog({
  3820. text: i18n('verifyAuth', 'Vk')
  3821. });
  3822. const {
  3823. result,
  3824. statusText,
  3825. status,
  3826. data
  3827. } = await tools_httpRequest({
  3828. url: 'https://vk.com/im',
  3829. method: 'GET'
  3830. });
  3831. if (result === 'Success') {
  3832. if (data?.finalUrl.includes('vk.com/login')) {
  3833. logStatus.error(`Error:${i18n('loginVk')}`, true);
  3834. return false;
  3835. }
  3836. if (data?.status === 200) {
  3837. this.#username = data.responseText.match(/TopNavBtn__profileLink" href="\/(.*?)"/)?.[1] || '';
  3838. logStatus.success();
  3839. return true;
  3840. }
  3841. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3842. return false;
  3843. }
  3844. logStatus.error(`${result}:${statusText}(${status})`);
  3845. return false;
  3846. } catch (error) {
  3847. throwError(error, 'Vk.verifyAuth');
  3848. return false;
  3849. }
  3850. }
  3851. async #toggleGroup(name, dataParam, doTask = true) {
  3852. try {
  3853. const logStatus = scripts_echoLog({
  3854. type: doTask ? 'joiningVkGroup' : 'leavingVkGroup',
  3855. text: name
  3856. });
  3857. if (dataParam.groupAct === 'enter' && !doTask || dataParam.groupAct === 'leave' && doTask) {
  3858. logStatus.success();
  3859. return true;
  3860. }
  3861. const reqData = {
  3862. act: doTask ? 'enter' : 'leave',
  3863. al: 1,
  3864. gid: dataParam.groupId,
  3865. hash: dataParam.groupHash
  3866. };
  3867. if (doTask) {
  3868. reqData.context = '_';
  3869. }
  3870. const {
  3871. result,
  3872. statusText,
  3873. status,
  3874. data
  3875. } = await tools_httpRequest({
  3876. url: 'https://vk.com/al_groups.php',
  3877. method: 'POST',
  3878. headers: {
  3879. origin: 'https://vk.com',
  3880. referer: `https://vk.com/${name}`,
  3881. 'content-type': 'application/x-www-form-urlencoded'
  3882. },
  3883. data: $.param(reqData)
  3884. });
  3885. if (result === 'Success') {
  3886. if (data?.status === 200) {
  3887. logStatus.success();
  3888. if (doTask) {
  3889. this.tasks.names = unique([ ...this.tasks.names, name ]);
  3890. }
  3891. return true;
  3892. }
  3893. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3894. return false;
  3895. }
  3896. logStatus.error(`${result}:${statusText}(${status})`);
  3897. return false;
  3898. } catch (error) {
  3899. throwError(error, 'Vk.toggleGroup');
  3900. return false;
  3901. }
  3902. }
  3903. async #togglePublic(name, dataParam, doTask = true) {
  3904. try {
  3905. const logStatus = scripts_echoLog({
  3906. type: doTask ? 'joiningVkPublic' : 'leavingVkPublic',
  3907. text: name
  3908. });
  3909. if (dataParam.publicJoined && doTask || !dataParam.publicJoined && !doTask) {
  3910. logStatus.success();
  3911. return true;
  3912. }
  3913. const {
  3914. result,
  3915. statusText,
  3916. status,
  3917. data
  3918. } = await tools_httpRequest({
  3919. url: 'https://vk.com/al_public.php',
  3920. method: 'POST',
  3921. headers: {
  3922. origin: 'https://vk.com',
  3923. referer: `https://vk.com/${name}`,
  3924. 'content-type': 'application/x-www-form-urlencoded'
  3925. },
  3926. data: $.param({
  3927. act: doTask ? 'a_enter' : 'a_leave',
  3928. al: 1,
  3929. pid: dataParam.publicPid,
  3930. hash: dataParam.publicHash
  3931. })
  3932. });
  3933. if (result === 'Success') {
  3934. if (data?.status === 200) {
  3935. logStatus.success();
  3936. if (doTask) {
  3937. this.tasks.names = unique([ ...this.tasks.names, name ]);
  3938. }
  3939. return true;
  3940. }
  3941. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3942. return false;
  3943. }
  3944. logStatus.error(`${result}:${statusText}(${status})`);
  3945. return false;
  3946. } catch (error) {
  3947. throwError(error, 'Vk.togglePublic');
  3948. return false;
  3949. }
  3950. }
  3951. async #toggleLikeWall(name, dataParam, doTask = true) {
  3952. try {
  3953. const logStatus = scripts_echoLog({
  3954. type: doTask ? 'likingVkPublic' : 'unlikingVkPublic',
  3955. text: name
  3956. });
  3957. const postData = {
  3958. act: 'a_set_reaction',
  3959. al: 1,
  3960. event_subtype: 'post_modal',
  3961. from: 'wall_page',
  3962. hash: dataParam.hash,
  3963. object: dataParam.object,
  3964. track_code: dataParam.trackCode,
  3965. wall: 2
  3966. };
  3967. if (doTask) {
  3968. postData.reaction_id = 0;
  3969. }
  3970. const {
  3971. result: resultR,
  3972. statusText: statusTextR,
  3973. status: statusR,
  3974. data: dataR
  3975. } = await tools_httpRequest({
  3976. url: 'https://vk.com/like.php?act=a_set_reaction',
  3977. method: 'POST',
  3978. headers: {
  3979. origin: 'https://vk.com',
  3980. referer: `https://vk.com/${name}`,
  3981. 'content-type': 'application/x-www-form-urlencoded'
  3982. },
  3983. data: $.param(postData)
  3984. });
  3985. if (resultR === 'Success') {
  3986. if (dataR?.status === 200) {
  3987. if (dataR.response?.payload?.[1]?.[1]?.like_my === true) {
  3988. logStatus.success();
  3989. return true;
  3990. }
  3991. }
  3992. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  3993. return false;
  3994. }
  3995. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  3996. return false;
  3997. } catch (error) {
  3998. throwError(error, 'Vk.sendWall');
  3999. return false;
  4000. }
  4001. }
  4002. async #sendWall(name) {
  4003. try {
  4004. const logStatus = scripts_echoLog({
  4005. type: 'sendingVkWall',
  4006. text: name
  4007. });
  4008. const {
  4009. result,
  4010. statusText,
  4011. status,
  4012. data
  4013. } = await tools_httpRequest({
  4014. url: 'https://vk.com/like.php',
  4015. method: 'POST',
  4016. headers: {
  4017. origin: 'https://vk.com',
  4018. referer: `https://vk.com/${name}`,
  4019. 'content-type': 'application/x-www-form-urlencoded'
  4020. },
  4021. data: $.param({
  4022. act: 'publish_box',
  4023. al: 1,
  4024. object: name
  4025. })
  4026. });
  4027. if (result === 'Success') {
  4028. if (data?.status === 200) {
  4029. const hash = data.responseText.match(/shHash:[\s]*'(.*?)'/)?.[1];
  4030. if (hash) {
  4031. const {
  4032. result: resultR,
  4033. statusText: statusTextR,
  4034. status: statusR,
  4035. data: dataR
  4036. } = await tools_httpRequest({
  4037. url: 'https://vk.com/like.php',
  4038. method: 'POST',
  4039. headers: {
  4040. origin: 'https://vk.com',
  4041. referer: `https://vk.com/${name}`,
  4042. 'content-type': 'application/x-www-form-urlencoded'
  4043. },
  4044. data: $.param({
  4045. Message: '',
  4046. act: 'a_do_publish',
  4047. al: 1,
  4048. close_comments: 0,
  4049. friends_only: 0,
  4050. from: 'box',
  4051. hash: hash,
  4052. list: '',
  4053. mark_as_ads: 0,
  4054. mute_notifications: 0,
  4055. object: name,
  4056. ret_data: 1,
  4057. to: 0
  4058. })
  4059. });
  4060. if (resultR === 'Success') {
  4061. if (dataR?.status === 200) {
  4062. const jsonData = JSON.parse(dataR.responseText?.replace('\x3c!--', '') || '{}');
  4063. if (jsonData?.payload?.[1]?.[1]?.share_my === true) {
  4064. logStatus.success();
  4065. const postId = String(jsonData?.payload?.[1]?.[1]?.post_id);
  4066. const ownerId = String(jsonData?.payload?.[1]?.[1]?.owner_id);
  4067. if (postId && ownerId) {
  4068. this.#setCache(name, `${ownerId}_${postId}`);
  4069. }
  4070. this.tasks.names = unique([ ...this.tasks.names, name ]);
  4071. return true;
  4072. }
  4073. }
  4074. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  4075. return false;
  4076. }
  4077. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  4078. return false;
  4079. }
  4080. logStatus.error('Error: Get "hash" failed');
  4081. return false;
  4082. }
  4083. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4084. return false;
  4085. }
  4086. logStatus.error(`${result}:${statusText}(${status})`);
  4087. return false;
  4088. } catch (error) {
  4089. throwError(error, 'Vk.sendWall');
  4090. return false;
  4091. }
  4092. }
  4093. async #deleteWall(name, dataParams) {
  4094. try {
  4095. const logStatus = scripts_echoLog({
  4096. type: 'deletingVkWall',
  4097. text: name
  4098. });
  4099. const {
  4100. result,
  4101. statusText,
  4102. status,
  4103. data
  4104. } = await tools_httpRequest({
  4105. url: 'https://vk.com/al_wall.php?act=delete',
  4106. method: 'POST',
  4107. headers: {
  4108. origin: 'https://vk.com',
  4109. referer: `https://vk.com/${this.#username}?w=wall${this.#cache[name]}%2Fall`,
  4110. 'content-type': 'application/x-www-form-urlencoded'
  4111. },
  4112. data: $.param({
  4113. act: 'delete',
  4114. al: 1,
  4115. confirm: 0,
  4116. from: 'wkview',
  4117. hash: dataParams.wallHash,
  4118. post: this.#cache[name]
  4119. })
  4120. });
  4121. if (result === 'Success') {
  4122. if (data?.status === 200) {
  4123. const jsonData = JSON.parse(data.responseText?.replace('\x3c!--', '') || '{}');
  4124. if (jsonData?.payload?.[1]?.[1]) {
  4125. logStatus.success();
  4126. return true;
  4127. }
  4128. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4129. return false;
  4130. }
  4131. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4132. return false;
  4133. }
  4134. logStatus.error(`${result}:${statusText}(${status})`);
  4135. return false;
  4136. } catch (error) {
  4137. throwError(error, 'Vk.deleteWall');
  4138. return false;
  4139. }
  4140. }
  4141. async #getId(name, doTask) {
  4142. try {
  4143. let url = `https://vk.com/${name}`;
  4144. if (/^wall-/.test(name)) {
  4145. if (doTask) {
  4146. return {
  4147. type: 'sendWall'
  4148. };
  4149. }
  4150. if (!this.#cache[name]) {
  4151. return {
  4152. type: 'unSupport'
  4153. };
  4154. }
  4155. url = `https://vk.com/${this.#username}?w=wall${this.#cache[name]}`;
  4156. }
  4157. const logStatus = scripts_echoLog({
  4158. type: 'gettingVkId',
  4159. text: name
  4160. });
  4161. const {
  4162. result,
  4163. statusText,
  4164. status,
  4165. data
  4166. } = await tools_httpRequest({
  4167. url: url,
  4168. method: 'GET'
  4169. });
  4170. if (result === 'Success') {
  4171. if (data?.status === 200) {
  4172. const [ , groupAct, groupId, , groupHash ] = data.responseText.match(/Groups.(enter|leave)\(.*?,.*?([\d]+?), (&#39;|')(.*?)(&#39;|')/) || [];
  4173. const publicHash = data.responseText.match(/"enterHash":"(.*?)"/)?.[1];
  4174. const publicPid = data.responseText.match(/"public_id":([\d]+?),/)?.[1];
  4175. const publicJoined = !data.responseText.includes('Public.subscribe');
  4176. if (groupAct && groupId && groupHash) {
  4177. logStatus.success();
  4178. return {
  4179. groupAct: groupAct,
  4180. groupId: groupId,
  4181. groupHash: groupHash,
  4182. type: 'group'
  4183. };
  4184. } else if (publicHash && publicPid) {
  4185. logStatus.success();
  4186. return {
  4187. publicHash: publicHash,
  4188. publicPid: publicPid,
  4189. publicJoined: publicJoined,
  4190. type: 'public'
  4191. };
  4192. } else if (name.includes('action=like')) {
  4193. const hash = data.responseText.match(/data-reaction-hash="(.*?)"/)?.[1];
  4194. const trackCode = data.responseText.match(/data-post-track-code="(.*?)"/)?.[1];
  4195. const object = name.match(/wall-[\w_]+/)?.[0];
  4196. if (hash && trackCode && object) {
  4197. logStatus.success();
  4198. return {
  4199. type: 'likeWall',
  4200. hash: hash,
  4201. trackCode: trackCode,
  4202. object: object
  4203. };
  4204. }
  4205. } else if (data.responseText.includes('wall.deletePost') && !doTask) {
  4206. const wallHash = data.responseText.match(/wall\.deletePost\(this, '.*?', '(.*?)'\)/)?.[1];
  4207. if (wallHash) {
  4208. logStatus.success();
  4209. return {
  4210. type: 'deleteWall',
  4211. wallHash: wallHash
  4212. };
  4213. }
  4214. } else if (name.includes('wall') && doTask) {
  4215. logStatus.success();
  4216. return {
  4217. type: 'sendWall'
  4218. };
  4219. }
  4220. logStatus.error('Error: Parameters not found!');
  4221. return false;
  4222. }
  4223. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4224. return false;
  4225. }
  4226. logStatus.error(`${result}:${statusText}(${status})`);
  4227. return false;
  4228. } catch (error) {
  4229. throwError(error, 'Vk.getId');
  4230. return false;
  4231. }
  4232. }
  4233. async #toggleVk({
  4234. name,
  4235. doTask = true
  4236. }) {
  4237. try {
  4238. if (!doTask && this.whiteList.names.includes(name)) {
  4239. scripts_echoLog({
  4240. type: 'whiteList',
  4241. text: 'Vk.undoTask',
  4242. id: name
  4243. });
  4244. return true;
  4245. }
  4246. const formatName = name.replace(/\/$/, '');
  4247. const data = await this.#getId(formatName, doTask);
  4248. if (!data) {
  4249. return false;
  4250. }
  4251. switch (data.type) {
  4252. case 'group':
  4253. return await this.#toggleGroup(formatName, data, doTask);
  4254.  
  4255. case 'public':
  4256. return await this.#togglePublic(formatName, data, doTask);
  4257.  
  4258. case 'likeWall':
  4259. return await this.#toggleLikeWall(formatName, data, doTask);
  4260.  
  4261. case 'sendWall':
  4262. return doTask ? await this.#sendWall(formatName) : true;
  4263.  
  4264. case 'deleteWall':
  4265. return doTask ? true : await this.#deleteWall(formatName, data);
  4266.  
  4267. default:
  4268. return false;
  4269. }
  4270. } catch (error) {
  4271. throwError(error, 'Vk.toggleVk');
  4272. return false;
  4273. }
  4274. }
  4275. async toggle({
  4276. doTask = true,
  4277. nameLinks = []
  4278. }) {
  4279. try {
  4280. if (!this.#initialized) {
  4281. scripts_echoLog({
  4282. text: i18n('needInit')
  4283. });
  4284. return false;
  4285. }
  4286. const prom = [];
  4287. if (doTask && !globalOptions.doTask.vk.names || !doTask && !globalOptions.undoTask.vk.names) {
  4288. scripts_echoLog({
  4289. type: 'globalOptionsSkip',
  4290. text: 'vk.names'
  4291. });
  4292. } else {
  4293. const realNames = this.getRealParams('names', nameLinks, doTask, link => link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1]);
  4294. if (realNames.length > 0) {
  4295. for (const name of realNames) {
  4296. prom.push(this.#toggleVk({
  4297. name: name,
  4298. doTask: doTask
  4299. }));
  4300. await delay(1e3);
  4301. }
  4302. }
  4303. }
  4304. return Promise.all(prom).then(() => true);
  4305. } catch (error) {
  4306. throwError(error, 'Vk.toggle');
  4307. return false;
  4308. }
  4309. }
  4310. #setCache(name, postId) {
  4311. try {
  4312. this.#cache[name] = postId;
  4313. GM_setValue('vkCache', this.#cache);
  4314. } catch (error) {
  4315. throwError(error, 'Vk.setCache');
  4316. }
  4317. }
  4318. }
  4319. const social_Vk = Vk;
  4320. const getInfo = async function(link, type) {
  4321. try {
  4322. const logStatus = scripts_echoLog({
  4323. text: i18n('gettingYtbToken')
  4324. });
  4325. const {
  4326. result,
  4327. statusText,
  4328. status,
  4329. data
  4330. } = await tools_httpRequest({
  4331. url: link,
  4332. method: 'GET'
  4333. });
  4334. if (result === 'Success') {
  4335. if (data?.status === 200) {
  4336. if (data.responseText.includes('accounts.google.com/ServiceLogin?service=youtube')) {
  4337. logStatus.error(`Error:${i18n('loginYtb')}`, true);
  4338. return {
  4339. needLogin: true
  4340. };
  4341. }
  4342. const apiKey = data.responseText.match(/"INNERTUBE_API_KEY":"(.*?)"/)?.[1];
  4343. const context = (data.responseText.match(/\(\{"INNERTUBE_CONTEXT":([\w\W]*?)\}\)/) || data.responseText.match(/"INNERTUBE_CONTEXT":([\w\W]*?\}),"INNERTUBE/))?.[1] || '{}';
  4344. const {
  4345. client,
  4346. request
  4347. } = JSON.parse(context);
  4348. if (apiKey && client && request) {
  4349. client.hl = 'en';
  4350. if (type === 'channel') {
  4351. const channelId = data.responseText.match(/"channelId":"(.+?)"/)?.[1];
  4352. if (channelId) {
  4353. logStatus.success();
  4354. return {
  4355. params: {
  4356. apiKey: apiKey,
  4357. client: client,
  4358. request: request,
  4359. channelId: channelId
  4360. }
  4361. };
  4362. }
  4363. logStatus.error('Error: Get "channelId" failed!');
  4364. return {};
  4365. } else if (type === 'likeVideo') {
  4366. const videoId = data.responseText.match(/<link rel="shortlinkUrl" href="https:\/\/youtu\.be\/(.*?)">/)?.[1];
  4367. const likeParams = data.responseText.match(/"likeParams":"(.*?)"/)?.[1];
  4368. if (videoId) {
  4369. logStatus.success();
  4370. return {
  4371. params: {
  4372. apiKey: apiKey,
  4373. client: client,
  4374. request: request,
  4375. videoId: videoId,
  4376. likeParams: likeParams
  4377. }
  4378. };
  4379. }
  4380. logStatus.error('Error: Get "videoId" failed!');
  4381. return {};
  4382. }
  4383. logStatus.error('Error: Unknown type');
  4384. return {};
  4385. }
  4386. logStatus.error('Error: Parameter "apiKey" not found!');
  4387. return {};
  4388. }
  4389. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4390. return {};
  4391. }
  4392. logStatus.error(`${result}:${statusText}(${status})`);
  4393. return {};
  4394. } catch (error) {
  4395. throwError(error, 'Youtube.getInfo');
  4396. return {};
  4397. }
  4398. };
  4399. class Youtube extends social_Social {
  4400. tasks;
  4401. whiteList;
  4402. #auth = GM_getValue('youtubeAuth') || {};
  4403. #initialized = false;
  4404. #verifyChannel = `https://www.youtube.com/channel/${globalOptions.other.youtubeVerifyChannel}`;
  4405. constructor() {
  4406. super();
  4407. const defaultTasksTemplate = {
  4408. channels: [],
  4409. likes: []
  4410. };
  4411. this.tasks = defaultTasksTemplate;
  4412. this.whiteList = {
  4413. ...defaultTasksTemplate,
  4414. ...GM_getValue('whiteList')?.youtube || {}
  4415. };
  4416. }
  4417. async init() {
  4418. try {
  4419. if (this.#initialized) {
  4420. return true;
  4421. }
  4422. if (!this.#auth.PAPISID) {
  4423. if (await this.#updateAuth()) {
  4424. this.#initialized = true;
  4425. return true;
  4426. }
  4427. return false;
  4428. }
  4429. const isVerified = await this.#verifyAuth();
  4430. if (isVerified) {
  4431. scripts_echoLog({}).success(i18n('initSuccess', 'Youtube'));
  4432. this.#initialized = true;
  4433. return true;
  4434. }
  4435. GM_setValue('youtubeAuth', null);
  4436. if (await this.#updateAuth()) {
  4437. scripts_echoLog({}).success(i18n('initSuccess', 'Youtube'));
  4438. this.#initialized = true;
  4439. return true;
  4440. }
  4441. scripts_echoLog({}).error(i18n('initFailed', 'Youtube'));
  4442. return false;
  4443. } catch (error) {
  4444. throwError(error, 'Youtube.init');
  4445. return false;
  4446. }
  4447. }
  4448. async #verifyAuth() {
  4449. try {
  4450. return await this.#toggleChannel({
  4451. link: this.#verifyChannel,
  4452. doTask: true,
  4453. verify: true
  4454. });
  4455. } catch (error) {
  4456. throwError(error, 'Youtube.verifyAuth');
  4457. return false;
  4458. }
  4459. }
  4460. async #updateAuth() {
  4461. try {
  4462. const logStatus = scripts_echoLog({
  4463. text: i18n('updatingAuth', 'Youtube')
  4464. });
  4465. return await new Promise(resolve => {
  4466. GM_cookie.list({
  4467. url: 'https://www.youtube.com/@YouTube'
  4468. }, async (cookies, error) => {
  4469. if (!error) {
  4470. const PAPISID = cookies.find(cookie => cookie.name === '__Secure-3PAPISID')?.value;
  4471. if (PAPISID) {
  4472. GM_setValue('youtubeAuth', {
  4473. PAPISID: PAPISID
  4474. });
  4475. this.#auth = {
  4476. PAPISID: PAPISID
  4477. };
  4478. logStatus.success();
  4479. resolve(await this.#verifyAuth());
  4480. } else {
  4481. logStatus.error(i18n('needLogin'));
  4482. resolve(false);
  4483. }
  4484. } else {
  4485. logStatus.error('Error: Update youtube auth failed!');
  4486. resolve(false);
  4487. }
  4488. });
  4489. });
  4490. } catch (error) {
  4491. throwError(error, 'Youtube.updateAuth');
  4492. return false;
  4493. }
  4494. }
  4495. #getInfo(link, type) {
  4496. return getInfo(link, type);
  4497. }
  4498. async #toggleChannel({
  4499. link,
  4500. doTask = true,
  4501. verify = false
  4502. }) {
  4503. try {
  4504. const {
  4505. params,
  4506. needLogin
  4507. } = await this.#getInfo(link, 'channel');
  4508. const {
  4509. apiKey,
  4510. client,
  4511. request,
  4512. channelId
  4513. } = params || {};
  4514. if (needLogin) {
  4515. scripts_echoLog({
  4516. html: i18n('loginYtb')
  4517. });
  4518. return false;
  4519. }
  4520. if (!(apiKey && client && request && channelId)) {
  4521. scripts_echoLog({
  4522. text: '"getYtbToken" failed'
  4523. });
  4524. return false;
  4525. }
  4526. if (!doTask && !verify && this.whiteList.channels.includes(channelId)) {
  4527. scripts_echoLog({
  4528. type: 'whiteList',
  4529. text: 'Youtube.unfollowChannel',
  4530. id: channelId
  4531. });
  4532. return true;
  4533. }
  4534. const logStatus = verify ? scripts_echoLog({
  4535. text: i18n('verifyingAuth', 'Youtube')
  4536. }) : scripts_echoLog({
  4537. type: doTask ? 'followingYtbChannel' : 'unfollowingYtbChannel',
  4538. text: channelId
  4539. });
  4540. const nowTime = parseInt(String(new Date().getTime() / 1e3), 10);
  4541. const {
  4542. result,
  4543. statusText,
  4544. status,
  4545. data
  4546. } = await tools_httpRequest({
  4547. url: `https://www.youtube.com/youtubei/v1/subscription/${doTask ? '' : 'un'}subscribe?key=${apiKey}&prettyPrint=false`,
  4548. method: 'POST',
  4549. headers: {
  4550. origin: 'https://www.youtube.com',
  4551. referer: `https://www.youtube.com/channel/${channelId}`,
  4552. 'content-type': 'application/json',
  4553. 'x-goog-authuser': '0',
  4554. 'x-goog-visitor-id': client?.visitorData,
  4555. 'x-origin': 'https://www.youtube.com',
  4556. authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
  4557. },
  4558. data: JSON.stringify({
  4559. context: {
  4560. client: client,
  4561. request: {
  4562. sessionId: request?.sessionId,
  4563. internalExperimentFlags: [],
  4564. consistencyTokenJars: []
  4565. },
  4566. user: {}
  4567. },
  4568. channelIds: [ channelId ],
  4569. params: doTask ? 'EgIIAhgA' : 'CgIIAhgA'
  4570. })
  4571. });
  4572. if (result === 'Success') {
  4573. if (data?.status === 200) {
  4574. if (doTask && (/"subscribed":true/.test(data.responseText) || data.responseText.includes('The subscription already exists')) || !doTask && /"subscribed":false/.test(data.responseText)) {
  4575. logStatus.success();
  4576. if (doTask && !verify) {
  4577. this.tasks.channels = unique([ ...this.tasks.channels, link ]);
  4578. }
  4579. return true;
  4580. }
  4581. if (verify && data.responseText.includes('You may not subscribe to yourself')) {
  4582. logStatus.success();
  4583. return true;
  4584. }
  4585. logStatus.error(i18n('tryUpdateYtbAuth'), true);
  4586. return false;
  4587. }
  4588. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4589. return false;
  4590. }
  4591. logStatus.error(`${result}:${statusText}(${status})`);
  4592. return false;
  4593. } catch (error) {
  4594. throwError(error, 'Youtube.toggleChannel');
  4595. return false;
  4596. }
  4597. }
  4598. async #toggleLikeVideo({
  4599. link,
  4600. doTask = true
  4601. }) {
  4602. try {
  4603. const {
  4604. params,
  4605. needLogin
  4606. } = await this.#getInfo(link, 'likeVideo');
  4607. const {
  4608. apiKey,
  4609. client,
  4610. request,
  4611. videoId,
  4612. likeParams
  4613. } = params || {};
  4614. if (needLogin) {
  4615. scripts_echoLog({
  4616. html: `${i18n('loginYtb')}`
  4617. });
  4618. return false;
  4619. }
  4620. if (!(apiKey && client && request && videoId && likeParams)) {
  4621. scripts_echoLog({
  4622. text: '"getYtbToken" failed'
  4623. });
  4624. return false;
  4625. }
  4626. if (!doTask && this.whiteList.likes.includes(videoId)) {
  4627. scripts_echoLog({
  4628. type: 'whiteList',
  4629. text: 'Youtube.unlikeVideo',
  4630. id: videoId
  4631. });
  4632. return true;
  4633. }
  4634. const logStatus = scripts_echoLog({
  4635. type: doTask ? 'likingYtbVideo' : 'unlikingYtbVideo',
  4636. text: videoId
  4637. });
  4638. const nowTime = parseInt(String(new Date().getTime() / 1e3), 10);
  4639. const likeVideoData = {
  4640. context: {
  4641. client: client,
  4642. request: {
  4643. sessionId: request.sessionId,
  4644. internalExperimentFlags: [],
  4645. consistencyTokenJars: []
  4646. },
  4647. user: {}
  4648. },
  4649. target: {
  4650. videoId: videoId
  4651. }
  4652. };
  4653. if (doTask) {
  4654. if (likeParams) {
  4655. likeVideoData.params = likeParams;
  4656. } else {
  4657. logStatus.error('Empty likeParams');
  4658. return false;
  4659. }
  4660. }
  4661. const {
  4662. result,
  4663. statusText,
  4664. status,
  4665. data
  4666. } = await tools_httpRequest({
  4667. url: `https://www.youtube.com/youtubei/v1/like/${doTask ? '' : 'remove'}like?key=${apiKey}`,
  4668. method: 'POST',
  4669. headers: {
  4670. origin: 'https://www.youtube.com',
  4671. referer: `https://www.youtube.com/watch?v=${videoId}`,
  4672. 'content-type': 'application/json',
  4673. 'x-goog-authuser': '0',
  4674. 'x-goog-visitor-id': client.visitorData,
  4675. 'x-origin': 'https://www.youtube.com',
  4676. authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
  4677. },
  4678. data: JSON.stringify(likeVideoData)
  4679. });
  4680. if (result === 'Success') {
  4681. if (data?.status === 200) {
  4682. if (doTask && data.responseText.includes('Added to Liked videos') || !doTask && (data.responseText.includes('Removed from Liked videos') || data.responseText.includes('Dislike removed'))) {
  4683. logStatus.success();
  4684. if (doTask) {
  4685. this.tasks.likes = unique([ ...this.tasks.likes, link ]);
  4686. }
  4687. return true;
  4688. }
  4689. logStatus.error(i18n('tryUpdateYtbAuth'), true);
  4690. return false;
  4691. }
  4692. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4693. return false;
  4694. }
  4695. logStatus.error(`${result}:${statusText}(${status})`);
  4696. return false;
  4697. } catch (error) {
  4698. throwError(error, 'Youtube.toggleLikeVideo');
  4699. return false;
  4700. }
  4701. }
  4702. async toggle({
  4703. doTask = true,
  4704. channelLinks = [],
  4705. videoLinks = []
  4706. }) {
  4707. try {
  4708. if (!this.#initialized) {
  4709. scripts_echoLog({
  4710. text: i18n('needInit')
  4711. });
  4712. return false;
  4713. }
  4714. const prom = [];
  4715. if (doTask && !globalOptions.doTask.youtube.channels || !doTask && !globalOptions.undoTask.youtube.channels) {
  4716. scripts_echoLog({
  4717. type: 'globalOptionsSkip',
  4718. text: 'youtube.channels'
  4719. });
  4720. } else {
  4721. const realChannels = this.getRealParams('channels', channelLinks, doTask, link => {
  4722. if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
  4723. return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
  4724. }
  4725. return link;
  4726. });
  4727. if (realChannels.length > 0) {
  4728. for (const channel of realChannels) {
  4729. prom.push(this.#toggleChannel({
  4730. link: channel,
  4731. doTask: doTask
  4732. }));
  4733. await delay(1e3);
  4734. }
  4735. }
  4736. }
  4737. if (doTask && !globalOptions.doTask.youtube.likes || !doTask && !globalOptions.undoTask.youtube.likes) {
  4738. scripts_echoLog({
  4739. type: 'globalOptionsSkip',
  4740. text: 'youtube.likes'
  4741. });
  4742. } else {
  4743. const realLikes = this.getRealParams('likes', videoLinks, doTask, link => {
  4744. if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
  4745. return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
  4746. }
  4747. return link;
  4748. });
  4749. if (realLikes.length > 0) {
  4750. for (const video of realLikes) {
  4751. prom.push(this.#toggleLikeVideo({
  4752. link: video,
  4753. doTask: doTask
  4754. }));
  4755. await delay(1e3);
  4756. }
  4757. }
  4758. }
  4759. return Promise.all(prom).then(() => true);
  4760. } catch (error) {
  4761. throwError(error, 'Youtube.toggle');
  4762. return false;
  4763. }
  4764. }
  4765. }
  4766. class SteamASF {
  4767. #asfOptions;
  4768. #botName = 'asf';
  4769. #groupInfo;
  4770. async init() {
  4771. try {
  4772. const asfCommandsUrl = new URL('/Api/Command/', globalOptions.ASF.AsfIpcUrl);
  4773. this.#asfOptions = {
  4774. url: asfCommandsUrl.href,
  4775. method: 'POST',
  4776. responseType: 'json',
  4777. headers: {
  4778. accept: 'application/json',
  4779. 'Content-Type': 'application/json',
  4780. Host: asfCommandsUrl.host,
  4781. Origin: asfCommandsUrl.origin,
  4782. Referer: asfCommandsUrl.href,
  4783. Authentication: globalOptions.ASF.AsfIpcPassword
  4784. }
  4785. };
  4786. if (globalOptions.ASF.AsfBotname) {
  4787. this.#botName = globalOptions.ASF.AsfBotname;
  4788. }
  4789. const logStatus = scripts_echoLog({
  4790. text: i18n('initingASF')
  4791. });
  4792. const {
  4793. result,
  4794. statusText,
  4795. status,
  4796. data
  4797. } = await tools_httpRequest({
  4798. ...this.#asfOptions,
  4799. data: '{"Command":"!stats"}'
  4800. });
  4801. if (result === 'Success') {
  4802. if (data?.response?.Success === true && data.response.Message === 'OK' && data.response.Result) {
  4803. logStatus.success();
  4804. return true;
  4805. }
  4806. if (data?.response?.Result || data?.response?.Message) {
  4807. logStatus.error(data?.response?.Result || data.response.Message);
  4808. return false;
  4809. }
  4810. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4811. return false;
  4812. }
  4813. logStatus.error(`${result}:${statusText}(${status})`);
  4814. return false;
  4815. } catch (error) {
  4816. throwError(error, 'SteamASF.init');
  4817. return false;
  4818. }
  4819. }
  4820. async joinGroup(groupName) {
  4821. try {
  4822. const logStatus = scripts_echoLog({
  4823. type: 'joiningSteamGroup',
  4824. text: groupName
  4825. });
  4826. const {
  4827. result,
  4828. statusText,
  4829. status,
  4830. data
  4831. } = await tools_httpRequest({
  4832. ...this.#asfOptions,
  4833. data: JSON.stringify({
  4834. Command: `!JOINGROUP ${this.#botName} ${groupName}`
  4835. })
  4836. });
  4837. if (result === 'Success') {
  4838. if (data?.status === 200 && [ '已加入', '已申请', 'Joined', 'Applied', 'Присоединился', 'costs' ].find(text => data.response?.Result?.includes(text))) {
  4839. logStatus.success();
  4840. return true;
  4841. }
  4842. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4843. return false;
  4844. }
  4845. logStatus.error(`${result}:${statusText}(${status})`);
  4846. return false;
  4847. } catch (error) {
  4848. throwError(error, 'SteamASF.joinGroup');
  4849. return false;
  4850. }
  4851. }
  4852. async leaveGroup(groupName) {
  4853. try {
  4854. if (!this.#groupInfo) {
  4855. if (!await this.#getGroupId()) {
  4856. return false;
  4857. }
  4858. }
  4859. const groupId = await this.#groupInfo[groupName];
  4860. if (!groupId) {
  4861. return false;
  4862. }
  4863. const logStatus = scripts_echoLog({
  4864. type: 'leavingSteamGroup',
  4865. text: groupName
  4866. });
  4867. const {
  4868. result,
  4869. statusText,
  4870. status,
  4871. data
  4872. } = await tools_httpRequest({
  4873. ...this.#asfOptions,
  4874. data: JSON.stringify({
  4875. Command: `!LEAVEGROUP ${this.#botName} ${groupId}`
  4876. })
  4877. });
  4878. if (result === 'Success') {
  4879. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4880. logStatus.success();
  4881. return true;
  4882. }
  4883. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4884. return false;
  4885. }
  4886. logStatus.error(`${result}:${statusText}(${status})`);
  4887. return false;
  4888. } catch (error) {
  4889. throwError(error, 'SteamASF.leaveGroup');
  4890. return false;
  4891. }
  4892. }
  4893. async #getGroupId() {
  4894. try {
  4895. const logStatus = scripts_echoLog({
  4896. type: 'gettingSteamGroupId',
  4897. text: 'All'
  4898. });
  4899. const {
  4900. result,
  4901. statusText,
  4902. status,
  4903. data
  4904. } = await tools_httpRequest({
  4905. ...this.#asfOptions,
  4906. data: JSON.stringify({
  4907. Command: `!GROUPLIST ${this.#botName}`
  4908. })
  4909. });
  4910. if (result === 'Success') {
  4911. if (data?.status === 200 && data.response?.Result?.includes('|')) {
  4912. this.#groupInfo = Object.fromEntries(data.response.Result.split('\n').map(line => {
  4913. const [ , name, id ] = line.trim().split('|');
  4914. if (name && id) {
  4915. return [ name, id ];
  4916. }
  4917. return null;
  4918. }).filter(ele => ele));
  4919. logStatus.success();
  4920. return true;
  4921. }
  4922. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4923. return false;
  4924. }
  4925. logStatus.error(`${result}:${statusText}(${status})`);
  4926. return false;
  4927. } catch (error) {
  4928. throwError(error, 'SteamASF.getGroupID');
  4929. return false;
  4930. }
  4931. }
  4932. async addToWishlist(gameId) {
  4933. try {
  4934. const logStatus = scripts_echoLog({
  4935. type: 'addingToWishlist',
  4936. text: gameId
  4937. });
  4938. if ((await this.#checkGame(gameId)).wishlist === true) {
  4939. logStatus.success();
  4940. return true;
  4941. }
  4942. const {
  4943. result,
  4944. statusText,
  4945. status,
  4946. data
  4947. } = await tools_httpRequest({
  4948. ...this.#asfOptions,
  4949. data: JSON.stringify({
  4950. Command: `!ADDWISHLIST ${this.#botName} ${gameId}`
  4951. })
  4952. });
  4953. if (result === 'Success') {
  4954. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4955. logStatus.success();
  4956. return true;
  4957. }
  4958. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4959. return false;
  4960. }
  4961. logStatus.error(`${result}:${statusText}(${status})`);
  4962. return false;
  4963. } catch (error) {
  4964. throwError(error, 'SteamASF.addToWishlist');
  4965. return false;
  4966. }
  4967. }
  4968. async removeFromWishlist(gameId) {
  4969. try {
  4970. const logStatus = scripts_echoLog({
  4971. type: 'removingFromWishlist',
  4972. text: gameId
  4973. });
  4974. if ((await this.#checkGame(gameId)).wishlist === false) {
  4975. logStatus.success();
  4976. return true;
  4977. }
  4978. const {
  4979. result,
  4980. statusText,
  4981. status,
  4982. data
  4983. } = await tools_httpRequest({
  4984. ...this.#asfOptions,
  4985. data: JSON.stringify({
  4986. Command: `!REMOVEWISHLIST ${this.#botName} ${gameId}`
  4987. })
  4988. });
  4989. if (result === 'Success') {
  4990. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4991. logStatus.success();
  4992. return true;
  4993. }
  4994. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4995. return false;
  4996. }
  4997. logStatus.error(`${result}:${statusText}(${status})`);
  4998. return false;
  4999. } catch (error) {
  5000. throwError(error, 'SteamASF.removeFromWishlist');
  5001. return false;
  5002. }
  5003. }
  5004. async toggleFollowGame(gameId, doTask) {
  5005. try {
  5006. const logStatus = scripts_echoLog({
  5007. type: `${doTask ? '' : 'un'}followingGame`,
  5008. text: gameId
  5009. });
  5010. if (doTask && (await this.#checkGame(gameId)).followed === true || !doTask && (await this.#checkGame(gameId)).followed === false) {
  5011. logStatus.success();
  5012. return true;
  5013. }
  5014. const {
  5015. result,
  5016. statusText,
  5017. status,
  5018. data
  5019. } = await tools_httpRequest({
  5020. ...this.#asfOptions,
  5021. data: JSON.stringify({
  5022. Command: `!${doTask ? '' : 'UN'}FOLLOWGAME ${this.#botName} ${gameId}`
  5023. })
  5024. });
  5025. if (result === 'Success') {
  5026. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  5027. logStatus.success();
  5028. return true;
  5029. }
  5030. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  5031. return false;
  5032. }
  5033. logStatus.error(`${result}:${statusText}(${status})`);
  5034. return false;
  5035. } catch (error) {
  5036. throwError(error, 'SteamASF.toggleFollowGame');
  5037. return false;
  5038. }
  5039. }
  5040. async #checkGame(gameId) {
  5041. try {
  5042. const {
  5043. result,
  5044. data
  5045. } = await tools_httpRequest({
  5046. ...this.#asfOptions,
  5047. data: JSON.stringify({
  5048. Command: `!CHECK ${this.#botName} ${gameId}`
  5049. })
  5050. });
  5051. if (result === 'Success') {
  5052. if (data?.status === 200 && data.response?.Result?.includes(gameId)) {
  5053. const matchedResult = data.response.Result.split('\n').find(result => result.includes(gameId))?.split('|');
  5054. if (matchedResult?.length > 3) {
  5055. return {
  5056. wishlist: matchedResult.at(-3).trim() === '√' || matchedResult.at(-2).trim() === '√',
  5057. followed: matchedResult.at(-1).trim() === '√'
  5058. };
  5059. }
  5060. return {};
  5061. }
  5062. return {};
  5063. }
  5064. return {};
  5065. } catch (error) {
  5066. throwError(error, 'SteamASF.checkGame');
  5067. return {};
  5068. }
  5069. }
  5070. async toggleCurator(curatorId, doTask = true) {
  5071. try {
  5072. const logStatus = scripts_echoLog({
  5073. type: doTask ? 'followingCurator' : 'unfollowingCurator',
  5074. text: curatorId
  5075. });
  5076. const {
  5077. result,
  5078. statusText,
  5079. status,
  5080. data
  5081. } = await tools_httpRequest({
  5082. ...this.#asfOptions,
  5083. data: JSON.stringify({
  5084. Command: `!${doTask ? '' : 'UN'}FOLLOWCURATOR ${this.#botName} ${curatorId}`
  5085. })
  5086. });
  5087. if (result === 'Success') {
  5088. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  5089. logStatus.success();
  5090. return true;
  5091. }
  5092. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  5093. return false;
  5094. }
  5095. logStatus.error(`${result}:${statusText}(${status})`);
  5096. return false;
  5097. } catch (error) {
  5098. throwError(error, 'Steam.toggleCurator');
  5099. return false;
  5100. }
  5101. }
  5102. async addLicense(id) {
  5103. try {
  5104. const [ type, ids ] = id.split('-');
  5105. if (type === 'appid') {
  5106. const logStatus = scripts_echoLog({
  5107. type: 'addingFreeLicense',
  5108. text: ids
  5109. });
  5110. const {
  5111. result,
  5112. statusText,
  5113. status,
  5114. data
  5115. } = await tools_httpRequest({
  5116. ...this.#asfOptions,
  5117. data: JSON.stringify({
  5118. Command: `!addlicense ${this.#botName} app/${ids}`
  5119. })
  5120. });
  5121. if (result === 'Success') {
  5122. if (data?.status === 200 && [ 'AlreadyPurchased', 'OK' ].find(text => data.response?.Result?.includes(text))) {
  5123. logStatus.success();
  5124. return true;
  5125. }
  5126. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  5127. return false;
  5128. }
  5129. logStatus.error(`${result}:${statusText}(${status})`);
  5130. return false;
  5131. } else if (type === 'subid') {
  5132. const idsArr = ids.split(',');
  5133. const logStatus = scripts_echoLog({
  5134. type: 'addingFreeLicenseSubid',
  5135. text: ids
  5136. });
  5137. const {
  5138. result,
  5139. statusText,
  5140. status,
  5141. data
  5142. } = await tools_httpRequest({
  5143. ...this.#asfOptions,
  5144. data: JSON.stringify({
  5145. Command: `!addlicense ${this.#botName} ${idsArr.map(id => `sub/${id}`).join(',')}`
  5146. })
  5147. });
  5148. if (result === 'Success') {
  5149. if (data?.status === 200 && data.response?.Result) {
  5150. const resultLines = data.response.Result.split('\n');
  5151. idsArr.forEach(subid => {
  5152. const targetLine = resultLines.find(text => text.includes(subid));
  5153. if (targetLine && [ '成功', 'Success', 'Успех' ].find(text => targetLine.includes(text))) {
  5154. scripts_echoLog({}).success(targetLine);
  5155. } else {
  5156. scripts_echoLog({}).error(targetLine);
  5157. }
  5158. });
  5159. return true;
  5160. }
  5161. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  5162. return false;
  5163. }
  5164. logStatus.error(`${result}:${statusText}(${status})`);
  5165. return false;
  5166. }
  5167. return false;
  5168. } catch (error) {
  5169. throwError(error, 'SteamASF.addLicense');
  5170. return false;
  5171. }
  5172. }
  5173. async requestPlayTestAccess(id) {
  5174. try {
  5175. const logStatus = scripts_echoLog({
  5176. type: 'requestingPlayTestAccess',
  5177. text: id
  5178. });
  5179. const {
  5180. result,
  5181. statusText,
  5182. status,
  5183. data
  5184. } = await tools_httpRequest({
  5185. ...this.#asfOptions,
  5186. data: JSON.stringify({
  5187. Command: `!REQUESTACCESS ${this.#botName} ${id}`
  5188. })
  5189. });
  5190. if (result === 'Success') {
  5191. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  5192. logStatus.success();
  5193. return true;
  5194. }
  5195. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  5196. return false;
  5197. }
  5198. logStatus.error(`${result}:${statusText}(${status})`);
  5199. return false;
  5200. } catch (error) {
  5201. throwError(error, 'Steam.requestPlayTestAccess');
  5202. return false;
  5203. }
  5204. }
  5205. }
  5206. const social_SteamASF = SteamASF;
  5207. class Steam extends social_Social {
  5208. tasks;
  5209. whiteList;
  5210. #cache = {
  5211. ...{
  5212. group: {},
  5213. officialGroup: {},
  5214. forum: {},
  5215. workshop: {},
  5216. curator: {}
  5217. },
  5218. ...GM_getValue('steamCache')
  5219. };
  5220. #auth = {};
  5221. #storeInitialized = false;
  5222. #communityInitialized = false;
  5223. #area = 'CN';
  5224. #oldArea;
  5225. #areaStatus = 'end';
  5226. #ASF;
  5227. constructor() {
  5228. super();
  5229. const defaultTasksTemplate = {
  5230. groups: [],
  5231. officialGroups: [],
  5232. wishlists: [],
  5233. follows: [],
  5234. forums: [],
  5235. workshops: [],
  5236. workshopVotes: [],
  5237. curators: [],
  5238. curatorLikes: [],
  5239. announcements: [],
  5240. licenses: [],
  5241. playtests: []
  5242. };
  5243. this.tasks = defaultTasksTemplate;
  5244. this.whiteList = {
  5245. ...defaultTasksTemplate,
  5246. ...GM_getValue('whiteList')?.steam || {}
  5247. };
  5248. }
  5249. async init(type = 'all') {
  5250. try {
  5251. if (globalOptions.ASF.AsfEnabled && globalOptions.ASF.AsfIpcUrl && globalOptions.ASF.AsfIpcPassword) {
  5252. this.#ASF = new social_SteamASF();
  5253. if (await this.#ASF.init()) {
  5254. this.#storeInitialized = true;
  5255. this.#communityInitialized = true;
  5256. return true;
  5257. }
  5258. return false;
  5259. }
  5260. if (type === 'store') {
  5261. if (this.#storeInitialized) {
  5262. return true;
  5263. }
  5264. let storeInitialized = await this.#updateStoreAuth();
  5265. if (!storeInitialized) {
  5266. storeInitialized = await this.#updateStoreAuthTab();
  5267. }
  5268. this.#storeInitialized = storeInitialized;
  5269. if (!this.#storeInitialized) {
  5270. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  5271. return false;
  5272. }
  5273. scripts_echoLog({}).success(i18n('initSuccess', 'SteamStore'));
  5274. return true;
  5275. }
  5276. if (type === 'community') {
  5277. if (this.#communityInitialized) {
  5278. return true;
  5279. }
  5280. let communityInitialized = await this.#updateCommunityAuth();
  5281. if (!communityInitialized) {
  5282. communityInitialized = await this.#updateCommunityAuthTab();
  5283. GM_setValue('steamCommunityAuth', null);
  5284. }
  5285. this.#communityInitialized = communityInitialized;
  5286. if (!this.#communityInitialized) {
  5287. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  5288. return false;
  5289. }
  5290. scripts_echoLog({}).success(i18n('initSuccess', 'SteamCommunity'));
  5291. return true;
  5292. }
  5293. if (this.#storeInitialized && this.#communityInitialized) {
  5294. scripts_echoLog({}).success(i18n('initSuccess', 'Steam'));
  5295. return true;
  5296. }
  5297. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  5298. return false;
  5299. } catch (error) {
  5300. throwError(error, 'Steam.init');
  5301. return false;
  5302. }
  5303. }
  5304. async #refreshToken(type = 'steamStore') {
  5305. try {
  5306. const host = {
  5307. steamStore: 'store.steampowered.com',
  5308. steamCommunity: 'steamcommunity.com'
  5309. };
  5310. const logStatus = scripts_echoLog({
  5311. text: i18n('refreshingToken', i18n(type))
  5312. });
  5313. const formData = new FormData();
  5314. formData.append('redir', `https://${host[type]}/`);
  5315. const {
  5316. result,
  5317. statusText,
  5318. status,
  5319. data
  5320. } = await tools_httpRequest({
  5321. url: 'https://login.steampowered.com/jwt/ajaxrefresh',
  5322. method: 'POST',
  5323. responseType: 'json',
  5324. headers: {
  5325. Host: 'login.steampowered.com',
  5326. Origin: `https://${host[type]}`,
  5327. Referer: `https://${host[type]}/`
  5328. },
  5329. data: formData
  5330. });
  5331. if (result === 'Success') {
  5332. if (data?.response?.success) {
  5333. if (await this.#setStoreToken(data.response, type)) {
  5334. logStatus.success();
  5335. return true;
  5336. }
  5337. logStatus.error('Error');
  5338. return false;
  5339. }
  5340. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5341. return false;
  5342. }
  5343. logStatus.error(`${result}:${statusText}(${status})`);
  5344. return false;
  5345. } catch (error) {
  5346. throwError(error, 'Steam.refreshToken');
  5347. return false;
  5348. }
  5349. }
  5350. async #setStoreToken(param, type) {
  5351. try {
  5352. const host = {
  5353. steamStore: 'store.steampowered.com',
  5354. steamCommunity: 'steamcommunity.com'
  5355. };
  5356. const logStatus = scripts_echoLog({
  5357. text: i18n('settingToken', i18n(type))
  5358. });
  5359. const formData = new FormData();
  5360. formData.append('steamID', param.steamID);
  5361. formData.append('nonce', param.nonce);
  5362. formData.append('redir', param.redir);
  5363. formData.append('auth', param.auth);
  5364. const {
  5365. result,
  5366. statusText,
  5367. status,
  5368. data
  5369. } = await tools_httpRequest({
  5370. url: `https://${host[type]}/login/settoken`,
  5371. method: 'POST',
  5372. headers: {
  5373. Accept: 'application/json, text/plain, */*',
  5374. Host: host[type],
  5375. Origin: `https://${host[type]}`
  5376. },
  5377. data: formData
  5378. });
  5379. if (result === 'Success') {
  5380. if (data?.status === 200) {
  5381. logStatus.success();
  5382. return true;
  5383. }
  5384. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5385. return false;
  5386. }
  5387. logStatus.error(`${result}:${statusText}(${status})`);
  5388. return false;
  5389. } catch (error) {
  5390. throwError(error, 'Steam.setStoreToken');
  5391. return false;
  5392. }
  5393. }
  5394. async #updateStoreAuth(retry = false) {
  5395. try {
  5396. const logStatus = scripts_echoLog({
  5397. text: i18n('updatingAuth', i18n('steamStore'))
  5398. });
  5399. const {
  5400. result,
  5401. statusText,
  5402. status,
  5403. data
  5404. } = await tools_httpRequest({
  5405. url: 'https://store.steampowered.com/',
  5406. method: 'GET',
  5407. headers: {
  5408. 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',
  5409. 'Sec-Fetch-Dest': 'document',
  5410. 'Sec-Fetch-Mode': 'navigate',
  5411. 'Upgrade-Insecure-Requests': '1'
  5412. },
  5413. fetch: false,
  5414. redirect: 'manual'
  5415. });
  5416. if (data?.status === 200) {
  5417. if (!data.responseText.includes('data-miniprofile=')) {
  5418. if (await this.#refreshToken('steamStore')) {
  5419. logStatus.warning(i18n('retry'));
  5420. if (retry) {
  5421. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  5422. return false;
  5423. }
  5424. return this.#updateStoreAuth(true);
  5425. }
  5426. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  5427. return false;
  5428. }
  5429. const storeSessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
  5430. if (storeSessionID) {
  5431. this.#auth.storeSessionID = storeSessionID;
  5432. logStatus.success();
  5433. return true;
  5434. }
  5435. logStatus.error('Error: Get "sessionID" failed');
  5436. return false;
  5437. }
  5438. if ([ 301, 302 ].includes(data?.status)) {
  5439. if (await this.#refreshToken('steamStore')) {
  5440. logStatus.warning(i18n('retry'));
  5441. if (retry) {
  5442. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  5443. return false;
  5444. }
  5445. return this.#updateStoreAuth(true);
  5446. }
  5447. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  5448. return false;
  5449. }
  5450. logStatus.error(`${result}:${statusText}(${status})`);
  5451. return false;
  5452. } catch (error) {
  5453. throwError(error, 'Steam.updateStoreAuth');
  5454. return false;
  5455. }
  5456. }
  5457. async #updateStoreAuthTab() {
  5458. try {
  5459. const logStatus = scripts_echoLog({
  5460. text: i18n('updatingAuth', i18n('steamStoreTab'))
  5461. });
  5462. return await new Promise(resolve => {
  5463. GM_deleteValue('steamStoreAuth');
  5464. GM_setValue('ATv4_updateStoreAuth', true);
  5465. const newTab = GM_openInTab('https://store.steampowered.com/', {
  5466. active: true,
  5467. setParent: true
  5468. });
  5469. newTab.name = 'ATv4_updateStoreAuth';
  5470. const listenerId = GM_addValueChangeListener('steamStoreAuth', (key, oldValue, newValue) => {
  5471. GM_removeValueChangeListener(listenerId);
  5472. GM_deleteValue('ATv4_updateStoreAuth');
  5473. newTab?.close();
  5474. window.focus();
  5475. if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
  5476. this.#auth.storeSessionID = newValue.storeSessionID;
  5477. logStatus.success();
  5478. resolve(true);
  5479. return;
  5480. }
  5481. logStatus.error('Failed');
  5482. resolve(false);
  5483. });
  5484. newTab.onclose = () => {
  5485. GM_deleteValue('ATv4_updateStoreAuth');
  5486. };
  5487. });
  5488. } catch (error) {
  5489. throwError(error, 'Steam.updateStoreAuthTab');
  5490. return false;
  5491. }
  5492. }
  5493. async #updateCommunityAuthTab() {
  5494. try {
  5495. const logStatus = scripts_echoLog({
  5496. text: i18n('updatingAuth', i18n('steamCommunityTab'))
  5497. });
  5498. return await new Promise(resolve => {
  5499. GM_deleteValue('steamCommunityAuth');
  5500. GM_setValue('ATv4_updateCommunityAuth', true);
  5501. const newTab = GM_openInTab('https://steamcommunity.com/my', {
  5502. active: true,
  5503. setParent: true
  5504. });
  5505. newTab.name = 'ATv4_updateCommunityAuth';
  5506. const listenerId = GM_addValueChangeListener('steamCommunityAuth', (key, oldValue, newValue) => {
  5507. GM_removeValueChangeListener(listenerId);
  5508. GM_deleteValue('ATv4_updateCommunityAuth');
  5509. newTab?.close();
  5510. window.focus();
  5511. if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
  5512. this.#auth.steam64Id = newValue.steam64Id;
  5513. this.#auth.communitySessionID = newValue.communitySessionID;
  5514. logStatus.success();
  5515. resolve(true);
  5516. return;
  5517. }
  5518. logStatus.error('Failed');
  5519. resolve(false);
  5520. });
  5521. newTab.onclose = () => {
  5522. GM_deleteValue('ATv4_updateCommunityAuth');
  5523. };
  5524. });
  5525. } catch (error) {
  5526. throwError(error, 'Steam.updateCommunityAuthTab');
  5527. return false;
  5528. }
  5529. }
  5530. async #updateCommunityAuth() {
  5531. try {
  5532. const logStatus = scripts_echoLog({
  5533. text: i18n('gettingUserLink')
  5534. });
  5535. const {
  5536. result,
  5537. statusText,
  5538. status,
  5539. data
  5540. } = await tools_httpRequest({
  5541. url: 'https://steamcommunity.com/my',
  5542. method: 'GET',
  5543. headers: {
  5544. 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',
  5545. Host: 'steamcommunity.com',
  5546. 'Sec-Fetch-Dest': 'document',
  5547. 'Sec-Fetch-Mode': 'navigate'
  5548. },
  5549. fetch: false
  5550. });
  5551. if (data?.status === 200) {
  5552. if (data.finalUrl.includes('https://steamcommunity.com/login/home')) {
  5553. logStatus.error(`Error:${i18n('needLoginSteamCommunity')}`, true);
  5554. return false;
  5555. }
  5556. const steam64Id = data.responseText.match(/g_steamID = "(.+?)";/)?.[1];
  5557. const communitySessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
  5558. if (steam64Id && communitySessionID) {
  5559. this.#auth.steam64Id = steam64Id;
  5560. this.#auth.communitySessionID = communitySessionID;
  5561. logStatus.success();
  5562. return true;
  5563. }
  5564. logStatus.error('Error: Get "sessionID" failed');
  5565. return false;
  5566. }
  5567. logStatus.error(`${result}:${statusText}(${status})`);
  5568. return false;
  5569. } catch (error) {
  5570. throwError(error, 'Steam.updateCommunityAuth');
  5571. return false;
  5572. }
  5573. }
  5574. async #getAreaInfo() {
  5575. try {
  5576. const logStatus = scripts_echoLog({
  5577. text: i18n('gettingAreaInfo')
  5578. });
  5579. const {
  5580. result,
  5581. statusText,
  5582. status,
  5583. data
  5584. } = await tools_httpRequest({
  5585. url: 'https://store.steampowered.com/cart/',
  5586. method: 'GET'
  5587. });
  5588. if (result === 'Success') {
  5589. if (data?.status === 200) {
  5590. const cartConfigRaw = data.responseText.match(/data-cart_config="(.*?)"/)?.[1];
  5591. const temp = document.createElement('div');
  5592. temp.innerHTML = cartConfigRaw || '{}';
  5593. const cartConfigStr = temp.textContent || temp.innerText;
  5594. let cartConfig;
  5595. try {
  5596. cartConfig = JSON.parse(cartConfigStr);
  5597. } catch (error) {
  5598. logStatus.error('Error: get country info filed');
  5599. console.error(error);
  5600. return {};
  5601. }
  5602. if (!cartConfig.rgUserCountryOptions) {
  5603. logStatus.warning('Warning: Area cannot be changed');
  5604. return {};
  5605. }
  5606. const userInfoRaw = data.responseText.match(/data-userinfo="(.*?)"/)?.[1];
  5607. const temp1 = document.createElement('div');
  5608. temp1.innerHTML = userInfoRaw || '{}';
  5609. const userInfoStr = temp1.textContent || temp1.innerText;
  5610. let userInfo;
  5611. try {
  5612. userInfo = JSON.parse(userInfoStr);
  5613. } catch (error) {
  5614. logStatus.error('Error: get country info filed');
  5615. console.error(error);
  5616. return {};
  5617. }
  5618. const currentArea = userInfo.country_code;
  5619. const areas = Object.keys(cartConfig.rgUserCountryOptions).filter(area => area !== 'help');
  5620. if (currentArea && areas.length > 0) {
  5621. this.#area = currentArea;
  5622. logStatus.success();
  5623. return {
  5624. currentArea: currentArea,
  5625. areas: areas
  5626. };
  5627. }
  5628. logStatus.error('Error: get country info filed');
  5629. return {};
  5630. }
  5631. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5632. return {};
  5633. }
  5634. logStatus.error(`${result}:${statusText}(${status})`);
  5635. return {};
  5636. } catch (error) {
  5637. throwError(error, 'Steam.getAreaInfo');
  5638. return {};
  5639. }
  5640. }
  5641. async #changeArea(area) {
  5642. try {
  5643. if (this.#areaStatus === 'waiting') {
  5644. await new Promise(resolve => {
  5645. const checker = setInterval(() => {
  5646. if (this.#areaStatus !== 'waiting') {
  5647. clearInterval(checker);
  5648. resolve(true);
  5649. }
  5650. });
  5651. });
  5652. }
  5653. if (this.#area === area || !area && this.#area !== 'CN') {
  5654. return true;
  5655. }
  5656. this.#areaStatus = 'waiting';
  5657. let aimedArea = area;
  5658. if (!aimedArea) {
  5659. const {
  5660. currentArea,
  5661. areas
  5662. } = await this.#getAreaInfo();
  5663. if (!currentArea || !areas) {
  5664. this.#areaStatus = 'error';
  5665. return false;
  5666. }
  5667. if (currentArea !== 'CN') {
  5668. this.#areaStatus = 'skip';
  5669. scripts_echoLog({
  5670. text: 'notNeededChangeArea'
  5671. });
  5672. return 'skip';
  5673. }
  5674. const anotherArea = areas.filter(area => area && area !== 'CN');
  5675. if (!anotherArea || anotherArea.length === 0) {
  5676. this.#areaStatus = 'noAnotherArea';
  5677. scripts_echoLog({
  5678. text: 'noAnotherArea'
  5679. });
  5680. return false;
  5681. }
  5682. [ aimedArea ] = anotherArea;
  5683. }
  5684. const logStatus = scripts_echoLog({
  5685. text: i18n('changingArea', aimedArea)
  5686. });
  5687. const {
  5688. result,
  5689. statusText,
  5690. status,
  5691. data
  5692. } = await tools_httpRequest({
  5693. url: 'https://store.steampowered.com/country/setcountry',
  5694. method: 'POST',
  5695. headers: {
  5696. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5697. },
  5698. data: $.param({
  5699. cc: aimedArea,
  5700. sessionid: this.#auth.storeSessionID
  5701. })
  5702. });
  5703. if (result === 'Success') {
  5704. if (data?.status === 200 && data.responseText === 'true') {
  5705. const {
  5706. currentArea
  5707. } = await this.#getAreaInfo();
  5708. if (currentArea) {
  5709. this.#area = currentArea;
  5710. if (!this.#oldArea) {
  5711. this.#oldArea = currentArea;
  5712. }
  5713. }
  5714. if (currentArea === aimedArea) {
  5715. this.#areaStatus = 'success';
  5716. logStatus.success();
  5717. return currentArea;
  5718. }
  5719. this.#areaStatus = 'error';
  5720. logStatus.error('Error: change country filed');
  5721. return 'CN';
  5722. }
  5723. this.#areaStatus = 'error';
  5724. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5725. return 'CN';
  5726. }
  5727. this.#areaStatus = 'error';
  5728. logStatus.error(`${result}:${statusText}(${status})`);
  5729. return 'CN';
  5730. } catch (error) {
  5731. this.#areaStatus = 'error';
  5732. throwError(error, 'Steam.changeArea');
  5733. return false;
  5734. }
  5735. }
  5736. async #joinGroup(groupName) {
  5737. try {
  5738. if (this.#ASF) {
  5739. if (await this.#ASF.joinGroup(groupName)) {
  5740. this.tasks.groups = unique([ ...this.tasks.groups, groupName ]);
  5741. return true;
  5742. }
  5743. return false;
  5744. }
  5745. const logStatus = scripts_echoLog({
  5746. type: 'joiningSteamGroup',
  5747. text: groupName
  5748. });
  5749. const {
  5750. result,
  5751. statusText,
  5752. status,
  5753. data
  5754. } = await tools_httpRequest({
  5755. url: `https://steamcommunity.com/groups/${groupName}`,
  5756. method: 'POST',
  5757. headers: {
  5758. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5759. },
  5760. data: $.param({
  5761. action: 'join',
  5762. sessionID: this.#auth.communitySessionID
  5763. })
  5764. });
  5765. if (result === 'Success') {
  5766. if (data?.status === 200 && !data.responseText.includes('grouppage_join_area')) {
  5767. logStatus.success();
  5768. this.tasks.groups = unique([ ...this.tasks.groups, groupName ]);
  5769. return true;
  5770. }
  5771. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5772. return false;
  5773. }
  5774. logStatus.error(`${result}:${statusText}(${status})`);
  5775. return false;
  5776. } catch (error) {
  5777. throwError(error, 'Steam.joinGroup');
  5778. return false;
  5779. }
  5780. }
  5781. async #leaveGroup(groupName) {
  5782. try {
  5783. if (this.whiteList.groups.includes(groupName)) {
  5784. scripts_echoLog({
  5785. type: 'whiteList',
  5786. text: 'Steam.leaveGroup',
  5787. id: groupName
  5788. });
  5789. return true;
  5790. }
  5791. if (this.#ASF) {
  5792. return await this.#ASF.leaveGroup(groupName);
  5793. }
  5794. const groupId = await this.#getGroupId(groupName);
  5795. if (!groupId) {
  5796. return false;
  5797. }
  5798. const logStatus = scripts_echoLog({
  5799. type: 'leavingSteamGroup',
  5800. text: groupName
  5801. });
  5802. const {
  5803. result,
  5804. statusText,
  5805. status,
  5806. data
  5807. } = await tools_httpRequest({
  5808. url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
  5809. method: 'POST',
  5810. headers: {
  5811. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5812. },
  5813. data: $.param({
  5814. sessionID: this.#auth.communitySessionID,
  5815. action: 'leaveGroup',
  5816. groupId: groupId
  5817. })
  5818. });
  5819. if (result === 'Success') {
  5820. 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) {
  5821. logStatus.success();
  5822. return true;
  5823. }
  5824. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5825. return false;
  5826. }
  5827. logStatus.error(`${result}:${statusText}(${status})`);
  5828. return false;
  5829. } catch (error) {
  5830. throwError(error, 'Steam.leaveGroup');
  5831. return false;
  5832. }
  5833. }
  5834. async #getGroupId(groupName) {
  5835. try {
  5836. const logStatus = scripts_echoLog({
  5837. type: 'gettingSteamGroupId',
  5838. text: groupName
  5839. });
  5840. const groupId = this.#cache.group[groupName];
  5841. if (groupId) {
  5842. logStatus.success();
  5843. return groupId;
  5844. }
  5845. const {
  5846. result,
  5847. statusText,
  5848. status,
  5849. data
  5850. } = await tools_httpRequest({
  5851. url: `https://steamcommunity.com/groups/${groupName}`,
  5852. method: 'GET',
  5853. headers: {
  5854. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5855. }
  5856. });
  5857. if (result === 'Success') {
  5858. if (data?.status === 200) {
  5859. const groupId = data.responseText.match(/OpenGroupChat\( '([0-9]+)'/)?.[1];
  5860. if (groupId) {
  5861. this.#setCache('group', groupName, groupId);
  5862. logStatus.success();
  5863. return groupId;
  5864. }
  5865. logStatus.error(`Error:${data.statusText}(${data.status})`);
  5866. return false;
  5867. }
  5868. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5869. return false;
  5870. }
  5871. logStatus.error(`${result}:${statusText}(${status})`);
  5872. return false;
  5873. } catch (error) {
  5874. throwError(error, 'Steam.getGroupID');
  5875. return false;
  5876. }
  5877. }
  5878. async #joinOfficialGroup(gameId) {
  5879. try {
  5880. if (this.#ASF) {
  5881. if (await this.#ASF.joinGroup(gameId)) {
  5882. this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]);
  5883. return true;
  5884. }
  5885. return false;
  5886. }
  5887. const logStatus = scripts_echoLog({
  5888. type: 'joiningSteamOfficialGroup',
  5889. text: gameId
  5890. });
  5891. const {
  5892. result,
  5893. statusText,
  5894. status,
  5895. data
  5896. } = await tools_httpRequest({
  5897. url: `https://steamcommunity.com/games/${gameId}?action=join&sessionID=${this.#auth.communitySessionID}`,
  5898. method: 'GET',
  5899. headers: {
  5900. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5901. }
  5902. });
  5903. if (result === 'Success') {
  5904. if (data?.status === 200 && !data.responseText.includes('id="publicGroupJoin"')) {
  5905. logStatus.success();
  5906. this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]);
  5907. const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
  5908. if (groupId) {
  5909. this.#setCache('officialGroup', gameId, groupId);
  5910. }
  5911. return true;
  5912. }
  5913. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5914. return false;
  5915. }
  5916. logStatus.error(`${result}:${statusText}(${status})`);
  5917. return false;
  5918. } catch (error) {
  5919. throwError(error, 'Steam.joinOfficialGroup');
  5920. return false;
  5921. }
  5922. }
  5923. async #leaveOfficialGroup(gameId) {
  5924. try {
  5925. if (this.whiteList.officialGroups.includes(gameId)) {
  5926. scripts_echoLog({
  5927. type: 'whiteList',
  5928. text: 'Steam.leaveOfficialGroup',
  5929. id: gameId
  5930. });
  5931. return true;
  5932. }
  5933. if (this.#ASF) {
  5934. return await this.#ASF.leaveGroup(gameId);
  5935. }
  5936. const groupId = await this.#getOfficialGroupId(gameId);
  5937. if (!groupId) {
  5938. return false;
  5939. }
  5940. const logStatus = scripts_echoLog({
  5941. type: 'leavingSteamOfficialGroup',
  5942. text: gameId
  5943. });
  5944. const {
  5945. result,
  5946. statusText,
  5947. status,
  5948. data
  5949. } = await tools_httpRequest({
  5950. url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
  5951. method: 'POST',
  5952. headers: {
  5953. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5954. },
  5955. data: $.param({
  5956. sessionID: this.#auth.communitySessionID,
  5957. action: 'leaveGroup',
  5958. groupId: groupId
  5959. })
  5960. });
  5961. if (result === 'Success') {
  5962. if (data?.status === 200) {
  5963. const {
  5964. result: resultR,
  5965. statusText: statusTextR,
  5966. status: statusR,
  5967. data: dataR
  5968. } = await tools_httpRequest({
  5969. url: `https://steamcommunity.com/games/${gameId}`,
  5970. method: 'GET',
  5971. headers: {
  5972. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5973. }
  5974. });
  5975. if (resultR === 'Success') {
  5976. if (dataR?.status === 200 && dataR.responseText.includes('id="publicGroupJoin"')) {
  5977. logStatus.success();
  5978. return true;
  5979. }
  5980. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  5981. return false;
  5982. }
  5983. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  5984. return false;
  5985. }
  5986. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5987. return false;
  5988. }
  5989. logStatus.error(`${result}:${statusText}(${status})`);
  5990. return false;
  5991. } catch (error) {
  5992. throwError(error, 'Steam.leaveOfficialGroup');
  5993. return false;
  5994. }
  5995. }
  5996. async #getOfficialGroupId(gameId) {
  5997. try {
  5998. const logStatus = scripts_echoLog({
  5999. type: 'gettingSteamOfficialGroupId',
  6000. text: gameId
  6001. });
  6002. const groupId = this.#cache.officialGroup[gameId];
  6003. if (groupId) {
  6004. logStatus.success();
  6005. return groupId;
  6006. }
  6007. const {
  6008. result,
  6009. statusText,
  6010. status,
  6011. data
  6012. } = await tools_httpRequest({
  6013. url: `https://steamcommunity.com/games/${gameId}`,
  6014. method: 'GET',
  6015. headers: {
  6016. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6017. }
  6018. });
  6019. if (result === 'Success') {
  6020. if (data?.status === 200) {
  6021. const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
  6022. if (groupId) {
  6023. this.#setCache('officialGroup', gameId, groupId);
  6024. logStatus.success();
  6025. return groupId;
  6026. }
  6027. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6028. return false;
  6029. }
  6030. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6031. return false;
  6032. }
  6033. logStatus.error(`${result}:${statusText}(${status})`);
  6034. return false;
  6035. } catch (error) {
  6036. throwError(error, 'Steam.getGroupID');
  6037. return false;
  6038. }
  6039. }
  6040. async #addToWishlist(gameId) {
  6041. try {
  6042. if (this.#ASF) {
  6043. if (await this.#ASF.addToWishlist(gameId)) {
  6044. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  6045. return true;
  6046. }
  6047. return false;
  6048. }
  6049. const logStatus = scripts_echoLog({
  6050. type: 'addingToWishlist',
  6051. text: gameId
  6052. });
  6053. const {
  6054. result,
  6055. data
  6056. } = await tools_httpRequest({
  6057. url: 'https://store.steampowered.com/api/addtowishlist',
  6058. method: 'POST',
  6059. headers: {
  6060. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6061. },
  6062. data: $.param({
  6063. sessionid: this.#auth.storeSessionID,
  6064. appid: gameId
  6065. }),
  6066. dataType: 'json'
  6067. });
  6068. if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
  6069. logStatus.success();
  6070. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  6071. return true;
  6072. }
  6073. const {
  6074. result: resultR,
  6075. statusText: statusTextR,
  6076. status: statusR,
  6077. data: dataR
  6078. } = await tools_httpRequest({
  6079. url: `https://store.steampowered.com/app/${gameId}`,
  6080. method: 'GET'
  6081. });
  6082. if (resultR === 'Success') {
  6083. if (dataR?.status === 200) {
  6084. if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
  6085. logStatus.warning(i18n('changeAreaNotice'));
  6086. if (!await this.#changeArea()) {
  6087. return false;
  6088. }
  6089. return await this.#addToWishlist(gameId);
  6090. }
  6091. if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('class="already_in_library"')) {
  6092. logStatus.success();
  6093. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  6094. return true;
  6095. } 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"')) {
  6096. logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
  6097. return false;
  6098. }
  6099. logStatus.success();
  6100. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  6101. return true;
  6102. }
  6103. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  6104. return false;
  6105. }
  6106. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  6107. return false;
  6108. } catch (error) {
  6109. throwError(error, 'Steam.addToWishlist');
  6110. return false;
  6111. }
  6112. }
  6113. async #removeFromWishlist(gameId) {
  6114. try {
  6115. if (this.whiteList.wishlists.includes(gameId)) {
  6116. scripts_echoLog({
  6117. type: 'whiteList',
  6118. text: 'Steam.removeFromWishlist',
  6119. id: gameId
  6120. });
  6121. return true;
  6122. }
  6123. if (this.#ASF) {
  6124. return await this.#ASF.removeFromWishlist(gameId);
  6125. }
  6126. const logStatus = scripts_echoLog({
  6127. type: 'removingFromWishlist',
  6128. text: gameId
  6129. });
  6130. const {
  6131. result,
  6132. data
  6133. } = await tools_httpRequest({
  6134. url: 'https://store.steampowered.com/api/removefromwishlist',
  6135. method: 'POST',
  6136. headers: {
  6137. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6138. },
  6139. data: $.param({
  6140. sessionid: this.#auth.storeSessionID,
  6141. appid: gameId
  6142. }),
  6143. dataType: 'json'
  6144. });
  6145. if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
  6146. logStatus.success();
  6147. return true;
  6148. }
  6149. const {
  6150. result: resultR,
  6151. statusText: statusTextR,
  6152. status: statusR,
  6153. data: dataR
  6154. } = await tools_httpRequest({
  6155. url: `https://store.steampowered.com/app/${gameId}`,
  6156. method: 'GET'
  6157. });
  6158. if (resultR === 'Success') {
  6159. if (dataR?.status === 200) {
  6160. if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
  6161. logStatus.warning(i18n('changeAreaNotice'));
  6162. const result = await this.#changeArea();
  6163. if (!result || result === 'CN' || result === 'skip') {
  6164. return false;
  6165. }
  6166. return await this.#removeFromWishlist(gameId);
  6167. }
  6168. if (dataR.responseText.includes('class="queue_actions_ctn"') && (dataR.responseText.includes('ds_owned_flag ds_flag') || dataR.responseText.includes('add_to_wishlist_area'))) {
  6169. logStatus.success();
  6170. return true;
  6171. }
  6172. logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
  6173. return false;
  6174. }
  6175. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  6176. return false;
  6177. }
  6178. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  6179. return false;
  6180. } catch (error) {
  6181. throwError(error, 'Steam.removeFromWishlist');
  6182. return false;
  6183. }
  6184. }
  6185. async #toggleFollowGame(gameId, doTask) {
  6186. try {
  6187. if (!doTask && this.whiteList.follows.includes(gameId)) {
  6188. scripts_echoLog({
  6189. type: 'whiteList',
  6190. text: 'Steam.unfollowGame',
  6191. id: gameId
  6192. });
  6193. return true;
  6194. }
  6195. if (this.#ASF) {
  6196. if (await this.#ASF.toggleFollowGame(gameId, doTask)) {
  6197. if (doTask) {
  6198. this.tasks.follows = unique([ ...this.tasks.follows, gameId ]);
  6199. }
  6200. return true;
  6201. }
  6202. return false;
  6203. }
  6204. const logStatus = scripts_echoLog({
  6205. type: `${doTask ? '' : 'un'}followingGame`,
  6206. text: gameId
  6207. });
  6208. const requestData = {
  6209. sessionid: this.#auth.storeSessionID,
  6210. appid: gameId
  6211. };
  6212. if (!doTask) {
  6213. requestData.unfollow = '1';
  6214. }
  6215. const {
  6216. result,
  6217. data
  6218. } = await tools_httpRequest({
  6219. url: 'https://store.steampowered.com/explore/followgame/',
  6220. method: 'POST',
  6221. headers: {
  6222. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6223. },
  6224. data: $.param(requestData)
  6225. });
  6226. if (result === 'Success' && data?.status === 200 && data.responseText === 'true') {
  6227. logStatus.success();
  6228. return true;
  6229. }
  6230. const followed = await this.#isFollowedGame(gameId);
  6231. if (this.#area === 'CN' && followed === 'areaLocked') {
  6232. logStatus.warning(i18n('changeAreaNotice'));
  6233. if (!await this.#changeArea()) {
  6234. return false;
  6235. }
  6236. return await this.#toggleFollowGame(gameId, doTask);
  6237. }
  6238. if (doTask === followed) {
  6239. logStatus.success();
  6240. if (doTask) {
  6241. this.tasks.follows = unique([ ...this.tasks.follows, gameId ]);
  6242. }
  6243. return true;
  6244. }
  6245. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6246. return false;
  6247. } catch (error) {
  6248. throwError(error, 'Steam.toggleFollowGame');
  6249. return false;
  6250. }
  6251. }
  6252. async #isFollowedGame(gameId) {
  6253. try {
  6254. const {
  6255. result,
  6256. data
  6257. } = await tools_httpRequest({
  6258. url: `https://store.steampowered.com/app/${gameId}`,
  6259. method: 'GET'
  6260. });
  6261. if (result === 'Success') {
  6262. if (data?.status === 200) {
  6263. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  6264. return 'areaLocked';
  6265. }
  6266. if ($(data.responseText.replace(/<img.*?>/g, '')).find('.queue_control_button.queue_btn_follow>.btnv6_blue_hoverfade.btn_medium.queue_btn_active').css('display') !== 'none') {
  6267. return true;
  6268. }
  6269. return false;
  6270. }
  6271. return false;
  6272. }
  6273. return false;
  6274. } catch (error) {
  6275. throwError(error, 'Steam.isFollowedGame');
  6276. return false;
  6277. }
  6278. }
  6279. async #toggleForum(gameId, doTask = true) {
  6280. try {
  6281. if (!doTask && this.whiteList.forums.includes(gameId)) {
  6282. scripts_echoLog({
  6283. type: 'whiteList',
  6284. text: 'Steam.unsubscribeForum',
  6285. id: gameId
  6286. });
  6287. return true;
  6288. }
  6289. const forumId = await this.#getForumId(gameId);
  6290. if (!forumId) {
  6291. return false;
  6292. }
  6293. const logStatus = scripts_echoLog({
  6294. type: `${doTask ? '' : 'un'}subscribingForum`,
  6295. text: gameId
  6296. });
  6297. const [ id, feature ] = forumId.split('_');
  6298. const {
  6299. result,
  6300. statusText,
  6301. status,
  6302. data
  6303. } = await tools_httpRequest({
  6304. url: `https://steamcommunity.com/forum/${id}/General/${doTask ? '' : 'un'}subscribe/${feature || '0'}/`,
  6305. method: 'POST',
  6306. responseType: 'json',
  6307. headers: {
  6308. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6309. },
  6310. data: $.param({
  6311. sessionid: this.#auth.communitySessionID
  6312. })
  6313. });
  6314. if (result === 'Success') {
  6315. if (data?.status === 200 && (data.response?.success === 1 || data.response?.success === 29)) {
  6316. if (doTask) {
  6317. this.tasks.forums = unique([ ...this.tasks.forums, gameId ]);
  6318. }
  6319. logStatus.success();
  6320. return true;
  6321. }
  6322. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6323. return true;
  6324. }
  6325. logStatus.error(`${result}:${statusText}(${status})`);
  6326. return true;
  6327. } catch (error) {
  6328. throwError(error, 'Steam.toggleForum');
  6329. return true;
  6330. }
  6331. }
  6332. async #getForumId(gameId) {
  6333. try {
  6334. const logStatus = scripts_echoLog({
  6335. type: 'gettingForumId',
  6336. text: gameId
  6337. });
  6338. const forumId = this.#cache.forum[gameId];
  6339. if (forumId) {
  6340. logStatus.success();
  6341. return forumId;
  6342. }
  6343. const {
  6344. result,
  6345. statusText,
  6346. status,
  6347. data
  6348. } = await tools_httpRequest({
  6349. url: `https://steamcommunity.com/app/${gameId}/discussions/`,
  6350. method: 'GET'
  6351. });
  6352. if (result === 'Success') {
  6353. if (data?.status === 200) {
  6354. const forumId = data.responseText?.match(/General_([\d]+(_[\d]+)?)/)?.[1];
  6355. if (forumId) {
  6356. this.#setCache('forum', gameId, forumId);
  6357. logStatus.success();
  6358. return forumId;
  6359. }
  6360. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6361. return false;
  6362. }
  6363. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6364. return false;
  6365. }
  6366. logStatus.error(`${result}:${statusText}(${status})`);
  6367. return false;
  6368. } catch (error) {
  6369. throwError(error, 'Steam.getForumId');
  6370. return false;
  6371. }
  6372. }
  6373. async #toggleFavoriteWorkshop(id, doTask = true) {
  6374. try {
  6375. if (!doTask && this.whiteList.workshops.includes(id)) {
  6376. scripts_echoLog({
  6377. type: 'whiteList',
  6378. text: 'Steam.unfavoriteWorkshop',
  6379. id: id
  6380. });
  6381. return true;
  6382. }
  6383. const appid = await this.#getWorkshopAppId(id);
  6384. if (!appid) {
  6385. return false;
  6386. }
  6387. const logStatus = scripts_echoLog({
  6388. type: doTask ? 'favoritingWorkshop' : 'unfavoritingWorkshop',
  6389. text: id
  6390. });
  6391. const {
  6392. result,
  6393. statusText,
  6394. status,
  6395. data
  6396. } = await tools_httpRequest({
  6397. url: `https://steamcommunity.com/sharedfiles/${doTask ? '' : 'un'}favorite`,
  6398. method: 'POST',
  6399. headers: {
  6400. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6401. },
  6402. data: $.param({
  6403. id: id,
  6404. appid: appid,
  6405. sessionid: this.#auth.communitySessionID
  6406. })
  6407. });
  6408. if (result === 'Success') {
  6409. if (data?.status === 200 && !data.responseText) {
  6410. if (doTask) {
  6411. this.tasks.workshops = unique([ ...this.tasks.workshops, id ]);
  6412. }
  6413. logStatus.success();
  6414. return true;
  6415. }
  6416. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6417. return false;
  6418. }
  6419. logStatus.error(`${result}:${statusText}(${status})`);
  6420. return false;
  6421. } catch (error) {
  6422. throwError(error, 'Steam.toggleFavoriteWorkshop');
  6423. return false;
  6424. }
  6425. }
  6426. async #getWorkshopAppId(id) {
  6427. try {
  6428. const logStatus = scripts_echoLog({
  6429. type: 'gettingWorkshopAppId',
  6430. text: id
  6431. });
  6432. const appId = this.#cache.workshop[id];
  6433. if (appId) {
  6434. logStatus.success();
  6435. return appId;
  6436. }
  6437. const {
  6438. result,
  6439. statusText,
  6440. status,
  6441. data
  6442. } = await tools_httpRequest({
  6443. url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${id}`,
  6444. method: 'GET'
  6445. });
  6446. if (result === 'Success') {
  6447. if (data?.status === 200) {
  6448. const appId = data.responseText.match(/<input type="hidden" name="appid" value="([\d]+?)" \/>/)?.[1];
  6449. if (appId) {
  6450. this.#setCache('workshop', id, appId);
  6451. logStatus.success();
  6452. return appId;
  6453. }
  6454. logStatus.error('Error: getWorkshopAppId failed');
  6455. return false;
  6456. }
  6457. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6458. return false;
  6459. }
  6460. logStatus.error(`${result}:${statusText}(${status})`);
  6461. return false;
  6462. } catch (error) {
  6463. throwError(error, 'Steam.getWorkshopAppId');
  6464. return false;
  6465. }
  6466. }
  6467. async #voteUpWorkshop(id) {
  6468. try {
  6469. const logStatus = scripts_echoLog({
  6470. type: 'votingUpWorkshop',
  6471. text: id
  6472. });
  6473. const {
  6474. result,
  6475. statusText,
  6476. status,
  6477. data
  6478. } = await tools_httpRequest({
  6479. url: 'https://steamcommunity.com/sharedfiles/voteup',
  6480. method: 'POST',
  6481. responseType: 'json',
  6482. headers: {
  6483. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6484. },
  6485. data: $.param({
  6486. id: id,
  6487. sessionid: this.#auth.communitySessionID
  6488. })
  6489. });
  6490. if (result === 'Success') {
  6491. if (data?.status === 200 && data.response?.success === 1) {
  6492. logStatus.success();
  6493. return true;
  6494. }
  6495. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6496. return true;
  6497. }
  6498. logStatus.error(`${result}:${statusText}(${status})`);
  6499. return true;
  6500. } catch (error) {
  6501. throwError(error, 'Steam.voteupWorkshop');
  6502. return true;
  6503. }
  6504. }
  6505. async #toggleCurator(curatorId, doTask = true) {
  6506. try {
  6507. if (!doTask && this.whiteList.curators.includes(curatorId)) {
  6508. scripts_echoLog({
  6509. type: 'whiteList',
  6510. text: 'Steam.unfollowCurator',
  6511. id: curatorId
  6512. });
  6513. return true;
  6514. }
  6515. if (this.#ASF) {
  6516. return await this.#ASF.toggleCurator(curatorId, doTask);
  6517. }
  6518. const logStatus = scripts_echoLog({
  6519. type: doTask ? 'followingCurator' : 'unfollowingCurator',
  6520. text: curatorId
  6521. });
  6522. const {
  6523. result,
  6524. statusText,
  6525. status,
  6526. data
  6527. } = await tools_httpRequest({
  6528. url: 'https://store.steampowered.com/curators/ajaxfollow',
  6529. method: 'POST',
  6530. headers: {
  6531. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6532. },
  6533. data: $.param({
  6534. clanid: curatorId,
  6535. sessionid: this.#auth.storeSessionID,
  6536. follow: doTask
  6537. }),
  6538. dataType: 'json'
  6539. });
  6540. if (result === 'Success') {
  6541. if (data?.status === 200 && data.response?.success?.success === 1) {
  6542. logStatus.success();
  6543. return true;
  6544. }
  6545. logStatus.error(`Error:${data?.statusText}(${data?.response?.success}` || `${data?.status})`);
  6546. return false;
  6547. }
  6548. logStatus.error(`${result}:${statusText}(${status})`);
  6549. return false;
  6550. } catch (error) {
  6551. throwError(error, 'Steam.toggleCurator');
  6552. return false;
  6553. }
  6554. }
  6555. async getCuratorId(path, name) {
  6556. try {
  6557. const logStatus = scripts_echoLog({
  6558. type: 'gettingCuratorId',
  6559. text: `${path}/${name}`
  6560. });
  6561. const curatorId = this.#cache.curator[`${path}/${name}`];
  6562. if (curatorId) {
  6563. logStatus.success();
  6564. return curatorId;
  6565. }
  6566. const {
  6567. result,
  6568. statusText,
  6569. status,
  6570. data
  6571. } = await tools_httpRequest({
  6572. url: `https://store.steampowered.com/${path}/${name}`,
  6573. method: 'GET',
  6574. headers: {
  6575. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6576. }
  6577. });
  6578. if (result === 'Success') {
  6579. if (data?.status === 200) {
  6580. const curatorId = data.responseText.match(/g_pagingData.*?"clanid":([\d]+)/)?.[1];
  6581. if (curatorId) {
  6582. this.#setCache('curator', `${path}/${name}`, curatorId);
  6583. logStatus.success();
  6584. return curatorId;
  6585. }
  6586. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6587. return false;
  6588. }
  6589. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6590. return false;
  6591. }
  6592. logStatus.error(`${result}:${statusText}(${status})`);
  6593. return false;
  6594. } catch (error) {
  6595. throwError(error, 'Steam.getCuratorID');
  6596. return false;
  6597. }
  6598. }
  6599. async #toggleCuratorLike(link, doTask = true) {
  6600. try {
  6601. const [ path, name ] = link.split('/');
  6602. if (!(path && name)) {
  6603. scripts_echoLog({
  6604. text: i18n('errorLink', link)
  6605. });
  6606. return false;
  6607. }
  6608. const curatorId = await this.getCuratorId(path, name);
  6609. if (curatorId) {
  6610. return await this.#toggleCurator(curatorId, doTask);
  6611. }
  6612. return false;
  6613. } catch (error) {
  6614. throwError(error, 'Steam.toggleCuratorLike');
  6615. return false;
  6616. }
  6617. }
  6618. async #getAnnouncementParams(appId, viewId) {
  6619. try {
  6620. const logStatus = scripts_echoLog({
  6621. type: 'gettingAnnouncementParams',
  6622. text: appId,
  6623. id: viewId
  6624. });
  6625. const {
  6626. result,
  6627. statusText,
  6628. status,
  6629. data
  6630. } = await tools_httpRequest({
  6631. 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`,
  6632. method: 'GET',
  6633. responseType: 'json',
  6634. headers: {
  6635. Host: 'store.steampowered.com',
  6636. Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
  6637. }
  6638. });
  6639. if (result === 'Success') {
  6640. if (data?.status === 200 && data?.response?.success === 1) {
  6641. const {
  6642. clanid,
  6643. gid
  6644. } = data.response.event?.announcement_body || {};
  6645. if (clanid) {
  6646. logStatus.success();
  6647. return {
  6648. clanId: clanid,
  6649. gid: gid
  6650. };
  6651. }
  6652. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6653. return {};
  6654. }
  6655. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6656. return {};
  6657. }
  6658. logStatus.error(`${result}:${statusText}(${status})`);
  6659. return {};
  6660. } catch (error) {
  6661. throwError(error, 'Steam.likeAnnouncement');
  6662. return {};
  6663. }
  6664. }
  6665. async #likeAnnouncement(id) {
  6666. try {
  6667. const [ appId, viewId ] = id.split('/');
  6668. if (!(appId && viewId)) {
  6669. scripts_echoLog({}).error(`${i18n('missParams')}(id)`);
  6670. return false;
  6671. }
  6672. const {
  6673. clanId,
  6674. gid
  6675. } = await this.#getAnnouncementParams(appId, viewId);
  6676. if (!clanId) {
  6677. return false;
  6678. }
  6679. const logStatus = scripts_echoLog({
  6680. type: 'likingAnnouncement',
  6681. text: appId,
  6682. id: viewId
  6683. });
  6684. const {
  6685. result,
  6686. statusText,
  6687. status,
  6688. data
  6689. } = await tools_httpRequest({
  6690. url: `https://store.steampowered.com/updated/ajaxrateupdate/${gid || viewId}`,
  6691. method: 'POST',
  6692. headers: {
  6693. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6694. Host: 'store.steampowered.com',
  6695. Origin: 'https://store.steampowered.com',
  6696. Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
  6697. },
  6698. data: $.param({
  6699. sessionid: this.#auth.storeSessionID,
  6700. voteup: 1,
  6701. clanid: clanId,
  6702. ajax: 1
  6703. }),
  6704. dataType: 'json'
  6705. });
  6706. if (result === 'Success') {
  6707. if (data?.status === 200 && data.response.success === 1) {
  6708. logStatus.success();
  6709. return true;
  6710. }
  6711. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6712. return false;
  6713. }
  6714. logStatus.error(`${result}:${statusText}(${status})`);
  6715. return false;
  6716. } catch (error) {
  6717. throwError(error, 'Steam.likeAnnouncement');
  6718. return false;
  6719. }
  6720. }
  6721. async #appid2subid(id) {
  6722. try {
  6723. const logStatus = scripts_echoLog({
  6724. type: 'gettingSubid',
  6725. text: id
  6726. });
  6727. const {
  6728. result,
  6729. statusText,
  6730. status,
  6731. data
  6732. } = await tools_httpRequest({
  6733. url: `https://store.steampowered.com/app/${id}`,
  6734. method: 'GET',
  6735. headers: {
  6736. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6737. }
  6738. });
  6739. if (result === 'Success') {
  6740. if (data?.status === 200) {
  6741. if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) {
  6742. logStatus.success(i18n('owned'));
  6743. return false;
  6744. }
  6745. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  6746. logStatus.warning(i18n('changeAreaNotice'));
  6747. const result = await this.#changeArea();
  6748. if (!result || result === 'CN' || result === 'skip') {
  6749. return false;
  6750. }
  6751. return await this.#appid2subid(id);
  6752. }
  6753. let subid = data.responseText.match(/name="subid" value="([\d]+?)"/)?.[1];
  6754. if (subid) {
  6755. logStatus.success();
  6756. return subid;
  6757. }
  6758. subid = data.responseText.match(/AddFreeLicense\(\s*(\d+)/)?.[1];
  6759. if (subid) {
  6760. logStatus.success();
  6761. return subid;
  6762. }
  6763. logStatus.error(`Error:${i18n('noSubid')}`);
  6764. return false;
  6765. }
  6766. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6767. return false;
  6768. }
  6769. logStatus.error(`${result}:${statusText}(${status})`);
  6770. return false;
  6771. } catch (error) {
  6772. throwError(error, 'Steam.appid2subid');
  6773. return false;
  6774. }
  6775. }
  6776. async #getLicenses() {
  6777. try {
  6778. const logStatus = scripts_echoLog({
  6779. text: i18n('gettingLicenses')
  6780. });
  6781. const {
  6782. result,
  6783. statusText,
  6784. status,
  6785. data
  6786. } = await tools_httpRequest({
  6787. url: `https://store.steampowered.com/dynamicstore/userdata/?t=${new Date().getTime()}`,
  6788. method: 'GET',
  6789. responseType: 'json'
  6790. });
  6791. if (result === 'Success') {
  6792. if (data?.status === 200) {
  6793. logStatus.success();
  6794. return data.response?.rgOwnedPackages;
  6795. }
  6796. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6797. return false;
  6798. }
  6799. logStatus.error(`${result}:${statusText}(${status})`);
  6800. return false;
  6801. } catch (error) {
  6802. throwError(error, 'Steam.getLicenses');
  6803. return false;
  6804. }
  6805. }
  6806. async #addLicense(id) {
  6807. try {
  6808. if (this.#ASF) {
  6809. return await this.#ASF.addLicense(id);
  6810. }
  6811. const [ type, ids ] = id.split('-');
  6812. if (type === 'appid') {
  6813. const subid = await this.#appid2subid(ids);
  6814. if (!subid) {
  6815. return false;
  6816. }
  6817. const logStatus = scripts_echoLog({
  6818. type: 'addingFreeLicense',
  6819. text: ids
  6820. });
  6821. if (!await this.#addFreeLicense(subid, logStatus)) {
  6822. return false;
  6823. }
  6824. const {
  6825. result,
  6826. statusText,
  6827. status,
  6828. data
  6829. } = await tools_httpRequest({
  6830. url: `https://store.steampowered.com/app/${ids}`,
  6831. method: 'GET'
  6832. });
  6833. if (result === 'Success') {
  6834. if (data?.status === 200) {
  6835. if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) {
  6836. logStatus.success();
  6837. return true;
  6838. }
  6839. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6840. return false;
  6841. }
  6842. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6843. return false;
  6844. }
  6845. logStatus.error(`${result}:${statusText}(${status})`);
  6846. return false;
  6847. } else if (type === 'subid') {
  6848. if (this.#area === 'CN') {
  6849. scripts_echoLog({}).success(i18n('tryChangeAreaNotice'));
  6850. await this.#changeArea();
  6851. }
  6852. const logStatusArr = {};
  6853. const idsArr = ids.split(',');
  6854. for (const subid of idsArr) {
  6855. const logStatus = scripts_echoLog({
  6856. type: 'addingFreeLicenseSubid',
  6857. text: subid
  6858. });
  6859. if (!await this.#addFreeLicense(subid, logStatus)) {
  6860. return false;
  6861. }
  6862. logStatusArr[subid] = logStatus;
  6863. }
  6864. const licenses = await this.#getLicenses();
  6865. if (!licenses) {
  6866. return false;
  6867. }
  6868. for (const subid of idsArr) {
  6869. if (licenses.includes(parseInt(subid, 10))) {
  6870. logStatusArr[subid].success();
  6871. } else {
  6872. logStatusArr[subid].error();
  6873. }
  6874. }
  6875. return true;
  6876. }
  6877. return false;
  6878. } catch (error) {
  6879. throwError(error, 'Steam.addLicense');
  6880. return false;
  6881. }
  6882. }
  6883. async #addFreeLicense(id, logStatusPre) {
  6884. try {
  6885. const logStatus = logStatusPre || scripts_echoLog({
  6886. type: 'addingFreeLicenseSubid',
  6887. text: id
  6888. });
  6889. const {
  6890. result,
  6891. statusText,
  6892. status,
  6893. data
  6894. } = await tools_httpRequest({
  6895. url: `https://store.steampowered.com/freelicense/addfreelicense/${id}`,
  6896. method: 'POST',
  6897. headers: {
  6898. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6899. Host: 'store.steampowered.com',
  6900. Origin: 'https://store.steampowered.com',
  6901. Referer: 'https://store.steampowered.com/account/licenses/'
  6902. },
  6903. data: $.param({
  6904. ajax: true,
  6905. sessionid: this.#auth.storeSessionID
  6906. }),
  6907. dataType: 'json'
  6908. });
  6909. if (result === 'Success') {
  6910. if (data?.status === 200) {
  6911. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  6912. logStatus.warning(i18n('changeAreaNotice'));
  6913. const result = await this.#changeArea();
  6914. if (!result || [ 'CN', 'skip' ].includes(result)) {
  6915. return false;
  6916. }
  6917. return await this.#addFreeLicense(id);
  6918. }
  6919. logStatus.success();
  6920. return true;
  6921. }
  6922. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6923. return false;
  6924. }
  6925. logStatus.error(`${result}:${statusText}(${status})`);
  6926. return false;
  6927. } catch (error) {
  6928. throwError(error, 'Steam.addFreeLicense');
  6929. return false;
  6930. }
  6931. }
  6932. async #requestPlayTestAccess(id) {
  6933. try {
  6934. if (this.#ASF) {
  6935. return await this.#ASF.requestPlayTestAccess(id);
  6936. }
  6937. const logStatus = scripts_echoLog({
  6938. type: 'requestingPlayTestAccess',
  6939. text: id
  6940. });
  6941. const {
  6942. result,
  6943. statusText,
  6944. status,
  6945. data
  6946. } = await tools_httpRequest({
  6947. url: `https://store.steampowered.com/ajaxrequestplaytestaccess/${id}`,
  6948. method: 'POST',
  6949. headers: {
  6950. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6951. Host: 'store.steampowered.com',
  6952. Origin: 'https://store.steampowered.com',
  6953. Referer: `https://store.steampowered.com/app/${id}`
  6954. },
  6955. data: $.param({
  6956. sessionid: this.#auth.storeSessionID
  6957. }),
  6958. dataType: 'json'
  6959. });
  6960. if (result === 'Success') {
  6961. if (data?.status === 200 && data?.response?.success === 1) {
  6962. logStatus.success();
  6963. return true;
  6964. }
  6965. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6966. return false;
  6967. }
  6968. logStatus.error(`${result}:${statusText}(${status})`);
  6969. return false;
  6970. } catch (error) {
  6971. throwError(error, 'Steam.requestPlayTestAccess');
  6972. return false;
  6973. }
  6974. }
  6975. async toggle({
  6976. doTask = true,
  6977. groupLinks = [],
  6978. officialGroupLinks = [],
  6979. wishlistLinks = [],
  6980. followLinks = [],
  6981. forumLinks = [],
  6982. workshopLinks = [],
  6983. workshopVoteLinks = [],
  6984. curatorLinks = [],
  6985. curatorLikeLinks = [],
  6986. announcementLinks = [],
  6987. licenseLinks = [],
  6988. playtestLinks = []
  6989. }) {
  6990. try {
  6991. if ([ ...groupLinks, ...officialGroupLinks, ...forumLinks, ...workshopLinks, ...workshopVoteLinks ].length > 0 && !this.#communityInitialized) {
  6992. scripts_echoLog({
  6993. text: i18n('needInit')
  6994. });
  6995. return false;
  6996. }
  6997. if ([ ...wishlistLinks, ...followLinks, ...curatorLinks, ...curatorLikeLinks, ...announcementLinks, ...licenseLinks, ...playtestLinks ].length > 0 && !this.#storeInitialized) {
  6998. scripts_echoLog({
  6999. text: i18n('needInit')
  7000. });
  7001. return false;
  7002. }
  7003. const prom = [];
  7004. if (doTask && !globalOptions.doTask.steam.groups || !doTask && !globalOptions.undoTask.steam.groups) {
  7005. scripts_echoLog({
  7006. type: 'globalOptionsSkip',
  7007. text: 'steam.groups'
  7008. });
  7009. } else {
  7010. const realGroups = this.getRealParams('groups', groupLinks, doTask, link => link.match(/groups\/(.+)\/?/)?.[1]?.split('/')?.[0]);
  7011. if (realGroups.length > 0) {
  7012. for (const group of realGroups) {
  7013. if (doTask) {
  7014. prom.push(this.#joinGroup(group));
  7015. } else {
  7016. prom.push(this.#leaveGroup(group));
  7017. }
  7018. await delay(1e3);
  7019. }
  7020. }
  7021. }
  7022. if (doTask && !globalOptions.doTask.steam.officialGroups || !doTask && !globalOptions.undoTask.steam.officialGroups) {
  7023. scripts_echoLog({
  7024. type: 'globalOptionsSkip',
  7025. text: 'steam.officialGroups'
  7026. });
  7027. } else {
  7028. const realOfficialGroups = this.getRealParams('officialGroups', officialGroupLinks, doTask, link => link.match(/games\/(.+)\/?/)?.[1]);
  7029. if (realOfficialGroups.length > 0) {
  7030. for (const officialGroup of realOfficialGroups) {
  7031. if (doTask) {
  7032. prom.push(this.#joinOfficialGroup(officialGroup));
  7033. } else {
  7034. prom.push(this.#leaveOfficialGroup(officialGroup));
  7035. }
  7036. await delay(1e3);
  7037. }
  7038. }
  7039. }
  7040. if (doTask && !globalOptions.doTask.steam.wishlists || !doTask && !globalOptions.undoTask.steam.wishlists) {
  7041. scripts_echoLog({
  7042. type: 'globalOptionsSkip',
  7043. text: 'steam.wishlists'
  7044. });
  7045. } else {
  7046. const realWishlists = this.getRealParams('wishlists', wishlistLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  7047. if (realWishlists.length > 0) {
  7048. for (const game of realWishlists) {
  7049. if (doTask) {
  7050. prom.push(this.#addToWishlist(game));
  7051. } else {
  7052. prom.push(this.#removeFromWishlist(game));
  7053. }
  7054. await delay(1e3);
  7055. }
  7056. }
  7057. }
  7058. if (doTask && !globalOptions.doTask.steam.follows || !doTask && !globalOptions.undoTask.steam.follows) {
  7059. scripts_echoLog({
  7060. type: 'globalOptionsSkip',
  7061. text: 'steam.follows'
  7062. });
  7063. } else {
  7064. const realFollows = this.getRealParams('follows', followLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  7065. if (realFollows.length > 0) {
  7066. for (const game of realFollows) {
  7067. prom.push(this.#toggleFollowGame(game, doTask));
  7068. await delay(1e3);
  7069. }
  7070. }
  7071. }
  7072. if (doTask && !globalOptions.doTask.steam.forums || !doTask && !globalOptions.undoTask.steam.forums) {
  7073. scripts_echoLog({
  7074. type: 'globalOptionsSkip',
  7075. text: 'steam.forums'
  7076. });
  7077. } else {
  7078. const realForums = this.getRealParams('forums', forumLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  7079. if (realForums.length > 0) {
  7080. for (const forum of realForums) {
  7081. prom.push(this.#toggleForum(forum, doTask));
  7082. await delay(1e3);
  7083. }
  7084. }
  7085. }
  7086. if (doTask && !globalOptions.doTask.steam.workshops || !doTask && !globalOptions.undoTask.steam.workshops) {
  7087. scripts_echoLog({
  7088. type: 'globalOptionsSkip',
  7089. text: 'steam.workshops'
  7090. });
  7091. } else {
  7092. const realWorkshops = this.getRealParams('workshops', workshopLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]);
  7093. if (realWorkshops.length > 0) {
  7094. for (const workshop of realWorkshops) {
  7095. prom.push(this.#toggleFavoriteWorkshop(workshop, doTask));
  7096. await delay(1e3);
  7097. }
  7098. }
  7099. }
  7100. if (doTask && !globalOptions.doTask.steam.workshopVotes) {
  7101. scripts_echoLog({
  7102. type: 'globalOptionsSkip',
  7103. text: 'steam.workshopVotes'
  7104. });
  7105. } else {
  7106. const realworkshopVotes = this.getRealParams('workshopVotes', workshopVoteLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]);
  7107. if (doTask && realworkshopVotes.length > 0) {
  7108. for (const workshop of realworkshopVotes) {
  7109. prom.push(this.#voteUpWorkshop(workshop));
  7110. await delay(1e3);
  7111. }
  7112. }
  7113. }
  7114. if (doTask && !globalOptions.doTask.steam.curators || !doTask && !globalOptions.undoTask.steam.curators) {
  7115. scripts_echoLog({
  7116. type: 'globalOptionsSkip',
  7117. text: 'steam.curators'
  7118. });
  7119. } else {
  7120. const realCurators = this.getRealParams('curators', curatorLinks, doTask, link => link.match(/curator\/([\d]+)/)?.[1]);
  7121. const realCuratorLikes = this.getRealParams('curatorLikes', curatorLikeLinks, doTask, link => link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3).join('/'));
  7122. if (realCurators.length > 0) {
  7123. for (const curator of realCurators) {
  7124. prom.push(this.#toggleCurator(curator, doTask));
  7125. await delay(1e3);
  7126. }
  7127. }
  7128. if (realCuratorLikes.length > 0) {
  7129. for (const curatorLike of realCuratorLikes) {
  7130. prom.push(this.#toggleCuratorLike(curatorLike, doTask));
  7131. await delay(1e3);
  7132. }
  7133. }
  7134. }
  7135. if (doTask && !globalOptions.doTask.steam.announcements) {
  7136. scripts_echoLog({
  7137. type: 'globalOptionsSkip',
  7138. text: 'steam.announcements'
  7139. });
  7140. } else {
  7141. const realAnnouncements = this.getRealParams('announcements', announcementLinks, doTask, link => {
  7142. if (link.includes('store.steampowered.com')) {
  7143. return link.match(/store\.steampowered\.com\/news\/app\/([\d]+)\/view\/([\d]+)/)?.slice(1, 3).join('/');
  7144. }
  7145. return link.match(/steamcommunity\.com\/games\/([\d]+)\/announcements\/detail\/([\d]+)/)?.slice(1, 3).join('/');
  7146. });
  7147. if (doTask && realAnnouncements.length > 0) {
  7148. for (const id of realAnnouncements) {
  7149. prom.push(this.#likeAnnouncement(id));
  7150. await delay(1e3);
  7151. }
  7152. }
  7153. }
  7154. if (doTask && !globalOptions.doTask.steam.licenses) {
  7155. scripts_echoLog({
  7156. type: 'globalOptionsSkip',
  7157. text: 'steam.licenses'
  7158. });
  7159. } else if (doTask && globalOptions.doTask.steam.licenses && licenseLinks.length > 0) {
  7160. for (const ids of licenseLinks) {
  7161. const [ type, idsStr ] = ids.split('-');
  7162. const idsArr = idsStr.split(',');
  7163. for (const id of idsArr) {
  7164. prom.push(this.#addLicense(`${type}-${id}`));
  7165. await delay(1e3);
  7166. }
  7167. }
  7168. }
  7169. if (doTask && !globalOptions.doTask.steam.playtests) {
  7170. scripts_echoLog({
  7171. type: 'globalOptionsSkip',
  7172. text: 'steam.playtests'
  7173. });
  7174. } else {
  7175. const realPlaytests = this.getRealParams('playtests', playtestLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  7176. if (doTask && globalOptions.doTask.steam.playtests && realPlaytests.length > 0) {
  7177. for (const id of realPlaytests) {
  7178. prom.push(this.#requestPlayTestAccess(id));
  7179. await delay(1e3);
  7180. }
  7181. }
  7182. }
  7183. return Promise.all(prom).then(async () => {
  7184. if (this.#oldArea && this.#area !== this.#oldArea) {
  7185. scripts_echoLog({}).warning(i18n('steamFinishNotice') + this.#oldArea);
  7186. await this.#changeArea(this.#oldArea);
  7187. }
  7188. return true;
  7189. });
  7190. } catch (error) {
  7191. throwError(error, 'Steam.toggle');
  7192. return false;
  7193. }
  7194. }
  7195. #setCache(type, name, id) {
  7196. try {
  7197. this.#cache[type][name] = id;
  7198. GM_setValue('steamCache', this.#cache);
  7199. } catch (error) {
  7200. throwError(error, 'Steam.setCache');
  7201. }
  7202. }
  7203. }
  7204. const social_Steam = Steam;
  7205. class Website {
  7206. undoneTasks;
  7207. socialTasks;
  7208. giveawayId;
  7209. socialInitialized = {
  7210. discord: false,
  7211. instagram: false,
  7212. reddit: false,
  7213. twitch: false,
  7214. twitter: false,
  7215. vk: false,
  7216. youtube: false,
  7217. steamStore: false,
  7218. steamCommunity: false
  7219. };
  7220. initialized = false;
  7221. steamTaskType = {
  7222. steamStore: false,
  7223. steamCommunity: false
  7224. };
  7225. social = {};
  7226. async #bind(name, init) {
  7227. try {
  7228. return {
  7229. name: name,
  7230. result: await init
  7231. };
  7232. } catch (error) {
  7233. throwError(error, 'Website.bind');
  7234. return {
  7235. name: name,
  7236. result: false
  7237. };
  7238. }
  7239. }
  7240. async initSocial(action) {
  7241. try {
  7242. const pro = [];
  7243. const tasks = action === 'do' ? this.undoneTasks : this.socialTasks;
  7244. if (tasks.discord) {
  7245. const hasDiscord = Object.values(tasks.discord).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7246. if (hasDiscord && (!this.socialInitialized.discord || !this.social.discord)) {
  7247. this.social.discord = new social_Discord();
  7248. pro.push(this.#bind('discord', this.social.discord.init(action)));
  7249. }
  7250. }
  7251. if (tasks.instagram) {
  7252. const hasInstagram = Object.values(tasks.instagram).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7253. if (hasInstagram && (!this.socialInitialized.instagram || !this.social.instagram)) {
  7254. this.social.instagram = new social_Instagram();
  7255. pro.push(this.#bind('instagram', this.social.instagram.init()));
  7256. }
  7257. }
  7258. if (tasks.reddit) {
  7259. const hasReddit = Object.values(tasks.reddit).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7260. if (hasReddit && (!this.socialInitialized.reddit || !this.social.reddit)) {
  7261. this.social.reddit = new social_Reddit();
  7262. pro.push(this.#bind('reddit', this.social.reddit.init()));
  7263. }
  7264. }
  7265. if (tasks.twitch) {
  7266. const hasTwitch = Object.values(tasks.twitch).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7267. if (hasTwitch && (!this.socialInitialized.twitch || !this.social.twitch)) {
  7268. this.social.twitch = new social_Twitch();
  7269. pro.push(this.#bind('twitch', this.social.twitch.init()));
  7270. }
  7271. }
  7272. if (tasks.twitter) {
  7273. const hasTwitter = Object.values(tasks.twitter).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7274. if (hasTwitter && (!this.socialInitialized.twitter || !this.social.twitter)) {
  7275. this.social.twitter = new social_Twitter();
  7276. pro.push(this.#bind('twitter', this.social.twitter.init()));
  7277. }
  7278. }
  7279. if (tasks.vk) {
  7280. const hasVk = Object.values(tasks.vk).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7281. if (hasVk && (!this.socialInitialized.vk || !this.social.vk)) {
  7282. this.social.vk = new social_Vk();
  7283. pro.push(this.#bind('vk', this.social.vk.init()));
  7284. }
  7285. }
  7286. if (tasks.youtube) {
  7287. const hasYoutube = Object.values(tasks.youtube).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7288. if (hasYoutube && (!this.socialInitialized.youtube || !this.social.youtube)) {
  7289. this.social.youtube = new Youtube();
  7290. pro.push(this.#bind('youtube', this.social.youtube.init()));
  7291. }
  7292. }
  7293. if (tasks.steam) {
  7294. const steamLength = Object.values(tasks.steam).reduce((total, arr) => [ ...total, ...arr ]).length;
  7295. if (steamLength > 0) {
  7296. if (!this.social.steam) {
  7297. this.social.steam = new social_Steam();
  7298. }
  7299. 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);
  7300. if (steamLength - steamCommunityLength > 0) {
  7301. this.steamTaskType.steamStore = true;
  7302. if (!this.socialInitialized.steamStore) {
  7303. pro.push(this.#bind('steamStore', this.social.steam.init('store')));
  7304. }
  7305. }
  7306. if (steamCommunityLength > 0) {
  7307. if (!this.socialInitialized.steamCommunity) {
  7308. this.steamTaskType.steamCommunity = true;
  7309. pro.push(this.#bind('steamCommunity', this.social.steam.init('community')));
  7310. }
  7311. }
  7312. }
  7313. }
  7314. if (tasks.links && tasks.links.length > 0) {
  7315. this.social.visitLink = visitLink;
  7316. }
  7317. return await Promise.all(pro).then(result => {
  7318. let checked = true;
  7319. for (const data of result) {
  7320. if (data.result) {
  7321. this.socialInitialized[data.name] = data.result;
  7322. } else {
  7323. checked = false;
  7324. }
  7325. }
  7326. return checked;
  7327. });
  7328. } catch (error) {
  7329. throwError(error, 'Website.initSocial');
  7330. return false;
  7331. }
  7332. }
  7333. uniqueTasks(allTasks) {
  7334. try {
  7335. const result = {};
  7336. for (const [ social, types ] of Object.entries(allTasks)) {
  7337. result[social] = {};
  7338. for (const [ type, tasks ] of Object.entries(types)) {
  7339. result[social][type] = unique(tasks);
  7340. }
  7341. }
  7342. return result;
  7343. } catch (error) {
  7344. throwError(error, 'Website.uniqueTasks');
  7345. return allTasks;
  7346. }
  7347. }
  7348. async toggleTask(action) {
  7349. try {
  7350. if (!this.initialized && !this.init()) {
  7351. return false;
  7352. }
  7353. if (!await this.classifyTask(action)) {
  7354. return false;
  7355. }
  7356. await this.initSocial(action);
  7357. const pro = [];
  7358. const doTask = action === 'do';
  7359. const tasks = doTask ? this.undoneTasks : this.socialTasks;
  7360. if (this.socialInitialized.discord === true && this.social.discord) {
  7361. pro.push(this.social.discord.toggle({
  7362. doTask: doTask,
  7363. ...tasks.discord
  7364. }));
  7365. }
  7366. if (this.socialInitialized.instagram === true && this.social.instagram) {
  7367. pro.push(this.social.instagram.toggle({
  7368. doTask: doTask,
  7369. ...tasks.instagram
  7370. }));
  7371. }
  7372. if (this.socialInitialized.reddit === true && this.social.reddit) {
  7373. pro.push(this.social.reddit.toggle({
  7374. doTask: doTask,
  7375. ...tasks.reddit
  7376. }));
  7377. }
  7378. if (this.socialInitialized.twitch === true && this.social.twitch) {
  7379. pro.push(this.social.twitch.toggle({
  7380. doTask: doTask,
  7381. ...tasks.twitch
  7382. }));
  7383. }
  7384. if (this.socialInitialized.twitter === true && this.social.twitter) {
  7385. pro.push(this.social.twitter.toggle({
  7386. doTask: doTask,
  7387. ...tasks.twitter
  7388. }));
  7389. }
  7390. if (this.socialInitialized.vk === true && this.social.vk) {
  7391. pro.push(this.social.vk.toggle({
  7392. doTask: doTask,
  7393. ...tasks.vk
  7394. }));
  7395. }
  7396. if (this.socialInitialized.youtube === true && this.social.youtube) {
  7397. pro.push(this.social.youtube.toggle({
  7398. doTask: doTask,
  7399. ...tasks.youtube
  7400. }));
  7401. }
  7402. if ((this.steamTaskType.steamCommunity ? this.socialInitialized.steamCommunity === true : true) && (this.steamTaskType.steamStore ? this.socialInitialized.steamStore === true : true) && this.social.steam) {
  7403. pro.push(this.social.steam.toggle({
  7404. doTask: doTask,
  7405. ...tasks.steam
  7406. }));
  7407. }
  7408. if (this.social.visitLink && tasks.links && doTask) {
  7409. for (const link of tasks.links) {
  7410. pro.push(this.social.visitLink(link));
  7411. }
  7412. }
  7413. if (doTask && tasks.extra && this.extraDoTask) {
  7414. const hasExtra = Object.values(tasks.extra).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  7415. if (hasExtra) {
  7416. pro.push(this.extraDoTask(tasks.extra));
  7417. }
  7418. }
  7419. await Promise.all(pro);
  7420. scripts_echoLog({}).success(i18n('allTasksComplete'));
  7421. return true;
  7422. } catch (error) {
  7423. throwError(error, 'Website.toggleTask');
  7424. return false;
  7425. }
  7426. }
  7427. async doTask() {
  7428. try {
  7429. return await this.toggleTask('do');
  7430. } catch (error) {
  7431. throwError(error, 'Website.doTask');
  7432. return false;
  7433. }
  7434. }
  7435. async undoTask() {
  7436. try {
  7437. return await this.toggleTask('undo');
  7438. } catch (error) {
  7439. throwError(error, 'Website.undoTask');
  7440. return false;
  7441. }
  7442. }
  7443. }
  7444. const website_Website = Website;
  7445. const defaultTasksTemplate = {
  7446. steam: {
  7447. groupLinks: [],
  7448. wishlistLinks: [],
  7449. curatorLinks: [],
  7450. followLinks: []
  7451. },
  7452. discord: {
  7453. serverLinks: []
  7454. },
  7455. vk: {
  7456. nameLinks: []
  7457. },
  7458. extra: {
  7459. website: []
  7460. }
  7461. };
  7462. const defaultTasks = JSON.stringify(defaultTasksTemplate);
  7463. class FreeAnyWhere extends website_Website {
  7464. name = 'FreeAnyWhere';
  7465. tasks = [];
  7466. socialTasks = JSON.parse(defaultTasks);
  7467. undoneTasks = JSON.parse(defaultTasks);
  7468. buttons = [ 'doTask', 'undoTask', 'verifyTask', 'getKey' ];
  7469. static test() {
  7470. return window.location.host === 'freeanywhere.net';
  7471. }
  7472. async init() {
  7473. try {
  7474. const logStatus = scripts_echoLog({
  7475. text: i18n('initing')
  7476. });
  7477. debug('检测登录按钮');
  7478. if ($('div.header__login a[href*=logout]').length === 0) {
  7479. window.open('https://freeanywhere.net/game.php?steam_login', '_self');
  7480. logStatus.warning(i18n('needLogin'));
  7481. return false;
  7482. }
  7483. debug('检测是否为登录页面');
  7484. if (window.location.href.includes('/login')) {
  7485. logStatus.warning(i18n('needLogin'));
  7486. return false;
  7487. }
  7488. this.initialized = true;
  7489. logStatus.success();
  7490. return true;
  7491. } catch (error) {
  7492. throwError(error, 'Freeanywhere.init');
  7493. return false;
  7494. }
  7495. }
  7496. async classifyTask(action) {
  7497. try {
  7498. const logStatus = scripts_echoLog({
  7499. text: i18n('getTasksInfo')
  7500. });
  7501. if (action === 'undo') {
  7502. this.socialTasks = GM_getValue(`fawTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks);
  7503. }
  7504. const tasks = $('div.game__content-tasks__task').map((index, element) => ({
  7505. id: $(element).attr('data-id'),
  7506. social: $(element).find('div.task-img img').attr('alt'),
  7507. link: $(element).find('div.task-link a').attr('href'),
  7508. title: $(element).find('div.task-link').text().trim(),
  7509. type: $(element).attr('data-type'),
  7510. isSuccess: $(element).hasClass('done')
  7511. })).toArray();
  7512. if (tasks.length === 0) {
  7513. logStatus.success();
  7514. return false;
  7515. }
  7516. if (action === 'verify') {
  7517. this.tasks = [];
  7518. }
  7519. for (const task of tasks) {
  7520. debug('任务分类', task);
  7521. const {
  7522. id,
  7523. social,
  7524. title,
  7525. type,
  7526. link,
  7527. isSuccess
  7528. } = task;
  7529. const taskInfo = {
  7530. id: id,
  7531. title: title,
  7532. social: social,
  7533. type: type
  7534. };
  7535. if (action === 'verify' && !isSuccess) {
  7536. this.tasks.push(taskInfo);
  7537. continue;
  7538. }
  7539. switch (type) {
  7540. case 'steam_account_verify':
  7541. break;
  7542.  
  7543. case 'steam_game_wishlist':
  7544. if (action === 'undo' && link) {
  7545. this.socialTasks.steam.wishlistLinks.push(link);
  7546. }
  7547. if (action === 'do' && !isSuccess && link) {
  7548. this.undoneTasks.steam.wishlistLinks.push(link);
  7549. }
  7550. break;
  7551.  
  7552. case 'steam_group_sub':
  7553. if (action === 'undo' && link) {
  7554. this.socialTasks.steam.groupLinks.push(link);
  7555. }
  7556. if (action === 'do' && !isSuccess && link) {
  7557. this.undoneTasks.steam.groupLinks.push(link);
  7558. }
  7559. break;
  7560.  
  7561. case 'site_visit':
  7562. if (action === 'do' && !isSuccess) {
  7563. this.undoneTasks.extra.website.push(`id=${id}&type=${type}&task=true`);
  7564. }
  7565. break;
  7566.  
  7567. case 'vk_community_sub':
  7568. if (action === 'undo' && link) {
  7569. this.socialTasks.vk.nameLinks.push(link);
  7570. }
  7571. if (action === 'do' && !isSuccess && link) {
  7572. this.undoneTasks.vk.nameLinks.push(link);
  7573. }
  7574. break;
  7575.  
  7576. case 'vk_post_like':
  7577. if (action === 'undo' && link) {
  7578. this.socialTasks.vk.nameLinks.push(`${link}&action=like`);
  7579. }
  7580. if (action === 'do' && !isSuccess && link) {
  7581. this.undoneTasks.vk.nameLinks.push(`${link}&action=like`);
  7582. }
  7583. break;
  7584.  
  7585. case 'discord_server_sub':
  7586. if (action === 'undo' && link) {
  7587. this.socialTasks.discord.serverLinks.push(link);
  7588. }
  7589. if (action === 'do' && !isSuccess && link) {
  7590. this.undoneTasks.discord.serverLinks.push(link);
  7591. }
  7592. break;
  7593.  
  7594. case 'telegram_channel_sub':
  7595. scripts_echoLog({}).warning(`${i18n('tgTaskNotice')}`);
  7596. break;
  7597.  
  7598. case 'none':
  7599. scripts_echoLog({}).warning(`${i18n('notConnect')}`);
  7600. break;
  7601.  
  7602. default:
  7603. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${type}`);
  7604. break;
  7605. }
  7606. }
  7607. logStatus.success();
  7608. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  7609. this.socialTasks = this.uniqueTasks(this.socialTasks);
  7610. if (window.DEBUG) {
  7611. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  7612. }
  7613. GM_setValue(`fawTasks-${this.giveawayId}`, {
  7614. tasks: this.socialTasks,
  7615. time: new Date().getTime()
  7616. });
  7617. return true;
  7618. } catch (error) {
  7619. throwError(error, 'Freeanywhere.classifyTask');
  7620. return false;
  7621. }
  7622. }
  7623. async verifyTask() {
  7624. try {
  7625. if (!this.initialized && !this.init()) {
  7626. debug('未初始化');
  7627. return false;
  7628. }
  7629. if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
  7630. debug('任务列表为空', this.tasks);
  7631. return false;
  7632. }
  7633. const pro = [];
  7634. for (const task of this.tasks) {
  7635. pro.push(this.#verify(task));
  7636. await delay(1e3);
  7637. }
  7638. await Promise.all(pro);
  7639. scripts_echoLog({}).success(i18n('allTasksComplete'));
  7640. return !!await this.getKey(true);
  7641. } catch (error) {
  7642. throwError(error, 'Freeanywhere.verifyTask');
  7643. return false;
  7644. }
  7645. }
  7646. async extraDoTask({
  7647. website
  7648. }) {
  7649. try {
  7650. const pro = [];
  7651. for (const link of website) {
  7652. pro.push(this.#doVisitWebsite(link));
  7653. }
  7654. return Promise.all(pro).then(() => true);
  7655. } catch (error) {
  7656. throwError(error, 'FreeAnyWhere.extraDoTask');
  7657. return false;
  7658. }
  7659. }
  7660. async #doVisitWebsite(link) {
  7661. try {
  7662. const logStatus = scripts_echoLog({
  7663. text: i18n('visitingLink')
  7664. });
  7665. const {
  7666. result,
  7667. statusText,
  7668. status
  7669. } = await tools_httpRequest({
  7670. url: 'https://freeanywhere.net/php/task_site_visit_done.php',
  7671. method: 'POST',
  7672. headers: {
  7673. 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  7674. },
  7675. data: link
  7676. });
  7677. if (result === 'Success') {
  7678. logStatus.success();
  7679. return true;
  7680. }
  7681. logStatus.error(`${result}:${statusText}(${status})`);
  7682. return false;
  7683. } catch (error) {
  7684. throwError(error, 'FreeAnyWhere.doVisitWebsite');
  7685. return false;
  7686. }
  7687. }
  7688. async getKey(initialized) {
  7689. try {
  7690. if (!initialized && !this.initialized && !this.init()) {
  7691. debug('未初始化');
  7692. return false;
  7693. }
  7694. const logStatus = scripts_echoLog({
  7695. text: i18n('gettingKey')
  7696. });
  7697. const {
  7698. result,
  7699. statusText,
  7700. status,
  7701. data
  7702. } = await tools_httpRequest({
  7703. url: 'https://freeanywhere.net/php/user_get_key.php',
  7704. method: 'POST'
  7705. });
  7706. if (result === 'Success') {
  7707. if (data?.responseText.indexOf('bad') !== -1 || data?.responseText.length > 50) {
  7708. logStatus.error(data?.responseText);
  7709. return false;
  7710. }
  7711. logStatus.success();
  7712. scripts_echoLog({}).success(data.responseText);
  7713. return data.responseText;
  7714. }
  7715. logStatus.error(`${result}:${statusText}(${status})`);
  7716. return false;
  7717. } catch (error) {
  7718. throwError(error, 'FreeAnyWhere.getGiveawayId');
  7719. return false;
  7720. }
  7721. }
  7722. async #verify(task) {
  7723. try {
  7724. const logStatus = scripts_echoLog({
  7725. html: `<li>${i18n('verifyingTask')}${task.title.trim()}...<font></font></li>`
  7726. });
  7727. const {
  7728. result,
  7729. statusText,
  7730. status,
  7731. data
  7732. } = await tools_httpRequest({
  7733. url: 'https://freeanywhere.net/php/user_task_update.php',
  7734. method: 'POST',
  7735. headers: {
  7736. 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  7737. },
  7738. data: `id=${task.id}&type=${task.type}`
  7739. });
  7740. if (result === 'Success') {
  7741. if (data?.responseText.trim() === 'good') {
  7742. logStatus.success();
  7743. return true;
  7744. }
  7745. debug('任务验证结果', data?.response);
  7746. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  7747. return false;
  7748. }
  7749. logStatus.error(`${result}:${statusText}(${status})`);
  7750. return false;
  7751. } catch (error) {
  7752. throwError(error, 'Freeanywhere.verify');
  7753. return false;
  7754. }
  7755. }
  7756. }
  7757. const Freeanywhere = FreeAnyWhere;
  7758. const Giveawaysu_defaultTasks = {
  7759. steam: {
  7760. groupLinks: [],
  7761. wishlistLinks: [],
  7762. curatorLinks: [],
  7763. curatorLikeLinks: [],
  7764. followLinks: [],
  7765. forumLinks: [],
  7766. announcementLinks: [],
  7767. workshopVoteLinks: [],
  7768. playtestLinks: []
  7769. },
  7770. discord: {
  7771. serverLinks: []
  7772. },
  7773. instagram: {
  7774. userLinks: []
  7775. },
  7776. vk: {
  7777. nameLinks: []
  7778. },
  7779. twitch: {
  7780. channelLinks: []
  7781. },
  7782. reddit: {
  7783. redditLinks: []
  7784. },
  7785. youtube: {
  7786. channelLinks: [],
  7787. likeLinks: []
  7788. },
  7789. twitter: {
  7790. userLinks: [],
  7791. retweetLinks: []
  7792. }
  7793. };
  7794. class GiveawaySu extends website_Website {
  7795. name = 'GiveawaySu';
  7796. socialTasks = Giveawaysu_defaultTasks;
  7797. undoneTasks = Giveawaysu_defaultTasks;
  7798. buttons = [ 'doTask', 'undoTask' ];
  7799. static test() {
  7800. return /^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(window.location.href);
  7801. }
  7802. async after() {
  7803. try {
  7804. if (!this.#checkLogin()) {
  7805. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  7806. }
  7807. if (!await this.#checkLeftKey()) {
  7808. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  7809. }
  7810. scripts_echoLog({}).warning(i18n('gsNotice'));
  7811. } catch (error) {
  7812. throwError(error, 'Giveawaysu.after');
  7813. }
  7814. }
  7815. init() {
  7816. try {
  7817. const logStatus = scripts_echoLog({
  7818. text: i18n('initing')
  7819. });
  7820. if ($('a.steam-login').length > 0) {
  7821. window.open('/steam/redirect', '_self');
  7822. logStatus.warning(i18n('needLogin'));
  7823. return false;
  7824. }
  7825. if (!this.#getGiveawayId()) {
  7826. return false;
  7827. }
  7828. this.initialized = true;
  7829. logStatus.success();
  7830. return true;
  7831. } catch (error) {
  7832. throwError(error, 'Giveawaysu.init');
  7833. return false;
  7834. }
  7835. }
  7836. async classifyTask(action) {
  7837. try {
  7838. const logStatus = scripts_echoLog({
  7839. text: i18n('getTasksInfo')
  7840. });
  7841. if (action === 'undo') {
  7842. this.socialTasks = GM_getValue(`gasTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks;
  7843. return true;
  7844. }
  7845. const pro = [];
  7846. const tasks = $('#actions tr');
  7847. if ($('div.bind-discord').is(':visible')) {
  7848. $('div.bind-discord a')[0].click();
  7849. }
  7850. if ($('div.bind-twitch').is(':visible')) {
  7851. $('div.bind-twitch a')[0].click();
  7852. }
  7853. for (const task of tasks) {
  7854. pro.push(new Promise(resolve => {
  7855. const td = $(task).find('td:not(".hidden")');
  7856. const colorfulTask = td.eq(1).find('a:not([data-trigger="link"])');
  7857. const colorlessTask = td.eq(2).find('a:not([data-trigger="link"])');
  7858. const taskDes = colorfulTask.length > 0 ? colorfulTask : colorlessTask;
  7859. const taskIcon = td.eq(0).find('i').attr('class') || '';
  7860. const taskName = taskDes.text().trim();
  7861. if (taskIcon.includes('ban') || /disable adblock/gi.test(taskName)) {
  7862. return resolve(true);
  7863. }
  7864. getRedirectLink(taskDes.attr('href')).then(taskLink => {
  7865. if (!taskLink) {
  7866. return resolve(false);
  7867. }
  7868. if (taskIcon.includes('steam') && /join/gi.test(taskName)) {
  7869. this.undoneTasks.steam.groupLinks.push(taskLink);
  7870. } else if (/like.*announcement/gi.test(taskName)) {
  7871. this.undoneTasks.steam.announcementLinks.push(taskLink);
  7872. } else if (/(follow|subscribe).*curator/gim.test(taskName) && /^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) {
  7873. this.undoneTasks.steam.curatorLinks.push(taskLink);
  7874. } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
  7875. this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
  7876. } else if (/subscribe.*steam.*forum/gim.test(taskName)) {
  7877. this.undoneTasks.steam.forumLinks.push(taskLink);
  7878. } else if (taskIcon.includes('thumbs-up') && /^https?:\/\/steamcommunity\.com\/sharedfiles\/filedetails\/\?id=[\d]+/.test(taskLink)) {
  7879. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  7880. } else if (taskIcon.includes('plus') && /request.*playtest/gim.test(taskName)) {
  7881. this.undoneTasks.steam.playtestLinks.push(taskLink);
  7882. } else if (taskIcon.includes('discord') || /join.*discord/gim.test(taskName)) {
  7883. this.undoneTasks.discord.serverLinks.push(taskLink);
  7884. } else if (taskIcon.includes('instagram') || /follow.*instagram/gim.test(taskName)) {
  7885. this.undoneTasks.instagram.userLinks.push(taskLink);
  7886. } else if (taskIcon.includes('twitch') || /follow.*twitch.*channel/gim.test(taskName)) {
  7887. this.undoneTasks.twitch.channelLinks.push(taskLink);
  7888. } else if (taskIcon.includes('reddit') || /subscribe.*subreddit/gim.test(taskName) || /follow.*reddit/gim.test(taskName)) {
  7889. this.undoneTasks.reddit.redditLinks.push(taskLink);
  7890. } else if (/watch.*art/gim.test(taskName)) {
  7891. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  7892. } else if (/subscribe.*youtube.*channel/gim.test(taskName)) {
  7893. this.undoneTasks.youtube.channelLinks.push(taskLink);
  7894. } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) {
  7895. this.undoneTasks.youtube.likeLinks.push(taskLink);
  7896. } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) {
  7897. this.undoneTasks.vk.nameLinks.push(taskLink);
  7898. } else {
  7899. if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else {
  7900. if (/wishlist.*game|add.*wishlist/gim.test(taskName)) {
  7901. this.undoneTasks.steam.wishlistLinks.push(taskLink);
  7902. }
  7903. if (/follow.*button/gim.test(taskName)) {
  7904. this.undoneTasks.steam.followLinks.push(taskLink);
  7905. }
  7906. }
  7907. }
  7908. resolve(true);
  7909. }).catch(error => {
  7910. throwError(error, 'Giveawaysu.classifyTask->getRedirectLink');
  7911. return false;
  7912. });
  7913. }));
  7914. }
  7915. await Promise.all(pro);
  7916. logStatus.success();
  7917. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  7918. this.socialTasks = this.undoneTasks;
  7919. if (window.DEBUG) {
  7920. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  7921. }
  7922. GM_setValue(`gasTasks-${this.giveawayId}`, {
  7923. tasks: this.socialTasks,
  7924. time: new Date().getTime()
  7925. });
  7926. return true;
  7927. } catch (error) {
  7928. throwError(error, 'Giveawaysu.classifyTask');
  7929. return false;
  7930. }
  7931. }
  7932. #checkLogin() {
  7933. try {
  7934. if (!globalOptions.other.checkLogin) {
  7935. return true;
  7936. }
  7937. if ($('a.steam-login').length > 0) {
  7938. window.open('/steam/redirect', '_self');
  7939. }
  7940. return true;
  7941. } catch (error) {
  7942. throwError(error, 'Giveawaysu.checkLogin');
  7943. return false;
  7944. }
  7945. }
  7946. async #checkLeftKey() {
  7947. try {
  7948. if (!globalOptions.other.checkLeftKey) {
  7949. return true;
  7950. }
  7951. if ($('.giveaway-ended').length > 0 && $('.giveaway-key').length === 0) {
  7952. await external_Swal_default().fire({
  7953. icon: 'warning',
  7954. title: i18n('notice'),
  7955. text: i18n('noKeysLeft'),
  7956. confirmButtonText: i18n('confirm'),
  7957. cancelButtonText: i18n('cancel'),
  7958. showCancelButton: true
  7959. }).then(({
  7960. value
  7961. }) => {
  7962. if (value) {
  7963. window.close();
  7964. }
  7965. });
  7966. }
  7967. return true;
  7968. } catch (error) {
  7969. throwError(error, 'Giveawaysu.checkLeftKey');
  7970. return false;
  7971. }
  7972. }
  7973. #getGiveawayId() {
  7974. try {
  7975. const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
  7976. if (giveawayId) {
  7977. this.giveawayId = giveawayId;
  7978. return true;
  7979. }
  7980. scripts_echoLog({
  7981. text: i18n('getFailed', 'GiveawayId')
  7982. });
  7983. return false;
  7984. } catch (error) {
  7985. throwError(error, 'Giveawaysu.getGiveawayId');
  7986. return false;
  7987. }
  7988. }
  7989. }
  7990. class Indiedb {
  7991. name = 'Indiedb';
  7992. buttons = [ 'doTask' ];
  7993. static test() {
  7994. return window.location.host === 'www.indiedb.com';
  7995. }
  7996. async after() {
  7997. try {
  7998. if (!this.#checkLogin()) {
  7999. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  8000. }
  8001. if (!await this.#checkLeftKey()) {
  8002. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8003. }
  8004. } catch (error) {
  8005. throwError(error, 'Indiedb.after');
  8006. }
  8007. }
  8008. async doTask() {
  8009. try {
  8010. if (!await this.#join()) {
  8011. return false;
  8012. }
  8013. return await this.#do();
  8014. } catch (error) {
  8015. throwError(error, 'Indiedb.doTask');
  8016. return false;
  8017. }
  8018. }
  8019. async #join() {
  8020. try {
  8021. if ($('a.buttonenter:contains(Register to join)').length > 0) {
  8022. scripts_echoLog({}).error(i18n('needLogin'));
  8023. return false;
  8024. }
  8025. const currentoption = $('a.buttonenter.buttongiveaway');
  8026. if (/join giveaway/gim.test(currentoption.text())) {
  8027. const logStatus = scripts_echoLog({
  8028. text: `${i18n('joiningGiveaway')}...`
  8029. });
  8030. const {
  8031. result,
  8032. statusText,
  8033. status,
  8034. data
  8035. } = await tools_httpRequest({
  8036. url: currentoption.attr('href'),
  8037. method: 'POST',
  8038. data: 'ajax=t',
  8039. dataType: 'json',
  8040. headers: {
  8041. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  8042. Accept: 'application/json, text/javascript, */*; q=0.01',
  8043. Origin: window.location.origin,
  8044. referer: window.location.href
  8045. }
  8046. });
  8047. if (result === 'Success') {
  8048. if (data?.status === 200) {
  8049. if (data.response?.success) {
  8050. currentoption.addClass('buttonentered').text('Success - Giveaway joined');
  8051. $('#giveawaysjoined').slideDown();
  8052. $('#giveawaysrecommend').slideDown();
  8053. logStatus.success(`Success${data.response?.text ? `:${data.response?.text}` : ''}`);
  8054. return true;
  8055. }
  8056. logStatus.error(`Error${data.response?.text ? `:${data.response?.text}` : ''}`);
  8057. return false;
  8058. }
  8059. if (await this.#join2()) {
  8060. logStatus.success('Success');
  8061. return true;
  8062. }
  8063. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  8064. return false;
  8065. }
  8066. logStatus.error(`${result}:${statusText}(${status})`);
  8067. return false;
  8068. } else if (/success/gim.test($('a.buttonenter.buttongiveaway').text())) {
  8069. return true;
  8070. }
  8071. scripts_echoLog({}).warning(i18n('needJoinGiveaway'));
  8072. return false;
  8073. } catch (error) {
  8074. throwError(error, 'Indiedb.join');
  8075. return false;
  8076. }
  8077. }
  8078. async #join2() {
  8079. try {
  8080. return await new Promise(resolve => {
  8081. const targetNode = document.getElementById('giveawaysjoined');
  8082. const config = {
  8083. attributes: true
  8084. };
  8085. const observer = new MutationObserver(() => {
  8086. if ($('#giveawaysjoined').is(':visible')) {
  8087. resolve(true);
  8088. observer.disconnect();
  8089. }
  8090. });
  8091. observer.observe(targetNode, config);
  8092. $('a.buttonenter.buttongiveaway')[0]?.click();
  8093. setTimeout(() => {
  8094. resolve(false);
  8095. observer.disconnect();
  8096. }, 3e4);
  8097. });
  8098. } catch (error) {
  8099. throwError(error, 'Indiedb.join2');
  8100. return false;
  8101. }
  8102. }
  8103. async #do() {
  8104. try {
  8105. const id = $('script').map((index, script) => {
  8106. if (/\$\(document\)/gim.test(script.innerHTML)) {
  8107. return [ script.innerHTML.match(/"\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0], script.innerHTML.match(/"\/newsletter\/ajax\/subscribeprofile\/optin\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0] ];
  8108. }
  8109. return null;
  8110. });
  8111. if (id.length === 2) {
  8112. const pro = [];
  8113. const tasks = $('#giveawaysjoined a[class*=promo]');
  8114. for (const task of tasks) {
  8115. const promo = $(task);
  8116. if (!promo.hasClass('buttonentered')) {
  8117. const status = scripts_echoLog({
  8118. text: `${i18n('doing')}:${promo.parents('p').text()}...`
  8119. });
  8120. if (/facebookpromo|twitterpromo|visitpromo/gim.test(task.className)) {
  8121. let text = '';
  8122. if (promo.hasClass('facebookpromo')) {
  8123. text = 'facebookpromo';
  8124. } else if (promo.hasClass('twitterpromo')) {
  8125. text = 'twitterpromo';
  8126. } else {
  8127. text = 'visitpromo';
  8128. }
  8129. pro.push(new Promise(resolve => {
  8130. $.ajax({
  8131. type: 'POST',
  8132. url: urlPath(`/giveaways/ajax/${text}/${id[0]}`),
  8133. timeout: 6e4,
  8134. dataType: 'json',
  8135. data: {
  8136. ajax: 't'
  8137. },
  8138. error(response, error, exception) {
  8139. if (window.DEBUG) {
  8140. console.log('%cAuto-Task[Debug]:', 'color:red', {
  8141. response: response,
  8142. error: error,
  8143. exception: exception
  8144. });
  8145. }
  8146. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  8147. resolve(true);
  8148. },
  8149. success(response) {
  8150. if (response.success) {
  8151. status.success(`Success:${response.text}`);
  8152. promo.addClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  8153. resolve(true);
  8154. } else {
  8155. status.error(`Error:${response.text}`);
  8156. resolve(true);
  8157. }
  8158. }
  8159. });
  8160. }));
  8161. } else if (promo.hasClass('emailoptinpromo')) {
  8162. pro.push(new Promise(resolve => {
  8163. $.ajax({
  8164. type: 'POST',
  8165. url: urlPath(`/newsletter/ajax/subscribeprofile/optin/${id[1]}`),
  8166. timeout: 6e4,
  8167. dataType: 'json',
  8168. data: {
  8169. ajax: 't',
  8170. emailsystoggle: 4
  8171. },
  8172. error(response, error, exception) {
  8173. if (window.DEBUG) {
  8174. console.log('%cAuto-Task[Debug]:', 'color:red', {
  8175. response: response,
  8176. error: error,
  8177. exception: exception
  8178. });
  8179. }
  8180. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  8181. resolve(true);
  8182. },
  8183. success(response) {
  8184. if (response.success) {
  8185. status.success(`Success:${response.text}`);
  8186. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  8187. resolve(true);
  8188. } else {
  8189. status.error(`Error:${response.text}`);
  8190. resolve(true);
  8191. }
  8192. }
  8193. });
  8194. }));
  8195. } else if (promo.hasClass('watchingpromo')) {
  8196. pro.push(new Promise(resolve => {
  8197. const data = getUrlQuery(promo.attr('href'));
  8198. data.ajax = 't';
  8199. $.ajax({
  8200. type: 'POST',
  8201. url: urlPath(promo.attr('href')?.split(/[?#]/)[0]),
  8202. timeout: 6e4,
  8203. dataType: 'json',
  8204. data: data,
  8205. error(response, error, exception) {
  8206. if (window.DEBUG) {
  8207. console.log('%cAuto-Task[Debug]:', 'color:red', {
  8208. response: response,
  8209. error: error,
  8210. exception: exception
  8211. });
  8212. }
  8213. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  8214. resolve(true);
  8215. },
  8216. success(response) {
  8217. if (response.success) {
  8218. status.success(`Success:${response.text}`);
  8219. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  8220. resolve(true);
  8221. } else {
  8222. status.error(`Error:${response.text}`);
  8223. resolve(true);
  8224. }
  8225. }
  8226. });
  8227. }));
  8228. } else if (!/the-challenge-of-adblock/gim.test(promo.attr('href'))) {
  8229. pro.push(new Promise(resolve => {
  8230. $.ajax({
  8231. type: 'POST',
  8232. url: urlPath(promo.attr('href')),
  8233. timeout: 6e4,
  8234. dataType: 'json',
  8235. data: {
  8236. ajax: 't'
  8237. },
  8238. error(response, error, exception) {
  8239. if (window.DEBUG) {
  8240. console.log('%cAuto-Task[Debug]:', 'color:red', {
  8241. response: response,
  8242. error: error,
  8243. exception: exception
  8244. });
  8245. }
  8246. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  8247. resolve(true);
  8248. },
  8249. success(response) {
  8250. if (response.success) {
  8251. status.success(`Success:${response.text}`);
  8252. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  8253. resolve(true);
  8254. } else {
  8255. status.error(`Error:${response.text}`);
  8256. resolve(true);
  8257. }
  8258. }
  8259. });
  8260. }));
  8261. } else {
  8262. status.error(`Error:${i18n('unKnownTaskType')}`);
  8263. }
  8264. }
  8265. }
  8266. await Promise.all(pro);
  8267. scripts_echoLog({}).success(i18n('allTasksComplete'));
  8268. return true;
  8269. }
  8270. scripts_echoLog({}).error(i18n('getFailed', 'TaskId'));
  8271. return false;
  8272. } catch (error) {
  8273. throwError(error, 'Indiedb.classifyTask');
  8274. return false;
  8275. }
  8276. }
  8277. #checkLogin() {
  8278. try {
  8279. if (!globalOptions.other.checkLogin) {
  8280. return true;
  8281. }
  8282. if ($('a.buttonenter:contains(Register to join)').length > 0) {
  8283. window.open('/members/login', '_self');
  8284. }
  8285. return true;
  8286. } catch (error) {
  8287. throwError(error, 'Indiedb.checkLogin');
  8288. return false;
  8289. }
  8290. }
  8291. async #checkLeftKey() {
  8292. try {
  8293. if (!globalOptions.other.checkLeftKey) {
  8294. return true;
  8295. }
  8296. if ($('a.buttonenter:contains("next time"), a.buttonenter:contains("Giveaway is closed")').length > 0) {
  8297. await external_Swal_default().fire({
  8298. icon: 'warning',
  8299. title: i18n('notice'),
  8300. text: i18n('giveawayEnded'),
  8301. confirmButtonText: i18n('confirm'),
  8302. cancelButtonText: i18n('cancel'),
  8303. showCancelButton: true
  8304. }).then(({
  8305. value
  8306. }) => {
  8307. if (value) {
  8308. window.close();
  8309. }
  8310. });
  8311. }
  8312. return true;
  8313. } catch (error) {
  8314. throwError(error, 'Indiedb.checkLeftKey');
  8315. return false;
  8316. }
  8317. }
  8318. }
  8319. const website_Indiedb = Indiedb;
  8320. const Keyhub_defaultTasksTemplate = {
  8321. steam: {
  8322. groupLinks: [],
  8323. officialGroupLinks: [],
  8324. wishlistLinks: [],
  8325. curatorLinks: []
  8326. },
  8327. discord: {
  8328. serverLinks: []
  8329. },
  8330. extra: {
  8331. videoTasks: []
  8332. },
  8333. links: []
  8334. };
  8335. const Keyhub_defaultTasks = JSON.stringify(Keyhub_defaultTasksTemplate);
  8336. class Keyhub extends website_Website {
  8337. name = 'Keyhub';
  8338. socialTasks = JSON.parse(Keyhub_defaultTasks);
  8339. undoneTasks = JSON.parse(Keyhub_defaultTasks);
  8340. buttons = [ 'doTask', 'undoTask' ];
  8341. static test() {
  8342. return window.location.host === 'key-hub.eu';
  8343. }
  8344. async after() {
  8345. try {
  8346. if (!this.#checkLogin()) {
  8347. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  8348. }
  8349. if (!await this.#checkLeftKey()) {
  8350. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8351. }
  8352. $('.NSFW').hide();
  8353. } catch (error) {
  8354. throwError(error, 'Keyhub.after');
  8355. }
  8356. }
  8357. init() {
  8358. try {
  8359. const logStatus = scripts_echoLog({
  8360. text: i18n('initing')
  8361. });
  8362. if ($('a[href*="/connect/steam"]').length > 0) {
  8363. window.open('/connect/steam', '_self');
  8364. logStatus.warning(i18n('needLogin'));
  8365. return false;
  8366. }
  8367. if (!this.#getGiveawayId()) {
  8368. return false;
  8369. }
  8370. $('#VPNoverlay').hide();
  8371. $('#mainArticleSection').show();
  8372. this.initialized = true;
  8373. logStatus.success();
  8374. return true;
  8375. } catch (error) {
  8376. throwError(error, 'Keyhub.init');
  8377. return false;
  8378. }
  8379. }
  8380. async classifyTask(action) {
  8381. try {
  8382. const logStatus = scripts_echoLog({
  8383. text: i18n('getTasksInfo')
  8384. });
  8385. if (action === 'undo') {
  8386. this.socialTasks = GM_getValue(`khTasks-${this.giveawayId}`)?.tasks || JSON.parse(Keyhub_defaultTasks);
  8387. }
  8388. const tasks = $('.task:not(".googleads")').filter((index, element) => action === 'do' ? $(element).find('i.fa-check-circle:visible').length === 0 : true).find('a');
  8389. for (const task of tasks) {
  8390. let link = $(task).attr('href');
  8391. const taskDes = $(task).text().trim();
  8392. if (!link) {
  8393. continue;
  8394. }
  8395. if (/\/away\?data=/.test(link) || /steamcommunity\.com\/gid\//.test(link)) {
  8396. link = await getRedirectLink(link) || link;
  8397. }
  8398. if (/https?:\/\/key-hub\.eu\/connect\/discord/.test(link)) {
  8399. GM_openInTab(link, {
  8400. active: true
  8401. });
  8402. } else if (/steamcommunity\.com\/groups\//.test(link)) {
  8403. if (action === 'undo') {
  8404. this.socialTasks.steam.groupLinks.push(link);
  8405. }
  8406. if (action === 'do') {
  8407. this.undoneTasks.steam.groupLinks.push(link);
  8408. }
  8409. } else if (/steamcommunity\.com\/games\/[\d]+/.test(link)) {
  8410. if (action === 'undo') {
  8411. this.socialTasks.steam.officialGroupLinks.push(link);
  8412. }
  8413. if (action === 'do') {
  8414. this.undoneTasks.steam.officialGroupLinks.push(link);
  8415. }
  8416. } else if (/store\.steampowered\.com\/app\//.test(link) && /wishlist/gim.test(taskDes)) {
  8417. if (action === 'undo') {
  8418. this.socialTasks.steam.wishlistLinks.push(link);
  8419. }
  8420. if (action === 'do') {
  8421. this.undoneTasks.steam.wishlistLinks.push(link);
  8422. }
  8423. } else if (/store\.steampowered\.com\/curator\//.test(link)) {
  8424. if (action === 'undo') {
  8425. this.socialTasks.steam.curatorLinks.push(link);
  8426. }
  8427. if (action === 'do') {
  8428. this.undoneTasks.steam.curatorLinks.push(link);
  8429. }
  8430. } else if (/^https?:\/\/discord\.com\/invite\//.test(link)) {
  8431. if (action === 'undo') {
  8432. this.socialTasks.discord.serverLinks.push(link);
  8433. }
  8434. if (action === 'do') {
  8435. this.undoneTasks.discord.serverLinks.push(link);
  8436. }
  8437. } else if (/^javascript:videoTask.+/.test(link)) {
  8438. if (action === 'do') {
  8439. const taskData = link.match(/javascript:videoTask\('.+?','(.+?)'/)?.[1];
  8440. if (taskData) {
  8441. this.undoneTasks.extra.videoTasks.push(taskData);
  8442. }
  8443. }
  8444. } 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 {
  8445. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`);
  8446. }
  8447. }
  8448. logStatus.success();
  8449. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8450. this.socialTasks = this.uniqueTasks(this.socialTasks);
  8451. if (window.DEBUG) {
  8452. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8453. }
  8454. GM_setValue(`khTasks-${this.giveawayId}`, {
  8455. tasks: this.socialTasks,
  8456. time: new Date().getTime()
  8457. });
  8458. return true;
  8459. } catch (error) {
  8460. throwError(error, 'Keyhub.classifyTask');
  8461. return false;
  8462. }
  8463. }
  8464. async #doScriptTask(data) {
  8465. try {
  8466. const logStatus = scripts_echoLog({
  8467. text: i18n('doingKeyhubTask')
  8468. });
  8469. const {
  8470. result,
  8471. statusText,
  8472. status,
  8473. data: response
  8474. } = await tools_httpRequest({
  8475. url: `/away?data=${data}`,
  8476. method: 'GET',
  8477. headers: {
  8478. origin: 'https://key-hub.eu',
  8479. referer: 'https://key-hub.eu/'
  8480. }
  8481. });
  8482. if (result === 'Success') {
  8483. if (response?.status === 200) {
  8484. logStatus.success();
  8485. return true;
  8486. }
  8487. logStatus.error(`Error:${response?.statusText}(${response?.status})`);
  8488. return false;
  8489. }
  8490. logStatus.error(`${result}:${statusText}(${status})`);
  8491. return false;
  8492. } catch (error) {
  8493. throwError(error, 'Keyhub.doScriptTask');
  8494. return false;
  8495. }
  8496. }
  8497. async extraDoTask({
  8498. videoTasks
  8499. }) {
  8500. try {
  8501. const pro = [];
  8502. for (const data of videoTasks) {
  8503. pro.push(this.#doScriptTask(data));
  8504. }
  8505. return Promise.all(pro).then(() => true);
  8506. } catch (error) {
  8507. throwError(error, 'Keyhub.extraDoTask');
  8508. return false;
  8509. }
  8510. }
  8511. #getGiveawayId() {
  8512. try {
  8513. const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
  8514. if (giveawayId) {
  8515. this.giveawayId = giveawayId;
  8516. return true;
  8517. }
  8518. scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId'));
  8519. return false;
  8520. } catch (error) {
  8521. throwError(error, 'Keyhub.getGiveawayId');
  8522. return false;
  8523. }
  8524. }
  8525. async #checkLeftKey() {
  8526. try {
  8527. if (!globalOptions.other.checkLeftKey) {
  8528. return true;
  8529. }
  8530. const leftKey = $('#keysleft').text().trim();
  8531. if (leftKey === '0') {
  8532. await external_Swal_default().fire({
  8533. icon: 'warning',
  8534. title: i18n('notice'),
  8535. text: i18n('noKeysLeft'),
  8536. confirmButtonText: i18n('confirm'),
  8537. cancelButtonText: i18n('cancel'),
  8538. showCancelButton: true
  8539. }).then(({
  8540. value
  8541. }) => {
  8542. if (value) {
  8543. window.close();
  8544. }
  8545. });
  8546. }
  8547. return true;
  8548. } catch (error) {
  8549. throwError(error, 'Keyhub.checkLeftKey');
  8550. return false;
  8551. }
  8552. }
  8553. #checkLogin() {
  8554. try {
  8555. if (!globalOptions.other.checkLogin) {
  8556. return true;
  8557. }
  8558. if ($('a[href*="/connect/steam"]').length > 0) {
  8559. window.open('/connect/steam', '_self');
  8560. }
  8561. return true;
  8562. } catch (error) {
  8563. throwError(error, 'Keyhub.checkLogin');
  8564. return false;
  8565. }
  8566. }
  8567. }
  8568. const website_Keyhub = Keyhub;
  8569. const Givekey_defaultTasksTemplate = {
  8570. steam: {
  8571. groupLinks: [],
  8572. wishlistLinks: [],
  8573. curatorLinks: [],
  8574. curatorLikeLinks: []
  8575. },
  8576. twitter: {
  8577. userLinks: []
  8578. },
  8579. vk: {
  8580. nameLinks: []
  8581. },
  8582. discord: {
  8583. serverLinks: []
  8584. }
  8585. };
  8586. const Givekey_defaultTasks = JSON.stringify(Givekey_defaultTasksTemplate);
  8587. class Givekey extends website_Website {
  8588. name = 'Givekey';
  8589. tasks = [];
  8590. socialTasks = JSON.parse(Givekey_defaultTasks);
  8591. undoneTasks = JSON.parse(Givekey_defaultTasks);
  8592. userId;
  8593. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  8594. static test() {
  8595. return window.location.host === 'givekey.ru';
  8596. }
  8597. async after() {
  8598. try {
  8599. await new Promise(resolve => {
  8600. const checker = setInterval(() => {
  8601. if ($('#navbarDropdown').length > 0) {
  8602. clearInterval(checker);
  8603. resolve(true);
  8604. }
  8605. }, 500);
  8606. });
  8607. if (!await this.#checkLeftKey()) {
  8608. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8609. }
  8610. } catch (error) {
  8611. throwError(error, 'Givekey.after');
  8612. }
  8613. }
  8614. init() {
  8615. try {
  8616. const logStatus = scripts_echoLog({
  8617. text: i18n('initing')
  8618. });
  8619. if ($('a[href*="/auth/steam"]').length > 0) {
  8620. window.open('/auth/steam', '_self');
  8621. logStatus.warning(i18n('needLogin'));
  8622. return false;
  8623. }
  8624. if (!this.#getGiveawayId()) {
  8625. return false;
  8626. }
  8627. const userId = $('meta[name="user-id"]').attr('content');
  8628. if (!userId) {
  8629. logStatus.error(i18n('getFailed', i18n('userId')));
  8630. return false;
  8631. }
  8632. this.userId = userId;
  8633. this.initialized = true;
  8634. logStatus.success();
  8635. return true;
  8636. } catch (error) {
  8637. throwError(error, 'Givekey.init');
  8638. return false;
  8639. }
  8640. }
  8641. async classifyTask(action) {
  8642. try {
  8643. const logStatus = scripts_echoLog({
  8644. text: i18n('getTasksInfo')
  8645. });
  8646. if (action === 'undo') {
  8647. this.socialTasks = GM_getValue(`gkTasks-${this.giveawayId}`)?.tasks || JSON.parse(Givekey_defaultTasks);
  8648. }
  8649. const tasks = $('.card-body:has("button") .row');
  8650. for (const task of tasks) {
  8651. const taskEle = $(task);
  8652. const isSuccess = /Complete/i.test(taskEle.find('button').text().trim());
  8653. if (isSuccess && action !== 'undo') {
  8654. continue;
  8655. }
  8656. const checkButton = taskEle.find('#task_check');
  8657. const taskId = checkButton.attr('data-id');
  8658. if (taskId) {
  8659. this.tasks.push(taskId);
  8660. }
  8661. if (action === 'verify') {
  8662. continue;
  8663. }
  8664. let href = taskEle.find('a').attr('href') || null;
  8665. const text = taskEle.find('a').text().trim();
  8666. const icon = taskEle.find('i');
  8667. if (!href || !text) {
  8668. continue;
  8669. }
  8670. if (/^https?:\/\/givekey\.ru\/giveaway\/[\d]+\/execution_task/.test(href)) {
  8671. href = await getRedirectLink(href);
  8672. }
  8673. if (!href) {
  8674. continue;
  8675. }
  8676. if (/^https?:\/\/vk\.com\//.test(href)) {
  8677. this.socialTasks.vk.nameLinks.push(href);
  8678. if (action === 'do' && !isSuccess) {
  8679. this.undoneTasks.vk.nameLinks.push(href);
  8680. }
  8681. } else if (/^https?:\/\/steamcommunity\.com\/groups/.test(href)) {
  8682. this.socialTasks.steam.groupLinks.push(href);
  8683. if (action === 'do' && !isSuccess) {
  8684. this.undoneTasks.steam.groupLinks.push(href);
  8685. }
  8686. } else if (/^https?:\/\/store\.steampowered\.com\/app\//.test(href)) {
  8687. this.socialTasks.steam.wishlistLinks.push(href);
  8688. if (action === 'do' && !isSuccess) {
  8689. this.undoneTasks.steam.wishlistLinks.push(href);
  8690. }
  8691. } else if (/Subscribe/gi.test(text) && icon.hasClass('fa-steam-square')) {
  8692. if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(href)) {
  8693. this.socialTasks.steam.curatorLinks.push(href);
  8694. if (action === 'do' && !isSuccess) {
  8695. this.undoneTasks.steam.curatorLinks.push(href);
  8696. }
  8697. } else {
  8698. this.socialTasks.steam.curatorLikeLinks.push(href);
  8699. if (action === 'do' && !isSuccess) {
  8700. this.undoneTasks.steam.curatorLikeLinks.push(href);
  8701. }
  8702. }
  8703. } else if (/^https?:\/\/twitter\.com\//.test(href) && /Subscribe/gi.test(text)) {
  8704. this.socialTasks.twitter.userLinks.push(href);
  8705. if (action === 'do' && !isSuccess) {
  8706. this.undoneTasks.twitter.userLinks.push(href);
  8707. }
  8708. } else if (icon.hasClass('fa-discord') || /^https?:\/\/discord\.com\/invite\//.test(href)) {
  8709. this.socialTasks.discord.serverLinks.push(href);
  8710. if (action === 'do' && !isSuccess) {
  8711. this.undoneTasks.discord.serverLinks.push(href);
  8712. }
  8713. } else {
  8714. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${text}(${href})`);
  8715. }
  8716. }
  8717. logStatus.success();
  8718. this.tasks = unique(this.tasks);
  8719. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8720. this.socialTasks = this.uniqueTasks(this.socialTasks);
  8721. if (window.DEBUG) {
  8722. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8723. }
  8724. GM_setValue(`gkTasks-${this.giveawayId}`, {
  8725. tasks: this.socialTasks,
  8726. time: new Date().getTime()
  8727. });
  8728. return true;
  8729. } catch (error) {
  8730. throwError(error, 'Givekey.classifyTask');
  8731. return false;
  8732. }
  8733. }
  8734. async verifyTask() {
  8735. try {
  8736. if (!this.initialized && !this.init()) {
  8737. return false;
  8738. }
  8739. if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
  8740. return false;
  8741. }
  8742. scripts_echoLog({}).warning(i18n('giveKeyNoticeBefore'));
  8743. const taskLength = this.tasks.length;
  8744. for (let i = 0; i < taskLength; i++) {
  8745. await this.#verify(this.tasks[i]);
  8746. if (i < taskLength - 1) {
  8747. await delay(15e3);
  8748. }
  8749. }
  8750. scripts_echoLog({}).success(i18n('allTasksComplete'));
  8751. scripts_echoLog({
  8752. html: `<li><font class="warning">${i18n('giveKeyNoticeAfter')}</font></li>`
  8753. });
  8754. return true;
  8755. } catch (error) {
  8756. throwError(error, 'Givekey.verifyTask');
  8757. return false;
  8758. }
  8759. }
  8760. async #verify(task) {
  8761. try {
  8762. const logStatus = scripts_echoLog({
  8763. html: `<li>${i18n('verifyingTask')}${task}...<font></font></li>`
  8764. });
  8765. return await new Promise(resolve => {
  8766. $.ajax({
  8767. url: 'https://givekey.ru/giveaway/task',
  8768. method: 'POST',
  8769. data: `id=${task}&user_id=${this.userId}`,
  8770. dataType: 'json',
  8771. headers: {
  8772. 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
  8773. },
  8774. success: data => {
  8775. if (data.btn) {
  8776. $(`button[data-id=${this.userId}]`).html(data.btn);
  8777. }
  8778. if (data.status === 'ok') {
  8779. $(`.task_check_${data.id}`).html(`<button class="btn btn-success mb-2 btn-block" disabled>${data.btn}</button>`);
  8780. logStatus.success();
  8781. resolve(true);
  8782. } else if (data.status === 'end') {
  8783. logStatus.success();
  8784. scripts_echoLog({}).success(data.key);
  8785. resolve(true);
  8786. } else {
  8787. logStatus.error(`Error:${data.msg}`);
  8788. resolve(false);
  8789. }
  8790. },
  8791. error: xhr => {
  8792. logStatus.error(`Error:${xhr.statusText}(${xhr.status})`);
  8793. resolve(false);
  8794. }
  8795. });
  8796. });
  8797. } catch (error) {
  8798. throwError(error, 'Givekey.verify');
  8799. return false;
  8800. }
  8801. }
  8802. #getGiveawayId() {
  8803. try {
  8804. const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
  8805. if (giveawayId) {
  8806. this.giveawayId = giveawayId;
  8807. return true;
  8808. }
  8809. scripts_echoLog({
  8810. text: i18n('getFailed', 'GiveawayId')
  8811. });
  8812. return false;
  8813. } catch (error) {
  8814. throwError(error, 'Givekey.getGiveawayId');
  8815. return false;
  8816. }
  8817. }
  8818. async #checkLeftKey() {
  8819. try {
  8820. if (!globalOptions.other.checkLeftKey) {
  8821. return true;
  8822. }
  8823. if (!$('#keys_count').text()) {
  8824. await external_Swal_default().fire({
  8825. icon: 'warning',
  8826. title: i18n('notice'),
  8827. text: i18n('noKeysLeft'),
  8828. confirmButtonText: i18n('confirm'),
  8829. cancelButtonText: i18n('cancel'),
  8830. showCancelButton: true
  8831. }).then(({
  8832. value
  8833. }) => {
  8834. if (value) {
  8835. window.close();
  8836. }
  8837. });
  8838. }
  8839. return true;
  8840. } catch (error) {
  8841. throwError(error, 'Givekey.checkLeftKey');
  8842. return false;
  8843. }
  8844. }
  8845. }
  8846. const website_Givekey = Givekey;
  8847. class GiveeClub extends GiveawaySu {
  8848. name = 'GiveeClub';
  8849. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  8850. static test() {
  8851. return /^https?:\/\/givee\.club\/.*?\/event\/[\d]+/.test(window.location.href);
  8852. }
  8853. async after() {
  8854. try {
  8855. if (!this.#checkLogin()) {
  8856. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  8857. }
  8858. if (!await this.#checkLeftKey()) {
  8859. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8860. }
  8861. } catch (error) {
  8862. throwError(error, 'GiveeClub.after');
  8863. }
  8864. }
  8865. init() {
  8866. try {
  8867. const logStatus = scripts_echoLog({
  8868. text: i18n('initing')
  8869. });
  8870. if (!this.#checkLogin()) {
  8871. logStatus.warning(i18n('needLogin'));
  8872. return false;
  8873. }
  8874. if (!this.#getGiveawayId()) {
  8875. return false;
  8876. }
  8877. this.initialized = true;
  8878. logStatus.success();
  8879. return true;
  8880. } catch (error) {
  8881. throwError(error, 'GiveeClub.init');
  8882. return false;
  8883. }
  8884. }
  8885. async classifyTask(action) {
  8886. try {
  8887. const logStatus = scripts_echoLog({
  8888. text: i18n('getTasksInfo')
  8889. });
  8890. if (action === 'undo') {
  8891. this.socialTasks = GM_getValue(`gcTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks;
  8892. return true;
  8893. }
  8894. this.undoneTasks = Giveawaysu_defaultTasks;
  8895. const pro = [];
  8896. const tasks = $('.event-actions tr');
  8897. for (const task of tasks) {
  8898. pro.push(new Promise(resolve => {
  8899. const taskDes = $(task).find('.event-action-label a');
  8900. const taskIcon = $(task).find('.event-action-icon i').attr('class') || '';
  8901. const taskName = taskDes.text().trim();
  8902. const taskType = $(task).find('button[data-type]')?.attr('data-type');
  8903. const taskFinished = $(task).find('.event-action-buttons .btn-success')?.length;
  8904. if (taskIcon.includes('ban') || /AdBlock/i.test(taskName) || taskIcon.includes('envelope') || taskFinished) {
  8905. return resolve(true);
  8906. }
  8907. getRedirectLink(taskDes.attr('href'), true).then(taskLink => {
  8908. if (!taskLink) {
  8909. return resolve(false);
  8910. }
  8911. if (taskType === 'steam.group.join' && /^https?:\/\/steamcommunity\.com\/groups/.test(taskLink)) {
  8912. this.undoneTasks.steam.groupLinks.push(taskLink);
  8913. } else if (/like.*announcement/gi.test(taskName)) {
  8914. this.undoneTasks.steam.announcementLinks.push(taskLink);
  8915. } else if (taskType === 'steam.game.wishlist' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
  8916. this.undoneTasks.steam.wishlistLinks.push(taskLink);
  8917. } else if (taskType === 'steam.game.wishlist' && taskDes.attr('data-steam-wishlist-appid')) {
  8918. this.undoneTasks.steam.wishlistLinks.push(`https://store.steampowered.com/app/${taskDes.attr('data-steam-wishlist-appid')}`);
  8919. } else if (taskType === 'steam.game.follow' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
  8920. this.undoneTasks.steam.followLinks.push(taskLink);
  8921. } else if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) {
  8922. this.undoneTasks.steam.curatorLinks.push(taskLink);
  8923. } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
  8924. this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
  8925. } else if (/subscribe.*steam.*forum/gim.test(taskName)) {
  8926. this.undoneTasks.steam.forumLinks.push(taskLink);
  8927. } else if (taskIcon.includes('discord')) {
  8928. this.undoneTasks.discord.serverLinks.push(taskLink);
  8929. } else if (taskIcon.includes('instagram')) {
  8930. this.undoneTasks.instagram.userLinks.push(taskLink);
  8931. } else if (taskIcon.includes('twitch')) {
  8932. this.undoneTasks.twitch.channelLinks.push(taskLink);
  8933. } else if (taskIcon.includes('reddit')) {
  8934. this.undoneTasks.reddit.redditLinks.push(taskLink);
  8935. } else if (/watch.*art/gim.test(taskName)) {
  8936. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  8937. } else if (/subscribe.*youtube.*channel/gim.test(taskName)) {
  8938. this.undoneTasks.youtube.channelLinks.push(taskLink);
  8939. } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) {
  8940. this.undoneTasks.youtube.likeLinks.push(taskLink);
  8941. } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) {
  8942. this.undoneTasks.vk.nameLinks.push(taskLink);
  8943. } else if (taskIcon.includes('twitter')) {
  8944. if (/https?:\/\/(twitter|x)\.com\/[^/]+\/?$/gim.test(taskLink)) {
  8945. this.undoneTasks.twitter.userLinks.push(taskLink);
  8946. } else if (/https?:\/\/(twitter|x)\.com\/[^/]+?\/status\/[\d]+/gim.test(taskLink)) {
  8947. this.undoneTasks.twitter.retweetLinks.push(taskLink);
  8948. }
  8949. } else {
  8950. if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else {
  8951. if (/follow.*button/gim.test(taskName)) {
  8952. this.undoneTasks.steam.followLinks.push(taskLink);
  8953. }
  8954. }
  8955. }
  8956. resolve(true);
  8957. }).catch(error => {
  8958. throwError(error, 'GiveeClub.classifyTask->getRedirectLink');
  8959. return false;
  8960. });
  8961. }));
  8962. }
  8963. await Promise.all(pro);
  8964. logStatus.success();
  8965. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8966. this.socialTasks = this.undoneTasks;
  8967. if (window.DEBUG) {
  8968. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8969. }
  8970. GM_setValue(`gcTasks-${this.giveawayId}`, {
  8971. tasks: this.socialTasks,
  8972. time: new Date().getTime()
  8973. });
  8974. return true;
  8975. } catch (error) {
  8976. throwError(error, 'GiveeClub.classifyTask');
  8977. return false;
  8978. }
  8979. }
  8980. async verifyTask() {
  8981. try {
  8982. const logStatus = scripts_echoLog({
  8983. text: i18n('giveeClubVerifyNotice')
  8984. });
  8985. const taskButtons = $('.event-actions tr button').has('i.glyphicon-refresh').not('[data-type="user.adblock"]');
  8986. for (const button of taskButtons) {
  8987. button.click();
  8988. if ($(button).attr('data-type') !== 'steam.game.wishlist') {
  8989. await delay(1e3);
  8990. }
  8991. }
  8992. logStatus.warning(i18n('giveeClubVerifyFinished'));
  8993. return true;
  8994. } catch (error) {
  8995. throwError(error, 'Givekey.verifyTask');
  8996. return false;
  8997. }
  8998. }
  8999. #checkLogin() {
  9000. try {
  9001. if (!globalOptions.other.checkLogin) {
  9002. return true;
  9003. }
  9004. if ($('a[href*="/account/auth"]').length > 0) {
  9005. window.open($('a[href*="/account/auth"]').attr('href'), '_self');
  9006. }
  9007. return true;
  9008. } catch (error) {
  9009. throwError(error, 'GiveeClub.checkLogin');
  9010. return false;
  9011. }
  9012. }
  9013. #getGiveawayId() {
  9014. const giveawayId = window.location.href.match(/\/event\/([\d]+)/)?.[1];
  9015. if (giveawayId) {
  9016. this.giveawayId = giveawayId;
  9017. return true;
  9018. }
  9019. scripts_echoLog({
  9020. text: i18n('getFailed', 'GiveawayId')
  9021. });
  9022. return false;
  9023. }
  9024. async #checkLeftKey() {
  9025. try {
  9026. if (!globalOptions.other.checkLeftKey) {
  9027. return true;
  9028. }
  9029. if ($('.event-ended').length > 0 && $('.event-winner').length === 0) {
  9030. await external_Swal_default().fire({
  9031. icon: 'warning',
  9032. title: i18n('notice'),
  9033. text: i18n('giveawayEnded'),
  9034. confirmButtonText: i18n('confirm'),
  9035. cancelButtonText: i18n('cancel'),
  9036. showCancelButton: true
  9037. }).then(({
  9038. value
  9039. }) => {
  9040. if (value) {
  9041. window.close();
  9042. }
  9043. });
  9044. }
  9045. return true;
  9046. } catch (error) {
  9047. throwError(error, 'Giveawaysu.checkLeftKey');
  9048. return false;
  9049. }
  9050. }
  9051. }
  9052. const website_GiveeClub = GiveeClub;
  9053. const defaultOptions = {
  9054. maxPoint: '99999999'
  9055. };
  9056. class OpiumPulses {
  9057. name = 'OpiumPulses';
  9058. options = {
  9059. ...defaultOptions,
  9060. ...GM_getValue('OpiumPulsesOptions')
  9061. };
  9062. maxPoints = 99999999;
  9063. myPoints = 0;
  9064. buttons = [ 'doFreeTask', 'doPointTask' ];
  9065. static test() {
  9066. return window.location.host === 'www.opiumpulses.com';
  9067. }
  9068. async after() {
  9069. try {
  9070. if (!this.#checkLogin()) {
  9071. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  9072. }
  9073. this.maxPoints = parseInt(this.options.maxPoint, 10);
  9074. } catch (error) {
  9075. throwError(error, 'OpiumPulses.after');
  9076. }
  9077. }
  9078. async doFreeTask() {
  9079. try {
  9080. this.#toggleTask('FREE');
  9081. } catch (error) {
  9082. throwError(error, 'OpiumPulses.doFreeTask');
  9083. }
  9084. }
  9085. async doPointTask() {
  9086. try {
  9087. this.myPoints = parseInt($('.page-header__nav-func-user-nav-items.points-items').text().match(/[\d]+/gim)?.[0] || '0', 10);
  9088. this.#toggleTask('points');
  9089. } catch (error) {
  9090. throwError(error, 'OpiumPulses.doPointTask');
  9091. }
  9092. }
  9093. async #toggleTask(type) {
  9094. try {
  9095. const items = $(`.giveaways-page-item:contains('${type}'):not(:contains('ENTERED'))`);
  9096. for (const item of items) {
  9097. const needPoints = parseInt($(item).find('.giveaways-page-item-header-points').text().match(/[\d]+/gim)?.[0] || '999999', 10);
  9098. const name = $(item).find('.giveaways-page-item-footer-name').text().trim();
  9099. if (type === 'points' && needPoints > this.myPoints) {
  9100. scripts_echoLog({}).warning(`${i18n('noPoints')}: ${name}`);
  9101. } else if (type === 'points' && !needPoints) {
  9102. scripts_echoLog({}).warning(`${i18n('getNeedPointsFailed')}: ${name}`);
  9103. } else if (!(type === 'points' && needPoints > this.maxPoints)) {
  9104. const logStatus = scripts_echoLog({
  9105. text: `${i18n('joiningLottery')}<a href="${$(item).find('a.giveaways-page-item-img-btn-more').attr('href')}" target="_blank">${name}</a>...`
  9106. });
  9107. const aElement = $(item).find('a.giveaways-page-item-img-btn-enter:contains(\'enter\')');
  9108. if (aElement?.attr('onclick')?.includes('checkUser')) {
  9109. const giveawayId = aElement.attr('onclick')?.match(/[\d]+/)?.[0];
  9110. if (giveawayId) {
  9111. checkUser(giveawayId);
  9112. }
  9113. }
  9114. if (!aElement.attr('href')) {
  9115. logStatus.error('Error: No "href".');
  9116. continue;
  9117. }
  9118. const {
  9119. result,
  9120. statusText,
  9121. status,
  9122. data
  9123. } = await tools_httpRequest({
  9124. url: aElement.attr('href'),
  9125. method: 'GET'
  9126. });
  9127. if (result === 'Success') {
  9128. const {
  9129. result: result0,
  9130. statusText: statusText0,
  9131. status: status0,
  9132. data: data0
  9133. } = await tools_httpRequest({
  9134. url: data?.finalUrl,
  9135. method: 'GET'
  9136. });
  9137. if (data0?.responseText && /You've entered this giveaway/gim.test(data0.responseText)) {
  9138. logStatus.success();
  9139. const points = data0.responseText.match(/Points:[\s]*?([\d]+)/)?.[1];
  9140. if (type === 'points' && points) {
  9141. this.myPoints = parseInt(points, 10);
  9142. }
  9143. } else if (data0?.responseText && /You're not eligible to enter/gim.test(data0.responseText)) {
  9144. logStatus.error('You\'re not eligible to enter');
  9145. } else {
  9146. logStatus.error(`${result0}:${statusText0}(${status0})`);
  9147. }
  9148. } else {
  9149. logStatus.error(`${result}:${statusText}(${status})`);
  9150. }
  9151. }
  9152. }
  9153. scripts_echoLog({
  9154. text: '-----END-----'
  9155. });
  9156. } catch (error) {
  9157. throwError(error, 'OpiumPulses.toggleTask');
  9158. }
  9159. }
  9160. init() {
  9161. return true;
  9162. }
  9163. classifyTask() {
  9164. return true;
  9165. }
  9166. #checkLogin() {
  9167. try {
  9168. if (!globalOptions.other.checkLogin) {
  9169. return true;
  9170. }
  9171. if ($('a[href*="/site/login"]').length > 1) {
  9172. window.open('/site/login', '_self');
  9173. }
  9174. return true;
  9175. } catch (error) {
  9176. throwError(error, 'OpiumPulses.checkLogin');
  9177. return false;
  9178. }
  9179. }
  9180. }
  9181. const website_OpiumPulses = OpiumPulses;
  9182. const external_dayjs_namespaceObject = dayjs;
  9183. var external_dayjs_default = __webpack_require__.n(external_dayjs_namespaceObject);
  9184. const leftKeyChecker = {
  9185. async classify(link) {
  9186. try {
  9187. if (/^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(link)) {
  9188. return await this.giveawaySu(link);
  9189. }
  9190. if (/^https?:\/\/givee\.club\/[\w]+?\/event\/[\d]+/.test(link)) {
  9191. return await this.giveeClub(link);
  9192. }
  9193. if (/^https?:\/\/gleam\.io\/.+?\/.+/.test(link)) {
  9194. return await this.gleam(link);
  9195. }
  9196. if (/^https?:\/\/www\.indiedb\.com\/giveaways\/.+/.test(link)) {
  9197. return await this.indieDb(link);
  9198. }
  9199. if (/^https?:\/\/key-hub\.eu\/giveaway\/[\d]+/.test(link)) {
  9200. return await this.keyhub(link);
  9201. }
  9202. if (/^https?:\/\/opquests\.com\/quests\/[\d]+/.test(link)) {
  9203. return await this.opquests(link);
  9204. }
  9205. if (/^https?:\/\/itch\.io\/s\/[\d]+?\/.*/.test(link)) {
  9206. return await this.itch(link);
  9207. }
  9208. return false;
  9209. } catch (error) {
  9210. throwError(error, 'leftKeyChecker.classify');
  9211. return false;
  9212. }
  9213. },
  9214. async giveawaySu(link) {
  9215. try {
  9216. const {
  9217. result,
  9218. data
  9219. } = await tools_httpRequest({
  9220. url: link,
  9221. method: 'GET'
  9222. });
  9223. if (result === 'Success' && data?.status === 200) {
  9224. if (data.responseText.includes('class="steam-login"')) {
  9225. return false;
  9226. }
  9227. if (data.responseText.includes('class="giveaway-ended"')) {
  9228. return 'Ended';
  9229. }
  9230. return 'Active';
  9231. }
  9232. return false;
  9233. } catch (error) {
  9234. throwError(error, 'leftKeyChecker.giveawaySu');
  9235. return false;
  9236. }
  9237. },
  9238. async giveeClub(link) {
  9239. try {
  9240. const {
  9241. result,
  9242. data
  9243. } = await tools_httpRequest({
  9244. url: link,
  9245. method: 'GET'
  9246. });
  9247. if (result === 'Success' && data?.status === 200) {
  9248. if (data.responseText.includes('class="event-winner"')) {
  9249. return 'Won';
  9250. }
  9251. if (data.responseText.includes('class="event-ended"')) {
  9252. return 'Ended';
  9253. }
  9254. return 'Active';
  9255. }
  9256. return false;
  9257. } catch (error) {
  9258. throwError(error, 'leftKeyChecker.giveeClub');
  9259. return false;
  9260. }
  9261. },
  9262. async gleam(link) {
  9263. try {
  9264. const {
  9265. result,
  9266. data
  9267. } = await tools_httpRequest({
  9268. url: link,
  9269. method: 'GET'
  9270. });
  9271. if (result === 'Success' && data?.status === 200) {
  9272. if (/incentives&quot;:{&quot;[\d]+?&quot;:\[&quot;.+?&quot;\]/.test(data.responseText)) {
  9273. return 'Won';
  9274. }
  9275. const campaignDiv = data.responseText.match(/<div class='popup-blocks-container'[\w\W]+?'>/)?.[0];
  9276. if (!campaignDiv) {
  9277. return false;
  9278. }
  9279. const campaignString = $(campaignDiv).attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
  9280. if (!campaignString) {
  9281. return false;
  9282. }
  9283. const {
  9284. campaign
  9285. } = JSON.parse(campaignString);
  9286. if (campaign.banned) {
  9287. return 'Banned';
  9288. }
  9289. if (campaign.finished) {
  9290. return 'Ended';
  9291. }
  9292. if (campaign.paused) {
  9293. return 'Paused';
  9294. }
  9295. if (new Date().getTime() < campaign.starts_at * 1e3) {
  9296. return 'NotStart';
  9297. }
  9298. return 'Active';
  9299. }
  9300. return false;
  9301. } catch (error) {
  9302. throwError(error, 'leftKeyChecker.gleam');
  9303. return false;
  9304. }
  9305. },
  9306. async indieDb(link) {
  9307. try {
  9308. const {
  9309. result,
  9310. data
  9311. } = await tools_httpRequest({
  9312. url: link,
  9313. method: 'GET'
  9314. });
  9315. if (result === 'Success' && data?.status === 200) {
  9316. if (data.responseText.includes('Congrats you WON')) {
  9317. return 'Won';
  9318. }
  9319. if (data.responseText.includes('Giveaway is closed') || data.responseText.includes('next time')) {
  9320. return 'Ended';
  9321. }
  9322. return 'Active';
  9323. }
  9324. return false;
  9325. } catch (error) {
  9326. throwError(error, 'leftKeyChecker.indieDb');
  9327. return false;
  9328. }
  9329. },
  9330. async keyhub(link) {
  9331. try {
  9332. const {
  9333. result,
  9334. data
  9335. } = await tools_httpRequest({
  9336. url: link,
  9337. method: 'GET'
  9338. });
  9339. if (result === 'Success' && data?.status === 200) {
  9340. const keysleft = data.responseText.match(/<span id="keysleft">([\d]+?)<\/span>/)?.[1];
  9341. if (!keysleft) {
  9342. return false;
  9343. }
  9344. if (keysleft === '0') {
  9345. return 'Ended';
  9346. }
  9347. return `Active(${keysleft})`;
  9348. }
  9349. return false;
  9350. } catch (error) {
  9351. throwError(error, 'leftKeyChecker.keyhub');
  9352. return false;
  9353. }
  9354. },
  9355. async opquests(link) {
  9356. try {
  9357. const {
  9358. result,
  9359. data
  9360. } = await tools_httpRequest({
  9361. url: link,
  9362. method: 'GET'
  9363. });
  9364. if (result === 'Success' && data?.status === 200) {
  9365. const keysleft = data.responseText.match(/<div class="">[\s]*?([\d]+?)[\s]*?of/)?.[1];
  9366. if (!keysleft) {
  9367. return false;
  9368. }
  9369. if (keysleft === '0') {
  9370. return 'Ended';
  9371. }
  9372. return `Active(${keysleft})`;
  9373. } else if (data?.status === 404) {
  9374. return 'Ended';
  9375. }
  9376. return false;
  9377. } catch (error) {
  9378. throwError(error, 'leftKeyChecker.opquests');
  9379. return false;
  9380. }
  9381. },
  9382. async itch(link) {
  9383. try {
  9384. const {
  9385. result,
  9386. data
  9387. } = await tools_httpRequest({
  9388. url: link,
  9389. method: 'GET'
  9390. });
  9391. if (result === 'Success' && data?.status === 200) {
  9392. const endDate = data.responseText.match(/{"start_date":"[0-9A-Z-:]+?".*?"end_date":"([0-9A-Z-:]+?)".*?}/)?.[1];
  9393. if (!endDate) {
  9394. return false;
  9395. }
  9396. if (new Date().getTime() > new Date(endDate).getTime()) {
  9397. return 'Ended';
  9398. }
  9399. return `Active(${external_dayjs_default()(endDate).format('YYYY-MM-DD HH:mm:ss')})`;
  9400. }
  9401. return false;
  9402. } catch (error) {
  9403. throwError(error, 'leftKeyChecker.itch');
  9404. return false;
  9405. }
  9406. }
  9407. };
  9408. const website_leftKeyChecker = leftKeyChecker;
  9409. const Keylol_defaultTasksTemplate = {
  9410. steam: {
  9411. groupLinks: [],
  9412. wishlistLinks: [],
  9413. curatorLinks: [],
  9414. curatorLikeLinks: [],
  9415. followLinks: [],
  9416. forumLinks: [],
  9417. announcementLinks: [],
  9418. workshopVoteLinks: [],
  9419. licenseLinks: []
  9420. },
  9421. discord: {
  9422. serverLinks: []
  9423. },
  9424. instagram: {
  9425. userLinks: []
  9426. },
  9427. vk: {
  9428. nameLinks: []
  9429. },
  9430. twitch: {
  9431. channelLinks: []
  9432. },
  9433. reddit: {
  9434. redditLinks: []
  9435. },
  9436. twitter: {
  9437. userLinks: [],
  9438. retweetLinks: []
  9439. },
  9440. youtube: {
  9441. channelLinks: [],
  9442. likeLinks: []
  9443. }
  9444. };
  9445. const Keylol_defaultTasks = JSON.stringify(Keylol_defaultTasksTemplate);
  9446. class Keylol extends website_Website {
  9447. name = 'Keylol';
  9448. socialTasks = JSON.parse(Keylol_defaultTasks);
  9449. undoneTasks = JSON.parse(Keylol_defaultTasks);
  9450. buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect' ];
  9451. static test() {
  9452. 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'));
  9453. }
  9454. init() {
  9455. return true;
  9456. }
  9457. after() {
  9458. try {
  9459. const selector = this.name === 'Keylol' ? '#postlist>div[id^="post_"]:first' : 'div.container';
  9460. const mainPost = $(selector);
  9461. const discordLinks = mainPost.find('a[href*="discord.com"]:visible');
  9462. const redditLinks = mainPost.find('a[href*="reddit.com"]:visible');
  9463. const insLinks = mainPost.find('a[href*="instagram.com"]:visible');
  9464. const twitterLinks = mainPost.find('a[href*="twitter.com"]:visible,a[href*="x.com"]:visible');
  9465. const twitchLinks = mainPost.find('a[href*="twitch.tv"]:visible');
  9466. const vkLinks = mainPost.find('a[href*="vk.com"]:visible');
  9467. const steamStoreLinks = mainPost.find('a[href*="store.steampowered.com"]:visible');
  9468. const steamCommunityLinks = mainPost.find('a[href*="steamcommunity.com"]:visible');
  9469. const ytbLinks = mainPost.find('a[href*="youtube.com"]:visible');
  9470. if (discordLinks.length > 0) {
  9471. for (const discordLink of discordLinks) {
  9472. const link = $(discordLink).attr('href');
  9473. if (!(link && /^https?:\/\/discord\.com\/invite\/.+/.test(link))) {
  9474. continue;
  9475. }
  9476. this.#addBtn(discordLink, 'discord', 'serverLinks', link);
  9477. }
  9478. }
  9479. if (redditLinks.length > 0) {
  9480. for (const redditLink of redditLinks) {
  9481. const link = $(redditLink).attr('href');
  9482. if (!(link && /^https?:\/\/www\.reddit\.com\/(r|user)\/.+/.test(link))) {
  9483. continue;
  9484. }
  9485. this.#addBtn(redditLink, 'reddit', 'redditLinks', link);
  9486. }
  9487. }
  9488. if (insLinks.length > 0) {
  9489. for (const insLink of insLinks) {
  9490. const link = $(insLink).attr('href');
  9491. if (!(link && /^https:\/\/www\.instagram\.com\/.+/.test(link))) {
  9492. continue;
  9493. }
  9494. this.#addBtn(insLink, 'instagram', 'userLinks', link);
  9495. }
  9496. }
  9497. if (twitterLinks.length > 0) {
  9498. for (const twitterLink of twitterLinks) {
  9499. const link = $(twitterLink).attr('href');
  9500. if (!(link && /^https:\/\/twitter\.com\/.+/.test(link))) {
  9501. continue;
  9502. }
  9503. if (/https:\/\/twitter\.com\/.*?\/status\/[\d]+/.test(link)) {
  9504. this.#addBtn(twitterLink, 'twitter', 'retweetLinks', link);
  9505. } else {
  9506. this.#addBtn(twitterLink, 'twitter', 'userLinks', link);
  9507. }
  9508. }
  9509. }
  9510. if (twitchLinks.length > 0) {
  9511. for (const twitchLink of twitchLinks) {
  9512. const link = $(twitchLink).attr('href');
  9513. if (!(link && /^https:\/\/(www\.)?twitch\.tv\/.+/.test(link))) {
  9514. continue;
  9515. }
  9516. this.#addBtn(twitchLink, 'twitch', 'channelLinks', link);
  9517. }
  9518. }
  9519. if (vkLinks.length > 0) {
  9520. for (const vkLink of vkLinks) {
  9521. const link = $(vkLink).attr('href');
  9522. if (!(link && /^https:\/\/vk\.com\/.+/.test(link))) {
  9523. continue;
  9524. }
  9525. this.#addBtn(vkLink, 'vk', 'nameLinks', link);
  9526. }
  9527. }
  9528. if (steamStoreLinks.length > 0) {
  9529. for (const steamStoreLink of steamStoreLinks) {
  9530. const link = $(steamStoreLink).attr('href');
  9531. if (!link) {
  9532. continue;
  9533. }
  9534. if (/curator\/[\d]+/.test(link)) {
  9535. this.#addBtn(steamStoreLink, 'steam', 'curatorLinks', link);
  9536. } else if (/(publisher|developer|franchise)\/.+/.test(link)) {
  9537. this.#addBtn(steamStoreLink, 'steam', 'curatorLikeLinks', link);
  9538. } else if (/news(hub)?\/app\/[\d]+\/view\/[\d]+/.test(link)) {
  9539. this.#addBtn(steamStoreLink, 'steam', 'announcementLinks', link);
  9540. } else if (/app\/[\d]+/.test(link)) {
  9541. this.#addBtn(steamStoreLink, 'steam', 'followLinks', link);
  9542. this.#addBtn(steamStoreLink, 'steam', 'wishlistLinks', link);
  9543. }
  9544. }
  9545. }
  9546. if (steamCommunityLinks.length > 0) {
  9547. for (const steamCommunityLink of steamCommunityLinks) {
  9548. const link = $(steamCommunityLink).attr('href');
  9549. if (!link) {
  9550. continue;
  9551. }
  9552. if (/groups\/.+/.test(link)) {
  9553. this.#addBtn(steamCommunityLink, 'steam', 'groupLinks', link);
  9554. } else if (/announcements\/detail\/[\d]+/.test(link)) {
  9555. this.#addBtn(steamCommunityLink, 'steam', 'announcementLinks', link);
  9556. }
  9557. }
  9558. }
  9559. if (ytbLinks.length > 0) {
  9560. for (const ytbLink of ytbLinks) {
  9561. const link = $(ytbLink).attr('href');
  9562. if (!link) {
  9563. continue;
  9564. }
  9565. this.#addBtn(ytbLink, 'youtube', 'channelLinks', link);
  9566. this.#addBtn(ytbLink, 'youtube', 'likeLinks', link);
  9567. }
  9568. }
  9569. 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');
  9570. if (giveawayLinks.length > 0) {
  9571. for (const giveawayLink of giveawayLinks) {
  9572. const link = $(giveawayLink).attr('href');
  9573. if (!link) {
  9574. continue;
  9575. }
  9576. website_leftKeyChecker.classify(link).then(status => {
  9577. if (!status) {
  9578. return;
  9579. }
  9580. if (/^Active/.test(status)) {
  9581. $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status active" title="${i18n('Active')}">${status}</font>`);
  9582. return;
  9583. }
  9584. $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status not-active" title="${i18n(status)}">${status}</font>`);
  9585. }).catch(error => {
  9586. throwError(error, 'keylol.after -> leftKeyChecker');
  9587. });
  9588. }
  9589. }
  9590. if (this.name === 'Keylol') {
  9591. const asfLinks = mainPost.find('a[href^="#asf"]:visible');
  9592. if (asfLinks.length > 0) {
  9593. for (const asfLink of asfLinks) {
  9594. const link = $(asfLink).attr('href');
  9595. if (!link) {
  9596. continue;
  9597. }
  9598. this.#addBtn($(`a[href="${link}"]`).after('<span style="color: #ccc; margin: 0 -5px 0 5px"> | </span>').next()[0], 'steam', 'licenseLinks', `appid-${link.replace('#asf', '')}`);
  9599. }
  9600. }
  9601. const subLinks = mainPost.find('a[href*="steamdb.info/sub/"]:visible');
  9602. if (subLinks.length > 0) {
  9603. for (const subLink of subLinks) {
  9604. const link = $(subLink).attr('href');
  9605. if (!link) {
  9606. continue;
  9607. }
  9608. const subid = link.match(/^https:\/\/steamdb\.info\/sub\/([\d]+)/)?.[1];
  9609. if (!subid) {
  9610. continue;
  9611. }
  9612. this.#addBtn(subLink, 'steam', 'licenseLinks', `subid-${subid}`);
  9613. }
  9614. }
  9615. const asfLinks2 = mainPost.find('.blockcode:contains("addlicense"):visible');
  9616. if (asfLinks2.length > 0) {
  9617. for (const asfLink of asfLinks2) {
  9618. const appid = [ ...asfLink.innerText.matchAll(/a(pp)?\/([\d]+)/g) ].map(matched => matched?.[2]).filter(id => id) || [];
  9619. if (appid.length > 0) {
  9620. this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `appid-${appid.join(',')}`);
  9621. }
  9622. const subid = asfLink.innerText.match(/[\d]+/g)?.filter(matched => !appid.includes(matched));
  9623. if (!subid || subid.length === 0) {
  9624. continue;
  9625. }
  9626. this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `subid-${subid.join(',')}`);
  9627. }
  9628. }
  9629. }
  9630. if ($('#threadindex').length > 0) {
  9631. const [ targetNode ] = $('#postlist').children('div[id^="post_"]');
  9632. const config = {
  9633. childList: true
  9634. };
  9635. const observer = new MutationObserver(() => {
  9636. observer.disconnect();
  9637. this.after();
  9638. });
  9639. observer.observe(targetNode, config);
  9640. }
  9641. } catch (error) {
  9642. throwError(error, 'keylol.after');
  9643. }
  9644. }
  9645. classifyTask(action) {
  9646. try {
  9647. this.socialTasks = JSON.parse(Keylol_defaultTasks);
  9648. this.undoneTasks = JSON.parse(Keylol_defaultTasks);
  9649. const selectedBtns = $('.auto-task-keylol[selected="selected"]:visible');
  9650. for (const btn of selectedBtns) {
  9651. const button = $(btn);
  9652. const social = button.attr('data-social');
  9653. const type = button.attr('data-type');
  9654. const link = button.attr('data-link');
  9655. if (!(social && type && link)) {
  9656. continue;
  9657. }
  9658. if (action === 'do') {
  9659. this.undoneTasks[social][type].push(link);
  9660. }
  9661. if (action === 'undo') {
  9662. this.socialTasks[social][type].push(link);
  9663. }
  9664. }
  9665. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  9666. this.socialTasks = this.uniqueTasks(this.socialTasks);
  9667. if (window.DEBUG) {
  9668. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  9669. }
  9670. return true;
  9671. } catch (error) {
  9672. throwError(error, 'Keylol.classifyTask');
  9673. return false;
  9674. }
  9675. }
  9676. selectAll() {
  9677. try {
  9678. $('.auto-task-keylol:visible').attr('selected', 'selected');
  9679. } catch (error) {
  9680. throwError(error, 'Keylol.selectAll');
  9681. }
  9682. }
  9683. selectNone() {
  9684. try {
  9685. $('.auto-task-keylol:visible').removeAttr('selected');
  9686. } catch (error) {
  9687. throwError(error, 'Keylol.selectNone');
  9688. }
  9689. }
  9690. invertSelect() {
  9691. try {
  9692. $('.auto-task-keylol:visible').each((index, element) => {
  9693. element.getAttribute('selected') ? element.removeAttribute('selected') : element.setAttribute('selected', 'selected');
  9694. });
  9695. } catch (error) {
  9696. throwError(error, 'Keylol.invertSelect');
  9697. }
  9698. }
  9699. #addBtn(before, social, linkType, link) {
  9700. try {
  9701. $(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>`);
  9702. } catch (error) {
  9703. throwError(error, 'keylol.addBtn');
  9704. }
  9705. }
  9706. }
  9707. const website_Keylol = Keylol;
  9708. const Opquests_defaultTasks = {
  9709. steam: {
  9710. groupLinks: [],
  9711. wishlistLinks: [],
  9712. followLinks: [],
  9713. curatorLikeLinks: []
  9714. },
  9715. twitter: {
  9716. userLinks: [],
  9717. retweetLinks: []
  9718. }
  9719. };
  9720. class Opquests extends website_Website {
  9721. name = 'Opquests';
  9722. undoneTasks = {
  9723. ...Opquests_defaultTasks
  9724. };
  9725. buttons = [ 'doTask', 'verifyTask', 'getKey' ];
  9726. static test() {
  9727. return window.location.host === 'opquests.com';
  9728. }
  9729. async after() {
  9730. try {
  9731. if (!this.#checkLogin()) {
  9732. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  9733. }
  9734. const opquestsVerifyTasks = GM_getValue('opquestsVerifyTasks') || [];
  9735. if (opquestsVerifyTasks.length > 0) {
  9736. const taskId = opquestsVerifyTasks.pop();
  9737. GM_setValue('opquestsVerifyTasks', opquestsVerifyTasks);
  9738. const [ verifyBtn ] = $(`#task_id[value="${taskId}"]`).parent().find('button[type="button"]').has('i.fa-check');
  9739. if (verifyBtn) {
  9740. verifyBtn.click();
  9741. return;
  9742. }
  9743. this.after();
  9744. return;
  9745. }
  9746. if (GM_getValue('opquestsVerifyTasks')) {
  9747. GM_deleteValue('opquestsVerifyTasks');
  9748. }
  9749. } catch (error) {
  9750. throwError(error, 'Opquests.after');
  9751. }
  9752. }
  9753. init() {
  9754. try {
  9755. const logStatus = scripts_echoLog({
  9756. text: i18n('initing')
  9757. });
  9758. if ($('a[href*="/auth/redirect"]').length > 0) {
  9759. window.open('/auth/redirect', '_self');
  9760. logStatus.warning(i18n('needLogin'));
  9761. return false;
  9762. }
  9763. if (!this.#getGiveawayId()) {
  9764. return false;
  9765. }
  9766. this.initialized = true;
  9767. logStatus.success();
  9768. return true;
  9769. } catch (error) {
  9770. throwError(error, 'Opquests.init');
  9771. return false;
  9772. }
  9773. }
  9774. async classifyTask(action) {
  9775. try {
  9776. if (action === 'undo') {
  9777. scripts_echoLog({
  9778. text: i18n('cannotUndo')
  9779. });
  9780. return false;
  9781. }
  9782. const logStatus = scripts_echoLog({
  9783. text: i18n('getTasksInfo')
  9784. });
  9785. const tasks = $('.w-full:contains("Validate") .items-center');
  9786. for (const task of tasks) {
  9787. const link = $(task).find('a:contains("Open")').attr('href');
  9788. const taskDes = $(task).find('div').eq(1).text().trim();
  9789. if (!link) {
  9790. continue;
  9791. }
  9792. if (/steamcommunity\.com\/groups\//.test(link)) {
  9793. this.undoneTasks.steam.groupLinks.push(link);
  9794. } else if (/store\.steampowered\.com\/app\//.test(link)) {
  9795. if (/wishlist/gim.test(taskDes)) {
  9796. this.undoneTasks.steam.wishlistLinks.push(link);
  9797. } else if (/follow/gim.test(taskDes)) {
  9798. this.undoneTasks.steam.followLinks.push(link);
  9799. }
  9800. } else if (/store\.steampowered\.com\/(publisher|developer|curator)\//.test(link) && /follow/gim.test(taskDes)) {
  9801. this.undoneTasks.steam.curatorLikeLinks.push(link);
  9802. } else if (link.includes('//x.com/') && /follow/gim.test(taskDes)) {
  9803. this.undoneTasks.twitter.userLinks.push(link);
  9804. } else if (link.includes('//x.com/') && link.includes('status') && /Repost/gim.test(taskDes)) {
  9805. this.undoneTasks.twitter.retweetLinks.push(link);
  9806. } else if (/clash\.gg/.test(link)) {
  9807. scripts_echoLog({}).warning(`${i18n('unSupporttedTaskType')}: ${taskDes}(${link})`);
  9808. } else {
  9809. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`);
  9810. }
  9811. }
  9812. logStatus.success();
  9813. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  9814. if (window.DEBUG) {
  9815. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  9816. }
  9817. return true;
  9818. } catch (error) {
  9819. throwError(error, 'Opquests.classifyTask');
  9820. return false;
  9821. }
  9822. }
  9823. async verifyTask() {
  9824. try {
  9825. if (!this.initialized) {
  9826. this.init();
  9827. }
  9828. const tasks = $.makeArray($('.items-center').has('input[name="task_id"]')).map(ele => $(ele).find('input[name="task_id"]').val());
  9829. GM_setValue('opquestsVerifyTasks', tasks);
  9830. await this.#confirm();
  9831. this.after();
  9832. return true;
  9833. } catch (error) {
  9834. throwError(error, 'Opquests.verifyTask');
  9835. return false;
  9836. }
  9837. }
  9838. async #confirm() {
  9839. try {
  9840. const logStatus = scripts_echoLog({
  9841. html: `<li>${i18n('confirmingTask')}...<font></font></li>`
  9842. });
  9843. const {
  9844. result,
  9845. statusText,
  9846. status,
  9847. data
  9848. } = await tools_httpRequest({
  9849. url: `https://opquests.com/quests/${this.giveawayId}?confirm=1`,
  9850. method: 'GET',
  9851. nochche: true,
  9852. headers: {
  9853. origin: 'https://opquests.com',
  9854. referer: `https://opquests.com/warning?id=${this.giveawayId}`
  9855. }
  9856. });
  9857. if (result === 'Success') {
  9858. if (data?.status === 200) {
  9859. logStatus.success();
  9860. return true;
  9861. }
  9862. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  9863. return false;
  9864. }
  9865. logStatus.error(`${result}:${statusText}(${status})`);
  9866. return false;
  9867. } catch (error) {
  9868. throwError(error, 'Opquests.confirm');
  9869. return false;
  9870. }
  9871. }
  9872. async getKey(isButton) {
  9873. try {
  9874. const logStatus = scripts_echoLog({
  9875. text: i18n('gettingKey')
  9876. });
  9877. const {
  9878. result,
  9879. statusText,
  9880. status,
  9881. data
  9882. } = await tools_httpRequest({
  9883. url: 'https://opquests.com/keys',
  9884. method: 'GET'
  9885. });
  9886. if (result === 'Success') {
  9887. if (data?.responseText) {
  9888. const key = $(data?.responseText).find(`div.items-center:contains("${$('h1.font-bold').text().trim().replace(' Quest', '')}")`).find('div.font-bold').next().text();
  9889. if (!key) {
  9890. logStatus.error('Error: Key was not found');
  9891. if (isButton) {
  9892. window.open('https://opquests.com/keys', '_self');
  9893. }
  9894. return false;
  9895. }
  9896. logStatus.success();
  9897. scripts_echoLog({}).success(key);
  9898. return true;
  9899. }
  9900. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  9901. return false;
  9902. }
  9903. logStatus.error(`${result}:${statusText}(${status})`);
  9904. return false;
  9905. } catch (error) {
  9906. throwError(error, 'Opquests.getGiveawayId');
  9907. return false;
  9908. }
  9909. }
  9910. #getGiveawayId() {
  9911. try {
  9912. const giveawayId = window.location.href.match(/quests\/([\d]+)/)?.[1];
  9913. if (giveawayId) {
  9914. this.giveawayId = giveawayId;
  9915. return true;
  9916. }
  9917. scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId'));
  9918. return false;
  9919. } catch (error) {
  9920. throwError(error, 'Opquests.getGiveawayId');
  9921. return false;
  9922. }
  9923. }
  9924. #checkLogin() {
  9925. try {
  9926. if (!globalOptions.other.checkLogin) {
  9927. return true;
  9928. }
  9929. if ($('a[href*="/auth/redirect"]').length > 0) {
  9930. window.open('/auth/redirect', '_self');
  9931. }
  9932. return true;
  9933. } catch (error) {
  9934. throwError(error, 'Opquests.checkLogin');
  9935. return false;
  9936. }
  9937. }
  9938. }
  9939. const website_Opquests = Opquests;
  9940. const Gleam_defaultTasksTemplate = {
  9941. steam: {
  9942. groupLinks: [],
  9943. wishlistLinks: [],
  9944. followLinks: [],
  9945. curatorLinks: [],
  9946. curatorLikeLinks: []
  9947. },
  9948. twitter: {
  9949. userLinks: [],
  9950. retweetLinks: []
  9951. },
  9952. twitch: {
  9953. channelLinks: []
  9954. },
  9955. discord: {
  9956. serverLinks: []
  9957. },
  9958. youtube: {
  9959. channelLinks: []
  9960. },
  9961. extra: {
  9962. gleam: []
  9963. }
  9964. };
  9965. const Gleam_defaultTasks = JSON.stringify(Gleam_defaultTasksTemplate);
  9966. class Gleam extends website_Website {
  9967. name = 'Gleam';
  9968. undoneTasks = JSON.parse(Gleam_defaultTasks);
  9969. socialTasks = JSON.parse(Gleam_defaultTasks);
  9970. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  9971. static test() {
  9972. return window.location.host === 'gleam.io';
  9973. }
  9974. before() {
  9975. try {
  9976. unsafeWindow.confirm = () => {};
  9977. unsafeWindow.alert = () => {};
  9978. unsafeWindow.prompt = () => {};
  9979. } catch (error) {
  9980. throwError(error, 'Gleam.before');
  9981. }
  9982. }
  9983. async after() {
  9984. try {
  9985. if (window.location.search.includes('8b07d23f4bfa65f9')) {
  9986. const checkComplete = setInterval(() => {
  9987. if ($('.entry-content .entry-method i.fa-check').length > 0) {
  9988. clearInterval(checkComplete);
  9989. window.close();
  9990. }
  9991. });
  9992. for (const task of $('.entry-content .entry-method')) {
  9993. const taskInfo = $(task).find('.user-links');
  9994. const expandInfo = $(task).find('.expandable');
  9995. const aElements = expandInfo.find('a.btn,a:contains(Continue),button:contains(Continue)');
  9996. if (aElements.length > 0) {
  9997. for (const element of aElements) {
  9998. const $element = $(element);
  9999. const href = $element.attr('href');
  10000. $element.removeAttr('href')[0].click();
  10001. $element.attr('href', href);
  10002. await delay(1e3);
  10003. }
  10004. }
  10005. taskInfo[0].click();
  10006. await delay(1e3);
  10007. }
  10008. scripts_echoLog({}).warning(i18n('gleamTaskNotice'));
  10009. } else if (!await this.#checkLeftKey()) {
  10010. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  10011. }
  10012. } catch (error) {
  10013. throwError(error, 'Gleam.after');
  10014. }
  10015. }
  10016. init() {
  10017. try {
  10018. const logStatus = scripts_echoLog({
  10019. text: i18n('initing')
  10020. });
  10021. if (!this.#getGiveawayId()) {
  10022. return false;
  10023. }
  10024. this.initialized = true;
  10025. logStatus.success();
  10026. return true;
  10027. } catch (error) {
  10028. throwError(error, 'Gleam.init');
  10029. return false;
  10030. }
  10031. }
  10032. async classifyTask(action) {
  10033. try {
  10034. const logStatus = scripts_echoLog({
  10035. text: i18n('getTasksInfo')
  10036. });
  10037. if (action === 'undo') {
  10038. this.socialTasks = GM_getValue(`gleamTasks-${this.giveawayId}`)?.tasks || JSON.parse(Gleam_defaultTasks);
  10039. }
  10040. const tasks = $('.entry-content .entry-method');
  10041. for (const task of tasks) {
  10042. const $task = $(task);
  10043. if (action === 'do' && $task.find('i.fa-question').length === 0) {
  10044. continue;
  10045. }
  10046. const socialIcon = $task.find('.icon-wrapper i');
  10047. const taskInfo = $task.find('.user-links');
  10048. const taskText = taskInfo.text().trim();
  10049. const expandInfo = $task.find('.expandable');
  10050. const aElements = expandInfo.find('a.btn');
  10051. if (aElements.length > 0) {
  10052. for (const element of aElements) {
  10053. const $element = $(element);
  10054. const href = $element.attr('href');
  10055. $element.removeAttr('href')[0].click();
  10056. $element.attr('href', href);
  10057. }
  10058. }
  10059. if (socialIcon.hasClass('fa-twitter') || socialIcon.hasClass('fa-x-twitter')) {
  10060. const link = $task.find('a[href^="https://twitter.com/"],a[href^="https://x.com/"]').attr('href');
  10061. if (!link) {
  10062. continue;
  10063. }
  10064. if (/follow/gi.test(taskText)) {
  10065. if (action === 'undo') {
  10066. this.socialTasks.twitter.userLinks.push(link);
  10067. }
  10068. if (action === 'do') {
  10069. this.undoneTasks.twitter.userLinks.push(link);
  10070. }
  10071. } else if (/retweet/gim.test(taskText)) {
  10072. if (action === 'undo') {
  10073. this.socialTasks.twitter.retweetLinks.push(link);
  10074. }
  10075. if (action === 'do') {
  10076. this.undoneTasks.twitter.retweetLinks.push(link);
  10077. }
  10078. }
  10079. } else if (socialIcon.hasClass('fa-twitch')) {
  10080. if (/follow/gim.test(taskText)) {
  10081. const link = $task.find('a[href^="https://twitch.tv/"]').attr('href');
  10082. if (!link) {
  10083. continue;
  10084. }
  10085. if (action === 'undo') {
  10086. this.socialTasks.twitch.channelLinks.push(link);
  10087. }
  10088. if (action === 'do') {
  10089. this.undoneTasks.twitch.channelLinks.push(link);
  10090. }
  10091. }
  10092. } else if (socialIcon.hasClass('fa-discord')) {
  10093. if (/join/gim.test(taskText)) {
  10094. let link = $task.find('a[href^="https://discord.com/invite/"]').attr('href');
  10095. if (!link) {
  10096. const ggLink = $task.find('a[href^="https://discord.gg/"]').attr('href')?.match(/discord\.gg\/([^/]+)/)?.[1];
  10097. if (!ggLink) {
  10098. continue;
  10099. }
  10100. link = `https://discord.com/invite/${ggLink}`;
  10101. }
  10102. if (action === 'undo') {
  10103. this.socialTasks.discord.serverLinks.push(link);
  10104. }
  10105. if (action === 'do') {
  10106. this.undoneTasks.discord.serverLinks.push(link);
  10107. }
  10108. }
  10109. } else if (socialIcon.hasClass('fa-external-link-square-alt')) {
  10110. continue;
  10111. } else if (socialIcon.hasClass('fa-youtube')) {
  10112. if (/subscribe/gim.test(taskText)) {
  10113. const link = $task.find('a[href^="https://www.youtube.com/channel/"]').attr('href');
  10114. if (!link) {
  10115. continue;
  10116. }
  10117. if (action === 'undo') {
  10118. this.socialTasks.youtube.channelLinks.push(link);
  10119. }
  10120. if (action === 'do') {
  10121. this.undoneTasks.youtube.channelLinks.push(link);
  10122. }
  10123. }
  10124. } else if (socialIcon.attr('class')?.includes('steam')) {
  10125. if (/join.*group/gi.test(taskText)) {
  10126. const link = $task.find('a[href^="https://steamcommunity.com/groups/"]').attr('href');
  10127. if (!link) {
  10128. continue;
  10129. }
  10130. if (action === 'undo') {
  10131. this.socialTasks.steam.groupLinks.push(link);
  10132. }
  10133. if (action === 'do') {
  10134. this.undoneTasks.steam.groupLinks.push(link);
  10135. }
  10136. } else if (/follow.*curator/gi.test(taskText)) {
  10137. const link = $task.find('a[href^="https://store.steampowered.com/curator/"]').attr('href');
  10138. if (!link) {
  10139. continue;
  10140. }
  10141. if (action === 'undo') {
  10142. this.socialTasks.steam.curatorLinks.push(link);
  10143. }
  10144. if (action === 'do') {
  10145. this.undoneTasks.steam.curatorLinks.push(link);
  10146. }
  10147. }
  10148. } else if (socialIcon.hasClass('fa-bullhorn') && /Complete|Increase/gi.test(taskText)) {
  10149. if (action !== 'do') {
  10150. continue;
  10151. }
  10152. const gleamLink = await this.#getGleamLink(taskText);
  10153. if (!gleamLink) {
  10154. continue;
  10155. }
  10156. this.undoneTasks.extra.gleam.push(gleamLink);
  10157. } 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 {
  10158. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskText}`);
  10159. }
  10160. }
  10161. logStatus.success();
  10162. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  10163. this.socialTasks = this.uniqueTasks(this.socialTasks);
  10164. if (window.DEBUG) {
  10165. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  10166. }
  10167. GM_setValue(`gleamTasks-${this.giveawayId}`, {
  10168. tasks: this.socialTasks,
  10169. time: new Date().getTime()
  10170. });
  10171. return true;
  10172. } catch (error) {
  10173. throwError(error, 'Gleam.classifyTask');
  10174. return false;
  10175. }
  10176. }
  10177. async extraDoTask({
  10178. gleam
  10179. }) {
  10180. try {
  10181. const pro = [];
  10182. for (const link of gleam) {
  10183. pro.push(this.#doGleamTask(link));
  10184. }
  10185. return Promise.all(pro).then(() => true);
  10186. } catch (error) {
  10187. throwError(error, 'Gleam.extraDoTask');
  10188. return false;
  10189. }
  10190. }
  10191. async verifyTask() {
  10192. try {
  10193. scripts_echoLog({
  10194. text: `${i18n('verifyingTask')}...`
  10195. });
  10196. const tasks = $('.entry-content .entry-method');
  10197. unsafeWindow._OxA = '_OxA';
  10198. for (const task of tasks) {
  10199. if ($('[campaign-key="campaign.key"]').length > 0) {
  10200. return scripts_echoLog({
  10201. text: i18n('campaign')
  10202. });
  10203. }
  10204. const $task = $(task);
  10205. if ($task.find('i.fa-question').length === 0) {
  10206. continue;
  10207. }
  10208. const taskInfo = $task.find('.user-links');
  10209. taskInfo[0].click();
  10210. const aElements = $task.find('.expandable').find('a.btn');
  10211. if (aElements.length > 0) {
  10212. for (const element of aElements) {
  10213. const $element = $(element);
  10214. const href = $element.attr('href');
  10215. $element.removeAttr('href')[0].click();
  10216. $element.attr('href', href);
  10217. }
  10218. }
  10219. unsafeWindow.$hookTimer?.setSpeed(1e3);
  10220. const visitBtn = $task.find('.expandable').find('span:contains(more seconds),button:contains(more seconds)').filter(':visible');
  10221. if (visitBtn.length > 0 && unsafeWindow.$hookTimer) {
  10222. const newTab = GM_openInTab('', {
  10223. active: true
  10224. });
  10225. await delay(1e3);
  10226. newTab?.close();
  10227. window.focus();
  10228. }
  10229. await delay(3e3);
  10230. unsafeWindow.$hookTimer?.setSpeed(1);
  10231. const expandInfo = $task.find('.expandable');
  10232. const [ input ] = expandInfo.find('input');
  10233. if (input) {
  10234. const evt = new Event('input', {
  10235. bubbles: true,
  10236. cancelable: true,
  10237. composed: true
  10238. });
  10239. const valuelimit = [ ...expandInfo.text().matchAll(/"(.+?)"/g) ].at(-1)?.[1];
  10240. input.value = valuelimit || 'vloot';
  10241. input.dispatchEvent(evt);
  10242. await delay(1e3);
  10243. }
  10244. await this.#checkSync();
  10245. const continueBtn = $task.find('.expandable').find('span:contains(Continue),button:contains(Continue)');
  10246. for (const button of continueBtn) {
  10247. button.click();
  10248. await delay(500);
  10249. await this.#checkSync();
  10250. }
  10251. }
  10252. scripts_echoLog({
  10253. text: i18n('verifiedGleamTasks')
  10254. });
  10255. } catch (error) {
  10256. throwError(error, 'Gleam.verifyTask');
  10257. return false;
  10258. }
  10259. }
  10260. async #checkSync() {
  10261. try {
  10262. return await new Promise(resolve => {
  10263. const checker = setInterval(() => {
  10264. if ($('.entry-content .entry-method i.fa-sync').length === 0) {
  10265. clearInterval(checker);
  10266. resolve(true);
  10267. }
  10268. }, 500);
  10269. });
  10270. } catch (error) {
  10271. throwError(error, 'Gleam.checkSync');
  10272. return false;
  10273. }
  10274. }
  10275. async #doGleamTask(link) {
  10276. try {
  10277. const logStatus = scripts_echoLog({
  10278. text: i18n('doingGleamTask')
  10279. });
  10280. return await new Promise(resolve => {
  10281. GM_openInTab(`${link}?8b07d23f4bfa65f9`, {
  10282. active: true,
  10283. insert: true,
  10284. setParent: true
  10285. }).onclose = () => {
  10286. logStatus.success();
  10287. resolve(true);
  10288. };
  10289. });
  10290. } catch (error) {
  10291. throwError(error, 'Gleam.doGleamTask');
  10292. return false;
  10293. }
  10294. }
  10295. #getGiveawayId() {
  10296. try {
  10297. const giveawayId = window.location.pathname;
  10298. if (giveawayId) {
  10299. this.giveawayId = giveawayId;
  10300. return true;
  10301. }
  10302. scripts_echoLog({
  10303. text: i18n('getFailed', 'GiveawayId')
  10304. });
  10305. return false;
  10306. } catch (error) {
  10307. throwError(error, 'Gleam.getGiveawayId');
  10308. return false;
  10309. }
  10310. }
  10311. async #getGleamLink(title) {
  10312. try {
  10313. const logStatus = scripts_echoLog({
  10314. text: i18n('gettingGleamLink')
  10315. });
  10316. const {
  10317. result,
  10318. statusText,
  10319. status,
  10320. data
  10321. } = await tools_httpRequest({
  10322. url: 'https://www.vloot.io/api/v1/giveaways',
  10323. method: 'GET',
  10324. responseType: 'json'
  10325. });
  10326. if (result === 'Success') {
  10327. if (data?.status === 200 && data?.response?.Success === true && data?.response?.Data) {
  10328. const {
  10329. link
  10330. } = data.response.Data.find(giveaway => title.replace(/[\s]/g, '').toLowerCase().includes(giveaway.title.replace(/[\s]/g, '').toLowerCase())) || {};
  10331. if (link) {
  10332. logStatus.success();
  10333. return link;
  10334. }
  10335. logStatus.error(`Error:${i18n('getLinkFailed')}`);
  10336. return false;
  10337. }
  10338. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10339. return false;
  10340. }
  10341. logStatus.error(`${result}:${statusText}(${status})`);
  10342. return false;
  10343. } catch (error) {
  10344. throwError(error, 'Gleam.getGleamLink');
  10345. return false;
  10346. }
  10347. }
  10348. async #checkLeftKey() {
  10349. try {
  10350. if (!globalOptions.other.checkLeftKey) {
  10351. return true;
  10352. }
  10353. const campaignString = $('div.popup-blocks-container').attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
  10354. if (!campaignString) {
  10355. return false;
  10356. }
  10357. const {
  10358. campaign,
  10359. incentive
  10360. } = JSON.parse(campaignString);
  10361. const controllerString = $('div.campaign.reward').attr('ng-init')?.match(/initContestant\(([\w\W]+?)\);/)?.[1];
  10362. let ownedKey = false;
  10363. if (controllerString) {
  10364. if (JSON.parse(controllerString).contestant?.claims?.incentives?.[incentive.id]?.length) {
  10365. ownedKey = true;
  10366. }
  10367. }
  10368. if (campaign.banned || campaign.finished && !ownedKey || campaign.paused || new Date().getTime() < campaign.starts_at * 1e3) {
  10369. await external_Swal_default().fire({
  10370. icon: 'warning',
  10371. title: i18n('notice'),
  10372. text: i18n('giveawayNotWork'),
  10373. confirmButtonText: i18n('confirm'),
  10374. cancelButtonText: i18n('cancel'),
  10375. showCancelButton: true
  10376. }).then(({
  10377. value
  10378. }) => {
  10379. if (value) {
  10380. window.close();
  10381. }
  10382. });
  10383. }
  10384. return true;
  10385. } catch (error) {
  10386. throwError(error, 'Gleam.checkLeftKey');
  10387. return false;
  10388. }
  10389. }
  10390. }
  10391. const website_Gleam = Gleam;
  10392. const SweepWidget_defaultOptions = {
  10393. username: '',
  10394. email: ''
  10395. };
  10396. class SweepWidget extends website_Website {
  10397. name = 'SweepWidget';
  10398. options = {
  10399. ...SweepWidget_defaultOptions,
  10400. ...GM_getValue('SweepWidgetOptions')
  10401. };
  10402. buttons = [ 'doTask' ];
  10403. static test() {
  10404. return /^https?:\/\/sweepwidget\.com\/view\/[\d]+/.test(window.location.href);
  10405. }
  10406. async after() {
  10407. try {
  10408. if (!this.#checkLogin()) {
  10409. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  10410. }
  10411. } catch (error) {
  10412. throwError(error, 'SweepWidget.after');
  10413. }
  10414. }
  10415. init() {
  10416. try {
  10417. const logStatus = scripts_echoLog({
  10418. text: i18n('initing')
  10419. });
  10420. if (!this.#checkLogin()) {
  10421. logStatus.warning(i18n('needLogin'));
  10422. return false;
  10423. }
  10424. if (!this.#getGiveawayId()) {
  10425. return false;
  10426. }
  10427. this.initialized = true;
  10428. logStatus.success();
  10429. return true;
  10430. } catch (error) {
  10431. throwError(error, 'SweepWidget.init');
  10432. return false;
  10433. }
  10434. }
  10435. classifyTask() {
  10436. return true;
  10437. }
  10438. async doTask() {
  10439. try {
  10440. if ($('#unlock_rewards_main_wrapper').length === 0) {
  10441. if ($('input[name="sw__login_name"]:visible').length > 0) {
  10442. $('input[name="sw__login_name"]').val(this.options.username);
  10443. }
  10444. if ($('input[name="sw__login_email"]:visible').length > 0) {
  10445. $('input[name="sw__login_email"]').val(this.options.email);
  10446. }
  10447. if ($('#sw_login_button:visible').length > 0) {
  10448. $('#sw_login_button')[0].click();
  10449. }
  10450. if (!await this.#checkEnter()) {
  10451. return false;
  10452. }
  10453. }
  10454. const logStatus = scripts_echoLog({
  10455. text: i18n('SweepWidgetNotice')
  10456. });
  10457. const tasks = $('#sw_inner_entry_methods_l2_wrapper>div.sw_entry');
  10458. for (const task of tasks) {
  10459. const $task = $(task);
  10460. if ($task.find('i.fa-check:visible').length > 0) {
  10461. continue;
  10462. }
  10463. const title = $task.find('.sw_text_inner');
  10464. title[0].click();
  10465. const aElement = $task.find('a.sw_link');
  10466. const link = aElement.attr('href');
  10467. aElement.attr('href', '#a').attr('target', '_self');
  10468. aElement[0]?.click();
  10469. await delay(300);
  10470. aElement.attr('href', link).attr('target', '_blank');
  10471. $task.find('input[type="text"]').val('test');
  10472. const verifyBtn = $task.find('input.sw_verify');
  10473. if (verifyBtn.prop('disabled') === true) {
  10474. title[0].click();
  10475. await delay(300);
  10476. title[0].click();
  10477. await delay(300);
  10478. }
  10479. $task.find('input.sw_verify').removeAttr('disabled')[0]?.click();
  10480. await this.#checkFinish($task);
  10481. await delay(parseInt(`${Math.random() * (3e3 - 1e3 + 1) + 1e3}`, 10));
  10482. }
  10483. logStatus.success();
  10484. return true;
  10485. } catch (error) {
  10486. throwError(error, 'SweepWidget.doTask');
  10487. return false;
  10488. }
  10489. }
  10490. #checkLogin() {
  10491. try {
  10492. if ($('#twitter_login_button').length > 0) {
  10493. $('#twitter_login_button')[0].click();
  10494. }
  10495. return true;
  10496. } catch (error) {
  10497. throwError(error, 'SweepWidget.checkLogin');
  10498. return false;
  10499. }
  10500. }
  10501. #getGiveawayId() {
  10502. try {
  10503. const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
  10504. if (giveawayId) {
  10505. this.giveawayId = giveawayId;
  10506. return true;
  10507. }
  10508. scripts_echoLog({
  10509. text: i18n('getFailed', 'GiveawayId')
  10510. });
  10511. return false;
  10512. } catch (error) {
  10513. throwError(error, 'SweepWidget.getGiveawayId');
  10514. return false;
  10515. }
  10516. }
  10517. async #checkEnter() {
  10518. try {
  10519. return new Promise(resolve => {
  10520. const checker = setInterval(() => {
  10521. if ($('#unlock_rewards_main_wrapper').length > 0) {
  10522. clearInterval(checker);
  10523. resolve(true);
  10524. }
  10525. }, 500);
  10526. });
  10527. } catch (error) {
  10528. throwError(error, 'SweepWidget.checkEnter');
  10529. return false;
  10530. }
  10531. }
  10532. async #checkFinish($task) {
  10533. try {
  10534. return new Promise(resolve => {
  10535. const checker = setInterval(() => {
  10536. if ($task.find('i.fa-check:visible').length > 0 || $task.find('.sw_entry_input:visible').length === 0) {
  10537. clearInterval(checker);
  10538. resolve(true);
  10539. }
  10540. }, 500);
  10541. });
  10542. } catch (error) {
  10543. throwError(error, 'SweepWidget.checkFinish');
  10544. return false;
  10545. }
  10546. }
  10547. }
  10548. const website_SweepWidget = SweepWidget;
  10549. const defaultWhiteList = {
  10550. discord: {
  10551. servers: []
  10552. },
  10553. instagram: {
  10554. users: []
  10555. },
  10556. twitch: {
  10557. channels: []
  10558. },
  10559. twitter: {
  10560. users: [],
  10561. retweets: [],
  10562. likes: []
  10563. },
  10564. vk: {
  10565. names: []
  10566. },
  10567. youtube: {
  10568. channels: [],
  10569. likes: []
  10570. },
  10571. reddit: {
  10572. reddits: []
  10573. },
  10574. steam: {
  10575. groups: [],
  10576. officialGroups: [],
  10577. wishlists: [],
  10578. follows: [],
  10579. forums: [],
  10580. workshops: [],
  10581. curators: [],
  10582. workshopVotes: [],
  10583. curatorLikes: [],
  10584. announcements: [],
  10585. licenses: [],
  10586. playtests: []
  10587. }
  10588. };
  10589. const link2id = async function(type) {
  10590. try {
  10591. const link = $('#socialLink').val();
  10592. let id = '';
  10593. switch (type) {
  10594. case 'discord.servers':
  10595. id = link.match(/invite\/(.+)/)?.[1] || '';
  10596. break;
  10597.  
  10598. case 'instagram.users':
  10599. id = link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1] || '';
  10600. break;
  10601.  
  10602. case 'twitch.channels':
  10603. id = link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2] || '';
  10604. break;
  10605.  
  10606. case 'twitter.users':
  10607. id = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || '';
  10608. break;
  10609.  
  10610. case 'twitter.retweets':
  10611. id = link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1] || '';
  10612. break;
  10613.  
  10614. case 'vk.names':
  10615. id = link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1] || '';
  10616. break;
  10617.  
  10618. case 'youtube.channels':
  10619. id = (await getInfo(link, 'channel'))?.params?.channelId || '';
  10620. break;
  10621.  
  10622. case 'youtube.likes':
  10623. id = (await getInfo(link, 'likeVideo'))?.params?.videoId || '';
  10624. break;
  10625.  
  10626. case 'reddit.reddits':
  10627. id = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1] || link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1] || '';
  10628. break;
  10629.  
  10630. case 'steam.groups':
  10631. id = link.match(/groups\/(.+)\/?/)?.[1] || '';
  10632. break;
  10633.  
  10634. case 'steam.wishlists':
  10635. case 'steam.follows':
  10636. case 'steam.forums':
  10637. id = link.match(/app\/([\d]+)/)?.[1] || '';
  10638. break;
  10639.  
  10640. case 'steam.workshops':
  10641. id = link.match(/\?id=([\d]+)/)?.[1] || '';
  10642. break;
  10643.  
  10644. case 'steam.curators':
  10645. {
  10646. if (link.includes('curator')) {
  10647. id = link.match(/curator\/([\d]+)/)?.[1] || '';
  10648. } else {
  10649. const param = link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3);
  10650. if (!param || param.length !== 2) {
  10651. break;
  10652. }
  10653. const steam = new social_Steam();
  10654. if (await steam.init()) {
  10655. id = await steam.getCuratorId(param[0], param[1]) || '';
  10656. }
  10657. }
  10658. }
  10659. break;
  10660. }
  10661. return id;
  10662. } catch (error) {
  10663. throwError(error, 'link2id');
  10664. return i18n('getFailed', 'id');
  10665. }
  10666. };
  10667. const disabledType = {
  10668. steam: [ 'workshopVotes', 'curatorLikes', 'announcements' ],
  10669. twitter: [ 'likes' ]
  10670. };
  10671. const assignWhiteList = whiteList => {
  10672. try {
  10673. const newWhiteList = {};
  10674. for (const [ key, value ] of Object.entries(defaultWhiteList)) {
  10675. newWhiteList[key] = {
  10676. ...value,
  10677. ...whiteList[key]
  10678. };
  10679. }
  10680. return newWhiteList;
  10681. } catch (error) {
  10682. throwError(error, 'assignWhiteList');
  10683. return defaultWhiteList;
  10684. }
  10685. };
  10686. const whiteListOptions = function(showType) {
  10687. try {
  10688. const whiteList = assignWhiteList(GM_getValue('whiteList') || {});
  10689. let whiteListOptionsForm = `<form id="whiteListForm" class="auto-task-form">
  10690. <table class="auto-task-table"><thead><tr><td>${i18n('website')}</td><td>${i18n('type')}</td><td>${i18n('edit')}</td></tr></thead><tbody>`;
  10691. for (const [ social, types ] of Object.entries(whiteList)) {
  10692. 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('');
  10693. }
  10694. whiteListOptionsForm += '</tbody></table></form>';
  10695. if (showType === 'swal') {
  10696. external_Swal_default().fire({
  10697. title: i18n('whiteListOptions'),
  10698. html: whiteListOptionsForm,
  10699. showConfirmButton: false,
  10700. showCloseButton: true
  10701. });
  10702. } else {
  10703. $('body').append(`<h2>${i18n('whiteList')}</h2>${whiteListOptionsForm}`);
  10704. }
  10705. $('.editWhiteList').on('click', function() {
  10706. const value = $(this).attr('data-value');
  10707. if (!value) {
  10708. return;
  10709. }
  10710. const [ social, type ] = value.split('.');
  10711. if (!whiteList?.[social]?.[type]) {
  10712. scripts_echoLog({}).warning(i18n('whiteListNotFound', value));
  10713. return;
  10714. }
  10715. external_Swal_default().fire({
  10716. title: i18n('changeWhiteListOption', value),
  10717. input: 'textarea',
  10718. html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">
  10719. <button id="link2id" data-type="${value}" class="swal2-confirm swal2-styled">获取id</button>
  10720. <p style="margin-bottom:0 !important;">在下方填写白名单,每行一个</p>`,
  10721. inputValue: whiteList[social][type].join('\n'),
  10722. showConfirmButton: true,
  10723. confirmButtonText: i18n('save'),
  10724. showCancelButton: true,
  10725. cancelButtonText: i18n('close'),
  10726. showDenyButton: true,
  10727. denyButtonText: i18n('return')
  10728. }).then(({
  10729. isDenied,
  10730. isConfirmed,
  10731. value
  10732. }) => {
  10733. if (isDenied) {
  10734. if (showType === 'swal') {
  10735. whiteListOptions(showType);
  10736. }
  10737. return;
  10738. } else if (isConfirmed) {
  10739. whiteList[social][type] = value.split('\n');
  10740. GM_setValue('whiteList', whiteList);
  10741. external_Swal_default().fire({
  10742. title: i18n('changeWhiteListSuccess'),
  10743. icon: 'success'
  10744. });
  10745. }
  10746. });
  10747. $('#link2id').on('click', async function() {
  10748. const type = $(this).attr('data-type');
  10749. $('#socialLink').val(await link2id(type));
  10750. });
  10751. });
  10752. } catch (error) {
  10753. throwError(error, 'whiteListOptions');
  10754. }
  10755. };
  10756. const whiteList = whiteListOptions;
  10757. const setGistData = async (token, gistId, fileName, content) => {
  10758. try {
  10759. const logStatus = scripts_echoLog({
  10760. text: i18n('settingData')
  10761. });
  10762. const contentData = JSON.stringify({
  10763. files: {
  10764. [fileName]: {
  10765. content: JSON.stringify(content)
  10766. }
  10767. }
  10768. });
  10769. const {
  10770. result,
  10771. statusText,
  10772. status,
  10773. data
  10774. } = await tools_httpRequest({
  10775. url: `https://api.github.com/gists/${gistId}`,
  10776. headers: {
  10777. Accept: 'application/vnd.github.v3+json',
  10778. Authorization: `token ${token}`
  10779. },
  10780. data: contentData,
  10781. responseType: 'json',
  10782. method: 'POST',
  10783. timeout: 3e4
  10784. });
  10785. if (result === 'Success') {
  10786. if (data?.status === 200 && data.response.files?.[fileName]?.content === JSON.stringify(content)) {
  10787. logStatus.success();
  10788. return true;
  10789. }
  10790. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10791. return false;
  10792. }
  10793. logStatus.error(`${result}:${statusText}(${status})`);
  10794. return false;
  10795. } catch (error) {
  10796. throwError(error, 'setGistData');
  10797. return false;
  10798. }
  10799. };
  10800. const getGistData = async (token, gistId, fileName, test = false) => {
  10801. try {
  10802. const logStatus = scripts_echoLog({
  10803. text: i18n('gettingData')
  10804. });
  10805. const {
  10806. result,
  10807. statusText,
  10808. status,
  10809. data
  10810. } = await tools_httpRequest({
  10811. url: `https://api.github.com/gists/${gistId}`,
  10812. headers: {
  10813. Accept: 'application/vnd.github.v3+json',
  10814. Authorization: `token ${token}`
  10815. },
  10816. responseType: 'json',
  10817. method: 'GET',
  10818. timeout: 3e4
  10819. });
  10820. if (result === 'Success') {
  10821. if (data?.status === 200) {
  10822. const content = data.response?.files?.[fileName]?.content;
  10823. let formatedContent;
  10824. if (!content) {
  10825. logStatus.error(`Error:${i18n('noRemoteData')}`);
  10826. return false;
  10827. }
  10828. if (test) {
  10829. logStatus.success();
  10830. return true;
  10831. }
  10832. try {
  10833. formatedContent = JSON.parse(content);
  10834. } catch (error) {
  10835. logStatus.error(`Error:${i18n('errorRemoteDataFormat')}`);
  10836. return false;
  10837. }
  10838. logStatus.success();
  10839. return formatedContent;
  10840. }
  10841. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10842. return false;
  10843. }
  10844. logStatus.error(`${result}:${statusText}(${status})`);
  10845. return false;
  10846. } catch (error) {
  10847. throwError(error, 'getGistData');
  10848. return false;
  10849. }
  10850. };
  10851. const syncOptions = () => {
  10852. try {
  10853. const {
  10854. TOKEN,
  10855. GIST_ID,
  10856. FILE_NAME,
  10857. SYNC_HISTORY
  10858. } = GM_getValue('gistOptions') || {
  10859. TOKEN: '',
  10860. GIST_ID: '',
  10861. FILE_NAME: '',
  10862. SYNC_HISTORY: true
  10863. };
  10864. external_Swal_default().fire({
  10865. title: i18n('gistOptions'),
  10866. 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;">
  10867. ${i18n('upload2gist')}</button>` + `<button id="download-data" type="button" class="swal2-confirm swal2-styled" style="display: inline-block;">
  10868. ${i18n('downloadFromGist')}</button></p>`,
  10869. focusConfirm: false,
  10870. showLoaderOnConfirm: true,
  10871. 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>`,
  10872. preConfirm: async () => {
  10873. const token = $('#github-token').val();
  10874. const gistId = $('#gist-id').val();
  10875. const fileName = $('#file-name').val();
  10876. const syncHistory = $('#sync-history').prop('checked');
  10877. GM_setValue('gistOptions', {
  10878. TOKEN: token,
  10879. GIST_ID: gistId,
  10880. FILE_NAME: fileName,
  10881. SYNC_HISTORY: syncHistory
  10882. });
  10883. return await getGistData(token, gistId, fileName, true);
  10884. },
  10885. allowOutsideClick: () => !external_Swal_default().isLoading(),
  10886. confirmButtonText: i18n('saveAndTest'),
  10887. showCancelButton: true,
  10888. cancelButtonText: i18n('close')
  10889. }).then(({
  10890. value
  10891. }) => {
  10892. if (value) {
  10893. external_Swal_default().fire({
  10894. icon: 'success',
  10895. title: i18n('testSuccess')
  10896. }).then(syncOptions);
  10897. } else if (value !== undefined) {
  10898. external_Swal_default().fire({
  10899. icon: 'error',
  10900. title: i18n('testFailed')
  10901. }).then(syncOptions);
  10902. }
  10903. });
  10904. $('#upload-data').on('click', async () => {
  10905. const {
  10906. TOKEN,
  10907. GIST_ID,
  10908. FILE_NAME
  10909. } = GM_getValue('gistOptions') || {};
  10910. if (!(TOKEN && GIST_ID && FILE_NAME)) {
  10911. return external_Swal_default().fire({
  10912. icon: 'error',
  10913. title: i18n('saveAndTestNotice')
  10914. }).then(syncOptions);
  10915. }
  10916. external_Swal_default().fire({
  10917. icon: 'info',
  10918. title: i18n('processingData')
  10919. });
  10920. const data = {};
  10921. const names = GM_listValues();
  10922. const SYNC_HISTORY = $('#sync-history').prop('checked');
  10923. for (const name of names) {
  10924. if (name === 'gistOptions' || /^[\w]+?Auth$/.test(name)) {
  10925. continue;
  10926. }
  10927. if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) {
  10928. continue;
  10929. }
  10930. data[name] = GM_getValue(name);
  10931. }
  10932. external_Swal_default().update({
  10933. icon: 'info',
  10934. title: i18n('updatingData')
  10935. });
  10936. if (await setGistData(TOKEN, GIST_ID, FILE_NAME, data)) {
  10937. external_Swal_default().fire({
  10938. icon: 'success',
  10939. title: i18n('syncDataSuccess')
  10940. });
  10941. } else {
  10942. external_Swal_default().fire({
  10943. icon: 'error',
  10944. title: i18n('syncDataFailed')
  10945. });
  10946. }
  10947. });
  10948. $('#download-data').on('click', async () => {
  10949. const {
  10950. TOKEN,
  10951. GIST_ID,
  10952. FILE_NAME
  10953. } = GM_getValue('gistOptions') || {};
  10954. if (!(TOKEN && GIST_ID && FILE_NAME)) {
  10955. return external_Swal_default().fire({
  10956. icon: 'error',
  10957. title: i18n('saveAndTestNotice')
  10958. }).then(syncOptions);
  10959. }
  10960. external_Swal_default().fire({
  10961. icon: 'info',
  10962. title: i18n('downloadingData')
  10963. });
  10964. const data = await getGistData(TOKEN, GIST_ID, FILE_NAME);
  10965. if (!data) {
  10966. return external_Swal_default().fire({
  10967. icon: 'error',
  10968. title: i18n('checkedNoData')
  10969. }).then(syncOptions);
  10970. }
  10971. external_Swal_default().update({
  10972. icon: 'info',
  10973. title: i18n('savingData')
  10974. });
  10975. const SYNC_HISTORY = $('#sync-history').prop('checked');
  10976. for (const [ name, value ] of Object.entries(data)) {
  10977. if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) {
  10978. continue;
  10979. }
  10980. GM_setValue(name, value);
  10981. }
  10982. external_Swal_default().fire({
  10983. icon: 'success',
  10984. title: i18n('syncDataSuccess')
  10985. });
  10986. });
  10987. } catch (error) {
  10988. throwError(error, 'syncOptions');
  10989. }
  10990. };
  10991. const dataSync = syncOptions;
  10992. class Setting {
  10993. name = 'Setting';
  10994. buttons = [ 'saveGlobalOptions', 'syncData', 'tasksHistory' ];
  10995. syncData = dataSync;
  10996. tasksHistory() {
  10997. GM_openInTab('https://auto-task-v4.hclonely.com/history.html', {
  10998. active: true
  10999. });
  11000. }
  11001. static test() {
  11002. return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/setting.html';
  11003. }
  11004. before() {
  11005. try {
  11006. $('body').html('').addClass('auto-task-options');
  11007. } catch (error) {
  11008. throwError(error, 'Setting.before');
  11009. }
  11010. }
  11011. after() {
  11012. try {
  11013. this.#environment();
  11014. changeGlobalOptions('page');
  11015. whiteList('page');
  11016. $('input[name="other.twitterVerifyId"]').after(`<button id="getTwitterUserId" type="button">${i18n('getTwitterUserId')}</button>`);
  11017. $('#getTwitterUserId').on('click', () => {
  11018. this.#getId('twitterUser');
  11019. });
  11020. $('input[name="other.youtubeVerifyChannel"]').after(`<button id="getYoutubeChannelId" type="button">${i18n('getYoutubeChannelId')}</button>`);
  11021. $('#getYoutubeChannelId').on('click', () => {
  11022. this.#getId('youtubeChannel');
  11023. });
  11024. $('input[name^="position"]').on('input', function() {
  11025. const type = $(this).attr('name').replace('position.', '');
  11026. const xLabel = 'rightleft';
  11027. const yLabel = 'topbottpm';
  11028. switch (type) {
  11029. case 'buttonSideX':
  11030. case 'buttonSideY':
  11031. case 'buttonDistance':
  11032. {
  11033. const distance = $('input[name="position.buttonDistance"]').val();
  11034. const sideX = $('input[name="position.buttonSideX"]').val();
  11035. const sideY = $('input[name="position.buttonSideY"]').val();
  11036. if (![ 'right', 'left' ].includes(sideX)) {
  11037. break;
  11038. }
  11039. if (![ 'top', 'bottom' ].includes(sideY)) {
  11040. break;
  11041. }
  11042. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  11043. break;
  11044. }
  11045. const distanceArr = distance.split(',');
  11046. $('#auto-task-buttons').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  11047. break;
  11048. }
  11049.  
  11050. case 'showButtonSideX':
  11051. case 'showButtonSideY':
  11052. case 'showButtonDistance':
  11053. {
  11054. const distance = $('input[name="position.showButtonDistance"]').val();
  11055. const sideX = $('input[name="position.showButtonSideX"]').val();
  11056. const sideY = $('input[name="position.showButtonSideY"]').val();
  11057. if (![ 'right', 'left' ].includes(sideX)) {
  11058. break;
  11059. }
  11060. if (![ 'top', 'bottom' ].includes(sideY)) {
  11061. break;
  11062. }
  11063. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  11064. break;
  11065. }
  11066. const distanceArr = distance.split(',');
  11067. $('div.show-button-div').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  11068. break;
  11069. }
  11070.  
  11071. case 'logSideX':
  11072. case 'logSideY':
  11073. case 'logDistance':
  11074. {
  11075. const distance = $('input[name="position.logDistance"]').val();
  11076. const sideX = $('input[name="position.logSideX"]').val();
  11077. const sideY = $('input[name="position.logSideY"]').val();
  11078. if (![ 'right', 'left' ].includes(sideX)) {
  11079. break;
  11080. }
  11081. if (![ 'top', 'bottom' ].includes(sideY)) {
  11082. break;
  11083. }
  11084. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  11085. break;
  11086. }
  11087. const distanceArr = distance.split(',');
  11088. $('#auto-task-info').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  11089. break;
  11090. }
  11091.  
  11092. default:
  11093. break;
  11094. }
  11095. });
  11096. $('input[name^="hotKey"]').attr('readonly', 'readonly').off('keydown').on('keydown', function(event) {
  11097. let functionKey = '';
  11098. if (event.altKey) {
  11099. functionKey += 'alt + ';
  11100. } else if (event.ctrlKey) {
  11101. functionKey += 'ctrl + ';
  11102. } else if (event.shiftKey) {
  11103. functionKey += 'shift + ';
  11104. }
  11105. $(this).val(functionKey + (event.key.length === 1 ? event.key.toLowerCase() : ''));
  11106. });
  11107. } catch (error) {
  11108. throwError(error, 'Setting.after');
  11109. }
  11110. }
  11111. saveGlobalOptions() {
  11112. try {
  11113. saveData();
  11114. } catch (error) {
  11115. throwError(error, 'Setting.saveGlobalOptions');
  11116. }
  11117. }
  11118. #getId(social) {
  11119. try {
  11120. external_Swal_default().fire({
  11121. title: i18n('getId', i18n(social)),
  11122. html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">
  11123. <button id="link2id" data-type="${social}" class="swal2-confirm swal2-styled">获取id</button>`,
  11124. showCancelButton: true,
  11125. cancelButtonText: i18n('close'),
  11126. showConfirmButton: false
  11127. });
  11128. $('#link2id').on('click', async function() {
  11129. const link = $('#socialLink').val();
  11130. if (!link) {
  11131. return;
  11132. }
  11133. const type = $(this).attr('data-type');
  11134. if (type === 'twitterUser') {
  11135. const name = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || link;
  11136. $('#socialLink').val(await new social_Twitter().userName2id(name) || '');
  11137. } else if (type === 'youtubeChannel') {
  11138. const name = /^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www.youtube.com\/.*/.test(link) ? link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1] : link;
  11139. $('#socialLink').val((await getInfo(name, 'channel'))?.params?.channelId || '');
  11140. }
  11141. });
  11142. } catch (error) {
  11143. throwError(error, 'Setting.getId');
  11144. }
  11145. }
  11146. #environment() {
  11147. try {
  11148. const userAgent = (0, javascript_utils_umd_min.ua)();
  11149. const environmentForm = `<form id="environmentForm" class="auto-task-form">
  11150. <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('name')}</td><td>${i18n('version')}</td></tr></thead><tbody>
  11151. <tr><td>${i18n('os')}</td><td>${userAgent.os}</td><td>${userAgent.osVersion}</td></tr>
  11152. <tr><td>${i18n('browser')}</td><td>${userAgent.browserZH}</td><td>${userAgent.browserVersion}</td></tr>
  11153. <tr><td>${i18n('scriptManager')}</td><td>${GM_info.scriptHandler}</td><td>${GM_info.version}</td></tr>
  11154. <tr><td>${i18n('script')}</td><td>${GM_info.script.name}</td><td>${GM_info.script.version}</td></tr>
  11155. </tbody></table></form>`;
  11156. $('body').append(`<h2>${i18n('environment')}</h2>${environmentForm}`);
  11157. } catch (error) {
  11158. throwError(error, 'Setting.environment');
  11159. }
  11160. }
  11161. }
  11162. const website_Setting = Setting;
  11163. class History extends website_Keylol {
  11164. name = 'History';
  11165. buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect', 'clearHistory' ];
  11166. static test() {
  11167. return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/history.html';
  11168. }
  11169. before() {
  11170. try {
  11171. $('body').html('<div class="container"></div>').addClass('auto-task-history');
  11172. const data = GM_listValues() || [];
  11173. const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value);
  11174. for (const item of tasksHistory) {
  11175. this.#addItem(item);
  11176. }
  11177. } catch (error) {
  11178. throwError(error, 'History.before');
  11179. }
  11180. }
  11181. clearHistory() {
  11182. try {
  11183. const data = GM_listValues() || [];
  11184. const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value);
  11185. for (const item of tasksHistory) {
  11186. GM_deleteValue(item);
  11187. }
  11188. external_Swal_default().fire({
  11189. title: i18n('clearHistoryFinished'),
  11190. icon: 'success'
  11191. });
  11192. } catch (error) {
  11193. throwError(error, 'History.clearHistory');
  11194. }
  11195. }
  11196. #addItem(item) {
  11197. try {
  11198. const tasksData = GM_getValue(item);
  11199. if (!tasksData?.tasks) {
  11200. return;
  11201. }
  11202. let html = '';
  11203. let title = '';
  11204. let link = '';
  11205. const [ website, id ] = item.split('-');
  11206. switch (website) {
  11207. case 'fawTasks':
  11208. title = `Freeanywhere[${id}]`;
  11209. link = `https://freeanywhere.net/#/giveaway/${id}`;
  11210. break;
  11211.  
  11212. case 'gasTasks':
  11213. title = `Giveawaysu[${id}]`;
  11214. link = `https://giveaway.su/giveaway/view/${id}`;
  11215. break;
  11216.  
  11217. case 'gcTasks':
  11218. title = `GiveeClub[${id}]`;
  11219. link = `https://givee.club/event/${id}`;
  11220. break;
  11221.  
  11222. case 'gkTasks':
  11223. title = `Givekey[${id}]`;
  11224. link = `https://givekey.ru/giveaway/${id}`;
  11225. break;
  11226.  
  11227. case 'gleamTasks':
  11228. title = `Gleam[${id}]`;
  11229. link = `https://gleam.io${id}`;
  11230. break;
  11231.  
  11232. case 'khTasks':
  11233. title = `keyhub[${id}]`;
  11234. link = `https://key-hub.eu/giveaway/${id}`;
  11235. break;
  11236.  
  11237. case 'prysTasks':
  11238. title = `Prys[${id}]`;
  11239. link = `https://prys.revadike.com/giveaway/?id=${id}`;
  11240. break;
  11241.  
  11242. default:
  11243. return;
  11244. }
  11245. for (const [ social, types ] of Object.entries(tasksData.tasks)) {
  11246. for (const [ type, tasks ] of Object.entries(types)) {
  11247. for (const task of tasks) {
  11248. 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>`;
  11249. }
  11250. }
  11251. }
  11252. $('.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>`);
  11253. $('span.delete-task').on('click', function() {
  11254. const itemName = $(this).attr('data-name');
  11255. if (itemName) {
  11256. GM_deleteValue(itemName);
  11257. $(`div.card[data-name="${itemName}"]`).remove();
  11258. external_Swal_default().fire({
  11259. title: i18n('clearTaskFinished'),
  11260. text: itemName,
  11261. icon: 'success'
  11262. });
  11263. } else {
  11264. external_Swal_default().fire({
  11265. title: i18n('clearTaskFailed'),
  11266. icon: 'error'
  11267. });
  11268. }
  11269. });
  11270. } catch (error) {
  11271. throwError(error, 'History.addItem');
  11272. }
  11273. }
  11274. }
  11275. const website_History = History;
  11276. const GiveawayHopper_defaultTasksTemplate = {
  11277. steam: {
  11278. groupLinks: [],
  11279. wishlistLinks: [],
  11280. followLinks: [],
  11281. curatorLinks: [],
  11282. curatorLikeLinks: []
  11283. },
  11284. twitter: {
  11285. userLinks: [],
  11286. retweetLinks: []
  11287. },
  11288. twitch: {
  11289. channelLinks: []
  11290. },
  11291. discord: {
  11292. serverLinks: []
  11293. },
  11294. youtube: {
  11295. channelLinks: []
  11296. },
  11297. extra: {
  11298. giveawayHopper: []
  11299. }
  11300. };
  11301. const GiveawayHopper_defaultTasks = JSON.stringify(GiveawayHopper_defaultTasksTemplate);
  11302. class GiveawayHopper extends website_Website {
  11303. name = 'GiveawayHopper';
  11304. undoneTasks = JSON.parse(GiveawayHopper_defaultTasks);
  11305. socialTasks = JSON.parse(GiveawayHopper_defaultTasks);
  11306. tasks = [];
  11307. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  11308. static test() {
  11309. return window.location.host === 'giveawayhopper.com';
  11310. }
  11311. async after() {
  11312. try {
  11313. if (!this.#checkLogin()) {
  11314. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  11315. }
  11316. this.#getGiveawayId();
  11317. } catch (error) {
  11318. throwError(error, 'GiveawayHopper.after');
  11319. }
  11320. }
  11321. async init() {
  11322. try {
  11323. const logStatus = scripts_echoLog({
  11324. text: i18n('initing')
  11325. });
  11326. if (!await this.#checkLeftKey()) {
  11327. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  11328. }
  11329. this.initialized = true;
  11330. logStatus.success();
  11331. return true;
  11332. } catch (error) {
  11333. throwError(error, 'GiveawayHopper.init');
  11334. return false;
  11335. }
  11336. }
  11337. async classifyTask(action) {
  11338. try {
  11339. if (!this.giveawayId) {
  11340. await this.#getGiveawayId();
  11341. }
  11342. const logStatus = scripts_echoLog({
  11343. text: i18n('getTasksInfo')
  11344. });
  11345. if (action === 'undo') {
  11346. this.socialTasks = GM_getValue(`giveawayHopperTasks-${this.giveawayId}`)?.tasks || JSON.parse(GiveawayHopper_defaultTasks);
  11347. }
  11348. const {
  11349. result,
  11350. statusText,
  11351. status,
  11352. data
  11353. } = await tools_httpRequest({
  11354. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/with-auth`,
  11355. method: 'GET',
  11356. responseType: 'json',
  11357. fetch: true,
  11358. headers: {
  11359. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11360. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  11361. }
  11362. });
  11363. if (result === 'Success') {
  11364. if (data?.status === 200 && data?.response?.tasks) {
  11365. this.tasks = data.response.tasks;
  11366. for (const task of data.response.tasks) {
  11367. if (task.isDone) {
  11368. continue;
  11369. }
  11370. await tools_httpRequest({
  11371. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/visited`,
  11372. method: 'GET',
  11373. responseType: 'json',
  11374. fetch: true,
  11375. headers: {
  11376. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11377. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  11378. }
  11379. });
  11380. if (task.category === 'Steam' && task.type === 'JoinGroup') {
  11381. const steamGroupLink = await getRedirectLink(`https://steamcommunity.com/gid/${task.group_id}`);
  11382. if (!steamGroupLink) {
  11383. continue;
  11384. }
  11385. if (action === 'undo') {
  11386. this.socialTasks.steam.groupLinks.push(steamGroupLink);
  11387. }
  11388. if (action === 'do') {
  11389. this.undoneTasks.steam.groupLinks.push(steamGroupLink);
  11390. }
  11391. continue;
  11392. }
  11393. if (task.category === 'Discord' && task.type === 'JoinServer') {
  11394. if (action === 'undo') {
  11395. this.socialTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`);
  11396. }
  11397. if (action === 'do') {
  11398. this.undoneTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`);
  11399. }
  11400. continue;
  11401. }
  11402. if ([ 'TikTok', 'YouTube', 'General' ].includes(task.category)) {
  11403. continue;
  11404. }
  11405. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${task.category}-${task.type}`);
  11406. }
  11407. logStatus.success();
  11408. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  11409. this.socialTasks = this.uniqueTasks(this.socialTasks);
  11410. if (window.DEBUG) {
  11411. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  11412. }
  11413. GM_setValue(`giveawayHopperTasks-${this.giveawayId}`, {
  11414. tasks: this.socialTasks,
  11415. time: new Date().getTime()
  11416. });
  11417. return true;
  11418. }
  11419. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  11420. return false;
  11421. }
  11422. logStatus.error(`${result}:${statusText}(${status})`);
  11423. return false;
  11424. } catch (error) {
  11425. throwError(error, 'GiveawayHopper.classifyTask');
  11426. return false;
  11427. }
  11428. }
  11429. async verifyTask() {
  11430. try {
  11431. for (const task of this.tasks) {
  11432. if (task.isDone) {
  11433. continue;
  11434. }
  11435. const logStatus = scripts_echoLog({
  11436. text: `${i18n('verifyingTask')}[${task.displayName?.replace(':target', task.targetName) || task.name}]...`
  11437. });
  11438. if (!task.link) {
  11439. if (task.category === 'YouTube' && task.type === 'FollowAccount') {
  11440. task.link = `https://www.youtube.com/@${task.targetName}`;
  11441. } else if (task.category === 'TikTok' && task.type === 'FollowAccount') {
  11442. task.link = `https://www.tiktok.com/@${task.targetName}`;
  11443. } else if (task.category === 'Steam' && task.type === 'JoinGroup') {
  11444. task.link = '';
  11445. } else if (task.category === 'Discord' && task.type === 'JoinServer') {
  11446. task.link = '';
  11447. }
  11448. }
  11449. if (task.link) {
  11450. await tools_httpRequest({
  11451. 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}`,
  11452. method: 'GET',
  11453. fetch: true,
  11454. headers: {
  11455. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11456. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  11457. }
  11458. });
  11459. }
  11460. await delay(1e3);
  11461. const postData = {
  11462. taskcategory: task.category,
  11463. taskname: task.type
  11464. };
  11465. if ([ 'YouTube', 'TikTok' ].includes(task.category)) {
  11466. postData.username = '1';
  11467. }
  11468. const {
  11469. result,
  11470. statusText,
  11471. status,
  11472. data
  11473. } = await tools_httpRequest({
  11474. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/complete`,
  11475. method: 'POST',
  11476. fetch: true,
  11477. headers: {
  11478. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11479. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]),
  11480. 'content-type': 'application/json'
  11481. },
  11482. dataType: 'json',
  11483. data: JSON.stringify(postData)
  11484. });
  11485. if (result === 'Success') {
  11486. if (data?.status === 200 && data?.response?.completed) {
  11487. logStatus.success();
  11488. continue;
  11489. }
  11490. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  11491. continue;
  11492. }
  11493. logStatus.error(`${result}:${statusText}(${status})`);
  11494. continue;
  11495. }
  11496. } catch (error) {
  11497. throwError(error, 'GiveawayHopper.verifyTask');
  11498. return false;
  11499. }
  11500. }
  11501. #getGiveawayId() {
  11502. try {
  11503. const giveawayId = window.location.pathname.split('/').at(-1);
  11504. if (giveawayId) {
  11505. this.giveawayId = giveawayId;
  11506. return true;
  11507. }
  11508. scripts_echoLog({
  11509. text: i18n('getFailed', 'GiveawayId')
  11510. });
  11511. return false;
  11512. } catch (error) {
  11513. throwError(error, 'GiveawayHopper.getGiveawayId');
  11514. return false;
  11515. }
  11516. }
  11517. #checkLogin() {
  11518. try {
  11519. if (!globalOptions.other.checkLogin) {
  11520. return true;
  11521. }
  11522. if ($('div.widget-connections-edit:contains("Log in")').length > 0) {
  11523. $('div.widget-connections-edit:contains("Log in") a')[0].click();
  11524. }
  11525. return true;
  11526. } catch (error) {
  11527. throwError(error, 'GiveawayHopper.checkLogin');
  11528. return false;
  11529. }
  11530. }
  11531. async #checkLeftKey() {
  11532. try {
  11533. if (!globalOptions.other.checkLeftKey) {
  11534. return true;
  11535. }
  11536. if ($('p.widget-single-prize span').length > 0 && parseInt($('p.widget-single-prize span').text()?.match(/\d+/)?.[0] || '0', 10) > 0) {
  11537. return true;
  11538. }
  11539. await external_Swal_default().fire({
  11540. icon: 'warning',
  11541. title: i18n('notice'),
  11542. text: i18n('noKeysLeft'),
  11543. confirmButtonText: i18n('confirm'),
  11544. cancelButtonText: i18n('cancel'),
  11545. showCancelButton: true
  11546. }).then(({
  11547. value
  11548. }) => {
  11549. if (value) {
  11550. window.close();
  11551. }
  11552. });
  11553. return true;
  11554. } catch (error) {
  11555. throwError(error, 'GiveawayHopper.checkLeftKey');
  11556. return false;
  11557. }
  11558. }
  11559. }
  11560. const website_GiveawayHopper = GiveawayHopper;
  11561. 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 ];
  11562. const websiteOptions = function(website, options) {
  11563. try {
  11564. let websiteOptionsForm = `<form id="websiteOptionsForm" class="auto-task-form">
  11565. <table class="auto-task-table"><thead><tr><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`;
  11566. for (const [ option, value ] of Object.entries(options)) {
  11567. websiteOptionsForm += `<tr><td>${option}</td><td><input class="editOption" type="text" name="${option}" value="${value}"/></td></tr>`;
  11568. }
  11569. websiteOptionsForm += '</tbody></table></form>';
  11570. external_Swal_default().fire({
  11571. title: i18n('websiteOptions'),
  11572. html: websiteOptionsForm,
  11573. showConfirmButton: true,
  11574. confirmButtonText: i18n('save'),
  11575. showCancelButton: true,
  11576. cancelButtonText: i18n('close')
  11577. }).then(({
  11578. isConfirmed
  11579. }) => {
  11580. if (isConfirmed) {
  11581. $('#websiteOptionsForm').serializeArray().map(value => {
  11582. options[value.name] = value.value;
  11583. return value;
  11584. });
  11585. GM_setValue(`${website}Options`, options);
  11586. external_Swal_default().fire({
  11587. title: i18n('changeWebsiteOptionsSuccess'),
  11588. icon: 'success'
  11589. });
  11590. }
  11591. });
  11592. } catch (error) {
  11593. throwError(error, 'websiteOptions');
  11594. }
  11595. };
  11596. const options = websiteOptions;
  11597. const external_keyboardJS_namespaceObject = keyboardJS;
  11598. var external_keyboardJS_default = __webpack_require__.n(external_keyboardJS_namespaceObject);
  11599. const checkUpdate = async (updateLink, auto) => {
  11600. try {
  11601. const checkUrl = `${updateLink}package.json?time=${new Date().getTime()}`;
  11602. const {
  11603. result,
  11604. statusText,
  11605. status,
  11606. data
  11607. } = await tools_httpRequest({
  11608. url: checkUrl,
  11609. responseType: 'json',
  11610. method: 'GET',
  11611. timeout: 3e4
  11612. });
  11613. if (result === 'Success') {
  11614. if (data?.response?.version) {
  11615. return data.response;
  11616. }
  11617. if (!auto) {
  11618. scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${data?.statusText}(${data?.status})]`);
  11619. }
  11620. return false;
  11621. }
  11622. if (!auto) {
  11623. scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${result}:${statusText}(${status})]`);
  11624. }
  11625. return false;
  11626. } catch (error) {
  11627. throwError(error, 'checkUpdate');
  11628. return false;
  11629. }
  11630. };
  11631. const hasNewVersion = (currentVersion, remoteVersion) => {
  11632. try {
  11633. const [ currentRealVersion ] = currentVersion.split('-');
  11634. const [ remoteRealVersion, isPreview ] = remoteVersion.split('-');
  11635. if (isPreview && !globalOptions.other.receivePreview) {
  11636. return false;
  11637. }
  11638. const [ currentVersion1, currentVersion2, currentVersion3 ] = currentRealVersion.split('.').map(value => parseInt(value, 10));
  11639. const [ remoteVersion1, remoteVersion2, remoteVersion3 ] = remoteRealVersion.split('.').map(value => parseInt(value, 10));
  11640. if (remoteVersion1 > currentVersion1) {
  11641. return true;
  11642. }
  11643. if (remoteVersion1 < currentVersion1) {
  11644. return false;
  11645. }
  11646. if (remoteVersion2 > currentVersion2) {
  11647. return true;
  11648. }
  11649. if (remoteVersion2 < currentVersion2) {
  11650. return false;
  11651. }
  11652. if (remoteVersion3 > currentVersion3) {
  11653. return true;
  11654. }
  11655. return false;
  11656. } catch (error) {
  11657. throwError(error, 'compareVersion');
  11658. return false;
  11659. }
  11660. };
  11661. const updateChecker = async () => {
  11662. try {
  11663. const currentVersion = GM_info.script.version;
  11664. const updateSource = globalOptions.other.autoUpdateSource.toLowerCase();
  11665. const updateLinks = {
  11666. github: 'https://github.com/HCLonely/auto-task-new/raw/main/',
  11667. jsdelivr: 'https://cdn.jsdelivr.net/gh/HCLonely/auto-task-v4@main/',
  11668. standby: 'https://auto-task-v4.hclonely.com/'
  11669. };
  11670. let version;
  11671. let updateLink = '';
  11672. let packageData;
  11673. if ([ 'github', 'jsdelivr', 'standby' ].includes(updateSource)) {
  11674. updateLink = updateLinks[updateSource];
  11675. packageData = await checkUpdate(updateLink, false);
  11676. } else {
  11677. updateLink = updateLinks.github;
  11678. packageData = await checkUpdate(updateLink, true);
  11679. if (!packageData) {
  11680. updateLink = updateLinks.jsdelivr;
  11681. packageData = await checkUpdate(updateLink, true);
  11682. if (!packageData) {
  11683. updateLink = updateLinks.standby;
  11684. packageData = await checkUpdate(updateLink, true);
  11685. }
  11686. }
  11687. }
  11688. if (packageData) {
  11689. version = packageData.version || currentVersion;
  11690. } else {
  11691. version = currentVersion;
  11692. scripts_echoLog({}).error(i18n('checkUpdateFailed'));
  11693. }
  11694. if (packageData && hasNewVersion(currentVersion, version)) {
  11695. scripts_echoLog({
  11696. html: `<li><font>${i18n('newVersionNotice', version, `${updateLink}dist/${GM_info.script.name}.user.js`)}</font></li>`
  11697. });
  11698. scripts_echoLog({
  11699. html: `<li>${i18n('updateText', version)}</li><ol class="update-text">${packageData.change?.map(change => `<li>${change}</li>`).join('')}<li>${i18n('updateHistory')}</li></ol>`
  11700. });
  11701. }
  11702. } catch (error) {
  11703. throwError(error, 'updateChecker');
  11704. }
  11705. };
  11706. const scripts_updateChecker = updateChecker;
  11707. window.STYLE = GM_addStyle(auto_task.A + GM_getResourceText('style'));
  11708. window.DEBUG = !!globalOptions.other?.debug;
  11709. window.TRACE = !!globalOptions.other?.debug && typeof console.trace === 'function';
  11710. const loadScript = async () => {
  11711. if (window.name === 'ATv4_twitchAuth' && window.location.hostname === 'www.twitch.tv') {
  11712. const authToken = external_Cookies_default().get('auth-token');
  11713. const isLogin = !!external_Cookies_default().get('login');
  11714. if (isLogin) {
  11715. GM_setValue('twitchAuth', {
  11716. authToken: authToken,
  11717. clientVersion: __twilightBuildID,
  11718. clientId: commonOptions?.headers?.['Client-ID'],
  11719. deviceId: commonOptions?.headers?.['Device-ID'],
  11720. clientSessionId: window.localStorage.local_storage_app_session_id.replace(/"/g, '')
  11721. });
  11722. window.close();
  11723. external_Swal_default().fire('', i18n('closePageNotice'));
  11724. } else {
  11725. external_Swal_default().fire('', i18n('needLogin'));
  11726. }
  11727. return;
  11728. }
  11729. if (window.name === 'ATv4_redditAuth' && window.location.hostname === 'www.reddit.com') {
  11730. const betaButton = $('#redesign-beta-optin-btn');
  11731. if (betaButton.length > 0) {
  11732. return betaButton[0].click();
  11733. }
  11734. window.close();
  11735. external_Swal_default().fire('', i18n('closePageNotice'));
  11736. return;
  11737. }
  11738. let website;
  11739. for (const Website of Websites) {
  11740. if (Website.test()) {
  11741. website = new Website();
  11742. break;
  11743. }
  11744. }
  11745. if (!website) {
  11746. console.log('%c%s', 'color:#ff0000', 'Auto-Task[Warning]: 脚本停止加载,当前网站不支持!');
  11747. return;
  11748. }
  11749. if (website?.before) {
  11750. await website?.before();
  11751. }
  11752. $('body').append(`
  11753. <div id="auto-task-info"
  11754. style="display:${globalOptions.other.defaultShowLog ? 'block' : 'none'};
  11755. ${globalOptions.position.logSideX}:${globalOptions.position.logDistance.split(',')[0]}px;
  11756. ${globalOptions.position.logSideY}:${globalOptions.position.logDistance.split(',')[1]}px;">
  11757. </div>
  11758. <div id="auto-task-buttons"
  11759. style="display:${globalOptions.other.defaultShowButton ? 'block' : 'none'};
  11760. ${globalOptions.position.buttonSideX}:${globalOptions.position.buttonDistance.split(',')[0]}px;
  11761. ${globalOptions.position.buttonSideY}:${globalOptions.position.buttonDistance.split(',')[1]}px;">
  11762. </div>
  11763. <div class="show-button-div"
  11764. style="display:${globalOptions.other.defaultShowButton ? 'none' : 'block'};
  11765. ${globalOptions.position.showButtonSideX}:${globalOptions.position.showButtonDistance.split(',')[0]}px;
  11766. ${globalOptions.position.showButtonSideY}:${globalOptions.position.showButtonDistance.split(',')[1]}px;">
  11767. <a class="auto-task-website-btn"
  11768. href="javascript:void(0);"
  11769. target="_self"
  11770. title="${i18n('showButton')}"> </a>
  11771. </div>
  11772. `);
  11773. $('div.show-button-div').on('click', () => {
  11774. $('#auto-task-buttons').show();
  11775. $('div.show-button-div').hide();
  11776. });
  11777. const toggleLog = () => {
  11778. const $this = $('#toggle-log');
  11779. const status = $this.attr('data-status');
  11780. if (status === 'show') {
  11781. $('#auto-task-info').hide();
  11782. $this.attr('data-status', 'hide').text(i18n('showLog'));
  11783. } else {
  11784. $('#auto-task-info').show();
  11785. $this.attr('data-status', 'show').text(i18n('hideLog'));
  11786. }
  11787. };
  11788. external_keyboardJS_default().bind(globalOptions.hotKey.doTaskKey, () => {
  11789. if (website.doTask) {
  11790. website.doTask();
  11791. }
  11792. });
  11793. external_keyboardJS_default().bind(globalOptions.hotKey.undoTaskKey, () => {
  11794. if (website.undoTask) {
  11795. website.undoTask();
  11796. }
  11797. });
  11798. external_keyboardJS_default().bind(globalOptions.hotKey.toggleLogKey, toggleLog);
  11799. if (website?.after) {
  11800. await website?.after();
  11801. }
  11802. if (website?.buttons && $('#auto-task-buttons').children().length === 0) {
  11803. $('#auto-task-buttons').addClass(`${website.name}-buttons`);
  11804. for (const button of website.buttons) {
  11805. if (website[button]) {
  11806. const btnElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">${i18n(button)}</a></p>`);
  11807. btnElement.find('a.auto-task-website-btn').on('click', () => {
  11808. website[button]();
  11809. });
  11810. $('#auto-task-buttons').append(btnElement);
  11811. }
  11812. }
  11813. }
  11814. const hideButtonElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">
  11815. ${i18n('hideButton')}</a></p>`);
  11816. hideButtonElement.find('a.auto-task-website-btn').on('click', () => {
  11817. $('#auto-task-buttons').hide();
  11818. $('div.show-button-div').show();
  11819. });
  11820. 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'}">
  11821. ${globalOptions.other.defaultShowLog ? i18n('hideLog') : i18n('showLog')}</a></p>`);
  11822. toggleLogElement.find('a.auto-task-website-btn').on('click', toggleLog);
  11823. $('#auto-task-buttons').append(hideButtonElement).append(toggleLogElement);
  11824. if (website?.options) {
  11825. GM_registerMenuCommand(i18n('changeWebsiteOptions'), () => {
  11826. options(website.name, website.options);
  11827. });
  11828. }
  11829. if (website.name !== 'Setting') {
  11830. GM_registerMenuCommand(i18n('changeGlobalOptions'), () => {
  11831. changeGlobalOptions('swal');
  11832. });
  11833. GM_registerMenuCommand(i18n('settingPage'), () => {
  11834. GM_openInTab('https://auto-task-v4.hclonely.com/setting.html', {
  11835. active: true
  11836. });
  11837. });
  11838. }
  11839. console.log('%c%s', 'color:#1bbe1a', 'Auto-Task[Load]: 脚本加载完成');
  11840. const [ v1, v2 ] = GM_info.version?.split('.') || [];
  11841. if (!(parseInt(v1, 10) >= 5 && parseInt(v2, 10) >= 2)) {
  11842. scripts_echoLog({}).error(i18n('versionNotMatched'));
  11843. }
  11844. if (!GM_getValue('notice')) {
  11845. external_Swal_default().fire({
  11846. title: i18n('swalNotice'),
  11847. icon: 'warning'
  11848. }).then(() => {
  11849. GM_openInTab(i18n('noticeLink'), {
  11850. active: true
  11851. });
  11852. GM_setValue('notice', new Date().getTime());
  11853. });
  11854. scripts_echoLog({
  11855. html: `<li><font class="warning">${i18n('echoNotice', i18n('noticeLink'))}</font></li>`
  11856. }).font?.find('a').on('click', () => {
  11857. GM_setValue('notice', new Date().getTime());
  11858. });
  11859. }
  11860. scripts_updateChecker();
  11861. };
  11862. if (window.location.hostname === 'discord.com') {
  11863. const LocalStorage = window.localStorage;
  11864. if (window.name === 'ATv4_discordAuth') {
  11865. window.localStorage.removeItem = () => true;
  11866. const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, '');
  11867. if (discordAuth && discordAuth.length > 0) {
  11868. GM_setValue('discordAuth', {
  11869. auth: discordAuth
  11870. });
  11871. window.close();
  11872. external_Swal_default().fire('', i18n('closePageNotice'));
  11873. } else {
  11874. external_Swal_default().fire({
  11875. text: i18n('getDiscordAuthFailed'),
  11876. icon: 'error'
  11877. });
  11878. }
  11879. } else {
  11880. const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, '');
  11881. if (discordAuth && discordAuth.length > 0) {
  11882. GM_setValue('discordAuth', {
  11883. auth: discordAuth
  11884. });
  11885. }
  11886. }
  11887. } else if (window.location.hostname === 'opquests.com') {
  11888. loadScript();
  11889. } else if ((window.name === 'ATv4_updateStoreAuth' || GM_getValue('ATv4_updateStoreAuth')) && window.location.host === 'store.steampowered.com') {
  11890. $(() => {
  11891. if ($('[data-miniprofile]').length === 0) {
  11892. return;
  11893. }
  11894. const storeSessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
  11895. if (storeSessionID) {
  11896. GM_deleteValue('ATv4_updateStoreAuth');
  11897. GM_setValue('steamStoreAuth', {
  11898. storeSessionID: storeSessionID
  11899. });
  11900. window.close();
  11901. external_Swal_default().fire('', i18n('closePageNotice'));
  11902. } else {
  11903. external_Swal_default().fire({
  11904. title: 'Error: Get "sessionID" failed',
  11905. icon: 'error'
  11906. });
  11907. }
  11908. });
  11909. } else if ((window.name === 'ATv4_updateCommunityAuth' || GM_getValue('ATv4_updateCommunityAuth')) && window.location.host === 'steamcommunity.com') {
  11910. $(() => {
  11911. const steam64Id = document.body.innerHTML.match(/g_steamID = "(.+?)";/)?.[1];
  11912. const communitySessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
  11913. if (steam64Id && communitySessionID) {
  11914. GM_deleteValue('ATv4_updateCommunityAuth');
  11915. GM_setValue('steamCommunityAuth', {
  11916. steam64Id: steam64Id,
  11917. communitySessionID: communitySessionID
  11918. });
  11919. window.close();
  11920. external_Swal_default().fire('', i18n('closePageNotice'));
  11921. } else {
  11922. setTimeout(() => {
  11923. external_Swal_default().fire({
  11924. title: 'Error: Get "sessionID" failed',
  11925. icon: 'error'
  11926. });
  11927. }, 3e3);
  11928. }
  11929. });
  11930. } else {
  11931. if (window.location.hostname === 'key-hub.eu') {
  11932. unsafeWindow.keyhubtracker = 1;
  11933. unsafeWindow.gaData = {};
  11934. }
  11935. $(loadScript);
  11936. }
  11937. }();
  11938. })();