auto-task-v4

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

当前为 2025-03-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name auto-task-v4
  3. // @namespace auto-task-v4
  4. // @version 4.7.3
  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 api.twitter.com
  66. // @connect youtube.com
  67. // @connect www.youtube.com
  68. // @connect facebook.com
  69. // @connect instagram.com
  70. // @connect vk.com
  71. // @connect twitch.tv
  72. // @connect www.twitch.tv
  73. // @connect gql.twitch.tv
  74. // @connect github.com
  75. // @connect discordapp.com
  76. // @connect discord.gg
  77. // @connect discord.com
  78. // @connect www.reddit.com
  79. // @connect oauth.reddit.com
  80. // @connect raw.githubusercontent.com
  81. // @connect t.me
  82. // @connect bit.ly
  83. // @connect giveaway.su
  84. // @connect google.com
  85. // @connect www.vloot.io
  86. // @connect givee.club
  87. // @connect gleam.io
  88. // @connect www.indiedb.com
  89. // @connect key-hub.eu
  90. // @connect opquests.com
  91. // @connect itch.io
  92. // @connect auto-task-v4.hclonely.com
  93. // @connect giveawayhopper.com
  94. // @connect *
  95. // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
  96. // @require https://cdn.jsdelivr.net/npm/js-cookie@3.0.1/dist/js.cookie.min.js
  97. // @require https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.5/runtime.min.js
  98. // @require https://cdn.jsdelivr.net/npm/js-sha1@0.6.0/src/sha1.min.js
  99. // @require https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js
  100. // @resource style https://cdn.jsdelivr.net/npm/sweetalert2@11.3.5/dist/sweetalert2.min.css
  101. // @require https://cdn.jsdelivr.net/npm/keyboardjs@2.6.4/dist/keyboard.min.js
  102. // @require https://cdn.jsdelivr.net/npm/dayjs@1.10.7/dayjs.min.js
  103.  
  104. // @noframes
  105. // ==/UserScript==
  106.  
  107. console.log('%c%s', 'color:blue', 'Auto-Task[Load]: 脚本开始加载');
  108. (function() {
  109. var __webpack_modules__ = {
  110. 314: function(module) {
  111. 'use strict';
  112. module.exports = function(cssWithMappingToString) {
  113. var list = [];
  114. list.toString = function toString() {
  115. return this.map(function(item) {
  116. var content = '';
  117. var needLayer = typeof item[5] !== 'undefined';
  118. if (item[4]) {
  119. content += '@supports ('.concat(item[4], ') {');
  120. }
  121. if (item[2]) {
  122. content += '@media '.concat(item[2], ' {');
  123. }
  124. if (needLayer) {
  125. content += '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {');
  126. }
  127. content += cssWithMappingToString(item);
  128. if (needLayer) {
  129. content += '}';
  130. }
  131. if (item[2]) {
  132. content += '}';
  133. }
  134. if (item[4]) {
  135. content += '}';
  136. }
  137. return content;
  138. }).join('');
  139. };
  140. list.i = function i(modules, media, dedupe, supports, layer) {
  141. if (typeof modules === 'string') {
  142. modules = [ [ null, modules, undefined ] ];
  143. }
  144. var alreadyImportedModules = {};
  145. if (dedupe) {
  146. for (var k = 0; k < this.length; k++) {
  147. var id = this[k][0];
  148. if (id != null) {
  149. alreadyImportedModules[id] = true;
  150. }
  151. }
  152. }
  153. for (var _k = 0; _k < modules.length; _k++) {
  154. var item = [].concat(modules[_k]);
  155. if (dedupe && alreadyImportedModules[item[0]]) {
  156. continue;
  157. }
  158. if (typeof layer !== 'undefined') {
  159. if (typeof item[5] === 'undefined') {
  160. item[5] = layer;
  161. } else {
  162. item[1] = '@layer'.concat(item[5].length > 0 ? ' '.concat(item[5]) : '', ' {').concat(item[1], '}');
  163. item[5] = layer;
  164. }
  165. }
  166. if (media) {
  167. if (!item[2]) {
  168. item[2] = media;
  169. } else {
  170. item[1] = '@media '.concat(item[2], ' {').concat(item[1], '}');
  171. item[2] = media;
  172. }
  173. }
  174. if (supports) {
  175. if (!item[4]) {
  176. item[4] = ''.concat(supports);
  177. } else {
  178. item[1] = '@supports ('.concat(item[4], ') {').concat(item[1], '}');
  179. item[4] = supports;
  180. }
  181. }
  182. list.push(item);
  183. }
  184. };
  185. return list;
  186. };
  187. },
  188. 601: function(module) {
  189. 'use strict';
  190. module.exports = function(i) {
  191. return i[1];
  192. };
  193. },
  194. 675: function(module, __webpack_exports__, __webpack_require__) {
  195. 'use strict';
  196. __webpack_require__.d(__webpack_exports__, {
  197. A: function() {
  198. return __WEBPACK_DEFAULT_EXPORT__;
  199. }
  200. });
  201. var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(601);
  202. 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__);
  203. var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(314);
  204. 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__);
  205. 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());
  206. ___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}`, '' ]);
  207. const __WEBPACK_DEFAULT_EXPORT__ = ___CSS_LOADER_EXPORT___.toString();
  208. },
  209. 991: function(__unused_webpack_module, exports) {
  210. !function(e, n) {
  211. true ? n(exports) : 0;
  212. }(this, function(e) {
  213. 'use strict';
  214. function l(e) {
  215. return '[object Object]' === o(e);
  216. }
  217. function n(e) {
  218. return /^\d+$/.test(e + '');
  219. }
  220. function t(e) {
  221. return /^\d+\.\d+$/.test(e + '');
  222. }
  223. var o = function(e) {
  224. return Object.prototype.toString.call(e);
  225. };
  226. var r = function() {
  227. return (r = Object.assign || function(e) {
  228. for (var n, t = 1, o = arguments.length; t < o; t++) {
  229. for (var r in n = arguments[t]) {
  230. Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r]);
  231. }
  232. }
  233. return e;
  234. }).apply(this, arguments);
  235. };
  236. function i(e, n, t) {
  237. if (t || 2 === arguments.length) {
  238. for (var o, r = 0, i = n.length; r < i; r++) {
  239. !o && r in n || ((o = o || Array.prototype.slice.call(n, 0, r))[r] = n[r]);
  240. }
  241. }
  242. return e.concat(o || Array.prototype.slice.call(n));
  243. }
  244. a.prototype.init = function() {
  245. try {
  246. this.getSystemName(), this.getBrowserName();
  247. } catch (e) {
  248. console.warn('[UA formatter error] '.concat(e));
  249. }
  250. }, a.prototype.getEngine = function() {
  251. var e = this.agent;
  252. return -1 !== e.indexOf('Trident') ? 'Trident' : -1 !== e.indexOf('Firefox') ? 'Gecko' : -1 !== e.indexOf('Presto') ? 'Presto' : 'WebKit';
  253. }, a.prototype.getSystemName = function() {
  254. var e, n = (this.agent.match(/^[a-z]+\/\d+\.\d+\s?\(([a-z\d\s:;./_-]+)\)/i) || [])[1];
  255. try {
  256. var t, o = '';
  257. if (/Windows/i.test(n)) {
  258. var r = (n.match(/NT\s(\d+\.\d+)/) || [])[1];
  259. switch (this.info.os = 'Windows', r) {
  260. case '6.3':
  261. o = '8.1';
  262. break;
  263.  
  264. case '6.2':
  265. o = '8';
  266. break;
  267.  
  268. case '6.1':
  269. o = '7';
  270. break;
  271.  
  272. case '5.2':
  273. case '5.1':
  274. o = 'XP';
  275. break;
  276.  
  277. default:
  278. o = r;
  279. }
  280. this.info.device = 'PC', this.info.osVersion = o;
  281. } else {
  282. /^Macintosh/i.test(n) ? (o = (n.match(/X\s((\d+(_|\.))+\d+)/) || [])[1],
  283. 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],
  284. this.info.os = 'iPad', this.info.device = 'Tablet', this.info.osVersion = o.replace(/_/g, '.')) : /^iPhone/i.test(n) ? (o = (n.match(/((\d+_)+\d+)/) || [])[1],
  285. 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],
  286. 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',
  287. this.info.osVersion = 'Unknown');
  288. }
  289. } catch (e) {
  290. this.info.os = 'Unknown', this.info.osVersion = 'Unknown';
  291. }
  292. }, a.prototype.getBrowserName = function() {
  293. var e = Object.keys(this.browserNameMap).map(function(e) {
  294. return new RegExp(''.concat(e, '(\\/|\\s)(\\d+\\.)+\\d+'));
  295. }), n = 1 < (n = (this.agent.match(/[a-z\d]+(\/|\s)(\d+\.)+\d+/gi) || []).filter(function(n) {
  296. return -1 !== e.findIndex(function(e) {
  297. return e.test(n);
  298. });
  299. })).length && !/^Safari/.test(n[n.length - 1]) ? n.reverse() : n;
  300. this.info = r(r({}, this.info), this._formatBrowserVersion(n[0]));
  301. }, a.prototype._formatBrowserVersion = function(e) {
  302. var n, t, o, r;
  303. try {
  304. 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++) {
  305. var l = f[u], d = l[0], h = l[1];
  306. if (new RegExp(d).test(s)) {
  307. c = h;
  308. break;
  309. }
  310. }
  311. var p = {
  312. browserVersion: null != a ? a : 'Unknown',
  313. browser: null != (o = c.en) ? o : 'Unknown',
  314. browserZH: null != (r = (null == c ? void 0 : c.zh) || c.en) ? r : 'Unknown'
  315. };
  316. return 'Trident' === s && (p.browserVersion = {
  317. '4.0': 8,
  318. '5.0': 9,
  319. '6.0': 10,
  320. '7.0': 11
  321. }[a]), p;
  322. } catch (e) {
  323. return console.warn('[UA formatter error] '.concat(e)), {
  324. browser: 'Unknown',
  325. browserVersion: 'Unknown'
  326. };
  327. }
  328. };
  329. var s = a;
  330. function a(e) {
  331. this.agent = '', this.info = {
  332. browser: '',
  333. browserZH: '',
  334. browserVersion: '',
  335. os: '',
  336. osVersion: '',
  337. device: 'Unknown',
  338. engine: 'WebKit'
  339. }, this.browserNameMap = {
  340. MicroMessenger: {
  341. en: 'MicroMessenger',
  342. zh: '微信'
  343. },
  344. MetaSr: {
  345. en: 'MetaSr',
  346. zh: '搜狗浏览器'
  347. },
  348. 'QQ(Browser)?': {
  349. en: 'QQBrowser',
  350. zh: 'QQ浏览器'
  351. },
  352. UCBrowser: {
  353. en: 'UCBrowser',
  354. zh: 'UC浏览器'
  355. },
  356. '2345Explorer': {
  357. en: '2345Explorer',
  358. zh: '2345极速浏览器'
  359. },
  360. Mb2345Browser: {
  361. en: 'Mb2345Browser',
  362. zh: '2345手机浏览器'
  363. },
  364. Trident: {
  365. en: 'Internet Explorer'
  366. },
  367. 'Edge?': {
  368. en: 'Edge'
  369. },
  370. OPR: {
  371. en: 'Opera'
  372. },
  373. Vivaldi: {
  374. en: 'Vivaldi'
  375. },
  376. Firefox: {
  377. en: 'Firefox'
  378. },
  379. Chrome: {
  380. en: 'Chrome'
  381. },
  382. Safari: {
  383. en: 'Safari'
  384. }
  385. }, this.agent = e, this.init();
  386. var e = this.info, n = e.browser, t = e.browserVersion, e = e.osVersion;
  387. this.info = r(r({}, this.info), {
  388. engine: this.getEngine(),
  389. browserVersion: 'Safari' === n ? e : t
  390. });
  391. }
  392. u.prototype.init = function() {
  393. var t;
  394. 'undefined' != typeof window && (t = {}, document.cookie.split(/;\s/).forEach(function(e) {
  395. var e = e.split(/=/), n = e[0], e = e[1];
  396. t[n] = e;
  397. }), this.cookies = t);
  398. }, u.prototype.getItem = function(e) {
  399. return this.cookies[e];
  400. }, u.prototype.getAllItems = function() {
  401. return this.cookies;
  402. }, u.prototype.setItem = function(e, n, t, o, r, i) {
  403. document.cookie = ''.concat(e, '=').concat(n).concat(t ? '; expires='.concat(t) : '').concat(o ? '; path='.concat(o) : '').concat(r ? '; domain='.concat(r) : '').concat(i ? '; secure' : '');
  404. };
  405. var c = u;
  406. function u() {
  407. this.cookies = {}, this.init();
  408. }
  409. function d(e, n) {
  410. var t = i(i([], n || [], !0), [ '_' ], !1).join('|');
  411. return e.replace(new RegExp('(('.concat(t, ')[a-z])+'), 'g'), function(e, n) {
  412. return n.replace(new RegExp(t), '').toLocaleUpperCase();
  413. });
  414. }
  415. function f(e) {
  416. return e.replace(/(-\w)/g, function(e) {
  417. return e.substr(1, 1).toUpperCase();
  418. }).replace(/^(\w)/, function(e) {
  419. return e.toUpperCase();
  420. });
  421. }
  422. e.countDown = function e(n, t, o, r) {
  423. if (!window) {
  424. throw new Error('window is not defined.');
  425. }
  426. if (0 < n) {
  427. return r && r(), n--, window[t] = window.setTimeout(function() {
  428. e(n, t, o, r);
  429. }, 1e3), function() {
  430. return clearTimeout(window[t]);
  431. };
  432. }
  433. clearTimeout(window[t]), o && o();
  434. }, e.createRandomID = function(e) {
  435. void 0 === e && (e = 12);
  436. for (var n = [], t = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), o = t.length, r = 0; r < e; r++) {
  437. n.push(t[Math.round(Math.random() * o)]);
  438. }
  439. return n.join('');
  440. }, e.dCookie = function() {
  441. return new c();
  442. }, e.debounce = function(o, r, i) {
  443. var s;
  444. return void 0 === r && (r = 0), void 0 === i && (i = !1), function() {
  445. for (var e = this, n = [], t = 0; t < arguments.length; t++) {
  446. n[t] = arguments[t];
  447. }
  448. i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() {
  449. o.apply(e, n);
  450. }, r));
  451. };
  452. }, e.debounceDecorator = function(r, i) {
  453. var s;
  454. return function(e, n, t) {
  455. var o = t.value;
  456. return t.value = function() {
  457. for (var e = this, n = [], t = 0; t < arguments.length; t++) {
  458. n[t] = arguments[t];
  459. }
  460. i ? o.apply(this, n) : (clearTimeout(s), s = setTimeout(function() {
  461. o.apply(e, n);
  462. }, r));
  463. }, t;
  464. };
  465. }, e.debugWarn = function(e, n) {
  466. console.warn('['.concat(e, ']: ').concat(n));
  467. }, e.deepCopy = function e(n) {
  468. if (l(n) || Array.isArray(n)) {
  469. var t, o = Array.isArray(n) ? [] : {};
  470. for (t in n) {
  471. o[t] = e(n[t]);
  472. }
  473. return o;
  474. }
  475. return n;
  476. }, e.deleteArrayItems = function(n, e, t) {
  477. return 'object' == typeof e[0] ? e.filter(function(e) {
  478. return !n.includes(e[t]);
  479. }) : e.filter(function(e) {
  480. return !n.includes(e);
  481. });
  482. }, e.formatQueryParams = function(e) {
  483. e = null == (e = /\?(?<params>(.*)=.+)/.exec(decodeURIComponent(e))) ? void 0 : e.groups;
  484. if (!e) {
  485. return {};
  486. }
  487. for (var n = e.params.split('&'), o = {}, t = 0; t < n.length; t++) {
  488. n[t].replace(/([^?&]*)=([^?&]*)/, function(e, n, t) {
  489. return o[n] = t, e;
  490. });
  491. }
  492. return o;
  493. }, e.formatThousandth = function(e) {
  494. 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, '$&,');
  495. return ''.concat(n).concat(e ? '.'.concat(e) : '');
  496. }, e.generateTree = function e(n, t, o, r) {
  497. for (var i = [], s = 0; s < n.length; s++) {
  498. var a = n[s];
  499. a[o] === t && (i.push(a), a.children = e(n, a[null != r ? r : 'id'], o, r));
  500. }
  501. return i;
  502. }, e.isBoolean = function(e) {
  503. return 'boolean' == typeof e;
  504. }, e.isEmpty = function(e) {
  505. 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);
  506. }, e.isFloatNumber = t, e.isFunction = function(e) {
  507. return '[object Function]' === o(e);
  508. }, e.isImageUrl = function(e) {
  509. return /\.((png)|(jpe?g)|(gif)|(svg)|(webp))$/gi.test(e);
  510. }, e.isInteger = n, e.isNumber = function(e) {
  511. return n(e) || t(e);
  512. }, e.isObject = l, e.isPromise = function(e) {
  513. return '[object Promise]' === o(e);
  514. }, e.isRegexp = function(e) {
  515. return '[object RegExp]' === o(e);
  516. }, e.objectKeyToCamelCase = function e(n, t, o) {
  517. if (Array.isArray(n)) {
  518. for (var r = [], i = 0; i < n.length; i++) {
  519. r[i] = e(t && n[i][t] ? n[i][t] : n[i], t, o);
  520. }
  521. } else if (l(n)) {
  522. r = {};
  523. for (var s = t && n[t] ? n[t] : n, a = 0, c = Object.entries(s); a < c.length; a++) {
  524. var u = (f = c[a])[0], f = f[1];
  525. Array.isArray(f) || l(s) ? r[d(u, o)] = e(f, t, o) : r[d(u, o)] = f;
  526. }
  527. } else {
  528. r = n;
  529. }
  530. return r;
  531. }, e.pickLastItem = function(e) {
  532. return e[e.length - 1];
  533. }, e.realType = o, e.searchParams = function(e, n) {
  534. return void 0 === e && (e = null === location || void 0 === location ? void 0 : location.search),
  535. new URLSearchParams(e).get(n);
  536. }, e.throwError = function(e, n) {
  537. throw '['.concat(f(e), ']: ').concat(n);
  538. }, e.toBoolean = function(e) {
  539. return 'true' === e || 'false' !== e && Boolean(e);
  540. }, e.toLowerCamelCase = d, e.toPascalCase = f, e.toUnderline = function(e) {
  541. return e.replace(/([A-Z])/g, function(e) {
  542. return '_'.concat(e.toLocaleLowerCase());
  543. });
  544. }, e.ua = function(e) {
  545. return void 0 === e && (e = navigator.userAgent), new s(e).info;
  546. };
  547. });
  548. }
  549. };
  550. var __webpack_module_cache__ = {};
  551. function __webpack_require__(moduleId) {
  552. var cachedModule = __webpack_module_cache__[moduleId];
  553. if (cachedModule !== undefined) {
  554. return cachedModule.exports;
  555. }
  556. var module = __webpack_module_cache__[moduleId] = {
  557. id: moduleId,
  558. exports: {}
  559. };
  560. __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  561. return module.exports;
  562. }
  563. !function() {
  564. __webpack_require__.n = function(module) {
  565. var getter = module && module.__esModule ? function() {
  566. return module['default'];
  567. } : function() {
  568. return module;
  569. };
  570. __webpack_require__.d(getter, {
  571. a: getter
  572. });
  573. return getter;
  574. };
  575. }();
  576. !function() {
  577. __webpack_require__.d = function(exports, definition) {
  578. for (var key in definition) {
  579. if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  580. Object.defineProperty(exports, key, {
  581. enumerable: true,
  582. get: definition[key]
  583. });
  584. }
  585. }
  586. };
  587. }();
  588. !function() {
  589. __webpack_require__.o = function(obj, prop) {
  590. return Object.prototype.hasOwnProperty.call(obj, prop);
  591. };
  592. }();
  593. var __webpack_exports__ = {};
  594. !function() {
  595. 'use strict';
  596. const external_Swal_namespaceObject = Swal;
  597. var external_Swal_default = __webpack_require__.n(external_Swal_namespaceObject);
  598. const external_Cookies_namespaceObject = Cookies;
  599. var external_Cookies_default = __webpack_require__.n(external_Cookies_namespaceObject);
  600. var auto_task = __webpack_require__(675);
  601. var javascript_utils_umd_min = __webpack_require__(991);
  602. const httpRequest = async (options, times = 0) => {
  603. if (window.TRACE) {
  604. console.trace('%cAuto-Task[Debug]:', 'color:blue');
  605. }
  606. try {
  607. const result = await new Promise(resolve => {
  608. if (options.dataType) {
  609. options.responseType = options.dataType;
  610. }
  611. const requestObj = {
  612. ...{
  613. timeout: 3e4,
  614. ontimeout(data) {
  615. resolve({
  616. result: 'Error',
  617. statusText: 'Timeout',
  618. status: 601,
  619. data: data,
  620. options: options
  621. });
  622. },
  623. onabort(data) {
  624. resolve({
  625. result: 'Error',
  626. statusText: 'Aborted',
  627. status: 602,
  628. data: data,
  629. options: options
  630. });
  631. },
  632. onerror(data) {
  633. resolve({
  634. result: 'Error',
  635. statusText: 'Error',
  636. status: 603,
  637. data: data,
  638. options: options
  639. });
  640. },
  641. onload(data) {
  642. const headers = {};
  643. data.responseHeaders?.split('\n').forEach(header => {
  644. const headerArr = header.trim().split(':');
  645. const name = headerArr.shift()?.trim() || '';
  646. const value = headerArr.join(':').trim();
  647. if (name && value) {
  648. if (headers[name]) {
  649. if (Array.isArray(headers[name])) {
  650. headers[name].push(value);
  651. } else {
  652. headers[name] = [ headers[name], value ];
  653. }
  654. } else {
  655. headers[name] = value;
  656. }
  657. }
  658. });
  659. if (headers['set-cookie'] && !Array.isArray(headers['set-cookie'])) {
  660. headers['set-cookie'] = [ headers['set-cookie'] ];
  661. }
  662. data.responseHeadersText = data.responseHeaders;
  663. data.responseHeaders = headers;
  664. data.finalUrl = data.responseHeaders?.location || data.finalUrl;
  665. if (options.responseType === 'json' && data?.response && typeof data.response !== 'object') {
  666. try {
  667. data.response = JSON.parse(data.responseText);
  668. } catch (error) {}
  669. }
  670. resolve({
  671. result: 'Success',
  672. statusText: 'Load',
  673. status: 600,
  674. data: data,
  675. options: options
  676. });
  677. }
  678. },
  679. ...options
  680. };
  681. GM_xmlhttpRequest(requestObj);
  682. });
  683. if (window.DEBUG) {
  684. console.log('%cAuto-Task[httpRequest]:', 'color:blue', JSON.stringify(result));
  685. }
  686. if (result.status !== 600 && times < 2) {
  687. return await httpRequest(options, times + 1);
  688. }
  689. return result;
  690. } catch (error) {
  691. console.log('%cAuto-Task[httpRequest]:', 'color:red', JSON.stringify({
  692. errorMsg: error,
  693. options: options
  694. }));
  695. throwError(error, 'httpRequest');
  696. return {
  697. result: 'JsError',
  698. statusText: 'Error',
  699. status: 604,
  700. error: error,
  701. options: options
  702. };
  703. }
  704. };
  705. const tools_httpRequest = httpRequest;
  706. const echoLog = ({
  707. type,
  708. text,
  709. html,
  710. id
  711. }) => {
  712. const emptyStatus = {
  713. success: () => emptyStatus,
  714. error: () => emptyStatus,
  715. warning: () => emptyStatus,
  716. info: () => emptyStatus,
  717. view: () => emptyStatus
  718. };
  719. try {
  720. let ele;
  721. if (type) {
  722. switch (type) {
  723. case 'joiningSteamGroup':
  724. case 'leavingSteamGroup':
  725. case 'gettingSteamGroupId':
  726. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/groups/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  727. break;
  728.  
  729. case 'joiningSteamOfficialGroup':
  730. case 'leavingSteamOfficialGroup':
  731. case 'gettingSteamOfficialGroupId':
  732. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/games/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  733. break;
  734.  
  735. case 'subscribingForum':
  736. case 'unsubscribingForum':
  737. case 'gettingForumId':
  738. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/app/${text}/discussions/" target="_blank">${text}</a>]...<font></font></li>`);
  739. break;
  740.  
  741. case 'followingCurator':
  742. case 'unfollowingCurator':
  743. case 'gettingCuratorId':
  744. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/${text?.includes('/') ? text : `curator/${text}`}" target="_blank">${text}</a>]...<font></font></li>`);
  745. break;
  746.  
  747. case 'addingToWishlist':
  748. case 'removingFromWishlist':
  749. case 'followingGame':
  750. case 'unfollowingGame':
  751. case 'gettingSubid':
  752. case 'addingFreeLicense':
  753. case 'requestingPlayTestAccess':
  754. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/app/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  755. break;
  756.  
  757. case 'addingFreeLicenseSubid':
  758. ele = $(`<li>${i18n('addingFreeLicense')}[<a href="https://steamdb.info/sub/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  759. break;
  760.  
  761. case 'favoritingWorkshop':
  762. case 'unfavoritingWorkshop':
  763. case 'gettingWorkshopAppId':
  764. case 'votingUpWorkshop':
  765. ele = $(`<li>${i18n(type)}[<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=${text}" target="_blank">
  766. ${text}</a>]...<font></font></li>`);
  767. break;
  768.  
  769. case 'gettingAnnouncementParams':
  770. case 'likingAnnouncement':
  771. ele = $(`<li>${i18n(type)}[<a href="https://store.steampowered.com/news/app/${text}/view/${id}" target="_blank">
  772. ${id}</a>]...<font></font></li>`);
  773. break;
  774.  
  775. case 'joiningDiscordServer':
  776. case 'gettingDiscordGuild':
  777. ele = $(`<li>${i18n(type)}[<a href="https://discord.com/invite/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  778. break;
  779.  
  780. case 'leavingDiscordServer':
  781. ele = $(`<li>${i18n(type)}[<a href="https://discord.com/channels/@me/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  782. break;
  783.  
  784. case 'updateDiscordAuth':
  785. ele = $(`<li style="color:red;">${i18n('updateDiscordAuth')}</li>`);
  786. break;
  787.  
  788. case 'followingTwitchChannel':
  789. case 'unfollowingTwitchChannel':
  790. case 'gettingTwitchChannelId':
  791. ele = $(`<li>${i18n(type)}[<a href="https://www.twitch.tv/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  792. break;
  793.  
  794. case 'gettingInsUserId':
  795. case 'followingIns':
  796. case 'unfollowingIns':
  797. ele = $(`<li>${i18n(type)}[<a href="https://www.instagram.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  798. break;
  799.  
  800. case 'gettingTwitterUserId':
  801. case 'followingTwitterUser':
  802. case 'unfollowingTwitterUser':
  803. ele = $(`<li>${i18n(type)}[<a href="https://x.com/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  804. break;
  805.  
  806. case 'retweetting':
  807. case 'unretweetting':
  808. ele = $(`<li>${i18n(type)}${text}...<font></font></li>`);
  809. break;
  810.  
  811. case 'joiningReddit':
  812. case 'leavingReddit':
  813. ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/r/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  814. break;
  815.  
  816. case 'followingRedditUser':
  817. case 'unfollowingRedditUser':
  818. ele = $(`<li>${i18n(type)}[<a href="https://www.reddit.com/user/${text?.replace('u_', '')}" target="_blank">
  819. ${text?.replace('u_', '')}</a>]...<font></font></li>`);
  820. break;
  821.  
  822. case 'followingYtbChannel':
  823. case 'unfollowingYtbChannel':
  824. ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/channel/${text}" target="_blank">${text}</a>]...<font></font></li>`);
  825. break;
  826.  
  827. case 'likingYtbVideo':
  828. case 'unlikingYtbVideo':
  829. ele = $(`<li>${i18n(type)}[<a href="https://www.youtube.com/watch?v=${text}" target="_blank">${text}</a>]...<font></font></li>`);
  830. break;
  831.  
  832. case 'gettingVkId':
  833. case 'joiningVkGroup':
  834. case 'leavingVkGroup':
  835. case 'joiningVkPublic':
  836. case 'leavingVkPublic':
  837. case 'sendingVkWall':
  838. case 'deletingVkWall':
  839. ele = $(`<li>${i18n(type)}[<a href="https://vk.com/${text}/" target="_blank">${text}</a>]...<font></font></li>`);
  840. break;
  841.  
  842. case 'visitingLink':
  843. ele = $(`<li>${i18n('visitingLink')}[<a href="${text}" target="_blank">${text}</a>]...<font></font></li>`);
  844. break;
  845.  
  846. case 'verifyingInsAuth':
  847. case 'text':
  848. ele = $(`<li>${i18n(text)}<font></font></li>`);
  849. break;
  850.  
  851. case 'html':
  852. ele = $(text || html);
  853. break;
  854.  
  855. case 'whiteList':
  856. ele = $(`<li><font class="warning">${i18n('skipTask')}[${text}(${id})](${i18n('whiteList')})</font></li>`);
  857. break;
  858.  
  859. case 'globalOptionsSkip':
  860. ele = $(`<li>${i18n('skipTaskOption')}<font class="warning">${text}</font></li>`);
  861. break;
  862.  
  863. default:
  864. ele = $(`<li>${i18n('unKnown')}:${type}(${text})...<font></font></li>`);
  865. break;
  866. }
  867. } else if (text) {
  868. ele = $(`<li>${i18n(text)}<font></font></li>`);
  869. } else if (html) {
  870. ele = $(html);
  871. } else {
  872. ele = $('<li><font></font></li>');
  873. }
  874. ele.addClass('card-text');
  875. $('#auto-task-info').append(ele);
  876. ele[0]?.scrollIntoView();
  877. const font = ele.find('font');
  878. const status = {
  879. font: font,
  880. success(text = 'Success', html = false) {
  881. this.font?.attr('class', '').addClass('success');
  882. html ? this.font?.html(text) : this.font?.text(text);
  883. return this;
  884. },
  885. error(text = 'Error', html = false) {
  886. this.font?.attr('class', '').addClass('error');
  887. html ? this.font?.html(text) : this.font?.text(text);
  888. return this;
  889. },
  890. warning(text = 'Warning', html = false) {
  891. this.font?.attr('class', '').addClass('warning');
  892. html ? this.font?.html(text) : this.font?.text(text);
  893. return this;
  894. },
  895. info(text = 'Info', html = false) {
  896. this.font?.attr('class', '').addClass('info');
  897. html ? this.font?.html(text) : this.font?.text(text);
  898. return this;
  899. },
  900. view() {
  901. this.font?.[0].scrollIntoView();
  902. return this;
  903. }
  904. };
  905. return status;
  906. } catch (error) {
  907. throwError(error, 'echoLog');
  908. return emptyStatus;
  909. }
  910. };
  911. const scripts_echoLog = echoLog;
  912. const unique = array => {
  913. try {
  914. return [ ...new Set(array) ];
  915. } catch (error) {
  916. throwError(error, 'unique');
  917. return [];
  918. }
  919. };
  920. const delay = (time = 1e3) => new Promise(resolve => {
  921. setTimeout(() => {
  922. resolve(true);
  923. }, time);
  924. });
  925. const getRedirectLink = async link => {
  926. try {
  927. if (!link) {
  928. return null;
  929. }
  930. const redirectLinksCache = GM_getValue('redirectLinks') || {};
  931. if (redirectLinksCache[link]) {
  932. redirectLinksCache[link];
  933. }
  934. return await tools_httpRequest({
  935. url: link,
  936. method: 'GET'
  937. }).then(({
  938. data
  939. }) => {
  940. if (data?.finalUrl) {
  941. redirectLinksCache[link] = data.finalUrl;
  942. GM_setValue('redirectLinks', redirectLinksCache);
  943. return data.finalUrl;
  944. }
  945. return null;
  946. });
  947. } catch (error) {
  948. throwError(error, 'getRedirectLink');
  949. return null;
  950. }
  951. };
  952. const visitLink = async (link, options) => {
  953. try {
  954. const logStatus = scripts_echoLog({
  955. type: 'visitLink',
  956. text: link
  957. });
  958. return await tools_httpRequest({
  959. url: link,
  960. method: 'GET',
  961. ...options
  962. }).then(({
  963. result,
  964. statusText,
  965. status
  966. }) => {
  967. if (result === 'Success') {
  968. logStatus.success();
  969. return true;
  970. }
  971. logStatus.error(`${result}:${statusText}(${status})`);
  972. return false;
  973. });
  974. } catch (error) {
  975. throwError(error, 'visitLink');
  976. return false;
  977. }
  978. };
  979. const getUrlQuery = url => {
  980. try {
  981. const query = {};
  982. if (url) {
  983. if (url.includes('?')) {
  984. url.split('?')[1].replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => {
  985. query[key] = value;
  986. return str;
  987. });
  988. }
  989. } else {
  990. window.location.search.replace(/([^?&=]+)=([^&]+)/g, (str, key, value) => {
  991. query[key] = value;
  992. return str;
  993. });
  994. }
  995. return query;
  996. } catch (error) {
  997. throwError(error, 'getUrlQuery');
  998. return {};
  999. }
  1000. };
  1001. const getUuid = () => {
  1002. const uuidUrl = URL.createObjectURL(new Blob()).toString();
  1003. return uuidUrl.slice(uuidUrl.lastIndexOf('/') + 1);
  1004. };
  1005. const stringToColour = str => {
  1006. try {
  1007. let hash = 0;
  1008. for (let i = 0; i < str.length; i++) {
  1009. hash = str.charCodeAt(i) + ((hash << 5) - hash);
  1010. }
  1011. let colour = '#';
  1012. for (let i = 0; i < 3; i++) {
  1013. const value = hash >> i * 8 & 255;
  1014. colour += `00${value.toString(16)}`.slice(-2);
  1015. }
  1016. return colour;
  1017. } catch (error) {
  1018. throwError(error, 'stringToColour');
  1019. return '#fff';
  1020. }
  1021. };
  1022. const debug = (log, data) => {
  1023. if (!window.DEBUG) {
  1024. return;
  1025. }
  1026. console.log('%c%s', 'color:#a7a7a7', `Auto-Task[Debug]: ${log}`);
  1027. if (data) {
  1028. console.log('%c%s', 'color:#a7a7a7', 'Auto-Task[Debug]: ', data);
  1029. }
  1030. };
  1031. const defaultGlobalOptions = {
  1032. doTask: {
  1033. discord: {
  1034. servers: true
  1035. },
  1036. instagram: {
  1037. users: true
  1038. },
  1039. twitch: {
  1040. channels: true
  1041. },
  1042. twitter: {
  1043. users: true,
  1044. retweets: true
  1045. },
  1046. vk: {
  1047. names: true
  1048. },
  1049. youtube: {
  1050. channels: true,
  1051. likes: true
  1052. },
  1053. reddit: {
  1054. reddits: true
  1055. },
  1056. steam: {
  1057. groups: true,
  1058. officialGroups: true,
  1059. wishlists: true,
  1060. follows: true,
  1061. forums: true,
  1062. workshops: true,
  1063. curators: true,
  1064. workshopVotes: true,
  1065. announcements: true,
  1066. licenses: true,
  1067. playtests: true
  1068. }
  1069. },
  1070. undoTask: {
  1071. discord: {
  1072. servers: true
  1073. },
  1074. instagram: {
  1075. users: true
  1076. },
  1077. twitch: {
  1078. channels: true
  1079. },
  1080. twitter: {
  1081. users: true,
  1082. retweets: true
  1083. },
  1084. vk: {
  1085. names: true
  1086. },
  1087. youtube: {
  1088. channels: true,
  1089. likes: true
  1090. },
  1091. reddit: {
  1092. reddits: true
  1093. },
  1094. steam: {
  1095. groups: true,
  1096. officialGroups: true,
  1097. wishlists: true,
  1098. follows: true,
  1099. forums: true,
  1100. workshops: true,
  1101. curators: true
  1102. }
  1103. },
  1104. ASF: {
  1105. AsfEnabled: false,
  1106. AsfIpcUrl: '',
  1107. AsfIpcPassword: '',
  1108. AsfBotname: 'asf'
  1109. },
  1110. position: {
  1111. buttonSideX: 'right',
  1112. buttonSideY: 'top',
  1113. buttonDistance: '15,30',
  1114. showButtonSideX: 'right',
  1115. showButtonSideY: 'top',
  1116. showButtonDistance: '15,30',
  1117. logSideX: 'right',
  1118. logSideY: 'bottom',
  1119. logDistance: '10,10'
  1120. },
  1121. hotKey: {
  1122. doTaskKey: 'alt + d',
  1123. undoTaskKey: 'alt + u',
  1124. toggleLogKey: 'alt + l'
  1125. },
  1126. other: {
  1127. twitterVerifyId: '783214',
  1128. youtubeVerifyChannel: 'UCrXUsMBcfTVqwAS7DKg9C0Q',
  1129. autoUpdateSource: 'jsdelivr',
  1130. language: 'zh',
  1131. checkLogin: true,
  1132. checkLeftKey: true,
  1133. defaultShowButton: true,
  1134. defaultShowLog: true,
  1135. debug: false,
  1136. receivePreview: true
  1137. }
  1138. };
  1139. const userDefinedGlobalOptions = GM_getValue('globalOptions') || {};
  1140. const assignObject = (obj1, obj2) => {
  1141. try {
  1142. const newObj = {};
  1143. for (const [ key, value ] of Object.entries(obj1)) {
  1144. if (Object.prototype.toString.call(value) === '[object Object]' && Object.prototype.toString.call(obj2[key]) === '[object Object]') {
  1145. newObj[key] = assignObject(value, obj2[key]);
  1146. } else {
  1147. newObj[key] = obj2[key] ?? value;
  1148. }
  1149. }
  1150. return newObj;
  1151. } catch (error) {
  1152. throwError(error, 'assignObject');
  1153. return defaultGlobalOptions;
  1154. }
  1155. };
  1156. const globalOptions = assignObject(defaultGlobalOptions, userDefinedGlobalOptions);
  1157. const saveData = () => {
  1158. try {
  1159. const data = {};
  1160. $('#globalOptionsForm').serializeArray().map(value => {
  1161. data[value.name] = value.value;
  1162. return value;
  1163. });
  1164. $.makeArray($('#globalOptionsForm input')).map(element => {
  1165. const name = $(element).attr('name');
  1166. const keys = name.split('.');
  1167. if (keys.length === 3) {
  1168. globalOptions[keys[0]][keys[1]][keys[2]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false;
  1169. } else if (keys.length === 2) {
  1170. globalOptions[keys[0]][keys[1]] = data[name] ? data[name] === 'on' ? true : data[name] : data[name] ?? false;
  1171. }
  1172. return element;
  1173. });
  1174. GM_setValue('globalOptions', globalOptions);
  1175. external_Swal_default().fire({
  1176. title: i18n('changeGlobalOptionsSuccess'),
  1177. icon: 'success'
  1178. });
  1179. } catch (error) {
  1180. throwError(error, 'saveData');
  1181. }
  1182. };
  1183. const changeGlobalOptions = showType => {
  1184. try {
  1185. let globalOptionsForm = `<form id="globalOptionsForm" class="auto-task-form">
  1186. <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`;
  1187. for (const [ type, data1 ] of Object.entries(globalOptions)) {
  1188. for (const [ option, data2 ] of Object.entries(data1)) {
  1189. if ([ 'other', 'position', 'hotKey', 'ASF' ].includes(type)) {
  1190. if (typeof data2 === 'boolean') {
  1191. 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>`;
  1192. } else {
  1193. 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>`;
  1194. }
  1195. } else {
  1196. for (const [ socialType, data3 ] of Object.entries(data2)) {
  1197. 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>`;
  1198. }
  1199. }
  1200. }
  1201. }
  1202. globalOptionsForm += '</tbody></table></form>';
  1203. if (showType === 'swal') {
  1204. external_Swal_default().fire({
  1205. title: i18n('globalOptions'),
  1206. html: globalOptionsForm,
  1207. showConfirmButton: true,
  1208. confirmButtonText: i18n('save'),
  1209. showCancelButton: true,
  1210. cancelButtonText: i18n('close')
  1211. }).then(({
  1212. isConfirmed
  1213. }) => {
  1214. if (isConfirmed) {
  1215. saveData();
  1216. }
  1217. });
  1218. } else {
  1219. $('body').append(`<h2>${i18n('globalOptions')}</h2>${globalOptionsForm}`);
  1220. }
  1221. } catch (error) {
  1222. throwError(error, 'changeGlobalOptions');
  1223. }
  1224. };
  1225. const data = {
  1226. website: '网站',
  1227. type: '类型',
  1228. edit: '编辑',
  1229. whiteList: '白名单',
  1230. skipTask: '跳过撤销任务',
  1231. whiteListOptions: '白名单设置',
  1232. changeWhiteListOption: '设置白名单(%0)',
  1233. whiteListNotFound: '找不到此项白名单: %0',
  1234. changeWhiteListSuccess: '白名单修改成功,刷新生效!',
  1235. changeWebsiteOptions: '网站设置',
  1236. changeGlobalOptions: '全局设置',
  1237. ok: '是',
  1238. save: '保存',
  1239. close: '关闭',
  1240. return: '返回',
  1241. option: '选项',
  1242. value: '值',
  1243. websiteOptions: '当前网站设置',
  1244. changeWebsiteOptionsSuccess: '更改当前网站设置成功,刷新生效!',
  1245. changeGlobalOptionsSuccess: '更改全局设置成功,刷新生效!',
  1246. needLogin: '请先登录!',
  1247. getTasksInfo: '正在获取并处理任务信息...',
  1248. gettingKey: '正在获取Key...',
  1249. verifyingTask: '正在验证任务',
  1250. notice: '自动任务脚本提醒',
  1251. noKeysLeft: '此页面已经没有剩余key了,是否关闭?',
  1252. giveawayEnded: '此活动已结束,是否关闭?',
  1253. giveawayNotWork: '此活动因某些原因(已结束/暂停/未开始...)不可用(如果是脚本误判请及时反馈),是否关闭?',
  1254. confirm: '确定',
  1255. cancel: '取消',
  1256. unKnown: '未知',
  1257. unKnownTaskType: '未识别的任务',
  1258. doing: '正在做任务',
  1259. allTasksComplete: '所有任务已完成!',
  1260. getTaskIdFailed: '获取任务Id失败!',
  1261. initSuccess: '%0 初始化成功!',
  1262. initFailed: '%0 初始化失败!',
  1263. errorLink: '链接错误: %0',
  1264. needInit: '请先初始化',
  1265. verifyingAuth: '正在验证%0凭证...',
  1266. updatingAuth: '正在更新%0凭证...',
  1267. refreshingToken: '正在刷新%0凭证...',
  1268. settingToken: '正在设置%0凭证...',
  1269. steamStoreTab: 'Steam商店(弹窗)',
  1270. steamCommunityTab: 'Steam社区(弹窗)',
  1271. initing: '正在初始化...',
  1272. getFailed: '获取%0失败!',
  1273. checkLoginFailed: '检测登录状态失败!',
  1274. checkLeftKeyFailed: '检测剩余Key失败!',
  1275. userId: '用户Id',
  1276. joiningGiveaway: '正在加入赠Key',
  1277. needJoinGiveaway: '需要先加入赠Key',
  1278. cannotUndo: '此网站不支持取消任务',
  1279. verifyAuth: '正在验证 %0 凭证...',
  1280. closePageNotice: '如果此页面没有自动关闭,请自行关闭本页面。',
  1281. errorReport: '检测到脚本报错,是否前往反馈BUG?',
  1282. visitingLink: '正在访问链接: ',
  1283. doTask: '做任务',
  1284. undoTask: '撤销任务',
  1285. verifyTask: '验证任务',
  1286. getKey: '获取Key',
  1287. selectAll: '全选',
  1288. selectNone: '全不选',
  1289. invertSelect: '反选',
  1290. doFreeTask: '加入免费赠品',
  1291. doPointTask: '加入点数赠品',
  1292. skipTaskOption: '设置中已配置跳过任务',
  1293. other: '其他',
  1294. globalOptions: '全局设置',
  1295. checkLogin: '登录检测</br>需要登录的网站自动登录,部分网站支持',
  1296. checkLeftKey: '剩余Key检测</br>赠Key活动结束提示是否关闭,部分网站支持',
  1297. twitterVerifyId: '通过尝试关注该账号验证Twitter凭证</br>默认为Twitter官方帐号 783214</br>不想关注官方账号可以改为自己的帐号',
  1298. youtubeVerifyChannel: '通过尝试订阅该频道验证YouTube凭证</br>默认为YouTube官方频道 UCrXUsMBcfTVqwAS7DKg9C0Q</br>不想关注官方频道可以改为自己的频道',
  1299. autoUpdateSource: '更新源</br>github: 需代理,实时更新</br>jsdelivr: 可不用代理,更新有延迟</br>standby: 备用</br>auto: 依次使用github, jsdelivr, standby源进行尝试更新',
  1300. saveGlobalOptions: '保存设置',
  1301. settingPage: '设置页面',
  1302. name: '名称',
  1303. version: '版本',
  1304. scriptManager: '脚本管理器',
  1305. script: '脚本',
  1306. environment: '环境',
  1307. os: '系统',
  1308. browser: '浏览器',
  1309. getId: '获取 %0 id',
  1310. getTwitterUserId: '获取Twitter用户id(获取id功能仅在设置页面可用)',
  1311. getYoutubeChannelId: '获取Youtube频道id(获取id功能仅在设置页面可用)',
  1312. showButton: '显示按钮',
  1313. hideButton: '隐藏按钮',
  1314. showLog: '显示日志',
  1315. hideLog: '隐藏日志',
  1316. defaultShowButton: '默认显示按钮',
  1317. defaultShowLog: '默认显示日志',
  1318. debug: '输出调试日志,不要开启此选项!',
  1319. receivePreview: '接收预览版更新',
  1320. position: '组件位置',
  1321. buttonSideX: '按钮区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1322. buttonSideY: '按钮区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1323. buttonDistance: '按钮区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1324. showButtonSideX: '显示按钮水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1325. showButtonSideY: '显示按钮垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1326. showButtonDistance: '显示按钮距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1327. logSideX: '日志区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
  1328. logSideY: '日志区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
  1329. logDistance: '日志区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
  1330. hotKey: '快捷键',
  1331. doTaskKey: '做任务快捷键</br>(实时预览功能仅在设置页面可用)',
  1332. undoTaskKey: '撤销任务快捷键</br>(实时预览功能仅在设置页面可用)',
  1333. toggleLogKey: '显示/隐藏日志快捷键</br>(实时预览功能仅在设置页面可用)',
  1334. tasksHistory: '任务历史',
  1335. clearHistory: '清空历史',
  1336. clearHistoryFinished: '已清空任务历史!',
  1337. deleteTask: '删除任务',
  1338. lastChangeTime: '最后一次修改时间',
  1339. clearTaskFinished: '删除以下任务完成!',
  1340. clearTaskFailed: '删除任务失败,没有找到任务名!',
  1341. syncData: '数据同步',
  1342. settingData: '正在上传数据...',
  1343. gettingData: '正在获取数据...',
  1344. help: '帮助',
  1345. fileName: '文件名',
  1346. upload2gist: '同步到Gist',
  1347. downloadFromGist: '从Gist同步',
  1348. saveAndTest: '保存配置并测试',
  1349. testSuccess: '测试成功!',
  1350. testFailed: '测试失败!',
  1351. saveAndTestNotice: '请先保存配置并测试!',
  1352. processingData: '正在处理数据...',
  1353. updatingData: '正在上传数据...',
  1354. syncDataSuccess: '同步数据成功!',
  1355. syncDataFailed: '同步数据失败,请在控制台查看错误信息!',
  1356. downloadingData: '正在下载数据...',
  1357. checkedNoData: '没有检测到远程数据,请确认配置是否正确!',
  1358. savingData: '正在保存数据...',
  1359. syncHistory: '同步任务历史',
  1360. checkUpdateFailed: '检测更新失败',
  1361. newVersionNotice: '检测到新版本V%0, <a class="high-light" href="%1" target="_blank">点此更新</a>',
  1362. language: '语言</br>目前仅支持zh: 中文, en: 英文',
  1363. gistOptions: 'Gist 设置',
  1364. swalNotice: '检测到您第一次安装V4版本脚本,请前往阅读用前必读内容!',
  1365. echoNotice: '检测到您第一次安装V4版本脚本,请<a class="high-light" href="%0" target="_blank">点此前往</a>阅读用前必读内容!',
  1366. noticeLink: 'https://auto-task-doc.js.org/guide/#用前必读',
  1367. toGithub: '前往Github反馈',
  1368. toKeylol: '前往其乐论坛反馈',
  1369. copySuccess: '错误信息已复制到剪切板,是否前往其乐论坛反馈?',
  1370. copyFailed: '请复制下方错误信息后前往Keylol论坛反馈!',
  1371. updateText: '%0 版本更新内容:',
  1372. Active: '进行中',
  1373. Ended: '已结束',
  1374. Banned: '已封禁',
  1375. Paused: '已暂停',
  1376. notStart: '未开始',
  1377. noRemoteData: '检测到远程无数据',
  1378. errorRemoteDataFormat: '远程数据格式错误',
  1379. updateHistory: '历史更新记录<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">点此查看</a>',
  1380. AsfEnabled: '使用ASF做Steam相关任务(需<a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a>插件)',
  1381. AsfIpcUrl: 'ASF IPC 地址',
  1382. AsfIpcPassword: 'ASF IPC 密码',
  1383. versionNotMatched: '脚本管理器版本过低,需TamperMonkey >= 5.2.0或TamperMonkey Beta >= 5.2.6196',
  1384. groups: '组',
  1385. officialGroups: '官方组',
  1386. wishlists: '愿望单',
  1387. follows: '游戏关注',
  1388. forums: '论坛',
  1389. workshops: '创意工坊收藏',
  1390. curators: '鉴赏家',
  1391. workshopVotes: '创意工坊点赞',
  1392. announcements: '社区通知',
  1393. steamCommunity: 'Steam社区',
  1394. steamStore: 'Steam商店',
  1395. licenses: '入库免费游戏',
  1396. playtests: '请求访问权限',
  1397. needLoginSteamStore: '请先<a href="https://store.steampowered.com/login/" target="_blank">登录Steam商店</a>',
  1398. needLoginSteamCommunity: '请先<a href="https://steamcommunity.com/login/home/" target="_blank">登录Steam社区</a>',
  1399. joiningSteamGroup: '正在加入Steam组',
  1400. leavingSteamGroup: '正在退出Steam组',
  1401. gettingSteamGroupId: '正在获取Steam组Id',
  1402. joiningSteamOfficialGroup: '正在加入Steam官方组',
  1403. leavingSteamOfficialGroup: '正在退出Steam官方组',
  1404. gettingSteamOfficialGroupId: '正在获取Steam官方组Id',
  1405. subscribingForum: '正在订阅Steam论坛',
  1406. unsubscribingForum: '正在取消订阅Steam论坛',
  1407. gettingForumId: '正在获取Steam论坛Id',
  1408. followingCurator: '正在关注Steam鉴赏家',
  1409. unfollowingCurator: '正在取关Steam鉴赏家',
  1410. gettingCuratorId: '正在获取Steam鉴赏家Id',
  1411. addingToWishlist: '正在添加游戏到Steam愿望单',
  1412. removingFromWishlist: '正在从Steam愿望单移除游戏',
  1413. followingGame: '正在关注Steam游戏',
  1414. unfollowingGame: '正在取关Steam游戏',
  1415. favoritingWorkshop: '正在收藏Steam创意工坊物品',
  1416. unfavoritingWorkshop: '正在取消收藏Steam创意工坊物品',
  1417. gettingWorkshopAppId: '正在获取Steam创意工坊物品Id',
  1418. votingUpWorkshop: '正在点赞Steam创意工坊物品',
  1419. gettingAnnouncementParams: '正在获取Steam通知信息',
  1420. likingAnnouncement: '正在点赞Steam通知',
  1421. changingArea: '正在更换Steam地区: %0...',
  1422. notNeededChangeArea: '当前地区不需要更换',
  1423. noAnotherArea: '请检测是否开启正确开启代理',
  1424. gettingAreaInfo: '正在获取Steam地区信息...',
  1425. changeAreaNotice: '疑似锁区游戏,尝试换区执行',
  1426. steamFinishNotice: 'Steam任务完成,尝试将购物车地区换回',
  1427. gettingSubid: '正在获取游戏subid',
  1428. addingFreeLicense: '正在入库',
  1429. missParams: '缺少参数',
  1430. gettingLicenses: '正在获取Licenses...',
  1431. requestingPlayTestAccess: '正在请求访问权限',
  1432. tryChangeAreaNotice: '此功能无法检测游戏是否限区,因此会尝试换区后再入库,换区失败也不影响后续入库',
  1433. gettingUserLink: '正在获取Steam用户社区链接...',
  1434. retry: '重试',
  1435. owned: '已拥有',
  1436. redirect: '重定向',
  1437. noSubid: '无法获取,跳过',
  1438. initingASF: '正在初始化ASF...',
  1439. servers: '服务器',
  1440. joiningDiscordServer: '正在加入Discord服务器',
  1441. leavingDiscordServer: '正在退出Discord服务器',
  1442. gettingDiscordGuild: '正在获取Discord服务器Id',
  1443. getDiscordAuthFailed: '获取Discord凭证失败,请检测Discord帐号是否已登录',
  1444. discordImportantNotice: '重要提醒!!!',
  1445. discordImportantNoticeText: '由于Discord网站后台更新,目前使用此脚本加组后可能会导致Discord帐号被强制退出,且需要两步验证才能正常登录,请谨慎使用!!!',
  1446. continue: '继续',
  1447. skipDiscordTask: '跳过Discord任务',
  1448. continueAndDontRemindAgain: '继续且不再提醒',
  1449. users: '用户',
  1450. loginIns: '请先<a href="https://www.instagram.com/accounts/login/" target="_blank">登录Instagram</a>',
  1451. insBanned: '您的Instagram账户已被封禁',
  1452. verifyingInsAuth: '正在验证Instagram凭证...',
  1453. gettingInsUserId: '正在获取Instagram用户Id',
  1454. followingIns: '正在关注Instagram用户',
  1455. unfollowingIns: '正在取关Instagram用户',
  1456. reddits: '社区/用户',
  1457. loginReddit: '请先<a href="https://www.reddit.com/login/" target="_blank">登录Reddit</a>',
  1458. changingRedditVersion: '正在切换Reddit为新版页面...',
  1459. joiningReddit: '正在加入Reddit社区',
  1460. leavingReddit: '正在退出Reddit社区',
  1461. followingRedditUser: '正在关注Reddit用户',
  1462. unfollowingRedditUser: '正在取关Reddit用户',
  1463. channels: '频道',
  1464. followingTwitchChannel: '正在关注Twitch频道',
  1465. unfollowingTwitchChannel: '正在取关Twitch频道',
  1466. gettingTwitchChannelId: '正在获取Twitch频道Id',
  1467. checkingTwitchIntegrity: '正在检查Twitch完整性...',
  1468. twitterUser: '推特用户',
  1469. retweets: '转推',
  1470. gettingTwitterUserId: '正在获取推特用户Id',
  1471. followingTwitterUser: '正在关注推特用户',
  1472. unfollowingTwitterUser: '正在取关推特用户',
  1473. retweetting: '正在转推',
  1474. unretweetting: '正在撤销转推',
  1475. names: '组/社区/动态',
  1476. loginVk: '请先<a href="https://vk.com/login/" target="_blank">登录Vk</a>',
  1477. gettingVkId: '正在获取Vk任务Id',
  1478. joiningVkGroup: '正在加入Vk组',
  1479. leavingVkGroup: '正在退出Vk组',
  1480. joiningVkPublic: '正在加入Vk社区',
  1481. leavingVkPublic: '正在退出Vk社区',
  1482. sendingVkWall: '正在转发Vk动态',
  1483. deletingVkWall: '正在撤销转发Vk动态',
  1484. youtubeChannel: 'YouTube频道',
  1485. likes: '点赞',
  1486. loginYtb: '请先<a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">登录YouTube</a>',
  1487. tryUpdateYtbAuth: '请尝试<a href="https://www.youtube.com/#auth" target="_blank">更新YouTube凭证</a>',
  1488. gettingYtbToken: '正在获取YouTube Token...',
  1489. followingYtbChannel: '正在订阅YouTube频道',
  1490. unfollowingYtbChannel: '正在退订YouTube频道',
  1491. likingYtbVideo: '正在点赞YouTube视频',
  1492. unlikingYtbVideo: '正在取消点赞YouTube视频',
  1493. giveKeyNoticeBefore: '每次验证间隔15s',
  1494. giveKeyNoticeAfter: '如果没有key, 请在<a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>查看',
  1495. noPoints: '点数不够,跳过抽奖',
  1496. getNeedPointsFailed: '获取所需点数失败,跳过抽奖',
  1497. joiningLottery: '正在加入抽奖',
  1498. doingGleamTask: '正在做Gleam任务...',
  1499. gettingGleamLink: '正在获取Gleam任务链接...',
  1500. gleamTaskNotice: '如果此页面长时间未关闭,请完成任一任务后自行关闭!',
  1501. verifiedGleamTasks: '已尝试验证所有任务,验证失败的任务请尝试手动验证或完成!',
  1502. campaign: '检测到人机验证,请完成验证后重新验证任务!',
  1503. gsNotice: '为避免得到"0000-0000-0000"key, 已自动屏蔽"Grab Key"按钮,获取key时请关闭脚本!',
  1504. giveeClubVerifyNotice: '正在验证任务...',
  1505. giveeClubVerifyFinished: '请等待验证完成后自行加入赠Key',
  1506. doingKeyhubTask: '正在做Keyhub任务...',
  1507. SweepWidgetNotice: '正在处理并验证任务,每次验证任务有1~3s间隔防止触发验证过快警告...',
  1508. tasksNotCompleted: '任务未完成',
  1509. notConnect: '社交平台未连接,跳过任务',
  1510. tgTaskNotice: '检测到Telegram任务,需要手动完成',
  1511. confirmingTask: '正在跳过警告页面...'
  1512. };
  1513. const zh_CN = data;
  1514. const en_US_data = {
  1515. website: 'Website',
  1516. type: 'Type',
  1517. edit: 'Edit',
  1518. whiteList: 'Whitelist',
  1519. skipTask: 'Skip undo task',
  1520. whiteListOptions: 'Whitelist options',
  1521. changeWhiteListOption: 'Whitelist option(%0)',
  1522. whiteListNotFound: 'Cannot find this whitelist: %0',
  1523. changeWhiteListSuccess: 'The whitelist is successfully modified, and the page refresh will take effect!',
  1524. changeWebsiteOptions: 'Website options',
  1525. changeGlobalOptions: 'Global options',
  1526. ok: 'OK',
  1527. save: 'Save',
  1528. close: 'Close',
  1529. return: 'Return',
  1530. option: 'Option',
  1531. value: 'Value',
  1532. websiteOptions: 'Current website settings',
  1533. changeWebsiteOptionsSuccess: 'The current website setting is changed successfully, and the page refresh will take effect!',
  1534. changeGlobalOptionsSuccess: 'The global setting is changed successfully, and the refresh will take effect!',
  1535. needLogin: 'Please log in first!',
  1536. getTasksInfo: 'Obtaining and processing task information...',
  1537. gettingKey: 'Getting Key...',
  1538. verifyingTask: 'Verifying task',
  1539. notice: 'Automatic task script notice',
  1540. noKeysLeft: 'There are no more keys left on this page. Do you want to close it?',
  1541. giveawayEnded: 'This event has ended, do you want to close it?',
  1542. 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?',
  1543. confirm: 'Confirm',
  1544. cancel: 'Cancel',
  1545. unKnown: 'Unknown',
  1546. unKnownTaskType: 'Unrecognized task',
  1547. doing: 'Doing a task',
  1548. allTasksComplete: 'All tasks have been completed!',
  1549. getTaskIdFailed: 'Failed to obtain task Id!',
  1550. initSuccess: '%0 was initialized successfully!',
  1551. initFailed: '%0 initialization failed!',
  1552. errorLink: 'Link error: %0',
  1553. needInit: 'Please initialize first',
  1554. verifyingAuth: 'Verifying %0 token...',
  1555. updatingAuth: 'Update %0 token...',
  1556. refreshingToken: 'Refreshing %0 token...',
  1557. settingToken: 'Setting %0 token...',
  1558. steamStoreTab: 'Steam store (new tab)',
  1559. steamCommunityTab: 'Steam community(new tab)',
  1560. initing: 'Initializing...',
  1561. getFailed: 'Failed to get %0!',
  1562. checkLoginFailed: 'Failed to detect login status!',
  1563. checkLeftKeyFailed: 'Failed to detect the remaining keys!',
  1564. userId: 'User Id',
  1565. joiningGiveaway: 'Joining giveaway',
  1566. needJoinGiveaway: 'Need to join the giveaway first',
  1567. cannotUndo: 'This website does not support canceling tasks',
  1568. verifyAuth: 'Verifying %0 token...',
  1569. closePageNotice: 'f this page does not close automatically, please close this page yourself.',
  1570. errorReport: 'A script error is detected, do you want to report the BUG?',
  1571. visitingLink: 'Visiting link: ',
  1572. doTask: 'DoTask',
  1573. undoTask: 'UndoTask',
  1574. verifyTask: 'Verify',
  1575. getKey: 'GetKey',
  1576. selectAll: 'SelectAll',
  1577. selectNone: 'SelectNone',
  1578. invertSelect: 'InvertSelect',
  1579. doFreeTask: 'FreeTask',
  1580. doPointTask: 'PointTask',
  1581. skipTaskOption: 'Skip task has been configured in the settings',
  1582. other: 'Other',
  1583. globalOptions: 'Global Options',
  1584. checkLogin: 'Login detection</br>Need to log in to the website automatically log in, part of this website supports.',
  1585. checkLeftKey: 'Key remaining detection</br>The end of the giveaway event prompts whether to close or not, part of this website supports.',
  1586. 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.',
  1587. 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.',
  1588. 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.',
  1589. saveGlobalOptions: 'SaveSettings',
  1590. settingPage: 'Setting Page',
  1591. name: 'Name',
  1592. version: 'Version',
  1593. scriptManager: 'Script Manager',
  1594. script: 'Script',
  1595. environment: 'Environment',
  1596. os: 'OS',
  1597. browser: 'Browser',
  1598. getId: 'Get %0 id',
  1599. getTwitterUserId: 'Get Twitter user id (Get id function is only available on the settings page).',
  1600. getYoutubeChannelId: 'Get Youtube channel id (Get id function is only available on the settings page).',
  1601. showButton: 'ShowButton',
  1602. hideButton: 'HideButton',
  1603. showLog: 'ShowLog',
  1604. hideLog: 'HideLog',
  1605. defaultShowButton: 'Default display button',
  1606. defaultShowLog: 'Display log by default',
  1607. debug: 'Output debug log, do not enable this option!',
  1608. receivePreview: 'Receive preview updates',
  1609. position: 'Component position',
  1610. buttonSideX: 'Horizontal positioning of the button area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  1611. 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',
  1612. 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',
  1613. showButtonSideX: 'ShowButton horizontal positioning (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  1614. showButtonSideY: 'ShowButton vertical positioning (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
  1615. 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',
  1616. logSideX: 'Horizontal positioning of the log area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
  1617. logSideY: 'Vertical positioning of the log area (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
  1618. 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',
  1619. hotKey: 'Shortcut key',
  1620. doTaskKey: 'DoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
  1621. undoTaskKey: 'UndoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
  1622. toggleLogKey: 'ShowLog/HideLog shortcut keys</br> (real-time preview function is only available on the settings page).',
  1623. tasksHistory: 'TasksHistory',
  1624. clearHistory: 'Clear history',
  1625. clearHistoryFinished: 'The mission history has been cleared!',
  1626. deleteTask: 'Delete task',
  1627. lastChangeTime: 'Last Change Time',
  1628. clearTaskFinished: 'Delete the following tasks completed!',
  1629. clearTaskFailed: 'Failed to delete the task, the task name was not found!',
  1630. syncData: 'DataSync',
  1631. settingData: 'Uploading data...',
  1632. gettingData: 'Getting data...',
  1633. help: 'Help',
  1634. fileName: 'Filename',
  1635. upload2gist: 'Sync to Gist',
  1636. downloadFromGist: 'Sync from Gist',
  1637. saveAndTest: 'Save configuration and test',
  1638. testSuccess: 'Test success!',
  1639. testFailed: 'Test failed!',
  1640. saveAndTestNotice: 'Please save the configuration and test first!',
  1641. processingData: 'Processing data...',
  1642. updatingData: 'Uploading data...',
  1643. syncDataSuccess: 'Synchronized data successfully!',
  1644. syncDataFailed: 'Failed to synchronize data, please check the error message on the console!',
  1645. downloadingData: 'Downloading data...',
  1646. checkedNoData: 'No remote data is detected, please confirm whether the configuration is correct!',
  1647. savingData: 'Saving data...',
  1648. syncHistory: 'Synchronize tasks history',
  1649. checkUpdateFailed: 'Check update failed',
  1650. newVersionNotice: 'Checked a new version V%0, <a class="high-light" href="%1" target="_blank">click to update</a>',
  1651. language: 'Language</br> Currently only supports zh: Chinese, en: English',
  1652. gistOptions: 'Gist Settings',
  1653. 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!',
  1654. 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!',
  1655. noticeLink: 'https://auto-task-doc.js.org/en/guide/#read-me-first',
  1656. toGithub: 'Feedback(Github)',
  1657. toKeylol: 'Feedback(Keylol)',
  1658. copySuccess: 'The error message has been copied to the clipboard. Do you want to go to the Keylol forum to give feedback?',
  1659. copyFailed: 'Please copy the error information below and report back to the Keylol forum!',
  1660. updateText: 'Updates in version %0:',
  1661. Active: 'Active',
  1662. Ended: 'Ended',
  1663. Banned: 'Banned',
  1664. Paused: 'Paused',
  1665. notStart: 'notStart',
  1666. noRemoteData: 'No data remotely',
  1667. errorRemoteDataFormat: 'Remote data has wrong format',
  1668. updateHistory: '<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">Click here</a>' + ' to view the historical update record.',
  1669. AsfEnabled: 'Use ASF to do Steam related tasks (requires <a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a> plugin)',
  1670. AsfIpcUrl: 'ASF IPC URL',
  1671. AsfIpcPassword: 'ASF IPC Password',
  1672. groups: 'Group',
  1673. officialGroups: 'Official Group',
  1674. wishlists: 'Wishlist',
  1675. follows: 'Follow Game',
  1676. forums: 'Forum',
  1677. workshops: 'Favorite Workshop',
  1678. curators: 'Curator',
  1679. workshopVotes: 'Voteup Workshop',
  1680. announcements: 'Announcement',
  1681. steamCommunity: 'Steam Community',
  1682. steamStore: 'Steam Store',
  1683. licenses: 'Add License',
  1684. playtests: 'Playtest Access',
  1685. needLoginSteamStore: 'Please <a href="https://store.steampowered.com/login/" target="_blank">log in to the Steam Store</a>',
  1686. needLoginSteamCommunity: 'Please <a href="https://steamcommunity.com/login/home/" target="_blank">log in to the Steam Community</a>',
  1687. joiningSteamGroup: 'Joining Steam Group',
  1688. leavingSteamGroup: 'Leaving Steam Group',
  1689. gettingSteamGroupId: 'Getting Steam Group Id',
  1690. joiningSteamOfficialGroup: 'Joining Steam Official Group',
  1691. leavingSteamOfficialGroup: 'Leaving Steam Official Group',
  1692. gettingSteamOfficialGroupId: 'Getting Steam Official Group Id',
  1693. subscribingForum: 'Subscribing the Steam Forum',
  1694. unsubscribingForum: 'Unsubscribing the Steam Forum',
  1695. gettingForumId: 'Getting Steam Forum Id',
  1696. followingCurator: 'Following Steam Curator',
  1697. unfollowingCurator: 'Unfollowing Steam Curator',
  1698. gettingCuratorId: 'Getting Steam Curator Id',
  1699. addingToWishlist: 'Adding the game to the Steam wishlist',
  1700. removingFromWishlist: 'Removing the game from the Steam wishlist',
  1701. followingGame: 'Following Steam games',
  1702. unfollowingGame: 'Unfollowing Steam games',
  1703. favoritingWorkshop: 'Favouring Steam Workshop Items',
  1704. unfavoritingWorkshop: 'Unfavoriting Steam Workshop Items',
  1705. gettingWorkshopAppId: 'Getting Steam Workshop Item Id',
  1706. votingUpWorkshop: 'Liking Steam workshop items',
  1707. gettingAnnouncementParams: 'Getting Steam announcement information',
  1708. likingAnnouncement: 'Liking Steam announcement',
  1709. changingArea: 'Changing Steam area: %0...',
  1710. notNeededChangeArea: 'The current area does not need to be changed',
  1711. noAnotherArea: 'Please check whether the proxy is turned on correctly',
  1712. gettingAreaInfo: 'Getting Steam area information...',
  1713. changeAreaNotice: 'Suspected of a locked zone game, try to change the zone to execute',
  1714. steamFinishNotice: 'Steam task completed, try to change the shopping cart area back to ',
  1715. gettingSubid: 'Getting subid',
  1716. addingFreeLicense: 'Adding free license',
  1717. missParams: 'Missing parameters',
  1718. gettingLicenses: 'Getting licenses...',
  1719. requestingPlayTestAccess: 'Requesting play test access',
  1720. 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.',
  1721. versionNotMatched: 'The script manager version is too low, requiring TamperMonkey >= 5.2.0 or TamperMonkey Beta >= 5.2.6196',
  1722. gettingUserLink: 'Getting steam user community link...',
  1723. retry: 'Retry',
  1724. owned: 'Owned',
  1725. redirect: 'Redirect',
  1726. noSubid: 'skip due to unrecognized',
  1727. initingASF: 'Initing ASF...',
  1728. servers: 'Server',
  1729. joiningDiscordServer: 'Joining Discord Server',
  1730. leavingDiscordServer: 'Leaving Discord Server',
  1731. gettingDiscordGuild: 'Getting Discord server Id',
  1732. getDiscordAuthFailed: 'Failed to get Discord token, please check whether the Discord account is logged in',
  1733. discordImportantNotice: 'Important Reminder! ! !',
  1734. 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! ! !',
  1735. continue: 'Continue',
  1736. skipDiscordTask: 'Skip',
  1737. continueAndDontRemindAgain: 'Continue without Reminders',
  1738. users: 'User',
  1739. loginIns: 'Please <a href="https://www.instagram.com/accounts/login/" target="_blank">log in to Instagram</a>',
  1740. insBanned: 'Your Instagram account has been banned',
  1741. verifyingInsAuth: 'Verifying Instagram token...',
  1742. gettingInsUserId: 'Getting Instagram user Id',
  1743. followingIns: 'Following Instagram user',
  1744. unfollowingIns: 'Unfollowing Instagram user',
  1745. reddits: 'Reddit/User',
  1746. loginReddit: 'Please <a href="https://www.reddit.com/login/" target="_blank">log in to Reddit</a>',
  1747. changingRedditVersion: 'Switching Reddit to a new version page...',
  1748. joiningReddit: 'Joining the Reddit',
  1749. leavingReddit: 'Leaving the Reddit',
  1750. followingRedditUser: 'Following Reddit User',
  1751. unfollowingRedditUser: 'Unfollowing Reddit User',
  1752. channels: 'Channel',
  1753. followingTwitchChannel: 'Following Twitch Channel',
  1754. unfollowingTwitchChannel: 'Unfollowing Twitch Channel',
  1755. gettingTwitchChannelId: 'Getting Twitch Channel Id',
  1756. checkingTwitchIntegrity: 'Checking Twitch integrity...',
  1757. twitterUser: 'Twitter User',
  1758. retweets: 'Retweet',
  1759. gettingTwitterUserId: 'Getting Twitter User Id',
  1760. followingTwitterUser: 'Following Twitter User',
  1761. unfollowingTwitterUser: 'Unfollowing Twitter User',
  1762. retweetting: 'Retweetting',
  1763. unretweetting: 'Unretweetting',
  1764. names: 'Group/Public/Wall',
  1765. loginVk: 'Please <a href="https://vk.com/login/" target="_blank">log in to Vk</a>',
  1766. gettingVkId: 'Getting Vk task Id',
  1767. joiningVkGroup: 'Joining Vk Group',
  1768. leavingVkGroup: 'Leaving Vk Group',
  1769. joiningVkPublic: 'Joining Vk Public',
  1770. leavingVkPublic: 'Leaving Vk Public',
  1771. sendingVkWall: 'Sending Vk Wall',
  1772. deletingVkWall: 'Deleting Vk Wall',
  1773. youtubeChannel: 'YouTube Channel',
  1774. likes: 'Like',
  1775. loginYtb: 'Please <a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">log in to YouTube</a>',
  1776. tryUpdateYtbAuth: 'Please try to <a href="https://www.youtube.com/#auth" target="_blank">update YouTube token</a>',
  1777. gettingYtbToken: 'Getting YouTube Token...',
  1778. followingYtbChannel: 'Subscribing to YouTube channel',
  1779. unfollowingYtbChannel: 'Unsubscribing to YouTube channel',
  1780. likingYtbVideo: 'Liking YouTube video',
  1781. unlikingYtbVideo: 'Unliking YouTube video',
  1782. giveKeyNoticeBefore: 'Each verification interval is 15s',
  1783. giveKeyNoticeAfter: 'If there is no key, please check at <a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>',
  1784. noPoints: 'Not enough points, skip the lottery',
  1785. getNeedPointsFailed: 'ailed to obtain the required points, skip the lottery',
  1786. joiningLottery: 'Joining the lottery',
  1787. doingGleamTask: 'Doing Gleam Task...',
  1788. gettingGleamLink: 'Getting Gleam task link...',
  1789. gleamTaskNotice: 'If this page has not been closed for a long time, please close it yourself after completing any task!',
  1790. verifiedGleamTasks: 'Attempted to verify all tasks. If the verification fails, please try to verify manually or complete it!',
  1791. campaign: 'ReCAPTCHA detected, please complete it and re-verify the tasks!',
  1792. 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!',
  1793. giveeClubVerifyNotice: 'Verifying task...',
  1794. giveeClubVerifyFinished: 'Wait for the verification to complete and join it by yourself',
  1795. doingKeyhubTask: 'Doing Keyhub Task...',
  1796. 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...',
  1797. tasksNotCompleted: 'Tasks Not Completed',
  1798. notConnect: 'Social platform is not connectted, skip',
  1799. tgTaskNotice: 'The telegram task is checked, need to do it yourself!',
  1800. confirmingTask: 'Confirming task...'
  1801. };
  1802. const en_US = en_US_data;
  1803. const languages = {
  1804. zh: zh_CN,
  1805. en: en_US
  1806. };
  1807. const language = [ 'zh', 'en' ].includes(globalOptions.other.language) ? globalOptions.other.language : 'en';
  1808. const I18n = (key, ...argvs) => {
  1809. if (!languages[language]?.[key]) {
  1810. return key;
  1811. }
  1812. return languages[language][key].replace(/%([\d]+)/g, (match, index) => argvs[parseInt(index, 10)]);
  1813. };
  1814. const i18n = I18n;
  1815. function throwError(error, name) {
  1816. if (window.TRACE) {
  1817. console.trace('%cAuto-Task[Debug]:', 'color:blue');
  1818. }
  1819. external_Swal_default().fire({
  1820. title: i18n('errorReport'),
  1821. icon: 'error',
  1822. showCancelButton: true,
  1823. confirmButtonText: i18n('toGithub'),
  1824. showDenyButton: true,
  1825. denyButtonText: i18n('toKeylol'),
  1826. cancelButtonText: i18n('close')
  1827. }).then(({
  1828. isDenied,
  1829. isConfirmed
  1830. }) => {
  1831. if (isConfirmed) {
  1832. 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,
  1833. 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'))}`, {
  1834. active: true
  1835. });
  1836. } else if (isDenied) {
  1837. const text = `错误链接: [url=${window.location.href}]${window.location.href}[/url]
  1838.  
  1839. 环境:
  1840.  
  1841. [code]${JSON.stringify((0, javascript_utils_umd_min.ua)(), null, 4)}[/code]
  1842.  
  1843. 脚本管理器: ${GM_info.scriptHandler} ${GM_info.version}
  1844. 脚本版本: ${GM_info.script.version}
  1845.  
  1846. 报错信息:
  1847. [code]${error.stack}[/code]
  1848.  
  1849. 执行日志:
  1850. [code]${$.makeArray($('#auto-task-info>li')).map(element => element.innerText).join('\n')}[/code]`;
  1851. GM_setClipboard(text);
  1852. external_Swal_default().fire({
  1853. title: i18n('copySuccess'),
  1854. icon: 'success',
  1855. confirmButtonText: i18n('ok')
  1856. }).then(() => {
  1857. GM_openInTab('https://keylol.com/forum.php?mod=post&action=reply&fid=319&tid=777450', {
  1858. active: true
  1859. });
  1860. });
  1861. }
  1862. });
  1863. console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: ${name}\n${error.stack}`);
  1864. }
  1865. class Social {
  1866. tasks;
  1867. getRealParams(name, links, doTask, link2param) {
  1868. try {
  1869. let realParams = [];
  1870. if (links.length > 0) {
  1871. realParams = [ ...realParams, ...links.map(link => link2param(link)).filter(link => link) ];
  1872. }
  1873. if (!doTask && this.tasks[name].length > 0) {
  1874. realParams = [ ...realParams, ...this.tasks[name] ];
  1875. }
  1876. return unique(realParams);
  1877. } catch (error) {
  1878. throwError(error, 'Social.getRealParams');
  1879. return [];
  1880. }
  1881. }
  1882. }
  1883. const social_Social = Social;
  1884. class Discord extends social_Social {
  1885. tasks;
  1886. whiteList;
  1887. #auth = GM_getValue('discordAuth') || {};
  1888. #cache = GM_getValue('discordCache') || {};
  1889. #initialized = false;
  1890. constructor() {
  1891. super();
  1892. const defaultTasksTemplate = {
  1893. servers: []
  1894. };
  1895. this.tasks = defaultTasksTemplate;
  1896. this.whiteList = {
  1897. ...defaultTasksTemplate,
  1898. ...GM_getValue('whiteList')?.discord || {}
  1899. };
  1900. }
  1901. async init(action) {
  1902. try {
  1903. if (!GM_getValue('dontRemindDiscordAgain')) {
  1904. const result = await external_Swal_default().fire({
  1905. title: i18n('discordImportantNotice'),
  1906. text: i18n('discordImportantNoticeText'),
  1907. showCancelButton: true,
  1908. showDenyButton: true,
  1909. confirmButtonText: i18n('continue'),
  1910. cancelButtonText: i18n('skipDiscordTask'),
  1911. denyButtonText: i18n('continueAndDontRemindAgain')
  1912. }).then(({
  1913. isConfirmed,
  1914. isDenied
  1915. }) => {
  1916. if (isConfirmed) {
  1917. return true;
  1918. }
  1919. if (isDenied) {
  1920. GM_setValue('dontRemindDiscordAgain', true);
  1921. return true;
  1922. }
  1923. return false;
  1924. });
  1925. if (!result) {
  1926. this.#initialized = false;
  1927. return 'skip';
  1928. }
  1929. }
  1930. if (GM_getValue('dontRemindDiscordAgain') || action === 'do' && !globalOptions.doTask.discord.servers || action === 'undo' && !globalOptions.undoTask.discord.servers) {
  1931. this.#initialized = false;
  1932. return 'skip';
  1933. }
  1934. if (this.#initialized) {
  1935. return true;
  1936. }
  1937. if (!this.#auth.auth) {
  1938. if (await this.#updateAuth()) {
  1939. this.#initialized = true;
  1940. return true;
  1941. }
  1942. return false;
  1943. }
  1944. const isVerified = await this.#verifyAuth();
  1945. if (isVerified) {
  1946. scripts_echoLog({}).success(i18n('initSuccess', 'Discord'));
  1947. this.#initialized = true;
  1948. return true;
  1949. }
  1950. GM_setValue('discordAuth', {
  1951. auth: null
  1952. });
  1953. if (await this.#updateAuth()) {
  1954. scripts_echoLog({}).success(i18n('initSuccess', 'Discord'));
  1955. this.#initialized = true;
  1956. return true;
  1957. }
  1958. scripts_echoLog({}).error(i18n('initFailed', 'Discord'));
  1959. return false;
  1960. } catch (error) {
  1961. throwError(error, 'Discord.init');
  1962. return false;
  1963. }
  1964. }
  1965. async #verifyAuth() {
  1966. try {
  1967. const logStatus = scripts_echoLog({
  1968. text: i18n('verifyingAuth', 'Discord')
  1969. });
  1970. const {
  1971. result,
  1972. statusText,
  1973. status,
  1974. data
  1975. } = await tools_httpRequest({
  1976. url: 'https://discord.com/api/v6/users/@me',
  1977. method: 'HEAD',
  1978. headers: {
  1979. authorization: this.#auth.auth
  1980. }
  1981. });
  1982. if (result === 'Success') {
  1983. if (data?.status === 200) {
  1984. logStatus.success();
  1985. return true;
  1986. }
  1987. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  1988. return false;
  1989. }
  1990. logStatus.error(`${result}:${statusText}(${status})`);
  1991. return false;
  1992. } catch (error) {
  1993. throwError(error, 'Discord.verifyAuth');
  1994. return false;
  1995. }
  1996. }
  1997. async #updateAuth() {
  1998. try {
  1999. const logStatus = scripts_echoLog({
  2000. text: i18n('updatingAuth', 'Discord')
  2001. });
  2002. return await new Promise(resolve => {
  2003. const newTab = GM_openInTab('https://discord.com/channels/@me', {
  2004. active: true,
  2005. insert: true,
  2006. setParent: true
  2007. });
  2008. newTab.name = 'ATv4_discordAuth';
  2009. newTab.onclose = async () => {
  2010. const auth = GM_getValue('discordAuth')?.auth;
  2011. if (auth) {
  2012. this.#auth = {
  2013. auth: auth
  2014. };
  2015. logStatus.success();
  2016. resolve(await this.#verifyAuth());
  2017. } else {
  2018. logStatus.error('Error: Update discord auth failed!');
  2019. resolve(false);
  2020. }
  2021. };
  2022. });
  2023. } catch (error) {
  2024. throwError(error, 'Discord.updateAuth');
  2025. return false;
  2026. }
  2027. }
  2028. async #joinServer(inviteId) {
  2029. try {
  2030. const logStatus = scripts_echoLog({
  2031. type: 'joiningDiscordServer',
  2032. text: inviteId
  2033. });
  2034. const {
  2035. result,
  2036. statusText,
  2037. status,
  2038. data
  2039. } = await tools_httpRequest({
  2040. url: `https://discord.com/api/v9/invites/${inviteId}`,
  2041. method: 'POST',
  2042. dataType: 'json',
  2043. headers: {
  2044. authorization: this.#auth.auth,
  2045. origin: 'https://discord.com',
  2046. referer: `https://discord.com/invite/${inviteId}`
  2047. }
  2048. });
  2049. if (result === 'Success' && data?.status === 200) {
  2050. logStatus.success();
  2051. const guild = String(data.response?.guild?.id);
  2052. if (guild) {
  2053. this.#setCache(inviteId, guild);
  2054. this.tasks.servers = unique([ ...this.tasks.servers, inviteId ]);
  2055. }
  2056. return true;
  2057. }
  2058. logStatus.error(`${result}:${statusText}(${status})`);
  2059. return false;
  2060. } catch (error) {
  2061. throwError(error, 'Discord.joinServer');
  2062. return false;
  2063. }
  2064. }
  2065. async #leaveServer(inviteId) {
  2066. try {
  2067. if (this.whiteList.servers.includes(inviteId)) {
  2068. scripts_echoLog({
  2069. type: 'whiteList',
  2070. text: 'Discord.leaveServer',
  2071. id: inviteId
  2072. });
  2073. return true;
  2074. }
  2075. const guild = await this.#getGuild(inviteId);
  2076. if (!guild) {
  2077. return false;
  2078. }
  2079. const logStatus = scripts_echoLog({
  2080. type: 'leavingDiscordServer',
  2081. text: guild
  2082. });
  2083. const {
  2084. result,
  2085. statusText,
  2086. status,
  2087. data
  2088. } = await tools_httpRequest({
  2089. url: `https://discord.com/api/v9/users/@me/guilds/${guild}`,
  2090. method: 'DELETE',
  2091. headers: {
  2092. authorization: this.#auth.auth
  2093. }
  2094. });
  2095. if (result === 'Success' && data?.status === 204) {
  2096. logStatus.success();
  2097. return true;
  2098. }
  2099. logStatus.error(`${result}:${statusText}(${status})`);
  2100. return false;
  2101. } catch (error) {
  2102. throwError(error, 'Discord.leaveServer');
  2103. return false;
  2104. }
  2105. }
  2106. async #getGuild(inviteId) {
  2107. try {
  2108. const logStatus = scripts_echoLog({
  2109. type: 'gettingDiscordGuild',
  2110. text: inviteId
  2111. });
  2112. const guild = this.#cache[inviteId];
  2113. if (guild) {
  2114. logStatus.success();
  2115. return guild;
  2116. }
  2117. const {
  2118. result,
  2119. statusText,
  2120. status,
  2121. data
  2122. } = await tools_httpRequest({
  2123. url: `https://discord.com/api/v9/invites/${inviteId}`,
  2124. responseType: 'json',
  2125. method: 'GET'
  2126. });
  2127. if (result === 'Success' && data?.status === 200) {
  2128. const guild = data.response?.guild?.id;
  2129. if (guild) {
  2130. logStatus.success();
  2131. this.#setCache(inviteId, guild);
  2132. return guild;
  2133. }
  2134. logStatus.error(`${result}:${statusText}(${status})`);
  2135. return false;
  2136. }
  2137. logStatus.error(`${result}:${statusText}(${status})`);
  2138. return false;
  2139. } catch (error) {
  2140. throwError(error, 'Discord.getGuild');
  2141. return false;
  2142. }
  2143. }
  2144. async toggle({
  2145. doTask = true,
  2146. serverLinks = []
  2147. }) {
  2148. try {
  2149. if (!this.#initialized) {
  2150. scripts_echoLog({
  2151. text: i18n('needInit')
  2152. });
  2153. return false;
  2154. }
  2155. const prom = [];
  2156. if (doTask && !globalOptions.doTask.discord.servers || !doTask && !globalOptions.undoTask.discord.servers) {
  2157. scripts_echoLog({
  2158. type: 'globalOptionsSkip',
  2159. text: 'discord.servers'
  2160. });
  2161. } else {
  2162. const realServers = this.getRealParams('servers', serverLinks, doTask, link => link.match(/invite\/(.+)/)?.[1]);
  2163. if (realServers.length > 0) {
  2164. for (const server of realServers) {
  2165. if (doTask) {
  2166. prom.push(this.#joinServer(server));
  2167. } else {
  2168. prom.push(this.#leaveServer(server));
  2169. }
  2170. await delay(1e3);
  2171. }
  2172. }
  2173. }
  2174. return await Promise.all(prom).then(() => true);
  2175. } catch (error) {
  2176. throwError(error, 'Discord.toggleServers');
  2177. return false;
  2178. }
  2179. }
  2180. #setCache(inviteId, guild) {
  2181. try {
  2182. this.#cache[inviteId] = guild;
  2183. GM_setValue('discordCache', this.#cache);
  2184. } catch (error) {
  2185. throwError(error, 'Discord.setCache');
  2186. }
  2187. }
  2188. }
  2189. const social_Discord = Discord;
  2190. class Instagram extends social_Social {
  2191. tasks;
  2192. whiteList;
  2193. #cache = GM_getValue('instagramCache') || {};
  2194. #auth = {};
  2195. #initialized = false;
  2196. constructor() {
  2197. super();
  2198. const defaultTasksTemplate = {
  2199. users: []
  2200. };
  2201. this.tasks = defaultTasksTemplate;
  2202. this.whiteList = {
  2203. ...defaultTasksTemplate,
  2204. ...GM_getValue('whiteList')?.instagram || {}
  2205. };
  2206. }
  2207. async init() {
  2208. try {
  2209. if (this.#initialized) {
  2210. return true;
  2211. }
  2212. const isVerified = await this.#getUserInfo();
  2213. if (isVerified) {
  2214. scripts_echoLog({}).success(i18n('initSuccess', 'Instagram'));
  2215. this.#initialized = true;
  2216. return true;
  2217. }
  2218. scripts_echoLog({}).error(i18n('initFailed', 'Instagram'));
  2219. return false;
  2220. } catch (error) {
  2221. throwError(error, 'Instagram.init');
  2222. return false;
  2223. }
  2224. }
  2225. async #getUserInfo(name = 'instagram') {
  2226. try {
  2227. const logStatus = scripts_echoLog({
  2228. type: name === 'instagram' ? 'verifyingInsAuth' : 'gettingInsUserId',
  2229. text: name
  2230. });
  2231. const userId = this.#cache[name];
  2232. if (userId && name !== 'instagram') {
  2233. logStatus.success();
  2234. return userId;
  2235. }
  2236. const {
  2237. result,
  2238. statusText,
  2239. status,
  2240. data
  2241. } = await tools_httpRequest({
  2242. url: `https://www.instagram.com/${name}/`,
  2243. method: 'GET'
  2244. });
  2245. if (result === 'Success') {
  2246. if (data?.finalUrl.includes('accounts/login')) {
  2247. logStatus.error(`Error:${i18n('loginIns')}`, true);
  2248. return false;
  2249. } else if (data?.finalUrl.includes('www.instagram.com/challenge')) {
  2250. logStatus.error(`Error:${i18n('insBanned')}`);
  2251. return false;
  2252. }
  2253. if (data?.status === 200) {
  2254. const csrftoken = data.responseText.match(/"csrf_token":"(.+?)"/)?.[1];
  2255. const hash = data.responseText.match(/"rollout_hash":"(.+?)"/)?.[1];
  2256. if (name === 'instagram') {
  2257. if (csrftoken && hash) {
  2258. this.#auth = {
  2259. csrftoken: csrftoken,
  2260. hash: hash
  2261. };
  2262. return true;
  2263. }
  2264. return false;
  2265. }
  2266. const id = data.responseText.match(/"profilePage_([\d]+?)"/)?.[1];
  2267. if (id) {
  2268. this.#setCache(name, id);
  2269. logStatus.success();
  2270. return id;
  2271. }
  2272. logStatus.error('Error: Get ins data error!');
  2273. return false;
  2274. }
  2275. logStatus.error(`${result}:${statusText}(${status})`);
  2276. return false;
  2277. }
  2278. return false;
  2279. } catch (error) {
  2280. throwError(error, 'Instagram.getUserInfo');
  2281. return false;
  2282. }
  2283. }
  2284. async #followUser(name) {
  2285. try {
  2286. const id = await this.#getUserInfo(name);
  2287. if (!id) {
  2288. return false;
  2289. }
  2290. const logStatus = scripts_echoLog({
  2291. type: 'followingIns',
  2292. text: name
  2293. });
  2294. const {
  2295. result,
  2296. statusText,
  2297. status,
  2298. data
  2299. } = await tools_httpRequest({
  2300. url: `https://www.instagram.com/web/friendships/${id}/follow/`,
  2301. method: 'POST',
  2302. dataType: 'json',
  2303. headers: {
  2304. 'x-csrftoken': this.#auth.csrftoken,
  2305. origin: 'https://www.instagram.com',
  2306. referer: `https://www.instagram.com/${name}/`,
  2307. 'content-type': 'application/x-www-form-urlencoded',
  2308. 'sec-fetch-site': 'same-origin',
  2309. 'x-instagram-ajax': this.#auth.hash
  2310. }
  2311. });
  2312. if (result === 'Success') {
  2313. if (data?.status === 200 && data.response?.result === 'following') {
  2314. logStatus.success();
  2315. this.tasks.users = unique([ ...this.tasks.users, name ]);
  2316. return true;
  2317. }
  2318. logStatus.error(`Error:${data?.response?.feedback_message || `${data?.statusText}(${data?.status})`}`);
  2319. return false;
  2320. }
  2321. logStatus.error(`${result}:${statusText}(${status})`);
  2322. return false;
  2323. } catch (error) {
  2324. throwError(error, 'Instagram.followUser');
  2325. return false;
  2326. }
  2327. }
  2328. async #unfollowUser(name) {
  2329. try {
  2330. if (this.whiteList.users.includes(name)) {
  2331. scripts_echoLog({
  2332. type: 'whiteList',
  2333. text: 'Instagram.unfollowUser',
  2334. id: name
  2335. });
  2336. return true;
  2337. }
  2338. const id = await this.#getUserInfo(name);
  2339. if (!id) {
  2340. return false;
  2341. }
  2342. const logStatus = scripts_echoLog({
  2343. type: 'unfollowingIns',
  2344. text: name
  2345. });
  2346. const {
  2347. result,
  2348. statusText,
  2349. status,
  2350. data
  2351. } = await tools_httpRequest({
  2352. url: `https://www.instagram.com/web/friendships/${id}/unfollow/`,
  2353. method: 'POST',
  2354. dataType: 'json',
  2355. headers: {
  2356. 'x-csrftoken': this.#auth.csrftoken,
  2357. origin: 'https://www.instagram.com',
  2358. referer: `https://www.instagram.com/${name}/`,
  2359. 'content-type': 'application/x-www-form-urlencoded',
  2360. 'sec-fetch-site': 'same-origin',
  2361. 'x-instagram-ajax': this.#auth.hash
  2362. }
  2363. });
  2364. if (result === 'Success') {
  2365. if (data?.status === 200 && data.response?.status === 'ok') {
  2366. logStatus.success();
  2367. return true;
  2368. }
  2369. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2370. return false;
  2371. }
  2372. logStatus.error(`${result}:${statusText}(${status})`);
  2373. return false;
  2374. } catch (error) {
  2375. throwError(error, 'Instagram.unfollowUser');
  2376. return false;
  2377. }
  2378. }
  2379. async toggle({
  2380. doTask = true,
  2381. userLinks = []
  2382. }) {
  2383. try {
  2384. if (!this.#initialized) {
  2385. scripts_echoLog({
  2386. text: i18n('needInit')
  2387. });
  2388. return false;
  2389. }
  2390. const prom = [];
  2391. if (doTask && !globalOptions.doTask.instagram.users || !doTask && !globalOptions.undoTask.instagram.users) {
  2392. scripts_echoLog({
  2393. type: 'globalOptionsSkip',
  2394. text: 'instagram.users'
  2395. });
  2396. } else {
  2397. const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1]);
  2398. if (realUsers.length > 0) {
  2399. for (const username of realUsers) {
  2400. if (doTask) {
  2401. prom.push(this.#followUser(username));
  2402. } else {
  2403. prom.push(this.#unfollowUser(username));
  2404. }
  2405. await delay(1e3);
  2406. }
  2407. }
  2408. }
  2409. return await Promise.all(prom).then(() => true);
  2410. } catch (error) {
  2411. throwError(error, 'Instagram.toggleUsers');
  2412. return false;
  2413. }
  2414. }
  2415. #setCache(name, id) {
  2416. try {
  2417. this.#cache[name] = id;
  2418. GM_setValue('instagramCache', this.#cache);
  2419. } catch (error) {
  2420. throwError(error, 'Instagram.setCache');
  2421. }
  2422. }
  2423. }
  2424. const social_Instagram = Instagram;
  2425. class Reddit extends social_Social {
  2426. tasks;
  2427. whiteList;
  2428. #auth;
  2429. #initialized = false;
  2430. constructor() {
  2431. super();
  2432. const defaultTasksTemplate = {
  2433. reddits: []
  2434. };
  2435. this.tasks = defaultTasksTemplate;
  2436. this.whiteList = {
  2437. ...defaultTasksTemplate,
  2438. ...GM_getValue('whiteList')?.reddit || {}
  2439. };
  2440. }
  2441. async init() {
  2442. try {
  2443. if (this.#initialized) {
  2444. return true;
  2445. }
  2446. const isVerified = await this.#updateAuth();
  2447. if (isVerified) {
  2448. scripts_echoLog({}).success(i18n('initSuccess', 'Reddit'));
  2449. this.#initialized = true;
  2450. return true;
  2451. }
  2452. scripts_echoLog({}).error(i18n('initFailed', 'Reddit'));
  2453. return false;
  2454. } catch (error) {
  2455. throwError(error, 'Reddit.init');
  2456. return false;
  2457. }
  2458. }
  2459. async #useBeta() {
  2460. try {
  2461. const logStatus = scripts_echoLog({
  2462. text: i18n('changingRedditVersion')
  2463. });
  2464. return await new Promise(resolve => {
  2465. const newTab = GM_openInTab('https://www.reddit.com/', {
  2466. active: true,
  2467. insert: true,
  2468. setParent: true
  2469. });
  2470. newTab.name = 'ATv4_redditAuth';
  2471. newTab.onclose = async () => {
  2472. logStatus.success();
  2473. resolve(await this.#updateAuth(true));
  2474. };
  2475. });
  2476. } catch (error) {
  2477. throwError(error, 'Reddit.useBeta');
  2478. return false;
  2479. }
  2480. }
  2481. async #updateAuth(beta = false) {
  2482. try {
  2483. const logStatus = scripts_echoLog({
  2484. text: i18n('updatingAuth', 'Reddit')
  2485. });
  2486. const {
  2487. result,
  2488. statusText,
  2489. status,
  2490. data
  2491. } = await tools_httpRequest({
  2492. url: 'https://www.reddit.com/',
  2493. method: 'GET',
  2494. nochche: true,
  2495. headers: {
  2496. 'Cache-Control': 'no-cache'
  2497. }
  2498. });
  2499. if (result === 'Success') {
  2500. if (data?.responseText.includes('www.reddit.com/login/')) {
  2501. logStatus.error(`Error:${i18n('loginReddit')}`, true);
  2502. return false;
  2503. }
  2504. if (data?.status === 200) {
  2505. if (data.responseText.includes('redesign-beta-optin-btn') && !beta) {
  2506. return await this.#useBeta();
  2507. }
  2508. const accessToken = data.responseText.match(/"accessToken":"(.*?)","expires":"(.*?)"/)?.[1];
  2509. if (accessToken) {
  2510. this.#auth = {
  2511. token: accessToken
  2512. };
  2513. logStatus.success();
  2514. return true;
  2515. }
  2516. logStatus.error('Error: Parameter "accessToken" not found!');
  2517. return false;
  2518. }
  2519. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2520. return false;
  2521. }
  2522. logStatus.error(`${result}:${statusText}(${status})`);
  2523. return false;
  2524. } catch (error) {
  2525. throwError(error, 'Reddit.updateAuth');
  2526. return false;
  2527. }
  2528. }
  2529. async #toggleTask({
  2530. name,
  2531. doTask = true
  2532. }) {
  2533. try {
  2534. if (!doTask && this.whiteList.reddits.includes(name)) {
  2535. scripts_echoLog({
  2536. type: 'whiteList',
  2537. text: 'Reddit.undoTask',
  2538. id: name
  2539. });
  2540. return true;
  2541. }
  2542. let type = doTask ? 'joiningReddit' : 'leavingReddit';
  2543. if (/^u_/.test(name)) {
  2544. type = doTask ? 'followingRedditUser' : 'unfollowingRedditUser';
  2545. }
  2546. const logStatus = scripts_echoLog({
  2547. type: type,
  2548. text: name
  2549. });
  2550. const {
  2551. result,
  2552. statusText,
  2553. status,
  2554. data
  2555. } = await tools_httpRequest({
  2556. url: 'https://oauth.reddit.com/api/subscribe?redditWebClient=desktop2x&app=desktop2x-client-production&raw_json=1&gilding_detail=1',
  2557. method: 'POST',
  2558. headers: {
  2559. authorization: `Bearer ${this.#auth.token}`,
  2560. 'content-type': 'application/x-www-form-urlencoded'
  2561. },
  2562. data: $.param({
  2563. action: doTask ? 'sub' : 'unsub',
  2564. sr_name: name,
  2565. api_type: 'json'
  2566. })
  2567. });
  2568. if (result === 'Success') {
  2569. if (data?.status === 200) {
  2570. logStatus.success();
  2571. if (doTask) {
  2572. this.tasks.reddits = unique([ ...this.tasks.reddits, name ]);
  2573. }
  2574. return true;
  2575. }
  2576. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2577. return false;
  2578. }
  2579. logStatus.error(`${result}:${statusText}(${status})`);
  2580. return false;
  2581. } catch (error) {
  2582. throwError(error, 'Reddit.toggleTask');
  2583. return false;
  2584. }
  2585. }
  2586. async toggle({
  2587. doTask = true,
  2588. redditLinks = []
  2589. }) {
  2590. try {
  2591. if (!this.#initialized) {
  2592. scripts_echoLog({
  2593. text: i18n('needInit')
  2594. });
  2595. return false;
  2596. }
  2597. const prom = [];
  2598. if (doTask && !globalOptions.doTask.reddit.reddits || !doTask && !globalOptions.undoTask.reddit.reddits) {
  2599. scripts_echoLog({
  2600. type: 'globalOptionsSkip',
  2601. text: 'reddit.reddits'
  2602. });
  2603. } else {
  2604. const realReddits = this.getRealParams('reddits', redditLinks, doTask, link => {
  2605. const name = link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1];
  2606. const userName = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1];
  2607. if (userName) {
  2608. return name || userName;
  2609. }
  2610. return name;
  2611. });
  2612. if (realReddits.length > 0) {
  2613. for (const name of realReddits) {
  2614. prom.push(this.#toggleTask({
  2615. name: name,
  2616. doTask: doTask
  2617. }));
  2618. await delay(1e3);
  2619. }
  2620. }
  2621. }
  2622. return await Promise.all(prom).then(() => true);
  2623. } catch (error) {
  2624. throwError(error, 'Reddit.toggle');
  2625. return false;
  2626. }
  2627. }
  2628. }
  2629. const social_Reddit = Reddit;
  2630. class Twitch extends social_Social {
  2631. tasks;
  2632. whiteList;
  2633. #auth = GM_getValue('twitchAuth') || {};
  2634. #cache = GM_getValue('twitchCache') || {};
  2635. #initialized = false;
  2636. #integrityToken;
  2637. constructor() {
  2638. super();
  2639. const defaultTasksTemplate = {
  2640. channels: []
  2641. };
  2642. this.tasks = defaultTasksTemplate;
  2643. this.whiteList = {
  2644. ...defaultTasksTemplate,
  2645. ...GM_getValue('whiteList')?.twitch || {}
  2646. };
  2647. }
  2648. async init() {
  2649. try {
  2650. if (this.#initialized) {
  2651. return true;
  2652. }
  2653. if (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId) {
  2654. if (await this.#updateAuth()) {
  2655. this.#initialized = true;
  2656. return true;
  2657. }
  2658. return false;
  2659. }
  2660. const isVerified = await this.#verifyAuth(true);
  2661. if (isVerified) {
  2662. scripts_echoLog({}).success(i18n('initSuccess', 'Twitch'));
  2663. this.#initialized = true;
  2664. return true;
  2665. }
  2666. GM_setValue('twitchAuth', null);
  2667. if (await this.#updateAuth()) {
  2668. scripts_echoLog({}).success(i18n('initSuccess', 'Twitch'));
  2669. this.#initialized = true;
  2670. return true;
  2671. }
  2672. scripts_echoLog({}).error(i18n('initFailed', 'Twitch'));
  2673. return false;
  2674. } catch (error) {
  2675. throwError(error, 'Twitch.init');
  2676. return false;
  2677. }
  2678. }
  2679. async #verifyAuth(isFirst) {
  2680. try {
  2681. const logStatus = scripts_echoLog({
  2682. text: i18n('verifyingAuth', 'Twitch')
  2683. });
  2684. const {
  2685. result,
  2686. statusText,
  2687. status,
  2688. data
  2689. } = await tools_httpRequest({
  2690. url: 'https://gql.twitch.tv/gql',
  2691. method: 'POST',
  2692. dataType: 'json',
  2693. headers: {
  2694. Authorization: `OAuth ${this.#auth.authToken}`,
  2695. 'Client-Id': this.#auth.clientId
  2696. },
  2697. data: '[{"operationName":"FrontPageNew_User","variables":{"limit":1},"extensions":{"persistedQuery":{"version":1,' + '"sha256Hash":"64bd07a2cbaca80699d62636d966cf6395a5d14a1f0a14282067dcb28b13eb11"}}}]'
  2698. });
  2699. if (result === 'Success') {
  2700. if (data?.status === 200 && data.response?.[0]?.data?.currentUser) {
  2701. await this.#integrity(isFirst);
  2702. logStatus.success();
  2703. return true;
  2704. }
  2705. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2706. return false;
  2707. }
  2708. logStatus.error(`${result}:${statusText}(${status})`);
  2709. return false;
  2710. } catch (error) {
  2711. throwError(error, 'Twitch.verifyAuth');
  2712. return false;
  2713. }
  2714. }
  2715. async #integrity(isFirst = true, ct = '') {
  2716. try {
  2717. const logStatus = scripts_echoLog({
  2718. text: i18n('checkingTwitchIntegrity')
  2719. });
  2720. if (isFirst && (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId)) {
  2721. return await this.#updateAuth(false);
  2722. }
  2723. const {
  2724. result,
  2725. statusText,
  2726. status,
  2727. data
  2728. } = await tools_httpRequest({
  2729. url: 'https://gql.twitch.tv/integrity',
  2730. method: 'POST',
  2731. dataType: 'json',
  2732. anonymous: true,
  2733. headers: {
  2734. Origin: 'https://www.twitch.tv',
  2735. Referer: 'https://www.twitch.tv/',
  2736. Authorization: `OAuth ${this.#auth.authToken}`,
  2737. 'Client-Id': this.#auth.clientId,
  2738. 'Client-Version': this.#auth.clientVersion,
  2739. 'X-Device-Id': this.#auth.deviceId,
  2740. 'Client-Session-Id': this.#auth.clientSessionId,
  2741. 'x-kpsdk-ct': ct
  2742. }
  2743. });
  2744. if (result === 'Success') {
  2745. if (!ct && data?.responseHeaders?.['x-kpsdk-ct']) {
  2746. return await this.#integrity(isFirst, data.responseHeaders['x-kpsdk-ct']);
  2747. }
  2748. if (data?.status === 200 && data.response?.token) {
  2749. this.#integrityToken = data.response.token;
  2750. logStatus.success();
  2751. return true;
  2752. }
  2753. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2754. return false;
  2755. }
  2756. logStatus.error(`${result}:${statusText}(${status})`);
  2757. return false;
  2758. } catch (error) {
  2759. throwError(error, 'Twitch.integrity');
  2760. return false;
  2761. }
  2762. }
  2763. async #updateAuth(isFirst = true) {
  2764. try {
  2765. const logStatus = scripts_echoLog({
  2766. text: i18n('updatingAuth', 'Twitch')
  2767. });
  2768. return await new Promise(resolve => {
  2769. const newTab = GM_openInTab('https://www.twitch.tv/', {
  2770. active: true,
  2771. insert: true,
  2772. setParent: true
  2773. });
  2774. newTab.name = 'ATv4_twitchAuth';
  2775. newTab.onclose = async () => {
  2776. const auth = GM_getValue('twitchAuth');
  2777. if (auth) {
  2778. this.#auth = auth;
  2779. logStatus.success();
  2780. resolve(await this.#verifyAuth(isFirst));
  2781. } else {
  2782. logStatus.error('Error: Update twitch auth failed!');
  2783. resolve(false);
  2784. }
  2785. };
  2786. });
  2787. } catch (error) {
  2788. throwError(error, 'Twitch.updateAuth');
  2789. return false;
  2790. }
  2791. }
  2792. async #toggleChannel({
  2793. name,
  2794. doTask = true
  2795. }) {
  2796. try {
  2797. if (!doTask && this.whiteList.channels.includes(name)) {
  2798. scripts_echoLog({
  2799. type: 'whiteList',
  2800. text: 'Twitch.unfollowChannel',
  2801. id: name
  2802. });
  2803. return true;
  2804. }
  2805. const channelId = await this.#getChannelId(name);
  2806. if (!channelId) {
  2807. return false;
  2808. }
  2809. const logStatus = scripts_echoLog({
  2810. type: `${doTask ? '' : 'un'}followingTwitchChannel`,
  2811. text: name
  2812. });
  2813. const followData = `[{"operationName":"FollowButton_FollowUser","variables":{"input":{"disableNotifications":false,"targetID":"${channelId}` + '"}},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"800e7346bdf7e5278a3c1d3f21b2b56e2639928f86815677a7126b093b2fdd08"}}}]';
  2814. const unfollowData = `[{"operationName":"FollowButton_UnfollowUser","variables":{"input":{"targetID":"${channelId}"}},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"f7dae976ebf41c755ae2d758546bfd176b4eeb856656098bb40e0a672ca0d880"}}}]';
  2815. const {
  2816. result,
  2817. statusText,
  2818. status,
  2819. data
  2820. } = await tools_httpRequest({
  2821. url: 'https://gql.twitch.tv/gql',
  2822. method: 'POST',
  2823. dataType: 'json',
  2824. anonymous: true,
  2825. headers: {
  2826. Origin: 'https://www.twitch.tv',
  2827. Referer: 'https://www.twitch.tv/',
  2828. Authorization: `OAuth ${this.#auth.authToken}`,
  2829. 'Client-Id': this.#auth.clientId,
  2830. 'Client-Version': this.#auth.clientVersion,
  2831. 'X-Device-Id': this.#auth.deviceId,
  2832. 'Client-Session-Id': this.#auth.clientSessionId,
  2833. 'Client-Integrity': this.#integrityToken
  2834. },
  2835. data: doTask ? followData : unfollowData
  2836. });
  2837. if (result === 'Success') {
  2838. if (data?.status === 200 && data.response?.[0] && !data.response[0].errors) {
  2839. logStatus.success();
  2840. if (doTask) {
  2841. this.tasks.channels = unique([ ...this.tasks.channels, name ]);
  2842. }
  2843. return true;
  2844. }
  2845. logStatus.error(`Error:${data?.response?.[0].errors?.[0]?.message || `${data?.statusText}(${data?.status})`}`);
  2846. return false;
  2847. }
  2848. logStatus.error(`${result}:${statusText}(${status})`);
  2849. return false;
  2850. } catch (error) {
  2851. throwError(error, 'Twitch.toggleChannel');
  2852. return false;
  2853. }
  2854. }
  2855. async #getChannelId(name) {
  2856. try {
  2857. const logStatus = scripts_echoLog({
  2858. type: 'gettingTwitchChannelId',
  2859. text: name
  2860. });
  2861. const channelId = this.#cache[name];
  2862. if (channelId) {
  2863. logStatus.success();
  2864. return channelId;
  2865. }
  2866. const {
  2867. result,
  2868. statusText,
  2869. status,
  2870. data
  2871. } = await tools_httpRequest({
  2872. url: 'https://gql.twitch.tv/gql',
  2873. method: 'POST',
  2874. headers: {
  2875. Authorization: `OAuth ${this.#auth.authToken}`,
  2876. 'Client-Id': this.#auth.clientId
  2877. },
  2878. responseType: 'json',
  2879. data: `[{"operationName":"ActiveWatchParty","variables":{"channelLogin":"${name}"},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"4a8156c97b19e3a36e081cf6d6ddb5dbf9f9b02ae60e4d2ff26ed70aebc80a30"}}}]'
  2880. });
  2881. if (result === 'Success') {
  2882. if (data?.status === 200) {
  2883. const channelId = data.response?.[0]?.data?.user?.id;
  2884. if (channelId) {
  2885. this.#setCache(name, String(channelId));
  2886. logStatus.success();
  2887. return channelId;
  2888. }
  2889. logStatus.error(`Error:${data.statusText}(${data.status})`);
  2890. return false;
  2891. }
  2892. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  2893. return false;
  2894. }
  2895. logStatus.error(`${result}:${statusText}(${status})`);
  2896. return false;
  2897. } catch (error) {
  2898. throwError(error, 'Twitch.getChannelId');
  2899. return false;
  2900. }
  2901. }
  2902. async toggle({
  2903. doTask = true,
  2904. channelLinks = []
  2905. }) {
  2906. try {
  2907. if (!this.#initialized) {
  2908. scripts_echoLog({
  2909. text: i18n('needInit')
  2910. });
  2911. return false;
  2912. }
  2913. const prom = [];
  2914. if (doTask && !globalOptions.doTask.twitch.channels || !doTask && !globalOptions.undoTask.twitch.channels) {
  2915. scripts_echoLog({
  2916. type: 'globalOptionsSkip',
  2917. text: 'twitch.channels'
  2918. });
  2919. } else {
  2920. const realChannels = this.getRealParams('channels', channelLinks, doTask, link => link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2]);
  2921. if (realChannels.length > 0) {
  2922. for (const channel of realChannels) {
  2923. prom.push(this.#toggleChannel({
  2924. name: channel,
  2925. doTask: doTask
  2926. }));
  2927. await delay(1e3);
  2928. }
  2929. }
  2930. }
  2931. return Promise.all(prom).then(() => true);
  2932. } catch (error) {
  2933. throwError(error, 'Twitch.toggle');
  2934. return false;
  2935. }
  2936. }
  2937. #setCache(name, id) {
  2938. try {
  2939. this.#cache[name] = id;
  2940. GM_setValue('twitchCache', this.#cache);
  2941. } catch (error) {
  2942. throwError(error, 'Twitch.setCache');
  2943. }
  2944. }
  2945. }
  2946. const social_Twitch = Twitch;
  2947. class Twitter extends social_Social {
  2948. tasks;
  2949. whiteList;
  2950. #verifyId = globalOptions.other.twitterVerifyId;
  2951. #auth = GM_getValue('twitterAuth') || {};
  2952. #cache = GM_getValue('twitterCache') || {};
  2953. #initialized = false;
  2954. constructor() {
  2955. super();
  2956. const defaultTasksTemplate = {
  2957. users: [],
  2958. retweets: [],
  2959. likes: []
  2960. };
  2961. this.tasks = defaultTasksTemplate;
  2962. this.whiteList = {
  2963. ...defaultTasksTemplate,
  2964. ...GM_getValue('whiteList')?.twitter || {}
  2965. };
  2966. }
  2967. async init() {
  2968. try {
  2969. if (this.#initialized) {
  2970. return true;
  2971. }
  2972. if (!this.#auth.ct0) {
  2973. if (await this.#updateAuth()) {
  2974. this.#initialized = true;
  2975. return true;
  2976. }
  2977. return false;
  2978. }
  2979. const isVerified = await this.#verifyAuth();
  2980. if (isVerified) {
  2981. scripts_echoLog({}).success(i18n('initSuccess', 'Twitter'));
  2982. this.#initialized = true;
  2983. return true;
  2984. }
  2985. GM_setValue('twitterAuth', null);
  2986. if (await this.#updateAuth()) {
  2987. scripts_echoLog({}).success(i18n('initSuccess', 'Twitter'));
  2988. this.#initialized = true;
  2989. return true;
  2990. }
  2991. scripts_echoLog({}).error(i18n('initFailed', 'Twitter'));
  2992. return false;
  2993. } catch (error) {
  2994. throwError(error, 'Twitter.init');
  2995. return false;
  2996. }
  2997. }
  2998. async #verifyAuth() {
  2999. try {
  3000. return await this.#toggleUser({
  3001. name: 'verify',
  3002. doTask: true,
  3003. verify: true
  3004. });
  3005. } catch (error) {
  3006. throwError(error, 'Twitter.verifyAuth');
  3007. return false;
  3008. }
  3009. }
  3010. async #updateAuth() {
  3011. try {
  3012. const logStatus = scripts_echoLog({
  3013. text: i18n('updatingAuth', 'Twitter')
  3014. });
  3015. return await new Promise(resolve => {
  3016. GM_cookie.list({
  3017. url: 'https://x.com/settings/account'
  3018. }, async (cookies, error) => {
  3019. if (!error) {
  3020. const [ ct0, isLogin ] = cookies.map(cookie => [ 'ct0', 'twid' ].includes(cookie.name) ? cookie.value : null).filter(cookie => cookie);
  3021. if (isLogin && ct0) {
  3022. GM_setValue('twitterAuth', {
  3023. ct0: ct0
  3024. });
  3025. this.#auth = {
  3026. ct0: ct0
  3027. };
  3028. logStatus.success();
  3029. resolve(await this.#verifyAuth());
  3030. } else {
  3031. logStatus.error(i18n('needLogin'));
  3032. resolve(false);
  3033. }
  3034. } else {
  3035. logStatus.error('Error: Update twitter auth failed!');
  3036. resolve(false);
  3037. }
  3038. });
  3039. });
  3040. } catch (error) {
  3041. throwError(error, 'Twitter.updateToken');
  3042. return false;
  3043. }
  3044. }
  3045. async #toggleUser({
  3046. name,
  3047. doTask = true,
  3048. verify = false,
  3049. retry = false
  3050. }) {
  3051. try {
  3052. if (!doTask && !verify && this.whiteList.users.includes(name)) {
  3053. scripts_echoLog({
  3054. type: 'whiteList',
  3055. text: 'Twitter.unfollowUser',
  3056. id: name
  3057. });
  3058. return true;
  3059. }
  3060. const userId = verify ? this.#verifyId : await this.userName2id(name);
  3061. if (!userId) {
  3062. return false;
  3063. }
  3064. const logStatus = verify ? scripts_echoLog({
  3065. text: i18n('verifyingAuth', 'Twitter')
  3066. }) : scripts_echoLog({
  3067. type: `${doTask ? '' : 'un'}followingTwitterUser`,
  3068. text: name
  3069. });
  3070. const {
  3071. result,
  3072. statusText,
  3073. status,
  3074. data
  3075. } = await tools_httpRequest({
  3076. url: `https://x.com/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`,
  3077. method: 'POST',
  3078. headers: {
  3079. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3080. 'Content-Type': 'application/x-www-form-urlencoded',
  3081. 'x-csrf-token': this.#auth.ct0,
  3082. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3083. 'X-Twitter-Active-User': 'yes'
  3084. },
  3085. responseType: 'json',
  3086. data: $.param({
  3087. include_profile_interstitial_type: 1,
  3088. include_blocking: 1,
  3089. include_blocked_by: 1,
  3090. include_followed_by: 1,
  3091. include_want_retweets: 1,
  3092. include_mute_edge: 1,
  3093. include_can_dm: 1,
  3094. include_can_media_tag: 1,
  3095. skip_status: 1,
  3096. id: userId
  3097. })
  3098. });
  3099. if (result === 'Success') {
  3100. if (data?.status === 200) {
  3101. logStatus.success();
  3102. if (doTask && !verify) {
  3103. this.tasks.users = unique([ ...this.tasks.users, name ]);
  3104. }
  3105. return true;
  3106. }
  3107. if (verify && data?.status === 403) {
  3108. if (data.response?.errors?.[0]?.code === 158) {
  3109. logStatus.success();
  3110. return true;
  3111. }
  3112. if (data.response?.errors?.[0]?.code === 353 && !retry && data.responseHeaders?.['set-cookie']) {
  3113. this.#auth.ct0 = data.responseHeaders['set-cookie']?.find(cookie => cookie.includes('ct0='))?.split(';')?.at(0)?.split('=')?.at(-1) || this.#auth.ct0;
  3114. logStatus.warning(i18n('retry'));
  3115. return this.#toggleUser({
  3116. name: name,
  3117. doTask: doTask,
  3118. verify: verify,
  3119. retry: true
  3120. });
  3121. }
  3122. }
  3123. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3124. return false;
  3125. }
  3126. logStatus.error(`${result}:${statusText}(${status})`);
  3127. return false;
  3128. } catch (error) {
  3129. throwError(error, 'Twitter.toggleUser');
  3130. return false;
  3131. }
  3132. }
  3133. async userName2id(name) {
  3134. try {
  3135. const logStatus = scripts_echoLog({
  3136. type: 'gettingTwitterUserId',
  3137. text: name
  3138. });
  3139. const userId = this.#cache[name];
  3140. if (userId) {
  3141. logStatus.success();
  3142. return userId;
  3143. }
  3144. const {
  3145. result,
  3146. statusText,
  3147. status,
  3148. data
  3149. } = await tools_httpRequest({
  3150. 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`,
  3151. method: 'GET',
  3152. headers: {
  3153. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3154. 'content-type': 'application/json',
  3155. referer: `https://x.com/${name}`,
  3156. 'x-csrf-token': this.#auth.ct0,
  3157. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3158. 'X-Twitter-Active-User': 'yes'
  3159. },
  3160. responseType: 'json'
  3161. });
  3162. if (result === 'Success') {
  3163. if (data?.status === 200) {
  3164. let response = data.response || (typeof data.responseText === 'object' ? data.responseText : null);
  3165. if (!response) {
  3166. try {
  3167. response = JSON.parse(data.responseText);
  3168. } catch (error) {
  3169. response = null;
  3170. }
  3171. }
  3172. const userId = String(response?.data?.user?.result?.rest_id);
  3173. if (userId) {
  3174. this.#setCache(name, userId);
  3175. logStatus.success();
  3176. return userId;
  3177. }
  3178. logStatus.error(`Error:${data.statusText}(${data.status})`);
  3179. return false;
  3180. }
  3181. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3182. return false;
  3183. }
  3184. logStatus.error(`${result}:${statusText}(${status})`);
  3185. return false;
  3186. } catch (error) {
  3187. throwError(error, 'Twitter.getUserId');
  3188. return false;
  3189. }
  3190. }
  3191. async #toggleRetweet({
  3192. retweetId,
  3193. doTask = true
  3194. }) {
  3195. try {
  3196. if (!doTask && this.whiteList.retweets.includes(retweetId)) {
  3197. scripts_echoLog({
  3198. type: 'whiteList',
  3199. text: 'Twitter.unretweet',
  3200. id: retweetId
  3201. });
  3202. return true;
  3203. }
  3204. const logStatus = scripts_echoLog({
  3205. type: `${doTask ? '' : 'un'}retweetting`,
  3206. text: retweetId
  3207. });
  3208. const {
  3209. result,
  3210. statusText,
  3211. status,
  3212. data
  3213. } = await tools_httpRequest({
  3214. url: `https://x.com/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`,
  3215. method: 'POST',
  3216. headers: {
  3217. authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
  3218. 'Content-Type': 'application/json',
  3219. 'x-csrf-token': this.#auth.ct0,
  3220. 'X-Twitter-Auth-Type': 'OAuth2Session',
  3221. 'X-Twitter-Active-User': 'yes'
  3222. },
  3223. data: `{"variables":{"tweet_id":"${retweetId}","dark_request":false},"queryId":"${doTask ? 'ojPdsZsimiJrUGLR1sjUtA' : 'iQtK4dl5hBmXewYZuEOKVw'}"}`,
  3224. responseType: 'json'
  3225. });
  3226. if (result === 'Success') {
  3227. if (data?.status === 200 || data?.status === 403 && data.response?.errors?.[0]?.code === 327) {
  3228. logStatus.success();
  3229. if (doTask) {
  3230. this.tasks.retweets = unique([ ...this.tasks.retweets, retweetId ]);
  3231. }
  3232. return true;
  3233. }
  3234. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3235. return false;
  3236. }
  3237. logStatus.error(`${result}:${statusText}(${status})`);
  3238. return false;
  3239. } catch (error) {
  3240. throwError(error, 'Twitter.toggleRetweet');
  3241. return false;
  3242. }
  3243. }
  3244. async toggle({
  3245. doTask = true,
  3246. userLinks = [],
  3247. retweetLinks = []
  3248. }) {
  3249. try {
  3250. if (!this.#initialized) {
  3251. scripts_echoLog({
  3252. text: i18n('needInit')
  3253. });
  3254. return false;
  3255. }
  3256. const prom = [];
  3257. if (doTask && !globalOptions.doTask.twitter.users || !doTask && !globalOptions.undoTask.twitter.users) {
  3258. scripts_echoLog({
  3259. type: 'globalOptionsSkip',
  3260. text: 'twitter.users'
  3261. });
  3262. } else {
  3263. const realUsers = this.getRealParams('users', userLinks, doTask, link => link.match(/https:\/\/x\.com\/(.+)/)?.[1] || link.match(/https:\/\/twitter\.com\/(.+)/)?.[1]);
  3264. if (realUsers.length > 0) {
  3265. for (const user of realUsers) {
  3266. prom.push(this.#toggleUser({
  3267. name: user,
  3268. doTask: doTask
  3269. }));
  3270. await delay(1e3);
  3271. }
  3272. }
  3273. }
  3274. if (doTask && !globalOptions.doTask.twitter.retweets || !doTask && !globalOptions.undoTask.twitter.retweets) {
  3275. scripts_echoLog({
  3276. type: 'globalOptionsSkip',
  3277. text: 'twitter.retweets'
  3278. });
  3279. } else {
  3280. const realRetweets = this.getRealParams('retweets', retweetLinks, doTask, link => link.match(/https:\/\/x\.com\/.*?\/status\/([\d]+)/)?.[1] || link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1]);
  3281. if (realRetweets.length > 0) {
  3282. for (const retweet of realRetweets) {
  3283. prom.push(this.#toggleRetweet({
  3284. retweetId: retweet,
  3285. doTask: doTask
  3286. }));
  3287. await delay(1e3);
  3288. }
  3289. }
  3290. }
  3291. return Promise.all(prom).then(() => true);
  3292. } catch (error) {
  3293. throwError(error, 'Twitter.toggle');
  3294. return false;
  3295. }
  3296. }
  3297. #setCache(name, id) {
  3298. try {
  3299. this.#cache[name] = id;
  3300. GM_setValue('twitterCache', this.#cache);
  3301. } catch (error) {
  3302. throwError(error, 'Twitter.setCache');
  3303. }
  3304. }
  3305. }
  3306. const social_Twitter = Twitter;
  3307. class Vk extends social_Social {
  3308. tasks;
  3309. whiteList;
  3310. #username = '';
  3311. #cache = GM_getValue('vkCache') || {};
  3312. #initialized = false;
  3313. constructor() {
  3314. super();
  3315. const defaultTasksTemplate = {
  3316. names: []
  3317. };
  3318. this.tasks = defaultTasksTemplate;
  3319. this.whiteList = {
  3320. ...defaultTasksTemplate,
  3321. ...GM_getValue('whiteList')?.vk || {}
  3322. };
  3323. }
  3324. async init() {
  3325. try {
  3326. if (this.#initialized) {
  3327. return true;
  3328. }
  3329. const isVerified = await this.#verifyAuth();
  3330. if (isVerified) {
  3331. scripts_echoLog({}).success(i18n('initSuccess', 'Vk'));
  3332. this.#initialized = true;
  3333. return true;
  3334. }
  3335. scripts_echoLog({}).error(i18n('initFailed', 'Vk'));
  3336. return false;
  3337. } catch (error) {
  3338. throwError(error, 'Vk.init');
  3339. return false;
  3340. }
  3341. }
  3342. async #verifyAuth() {
  3343. try {
  3344. const logStatus = scripts_echoLog({
  3345. text: i18n('verifyAuth', 'Vk')
  3346. });
  3347. const {
  3348. result,
  3349. statusText,
  3350. status,
  3351. data
  3352. } = await tools_httpRequest({
  3353. url: 'https://vk.com/im',
  3354. method: 'GET'
  3355. });
  3356. if (result === 'Success') {
  3357. if (data?.finalUrl.includes('vk.com/login')) {
  3358. logStatus.error(`Error:${i18n('loginVk')}`, true);
  3359. return false;
  3360. }
  3361. if (data?.status === 200) {
  3362. this.#username = data.responseText.match(/TopNavBtn__profileLink" href="\/(.*?)"/)?.[1] || '';
  3363. logStatus.success();
  3364. return true;
  3365. }
  3366. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3367. return false;
  3368. }
  3369. logStatus.error(`${result}:${statusText}(${status})`);
  3370. return false;
  3371. } catch (error) {
  3372. throwError(error, 'Vk.verifyAuth');
  3373. return false;
  3374. }
  3375. }
  3376. async #toggleGroup(name, dataParam, doTask = true) {
  3377. try {
  3378. const logStatus = scripts_echoLog({
  3379. type: doTask ? 'joiningVkGroup' : 'leavingVkGroup',
  3380. text: name
  3381. });
  3382. if (dataParam.groupAct === 'enter' && !doTask || dataParam.groupAct === 'leave' && doTask) {
  3383. logStatus.success();
  3384. return true;
  3385. }
  3386. const reqData = {
  3387. act: doTask ? 'enter' : 'leave',
  3388. al: 1,
  3389. gid: dataParam.groupId,
  3390. hash: dataParam.groupHash
  3391. };
  3392. if (doTask) {
  3393. reqData.context = '_';
  3394. }
  3395. const {
  3396. result,
  3397. statusText,
  3398. status,
  3399. data
  3400. } = await tools_httpRequest({
  3401. url: 'https://vk.com/al_groups.php',
  3402. method: 'POST',
  3403. headers: {
  3404. origin: 'https://vk.com',
  3405. referer: `https://vk.com/${name}`,
  3406. 'content-type': 'application/x-www-form-urlencoded'
  3407. },
  3408. data: $.param(reqData)
  3409. });
  3410. if (result === 'Success') {
  3411. if (data?.status === 200) {
  3412. logStatus.success();
  3413. if (doTask) {
  3414. this.tasks.names = unique([ ...this.tasks.names, name ]);
  3415. }
  3416. return true;
  3417. }
  3418. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3419. return false;
  3420. }
  3421. logStatus.error(`${result}:${statusText}(${status})`);
  3422. return false;
  3423. } catch (error) {
  3424. throwError(error, 'Vk.toggleGroup');
  3425. return false;
  3426. }
  3427. }
  3428. async #togglePublic(name, dataParam, doTask = true) {
  3429. try {
  3430. const logStatus = scripts_echoLog({
  3431. type: doTask ? 'joiningVkPublic' : 'leavingVkPublic',
  3432. text: name
  3433. });
  3434. if (dataParam.publicJoined && doTask || !dataParam.publicJoined && !doTask) {
  3435. logStatus.success();
  3436. return true;
  3437. }
  3438. const {
  3439. result,
  3440. statusText,
  3441. status,
  3442. data
  3443. } = await tools_httpRequest({
  3444. url: 'https://vk.com/al_public.php',
  3445. method: 'POST',
  3446. headers: {
  3447. origin: 'https://vk.com',
  3448. referer: `https://vk.com/${name}`,
  3449. 'content-type': 'application/x-www-form-urlencoded'
  3450. },
  3451. data: $.param({
  3452. act: doTask ? 'a_enter' : 'a_leave',
  3453. al: 1,
  3454. pid: dataParam.publicPid,
  3455. hash: dataParam.publicHash
  3456. })
  3457. });
  3458. if (result === 'Success') {
  3459. if (data?.status === 200) {
  3460. logStatus.success();
  3461. if (doTask) {
  3462. this.tasks.names = unique([ ...this.tasks.names, name ]);
  3463. }
  3464. return true;
  3465. }
  3466. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3467. return false;
  3468. }
  3469. logStatus.error(`${result}:${statusText}(${status})`);
  3470. return false;
  3471. } catch (error) {
  3472. throwError(error, 'Vk.togglePublic');
  3473. return false;
  3474. }
  3475. }
  3476. async #toggleLikeWall(name, dataParam, doTask = true) {
  3477. try {
  3478. const logStatus = scripts_echoLog({
  3479. type: doTask ? 'likingVkPublic' : 'unlikingVkPublic',
  3480. text: name
  3481. });
  3482. const postData = {
  3483. act: 'a_set_reaction',
  3484. al: 1,
  3485. event_subtype: 'post_modal',
  3486. from: 'wall_page',
  3487. hash: dataParam.hash,
  3488. object: dataParam.object,
  3489. track_code: dataParam.trackCode,
  3490. wall: 2
  3491. };
  3492. if (doTask) {
  3493. postData.reaction_id = 0;
  3494. }
  3495. const {
  3496. result: resultR,
  3497. statusText: statusTextR,
  3498. status: statusR,
  3499. data: dataR
  3500. } = await tools_httpRequest({
  3501. url: 'https://vk.com/like.php?act=a_set_reaction',
  3502. method: 'POST',
  3503. headers: {
  3504. origin: 'https://vk.com',
  3505. referer: `https://vk.com/${name}`,
  3506. 'content-type': 'application/x-www-form-urlencoded'
  3507. },
  3508. data: $.param(postData)
  3509. });
  3510. if (resultR === 'Success') {
  3511. if (dataR?.status === 200) {
  3512. if (dataR.response?.payload?.[1]?.[1]?.like_my === true) {
  3513. logStatus.success();
  3514. return true;
  3515. }
  3516. }
  3517. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  3518. return false;
  3519. }
  3520. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  3521. return false;
  3522. } catch (error) {
  3523. throwError(error, 'Vk.sendWall');
  3524. return false;
  3525. }
  3526. }
  3527. async #sendWall(name) {
  3528. try {
  3529. const logStatus = scripts_echoLog({
  3530. type: 'sendingVkWall',
  3531. text: name
  3532. });
  3533. const {
  3534. result,
  3535. statusText,
  3536. status,
  3537. data
  3538. } = await tools_httpRequest({
  3539. url: 'https://vk.com/like.php',
  3540. method: 'POST',
  3541. headers: {
  3542. origin: 'https://vk.com',
  3543. referer: `https://vk.com/${name}`,
  3544. 'content-type': 'application/x-www-form-urlencoded'
  3545. },
  3546. data: $.param({
  3547. act: 'publish_box',
  3548. al: 1,
  3549. object: name
  3550. })
  3551. });
  3552. if (result === 'Success') {
  3553. if (data?.status === 200) {
  3554. const hash = data.responseText.match(/shHash:[\s]*'(.*?)'/)?.[1];
  3555. if (hash) {
  3556. const {
  3557. result: resultR,
  3558. statusText: statusTextR,
  3559. status: statusR,
  3560. data: dataR
  3561. } = await tools_httpRequest({
  3562. url: 'https://vk.com/like.php',
  3563. method: 'POST',
  3564. headers: {
  3565. origin: 'https://vk.com',
  3566. referer: `https://vk.com/${name}`,
  3567. 'content-type': 'application/x-www-form-urlencoded'
  3568. },
  3569. data: $.param({
  3570. Message: '',
  3571. act: 'a_do_publish',
  3572. al: 1,
  3573. close_comments: 0,
  3574. friends_only: 0,
  3575. from: 'box',
  3576. hash: hash,
  3577. list: '',
  3578. mark_as_ads: 0,
  3579. mute_notifications: 0,
  3580. object: name,
  3581. ret_data: 1,
  3582. to: 0
  3583. })
  3584. });
  3585. if (resultR === 'Success') {
  3586. if (dataR?.status === 200) {
  3587. const jsonData = JSON.parse(dataR.responseText?.replace('\x3c!--', '') || '{}');
  3588. if (jsonData?.payload?.[1]?.[1]?.share_my === true) {
  3589. logStatus.success();
  3590. const postId = String(jsonData?.payload?.[1]?.[1]?.post_id);
  3591. const ownerId = String(jsonData?.payload?.[1]?.[1]?.owner_id);
  3592. if (postId && ownerId) {
  3593. this.#setCache(name, `${ownerId}_${postId}`);
  3594. }
  3595. this.tasks.names = unique([ ...this.tasks.names, name ]);
  3596. return true;
  3597. }
  3598. }
  3599. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  3600. return false;
  3601. }
  3602. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  3603. return false;
  3604. }
  3605. logStatus.error('Error: Get "hash" failed');
  3606. return false;
  3607. }
  3608. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3609. return false;
  3610. }
  3611. logStatus.error(`${result}:${statusText}(${status})`);
  3612. return false;
  3613. } catch (error) {
  3614. throwError(error, 'Vk.sendWall');
  3615. return false;
  3616. }
  3617. }
  3618. async #deleteWall(name, dataParams) {
  3619. try {
  3620. const logStatus = scripts_echoLog({
  3621. type: 'deletingVkWall',
  3622. text: name
  3623. });
  3624. const {
  3625. result,
  3626. statusText,
  3627. status,
  3628. data
  3629. } = await tools_httpRequest({
  3630. url: 'https://vk.com/al_wall.php?act=delete',
  3631. method: 'POST',
  3632. headers: {
  3633. origin: 'https://vk.com',
  3634. referer: `https://vk.com/${this.#username}?w=wall${this.#cache[name]}%2Fall`,
  3635. 'content-type': 'application/x-www-form-urlencoded'
  3636. },
  3637. data: $.param({
  3638. act: 'delete',
  3639. al: 1,
  3640. confirm: 0,
  3641. from: 'wkview',
  3642. hash: dataParams.wallHash,
  3643. post: this.#cache[name]
  3644. })
  3645. });
  3646. if (result === 'Success') {
  3647. if (data?.status === 200) {
  3648. const jsonData = JSON.parse(data.responseText?.replace('\x3c!--', '') || '{}');
  3649. if (jsonData?.payload?.[1]?.[1]) {
  3650. logStatus.success();
  3651. return true;
  3652. }
  3653. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3654. return false;
  3655. }
  3656. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3657. return false;
  3658. }
  3659. logStatus.error(`${result}:${statusText}(${status})`);
  3660. return false;
  3661. } catch (error) {
  3662. throwError(error, 'Vk.deleteWall');
  3663. return false;
  3664. }
  3665. }
  3666. async #getId(name, doTask) {
  3667. try {
  3668. let url = `https://vk.com/${name}`;
  3669. if (/^wall-/.test(name)) {
  3670. if (doTask) {
  3671. return {
  3672. type: 'sendWall'
  3673. };
  3674. }
  3675. if (!this.#cache[name]) {
  3676. return {
  3677. type: 'unSupport'
  3678. };
  3679. }
  3680. url = `https://vk.com/${this.#username}?w=wall${this.#cache[name]}`;
  3681. }
  3682. const logStatus = scripts_echoLog({
  3683. type: 'gettingVkId',
  3684. text: name
  3685. });
  3686. const {
  3687. result,
  3688. statusText,
  3689. status,
  3690. data
  3691. } = await tools_httpRequest({
  3692. url: url,
  3693. method: 'GET'
  3694. });
  3695. if (result === 'Success') {
  3696. if (data?.status === 200) {
  3697. const [ , groupAct, groupId, , groupHash ] = data.responseText.match(/Groups.(enter|leave)\(.*?,.*?([\d]+?), (&#39;|')(.*?)(&#39;|')/) || [];
  3698. const publicHash = data.responseText.match(/"enterHash":"(.*?)"/)?.[1];
  3699. const publicPid = data.responseText.match(/"public_id":([\d]+?),/)?.[1];
  3700. const publicJoined = !data.responseText.includes('Public.subscribe');
  3701. if (groupAct && groupId && groupHash) {
  3702. logStatus.success();
  3703. return {
  3704. groupAct: groupAct,
  3705. groupId: groupId,
  3706. groupHash: groupHash,
  3707. type: 'group'
  3708. };
  3709. } else if (publicHash && publicPid) {
  3710. logStatus.success();
  3711. return {
  3712. publicHash: publicHash,
  3713. publicPid: publicPid,
  3714. publicJoined: publicJoined,
  3715. type: 'public'
  3716. };
  3717. } else if (name.includes('action=like')) {
  3718. const hash = data.responseText.match(/data-reaction-hash="(.*?)"/)?.[1];
  3719. const trackCode = data.responseText.match(/data-post-track-code="(.*?)"/)?.[1];
  3720. const object = name.match(/wall-[\w_]+/)?.[0];
  3721. if (hash && trackCode && object) {
  3722. logStatus.success();
  3723. return {
  3724. type: 'likeWall',
  3725. hash: hash,
  3726. trackCode: trackCode,
  3727. object: object
  3728. };
  3729. }
  3730. } else if (data.responseText.includes('wall.deletePost') && !doTask) {
  3731. const wallHash = data.responseText.match(/wall\.deletePost\(this, '.*?', '(.*?)'\)/)?.[1];
  3732. if (wallHash) {
  3733. logStatus.success();
  3734. return {
  3735. type: 'deleteWall',
  3736. wallHash: wallHash
  3737. };
  3738. }
  3739. } else if (name.includes('wall') && doTask) {
  3740. logStatus.success();
  3741. return {
  3742. type: 'sendWall'
  3743. };
  3744. }
  3745. logStatus.error('Error: Parameters not found!');
  3746. return false;
  3747. }
  3748. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3749. return false;
  3750. }
  3751. logStatus.error(`${result}:${statusText}(${status})`);
  3752. return false;
  3753. } catch (error) {
  3754. throwError(error, 'Vk.getId');
  3755. return false;
  3756. }
  3757. }
  3758. async #toggleVk({
  3759. name,
  3760. doTask = true
  3761. }) {
  3762. try {
  3763. if (!doTask && this.whiteList.names.includes(name)) {
  3764. scripts_echoLog({
  3765. type: 'whiteList',
  3766. text: 'Vk.undoTask',
  3767. id: name
  3768. });
  3769. return true;
  3770. }
  3771. const formatName = name.replace(/\/$/, '');
  3772. const data = await this.#getId(formatName, doTask);
  3773. if (!data) {
  3774. return false;
  3775. }
  3776. switch (data.type) {
  3777. case 'group':
  3778. return await this.#toggleGroup(formatName, data, doTask);
  3779.  
  3780. case 'public':
  3781. return await this.#togglePublic(formatName, data, doTask);
  3782.  
  3783. case 'likeWall':
  3784. return await this.#toggleLikeWall(formatName, data, doTask);
  3785.  
  3786. case 'sendWall':
  3787. return doTask ? await this.#sendWall(formatName) : true;
  3788.  
  3789. case 'deleteWall':
  3790. return doTask ? true : await this.#deleteWall(formatName, data);
  3791.  
  3792. default:
  3793. return false;
  3794. }
  3795. } catch (error) {
  3796. throwError(error, 'Vk.toggleVk');
  3797. return false;
  3798. }
  3799. }
  3800. async toggle({
  3801. doTask = true,
  3802. nameLinks = []
  3803. }) {
  3804. try {
  3805. if (!this.#initialized) {
  3806. scripts_echoLog({
  3807. text: i18n('needInit')
  3808. });
  3809. return false;
  3810. }
  3811. const prom = [];
  3812. if (doTask && !globalOptions.doTask.vk.names || !doTask && !globalOptions.undoTask.vk.names) {
  3813. scripts_echoLog({
  3814. type: 'globalOptionsSkip',
  3815. text: 'vk.names'
  3816. });
  3817. } else {
  3818. const realNames = this.getRealParams('names', nameLinks, doTask, link => link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1]);
  3819. if (realNames.length > 0) {
  3820. for (const name of realNames) {
  3821. prom.push(this.#toggleVk({
  3822. name: name,
  3823. doTask: doTask
  3824. }));
  3825. await delay(1e3);
  3826. }
  3827. }
  3828. }
  3829. return Promise.all(prom).then(() => true);
  3830. } catch (error) {
  3831. throwError(error, 'Vk.toggle');
  3832. return false;
  3833. }
  3834. }
  3835. #setCache(name, postId) {
  3836. try {
  3837. this.#cache[name] = postId;
  3838. GM_setValue('vkCache', this.#cache);
  3839. } catch (error) {
  3840. throwError(error, 'Vk.setCache');
  3841. }
  3842. }
  3843. }
  3844. const social_Vk = Vk;
  3845. const getInfo = async function(link, type) {
  3846. try {
  3847. const logStatus = scripts_echoLog({
  3848. text: i18n('gettingYtbToken')
  3849. });
  3850. const {
  3851. result,
  3852. statusText,
  3853. status,
  3854. data
  3855. } = await tools_httpRequest({
  3856. url: link,
  3857. method: 'GET'
  3858. });
  3859. if (result === 'Success') {
  3860. if (data?.status === 200) {
  3861. if (data.responseText.includes('accounts.google.com/ServiceLogin?service=youtube')) {
  3862. logStatus.error(`Error:${i18n('loginYtb')}`, true);
  3863. return {
  3864. needLogin: true
  3865. };
  3866. }
  3867. const apiKey = data.responseText.match(/"INNERTUBE_API_KEY":"(.*?)"/)?.[1];
  3868. const context = (data.responseText.match(/\(\{"INNERTUBE_CONTEXT":([\w\W]*?)\}\)/) || data.responseText.match(/"INNERTUBE_CONTEXT":([\w\W]*?\}),"INNERTUBE/))?.[1] || '{}';
  3869. const {
  3870. client,
  3871. request
  3872. } = JSON.parse(context);
  3873. if (apiKey && client && request) {
  3874. client.hl = 'en';
  3875. if (type === 'channel') {
  3876. const channelId = data.responseText.match(/"channelId":"(.+?)"/)?.[1];
  3877. if (channelId) {
  3878. logStatus.success();
  3879. return {
  3880. params: {
  3881. apiKey: apiKey,
  3882. client: client,
  3883. request: request,
  3884. channelId: channelId
  3885. }
  3886. };
  3887. }
  3888. logStatus.error('Error: Get "channelId" failed!');
  3889. return {};
  3890. } else if (type === 'likeVideo') {
  3891. const videoId = data.responseText.match(/<link rel="shortlinkUrl" href="https:\/\/youtu\.be\/(.*?)">/)?.[1];
  3892. const likeParams = data.responseText.match(/"likeParams":"(.*?)"/)?.[1];
  3893. if (videoId) {
  3894. logStatus.success();
  3895. return {
  3896. params: {
  3897. apiKey: apiKey,
  3898. client: client,
  3899. request: request,
  3900. videoId: videoId,
  3901. likeParams: likeParams
  3902. }
  3903. };
  3904. }
  3905. logStatus.error('Error: Get "videoId" failed!');
  3906. return {};
  3907. }
  3908. logStatus.error('Error: Unknown type');
  3909. return {};
  3910. }
  3911. logStatus.error('Error: Parameter "apiKey" not found!');
  3912. return {};
  3913. }
  3914. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  3915. return {};
  3916. }
  3917. logStatus.error(`${result}:${statusText}(${status})`);
  3918. return {};
  3919. } catch (error) {
  3920. throwError(error, 'Youtube.getInfo');
  3921. return {};
  3922. }
  3923. };
  3924. class Youtube extends social_Social {
  3925. tasks;
  3926. whiteList;
  3927. #auth = GM_getValue('youtubeAuth') || {};
  3928. #initialized = false;
  3929. #verifyChannel = `https://www.youtube.com/channel/${globalOptions.other.youtubeVerifyChannel}`;
  3930. constructor() {
  3931. super();
  3932. const defaultTasksTemplate = {
  3933. channels: [],
  3934. likes: []
  3935. };
  3936. this.tasks = defaultTasksTemplate;
  3937. this.whiteList = {
  3938. ...defaultTasksTemplate,
  3939. ...GM_getValue('whiteList')?.youtube || {}
  3940. };
  3941. }
  3942. async init() {
  3943. try {
  3944. if (this.#initialized) {
  3945. return true;
  3946. }
  3947. if (!this.#auth.PAPISID) {
  3948. if (await this.#updateAuth()) {
  3949. this.#initialized = true;
  3950. return true;
  3951. }
  3952. return false;
  3953. }
  3954. const isVerified = await this.#verifyAuth();
  3955. if (isVerified) {
  3956. scripts_echoLog({}).success(i18n('initSuccess', 'Youtube'));
  3957. this.#initialized = true;
  3958. return true;
  3959. }
  3960. GM_setValue('youtubeAuth', null);
  3961. if (await this.#updateAuth()) {
  3962. scripts_echoLog({}).success(i18n('initSuccess', 'Youtube'));
  3963. this.#initialized = true;
  3964. return true;
  3965. }
  3966. scripts_echoLog({}).error(i18n('initFailed', 'Youtube'));
  3967. return false;
  3968. } catch (error) {
  3969. throwError(error, 'Youtube.init');
  3970. return false;
  3971. }
  3972. }
  3973. async #verifyAuth() {
  3974. try {
  3975. return await this.#toggleChannel({
  3976. link: this.#verifyChannel,
  3977. doTask: true,
  3978. verify: true
  3979. });
  3980. } catch (error) {
  3981. throwError(error, 'Youtube.verifyAuth');
  3982. return false;
  3983. }
  3984. }
  3985. async #updateAuth() {
  3986. try {
  3987. const logStatus = scripts_echoLog({
  3988. text: i18n('updatingAuth', 'Youtube')
  3989. });
  3990. return await new Promise(resolve => {
  3991. GM_cookie.list({
  3992. url: 'https://www.youtube.com/@YouTube'
  3993. }, async (cookies, error) => {
  3994. if (!error) {
  3995. const PAPISID = cookies.find(cookie => cookie.name === '__Secure-3PAPISID')?.value;
  3996. if (PAPISID) {
  3997. GM_setValue('youtubeAuth', {
  3998. PAPISID: PAPISID
  3999. });
  4000. this.#auth = {
  4001. PAPISID: PAPISID
  4002. };
  4003. logStatus.success();
  4004. resolve(await this.#verifyAuth());
  4005. } else {
  4006. logStatus.error(i18n('needLogin'));
  4007. resolve(false);
  4008. }
  4009. } else {
  4010. logStatus.error('Error: Update youtube auth failed!');
  4011. resolve(false);
  4012. }
  4013. });
  4014. });
  4015. } catch (error) {
  4016. throwError(error, 'Youtube.updateAuth');
  4017. return false;
  4018. }
  4019. }
  4020. #getInfo(link, type) {
  4021. return getInfo(link, type);
  4022. }
  4023. async #toggleChannel({
  4024. link,
  4025. doTask = true,
  4026. verify = false
  4027. }) {
  4028. try {
  4029. const {
  4030. params,
  4031. needLogin
  4032. } = await this.#getInfo(link, 'channel');
  4033. const {
  4034. apiKey,
  4035. client,
  4036. request,
  4037. channelId
  4038. } = params || {};
  4039. if (needLogin) {
  4040. scripts_echoLog({
  4041. html: i18n('loginYtb')
  4042. });
  4043. return false;
  4044. }
  4045. if (!(apiKey && client && request && channelId)) {
  4046. scripts_echoLog({
  4047. text: '"getYtbToken" failed'
  4048. });
  4049. return false;
  4050. }
  4051. if (!doTask && !verify && this.whiteList.channels.includes(channelId)) {
  4052. scripts_echoLog({
  4053. type: 'whiteList',
  4054. text: 'Youtube.unfollowChannel',
  4055. id: channelId
  4056. });
  4057. return true;
  4058. }
  4059. const logStatus = verify ? scripts_echoLog({
  4060. text: i18n('verifyingAuth', 'Youtube')
  4061. }) : scripts_echoLog({
  4062. type: doTask ? 'followingYtbChannel' : 'unfollowingYtbChannel',
  4063. text: channelId
  4064. });
  4065. const nowTime = parseInt(String(new Date().getTime() / 1e3), 10);
  4066. const {
  4067. result,
  4068. statusText,
  4069. status,
  4070. data
  4071. } = await tools_httpRequest({
  4072. url: `https://www.youtube.com/youtubei/v1/subscription/${doTask ? '' : 'un'}subscribe?key=${apiKey}&prettyPrint=false`,
  4073. method: 'POST',
  4074. headers: {
  4075. origin: 'https://www.youtube.com',
  4076. referer: `https://www.youtube.com/channel/${channelId}`,
  4077. 'content-type': 'application/json',
  4078. 'x-goog-authuser': '0',
  4079. 'x-goog-visitor-id': client?.visitorData,
  4080. 'x-origin': 'https://www.youtube.com',
  4081. authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
  4082. },
  4083. data: JSON.stringify({
  4084. context: {
  4085. client: client,
  4086. request: {
  4087. sessionId: request?.sessionId,
  4088. internalExperimentFlags: [],
  4089. consistencyTokenJars: []
  4090. },
  4091. user: {}
  4092. },
  4093. channelIds: [ channelId ],
  4094. params: doTask ? 'EgIIAhgA' : 'CgIIAhgA'
  4095. })
  4096. });
  4097. if (result === 'Success') {
  4098. if (data?.status === 200) {
  4099. if (doTask && (/"subscribed":true/.test(data.responseText) || data.responseText.includes('The subscription already exists')) || !doTask && /"subscribed":false/.test(data.responseText)) {
  4100. logStatus.success();
  4101. if (doTask && !verify) {
  4102. this.tasks.channels = unique([ ...this.tasks.channels, link ]);
  4103. }
  4104. return true;
  4105. }
  4106. if (verify && data.responseText.includes('You may not subscribe to yourself')) {
  4107. logStatus.success();
  4108. return true;
  4109. }
  4110. logStatus.error(i18n('tryUpdateYtbAuth'), true);
  4111. return false;
  4112. }
  4113. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4114. return false;
  4115. }
  4116. logStatus.error(`${result}:${statusText}(${status})`);
  4117. return false;
  4118. } catch (error) {
  4119. throwError(error, 'Youtube.toggleChannel');
  4120. return false;
  4121. }
  4122. }
  4123. async #toggleLikeVideo({
  4124. link,
  4125. doTask = true
  4126. }) {
  4127. try {
  4128. const {
  4129. params,
  4130. needLogin
  4131. } = await this.#getInfo(link, 'likeVideo');
  4132. const {
  4133. apiKey,
  4134. client,
  4135. request,
  4136. videoId,
  4137. likeParams
  4138. } = params || {};
  4139. if (needLogin) {
  4140. scripts_echoLog({
  4141. html: `${i18n('loginYtb')}`
  4142. });
  4143. return false;
  4144. }
  4145. if (!(apiKey && client && request && videoId && likeParams)) {
  4146. scripts_echoLog({
  4147. text: '"getYtbToken" failed'
  4148. });
  4149. return false;
  4150. }
  4151. if (!doTask && this.whiteList.likes.includes(videoId)) {
  4152. scripts_echoLog({
  4153. type: 'whiteList',
  4154. text: 'Youtube.unlikeVideo',
  4155. id: videoId
  4156. });
  4157. return true;
  4158. }
  4159. const logStatus = scripts_echoLog({
  4160. type: doTask ? 'likingYtbVideo' : 'unlikingYtbVideo',
  4161. text: videoId
  4162. });
  4163. const nowTime = parseInt(String(new Date().getTime() / 1e3), 10);
  4164. const likeVideoData = {
  4165. context: {
  4166. client: client,
  4167. request: {
  4168. sessionId: request.sessionId,
  4169. internalExperimentFlags: [],
  4170. consistencyTokenJars: []
  4171. },
  4172. user: {}
  4173. },
  4174. target: {
  4175. videoId: videoId
  4176. }
  4177. };
  4178. if (doTask) {
  4179. if (likeParams) {
  4180. likeVideoData.params = likeParams;
  4181. } else {
  4182. logStatus.error('Empty likeParams');
  4183. return false;
  4184. }
  4185. }
  4186. const {
  4187. result,
  4188. statusText,
  4189. status,
  4190. data
  4191. } = await tools_httpRequest({
  4192. url: `https://www.youtube.com/youtubei/v1/like/${doTask ? '' : 'remove'}like?key=${apiKey}`,
  4193. method: 'POST',
  4194. headers: {
  4195. origin: 'https://www.youtube.com',
  4196. referer: `https://www.youtube.com/watch?v=${videoId}`,
  4197. 'content-type': 'application/json',
  4198. 'x-goog-authuser': '0',
  4199. 'x-goog-visitor-id': client.visitorData,
  4200. 'x-origin': 'https://www.youtube.com',
  4201. authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
  4202. },
  4203. data: JSON.stringify(likeVideoData)
  4204. });
  4205. if (result === 'Success') {
  4206. if (data?.status === 200) {
  4207. if (doTask && data.responseText.includes('Added to Liked videos') || !doTask && (data.responseText.includes('Removed from Liked videos') || data.responseText.includes('Dislike removed'))) {
  4208. logStatus.success();
  4209. if (doTask) {
  4210. this.tasks.likes = unique([ ...this.tasks.likes, link ]);
  4211. }
  4212. return true;
  4213. }
  4214. logStatus.error(i18n('tryUpdateYtbAuth'), true);
  4215. return false;
  4216. }
  4217. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4218. return false;
  4219. }
  4220. logStatus.error(`${result}:${statusText}(${status})`);
  4221. return false;
  4222. } catch (error) {
  4223. throwError(error, 'Youtube.toggleLikeVideo');
  4224. return false;
  4225. }
  4226. }
  4227. async toggle({
  4228. doTask = true,
  4229. channelLinks = [],
  4230. videoLinks = []
  4231. }) {
  4232. try {
  4233. if (!this.#initialized) {
  4234. scripts_echoLog({
  4235. text: i18n('needInit')
  4236. });
  4237. return false;
  4238. }
  4239. const prom = [];
  4240. if (doTask && !globalOptions.doTask.youtube.channels || !doTask && !globalOptions.undoTask.youtube.channels) {
  4241. scripts_echoLog({
  4242. type: 'globalOptionsSkip',
  4243. text: 'youtube.channels'
  4244. });
  4245. } else {
  4246. const realChannels = this.getRealParams('channels', channelLinks, doTask, link => {
  4247. if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
  4248. return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
  4249. }
  4250. return link;
  4251. });
  4252. if (realChannels.length > 0) {
  4253. for (const channel of realChannels) {
  4254. prom.push(this.#toggleChannel({
  4255. link: channel,
  4256. doTask: doTask
  4257. }));
  4258. await delay(1e3);
  4259. }
  4260. }
  4261. }
  4262. if (doTask && !globalOptions.doTask.youtube.likes || !doTask && !globalOptions.undoTask.youtube.likes) {
  4263. scripts_echoLog({
  4264. type: 'globalOptionsSkip',
  4265. text: 'youtube.likes'
  4266. });
  4267. } else {
  4268. const realLikes = this.getRealParams('likes', videoLinks, doTask, link => {
  4269. if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
  4270. return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
  4271. }
  4272. return link;
  4273. });
  4274. if (realLikes.length > 0) {
  4275. for (const video of realLikes) {
  4276. prom.push(this.#toggleLikeVideo({
  4277. link: video,
  4278. doTask: doTask
  4279. }));
  4280. await delay(1e3);
  4281. }
  4282. }
  4283. }
  4284. return Promise.all(prom).then(() => true);
  4285. } catch (error) {
  4286. throwError(error, 'Youtube.toggle');
  4287. return false;
  4288. }
  4289. }
  4290. }
  4291. class SteamASF {
  4292. #asfOptions;
  4293. #botName = 'asf';
  4294. #groupInfo;
  4295. async init() {
  4296. try {
  4297. const asfCommandsUrl = new URL('/Api/Command/', globalOptions.ASF.AsfIpcUrl);
  4298. this.#asfOptions = {
  4299. url: asfCommandsUrl.href,
  4300. method: 'POST',
  4301. responseType: 'json',
  4302. headers: {
  4303. accept: 'application/json',
  4304. 'Content-Type': 'application/json',
  4305. Host: asfCommandsUrl.host,
  4306. Origin: asfCommandsUrl.origin,
  4307. Referer: asfCommandsUrl.href,
  4308. Authentication: globalOptions.ASF.AsfIpcPassword
  4309. }
  4310. };
  4311. if (globalOptions.ASF.AsfBotname) {
  4312. this.#botName = globalOptions.ASF.AsfBotname;
  4313. }
  4314. const logStatus = scripts_echoLog({
  4315. text: i18n('initingASF')
  4316. });
  4317. const {
  4318. result,
  4319. statusText,
  4320. status,
  4321. data
  4322. } = await tools_httpRequest({
  4323. ...this.#asfOptions,
  4324. data: '{"Command":"!stats"}'
  4325. });
  4326. if (result === 'Success') {
  4327. if (data?.response?.Success === true && data.response.Message === 'OK' && data.response.Result) {
  4328. logStatus.success();
  4329. return true;
  4330. }
  4331. if (data?.response?.Result || data?.response?.Message) {
  4332. logStatus.error(data?.response?.Result || data.response.Message);
  4333. return false;
  4334. }
  4335. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4336. return false;
  4337. }
  4338. logStatus.error(`${result}:${statusText}(${status})`);
  4339. return false;
  4340. } catch (error) {
  4341. throwError(error, 'SteamASF.init');
  4342. return false;
  4343. }
  4344. }
  4345. async joinGroup(groupName) {
  4346. try {
  4347. const logStatus = scripts_echoLog({
  4348. type: 'joiningSteamGroup',
  4349. text: groupName
  4350. });
  4351. const {
  4352. result,
  4353. statusText,
  4354. status,
  4355. data
  4356. } = await tools_httpRequest({
  4357. ...this.#asfOptions,
  4358. data: JSON.stringify({
  4359. Command: `!JOINGROUP ${this.#botName} ${groupName}`
  4360. })
  4361. });
  4362. if (result === 'Success') {
  4363. if (data?.status === 200 && [ '已加入', '已申请', 'Joined', 'Applied', 'Присоединился', 'costs' ].find(text => data.response?.Result?.includes(text))) {
  4364. logStatus.success();
  4365. return true;
  4366. }
  4367. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4368. return false;
  4369. }
  4370. logStatus.error(`${result}:${statusText}(${status})`);
  4371. return false;
  4372. } catch (error) {
  4373. throwError(error, 'SteamASF.joinGroup');
  4374. return false;
  4375. }
  4376. }
  4377. async leaveGroup(groupName) {
  4378. try {
  4379. if (!this.#groupInfo) {
  4380. if (!await this.#getGroupId()) {
  4381. return false;
  4382. }
  4383. }
  4384. const groupId = await this.#groupInfo[groupName];
  4385. if (!groupId) {
  4386. return false;
  4387. }
  4388. const logStatus = scripts_echoLog({
  4389. type: 'leavingSteamGroup',
  4390. text: groupName
  4391. });
  4392. const {
  4393. result,
  4394. statusText,
  4395. status,
  4396. data
  4397. } = await tools_httpRequest({
  4398. ...this.#asfOptions,
  4399. data: JSON.stringify({
  4400. Command: `!LEAVEGROUP ${this.#botName} ${groupId}`
  4401. })
  4402. });
  4403. if (result === 'Success') {
  4404. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4405. logStatus.success();
  4406. return true;
  4407. }
  4408. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4409. return false;
  4410. }
  4411. logStatus.error(`${result}:${statusText}(${status})`);
  4412. return false;
  4413. } catch (error) {
  4414. throwError(error, 'SteamASF.leaveGroup');
  4415. return false;
  4416. }
  4417. }
  4418. async #getGroupId() {
  4419. try {
  4420. const logStatus = scripts_echoLog({
  4421. type: 'gettingSteamGroupId',
  4422. text: 'All'
  4423. });
  4424. const {
  4425. result,
  4426. statusText,
  4427. status,
  4428. data
  4429. } = await tools_httpRequest({
  4430. ...this.#asfOptions,
  4431. data: JSON.stringify({
  4432. Command: `!GROUPLIST ${this.#botName}`
  4433. })
  4434. });
  4435. if (result === 'Success') {
  4436. if (data?.status === 200 && data.response?.Result?.includes('|')) {
  4437. this.#groupInfo = Object.fromEntries(data.response.Result.split('\n').map(line => {
  4438. const [ , name, id ] = line.trim().split('|');
  4439. if (name && id) {
  4440. return [ name, id ];
  4441. }
  4442. return null;
  4443. }).filter(ele => ele));
  4444. logStatus.success();
  4445. return true;
  4446. }
  4447. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4448. return false;
  4449. }
  4450. logStatus.error(`${result}:${statusText}(${status})`);
  4451. return false;
  4452. } catch (error) {
  4453. throwError(error, 'SteamASF.getGroupID');
  4454. return false;
  4455. }
  4456. }
  4457. async addToWishlist(gameId) {
  4458. try {
  4459. const logStatus = scripts_echoLog({
  4460. type: 'addingToWishlist',
  4461. text: gameId
  4462. });
  4463. if ((await this.#checkGame(gameId)).wishlist === true) {
  4464. logStatus.success();
  4465. return true;
  4466. }
  4467. const {
  4468. result,
  4469. statusText,
  4470. status,
  4471. data
  4472. } = await tools_httpRequest({
  4473. ...this.#asfOptions,
  4474. data: JSON.stringify({
  4475. Command: `!ADDWISHLIST ${this.#botName} ${gameId}`
  4476. })
  4477. });
  4478. if (result === 'Success') {
  4479. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4480. logStatus.success();
  4481. return true;
  4482. }
  4483. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4484. return false;
  4485. }
  4486. logStatus.error(`${result}:${statusText}(${status})`);
  4487. return false;
  4488. } catch (error) {
  4489. throwError(error, 'SteamASF.addToWishlist');
  4490. return false;
  4491. }
  4492. }
  4493. async removeFromWishlist(gameId) {
  4494. try {
  4495. const logStatus = scripts_echoLog({
  4496. type: 'removingFromWishlist',
  4497. text: gameId
  4498. });
  4499. if ((await this.#checkGame(gameId)).wishlist === false) {
  4500. logStatus.success();
  4501. return true;
  4502. }
  4503. const {
  4504. result,
  4505. statusText,
  4506. status,
  4507. data
  4508. } = await tools_httpRequest({
  4509. ...this.#asfOptions,
  4510. data: JSON.stringify({
  4511. Command: `!REMOVEWISHLIST ${this.#botName} ${gameId}`
  4512. })
  4513. });
  4514. if (result === 'Success') {
  4515. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4516. logStatus.success();
  4517. return true;
  4518. }
  4519. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4520. return false;
  4521. }
  4522. logStatus.error(`${result}:${statusText}(${status})`);
  4523. return false;
  4524. } catch (error) {
  4525. throwError(error, 'SteamASF.removeFromWishlist');
  4526. return false;
  4527. }
  4528. }
  4529. async toggleFollowGame(gameId, doTask) {
  4530. try {
  4531. const logStatus = scripts_echoLog({
  4532. type: `${doTask ? '' : 'un'}followingGame`,
  4533. text: gameId
  4534. });
  4535. if (doTask && (await this.#checkGame(gameId)).followed === true || !doTask && (await this.#checkGame(gameId)).followed === false) {
  4536. logStatus.success();
  4537. return true;
  4538. }
  4539. const {
  4540. result,
  4541. statusText,
  4542. status,
  4543. data
  4544. } = await tools_httpRequest({
  4545. ...this.#asfOptions,
  4546. data: JSON.stringify({
  4547. Command: `!${doTask ? '' : 'UN'}FOLLOWGAME ${this.#botName} ${gameId}`
  4548. })
  4549. });
  4550. if (result === 'Success') {
  4551. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4552. logStatus.success();
  4553. return true;
  4554. }
  4555. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4556. return false;
  4557. }
  4558. logStatus.error(`${result}:${statusText}(${status})`);
  4559. return false;
  4560. } catch (error) {
  4561. throwError(error, 'SteamASF.toggleFollowGame');
  4562. return false;
  4563. }
  4564. }
  4565. async #checkGame(gameId) {
  4566. try {
  4567. const {
  4568. result,
  4569. data
  4570. } = await tools_httpRequest({
  4571. ...this.#asfOptions,
  4572. data: JSON.stringify({
  4573. Command: `!CHECK ${this.#botName} ${gameId}`
  4574. })
  4575. });
  4576. if (result === 'Success') {
  4577. if (data?.status === 200 && data.response?.Result?.includes(gameId)) {
  4578. const matchedResult = data.response.Result.split('\n').find(result => result.includes(gameId))?.split('|');
  4579. if (matchedResult?.length > 3) {
  4580. return {
  4581. wishlist: matchedResult.at(-3).trim() === '√' || matchedResult.at(-2).trim() === '√',
  4582. followed: matchedResult.at(-1).trim() === '√'
  4583. };
  4584. }
  4585. return {};
  4586. }
  4587. return {};
  4588. }
  4589. return {};
  4590. } catch (error) {
  4591. throwError(error, 'SteamASF.checkGame');
  4592. return {};
  4593. }
  4594. }
  4595. async toggleCurator(curatorId, doTask = true) {
  4596. try {
  4597. const logStatus = scripts_echoLog({
  4598. type: doTask ? 'followingCurator' : 'unfollowingCurator',
  4599. text: curatorId
  4600. });
  4601. const {
  4602. result,
  4603. statusText,
  4604. status,
  4605. data
  4606. } = await tools_httpRequest({
  4607. ...this.#asfOptions,
  4608. data: JSON.stringify({
  4609. Command: `!${doTask ? '' : 'UN'}FOLLOWCURATOR ${this.#botName} ${curatorId}`
  4610. })
  4611. });
  4612. if (result === 'Success') {
  4613. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4614. logStatus.success();
  4615. return true;
  4616. }
  4617. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4618. return false;
  4619. }
  4620. logStatus.error(`${result}:${statusText}(${status})`);
  4621. return false;
  4622. } catch (error) {
  4623. throwError(error, 'Steam.toggleCurator');
  4624. return false;
  4625. }
  4626. }
  4627. async addLicense(id) {
  4628. try {
  4629. const [ type, ids ] = id.split('-');
  4630. if (type === 'appid') {
  4631. const logStatus = scripts_echoLog({
  4632. type: 'addingFreeLicense',
  4633. text: ids
  4634. });
  4635. const {
  4636. result,
  4637. statusText,
  4638. status,
  4639. data
  4640. } = await tools_httpRequest({
  4641. ...this.#asfOptions,
  4642. data: JSON.stringify({
  4643. Command: `!addlicense ${this.#botName} app/${ids}`
  4644. })
  4645. });
  4646. if (result === 'Success') {
  4647. if (data?.status === 200 && [ 'AlreadyPurchased', 'OK' ].find(text => data.response?.Result?.includes(text))) {
  4648. logStatus.success();
  4649. return true;
  4650. }
  4651. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4652. return false;
  4653. }
  4654. logStatus.error(`${result}:${statusText}(${status})`);
  4655. return false;
  4656. } else if (type === 'subid') {
  4657. const idsArr = ids.split(',');
  4658. const logStatus = scripts_echoLog({
  4659. type: 'addingFreeLicenseSubid',
  4660. text: ids
  4661. });
  4662. const {
  4663. result,
  4664. statusText,
  4665. status,
  4666. data
  4667. } = await tools_httpRequest({
  4668. ...this.#asfOptions,
  4669. data: JSON.stringify({
  4670. Command: `!addlicense ${this.#botName} ${idsArr.map(id => `sub/${id}`).join(',')}`
  4671. })
  4672. });
  4673. if (result === 'Success') {
  4674. if (data?.status === 200 && data.response?.Result) {
  4675. const resultLines = data.response.Result.split('\n');
  4676. idsArr.forEach(subid => {
  4677. const targetLine = resultLines.find(text => text.includes(subid));
  4678. if (targetLine && [ '成功', 'Success', 'Успех' ].find(text => targetLine.includes(text))) {
  4679. scripts_echoLog({}).success(targetLine);
  4680. } else {
  4681. scripts_echoLog({}).error(targetLine);
  4682. }
  4683. });
  4684. return true;
  4685. }
  4686. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4687. return false;
  4688. }
  4689. logStatus.error(`${result}:${statusText}(${status})`);
  4690. return false;
  4691. }
  4692. return false;
  4693. } catch (error) {
  4694. throwError(error, 'SteamASF.addLicense');
  4695. return false;
  4696. }
  4697. }
  4698. async requestPlayTestAccess(id) {
  4699. try {
  4700. const logStatus = scripts_echoLog({
  4701. type: 'requestingPlayTestAccess',
  4702. text: id
  4703. });
  4704. const {
  4705. result,
  4706. statusText,
  4707. status,
  4708. data
  4709. } = await tools_httpRequest({
  4710. ...this.#asfOptions,
  4711. data: JSON.stringify({
  4712. Command: `!REQUESTACCESS ${this.#botName} ${id}`
  4713. })
  4714. });
  4715. if (result === 'Success') {
  4716. if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find(text => data.response?.Result?.includes(text))) {
  4717. logStatus.success();
  4718. return true;
  4719. }
  4720. logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
  4721. return false;
  4722. }
  4723. logStatus.error(`${result}:${statusText}(${status})`);
  4724. return false;
  4725. } catch (error) {
  4726. throwError(error, 'Steam.requestPlayTestAccess');
  4727. return false;
  4728. }
  4729. }
  4730. }
  4731. const social_SteamASF = SteamASF;
  4732. class Steam extends social_Social {
  4733. tasks;
  4734. whiteList;
  4735. #cache = {
  4736. ...{
  4737. group: {},
  4738. officialGroup: {},
  4739. forum: {},
  4740. workshop: {},
  4741. curator: {}
  4742. },
  4743. ...GM_getValue('steamCache')
  4744. };
  4745. #auth = {};
  4746. #storeInitialized = false;
  4747. #communityInitialized = false;
  4748. #area = 'CN';
  4749. #oldArea;
  4750. #areaStatus = 'end';
  4751. #ASF;
  4752. constructor() {
  4753. super();
  4754. const defaultTasksTemplate = {
  4755. groups: [],
  4756. officialGroups: [],
  4757. wishlists: [],
  4758. follows: [],
  4759. forums: [],
  4760. workshops: [],
  4761. workshopVotes: [],
  4762. curators: [],
  4763. curatorLikes: [],
  4764. announcements: [],
  4765. licenses: [],
  4766. playtests: []
  4767. };
  4768. this.tasks = defaultTasksTemplate;
  4769. this.whiteList = {
  4770. ...defaultTasksTemplate,
  4771. ...GM_getValue('whiteList')?.steam || {}
  4772. };
  4773. }
  4774. async init(type = 'all') {
  4775. try {
  4776. if (globalOptions.ASF.AsfEnabled && globalOptions.ASF.AsfIpcUrl && globalOptions.ASF.AsfIpcPassword) {
  4777. this.#ASF = new social_SteamASF();
  4778. if (await this.#ASF.init()) {
  4779. this.#storeInitialized = true;
  4780. this.#communityInitialized = true;
  4781. return true;
  4782. }
  4783. return false;
  4784. }
  4785. if (type === 'store') {
  4786. if (this.#storeInitialized) {
  4787. return true;
  4788. }
  4789. let storeInitialized = await this.#updateStoreAuth();
  4790. if (!storeInitialized) {
  4791. storeInitialized = await this.#updateStoreAuthTab();
  4792. }
  4793. this.#storeInitialized = storeInitialized;
  4794. if (!this.#storeInitialized) {
  4795. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  4796. return false;
  4797. }
  4798. scripts_echoLog({}).success(i18n('initSuccess', 'SteamStore'));
  4799. return true;
  4800. }
  4801. if (type === 'community') {
  4802. if (this.#communityInitialized) {
  4803. return true;
  4804. }
  4805. let communityInitialized = await this.#updateCommunityAuth();
  4806. if (!communityInitialized) {
  4807. communityInitialized = await this.#updateCommunityAuthTab();
  4808. GM_setValue('steamCommunityAuth', null);
  4809. }
  4810. this.#communityInitialized = communityInitialized;
  4811. if (!this.#communityInitialized) {
  4812. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  4813. return false;
  4814. }
  4815. scripts_echoLog({}).success(i18n('initSuccess', 'SteamCommunity'));
  4816. return true;
  4817. }
  4818. if (this.#storeInitialized && this.#communityInitialized) {
  4819. scripts_echoLog({}).success(i18n('initSuccess', 'Steam'));
  4820. return true;
  4821. }
  4822. scripts_echoLog({}).error(i18n('initFailed', 'Steam'));
  4823. return false;
  4824. } catch (error) {
  4825. throwError(error, 'Steam.init');
  4826. return false;
  4827. }
  4828. }
  4829. async #refreshToken(type = 'steamStore') {
  4830. try {
  4831. const host = {
  4832. steamStore: 'store.steampowered.com',
  4833. steamCommunity: 'steamcommunity.com'
  4834. };
  4835. const logStatus = scripts_echoLog({
  4836. text: i18n('refreshingToken', i18n(type))
  4837. });
  4838. const formData = new FormData();
  4839. formData.append('redir', `https://${host[type]}/`);
  4840. const {
  4841. result,
  4842. statusText,
  4843. status,
  4844. data
  4845. } = await tools_httpRequest({
  4846. url: 'https://login.steampowered.com/jwt/ajaxrefresh',
  4847. method: 'POST',
  4848. responseType: 'json',
  4849. headers: {
  4850. Host: 'login.steampowered.com',
  4851. Origin: `https://${host[type]}`,
  4852. Referer: `https://${host[type]}/`
  4853. },
  4854. data: formData
  4855. });
  4856. if (result === 'Success') {
  4857. if (data?.response?.success) {
  4858. if (await this.#setStoreToken(data.response, type)) {
  4859. logStatus.success();
  4860. return true;
  4861. }
  4862. logStatus.error('Error');
  4863. return false;
  4864. }
  4865. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4866. return false;
  4867. }
  4868. logStatus.error(`${result}:${statusText}(${status})`);
  4869. return false;
  4870. } catch (error) {
  4871. throwError(error, 'Steam.refreshToken');
  4872. return false;
  4873. }
  4874. }
  4875. async #setStoreToken(param, type) {
  4876. try {
  4877. const host = {
  4878. steamStore: 'store.steampowered.com',
  4879. steamCommunity: 'steamcommunity.com'
  4880. };
  4881. const logStatus = scripts_echoLog({
  4882. text: i18n('settingToken', i18n(type))
  4883. });
  4884. const formData = new FormData();
  4885. formData.append('steamID', param.steamID);
  4886. formData.append('nonce', param.nonce);
  4887. formData.append('redir', param.redir);
  4888. formData.append('auth', param.auth);
  4889. const {
  4890. result,
  4891. statusText,
  4892. status,
  4893. data
  4894. } = await tools_httpRequest({
  4895. url: `https://${host[type]}/login/settoken`,
  4896. method: 'POST',
  4897. headers: {
  4898. Accept: 'application/json, text/plain, */*',
  4899. Host: host[type],
  4900. Origin: `https://${host[type]}`
  4901. },
  4902. data: formData
  4903. });
  4904. if (result === 'Success') {
  4905. if (data?.status === 200) {
  4906. logStatus.success();
  4907. return true;
  4908. }
  4909. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  4910. return false;
  4911. }
  4912. logStatus.error(`${result}:${statusText}(${status})`);
  4913. return false;
  4914. } catch (error) {
  4915. throwError(error, 'Steam.setStoreToken');
  4916. return false;
  4917. }
  4918. }
  4919. async #updateStoreAuth(retry = false) {
  4920. try {
  4921. const logStatus = scripts_echoLog({
  4922. text: i18n('updatingAuth', i18n('steamStore'))
  4923. });
  4924. const {
  4925. result,
  4926. statusText,
  4927. status,
  4928. data
  4929. } = await tools_httpRequest({
  4930. url: 'https://store.steampowered.com/',
  4931. method: 'GET',
  4932. headers: {
  4933. 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',
  4934. 'Sec-Fetch-Dest': 'document',
  4935. 'Sec-Fetch-Mode': 'navigate',
  4936. 'Upgrade-Insecure-Requests': '1'
  4937. },
  4938. fetch: false,
  4939. redirect: 'manual'
  4940. });
  4941. if (data?.status === 200) {
  4942. if (!data.responseText.includes('data-miniprofile=')) {
  4943. if (await this.#refreshToken('steamStore')) {
  4944. logStatus.warning(i18n('retry'));
  4945. if (retry) {
  4946. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  4947. return false;
  4948. }
  4949. return this.#updateStoreAuth(true);
  4950. }
  4951. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  4952. return false;
  4953. }
  4954. const storeSessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
  4955. if (storeSessionID) {
  4956. this.#auth.storeSessionID = storeSessionID;
  4957. logStatus.success();
  4958. return true;
  4959. }
  4960. logStatus.error('Error: Get "sessionID" failed');
  4961. return false;
  4962. }
  4963. if ([ 301, 302 ].includes(data?.status)) {
  4964. if (await this.#refreshToken('steamStore')) {
  4965. logStatus.warning(i18n('retry'));
  4966. if (retry) {
  4967. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  4968. return false;
  4969. }
  4970. return this.#updateStoreAuth(true);
  4971. }
  4972. logStatus.error(`Error:${i18n('needLoginSteamStore')}`, true);
  4973. return false;
  4974. }
  4975. logStatus.error(`${result}:${statusText}(${status})`);
  4976. return false;
  4977. } catch (error) {
  4978. throwError(error, 'Steam.updateStoreAuth');
  4979. return false;
  4980. }
  4981. }
  4982. async #updateStoreAuthTab() {
  4983. try {
  4984. const logStatus = scripts_echoLog({
  4985. text: i18n('updatingAuth', i18n('steamStoreTab'))
  4986. });
  4987. return await new Promise(resolve => {
  4988. GM_deleteValue('steamStoreAuth');
  4989. GM_setValue('ATv4_updateStoreAuth', true);
  4990. const newTab = GM_openInTab('https://store.steampowered.com/', {
  4991. active: true,
  4992. setParent: true
  4993. });
  4994. newTab.name = 'ATv4_updateStoreAuth';
  4995. const listenerId = GM_addValueChangeListener('steamStoreAuth', (key, oldValue, newValue) => {
  4996. GM_removeValueChangeListener(listenerId);
  4997. GM_deleteValue('ATv4_updateStoreAuth');
  4998. newTab?.close();
  4999. window.focus();
  5000. if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
  5001. this.#auth.storeSessionID = newValue.storeSessionID;
  5002. logStatus.success();
  5003. resolve(true);
  5004. return;
  5005. }
  5006. logStatus.error('Failed');
  5007. resolve(false);
  5008. });
  5009. newTab.onclose = () => {
  5010. GM_deleteValue('ATv4_updateStoreAuth');
  5011. };
  5012. });
  5013. } catch (error) {
  5014. throwError(error, 'Steam.updateStoreAuthTab');
  5015. return false;
  5016. }
  5017. }
  5018. async #updateCommunityAuthTab() {
  5019. try {
  5020. const logStatus = scripts_echoLog({
  5021. text: i18n('updatingAuth', i18n('steamCommunityTab'))
  5022. });
  5023. return await new Promise(resolve => {
  5024. GM_deleteValue('steamCommunityAuth');
  5025. GM_setValue('ATv4_updateCommunityAuth', true);
  5026. const newTab = GM_openInTab('https://steamcommunity.com/my', {
  5027. active: true,
  5028. setParent: true
  5029. });
  5030. newTab.name = 'ATv4_updateCommunityAuth';
  5031. const listenerId = GM_addValueChangeListener('steamCommunityAuth', (key, oldValue, newValue) => {
  5032. GM_removeValueChangeListener(listenerId);
  5033. GM_deleteValue('ATv4_updateCommunityAuth');
  5034. newTab?.close();
  5035. window.focus();
  5036. if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
  5037. this.#auth.steam64Id = newValue.steam64Id;
  5038. this.#auth.communitySessionID = newValue.communitySessionID;
  5039. logStatus.success();
  5040. resolve(true);
  5041. return;
  5042. }
  5043. logStatus.error('Failed');
  5044. resolve(false);
  5045. });
  5046. newTab.onclose = () => {
  5047. GM_deleteValue('ATv4_updateCommunityAuth');
  5048. };
  5049. });
  5050. } catch (error) {
  5051. throwError(error, 'Steam.updateCommunityAuthTab');
  5052. return false;
  5053. }
  5054. }
  5055. async #updateCommunityAuth() {
  5056. try {
  5057. const logStatus = scripts_echoLog({
  5058. text: i18n('gettingUserLink')
  5059. });
  5060. const {
  5061. result,
  5062. statusText,
  5063. status,
  5064. data
  5065. } = await tools_httpRequest({
  5066. url: 'https://steamcommunity.com/my',
  5067. method: 'GET',
  5068. headers: {
  5069. 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',
  5070. Host: 'steamcommunity.com',
  5071. 'Sec-Fetch-Dest': 'document',
  5072. 'Sec-Fetch-Mode': 'navigate'
  5073. },
  5074. fetch: false
  5075. });
  5076. if (data?.status === 200) {
  5077. if (data.finalUrl.includes('https://steamcommunity.com/login/home')) {
  5078. logStatus.error(`Error:${i18n('needLoginSteamCommunity')}`, true);
  5079. return false;
  5080. }
  5081. const steam64Id = data.responseText.match(/g_steamID = "(.+?)";/)?.[1];
  5082. const communitySessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
  5083. if (steam64Id && communitySessionID) {
  5084. this.#auth.steam64Id = steam64Id;
  5085. this.#auth.communitySessionID = communitySessionID;
  5086. logStatus.success();
  5087. return true;
  5088. }
  5089. logStatus.error('Error: Get "sessionID" failed');
  5090. return false;
  5091. }
  5092. logStatus.error(`${result}:${statusText}(${status})`);
  5093. return false;
  5094. } catch (error) {
  5095. throwError(error, 'Steam.updateCommunityAuth');
  5096. return false;
  5097. }
  5098. }
  5099. async #getAreaInfo() {
  5100. try {
  5101. const logStatus = scripts_echoLog({
  5102. text: i18n('gettingAreaInfo')
  5103. });
  5104. const {
  5105. result,
  5106. statusText,
  5107. status,
  5108. data
  5109. } = await tools_httpRequest({
  5110. url: 'https://store.steampowered.com/cart/',
  5111. method: 'GET'
  5112. });
  5113. if (result === 'Success') {
  5114. if (data?.status === 200) {
  5115. const cartConfigRaw = data.responseText.match(/data-cart_config="(.*?)"/)?.[1];
  5116. const temp = document.createElement('div');
  5117. temp.innerHTML = cartConfigRaw || '{}';
  5118. const cartConfigStr = temp.textContent || temp.innerText;
  5119. let cartConfig;
  5120. try {
  5121. cartConfig = JSON.parse(cartConfigStr);
  5122. } catch (error) {
  5123. logStatus.error('Error: get country info filed');
  5124. console.error(error);
  5125. return {};
  5126. }
  5127. if (!cartConfig.rgUserCountryOptions) {
  5128. logStatus.warning('Warning: Area cannot be changed');
  5129. return {};
  5130. }
  5131. const userInfoRaw = data.responseText.match(/data-userinfo="(.*?)"/)?.[1];
  5132. const temp1 = document.createElement('div');
  5133. temp1.innerHTML = userInfoRaw || '{}';
  5134. const userInfoStr = temp1.textContent || temp1.innerText;
  5135. let userInfo;
  5136. try {
  5137. userInfo = JSON.parse(userInfoStr);
  5138. } catch (error) {
  5139. logStatus.error('Error: get country info filed');
  5140. console.error(error);
  5141. return {};
  5142. }
  5143. const currentArea = userInfo.country_code;
  5144. const areas = Object.keys(cartConfig.rgUserCountryOptions).filter(area => area !== 'help');
  5145. if (currentArea && areas.length > 0) {
  5146. this.#area = currentArea;
  5147. logStatus.success();
  5148. return {
  5149. currentArea: currentArea,
  5150. areas: areas
  5151. };
  5152. }
  5153. logStatus.error('Error: get country info filed');
  5154. return {};
  5155. }
  5156. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5157. return {};
  5158. }
  5159. logStatus.error(`${result}:${statusText}(${status})`);
  5160. return {};
  5161. } catch (error) {
  5162. throwError(error, 'Steam.getAreaInfo');
  5163. return {};
  5164. }
  5165. }
  5166. async #changeArea(area) {
  5167. try {
  5168. if (this.#areaStatus === 'waiting') {
  5169. await new Promise(resolve => {
  5170. const checker = setInterval(() => {
  5171. if (this.#areaStatus !== 'waiting') {
  5172. clearInterval(checker);
  5173. resolve(true);
  5174. }
  5175. });
  5176. });
  5177. }
  5178. if (this.#area === area || !area && this.#area !== 'CN') {
  5179. return true;
  5180. }
  5181. this.#areaStatus = 'waiting';
  5182. let aimedArea = area;
  5183. if (!aimedArea) {
  5184. const {
  5185. currentArea,
  5186. areas
  5187. } = await this.#getAreaInfo();
  5188. if (!currentArea || !areas) {
  5189. this.#areaStatus = 'error';
  5190. return false;
  5191. }
  5192. if (currentArea !== 'CN') {
  5193. this.#areaStatus = 'skip';
  5194. scripts_echoLog({
  5195. text: 'notNeededChangeArea'
  5196. });
  5197. return 'skip';
  5198. }
  5199. const anotherArea = areas.filter(area => area && area !== 'CN');
  5200. if (!anotherArea || anotherArea.length === 0) {
  5201. this.#areaStatus = 'noAnotherArea';
  5202. scripts_echoLog({
  5203. text: 'noAnotherArea'
  5204. });
  5205. return false;
  5206. }
  5207. [ aimedArea ] = anotherArea;
  5208. }
  5209. const logStatus = scripts_echoLog({
  5210. text: i18n('changingArea', aimedArea)
  5211. });
  5212. const {
  5213. result,
  5214. statusText,
  5215. status,
  5216. data
  5217. } = await tools_httpRequest({
  5218. url: 'https://store.steampowered.com/country/setcountry',
  5219. method: 'POST',
  5220. headers: {
  5221. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5222. },
  5223. data: $.param({
  5224. cc: aimedArea,
  5225. sessionid: this.#auth.storeSessionID
  5226. })
  5227. });
  5228. if (result === 'Success') {
  5229. if (data?.status === 200 && data.responseText === 'true') {
  5230. const {
  5231. currentArea
  5232. } = await this.#getAreaInfo();
  5233. if (currentArea) {
  5234. this.#area = currentArea;
  5235. if (!this.#oldArea) {
  5236. this.#oldArea = currentArea;
  5237. }
  5238. }
  5239. if (currentArea === aimedArea) {
  5240. this.#areaStatus = 'success';
  5241. logStatus.success();
  5242. return currentArea;
  5243. }
  5244. this.#areaStatus = 'error';
  5245. logStatus.error('Error: change country filed');
  5246. return 'CN';
  5247. }
  5248. this.#areaStatus = 'error';
  5249. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5250. return 'CN';
  5251. }
  5252. this.#areaStatus = 'error';
  5253. logStatus.error(`${result}:${statusText}(${status})`);
  5254. return 'CN';
  5255. } catch (error) {
  5256. this.#areaStatus = 'error';
  5257. throwError(error, 'Steam.changeArea');
  5258. return false;
  5259. }
  5260. }
  5261. async #joinGroup(groupName) {
  5262. try {
  5263. if (this.#ASF) {
  5264. if (await this.#ASF.joinGroup(groupName)) {
  5265. this.tasks.groups = unique([ ...this.tasks.groups, groupName ]);
  5266. return true;
  5267. }
  5268. return false;
  5269. }
  5270. const logStatus = scripts_echoLog({
  5271. type: 'joiningSteamGroup',
  5272. text: groupName
  5273. });
  5274. const {
  5275. result,
  5276. statusText,
  5277. status,
  5278. data
  5279. } = await tools_httpRequest({
  5280. url: `https://steamcommunity.com/groups/${groupName}`,
  5281. method: 'POST',
  5282. headers: {
  5283. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5284. },
  5285. data: $.param({
  5286. action: 'join',
  5287. sessionID: this.#auth.communitySessionID
  5288. })
  5289. });
  5290. if (result === 'Success') {
  5291. if (data?.status === 200 && !data.responseText.includes('grouppage_join_area')) {
  5292. logStatus.success();
  5293. this.tasks.groups = unique([ ...this.tasks.groups, groupName ]);
  5294. return true;
  5295. }
  5296. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5297. return false;
  5298. }
  5299. logStatus.error(`${result}:${statusText}(${status})`);
  5300. return false;
  5301. } catch (error) {
  5302. throwError(error, 'Steam.joinGroup');
  5303. return false;
  5304. }
  5305. }
  5306. async #leaveGroup(groupName) {
  5307. try {
  5308. if (this.whiteList.groups.includes(groupName)) {
  5309. scripts_echoLog({
  5310. type: 'whiteList',
  5311. text: 'Steam.leaveGroup',
  5312. id: groupName
  5313. });
  5314. return true;
  5315. }
  5316. if (this.#ASF) {
  5317. return await this.#ASF.leaveGroup(groupName);
  5318. }
  5319. const groupId = await this.#getGroupId(groupName);
  5320. if (!groupId) {
  5321. return false;
  5322. }
  5323. const logStatus = scripts_echoLog({
  5324. type: 'leavingSteamGroup',
  5325. text: groupName
  5326. });
  5327. const {
  5328. result,
  5329. statusText,
  5330. status,
  5331. data
  5332. } = await tools_httpRequest({
  5333. url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
  5334. method: 'POST',
  5335. headers: {
  5336. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5337. },
  5338. data: $.param({
  5339. sessionID: this.#auth.communitySessionID,
  5340. action: 'leaveGroup',
  5341. groupId: groupId
  5342. })
  5343. });
  5344. if (result === 'Success') {
  5345. 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) {
  5346. logStatus.success();
  5347. return true;
  5348. }
  5349. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5350. return false;
  5351. }
  5352. logStatus.error(`${result}:${statusText}(${status})`);
  5353. return false;
  5354. } catch (error) {
  5355. throwError(error, 'Steam.leaveGroup');
  5356. return false;
  5357. }
  5358. }
  5359. async #getGroupId(groupName) {
  5360. try {
  5361. const logStatus = scripts_echoLog({
  5362. type: 'gettingSteamGroupId',
  5363. text: groupName
  5364. });
  5365. const groupId = this.#cache.group[groupName];
  5366. if (groupId) {
  5367. logStatus.success();
  5368. return groupId;
  5369. }
  5370. const {
  5371. result,
  5372. statusText,
  5373. status,
  5374. data
  5375. } = await tools_httpRequest({
  5376. url: `https://steamcommunity.com/groups/${groupName}`,
  5377. method: 'GET',
  5378. headers: {
  5379. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5380. }
  5381. });
  5382. if (result === 'Success') {
  5383. if (data?.status === 200) {
  5384. const groupId = data.responseText.match(/OpenGroupChat\( '([0-9]+)'/)?.[1];
  5385. if (groupId) {
  5386. this.#setCache('group', groupName, groupId);
  5387. logStatus.success();
  5388. return groupId;
  5389. }
  5390. logStatus.error(`Error:${data.statusText}(${data.status})`);
  5391. return false;
  5392. }
  5393. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5394. return false;
  5395. }
  5396. logStatus.error(`${result}:${statusText}(${status})`);
  5397. return false;
  5398. } catch (error) {
  5399. throwError(error, 'Steam.getGroupID');
  5400. return false;
  5401. }
  5402. }
  5403. async #joinOfficialGroup(gameId) {
  5404. try {
  5405. if (this.#ASF) {
  5406. if (await this.#ASF.joinGroup(gameId)) {
  5407. this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]);
  5408. return true;
  5409. }
  5410. return false;
  5411. }
  5412. const logStatus = scripts_echoLog({
  5413. type: 'joiningSteamOfficialGroup',
  5414. text: gameId
  5415. });
  5416. const {
  5417. result,
  5418. statusText,
  5419. status,
  5420. data
  5421. } = await tools_httpRequest({
  5422. url: `https://steamcommunity.com/games/${gameId}?action=join&sessionID=${this.#auth.communitySessionID}`,
  5423. method: 'GET',
  5424. headers: {
  5425. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5426. }
  5427. });
  5428. if (result === 'Success') {
  5429. if (data?.status === 200 && !data.responseText.includes('id="publicGroupJoin"')) {
  5430. logStatus.success();
  5431. this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]);
  5432. const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
  5433. if (groupId) {
  5434. this.#setCache('officialGroup', gameId, groupId);
  5435. }
  5436. return true;
  5437. }
  5438. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5439. return false;
  5440. }
  5441. logStatus.error(`${result}:${statusText}(${status})`);
  5442. return false;
  5443. } catch (error) {
  5444. throwError(error, 'Steam.joinOfficialGroup');
  5445. return false;
  5446. }
  5447. }
  5448. async #leaveOfficialGroup(gameId) {
  5449. try {
  5450. if (this.whiteList.officialGroups.includes(gameId)) {
  5451. scripts_echoLog({
  5452. type: 'whiteList',
  5453. text: 'Steam.leaveOfficialGroup',
  5454. id: gameId
  5455. });
  5456. return true;
  5457. }
  5458. if (this.#ASF) {
  5459. return await this.#ASF.leaveGroup(gameId);
  5460. }
  5461. const groupId = await this.#getOfficialGroupId(gameId);
  5462. if (!groupId) {
  5463. return false;
  5464. }
  5465. const logStatus = scripts_echoLog({
  5466. type: 'leavingSteamOfficialGroup',
  5467. text: gameId
  5468. });
  5469. const {
  5470. result,
  5471. statusText,
  5472. status,
  5473. data
  5474. } = await tools_httpRequest({
  5475. url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
  5476. method: 'POST',
  5477. headers: {
  5478. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5479. },
  5480. data: $.param({
  5481. sessionID: this.#auth.communitySessionID,
  5482. action: 'leaveGroup',
  5483. groupId: groupId
  5484. })
  5485. });
  5486. if (result === 'Success') {
  5487. if (data?.status === 200) {
  5488. const {
  5489. result: resultR,
  5490. statusText: statusTextR,
  5491. status: statusR,
  5492. data: dataR
  5493. } = await tools_httpRequest({
  5494. url: `https://steamcommunity.com/games/${gameId}`,
  5495. method: 'GET',
  5496. headers: {
  5497. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5498. }
  5499. });
  5500. if (resultR === 'Success') {
  5501. if (dataR?.status === 200 && dataR.responseText.includes('id="publicGroupJoin"')) {
  5502. logStatus.success();
  5503. return true;
  5504. }
  5505. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  5506. return false;
  5507. }
  5508. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  5509. return false;
  5510. }
  5511. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5512. return false;
  5513. }
  5514. logStatus.error(`${result}:${statusText}(${status})`);
  5515. return false;
  5516. } catch (error) {
  5517. throwError(error, 'Steam.leaveOfficialGroup');
  5518. return false;
  5519. }
  5520. }
  5521. async #getOfficialGroupId(gameId) {
  5522. try {
  5523. const logStatus = scripts_echoLog({
  5524. type: 'gettingSteamOfficialGroupId',
  5525. text: gameId
  5526. });
  5527. const groupId = this.#cache.officialGroup[gameId];
  5528. if (groupId) {
  5529. logStatus.success();
  5530. return groupId;
  5531. }
  5532. const {
  5533. result,
  5534. statusText,
  5535. status,
  5536. data
  5537. } = await tools_httpRequest({
  5538. url: `https://steamcommunity.com/games/${gameId}`,
  5539. method: 'GET',
  5540. headers: {
  5541. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5542. }
  5543. });
  5544. if (result === 'Success') {
  5545. if (data?.status === 200) {
  5546. const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
  5547. if (groupId) {
  5548. this.#setCache('officialGroup', gameId, groupId);
  5549. logStatus.success();
  5550. return groupId;
  5551. }
  5552. logStatus.error(`Error:${data.statusText}(${data.status})`);
  5553. return false;
  5554. }
  5555. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5556. return false;
  5557. }
  5558. logStatus.error(`${result}:${statusText}(${status})`);
  5559. return false;
  5560. } catch (error) {
  5561. throwError(error, 'Steam.getGroupID');
  5562. return false;
  5563. }
  5564. }
  5565. async #addToWishlist(gameId) {
  5566. try {
  5567. if (this.#ASF) {
  5568. if (await this.#ASF.addToWishlist(gameId)) {
  5569. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  5570. return true;
  5571. }
  5572. return false;
  5573. }
  5574. const logStatus = scripts_echoLog({
  5575. type: 'addingToWishlist',
  5576. text: gameId
  5577. });
  5578. const {
  5579. result,
  5580. data
  5581. } = await tools_httpRequest({
  5582. url: 'https://store.steampowered.com/api/addtowishlist',
  5583. method: 'POST',
  5584. headers: {
  5585. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5586. },
  5587. data: $.param({
  5588. sessionid: this.#auth.storeSessionID,
  5589. appid: gameId
  5590. }),
  5591. dataType: 'json'
  5592. });
  5593. if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
  5594. logStatus.success();
  5595. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  5596. return true;
  5597. }
  5598. const {
  5599. result: resultR,
  5600. statusText: statusTextR,
  5601. status: statusR,
  5602. data: dataR
  5603. } = await tools_httpRequest({
  5604. url: `https://store.steampowered.com/app/${gameId}`,
  5605. method: 'GET'
  5606. });
  5607. if (resultR === 'Success') {
  5608. if (dataR?.status === 200) {
  5609. if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
  5610. logStatus.warning(i18n('changeAreaNotice'));
  5611. if (!await this.#changeArea()) {
  5612. return false;
  5613. }
  5614. return await this.#addToWishlist(gameId);
  5615. }
  5616. if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('class="already_in_library"')) {
  5617. logStatus.success();
  5618. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  5619. return true;
  5620. } 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"')) {
  5621. logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
  5622. return false;
  5623. }
  5624. logStatus.success();
  5625. this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
  5626. return true;
  5627. }
  5628. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  5629. return false;
  5630. }
  5631. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  5632. return false;
  5633. } catch (error) {
  5634. throwError(error, 'Steam.addToWishlist');
  5635. return false;
  5636. }
  5637. }
  5638. async #removeFromWishlist(gameId) {
  5639. try {
  5640. if (this.whiteList.wishlists.includes(gameId)) {
  5641. scripts_echoLog({
  5642. type: 'whiteList',
  5643. text: 'Steam.removeFromWishlist',
  5644. id: gameId
  5645. });
  5646. return true;
  5647. }
  5648. if (this.#ASF) {
  5649. return await this.#ASF.removeFromWishlist(gameId);
  5650. }
  5651. const logStatus = scripts_echoLog({
  5652. type: 'removingFromWishlist',
  5653. text: gameId
  5654. });
  5655. const {
  5656. result,
  5657. data
  5658. } = await tools_httpRequest({
  5659. url: 'https://store.steampowered.com/api/removefromwishlist',
  5660. method: 'POST',
  5661. headers: {
  5662. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5663. },
  5664. data: $.param({
  5665. sessionid: this.#auth.storeSessionID,
  5666. appid: gameId
  5667. }),
  5668. dataType: 'json'
  5669. });
  5670. if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
  5671. logStatus.success();
  5672. return true;
  5673. }
  5674. const {
  5675. result: resultR,
  5676. statusText: statusTextR,
  5677. status: statusR,
  5678. data: dataR
  5679. } = await tools_httpRequest({
  5680. url: `https://store.steampowered.com/app/${gameId}`,
  5681. method: 'GET'
  5682. });
  5683. if (resultR === 'Success') {
  5684. if (dataR?.status === 200) {
  5685. if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
  5686. logStatus.warning(i18n('changeAreaNotice'));
  5687. const result = await this.#changeArea();
  5688. if (!result || result === 'CN' || result === 'skip') {
  5689. return false;
  5690. }
  5691. return await this.#removeFromWishlist(gameId);
  5692. }
  5693. if (dataR.responseText.includes('class="queue_actions_ctn"') && (dataR.responseText.includes('ds_owned_flag ds_flag') || dataR.responseText.includes('add_to_wishlist_area'))) {
  5694. logStatus.success();
  5695. return true;
  5696. }
  5697. logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
  5698. return false;
  5699. }
  5700. logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
  5701. return false;
  5702. }
  5703. logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
  5704. return false;
  5705. } catch (error) {
  5706. throwError(error, 'Steam.removeFromWishlist');
  5707. return false;
  5708. }
  5709. }
  5710. async #toggleFollowGame(gameId, doTask) {
  5711. try {
  5712. if (!doTask && this.whiteList.follows.includes(gameId)) {
  5713. scripts_echoLog({
  5714. type: 'whiteList',
  5715. text: 'Steam.unfollowGame',
  5716. id: gameId
  5717. });
  5718. return true;
  5719. }
  5720. if (this.#ASF) {
  5721. if (await this.#ASF.toggleFollowGame(gameId, doTask)) {
  5722. if (doTask) {
  5723. this.tasks.follows = unique([ ...this.tasks.follows, gameId ]);
  5724. }
  5725. return true;
  5726. }
  5727. return false;
  5728. }
  5729. const logStatus = scripts_echoLog({
  5730. type: `${doTask ? '' : 'un'}followingGame`,
  5731. text: gameId
  5732. });
  5733. const requestData = {
  5734. sessionid: this.#auth.storeSessionID,
  5735. appid: gameId
  5736. };
  5737. if (!doTask) {
  5738. requestData.unfollow = '1';
  5739. }
  5740. const {
  5741. result,
  5742. data
  5743. } = await tools_httpRequest({
  5744. url: 'https://store.steampowered.com/explore/followgame/',
  5745. method: 'POST',
  5746. headers: {
  5747. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5748. },
  5749. data: $.param(requestData)
  5750. });
  5751. if (result === 'Success' && data?.status === 200 && data.responseText === 'true') {
  5752. logStatus.success();
  5753. return true;
  5754. }
  5755. const followed = await this.#isFollowedGame(gameId);
  5756. if (this.#area === 'CN' && followed === 'areaLocked') {
  5757. logStatus.warning(i18n('changeAreaNotice'));
  5758. if (!await this.#changeArea()) {
  5759. return false;
  5760. }
  5761. return await this.#toggleFollowGame(gameId, doTask);
  5762. }
  5763. if (doTask === followed) {
  5764. logStatus.success();
  5765. if (doTask) {
  5766. this.tasks.follows = unique([ ...this.tasks.follows, gameId ]);
  5767. }
  5768. return true;
  5769. }
  5770. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5771. return false;
  5772. } catch (error) {
  5773. throwError(error, 'Steam.toggleFollowGame');
  5774. return false;
  5775. }
  5776. }
  5777. async #isFollowedGame(gameId) {
  5778. try {
  5779. const {
  5780. result,
  5781. data
  5782. } = await tools_httpRequest({
  5783. url: `https://store.steampowered.com/app/${gameId}`,
  5784. method: 'GET'
  5785. });
  5786. if (result === 'Success') {
  5787. if (data?.status === 200) {
  5788. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  5789. return 'areaLocked';
  5790. }
  5791. if ($(data.responseText.replace(/<img.*?>/g, '')).find('.queue_control_button.queue_btn_follow>.btnv6_blue_hoverfade.btn_medium.queue_btn_active').css('display') !== 'none') {
  5792. return true;
  5793. }
  5794. return false;
  5795. }
  5796. return false;
  5797. }
  5798. return false;
  5799. } catch (error) {
  5800. throwError(error, 'Steam.isFollowedGame');
  5801. return false;
  5802. }
  5803. }
  5804. async #toggleForum(gameId, doTask = true) {
  5805. try {
  5806. if (!doTask && this.whiteList.forums.includes(gameId)) {
  5807. scripts_echoLog({
  5808. type: 'whiteList',
  5809. text: 'Steam.unsubscribeForum',
  5810. id: gameId
  5811. });
  5812. return true;
  5813. }
  5814. const forumId = await this.#getForumId(gameId);
  5815. if (!forumId) {
  5816. return false;
  5817. }
  5818. const logStatus = scripts_echoLog({
  5819. type: `${doTask ? '' : 'un'}subscribingForum`,
  5820. text: gameId
  5821. });
  5822. const [ id, feature ] = forumId.split('_');
  5823. const {
  5824. result,
  5825. statusText,
  5826. status,
  5827. data
  5828. } = await tools_httpRequest({
  5829. url: `https://steamcommunity.com/forum/${id}/General/${doTask ? '' : 'un'}subscribe/${feature || '0'}/`,
  5830. method: 'POST',
  5831. responseType: 'json',
  5832. headers: {
  5833. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5834. },
  5835. data: $.param({
  5836. sessionid: this.#auth.communitySessionID
  5837. })
  5838. });
  5839. if (result === 'Success') {
  5840. if (data?.status === 200 && (data.response?.success === 1 || data.response?.success === 29)) {
  5841. if (doTask) {
  5842. this.tasks.forums = unique([ ...this.tasks.forums, gameId ]);
  5843. }
  5844. logStatus.success();
  5845. return true;
  5846. }
  5847. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5848. return true;
  5849. }
  5850. logStatus.error(`${result}:${statusText}(${status})`);
  5851. return true;
  5852. } catch (error) {
  5853. throwError(error, 'Steam.toggleForum');
  5854. return true;
  5855. }
  5856. }
  5857. async #getForumId(gameId) {
  5858. try {
  5859. const logStatus = scripts_echoLog({
  5860. type: 'gettingForumId',
  5861. text: gameId
  5862. });
  5863. const forumId = this.#cache.forum[gameId];
  5864. if (forumId) {
  5865. logStatus.success();
  5866. return forumId;
  5867. }
  5868. const {
  5869. result,
  5870. statusText,
  5871. status,
  5872. data
  5873. } = await tools_httpRequest({
  5874. url: `https://steamcommunity.com/app/${gameId}/discussions/`,
  5875. method: 'GET'
  5876. });
  5877. if (result === 'Success') {
  5878. if (data?.status === 200) {
  5879. const forumId = data.responseText?.match(/General_([\d]+(_[\d]+)?)/)?.[1];
  5880. if (forumId) {
  5881. this.#setCache('forum', gameId, forumId);
  5882. logStatus.success();
  5883. return forumId;
  5884. }
  5885. logStatus.error(`Error:${data.statusText}(${data.status})`);
  5886. return false;
  5887. }
  5888. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5889. return false;
  5890. }
  5891. logStatus.error(`${result}:${statusText}(${status})`);
  5892. return false;
  5893. } catch (error) {
  5894. throwError(error, 'Steam.getForumId');
  5895. return false;
  5896. }
  5897. }
  5898. async #toggleFavoriteWorkshop(id, doTask = true) {
  5899. try {
  5900. if (!doTask && this.whiteList.workshops.includes(id)) {
  5901. scripts_echoLog({
  5902. type: 'whiteList',
  5903. text: 'Steam.unfavoriteWorkshop',
  5904. id: id
  5905. });
  5906. return true;
  5907. }
  5908. const appid = await this.#getWorkshopAppId(id);
  5909. if (!appid) {
  5910. return false;
  5911. }
  5912. const logStatus = scripts_echoLog({
  5913. type: doTask ? 'favoritingWorkshop' : 'unfavoritingWorkshop',
  5914. text: id
  5915. });
  5916. const {
  5917. result,
  5918. statusText,
  5919. status,
  5920. data
  5921. } = await tools_httpRequest({
  5922. url: `https://steamcommunity.com/sharedfiles/${doTask ? '' : 'un'}favorite`,
  5923. method: 'POST',
  5924. headers: {
  5925. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  5926. },
  5927. data: $.param({
  5928. id: id,
  5929. appid: appid,
  5930. sessionid: this.#auth.communitySessionID
  5931. })
  5932. });
  5933. if (result === 'Success') {
  5934. if (data?.status === 200 && !data.responseText) {
  5935. if (doTask) {
  5936. this.tasks.workshops = unique([ ...this.tasks.workshops, id ]);
  5937. }
  5938. logStatus.success();
  5939. return true;
  5940. }
  5941. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5942. return false;
  5943. }
  5944. logStatus.error(`${result}:${statusText}(${status})`);
  5945. return false;
  5946. } catch (error) {
  5947. throwError(error, 'Steam.toggleFavoriteWorkshop');
  5948. return false;
  5949. }
  5950. }
  5951. async #getWorkshopAppId(id) {
  5952. try {
  5953. const logStatus = scripts_echoLog({
  5954. type: 'gettingWorkshopAppId',
  5955. text: id
  5956. });
  5957. const appId = this.#cache.workshop[id];
  5958. if (appId) {
  5959. logStatus.success();
  5960. return appId;
  5961. }
  5962. const {
  5963. result,
  5964. statusText,
  5965. status,
  5966. data
  5967. } = await tools_httpRequest({
  5968. url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${id}`,
  5969. method: 'GET'
  5970. });
  5971. if (result === 'Success') {
  5972. if (data?.status === 200) {
  5973. const appId = data.responseText.match(/<input type="hidden" name="appid" value="([\d]+?)" \/>/)?.[1];
  5974. if (appId) {
  5975. this.#setCache('workshop', id, appId);
  5976. logStatus.success();
  5977. return appId;
  5978. }
  5979. logStatus.error('Error: getWorkshopAppId failed');
  5980. return false;
  5981. }
  5982. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  5983. return false;
  5984. }
  5985. logStatus.error(`${result}:${statusText}(${status})`);
  5986. return false;
  5987. } catch (error) {
  5988. throwError(error, 'Steam.getWorkshopAppId');
  5989. return false;
  5990. }
  5991. }
  5992. async #voteUpWorkshop(id) {
  5993. try {
  5994. const logStatus = scripts_echoLog({
  5995. type: 'votingUpWorkshop',
  5996. text: id
  5997. });
  5998. const {
  5999. result,
  6000. statusText,
  6001. status,
  6002. data
  6003. } = await tools_httpRequest({
  6004. url: 'https://steamcommunity.com/sharedfiles/voteup',
  6005. method: 'POST',
  6006. responseType: 'json',
  6007. headers: {
  6008. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6009. },
  6010. data: $.param({
  6011. id: id,
  6012. sessionid: this.#auth.communitySessionID
  6013. })
  6014. });
  6015. if (result === 'Success') {
  6016. if (data?.status === 200 && data.response?.success === 1) {
  6017. logStatus.success();
  6018. return true;
  6019. }
  6020. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6021. return true;
  6022. }
  6023. logStatus.error(`${result}:${statusText}(${status})`);
  6024. return true;
  6025. } catch (error) {
  6026. throwError(error, 'Steam.voteupWorkshop');
  6027. return true;
  6028. }
  6029. }
  6030. async #toggleCurator(curatorId, doTask = true) {
  6031. try {
  6032. if (!doTask && this.whiteList.curators.includes(curatorId)) {
  6033. scripts_echoLog({
  6034. type: 'whiteList',
  6035. text: 'Steam.unfollowCurator',
  6036. id: curatorId
  6037. });
  6038. return true;
  6039. }
  6040. if (this.#ASF) {
  6041. return await this.#ASF.toggleCurator(curatorId, doTask);
  6042. }
  6043. const logStatus = scripts_echoLog({
  6044. type: doTask ? 'followingCurator' : 'unfollowingCurator',
  6045. text: curatorId
  6046. });
  6047. const {
  6048. result,
  6049. statusText,
  6050. status,
  6051. data
  6052. } = await tools_httpRequest({
  6053. url: 'https://store.steampowered.com/curators/ajaxfollow',
  6054. method: 'POST',
  6055. headers: {
  6056. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6057. },
  6058. data: $.param({
  6059. clanid: curatorId,
  6060. sessionid: this.#auth.storeSessionID,
  6061. follow: doTask
  6062. }),
  6063. dataType: 'json'
  6064. });
  6065. if (result === 'Success') {
  6066. if (data?.status === 200 && data.response?.success?.success === 1) {
  6067. logStatus.success();
  6068. return true;
  6069. }
  6070. logStatus.error(`Error:${data?.statusText}(${data?.response?.success}` || `${data?.status})`);
  6071. return false;
  6072. }
  6073. logStatus.error(`${result}:${statusText}(${status})`);
  6074. return false;
  6075. } catch (error) {
  6076. throwError(error, 'Steam.toggleCurator');
  6077. return false;
  6078. }
  6079. }
  6080. async getCuratorId(path, name) {
  6081. try {
  6082. const logStatus = scripts_echoLog({
  6083. type: 'gettingCuratorId',
  6084. text: `${path}/${name}`
  6085. });
  6086. const curatorId = this.#cache.curator[`${path}/${name}`];
  6087. if (curatorId) {
  6088. logStatus.success();
  6089. return curatorId;
  6090. }
  6091. const {
  6092. result,
  6093. statusText,
  6094. status,
  6095. data
  6096. } = await tools_httpRequest({
  6097. url: `https://store.steampowered.com/${path}/${name}`,
  6098. method: 'GET',
  6099. headers: {
  6100. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6101. }
  6102. });
  6103. if (result === 'Success') {
  6104. if (data?.status === 200) {
  6105. const curatorId = data.responseText.match(/g_pagingData.*?"clanid":([\d]+)/)?.[1];
  6106. if (curatorId) {
  6107. this.#setCache('curator', `${path}/${name}`, curatorId);
  6108. logStatus.success();
  6109. return curatorId;
  6110. }
  6111. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6112. return false;
  6113. }
  6114. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6115. return false;
  6116. }
  6117. logStatus.error(`${result}:${statusText}(${status})`);
  6118. return false;
  6119. } catch (error) {
  6120. throwError(error, 'Steam.getCuratorID');
  6121. return false;
  6122. }
  6123. }
  6124. async #toggleCuratorLike(link, doTask = true) {
  6125. try {
  6126. const [ path, name ] = link.split('/');
  6127. if (!(path && name)) {
  6128. scripts_echoLog({
  6129. text: i18n('errorLink', link)
  6130. });
  6131. return false;
  6132. }
  6133. const curatorId = await this.getCuratorId(path, name);
  6134. if (curatorId) {
  6135. return await this.#toggleCurator(curatorId, doTask);
  6136. }
  6137. return false;
  6138. } catch (error) {
  6139. throwError(error, 'Steam.toggleCuratorLike');
  6140. return false;
  6141. }
  6142. }
  6143. async #getAnnouncementParams(appId, viewId) {
  6144. try {
  6145. const logStatus = scripts_echoLog({
  6146. type: 'gettingAnnouncementParams',
  6147. text: appId,
  6148. id: viewId
  6149. });
  6150. const {
  6151. result,
  6152. statusText,
  6153. status,
  6154. data
  6155. } = await tools_httpRequest({
  6156. 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`,
  6157. method: 'GET',
  6158. responseType: 'json',
  6159. headers: {
  6160. Host: 'store.steampowered.com',
  6161. Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
  6162. }
  6163. });
  6164. if (result === 'Success') {
  6165. if (data?.status === 200 && data?.response?.success === 1) {
  6166. const {
  6167. clanid,
  6168. gid
  6169. } = data.response.event?.announcement_body || {};
  6170. if (clanid) {
  6171. logStatus.success();
  6172. return {
  6173. clanId: clanid,
  6174. gid: gid
  6175. };
  6176. }
  6177. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6178. return {};
  6179. }
  6180. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6181. return {};
  6182. }
  6183. logStatus.error(`${result}:${statusText}(${status})`);
  6184. return {};
  6185. } catch (error) {
  6186. throwError(error, 'Steam.likeAnnouncement');
  6187. return {};
  6188. }
  6189. }
  6190. async #likeAnnouncement(id) {
  6191. try {
  6192. const [ appId, viewId ] = id.split('/');
  6193. if (!(appId && viewId)) {
  6194. scripts_echoLog({}).error(`${i18n('missParams')}(id)`);
  6195. return false;
  6196. }
  6197. const {
  6198. clanId,
  6199. gid
  6200. } = await this.#getAnnouncementParams(appId, viewId);
  6201. if (!clanId) {
  6202. return false;
  6203. }
  6204. const logStatus = scripts_echoLog({
  6205. type: 'likingAnnouncement',
  6206. text: appId,
  6207. id: viewId
  6208. });
  6209. const {
  6210. result,
  6211. statusText,
  6212. status,
  6213. data
  6214. } = await tools_httpRequest({
  6215. url: `https://store.steampowered.com/updated/ajaxrateupdate/${gid || viewId}`,
  6216. method: 'POST',
  6217. headers: {
  6218. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6219. Host: 'store.steampowered.com',
  6220. Origin: 'https://store.steampowered.com',
  6221. Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
  6222. },
  6223. data: $.param({
  6224. sessionid: this.#auth.storeSessionID,
  6225. voteup: 1,
  6226. clanid: clanId,
  6227. ajax: 1
  6228. }),
  6229. dataType: 'json'
  6230. });
  6231. if (result === 'Success') {
  6232. if (data?.status === 200 && data.response.success === 1) {
  6233. logStatus.success();
  6234. return true;
  6235. }
  6236. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6237. return false;
  6238. }
  6239. logStatus.error(`${result}:${statusText}(${status})`);
  6240. return false;
  6241. } catch (error) {
  6242. throwError(error, 'Steam.likeAnnouncement');
  6243. return false;
  6244. }
  6245. }
  6246. async #appid2subid(id) {
  6247. try {
  6248. const logStatus = scripts_echoLog({
  6249. type: 'gettingSubid',
  6250. text: id
  6251. });
  6252. const {
  6253. result,
  6254. statusText,
  6255. status,
  6256. data
  6257. } = await tools_httpRequest({
  6258. url: `https://store.steampowered.com/app/${id}`,
  6259. method: 'GET',
  6260. headers: {
  6261. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  6262. }
  6263. });
  6264. if (result === 'Success') {
  6265. if (data?.status === 200) {
  6266. if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) {
  6267. logStatus.success(i18n('owned'));
  6268. return false;
  6269. }
  6270. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  6271. logStatus.warning(i18n('changeAreaNotice'));
  6272. const result = await this.#changeArea();
  6273. if (!result || result === 'CN' || result === 'skip') {
  6274. return false;
  6275. }
  6276. return await this.#appid2subid(id);
  6277. }
  6278. let subid = data.responseText.match(/name="subid" value="([\d]+?)"/)?.[1];
  6279. if (subid) {
  6280. logStatus.success();
  6281. return subid;
  6282. }
  6283. subid = data.responseText.match(/AddFreeLicense\(\s*(\d+)/)?.[1];
  6284. if (subid) {
  6285. logStatus.success();
  6286. return subid;
  6287. }
  6288. logStatus.error(`Error:${i18n('noSubid')}`);
  6289. return false;
  6290. }
  6291. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6292. return false;
  6293. }
  6294. logStatus.error(`${result}:${statusText}(${status})`);
  6295. return false;
  6296. } catch (error) {
  6297. throwError(error, 'Steam.appid2subid');
  6298. return false;
  6299. }
  6300. }
  6301. async #getLicenses() {
  6302. try {
  6303. const logStatus = scripts_echoLog({
  6304. text: i18n('gettingLicenses')
  6305. });
  6306. const {
  6307. result,
  6308. statusText,
  6309. status,
  6310. data
  6311. } = await tools_httpRequest({
  6312. url: `https://store.steampowered.com/dynamicstore/userdata/?t=${new Date().getTime()}`,
  6313. method: 'GET',
  6314. responseType: 'json'
  6315. });
  6316. if (result === 'Success') {
  6317. if (data?.status === 200) {
  6318. logStatus.success();
  6319. return data.response?.rgOwnedPackages;
  6320. }
  6321. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6322. return false;
  6323. }
  6324. logStatus.error(`${result}:${statusText}(${status})`);
  6325. return false;
  6326. } catch (error) {
  6327. throwError(error, 'Steam.getLicenses');
  6328. return false;
  6329. }
  6330. }
  6331. async #addLicense(id) {
  6332. try {
  6333. if (this.#ASF) {
  6334. return await this.#ASF.addLicense(id);
  6335. }
  6336. const [ type, ids ] = id.split('-');
  6337. if (type === 'appid') {
  6338. const subid = await this.#appid2subid(ids);
  6339. if (!subid) {
  6340. return false;
  6341. }
  6342. const logStatus = scripts_echoLog({
  6343. type: 'addingFreeLicense',
  6344. text: ids
  6345. });
  6346. if (!await this.#addFreeLicense(subid, logStatus)) {
  6347. return false;
  6348. }
  6349. const {
  6350. result,
  6351. statusText,
  6352. status,
  6353. data
  6354. } = await tools_httpRequest({
  6355. url: `https://store.steampowered.com/app/${ids}`,
  6356. method: 'GET'
  6357. });
  6358. if (result === 'Success') {
  6359. if (data?.status === 200) {
  6360. if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) {
  6361. logStatus.success();
  6362. return true;
  6363. }
  6364. logStatus.error(`Error:${data.statusText}(${data.status})`);
  6365. return false;
  6366. }
  6367. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6368. return false;
  6369. }
  6370. logStatus.error(`${result}:${statusText}(${status})`);
  6371. return false;
  6372. } else if (type === 'subid') {
  6373. if (this.#area === 'CN') {
  6374. scripts_echoLog({}).success(i18n('tryChangeAreaNotice'));
  6375. await this.#changeArea();
  6376. }
  6377. const logStatusArr = {};
  6378. const idsArr = ids.split(',');
  6379. for (const subid of idsArr) {
  6380. const logStatus = scripts_echoLog({
  6381. type: 'addingFreeLicenseSubid',
  6382. text: subid
  6383. });
  6384. if (!await this.#addFreeLicense(subid, logStatus)) {
  6385. return false;
  6386. }
  6387. logStatusArr[subid] = logStatus;
  6388. }
  6389. const licenses = await this.#getLicenses();
  6390. if (!licenses) {
  6391. return false;
  6392. }
  6393. for (const subid of idsArr) {
  6394. if (licenses.includes(parseInt(subid, 10))) {
  6395. logStatusArr[subid].success();
  6396. } else {
  6397. logStatusArr[subid].error();
  6398. }
  6399. }
  6400. return true;
  6401. }
  6402. return false;
  6403. } catch (error) {
  6404. throwError(error, 'Steam.addLicense');
  6405. return false;
  6406. }
  6407. }
  6408. async #addFreeLicense(id, logStatusPre) {
  6409. try {
  6410. const logStatus = logStatusPre || scripts_echoLog({
  6411. type: 'addingFreeLicenseSubid',
  6412. text: id
  6413. });
  6414. const {
  6415. result,
  6416. statusText,
  6417. status,
  6418. data
  6419. } = await tools_httpRequest({
  6420. url: `https://store.steampowered.com/freelicense/addfreelicense/${id}`,
  6421. method: 'POST',
  6422. headers: {
  6423. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6424. Host: 'store.steampowered.com',
  6425. Origin: 'https://store.steampowered.com',
  6426. Referer: 'https://store.steampowered.com/account/licenses/'
  6427. },
  6428. data: $.param({
  6429. ajax: true,
  6430. sessionid: this.#auth.storeSessionID
  6431. }),
  6432. dataType: 'json'
  6433. });
  6434. if (result === 'Success') {
  6435. if (data?.status === 200) {
  6436. if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
  6437. logStatus.warning(i18n('changeAreaNotice'));
  6438. const result = await this.#changeArea();
  6439. if (!result || [ 'CN', 'skip' ].includes(result)) {
  6440. return false;
  6441. }
  6442. return await this.#addFreeLicense(id);
  6443. }
  6444. logStatus.success();
  6445. return true;
  6446. }
  6447. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6448. return false;
  6449. }
  6450. logStatus.error(`${result}:${statusText}(${status})`);
  6451. return false;
  6452. } catch (error) {
  6453. throwError(error, 'Steam.addFreeLicense');
  6454. return false;
  6455. }
  6456. }
  6457. async #requestPlayTestAccess(id) {
  6458. try {
  6459. if (this.#ASF) {
  6460. return await this.#ASF.requestPlayTestAccess(id);
  6461. }
  6462. const logStatus = scripts_echoLog({
  6463. type: 'requestingPlayTestAccess',
  6464. text: id
  6465. });
  6466. const {
  6467. result,
  6468. statusText,
  6469. status,
  6470. data
  6471. } = await tools_httpRequest({
  6472. url: `https://store.steampowered.com/ajaxrequestplaytestaccess/${id}`,
  6473. method: 'POST',
  6474. headers: {
  6475. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  6476. Host: 'store.steampowered.com',
  6477. Origin: 'https://store.steampowered.com',
  6478. Referer: `https://store.steampowered.com/app/${id}`
  6479. },
  6480. data: $.param({
  6481. sessionid: this.#auth.storeSessionID
  6482. }),
  6483. dataType: 'json'
  6484. });
  6485. if (result === 'Success') {
  6486. if (data?.status === 200 && data?.response?.success === 1) {
  6487. logStatus.success();
  6488. return true;
  6489. }
  6490. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  6491. return false;
  6492. }
  6493. logStatus.error(`${result}:${statusText}(${status})`);
  6494. return false;
  6495. } catch (error) {
  6496. throwError(error, 'Steam.requestPlayTestAccess');
  6497. return false;
  6498. }
  6499. }
  6500. async toggle({
  6501. doTask = true,
  6502. groupLinks = [],
  6503. officialGroupLinks = [],
  6504. wishlistLinks = [],
  6505. followLinks = [],
  6506. forumLinks = [],
  6507. workshopLinks = [],
  6508. workshopVoteLinks = [],
  6509. curatorLinks = [],
  6510. curatorLikeLinks = [],
  6511. announcementLinks = [],
  6512. licenseLinks = [],
  6513. playtestLinks = []
  6514. }) {
  6515. try {
  6516. if ([ ...groupLinks, ...officialGroupLinks, ...forumLinks, ...workshopLinks, ...workshopVoteLinks ].length > 0 && !this.#communityInitialized) {
  6517. scripts_echoLog({
  6518. text: i18n('needInit')
  6519. });
  6520. return false;
  6521. }
  6522. if ([ ...wishlistLinks, ...followLinks, ...curatorLinks, ...curatorLikeLinks, ...announcementLinks, ...licenseLinks, ...playtestLinks ].length > 0 && !this.#storeInitialized) {
  6523. scripts_echoLog({
  6524. text: i18n('needInit')
  6525. });
  6526. return false;
  6527. }
  6528. const prom = [];
  6529. if (doTask && !globalOptions.doTask.steam.groups || !doTask && !globalOptions.undoTask.steam.groups) {
  6530. scripts_echoLog({
  6531. type: 'globalOptionsSkip',
  6532. text: 'steam.groups'
  6533. });
  6534. } else {
  6535. const realGroups = this.getRealParams('groups', groupLinks, doTask, link => link.match(/groups\/(.+)\/?/)?.[1]);
  6536. if (realGroups.length > 0) {
  6537. for (const group of realGroups) {
  6538. if (doTask) {
  6539. prom.push(this.#joinGroup(group));
  6540. } else {
  6541. prom.push(this.#leaveGroup(group));
  6542. }
  6543. await delay(1e3);
  6544. }
  6545. }
  6546. }
  6547. if (doTask && !globalOptions.doTask.steam.officialGroups || !doTask && !globalOptions.undoTask.steam.officialGroups) {
  6548. scripts_echoLog({
  6549. type: 'globalOptionsSkip',
  6550. text: 'steam.officialGroups'
  6551. });
  6552. } else {
  6553. const realOfficialGroups = this.getRealParams('officialGroups', officialGroupLinks, doTask, link => link.match(/games\/(.+)\/?/)?.[1]);
  6554. if (realOfficialGroups.length > 0) {
  6555. for (const officialGroup of realOfficialGroups) {
  6556. if (doTask) {
  6557. prom.push(this.#joinOfficialGroup(officialGroup));
  6558. } else {
  6559. prom.push(this.#leaveOfficialGroup(officialGroup));
  6560. }
  6561. await delay(1e3);
  6562. }
  6563. }
  6564. }
  6565. if (doTask && !globalOptions.doTask.steam.wishlists || !doTask && !globalOptions.undoTask.steam.wishlists) {
  6566. scripts_echoLog({
  6567. type: 'globalOptionsSkip',
  6568. text: 'steam.wishlists'
  6569. });
  6570. } else {
  6571. const realWishlists = this.getRealParams('wishlists', wishlistLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  6572. if (realWishlists.length > 0) {
  6573. for (const game of realWishlists) {
  6574. if (doTask) {
  6575. prom.push(this.#addToWishlist(game));
  6576. } else {
  6577. prom.push(this.#removeFromWishlist(game));
  6578. }
  6579. await delay(1e3);
  6580. }
  6581. }
  6582. }
  6583. if (doTask && !globalOptions.doTask.steam.follows || !doTask && !globalOptions.undoTask.steam.follows) {
  6584. scripts_echoLog({
  6585. type: 'globalOptionsSkip',
  6586. text: 'steam.follows'
  6587. });
  6588. } else {
  6589. const realFollows = this.getRealParams('follows', followLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  6590. if (realFollows.length > 0) {
  6591. for (const game of realFollows) {
  6592. prom.push(this.#toggleFollowGame(game, doTask));
  6593. await delay(1e3);
  6594. }
  6595. }
  6596. }
  6597. if (doTask && !globalOptions.doTask.steam.forums || !doTask && !globalOptions.undoTask.steam.forums) {
  6598. scripts_echoLog({
  6599. type: 'globalOptionsSkip',
  6600. text: 'steam.forums'
  6601. });
  6602. } else {
  6603. const realForums = this.getRealParams('forums', forumLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  6604. if (realForums.length > 0) {
  6605. for (const forum of realForums) {
  6606. prom.push(this.#toggleForum(forum, doTask));
  6607. await delay(1e3);
  6608. }
  6609. }
  6610. }
  6611. if (doTask && !globalOptions.doTask.steam.workshops || !doTask && !globalOptions.undoTask.steam.workshops) {
  6612. scripts_echoLog({
  6613. type: 'globalOptionsSkip',
  6614. text: 'steam.workshops'
  6615. });
  6616. } else {
  6617. const realWorkshops = this.getRealParams('workshops', workshopLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]);
  6618. if (realWorkshops.length > 0) {
  6619. for (const workshop of realWorkshops) {
  6620. prom.push(this.#toggleFavoriteWorkshop(workshop, doTask));
  6621. await delay(1e3);
  6622. }
  6623. }
  6624. }
  6625. if (doTask && !globalOptions.doTask.steam.workshopVotes) {
  6626. scripts_echoLog({
  6627. type: 'globalOptionsSkip',
  6628. text: 'steam.workshopVotes'
  6629. });
  6630. } else {
  6631. const realworkshopVotes = this.getRealParams('workshopVotes', workshopVoteLinks, doTask, link => link.match(/\?id=([\d]+)/)?.[1]);
  6632. if (doTask && realworkshopVotes.length > 0) {
  6633. for (const workshop of realworkshopVotes) {
  6634. prom.push(this.#voteUpWorkshop(workshop));
  6635. await delay(1e3);
  6636. }
  6637. }
  6638. }
  6639. if (doTask && !globalOptions.doTask.steam.curators || !doTask && !globalOptions.undoTask.steam.curators) {
  6640. scripts_echoLog({
  6641. type: 'globalOptionsSkip',
  6642. text: 'steam.curators'
  6643. });
  6644. } else {
  6645. const realCurators = this.getRealParams('curators', curatorLinks, doTask, link => link.match(/curator\/([\d]+)/)?.[1]);
  6646. const realCuratorLikes = this.getRealParams('curatorLikes', curatorLikeLinks, doTask, link => link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3).join('/'));
  6647. if (realCurators.length > 0) {
  6648. for (const curator of realCurators) {
  6649. prom.push(this.#toggleCurator(curator, doTask));
  6650. await delay(1e3);
  6651. }
  6652. }
  6653. if (realCuratorLikes.length > 0) {
  6654. for (const curatorLike of realCuratorLikes) {
  6655. prom.push(this.#toggleCuratorLike(curatorLike, doTask));
  6656. await delay(1e3);
  6657. }
  6658. }
  6659. }
  6660. if (doTask && !globalOptions.doTask.steam.announcements) {
  6661. scripts_echoLog({
  6662. type: 'globalOptionsSkip',
  6663. text: 'steam.announcements'
  6664. });
  6665. } else {
  6666. const realAnnouncements = this.getRealParams('announcements', announcementLinks, doTask, link => {
  6667. if (link.includes('store.steampowered.com')) {
  6668. return link.match(/store\.steampowered\.com\/news\/app\/([\d]+)\/view\/([\d]+)/)?.slice(1, 3).join('/');
  6669. }
  6670. return link.match(/steamcommunity\.com\/games\/([\d]+)\/announcements\/detail\/([\d]+)/)?.slice(1, 3).join('/');
  6671. });
  6672. if (doTask && realAnnouncements.length > 0) {
  6673. for (const id of realAnnouncements) {
  6674. prom.push(this.#likeAnnouncement(id));
  6675. await delay(1e3);
  6676. }
  6677. }
  6678. }
  6679. if (doTask && !globalOptions.doTask.steam.licenses) {
  6680. scripts_echoLog({
  6681. type: 'globalOptionsSkip',
  6682. text: 'steam.licenses'
  6683. });
  6684. } else if (doTask && globalOptions.doTask.steam.licenses && licenseLinks.length > 0) {
  6685. for (const ids of licenseLinks) {
  6686. const [ type, idsStr ] = ids.split('-');
  6687. const idsArr = idsStr.split(',');
  6688. for (const id of idsArr) {
  6689. prom.push(this.#addLicense(`${type}-${id}`));
  6690. await delay(1e3);
  6691. }
  6692. }
  6693. }
  6694. if (doTask && !globalOptions.doTask.steam.playtests) {
  6695. scripts_echoLog({
  6696. type: 'globalOptionsSkip',
  6697. text: 'steam.playtests'
  6698. });
  6699. } else {
  6700. const realPlaytests = this.getRealParams('playtests', playtestLinks, doTask, link => link.match(/app\/([\d]+)/)?.[1]);
  6701. if (doTask && globalOptions.doTask.steam.playtests && realPlaytests.length > 0) {
  6702. for (const id of realPlaytests) {
  6703. prom.push(this.#requestPlayTestAccess(id));
  6704. await delay(1e3);
  6705. }
  6706. }
  6707. }
  6708. return Promise.all(prom).then(async () => {
  6709. if (this.#oldArea && this.#area !== this.#oldArea) {
  6710. scripts_echoLog({}).warning(i18n('steamFinishNotice') + this.#oldArea);
  6711. await this.#changeArea(this.#oldArea);
  6712. }
  6713. return true;
  6714. });
  6715. } catch (error) {
  6716. throwError(error, 'Steam.toggle');
  6717. return false;
  6718. }
  6719. }
  6720. #setCache(type, name, id) {
  6721. try {
  6722. this.#cache[type][name] = id;
  6723. GM_setValue('steamCache', this.#cache);
  6724. } catch (error) {
  6725. throwError(error, 'Steam.setCache');
  6726. }
  6727. }
  6728. }
  6729. const social_Steam = Steam;
  6730. class Website {
  6731. undoneTasks;
  6732. socialTasks;
  6733. giveawayId;
  6734. socialInitialized = {
  6735. discord: false,
  6736. instagram: false,
  6737. reddit: false,
  6738. twitch: false,
  6739. twitter: false,
  6740. vk: false,
  6741. youtube: false,
  6742. steamStore: false,
  6743. steamCommunity: false
  6744. };
  6745. initialized = false;
  6746. steamTaskType = {
  6747. steamStore: false,
  6748. steamCommunity: false
  6749. };
  6750. social = {};
  6751. async #bind(name, init) {
  6752. try {
  6753. return {
  6754. name: name,
  6755. result: await init
  6756. };
  6757. } catch (error) {
  6758. throwError(error, 'Website.bind');
  6759. return {
  6760. name: name,
  6761. result: false
  6762. };
  6763. }
  6764. }
  6765. async initSocial(action) {
  6766. try {
  6767. const pro = [];
  6768. const tasks = action === 'do' ? this.undoneTasks : this.socialTasks;
  6769. if (tasks.discord) {
  6770. const hasDiscord = Object.values(tasks.discord).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6771. if (hasDiscord && (!this.socialInitialized.discord || !this.social.discord)) {
  6772. this.social.discord = new social_Discord();
  6773. pro.push(this.#bind('discord', this.social.discord.init(action)));
  6774. }
  6775. }
  6776. if (tasks.instagram) {
  6777. const hasInstagram = Object.values(tasks.instagram).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6778. if (hasInstagram && (!this.socialInitialized.instagram || !this.social.instagram)) {
  6779. this.social.instagram = new social_Instagram();
  6780. pro.push(this.#bind('instagram', this.social.instagram.init()));
  6781. }
  6782. }
  6783. if (tasks.reddit) {
  6784. const hasReddit = Object.values(tasks.reddit).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6785. if (hasReddit && (!this.socialInitialized.reddit || !this.social.reddit)) {
  6786. this.social.reddit = new social_Reddit();
  6787. pro.push(this.#bind('reddit', this.social.reddit.init()));
  6788. }
  6789. }
  6790. if (tasks.twitch) {
  6791. const hasTwitch = Object.values(tasks.twitch).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6792. if (hasTwitch && (!this.socialInitialized.twitch || !this.social.twitch)) {
  6793. this.social.twitch = new social_Twitch();
  6794. pro.push(this.#bind('twitch', this.social.twitch.init()));
  6795. }
  6796. }
  6797. if (tasks.twitter) {
  6798. const hasTwitter = Object.values(tasks.twitter).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6799. if (hasTwitter && (!this.socialInitialized.twitter || !this.social.twitter)) {
  6800. this.social.twitter = new social_Twitter();
  6801. pro.push(this.#bind('twitter', this.social.twitter.init()));
  6802. }
  6803. }
  6804. if (tasks.vk) {
  6805. const hasVk = Object.values(tasks.vk).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6806. if (hasVk && (!this.socialInitialized.vk || !this.social.vk)) {
  6807. this.social.vk = new social_Vk();
  6808. pro.push(this.#bind('vk', this.social.vk.init()));
  6809. }
  6810. }
  6811. if (tasks.youtube) {
  6812. const hasYoutube = Object.values(tasks.youtube).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6813. if (hasYoutube && (!this.socialInitialized.youtube || !this.social.youtube)) {
  6814. this.social.youtube = new Youtube();
  6815. pro.push(this.#bind('youtube', this.social.youtube.init()));
  6816. }
  6817. }
  6818. if (tasks.steam) {
  6819. const steamLength = Object.values(tasks.steam).reduce((total, arr) => [ ...total, ...arr ]).length;
  6820. if (steamLength > 0) {
  6821. if (!this.social.steam) {
  6822. this.social.steam = new social_Steam();
  6823. }
  6824. 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);
  6825. if (steamLength - steamCommunityLength > 0) {
  6826. this.steamTaskType.steamStore = true;
  6827. if (!this.socialInitialized.steamStore) {
  6828. pro.push(this.#bind('steamStore', this.social.steam.init('store')));
  6829. }
  6830. }
  6831. if (steamCommunityLength > 0) {
  6832. if (!this.socialInitialized.steamCommunity) {
  6833. this.steamTaskType.steamCommunity = true;
  6834. pro.push(this.#bind('steamCommunity', this.social.steam.init('community')));
  6835. }
  6836. }
  6837. }
  6838. }
  6839. if (tasks.links && tasks.links.length > 0) {
  6840. this.social.visitLink = visitLink;
  6841. }
  6842. return await Promise.all(pro).then(result => {
  6843. let checked = true;
  6844. for (const data of result) {
  6845. if (data.result) {
  6846. this.socialInitialized[data.name] = data.result;
  6847. } else {
  6848. checked = false;
  6849. }
  6850. }
  6851. return checked;
  6852. });
  6853. } catch (error) {
  6854. throwError(error, 'Website.initSocial');
  6855. return false;
  6856. }
  6857. }
  6858. uniqueTasks(allTasks) {
  6859. try {
  6860. const result = {};
  6861. for (const [ social, types ] of Object.entries(allTasks)) {
  6862. result[social] = {};
  6863. for (const [ type, tasks ] of Object.entries(types)) {
  6864. result[social][type] = unique(tasks);
  6865. }
  6866. }
  6867. return result;
  6868. } catch (error) {
  6869. throwError(error, 'Website.uniqueTasks');
  6870. return allTasks;
  6871. }
  6872. }
  6873. async toggleTask(action) {
  6874. try {
  6875. if (!this.initialized && !this.init()) {
  6876. return false;
  6877. }
  6878. if (!await this.classifyTask(action)) {
  6879. return false;
  6880. }
  6881. await this.initSocial(action);
  6882. const pro = [];
  6883. const doTask = action === 'do';
  6884. const tasks = doTask ? this.undoneTasks : this.socialTasks;
  6885. if (this.socialInitialized.discord === true && this.social.discord) {
  6886. pro.push(this.social.discord.toggle({
  6887. doTask: doTask,
  6888. ...tasks.discord
  6889. }));
  6890. }
  6891. if (this.socialInitialized.instagram === true && this.social.instagram) {
  6892. pro.push(this.social.instagram.toggle({
  6893. doTask: doTask,
  6894. ...tasks.instagram
  6895. }));
  6896. }
  6897. if (this.socialInitialized.reddit === true && this.social.reddit) {
  6898. pro.push(this.social.reddit.toggle({
  6899. doTask: doTask,
  6900. ...tasks.reddit
  6901. }));
  6902. }
  6903. if (this.socialInitialized.twitch === true && this.social.twitch) {
  6904. pro.push(this.social.twitch.toggle({
  6905. doTask: doTask,
  6906. ...tasks.twitch
  6907. }));
  6908. }
  6909. if (this.socialInitialized.twitter === true && this.social.twitter) {
  6910. pro.push(this.social.twitter.toggle({
  6911. doTask: doTask,
  6912. ...tasks.twitter
  6913. }));
  6914. }
  6915. if (this.socialInitialized.vk === true && this.social.vk) {
  6916. pro.push(this.social.vk.toggle({
  6917. doTask: doTask,
  6918. ...tasks.vk
  6919. }));
  6920. }
  6921. if (this.socialInitialized.youtube === true && this.social.youtube) {
  6922. pro.push(this.social.youtube.toggle({
  6923. doTask: doTask,
  6924. ...tasks.youtube
  6925. }));
  6926. }
  6927. if ((this.steamTaskType.steamCommunity ? this.socialInitialized.steamCommunity === true : true) && (this.steamTaskType.steamStore ? this.socialInitialized.steamStore === true : true) && this.social.steam) {
  6928. pro.push(this.social.steam.toggle({
  6929. doTask: doTask,
  6930. ...tasks.steam
  6931. }));
  6932. }
  6933. if (this.social.visitLink && tasks.links && doTask) {
  6934. for (const link of tasks.links) {
  6935. pro.push(this.social.visitLink(link));
  6936. }
  6937. }
  6938. if (doTask && tasks.extra && this.extraDoTask) {
  6939. const hasExtra = Object.values(tasks.extra).reduce((total, arr) => [ ...total, ...arr ]).length > 0;
  6940. if (hasExtra) {
  6941. pro.push(this.extraDoTask(tasks.extra));
  6942. }
  6943. }
  6944. await Promise.all(pro);
  6945. scripts_echoLog({}).success(i18n('allTasksComplete'));
  6946. return true;
  6947. } catch (error) {
  6948. throwError(error, 'Website.toggleTask');
  6949. return false;
  6950. }
  6951. }
  6952. async doTask() {
  6953. try {
  6954. return await this.toggleTask('do');
  6955. } catch (error) {
  6956. throwError(error, 'Website.doTask');
  6957. return false;
  6958. }
  6959. }
  6960. async undoTask() {
  6961. try {
  6962. return await this.toggleTask('undo');
  6963. } catch (error) {
  6964. throwError(error, 'Website.undoTask');
  6965. return false;
  6966. }
  6967. }
  6968. }
  6969. const website_Website = Website;
  6970. const defaultTasksTemplate = {
  6971. steam: {
  6972. groupLinks: [],
  6973. wishlistLinks: [],
  6974. curatorLinks: [],
  6975. followLinks: []
  6976. },
  6977. discord: {
  6978. serverLinks: []
  6979. },
  6980. vk: {
  6981. nameLinks: []
  6982. },
  6983. extra: {
  6984. website: []
  6985. }
  6986. };
  6987. const defaultTasks = JSON.stringify(defaultTasksTemplate);
  6988. class FreeAnyWhere extends website_Website {
  6989. name = 'FreeAnyWhere';
  6990. tasks = [];
  6991. socialTasks = JSON.parse(defaultTasks);
  6992. undoneTasks = JSON.parse(defaultTasks);
  6993. buttons = [ 'doTask', 'undoTask', 'verifyTask', 'getKey' ];
  6994. static test() {
  6995. return window.location.host === 'freeanywhere.net';
  6996. }
  6997. async init() {
  6998. try {
  6999. const logStatus = scripts_echoLog({
  7000. text: i18n('initing')
  7001. });
  7002. debug('检测登录按钮');
  7003. if ($('div.header__login a[href*=logout]').length === 0) {
  7004. window.open('https://freeanywhere.net/game.php?steam_login', '_self');
  7005. logStatus.warning(i18n('needLogin'));
  7006. return false;
  7007. }
  7008. debug('检测是否为登录页面');
  7009. if (window.location.href.includes('/login')) {
  7010. logStatus.warning(i18n('needLogin'));
  7011. return false;
  7012. }
  7013. this.initialized = true;
  7014. logStatus.success();
  7015. return true;
  7016. } catch (error) {
  7017. throwError(error, 'Freeanywhere.init');
  7018. return false;
  7019. }
  7020. }
  7021. async classifyTask(action) {
  7022. try {
  7023. const logStatus = scripts_echoLog({
  7024. text: i18n('getTasksInfo')
  7025. });
  7026. if (action === 'undo') {
  7027. this.socialTasks = GM_getValue(`fawTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks);
  7028. }
  7029. const tasks = $('div.game__content-tasks__task').map((index, element) => ({
  7030. id: $(element).attr('data-id'),
  7031. social: $(element).find('div.task-img img').attr('alt'),
  7032. link: $(element).find('div.task-link a').attr('href'),
  7033. title: $(element).find('div.task-link').text().trim(),
  7034. type: $(element).attr('data-type'),
  7035. isSuccess: $(element).hasClass('done')
  7036. })).toArray();
  7037. if (tasks.length === 0) {
  7038. logStatus.success();
  7039. return false;
  7040. }
  7041. if (action === 'verify') {
  7042. this.tasks = [];
  7043. }
  7044. for (const task of tasks) {
  7045. debug('任务分类', task);
  7046. const {
  7047. id,
  7048. social,
  7049. title,
  7050. type,
  7051. link,
  7052. isSuccess
  7053. } = task;
  7054. const taskInfo = {
  7055. id: id,
  7056. title: title,
  7057. social: social,
  7058. type: type
  7059. };
  7060. if (action === 'verify' && !isSuccess) {
  7061. this.tasks.push(taskInfo);
  7062. continue;
  7063. }
  7064. switch (type) {
  7065. case 'steam_account_verify':
  7066. break;
  7067.  
  7068. case 'steam_game_wishlist':
  7069. if (action === 'undo' && link) {
  7070. this.socialTasks.steam.wishlistLinks.push(link);
  7071. }
  7072. if (action === 'do' && !isSuccess && link) {
  7073. this.undoneTasks.steam.wishlistLinks.push(link);
  7074. }
  7075. break;
  7076.  
  7077. case 'steam_group_sub':
  7078. if (action === 'undo' && link) {
  7079. this.socialTasks.steam.groupLinks.push(link);
  7080. }
  7081. if (action === 'do' && !isSuccess && link) {
  7082. this.undoneTasks.steam.groupLinks.push(link);
  7083. }
  7084. break;
  7085.  
  7086. case 'site_visit':
  7087. if (action === 'do' && !isSuccess) {
  7088. this.undoneTasks.extra.website.push(`id=${id}&type=${type}&task=true`);
  7089. }
  7090. break;
  7091.  
  7092. case 'vk_community_sub':
  7093. if (action === 'undo' && link) {
  7094. this.socialTasks.vk.nameLinks.push(link);
  7095. }
  7096. if (action === 'do' && !isSuccess && link) {
  7097. this.undoneTasks.vk.nameLinks.push(link);
  7098. }
  7099. break;
  7100.  
  7101. case 'vk_post_like':
  7102. if (action === 'undo' && link) {
  7103. this.socialTasks.vk.nameLinks.push(`${link}&action=like`);
  7104. }
  7105. if (action === 'do' && !isSuccess && link) {
  7106. this.undoneTasks.vk.nameLinks.push(`${link}&action=like`);
  7107. }
  7108. break;
  7109.  
  7110. case 'discord_server_sub':
  7111. if (action === 'undo' && link) {
  7112. this.socialTasks.discord.serverLinks.push(link);
  7113. }
  7114. if (action === 'do' && !isSuccess && link) {
  7115. this.undoneTasks.discord.serverLinks.push(link);
  7116. }
  7117. break;
  7118.  
  7119. case 'telegram_channel_sub':
  7120. scripts_echoLog({}).warning(`${i18n('tgTaskNotice')}`);
  7121. break;
  7122.  
  7123. case 'none':
  7124. scripts_echoLog({}).warning(`${i18n('notConnect')}`);
  7125. break;
  7126.  
  7127. default:
  7128. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${type}`);
  7129. break;
  7130. }
  7131. }
  7132. logStatus.success();
  7133. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  7134. this.socialTasks = this.uniqueTasks(this.socialTasks);
  7135. if (window.DEBUG) {
  7136. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  7137. }
  7138. GM_setValue(`fawTasks-${this.giveawayId}`, {
  7139. tasks: this.socialTasks,
  7140. time: new Date().getTime()
  7141. });
  7142. return true;
  7143. } catch (error) {
  7144. throwError(error, 'Freeanywhere.classifyTask');
  7145. return false;
  7146. }
  7147. }
  7148. async verifyTask() {
  7149. try {
  7150. if (!this.initialized && !this.init()) {
  7151. debug('未初始化');
  7152. return false;
  7153. }
  7154. if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
  7155. debug('任务列表为空', this.tasks);
  7156. return false;
  7157. }
  7158. const pro = [];
  7159. for (const task of this.tasks) {
  7160. pro.push(this.#verify(task));
  7161. await delay(1e3);
  7162. }
  7163. await Promise.all(pro);
  7164. scripts_echoLog({}).success(i18n('allTasksComplete'));
  7165. return !!await this.getKey(true);
  7166. } catch (error) {
  7167. throwError(error, 'Freeanywhere.verifyTask');
  7168. return false;
  7169. }
  7170. }
  7171. async extraDoTask({
  7172. website
  7173. }) {
  7174. try {
  7175. const pro = [];
  7176. for (const link of website) {
  7177. pro.push(this.#doVisitWebsite(link));
  7178. }
  7179. return Promise.all(pro).then(() => true);
  7180. } catch (error) {
  7181. throwError(error, 'FreeAnyWhere.extraDoTask');
  7182. return false;
  7183. }
  7184. }
  7185. async #doVisitWebsite(link) {
  7186. try {
  7187. const logStatus = scripts_echoLog({
  7188. text: i18n('visitingLink')
  7189. });
  7190. const {
  7191. result,
  7192. statusText,
  7193. status,
  7194. data
  7195. } = await tools_httpRequest({
  7196. url: 'https://freeanywhere.net/php/task_site_visit_done.php',
  7197. method: 'POST',
  7198. headers: {
  7199. 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  7200. },
  7201. data: link
  7202. });
  7203. if (result === 'Success') {
  7204. logStatus.success();
  7205. return true;
  7206. }
  7207. logStatus.error(`${result}:${statusText}(${status})`);
  7208. return false;
  7209. } catch (error) {
  7210. throwError(error, 'FreeAnyWhere.doVisitWebsite');
  7211. return false;
  7212. }
  7213. }
  7214. async getKey(initialized) {
  7215. try {
  7216. if (!initialized && !this.initialized && !this.init()) {
  7217. debug('未初始化');
  7218. return false;
  7219. }
  7220. const logStatus = scripts_echoLog({
  7221. text: i18n('gettingKey')
  7222. });
  7223. const {
  7224. result,
  7225. statusText,
  7226. status,
  7227. data
  7228. } = await tools_httpRequest({
  7229. url: 'https://freeanywhere.net/php/user_get_key.php',
  7230. method: 'POST'
  7231. });
  7232. if (result === 'Success') {
  7233. if (data?.responseText.indexOf('bad') !== -1 || data?.responseText.length > 50) {
  7234. logStatus.error(data?.responseText);
  7235. return false;
  7236. }
  7237. logStatus.success();
  7238. scripts_echoLog({}).success(data.responseText);
  7239. return data.responseText;
  7240. }
  7241. logStatus.error(`${result}:${statusText}(${status})`);
  7242. return false;
  7243. } catch (error) {
  7244. throwError(error, 'FreeAnyWhere.getGiveawayId');
  7245. return false;
  7246. }
  7247. }
  7248. #getGiveawayId() {
  7249. try {
  7250. const giveawayId = new URLSearchParams(window.location.search).get('n');
  7251. if (giveawayId) {
  7252. this.giveawayId = giveawayId;
  7253. return true;
  7254. }
  7255. scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId'));
  7256. return false;
  7257. } catch (error) {
  7258. throwError(error, 'FreeAnyWhere.getGiveawayId');
  7259. return false;
  7260. }
  7261. }
  7262. async #verify(task) {
  7263. try {
  7264. const logStatus = scripts_echoLog({
  7265. html: `<li>${i18n('verifyingTask')}${task.title.trim()}...<font></font></li>`
  7266. });
  7267. const {
  7268. result,
  7269. statusText,
  7270. status,
  7271. data
  7272. } = await tools_httpRequest({
  7273. url: 'https://freeanywhere.net/php/user_task_update.php',
  7274. method: 'POST',
  7275. headers: {
  7276. 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  7277. },
  7278. data: `id=${task.id}&type=${task.type}`
  7279. });
  7280. if (result === 'Success') {
  7281. if (data?.responseText.trim() === 'good') {
  7282. logStatus.success();
  7283. return true;
  7284. }
  7285. debug('任务验证结果', data?.response);
  7286. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  7287. return false;
  7288. }
  7289. logStatus.error(`${result}:${statusText}(${status})`);
  7290. return false;
  7291. } catch (error) {
  7292. throwError(error, 'Freeanywhere.verify');
  7293. return false;
  7294. }
  7295. }
  7296. async #checkLeftKey() {
  7297. try {
  7298. if (!globalOptions.other.checkLeftKey) {
  7299. return true;
  7300. }
  7301. debug('检测剩余Key');
  7302. const {
  7303. data
  7304. } = await tools_httpRequest({
  7305. url: 'https://freeanywhere.net/api/v1/widget/?format=json',
  7306. method: 'GET',
  7307. dataType: 'json',
  7308. headers: {
  7309. authorization: `Token ${window.localStorage.getItem('token')}`
  7310. }
  7311. });
  7312. if (data?.response?.giveaways.find(giveaway => `${giveaway?.id}` === this.giveawayId)) {
  7313. return true;
  7314. }
  7315. await external_Swal_default().fire({
  7316. icon: 'warning',
  7317. title: i18n('notice'),
  7318. text: i18n('noKeysLeft'),
  7319. confirmButtonText: i18n('confirm'),
  7320. cancelButtonText: i18n('cancel'),
  7321. showCancelButton: true
  7322. }).then(({
  7323. value
  7324. }) => {
  7325. if (value) {
  7326. window.close();
  7327. }
  7328. });
  7329. return true;
  7330. } catch (error) {
  7331. throwError(error, 'Giveawaysu.checkLeftKey');
  7332. return false;
  7333. }
  7334. }
  7335. }
  7336. const Freeanywhere = FreeAnyWhere;
  7337. const Giveawaysu_defaultTasks = {
  7338. steam: {
  7339. groupLinks: [],
  7340. wishlistLinks: [],
  7341. curatorLinks: [],
  7342. curatorLikeLinks: [],
  7343. followLinks: [],
  7344. forumLinks: [],
  7345. announcementLinks: [],
  7346. workshopVoteLinks: [],
  7347. playtestLinks: []
  7348. },
  7349. discord: {
  7350. serverLinks: []
  7351. },
  7352. instagram: {
  7353. userLinks: []
  7354. },
  7355. vk: {
  7356. nameLinks: []
  7357. },
  7358. twitch: {
  7359. channelLinks: []
  7360. },
  7361. reddit: {
  7362. redditLinks: []
  7363. },
  7364. youtube: {
  7365. channelLinks: [],
  7366. likeLinks: []
  7367. },
  7368. twitter: {
  7369. userLinks: [],
  7370. retweetLinks: []
  7371. }
  7372. };
  7373. class GiveawaySu extends website_Website {
  7374. name = 'GiveawaySu';
  7375. socialTasks = Giveawaysu_defaultTasks;
  7376. undoneTasks = Giveawaysu_defaultTasks;
  7377. buttons = [ 'doTask', 'undoTask' ];
  7378. static test() {
  7379. return /^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(window.location.href);
  7380. }
  7381. async after() {
  7382. try {
  7383. if (!this.#checkLogin()) {
  7384. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  7385. }
  7386. if (!await this.#checkLeftKey()) {
  7387. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  7388. }
  7389. scripts_echoLog({}).warning(i18n('gsNotice'));
  7390. } catch (error) {
  7391. throwError(error, 'Giveawaysu.after');
  7392. }
  7393. }
  7394. init() {
  7395. try {
  7396. const logStatus = scripts_echoLog({
  7397. text: i18n('initing')
  7398. });
  7399. if ($('a.steam-login').length > 0) {
  7400. window.open('/steam/redirect', '_self');
  7401. logStatus.warning(i18n('needLogin'));
  7402. return false;
  7403. }
  7404. if (!this.#getGiveawayId()) {
  7405. return false;
  7406. }
  7407. this.initialized = true;
  7408. logStatus.success();
  7409. return true;
  7410. } catch (error) {
  7411. throwError(error, 'Giveawaysu.init');
  7412. return false;
  7413. }
  7414. }
  7415. async classifyTask(action) {
  7416. try {
  7417. const logStatus = scripts_echoLog({
  7418. text: i18n('getTasksInfo')
  7419. });
  7420. if (action === 'undo') {
  7421. this.socialTasks = GM_getValue(`gasTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks;
  7422. return true;
  7423. }
  7424. const pro = [];
  7425. const tasks = $('#actions tr');
  7426. if ($('div.bind-discord').is(':visible')) {
  7427. $('div.bind-discord a')[0].click();
  7428. }
  7429. if ($('div.bind-twitch').is(':visible')) {
  7430. $('div.bind-twitch a')[0].click();
  7431. }
  7432. for (const task of tasks) {
  7433. pro.push(new Promise(resolve => {
  7434. const td = $(task).find('td:not(".hidden")');
  7435. const colorfulTask = td.eq(1).find('a:not([data-trigger="link"])');
  7436. const colorlessTask = td.eq(2).find('a:not([data-trigger="link"])');
  7437. const taskDes = colorfulTask.length > 0 ? colorfulTask : colorlessTask;
  7438. const taskIcon = td.eq(0).find('i').attr('class') || '';
  7439. const taskName = taskDes.text().trim();
  7440. if (taskIcon.includes('ban') || /disable adblock/gi.test(taskName)) {
  7441. return resolve(true);
  7442. }
  7443. getRedirectLink(taskDes.attr('href')).then(taskLink => {
  7444. if (!taskLink) {
  7445. return resolve(false);
  7446. }
  7447. if (taskIcon.includes('steam') && /join/gi.test(taskName)) {
  7448. this.undoneTasks.steam.groupLinks.push(taskLink);
  7449. } else if (/like.*announcement/gi.test(taskName)) {
  7450. this.undoneTasks.steam.announcementLinks.push(taskLink);
  7451. } else if (/(follow|subscribe).*curator/gim.test(taskName) && /^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) {
  7452. this.undoneTasks.steam.curatorLinks.push(taskLink);
  7453. } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
  7454. this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
  7455. } else if (/subscribe.*steam.*forum/gim.test(taskName)) {
  7456. this.undoneTasks.steam.forumLinks.push(taskLink);
  7457. } else if (taskIcon.includes('thumbs-up') && /^https?:\/\/steamcommunity\.com\/sharedfiles\/filedetails\/\?id=[\d]+/.test(taskLink)) {
  7458. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  7459. } else if (taskIcon.includes('plus') && /request.*playtest/gim.test(taskName)) {
  7460. this.undoneTasks.steam.playtestLinks.push(taskLink);
  7461. } else if (taskIcon.includes('discord') || /join.*discord/gim.test(taskName)) {
  7462. this.undoneTasks.discord.serverLinks.push(taskLink);
  7463. } else if (taskIcon.includes('instagram') || /follow.*instagram/gim.test(taskName)) {
  7464. this.undoneTasks.instagram.userLinks.push(taskLink);
  7465. } else if (taskIcon.includes('twitch') || /follow.*twitch.*channel/gim.test(taskName)) {
  7466. this.undoneTasks.twitch.channelLinks.push(taskLink);
  7467. } else if (taskIcon.includes('reddit') || /subscribe.*subreddit/gim.test(taskName) || /follow.*reddit/gim.test(taskName)) {
  7468. this.undoneTasks.reddit.redditLinks.push(taskLink);
  7469. } else if (/watch.*art/gim.test(taskName)) {
  7470. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  7471. } else if (/subscribe.*youtube.*channel/gim.test(taskName)) {
  7472. this.undoneTasks.youtube.channelLinks.push(taskLink);
  7473. } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) {
  7474. this.undoneTasks.youtube.likeLinks.push(taskLink);
  7475. } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) {
  7476. this.undoneTasks.vk.nameLinks.push(taskLink);
  7477. } else {
  7478. if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else {
  7479. if (/wishlist.*game|add.*wishlist/gim.test(taskName)) {
  7480. this.undoneTasks.steam.wishlistLinks.push(taskLink);
  7481. }
  7482. if (/follow.*button/gim.test(taskName)) {
  7483. this.undoneTasks.steam.followLinks.push(taskLink);
  7484. }
  7485. }
  7486. }
  7487. resolve(true);
  7488. }).catch(error => {
  7489. throwError(error, 'Giveawaysu.classifyTask->getRedirectLink');
  7490. return false;
  7491. });
  7492. }));
  7493. }
  7494. await Promise.all(pro);
  7495. logStatus.success();
  7496. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  7497. this.socialTasks = this.undoneTasks;
  7498. if (window.DEBUG) {
  7499. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  7500. }
  7501. GM_setValue(`gasTasks-${this.giveawayId}`, {
  7502. tasks: this.socialTasks,
  7503. time: new Date().getTime()
  7504. });
  7505. return true;
  7506. } catch (error) {
  7507. throwError(error, 'Giveawaysu.classifyTask');
  7508. return false;
  7509. }
  7510. }
  7511. #checkLogin() {
  7512. try {
  7513. if (!globalOptions.other.checkLogin) {
  7514. return true;
  7515. }
  7516. if ($('a.steam-login').length > 0) {
  7517. window.open('/steam/redirect', '_self');
  7518. }
  7519. return true;
  7520. } catch (error) {
  7521. throwError(error, 'Giveawaysu.checkLogin');
  7522. return false;
  7523. }
  7524. }
  7525. async #checkLeftKey() {
  7526. try {
  7527. if (!globalOptions.other.checkLeftKey) {
  7528. return true;
  7529. }
  7530. if ($('.giveaway-ended').length > 0 && $('.giveaway-key').length === 0) {
  7531. await external_Swal_default().fire({
  7532. icon: 'warning',
  7533. title: i18n('notice'),
  7534. text: i18n('noKeysLeft'),
  7535. confirmButtonText: i18n('confirm'),
  7536. cancelButtonText: i18n('cancel'),
  7537. showCancelButton: true
  7538. }).then(({
  7539. value
  7540. }) => {
  7541. if (value) {
  7542. window.close();
  7543. }
  7544. });
  7545. }
  7546. return true;
  7547. } catch (error) {
  7548. throwError(error, 'Giveawaysu.checkLeftKey');
  7549. return false;
  7550. }
  7551. }
  7552. #getGiveawayId() {
  7553. try {
  7554. const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
  7555. if (giveawayId) {
  7556. this.giveawayId = giveawayId;
  7557. return true;
  7558. }
  7559. scripts_echoLog({
  7560. text: i18n('getFailed', 'GiveawayId')
  7561. });
  7562. return false;
  7563. } catch (error) {
  7564. throwError(error, 'Giveawaysu.getGiveawayId');
  7565. return false;
  7566. }
  7567. }
  7568. }
  7569. class Indiedb {
  7570. name = 'Indiedb';
  7571. buttons = [ 'doTask' ];
  7572. static test() {
  7573. return window.location.host === 'www.indiedb.com';
  7574. }
  7575. async after() {
  7576. try {
  7577. if (!this.#checkLogin()) {
  7578. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  7579. }
  7580. if (!await this.#checkLeftKey()) {
  7581. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  7582. }
  7583. } catch (error) {
  7584. throwError(error, 'Indiedb.after');
  7585. }
  7586. }
  7587. async doTask() {
  7588. try {
  7589. if (!await this.#join()) {
  7590. return false;
  7591. }
  7592. return await this.#do();
  7593. } catch (error) {
  7594. throwError(error, 'Indiedb.doTask');
  7595. return false;
  7596. }
  7597. }
  7598. async #join() {
  7599. try {
  7600. if ($('a.buttonenter:contains(Register to join)').length > 0) {
  7601. scripts_echoLog({}).error(i18n('needLogin'));
  7602. return false;
  7603. }
  7604. const currentoption = $('a.buttonenter.buttongiveaway');
  7605. if (/join giveaway/gim.test(currentoption.text())) {
  7606. const logStatus = scripts_echoLog({
  7607. text: `${i18n('joiningGiveaway')}...`
  7608. });
  7609. const {
  7610. result,
  7611. statusText,
  7612. status,
  7613. data
  7614. } = await tools_httpRequest({
  7615. url: currentoption.attr('href'),
  7616. method: 'POST',
  7617. data: 'ajax=t',
  7618. dataType: 'json',
  7619. headers: {
  7620. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  7621. Accept: 'application/json, text/javascript, */*; q=0.01',
  7622. Origin: window.location.origin,
  7623. referer: window.location.href
  7624. }
  7625. });
  7626. if (result === 'Success') {
  7627. if (data?.status === 200) {
  7628. if (data.response?.success) {
  7629. currentoption.addClass('buttonentered').text('Success - Giveaway joined');
  7630. $('#giveawaysjoined').slideDown();
  7631. $('#giveawaysrecommend').slideDown();
  7632. logStatus.success(`Success${data.response?.text ? `:${data.response?.text}` : ''}`);
  7633. return true;
  7634. }
  7635. logStatus.error(`Error${data.response?.text ? `:${data.response?.text}` : ''}`);
  7636. return false;
  7637. }
  7638. if (await this.#join2()) {
  7639. logStatus.success('Success');
  7640. return true;
  7641. }
  7642. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  7643. return false;
  7644. }
  7645. logStatus.error(`${result}:${statusText}(${status})`);
  7646. return false;
  7647. } else if (/success/gim.test($('a.buttonenter.buttongiveaway').text())) {
  7648. return true;
  7649. }
  7650. scripts_echoLog({}).warning(i18n('needJoinGiveaway'));
  7651. return false;
  7652. } catch (error) {
  7653. throwError(error, 'Indiedb.join');
  7654. return false;
  7655. }
  7656. }
  7657. async #join2() {
  7658. try {
  7659. return await new Promise(resolve => {
  7660. const targetNode = document.getElementById('giveawaysjoined');
  7661. const config = {
  7662. attributes: true
  7663. };
  7664. const observer = new MutationObserver(() => {
  7665. if ($('#giveawaysjoined').is(':visible')) {
  7666. resolve(true);
  7667. observer.disconnect();
  7668. }
  7669. });
  7670. observer.observe(targetNode, config);
  7671. $('a.buttonenter.buttongiveaway')[0]?.click();
  7672. setTimeout(() => {
  7673. resolve(false);
  7674. observer.disconnect();
  7675. }, 3e4);
  7676. });
  7677. } catch (error) {
  7678. throwError(error, 'Indiedb.join2');
  7679. return false;
  7680. }
  7681. }
  7682. async #do() {
  7683. try {
  7684. const id = $('script').map((index, script) => {
  7685. if (/\$\(document\)/gim.test(script.innerHTML)) {
  7686. return [ script.innerHTML.match(/"\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0], script.innerHTML.match(/"\/newsletter\/ajax\/subscribeprofile\/optin\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0] ];
  7687. }
  7688. return null;
  7689. });
  7690. if (id.length === 2) {
  7691. const pro = [];
  7692. const tasks = $('#giveawaysjoined a[class*=promo]');
  7693. for (const task of tasks) {
  7694. const promo = $(task);
  7695. if (!promo.hasClass('buttonentered')) {
  7696. const status = scripts_echoLog({
  7697. text: `${i18n('doing')}:${promo.parents('p').text()}...`
  7698. });
  7699. if (/facebookpromo|twitterpromo|visitpromo/gim.test(task.className)) {
  7700. let text = '';
  7701. if (promo.hasClass('facebookpromo')) {
  7702. text = 'facebookpromo';
  7703. } else if (promo.hasClass('twitterpromo')) {
  7704. text = 'twitterpromo';
  7705. } else {
  7706. text = 'visitpromo';
  7707. }
  7708. pro.push(new Promise(resolve => {
  7709. $.ajax({
  7710. type: 'POST',
  7711. url: urlPath(`/giveaways/ajax/${text}/${id[0]}`),
  7712. timeout: 6e4,
  7713. dataType: 'json',
  7714. data: {
  7715. ajax: 't'
  7716. },
  7717. error(response, error, exception) {
  7718. if (window.DEBUG) {
  7719. console.log('%cAuto-Task[Debug]:', 'color:red', {
  7720. response: response,
  7721. error: error,
  7722. exception: exception
  7723. });
  7724. }
  7725. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  7726. resolve(true);
  7727. },
  7728. success(response) {
  7729. if (response.success) {
  7730. status.success(`Success:${response.text}`);
  7731. promo.addClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  7732. resolve(true);
  7733. } else {
  7734. status.error(`Error:${response.text}`);
  7735. resolve(true);
  7736. }
  7737. }
  7738. });
  7739. }));
  7740. } else if (promo.hasClass('emailoptinpromo')) {
  7741. pro.push(new Promise(resolve => {
  7742. $.ajax({
  7743. type: 'POST',
  7744. url: urlPath(`/newsletter/ajax/subscribeprofile/optin/${id[1]}`),
  7745. timeout: 6e4,
  7746. dataType: 'json',
  7747. data: {
  7748. ajax: 't',
  7749. emailsystoggle: 4
  7750. },
  7751. error(response, error, exception) {
  7752. if (window.DEBUG) {
  7753. console.log('%cAuto-Task[Debug]:', 'color:red', {
  7754. response: response,
  7755. error: error,
  7756. exception: exception
  7757. });
  7758. }
  7759. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  7760. resolve(true);
  7761. },
  7762. success(response) {
  7763. if (response.success) {
  7764. status.success(`Success:${response.text}`);
  7765. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  7766. resolve(true);
  7767. } else {
  7768. status.error(`Error:${response.text}`);
  7769. resolve(true);
  7770. }
  7771. }
  7772. });
  7773. }));
  7774. } else if (promo.hasClass('watchingpromo')) {
  7775. pro.push(new Promise(resolve => {
  7776. const data = getUrlQuery(promo.attr('href'));
  7777. data.ajax = 't';
  7778. $.ajax({
  7779. type: 'POST',
  7780. url: urlPath(promo.attr('href')?.split(/[?#]/)[0]),
  7781. timeout: 6e4,
  7782. dataType: 'json',
  7783. data: data,
  7784. error(response, error, exception) {
  7785. if (window.DEBUG) {
  7786. console.log('%cAuto-Task[Debug]:', 'color:red', {
  7787. response: response,
  7788. error: error,
  7789. exception: exception
  7790. });
  7791. }
  7792. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  7793. resolve(true);
  7794. },
  7795. success(response) {
  7796. if (response.success) {
  7797. status.success(`Success:${response.text}`);
  7798. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  7799. resolve(true);
  7800. } else {
  7801. status.error(`Error:${response.text}`);
  7802. resolve(true);
  7803. }
  7804. }
  7805. });
  7806. }));
  7807. } else if (!/the-challenge-of-adblock/gim.test(promo.attr('href'))) {
  7808. pro.push(new Promise(resolve => {
  7809. $.ajax({
  7810. type: 'POST',
  7811. url: urlPath(promo.attr('href')),
  7812. timeout: 6e4,
  7813. dataType: 'json',
  7814. data: {
  7815. ajax: 't'
  7816. },
  7817. error(response, error, exception) {
  7818. if (window.DEBUG) {
  7819. console.log('%cAuto-Task[Debug]:', 'color:red', {
  7820. response: response,
  7821. error: error,
  7822. exception: exception
  7823. });
  7824. }
  7825. status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
  7826. resolve(true);
  7827. },
  7828. success(response) {
  7829. if (response.success) {
  7830. status.success(`Success:${response.text}`);
  7831. promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
  7832. resolve(true);
  7833. } else {
  7834. status.error(`Error:${response.text}`);
  7835. resolve(true);
  7836. }
  7837. }
  7838. });
  7839. }));
  7840. } else {
  7841. status.error(`Error:${i18n('unKnownTaskType')}`);
  7842. }
  7843. }
  7844. }
  7845. await Promise.all(pro);
  7846. scripts_echoLog({}).success(i18n('allTasksComplete'));
  7847. return true;
  7848. }
  7849. scripts_echoLog({}).error(i18n('getFailed', 'TaskId'));
  7850. return false;
  7851. } catch (error) {
  7852. throwError(error, 'Indiedb.classifyTask');
  7853. return false;
  7854. }
  7855. }
  7856. #checkLogin() {
  7857. try {
  7858. if (!globalOptions.other.checkLogin) {
  7859. return true;
  7860. }
  7861. if ($('a.buttonenter:contains(Register to join)').length > 0) {
  7862. window.open('/members/login', '_self');
  7863. }
  7864. return true;
  7865. } catch (error) {
  7866. throwError(error, 'Indiedb.checkLogin');
  7867. return false;
  7868. }
  7869. }
  7870. async #checkLeftKey() {
  7871. try {
  7872. if (!globalOptions.other.checkLeftKey) {
  7873. return true;
  7874. }
  7875. if ($('a.buttonenter:contains("next time"), a.buttonenter:contains("Giveaway is closed")').length > 0) {
  7876. await external_Swal_default().fire({
  7877. icon: 'warning',
  7878. title: i18n('notice'),
  7879. text: i18n('giveawayEnded'),
  7880. confirmButtonText: i18n('confirm'),
  7881. cancelButtonText: i18n('cancel'),
  7882. showCancelButton: true
  7883. }).then(({
  7884. value
  7885. }) => {
  7886. if (value) {
  7887. window.close();
  7888. }
  7889. });
  7890. }
  7891. return true;
  7892. } catch (error) {
  7893. throwError(error, 'Indiedb.checkLeftKey');
  7894. return false;
  7895. }
  7896. }
  7897. }
  7898. const website_Indiedb = Indiedb;
  7899. const Keyhub_defaultTasksTemplate = {
  7900. steam: {
  7901. groupLinks: [],
  7902. officialGroupLinks: [],
  7903. wishlistLinks: [],
  7904. curatorLinks: []
  7905. },
  7906. discord: {
  7907. serverLinks: []
  7908. },
  7909. extra: {
  7910. videoTasks: []
  7911. },
  7912. links: []
  7913. };
  7914. const Keyhub_defaultTasks = JSON.stringify(Keyhub_defaultTasksTemplate);
  7915. class Keyhub extends website_Website {
  7916. name = 'Keyhub';
  7917. socialTasks = JSON.parse(Keyhub_defaultTasks);
  7918. undoneTasks = JSON.parse(Keyhub_defaultTasks);
  7919. buttons = [ 'doTask', 'undoTask' ];
  7920. static test() {
  7921. return window.location.host === 'key-hub.eu';
  7922. }
  7923. async after() {
  7924. try {
  7925. if (!this.#checkLogin()) {
  7926. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  7927. }
  7928. if (!await this.#checkLeftKey()) {
  7929. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  7930. }
  7931. $('.NSFW').hide();
  7932. } catch (error) {
  7933. throwError(error, 'Keyhub.after');
  7934. }
  7935. }
  7936. init() {
  7937. try {
  7938. const logStatus = scripts_echoLog({
  7939. text: i18n('initing')
  7940. });
  7941. if ($('a[href*="/connect/steam"]').length > 0) {
  7942. window.open('/connect/steam', '_self');
  7943. logStatus.warning(i18n('needLogin'));
  7944. return false;
  7945. }
  7946. if (!this.#getGiveawayId()) {
  7947. return false;
  7948. }
  7949. $('#VPNoverlay').hide();
  7950. $('#mainArticleSection').show();
  7951. this.initialized = true;
  7952. logStatus.success();
  7953. return true;
  7954. } catch (error) {
  7955. throwError(error, 'Keyhub.init');
  7956. return false;
  7957. }
  7958. }
  7959. async classifyTask(action) {
  7960. try {
  7961. const logStatus = scripts_echoLog({
  7962. text: i18n('getTasksInfo')
  7963. });
  7964. if (action === 'undo') {
  7965. this.socialTasks = GM_getValue(`khTasks-${this.giveawayId}`)?.tasks || JSON.parse(Keyhub_defaultTasks);
  7966. }
  7967. const tasks = $('.task:not(".googleads")').filter((index, element) => action === 'do' ? $(element).find('i.fa-check-circle:visible').length === 0 : true).find('a');
  7968. for (const task of tasks) {
  7969. let link = $(task).attr('href');
  7970. const taskDes = $(task).text().trim();
  7971. if (!link) {
  7972. continue;
  7973. }
  7974. if (/\/away\?data=/.test(link) || /steamcommunity\.com\/gid\//.test(link)) {
  7975. link = await getRedirectLink(link) || link;
  7976. }
  7977. if (/https?:\/\/key-hub\.eu\/connect\/discord/.test(link)) {
  7978. GM_openInTab(link, {
  7979. active: true
  7980. });
  7981. } else if (/steamcommunity\.com\/groups\//.test(link)) {
  7982. if (action === 'undo') {
  7983. this.socialTasks.steam.groupLinks.push(link);
  7984. }
  7985. if (action === 'do') {
  7986. this.undoneTasks.steam.groupLinks.push(link);
  7987. }
  7988. } else if (/steamcommunity\.com\/games\/[\d]+/.test(link)) {
  7989. if (action === 'undo') {
  7990. this.socialTasks.steam.officialGroupLinks.push(link);
  7991. }
  7992. if (action === 'do') {
  7993. this.undoneTasks.steam.officialGroupLinks.push(link);
  7994. }
  7995. } else if (/store\.steampowered\.com\/app\//.test(link) && /wishlist/gim.test(taskDes)) {
  7996. if (action === 'undo') {
  7997. this.socialTasks.steam.wishlistLinks.push(link);
  7998. }
  7999. if (action === 'do') {
  8000. this.undoneTasks.steam.wishlistLinks.push(link);
  8001. }
  8002. } else if (/store\.steampowered\.com\/curator\//.test(link)) {
  8003. if (action === 'undo') {
  8004. this.socialTasks.steam.curatorLinks.push(link);
  8005. }
  8006. if (action === 'do') {
  8007. this.undoneTasks.steam.curatorLinks.push(link);
  8008. }
  8009. } else if (/^https?:\/\/discord\.com\/invite\//.test(link)) {
  8010. if (action === 'undo') {
  8011. this.socialTasks.discord.serverLinks.push(link);
  8012. }
  8013. if (action === 'do') {
  8014. this.undoneTasks.discord.serverLinks.push(link);
  8015. }
  8016. } else if (/^javascript:videoTask.+/.test(link)) {
  8017. if (action === 'do') {
  8018. const taskData = link.match(/javascript:videoTask\('.+?','(.+?)'/)?.[1];
  8019. if (taskData) {
  8020. this.undoneTasks.extra.videoTasks.push(taskData);
  8021. }
  8022. }
  8023. } 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 {
  8024. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`);
  8025. }
  8026. }
  8027. logStatus.success();
  8028. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8029. this.socialTasks = this.uniqueTasks(this.socialTasks);
  8030. if (window.DEBUG) {
  8031. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8032. }
  8033. GM_setValue(`khTasks-${this.giveawayId}`, {
  8034. tasks: this.socialTasks,
  8035. time: new Date().getTime()
  8036. });
  8037. return true;
  8038. } catch (error) {
  8039. throwError(error, 'Keyhub.classifyTask');
  8040. return false;
  8041. }
  8042. }
  8043. async #doScriptTask(data) {
  8044. try {
  8045. const logStatus = scripts_echoLog({
  8046. text: i18n('doingKeyhubTask')
  8047. });
  8048. const {
  8049. result,
  8050. statusText,
  8051. status,
  8052. data: response
  8053. } = await tools_httpRequest({
  8054. url: `/away?data=${data}`,
  8055. method: 'GET',
  8056. headers: {
  8057. origin: 'https://key-hub.eu',
  8058. referer: 'https://key-hub.eu/'
  8059. }
  8060. });
  8061. if (result === 'Success') {
  8062. if (response?.status === 200) {
  8063. logStatus.success();
  8064. return true;
  8065. }
  8066. logStatus.error(`Error:${response?.statusText}(${response?.status})`);
  8067. return false;
  8068. }
  8069. logStatus.error(`${result}:${statusText}(${status})`);
  8070. return false;
  8071. } catch (error) {
  8072. throwError(error, 'Keyhub.doScriptTask');
  8073. return false;
  8074. }
  8075. }
  8076. async extraDoTask({
  8077. videoTasks
  8078. }) {
  8079. try {
  8080. const pro = [];
  8081. for (const data of videoTasks) {
  8082. pro.push(this.#doScriptTask(data));
  8083. }
  8084. return Promise.all(pro).then(() => true);
  8085. } catch (error) {
  8086. throwError(error, 'Keyhub.extraDoTask');
  8087. return false;
  8088. }
  8089. }
  8090. #getGiveawayId() {
  8091. try {
  8092. const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
  8093. if (giveawayId) {
  8094. this.giveawayId = giveawayId;
  8095. return true;
  8096. }
  8097. scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId'));
  8098. return false;
  8099. } catch (error) {
  8100. throwError(error, 'Keyhub.getGiveawayId');
  8101. return false;
  8102. }
  8103. }
  8104. async #checkLeftKey() {
  8105. try {
  8106. if (!globalOptions.other.checkLeftKey) {
  8107. return true;
  8108. }
  8109. const leftKey = $('#keysleft').text().trim();
  8110. if (leftKey === '0') {
  8111. await external_Swal_default().fire({
  8112. icon: 'warning',
  8113. title: i18n('notice'),
  8114. text: i18n('noKeysLeft'),
  8115. confirmButtonText: i18n('confirm'),
  8116. cancelButtonText: i18n('cancel'),
  8117. showCancelButton: true
  8118. }).then(({
  8119. value
  8120. }) => {
  8121. if (value) {
  8122. window.close();
  8123. }
  8124. });
  8125. }
  8126. return true;
  8127. } catch (error) {
  8128. throwError(error, 'Keyhub.checkLeftKey');
  8129. return false;
  8130. }
  8131. }
  8132. #checkLogin() {
  8133. try {
  8134. if (!globalOptions.other.checkLogin) {
  8135. return true;
  8136. }
  8137. if ($('a[href*="/connect/steam"]').length > 0) {
  8138. window.open('/connect/steam', '_self');
  8139. }
  8140. return true;
  8141. } catch (error) {
  8142. throwError(error, 'Keyhub.checkLogin');
  8143. return false;
  8144. }
  8145. }
  8146. }
  8147. const website_Keyhub = Keyhub;
  8148. const Givekey_defaultTasksTemplate = {
  8149. steam: {
  8150. groupLinks: [],
  8151. wishlistLinks: [],
  8152. curatorLinks: [],
  8153. curatorLikeLinks: []
  8154. },
  8155. twitter: {
  8156. userLinks: []
  8157. },
  8158. vk: {
  8159. nameLinks: []
  8160. },
  8161. discord: {
  8162. serverLinks: []
  8163. }
  8164. };
  8165. const Givekey_defaultTasks = JSON.stringify(Givekey_defaultTasksTemplate);
  8166. class Givekey extends website_Website {
  8167. name = 'Givekey';
  8168. tasks = [];
  8169. socialTasks = JSON.parse(Givekey_defaultTasks);
  8170. undoneTasks = JSON.parse(Givekey_defaultTasks);
  8171. userId;
  8172. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  8173. static test() {
  8174. return window.location.host === 'givekey.ru';
  8175. }
  8176. async after() {
  8177. try {
  8178. await new Promise(resolve => {
  8179. const checker = setInterval(() => {
  8180. if ($('#navbarDropdown').length > 0) {
  8181. clearInterval(checker);
  8182. resolve(true);
  8183. }
  8184. }, 500);
  8185. });
  8186. if (!await this.#checkLeftKey()) {
  8187. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8188. }
  8189. } catch (error) {
  8190. throwError(error, 'Givekey.after');
  8191. }
  8192. }
  8193. init() {
  8194. try {
  8195. const logStatus = scripts_echoLog({
  8196. text: i18n('initing')
  8197. });
  8198. if ($('a[href*="/auth/steam"]').length > 0) {
  8199. window.open('/auth/steam', '_self');
  8200. logStatus.warning(i18n('needLogin'));
  8201. return false;
  8202. }
  8203. if (!this.#getGiveawayId()) {
  8204. return false;
  8205. }
  8206. const userId = $('meta[name="user-id"]').attr('content');
  8207. if (!userId) {
  8208. logStatus.error(i18n('getFailed', i18n('userId')));
  8209. return false;
  8210. }
  8211. this.userId = userId;
  8212. this.initialized = true;
  8213. logStatus.success();
  8214. return true;
  8215. } catch (error) {
  8216. throwError(error, 'Givekey.init');
  8217. return false;
  8218. }
  8219. }
  8220. async classifyTask(action) {
  8221. try {
  8222. const logStatus = scripts_echoLog({
  8223. text: i18n('getTasksInfo')
  8224. });
  8225. if (action === 'undo') {
  8226. this.socialTasks = GM_getValue(`gkTasks-${this.giveawayId}`)?.tasks || JSON.parse(Givekey_defaultTasks);
  8227. }
  8228. const tasks = $('.card-body:has("button") .row');
  8229. for (const task of tasks) {
  8230. const taskEle = $(task);
  8231. const isSuccess = /Complete/i.test(taskEle.find('button').text().trim());
  8232. if (isSuccess && action !== 'undo') {
  8233. continue;
  8234. }
  8235. const checkButton = taskEle.find('#task_check');
  8236. const taskId = checkButton.attr('data-id');
  8237. if (taskId) {
  8238. this.tasks.push(taskId);
  8239. }
  8240. if (action === 'verify') {
  8241. continue;
  8242. }
  8243. let href = taskEle.find('a').attr('href') || null;
  8244. const text = taskEle.find('a').text().trim();
  8245. const icon = taskEle.find('i');
  8246. if (!href || !text) {
  8247. continue;
  8248. }
  8249. if (/^https?:\/\/givekey\.ru\/giveaway\/[\d]+\/execution_task/.test(href)) {
  8250. href = await getRedirectLink(href);
  8251. }
  8252. if (!href) {
  8253. continue;
  8254. }
  8255. if (/^https?:\/\/vk\.com\//.test(href)) {
  8256. this.socialTasks.vk.nameLinks.push(href);
  8257. if (action === 'do' && !isSuccess) {
  8258. this.undoneTasks.vk.nameLinks.push(href);
  8259. }
  8260. } else if (/^https?:\/\/steamcommunity\.com\/groups/.test(href)) {
  8261. this.socialTasks.steam.groupLinks.push(href);
  8262. if (action === 'do' && !isSuccess) {
  8263. this.undoneTasks.steam.groupLinks.push(href);
  8264. }
  8265. } else if (/^https?:\/\/store\.steampowered\.com\/app\//.test(href)) {
  8266. this.socialTasks.steam.wishlistLinks.push(href);
  8267. if (action === 'do' && !isSuccess) {
  8268. this.undoneTasks.steam.wishlistLinks.push(href);
  8269. }
  8270. } else if (/Subscribe/gi.test(text) && icon.hasClass('fa-steam-square')) {
  8271. if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(href)) {
  8272. this.socialTasks.steam.curatorLinks.push(href);
  8273. if (action === 'do' && !isSuccess) {
  8274. this.undoneTasks.steam.curatorLinks.push(href);
  8275. }
  8276. } else {
  8277. this.socialTasks.steam.curatorLikeLinks.push(href);
  8278. if (action === 'do' && !isSuccess) {
  8279. this.undoneTasks.steam.curatorLikeLinks.push(href);
  8280. }
  8281. }
  8282. } else if (/^https?:\/\/twitter\.com\//.test(href) && /Subscribe/gi.test(text)) {
  8283. this.socialTasks.twitter.userLinks.push(href);
  8284. if (action === 'do' && !isSuccess) {
  8285. this.undoneTasks.twitter.userLinks.push(href);
  8286. }
  8287. } else if (icon.hasClass('fa-discord') || /^https?:\/\/discord\.com\/invite\//.test(href)) {
  8288. this.socialTasks.discord.serverLinks.push(href);
  8289. if (action === 'do' && !isSuccess) {
  8290. this.undoneTasks.discord.serverLinks.push(href);
  8291. }
  8292. } else {
  8293. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${text}(${href})`);
  8294. }
  8295. }
  8296. logStatus.success();
  8297. this.tasks = unique(this.tasks);
  8298. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8299. this.socialTasks = this.uniqueTasks(this.socialTasks);
  8300. if (window.DEBUG) {
  8301. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8302. }
  8303. GM_setValue(`gkTasks-${this.giveawayId}`, {
  8304. tasks: this.socialTasks,
  8305. time: new Date().getTime()
  8306. });
  8307. return true;
  8308. } catch (error) {
  8309. throwError(error, 'Givekey.classifyTask');
  8310. return false;
  8311. }
  8312. }
  8313. async verifyTask() {
  8314. try {
  8315. if (!this.initialized && !this.init()) {
  8316. return false;
  8317. }
  8318. if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
  8319. return false;
  8320. }
  8321. scripts_echoLog({}).warning(i18n('giveKeyNoticeBefore'));
  8322. const taskLength = this.tasks.length;
  8323. for (let i = 0; i < taskLength; i++) {
  8324. await this.#verify(this.tasks[i]);
  8325. if (i < taskLength - 1) {
  8326. await delay(15e3);
  8327. }
  8328. }
  8329. scripts_echoLog({}).success(i18n('allTasksComplete'));
  8330. scripts_echoLog({
  8331. html: `<li><font class="warning">${i18n('giveKeyNoticeAfter')}</font></li>`
  8332. });
  8333. return true;
  8334. } catch (error) {
  8335. throwError(error, 'Givekey.verifyTask');
  8336. return false;
  8337. }
  8338. }
  8339. async #verify(task) {
  8340. try {
  8341. const logStatus = scripts_echoLog({
  8342. html: `<li>${i18n('verifyingTask')}${task}...<font></font></li>`
  8343. });
  8344. return await new Promise(resolve => {
  8345. $.ajax({
  8346. url: 'https://givekey.ru/giveaway/task',
  8347. method: 'POST',
  8348. data: `id=${task}&user_id=${this.userId}`,
  8349. dataType: 'json',
  8350. headers: {
  8351. 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
  8352. },
  8353. success: data => {
  8354. if (data.btn) {
  8355. $(`button[data-id=${this.userId}]`).html(data.btn);
  8356. }
  8357. if (data.status === 'ok') {
  8358. $(`.task_check_${data.id}`).html(`<button class="btn btn-success mb-2 btn-block" disabled>${data.btn}</button>`);
  8359. logStatus.success();
  8360. resolve(true);
  8361. } else if (data.status === 'end') {
  8362. logStatus.success();
  8363. scripts_echoLog({}).success(data.key);
  8364. resolve(true);
  8365. } else {
  8366. logStatus.error(`Error:${data.msg}`);
  8367. resolve(false);
  8368. }
  8369. },
  8370. error: xhr => {
  8371. logStatus.error(`Error:${xhr.statusText}(${xhr.status})`);
  8372. resolve(false);
  8373. }
  8374. });
  8375. });
  8376. } catch (error) {
  8377. throwError(error, 'Givekey.verify');
  8378. return false;
  8379. }
  8380. }
  8381. #getGiveawayId() {
  8382. try {
  8383. const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
  8384. if (giveawayId) {
  8385. this.giveawayId = giveawayId;
  8386. return true;
  8387. }
  8388. scripts_echoLog({
  8389. text: i18n('getFailed', 'GiveawayId')
  8390. });
  8391. return false;
  8392. } catch (error) {
  8393. throwError(error, 'Givekey.getGiveawayId');
  8394. return false;
  8395. }
  8396. }
  8397. async #checkLeftKey() {
  8398. try {
  8399. if (!globalOptions.other.checkLeftKey) {
  8400. return true;
  8401. }
  8402. if (!$('#keys_count').text()) {
  8403. await external_Swal_default().fire({
  8404. icon: 'warning',
  8405. title: i18n('notice'),
  8406. text: i18n('noKeysLeft'),
  8407. confirmButtonText: i18n('confirm'),
  8408. cancelButtonText: i18n('cancel'),
  8409. showCancelButton: true
  8410. }).then(({
  8411. value
  8412. }) => {
  8413. if (value) {
  8414. window.close();
  8415. }
  8416. });
  8417. }
  8418. return true;
  8419. } catch (error) {
  8420. throwError(error, 'Givekey.checkLeftKey');
  8421. return false;
  8422. }
  8423. }
  8424. }
  8425. const website_Givekey = Givekey;
  8426. class GiveeClub extends GiveawaySu {
  8427. name = 'GiveeClub';
  8428. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  8429. static test() {
  8430. return /^https?:\/\/givee\.club\/.*?\/event\/[\d]+/.test(window.location.href);
  8431. }
  8432. async after() {
  8433. try {
  8434. if (!this.#checkLogin()) {
  8435. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  8436. }
  8437. if (!await this.#checkLeftKey()) {
  8438. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  8439. }
  8440. } catch (error) {
  8441. throwError(error, 'GiveeClub.after');
  8442. }
  8443. }
  8444. init() {
  8445. try {
  8446. const logStatus = scripts_echoLog({
  8447. text: i18n('initing')
  8448. });
  8449. if (!this.#checkLogin()) {
  8450. logStatus.warning(i18n('needLogin'));
  8451. return false;
  8452. }
  8453. if (!this.#getGiveawayId()) {
  8454. return false;
  8455. }
  8456. this.initialized = true;
  8457. logStatus.success();
  8458. return true;
  8459. } catch (error) {
  8460. throwError(error, 'GiveeClub.init');
  8461. return false;
  8462. }
  8463. }
  8464. async classifyTask(action) {
  8465. try {
  8466. const logStatus = scripts_echoLog({
  8467. text: i18n('getTasksInfo')
  8468. });
  8469. if (action === 'undo') {
  8470. this.socialTasks = GM_getValue(`gcTasks-${this.giveawayId}`)?.tasks || Giveawaysu_defaultTasks;
  8471. return true;
  8472. }
  8473. this.undoneTasks = Giveawaysu_defaultTasks;
  8474. const pro = [];
  8475. const tasks = $('.event-actions tr');
  8476. for (const task of tasks) {
  8477. pro.push(new Promise(resolve => {
  8478. const taskDes = $(task).find('.event-action-label a');
  8479. const taskIcon = $(task).find('.event-action-icon i').attr('class') || '';
  8480. const taskName = taskDes.text().trim();
  8481. const taskType = $(task).find('button[data-type]')?.attr('data-type');
  8482. const taskFinished = $(task).find('.event-action-buttons .btn-success')?.length;
  8483. if (taskIcon.includes('ban') || /AdBlock/i.test(taskName) || taskIcon.includes('envelope') || taskFinished) {
  8484. return resolve(true);
  8485. }
  8486. getRedirectLink(taskDes.attr('href')).then(taskLink => {
  8487. if (!taskLink) {
  8488. return resolve(false);
  8489. }
  8490. if (taskType === 'steam.group.join' && /^https?:\/\/steamcommunity\.com\/groups/.test(taskLink)) {
  8491. this.undoneTasks.steam.groupLinks.push(taskLink);
  8492. } else if (/like.*announcement/gi.test(taskName)) {
  8493. this.undoneTasks.steam.announcementLinks.push(taskLink);
  8494. } else if (taskType === 'steam.game.wishlist' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
  8495. this.undoneTasks.steam.wishlistLinks.push(taskLink);
  8496. } else if (taskType === 'steam.game.wishlist' && taskDes.attr('data-steam-wishlist-appid')) {
  8497. this.undoneTasks.steam.wishlistLinks.push(`https://store.steampowered.com/app/${taskDes.attr('data-steam-wishlist-appid')}`);
  8498. } else if (taskType === 'steam.game.follow' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
  8499. this.undoneTasks.steam.followLinks.push(taskLink);
  8500. } else if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) {
  8501. this.undoneTasks.steam.curatorLinks.push(taskLink);
  8502. } else if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
  8503. this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
  8504. } else if (/subscribe.*steam.*forum/gim.test(taskName)) {
  8505. this.undoneTasks.steam.forumLinks.push(taskLink);
  8506. } else if (taskIcon.includes('discord')) {
  8507. this.undoneTasks.discord.serverLinks.push(taskLink);
  8508. } else if (taskIcon.includes('instagram')) {
  8509. this.undoneTasks.instagram.userLinks.push(taskLink);
  8510. } else if (taskIcon.includes('twitch')) {
  8511. this.undoneTasks.twitch.channelLinks.push(taskLink);
  8512. } else if (taskIcon.includes('reddit')) {
  8513. this.undoneTasks.reddit.redditLinks.push(taskLink);
  8514. } else if (/watch.*art/gim.test(taskName)) {
  8515. this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
  8516. } else if (/subscribe.*youtube.*channel/gim.test(taskName)) {
  8517. this.undoneTasks.youtube.channelLinks.push(taskLink);
  8518. } else if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) {
  8519. this.undoneTasks.youtube.likeLinks.push(taskLink);
  8520. } else if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) {
  8521. this.undoneTasks.vk.nameLinks.push(taskLink);
  8522. } else if (taskIcon.includes('twitter')) {
  8523. if (/https?:\/\/(twitter|x)\.com\/[^/]+\/?$/gim.test(taskLink)) {
  8524. this.undoneTasks.twitter.userLinks.push(taskLink);
  8525. } else if (/https?:\/\/(twitter|x)\.com\/[^/]+?\/status\/[\d]+/gim.test(taskLink)) {
  8526. this.undoneTasks.twitter.retweetLinks.push(taskLink);
  8527. }
  8528. } else {
  8529. if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {} else {
  8530. if (/follow.*button/gim.test(taskName)) {
  8531. this.undoneTasks.steam.followLinks.push(taskLink);
  8532. }
  8533. }
  8534. }
  8535. resolve(true);
  8536. }).catch(error => {
  8537. throwError(error, 'GiveeClub.classifyTask->getRedirectLink');
  8538. return false;
  8539. });
  8540. }));
  8541. }
  8542. await Promise.all(pro);
  8543. logStatus.success();
  8544. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  8545. this.socialTasks = this.undoneTasks;
  8546. if (window.DEBUG) {
  8547. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  8548. }
  8549. GM_setValue(`gcTasks-${this.giveawayId}`, {
  8550. tasks: this.socialTasks,
  8551. time: new Date().getTime()
  8552. });
  8553. return true;
  8554. } catch (error) {
  8555. throwError(error, 'GiveeClub.classifyTask');
  8556. return false;
  8557. }
  8558. }
  8559. async verifyTask() {
  8560. try {
  8561. const logStatus = scripts_echoLog({
  8562. text: i18n('giveeClubVerifyNotice')
  8563. });
  8564. const taskButtons = $('.event-actions tr button').has('i.glyphicon-refresh').not('[data-type="user.adblock"]');
  8565. for (const button of taskButtons) {
  8566. button.click();
  8567. if ($(button).attr('data-type') !== 'steam.game.wishlist') {
  8568. await delay(1e3);
  8569. }
  8570. }
  8571. logStatus.warning(i18n('giveeClubVerifyFinished'));
  8572. return true;
  8573. } catch (error) {
  8574. throwError(error, 'Givekey.verifyTask');
  8575. return false;
  8576. }
  8577. }
  8578. #checkLogin() {
  8579. try {
  8580. if (!globalOptions.other.checkLogin) {
  8581. return true;
  8582. }
  8583. if ($('a[href*="/account/auth"]').length > 0) {
  8584. window.open($('a[href*="/account/auth"]').attr('href'), '_self');
  8585. }
  8586. return true;
  8587. } catch (error) {
  8588. throwError(error, 'GiveeClub.checkLogin');
  8589. return false;
  8590. }
  8591. }
  8592. #getGiveawayId() {
  8593. const giveawayId = window.location.href.match(/\/event\/([\d]+)/)?.[1];
  8594. if (giveawayId) {
  8595. this.giveawayId = giveawayId;
  8596. return true;
  8597. }
  8598. scripts_echoLog({
  8599. text: i18n('getFailed', 'GiveawayId')
  8600. });
  8601. return false;
  8602. }
  8603. async #checkLeftKey() {
  8604. try {
  8605. if (!globalOptions.other.checkLeftKey) {
  8606. return true;
  8607. }
  8608. if ($('.event-ended').length > 0 && $('.event-winner').length === 0) {
  8609. await external_Swal_default().fire({
  8610. icon: 'warning',
  8611. title: i18n('notice'),
  8612. text: i18n('giveawayEnded'),
  8613. confirmButtonText: i18n('confirm'),
  8614. cancelButtonText: i18n('cancel'),
  8615. showCancelButton: true
  8616. }).then(({
  8617. value
  8618. }) => {
  8619. if (value) {
  8620. window.close();
  8621. }
  8622. });
  8623. }
  8624. return true;
  8625. } catch (error) {
  8626. throwError(error, 'Giveawaysu.checkLeftKey');
  8627. return false;
  8628. }
  8629. }
  8630. }
  8631. const website_GiveeClub = GiveeClub;
  8632. const defaultOptions = {
  8633. maxPoint: '99999999'
  8634. };
  8635. class OpiumPulses {
  8636. name = 'OpiumPulses';
  8637. options = {
  8638. ...defaultOptions,
  8639. ...GM_getValue('OpiumPulsesOptions')
  8640. };
  8641. maxPoints = 99999999;
  8642. myPoints = 0;
  8643. buttons = [ 'doFreeTask', 'doPointTask' ];
  8644. static test() {
  8645. return window.location.host === 'www.opiumpulses.com';
  8646. }
  8647. async after() {
  8648. try {
  8649. if (!this.#checkLogin()) {
  8650. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  8651. }
  8652. this.maxPoints = parseInt(this.options.maxPoint, 10);
  8653. } catch (error) {
  8654. throwError(error, 'OpiumPulses.after');
  8655. }
  8656. }
  8657. async doFreeTask() {
  8658. try {
  8659. this.#toggleTask('FREE');
  8660. } catch (error) {
  8661. throwError(error, 'OpiumPulses.doFreeTask');
  8662. }
  8663. }
  8664. async doPointTask() {
  8665. try {
  8666. this.myPoints = parseInt($('.page-header__nav-func-user-nav-items.points-items').text().match(/[\d]+/gim)?.[0] || '0', 10);
  8667. this.#toggleTask('points');
  8668. } catch (error) {
  8669. throwError(error, 'OpiumPulses.doPointTask');
  8670. }
  8671. }
  8672. async #toggleTask(type) {
  8673. try {
  8674. const items = $(`.giveaways-page-item:contains('${type}'):not(:contains('ENTERED'))`);
  8675. for (const item of items) {
  8676. const needPoints = parseInt($(item).find('.giveaways-page-item-header-points').text().match(/[\d]+/gim)?.[0] || '999999', 10);
  8677. const name = $(item).find('.giveaways-page-item-footer-name').text().trim();
  8678. if (type === 'points' && needPoints > this.myPoints) {
  8679. scripts_echoLog({}).warning(`${i18n('noPoints')}: ${name}`);
  8680. } else if (type === 'points' && !needPoints) {
  8681. scripts_echoLog({}).warning(`${i18n('getNeedPointsFailed')}: ${name}`);
  8682. } else if (!(type === 'points' && needPoints > this.maxPoints)) {
  8683. const logStatus = scripts_echoLog({
  8684. text: `${i18n('joiningLottery')}<a href="${$(item).find('a.giveaways-page-item-img-btn-more').attr('href')}" target="_blank">${name}</a>...`
  8685. });
  8686. const aElement = $(item).find('a.giveaways-page-item-img-btn-enter:contains(\'enter\')');
  8687. if (aElement?.attr('onclick')?.includes('checkUser')) {
  8688. const giveawayId = aElement.attr('onclick')?.match(/[\d]+/)?.[0];
  8689. if (giveawayId) {
  8690. checkUser(giveawayId);
  8691. }
  8692. }
  8693. if (!aElement.attr('href')) {
  8694. logStatus.error('Error: No "href".');
  8695. continue;
  8696. }
  8697. const {
  8698. result,
  8699. statusText,
  8700. status,
  8701. data
  8702. } = await tools_httpRequest({
  8703. url: aElement.attr('href'),
  8704. method: 'GET'
  8705. });
  8706. if (result === 'Success') {
  8707. const {
  8708. result: result0,
  8709. statusText: statusText0,
  8710. status: status0,
  8711. data: data0
  8712. } = await tools_httpRequest({
  8713. url: data?.finalUrl,
  8714. method: 'GET'
  8715. });
  8716. if (data0?.responseText && /You've entered this giveaway/gim.test(data0.responseText)) {
  8717. logStatus.success();
  8718. const points = data0.responseText.match(/Points:[\s]*?([\d]+)/)?.[1];
  8719. if (type === 'points' && points) {
  8720. this.myPoints = parseInt(points, 10);
  8721. }
  8722. } else if (data0?.responseText && /You're not eligible to enter/gim.test(data0.responseText)) {
  8723. logStatus.error('You\'re not eligible to enter');
  8724. } else {
  8725. logStatus.error(`${result0}:${statusText0}(${status0})`);
  8726. }
  8727. } else {
  8728. logStatus.error(`${result}:${statusText}(${status})`);
  8729. }
  8730. }
  8731. }
  8732. scripts_echoLog({
  8733. text: '-----END-----'
  8734. });
  8735. } catch (error) {
  8736. throwError(error, 'OpiumPulses.toggleTask');
  8737. }
  8738. }
  8739. init() {
  8740. return true;
  8741. }
  8742. classifyTask() {
  8743. return true;
  8744. }
  8745. #checkLogin() {
  8746. try {
  8747. if (!globalOptions.other.checkLogin) {
  8748. return true;
  8749. }
  8750. if ($('a[href*="/site/login"]').length > 1) {
  8751. window.open('/site/login', '_self');
  8752. }
  8753. return true;
  8754. } catch (error) {
  8755. throwError(error, 'OpiumPulses.checkLogin');
  8756. return false;
  8757. }
  8758. }
  8759. }
  8760. const website_OpiumPulses = OpiumPulses;
  8761. const external_dayjs_namespaceObject = dayjs;
  8762. var external_dayjs_default = __webpack_require__.n(external_dayjs_namespaceObject);
  8763. const leftKeyChecker = {
  8764. async classify(link) {
  8765. try {
  8766. if (/^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(link)) {
  8767. return await this.giveawaySu(link);
  8768. }
  8769. if (/^https?:\/\/givee\.club\/[\w]+?\/event\/[\d]+/.test(link)) {
  8770. return await this.giveeClub(link);
  8771. }
  8772. if (/^https?:\/\/gleam\.io\/.+?\/.+/.test(link)) {
  8773. return await this.gleam(link);
  8774. }
  8775. if (/^https?:\/\/www\.indiedb\.com\/giveaways\/.+/.test(link)) {
  8776. return await this.indieDb(link);
  8777. }
  8778. if (/^https?:\/\/key-hub\.eu\/giveaway\/[\d]+/.test(link)) {
  8779. return await this.keyhub(link);
  8780. }
  8781. if (/^https?:\/\/opquests\.com\/quests\/[\d]+/.test(link)) {
  8782. return await this.opquests(link);
  8783. }
  8784. if (/^https?:\/\/itch\.io\/s\/[\d]+?\/.*/.test(link)) {
  8785. return await this.itch(link);
  8786. }
  8787. return false;
  8788. } catch (error) {
  8789. throwError(error, 'leftKeyChecker.classify');
  8790. return false;
  8791. }
  8792. },
  8793. async giveawaySu(link) {
  8794. try {
  8795. const {
  8796. result,
  8797. data
  8798. } = await tools_httpRequest({
  8799. url: link,
  8800. method: 'GET'
  8801. });
  8802. if (result === 'Success' && data?.status === 200) {
  8803. if (data.responseText.includes('class="steam-login"')) {
  8804. return false;
  8805. }
  8806. if (data.responseText.includes('class="giveaway-ended"')) {
  8807. return 'Ended';
  8808. }
  8809. return 'Active';
  8810. }
  8811. return false;
  8812. } catch (error) {
  8813. throwError(error, 'leftKeyChecker.giveawaySu');
  8814. return false;
  8815. }
  8816. },
  8817. async giveeClub(link) {
  8818. try {
  8819. const {
  8820. result,
  8821. data
  8822. } = await tools_httpRequest({
  8823. url: link,
  8824. method: 'GET'
  8825. });
  8826. if (result === 'Success' && data?.status === 200) {
  8827. if (data.responseText.includes('class="event-winner"')) {
  8828. return 'Won';
  8829. }
  8830. if (data.responseText.includes('class="event-ended"')) {
  8831. return 'Ended';
  8832. }
  8833. return 'Active';
  8834. }
  8835. return false;
  8836. } catch (error) {
  8837. throwError(error, 'leftKeyChecker.giveeClub');
  8838. return false;
  8839. }
  8840. },
  8841. async gleam(link) {
  8842. try {
  8843. const {
  8844. result,
  8845. data
  8846. } = await tools_httpRequest({
  8847. url: link,
  8848. method: 'GET'
  8849. });
  8850. if (result === 'Success' && data?.status === 200) {
  8851. if (/incentives&quot;:{&quot;[\d]+?&quot;:\[&quot;.+?&quot;\]/.test(data.responseText)) {
  8852. return 'Won';
  8853. }
  8854. const campaignDiv = data.responseText.match(/<div class='popup-blocks-container'[\w\W]+?'>/)?.[0];
  8855. if (!campaignDiv) {
  8856. return false;
  8857. }
  8858. const campaignString = $(campaignDiv).attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
  8859. if (!campaignString) {
  8860. return false;
  8861. }
  8862. const {
  8863. campaign
  8864. } = JSON.parse(campaignString);
  8865. if (campaign.banned) {
  8866. return 'Banned';
  8867. }
  8868. if (campaign.finished) {
  8869. return 'Ended';
  8870. }
  8871. if (campaign.paused) {
  8872. return 'Paused';
  8873. }
  8874. if (new Date().getTime() < campaign.starts_at * 1e3) {
  8875. return 'NotStart';
  8876. }
  8877. return 'Active';
  8878. }
  8879. return false;
  8880. } catch (error) {
  8881. throwError(error, 'leftKeyChecker.gleam');
  8882. return false;
  8883. }
  8884. },
  8885. async indieDb(link) {
  8886. try {
  8887. const {
  8888. result,
  8889. data
  8890. } = await tools_httpRequest({
  8891. url: link,
  8892. method: 'GET'
  8893. });
  8894. if (result === 'Success' && data?.status === 200) {
  8895. if (data.responseText.includes('Congrats you WON')) {
  8896. return 'Won';
  8897. }
  8898. if (data.responseText.includes('Giveaway is closed') || data.responseText.includes('next time')) {
  8899. return 'Ended';
  8900. }
  8901. return 'Active';
  8902. }
  8903. return false;
  8904. } catch (error) {
  8905. throwError(error, 'leftKeyChecker.indieDb');
  8906. return false;
  8907. }
  8908. },
  8909. async keyhub(link) {
  8910. try {
  8911. const {
  8912. result,
  8913. data
  8914. } = await tools_httpRequest({
  8915. url: link,
  8916. method: 'GET'
  8917. });
  8918. if (result === 'Success' && data?.status === 200) {
  8919. const keysleft = data.responseText.match(/<span id="keysleft">([\d]+?)<\/span>/)?.[1];
  8920. if (!keysleft) {
  8921. return false;
  8922. }
  8923. if (keysleft === '0') {
  8924. return 'Ended';
  8925. }
  8926. return `Active(${keysleft})`;
  8927. }
  8928. return false;
  8929. } catch (error) {
  8930. throwError(error, 'leftKeyChecker.keyhub');
  8931. return false;
  8932. }
  8933. },
  8934. async opquests(link) {
  8935. try {
  8936. const {
  8937. result,
  8938. data
  8939. } = await tools_httpRequest({
  8940. url: link,
  8941. method: 'GET'
  8942. });
  8943. if (result === 'Success' && data?.status === 200) {
  8944. const keysleft = data.responseText.match(/<div class="">[\s]*?([\d]+?)[\s]*?of/)?.[1];
  8945. if (!keysleft) {
  8946. return false;
  8947. }
  8948. if (keysleft === '0') {
  8949. return 'Ended';
  8950. }
  8951. return `Active(${keysleft})`;
  8952. } else if (data?.status === 404) {
  8953. return 'Ended';
  8954. }
  8955. return false;
  8956. } catch (error) {
  8957. throwError(error, 'leftKeyChecker.opquests');
  8958. return false;
  8959. }
  8960. },
  8961. async itch(link) {
  8962. try {
  8963. const {
  8964. result,
  8965. data
  8966. } = await tools_httpRequest({
  8967. url: link,
  8968. method: 'GET'
  8969. });
  8970. if (result === 'Success' && data?.status === 200) {
  8971. const endDate = data.responseText.match(/{"start_date":"[0-9A-Z-:]+?".*?"end_date":"([0-9A-Z-:]+?)".*?}/)?.[1];
  8972. if (!endDate) {
  8973. return false;
  8974. }
  8975. if (new Date().getTime() > new Date(endDate).getTime()) {
  8976. return 'Ended';
  8977. }
  8978. return `Active(${external_dayjs_default()(endDate).format('YYYY-MM-DD HH:mm:ss')})`;
  8979. }
  8980. return false;
  8981. } catch (error) {
  8982. throwError(error, 'leftKeyChecker.itch');
  8983. return false;
  8984. }
  8985. }
  8986. };
  8987. const website_leftKeyChecker = leftKeyChecker;
  8988. const Keylol_defaultTasksTemplate = {
  8989. steam: {
  8990. groupLinks: [],
  8991. wishlistLinks: [],
  8992. curatorLinks: [],
  8993. curatorLikeLinks: [],
  8994. followLinks: [],
  8995. forumLinks: [],
  8996. announcementLinks: [],
  8997. workshopVoteLinks: [],
  8998. licenseLinks: []
  8999. },
  9000. discord: {
  9001. serverLinks: []
  9002. },
  9003. instagram: {
  9004. userLinks: []
  9005. },
  9006. vk: {
  9007. nameLinks: []
  9008. },
  9009. twitch: {
  9010. channelLinks: []
  9011. },
  9012. reddit: {
  9013. redditLinks: []
  9014. },
  9015. twitter: {
  9016. userLinks: [],
  9017. retweetLinks: []
  9018. },
  9019. youtube: {
  9020. channelLinks: [],
  9021. likeLinks: []
  9022. }
  9023. };
  9024. const Keylol_defaultTasks = JSON.stringify(Keylol_defaultTasksTemplate);
  9025. class Keylol extends website_Website {
  9026. name = 'Keylol';
  9027. socialTasks = JSON.parse(Keylol_defaultTasks);
  9028. undoneTasks = JSON.parse(Keylol_defaultTasks);
  9029. buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect' ];
  9030. static test() {
  9031. 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'));
  9032. }
  9033. init() {
  9034. return true;
  9035. }
  9036. after() {
  9037. try {
  9038. const selector = this.name === 'Keylol' ? '#postlist>div[id^="post_"]:first' : 'div.container';
  9039. const mainPost = $(selector);
  9040. const discordLinks = mainPost.find('a[href*="discord.com"]:visible');
  9041. const redditLinks = mainPost.find('a[href*="reddit.com"]:visible');
  9042. const insLinks = mainPost.find('a[href*="instagram.com"]:visible');
  9043. const twitterLinks = mainPost.find('a[href*="twitter.com"]:visible,a[href*="x.com"]:visible');
  9044. const twitchLinks = mainPost.find('a[href*="twitch.tv"]:visible');
  9045. const vkLinks = mainPost.find('a[href*="vk.com"]:visible');
  9046. const steamStoreLinks = mainPost.find('a[href*="store.steampowered.com"]:visible');
  9047. const steamCommunityLinks = mainPost.find('a[href*="steamcommunity.com"]:visible');
  9048. const ytbLinks = mainPost.find('a[href*="youtube.com"]:visible');
  9049. if (discordLinks.length > 0) {
  9050. for (const discordLink of discordLinks) {
  9051. const link = $(discordLink).attr('href');
  9052. if (!(link && /^https?:\/\/discord\.com\/invite\/.+/.test(link))) {
  9053. continue;
  9054. }
  9055. this.#addBtn(discordLink, 'discord', 'serverLinks', link);
  9056. }
  9057. }
  9058. if (redditLinks.length > 0) {
  9059. for (const redditLink of redditLinks) {
  9060. const link = $(redditLink).attr('href');
  9061. if (!(link && /^https?:\/\/www\.reddit\.com\/(r|user)\/.+/.test(link))) {
  9062. continue;
  9063. }
  9064. this.#addBtn(redditLink, 'reddit', 'redditLinks', link);
  9065. }
  9066. }
  9067. if (insLinks.length > 0) {
  9068. for (const insLink of insLinks) {
  9069. const link = $(insLink).attr('href');
  9070. if (!(link && /^https:\/\/www\.instagram\.com\/.+/.test(link))) {
  9071. continue;
  9072. }
  9073. this.#addBtn(insLink, 'instagram', 'userLinks', link);
  9074. }
  9075. }
  9076. if (twitterLinks.length > 0) {
  9077. for (const twitterLink of twitterLinks) {
  9078. const link = $(twitterLink).attr('href');
  9079. if (!(link && /^https:\/\/twitter\.com\/.+/.test(link))) {
  9080. continue;
  9081. }
  9082. if (/https:\/\/twitter\.com\/.*?\/status\/[\d]+/.test(link)) {
  9083. this.#addBtn(twitterLink, 'twitter', 'retweetLinks', link);
  9084. } else {
  9085. this.#addBtn(twitterLink, 'twitter', 'userLinks', link);
  9086. }
  9087. }
  9088. }
  9089. if (twitchLinks.length > 0) {
  9090. for (const twitchLink of twitchLinks) {
  9091. const link = $(twitchLink).attr('href');
  9092. if (!(link && /^https:\/\/(www\.)?twitch\.tv\/.+/.test(link))) {
  9093. continue;
  9094. }
  9095. this.#addBtn(twitchLink, 'twitch', 'channelLinks', link);
  9096. }
  9097. }
  9098. if (vkLinks.length > 0) {
  9099. for (const vkLink of vkLinks) {
  9100. const link = $(vkLink).attr('href');
  9101. if (!(link && /^https:\/\/vk\.com\/.+/.test(link))) {
  9102. continue;
  9103. }
  9104. this.#addBtn(vkLink, 'vk', 'nameLinks', link);
  9105. }
  9106. }
  9107. if (steamStoreLinks.length > 0) {
  9108. for (const steamStoreLink of steamStoreLinks) {
  9109. const link = $(steamStoreLink).attr('href');
  9110. if (!link) {
  9111. continue;
  9112. }
  9113. if (/curator\/[\d]+/.test(link)) {
  9114. this.#addBtn(steamStoreLink, 'steam', 'curatorLinks', link);
  9115. } else if (/(publisher|developer|franchise)\/.+/.test(link)) {
  9116. this.#addBtn(steamStoreLink, 'steam', 'curatorLikeLinks', link);
  9117. } else if (/news(hub)?\/app\/[\d]+\/view\/[\d]+/.test(link)) {
  9118. this.#addBtn(steamStoreLink, 'steam', 'announcementLinks', link);
  9119. } else if (/app\/[\d]+/.test(link)) {
  9120. this.#addBtn(steamStoreLink, 'steam', 'followLinks', link);
  9121. this.#addBtn(steamStoreLink, 'steam', 'wishlistLinks', link);
  9122. }
  9123. }
  9124. }
  9125. if (steamCommunityLinks.length > 0) {
  9126. for (const steamCommunityLink of steamCommunityLinks) {
  9127. const link = $(steamCommunityLink).attr('href');
  9128. if (!link) {
  9129. continue;
  9130. }
  9131. if (/groups\/.+/.test(link)) {
  9132. this.#addBtn(steamCommunityLink, 'steam', 'groupLinks', link);
  9133. } else if (/announcements\/detail\/[\d]+/.test(link)) {
  9134. this.#addBtn(steamCommunityLink, 'steam', 'announcementLinks', link);
  9135. }
  9136. }
  9137. }
  9138. if (ytbLinks.length > 0) {
  9139. for (const ytbLink of ytbLinks) {
  9140. const link = $(ytbLink).attr('href');
  9141. if (!link) {
  9142. continue;
  9143. }
  9144. this.#addBtn(ytbLink, 'youtube', 'channelLinks', link);
  9145. this.#addBtn(ytbLink, 'youtube', 'likeLinks', link);
  9146. }
  9147. }
  9148. 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');
  9149. if (giveawayLinks.length > 0) {
  9150. for (const giveawayLink of giveawayLinks) {
  9151. const link = $(giveawayLink).attr('href');
  9152. if (!link) {
  9153. continue;
  9154. }
  9155. website_leftKeyChecker.classify(link).then(status => {
  9156. if (!status) {
  9157. return;
  9158. }
  9159. if (/^Active/.test(status)) {
  9160. $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status active" title="${i18n('Active')}">${status}</font>`);
  9161. return;
  9162. }
  9163. $(`a[href="${link}"]`).after(`<font class="auto-task-giveaway-status not-active" title="${i18n(status)}">${status}</font>`);
  9164. }).catch(error => {
  9165. throwError(error, 'keylol.after -> leftKeyChecker');
  9166. });
  9167. }
  9168. }
  9169. if (this.name === 'Keylol') {
  9170. const asfLinks = mainPost.find('a[href^="#asf"]:visible');
  9171. if (asfLinks.length > 0) {
  9172. for (const asfLink of asfLinks) {
  9173. const link = $(asfLink).attr('href');
  9174. if (!link) {
  9175. continue;
  9176. }
  9177. this.#addBtn($(`a[href="${link}"]`).after('<span style="color: #ccc; margin: 0 -5px 0 5px"> | </span>').next()[0], 'steam', 'licenseLinks', `appid-${link.replace('#asf', '')}`);
  9178. }
  9179. }
  9180. const subLinks = mainPost.find('a[href*="steamdb.info/sub/"]:visible');
  9181. if (subLinks.length > 0) {
  9182. for (const subLink of subLinks) {
  9183. const link = $(subLink).attr('href');
  9184. if (!link) {
  9185. continue;
  9186. }
  9187. const subid = link.match(/^https:\/\/steamdb\.info\/sub\/([\d]+)/)?.[1];
  9188. if (!subid) {
  9189. continue;
  9190. }
  9191. this.#addBtn(subLink, 'steam', 'licenseLinks', `subid-${subid}`);
  9192. }
  9193. }
  9194. const asfLinks2 = mainPost.find('.blockcode:contains("addlicense"):visible');
  9195. if (asfLinks2.length > 0) {
  9196. for (const asfLink of asfLinks2) {
  9197. const appid = [ ...asfLink.innerText.matchAll(/a(pp)?\/([\d]+)/g) ].map(matched => matched?.[2]).filter(id => id) || [];
  9198. if (appid.length > 0) {
  9199. this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `appid-${appid.join(',')}`);
  9200. }
  9201. const subid = asfLink.innerText.match(/[\d]+/g)?.filter(matched => !appid.includes(matched));
  9202. if (!subid || subid.length === 0) {
  9203. continue;
  9204. }
  9205. this.#addBtn($(asfLink).children('em')[0], 'steam', 'licenseLinks', `subid-${subid.join(',')}`);
  9206. }
  9207. }
  9208. }
  9209. if ($('#threadindex').length > 0) {
  9210. const [ targetNode ] = $('#postlist').children('div[id^="post_"]');
  9211. const config = {
  9212. childList: true
  9213. };
  9214. const observer = new MutationObserver(() => {
  9215. observer.disconnect();
  9216. this.after();
  9217. });
  9218. observer.observe(targetNode, config);
  9219. }
  9220. } catch (error) {
  9221. throwError(error, 'keylol.after');
  9222. }
  9223. }
  9224. classifyTask(action) {
  9225. try {
  9226. this.socialTasks = JSON.parse(Keylol_defaultTasks);
  9227. this.undoneTasks = JSON.parse(Keylol_defaultTasks);
  9228. const selectedBtns = $('.auto-task-keylol[selected="selected"]:visible');
  9229. for (const btn of selectedBtns) {
  9230. const button = $(btn);
  9231. const social = button.attr('data-social');
  9232. const type = button.attr('data-type');
  9233. const link = button.attr('data-link');
  9234. if (!(social && type && link)) {
  9235. continue;
  9236. }
  9237. if (action === 'do') {
  9238. this.undoneTasks[social][type].push(link);
  9239. }
  9240. if (action === 'undo') {
  9241. this.socialTasks[social][type].push(link);
  9242. }
  9243. }
  9244. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  9245. this.socialTasks = this.uniqueTasks(this.socialTasks);
  9246. if (window.DEBUG) {
  9247. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  9248. }
  9249. return true;
  9250. } catch (error) {
  9251. throwError(error, 'Keylol.classifyTask');
  9252. return false;
  9253. }
  9254. }
  9255. selectAll() {
  9256. try {
  9257. $('.auto-task-keylol:visible').attr('selected', 'selected');
  9258. } catch (error) {
  9259. throwError(error, 'Keylol.selectAll');
  9260. }
  9261. }
  9262. selectNone() {
  9263. try {
  9264. $('.auto-task-keylol:visible').removeAttr('selected');
  9265. } catch (error) {
  9266. throwError(error, 'Keylol.selectNone');
  9267. }
  9268. }
  9269. invertSelect() {
  9270. try {
  9271. $('.auto-task-keylol:visible').each((index, element) => {
  9272. element.getAttribute('selected') ? element.removeAttribute('selected') : element.setAttribute('selected', 'selected');
  9273. });
  9274. } catch (error) {
  9275. throwError(error, 'Keylol.invertSelect');
  9276. }
  9277. }
  9278. #addBtn(before, social, linkType, link) {
  9279. try {
  9280. $(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>`);
  9281. } catch (error) {
  9282. throwError(error, 'keylol.addBtn');
  9283. }
  9284. }
  9285. }
  9286. const website_Keylol = Keylol;
  9287. const Opquests_defaultTasks = {
  9288. steam: {
  9289. groupLinks: [],
  9290. wishlistLinks: [],
  9291. followLinks: [],
  9292. curatorLikeLinks: []
  9293. }
  9294. };
  9295. class Opquests extends website_Website {
  9296. name = 'Opquests';
  9297. undoneTasks = {
  9298. ...Opquests_defaultTasks
  9299. };
  9300. buttons = [ 'doTask', 'verifyTask', 'getKey' ];
  9301. static test() {
  9302. return window.location.host === 'opquests.com';
  9303. }
  9304. async after() {
  9305. try {
  9306. if (!this.#checkLogin()) {
  9307. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  9308. }
  9309. const opquestsVerifyTasks = GM_getValue('opquestsVerifyTasks') || [];
  9310. if (opquestsVerifyTasks.length > 0) {
  9311. const taskId = opquestsVerifyTasks.pop();
  9312. GM_setValue('opquestsVerifyTasks', opquestsVerifyTasks);
  9313. const [ verifyBtn ] = $(`#task_id[value="${taskId}"]`).parent().find('button[type="button"]').has('i.fa-check');
  9314. if (verifyBtn) {
  9315. verifyBtn.click();
  9316. return;
  9317. }
  9318. this.after();
  9319. return;
  9320. }
  9321. if (GM_getValue('opquestsVerifyTasks')) {
  9322. GM_deleteValue('opquestsVerifyTasks');
  9323. }
  9324. } catch (error) {
  9325. throwError(error, 'Opquests.after');
  9326. }
  9327. }
  9328. init() {
  9329. try {
  9330. const logStatus = scripts_echoLog({
  9331. text: i18n('initing')
  9332. });
  9333. if ($('a[href*="/auth/redirect"]').length > 0) {
  9334. window.open('/auth/redirect', '_self');
  9335. logStatus.warning(i18n('needLogin'));
  9336. return false;
  9337. }
  9338. if (!this.#getGiveawayId()) {
  9339. return false;
  9340. }
  9341. this.initialized = true;
  9342. logStatus.success();
  9343. return true;
  9344. } catch (error) {
  9345. throwError(error, 'Opquests.init');
  9346. return false;
  9347. }
  9348. }
  9349. async classifyTask(action) {
  9350. try {
  9351. if (action === 'undo') {
  9352. scripts_echoLog({
  9353. text: i18n('cannotUndo')
  9354. });
  9355. return false;
  9356. }
  9357. const logStatus = scripts_echoLog({
  9358. text: i18n('getTasksInfo')
  9359. });
  9360. const tasks = $('.w-full:contains("Validate") .items-center');
  9361. for (const task of tasks) {
  9362. const link = $(task).find('a:contains("Open")').attr('href');
  9363. const taskDes = $(task).find('div').eq(1).text().trim();
  9364. if (!link) {
  9365. continue;
  9366. }
  9367. if (/steamcommunity\.com\/groups\//.test(link)) {
  9368. this.undoneTasks.steam.groupLinks.push(link);
  9369. } else if (/store\.steampowered\.com\/app\//.test(link)) {
  9370. if (/wishlist/gim.test(taskDes)) {
  9371. this.undoneTasks.steam.wishlistLinks.push(link);
  9372. } else if (/follow/gim.test(taskDes)) {
  9373. this.undoneTasks.steam.followLinks.push(link);
  9374. }
  9375. } else if (/store\.steampowered\.com\/(publisher|developer|curator)\//.test(link) && /follow/gim.test(taskDes)) {
  9376. this.undoneTasks.steam.curatorLikeLinks.push(link);
  9377. } else {
  9378. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskDes}(${link})`);
  9379. }
  9380. }
  9381. logStatus.success();
  9382. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  9383. if (window.DEBUG) {
  9384. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  9385. }
  9386. return true;
  9387. } catch (error) {
  9388. throwError(error, 'Opquests.classifyTask');
  9389. return false;
  9390. }
  9391. }
  9392. async verifyTask() {
  9393. try {
  9394. if (!this.initialized) {
  9395. this.init();
  9396. }
  9397. const tasks = $.makeArray($('.items-center').has('input[name="task_id"]')).map(ele => $(ele).find('input[name="task_id"]').val());
  9398. GM_setValue('opquestsVerifyTasks', tasks);
  9399. await this.#confirm();
  9400. this.after();
  9401. return true;
  9402. } catch (error) {
  9403. throwError(error, 'Opquests.verifyTask');
  9404. return false;
  9405. }
  9406. }
  9407. async #confirm() {
  9408. try {
  9409. const logStatus = scripts_echoLog({
  9410. html: `<li>${i18n('confirmingTask')}...<font></font></li>`
  9411. });
  9412. const {
  9413. result,
  9414. statusText,
  9415. status,
  9416. data
  9417. } = await tools_httpRequest({
  9418. url: `https://opquests.com/quests/${this.giveawayId}?confirm=1`,
  9419. method: 'GET',
  9420. nochche: true,
  9421. headers: {
  9422. origin: 'https://opquests.com',
  9423. referer: `https://opquests.com/warning?id=${this.giveawayId}`
  9424. }
  9425. });
  9426. if (result === 'Success') {
  9427. if (data?.status === 200) {
  9428. logStatus.success();
  9429. return true;
  9430. }
  9431. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  9432. return false;
  9433. }
  9434. logStatus.error(`${result}:${statusText}(${status})`);
  9435. return false;
  9436. } catch (error) {
  9437. throwError(error, 'Opquests.confirm');
  9438. return false;
  9439. }
  9440. }
  9441. async getKey(isButton) {
  9442. try {
  9443. const logStatus = scripts_echoLog({
  9444. text: i18n('gettingKey')
  9445. });
  9446. const {
  9447. result,
  9448. statusText,
  9449. status,
  9450. data
  9451. } = await tools_httpRequest({
  9452. url: 'https://opquests.com/keys',
  9453. method: 'GET'
  9454. });
  9455. if (result === 'Success') {
  9456. if (data?.responseText) {
  9457. const key = $(data?.responseText).find(`div.items-center:contains("${$('h1.font-bold').text().trim().replace(' Quest', '')}")`).find('div.font-bold').next().text();
  9458. if (!key) {
  9459. logStatus.error('Error: Key was not found');
  9460. if (isButton) {
  9461. window.open('https://opquests.com/keys', '_self');
  9462. }
  9463. return false;
  9464. }
  9465. logStatus.success();
  9466. scripts_echoLog({}).success(key);
  9467. return true;
  9468. }
  9469. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  9470. return false;
  9471. }
  9472. logStatus.error(`${result}:${statusText}(${status})`);
  9473. return false;
  9474. } catch (error) {
  9475. throwError(error, 'Opquests.getGiveawayId');
  9476. return false;
  9477. }
  9478. }
  9479. #getGiveawayId() {
  9480. try {
  9481. const giveawayId = window.location.href.match(/quests\/([\d]+)/)?.[1];
  9482. if (giveawayId) {
  9483. this.giveawayId = giveawayId;
  9484. return true;
  9485. }
  9486. scripts_echoLog({}).error(i18n('getFailed', 'GiveawayId'));
  9487. return false;
  9488. } catch (error) {
  9489. throwError(error, 'Opquests.getGiveawayId');
  9490. return false;
  9491. }
  9492. }
  9493. #checkLogin() {
  9494. try {
  9495. if (!globalOptions.other.checkLogin) {
  9496. return true;
  9497. }
  9498. if ($('a[href*="/auth/redirect"]').length > 0) {
  9499. window.open('/auth/redirect', '_self');
  9500. }
  9501. return true;
  9502. } catch (error) {
  9503. throwError(error, 'Opquests.checkLogin');
  9504. return false;
  9505. }
  9506. }
  9507. }
  9508. const website_Opquests = Opquests;
  9509. const Gleam_defaultTasksTemplate = {
  9510. steam: {
  9511. groupLinks: [],
  9512. wishlistLinks: [],
  9513. followLinks: [],
  9514. curatorLinks: [],
  9515. curatorLikeLinks: []
  9516. },
  9517. twitter: {
  9518. userLinks: [],
  9519. retweetLinks: []
  9520. },
  9521. twitch: {
  9522. channelLinks: []
  9523. },
  9524. discord: {
  9525. serverLinks: []
  9526. },
  9527. youtube: {
  9528. channelLinks: []
  9529. },
  9530. extra: {
  9531. gleam: []
  9532. }
  9533. };
  9534. const Gleam_defaultTasks = JSON.stringify(Gleam_defaultTasksTemplate);
  9535. class Gleam extends website_Website {
  9536. name = 'Gleam';
  9537. undoneTasks = JSON.parse(Gleam_defaultTasks);
  9538. socialTasks = JSON.parse(Gleam_defaultTasks);
  9539. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  9540. static test() {
  9541. return window.location.host === 'gleam.io';
  9542. }
  9543. before() {
  9544. try {
  9545. unsafeWindow.confirm = () => {};
  9546. unsafeWindow.alert = () => {};
  9547. unsafeWindow.prompt = () => {};
  9548. } catch (error) {
  9549. throwError(error, 'Gleam.before');
  9550. }
  9551. }
  9552. async after() {
  9553. try {
  9554. if (window.location.search.includes('8b07d23f4bfa65f9')) {
  9555. const checkComplete = setInterval(() => {
  9556. if ($('.entry-content .entry-method i.fa-check').length > 0) {
  9557. clearInterval(checkComplete);
  9558. window.close();
  9559. }
  9560. });
  9561. for (const task of $('.entry-content .entry-method')) {
  9562. const taskInfo = $(task).find('.user-links');
  9563. const expandInfo = $(task).find('.expandable');
  9564. const aElements = expandInfo.find('a.btn,a:contains(Continue),button:contains(Continue)');
  9565. if (aElements.length > 0) {
  9566. for (const element of aElements) {
  9567. const $element = $(element);
  9568. const href = $element.attr('href');
  9569. $element.removeAttr('href')[0].click();
  9570. $element.attr('href', href);
  9571. await delay(1e3);
  9572. }
  9573. }
  9574. taskInfo[0].click();
  9575. await delay(1e3);
  9576. }
  9577. scripts_echoLog({}).warning(i18n('gleamTaskNotice'));
  9578. } else if (!await this.#checkLeftKey()) {
  9579. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  9580. }
  9581. } catch (error) {
  9582. throwError(error, 'Gleam.after');
  9583. }
  9584. }
  9585. init() {
  9586. try {
  9587. const logStatus = scripts_echoLog({
  9588. text: i18n('initing')
  9589. });
  9590. if (!this.#getGiveawayId()) {
  9591. return false;
  9592. }
  9593. this.initialized = true;
  9594. logStatus.success();
  9595. return true;
  9596. } catch (error) {
  9597. throwError(error, 'Gleam.init');
  9598. return false;
  9599. }
  9600. }
  9601. async classifyTask(action) {
  9602. try {
  9603. const logStatus = scripts_echoLog({
  9604. text: i18n('getTasksInfo')
  9605. });
  9606. if (action === 'undo') {
  9607. this.socialTasks = GM_getValue(`gleamTasks-${this.giveawayId}`)?.tasks || JSON.parse(Gleam_defaultTasks);
  9608. }
  9609. const tasks = $('.entry-content .entry-method');
  9610. for (const task of tasks) {
  9611. const $task = $(task);
  9612. if (action === 'do' && $task.find('i.fa-question').length === 0) {
  9613. continue;
  9614. }
  9615. const socialIcon = $task.find('.icon-wrapper i');
  9616. const taskInfo = $task.find('.user-links');
  9617. const taskText = taskInfo.text().trim();
  9618. const expandInfo = $task.find('.expandable');
  9619. const aElements = expandInfo.find('a.btn');
  9620. if (aElements.length > 0) {
  9621. for (const element of aElements) {
  9622. const $element = $(element);
  9623. const href = $element.attr('href');
  9624. $element.removeAttr('href')[0].click();
  9625. $element.attr('href', href);
  9626. }
  9627. }
  9628. if (socialIcon.hasClass('fa-twitter') || socialIcon.hasClass('fa-x-twitter')) {
  9629. const link = $task.find('a[href^="https://twitter.com/"],a[href^="https://x.com/"]').attr('href');
  9630. if (!link) {
  9631. continue;
  9632. }
  9633. if (/follow/gi.test(taskText)) {
  9634. if (action === 'undo') {
  9635. this.socialTasks.twitter.userLinks.push(link);
  9636. }
  9637. if (action === 'do') {
  9638. this.undoneTasks.twitter.userLinks.push(link);
  9639. }
  9640. } else if (/retweet/gim.test(taskText)) {
  9641. if (action === 'undo') {
  9642. this.socialTasks.twitter.retweetLinks.push(link);
  9643. }
  9644. if (action === 'do') {
  9645. this.undoneTasks.twitter.retweetLinks.push(link);
  9646. }
  9647. }
  9648. } else if (socialIcon.hasClass('fa-twitch')) {
  9649. if (/follow/gim.test(taskText)) {
  9650. const link = $task.find('a[href^="https://twitch.tv/"]').attr('href');
  9651. if (!link) {
  9652. continue;
  9653. }
  9654. if (action === 'undo') {
  9655. this.socialTasks.twitch.channelLinks.push(link);
  9656. }
  9657. if (action === 'do') {
  9658. this.undoneTasks.twitch.channelLinks.push(link);
  9659. }
  9660. }
  9661. } else if (socialIcon.hasClass('fa-discord')) {
  9662. if (/join/gim.test(taskText)) {
  9663. let link = $task.find('a[href^="https://discord.com/invite/"]').attr('href');
  9664. if (!link) {
  9665. const ggLink = $task.find('a[href^="https://discord.gg/"]').attr('href')?.match(/discord\.gg\/([^/]+)/)?.[1];
  9666. if (!ggLink) {
  9667. continue;
  9668. }
  9669. link = `https://discord.com/invite/${ggLink}`;
  9670. }
  9671. if (action === 'undo') {
  9672. this.socialTasks.discord.serverLinks.push(link);
  9673. }
  9674. if (action === 'do') {
  9675. this.undoneTasks.discord.serverLinks.push(link);
  9676. }
  9677. }
  9678. } else if (socialIcon.hasClass('fa-external-link-square-alt')) {
  9679. continue;
  9680. } else if (socialIcon.hasClass('fa-youtube')) {
  9681. if (/subscribe/gim.test(taskText)) {
  9682. const link = $task.find('a[href^="https://www.youtube.com/channel/"]').attr('href');
  9683. if (!link) {
  9684. continue;
  9685. }
  9686. if (action === 'undo') {
  9687. this.socialTasks.youtube.channelLinks.push(link);
  9688. }
  9689. if (action === 'do') {
  9690. this.undoneTasks.youtube.channelLinks.push(link);
  9691. }
  9692. }
  9693. } else if (socialIcon.attr('class')?.includes('steam')) {
  9694. if (/join.*group/gi.test(taskText)) {
  9695. const link = $task.find('a[href^="https://steamcommunity.com/groups/"]').attr('href');
  9696. if (!link) {
  9697. continue;
  9698. }
  9699. if (action === 'undo') {
  9700. this.socialTasks.steam.groupLinks.push(link);
  9701. }
  9702. if (action === 'do') {
  9703. this.undoneTasks.steam.groupLinks.push(link);
  9704. }
  9705. } else if (/follow.*curator/gi.test(taskText)) {
  9706. const link = $task.find('a[href^="https://store.steampowered.com/curator/"]').attr('href');
  9707. if (!link) {
  9708. continue;
  9709. }
  9710. if (action === 'undo') {
  9711. this.socialTasks.steam.curatorLinks.push(link);
  9712. }
  9713. if (action === 'do') {
  9714. this.undoneTasks.steam.curatorLinks.push(link);
  9715. }
  9716. }
  9717. } else if (socialIcon.hasClass('fa-bullhorn') && /Complete|Increase/gi.test(taskText)) {
  9718. if (action !== 'do') {
  9719. continue;
  9720. }
  9721. const gleamLink = await this.#getGleamLink(taskText);
  9722. if (!gleamLink) {
  9723. continue;
  9724. }
  9725. this.undoneTasks.extra.gleam.push(gleamLink);
  9726. } 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 {
  9727. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${taskText}`);
  9728. }
  9729. }
  9730. logStatus.success();
  9731. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  9732. this.socialTasks = this.uniqueTasks(this.socialTasks);
  9733. if (window.DEBUG) {
  9734. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  9735. }
  9736. GM_setValue(`gleamTasks-${this.giveawayId}`, {
  9737. tasks: this.socialTasks,
  9738. time: new Date().getTime()
  9739. });
  9740. return true;
  9741. } catch (error) {
  9742. throwError(error, 'Gleam.classifyTask');
  9743. return false;
  9744. }
  9745. }
  9746. async extraDoTask({
  9747. gleam
  9748. }) {
  9749. try {
  9750. const pro = [];
  9751. for (const link of gleam) {
  9752. pro.push(this.#doGleamTask(link));
  9753. }
  9754. return Promise.all(pro).then(() => true);
  9755. } catch (error) {
  9756. throwError(error, 'Gleam.extraDoTask');
  9757. return false;
  9758. }
  9759. }
  9760. async verifyTask() {
  9761. try {
  9762. scripts_echoLog({
  9763. text: `${i18n('verifyingTask')}...`
  9764. });
  9765. const tasks = $('.entry-content .entry-method');
  9766. unsafeWindow._OxA = '_OxA';
  9767. for (const task of tasks) {
  9768. if ($('[campaign-key="campaign.key"]').length > 0) {
  9769. return scripts_echoLog({
  9770. text: i18n('campaign')
  9771. });
  9772. }
  9773. const $task = $(task);
  9774. if ($task.find('i.fa-question').length === 0) {
  9775. continue;
  9776. }
  9777. const taskInfo = $task.find('.user-links');
  9778. taskInfo[0].click();
  9779. const aElements = $task.find('.expandable').find('a.btn');
  9780. if (aElements.length > 0) {
  9781. for (const element of aElements) {
  9782. const $element = $(element);
  9783. const href = $element.attr('href');
  9784. $element.removeAttr('href')[0].click();
  9785. $element.attr('href', href);
  9786. }
  9787. }
  9788. unsafeWindow.$hookTimer?.setSpeed(1e3);
  9789. const visitBtn = $task.find('.expandable').find('span:contains(more seconds),button:contains(more seconds)').filter(':visible');
  9790. if (visitBtn.length > 0 && unsafeWindow.$hookTimer) {
  9791. const newTab = GM_openInTab('', {
  9792. active: true
  9793. });
  9794. await delay(1e3);
  9795. newTab?.close();
  9796. window.focus();
  9797. }
  9798. await delay(3e3);
  9799. unsafeWindow.$hookTimer?.setSpeed(1);
  9800. const expandInfo = $task.find('.expandable');
  9801. const [ input ] = expandInfo.find('input');
  9802. if (input) {
  9803. const evt = new Event('input', {
  9804. bubbles: true,
  9805. cancelable: true,
  9806. composed: true
  9807. });
  9808. const valuelimit = [ ...expandInfo.text().matchAll(/"(.+?)"/g) ].at(-1)?.[1];
  9809. input.value = valuelimit || 'vloot';
  9810. input.dispatchEvent(evt);
  9811. await delay(1e3);
  9812. }
  9813. await this.#checkSync();
  9814. const continueBtn = $task.find('.expandable').find('span:contains(Continue),button:contains(Continue)');
  9815. for (const button of continueBtn) {
  9816. button.click();
  9817. await delay(500);
  9818. await this.#checkSync();
  9819. }
  9820. }
  9821. scripts_echoLog({
  9822. text: i18n('verifiedGleamTasks')
  9823. });
  9824. } catch (error) {
  9825. throwError(error, 'Gleam.verifyTask');
  9826. return false;
  9827. }
  9828. }
  9829. async #checkSync() {
  9830. try {
  9831. return await new Promise(resolve => {
  9832. const checker = setInterval(() => {
  9833. if ($('.entry-content .entry-method i.fa-sync').length === 0) {
  9834. clearInterval(checker);
  9835. resolve(true);
  9836. }
  9837. }, 500);
  9838. });
  9839. } catch (error) {
  9840. throwError(error, 'Gleam.checkSync');
  9841. return false;
  9842. }
  9843. }
  9844. async #doGleamTask(link) {
  9845. try {
  9846. const logStatus = scripts_echoLog({
  9847. text: i18n('doingGleamTask')
  9848. });
  9849. return await new Promise(resolve => {
  9850. GM_openInTab(`${link}?8b07d23f4bfa65f9`, {
  9851. active: true,
  9852. insert: true,
  9853. setParent: true
  9854. }).onclose = () => {
  9855. logStatus.success();
  9856. resolve(true);
  9857. };
  9858. });
  9859. } catch (error) {
  9860. throwError(error, 'Gleam.doGleamTask');
  9861. return false;
  9862. }
  9863. }
  9864. #getGiveawayId() {
  9865. try {
  9866. const giveawayId = window.location.pathname;
  9867. if (giveawayId) {
  9868. this.giveawayId = giveawayId;
  9869. return true;
  9870. }
  9871. scripts_echoLog({
  9872. text: i18n('getFailed', 'GiveawayId')
  9873. });
  9874. return false;
  9875. } catch (error) {
  9876. throwError(error, 'Gleam.getGiveawayId');
  9877. return false;
  9878. }
  9879. }
  9880. async #getGleamLink(title) {
  9881. try {
  9882. const logStatus = scripts_echoLog({
  9883. text: i18n('gettingGleamLink')
  9884. });
  9885. const {
  9886. result,
  9887. statusText,
  9888. status,
  9889. data
  9890. } = await tools_httpRequest({
  9891. url: 'https://www.vloot.io/api/v1/giveaways',
  9892. method: 'GET',
  9893. responseType: 'json'
  9894. });
  9895. if (result === 'Success') {
  9896. if (data?.status === 200 && data?.response?.Success === true && data?.response?.Data) {
  9897. const {
  9898. link
  9899. } = data.response.Data.find(giveaway => title.replace(/[\s]/g, '').toLowerCase().includes(giveaway.title.replace(/[\s]/g, '').toLowerCase())) || {};
  9900. if (link) {
  9901. logStatus.success();
  9902. return link;
  9903. }
  9904. logStatus.error(`Error:${i18n('getLinkFailed')}`);
  9905. return false;
  9906. }
  9907. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  9908. return false;
  9909. }
  9910. logStatus.error(`${result}:${statusText}(${status})`);
  9911. return false;
  9912. } catch (error) {
  9913. throwError(error, 'Gleam.getGleamLink');
  9914. return false;
  9915. }
  9916. }
  9917. async #checkLeftKey() {
  9918. try {
  9919. if (!globalOptions.other.checkLeftKey) {
  9920. return true;
  9921. }
  9922. const campaignString = $('div.popup-blocks-container').attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
  9923. if (!campaignString) {
  9924. return false;
  9925. }
  9926. const {
  9927. campaign,
  9928. incentive
  9929. } = JSON.parse(campaignString);
  9930. const controllerString = $('div.campaign.reward').attr('ng-init')?.match(/initContestant\(([\w\W]+?)\);/)?.[1];
  9931. let ownedKey = false;
  9932. if (controllerString) {
  9933. if (JSON.parse(controllerString).contestant?.claims?.incentives?.[incentive.id]?.length) {
  9934. ownedKey = true;
  9935. }
  9936. }
  9937. if (campaign.banned || campaign.finished && !ownedKey || campaign.paused || new Date().getTime() < campaign.starts_at * 1e3) {
  9938. await external_Swal_default().fire({
  9939. icon: 'warning',
  9940. title: i18n('notice'),
  9941. text: i18n('giveawayNotWork'),
  9942. confirmButtonText: i18n('confirm'),
  9943. cancelButtonText: i18n('cancel'),
  9944. showCancelButton: true
  9945. }).then(({
  9946. value
  9947. }) => {
  9948. if (value) {
  9949. window.close();
  9950. }
  9951. });
  9952. }
  9953. return true;
  9954. } catch (error) {
  9955. throwError(error, 'Gleam.checkLeftKey');
  9956. return false;
  9957. }
  9958. }
  9959. }
  9960. const website_Gleam = Gleam;
  9961. const SweepWidget_defaultOptions = {
  9962. username: '',
  9963. email: ''
  9964. };
  9965. class SweepWidget extends website_Website {
  9966. name = 'SweepWidget';
  9967. options = {
  9968. ...SweepWidget_defaultOptions,
  9969. ...GM_getValue('SweepWidgetOptions')
  9970. };
  9971. buttons = [ 'doTask' ];
  9972. static test() {
  9973. return /^https?:\/\/sweepwidget\.com\/view\/[\d]+/.test(window.location.href);
  9974. }
  9975. async after() {
  9976. try {
  9977. if (!this.#checkLogin()) {
  9978. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  9979. }
  9980. } catch (error) {
  9981. throwError(error, 'SweepWidget.after');
  9982. }
  9983. }
  9984. init() {
  9985. try {
  9986. const logStatus = scripts_echoLog({
  9987. text: i18n('initing')
  9988. });
  9989. if (!this.#checkLogin()) {
  9990. logStatus.warning(i18n('needLogin'));
  9991. return false;
  9992. }
  9993. if (!this.#getGiveawayId()) {
  9994. return false;
  9995. }
  9996. this.initialized = true;
  9997. logStatus.success();
  9998. return true;
  9999. } catch (error) {
  10000. throwError(error, 'SweepWidget.init');
  10001. return false;
  10002. }
  10003. }
  10004. classifyTask() {
  10005. return true;
  10006. }
  10007. async doTask() {
  10008. try {
  10009. if ($('#unlock_rewards_main_wrapper').length === 0) {
  10010. if ($('input[name="sw__login_name"]:visible').length > 0) {
  10011. $('input[name="sw__login_name"]').val(this.options.username);
  10012. }
  10013. if ($('input[name="sw__login_email"]:visible').length > 0) {
  10014. $('input[name="sw__login_email"]').val(this.options.email);
  10015. }
  10016. if ($('#sw_login_button:visible').length > 0) {
  10017. $('#sw_login_button')[0].click();
  10018. }
  10019. if (!await this.#checkEnter()) {
  10020. return false;
  10021. }
  10022. }
  10023. const logStatus = scripts_echoLog({
  10024. text: i18n('SweepWidgetNotice')
  10025. });
  10026. const tasks = $('#sw_inner_entry_methods_l2_wrapper>div.sw_entry');
  10027. for (const task of tasks) {
  10028. const $task = $(task);
  10029. if ($task.find('i.fa-check:visible').length > 0) {
  10030. continue;
  10031. }
  10032. const title = $task.find('.sw_text_inner');
  10033. title[0].click();
  10034. const aElement = $task.find('a.sw_link');
  10035. const link = aElement.attr('href');
  10036. aElement.attr('href', '#a').attr('target', '_self');
  10037. aElement[0]?.click();
  10038. await delay(300);
  10039. aElement.attr('href', link).attr('target', '_blank');
  10040. $task.find('input[type="text"]').val('test');
  10041. const verifyBtn = $task.find('input.sw_verify');
  10042. if (verifyBtn.prop('disabled') === true) {
  10043. title[0].click();
  10044. await delay(300);
  10045. title[0].click();
  10046. await delay(300);
  10047. }
  10048. $task.find('input.sw_verify').removeAttr('disabled')[0]?.click();
  10049. await this.#checkFinish($task);
  10050. await delay(parseInt(`${Math.random() * (3e3 - 1e3 + 1) + 1e3}`, 10));
  10051. }
  10052. logStatus.success();
  10053. return true;
  10054. } catch (error) {
  10055. throwError(error, 'SweepWidget.doTask');
  10056. return false;
  10057. }
  10058. }
  10059. #checkLogin() {
  10060. try {
  10061. if ($('#twitter_login_button').length > 0) {
  10062. $('#twitter_login_button')[0].click();
  10063. }
  10064. return true;
  10065. } catch (error) {
  10066. throwError(error, 'SweepWidget.checkLogin');
  10067. return false;
  10068. }
  10069. }
  10070. #getGiveawayId() {
  10071. try {
  10072. const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
  10073. if (giveawayId) {
  10074. this.giveawayId = giveawayId;
  10075. return true;
  10076. }
  10077. scripts_echoLog({
  10078. text: i18n('getFailed', 'GiveawayId')
  10079. });
  10080. return false;
  10081. } catch (error) {
  10082. throwError(error, 'SweepWidget.getGiveawayId');
  10083. return false;
  10084. }
  10085. }
  10086. async #checkEnter() {
  10087. try {
  10088. return new Promise(resolve => {
  10089. const checker = setInterval(() => {
  10090. if ($('#unlock_rewards_main_wrapper').length > 0) {
  10091. clearInterval(checker);
  10092. resolve(true);
  10093. }
  10094. }, 500);
  10095. });
  10096. } catch (error) {
  10097. throwError(error, 'SweepWidget.checkEnter');
  10098. return false;
  10099. }
  10100. }
  10101. async #checkFinish($task) {
  10102. try {
  10103. return new Promise(resolve => {
  10104. const checker = setInterval(() => {
  10105. if ($task.find('i.fa-check:visible').length > 0 || $task.find('.sw_entry_input:visible').length === 0) {
  10106. clearInterval(checker);
  10107. resolve(true);
  10108. }
  10109. }, 500);
  10110. });
  10111. } catch (error) {
  10112. throwError(error, 'SweepWidget.checkFinish');
  10113. return false;
  10114. }
  10115. }
  10116. }
  10117. const website_SweepWidget = SweepWidget;
  10118. const defaultWhiteList = {
  10119. discord: {
  10120. servers: []
  10121. },
  10122. instagram: {
  10123. users: []
  10124. },
  10125. twitch: {
  10126. channels: []
  10127. },
  10128. twitter: {
  10129. users: [],
  10130. retweets: [],
  10131. likes: []
  10132. },
  10133. vk: {
  10134. names: []
  10135. },
  10136. youtube: {
  10137. channels: [],
  10138. likes: []
  10139. },
  10140. reddit: {
  10141. reddits: []
  10142. },
  10143. steam: {
  10144. groups: [],
  10145. officialGroups: [],
  10146. wishlists: [],
  10147. follows: [],
  10148. forums: [],
  10149. workshops: [],
  10150. curators: [],
  10151. workshopVotes: [],
  10152. curatorLikes: [],
  10153. announcements: [],
  10154. licenses: [],
  10155. playtests: []
  10156. }
  10157. };
  10158. const link2id = async function(type) {
  10159. try {
  10160. const link = $('#socialLink').val();
  10161. let id = '';
  10162. switch (type) {
  10163. case 'discord.servers':
  10164. id = link.match(/invite\/(.+)/)?.[1] || '';
  10165. break;
  10166.  
  10167. case 'instagram.users':
  10168. id = link.match(/https:\/\/www\.instagram\.com\/(.+)?\//)?.[1] || '';
  10169. break;
  10170.  
  10171. case 'twitch.channels':
  10172. id = link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2] || '';
  10173. break;
  10174.  
  10175. case 'twitter.users':
  10176. id = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || '';
  10177. break;
  10178.  
  10179. case 'twitter.retweets':
  10180. id = link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1] || '';
  10181. break;
  10182.  
  10183. case 'vk.names':
  10184. id = link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1] || '';
  10185. break;
  10186.  
  10187. case 'youtube.channels':
  10188. id = (await getInfo(link, 'channel'))?.params?.channelId || '';
  10189. break;
  10190.  
  10191. case 'youtube.likes':
  10192. id = (await getInfo(link, 'likeVideo'))?.params?.videoId || '';
  10193. break;
  10194.  
  10195. case 'reddit.reddits':
  10196. id = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1] || link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1] || '';
  10197. break;
  10198.  
  10199. case 'steam.groups':
  10200. id = link.match(/groups\/(.+)\/?/)?.[1] || '';
  10201. break;
  10202.  
  10203. case 'steam.wishlists':
  10204. case 'steam.follows':
  10205. case 'steam.forums':
  10206. id = link.match(/app\/([\d]+)/)?.[1] || '';
  10207. break;
  10208.  
  10209. case 'steam.workshops':
  10210. id = link.match(/\?id=([\d]+)/)?.[1] || '';
  10211. break;
  10212.  
  10213. case 'steam.curators':
  10214. {
  10215. if (link.includes('curator')) {
  10216. id = link.match(/curator\/([\d]+)/)?.[1] || '';
  10217. } else {
  10218. const param = link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3);
  10219. if (!param || param.length !== 2) {
  10220. break;
  10221. }
  10222. const steam = new social_Steam();
  10223. if (await steam.init()) {
  10224. id = await steam.getCuratorId(param[0], param[1]) || '';
  10225. }
  10226. }
  10227. }
  10228. break;
  10229. }
  10230. return id;
  10231. } catch (error) {
  10232. throwError(error, 'link2id');
  10233. return i18n('getFailed', 'id');
  10234. }
  10235. };
  10236. const disabledType = {
  10237. steam: [ 'workshopVotes', 'curatorLikes', 'announcements' ],
  10238. twitter: [ 'likes' ]
  10239. };
  10240. const assignWhiteList = whiteList => {
  10241. try {
  10242. const newWhiteList = {};
  10243. for (const [ key, value ] of Object.entries(defaultWhiteList)) {
  10244. newWhiteList[key] = {
  10245. ...value,
  10246. ...whiteList[key]
  10247. };
  10248. }
  10249. return newWhiteList;
  10250. } catch (error) {
  10251. throwError(error, 'assignWhiteList');
  10252. return defaultWhiteList;
  10253. }
  10254. };
  10255. const whiteListOptions = function(showType) {
  10256. try {
  10257. const whiteList = assignWhiteList(GM_getValue('whiteList') || {});
  10258. let whiteListOptionsForm = `<form id="whiteListForm" class="auto-task-form">
  10259. <table class="auto-task-table"><thead><tr><td>${i18n('website')}</td><td>${i18n('type')}</td><td>${i18n('edit')}</td></tr></thead><tbody>`;
  10260. for (const [ social, types ] of Object.entries(whiteList)) {
  10261. 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('');
  10262. }
  10263. whiteListOptionsForm += '</tbody></table></form>';
  10264. if (showType === 'swal') {
  10265. external_Swal_default().fire({
  10266. title: i18n('whiteListOptions'),
  10267. html: whiteListOptionsForm,
  10268. showConfirmButton: false,
  10269. showCloseButton: true
  10270. });
  10271. } else {
  10272. $('body').append(`<h2>${i18n('whiteList')}</h2>${whiteListOptionsForm}`);
  10273. }
  10274. $('.editWhiteList').on('click', function() {
  10275. const value = $(this).attr('data-value');
  10276. if (!value) {
  10277. return;
  10278. }
  10279. const [ social, type ] = value.split('.');
  10280. if (!whiteList?.[social]?.[type]) {
  10281. scripts_echoLog({}).warning(i18n('whiteListNotFound', value));
  10282. return;
  10283. }
  10284. external_Swal_default().fire({
  10285. title: i18n('changeWhiteListOption', value),
  10286. input: 'textarea',
  10287. html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">
  10288. <button id="link2id" data-type="${value}" class="swal2-confirm swal2-styled">获取id</button>
  10289. <p style="margin-bottom:0 !important;">在下方填写白名单,每行一个</p>`,
  10290. inputValue: whiteList[social][type].join('\n'),
  10291. showConfirmButton: true,
  10292. confirmButtonText: i18n('save'),
  10293. showCancelButton: true,
  10294. cancelButtonText: i18n('close'),
  10295. showDenyButton: true,
  10296. denyButtonText: i18n('return')
  10297. }).then(({
  10298. isDenied,
  10299. isConfirmed,
  10300. value
  10301. }) => {
  10302. if (isDenied) {
  10303. if (showType === 'swal') {
  10304. whiteListOptions(showType);
  10305. }
  10306. return;
  10307. } else if (isConfirmed) {
  10308. whiteList[social][type] = value.split('\n');
  10309. GM_setValue('whiteList', whiteList);
  10310. external_Swal_default().fire({
  10311. title: i18n('changeWhiteListSuccess'),
  10312. icon: 'success'
  10313. });
  10314. }
  10315. });
  10316. $('#link2id').on('click', async function() {
  10317. const type = $(this).attr('data-type');
  10318. $('#socialLink').val(await link2id(type));
  10319. });
  10320. });
  10321. } catch (error) {
  10322. throwError(error, 'whiteListOptions');
  10323. }
  10324. };
  10325. const whiteList = whiteListOptions;
  10326. const setGistData = async (token, gistId, fileName, content) => {
  10327. try {
  10328. const logStatus = scripts_echoLog({
  10329. text: i18n('settingData')
  10330. });
  10331. const contentData = JSON.stringify({
  10332. files: {
  10333. [fileName]: {
  10334. content: JSON.stringify(content)
  10335. }
  10336. }
  10337. });
  10338. const {
  10339. result,
  10340. statusText,
  10341. status,
  10342. data
  10343. } = await tools_httpRequest({
  10344. url: `https://api.github.com/gists/${gistId}`,
  10345. headers: {
  10346. Accept: 'application/vnd.github.v3+json',
  10347. Authorization: `token ${token}`
  10348. },
  10349. data: contentData,
  10350. responseType: 'json',
  10351. method: 'POST',
  10352. timeout: 3e4
  10353. });
  10354. if (result === 'Success') {
  10355. if (data?.status === 200 && data.response.files?.[fileName]?.content === JSON.stringify(content)) {
  10356. logStatus.success();
  10357. return true;
  10358. }
  10359. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10360. return false;
  10361. }
  10362. logStatus.error(`${result}:${statusText}(${status})`);
  10363. return false;
  10364. } catch (error) {
  10365. throwError(error, 'setGistData');
  10366. return false;
  10367. }
  10368. };
  10369. const getGistData = async (token, gistId, fileName, test = false) => {
  10370. try {
  10371. const logStatus = scripts_echoLog({
  10372. text: i18n('gettingData')
  10373. });
  10374. const {
  10375. result,
  10376. statusText,
  10377. status,
  10378. data
  10379. } = await tools_httpRequest({
  10380. url: `https://api.github.com/gists/${gistId}`,
  10381. headers: {
  10382. Accept: 'application/vnd.github.v3+json',
  10383. Authorization: `token ${token}`
  10384. },
  10385. responseType: 'json',
  10386. method: 'GET',
  10387. timeout: 3e4
  10388. });
  10389. if (result === 'Success') {
  10390. if (data?.status === 200) {
  10391. const content = data.response?.files?.[fileName]?.content;
  10392. let formatedContent;
  10393. if (!content) {
  10394. logStatus.error(`Error:${i18n('noRemoteData')}`);
  10395. return false;
  10396. }
  10397. if (test) {
  10398. logStatus.success();
  10399. return true;
  10400. }
  10401. try {
  10402. formatedContent = JSON.parse(content);
  10403. } catch (error) {
  10404. logStatus.error(`Error:${i18n('errorRemoteDataFormat')}`);
  10405. return false;
  10406. }
  10407. logStatus.success();
  10408. return formatedContent;
  10409. }
  10410. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10411. return false;
  10412. }
  10413. logStatus.error(`${result}:${statusText}(${status})`);
  10414. return false;
  10415. } catch (error) {
  10416. throwError(error, 'getGistData');
  10417. return false;
  10418. }
  10419. };
  10420. const syncOptions = () => {
  10421. try {
  10422. const {
  10423. TOKEN,
  10424. GIST_ID,
  10425. FILE_NAME,
  10426. SYNC_HISTORY
  10427. } = GM_getValue('gistOptions') || {
  10428. TOKEN: '',
  10429. GIST_ID: '',
  10430. FILE_NAME: '',
  10431. SYNC_HISTORY: true
  10432. };
  10433. external_Swal_default().fire({
  10434. title: i18n('gistOptions'),
  10435. 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;">
  10436. ${i18n('upload2gist')}</button>` + `<button id="download-data" type="button" class="swal2-confirm swal2-styled" style="display: inline-block;">
  10437. ${i18n('downloadFromGist')}</button></p>`,
  10438. focusConfirm: false,
  10439. showLoaderOnConfirm: true,
  10440. 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>`,
  10441. preConfirm: async () => {
  10442. const token = $('#github-token').val();
  10443. const gistId = $('#gist-id').val();
  10444. const fileName = $('#file-name').val();
  10445. const syncHistory = $('#sync-history').prop('checked');
  10446. GM_setValue('gistOptions', {
  10447. TOKEN: token,
  10448. GIST_ID: gistId,
  10449. FILE_NAME: fileName,
  10450. SYNC_HISTORY: syncHistory
  10451. });
  10452. return await getGistData(token, gistId, fileName, true);
  10453. },
  10454. allowOutsideClick: () => !external_Swal_default().isLoading(),
  10455. confirmButtonText: i18n('saveAndTest'),
  10456. showCancelButton: true,
  10457. cancelButtonText: i18n('close')
  10458. }).then(({
  10459. value
  10460. }) => {
  10461. if (value) {
  10462. external_Swal_default().fire({
  10463. icon: 'success',
  10464. title: i18n('testSuccess')
  10465. }).then(syncOptions);
  10466. } else if (value !== undefined) {
  10467. external_Swal_default().fire({
  10468. icon: 'error',
  10469. title: i18n('testFailed')
  10470. }).then(syncOptions);
  10471. }
  10472. });
  10473. $('#upload-data').on('click', async () => {
  10474. const {
  10475. TOKEN,
  10476. GIST_ID,
  10477. FILE_NAME
  10478. } = GM_getValue('gistOptions') || {};
  10479. if (!(TOKEN && GIST_ID && FILE_NAME)) {
  10480. return external_Swal_default().fire({
  10481. icon: 'error',
  10482. title: i18n('saveAndTestNotice')
  10483. }).then(syncOptions);
  10484. }
  10485. external_Swal_default().fire({
  10486. icon: 'info',
  10487. title: i18n('processingData')
  10488. });
  10489. const data = {};
  10490. const names = GM_listValues();
  10491. const SYNC_HISTORY = $('#sync-history').prop('checked');
  10492. for (const name of names) {
  10493. if (name === 'gistOptions' || /^[\w]+?Auth$/.test(name)) {
  10494. continue;
  10495. }
  10496. if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) {
  10497. continue;
  10498. }
  10499. data[name] = GM_getValue(name);
  10500. }
  10501. external_Swal_default().update({
  10502. icon: 'info',
  10503. title: i18n('updatingData')
  10504. });
  10505. if (await setGistData(TOKEN, GIST_ID, FILE_NAME, data)) {
  10506. external_Swal_default().fire({
  10507. icon: 'success',
  10508. title: i18n('syncDataSuccess')
  10509. });
  10510. } else {
  10511. external_Swal_default().fire({
  10512. icon: 'error',
  10513. title: i18n('syncDataFailed')
  10514. });
  10515. }
  10516. });
  10517. $('#download-data').on('click', async () => {
  10518. const {
  10519. TOKEN,
  10520. GIST_ID,
  10521. FILE_NAME
  10522. } = GM_getValue('gistOptions') || {};
  10523. if (!(TOKEN && GIST_ID && FILE_NAME)) {
  10524. return external_Swal_default().fire({
  10525. icon: 'error',
  10526. title: i18n('saveAndTestNotice')
  10527. }).then(syncOptions);
  10528. }
  10529. external_Swal_default().fire({
  10530. icon: 'info',
  10531. title: i18n('downloadingData')
  10532. });
  10533. const data = await getGistData(TOKEN, GIST_ID, FILE_NAME);
  10534. if (!data) {
  10535. return external_Swal_default().fire({
  10536. icon: 'error',
  10537. title: i18n('checkedNoData')
  10538. }).then(syncOptions);
  10539. }
  10540. external_Swal_default().update({
  10541. icon: 'info',
  10542. title: i18n('savingData')
  10543. });
  10544. const SYNC_HISTORY = $('#sync-history').prop('checked');
  10545. for (const [ name, value ] of Object.entries(data)) {
  10546. if (!SYNC_HISTORY && /^[\w]+?Tasks-/.test(name)) {
  10547. continue;
  10548. }
  10549. GM_setValue(name, value);
  10550. }
  10551. external_Swal_default().fire({
  10552. icon: 'success',
  10553. title: i18n('syncDataSuccess')
  10554. });
  10555. });
  10556. } catch (error) {
  10557. throwError(error, 'syncOptions');
  10558. }
  10559. };
  10560. const dataSync = syncOptions;
  10561. class Setting {
  10562. name = 'Setting';
  10563. buttons = [ 'saveGlobalOptions', 'syncData', 'tasksHistory' ];
  10564. syncData = dataSync;
  10565. tasksHistory() {
  10566. GM_openInTab('https://auto-task-v4.hclonely.com/history.html', {
  10567. active: true
  10568. });
  10569. }
  10570. static test() {
  10571. return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/setting.html';
  10572. }
  10573. before() {
  10574. try {
  10575. $('body').html('').addClass('auto-task-options');
  10576. } catch (error) {
  10577. throwError(error, 'Setting.before');
  10578. }
  10579. }
  10580. after() {
  10581. try {
  10582. this.#environment();
  10583. changeGlobalOptions('page');
  10584. whiteList('page');
  10585. $('input[name="other.twitterVerifyId"]').after(`<button id="getTwitterUserId" type="button">${i18n('getTwitterUserId')}</button>`);
  10586. $('#getTwitterUserId').on('click', () => {
  10587. this.#getId('twitterUser');
  10588. });
  10589. $('input[name="other.youtubeVerifyChannel"]').after(`<button id="getYoutubeChannelId" type="button">${i18n('getYoutubeChannelId')}</button>`);
  10590. $('#getYoutubeChannelId').on('click', () => {
  10591. this.#getId('youtubeChannel');
  10592. });
  10593. $('input[name^="position"]').on('input', function() {
  10594. const type = $(this).attr('name').replace('position.', '');
  10595. const xLabel = 'rightleft';
  10596. const yLabel = 'topbottpm';
  10597. switch (type) {
  10598. case 'buttonSideX':
  10599. case 'buttonSideY':
  10600. case 'buttonDistance':
  10601. {
  10602. const distance = $('input[name="position.buttonDistance"]').val();
  10603. const sideX = $('input[name="position.buttonSideX"]').val();
  10604. const sideY = $('input[name="position.buttonSideY"]').val();
  10605. if (![ 'right', 'left' ].includes(sideX)) {
  10606. break;
  10607. }
  10608. if (![ 'top', 'bottom' ].includes(sideY)) {
  10609. break;
  10610. }
  10611. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  10612. break;
  10613. }
  10614. const distanceArr = distance.split(',');
  10615. $('#auto-task-buttons').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  10616. break;
  10617. }
  10618.  
  10619. case 'showButtonSideX':
  10620. case 'showButtonSideY':
  10621. case 'showButtonDistance':
  10622. {
  10623. const distance = $('input[name="position.showButtonDistance"]').val();
  10624. const sideX = $('input[name="position.showButtonSideX"]').val();
  10625. const sideY = $('input[name="position.showButtonSideY"]').val();
  10626. if (![ 'right', 'left' ].includes(sideX)) {
  10627. break;
  10628. }
  10629. if (![ 'top', 'bottom' ].includes(sideY)) {
  10630. break;
  10631. }
  10632. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  10633. break;
  10634. }
  10635. const distanceArr = distance.split(',');
  10636. $('div.show-button-div').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  10637. break;
  10638. }
  10639.  
  10640. case 'logSideX':
  10641. case 'logSideY':
  10642. case 'logDistance':
  10643. {
  10644. const distance = $('input[name="position.logDistance"]').val();
  10645. const sideX = $('input[name="position.logSideX"]').val();
  10646. const sideY = $('input[name="position.logSideY"]').val();
  10647. if (![ 'right', 'left' ].includes(sideX)) {
  10648. break;
  10649. }
  10650. if (![ 'top', 'bottom' ].includes(sideY)) {
  10651. break;
  10652. }
  10653. if (!/^[\d]+?,[\d]+$/.test(distance)) {
  10654. break;
  10655. }
  10656. const distanceArr = distance.split(',');
  10657. $('#auto-task-info').css(sideX, `${distanceArr[0]}px`).css(sideY, `${distanceArr[1]}px`).css(xLabel.replace(sideX, ''), '').css(yLabel.replace(sideY, ''), '');
  10658. break;
  10659. }
  10660.  
  10661. default:
  10662. break;
  10663. }
  10664. });
  10665. $('input[name^="hotKey"]').attr('readonly', 'readonly').off('keydown').on('keydown', function(event) {
  10666. let functionKey = '';
  10667. if (event.altKey) {
  10668. functionKey += 'alt + ';
  10669. } else if (event.ctrlKey) {
  10670. functionKey += 'ctrl + ';
  10671. } else if (event.shiftKey) {
  10672. functionKey += 'shift + ';
  10673. }
  10674. $(this).val(functionKey + (event.key.length === 1 ? event.key.toLowerCase() : ''));
  10675. });
  10676. } catch (error) {
  10677. throwError(error, 'Setting.after');
  10678. }
  10679. }
  10680. saveGlobalOptions() {
  10681. try {
  10682. saveData();
  10683. } catch (error) {
  10684. throwError(error, 'Setting.saveGlobalOptions');
  10685. }
  10686. }
  10687. #getId(social) {
  10688. try {
  10689. external_Swal_default().fire({
  10690. title: i18n('getId', i18n(social)),
  10691. html: `<input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">
  10692. <button id="link2id" data-type="${social}" class="swal2-confirm swal2-styled">获取id</button>`,
  10693. showCancelButton: true,
  10694. cancelButtonText: i18n('close'),
  10695. showConfirmButton: false
  10696. });
  10697. $('#link2id').on('click', async function() {
  10698. const link = $('#socialLink').val();
  10699. if (!link) {
  10700. return;
  10701. }
  10702. const type = $(this).attr('data-type');
  10703. if (type === 'twitterUser') {
  10704. const name = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || link;
  10705. $('#socialLink').val(await new social_Twitter().userName2id(name) || '');
  10706. } else if (type === 'youtubeChannel') {
  10707. const name = /^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www.youtube.com\/.*/.test(link) ? link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1] : link;
  10708. $('#socialLink').val((await getInfo(name, 'channel'))?.params?.channelId || '');
  10709. }
  10710. });
  10711. } catch (error) {
  10712. throwError(error, 'Setting.getId');
  10713. }
  10714. }
  10715. #environment() {
  10716. try {
  10717. const userAgent = (0, javascript_utils_umd_min.ua)();
  10718. const environmentForm = `<form id="environmentForm" class="auto-task-form">
  10719. <table class="auto-task-table"><thead><tr><td>${i18n('type')}</td><td>${i18n('name')}</td><td>${i18n('version')}</td></tr></thead><tbody>
  10720. <tr><td>${i18n('os')}</td><td>${userAgent.os}</td><td>${userAgent.osVersion}</td></tr>
  10721. <tr><td>${i18n('browser')}</td><td>${userAgent.browserZH}</td><td>${userAgent.browserVersion}</td></tr>
  10722. <tr><td>${i18n('scriptManager')}</td><td>${GM_info.scriptHandler}</td><td>${GM_info.version}</td></tr>
  10723. <tr><td>${i18n('script')}</td><td>${GM_info.script.name}</td><td>${GM_info.script.version}</td></tr>
  10724. </tbody></table></form>`;
  10725. $('body').append(`<h2>${i18n('environment')}</h2>${environmentForm}`);
  10726. } catch (error) {
  10727. throwError(error, 'Setting.environment');
  10728. }
  10729. }
  10730. }
  10731. const website_Setting = Setting;
  10732. class History extends website_Keylol {
  10733. name = 'History';
  10734. buttons = [ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect', 'clearHistory' ];
  10735. static test() {
  10736. return window.location.host === 'auto-task-v4.hclonely.com' && window.location.pathname === '/history.html';
  10737. }
  10738. before() {
  10739. try {
  10740. $('body').html('<div class="container"></div>').addClass('auto-task-history');
  10741. const data = GM_listValues() || [];
  10742. const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value);
  10743. for (const item of tasksHistory) {
  10744. this.#addItem(item);
  10745. }
  10746. } catch (error) {
  10747. throwError(error, 'History.before');
  10748. }
  10749. }
  10750. clearHistory() {
  10751. try {
  10752. const data = GM_listValues() || [];
  10753. const tasksHistory = data.map(value => /^[\w]+?Tasks-/.test(value) ? value : null).filter(value => value);
  10754. for (const item of tasksHistory) {
  10755. GM_deleteValue(item);
  10756. }
  10757. external_Swal_default().fire({
  10758. title: i18n('clearHistoryFinished'),
  10759. icon: 'success'
  10760. });
  10761. } catch (error) {
  10762. throwError(error, 'History.clearHistory');
  10763. }
  10764. }
  10765. #addItem(item) {
  10766. try {
  10767. const tasksData = GM_getValue(item);
  10768. if (!tasksData?.tasks) {
  10769. return;
  10770. }
  10771. let html = '';
  10772. let title = '';
  10773. let link = '';
  10774. const [ website, id ] = item.split('-');
  10775. switch (website) {
  10776. case 'fawTasks':
  10777. title = `Freeanywhere[${id}]`;
  10778. link = `https://freeanywhere.net/#/giveaway/${id}`;
  10779. break;
  10780.  
  10781. case 'gasTasks':
  10782. title = `Giveawaysu[${id}]`;
  10783. link = `https://giveaway.su/giveaway/view/${id}`;
  10784. break;
  10785.  
  10786. case 'gcTasks':
  10787. title = `GiveeClub[${id}]`;
  10788. link = `https://givee.club/event/${id}`;
  10789. break;
  10790.  
  10791. case 'gkTasks':
  10792. title = `Givekey[${id}]`;
  10793. link = `https://givekey.ru/giveaway/${id}`;
  10794. break;
  10795.  
  10796. case 'gleamTasks':
  10797. title = `Gleam[${id}]`;
  10798. link = `https://gleam.io${id}`;
  10799. break;
  10800.  
  10801. case 'khTasks':
  10802. title = `keyhub[${id}]`;
  10803. link = `https://key-hub.eu/giveaway/${id}`;
  10804. break;
  10805.  
  10806. case 'prysTasks':
  10807. title = `Prys[${id}]`;
  10808. link = `https://prys.revadike.com/giveaway/?id=${id}`;
  10809. break;
  10810.  
  10811. default:
  10812. return;
  10813. }
  10814. for (const [ social, types ] of Object.entries(tasksData.tasks)) {
  10815. for (const [ type, tasks ] of Object.entries(types)) {
  10816. for (const task of tasks) {
  10817. 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>`;
  10818. }
  10819. }
  10820. }
  10821. $('.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>`);
  10822. $('span.delete-task').on('click', function() {
  10823. const itemName = $(this).attr('data-name');
  10824. if (itemName) {
  10825. GM_deleteValue(itemName);
  10826. $(`div.card[data-name="${itemName}"]`).remove();
  10827. external_Swal_default().fire({
  10828. title: i18n('clearTaskFinished'),
  10829. text: itemName,
  10830. icon: 'success'
  10831. });
  10832. } else {
  10833. external_Swal_default().fire({
  10834. title: i18n('clearTaskFailed'),
  10835. icon: 'error'
  10836. });
  10837. }
  10838. });
  10839. } catch (error) {
  10840. throwError(error, 'History.addItem');
  10841. }
  10842. }
  10843. }
  10844. const website_History = History;
  10845. const GiveawayHopper_defaultTasksTemplate = {
  10846. steam: {
  10847. groupLinks: [],
  10848. wishlistLinks: [],
  10849. followLinks: [],
  10850. curatorLinks: [],
  10851. curatorLikeLinks: []
  10852. },
  10853. twitter: {
  10854. userLinks: [],
  10855. retweetLinks: []
  10856. },
  10857. twitch: {
  10858. channelLinks: []
  10859. },
  10860. discord: {
  10861. serverLinks: []
  10862. },
  10863. youtube: {
  10864. channelLinks: []
  10865. },
  10866. extra: {
  10867. giveawayHopper: []
  10868. }
  10869. };
  10870. const GiveawayHopper_defaultTasks = JSON.stringify(GiveawayHopper_defaultTasksTemplate);
  10871. class GiveawayHopper extends website_Website {
  10872. name = 'GiveawayHopper';
  10873. undoneTasks = JSON.parse(GiveawayHopper_defaultTasks);
  10874. socialTasks = JSON.parse(GiveawayHopper_defaultTasks);
  10875. tasks = [];
  10876. buttons = [ 'doTask', 'undoTask', 'verifyTask' ];
  10877. static test() {
  10878. return window.location.host === 'giveawayhopper.com';
  10879. }
  10880. async after() {
  10881. try {
  10882. if (!this.#checkLogin()) {
  10883. scripts_echoLog({}).warning(i18n('checkLoginFailed'));
  10884. }
  10885. this.#getGiveawayId();
  10886. } catch (error) {
  10887. throwError(error, 'GiveawayHopper.after');
  10888. }
  10889. }
  10890. async init() {
  10891. try {
  10892. const logStatus = scripts_echoLog({
  10893. text: i18n('initing')
  10894. });
  10895. if (!await this.#checkLeftKey()) {
  10896. scripts_echoLog({}).warning(i18n('checkLeftKeyFailed'));
  10897. }
  10898. this.initialized = true;
  10899. logStatus.success();
  10900. return true;
  10901. } catch (error) {
  10902. throwError(error, 'GiveawayHopper.init');
  10903. return false;
  10904. }
  10905. }
  10906. async classifyTask(action) {
  10907. try {
  10908. if (!this.giveawayId) {
  10909. await this.#getGiveawayId();
  10910. }
  10911. const logStatus = scripts_echoLog({
  10912. text: i18n('getTasksInfo')
  10913. });
  10914. if (action === 'undo') {
  10915. this.socialTasks = GM_getValue(`giveawayHopperTasks-${this.giveawayId}`)?.tasks || JSON.parse(GiveawayHopper_defaultTasks);
  10916. }
  10917. const {
  10918. result,
  10919. statusText,
  10920. status,
  10921. data
  10922. } = await tools_httpRequest({
  10923. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/with-auth`,
  10924. method: 'GET',
  10925. responseType: 'json',
  10926. fetch: true,
  10927. headers: {
  10928. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  10929. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  10930. }
  10931. });
  10932. if (result === 'Success') {
  10933. if (data?.status === 200 && data?.response?.tasks) {
  10934. this.tasks = data.response.tasks;
  10935. for (const task of data.response.tasks) {
  10936. if (task.isDone) {
  10937. continue;
  10938. }
  10939. await tools_httpRequest({
  10940. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/visited`,
  10941. method: 'GET',
  10942. responseType: 'json',
  10943. fetch: true,
  10944. headers: {
  10945. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  10946. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  10947. }
  10948. });
  10949. if (task.category === 'Steam' && task.type === 'JoinGroup') {
  10950. const steamGroupLink = await getRedirectLink(`https://steamcommunity.com/gid/${task.group_id}`);
  10951. if (!steamGroupLink) {
  10952. continue;
  10953. }
  10954. if (action === 'undo') {
  10955. this.socialTasks.steam.groupLinks.push(steamGroupLink);
  10956. }
  10957. if (action === 'do') {
  10958. this.undoneTasks.steam.groupLinks.push(steamGroupLink);
  10959. }
  10960. continue;
  10961. }
  10962. if (task.category === 'Discord' && task.type === 'JoinServer') {
  10963. if (action === 'undo') {
  10964. this.socialTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`);
  10965. }
  10966. if (action === 'do') {
  10967. this.undoneTasks.discord.serverLinks.push(`https://discord.gg/${task.invite_code}`);
  10968. }
  10969. continue;
  10970. }
  10971. if ([ 'TikTok', 'YouTube', 'General' ].includes(task.category)) {
  10972. continue;
  10973. }
  10974. scripts_echoLog({}).warning(`${i18n('unKnownTaskType')}: ${task.category}-${task.type}`);
  10975. }
  10976. logStatus.success();
  10977. this.undoneTasks = this.uniqueTasks(this.undoneTasks);
  10978. this.socialTasks = this.uniqueTasks(this.socialTasks);
  10979. if (window.DEBUG) {
  10980. console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
  10981. }
  10982. GM_setValue(`giveawayHopperTasks-${this.giveawayId}`, {
  10983. tasks: this.socialTasks,
  10984. time: new Date().getTime()
  10985. });
  10986. return true;
  10987. }
  10988. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  10989. return false;
  10990. }
  10991. logStatus.error(`${result}:${statusText}(${status})`);
  10992. return false;
  10993. } catch (error) {
  10994. throwError(error, 'GiveawayHopper.classifyTask');
  10995. return false;
  10996. }
  10997. }
  10998. async verifyTask() {
  10999. try {
  11000. for (const task of this.tasks) {
  11001. if (task.isDone) {
  11002. continue;
  11003. }
  11004. const logStatus = scripts_echoLog({
  11005. text: `${i18n('verifyingTask')}[${task.displayName?.replace(':target', task.targetName) || task.name}]...`
  11006. });
  11007. if (!task.link) {
  11008. if (task.category === 'YouTube' && task.type === 'FollowAccount') {
  11009. task.link = `https://www.youtube.com/@${task.targetName}`;
  11010. } else if (task.category === 'TikTok' && task.type === 'FollowAccount') {
  11011. task.link = `https://www.tiktok.com/@${task.targetName}`;
  11012. } else if (task.category === 'Steam' && task.type === 'JoinGroup') {
  11013. task.link = '';
  11014. } else if (task.category === 'Discord' && task.type === 'JoinServer') {
  11015. task.link = '';
  11016. }
  11017. }
  11018. if (task.link) {
  11019. await tools_httpRequest({
  11020. 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}`,
  11021. method: 'GET',
  11022. fetch: true,
  11023. headers: {
  11024. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11025. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
  11026. }
  11027. });
  11028. }
  11029. await delay(1e3);
  11030. const postData = {
  11031. taskcategory: task.category,
  11032. taskname: task.type
  11033. };
  11034. if ([ 'YouTube', 'TikTok' ].includes(task.category)) {
  11035. postData.username = '1';
  11036. }
  11037. const {
  11038. result,
  11039. statusText,
  11040. status,
  11041. data
  11042. } = await tools_httpRequest({
  11043. url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/complete`,
  11044. method: 'POST',
  11045. fetch: true,
  11046. headers: {
  11047. authorization: `Bearer ${window.sessionStorage.gw_auth}`,
  11048. 'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]),
  11049. 'content-type': 'application/json'
  11050. },
  11051. dataType: 'json',
  11052. data: JSON.stringify(postData)
  11053. });
  11054. if (result === 'Success') {
  11055. if (data?.status === 200 && data?.response?.completed) {
  11056. logStatus.success();
  11057. continue;
  11058. }
  11059. logStatus.error(`Error:${data?.statusText}(${data?.status})`);
  11060. continue;
  11061. }
  11062. logStatus.error(`${result}:${statusText}(${status})`);
  11063. continue;
  11064. }
  11065. } catch (error) {
  11066. throwError(error, 'GiveawayHopper.verifyTask');
  11067. return false;
  11068. }
  11069. }
  11070. #getGiveawayId() {
  11071. try {
  11072. const giveawayId = window.location.pathname.split('/').at(-1);
  11073. if (giveawayId) {
  11074. this.giveawayId = giveawayId;
  11075. return true;
  11076. }
  11077. scripts_echoLog({
  11078. text: i18n('getFailed', 'GiveawayId')
  11079. });
  11080. return false;
  11081. } catch (error) {
  11082. throwError(error, 'GiveawayHopper.getGiveawayId');
  11083. return false;
  11084. }
  11085. }
  11086. #checkLogin() {
  11087. try {
  11088. if (!globalOptions.other.checkLogin) {
  11089. return true;
  11090. }
  11091. if ($('div.widget-connections-edit:contains("Log in")').length > 0) {
  11092. $('div.widget-connections-edit:contains("Log in") a')[0].click();
  11093. }
  11094. return true;
  11095. } catch (error) {
  11096. throwError(error, 'GiveawayHopper.checkLogin');
  11097. return false;
  11098. }
  11099. }
  11100. async #checkLeftKey() {
  11101. try {
  11102. if (!globalOptions.other.checkLeftKey) {
  11103. return true;
  11104. }
  11105. if ($('p.widget-single-prize span').length > 0 && parseInt($('p.widget-single-prize span').text()?.match(/\d+/)?.[0] || '0', 10) > 0) {
  11106. return true;
  11107. }
  11108. await external_Swal_default().fire({
  11109. icon: 'warning',
  11110. title: i18n('notice'),
  11111. text: i18n('noKeysLeft'),
  11112. confirmButtonText: i18n('confirm'),
  11113. cancelButtonText: i18n('cancel'),
  11114. showCancelButton: true
  11115. }).then(({
  11116. value
  11117. }) => {
  11118. if (value) {
  11119. window.close();
  11120. }
  11121. });
  11122. return true;
  11123. } catch (error) {
  11124. throwError(error, 'GiveawayHopper.checkLeftKey');
  11125. return false;
  11126. }
  11127. }
  11128. }
  11129. const website_GiveawayHopper = GiveawayHopper;
  11130. 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 ];
  11131. const websiteOptions = function(website, options) {
  11132. try {
  11133. let websiteOptionsForm = `<form id="websiteOptionsForm" class="auto-task-form">
  11134. <table class="auto-task-table"><thead><tr><td>${i18n('option')}</td><td>${i18n('value')}</td></tr></thead><tbody>`;
  11135. for (const [ option, value ] of Object.entries(options)) {
  11136. websiteOptionsForm += `<tr><td>${option}</td><td><input class="editOption" type="text" name="${option}" value="${value}"/></td></tr>`;
  11137. }
  11138. websiteOptionsForm += '</tbody></table></form>';
  11139. external_Swal_default().fire({
  11140. title: i18n('websiteOptions'),
  11141. html: websiteOptionsForm,
  11142. showConfirmButton: true,
  11143. confirmButtonText: i18n('save'),
  11144. showCancelButton: true,
  11145. cancelButtonText: i18n('close')
  11146. }).then(({
  11147. isConfirmed
  11148. }) => {
  11149. if (isConfirmed) {
  11150. $('#websiteOptionsForm').serializeArray().map(value => {
  11151. options[value.name] = value.value;
  11152. return value;
  11153. });
  11154. GM_setValue(`${website}Options`, options);
  11155. external_Swal_default().fire({
  11156. title: i18n('changeWebsiteOptionsSuccess'),
  11157. icon: 'success'
  11158. });
  11159. }
  11160. });
  11161. } catch (error) {
  11162. throwError(error, 'websiteOptions');
  11163. }
  11164. };
  11165. const options = websiteOptions;
  11166. const external_keyboardJS_namespaceObject = keyboardJS;
  11167. var external_keyboardJS_default = __webpack_require__.n(external_keyboardJS_namespaceObject);
  11168. const checkUpdate = async (updateLink, auto) => {
  11169. try {
  11170. const checkUrl = `${updateLink}package.json?time=${new Date().getTime()}`;
  11171. const {
  11172. result,
  11173. statusText,
  11174. status,
  11175. data
  11176. } = await tools_httpRequest({
  11177. url: checkUrl,
  11178. responseType: 'json',
  11179. method: 'GET',
  11180. timeout: 3e4
  11181. });
  11182. if (result === 'Success') {
  11183. if (data?.response?.version) {
  11184. return data.response;
  11185. }
  11186. if (!auto) {
  11187. scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${data?.statusText}(${data?.status})]`);
  11188. }
  11189. return false;
  11190. }
  11191. if (!auto) {
  11192. scripts_echoLog({}).error(`${i18n('checkUpdateFailed')}[${result}:${statusText}(${status})]`);
  11193. }
  11194. return false;
  11195. } catch (error) {
  11196. throwError(error, 'checkUpdate');
  11197. return false;
  11198. }
  11199. };
  11200. const hasNewVersion = (currentVersion, remoteVersion) => {
  11201. try {
  11202. const [ currentRealVersion ] = currentVersion.split('-');
  11203. const [ remoteRealVersion, isPreview ] = remoteVersion.split('-');
  11204. if (isPreview && !globalOptions.other.receivePreview) {
  11205. return false;
  11206. }
  11207. const [ currentVersion1, currentVersion2, currentVersion3 ] = currentRealVersion.split('.').map(value => parseInt(value, 10));
  11208. const [ remoteVersion1, remoteVersion2, remoteVersion3 ] = remoteRealVersion.split('.').map(value => parseInt(value, 10));
  11209. if (remoteVersion1 > currentVersion1) {
  11210. return true;
  11211. }
  11212. if (remoteVersion1 < currentVersion1) {
  11213. return false;
  11214. }
  11215. if (remoteVersion2 > currentVersion2) {
  11216. return true;
  11217. }
  11218. if (remoteVersion2 < currentVersion2) {
  11219. return false;
  11220. }
  11221. if (remoteVersion3 > currentVersion3) {
  11222. return true;
  11223. }
  11224. return false;
  11225. } catch (error) {
  11226. throwError(error, 'compareVersion');
  11227. return false;
  11228. }
  11229. };
  11230. const updateChecker = async () => {
  11231. try {
  11232. const currentVersion = GM_info.script.version;
  11233. const updateSource = globalOptions.other.autoUpdateSource.toLowerCase();
  11234. const updateLinks = {
  11235. github: 'https://github.com/HCLonely/auto-task-new/raw/main/',
  11236. jsdelivr: 'https://cdn.jsdelivr.net/gh/HCLonely/auto-task-v4@main/',
  11237. standby: 'https://auto-task-v4.hclonely.com/'
  11238. };
  11239. let version;
  11240. let updateLink = '';
  11241. let packageData;
  11242. if ([ 'github', 'jsdelivr', 'standby' ].includes(updateSource)) {
  11243. updateLink = updateLinks[updateSource];
  11244. packageData = await checkUpdate(updateLink, false);
  11245. } else {
  11246. updateLink = updateLinks.github;
  11247. packageData = await checkUpdate(updateLink, true);
  11248. if (!packageData) {
  11249. updateLink = updateLinks.jsdelivr;
  11250. packageData = await checkUpdate(updateLink, true);
  11251. if (!packageData) {
  11252. updateLink = updateLinks.standby;
  11253. packageData = await checkUpdate(updateLink, true);
  11254. }
  11255. }
  11256. }
  11257. if (packageData) {
  11258. version = packageData.version || currentVersion;
  11259. } else {
  11260. version = currentVersion;
  11261. scripts_echoLog({}).error(i18n('checkUpdateFailed'));
  11262. }
  11263. if (packageData && hasNewVersion(currentVersion, version)) {
  11264. scripts_echoLog({
  11265. html: `<li><font>${i18n('newVersionNotice', version, `${updateLink}dist/${GM_info.script.name}.user.js`)}</font></li>`
  11266. });
  11267. scripts_echoLog({
  11268. html: `<li>${i18n('updateText', version)}</li><ol class="update-text">${packageData.change?.map(change => `<li>${change}</li>`).join('')}<li>${i18n('updateHistory')}</li></ol>`
  11269. });
  11270. }
  11271. } catch (error) {
  11272. throwError(error, 'updateChecker');
  11273. }
  11274. };
  11275. const scripts_updateChecker = updateChecker;
  11276. window.STYLE = GM_addStyle(auto_task.A + GM_getResourceText('style'));
  11277. window.DEBUG = !!globalOptions.other?.debug;
  11278. window.TRACE = !!globalOptions.other?.debug && typeof console.trace === 'function';
  11279. const loadScript = async () => {
  11280. if (window.name === 'ATv4_twitchAuth' && window.location.hostname === 'www.twitch.tv') {
  11281. const authToken = external_Cookies_default().get('auth-token');
  11282. const isLogin = !!external_Cookies_default().get('login');
  11283. if (isLogin) {
  11284. GM_setValue('twitchAuth', {
  11285. authToken: authToken,
  11286. clientVersion: __twilightBuildID,
  11287. clientId: commonOptions?.headers?.['Client-ID'],
  11288. deviceId: commonOptions?.headers?.['Device-ID'],
  11289. clientSessionId: window.localStorage.local_storage_app_session_id.replace(/"/g, '')
  11290. });
  11291. window.close();
  11292. external_Swal_default().fire('', i18n('closePageNotice'));
  11293. } else {
  11294. external_Swal_default().fire('', i18n('needLogin'));
  11295. }
  11296. return;
  11297. }
  11298. if (window.name === 'ATv4_redditAuth' && window.location.hostname === 'www.reddit.com') {
  11299. const betaButton = $('#redesign-beta-optin-btn');
  11300. if (betaButton.length > 0) {
  11301. return betaButton[0].click();
  11302. }
  11303. window.close();
  11304. external_Swal_default().fire('', i18n('closePageNotice'));
  11305. return;
  11306. }
  11307. let website;
  11308. for (const Website of Websites) {
  11309. if (Website.test()) {
  11310. website = new Website();
  11311. break;
  11312. }
  11313. }
  11314. if (!website) {
  11315. console.log('%c%s', 'color:#ff0000', 'Auto-Task[Warning]: 脚本停止加载,当前网站不支持!');
  11316. return;
  11317. }
  11318. if (website?.before) {
  11319. await website?.before();
  11320. }
  11321. $('body').append(`
  11322. <div id="auto-task-info"
  11323. style="display:${globalOptions.other.defaultShowLog ? 'block' : 'none'};
  11324. ${globalOptions.position.logSideX}:${globalOptions.position.logDistance.split(',')[0]}px;
  11325. ${globalOptions.position.logSideY}:${globalOptions.position.logDistance.split(',')[1]}px;">
  11326. </div>
  11327. <div id="auto-task-buttons"
  11328. style="display:${globalOptions.other.defaultShowButton ? 'block' : 'none'};
  11329. ${globalOptions.position.buttonSideX}:${globalOptions.position.buttonDistance.split(',')[0]}px;
  11330. ${globalOptions.position.buttonSideY}:${globalOptions.position.buttonDistance.split(',')[1]}px;">
  11331. </div>
  11332. <div class="show-button-div"
  11333. style="display:${globalOptions.other.defaultShowButton ? 'none' : 'block'};
  11334. ${globalOptions.position.showButtonSideX}:${globalOptions.position.showButtonDistance.split(',')[0]}px;
  11335. ${globalOptions.position.showButtonSideY}:${globalOptions.position.showButtonDistance.split(',')[1]}px;">
  11336. <a class="auto-task-website-btn"
  11337. href="javascript:void(0);"
  11338. target="_self"
  11339. title="${i18n('showButton')}"> </a>
  11340. </div>
  11341. `);
  11342. $('div.show-button-div').on('click', () => {
  11343. $('#auto-task-buttons').show();
  11344. $('div.show-button-div').hide();
  11345. });
  11346. const toggleLog = () => {
  11347. const $this = $('#toggle-log');
  11348. const status = $this.attr('data-status');
  11349. if (status === 'show') {
  11350. $('#auto-task-info').hide();
  11351. $this.attr('data-status', 'hide').text(i18n('showLog'));
  11352. } else {
  11353. $('#auto-task-info').show();
  11354. $this.attr('data-status', 'show').text(i18n('hideLog'));
  11355. }
  11356. };
  11357. external_keyboardJS_default().bind(globalOptions.hotKey.doTaskKey, () => {
  11358. if (website.doTask) {
  11359. website.doTask();
  11360. }
  11361. });
  11362. external_keyboardJS_default().bind(globalOptions.hotKey.undoTaskKey, () => {
  11363. if (website.undoTask) {
  11364. website.undoTask();
  11365. }
  11366. });
  11367. external_keyboardJS_default().bind(globalOptions.hotKey.toggleLogKey, toggleLog);
  11368. if (website?.after) {
  11369. await website?.after();
  11370. }
  11371. if (website?.buttons && $('#auto-task-buttons').children().length === 0) {
  11372. $('#auto-task-buttons').addClass(`${website.name}-buttons`);
  11373. for (const button of website.buttons) {
  11374. if (website[button]) {
  11375. const btnElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">${i18n(button)}</a></p>`);
  11376. btnElement.find('a.auto-task-website-btn').on('click', () => {
  11377. website[button]();
  11378. });
  11379. $('#auto-task-buttons').append(btnElement);
  11380. }
  11381. }
  11382. }
  11383. const hideButtonElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">
  11384. ${i18n('hideButton')}</a></p>`);
  11385. hideButtonElement.find('a.auto-task-website-btn').on('click', () => {
  11386. $('#auto-task-buttons').hide();
  11387. $('div.show-button-div').show();
  11388. });
  11389. 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'}">
  11390. ${globalOptions.other.defaultShowLog ? i18n('hideLog') : i18n('showLog')}</a></p>`);
  11391. toggleLogElement.find('a.auto-task-website-btn').on('click', toggleLog);
  11392. $('#auto-task-buttons').append(hideButtonElement).append(toggleLogElement);
  11393. if (website?.options) {
  11394. GM_registerMenuCommand(i18n('changeWebsiteOptions'), () => {
  11395. options(website.name, website.options);
  11396. });
  11397. }
  11398. if (website.name !== 'Setting') {
  11399. GM_registerMenuCommand(i18n('changeGlobalOptions'), () => {
  11400. changeGlobalOptions('swal');
  11401. });
  11402. GM_registerMenuCommand(i18n('settingPage'), () => {
  11403. GM_openInTab('https://auto-task-v4.hclonely.com/setting.html', {
  11404. active: true
  11405. });
  11406. });
  11407. }
  11408. console.log('%c%s', 'color:#1bbe1a', 'Auto-Task[Load]: 脚本加载完成');
  11409. const [ v1, v2 ] = GM_info.version.split('.');
  11410. if (!(parseInt(v1, 10) >= 5 && parseInt(v2, 10) >= 2)) {
  11411. scripts_echoLog({}).error(i18n('versionNotMatched'));
  11412. }
  11413. if (!GM_getValue('notice')) {
  11414. external_Swal_default().fire({
  11415. title: i18n('swalNotice'),
  11416. icon: 'warning'
  11417. }).then(() => {
  11418. GM_openInTab(i18n('noticeLink'), {
  11419. active: true
  11420. });
  11421. GM_setValue('notice', new Date().getTime());
  11422. });
  11423. scripts_echoLog({
  11424. html: `<li><font class="warning">${i18n('echoNotice', i18n('noticeLink'))}</font></li>`
  11425. }).font?.find('a').on('click', () => {
  11426. GM_setValue('notice', new Date().getTime());
  11427. });
  11428. }
  11429. scripts_updateChecker();
  11430. };
  11431. if (window.location.hostname === 'discord.com') {
  11432. const LocalStorage = window.localStorage;
  11433. if (window.name === 'ATv4_discordAuth') {
  11434. window.localStorage.removeItem = () => true;
  11435. const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, '');
  11436. if (discordAuth && discordAuth.length > 0) {
  11437. GM_setValue('discordAuth', {
  11438. auth: discordAuth
  11439. });
  11440. window.close();
  11441. external_Swal_default().fire('', i18n('closePageNotice'));
  11442. } else {
  11443. external_Swal_default().fire({
  11444. text: i18n('getDiscordAuthFailed'),
  11445. icon: 'error'
  11446. });
  11447. }
  11448. } else {
  11449. const discordAuth = LocalStorage?.getItem('token')?.replace(/^"|"$/g, '');
  11450. if (discordAuth && discordAuth.length > 0) {
  11451. GM_setValue('discordAuth', {
  11452. auth: discordAuth
  11453. });
  11454. }
  11455. }
  11456. } else if (window.location.hostname === 'opquests.com') {
  11457. loadScript();
  11458. } else if ((window.name === 'ATv4_updateStoreAuth' || GM_getValue('ATv4_updateStoreAuth')) && window.location.host === 'store.steampowered.com') {
  11459. $(() => {
  11460. if ($('[data-miniprofile]').length === 0) {
  11461. return;
  11462. }
  11463. const storeSessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
  11464. if (storeSessionID) {
  11465. GM_deleteValue('ATv4_updateStoreAuth');
  11466. GM_setValue('steamStoreAuth', {
  11467. storeSessionID: storeSessionID
  11468. });
  11469. window.close();
  11470. external_Swal_default().fire('', i18n('closePageNotice'));
  11471. } else {
  11472. external_Swal_default().fire({
  11473. title: 'Error: Get "sessionID" failed',
  11474. icon: 'error'
  11475. });
  11476. }
  11477. });
  11478. } else if ((window.name === 'ATv4_updateCommunityAuth' || GM_getValue('ATv4_updateCommunityAuth')) && window.location.host === 'steamcommunity.com') {
  11479. $(() => {
  11480. const steam64Id = document.body.innerHTML.match(/g_steamID = "(.+?)";/)?.[1];
  11481. const communitySessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
  11482. if (steam64Id && communitySessionID) {
  11483. GM_deleteValue('ATv4_updateCommunityAuth');
  11484. GM_setValue('steamCommunityAuth', {
  11485. steam64Id: steam64Id,
  11486. communitySessionID: communitySessionID
  11487. });
  11488. window.close();
  11489. external_Swal_default().fire('', i18n('closePageNotice'));
  11490. } else {
  11491. setTimeout(() => {
  11492. external_Swal_default().fire({
  11493. title: 'Error: Get "sessionID" failed',
  11494. icon: 'error'
  11495. });
  11496. }, 3e3);
  11497. }
  11498. });
  11499. } else {
  11500. if (window.location.hostname === 'key-hub.eu') {
  11501. unsafeWindow.keyhubtracker = 1;
  11502. unsafeWindow.gaData = {};
  11503. }
  11504. $(loadScript);
  11505. }
  11506. }();
  11507. })();