[satology] Auto Claim Multiple Faucets with Monitor UI

Automatic rolls and claims for 50+ crypto faucets/PTC/miners (Freebitco.in BTC, auto promo code for 16 CryptosFaucet, FaucetPay, StormGain, etc)

  1. // ==UserScript==
  2. // @name [satology] Auto Claim Multiple Faucets with Monitor UI
  3. // @description Automatic rolls and claims for 50+ crypto faucets/PTC/miners (Freebitco.in BTC, auto promo code for 16 CryptosFaucet, FaucetPay, StormGain, etc)
  4. // @description Claim free ADA, BNB, BCH, BTC, DASH, DGB, DOGE, ETH, FEY, LINK, LTC, NEO, SHIB, STEAM, TRX, USDC, USDT, XEM, XRP, ZEC, ETC
  5. // @version 3.0.57
  6. // @author satology
  7. // @namespace satology.onrender.com
  8. // @homepage https://criptologico.com/tools/cc
  9. // @noframes
  10.  
  11. // @grant GM_info
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // @grant GM_deleteValue
  15. // @grant GM_xmlhttpRequest
  16. // @grant window.close
  17. // @grant GM_openInTab
  18. // @grant window.onurlchange
  19. // @connect criptologico.com
  20.  
  21.  
  22. // @note IMPORTANT
  23. // @note - To start the script you need to navigate to https://criptologico.com/tools/cc
  24. // @note - Each schedule will open it's own tab to allow multiclaiming
  25.  
  26. // @icon https://www.google.com/s2/favicons?domain=criptologico.com
  27. // @require https://cdnjs.cloudflare.com/ajax/libs/nearest-color/0.4.4/nearestColor.js
  28. // @match https://app.stormgain.com/crypto-miner/
  29. // @match https://app.freecardano.com/*
  30. // @match https://app.freebinancecoin.com/*
  31. // @match https://app.freebitcoin.io/*
  32. // @match https://app.freedash.io/*
  33. // @match https://app.free-doge.com/*
  34. // @match https://app.freeethereum.com/*
  35. // @match https://app.freecryptom.com/*
  36. // @match https://app.free-ltc.com/*
  37. // @match https://app.freeneo.io/*
  38. // @match https://app.freesteam.io/*
  39. // @match https://app.free-tron.com/*
  40. // @match https://app.freeusdcoin.com/*
  41. // @match https://app.freetether.com/*
  42. // @match https://app.freenem.com/*
  43. // @match https://app.freeshibainu.com/*
  44. // @match https://app.coinfaucet.io/*
  45. // @match https://app.freepancake.com/*
  46. // @match https://app.freematic.com/*
  47. // @match https://app.freebittorrent.com/*
  48. // @match https://app.freebfg.com/*
  49. // @match https://freebitco.in/*
  50. // @match https://faucetpay.io/*
  51. // @match https://bigbtc.win/*
  52. // @match https://www.bestchange.com/*
  53. // @match https://faucetok.net/*
  54. // @match https://betfury.io/boxes/all*
  55. // @match https://www.free-doge.io/
  56. // @match https://www.free-doge.io/free/
  57. // @match https://autofaucet.dutchycorp.space/login.php*
  58. // @match https://autofaucet.dutchycorp.space/roll.php*
  59. // @match https://autofaucet.dutchycorp.space/coin_roll.php*
  60. // @match https://express.dutchycorp.space/index.php*
  61. // @match https://express.dutchycorp.space/roll.php*
  62. // @match https://express.dutchycorp.space/coin_roll.php*
  63. // @match https://faucetcrypto.com/dashboard
  64. // @match https://faucetcrypto.com/task/faucet-claim
  65. // @match https://faucetcrypto.com/ptc/*
  66. // @match https://faucetcrypto.com/task/ptc-advertisement/*
  67. // @match https://faupig-bit.online/page/dashboard*
  68. // @match https://faupig-bit.online/account/login/not-logged-in
  69. // @match https://freegridco.in/*
  70. // @match https://james-trussy.com/*
  71. // @match https://www.only1024.com/f*
  72. // @match https://criptologico.com/tools/cc*
  73. // @match https://yescoiner.com/*
  74. // @match https://coindiversity.io/*
  75. // @match https://ltcfaucet.top/*
  76. // @match https://bnbfaucet.top/*
  77. // @match https://dogecoinfaucet.top/*
  78. // @match https://tronfaucet.top/*
  79. // @match https://ethfaucet.top/*
  80. // @match https://freebch.club/*
  81. // @match https://zecfaucet.net/*
  82. // @match https://faucet.monster/*
  83. // @match https://auto-crypto.ml/*
  84. // @match https://claimclicks.com/*
  85. // @match https://cryptoclicks.net/*
  86. // @match https://freeshiba.cf/*
  87. // @match https://auto-crypto.click/*
  88. // ==/UserScript==
  89.  
  90. (function() {
  91. 'use strict';
  92. const localeConfig = {
  93. setToEnglish: true, // will set the faucets to English
  94. stringSearches: {
  95. promoCodeAccepted: 'roll',
  96. promoCodeUsed: 'already used',
  97. promoCodeInvalid: ['not found', 'only alphanumeric'],
  98. promoCodeExpired: ['ended']
  99. }
  100. };
  101.  
  102. const STATUS = {
  103. INITIALIZING: 0,
  104. IDLE: 1,
  105. CLAIMING: 2
  106. };
  107.  
  108. const K = Object.freeze({
  109. WebType: {
  110. UNDEFINED: 0,
  111. CRYPTOSFAUCETS: 1,
  112. STORMGAIN: 2,
  113. FREEBITCOIN: 3,
  114. FAUCETPAY: 4,
  115. FREELITECOIN: 5,
  116. FREEETHEREUMIO: 6,
  117. BAGIKERAN: 7,
  118. OKFAUCET: 8,
  119. BIGBTC: 9,
  120. BESTCHANGE: 10,
  121. KINGBIZ: 11,
  122. BFBOX: 13,
  123. FREEDOGEIO: 14,
  124. DUTCHYROLL: 15,
  125. FCRYPTO: 16,
  126. CPU: 17,
  127. CBG: 18,
  128. FPB: 19,
  129. G8: 20,
  130. FREEGRC: 21,
  131. HELI: 22,
  132. VIE: 23,
  133. O24: 24,
  134. YCOIN: 25,
  135. CDIVERSITY: 26,
  136. BSCADS: 27,
  137. CTOP: 28,
  138. AUTOCML: 29,
  139. CCLICKS: 30
  140. },
  141. CF: {
  142. UrlType: {
  143. HOME: 0,
  144. FREE: 1,
  145. CONTACTTWITTER: 2,
  146. PROMOTION: 3,
  147. STATS: 4,
  148. SETTINGS: 5,
  149. FREEROLLS: 6,
  150. LOGIN: 7,
  151. GAMES: 8,
  152. IGNORE: 99
  153. },
  154. PromoStatus: {
  155. NOCODE: 0,
  156. PENDING: 1,
  157. ACCEPTED: 2,
  158. USEDBEFORE: 3,
  159. INVALID: 4,
  160. UNKNOWNERROR: 5,
  161. EXPIRED: 6
  162. },
  163. },
  164. RandomInteractionLevel: {
  165. NONE: 0,
  166. LOW: 1,
  167. MEDIUM: 2,
  168. HIGH: 3
  169. },
  170. Integers: {
  171. HS_26_IN_MILLISECONDS: 93600000, //Using 26 hs instead of 24hs
  172. HS_2_IN_MILLISECONDS: 7200000 //and 2hs gap retry when code is flagged as USEDBEFORE
  173. },
  174. WalletType: {
  175. FP_USERNAME: 99,
  176. FP_MAIL: 100,
  177. FP_BTC: 101,
  178. FP_BNB: 102,
  179. FP_BCH: 103,
  180. FP_DASH: 104,
  181. FP_DGB: 105,
  182. FP_DOGE: 106,
  183. FP_ETH: 107,
  184. FP_FEY: 108,
  185. FP_LTC: 109,
  186. FP_TRX: 110,
  187. FP_USDT: 111,
  188. FP_ZEC: 112,
  189. FP_SOL: 113,
  190. FP_MATIC: 114,
  191. FP_XRP: 115,
  192. FP_ADA: 116,
  193. EC: 200,
  194. BTC: 1,
  195. LTC: 2
  196. },
  197. ErrorType: {
  198. ERROR: 0,
  199. TIMEOUT: 1,
  200. NEED_TO_LOGIN: 2,
  201. ROLL_ERROR: 3,
  202. CLICK_ROLL_ERROR: 4,
  203. LOGIN_ERROR: 5,
  204. CLAIM_ERROR: 6,
  205. ADDRESS_ERROR: 7,
  206. MIN_WITHDRAW_ERROR: 8,
  207. IP_BAN: 9,
  208. IP_RESTRICTED: 10,
  209. IP_ERROR: 11,
  210. FORCE_CLOSED: 12,
  211. NO_FUNDS: 13,
  212. VERIFY_EMAIL: 14,
  213. NO_ADDRESS: 15,
  214. FAUCET_EMPTY: 16
  215. },
  216. CMC: {
  217. MULT: '-1',
  218. BTC: '1',
  219. LTC: '2',
  220. XRP: '52',
  221. DOGE: '74',
  222. DGB: '109',
  223. DASH: '131',
  224. USDT: '825',
  225. XEM: '873',
  226. ETH: '1027',
  227. STEEM: '1230',
  228. NEO: '1376',
  229. ZEC: '1437',
  230. BCH: '1831',
  231. BNB: '1839',
  232. TRX: '1958',
  233. LINK: '1975',
  234. ADA: '2010',
  235. USDC: '3408',
  236. SOL: '5426',
  237. SHIB: '5994',
  238. FEY: '10361',
  239. BFG: '11038',
  240. CAKE: '7186',
  241. GRC: '833',
  242. MATIC: '3890',
  243. BABY: '10334',
  244. BTT: '16086',
  245. BSW: '10746',
  246. },
  247. LOCATION: {
  248. UNKNOWN: 0,
  249. MANAGER: 1,
  250. SITE: 2
  251. }
  252. });
  253.  
  254. let persistence, shared, manager, ui, CFPromotions, interactions, CFHistory, SiteProcessor, eventer;
  255. let uiRenderer;
  256.  
  257. Element.prototype.isVisible = function() {
  258. return !!(this.offsetWidth||this.offsetHeight||this.getClientRects().length);
  259. };
  260. Element.prototype.isUserFriendly = function(selector) {
  261. let e = selector ? this.querySelector(selector) : this;
  262. return e && e.isVisible() ? e : null;
  263. };
  264. Document.prototype.isUserFriendly = Element.prototype.isUserFriendly;
  265.  
  266. Number.prototype.toDate = function() {
  267. return new Date(this);
  268. };
  269. Number.prototype.msToCountdown = function() {
  270. const remainingSeconds = Math.ceil(this / 1000);
  271. const hours = Math.floor(remainingSeconds / 3600).toString().padStart(2, '0');
  272. const minutes = Math.floor((remainingSeconds % 3600) / 60).toString().padStart(2, '0');
  273. const seconds = (remainingSeconds % 60).toString().padStart(2, '0');
  274. return `${hours}:${minutes}:${seconds}`;
  275. };
  276.  
  277. String.prototype.clean = function() {
  278. let output = "";
  279. for (let i = 0; i < this.length; i++) {
  280. if (this.charCodeAt(i) <= 127) {
  281. output += this.charAt(i);
  282. }
  283. }
  284. return output;
  285. };
  286. String.prototype.formatUnicorn = function () {
  287. "use strict";
  288. var str = this.toString();
  289. if (arguments.length) {
  290. var t = typeof arguments[0];
  291. var key;
  292. var args = ("string" === t || "number" === t) ?
  293. Array.prototype.slice.call(arguments)
  294. : arguments[0];
  295.  
  296. for (key in args) {
  297. str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
  298. }
  299. }
  300.  
  301. return str;
  302. };
  303.  
  304. Array.prototype.shuffle = function () {
  305. let currentIndex = this.length, temporaryValue, randomIndex;
  306.  
  307. while (0 !== currentIndex) {
  308. randomIndex = Math.floor(Math.random() * currentIndex);
  309. currentIndex -= 1;
  310. temporaryValue = this[currentIndex];
  311. this[currentIndex] = this[randomIndex];
  312. this[randomIndex] = temporaryValue;
  313. }
  314.  
  315. return this;
  316. };
  317.  
  318. let helpers = {
  319. typer: function(inputElm, value) {
  320. let lastValue = inputElm.value;
  321. inputElm.value = value;
  322. let event = new Event('input', { bubbles: true });
  323. event.simulated = true;
  324. let tracker = inputElm._valueTracker;
  325. if (tracker) {
  326. tracker.setValue(lastValue);
  327. }
  328. inputElm.dispatchEvent(event);
  329. },
  330.  
  331. hasValue: function (val) {
  332. return val !== null && val !== undefined;
  333. },
  334. getTdPrintableTime: function (date = new Date()) {
  335. if (date != null) {
  336. return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
  337. }
  338. return '';
  339. },
  340. getPrintableTime: function (date = new Date()) {
  341. if (date == null) {
  342. return '';
  343. }
  344. return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2);
  345. },
  346. getPrintableDateTime: function (date) {
  347. if (date != null) {
  348. return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
  349. } else {
  350. return '';
  351. }
  352. },
  353. getEnumText: function (enm, value) {
  354. return Object.keys(enm).find(key => enm[key] === value) || '_ERR';
  355. },
  356. randomMs: function (a, b){
  357. return a + (b - a) * Math.random();
  358. },
  359. addMinutes: function(mins, date = new Date()) {
  360. return date.setMinutes(date.getMinutes() + +mins);
  361. },
  362. addSeconds: function(secs, date = new Date()) {
  363. return date.setSeconds(date.getSeconds() + +secs);
  364. },
  365. randomHexColor: function() {
  366. const hexChars = '0123456789abcdef';
  367. let color = '';
  368. for (let i = 0; i < 6; i++) {
  369. color += hexChars[Math.floor(Math.random() * hexChars.length)];
  370. }
  371. return color;
  372. },
  373. randomString: function(length) {
  374. let str = '';
  375. const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  376. const charactersLength = characters.length;
  377.  
  378. for (let i = 0; i < length; i++) {
  379. str += characters.charAt(Math.floor(Math.random() * charactersLength));
  380. }
  381.  
  382. return str;
  383. },
  384. randomInt: function(min, max) {
  385. min = Math.ceil(min);
  386. max = Math.floor(max);
  387. return Math.floor(Math.random() * (max - min + 1)) + min;
  388. },
  389. addMs: function(ms, date = new Date()) {
  390. return date.setMilliseconds(date.getMilliseconds() + ms);
  391. },
  392. getRandomMs: function(minute, rangeDiffInPercentage) { // Now will be a random value between minute and minute + rangeDiffPercentage%; Example if minute = 30 and rangeDiffPercentage = 5 => random in the range [30, 31.5]
  393. let msMin = minute * 60 * 1000;
  394. let msMax = msMin + rangeDiffInPercentage/100 * msMin;
  395. return helpers.randomMs(msMin, msMax);
  396. },
  397. hsToMs: function(hours) {
  398. return hours * 60 * 60 * 1000;
  399. },
  400. minToMs: function(min) {
  401. return min * 60 * 1000;
  402. },
  403. getEmojiForPromoStatus: function(promoStatus) {
  404. switch (promoStatus) {
  405. case K.CF.PromoStatus.NOCODE:
  406. return '⚪';
  407. case K.CF.PromoStatus.PENDING:
  408. return '⏳';
  409. case K.CF.PromoStatus.ACCEPTED:
  410. return '✔️';
  411. case K.CF.PromoStatus.USEDBEFORE:
  412. return '🕙';
  413. case K.CF.PromoStatus.INVALID:
  414. return '❌';
  415. case K.CF.PromoStatus.EXPIRED:
  416. return '📅';
  417. case K.CF.PromoStatus.UNKNOWNERROR:
  418. return '❗';
  419. }
  420. },
  421. getHost: function(url, withHttps = false) {
  422. if (url.includes('//')) {
  423. url = url.split('//')[1];
  424. }
  425. url = url.split('/')[0];
  426. return withHttps ? ('https://' + url) : url;
  427. },
  428. cf: {
  429. getUrlType: function(url) {
  430. if (url.endsWith('/free-rolls')) {
  431. return K.CF.UrlType.FREEROLLS;
  432. }
  433. if (url.split('?')[0].endsWith('/free')) {
  434. return K.CF.UrlType.FREE;
  435. }
  436. if (url.includes('/promotion/')) {
  437. return K.CF.UrlType.PROMOTION;
  438. }
  439. if (url.endsWith('/contact-twitter')) {
  440. return K.CF.UrlType.CONTACTTWITTER;
  441. }
  442. if (url.endsWith('/settings')) {
  443. return K.CF.UrlType.SETTINGS;
  444. }
  445. if (url.endsWith('/stats')) {
  446. return K.CF.UrlType.STATS;
  447. }
  448. if (url.endsWith('/games')) {
  449. return K.CF.UrlType.GAMES;
  450. }
  451. if (url.endsWith('/')) {
  452. url = url.slice(0, -1);
  453. if (url == helpers.getHost(url, true)) {
  454. return K.CF.UrlType.HOME;
  455. }
  456. }
  457. if (url.endsWith('/login')) {
  458. return K.CF.UrlType.LOGIN;
  459. }
  460.  
  461. return K.CF.UrlType.IGNORE;
  462. }
  463. },
  464. triggerMouseEvent: function (elm, eventType) {
  465. let clickEvent = document.createEvent('MouseEvents');
  466. clickEvent.initEvent (eventType, true, true);
  467. elm.dispatchEvent (clickEvent);
  468. },
  469. alternativeClick: function (elm) {
  470. helpers.triggerMouseEvent (elm, "mouseover");
  471. helpers.triggerMouseEvent (elm, "mousedown");
  472. helpers.triggerMouseEvent (elm, "mouseup");
  473. helpers.triggerMouseEvent (elm, "click");
  474. },
  475. textQuerySelector: function (selector, text) {
  476. let all = [...document.querySelectorAll(selector)].filter(x => x.innerText.toLowerCase() == text.toLowerCase())
  477. if (all.length == 1) {
  478. return all[0];
  479. }
  480. return undefined;
  481. }
  482. }
  483.  
  484. class Persistence {
  485. constructor(prefix = 'autoWeb_') {
  486. this.prefix = prefix;
  487. }
  488. save(key, value, parseIt = false) {
  489. GM_setValue(this.prefix + key, parseIt ? JSON.stringify(value) : value);
  490. }
  491. load(key, parseIt = false) {
  492. let value = GM_getValue(this.prefix + key);
  493. if(value && parseIt) {
  494. value = JSON.parse(value);
  495. }
  496. return value;
  497.  
  498. }
  499. }
  500.  
  501. let objectGenerator = {
  502. createShared: function() {
  503. let config = {};
  504. function initializeConfig() {
  505. config = {
  506. 'devlog.enabled': false,
  507. 'devlog.maxLines': 200,
  508. 'defaults.extraInterval': true,
  509. 'defaults.timeout': 4,
  510. 'defaults.postponeMinutes': 65,
  511. 'defaults.postponeMinutes.min': 65,
  512. 'defaults.postponeMinutes.max': 65,
  513. 'defaults.workInBackground': true,
  514. 'defaults.nextRun.useCountdown': true,
  515. 'defaults.nextRun': 60,
  516. 'defaults.nextRun.min': 60,
  517. 'defaults.nextRun.max': 60,
  518. 'defaults.sleepMode': false,
  519. 'defaults.sleepMode.min': "00:00",
  520. 'defaults.sleepMode.max': "01:00",
  521. 'cf.tryGetCodes': false,
  522. 'cf.usePromoCodes': true,
  523. 'cf.rollOnce': false,
  524. 'cf.autologin': false,
  525. 'cf.credentials.mode': 1,
  526. 'cf.credentials.email': 'YOUR@EMAIL.com',
  527. 'cf.credentials.password': 'YOURPASSWORD',
  528. 'cf.sleepHoursIfIpBan': 8,
  529. 'fp.maxTimeInMinutes': 15,
  530. 'fp.randomPtcOrder': true,
  531. 'dutchy.useBoosted': false,
  532. 'bk.withdrawMode': "0",
  533. 'bk.hoursBetweenWithdraws': 4,
  534. 'bk.sleepMinutesIfIpBan': 75,
  535. 'bestchange.address': '101',
  536. 'ui.runtime': 0,
  537. 'bigbtc.postponeMinutes': '0',
  538. 'jtfey.credentials.mode': 2,
  539. 'jtfey.credentials.username': 'YOUR_USERNAME',
  540. 'jtfey.credentials.password': 'YOURPASSWORD',
  541. 'ycoin.credentials.mode': 2,
  542. 'ycoin.credentials.username': 'YOUR_ACCOUNT_NUMBER',
  543. 'ycoin.credentials.password': 'YOURPASSWORD',
  544. 'bkclass.coin': 'LTC',
  545. 'bkclass.bcoin': 'LTC',
  546. 'migrations': [
  547. {version: '00200799', applied: false} // migration to change pcodes status from error to usable due to ui changes
  548. ]
  549. };
  550.  
  551. let storedData = persistence.load('config', true);
  552. if(storedData) {
  553. for (const prop in config) {
  554. if(storedData.hasOwnProperty(prop)) {
  555. config[prop] = storedData[prop];
  556. }
  557. }
  558. }
  559.  
  560. config.version = GM_info.script.version;
  561. };
  562. function getConfig() {
  563. return config;
  564. };
  565. function updateConfig(items) {
  566. items.forEach( function (item) {
  567. config[item.prop] = item.value;
  568. });
  569. persistence.save('config', config, true);
  570. };
  571. function migrationApplied(migrationVersion) {
  572. try {
  573. let mig = config.migrations.find(x => x.version == migrationVersion);
  574. mig.applied = true;
  575. persistence.save('config', config, true);
  576. } catch (err) {
  577. console.warn('Error saving migration as applied');
  578. console.error(err);
  579. }
  580. };
  581. function devlog(msg, elapsed = false, reset = false) {
  582. if(!config['devlog.enabled']) {
  583. return;
  584. }
  585.  
  586. let log;
  587. if(reset) {
  588. log = [`${helpers.getPrintableTime()}|Log cleared`];
  589. } else {
  590. log = persistence.load('devlog', true);
  591. log = log ?? [];
  592. }
  593.  
  594. if(msg) {
  595. msg = scheduleUuid ? `[${scheduleUuid}] ${msg}` : msg;
  596. let previous;
  597. try {
  598. previous = log[log.length - 1].split('|')[1];
  599. } catch {}
  600. if(elapsed && (previous == msg)) {
  601. log[log.length - 1] = `${helpers.getPrintableTime()}|${msg}|[Elapsed time: ${elapsed} seconds]`;
  602. } else {
  603. log.push(`${helpers.getPrintableTime()}|${msg}`);
  604. }
  605. }
  606.  
  607. if(log.length > 200) {
  608. log.splice(0, log.length - 200);
  609. }
  610.  
  611. persistence.save('devlog', log, true);
  612. };
  613. function getDevLog() {
  614. let log;
  615. log = persistence.load('devlog', true);
  616. if(log) {
  617. return log;
  618. }
  619. };
  620.  
  621. function getRunningSites() {
  622. let ret = [];
  623. loadFlowControl();
  624. if(!runningSites || runningSites == {}) {
  625. return ret;
  626. }
  627. for (const sch in runningSites) {
  628. if (runningSites[sch].host) {
  629. ret.push(runningSites[sch].host);
  630. }
  631. }
  632. return ret;
  633. }
  634.  
  635. let runningSites = {}
  636. let scheduleUuid = null;
  637. function isOpenedByManager() {
  638. loadFlowControl();
  639. if(!runningSites || runningSites == {}) {
  640. return false;
  641. }
  642. let uuid = null;
  643. for (const sch in runningSites) {
  644. if ( (runningSites[sch].host && runningSites[sch].host == window.location.host) ||
  645. (runningSites[sch].params && runningSites[sch].params.trackUrl && window.location.href.includes(runningSites[sch].params.trackUrl))
  646. ) {
  647. uuid = sch;
  648. break;
  649. }
  650. }
  651. if (!uuid) {
  652. return false;
  653. }
  654.  
  655. if (runningSites[uuid].runStatus == 'COMPLETED') {
  656. return false;
  657. } else {
  658. scheduleUuid = uuid;
  659. return true;
  660. }
  661. };
  662. function loadFlowControl() {
  663. runningSites = persistence.load('runningSites', true) || {};
  664. };
  665. function setFlowControl(schedule, id, url, webType, params = null) {
  666. runningSites[schedule] = {
  667. id: id,
  668. changedAt: Date.now(),
  669. url: url,
  670. host: url.host,
  671. type: webType,
  672. opened: false,
  673. error: false,
  674. result: {}
  675. };
  676.  
  677. if(params) {
  678. runningSites[schedule].params = params;
  679. } else {
  680. runningSites[schedule].params = {};
  681. }
  682. saveFlowControl(schedule);
  683. };
  684. function isCompleted(expectedId) {
  685. loadFlowControl();
  686. for(const sch in runningSites) {
  687. if (runningSites[sch].id == expectedId) {
  688. if (runningSites[sch].runStatus == 'COMPLETED') {
  689. return true;
  690. } else {
  691. return false;
  692. }
  693. }
  694. }
  695. return false;
  696. };
  697. function isIncompleted(expectedId) {
  698. loadFlowControl();
  699. for(const sch in runningSites) {
  700. if (runningSites[sch].id == expectedId) {
  701. if (runningSites[sch].runStatus == 'WORKING') {
  702. return true;
  703. } else {
  704. return false;
  705. }
  706. }
  707. }
  708. return false;
  709. };
  710. function hasErrors(expectedId) {
  711. for(const sch in runningSites) {
  712. if (runningSites[sch].id == expectedId && runningSites[sch].error) {
  713. return true;
  714. }
  715. }
  716. return false;
  717. };
  718. function getResult(schedule) {
  719. if (schedule) {
  720. return runningSites.hasOwnProperty(schedule) ? runningSites[schedule].result : {};
  721. }
  722. return runningSites.hasOwnProperty(scheduleUuid) ? runningSites[scheduleUuid].result : {};
  723. };
  724. function getCurrent(schedule) {
  725. if (schedule) {
  726. return runningSites.hasOwnProperty(schedule) ? runningSites[schedule] : {};
  727. }
  728. return runningSites.hasOwnProperty(scheduleUuid) ? runningSites[scheduleUuid] : {};
  729. };
  730. function saveAndclose(runDetails, delay = 0) {
  731. markAsVisited(runDetails);
  732. if(delay) {
  733. setTimeout(window.close, delay);
  734. } else {
  735. setTimeout(window.close, 1000);
  736. }
  737. };
  738. function purgeFlowControlSchedules(validSchedules) {
  739. loadFlowControl();
  740. let deletables = [];
  741. for (var sch in runningSites) {
  742. if (!validSchedules.includes(sch)) {
  743. deletables.push(sch);
  744. }
  745. }
  746. deletables.forEach(x => {
  747. delete runningSites[sch];
  748. });
  749. persistence.save('runningSites', runningSites, true);
  750. };
  751. function saveFlowControl(schedule) {
  752. schedule = schedule ? schedule : scheduleUuid;
  753. if (!schedule) {
  754. persistence.save('runningSites', runningSites, true);
  755. return;
  756. }
  757. let tempFlow = persistence.load('runningSites', true);
  758. tempFlow[schedule] = runningSites[schedule];
  759. persistence.save('runningSites', tempFlow, true);
  760. };
  761. function markAsVisited(runDetails, runStatus = 'COMPLETED') {
  762. if (!scheduleUuid) {
  763. return;
  764. }
  765. runningSites[scheduleUuid].opened = true;
  766. runningSites[scheduleUuid].runStatus = runStatus;
  767. runningSites[scheduleUuid].result = runDetails ? runDetails : runningSites[scheduleUuid].result;
  768.  
  769. saveFlowControl(scheduleUuid);
  770. };
  771. function addError(errorType, errorMessage, schedule) {
  772. if (schedule) {
  773. runningSites[schedule].error = true;
  774. runningSites[schedule].result.errorType = errorType;
  775. runningSites[schedule].result.errorMessage = errorMessage;
  776. } else {
  777. runningSites[scheduleUuid].error = true;
  778. runningSites[scheduleUuid].result.errorType = errorType;
  779. runningSites[scheduleUuid].result.errorMessage = errorMessage;
  780. }
  781.  
  782. saveFlowControl(schedule ? schedule : scheduleUuid);
  783. };
  784. function closeWithError(errorType, errorMessage) {
  785. addError(errorType, errorMessage);
  786. window.close();
  787. setInterval(() => {
  788. window.close();
  789. }, 15000);
  790. };
  791. function clearFlowControl(schedule) {
  792. if (schedule && schedule != 'all') {
  793. runningSites[schedule] = {};
  794. saveFlowControl(schedule);
  795. } else if (schedule == 'all') {
  796. runningSites = {};
  797. persistence.save('runningSites', {}, true);
  798. }
  799. };
  800. function clearRetries() {
  801. loadFlowControl();
  802. runningSites[scheduleUuid].retrying = false;
  803. saveFlowControl(scheduleUuid);
  804. return false;
  805. };
  806. function isRetrying() {
  807. if(runningSites[scheduleUuid].retrying) {
  808. return true;
  809. }
  810. runningSites[scheduleUuid].retrying = true;
  811. saveFlowControl(scheduleUuid);
  812. return false;
  813. };
  814. function setProp(key, val) {
  815. runningSites[scheduleUuid][key] = val;
  816. saveFlowControl(scheduleUuid);
  817. };
  818. function getProp(key) {
  819. return runningSites[scheduleUuid][key];
  820. };
  821. function getParam(key) {
  822. try {
  823. } catch {}
  824. return runningSites[scheduleUuid].params[key];
  825. };
  826. initializeConfig();
  827. return {
  828. devlog: devlog,
  829. getDevLog: getDevLog,
  830. setFlowControl: setFlowControl,
  831. isCompleted: isCompleted,
  832. isIncompleted: isIncompleted,
  833. isOpenedByManager: isOpenedByManager,
  834. saveFlowControl: saveFlowControl,
  835. getCurrent: getCurrent,
  836. getResult: getResult,
  837. addError: addError,
  838. closeWindow: saveAndclose,
  839. closeWithError: closeWithError,
  840. updateWithoutClosing: markAsVisited,
  841. hasErrors: hasErrors,
  842. clearFlowControl: clearFlowControl,
  843. getConfig: getConfig,
  844. updateConfig: updateConfig,
  845. clearRetries: clearRetries,
  846. isRetrying: isRetrying,
  847. setProp: setProp,
  848. getProp: getProp,
  849. getParam: getParam,
  850. migrationApplied: migrationApplied,
  851. purgeFlowControlSchedules: purgeFlowControlSchedules,
  852. getRunningSites: getRunningSites
  853. };
  854. },
  855. createCFPromotions: function() {
  856. let codes = [];
  857.  
  858. function PromotionCode(id, code, repeatDaily = false, expiration = null, isRemoved = false) {
  859. this.id = id;
  860. this.code = code;
  861. this.added = new Date();
  862. this.statusPerFaucet = [];
  863. this.repeatDaily = repeatDaily;
  864. this.lastExecTimeStamp = null;
  865. this['expiration' + 'Date'] = expiration;
  866. this.isRemoved = isRemoved;
  867. };
  868.  
  869. function getFaucetStatusInPromo(promo, faucetId) {
  870. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  871. if (faucet.status && promo.repeatDaily) {
  872. if((faucet.status == K.CF.PromoStatus.ACCEPTED && (Date.now() - faucet.execTimeStamp.getTime()) > K.Integers.HS_26_IN_MILLISECONDS)
  873. || (faucet.status == K.CF.PromoStatus.USEDBEFORE && (Date.now() - faucet.execTimeStamp.getTime()) > K.Integers.HS_2_IN_MILLISECONDS)) {
  874. faucet.status = K.CF.PromoStatus.PENDING;
  875. }
  876. }
  877. return faucet.status ?? K.CF.PromoStatus.NOCODE;
  878. };
  879.  
  880. function addNew(code, repeatDaily = false, expiration = null) {
  881. let found = codes.find(x => x.code == code);
  882. if (found) {
  883. found.repeatDaily = repeatDaily;
  884. found['expiration' + 'Date'] = expiration;
  885. found.isRemoved = false;
  886. } else {
  887. found = new PromotionCode(codes.length, code, repeatDaily, expiration);
  888. codes.push(found);
  889. }
  890.  
  891. found.statusPerFaucet = manager.getFaucetsForPromotion().map(x => {
  892. return {
  893. id: x.id,
  894. };});
  895. found.statusPerFaucet.forEach(function (element, idx, arr) {
  896. arr[idx].status = K.CF.PromoStatus.PENDING;
  897. arr[idx].execTimeStamp = null;
  898. });
  899.  
  900. save();
  901. };
  902.  
  903. function includeNewCodes(newCodes) {
  904. for(let i=0; i<newCodes.length; i++) {
  905. let item = newCodes[i];
  906. let exists = codes.find(x => x.code.toLowerCase() == item.code.toLowerCase());
  907. if (!exists) {
  908. addNew(item.code, !item.oneTimeOnly, item['expiration' + 'Date']);
  909. } else {
  910. }
  911. }
  912. };
  913.  
  914. function getAll() {
  915. return codes.filter(x => !x.isRemoved);
  916. };
  917.  
  918. function updateFaucetForCode(code, faucetId, newStatus) {
  919. let promo = codes.find(x => x.code == code);
  920. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  921. if(faucet) {
  922. faucet.status = newStatus;
  923. faucet.execTimeStamp = new Date();
  924. promo.lastExecTimeStamp = faucet.execTimeStamp;
  925. }
  926. save();
  927. };
  928.  
  929. function hasPromoAvailable(faucetId) {
  930. let resp = [];
  931. codes.forEach(function (promotion, idx, arr) {
  932. let status = getFaucetStatusInPromo(promotion, faucetId);
  933. if (status == K.CF.PromoStatus.PENDING && !promotion.isRemoved) {
  934. resp.push(promotion.code);
  935. }
  936. });
  937. if (resp.length > 0) {
  938. return resp;
  939. } else {
  940. return false;
  941. }
  942. };
  943.  
  944. function save() {
  945. persistence.save('CFPromotions', codes, true);
  946. };
  947.  
  948. function load(data) {
  949. codes = data;
  950. save();
  951. };
  952.  
  953. function removeAll() {
  954. codes.forEach(x => x.isRemoved = true);
  955. codes = codes.filter(x => x['expiration' + 'Date'] && Date.parse(x['expiration' + 'Date']) > Date.now());
  956. save();
  957. };
  958.  
  959. function remove(id, code) {
  960. let idx = codes.findIndex(x => x.id == id && x.code == code);
  961. if(idx != -1) {
  962. codes[idx].isRemoved = true;
  963. save();
  964. }
  965.  
  966. return idx;
  967. };
  968.  
  969. return {
  970. addNew: addNew,
  971. removeAll: removeAll,
  972. remove: remove,
  973. getAll: getAll,
  974. load: load,
  975. updateFaucetForCode: updateFaucetForCode,
  976. hasPromoAvailable: hasPromoAvailable,
  977. includeNewCodes: includeNewCodes
  978. }
  979. },
  980. createInteractions: function(){
  981. let randomInteractionLevel = K.RandomInteractionLevel.MEDIUM;
  982. let maxActions = 0;
  983. let performedActions = -1;
  984. let selectableElements;
  985. let actions = {
  986. available: [
  987. function() {
  988. let element = interactions.selectableElements[helpers.randomInt(0, interactions.selectableElements.length - 1)];
  989.  
  990. try {
  991. if (document.body.createTextRange) {
  992. const range = document.body.createTextRange();
  993. range.moveToElementText(element);
  994. range.select();
  995. } else if (window.getSelection) {
  996. const selection = window.getSelection();
  997. const range = document.createRange();
  998. range.selectNodeContents(element);
  999. selection.removeAllRanges();
  1000. selection.addRange(range);
  1001. }
  1002. } catch (err) { }
  1003.  
  1004. interactions.addPerformed();
  1005. }
  1006. ]
  1007. };
  1008.  
  1009. function start(selectableElements) {
  1010. performedActions = 0;
  1011. switch(randomInteractionLevel) {
  1012. case K.RandomInteractionLevel.NONE:
  1013. maxActions = 0;
  1014. break;
  1015. case K.RandomInteractionLevel.LOW:
  1016. maxActions = helpers.randomInt(2, 4);
  1017. break;
  1018. case K.RandomInteractionLevel.MEDIUM:
  1019. maxActions = helpers.randomInt(5, 8);
  1020. break;
  1021. case K.RandomInteractionLevel.HIGH:
  1022. maxActions = helpers.randomInt(12, 16);
  1023. break;
  1024. }
  1025. interactions.selectableElements = selectableElements;
  1026. performActions();
  1027. }
  1028.  
  1029. function performActions() {
  1030. if(performedActions >= maxActions) {
  1031. return;
  1032. }
  1033. let delay = 0;
  1034. for(let i = 0; i < maxActions; i++) {
  1035. delay += helpers.randomMs(350, 1500);
  1036. setTimeout(actions.available[helpers.randomInt(0, actions.available.length - 1)], delay);
  1037. }
  1038. }
  1039.  
  1040. function addPerformed() {
  1041. performedActions++;
  1042. }
  1043. function completed() {
  1044. return (performedActions >= maxActions);
  1045. }
  1046.  
  1047. return {
  1048. start: start,
  1049. completed: completed,
  1050. addPerformed: addPerformed,
  1051. selectableElements: selectableElements
  1052. };
  1053. },
  1054. createCFProcessor: function() {
  1055. const NavigationProcess = {
  1056. ROLLING: 1,
  1057. PROCESSING_PROMOTION: 2,
  1058. LOGIN: 3
  1059. };
  1060. let navigationProcess;
  1061. let countdown;
  1062. let rollButton;
  1063. let promotionTag;
  1064. let timeWaiting= 0;
  1065. let loopingForErrors = false;
  1066. let tempRollNumber = null;
  1067. let firstRollCompleted = false;
  1068.  
  1069. function init() {
  1070. let urlType = helpers.cf.getUrlType(window.location.href);
  1071. console.log('URL TYPE:', urlType)
  1072. switch(urlType) {
  1073. case K.CF.UrlType.FREE:
  1074. if(localeConfig.setToEnglish) {
  1075. document.querySelector('.locale-changer .p-dropdown-trigger')?.click();
  1076. setTimeout(() => {
  1077. document.querySelector("#pv_id_3_3")?.click();
  1078. }, 1000);
  1079. }
  1080. addJS_Node (null, null, overrideSelectNativeJS_Functions);
  1081. interactions = objectGenerator.createInteractions();
  1082. run();
  1083. break;
  1084.  
  1085. case K.CF.UrlType.PROMOTION:
  1086. interactions = objectGenerator.createInteractions();
  1087. runPromotion();
  1088. break;
  1089. case K.CF.UrlType.GAMES:
  1090. location.replace('/free');
  1091. break;
  1092. case K.CF.UrlType.HOME:
  1093. case K.CF.UrlType.LOGIN:
  1094. if (shared.getConfig()['cf.autologin']) {
  1095. addJS_Node (null, null, overrideSelectNativeJS_Functions);
  1096. doLogin();
  1097. } else {
  1098. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
  1099. }
  1100. break;
  1101.  
  1102. case K.CF.UrlType.CONTACTTWITTER:
  1103. shared.closeWithError(K.ErrorType.IP_BAN, '');
  1104. break;
  1105. default:
  1106. break;
  1107. }
  1108. return;
  1109. }
  1110.  
  1111. function run() {
  1112. navigationProcess = NavigationProcess.ROLLING;
  1113. setInterval(tryClosePopup, helpers.randomMs(3000, 6000));
  1114. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  1115. };
  1116.  
  1117. function doLogin() {
  1118. navigationProcess = NavigationProcess.LOGIN;
  1119.  
  1120. setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
  1121. };
  1122.  
  1123. function isFullyLoaded() { //Waits 55 seconds max
  1124. if(document.readyState == 'complete' || timeWaiting == -1) {
  1125. timeWaiting = 0;
  1126. if (firstRollCompleted) {
  1127. roll();
  1128. } else {
  1129. interact();
  1130. }
  1131. } else {
  1132. timeWaiting = -1;
  1133. setTimeout(isFullyLoaded, helpers.randomMs(15000, 25000));
  1134. }
  1135. };
  1136. function runPromotion() {
  1137. navigationProcess = NavigationProcess.PROCESSING_PROMOTION
  1138. setTimeout(findPromotionTag, helpers.randomMs(1000, 3000));
  1139. };
  1140. function tryClosePopup() {
  1141. let popupBtn = document.querySelector('.p-dialog .p-dialog-header-close');
  1142. if (popupBtn && popupBtn.isVisible()) {
  1143. popupBtn.click();
  1144. }
  1145. };
  1146. function isRollResultVisible() {
  1147. let rollDiv = document.querySelector('.result');
  1148. if (rollDiv && rollDiv.isVisible() && rollDiv.innerText != '') {
  1149. }
  1150. };
  1151. let waitRollNumberCount = 0;
  1152. function closeToast() {
  1153. document.querySelector('.p-toast-icon-close')?.click();
  1154. }
  1155. async function waitForRollNumber() {
  1156. let newNumber = -1;
  1157. try { // intento leer el rolled number
  1158. newNumber = [...document.querySelectorAll('.lucky-number-wrapper img')].map(x => x.src.split('/').slice(-1)[0].split('.').slice(-3)[0]).join('');
  1159. newNumber = parseInt(newNumber)
  1160. } catch(err) {
  1161. newNumber = null;
  1162. }
  1163. if (newNumber === null) { // si no logro leerlo, bajo 1 en tempRollNumber
  1164. if (tempRollNumber < 0) {
  1165. tempRollNumber -= 1;
  1166. } else {
  1167. tempRollNumber = -1;
  1168. }
  1169. if (tempRollNumber < -5) {
  1170. processRunDetails();
  1171. return;
  1172. } else {
  1173. await wait(3000);
  1174. return waitForRollNumber();
  1175. }
  1176. }
  1177.  
  1178. if (newNumber == tempRollNumber) {
  1179. timeWaiting = 0;
  1180. if (shared.getConfig()['cf.rollOnce']) {
  1181. processRunDetails();
  1182. return;
  1183. } else {
  1184. firstRollCompleted = true;
  1185. closeToast();
  1186. setTimeout(findCountdownOrRollButton, helpers.randomMs(1000, 2000));
  1187. return;
  1188. }
  1189. } else {
  1190. waitRollNumberCount++;
  1191. if (waitRollNumberCount > 15) {
  1192. setTimeout(() => { location.reload(); }, 5000);
  1193. return;
  1194. }
  1195.  
  1196. tempRollNumber = newNumber;
  1197. await wait(3000);
  1198. return waitForRollNumber();
  1199. }
  1200.  
  1201. };
  1202. function isLoggedIn() {
  1203. return !!document.querySelector('[data-icon="user"]');
  1204. }
  1205.  
  1206. function findCountdownOrRollButton() {
  1207. if (!isLoggedIn()) {
  1208. location.reload();
  1209. }
  1210. if( isCountdownVisible() && !isRollButtonVisible() ) {
  1211. timeWaiting = 0;
  1212. processRunDetails();
  1213. } else if ( !isCountdownVisible() && isRollButtonVisible() ) {
  1214. timeWaiting = 0;
  1215. setTimeout(isFullyLoaded, helpers.randomMs(1000, 5000));
  1216. } else if ( isCountdownVisible() && isRollButtonVisible() ) {
  1217. try {
  1218. let minLeft = document.querySelector('.minutes .digits').innerText;
  1219. if (minLeft < 1) {
  1220. timeWaiting = 0;
  1221. setTimeout(isFullyLoaded, helpers.randomMs(1000, 5000));
  1222. }
  1223. } catch (err) { console.log(`Error on alt logic of CF roll: ${err}`); }
  1224. } else {
  1225. if (timeWaiting/1000 > shared.getConfig()['defaults.timeout'] * 60) {
  1226. shared.closeWithError(K.ErrorType.TIMEOUT, '');
  1227. return;
  1228. }
  1229.  
  1230. timeWaiting += 3000;
  1231. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  1232. }
  1233. };
  1234. function addUrlChangeListener() {
  1235. if (window.onurlchange === null) {
  1236. window.addEventListener('urlchange', (data) => {
  1237. if (navigationProcess == NavigationProcess.LOGIN && !window.location.href.includes('/login')) {
  1238. loopingForErrors = false;
  1239. init();
  1240. }
  1241. });
  1242. }
  1243. };
  1244. function findLoginForm() {
  1245. if ( document.querySelector('#email')?.isVisible() && document.querySelector('#password')?.isVisible() ) {
  1246. addUrlChangeListener();
  1247. let errElement = document.querySelector('.login-wrapper .error');
  1248. if( errElement && errElement.innerHTML != '') {
  1249. let errorMessage = errElement.innerText;
  1250. shared.closeWithError(K.ErrorType.LOGIN_ERROR, errorMessage);
  1251. return;
  1252. }
  1253. if(!loopingForErrors) {
  1254. if(shared.getConfig()['cf.credentials.mode'] == 1) {
  1255. timeWaiting = 0;
  1256. helpers.typer(document.querySelector('.login-wrapper input[name="email"],#email'), shared.getConfig()['cf.credentials.email']);
  1257. helpers.typer(document.querySelector('.login-wrapper input[name="password"],#password'), shared.getConfig()['cf.credentials.password']);
  1258. document.querySelector('#password')?.closest('div')?.querySelector('button')?.click();
  1259. loopingForErrors = true;
  1260. } else {
  1261. if(document.querySelector('.login-wrapper input[name="email"],#email').value != '' && document.querySelector('.login-wrapper input[name="password"],#password').value != '') {
  1262. document.querySelector('#password')?.closest('div')?.querySelector('button')?.click();
  1263. loopingForErrors = true;
  1264. } else {
  1265. if (timeWaiting/1000 > (shared.getConfig()['defaults.timeout'] / 1.5) * 60) {
  1266. shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
  1267. return;
  1268. }
  1269. }
  1270. }
  1271. }
  1272. }
  1273.  
  1274. if (timeWaiting/1000 > shared.getConfig()['defaults.timeout'] * 60) {
  1275. shared.closeWithError(K.ErrorType.TIMEOUT, '');
  1276. return;
  1277. }
  1278.  
  1279. timeWaiting += 3000;
  1280. setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
  1281. };
  1282. function interact() {
  1283. let selectables = [].concat([...document.querySelectorAll('td')], [...document.querySelectorAll('p')], [...document.querySelectorAll('th')]);
  1284.  
  1285. interactions.start(selectables);
  1286. setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
  1287. }
  1288. function waitInteractions() {
  1289. if(interactions.completed()) {
  1290. roll();
  1291. } else {
  1292. setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
  1293. }
  1294. }
  1295. function isCountdownVisible() {
  1296. countdown = document.querySelectorAll('.minutes .digits');
  1297. return (countdown.length > 0 && countdown[0].isVisible());
  1298. };
  1299. function isRollButtonVisible() {
  1300. let rollButtonIcon = document.querySelector('.p-button [data-icon="gift"]');
  1301. if (!rollButtonIcon) {
  1302. return false;
  1303. }
  1304. rollButton = rollButtonIcon.closest('button');
  1305. return rollButton && !rollButton.disabled && rollButton.isVisible();
  1306. };
  1307. function roll() {
  1308. rollButton.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
  1309. rollButton.click();
  1310. tempRollNumber = -1;
  1311. setTimeout(waitForRollNumber, helpers.randomMs(4000, 7000));
  1312. }
  1313. function isPromotionTagVisible() {
  1314. let pTag;
  1315. try {
  1316. pTag = document.querySelectorAll('.p-message-text.p-message-text')[0];
  1317. } catch(err) {
  1318. return false;
  1319. }
  1320. if (pTag) {
  1321. promotionTag = pTag;
  1322. return true;
  1323. }
  1324. return false;
  1325. };
  1326. function findPromotionTag() {
  1327. if( isPromotionTagVisible() ) {
  1328. processRunDetails();
  1329. } else {
  1330. setTimeout(findPromotionTag, helpers.randomMs(2000, 5000));
  1331. }
  1332. };
  1333. function processRunDetails() {
  1334. let result = {};
  1335. if(navigationProcess == NavigationProcess.ROLLING) {
  1336. result.claimed = readClaimed();
  1337. result.balance = readBalance();
  1338. if(result.claimed != 0) {
  1339. result.rolledNumber = readRolledNumber();
  1340. }
  1341. let minOneHour = result.rolledNumber && result.rolledNumber != 0;
  1342. result.nextRoll = readCountdown(minOneHour);
  1343. result.balance = readBalance();
  1344. } else if (navigationProcess == NavigationProcess.PROCESSING_PROMOTION) {
  1345. result = shared.getResult() || {};
  1346. if (!result.promoCodeResults) {
  1347. result.promoCodeResults = [];
  1348. }
  1349. let pc = {
  1350. promoCode: readPromoCode(),
  1351. promoStatus: readPromoStatus()
  1352. };
  1353.  
  1354. result.promoCodeResults.push(pc);
  1355. shared.updateWithoutClosing(result, 'WORKING');
  1356. setTimeout(gotoNextPromoCode, helpers.randomMs(1000, 2500));
  1357. return;
  1358. }
  1359. shared.closeWindow(result);
  1360. };
  1361. function gotoNextPromoCode() {
  1362. let codes = shared.getCurrent().params.promoCodes;
  1363. if (!codes) {
  1364. shared.closeWindow();
  1365. return;
  1366. }
  1367. let pc = readPromoCode();
  1368. let pcIdx = codes.findIndex(x => x == pc);
  1369. if (pcIdx == -1 || pcIdx == codes.length - 1) {
  1370. shared.closeWindow();
  1371. return;
  1372. }
  1373. window.location.href = '/promotion/' + codes[pcIdx + 1];
  1374. };
  1375. function readCountdown(minOneHour = false) {
  1376. let minsElement = document.querySelector('.minutes .digits');
  1377. let mins = "0";
  1378. if (minsElement) {
  1379. mins = minsElement.innerHTML;
  1380. }
  1381. if (mins) {
  1382. let estimated = helpers.addMinutes(+mins + 1);
  1383. let oneHour = Date.now() + (60*60*1000);
  1384. if (minOneHour && (oneHour > estimated) ) {
  1385. return oneHour;
  1386. }
  1387. return estimated;
  1388. } else {
  1389. return null;
  1390. }
  1391. };
  1392. function readClaimed() {
  1393. let claimed = 0;
  1394. try {
  1395. claimed = document.querySelector('.p-toast-message-text .p-toast-detail').innerHTML;
  1396. claimed = claimed.trim();
  1397. claimed = claimed.split(' ').slice(-2)[0]
  1398. } catch(err) { }
  1399. return claimed;
  1400. };
  1401. function readRolledNumber() {
  1402. let number = 0;
  1403. try {
  1404. number = [...document.querySelectorAll('.lucky-number-wrapper img')].map(x => x.src.split('/').slice(-1)[0].split('.').slice(-3)[0]).join('');
  1405. number = parseInt(number);
  1406. } catch(err) { }
  1407. return number;
  1408. };
  1409. function readBalance() {
  1410. let balance = "";
  1411. try {
  1412. balance = document.querySelectorAll('header div div div > span span')[1].innerText.trim().split(' ')[0];
  1413. } catch(err) { }
  1414. return balance;
  1415. };
  1416. function readPromoStatus() {
  1417. let promoStatus = K.CF.PromoStatus.UNKNOWNERROR;
  1418. try {
  1419. if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeAccepted) > 0) {
  1420. return K.CF.PromoStatus.ACCEPTED;
  1421. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeUsed) > 0) {
  1422. return K.CF.PromoStatus.USEDBEFORE;
  1423. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeExpired) > 0) {
  1424. return K.CF.PromoStatus.EXPIRED;
  1425. } else if(localeConfig.stringSearches.promoCodeInvalid.findIndex(x => promotionTag.innerHTML.indexOf(x) > -1) == -1) {
  1426. return K.CF.PromoStatus.INVALID;
  1427. }
  1428. } catch ( err ) { }
  1429. return promoStatus;
  1430. };
  1431. function validatePromoString() {
  1432.  
  1433. };
  1434. function readPromoCode() {
  1435. var urlSplit = window.location.href.split('/');
  1436. return urlSplit[urlSplit.length - 1];
  1437. };
  1438. function displayStatusUi() {
  1439. let wrapper = document.createElement('div');
  1440. wrapper.innerHTML = '<div class="withdraw-button bg-2" style="top:30%; z-index:1500;" href="#">⚙️ <span id="process-status">Processing</span></div>';
  1441. document.querySelector( 'body' ).prepend( wrapper.firstChild );
  1442. };
  1443. return {
  1444. init: init
  1445. };
  1446. },
  1447. createCFHistory: function() {
  1448. let rollsMeta = [
  1449. { id: 0, range: '0000-9885', count: 0 },
  1450. { id: 1, range: '9886-9985', count: 0 },
  1451. { id: 2, range: '9986-9993', count: 0 },
  1452. { id: 3, range: '9994-9997', count: 0 },
  1453. { id: 4, range: '9998-9999', count: 0 },
  1454. { id: 5, range: '10000', count: 0 }
  1455. ];
  1456.  
  1457. function initOrLoad() {
  1458. let storedData = persistence.load('CFHistory', true);
  1459. if(storedData) {
  1460. rollsMeta = storedData;
  1461. }
  1462. };
  1463.  
  1464. function addRoll(number) {
  1465. switch(true) {
  1466. case (number <= 9885):
  1467. rollsMeta[0].count++;
  1468. break;
  1469. case (number <= 9985):
  1470. rollsMeta[1].count++;
  1471. break;
  1472. case (number <= 9993):
  1473. rollsMeta[2].count++;
  1474. break;
  1475. case (number <= 9997):
  1476. rollsMeta[3].count++;
  1477. break;
  1478. case (number <= 9999):
  1479. rollsMeta[4].count++;
  1480. break;
  1481. case (number == 10000):
  1482. rollsMeta[5].count++;
  1483. break;
  1484. default:
  1485. break;
  1486. }
  1487. save();
  1488. };
  1489.  
  1490. function getRollsMeta() {
  1491. return rollsMeta.map(x => x.count);
  1492. };
  1493.  
  1494. function save() {
  1495. persistence.save('CFHistory', rollsMeta, true);
  1496. };
  1497.  
  1498. return {
  1499. initOrLoad: initOrLoad,
  1500. addRoll: addRoll,
  1501. getRollsMeta: getRollsMeta
  1502. }
  1503. },
  1504. };
  1505.  
  1506. function overrideSelectNativeJS_Functions () {
  1507. window.alert = function alert (message) {
  1508. }
  1509. }
  1510. function addJS_Node (text, s_URL, funcToRun) {
  1511. var scriptNode= document.createElement ('script');
  1512. scriptNode.type= "text/javascript";
  1513. if (text)scriptNode.textContent= text;
  1514. if (s_URL)scriptNode.src= s_URL;
  1515. if (funcToRun)scriptNode.textContent = '(' + funcToRun.toString() + ')()';
  1516. var element = document.getElementsByTagName ('head')[0] || document.body || document.documentElement;
  1517. element.appendChild (scriptNode);
  1518. }
  1519. function addHtml(data) { // data = { target: '', where: '', content: '' }
  1520. document.querySelector(data.target).insertAdjacentHTML(data.where, data.content);
  1521. }
  1522. function addTemplateTag(data) {
  1523. let templateTag = document.createElement('template');
  1524. templateTag.id = data.id;
  1525. templateTag.innerHTML = data.content;
  1526. let container = document.body || document.documentElement;
  1527. container.appendChild(templateTag);
  1528. }
  1529. function useTemplate(data) { // data = { templateId: '', target: '', where: '', replacements: {} }
  1530. let template = document.querySelector(`#${data.templateId}`).innerHTML;
  1531. let content = template.formatUnicorn(data.replacements);
  1532. addHtml({
  1533. target: data.target,
  1534. where: data.where,
  1535. content: content
  1536. });
  1537. }
  1538.  
  1539. function isExpectedPtc() {
  1540. let runningList = shared.getRunningSites();
  1541. let ptcHosts = ['faucetpay.io'];
  1542.  
  1543. for (let i = 0; i < ptcHosts.length; i++) {
  1544. if (document.referrer.includes(`//${ptcHosts[i]}`) && runningList.includes(ptcHosts[i])) {
  1545. waitForCloseSignal(ptcHosts[i]);
  1546. return true;
  1547. }
  1548. }
  1549. return false;
  1550. }
  1551.  
  1552. async function waitForCloseSignal(host) {
  1553. await wait(3000);
  1554. const signal = GM_getValue(`ptc-close-signal-${host}`) || null;
  1555. if (signal) {
  1556. window.close();
  1557. }
  1558. return waitForCloseSignal(host);
  1559. }
  1560.  
  1561. function detectWeb() {
  1562. if (isExpectedPtc()) {
  1563. return;
  1564. }
  1565. if(!shared.isOpenedByManager()) {
  1566. return;
  1567. }
  1568. instance = K.LOCATION.SITE;
  1569.  
  1570. let typeFromManager = shared.getCurrent().type;
  1571.  
  1572. siteTimer = new Timer({ isManager: false, delaySeconds: 20, uuid: shared.getProp('schedule'), webType: typeFromManager });
  1573. switch( typeFromManager ) {
  1574. case K.WebType.STORMGAIN:
  1575. SiteProcessor = createSGProcessor();
  1576. setTimeout(SiteProcessor.run, helpers.randomMs(10000, 20000));
  1577. break;
  1578. case K.WebType.CRYPTOSFAUCETS:
  1579. SiteProcessor = objectGenerator.createCFProcessor();
  1580. setTimeout(SiteProcessor.init, helpers.randomMs(1000, 3000));
  1581. break;
  1582. case K.WebType.FREEBITCOIN:
  1583. SiteProcessor = createFBProcessor();
  1584. setTimeout(SiteProcessor.run, helpers.randomMs(2000, 5000));
  1585. break;
  1586. case K.WebType.FAUCETPAY:
  1587. SiteProcessor = new FPPtc();
  1588. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
  1589. break;
  1590. case K.WebType.BIGBTC:
  1591. SiteProcessor = createBigBtcProcessor();
  1592. setTimeout(SiteProcessor.init, helpers.randomMs(2000, 4000));
  1593. break;
  1594. case K.WebType.BESTCHANGE:
  1595. SiteProcessor = createBestChangeProcessor();
  1596. setTimeout(SiteProcessor.init, helpers.randomMs(4000, 6000));
  1597. break;
  1598. case K.WebType.BFBOX:
  1599. SiteProcessor = new BFRoll(helpers.getEnumText(K.CMC, shared.getCurrent().params.cmc).toLowerCase());
  1600. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
  1601. break;
  1602. case K.WebType.DUTCHYROLL:
  1603. SiteProcessor = new DutchyRoll();
  1604. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
  1605. break;
  1606. case K.WebType.FCRYPTO:
  1607. SiteProcessor = new FCryptoRoll();
  1608. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
  1609. break;
  1610. case K.WebType.FPB:
  1611. SiteProcessor = new FPB(shared.getCurrent().params.sitePrefix);
  1612. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1613. break;
  1614. case K.WebType.FREEGRC:
  1615. SiteProcessor = new GRCRoll();
  1616. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1617. break;
  1618. case K.WebType.VIE:
  1619. SiteProcessor = new VieRoll();
  1620. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1621. break;
  1622. case K.WebType.O24:
  1623. SiteProcessor = new O24Roll();
  1624. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1625. break;
  1626. case K.WebType.YCOIN:
  1627. SiteProcessor = new YCoin();
  1628. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1629. break;
  1630. case K.WebType.CDIVERSITY:
  1631. SiteProcessor = new CDiversity();
  1632. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1633. break;
  1634. case K.WebType.CTOP:
  1635. SiteProcessor = new CTop();
  1636. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1637. break;
  1638. case K.WebType.AUTOCML:
  1639. SiteProcessor = new AutoCMl();
  1640. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1641. break;
  1642. case K.WebType.CCLICKS:
  1643. SiteProcessor = new CClicks();
  1644. setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
  1645. break;
  1646. default:
  1647. break;
  1648. }
  1649. }
  1650.  
  1651. class UiBaseRenderer {
  1652. constructor(uiRenderer) { this.uiRenderer = uiRenderer; }
  1653. }
  1654. class UiSitesRenderer extends UiBaseRenderer {
  1655. appendEventListeners() {
  1656.  
  1657. document.querySelector('#modal-assign-schedule').addEventListener('click', this.onClickOnModalAssignSchedule.bind(this));
  1658. eventer.on('siteChangedSchedule', (e) => {
  1659. this.uiRenderer.toast(`Site moved to schedule ${e.scheduleId}`);
  1660. manager.resyncAll({withUpdate: true}); // should act based on data only
  1661. });
  1662.  
  1663. document.querySelector('#schedule-table-body').addEventListener('click', this.onClickOnSitesTableBody.bind(this));
  1664.  
  1665. document.querySelector('.action-edit-all-sites').addEventListener('click', this.onClickOnEditAllSites.bind(this));
  1666. document.querySelector('.action-edit-all-sites-cancel').addEventListener('click', this.onClickOnCancelEditAllSites.bind(this));
  1667. document.querySelector('.action-edit-all-sites-save').addEventListener('click', this.onClickOnSaveEditAllSites.bind(this));
  1668.  
  1669. document.querySelector('.action-add-external-site').addEventListener('click', this.onClickOnAddSiteButton.bind(this));
  1670. document.querySelector('#modal-add-site').addEventListener('click', this.onClickOnModalAddSite.bind(this));
  1671. eventer.on('siteAdded', (e) => {
  1672. this.uiRenderer.toast(`Site ${e.siteName} added`);
  1673. manager.resyncAll({withUpdate: true}); // should act based on data only
  1674. });
  1675. eventer.on('siteRemoved', (e) => {
  1676. this.uiRenderer.toast(`Site ${e.siteName} removed`);
  1677. manager.resyncAll({withUpdate: true}); // should act based on data only
  1678. });
  1679. }
  1680.  
  1681. _legacyAddBadges(stats) {
  1682. let consecutiveTimeout = stats.countTimeouts;
  1683. let otherErrors = stats.errors;
  1684. let html = ' ';
  1685.  
  1686. if (consecutiveTimeout) {
  1687. html += `<span class="badge badge-pill badge-warning" title="${consecutiveTimeout} consecutive timeouts">${consecutiveTimeout}</span>`;
  1688. }
  1689.  
  1690. if (otherErrors) {
  1691. html += `<span class="badge badge-pill badge-warning" title="${otherErrors.errorMessage}">${helpers.getEnumText(K.ErrorType, otherErrors.errorType)}</span>`;
  1692. }
  1693. return html;
  1694. }
  1695.  
  1696. removeDeletedSitesRows(validSiteIds) {
  1697. let removableRows = [...document.querySelectorAll('#schedule-table-body tr')].filter(r => !validSiteIds.includes(r.dataset.id));
  1698. removableRows.forEach(r => {
  1699. r.remove();
  1700. });
  1701. }
  1702.  
  1703. renderSiteRow(site) {
  1704.  
  1705. let row = [...document.querySelectorAll('#schedule-table-body tr')]
  1706. .filter(r => r.dataset.id == site.id);
  1707.  
  1708. if (row.length == 0) {
  1709. row = document.createElement('tr');
  1710. document.querySelector('#schedule-table-body').appendChild(row);
  1711. row.setAttribute('aria-expanded', false);
  1712. row.classList.add('align-middle');
  1713. row.dataset.id = site.id;
  1714. row.dataset.cmc = site.cmc;
  1715. } else {
  1716. row = row[0];
  1717. }
  1718.  
  1719. row.dataset.json = `${JSON.stringify(site)}`;
  1720. row.dataset.schedule = site.schedule;
  1721. row.dataset.nextRollTimestamp = site.nextRoll ? site.nextRoll.getTime() : 'null';
  1722. row.dataset.enabled = site.enabled ? '1' : '0';
  1723. if (site.balance) {
  1724. if (typeof site.balance == 'string') {
  1725. row.dataset.balance = site.balance.split(' ')[0];
  1726. } else {
  1727. row.dataset.balance = site.balance.toFixed(8);
  1728. }
  1729. } else {
  1730. row.dataset.balance = '';
  1731. }
  1732.  
  1733. let tds = '';
  1734.  
  1735. tds += '<td class="align-middle edit-status d-none em-only"><label class="switch"><input type="checkbox" data-original="' + (site.enabled ? '1' : '0') + '" ' + (site.enabled ? 'checked' : ' ') + '><span class="slider round"></span></label></td>';
  1736. tds += '<td class="align-middle" title="' + helpers.getPrintableDateTime(site.nextRoll) + '"><span><i class="fas fa-square pr-1" style="color: #' + site.schedule + ';"></i></span>' + helpers.getTdPrintableTime(site.nextRoll) + '</td>';
  1737. if (site.isExternal && site.clId == -1) {
  1738. tds += '<td class="align-middle text-left"><a class="" title="Visit site" target="_blank" rel="noreferrer" href="' + site.url + '"><i class="fa fa-external-link-alt"></i></a></td>';
  1739. } else {
  1740. tds += '<td class="align-middle text-left"><a class="" title="Visit site" target="_blank" rel="noreferrer" href="' + (new URL(site.clId, 'https://criptologico.com/goto/')).href + '"><i class="fa fa-external-link-alt"></i></a></td>';
  1741. }
  1742.  
  1743. tds += '<td class="align-middle em-input text-left" data-field="displayName">';
  1744. if (site.cmc) {
  1745. tds +='<div class="input-group input-group-sm">';
  1746. tds += '<div class="input-group-prepend"><span class="input-group-text">';
  1747. if (site.cmc > 0) {
  1748. let cmcLower = helpers.getEnumText(K.CMC, site.cmc).toLowerCase();
  1749. tds += '<img loading="lazy" src="/static/c-icons/' + cmcLower + '.svg" height="20" alt="' + cmcLower + '">';
  1750. } else {
  1751. tds += '<i class="fa fa-question-circle"></i>';
  1752. }
  1753. tds += '</span></div>';
  1754. }
  1755. tds += ' <span class="site-name-container px-1">' + site.name + '</span></div></td>';
  1756.  
  1757. tds +='<td class="align-middle text-right">' + site.lastClaim.toFixed(Number.isInteger(site.lastClaim) ? 0 : 8) + '</td>';
  1758. tds +='<td class="align-middle text-right">' + site.aggregate.toFixed(Number.isInteger(site.aggregate) ? 0 : 8) + '</td>';
  1759.  
  1760. tds += '<td class="align-middle text-right">' + (+row.dataset.balance > 100 ? (+row.dataset.balance).toFixed(2) : row.dataset.balance) + '</td>';
  1761. tds +='<td class="align-middle text-right fiat-conversion em-hide"></td>';
  1762. tds +='<td class="align-middle">' + this._legacyAddBadges(site.stats) + '</td>';
  1763. tds +='<td class="align-middle justify-content-center em-hide">';
  1764.  
  1765. tds +=
  1766. `<div class="btn-group btn-group-sm">
  1767. <button type="button" title="Run ASAP" class="btn btn-default action-run-asap">
  1768. <i class="fa fa-bolt"></i>
  1769. </button>
  1770. <button type="button" title="Schedule parameters..."
  1771. class="btn btn-default action-edit-site ${Object.keys(site.params).some( k => k.endsWith('.override') && site.params[k] == true ) ? 'text-warning' : ''}">
  1772. <i class="fa fa-clock"></i>
  1773. </button>
  1774. <div class="btn-group btn-group-sm">
  1775. <button type="button" class="btn btn-default dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
  1776. </button>
  1777. <div class="dropdown-menu dropdown-menu-right text-sm" style="">
  1778. <a class="dropdown-item action-site-edit-parameters"><i class="fa fa-edit"></i> Site arguments...</a>
  1779. <a class="dropdown-item action-site-assign-schedule"><i class="fa fa-exchange-alt"></i> Move to...</a>`;
  1780. if (site.isExternal) {
  1781. tds += `<a class="dropdown-item action-site-remove-external"><i class="fa fa-trash"></i> Remove site</a>`;
  1782. }
  1783. tds += `</div></div></div>`;
  1784.  
  1785. tds +='</td></tr>';
  1786.  
  1787. row.innerHTML = tds;
  1788. }
  1789.  
  1790. legacyRenderSiteData(site, config) {
  1791. document.querySelector('#faucet-name').innerHTML = site.name;
  1792. document.querySelector('#faucet-name').dataset.id = site.id;
  1793. let data = site.params || {};
  1794.  
  1795. for (const prop in config) {
  1796. let overrideElement = document.querySelector('[data-site-prop="' + prop + '.override"]');
  1797. if (overrideElement) {
  1798. overrideElement.dataset.original = (data[prop + '.override'] ? "1" : "0");
  1799. overrideElement.checked = data[prop + '.override'];
  1800. }
  1801.  
  1802. let element = document.querySelector('[data-site-prop="' + prop + '"]');
  1803. if(element) {
  1804. if(element.type == 'select-one' || element.type == 'text' || element.type == 'password' || element.type == 'number' || element.type == 'time') {
  1805. element.dataset.original = data[prop] ?? config[prop];
  1806. element.value = data[prop] ?? config[prop];
  1807. } else if (element.type == 'checkbox') {
  1808. element.dataset.original = ((data[prop] ?? config[prop]) ? "1" : "0");
  1809. element.checked = data[prop] ?? config[prop];
  1810. }
  1811. element.disabled = true;
  1812. }
  1813. }
  1814.  
  1815. let elWorkInBackgroundOverride = document.querySelector('[data-site-prop="defaults.workInBackground.override"]');
  1816. let elWorkInBackground = document.querySelector('[data-site-prop="defaults.workInBackground"]');
  1817. elWorkInBackground.disabled = !elWorkInBackgroundOverride.checked;
  1818. elWorkInBackgroundOverride.onchange = function (e) {
  1819. document.querySelector('[data-site-prop="defaults.workInBackground"]').disabled = !e.target.checked;
  1820. }
  1821.  
  1822. let elTimeoutOverride = document.querySelector('[data-site-prop="defaults.timeout.override"]');
  1823. let elTimeout = document.querySelector('[data-site-prop="defaults.timeout"]');
  1824. elTimeout.disabled = !elTimeoutOverride.checked;
  1825. elTimeoutOverride.onchange = function (e) {
  1826. document.querySelector('[data-site-prop="defaults.timeout"]').disabled = !e.target.checked;
  1827. }
  1828.  
  1829. let elPostponeOverride = document.querySelector('[data-site-prop="defaults.postponeMinutes.override"]');
  1830. let elPostpone = document.querySelector('[data-site-prop="defaults.postponeMinutes"]');
  1831. let elPostponeMin = document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]');
  1832. let elPostponeMax = document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]');
  1833. elPostpone.disabled = !elPostponeOverride.checked;
  1834. elPostponeMin.disabled = !elPostponeOverride.checked || (elPostpone.value > "0");
  1835. elPostponeMax.disabled = !elPostponeOverride.checked || (elPostpone.value > "0");
  1836. elPostponeOverride.onchange = function (e) {
  1837. let mode = document.querySelector('[data-site-prop="defaults.postponeMinutes"]');
  1838. mode.disabled = !e.target.checked;
  1839. document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').disabled = !e.target.checked || mode.value > 0;
  1840. document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').disabled = !e.target.checked || mode.value > 0;
  1841. }
  1842. elPostpone.onchange = function (e) {
  1843. document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').disabled = e.target.value > 0;
  1844. document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').disabled = e.target.value > 0;
  1845. if (e.target.value > 0) {
  1846. document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').value = e.target.value;
  1847. document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').value = e.target.value;
  1848. }
  1849. }
  1850.  
  1851. let elNextRunOverride = document.querySelector('[data-site-prop="defaults.nextRun.override"]');
  1852. let elNextRun = document.querySelector('[data-site-prop="defaults.nextRun"]');
  1853. let elNextRunMin = document.querySelector('[data-site-prop="defaults.nextRun.min"]');
  1854. let elNextRunMax = document.querySelector('[data-site-prop="defaults.nextRun.max"]');
  1855. let elNextRunUseCountdown = document.querySelector('[data-site-prop="defaults.nextRun.useCountdown"]');
  1856. elNextRun.disabled = !elNextRunOverride.checked;
  1857. elNextRunMin.disabled = !elNextRunOverride.checked || (elNextRun.value > "0");
  1858. elNextRunMax.disabled = !elNextRunOverride.checked || (elNextRun.value > "0");
  1859. elNextRunUseCountdown.disabled = !elNextRunOverride.checked;
  1860. elNextRunOverride.onchange = function (e) {
  1861. let mode = document.querySelector('[data-site-prop="defaults.nextRun"]');
  1862. mode.disabled = !e.target.checked;
  1863. document.querySelector('[data-site-prop="defaults.nextRun.min"]').disabled = !e.target.checked || mode.value > 0;
  1864. document.querySelector('[data-site-prop="defaults.nextRun.max"]').disabled = !e.target.checked || mode.value > 0;
  1865. document.querySelector('[data-site-prop="defaults.nextRun.useCountdown"]').disabled = !e.target.checked;
  1866. }
  1867. elNextRun.onchange = function (e) {
  1868. document.querySelector('[data-site-prop="defaults.nextRun.min"]').disabled = e.target.value > 0;
  1869. document.querySelector('[data-site-prop="defaults.nextRun.max"]').disabled = e.target.value > 0;
  1870. if (e.target.value > 0) {
  1871. document.querySelector('[data-site-prop="defaults.nextRun.min"]').value = e.target.value;
  1872. document.querySelector('[data-site-prop="defaults.nextRun.max"]').value = e.target.value;
  1873. }
  1874. }
  1875.  
  1876. let elSleepOverride = document.querySelector('[data-site-prop="defaults.sleepMode.override"]');
  1877. let elSleep = document.querySelector('[data-site-prop="defaults.sleepMode"]');
  1878. let elSleepMin = document.querySelector('[data-site-prop="defaults.sleepMode.min"]');
  1879. let elSleepMax = document.querySelector('[data-site-prop="defaults.sleepMode.max"]');
  1880. elSleep.disabled = !elSleepOverride.checked;
  1881. elSleepMin.disabled = !elSleepOverride.checked || !elSleep.checked;
  1882. elSleepMax.disabled = !elSleepOverride.checked || !elSleep.checked;
  1883. elSleepOverride.onchange = function (e) {
  1884. let mode = document.querySelector('[data-site-prop="defaults.sleepMode"]');
  1885. mode.disabled = !e.target.checked;
  1886. document.querySelector('[data-site-prop="defaults.sleepMode.min"]').disabled = !e.target.checked || !mode.checked;
  1887. document.querySelector('[data-site-prop="defaults.sleepMode.max"]').disabled = !e.target.checked || !mode.checked;
  1888. }
  1889. elSleep.onchange = function (e) {
  1890. document.querySelector('[data-site-prop="defaults.sleepMode.min"]').disabled = !e.target.checked;
  1891. document.querySelector('[data-site-prop="defaults.sleepMode.max"]').disabled = !e.target.checked;
  1892. }
  1893.  
  1894. return;
  1895. }
  1896.  
  1897. sortSitesTable() {
  1898. const tbody = document.querySelector('#schedule-table-body');
  1899.  
  1900. let rows, switching, i, shouldSwitch;
  1901. switching = true;
  1902. while (switching) {
  1903. switching = false;
  1904. rows = tbody.rows;
  1905.  
  1906. for (i = 0; i < (rows.length - 1); i++) {
  1907. shouldSwitch = false;
  1908.  
  1909. let aNextRoll, bNextRoll, aHasLoginError, bHasLoginError, aName, bName;
  1910. aNextRoll = rows[i].dataset.nextRollTimestamp;
  1911. bNextRoll = rows[i + 1].dataset.nextRollTimestamp;
  1912. if (aNextRoll == 'null' && bNextRoll == 'null') {
  1913. aName = rows[i].querySelector('.site-name-container').innerText;
  1914. bName = rows[i + 1].querySelector('.site-name-container').innerText;
  1915. if (aName.toLowerCase() > bName.toLowerCase()) {
  1916. shouldSwitch = true;
  1917. break;
  1918. }
  1919. } else if (aNextRoll == 'null' || (aNextRoll > bNextRoll)) {
  1920. shouldSwitch = true;
  1921. break;
  1922. }
  1923. }
  1924. if (shouldSwitch) {
  1925. rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
  1926. switching = true;
  1927. }
  1928. }
  1929. }
  1930.  
  1931. onClickOnSitesTableBody(e) {
  1932. let actionElement = e.target;
  1933. if (actionElement.tagName === 'I') {
  1934. actionElement = actionElement.parentElement;
  1935. }
  1936. const row = actionElement.closest('tr');
  1937. if (actionElement.classList.contains('action-edit-site')) {
  1938. e.stopPropagation();
  1939. this.uiRenderer.openModal('modal-site', row.dataset.id);
  1940. } else if (actionElement.classList.contains('action-run-asap')) {
  1941. e.stopPropagation();
  1942. Site.setAsRunAsap(row.dataset.id);
  1943. } else if (actionElement.classList.contains('action-site-assign-schedule')) {
  1944. this.uiRenderer.openModal('modal-assign-schedule', { site_id: row.dataset.id, schedule_id: row.dataset.schedule });
  1945. } else if (actionElement.classList.contains('action-site-edit-parameters')) {
  1946. this.uiRenderer.openModal('modal-site-parameters', { site_id: row.dataset.id });
  1947. } else if (actionElement.classList.contains('action-site-remove-external')) {
  1948. Site.remove(row.dataset.id);
  1949. console.info('TODO: remove site and all the related configuration', row.dataset.id);
  1950. }
  1951. }
  1952.  
  1953. onClickOnModalAssignSchedule(e) {
  1954. const modalAssignScheduleToSite = document.querySelector('#modal-assign-schedule');
  1955. let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
  1956. if (actionElement.classList.contains('modal-save')) {
  1957. let data = this.uiRenderer.parseContainer(modalAssignScheduleToSite.querySelector('.form-container'));
  1958. if (data.original_schedule_id == data.schedule) {
  1959. } else {
  1960. Site.getById(data.site_id).changeSchedule(data.schedule);
  1961. }
  1962. }
  1963. }
  1964.  
  1965. onClickOnModalAddSite(e) {
  1966. const modal = document.querySelector('#modal-add-site');
  1967. let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
  1968. if (actionElement.classList.contains('modal-save')) {
  1969. let formData = this.uiRenderer.parseContainer(modal.querySelector('.form-container'));
  1970. let data = {};
  1971. data.name = formData.site_name;
  1972. data.url = new URL(formData.site_url);
  1973. data.schedule = formData.schedule;
  1974. data.clId = -1;
  1975. data.id = 'ext_rnd_id_' + helpers.randomString(8);
  1976. data.type = K.WebType.UNDEFINED;
  1977. data.cmc = -1;
  1978. data.rf = '';
  1979. data.isExternal = true;
  1980.  
  1981. console.warn('Savable new site');
  1982. Site.add(data);
  1983. return;
  1984. if (data.original_schedule_id == data.schedule) {
  1985. } else {
  1986. Site.getById(data.site_id).changeSchedule(data.schedule);
  1987. }
  1988. }
  1989. }
  1990.  
  1991. onClickOnEditAllSites(e) {
  1992. document.querySelectorAll("#schedule-table-body td.em-input .site-name-container").forEach(function (x) {
  1993. let val = x.innerHTML;
  1994. x.innerHTML = "<input type=\'text\' class=\'form-control form-control-sm\' data-original=\'" + val.trim() + "\' value=\'" + val.trim() + "\' />";
  1995. });
  1996. document.querySelectorAll("#schedule-table-body td.edit-status").forEach(function (x) {
  1997. x.classList.remove("d-none");
  1998. });
  1999. document.querySelectorAll(".em-only").forEach(x => x.classList.remove("d-none"));
  2000. document.querySelectorAll(".em-hide").forEach(x => x.classList.add("d-none"));
  2001. }
  2002.  
  2003. onClickOnCancelEditAllSites(e) {
  2004. document.querySelectorAll("#schedule-table-body td.em-input .site-name-container input").forEach(function(x) {
  2005. x.parentNode.innerHTML = x.dataset.original;
  2006. });
  2007. document.querySelectorAll(".em-only").forEach(x => x.classList.add("d-none"));
  2008. document.querySelectorAll(".em-hide").forEach(x => x.classList.remove("d-none"));
  2009. }
  2010.  
  2011. onClickOnSaveEditAllSites(e) {
  2012. let updateObject;
  2013. var updateData = document.getElementById("update-data");
  2014. if (updateData.innerHTML != "") {
  2015. updateObject = JSON.parse(updateData.innerHTML);
  2016. } else {
  2017. updateObject = {
  2018. runAsap: { ids: [], changed: false },
  2019. editSingle: { changed: false, items: [] },
  2020. wallet: { changed: false, items: [] },
  2021. config: { changed: false, items: [] },
  2022. site: { changed: false, list: [] }
  2023. };
  2024. }
  2025.  
  2026. document.querySelectorAll("#schedule-table-body tr").forEach(function (row) {
  2027. let textInputCell = row.querySelector(".em-input .site-name-container");
  2028. let textInput = textInputCell.querySelector("input");
  2029. let activeSwitch = row.querySelector("td.edit-status input");
  2030. let single = { id: row.dataset.id, displayName: textInput.dataset.original, enabled: activeSwitch.dataset.original };
  2031. textInputCell.innerHTML = textInput.value;
  2032. if(textInput.dataset.original != textInput.value) {
  2033. single.displayName = textInput.value;
  2034. }
  2035. if(activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {
  2036. single.enabled = Boolean(activeSwitch.checked);
  2037. }
  2038. if(textInput.dataset.original != textInput.value || activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {
  2039. updateObject.editSingle.items.push(single);
  2040. updateObject.editSingle.changed = true;
  2041. }
  2042. });
  2043. if(updateObject.editSingle.changed) {
  2044. document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
  2045. this.uiRenderer.toast("Data will be updated as soon as possible");
  2046. }
  2047.  
  2048. document.querySelectorAll(".em-only").forEach(x => x.classList.add("d-none"));
  2049. document.querySelectorAll(".em-hide").forEach(x => x.classList.remove("d-none"));
  2050. }
  2051.  
  2052. onClickOnAddSiteButton(e) {
  2053. e.stopPropagation();
  2054. this.uiRenderer.openModal('modal-add-site');
  2055. }
  2056.  
  2057. renderAddExternalSite() {
  2058. const modalAssignSchedule = document.getElementById('modal-add-site');
  2059. let selectElm = modalAssignSchedule.querySelector('select');
  2060. let options = [];
  2061. let firstSchedule = '';
  2062. Schedule.getAllForCrud().forEach(sch => {
  2063. if (firstSchedule == '') {
  2064. firstSchedule = sch.uuid;
  2065. }
  2066. options.push(`<option value="${sch.uuid}"><i class="fas fa-square" style="color: #${sch.uuid}"></i>${sch.name}</option>`)
  2067. });
  2068. selectElm.innerHTML = options.join('');
  2069. selectElm.value = firstSchedule;
  2070. return;
  2071. }
  2072.  
  2073. renderAssignScheduleToSite(values) {
  2074. const modalAssignSchedule = document.getElementById('modal-assign-schedule');
  2075. modalAssignSchedule.querySelector('input[name="site_id"]').value = values.site_id;
  2076. modalAssignSchedule.querySelector('input[name="original_schedule_id"]').value = values.schedule_id;
  2077. let selectElm = modalAssignSchedule.querySelector('select');
  2078. let options = [];
  2079. Schedule.getAllForCrud().forEach(sch => {
  2080. options.push(`<option value="${sch.uuid}"><i class="fas fa-square" style="color: #${sch.uuid}"></i>${sch.name}</option>`)
  2081. });
  2082. selectElm.innerHTML = options.join('');
  2083. selectElm.value = values.schedule_id || "";
  2084. return;
  2085. }
  2086. }
  2087. class UiPromosRenderer extends UiBaseRenderer {
  2088. appendEventListeners() {
  2089. document.querySelector('#promo-button').addEventListener('click', this.onClickSavePromoCode.bind(this));
  2090. document.querySelector('#button-try-get-codes').addEventListener('click', this.onClickTryGetCodes.bind(this));
  2091. document.querySelector('#promo-table-body').addEventListener('click', this.onClickOnPromoTableBody.bind(this));
  2092. }
  2093.  
  2094. onClickSavePromoCode(e) {
  2095. var promoText = document.getElementById("promo-text-input");
  2096. var promoCode = document.getElementById("promo-code-new");
  2097. var promoDaily = document.getElementById("promo-daily");
  2098. var promoObject = { action: "ADD", code: promoText.value.trim(), repeatDaily: promoDaily.checked };
  2099. promoCode.innerHTML =JSON.stringify(promoObject);
  2100. this.uiRenderer.toast("Adding promo code: " + promoObject.code + "...");
  2101. promoText.value = '';
  2102. }
  2103.  
  2104. onClickTryGetCodes(e) {
  2105. var promoCode = document.getElementById("promo-code-new");
  2106. var promoObject = { action: "TRYGETCODES" };
  2107. promoCode.innerHTML =JSON.stringify(promoObject);
  2108. this.uiRenderer.toast("Fetching codes...");
  2109. }
  2110.  
  2111. _legacyRemoveUsedDailyCodes(codes) {
  2112. if(codes && codes.length) {
  2113. codes.forEach(code => {
  2114. if(!code.repeatDaily) {
  2115. let counter = 0;
  2116. for(let i = 0; i < code.statusPerFaucet.length; i++) {
  2117. if(code.statusPerFaucet[i].execTimeStamp) {
  2118. counter++;
  2119. }
  2120. }
  2121. if(counter == code.statusPerFaucet.length) {
  2122. setTimeout(() => removePromoCode(code.id, code.code), 20000);
  2123. }
  2124. }
  2125. });
  2126. }
  2127. }
  2128.  
  2129. legacyRenderPromotionTable(codes) {
  2130. let tableBody = '';
  2131. this._legacyRemoveUsedDailyCodes(codes);
  2132.  
  2133. for(let c=0; c < codes.length; c++) {
  2134. let data = codes[c];
  2135. tableBody += '<tr data-promotion-code="' + data.code + '" data-promotion-id="' + data.id + '">';
  2136. tableBody += '<td class="align-middle text-left ' + (data.repeatDaily ? 'text-warning' : '') + '">';
  2137. tableBody += `<a class="action-remove-promo-code" data-toggle="tooltip" data-placement="left" title="Remove" onclick=""><i class="fa fa-times-circle"></i></a>`;
  2138. tableBody += '<span title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + data.code + '</span></td>';
  2139. tableBody +='<td class="align-middle" title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + helpers.getPrintableDateTime(data.added) + '</td>';
  2140.  
  2141. for(let i=0, all = data.statusPerFaucet.length; i < all; i++) {
  2142. tableBody +='<td class="align-middle" title="Runned @' + helpers.getPrintableDateTime(data.statusPerFaucet[i].execTimeStamp) + '">' + helpers.getEmojiForPromoStatus(data.statusPerFaucet[i].status ?? 0) + '</td>';
  2143. }
  2144. tableBody +='</tr>';
  2145. }
  2146.  
  2147. document.getElementById('promo-table-body').innerHTML = tableBody;
  2148. }
  2149.  
  2150. onClickOnPromoTableBody(e) {
  2151. let actionElement = e.target;
  2152. if (actionElement.tagName === 'I') {
  2153. actionElement = actionElement.parentElement;
  2154. }
  2155. const row = actionElement.closest('tr');
  2156. if (actionElement.classList.contains('action-remove-promo-code')) {
  2157. e.stopPropagation();
  2158. var promoCode = document.getElementById("promo-code-new");
  2159. var promoObject = { action: "REMOVE", id: row.dataset.promotionId, code: row.dataset.promotionCode };
  2160. promoCode.innerHTML =JSON.stringify(promoObject);
  2161. }
  2162. }
  2163. }
  2164. class UiConfigRenderer extends UiBaseRenderer {
  2165. legacyRenderConfigData(data) {
  2166. for (const prop in data) {
  2167. let element = document.querySelector('[data-prop="' + prop + '"]');
  2168. if(element) {
  2169. if(element.type == 'select-one' || element.type == 'text' || element.type == 'password' || element.type == 'number' || element.type == 'time') {
  2170. element.dataset.original = data[prop];
  2171. element.value = data[prop];
  2172. } else if (element.type == 'checkbox') {
  2173. element.dataset.original = (data[prop] ? "1" : "0");
  2174. element.checked = data[prop];
  2175. }
  2176. }
  2177. }
  2178.  
  2179. let elCfTryGetCodes = document.querySelector('[data-prop="cf.tryGetCodes"]')
  2180. let elCredentialsAutologin = document.querySelector('[data-prop="cf.autologin"]');
  2181. let elCredentialsMode = document.querySelector('[data-prop="cf.credentials.mode"]');
  2182. let elCredentialsEmail = document.querySelector('[data-prop="cf.credentials.email"]');
  2183. let elCredentialsPassword = document.querySelector('[data-prop="cf.credentials.password"]');
  2184. let elDevlogEnabled = document.querySelector('[data-prop="devlog.enabled"]');
  2185. let elDevlogMaxLines = document.querySelector('[data-prop="devlog.maxLines"]');
  2186. let elJtfeyCredentialsMode = document.querySelector('[data-prop="jtfey.credentials.mode"]');
  2187. let elJtfeyCredentialsUsername = document.querySelector('[data-prop="jtfey.credentials.username"]');
  2188. let elJtfeyCredentialsPassword = document.querySelector('[data-prop="jtfey.credentials.password"]');
  2189. let elYCoinCredentialsMode = document.querySelector('[data-prop="ycoin.credentials.mode"]');
  2190. let elYCoinCredentialsUsername = document.querySelector('[data-prop="ycoin.credentials.username"]');
  2191. let elYCoinCredentialsPassword = document.querySelector('[data-prop="ycoin.credentials.password"]');
  2192.  
  2193. let elPostpone = document.querySelector('[data-prop="defaults.postponeMinutes"]');
  2194. let elPostponeMin = document.querySelector('[data-prop="defaults.postponeMinutes.min"]');
  2195. let elPostponeMax = document.querySelector('[data-prop="defaults.postponeMinutes.max"]');
  2196. elPostponeMin.disabled = (elPostpone.value > "0");
  2197. elPostponeMax.disabled = (elPostpone.value > "0");
  2198. if (elPostponeMin.disabled && elPostponeMax.disabled) {
  2199. elPostponeMin.value = elPostpone.value;
  2200. elPostponeMax.value = elPostpone.value;
  2201. }
  2202. elPostpone.onchange = function (e) {
  2203. document.querySelector('[data-prop="defaults.postponeMinutes.min"]').disabled = e.target.value > 0;
  2204. document.querySelector('[data-prop="defaults.postponeMinutes.max"]').disabled = e.target.value > 0;
  2205. if (e.target.value > 0) {
  2206. document.querySelector('[data-prop="defaults.postponeMinutes.min"]').value = e.target.value;
  2207. document.querySelector('[data-prop="defaults.postponeMinutes.max"]').value = e.target.value;
  2208. }
  2209. }
  2210.  
  2211. let elNextRun = document.querySelector('[data-prop="defaults.nextRun"]');
  2212. let elNextRunMin = document.querySelector('[data-prop="defaults.nextRun.min"]');
  2213. let elNextRunMax = document.querySelector('[data-prop="defaults.nextRun.max"]');
  2214. let elNextRunUseCountdown = document.querySelector('[data-prop="defaults.nextRun.useCountdown"]');
  2215. elNextRunMin.disabled = (elNextRun.value > "0");
  2216. elNextRunMax.disabled = (elNextRun.value > "0");
  2217. if (elNextRunMin.disabled && elNextRunMax.disabled) {
  2218. elNextRunMin.value = elNextRun.value;
  2219. elNextRunMax.value = elNextRun.value;
  2220. }
  2221. elNextRun.onchange = function (e) {
  2222. document.querySelector('[data-prop="defaults.nextRun.min"]').disabled = e.target.value > 0;
  2223. document.querySelector('[data-prop="defaults.nextRun.max"]').disabled = e.target.value > 0;
  2224. if (e.target.value > 0) {
  2225. document.querySelector('[data-prop="defaults.nextRun.min"]').value = e.target.value;
  2226. document.querySelector('[data-prop="defaults.nextRun.max"]').value = e.target.value;
  2227. }
  2228. }
  2229.  
  2230. let elSleepMode = document.querySelector('[data-prop="defaults.sleepMode"]');
  2231. let elSleepModeMin = document.querySelector('[data-prop="defaults.sleepMode.min"]');
  2232. let elSleepModeMax = document.querySelector('[data-prop="defaults.sleepMode.max"]');
  2233. elSleepModeMin.disabled = !elSleepMode.checked;
  2234. elSleepModeMax.disabled = !elSleepMode.checked;
  2235. elSleepMode.onchange = function (e) {
  2236. document.querySelector('[data-prop="defaults.sleepMode.min"]').disabled = !e.target.checked;
  2237. document.querySelector('[data-prop="defaults.sleepMode.max"]').disabled = !e.target.checked;
  2238. }
  2239.  
  2240. elCredentialsMode.disabled = !elCredentialsAutologin.checked;
  2241.  
  2242. elCredentialsEmail.disabled = ( (!elCredentialsAutologin.checked || elCredentialsMode.value == "2") ? true : false);
  2243. elCredentialsPassword.disabled = ( (!elCredentialsAutologin.checked || elCredentialsMode.value == "2") ? true : false);
  2244.  
  2245. elCredentialsAutologin.onchange = function (e) {
  2246. document.querySelector('[data-prop="cf.credentials.mode"]').disabled = !e.target.checked;
  2247. if (elCredentialsMode.value == "2") {
  2248. document.querySelector('[data-prop="cf.credentials.email"]').disabled = true;
  2249. document.querySelector('[data-prop="cf.credentials.password"]').disabled = true;
  2250. } else {
  2251. document.querySelector('[data-prop="cf.credentials.email"]').disabled = false;
  2252. document.querySelector('[data-prop="cf.credentials.password"]').disabled = false;
  2253. }
  2254. }
  2255.  
  2256. elCredentialsMode.onchange = function (e) {
  2257. if (e.target.value == "2") {
  2258. document.querySelector('[data-prop="cf.credentials.email"]').disabled = true;
  2259. document.querySelector('[data-prop="cf.credentials.password"]').disabled = true;
  2260. } else {
  2261. document.querySelector('[data-prop="cf.credentials.email"]').disabled = false;
  2262. document.querySelector('[data-prop="cf.credentials.password"]').disabled = false;
  2263. }
  2264. }
  2265.  
  2266. elYCoinCredentialsUsername.disabled = ( (elYCoinCredentialsMode.value == "2") ? true : false);
  2267. elYCoinCredentialsPassword.disabled = ( (elYCoinCredentialsMode.value == "2") ? true : false);
  2268. elYCoinCredentialsMode.onchange = function (e) {
  2269. if (e.target.value == "2") {
  2270. document.querySelector('[data-prop="ycoin.credentials.username"]').disabled = true;
  2271. document.querySelector('[data-prop="ycoin.credentials.password"]').disabled = true;
  2272. } else {
  2273. document.querySelector('[data-prop="ycoin.credentials.username"]').disabled = false;
  2274. document.querySelector('[data-prop="ycoin.credentials.password"]').disabled = false;
  2275. }
  2276. }
  2277.  
  2278. elJtfeyCredentialsUsername.disabled = ( (elJtfeyCredentialsMode.value == "2") ? true : false);
  2279. elJtfeyCredentialsPassword.disabled = ( (elJtfeyCredentialsMode.value == "2") ? true : false);
  2280. elJtfeyCredentialsMode.onchange = function (e) {
  2281. if (e.target.value == "2") {
  2282. document.querySelector('[data-prop="jtfey.credentials.username"]').disabled = true;
  2283. document.querySelector('[data-prop="jtfey.credentials.password"]').disabled = true;
  2284. } else {
  2285. document.querySelector('[data-prop="jtfey.credentials.username"]').disabled = false;
  2286. document.querySelector('[data-prop="jtfey.credentials.password"]').disabled = false;
  2287. }
  2288. }
  2289.  
  2290. elDevlogMaxLines.disabled = !elDevlogEnabled.checked;
  2291. elDevlogEnabled.onchange = function (e) {
  2292. document.querySelector('[data-prop="devlog.maxLines"]').disabled = !e.target.checked;
  2293. }
  2294. }
  2295. }
  2296. class UiWalletRenderer extends UiBaseRenderer {
  2297. legacyRenderWalletTable(data) {
  2298. let tableBody = '';
  2299.  
  2300. for(let i=0, all = data.length; i < all; i++) {
  2301. tableBody += '<tr class="align-middle" data-id="'+ data[i].id + '">';
  2302. tableBody += '<td class="align-middle">' + data[i].name + '</td>';
  2303. tableBody += '<td class="align-middle em-input"><input type="text" class="w-100" onfocus="this.select();" data-field="address" data-original="' + data[i].address + '" value="' + data[i].address + '"></td>';
  2304. tableBody += '</tr>';
  2305. }
  2306.  
  2307. document.getElementById('wallet-table-body').innerHTML = tableBody;
  2308. }
  2309. }
  2310. class UiSchedulesRenderer extends UiBaseRenderer {
  2311. appendEventListeners() {
  2312. document.querySelector('#schedules-toggler').addEventListener('change', this.onScheduleToggled.bind(this));
  2313. }
  2314.  
  2315. onScheduleToggled(e) {
  2316. e.stopPropagation();
  2317. let actionElement = e.target.tagName !== 'LABEL' ? e.target.closest('label') : e.target;
  2318. let otherActiveLabels = [...actionElement.parentElement.querySelectorAll('label.active')].filter(l => l.dataset.schedule != actionElement.dataset.schedule);
  2319. if (otherActiveLabels.length > 0) {
  2320. otherActiveLabels.forEach(l => l.classList.remove('active'));
  2321. }
  2322. this.toggleSchedule(actionElement.dataset.schedule);
  2323. }
  2324.  
  2325. toggleSchedule(uuid) {
  2326.  
  2327. if (uuid) {
  2328. this.selectedSchedule = uuid;
  2329. } else {
  2330. if (!this.selectedSchedule) {
  2331. this.selectedSchedule = 'all';
  2332. }
  2333. }
  2334.  
  2335. [...document.querySelectorAll('#schedule-table-body tr')].forEach((row) => {
  2336. if (this.selectedSchedule == 'all') {
  2337. row.classList.remove('d-none');
  2338. } else if (row.getAttribute('data-schedule') == this.selectedSchedule) {
  2339. row.classList.remove('d-none');
  2340. } else {
  2341. row.classList.add('d-none');
  2342. }
  2343. });
  2344.  
  2345. if (this.selectedSchedule == 'all') {
  2346. [...document.querySelectorAll('#console-log tr')].forEach(x => {
  2347. x.classList.remove('d-none');
  2348. })
  2349. } else {
  2350. [...document.querySelectorAll('#console-log tr')].forEach(x => {
  2351. if (x.getAttribute('data-schedule') == 'false' || x.getAttribute('data-schedule') == this.selectedSchedule) {
  2352. x.classList.remove('d-none');
  2353. } else {
  2354. x.classList.add('d-none');
  2355. }
  2356. })
  2357. }
  2358. };
  2359.  
  2360. renderTBody() {
  2361. let rows = [];
  2362. Schedule.getAllForCrud().forEach(sch => {
  2363. rows.push(this.renderRow(sch));
  2364. });
  2365. return rows.join('');
  2366. }
  2367.  
  2368. renderRow(sch) {
  2369. let row =
  2370. `<tr data-uuid="${sch.uuid}"
  2371. data-order="${sch.order}"
  2372. data-added="${sch.added ? 'true' : 'false'}"
  2373. data-removed="false"
  2374. data-updated="false"
  2375. data-originals='${!sch.added ? JSON.stringify(sch) : ""}'>
  2376. <td class="row-handle"><i class="fas fa-grip-vertical"></i></td>
  2377. <td><div class="input-group input-group-sm color-picker colorpicker-element" style="max-width: 125px;">
  2378. <div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-square" style="color: #${sch.uuid}"></i></span></div>
  2379. <input type="text" name="uuid" class="form-control" data-original-title="" value="${sch.uuid}">
  2380. </div></td>
  2381. <td><input type="text" name="name" class="form-control form-control-sm" value="${sch.name}"></td>
  2382. <td>
  2383. <button type="button" title="Remove" class="btn btn-default btn-sm action-schedule-remove"><i class="fa fa-trash"></i></button>
  2384. </td>
  2385. </tr>`;
  2386. return row;
  2387. }
  2388. }
  2389. class UiSiteParameterRenderer extends UiBaseRenderer {
  2390. static handlers = new Map();
  2391.  
  2392. static registerHandler(name, handler) {
  2393. UiSiteParameterRenderer.handlers.set(name, handler);
  2394. }
  2395.  
  2396. static getHandler(name) {
  2397. const handlerClass = UiSiteParameterRenderer.handlers.get(name);
  2398. return handlerClass || false;
  2399. }
  2400.  
  2401. appendEventListeners() {
  2402. document.querySelector('#modal-site-parameters').addEventListener('click', this.onClickOnModalSiteParameter.bind(this));
  2403. }
  2404.  
  2405. onClickOnModalSiteParameter(e) {
  2406. const modal = document.querySelector('#modal-site-parameters');
  2407. let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
  2408. if (actionElement.classList.contains('modal-save')) {
  2409. e.preventDefault();
  2410. let form = modal.querySelector('.form-container form');
  2411. if (!form.checkValidity()) {
  2412. form.reportValidity();
  2413. return;
  2414. }
  2415. let data = this.uiRenderer.parseContainer(form);
  2416. $(modal).modal('hide');
  2417. }
  2418. }
  2419.  
  2420. renderFields(values) {
  2421. let fieldsHtml = '';
  2422. values.forEach( field => {
  2423. field.text = field.text || field.name.charAt(0).toUpperCase() + field.name.slice(1).toLowerCase().replaceAll('_', ' ');
  2424.  
  2425. switch (field.type) {
  2426. case 'credentials_or_autofilled': // TODO: will need to condition username/email/password!
  2427. break;
  2428. case 'email':
  2429. fieldsHtml += uiRenderer.addInputEmailHtml(field);
  2430. break;
  2431. case 'password':
  2432. fieldsHtml += uiRenderer.addInputPasswordHtml(field);
  2433. break;
  2434. case 'checkbox':
  2435. field.value = (field.value === true || field.value === 'true' || field.value === 1 || field.value === "1") ? true : false;
  2436. fieldsHtml += uiRenderer.addSliderHtml(field);
  2437. break;
  2438. case 'numberInput':
  2439. fieldsHtml += uiRenderer.addInputNumberHtml(field);
  2440. break;
  2441. case 'textInput':
  2442. case 'username':
  2443. field.required = 'true';
  2444. default:
  2445. fieldsHtml += uiRenderer.addInputTextHtml(field);
  2446. break;
  2447. }
  2448. });
  2449. const modalSiteParameters = document.getElementById('modal-site-parameters');
  2450. modalSiteParameters.querySelector('.form-container form').innerHTML = fieldsHtml;
  2451. }
  2452.  
  2453. renderEditSiteParameters(args) { // { site_id: 'x' }
  2454. const site = Site.getById(args.site_id);
  2455.  
  2456. const siteParameters = site.getSiteParameters(); // async? for external site parameters that need to be loaded from other stg...
  2457.  
  2458. if (!siteParameters) {
  2459. console.warn(`Site ${site.id} ${site.name} does not require parameters setup.`);
  2460. return;
  2461. }
  2462.  
  2463. if (!siteParameters.handler) {
  2464. console.warn(`Handler name is missing`);
  2465. return;
  2466. }
  2467.  
  2468. const handlerClass = UiSiteParameterRenderer.getHandler(siteParameters.handler);
  2469. if (!handlerClass) {
  2470. console.warn(`Invalid handler class name: ${siteParameters.handler}`);
  2471. return;
  2472. }
  2473.  
  2474. const handler = new handlerClass(siteParameters.values);
  2475. handler.preRender();
  2476.  
  2477. let fields = [
  2478. { name: 'AUTO_UPDATE_PROMO_CODES', type: 'checkbox', value: 'false' },
  2479. { name: 'MAX_ROLLS_PER_VISIT', type: 'numberInput', value: 1, min: 0 },
  2480. { name: 'AUTO_LOGIN', type: 'checkbox', value: 'true' },
  2481. { name: 'EMAIL', type: 'email', value: '' },
  2482. { name: 'PASSWORD', type: 'password', value: '' }
  2483. ];
  2484.  
  2485. fields.forEach( (f, idx) => {
  2486. if (f.order == null || f.order == undefined) {
  2487. f.order = idx;
  2488. }
  2489. });
  2490.  
  2491. let values = persistence.load(`site_parameters_${args.site_id}`, true) || [];
  2492. for(const field of fields) {
  2493. let vIdx = values.findIndex(v => v.name == field.name);
  2494. if (vIdx > -1) {
  2495. field.value = values[vIdx].value;
  2496. }
  2497. }
  2498. values = fields;
  2499.  
  2500. this.renderFields(values);
  2501.  
  2502. handler.postRender();
  2503. return;
  2504. }
  2505.  
  2506. }
  2507.  
  2508. class UiRenderer {
  2509. constructor () {
  2510. this.sites = new UiSitesRenderer(this);
  2511. this.siteParameters = new UiSiteParameterRenderer(this);
  2512. this.promos = new UiPromosRenderer(this);
  2513. this.config = new UiConfigRenderer(this);
  2514. this.wallet = new UiWalletRenderer(this);
  2515. this.schedules = new UiSchedulesRenderer(this);
  2516. this.selectedSchedule = null;
  2517. }
  2518.  
  2519. initialize() {
  2520. this.appendCSS();
  2521. }
  2522.  
  2523. toast(msg, msgType = "info") {
  2524. toastr[msgType](msg);
  2525. }
  2526.  
  2527. openModal(id, values = null) {
  2528. const dlg = document.querySelector('#modal-dlg');
  2529. dlg.querySelectorAll(".modal-content").forEach(x => x.classList.add('d-none'));
  2530. switch (id) {
  2531. case 'modal-backup':
  2532. console.info('TODO: GM_listValues => loop keys => save json as blob');
  2533. break;
  2534.  
  2535. case 'modal-ereport':
  2536. case 'modal-config':
  2537. case 'modal-site':
  2538. document.getElementById("target-spinner").innerHTML = JSON.stringify({id: id, siteId: values});
  2539. document.getElementById("modal-spinner").classList.remove("d-none");
  2540. dlg.querySelector('div').classList.add('modal-lg');
  2541. break;
  2542. case 'modal-add-site':
  2543. this.sites.renderAddExternalSite();
  2544. document.getElementById(id).classList.remove("d-none");
  2545. dlg.querySelector('div').classList.remove('modal-lg');
  2546. break;
  2547. case 'modal-slAlert':
  2548. shortlinkAlert.load(id);
  2549. dlg.querySelector('div').classList.add('modal-lg');
  2550. break;
  2551. case 'modal-schedules':
  2552. document.getElementById(id).querySelector('table tbody').innerHTML = this.schedules.renderTBody();
  2553. this.appendColorPickers('.color-picker');
  2554. dlg.querySelector('div').classList.remove('modal-lg');
  2555. document.getElementById(id).classList.remove("d-none");
  2556. break;
  2557. case 'modal-assign-schedule':
  2558. this.sites.renderAssignScheduleToSite(values);
  2559. document.getElementById(id).classList.remove("d-none");
  2560. dlg.querySelector('div').classList.remove('modal-lg');
  2561. break;
  2562. case 'modal-site-parameters':
  2563. this.siteParameters.renderEditSiteParameters(values);
  2564. document.getElementById(id).classList.remove("d-none");
  2565. dlg.querySelector('div').classList.remove('modal-lg');
  2566. break;
  2567. default:
  2568. dlg.querySelector('div').classList.add('modal-lg');
  2569. document.getElementById(id).classList.remove("d-none");
  2570. break;
  2571. }
  2572.  
  2573. $(dlg).modal('show');
  2574. }
  2575.  
  2576. appendEventListeners() {
  2577. for (const renderer in this) {
  2578. if (this[renderer] && typeof this[renderer].appendEventListeners === 'function') {
  2579. this[renderer].appendEventListeners();
  2580. }
  2581. }
  2582. $('[data-toggle="tooltip"]').tooltip({
  2583. trigger: 'hover'
  2584. });
  2585. }
  2586.  
  2587. appendCSS() {
  2588. let css = document.createElement('style');
  2589. css.innerHTML = `
  2590. td.em-input {
  2591. padding-top: 0;
  2592. padding-bottom: 0;
  2593. }
  2594. pre {
  2595. height: 145px;
  2596. width:100%;
  2597. white-space: pre-wrap;
  2598. padding-left: 1em;
  2599. }
  2600. pre span {
  2601. display: block;
  2602. }
  2603. .row-schedule-handle {
  2604.  
  2605. }
  2606. .grabbable:not(.d-none):not(.in-use) {
  2607. cursor: move;
  2608. cursor: grab;
  2609. cursor: -moz-grab;
  2610. cursor: -webkit-grab;
  2611. }
  2612.  
  2613. .grabbable:not(.d-none):not(.in-use):active {
  2614. cursor: grabbing;
  2615. cursor: -moz-grabbing;
  2616. cursor: -webkit-grabbing;
  2617. }
  2618.  
  2619. .row-handle {
  2620. cursor: grab;
  2621. }
  2622.  
  2623. .dropdown-item {
  2624. cursor: pointer;
  2625. }
  2626.  
  2627. #schedule-table th,td {
  2628. vertical-align: middle;
  2629. padding-top: .25rem!important;
  2630. padding-bottom: .25rem!important;
  2631. }
  2632.  
  2633. #schedule-table-body td.em-input input[readonly] {
  2634. background-color:transparent;
  2635. border: 0;
  2636. font-size: 1em;
  2637. }
  2638.  
  2639. td[data-field="displayName"] .input-group-prepend .input-group-text {
  2640. background-color: transparent;
  2641. border-color: transparent;
  2642. font-size: 1em;
  2643. }
  2644.  
  2645. .custom-switch input,label {
  2646. cursor: pointer;
  2647. }
  2648. `;
  2649. document.head.appendChild(css);
  2650. }
  2651.  
  2652. addLegacySliderHtml(propName, propValue, text) {
  2653. return `<label class="switch"><input type="checkbox" ${propName}="${propValue}" data-original="1"><span class="slider round"></span></label> ${text}`;
  2654. }
  2655.  
  2656. addSliderHtml(field) {
  2657. const rndStr = helpers.randomString(8);
  2658. return `<div class="form-group"><div class="custom-control custom-switch custom-switch-off-danger custom-switch-on-success">
  2659. <input type="checkbox" class="custom-control-input" name="${field.name}" id="${rndStr}" ${field.value ? 'checked' : ''}>
  2660. <label class="custom-control-label" for="${rndStr}">${field.text}</label>
  2661. </div></div>`;
  2662. }
  2663.  
  2664. addInputEmailHtml(field) {
  2665. const rndStr = helpers.randomString(8);
  2666. const pattern = "[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$";
  2667. return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
  2668. <div class="col-sm-8">
  2669. <input type="email" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" pattern="${pattern}" value="${field.value || ''}">
  2670. </div></div>`;
  2671.  
  2672. }
  2673.  
  2674. addInputPasswordHtml(field) {
  2675. const rndStr = helpers.randomString(8);
  2676. return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
  2677. <div class="col-sm-8">
  2678. <input type="password" min="${field.min !== undefined ? field.min : ''}" min="${field.max !== undefined ? field.max : ''}" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
  2679. </div></div>`;
  2680. }
  2681.  
  2682. addInputTextHtml(field) {
  2683. const rndStr = helpers.randomString(8);
  2684. return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
  2685. <div class="col-sm-8">
  2686. <input type="text" class="form-control" required="${field.required || 'false'}" id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
  2687. </div></div>`;
  2688. }
  2689.  
  2690. addInputNumberHtml(field) {
  2691. const rndStr = helpers.randomString(8);
  2692. return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
  2693. <div class="col-sm-8">
  2694. <input type="number" step="${field.step || 1}" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
  2695. </div></div>`;
  2696. }
  2697.  
  2698. parseContainer(container) {
  2699. let obj = {};
  2700. Object.assign(obj, container.dataset);
  2701. let inputs = container.querySelectorAll('input, select');
  2702. inputs.forEach(function (input) {
  2703. if (input.type == 'checkbox') {
  2704. obj[input.name] = input.checked ? 'true' : 'false';
  2705. } else if (input.type == 'number') {
  2706. obj[input.name] = +input.value;
  2707. } else {
  2708. obj[input.name] = input.value;
  2709. }
  2710. });
  2711.  
  2712. for (const p in obj) { // type converter. TODO: add int, float, etc.
  2713. if (obj[p] === 'true') { obj[p] = true }
  2714. if (obj[p] === 'false') { obj[p] = false }
  2715.  
  2716. if (p == 'uuid') {
  2717. obj[p] = obj[p].toLowerCase().replace('#', '');
  2718. }
  2719. if (p == 'originals') {
  2720. try {
  2721. obj[p] = JSON.parse(obj[p]);
  2722. } catch (err) { delete obj[p]; }
  2723. }
  2724. }
  2725. return obj;
  2726. }
  2727.  
  2728. parseTable(table) {
  2729. let rows = table.querySelectorAll('tbody tr');
  2730. let data = [];
  2731. rows.forEach( (r, idx) => {
  2732. let obj = this.parseContainer(r);
  2733. obj.order = '' + idx; // fix order
  2734. if (!(obj.added && obj.removed)) { // skip if it was just added and removed
  2735. data.push(obj);
  2736. }
  2737. });
  2738.  
  2739. return data;
  2740. }
  2741.  
  2742. appendColorPickers(selector) {
  2743. $(selector).each(function () {
  2744. $(this).colorpicker();
  2745. $(this).on('colorpickerChange', function(event) {
  2746. $(event.target.querySelector('.fa-square')).css('color', event.color.toString());
  2747. });
  2748. });
  2749. }
  2750. }
  2751.  
  2752. class EventEmitter {
  2753. constructor() {
  2754. this.events = {};
  2755. }
  2756.  
  2757. on(eventName, callback) {
  2758. if (!this.events[eventName]) {
  2759. this.events[eventName] = [];
  2760. }
  2761. this.events[eventName].push(callback);
  2762. }
  2763.  
  2764. emit(eventName, data) {
  2765. const eventCallbacks = this.events[eventName];
  2766. if (eventCallbacks) {
  2767. eventCallbacks.forEach(callback => {
  2768. callback(data);
  2769. });
  2770. }
  2771. }
  2772. }
  2773.  
  2774. class Timeout {
  2775. constructor() {
  2776. this.startedAt;
  2777. this.interval;
  2778. this.cb = (() => { shared.closeWithError(K.ErrorType.TIMEOUT, '') });
  2779. let paramTimeout = shared.getParam('timeout');
  2780. if (paramTimeout) {
  2781. this.wait = paramTimeout * 60;
  2782. } else {
  2783. this.wait = shared.getConfig()['defaults.timeout'] * 60
  2784. }
  2785. this.wait += 30; // add a threshold
  2786. this.restart();
  2787. }
  2788.  
  2789. get elapsed() {
  2790. return Date.now() - this.startedAt;
  2791. }
  2792.  
  2793. restart(addSeconds = false) {
  2794. if(this.interval) {
  2795. clearTimeout(this.interval);
  2796. }
  2797. this.startedAt = Date.now();
  2798. if(addSeconds) {
  2799. this.wait = this.wait + addSeconds;
  2800. }
  2801. this.interval = setTimeout( () => { this.cb() }, this.wait * 1000);
  2802. }
  2803. }
  2804.  
  2805. class Timer {
  2806. constructor(params) {
  2807. Object.assign(this, params);
  2808. if(!useTimer || (this.webType && !Timer.webTypes().includes(this.webType))) {
  2809. return;
  2810. }
  2811. this.delay = this.delaySeconds * 1000;
  2812.  
  2813. }
  2814.  
  2815. static webTypes() {
  2816. return [K.WebType.FREELITECOIN, K.WebType.FREEETHEREUMIO, K.WebType.BIGBTC, K.WebType.FCRYPTO, K.WebType.FPB] // , K.WebType.BSCADS]
  2817. };
  2818.  
  2819. startCheck(webType) {
  2820. this.webType = webType;
  2821. if(!useTimer || (helpers.hasValue(webType) && !Timer.webTypes().includes(webType))) {
  2822. return;
  2823. }
  2824. persistence.save(this.uuid + '_lastAccess', Date.now());
  2825. this.interval = setInterval(() => {
  2826. this.isAlive();
  2827. }, this.delay);
  2828. }
  2829.  
  2830. stopCheck() {
  2831. if(!useTimer) {
  2832. return;
  2833. }
  2834. clearInterval(this.interval);
  2835. }
  2836.  
  2837. tick() {
  2838. if(!useTimer) {
  2839. return;
  2840. }
  2841. persistence.save(this.uuid + '_lastAccess', Date.now());
  2842. }
  2843.  
  2844. isAlive() {
  2845. return;
  2846. }
  2847. }
  2848.  
  2849. const wait = ms => new Promise(resolve => setTimeout(resolve, ms || 3000));
  2850.  
  2851. class CrawlerWidget {
  2852. constructor(params) {
  2853. if (!params || (!params.selector && !params.fnSelector)) {
  2854. throw new Error('CrawlerWidget requires a selector or a function selector parameter');
  2855. }
  2856. this.context = this.context || document;
  2857. Object.assign(this, params);
  2858. }
  2859.  
  2860. get isUserFriendly() {
  2861. if (this.selector) {
  2862. this.element = this.context.isUserFriendly(this.selector);
  2863. return this.element;
  2864. } else {
  2865. this.element = this.fnSelector();
  2866. return this.element;
  2867. }
  2868. }
  2869. }
  2870.  
  2871. class ReadableWidget extends CrawlerWidget {
  2872. constructor(params) {
  2873. if (params && !params.parser) {
  2874. params.parser = Parsers.innerText; //default parser
  2875. }
  2876. super(params);
  2877. }
  2878.  
  2879. get value() {
  2880. if (this.isUserFriendly) {
  2881. return this.parser(this.element, this.options);
  2882. } else {
  2883. return '';
  2884. }
  2885. }
  2886. }
  2887.  
  2888. class TextboxWidget extends CrawlerWidget {
  2889. get value() {
  2890. if (!this.isUserFriendly) {
  2891. return '';
  2892. }
  2893. return this.element.value;
  2894. }
  2895.  
  2896. set value(newValue) {
  2897. if (!this.isUserFriendly) {
  2898. return '';
  2899. }
  2900. this.element.value = newValue;
  2901. return '';
  2902. }
  2903. }
  2904.  
  2905. class ButtonWidget extends CrawlerWidget {
  2906.  
  2907. click() {
  2908. if (this.isUserFriendly) {
  2909. this.element.click();
  2910. return Promise.resolve(true);
  2911. } else {
  2912. }
  2913. }
  2914. }
  2915.  
  2916. class SubmitWidget extends CrawlerWidget {
  2917. click() {
  2918. if (this.isUserFriendly) {
  2919. let frm = this.element;
  2920. while(frm.nodeName != 'FORM' && frm.nodeName != null) {
  2921. frm = frm.parentElement;
  2922. }
  2923. if (frm.nodeName == 'FORM') {
  2924. frm.submit();
  2925. } else {
  2926. return;
  2927. }
  2928. return Promise.resolve(true);
  2929. } else {
  2930. }
  2931. }
  2932. }
  2933.  
  2934. class CountdownWidget extends CrawlerWidget {
  2935. constructor(params) {
  2936. if (params && !params.parser) {
  2937. params.parser = Parsers.innerText; //default parser
  2938. }
  2939. super(params);
  2940. }
  2941.  
  2942. get timeLeft() {
  2943. if (this.isUserFriendly) {
  2944. return this.parser(this.element, this.options);
  2945. } else {
  2946. throw new Error(`CountdownWidget (selector: '${this.selector}') cannot be read`);
  2947. }
  2948. }
  2949. }
  2950.  
  2951. class Parsers {
  2952. static innerText(elm) { // '0.12341234' => '0.12341234'
  2953. try {
  2954. return elm.innerText;
  2955. } catch (err) { }
  2956. }
  2957. static trimNaNs(elm) { // 'You won 0.12341234 TRX' => '0.12341234'
  2958. try {
  2959. return elm.innerText.replace(/[^\d.-]/g, '');
  2960. } catch (err) { }
  2961. }
  2962. static splitAndIdxTrimNaNs(elm, options) { // '17.96 Coins (17.50 + 0.46)' => 17.96
  2963. try {
  2964. return elm.innerText.split(options.splitter)[options.idx].replace(/[^\d.-]/g, '');
  2965. } catch (err) { }
  2966. }
  2967. static innerTextIntToFloat(elm) { // 'You won 1234 satoshis' => 0.00001234
  2968. try {
  2969. let sats = elm.innerText.replace(/\D/g, '');
  2970. return sats / 100000000;
  2971. } catch (err) { }
  2972. }
  2973. static innerTextJoinedToInt(elm) { // '7|2|9|6' => 7296
  2974. try {
  2975. return parseInt([... elm].map( x => x.innerText).join(''));
  2976. } catch (err) { }
  2977. }
  2978. static stormGainCountdown(elm) { // '3:01:01' => 120000
  2979. try {
  2980. let timeLeft = elm.innerText.split(':');
  2981. if (timeLeft[0] == 'Synchronizing') {
  2982. }
  2983.  
  2984. if(timeLeft.length === 3) {
  2985. return parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
  2986. }
  2987. } catch (err) {
  2988. return null;
  2989. }
  2990. }
  2991. static kingBizCountdown(elm) { // '4|2' => 42
  2992. try {
  2993. let itms = elm.querySelectorAll('.flip-clock-active .up');
  2994. if (itms.length > 1 && itms[0].isVisible() && itms[1].isVisible()) {
  2995. return parseInt([itms[0].innerText, itms[1].innerText].join(''));
  2996. }
  2997. } catch (err) {
  2998. return null;
  2999. }
  3000. }
  3001. static freeGrcCountdown(elm) { // 'Wait for 53:31 before next roll' => 53
  3002. try {
  3003. let val = elm.innerText.split(':')[0];
  3004. val = val.replace(/[^\d.-]/g, '');
  3005. return parseInt(val);
  3006. } catch (err) {
  3007. return null;
  3008. }
  3009. }
  3010. static bestChangeCountdown(elm) { // '00:58:35' => 58
  3011. try {
  3012. if (elm.value) {
  3013. let timeLeft = elm.value.split(':');
  3014. if (timeLeft.length > 1) {
  3015. return parseInt(timeLeft[1]);
  3016. }
  3017. }
  3018. } catch (err) {
  3019. return null;
  3020. }
  3021. }
  3022. static freeEthereumIoClaimed(elm) { // 'You won 0.12341234 TRX and rolled number 7623' => 0.12341234
  3023. try {
  3024. let line = elm.innerHTML;
  3025. let idx = line.search(/0\./);
  3026. return parseFloat(line.slice(idx, idx + 10));
  3027. } catch (err) { }
  3028. }
  3029. static bfBoxClaimed(elm) {
  3030. try {
  3031. let currency = elm.querySelector('.free-box__withdraw-currency').innerText;
  3032. let val = elm.querySelector('.free-box__need-sum').innerText.replace(/ /g,'').split('/')[1];
  3033.  
  3034. if (currency == 'Satoshi') {
  3035. val = val/100000000;
  3036. }
  3037. return val;
  3038. } catch (err) {
  3039. return null;
  3040. }
  3041. }
  3042. static g8ClaimsLeft(elm) {
  3043. try {
  3044. if (elm.innerText.includes('\nYou have ')) { // 'Claim 183848 satoshi (0.00012 USD) every 20 Seconds\nYou have 70 claims left today.'
  3045. let val = elm.innerText.split('\nYou have ')[1].split(' ')[0];
  3046. return val;
  3047. } else {
  3048. return null;
  3049. }
  3050. } catch (err) {
  3051. return null;
  3052. }
  3053. }
  3054. static cbgClaimed(elm) {
  3055. try {
  3056. if (elm.innerText.includes('was sent to')) { //?? was sent to you on...
  3057. let val = elm.innerText.trim().split(' ')[0];
  3058. if (elm.innerText.includes('oshi') || elm.innerText.includes('gwei')) {
  3059. val = val/100000000;
  3060. }
  3061. return val;
  3062. } else {
  3063. return null;
  3064. }
  3065. } catch (err) {
  3066. return null;
  3067. }
  3068. }
  3069. static dutchysClaimed(elm) { // 'You Won :101 DUTCHY + 20 XP' => 101
  3070. try {
  3071. let splitted = elm.innerText.split('DUTCHY');
  3072. return splitted[0].replace(/[^\d.-]/g, '');
  3073. } catch (err) { shared.devlog(`@Parsers.dutchysClaimed, with element [${elm}] Error: ${err}`); }
  3074. }
  3075. static dutchysClaimedToFloat(elm) { // 'You Won :22437 ADA + 100 XP' => 0.00022437
  3076. try {
  3077. let sats = elm.innerText.split('+');
  3078. sats = sats[0].replace(/\D/g, '');
  3079. return sats / 100000000;
  3080. } catch (err) { shared.devlog(`@Parsers.dutchysClaimedToFloat, with element [${elm}] Error: ${err}`); }
  3081. }
  3082. static splitAndIdxToInt(elm, options) { // options: { splitter: ':', idx: 1} // '26 Minutes 23' w/spliiter='Minutes' => 26
  3083. try {
  3084. return parseInt(elm.innerText.split(options.splitter)[options.idx].trim());
  3085. } catch (err) { shared.devlog(`Error @Parsers.splitAndIdxToInt: ${err}`); }
  3086. }
  3087. static fromTextTimer(elm) { // '0 hours 11 minutes 1 seconds' => 12 minutes
  3088. try {
  3089. let hours, minutes;
  3090. hours = +elm.innerText.split(' hours')[0].trim();
  3091. minutes = +elm.innerText.split('hours ')[1].split('minutes')[0].trim();
  3092. return hours * 60 + minutes + 1;
  3093. } catch (err) { shared.devlog(`Error @Parsers.splitAndIdxToInt: ${err}`); }
  3094. }
  3095. }
  3096. class ImageProcessor {
  3097. constructor(img) {
  3098. this._img = img;
  3099. }
  3100.  
  3101. isImageComplete() {
  3102. return this._img && this._img.complete;
  3103. }
  3104.  
  3105. createDrawer(width, height) {
  3106. let canvas = document.createElement('canvas');
  3107. canvas.setAttribute('width', width);
  3108. canvas.setAttribute('height', height);
  3109. let ctx = canvas.getContext('2d');
  3110. return {
  3111. canvas: canvas,
  3112. ctx: ctx
  3113. };
  3114. }
  3115.  
  3116. getDrawer() {
  3117. return this._drawer;
  3118. }
  3119.  
  3120. toCanvas() {
  3121. this._drawer = this.createDrawer(this._img.width, this._img.height);
  3122. this._drawer.ctx.drawImage(this._img, 0, 0);
  3123. }
  3124.  
  3125. foreach(filter) {
  3126. let imgData = this._drawer.ctx.getImageData(0, 0, this._drawer.canvas.width, this._drawer.canvas.height);
  3127. for (var x = 0; x < imgData.width; x++) {
  3128. for (var y = 0; y < imgData.height; y++) {
  3129. var i = x * 4 + y * 4 * imgData.width;
  3130. var pixel = { r: imgData.data[i + 0], g: imgData.data[i + 1], b: imgData.data[i + 2] };
  3131.  
  3132. pixel = filter(pixel);
  3133.  
  3134. imgData.data[i + 0] = pixel.r;
  3135. imgData.data[i + 1] = pixel.g;
  3136. imgData.data[i + 2] = pixel.b;
  3137. imgData.data[i + 3] = 255;
  3138. }
  3139. }
  3140. this._drawer.ctx.putImageData(imgData, 0, 0);
  3141. }
  3142.  
  3143. binarize (threshold) {
  3144. var image = this._drawer.canvas.getContext('2d').getImageData(0, 0, this._drawer.canvas.width, this._drawer.canvas.height);
  3145. for (var x = 0; x < image.width; x++) {
  3146. for (var y = 0; y < image.height; y++) {
  3147. var i = x * 4 + y * 4 * image.width;
  3148. var brightness = 0.34 * image.data[i] + 0.5 * image.data[i + 1] + 0.16 * image.data[i + 2];
  3149. image.data[i] = brightness >= threshold ? 255 : 0;
  3150. image.data[i + 1] = brightness >= threshold ? 255 : 0;
  3151. image.data[i + 2] = brightness >= threshold ? 255 : 0;
  3152. image.data[i + 3] = 255;
  3153. }
  3154. }
  3155. this._drawer.canvas.getContext('2d').putImageData(image, 0, 0);
  3156. }
  3157.  
  3158. invert(filter) {
  3159. this.foreach(function (p) {
  3160. p.r = 255 - p.r;
  3161. p.g = 255 - p.g;
  3162. p.b = 255 - p.b;
  3163. return p;
  3164. });
  3165. }
  3166.  
  3167. imgDataToBool(imgData) {
  3168. let character = [];
  3169. const data = imgData.data;
  3170. for (let i = 0; i < imgData.data.length; i += 4) {
  3171. let val = data[i] + data[i+1] + data[i+2];
  3172. character.push(val == 0 ? true : false);
  3173. }
  3174. return character;
  3175. }
  3176. }
  3177.  
  3178. class CaptchaWidget extends CrawlerWidget {
  3179. constructor(params) {
  3180. super(params);
  3181. }
  3182.  
  3183. solve() { return true; }
  3184.  
  3185. async isSolved() { return false; }
  3186. }
  3187.  
  3188. class RecaptchaWidget extends CaptchaWidget {
  3189. constructor(params) {
  3190. let defaultParams = {
  3191. selector: function() { return grecaptcha },
  3192. waitMs: [1000, 5000],
  3193. timeoutMs: 4 * 60 * 1000
  3194. };
  3195. for (let p in params) {
  3196. defaultParams[p] = params[p];
  3197. }
  3198. super(defaultParams);
  3199. }
  3200.  
  3201. get isUserFriendly() {
  3202. this.element = grecaptcha;
  3203. return this.element;
  3204. }
  3205.  
  3206. async isSolved() {
  3207. return wait().then( () => {
  3208. try {
  3209. if (this.isUserFriendly && this.element.hasOwnProperty('getPageId') && this.element.getPageId() && this.element.hasOwnProperty('getResponse') && (typeof(this.element.getResponse) == 'function')
  3210. && this.element.getResponse().length > 0) {
  3211. return Promise.resolve(true);
  3212. }
  3213. } catch (err) {}
  3214. return this.isSolved();
  3215. });
  3216. }
  3217. }
  3218.  
  3219. class HCaptchaWidget extends CaptchaWidget {
  3220. constructor(params) {
  3221. let defaultParams = {
  3222. selector: '.h-captcha > iframe',
  3223. waitMs: [1000, 5000],
  3224. timeoutMs: 4 * 60 * 1000
  3225. };
  3226. for (let p in params) {
  3227. defaultParams[p] = params[p];
  3228. }
  3229. super(defaultParams);
  3230. }
  3231.  
  3232. async isSolved() {
  3233. return wait().then( () => {
  3234. if (this.isUserFriendly && this.element.hasAttribute('data-hcaptcha-response') && this.element.getAttribute('data-hcaptcha-response').length > 0) {
  3235. return Promise.resolve(true);
  3236. }
  3237. return this.isSolved();
  3238. });
  3239. }
  3240. }
  3241.  
  3242. class BKCaptchaWidget extends CaptchaWidget {
  3243. constructor() {
  3244. let defaultParams = {
  3245. selector: 'img[src="antibot.php"]',
  3246. waitMs: [1000, 5000],
  3247. timeoutMs: 4 * 60 * 1000
  3248. };
  3249. super(defaultParams);
  3250. this._imgProcessor;
  3251. this._characters = [];
  3252. }
  3253.  
  3254. charList() {
  3255. return [{"answer":"g","width":8,"height":9,"bools":[false,true,true,true,true,true,false,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3256. {"answer":"5","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3257. {"answer":"W","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true]},
  3258. {"answer":"O","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3259. {"answer":"N","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,false,true,true,true,true,true,true,false,false,true,true,true,true,true,true,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,true,true,true,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,true,true,true,false,false,false,false,true,true]},
  3260. {"answer":"T","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
  3261. {"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
  3262. {"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
  3263. {"answer":"B","width":8,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false]},
  3264. {"answer":"3","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false]},
  3265. {"answer":"s","width":8,"height":7,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3266. {"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3267. {"answer":"L","width":7,"height":10,"bools":[true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
  3268. {"answer":"Z","width":7,"height":10,"bools":[false,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
  3269. {"answer":"F","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3270. {"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3271. {"answer":"T","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
  3272. {"answer":"8","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3273. {"answer":"P","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3274. {"answer":"J","width":6,"height":10,"bools":[false,false,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,true,false,false,false,true,true,true,true,false,true,true,false,false,true,true,true,false,false]},
  3275. {"answer":"y","width":8,"height":9,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,true,false,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3276. {"answer":"r","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3277. {"answer":"R","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3278. {"answer":"M","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3279. {"answer":"d","width":8,"height":10,"bools":[false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
  3280. {"answer":"E","width":7,"height":10,"bools":[true,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
  3281. {"answer":"7","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3282. {"answer":"Z","width":7,"height":10,"bools":[true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
  3283. {"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
  3284. {"answer":"K","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true]},
  3285. {"answer":"6","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,false,false,false,false,true,true,true,true,false,false]},
  3286. {"answer":"H","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3287. {"answer":"5","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3288. {"answer":"Y","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
  3289. {"answer":"d","width":8,"height":10,"bools":[false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
  3290. {"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
  3291. {"answer":"z","width":6,"height":7,"bools":[true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true]},
  3292. {"answer":"n","width":8,"height":7,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3293. {"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
  3294. {"answer":"8","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3295. {"answer":"t","width":8,"height":9,"bools":[false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false]},
  3296. {"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
  3297. {"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
  3298. {"answer":"Z","width":7,"height":10,"bools":[true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,true,true]},
  3299. {"answer":"1","width":6,"height":10,"bools":[false,false,true,true,false,false,false,true,true,true,false,false,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
  3300. {"answer":"m","width":8,"height":7,"bools":[true,false,true,true,false,true,true,false,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true]},
  3301. {"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
  3302. {"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
  3303. {"answer":"C","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3304. {"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
  3305. {"answer":"2","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true]},
  3306. {"answer":"h","width":8,"height":10,"bools":[true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3307. {"answer":"F","width":7,"height":10,"bools":[true,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false]},
  3308. {"answer":"c","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3309. {"answer":"P","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,false,false,false,false,false,false,false]},
  3310. {"answer":"r","width":8,"height":7,"bools":[true,true,false,true,true,true,false,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false]},
  3311. {"answer":"Y","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
  3312. {"answer":"S","width":8,"height":10,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3313. {"answer":"u","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
  3314. {"answer":"M","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3315. {"answer":"S","width":8,"height":10,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3316. {"answer":"g","width":8,"height":9,"bools":[false,true,true,true,true,true,false,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
  3317. {"answer":"U","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3318. {"answer":"k","width":7,"height":10,"bools":[true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,true,true,false,true,true,false,true,true,false,false,true,true,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true]},
  3319. {"answer":"4","width":8,"height":10,"bools":[false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true,false,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false]},
  3320. {"answer":"A","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3321. {"answer":"b","width":8,"height":10,"bools":[true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false]},
  3322. {"answer":"I","width":6,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
  3323. {"answer":"o","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
  3324. {"answer":"i","width":6,"height":10,"bools":[false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
  3325. {"answer":"C","width":8,"height":10,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3326. {"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3327. {"answer":"w","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,true,true,true,true,true,true,false,true,true,false,false,true,true,false]},
  3328. {"answer":"f","width":8,"height":10,"bools":[false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false]},
  3329. {"answer":"j","width":7,"height":12,"bools":[false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,false]},
  3330. {"answer":"F","width":6,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false]},
  3331. {"answer":"x","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true]},
  3332. {"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3333. {"answer":"G","width":8,"height":10,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3334. {"answer":"0","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false]},
  3335. {"answer":"0","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false]},
  3336. {"answer":"D","width":8,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false]},
  3337. {"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
  3338. {"answer":"X","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
  3339. {"answer":"Q","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,true,true,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,true]}];
  3340. }
  3341.  
  3342. async isReady() {
  3343. return wait().then( () => {
  3344. let img = document.querySelector(this.selector);
  3345. if(img && img.complete) {
  3346. this._imgProcessor = new ImageProcessor(img);
  3347. return Promise.resolve(true);
  3348. }
  3349. return this.isReady();
  3350. });
  3351. }
  3352.  
  3353. async isSolved() {
  3354. return this.isReady()
  3355. .then( () => this.solve())
  3356. .then( (solution) => {
  3357. document.querySelector('input[name="kodecaptcha"]').value = solution;
  3358. return Promise.resolve(true);
  3359. })
  3360. .catch(err => {
  3361. return Promise.reject(`Error ${err}`);
  3362. });
  3363. }
  3364.  
  3365. preProcessImage() {
  3366. this._imgProcessor.toCanvas();
  3367. this._imgProcessor.binarize(200);
  3368. this._imgProcessor.invert();
  3369. }
  3370.  
  3371. cropCharacter(startFrom = 0) {
  3372. let imgData = this._imgProcessor.getDrawer().ctx.getImageData(startFrom, 0, this._imgProcessor.getDrawer().canvas.width - startFrom, this._imgProcessor.getDrawer().canvas.height);
  3373. let newBounds = { left: null, right:null, top: null, bottom: null };
  3374. let readingCharacter = false;
  3375. let endOfCharacter = null;
  3376.  
  3377. for (var x = 0; x < imgData.width; x++) {
  3378. if (endOfCharacter) {
  3379. newBounds.right = endOfCharacter;
  3380. break;
  3381. }
  3382.  
  3383. let isColumnEmpty = true;
  3384. for (var y = 0; y < imgData.height; y++) {
  3385. var i = x * 4 + y * 4 * imgData.width;
  3386. var pixel = { r: imgData.data[i + 0], g: imgData.data[i + 1], b: imgData.data[i + 2] };
  3387.  
  3388. if (pixel.r + pixel.g + pixel.b == 0) {
  3389. if (newBounds.left == null || newBounds.left > x) {
  3390. newBounds.left = x;
  3391. }
  3392. if (newBounds.right == null || newBounds.right < x) {
  3393. newBounds.right = x;
  3394. }
  3395.  
  3396. if (newBounds.top == null || newBounds.top > y) {
  3397. newBounds.top = y;
  3398. }
  3399.  
  3400. if (newBounds.bottom == null || newBounds.bottom < y) {
  3401. newBounds.bottom = y;
  3402. }
  3403. readingCharacter = true;
  3404. isColumnEmpty = false;
  3405. }
  3406. }
  3407.  
  3408. if (isColumnEmpty && readingCharacter) {
  3409. endOfCharacter = x - 1;
  3410. break;
  3411. }
  3412. }
  3413.  
  3414. return {
  3415. x: startFrom + newBounds.left,
  3416. y: newBounds.top,
  3417. width: newBounds.right - newBounds.left + 1,
  3418. height: newBounds.bottom - newBounds.top + 1,
  3419. nextBegins: startFrom + newBounds.right + 1
  3420. };
  3421. }
  3422.  
  3423. splitInCharacters() {
  3424. let chars = [];
  3425. let i =0;
  3426. do {
  3427. chars.push(this.cropCharacter( i== 0 ? 0 : chars[i-1].nextBegins ) );
  3428. let copy = document.createElement('canvas').getContext('2d');
  3429. copy.canvas.width = chars[i].width;
  3430. copy.canvas.height = chars[i].height;
  3431.  
  3432. let trimmedData = this._imgProcessor.getDrawer().ctx.getImageData(chars[i].x, chars[i].y, chars[i].width, chars[i].height);
  3433. copy.putImageData(trimmedData, 0, 0);
  3434.  
  3435. chars[i].bools = this._imgProcessor.imgDataToBool(trimmedData);
  3436. chars[i].dataUrl = copy.canvas.toDataURL("image/png");
  3437.  
  3438. i++;
  3439. } while(i < 5);
  3440.  
  3441. this._characters = chars;
  3442. }
  3443.  
  3444. guess(charElm) {
  3445. let bestGuess = {
  3446. answer: '',
  3447. blacksMatched: 0,
  3448. blacksMissed: 0,
  3449. percentageBlacks: 0,
  3450. exactMatch: false
  3451. };
  3452.  
  3453. let totalPixels = charElm.width * charElm.height;
  3454. let totalBlacks = charElm.bools.filter(x => x === true).length;
  3455. this.charList().filter(x => x.answer != '').forEach( function (elm) {
  3456. if (bestGuess.exactMatch) {
  3457. return;
  3458. }
  3459. if (charElm.width == elm.width && charElm.height == elm.height) {
  3460. if (charElm.bools.join(',') == elm.bools.join(',')) {
  3461. bestGuess = {
  3462. answer: elm.answer,
  3463. percentageBlacks: 100,
  3464. exactMatch: true
  3465. };
  3466. return;
  3467. }
  3468.  
  3469. let blacksMatched = 0;
  3470. let blacksMissed = 0;
  3471. let percentageBlacks = 0;
  3472. for (let p = 0; p < totalPixels; p++) {
  3473. if (charElm.bools[p] === true || elm.bools[p] === true) {
  3474. if (elm.bools[p] == charElm.bools[p]) {
  3475. blacksMatched++;
  3476. } else {
  3477. blacksMissed++;
  3478. }
  3479. }
  3480. }
  3481.  
  3482. if (blacksMatched != 0 || blacksMissed != 0) {
  3483. percentageBlacks = blacksMatched/(blacksMatched + blacksMissed);
  3484. }
  3485.  
  3486. if (percentageBlacks > bestGuess.percentageBlacks) {
  3487. bestGuess = {
  3488. answer: elm.answer,
  3489. blacksMatched: blacksMatched,
  3490. blacksMissed: blacksMissed,
  3491. percentageBlacks: percentageBlacks
  3492. };
  3493. }
  3494. }
  3495. });
  3496. return bestGuess;
  3497. }
  3498.  
  3499. async solve() {
  3500. let solution = '';
  3501. if(this._imgProcessor.isImageComplete()) {
  3502. this.preProcessImage();
  3503. this.splitInCharacters();
  3504.  
  3505. this._characters.forEach( ch => {
  3506. let bestGuess = this.guess(ch);
  3507. solution += bestGuess.answer;
  3508. });
  3509. }
  3510. return Promise.resolve(solution);
  3511. }
  3512. }
  3513.  
  3514. class NoCaptchaWidget extends CaptchaWidget {
  3515. constructor(params) {
  3516. let defaultParams = {
  3517. selector: 'svg.feather-check-circle',
  3518. waitMs: 10000
  3519. };
  3520. for (let p in params) {
  3521. defaultParams[p] = params[p];
  3522. }
  3523. super(defaultParams);
  3524. }
  3525.  
  3526. async isSolved() {
  3527. return wait().then( () => {
  3528. if (this.isUserFriendly) {
  3529. return Promise.resolve(true);
  3530. }
  3531. return this.isSolved();
  3532. });
  3533. }
  3534. }
  3535.  
  3536. class GeeTestCaptchaWidget extends CaptchaWidget {
  3537. constructor(params) {
  3538. let defaultParams = {
  3539. selector: '.geetest_captcha.geetest_lock_success,.geetest_ghost_success.geetest_success_animate',
  3540. waitMs: 2000
  3541. };
  3542. for (let p in params) {
  3543. defaultParams[p] = params[p];
  3544. }
  3545. super(defaultParams);
  3546. }
  3547.  
  3548. async isSolved() {
  3549. return wait().then( () => {
  3550. if (this.isUserFriendly) {
  3551. return Promise.resolve(true);
  3552. }
  3553. return this.isSolved();
  3554. });
  3555. }
  3556. }
  3557.  
  3558. class CBL01CaptchaWidget extends CaptchaWidget {
  3559. constructor(params) {
  3560. let defaultParams = {
  3561. selector: '',
  3562. waitMs: 2000
  3563. };
  3564. for (let p in params) {
  3565. defaultParams[p] = params[p];
  3566. }
  3567. super(defaultParams);
  3568. }
  3569.  
  3570. async isReady() {
  3571. return wait(1).then( () => {
  3572. if(this.isUserFriendly) {
  3573. return Promise.resolve(true);
  3574. }
  3575. return wait().then( () => { this.isReady(); });
  3576. });
  3577. }
  3578.  
  3579. async solve() {
  3580. let answer = document.getElementById('captchainput').value;
  3581. if (answer != '') {
  3582. if (answer.startsWith('JJJ')) {
  3583. answer = answer.slice(3);
  3584. document.getElementById('captchainput').value = answer;
  3585. }
  3586.  
  3587. if (answer.length != 6) {
  3588. document.getElementById('captchainput').value ='';
  3589. window.location.reload();
  3590. return wait(10000).then( () => { this.solve(); });
  3591. } else {
  3592. return wait().then( () => { return true; } );
  3593. }
  3594. } else {
  3595. return wait().then( () => { this.solve(); });
  3596. }
  3597. }
  3598.  
  3599. async isSolved() {
  3600. return this.isReady()
  3601. .then( () => this.solve())
  3602. .then( (solution) => {
  3603. return Promise.resolve(true);
  3604. })
  3605. .catch(err => { shared.devlog(err); })
  3606. }
  3607. }
  3608.  
  3609. class D1CaptchaWidget extends CaptchaWidget {
  3610. constructor() {
  3611. let defaultParams = {
  3612. selector: '#submit_captcha span',
  3613. waitMs: [1000, 5000],
  3614. timeoutMs: 4 * 60 * 1000
  3615. };
  3616. super(defaultParams);
  3617. this.selectors = {
  3618. submitButton: '#submit',
  3619. answerSpan: '#submit_captcha span'
  3620. }
  3621. this._elements = {
  3622. submitButton: new ButtonWidget({selector: '#submit'}),
  3623. answerSpan: new ReadableWidget({selector: '#submit_captcha span'})
  3624. };
  3625. }
  3626.  
  3627. async isReady() {
  3628. return wait().then( () => {
  3629. if(this._elements.submitButton.isUserFriendly) {
  3630. return Promise.resolve(true);
  3631. }
  3632. return this.isReady();
  3633. });
  3634. }
  3635.  
  3636. async solve() {
  3637. if (this._elements.answerSpan.isUserFriendly) {
  3638. let answer = this._elements.answerSpan.value;
  3639. answer = answer ? answer.trim() : answer;
  3640. let input = document.querySelector(`input[value="${answer}"`);
  3641. if (input) {
  3642. helpers.alternativeClick(input.parentElement.querySelector('i'));
  3643. return wait().then( () => { return true; } );
  3644. } else {
  3645. return Promise.reject(`@D1Captcha input NOT FOUND for answer: ${answer}`);
  3646. }
  3647. } else {
  3648. return Promise.reject('Answer span not found!!!');
  3649. }
  3650. }
  3651.  
  3652. async isSolved() {
  3653. return this.isReady()
  3654. .then( () => this.solve())
  3655. .then( (solution) => {
  3656. return Promise.resolve(true);
  3657. })
  3658. .catch(err => { shared.devlog(err); })
  3659. }
  3660. }
  3661.  
  3662. class Faucet {
  3663. constructor(elements, actions = {}) {
  3664. this._url = window.location.href;
  3665. this._timeout = new Timeout(); // this.maxSeconds);
  3666. this._elements = elements;
  3667. this._actions = {
  3668. preRun: false,
  3669. preRoll: false,
  3670. altValidation: false,
  3671. readClaimed: true,
  3672. readBalance: true,
  3673. readTimeLeft: true,
  3674. readRolledNumber: false,
  3675. isMultiClaim: false,
  3676. checkIfOutOfFunds: false,
  3677. preSaveResult: false
  3678. }
  3679. this._actions = { ...this._actions, ...actions };
  3680. this._params = shared.getCurrent().params || {};
  3681. this._result = this._actions.isMultiClaim ? (shared.getProp('tempResults') || {}) : (shared.getResult() || {});
  3682. }
  3683.  
  3684. hasCloudflare() {
  3685. let h2 = document.querySelector('h2#challenge-running');
  3686. let stage = document.querySelector('#challenge-stage');
  3687. if (h2 || stage) {
  3688. return true;
  3689. }
  3690. return false;
  3691. }
  3692.  
  3693. useUrlListener() {
  3694. if (window.onurlchange === null) {
  3695. window.addEventListener('urlchange', (data) => {
  3696. if (this._url != window.location.href) {
  3697. this._url = window.location.href;
  3698. this.resetRun();
  3699. }
  3700. });
  3701. }
  3702. }
  3703.  
  3704. resetRun() {
  3705. wait().then( () => { this.init(); });
  3706. }
  3707.  
  3708. init() {
  3709. throw new Error('Init not implemented!');
  3710. }
  3711.  
  3712. login() {
  3713. throw new Error('Login not implemented!'); //return NEED_TO_LOGIN
  3714. }
  3715.  
  3716. async run(action = false) {
  3717. if (this._actions.checkIfOutOfFunds) {
  3718. this.checkIfOutOfFunds();
  3719. }
  3720.  
  3721. if (this._actions.preRun) {
  3722. await wait().then( () => { this.preRun() } );;
  3723. }
  3724.  
  3725. if (!action) {
  3726. this.detectAction().then( (resolve) => {
  3727. this.perform(resolve.action);
  3728. });
  3729. } else {
  3730. this.perform(action);
  3731. }
  3732. }
  3733.  
  3734. perform(action) {
  3735. switch(action) {
  3736. case 'doRoll':
  3737. if(this._actions.preRoll) {
  3738. this.preRoll();
  3739. }
  3740. this._elements.captcha.isSolved().then(() => { this.clickRoll() });
  3741. break;
  3742. case 'needToWait':
  3743. this.updateResult();
  3744. break;
  3745. default:
  3746. break;
  3747. }
  3748. }
  3749.  
  3750. async detectAction() {
  3751. return wait().then( () => {
  3752. if ( this.isCountdownVisible() ) {
  3753. return Promise.resolve({action: 'needToWait'});
  3754. } else if ( this.isRollButtonVisible() ) {
  3755. return Promise.resolve({action: 'doRoll'});
  3756. } else {
  3757. return this.detectAction();
  3758. }
  3759. });
  3760. }
  3761.  
  3762. preRoll() {
  3763. throw new Error('PreRoll not implemented!');
  3764. }
  3765.  
  3766. preRun() {
  3767. throw new Error('PreRun not implemented!');
  3768. }
  3769.  
  3770. altValidation() {
  3771. throw new Error('AltValidation not implemented!');
  3772. }
  3773.  
  3774. isCountdownVisible() {
  3775. return this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly;
  3776. }
  3777.  
  3778. isRollButtonVisible() {
  3779. return this._elements.rollButton && this._elements.rollButton.isUserFriendly;
  3780. }
  3781.  
  3782. clickRoll() {
  3783. try {
  3784. this._elements.rollButton.element.scrollIntoView(false);
  3785. this._elements.rollButton.click();
  3786. this.validateRun();
  3787. } catch (err) {
  3788. shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
  3789. }
  3790. }
  3791.  
  3792. failureValidation() {
  3793. throw new Error('FailureValidation not implemented!');
  3794. }
  3795.  
  3796. async validateRun() {
  3797. return wait(this._actions.useFailureValidation ? 6000 : null).then( () => {
  3798. if (this._actions.useFailureValidation) {
  3799. if (this.failureValidation()) {
  3800. return;
  3801. }
  3802. }
  3803. if (this._elements.success?.isUserFriendly) {
  3804. return this.updateResult();
  3805. } else if(this._actions.altValidation) {
  3806. if(this.altValidation()) {
  3807. return this.updateResult();
  3808. }
  3809. }
  3810. return wait(2000).then( () => { this.validateRun() });
  3811. });
  3812. }
  3813.  
  3814. async updateResult() {
  3815. if(this._actions.readClaimed) {
  3816. this._result.claimed = this.readClaimed();
  3817. }
  3818. if(this._actions.readBalance) {
  3819. this._result.balance = this.readBalance();
  3820. }
  3821. if(this._actions.readTimeLeft) {
  3822. this._result.nextRoll = this.readNextRoll();
  3823. }
  3824. if(this._actions.readRolledNumber) {
  3825. this._result.rolledNumber = this.readRolledNumber();
  3826. }
  3827. if (this._actions.isMultiClaim) {
  3828. shared.setProp('tempResults', this._result);
  3829. return this._actions.postRun ? this.postRun() : true;
  3830. }
  3831. if (this._actions.preSaveResult) {
  3832. this.preSaveResult();
  3833. }
  3834. if (this._actions.updateWithoutClosing) {
  3835. shared.updateWithoutClosing(this._result);
  3836. return this._actions.postRun ? this.postRun() : true;
  3837. } else {
  3838. shared.closeWindow(this._result);
  3839. }
  3840. }
  3841.  
  3842. readNextRoll() {
  3843. try {
  3844. if (this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly) {
  3845. return helpers.addMinutes(this._elements.countdownMinutes.timeLeft);
  3846. }
  3847. } catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
  3848. return null;
  3849. }
  3850.  
  3851. readRolledNumber() {
  3852. let rolled = 0;
  3853. try {
  3854. if(this._elements.rolledNumber.isUserFriendly) {
  3855. rolled = this._elements.rolledNumber.value;
  3856. }
  3857. } catch (err) { shared.devlog(`@readRolledNumber: ${err}`); }
  3858. return rolled;
  3859. }
  3860.  
  3861. readBalance() {
  3862. let balance = 0;
  3863. try {
  3864. if(this._elements.balance.isUserFriendly) {
  3865. balance = this._elements.balance.value;
  3866. }
  3867. } catch (err) { shared.devlog(`@readBalance: ${err}`); }
  3868. return balance;
  3869. }
  3870.  
  3871. readClaimed() { //TODO: review if previous claimed should be received as arg
  3872. let claimed = this._result.claimed ?? 0;
  3873. if (this._actions.isMultiClaim) {
  3874. this._oldClaimed = claimed;
  3875. } else {
  3876. }
  3877.  
  3878. try {
  3879. if(this._elements.claimed.isUserFriendly) {
  3880. claimed = +claimed + +this._elements.claimed.value;
  3881. } else {
  3882. }
  3883. } catch (err) { shared.devlog(`@readClaimed: ${err}`); }
  3884. return claimed;
  3885. }
  3886.  
  3887. checkIfOutOfFunds() {
  3888. let divAlerts = [...document.querySelectorAll(this._elements.outOfFundsDivSelector)];
  3889. divAlerts.forEach( function (d) {
  3890. if (d.innerText.toLowerCase().includes('not have sufficient funds')) {
  3891. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, d.innerText);
  3892. return;
  3893. }
  3894. });
  3895. }
  3896.  
  3897. setCurrentCaptcha() {
  3898. if ([...document.querySelectorAll('iframe')].map(x => x.src || '').filter(x => x.includes('hcaptcha.com')).length > 0) {
  3899. return;
  3900. }
  3901. this._elements.captcha = new RecaptchaWidget();
  3902. }
  3903. }
  3904.  
  3905. class BFRoll extends Faucet {
  3906. constructor(coinPrefix, trySpin = false) {
  3907. let elements = {
  3908. preRunButton: new ButtonWidget({selector: '.free-box.free-box__' + coinPrefix + ' button'}), //'#' + coinPrefix + '_free_box_withdraw_page'}),
  3909. captcha: new NoCaptchaWidget({ selector: '.free-box-withdraw__footer button' }), // .button_red.button_center.button_fullwidth' }),
  3910. rollButton: new ButtonWidget({selector: '.free-box-withdraw__footer button' }), // .button_red.button_center.button_fullwidth'}),
  3911. success: new ReadableWidget({selector: '.modal:not(.free-box-withdraw,fury-wheel-modal), .vue-notification-template.my-notify.success'}),
  3912. claimed: new ReadableWidget({selector: '.free-box.free-box__' + coinPrefix, parser: Parsers.bfBoxClaimed}),
  3913. progressBar: new ReadableWidget({selector: '.free-box.free-box__' + coinPrefix + ' .free-box__progress-bar progress'}),
  3914. };
  3915.  
  3916. let actions = {
  3917. preRun: true,
  3918. readClaimed: true,
  3919. readBalance: false,
  3920. readRolledNumber: false
  3921. };
  3922. super(elements, actions);
  3923. this.coinPrefix = coinPrefix;
  3924. this.trySpin = trySpin;
  3925. }
  3926.  
  3927. init() {
  3928. if (this._url.includes('https://betfury.io/boxes/all')) {
  3929. this.run();
  3930. return;
  3931. } else {
  3932. return;
  3933. }
  3934. }
  3935.  
  3936. async spin() {
  3937. let clickables = document.querySelectorAll('.fury-wheel__wheel-btn, .fury-wheel__btn-wrap, .fury-wheel__btn-content, .fury-wheel__btn-img');
  3938. if (clickables.length > 0) {
  3939. clickables[Math.floor(Math.random()*clickables.length)].click();
  3940. wait(15000).then ( () => { shared.closeWindow(this._result); } );
  3941. }
  3942. return;
  3943. }
  3944.  
  3945. async preRun() {
  3946. return wait().then( () => {
  3947. try {
  3948. let popup = document.querySelector('.modal-wrapper .modal:not(.free-box-withdraw,fury-wheel-modal) .modal__btn-close');
  3949. if (popup) {
  3950. popup.click();
  3951. popup.click(); // twice
  3952. }
  3953. } catch (err) {}
  3954.  
  3955. if (this.trySpin) {
  3956. let spinUnavailable = document.querySelector('.bonus.bonus_furywheel.wait');
  3957. if (spinUnavailable) {
  3958. } else {
  3959. let spinBtn = document.querySelector('.wheel-amin'); //bonus bonus_furywheel wait
  3960. if (spinBtn) {
  3961. spinBtn.click();
  3962. wait(10000).then ( () => { this.spin() } );
  3963. return wait(60000).then ( () => { this.preRun(); } );
  3964. }
  3965. }
  3966. }
  3967.  
  3968. if (!this._elements.progressBar || !this._elements.progressBar.isUserFriendly) {
  3969. return this.preRun();
  3970. }
  3971.  
  3972. if (this._elements.preRunButton.isUserFriendly) {
  3973. if (!this._elements.preRunButton.isUserFriendly.disabled) {
  3974. return this._elements.preRunButton.click();
  3975. } else {
  3976. this._timeout.restart();
  3977. shared.closeWindow(this._result);
  3978. return;
  3979. }
  3980. } else if (document.querySelectorAll('.free-box').length > 1) {
  3981. shared.closeWithError(K.ErrorType.ERROR, 'Box might not exist for your account.');
  3982. return;
  3983. }
  3984. return this.preRun();
  3985. });
  3986. }
  3987.  
  3988. async validateRun() {
  3989. return wait(7000).then( () => {
  3990. let gtHook = document.querySelector('div.geetest_slice_bg');
  3991. if (gtHook) {
  3992. if (gtHook.isUserFriendly()) {
  3993. return this.validateRun();
  3994. }
  3995. }
  3996. let popup = document.querySelector('.modal-wrapper .modal:not(.free-box-withdraw,fury-wheel-modal) .modal__btn-close');
  3997. if (!popup) {
  3998. if (this._elements.preRunButton.isUserFriendly && !this._elements.preRunButton.isUserFriendly.disabled) {
  3999. this._elements.preRunButton.click();
  4000. return this.validateRun();
  4001. }
  4002. } else {
  4003. try {
  4004. if (popup) {
  4005. popup.click();
  4006. popup.click();
  4007. }
  4008. } catch (err) {}
  4009. }
  4010.  
  4011. if (this._elements.success.isUserFriendly) {
  4012. return this.updateResult();
  4013. } else if(this._actions.altValidation) {
  4014. if(this.altValidation()) {
  4015. return this.updateResult();
  4016. }
  4017. }
  4018. return this.validateRun();
  4019. });
  4020. }
  4021. }
  4022.  
  4023. class DutchyRoll extends Faucet {
  4024. constructor() {
  4025. let elements = {
  4026. countdownMinutes: new CountdownWidget({selector: '#timer', parser: Parsers.splitAndIdxToInt, options: { splitter: 'Minutes', idx: 0} }), // "26 Minutes 23"
  4027. captcha: new HCaptchaWidget(),
  4028. rollButton: new ButtonWidget({selector: '#claim'}), //w/booster video: '#unlockbutton' & then #claim_boosted
  4029. success: new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse'}),
  4030. claimed: new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.freeEthereumIoClaimed}) //"You Won 0.00409070 TRX + 20 XP"
  4031. };
  4032. let actions = {
  4033. preRun: true,
  4034. readClaimed: true,
  4035. readBalance: false,
  4036. readRolledNumber: false
  4037. };
  4038. super(elements, actions);
  4039. }
  4040.  
  4041. init() {
  4042. switch(window.location.host) {
  4043. case 'autofaucet.dutchycorp.space':
  4044. if (this._url.includes('/roll.php')) {
  4045. this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimed})
  4046. } else if (this._url.includes('/login.php')) {
  4047. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
  4048. return;
  4049. }
  4050. break;
  4051. case 'express.dutchycorp.space':
  4052. if (this._url.includes('/roll.php')) {
  4053. this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimed})
  4054. } else if (this._url.includes('/coin_roll.php')) {
  4055. this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimedToFloat})
  4056. } else if (this._url.includes('/index.php')) {
  4057. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'You need to login using ExpressCrypto (EC-UserId-XXXXXX).');
  4058. return;
  4059. }
  4060. break;
  4061. }
  4062. this.run();
  4063. return;
  4064. }
  4065.  
  4066. async preRun() {
  4067. if (this._elements.captcha.isUserFriendly) {
  4068. if (shared.getConfig()['dutchy.useBoosted']) {
  4069. this._elements.rollButton = new ButtonWidget({selector: '#unlockbutton'});
  4070. this._elements.confirmBoost = new ButtonWidget({selector: '#claim_boosted'});
  4071. setInterval(() => {
  4072. try {
  4073. if (this._elements.confirmBoost.isUserFriendly) {
  4074. this._elements.confirmBoost.click();
  4075. }
  4076. } catch (err) {}
  4077. }, 8000);
  4078. }
  4079. return true;
  4080. } else {
  4081. this.setCurrentCaptcha();
  4082. await wait();
  4083. return this.preRun();
  4084. }
  4085. }
  4086. }
  4087.  
  4088. class YCoin extends Faucet {
  4089. constructor() {
  4090. let elements = {
  4091. rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Get Free Crypto!"]'}),
  4092. claimed: new ReadableWidget({selector: 'div.alert.alert-info', parser: Parsers.freeEthereumIoClaimed}),
  4093. captcha: new HCaptchaWidget(),
  4094. balance: new ReadableWidget({selector: 'a.wha[href="/account?page=history"]', parser: Parsers.trimNaNs}),
  4095. success: new ReadableWidget({selector: 'div.alert.alert-info'}),
  4096. login: {
  4097. inputUser: new TextboxWidget({ selector: 'input[name="number"]' }),
  4098. inputPass: new TextboxWidget({ selector: 'input[name="pass"]' }),
  4099. inputSubmit: new SubmitWidget({ selector: 'input[type="submit"][value="Login!"]' }),
  4100. setCredentials: false
  4101. },
  4102. };
  4103.  
  4104. if(shared.getConfig()['ycoin.credentials.mode'] == 1) {
  4105. elements.login.setCredentials = {
  4106. username: shared.getConfig()['ycoin.credentials.username'],
  4107. password: shared.getConfig()['ycoin.credentials.password']
  4108. };
  4109. }
  4110.  
  4111. let actions = {
  4112. preRun: true,
  4113. readClaimed: true,
  4114. readBalance: true,
  4115. readRolledNumber: false,
  4116. checkIfOutOfFunds: false
  4117. };
  4118. super(elements, actions);
  4119. }
  4120.  
  4121. async preRun() {
  4122. let msgDiv;
  4123. msgDiv = document.querySelector('p.info.success');
  4124. if (msgDiv && msgDiv.innerText.includes('has been transferred')) {
  4125. let result = {};
  4126. if (msgDiv.innerText.includes('0 claims')) {
  4127. result.nextRoll = helpers.addMinutes(60 * 24 + helpers.randomInt(10, 50));
  4128. } else {
  4129. result.nextRoll = helpers.addMinutes('60');
  4130. }
  4131. result.claimed = +msgDiv.innerText.split(' ')[0];
  4132. result.balance = this.readBalance();
  4133. shared.closeWindow(result);
  4134. return;
  4135. }
  4136.  
  4137. msgDiv = document.querySelector('p.info.warn');
  4138. if (msgDiv) {
  4139. if (msgDiv.innerText.includes('can claim only')) {
  4140. let result = {};
  4141. result.nextRoll = helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  4142. shared.closeWindow(result);
  4143. return;
  4144. } else if (msgDiv.innerText.includes('Please wait')) {
  4145. let result = {};
  4146. try {
  4147. let unit = msgDiv.innerText.includes(' seconds') ? ' seconds' : ' minutes';
  4148. let val = msgDiv.innerText.split('Please wait ')[1].replace(/\D/g, '');
  4149. if (unit == ' seconds') {
  4150. result.nextRoll = helpers.addSeconds(val);
  4151. } else {
  4152. result.nextRoll = helpers.addMinutes(val);
  4153. }
  4154. } catch {
  4155. result.nextRoll = helpers.addMinutes(60);
  4156. }
  4157. shared.closeWindow(result);
  4158. return;
  4159. }
  4160. }
  4161. msgDiv = document.querySelector('p.info.fail');
  4162. if (msgDiv) {
  4163. if (msgDiv.innerText.toLowerCase().includes('run out of bitcoin')) {
  4164. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
  4165. return;
  4166. }
  4167. }
  4168.  
  4169. if (this._elements.captcha.isUserFriendly) {
  4170. } else {
  4171. if (this._elements.rollButton) {
  4172. this._elements.rollButton.click();
  4173. return;
  4174. }
  4175. }
  4176. }
  4177.  
  4178. async init() {
  4179. if (this._url.includes('/faucet')) {
  4180. let needToLoginButton = document.querySelector('input[type="submit"][value="Login / Signup"]');
  4181. if (needToLoginButton) {
  4182. needToLoginButton.click();
  4183. return;
  4184. }
  4185.  
  4186. this.run();
  4187. this.solveColorCaptcha();
  4188. return;
  4189. } else if (this._url.includes('/account')) {
  4190. this.doLogin();
  4191. return;
  4192. }
  4193. }
  4194.  
  4195. async doLogin() {
  4196. return wait().then( () => {
  4197. let container = document.querySelector('#cc');
  4198. if (container.innerText.includes('You are now logged in as account')) {
  4199. let toFaucetButton = document.querySelector('#mmenu a[href="/faucet"]');
  4200. if (toFaucetButton) {
  4201. toFaucetButton.click();
  4202. return;
  4203. }
  4204. return this.doLogin();
  4205. }
  4206. if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
  4207. return this.doLogin();
  4208. }
  4209.  
  4210. let loginErrorDiv = document.querySelector('#cc .info.fail');
  4211. if (loginErrorDiv && loginErrorDiv.innerText.includes('Invalid')) {
  4212. shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
  4213. return;
  4214. }
  4215.  
  4216. if (this._elements.login.setCredentials != false) {
  4217. this._elements.login.inputUser.value = this._elements.login.setCredentials.username;
  4218. this._elements.login.inputPass.value = this._elements.login.setCredentials.password;
  4219. }
  4220.  
  4221. try {
  4222. this._elements.login.rememberMe.isUserFriendly.checked = true;
  4223. } catch (err) {}
  4224.  
  4225. if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
  4226. this._elements.login.inputSubmit.click();
  4227. } else {
  4228. shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
  4229. return;
  4230. }
  4231. });
  4232. }
  4233.  
  4234. async solveColorCaptcha() {
  4235. await wait(2000);
  4236. let optionInputs = [...document.querySelectorAll('#newch input[type="submit"]')];
  4237. let options = optionInputs.map(x => x.style.background);
  4238. let wantedColor = document.querySelector('#newch p b');
  4239. if (options.length > 0 && wantedColor) {
  4240. try {
  4241. let knownColors = Object.keys(nearestColor.STANDARD_COLORS);
  4242. let toColorName = nearestColor.from(nearestColor.STANDARD_COLORS);
  4243.  
  4244. options = options.map(x => toColorName(x).name);
  4245. wantedColor = wantedColor.innerText.toLowerCase();
  4246. if (wantedColor == 'grey') { wantedColor = 'gray'; }
  4247. let solutionIdx = options.findIndex(x => x.includes(wantedColor));
  4248. if (solutionIdx > -1) {
  4249. optionInputs[solutionIdx].click();
  4250. return;
  4251. }
  4252. if (wantedColor == 'green') {
  4253. wantedColor = 'lime';
  4254. solutionIdx = options.findIndex(x => x.includes(wantedColor));
  4255. if (solutionIdx > -1) {
  4256. optionInputs[solutionIdx].click();
  4257. return;
  4258. }
  4259. }
  4260. await wait(5000);
  4261. location.reload();
  4262. } catch (err) {
  4263. await wait(15000);
  4264. location.reload();
  4265. }
  4266. } else {
  4267. return this.solveColorCaptcha();
  4268. }
  4269. }
  4270.  
  4271. }
  4272.  
  4273. class CDiversity extends Faucet {
  4274. constructor() {
  4275. let elements = {
  4276. claimed: new ReadableWidget({selector: 'p.success', parser: Parsers.trimNaNs}),
  4277. captcha: new HCaptchaWidget(),
  4278. rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Get Free Crypto!"]'}),
  4279. };
  4280. let actions = {
  4281. readTimeLeft: true,
  4282. readRolledNumber: false,
  4283. readBalance: false
  4284. };
  4285. super(elements, actions);
  4286. }
  4287.  
  4288. init() {
  4289. if(this.hasErrorMessage()) {
  4290. shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
  4291. return;
  4292. }
  4293.  
  4294. let claimed = this.readClaimed();
  4295. if (claimed != 0) {
  4296. let result = {
  4297. claimed: claimed,
  4298. nextRoll: this.readNextRoll()
  4299. };
  4300. shared.closeWindow(result);
  4301. return;
  4302. }
  4303.  
  4304. let nextRoll = this.readNextRoll();
  4305. if(nextRoll) {
  4306. let result = {
  4307. nextRoll: nextRoll
  4308. };
  4309. shared.closeWindow(result);
  4310. return;
  4311. }
  4312.  
  4313. this.solve();
  4314. }
  4315.  
  4316. hasErrorMessage() {
  4317. return document.body.innerText.toLowerCase().includes('suspicious activity');
  4318. }
  4319.  
  4320. isFirstStep() {
  4321. return document.querySelector('form select[name="coin"]') ? true : false;
  4322. }
  4323.  
  4324. async doFirstStep() {
  4325. let form = document.querySelector('form');
  4326. if (!form) {
  4327. this.updateResult();
  4328. return;
  4329. }
  4330. let coinSelect = form.querySelector('select[name="coin"]');
  4331. if (!coinSelect) {
  4332. this.updateResult();
  4333. return;
  4334. }
  4335. let userInput = form.querySelector('input[name="ado"]');
  4336. if (!userInput) {
  4337. this.updateResult();
  4338. return;
  4339. }
  4340. let submitButton = form.querySelector('input[type="submit"]');
  4341. if (!submitButton) {
  4342. this.updateResult();
  4343. return;
  4344. }
  4345. coinSelect.value = this.getCoin();
  4346. userInput.value = this._params.address;
  4347.  
  4348. submitButton.parentElement.submit();
  4349. return;
  4350. }
  4351.  
  4352. getCoin() {
  4353. try {
  4354. let tds = document.querySelectorAll('table tr td:nth-child(2)');
  4355. return tds[helpers.randomInt(0, 5)].innerText.split(' ')[1]
  4356. } catch (err) {
  4357. return 'BTC';
  4358. }
  4359. }
  4360.  
  4361. isSecondStep() {
  4362. let ps = [...document.querySelectorAll('p')];
  4363. return ps.findIndex(x => x.innerText.toLowerCase().includes('one more step...')) >= 0;
  4364. }
  4365.  
  4366. async solve() {
  4367. if (this.isSecondStep()) {
  4368. return this.run();
  4369. }
  4370. if (this.isFirstStep()) {
  4371. return this.doFirstStep();
  4372. }
  4373. }
  4374.  
  4375. isCountdownVisible() {
  4376. let successDiv = document.querySelector('p.success');
  4377. if (!successDiv) {
  4378. return false;
  4379. }
  4380. if (successDiv.innerText.includes('0 claims')) {
  4381. return true;
  4382. }
  4383.  
  4384. return false;
  4385. }
  4386.  
  4387. readClaimed() {
  4388. let successDiv = document.querySelector('p.success');
  4389. if (successDiv) {
  4390. return successDiv.innerText.split(' ')[0];
  4391. } else {
  4392. return 0;
  4393. }
  4394. }
  4395.  
  4396. readNextRoll() {
  4397. try {
  4398. let successDiv = document.querySelector('p.success');
  4399. if (successDiv && successDiv.innerText.includes('You have')) {
  4400. let claimsLeft;
  4401. try {
  4402. claimsLeft = successDiv.innerText.split(' claims')[0].split('have ')[1];
  4403. } catch (err) {}
  4404. if (claimsLeft) {
  4405. return helpers.addMinutes(helpers.randomInt(6, 22));
  4406. } else if (claimsLeft === '0') {
  4407. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  4408. }
  4409. }
  4410. } catch (err) { }
  4411.  
  4412. try {
  4413. let warnDiv = document.querySelector('p.warn');
  4414. if (warnDiv) {
  4415. if (warnDiv.innerText.includes('You can claim only')) {
  4416. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  4417. }
  4418.  
  4419. if (warnDiv.innerText.includes('Please wait ')) {
  4420. try {
  4421. let unit = warnDiv.innerText.includes(' seconds') ? ' seconds' : ' minutes';
  4422. let val = warnDiv.innerText.split('Please wait ')[1].split(unit)[0].replace(/\D/g, '');
  4423. if (unit == ' seconds') {
  4424. return helpers.addSeconds(val);
  4425. } else {
  4426. return helpers.addMinutes(val);
  4427. }
  4428. } catch { }
  4429. let claimsLeft;
  4430. try {
  4431. claimsLeft = warnDiv.innerText.split(' seconds')[0].split('wait ')[1];
  4432. } catch (err) {}
  4433. if (claimsLeft) {
  4434. return helpers.addMinutes(helpers.randomInt(6, 22));
  4435. }
  4436. }
  4437. }
  4438.  
  4439. } catch (err) { }
  4440. return null;
  4441. }
  4442. }
  4443.  
  4444. class CTop extends Faucet {
  4445. constructor() {
  4446. let elements = {
  4447. claimed: new ReadableWidget({selector: 'p.success', parser: Parsers.trimNaNs}),
  4448. captcha: new HCaptchaWidget(),
  4449. rollButton: new ButtonWidget({selector: 'input[type="submit"]'}),
  4450. addressInput: new TextboxWidget({ selector: 'form input[name="adr"], form input[name="a"]'})
  4451. };
  4452. let actions = {
  4453. readTimeLeft: true,
  4454. readRolledNumber: false,
  4455. readBalance: false
  4456. };
  4457. super(elements, actions);
  4458. }
  4459.  
  4460. init() {
  4461. if(this.hasErrorMessage('suspicious activity')) {
  4462. shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
  4463. return;
  4464. }
  4465. if(this.hasErrorMessage('no funds left')) {
  4466. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
  4467. return;
  4468. }
  4469. if(this.hasErrorMessage('faucet is currently disabled')) {
  4470. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Faucet is disabled');
  4471. return;
  4472. }
  4473.  
  4474. let claimed = this.readClaimed();
  4475. if (claimed != 0) {
  4476. let result = {
  4477. claimed: claimed,
  4478. nextRoll: this.readNextRoll()
  4479. };
  4480. shared.closeWindow(result);
  4481. return;
  4482. }
  4483.  
  4484. let nextRoll = this.readNextRoll();
  4485. if(nextRoll) {
  4486. let result = {
  4487. nextRoll: nextRoll
  4488. };
  4489. shared.closeWindow(result);
  4490. return;
  4491. }
  4492.  
  4493. this.solve();
  4494. }
  4495.  
  4496. hasErrorMessage(searchTerm) {
  4497. return document.body.innerText.toLowerCase().includes(searchTerm);
  4498. }
  4499.  
  4500. isFirstStep() {
  4501. return this._elements.addressInput.isUserFriendly;
  4502. }
  4503.  
  4504. async doFirstStep() {
  4505. let form = document.querySelector('form');
  4506. if (!form) {
  4507. this.updateResult();
  4508. return;
  4509. }
  4510. if (!this._elements.addressInput.isUserFriendly) {
  4511. this.updateResult();
  4512. return;
  4513. }
  4514. let submitButton = form.querySelector('input[type="submit"]');
  4515. if (!submitButton) {
  4516. this.updateResult();
  4517. return;
  4518. }
  4519. this._elements.addressInput.value = this._params.address;
  4520.  
  4521. submitButton.closest('form').submit();
  4522. return;
  4523. }
  4524.  
  4525. isSecondStep() {
  4526. let ps = [...document.querySelectorAll('p')];
  4527. return ps.findIndex(x => x.innerText.toLowerCase().includes('one more step...')) >= 0;
  4528. }
  4529.  
  4530. async solve() {
  4531. if (this.isSecondStep()) {
  4532. return this.run();
  4533. }
  4534. if (this.isFirstStep()) {
  4535. return this.doFirstStep();
  4536. }
  4537. }
  4538.  
  4539. isCountdownVisible() {
  4540. let successDiv = document.querySelector('p.success');
  4541. if (!successDiv) {
  4542. return false;
  4543. }
  4544. if (successDiv.innerText.includes('0 claims')) {
  4545. return true;
  4546. }
  4547.  
  4548. return false;
  4549. }
  4550.  
  4551. readClaimed() {
  4552. let successDiv = document.querySelector('p.success');
  4553. if (successDiv) {
  4554. return successDiv.innerText.split(' ')[0];
  4555. } else {
  4556. return 0;
  4557. }
  4558. }
  4559.  
  4560. readNextRoll() {
  4561. try {
  4562. let successDiv = document.querySelector('p.success');
  4563. if (successDiv && successDiv.innerText.includes('You have')) {
  4564. let claimsLeft;
  4565. try {
  4566. claimsLeft = successDiv.innerText.split(' claims')[0].split('have ')[1];
  4567. } catch (err) {}
  4568. if (claimsLeft) {
  4569. return helpers.addMinutes(helpers.randomInt(12, 22));
  4570. } else if (claimsLeft === '0') {
  4571. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  4572. }
  4573. }
  4574. } catch (err) { }
  4575.  
  4576. try {
  4577. let warnDiv = document.querySelector('p.warn');
  4578. if (warnDiv) {
  4579. if (warnDiv.innerText.includes('You can claim only')) {
  4580. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  4581. }
  4582.  
  4583. if (warnDiv.innerText.includes('Please wait ')) {
  4584. try {
  4585. let unit = warnDiv.innerText.includes(' seconds') ? ' seconds ' : ' minutes ';
  4586. let val = warnDiv.innerText.split('Please wait ')[1].split(unit)[0].replace(/\D/g, '');
  4587. if (unit == ' seconds ') {
  4588. return helpers.addSeconds(val + helpers.randomInt(90, 180));
  4589. } else {
  4590. return helpers.addMinutes(val + helpers.randomInt(1, 5));
  4591. }
  4592. } catch { }
  4593. let claimsLeft;
  4594. try {
  4595. claimsLeft = warnDiv.innerText.split(' seconds')[0].split('wait ')[1];
  4596. } catch (err) {}
  4597. if (claimsLeft) {
  4598. return helpers.addMinutes(helpers.randomInt(12, 22));
  4599. }
  4600. }
  4601. }
  4602.  
  4603. } catch (err) { }
  4604. return null;
  4605. }
  4606. }
  4607.  
  4608. class FPB extends Faucet {
  4609. constructor(sitePrefix = null) {
  4610. let elements = {
  4611. rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Claim From Faucet"],input[type="submit"][name="claim"]'}),
  4612. claimed: new ReadableWidget({selector: 'div.alert.alert-info', parser: Parsers.freeEthereumIoClaimed}),
  4613. captcha: new HCaptchaWidget(),
  4614. success: new ReadableWidget({selector: 'div.alert.alert-info'}),
  4615. login: {
  4616. inputUser: new TextboxWidget({ selector: 'input[name="user_name"]' }),
  4617. inputPass: new TextboxWidget({ selector: 'input[name="password"]' }),
  4618. rememberMe: new TextboxWidget({ selector: 'input[name="remember_me"]' }),
  4619. inputSubmit: new ButtonWidget({ selector: 'input[type="submit"][name="login"]' }),
  4620. setCredentials: false
  4621. },
  4622. outOfFundsDivSelector: '.alert.alert-info'
  4623. };
  4624.  
  4625. if(shared.getConfig()[sitePrefix + '.credentials.mode'] == 1) {
  4626. elements.login.setCredentials = {
  4627. username: shared.getConfig()[sitePrefix + '.credentials.username'],
  4628. password: shared.getConfig()[sitePrefix + '.credentials.password']
  4629. };
  4630. }
  4631.  
  4632. let actions = {
  4633. readClaimed: true,
  4634. readBalance: false,
  4635. readRolledNumber: false,
  4636. checkIfOutOfFunds: true
  4637. };
  4638. super(elements, actions);
  4639. }
  4640.  
  4641. init() {
  4642. if (this._url.includes('/dashboard')) {
  4643. this.run();
  4644. return;
  4645. } else if (this._url.includes('/login')) {
  4646. this.doLogin();
  4647. return;
  4648. }
  4649. }
  4650.  
  4651. async doLogin() {
  4652. return wait().then( () => {
  4653. if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
  4654. return this.doLogin();
  4655. }
  4656.  
  4657. let loginErrorDiv = document.querySelector('div.alert.alert-info');
  4658. if (loginErrorDiv && loginErrorDiv.innerText.includes('not valid')) {
  4659. shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
  4660. return;
  4661. }
  4662.  
  4663. if (this._elements.login.setCredentials != false) {
  4664. this._elements.login.inputUser.value = this._elements.login.setCredentials.username;
  4665. this._elements.login.inputPass.value = this._elements.login.setCredentials.password;
  4666. }
  4667.  
  4668. try {
  4669. this._elements.login.rememberMe.isUserFriendly.checked = true;
  4670. } catch (err) {}
  4671.  
  4672. if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
  4673. this._elements.captcha.isSolved().then(() => {
  4674. this._elements.login.inputSubmit.click();
  4675. return;
  4676. });
  4677. } else {
  4678. shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
  4679. return;
  4680. }
  4681. });
  4682. }
  4683.  
  4684. async detectAction() {
  4685. return wait().then( () => {
  4686. if ( this.isCountdownVisible() ) {
  4687. return Promise.resolve({action: 'needToWait'});
  4688. } else if ( this._elements.success.isUserFriendly ) {
  4689. return this.updateResult();
  4690. } else if ( this.isRollButtonVisible() ) {
  4691. return Promise.resolve({action: 'doRoll'});
  4692. } else {
  4693. return this.detectAction();
  4694. }
  4695. });
  4696. }
  4697.  
  4698. clickRoll() {
  4699. try {
  4700. try {
  4701. window.scrollTo(0, document.body.scrollHeight);
  4702. } catch (err) { }
  4703. this._elements.rollButton.click();
  4704. setTimeout( () => { this._elements.rollButton.click(); }, 5000);
  4705. } catch (err) {
  4706. shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
  4707. }
  4708. }
  4709. }
  4710.  
  4711. class VieRoll extends Faucet {
  4712. constructor() {
  4713. let elements = {
  4714. rollButton: new SubmitWidget({selector: '.main-content button[type="submit"]'}),
  4715. claimed: new ReadableWidget({selector: '.swal2-html-container', parser: Parsers.trimNaNs}),
  4716. captcha: new HCaptchaWidget(),
  4717. success: new ReadableWidget({selector: '.swal2-success-ring'}),
  4718. login: {
  4719. inputUser: new TextboxWidget({ selector: '#email' }),
  4720. inputPass: new TextboxWidget({ selector: '#password' }),
  4721. inputSubmit: new SubmitWidget({ selector: 'button[type="submit"]' })
  4722. }
  4723. };
  4724.  
  4725. let actions = {
  4726. readClaimed: true,
  4727. readBalance: false,
  4728. readTimeLeft: false,
  4729. readRolledNumber: false,
  4730. preSaveResult: false,
  4731. preRun: true
  4732. };
  4733. super(elements, actions);
  4734. }
  4735.  
  4736. getClaimsQty() {
  4737. let statWidgets = document.querySelectorAll('.card.mini-stats-wid');
  4738. if (statWidgets.length < 4) return false;
  4739.  
  4740. let claimCounts = statWidgets[3].querySelector('p');
  4741. if (!claimCounts) return false;
  4742.  
  4743. claimCounts = claimCounts.innerText.split('/');
  4744. if (claimCounts.length != 2) return false;
  4745.  
  4746. return claimCounts[0];
  4747. }
  4748.  
  4749. async evalClaimsQty() {
  4750. let current = this.getClaimsQty();
  4751.  
  4752. if (current) {
  4753. current = +current;
  4754. } else {
  4755. return;
  4756. }
  4757.  
  4758. let previous = await shared.getProp('tempClaimsQty') || 0;
  4759. if (!isNaN(previous)) previous = +previous;
  4760.  
  4761. if (current == previous) {
  4762. return;
  4763. } else if (current < previous) {
  4764. return this.updateResult();
  4765. } else {
  4766. await shared.setProp('tempClaimsQty', current);
  4767. }
  4768. }
  4769.  
  4770. readClaimed() {
  4771. let claimed = 0.12;
  4772. try {
  4773. claimed = +document.querySelectorAll('.card.mini-stats-wid')[2].querySelector('p').innerText.split(' ')[0];
  4774. } catch (err) { }
  4775. return claimed;
  4776. }
  4777.  
  4778. async init() {
  4779. await this.evalClaimsQty();
  4780.  
  4781. if (window.location.pathname.includes('/faucet')) {
  4782. this.run();
  4783. return;
  4784. } else if (window.location.pathname.includes('/firewall')) {
  4785. this.solveFirewall();
  4786. return;
  4787. } else if (window.location.pathname.includes('/dashboard')) {
  4788. window.location.href = (new URL('faucet', window.location)).href;
  4789. return;
  4790. } else if (window.location.pathname == '/') {
  4791. let loginBtn = document.querySelector('.btn.btn-success');
  4792. if (loginBtn) {
  4793. loginBtn.click();
  4794. return;
  4795. } else {
  4796. window.location.href = (new URL('login', window.location)).href;
  4797. }
  4798. return;
  4799. } else if (this._url.includes('/login')) {
  4800.  
  4801. let credentialsMode = this._params.credentials.mode;
  4802. switch(credentialsMode) {
  4803. case -1:
  4804. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'Manual login required.');
  4805. break;
  4806. case 0:
  4807. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'Login required and autologin is not configured.');
  4808. break;
  4809. default:
  4810. this.doLogin();
  4811. break;
  4812. }
  4813. return;
  4814. }
  4815. }
  4816.  
  4817. async preRun() {
  4818. return;
  4819. }
  4820.  
  4821. async solveFirewall() {
  4822. this.closeSwal();
  4823.  
  4824. this._elements.captcha.isSolved().then(() => {
  4825. let btn = new SubmitWidget({selector: 'form:not(.p-3) button[type="submit"]'});
  4826. btn.click();
  4827. });
  4828. }
  4829.  
  4830. async doLogin() {
  4831. return wait().then( () => {
  4832. if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
  4833. return this.doLogin();
  4834. }
  4835.  
  4836. let loginErrorDiv = document.querySelector('div.alert.alert-danger');
  4837. if (loginErrorDiv) {
  4838. shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
  4839. return;
  4840. }
  4841.  
  4842. if (this._params.credentials.mode == 1) {
  4843. this._elements.login.inputUser.value = this._params.credentials.username;
  4844. this._elements.login.inputPass.value = this._params.credentials.password;
  4845. }
  4846.  
  4847. if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
  4848. this._elements.captcha.isSolved().then(() => {
  4849. this._elements.login.inputSubmit.click();
  4850. return;
  4851. });
  4852. } else {
  4853. shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
  4854. return;
  4855. }
  4856. });
  4857. }
  4858.  
  4859. preSaveResult() {
  4860. this.closeSwal();
  4861. }
  4862.  
  4863. closeSwal() {
  4864. let okButton = document.querySelector('button.swal2-confirm');
  4865. if (okButton) {
  4866. okButton.click();
  4867. }
  4868. }
  4869. }
  4870.  
  4871. class GRCRoll extends Faucet {
  4872. constructor() {
  4873. let elements = {
  4874. countdownMinutes: new CountdownWidget({selector: '#roll_wait_text', parser: Parsers.freeGrcCountdown}),
  4875. rollButton: new ButtonWidget({selector: 'input[id="roll_button"]'}),
  4876. balance: new ReadableWidget({selector: '#balance', parser: Parsers.trimNaNs}),
  4877. claimed: new ReadableWidget({selector: '#roll_comment .won', parser: Parsers.trimNaNs}),
  4878. rolledNumber: new ReadableWidget({selector: '#roll_result', parser: Parsers.trimNaNs}),
  4879. captcha: new NoCaptchaWidget({selector: '#roll_button'}),
  4880. success: new ReadableWidget({selector: '#roll_result'})
  4881. };
  4882. let actions = {
  4883. readTimeLeft: true,
  4884. readRolledNumber: true
  4885. };
  4886. super(elements, actions);
  4887. }
  4888.  
  4889. init() {
  4890. if (this._url.includes('#free_roll')) {
  4891. if (document.querySelectorAll('a[href="#login"]').length > 0) {
  4892. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
  4893. return;
  4894. } else {
  4895. this.run();
  4896. return;
  4897. }
  4898. } else {
  4899. return;
  4900. }
  4901. }
  4902.  
  4903. isCountdownVisible() {
  4904. return this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly && this._elements.countdownMinutes.isUserFriendly.innerText != '';
  4905. }
  4906. }
  4907.  
  4908. class O24Roll extends Faucet {
  4909. constructor() {
  4910. let elements = {
  4911. claimed: new ReadableWidget({selector: '#roll_comment .won', parser: Parsers.trimNaNs})
  4912. };
  4913. let actions = {
  4914. readTimeLeft: true,
  4915. readRolledNumber: false,
  4916. readBalance: false
  4917. };
  4918. super(elements, actions);
  4919. this._isFMonster = location.host === 'faucet.monster';
  4920. }
  4921.  
  4922. init() {
  4923. if(this.hasErrorMessage('no funds left')) {
  4924. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
  4925. return;
  4926. }
  4927.  
  4928. if (this.isCountdownVisible() || this.readClaimed() != 0) {
  4929. this.updateResult();
  4930. return;
  4931. }
  4932.  
  4933. this.solve();
  4934. }
  4935.  
  4936. hasErrorMessage(searchTerm) {
  4937. return document.body.innerText.toLowerCase().includes(searchTerm);
  4938. }
  4939.  
  4940. getSpotsAvailable() {
  4941. try {
  4942. let soldSpots = document.querySelectorAll('.pos:not(.pfree)').length;
  4943. let available = 1024-soldSpots;
  4944. return {
  4945. sold: '' + soldSpots,
  4946. available: '' + available
  4947. }
  4948. } catch (err) {
  4949. }
  4950. }
  4951.  
  4952. isPrime(num) {
  4953. for(var i = 2; i < num; i++){
  4954. if(num % i === 0){
  4955. return false;
  4956. }
  4957. }
  4958. return num > 1;
  4959. }
  4960.  
  4961. async solve() {
  4962. let spots;
  4963. spots = this.getSpotsAvailable();
  4964. if(!this._isFMonster && !spots) {
  4965. this.updateResult();
  4966. return;
  4967. }
  4968.  
  4969. const findNotPrime = document.querySelector('select[name="pr"]').parentElement.innerText.includes('not a prime')
  4970. let numbers = [...document.querySelectorAll('select[name="pr"] option[value]')].map(x => x.innerText)
  4971. let prime = null;
  4972. if (findNotPrime) {
  4973. prime = numbers.find(x => {
  4974. return !this.isPrime(x)
  4975. });
  4976. } else {
  4977. prime = numbers.find(x => {
  4978. return this.isPrime(x)
  4979. });
  4980. }
  4981. if(!prime) {
  4982. this.updateResult();
  4983. return;
  4984. }
  4985.  
  4986. let addrInput = document.querySelector('label input[name="a"]');
  4987. if (addrInput) {
  4988. addrInput.value = this._params.address;
  4989. } else {
  4990. this.updateResult();
  4991. return;
  4992. }
  4993. await wait(helpers.randomInt(1500, 3000));
  4994.  
  4995. if (this._isFMonster) {
  4996. let usdtQuestion = document.querySelector('form p:nth-child(2)');
  4997. if (!usdtQuestion || !usdtQuestion.innerText.toLowerCase().includes('faucet monitor lists tether faucets')) {
  4998. this.updateResult();
  4999. return;
  5000. }
  5001. let usdtAnswersList = [...document.querySelectorAll('select[name="fm"] option')];
  5002. if (usdtAnswersList.length == 0) {
  5003. this.updateResult();
  5004. return;
  5005. }
  5006. usdtAnswersList = usdtAnswersList.map(x => x.value);
  5007. let idxCorrect = usdtAnswersList.findIndex(x => x.toLowerCase() == 'yes' || x.toLowerCase() == 'y');
  5008. if (idxCorrect === -1) {
  5009. this.updateResult();
  5010. return;
  5011. }
  5012. document.querySelector('select[name="fm"]').value = usdtAnswersList[idxCorrect];
  5013. } else {
  5014. let answersList = [...document.querySelectorAll('select[name="tt"] option')].map(x => x.value);
  5015. if (answersList.includes(spots.sold)) {
  5016. document.querySelector('select[name="tt"]').value=spots.sold;
  5017. } else if (answersList.includes(spots.available)) {
  5018. document.querySelector('select[name="tt"]').value=spots.available;
  5019. } else {
  5020. this.updateResult();
  5021. return;
  5022. }
  5023. }
  5024. await wait(helpers.randomInt(400, 5000));
  5025.  
  5026. let primeSelect = document.querySelector('select[name="pr"]');
  5027. helpers.triggerMouseEvent (primeSelect, "mouseenter");
  5028. await wait(helpers.randomInt(5600, 29000));
  5029. helpers.triggerMouseEvent (primeSelect, "mouseout");
  5030. primeSelect.value=prime.toString()
  5031. await wait(helpers.randomInt(1500, 5000));
  5032.  
  5033. let claimForm = document.querySelector('form');
  5034. if(claimForm) {
  5035. claimForm.submit();
  5036. }
  5037. }
  5038.  
  5039. isCountdownVisible() {
  5040. let pars = [...document.querySelectorAll('p')];
  5041. if (pars.find(x => x.innerText.includes('wait until next day'))) {
  5042. return true;
  5043. }
  5044.  
  5045. if (pars.find(x => x.innerText.includes('PROBLEM'))) {
  5046. return true;
  5047. }
  5048.  
  5049. return false;
  5050. }
  5051.  
  5052. readClaimed() {
  5053. let pars = [...document.querySelectorAll('p')];
  5054. let claimedElm = pars.find(x => x.innerText.includes('been transferred to your account'));
  5055. if (claimedElm) {
  5056. return claimedElm.innerText.split(' ')[0];
  5057. } else {
  5058. return 0;
  5059. }
  5060. }
  5061.  
  5062. readNextRoll() {
  5063. try {
  5064. let pars = [...document.querySelectorAll('p')];
  5065. if (pars.find(x => x.innerText.includes('until next day') || x.innerText.includes('ALL DAILY CLAIMS') || x.innerText.includes('You have 0 claims left'))) {
  5066. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  5067. }
  5068.  
  5069. if (pars.find(x => x.innerText.includes('PROBLEM'))) {
  5070. return helpers.addMinutes(helpers.randomInt(6, 22));
  5071. }
  5072.  
  5073. if (pars.find(x => x.innerText.includes('You have'))) {
  5074. return helpers.addMinutes(helpers.randomInt(6, 22));
  5075. }
  5076. } catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
  5077. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  5078. }
  5079. }
  5080.  
  5081. class FCryptoRoll extends Faucet {
  5082. constructor() {
  5083. let elements = {
  5084. countdownMinutes: new CountdownWidget({selector: '.sidebar-links .cursor-not-allowed span.notranslate', parser: Parsers.splitAndIdxToInt, options: { splitter: ':', idx: 1} }), // '00:21:28'
  5085. rollButton: new ButtonWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'}),
  5086. balance: new ReadableWidget({selector: 'div.flex.badge.text-bg-yellow', parser: Parsers.trimNaNs}), // '405.81 Coins'
  5087. claimed: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium', parser: Parsers.splitAndIdxTrimNaNs, options: { splitter: '(', idx: 0} }), // '25.05 Coins (12 + 13.05)'
  5088. captcha: new HCaptchaWidget({selector: '#hcap-script > iframe'}),
  5089. success: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium'})
  5090. };
  5091. let actions = {
  5092. isMultiClaim: true,
  5093. preRoll: true,
  5094. postRun: true,
  5095. readRolledNumber: false,
  5096. };
  5097. super(elements, actions);
  5098. this._paths = {
  5099. faucet: '/task/faucet-claim',
  5100. dashboard: '/dashboard'
  5101. };
  5102. this._linkSelectors = {
  5103. Faucet: 'a[href="https://faucetcrypto.com/task/faucet-claim"]'
  5104. }
  5105. this.useUrlListener();
  5106. }
  5107.  
  5108. init() {
  5109. this._elements.captcha = new HCaptchaWidget({selector: '#hcap-script > iframe'});
  5110. this._elements.rollButton = new ButtonWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'});
  5111. if (this._url.endsWith(this._paths.dashboard)) {
  5112. return this.runDashboard();
  5113. } else if (this._url.includes(this._paths.faucet)) {
  5114. return wait().then( () => { this.run(); });
  5115. }
  5116.  
  5117. return;
  5118. }
  5119.  
  5120. readSections() {
  5121. let sections = {};
  5122. try {
  5123. for (var l in this._linkSelectors) {
  5124. sections[l] = {};
  5125. sections[l].elm = document.querySelector(this._linkSelectors[l]);
  5126. if (sections[l].elm) {
  5127. let qty = sections[l].elm.querySelector('span.ml-auto');
  5128. sections[l].qty = (qty && !isNaN(qty.innerText)) ? qty.innerText : 0;
  5129. }
  5130. }
  5131. } catch {}
  5132.  
  5133. this.sections = sections;
  5134. }
  5135.  
  5136. runDashboard() {
  5137. this.readSections();
  5138.  
  5139. if (this.sections['Faucet'].elm) {
  5140. this.sections['Faucet'].elm.click();
  5141. return;
  5142. } else {
  5143. return wait().then( () => { this.run(); });
  5144. }
  5145. }
  5146.  
  5147. scrollTo() {
  5148. let mainContainer = document.querySelector('main');
  5149. if (mainContainer) {
  5150. mainContainer.scrollTo(0, mainContainer.scrollHeight - mainContainer.offsetHeight);
  5151. }
  5152. }
  5153.  
  5154. preRoll() { // search for 'You don't need to solve any captcha! The system is telling me that you are a good person :)'
  5155. this.scrollTo();
  5156. let checkCircleSpan = document.querySelector('p.font-medium.flex.justify-center.leading-0 span.text-green-500.mr-3 svg');
  5157. if(checkCircleSpan) {
  5158. if (checkCircleSpan.parentElement.parentElement.innerText.toLowerCase().includes('the system is telling me that you are a good person')) {
  5159. this._elements.captcha = new NoCaptchaWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'});
  5160. return;
  5161. }
  5162. }
  5163. }
  5164.  
  5165. postRun() {
  5166.  
  5167. if (this._url.endsWith(this._paths.dashboard) || this._oldClaimed != this._result.claimed) {
  5168. try {
  5169. this._elements.claimed.isUserFriendly.parentElement.parentElement.parentElement.querySelector('button');
  5170. } catch (err) {
  5171. }
  5172. this._oldClaimed = null;
  5173. this.readSections();
  5174. if (this.sections != {}) {
  5175. if (this.sections['Faucet'].elm) {
  5176. this.sections['Faucet'].elm.click();
  5177. return;
  5178. } else {
  5179. }
  5180. } else {
  5181. }
  5182. } else {
  5183. }
  5184.  
  5185. this._result = shared.getProp('tempResults');
  5186. shared.closeWindow(this._result);
  5187. return;
  5188. }
  5189.  
  5190. async runPtcList() {
  5191. let listItems = [...document.querySelectorAll('.grid.grid-responsive-3 .feather.feather-eye')].map(x => x.parentElement.parentElement).filter(x => x.isUserFriendly());
  5192. if (listItems.length > 0) {
  5193. listItems[0].click();
  5194. return;
  5195. } else {
  5196. return wait().then( () => { this.runPtcList() } );
  5197. }
  5198. }
  5199.  
  5200. runPtcSingleStart() {
  5201. return this.run('doRoll');
  5202. }
  5203.  
  5204. runPtcSingleWait() {
  5205. this._elements.captcha = new NoCaptchaWidget({selector: 'a.notranslate:not(.cursor-not-allowed)' });
  5206. this._elements.rollButton = new ButtonWidget({selector: 'a.notranslate:not(.cursor-not-allowed)' });
  5207. return this.run('doRoll');
  5208. }
  5209. }
  5210.  
  5211. class FPPtc extends Faucet {
  5212. constructor() {
  5213. let elements = {
  5214. claimButton: new ButtonWidget({selector: '#pop-up button.purpleButton:not([disabled])'}),
  5215. claimButtonDisabled: new ButtonWidget({selector: '#pop-up button.purpleButton'}),
  5216. openPtcButton: new ButtonWidget({fnSelector: function() {
  5217. let blacklistTitles = ['JOIN US ON WINTOMATO.COM'];
  5218. let btn = [...document.querySelectorAll('button')].filter(x => x.innerText.toLowerCase().includes('view'));
  5219. try {
  5220. btn = btn.filter(x => !blacklistTitles.includes(x.parentElement.parentElement.querySelector('h2').innerText.toUpperCase()));
  5221. } catch (err) {}
  5222. return (btn.length > 0) ? btn[0] : null;
  5223. }}),
  5224. claimed: new ReadableWidget({fnSelector: function() {
  5225. let divSpanSuccessClaim = [...document.querySelectorAll('div span')].filter(x => x.innerText.toLowerCase().includes('successfully credited with'));
  5226. return (divSpanSuccessClaim.length > 0) ? divSpanSuccessClaim[0] : null;
  5227. }, parser: Parsers.trimNaNs}),
  5228. captcha: new GeeTestCaptchaWidget(),
  5229. success: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium'})
  5230. };
  5231. let actions = {
  5232. isMultiClaim: true,
  5233. preRoll: true,
  5234. postRun: true,
  5235. readRolledNumber: false,
  5236. };
  5237. super(elements, actions);
  5238. this._paths = {
  5239. ptcList: '/ptc',
  5240. ptcSingleView: '/ptc/view',
  5241. login: '/account/login',
  5242. dashboard: '/user-admin'
  5243. };
  5244. this.useUrlListener();
  5245. }
  5246.  
  5247. init() {
  5248. if (this._url.includes(this._paths.ptcSingleView)) {
  5249. this.doPtcList(true);
  5250. return;
  5251. } else if (this._url.includes(this._paths.ptcList)) {
  5252. this.doPtcList();
  5253. return;
  5254. } else if (this._url.includes(this._paths.login)) {
  5255. this.doLogin();
  5256. return;
  5257. } else if (this._url.includes(this._paths.dashboard)) {
  5258. return;
  5259. }
  5260.  
  5261. return;
  5262. }
  5263.  
  5264. hasExpired() {
  5265. return document.body.innerText.includes('The session has expired');
  5266. }
  5267.  
  5268. hasError() {
  5269. return document.body.innerText.includes('must finish watching') || document.title.includes('Tab Closed Error');
  5270. }
  5271.  
  5272. getETAWaitSeconds(btn) {
  5273. try {
  5274. let seconds = btn.nextSibling.firstChild.innerText.split('s')[0];
  5275. return +seconds;
  5276. } catch (err) {
  5277. }
  5278. return 15;
  5279. }
  5280.  
  5281. getPayout(btn) {
  5282. this.lastClaimed = 0;
  5283. try {
  5284. let payout = btn.nextSibling.lastChild.innerText.split(' ')[0];
  5285. this.lastClaimed = +payout;
  5286. } catch (err) {
  5287. }
  5288. }
  5289.  
  5290. async validateClaim() {
  5291. await wait(1000);
  5292. if (this.hasExpired()) {
  5293. console.info('CLAIM => expired');
  5294. await wait(2000);
  5295. return false;
  5296. }
  5297. if (this._elements.claimed.isUserFriendly) {
  5298. let claimed = this._elements.claimed.value;
  5299. if (claimed) {
  5300. console.info('CLAIM => Returning claimed:', claimed);
  5301. await this.storeClaim();
  5302. await wait(2000);
  5303. return claimed;
  5304. }
  5305. }
  5306. console.info('@validateClaim => Still waiting...');
  5307. return this.validateClaim();
  5308. }
  5309.  
  5310. async storeClaim() {
  5311. let result = shared.getResult();
  5312. result.ptcsDone = (result.ptcsDone ?? 0) + 1;
  5313. result.claimed = +(result.claimed ?? 0) + +this.lastClaimed;
  5314. this.lastClaimed = 0;
  5315. shared.updateWithoutClosing(result, 'WORKING');
  5316. }
  5317.  
  5318. async confirmClaim() {
  5319. GM_setValue(`ptc-close-signal-faucetpay.io`, Date.now());
  5320. await wait(5000);
  5321. GM_deleteValue(`ptc-close-signal-faucetpay.io`);
  5322. let captcha = new GeeTestCaptchaWidget();
  5323.  
  5324. await captcha.isSolved();
  5325. if (!this._elements.claimButton.isUserFriendly) {
  5326. return;
  5327. }
  5328. this._elements.claimButton.click();
  5329. let validation = await this.validateClaim();
  5330. return this.doPtcList();
  5331. }
  5332.  
  5333. async startPtc() {
  5334. await wait(1000);
  5335. let minSeconds = this.getETAWaitSeconds(this._elements.openPtcButton.isUserFriendly);
  5336. this.getPayout(this._elements.openPtcButton.isUserFriendly);
  5337. this._elements.openPtcButton.click();
  5338. await wait(4000);
  5339. return this.waitPtcSeconds();
  5340. }
  5341.  
  5342. async waitPtcSeconds() {
  5343. if (this._elements.claimButtonDisabled.isUserFriendly) {
  5344. return this.confirmClaim();
  5345. }
  5346. if (!document.title.includes('PTC Ads') && document.title.includes('s |')) {
  5347. await wait(5000);
  5348. return this.waitPtcSeconds();
  5349. }
  5350. let iframe = document.querySelector('iframe[title="ptc-view"]');
  5351. if (document.title.includes('PTC Ads') && iframe) {
  5352. await wait(5000);
  5353. return this.waitPtcSeconds();
  5354. }
  5355. return this.confirmClaim();
  5356. }
  5357.  
  5358. async doPtcList(isSingle = false) {
  5359. if (document.title.includes('PTC Ads') || document.title.includes('Complete Visit')) {
  5360. if (this._elements.claimButtonDisabled.isUserFriendly) {
  5361. return this.confirmClaim();
  5362. } else {
  5363. if(isSingle) {
  5364. await wait(4000);
  5365. return this.doPtcList(true);
  5366. }
  5367. if (this._elements.openPtcButton.isUserFriendly) {
  5368. return this.startPtc();
  5369. } else {
  5370. shared.closeWindow();
  5371. return;
  5372. }
  5373. }
  5374. }
  5375. }
  5376.  
  5377. async doLogin() {
  5378. let username = document.querySelector('input');
  5379. let password = document.querySelector('input[type="password"]');
  5380. let captcha = new GeeTestCaptchaWidget();
  5381. let btn = document.querySelector('button[type="submit"');
  5382. if (username && password && btn && username.value != '' && password.value != '') {
  5383. await captcha.isSolved();
  5384. btn.click();
  5385. return;
  5386. } else {
  5387. shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
  5388. }
  5389. }
  5390. }
  5391.  
  5392. function createFBProcessor() {
  5393. let countdownMinutes;
  5394. let timeout = new Timeout(); // this.maxSeconds);
  5395. let captcha = new HCaptchaWidget();
  5396.  
  5397. function run() {
  5398. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  5399. };
  5400. function findCountdownOrRollButton() {
  5401. if ( isCountdownVisible() ) {
  5402. timeout.restart();
  5403. countdownMinutes = +document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount')[0].innerHTML + 1;
  5404. let result = {};
  5405. result.balance = readBalance();
  5406. result.nextRoll = helpers.addMinutes(countdownMinutes.toString());
  5407.  
  5408. shared.closeWindow(result);
  5409. return;
  5410. }
  5411.  
  5412. if ( isRollButtonVisible() ) {
  5413.  
  5414. try {
  5415. let doBonus = false; // true;
  5416. if (doBonus) {
  5417. if (!document.getElementById('bonus_span_free_wof')) {
  5418. RedeemRPProduct('free_wof_5');
  5419. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  5420. return;
  5421. }
  5422. }
  5423. } catch { }
  5424.  
  5425. /* For 'Play without captcha accounts' */
  5426. if (!captcha.isUserFriendly) {
  5427. clickRoll()
  5428. } else {
  5429. captcha.isSolved().then(() => { clickRoll(); });
  5430. }
  5431. } else {
  5432. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  5433. }
  5434. };
  5435. function isCountdownVisible() {
  5436. return document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount').length > 0;
  5437. };
  5438. function isHCaptchaVisible() {
  5439. let hCaptchaFrame = document.querySelector('.h-captcha > iframe');
  5440. if (hCaptchaFrame && hCaptchaFrame.isVisible()) {
  5441. return true;
  5442. }
  5443. return false;
  5444. };
  5445. function isRollButtonVisible() {
  5446. return document.getElementById('free_play_form_button').isVisible();
  5447. };
  5448. function clickRoll() {
  5449. try {
  5450. document.getElementById('free_play_form_button').click();
  5451. setTimeout(processRunDetails, helpers.randomMs(3000, 10000));
  5452. } catch (err) {
  5453. shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
  5454. }
  5455. };
  5456. function processRunDetails() {
  5457. if (document.getElementById('winnings').isVisible()) {
  5458. closePopup();
  5459.  
  5460. let result = {};
  5461. result.claimed = readClaimed();
  5462. result.balance = readBalance();
  5463. if(result.claimed != 0) {
  5464. result.rolledNumber = readRolledNumber();
  5465. }
  5466. shared.closeWindow(result);
  5467. return;
  5468. }
  5469.  
  5470. if (document.querySelector('.free_play_result_error').isVisible()) {
  5471. shared.closeWithError(K.ErrorType.ROLL_ERROR, document.querySelector('.free_play_result_error').innerHTML);
  5472. return;
  5473. }
  5474.  
  5475. if(document.getElementById('free_play_error').isVisible()) {
  5476. shared.closeWithError(K.ErrorType.ROLL_ERROR, document.querySelector('.free_play_error').innerHTML);
  5477. return;
  5478. }
  5479.  
  5480. if (document.getElementById('same_ip_error').isVisible()) {
  5481. shared.closeWithError(K.ErrorType.ROLL_ERROR, document.getElementById('same_ip_error').innerHTML);
  5482. return;
  5483. }
  5484.  
  5485. setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
  5486. };
  5487. function closePopup() {
  5488. let closePopupBtn = document.querySelector('.reveal-modal.open .close-reveal-modal');
  5489. if (closePopupBtn) {
  5490. closePopupBtn.click();
  5491. }
  5492. };
  5493. function readRolledNumber() {
  5494. let rolled = 0;
  5495. try {
  5496. rolled = parseInt([... document.querySelectorAll('#free_play_digits span')].map( x => x.innerHTML).join(''));
  5497. } catch { }
  5498. return rolled;
  5499. };
  5500. function readBalance() {
  5501. let balance = 0;
  5502. try {
  5503. balance = document.getElementById('balance').innerHTML;
  5504. } catch { }
  5505. return balance;
  5506. };
  5507. function readClaimed() {
  5508. let claimed = 0;
  5509. try {
  5510. claimed = document.getElementById('winnings').innerHTML;
  5511. } catch { }
  5512. return claimed;
  5513. };
  5514.  
  5515. return {
  5516. run: run
  5517. };
  5518. }
  5519.  
  5520. function createBigBtcProcessor() {
  5521. let timeout = new Timeout(); // this.maxSeconds);
  5522. let countdownMinutes;
  5523. let captcha = new HCaptchaWidget();
  5524. let selectElement = {
  5525. loadingDiv: function() {
  5526. let loading = document.querySelector('#loading');
  5527. if (loading && loading.isVisible()) {
  5528. return true;
  5529. } else {
  5530. return false;
  5531. }
  5532. },
  5533. addressInput: function() {
  5534. return document.querySelector('#login input[name="address"]');
  5535. },
  5536. loginButton: function() {
  5537. return document.querySelector('#login input[type="submit"]');
  5538. },
  5539. claimButton: function() {
  5540. return document.getElementById('claimbutn');
  5541. },
  5542. countdown: function() { // "You have to wait\n60 minutes"
  5543. let cd = document.getElementById('countdown');
  5544. if(cd && cd.isVisible()) {
  5545. return parseInt(cd.innerText);
  5546. }
  5547. return null;
  5548. },
  5549. claimedAmount: function() {
  5550. let elm = document.querySelector('.alert.alert-success.pulse'); //"Yuppie! You won 2 satoshi!"
  5551. if(elm && elm.isVisible()) {
  5552. let val = parseInt(elm.innerText.replace(/\D/g, ''));
  5553. if (Number.isInteger(val)) {
  5554. val = val / 100000000;
  5555. }
  5556.  
  5557. return val;
  5558. } else {
  5559. return null;
  5560. }
  5561. },
  5562. balance: function() {
  5563. let elm = document.querySelector('a b');
  5564. if (elm && elm.isVisible()) {
  5565. let val = parseInt(elm.innerText.replace(',', ''));
  5566. if (Number.isInteger(val)) {
  5567. val = val / 100000000;
  5568. }
  5569.  
  5570. return val;
  5571. } else {
  5572. return null;
  5573. }
  5574. },
  5575. error: function () {
  5576. return null;
  5577. }
  5578. };
  5579.  
  5580. function init() {
  5581. window.scrollTo(0, document.body.scrollHeight);
  5582. let m = document.getElementById('main'); if (m) { m.style.display='block'; }
  5583. m = document.getElementById('block-adb-enabled'); if (m) { m.style.display='none'; }
  5584. m = document.getElementById('ielement'); if (m) { m.style.display='block'; }
  5585. setInterval(() => {
  5586. let frames = [...document.querySelectorAll('iframe')];
  5587. frames.forEach(x => {
  5588. if (!x.src.includes('hcaptcha')) {
  5589. x.remove()
  5590. }
  5591. });
  5592. }, 5000);
  5593.  
  5594. if (window.location.href.includes('/faucet')) {
  5595. setTimeout(runFaucet, helpers.randomMs(12000, 14000));
  5596. return;
  5597. } else {
  5598. setTimeout(run, helpers.randomMs(3000, 5000));
  5599. return;
  5600. }
  5601. }
  5602.  
  5603. function run() {
  5604. try {
  5605. setTimeout(waitIfLoading, helpers.randomMs(12000, 15000));
  5606. } catch (err) {
  5607. shared.closeWithErrors(K.ErrorType.ERROR, err);
  5608. }
  5609. };
  5610. function doLogin() {
  5611. let address = selectElement.addressInput();
  5612. if(address && address.value != shared.getCurrent().params.address) {
  5613. address.value = shared.getCurrent().params.address;
  5614. } else {
  5615. selectElement.loginButton().click();
  5616. return;
  5617. }
  5618. setTimeout( doLogin , helpers.randomMs(1000, 2000));
  5619. };
  5620. function waitIfLoading() {
  5621. if ( !selectElement.loadingDiv() ) {
  5622. doLogin();
  5623. return;
  5624. } else {
  5625. }
  5626.  
  5627. setTimeout(waitIfLoading, helpers.randomMs(5000, 7000));
  5628. };
  5629. function runFaucet() {
  5630. let claimedAmount = selectElement.claimedAmount();
  5631. if(claimedAmount) {
  5632. processRunDetails();
  5633. return;
  5634. } else if (selectElement.countdown()) {
  5635. let result = {};
  5636.  
  5637. shared.closeWindow(result);
  5638. } else {
  5639. captcha.isSolved().then(() => { clickClaim(); });
  5640. }
  5641. }
  5642. function clickClaim() {
  5643. try {
  5644. selectElement.claimButton().click();
  5645. return;
  5646. } catch (err) {
  5647. shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
  5648. }
  5649. };
  5650. function processRunDetails() {
  5651. let claimedAmount = selectElement.claimedAmount();
  5652. let balance = selectElement.balance();
  5653. let countdown = selectElement.countdown();
  5654.  
  5655. if (claimedAmount && balance) {
  5656. let result = {};
  5657. result.claimed = claimedAmount;
  5658. result.balance = balance;
  5659.  
  5660. shared.closeWindow(result);
  5661. return;
  5662. }
  5663.  
  5664. setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
  5665. };
  5666.  
  5667. return {
  5668. init: init
  5669. };
  5670. }
  5671.  
  5672. function createBestChangeProcessor() {
  5673. let timeout = new Timeout(); // this.maxSeconds);
  5674. let countdownMinutes;
  5675. let captcha = new HCaptchaWidget({selector: '.hcaptcha > iframe'});
  5676. let elements = {
  5677. captcha: function() {
  5678. return document.querySelector('.hcaptcha > iframe');
  5679. },
  5680. container: function() {
  5681. return document.querySelector('#info_bonus');
  5682. },
  5683. containerOpener: function() {
  5684. return document.querySelector('#tab_bonus a');
  5685. },
  5686. addressInput: function() {
  5687. return document.querySelector('#bonus_purse');
  5688. },
  5689. claimButton: function() {
  5690. return document.querySelector('#bonus_button');
  5691. },
  5692. countdown: function() { // Time left: mm:ss
  5693. let elm = document.querySelector('#bonus_button');
  5694. try {
  5695. if (elm.value) {
  5696. let timeLeft = elm.value.split(':');
  5697. if (timeLeft.length > 1) {
  5698. return parseInt(timeLeft[1]);
  5699. }
  5700. }
  5701. } catch (err) {
  5702. return null;
  5703. }
  5704. },
  5705. claimedAmount: function() {
  5706. let elm = document.querySelector("#bonus_status b");
  5707. try {
  5708. let sats = elm.innerText.replace(/\D/g, '');
  5709. return sats / 100000000;
  5710. } catch (err) {
  5711. return null;
  5712. }
  5713. },
  5714. balance: function() {
  5715. let elm = document.querySelector("#faucet_unpaid_balance b");
  5716. try {
  5717. let sats = elm.innerText.replace(/\D/g, '');
  5718. return sats / 100000000;
  5719. } catch (err) {
  5720. return null;
  5721. }
  5722. }
  5723. };
  5724.  
  5725. function init() {
  5726. run();
  5727. }
  5728.  
  5729. function run() {
  5730. try {
  5731. if (!elements.container().isUserFriendly()) {
  5732. let co = elements.containerOpener();
  5733. if(co.isUserFriendly()) {
  5734. co.onclick = co.onmousedown;
  5735. co.click();
  5736. }
  5737. }
  5738. setTimeout(findCountdownOrRoll, helpers.randomMs(4000, 5000));
  5739. } catch (err) {
  5740. shared.closeWithErrors(K.ErrorType.ERROR, err);
  5741. }
  5742. };
  5743. function findCountdownOrRoll() {
  5744. let countdown = elements.countdown();
  5745. if(countdown) {
  5746. let result = { };
  5747. result.nextRoll = helpers.addMinutes(countdown.toString());
  5748.  
  5749. shared.closeWindow(result);
  5750. return;
  5751. }
  5752.  
  5753. let ai = elements.addressInput();
  5754.  
  5755. if (ai.isUserFriendly()) {
  5756. if (ai.value != shared.getCurrent().params.address) {
  5757. ai.value = shared.getCurrent().params.address;
  5758. }
  5759. captcha.isSolved().then(() => { clickClaim(); });
  5760. return;
  5761. }
  5762.  
  5763. setTimeout(findCountdownOrRoll, helpers.randomMs(10000, 12000));
  5764. };
  5765.  
  5766. function clickClaim() {
  5767. try {
  5768. let btn = elements.claimButton();
  5769. if(btn.isUserFriendly()) {
  5770. btn.click();
  5771. setTimeout(processRunDetails, helpers.randomMs(4000, 8000));
  5772. } else {
  5773. setTimeout(clickClaim, helpers.randomMs(4000, 8000));
  5774. }
  5775. return;
  5776. } catch (err) {
  5777. shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
  5778. }
  5779. };
  5780.  
  5781. function processRunDetails() {
  5782. let claimedAmount = elements.claimedAmount();
  5783. let balance = elements.balance();
  5784.  
  5785. if (claimedAmount && balance) {
  5786. let result = {};
  5787. result.claimed = claimedAmount;
  5788. result.balance = balance;
  5789.  
  5790. shared.closeWindow(result);
  5791. return;
  5792. }
  5793.  
  5794. setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
  5795. };
  5796.  
  5797. return {
  5798. init: init
  5799. };
  5800. }
  5801.  
  5802. function createSGProcessor() {
  5803. let timerSpans;
  5804. function run() {
  5805. if(isLoading()) {
  5806. setTimeout(run, helpers.randomMs(5000, 10000));
  5807. return;
  5808. } else if (hasPopup()) {
  5809. closePopup();
  5810. setTimeout(run, helpers.randomMs(5000, 10000));
  5811. } else {
  5812. if(isMinerActive()) {
  5813. processRunDetails();
  5814. } else {
  5815. setTimeout(run, helpers.randomMs(5000, 10000));
  5816. activateMiner();
  5817. }
  5818. }
  5819. };
  5820. function hasPopup() {
  5821. if (document.querySelector('div.absolute.flex.top-0.right-0.cursor-pointer.p-4.text-white.md-text-gray-1')) {
  5822. return true;
  5823. }
  5824. return false;
  5825. };
  5826. function closePopup() {
  5827. try {
  5828. document.querySelector("div.absolute.flex.top-0.right-0.cursor-pointer.p-4.text-white.md-text-gray-1").click();
  5829. document.querySelector('svg.flex.w-8.h-8.fill-current').parentElement.click();
  5830. } catch { shared.devlog(`@SG: error closing popup`); }
  5831. };
  5832. function isLoading() {
  5833. return document.getElementById('loader-logo') ? true : false;
  5834. };
  5835. function isMinerActive() {
  5836. timerSpans = document.querySelector('.font-bold.text-center.text-accent.w-11-12.text-18 span');
  5837.  
  5838. if(timerSpans) {
  5839. return true;
  5840. } else {
  5841. return false;
  5842. }
  5843. return (!!timerSpans);
  5844. };
  5845. function activateMiner() {
  5846. let activateButton = document.querySelector("#region-main button.activate.block.w-full.h-full.mx-auto.p-0.rounded-full.select-none.cursor-pointer.focus-outline-none.border-0.bg-transparent");
  5847. if (activateButton) {
  5848. activateButton.click();
  5849. setTimeout(run, helpers.randomMs(10000, 20000));
  5850. } else {
  5851. processRunDetails()
  5852. }
  5853. };
  5854.  
  5855. function processRunDetails() {
  5856. let result = {};
  5857. result.nextRoll = helpers.addMinutes(readCountdown().toString());
  5858. result.balance = readBalance();
  5859. shared.closeWindow(result);
  5860. };
  5861.  
  5862. function readCountdown() {
  5863. let synchronizing = document.querySelector('.text-15.font-bold.text-center.text-accent'); // use
  5864. let mins = 15;
  5865. try {
  5866. let timeLeft = timerSpans.innerText.split(':');
  5867. if (timeLeft[0] == 'Synchronizing') {
  5868. }
  5869.  
  5870. if(timeLeft.length === 3) {
  5871. mins = parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
  5872. }
  5873. } catch (err) { shared.devlog(`SG Error reading countdown: ${err}`); }
  5874. return mins;
  5875. };
  5876. function readBalance() {
  5877. let balance = "";
  5878. try {
  5879. balance = document.querySelector('span.text-accent').innerText + " BTC";
  5880. } catch (err) { }
  5881. return balance;
  5882. };
  5883. return {
  5884. run: run,
  5885. processRunDetails: processRunDetails
  5886. };
  5887. }
  5888.  
  5889. class AutoCMl extends Faucet {
  5890. constructor() {
  5891. let elements = {
  5892. claimed: new ReadableWidget({selector: 'div.alert.alert-success', parser: Parsers.splitAndIdxTrimNaNs, options: { splitter: ' ', idx: 0} }),
  5893. captcha: new HCaptchaWidget(),
  5894. rollButton: new ButtonWidget({selector: 'input[type="submit"].claim-button'}),
  5895. addressInput: new TextboxWidget({ selector: 'form[role="form"] input[type="text"]'})
  5896. };
  5897. let actions = {
  5898. readTimeLeft: false,
  5899. readRolledNumber: false,
  5900. readBalance: false
  5901. };
  5902. super(elements, actions);
  5903. }
  5904.  
  5905. init() {
  5906. this.hideAdBlocker();
  5907. if(this.hasErrorMessage('suspicious activity')) {
  5908. shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
  5909. return;
  5910. }
  5911. if(this.hasErrorMessage('no funds left') || this.hasErrorMessage('not have sufficient funds')) {
  5912. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
  5913. return;
  5914. }
  5915.  
  5916. if(this.hasErrorMessage('reached the daily claim limit')) {
  5917. let result = {
  5918. nextRoll: this.readNextRoll()
  5919. };
  5920. shared.closeWindow(result);
  5921. return;
  5922. }
  5923.  
  5924. let claimed = this.readClaimed();
  5925. if (claimed != 0) {
  5926. if (!location.href.includes('doge')) {
  5927. claimed = claimed/100000000;
  5928. }
  5929. let result = {
  5930. claimed: claimed,
  5931. nextRoll: this.readNextRoll()
  5932. };
  5933. shared.closeWindow(result);
  5934. return;
  5935. }
  5936.  
  5937. let waitTime = this.hasWaitTime();
  5938. if (waitTime) {
  5939. let result = {
  5940. nextRoll: helpers.addMinutes(waitTime + 1)
  5941. };
  5942. shared.closeWindow(result);
  5943. return;
  5944. }
  5945.  
  5946. if (this.changeCaptcha()) {
  5947. return;
  5948. }
  5949.  
  5950. this.setCurrentCaptcha();
  5951.  
  5952. if (this._elements.addressInput.isUserFriendly) {
  5953. if (this._elements.addressInput.value != this._params.address) {
  5954. this._elements.addressInput.value = this._params.address;
  5955. }
  5956. }
  5957. this.run();
  5958. }
  5959.  
  5960. hideAdBlocker() {
  5961. try {
  5962. document.getElementById("page-body").style.display = "block";
  5963. document.getElementById("blocker-enabled").style.display = "none";
  5964. } catch (err) {}
  5965. setInterval(() => {
  5966. try {
  5967. document.getElementById("page-body").style.display = "block";
  5968. document.getElementById("blocker-enabled").style.display = "none";
  5969. } catch (err) {}
  5970. }, 3000);
  5971. }
  5972.  
  5973. changeCaptcha() {
  5974. let selections = [...document.querySelectorAll('div.text-center b')];
  5975. if (selections.length == 0) {
  5976. return false;
  5977. }
  5978. if (selections.filter(x => x.innerText.toLowerCase().includes('hcaptcha')).length != 1) {
  5979. location.href = location.href.includes('?') ? (location.href + '&cc=hCaptcha') : (location.href + '?cc=hCaptcha');
  5980. return true;
  5981. }
  5982. return false;
  5983. }
  5984.  
  5985. hasErrorMessage(searchTerm) {
  5986. return document.body.innerText.toLowerCase().includes(searchTerm);
  5987. }
  5988.  
  5989. hasWaitTime() {
  5990. try {
  5991. let pInfos = [...document.querySelectorAll('p.alert.alert-info')].filter(x => x.innerText.toLowerCase().includes('you have to wait'));
  5992. if (pInfos.length == 1) {
  5993. let time = +pInfos[0].innerText.toLowerCase().replace('you have to wait ', '').split(' ')[0];
  5994. return time;
  5995. }
  5996. } catch (err) {}
  5997. return false;
  5998. }
  5999.  
  6000. readNextRoll() {
  6001. try {
  6002. let spans = [...document.querySelectorAll('div.row div.col-md-5ths span:not(.glyphicon)')];
  6003. let idxClaimsLeft = spans.findIndex(x => x.innerText.includes('daily claims left'));
  6004. if (idxClaimsLeft > -1) {
  6005. if (spans[idxClaimsLeft].innerText.includes('0')) {
  6006. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  6007. } else {
  6008. return helpers.addMinutes(helpers.randomInt(5, 12));
  6009. }
  6010. }
  6011. } catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
  6012. return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
  6013. }
  6014. }
  6015.  
  6016. class CClicks extends Faucet {
  6017. constructor() {
  6018. let elements = {
  6019. claimed: new ReadableWidget({selector: 'div.alert.alert-success', parser: Parsers.cbgClaimed}),
  6020. captcha: new HCaptchaWidget(),
  6021. rollButton: new ButtonWidget({selector: '#myModal input[type="submit"].btnclaim'}),
  6022. addressInput: new TextboxWidget({ selector: '#myModal input[type="text"]'}),
  6023. openModalButton: new ButtonWidget({selector: 'button[data-target="#myModal"]'})
  6024. };
  6025. let actions = {
  6026. readTimeLeft: false,
  6027. readRolledNumber: false,
  6028. readBalance: false
  6029. };
  6030. super(elements, actions);
  6031. }
  6032.  
  6033. async init() {
  6034. if (this.hasCloudflare()) {
  6035. return;
  6036. }
  6037.  
  6038. if(this.hasErrorMessage('suspicious activity')) {
  6039. shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
  6040. return;
  6041. }
  6042. if(this.hasErrorMessage('no funds left') || this.hasErrorMessage('not have sufficient funds')) {
  6043. shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
  6044. return;
  6045. }
  6046. if(this.hasErrorMessage('reached the daily claim limit') || this.hasErrorMessage('reached the daily limit')) {
  6047. let result = {
  6048. nextRoll: helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40))
  6049. };
  6050. shared.closeWindow(result);
  6051. return;
  6052. }
  6053.  
  6054. let claimed = this.readClaimed();
  6055. if (claimed != 0) {
  6056. let result = {
  6057. claimed: claimed,
  6058. nextRoll: this.readNextRoll()
  6059. };
  6060. shared.closeWindow(result);
  6061. return;
  6062. }
  6063.  
  6064. if (this.changeCaptcha()) {
  6065. return;
  6066. }
  6067.  
  6068. if (this._elements.openModalButton.isUserFriendly) {
  6069. this._elements.openModalButton.click();
  6070. await wait(helpers.randomInt(1000, 2000));
  6071. }
  6072.  
  6073. if (this._elements.addressInput.isUserFriendly) {
  6074. if (this._elements.addressInput.value != this._params.address) {
  6075. this._elements.addressInput.value = this._params.address;
  6076. }
  6077. }
  6078. this.run();
  6079. }
  6080.  
  6081. changeCaptcha() {
  6082. let selections = [...document.querySelectorAll('div.text-center b')];
  6083. if (selections.length == 0) {
  6084. return false;
  6085. }
  6086. if (selections.filter(x => x.innerText.toLowerCase().includes('hcaptcha')).length != 1) {
  6087. location.href = location.href.includes('?') ? (location.href + '&cc=hCaptcha') : (location.href + '?cc=hCaptcha');
  6088. return true;
  6089. }
  6090. return false;
  6091. }
  6092.  
  6093. hasErrorMessage(searchTerm) {
  6094. return document.body.innerText.toLowerCase().includes(searchTerm);
  6095. }
  6096.  
  6097. readNextRoll() {
  6098. try {
  6099. let p = document.querySelector('p.alert.alert-success');
  6100. if (p && p.innerText.toLowerCase().includes('daily')) {
  6101. p = p.innerText.split('\n')[1];
  6102. p = +p.split(' daily')[0];
  6103.  
  6104. if (p > 0) {
  6105. return helpers.addMinutes(helpers.randomInt(3, 9));
  6106. } else {
  6107. return helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40));
  6108. }
  6109. }
  6110. return helpers.addMinutes(helpers.randomInt(3, 9));
  6111. } catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
  6112. return helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40));
  6113. }
  6114. }
  6115.  
  6116. let landing, instance, siteTimer;
  6117. let useTimer;
  6118.  
  6119. class Site {
  6120. constructor(params) {
  6121. Object.assign(this, {
  6122. schedule: '4a70e0', // Owner!
  6123. id: null,
  6124. name: null,
  6125. cmc: null, // REVIEW LOCATION
  6126. coinRef: null, // REVIEW LOCATION. Only for CFs?
  6127. url: null, // REVIEW FORMAT. Only one/'start' url? What about complex scripts/rotators/SLs?
  6128. rf: null, // ...
  6129. type: null, // REVIEW DEFAULT. It should be something like 'Crawler' or 'Handler' and the site params should depend on this value
  6130. clId: null,
  6131. wallet: null, // should be part of site parameters/crawler based?
  6132. enabled: false,
  6133. lastClaim: 0,
  6134. aggregate: 0,
  6135. balance: 0,
  6136. stats: {},
  6137. nextRoll: null,
  6138. params: {}, // should have schedule overrides and be called customExecution, scheduleParamaters or something like that
  6139. firstRun: true,
  6140. isExternal: false,
  6141. }, params);
  6142.  
  6143. this.setLegacyConditionalDefaults();
  6144.  
  6145. }
  6146.  
  6147. setLegacyConditionalDefaults() {
  6148. if (this.type == K.WebType.CRYPTOSFAUCETS) {
  6149. this.schedule = '65329c';
  6150. }
  6151.  
  6152. if (this.type == K.WebType.FREEBITCOIN) {
  6153. this.params['custom.useWofRp'] = 0;
  6154. this.params['custom.useFunRp'] = 0;
  6155. }
  6156.  
  6157. if (this.type == K.WebType.STORMGAIN) {
  6158. this.params['defaults.nextRun.override'] = true;
  6159. this.params['defaults.nextRun.useCountdown'] = true;
  6160. this.params['defaults.nextRun'] = 0;
  6161. this.params['defaults.nextRun.min'] = 15;
  6162. this.params['defaults.nextRun.max'] = 20;
  6163. }
  6164. if (this.type == K.WebType.FAUCETPAY) {
  6165. this.params['defaults.workInBackground.override'] = true;
  6166. this.params['defaults.workInBackground'] = false;
  6167. this.params['defaults.nextRun.override'] = true;
  6168. this.params['defaults.nextRun.useCountdown'] = false;
  6169. this.params['defaults.nextRun'] = 0;
  6170. this.params['defaults.nextRun.min'] = 300;
  6171. this.params['defaults.nextRun.max'] = 360;
  6172. }
  6173. if (this.type == K.WebType.BIGBTC) {
  6174. this.params['defaults.nextRun.override'] = true;
  6175. this.params['defaults.nextRun.useCountdown'] = false;
  6176. this.params['defaults.nextRun'] = 0;
  6177. this.params['defaults.nextRun.min'] = 15;
  6178. this.params['defaults.nextRun.max'] = 40;
  6179. }
  6180. if (this.type == K.WebType.DUTCHYROLL) {
  6181. this.params['defaults.nextRun.override'] = true;
  6182. this.params['defaults.nextRun.useCountdown'] = true;
  6183. this.params['defaults.nextRun'] = 0;
  6184. this.params['defaults.nextRun.min'] = 30;
  6185. this.params['defaults.nextRun.max'] = 35;
  6186. }
  6187. if (this.type == K.WebType.FCRYPTO) {
  6188. this.params['defaults.workInBackground.override'] = true;
  6189. this.params['defaults.workInBackground'] = false;
  6190. this.params['defaults.nextRun.override'] = true;
  6191. this.params['defaults.nextRun.useCountdown'] = false;
  6192. this.params['defaults.nextRun'] = 0;
  6193. this.params['defaults.nextRun.min'] = 26;
  6194. this.params['defaults.nextRun.max'] = 35;
  6195. this.params['defaults.timeout.override'] = true;
  6196. this.params['defaults.timeout'] = 3;
  6197. this.params['defaults.postponeMinutes.override'] = true;
  6198. this.params['defaults.postponeMinutes'] = 0;
  6199. this.params['defaults.postponeMinutes.min'] = 12;
  6200. this.params['defaults.postponeMinutes.max'] = 18;
  6201. }
  6202. if (this.type == K.WebType.FPB) {
  6203. this.params['defaults.nextRun.override'] = true;
  6204. this.params['defaults.nextRun.useCountdown'] = false;
  6205. this.params['defaults.nextRun'] = 0;
  6206. this.params['defaults.nextRun.min'] = 22;
  6207. this.params['defaults.nextRun.max'] = 45;
  6208. }
  6209. }
  6210.  
  6211. static _sites = [];
  6212. static getAll() {
  6213. return Site._sites;
  6214. }
  6215.  
  6216. static getById(siteId) {
  6217. return Site.getAll().find(x => x.id == siteId) || false;
  6218. }
  6219.  
  6220. static createFromDataArray(newSites) {
  6221. if (!Array.isArray(newSites)) {
  6222. newSites = [...newSites];
  6223. }
  6224. newSites.forEach(s => Site.getAll().push(new Site(s)));
  6225. }
  6226.  
  6227. static add(data) {
  6228. let newSite = new Site(data);
  6229. Site.getAll().push(newSite);
  6230.  
  6231. let schedule = Schedule.getById(newSite.schedule);
  6232.  
  6233. if (!schedule) {
  6234. try {
  6235. schedule = Schedule.getAll()[0];
  6236. } catch (err) {
  6237. console.warn('No schedules found! Reseting to default schedules');
  6238. let defaultSchedule = new Schedule({ uuid: '4a70e0', name: 'Default' });
  6239. let sampleSchedule = new Schedule({ uuid: '65329c', name: 'CF' });
  6240. if (Schedule.getAll().length == 0) {
  6241. Schedule.add(defaultSchedule);
  6242. Schedule.add(sampleSchedule);
  6243. }
  6244. schedule = Schedule.getAll()[0];
  6245. }
  6246. }
  6247.  
  6248. if (!schedule) {
  6249. console.warn('Schedule NOT found');
  6250. console.warn(data);
  6251. return;
  6252. }
  6253. schedule.addSite(newSite);
  6254.  
  6255. eventer.emit('siteAdded', {
  6256. siteId: newSite.id,
  6257. siteName: newSite.name,
  6258. scheduleId: newSite.schedule
  6259. });
  6260. }
  6261.  
  6262. static remove(siteId) {
  6263. let idx = this._sites.findIndex(x => x.id === siteId);
  6264. if (idx > -1 && this._sites[idx].isExternal) {
  6265. let siteName = this._sites[idx].name;
  6266. this._sites = Site.getAll().filter(x => x.id !== siteId);
  6267. Schedule.getAll().forEach(sch => {
  6268. sch.removeSite(siteId);
  6269. });
  6270. eventer.emit('siteRemoved', {
  6271. siteId: siteId,
  6272. siteName: siteName
  6273. });
  6274. }
  6275.  
  6276. }
  6277.  
  6278. static sortAll() {
  6279. Site.getAll().sort( function(a,b) {
  6280. if (a === b) {
  6281. return 0;
  6282. } else if (a.nextRoll === null && b.nextRoll === null) {
  6283. let aHasLoginError = a.stats?.errors?.errorType == 2;
  6284. let bHasLoginError = b.stats?.errors?.errorType == 2;
  6285. if (aHasLoginError) {
  6286. return -1;
  6287. } else if (bHasLoginError) {
  6288. return 1;
  6289. }
  6290. return a.id > b.id ? -1 : 1
  6291. } else if (a.nextRoll === null) {
  6292. return 1;
  6293. } else if (b.nextRoll === null) {
  6294. return -1;
  6295. } else {
  6296. return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
  6297. }
  6298. });
  6299. }
  6300.  
  6301. static setAsRunAsap(siteId) {
  6302. let site = Site.getById(siteId);
  6303. if (!site) return false;
  6304.  
  6305. try {
  6306. let schedule = Schedule.getById(site.schedule);
  6307. if (schedule.status == STATUS.CLAIMING) {
  6308. console.warn(`Setting ASAP as 1st in schedule time + 1`);
  6309. site.nextRoll = new Date(schedule.currentSite.nextRoll.getTime() + 1);
  6310. } else {
  6311. let now = new Date();
  6312. if (!schedule.currentSite?.nextRoll) {
  6313. console.warn(`Setting ASAP as now()`);
  6314. site.nextRoll = now;
  6315. } else if (now < schedule.currentSite.nextRoll) {
  6316. console.warn(`Setting ASAP as now()`);
  6317. site.nextRoll = now;
  6318. } else {
  6319. console.warn(`Setting ASAP as 1st in schedule time - 1`);
  6320. site.nextRoll = new Date(schedule.currentSite.nextRoll.getTime() - 1);
  6321. }
  6322. }
  6323. site.enabled = true;
  6324.  
  6325. console.warn(`[${site.schedule}] ${site.name} updated to run ASAP from Site`);
  6326. eventer.emit('siteUpdated', site);
  6327. return;
  6328. } catch (err) {
  6329. console.error(err);
  6330. ui.log({msg: `Error setting faucet to run ASAP from Site: ${err}`});
  6331. }
  6332. }
  6333.  
  6334. changeSchedule(newScheduleId) {
  6335. let oldScheduleId = null;
  6336. if (this.schedule) {
  6337. oldScheduleId = this.schedule;
  6338. Schedule.getById(this.schedule)?.removeSite(this.id);
  6339. }
  6340. this.schedule = newScheduleId;
  6341. let newSchedule = Schedule.getById(this.schedule);
  6342. newSchedule.addSite(this); // maybe use just the ids...
  6343. eventer.emit('siteChangedSchedule', {
  6344. siteId: this.id,
  6345. scheduleId: this.schedule,
  6346. oldScheduleId: oldScheduleId
  6347. });
  6348. }
  6349.  
  6350. static saveAll() {
  6351. persistence.save('webList', Site._sites.map(x => x.toStorage()), true);
  6352. }
  6353.  
  6354. toStorage() { // Single site
  6355. if (!this.isExternal) {
  6356. return {
  6357. id: this.id,
  6358. isExternal: this.isExternal || false,
  6359. name: this.name,
  6360. schedule:this.schedule,
  6361. lastClaim: this.lastClaim,
  6362. aggregate: this.aggregate,
  6363. balance: this.balance,
  6364. stats: this.stats,
  6365. nextRoll: this.nextRoll,
  6366. enabled: this.enabled,
  6367. params: this.params
  6368. };
  6369. } else {
  6370. return {
  6371. id: this.id,
  6372. url: this.url.href,
  6373. clId: this.clId,
  6374. type: this.type,
  6375. cmc: this.cmc,
  6376. rf: this.rf,
  6377. name: this.name,
  6378. isExternal: this.isExternal || false,
  6379. schedule:this.schedule,
  6380. lastClaim: this.lastClaim,
  6381. aggregate: this.aggregate,
  6382. balance: this.balance,
  6383. stats: this.stats,
  6384. nextRoll: this.nextRoll,
  6385. enabled: this.enabled,
  6386. params: this.params
  6387. };
  6388. }
  6389. }
  6390.  
  6391. update(items) { // this should be for Parameters or Execution (custom)
  6392. this.params = this.params || {};
  6393. items.forEach( item => {
  6394. this.params[item.prop] = item.value;
  6395. });
  6396. ui.log({schedule: this.schedule, siteName: this.name, msg: `Site ${this.name} updated`});
  6397. }
  6398.  
  6399. getSiteParameters() {
  6400. if (this.type == K.WebType.CRYPTOSFAUCETS) {
  6401. this.siteParameters = {
  6402. handler: 'CF',
  6403. fields: [
  6404. { name: 'try_get_codes', type: 'checkbox', value: 'false', text: 'Auto update promo codes' },
  6405. { name: 'max_rolls_per_visit', type: 'numberInput', value: 1, min: 0 },
  6406. { name: 'autologin', type: 'checkbox', value: 'true', text: 'Autologin when necessary' },
  6407. { name: 'credentials_mode', type: 'credentials_or_autofilled', value: '2' },
  6408. { name: 'email', type: 'email', value: '' },
  6409. { name: 'password', type: 'password', value: '' }
  6410. ]
  6411. };
  6412. }
  6413. return this.siteParameters || false;
  6414. }
  6415. }
  6416. class Schedule {
  6417. constructor(params) {
  6418. Object.assign(this, {
  6419. uuid: '4a70e0',
  6420. name: 'default_schedule',
  6421. status: STATUS.INITIALIZING,
  6422. currentSite: null,
  6423. sites: [],
  6424. tab: null,
  6425. timer: null, // TBD
  6426. timeWaiting: 0,
  6427. timeUntilNext: null,
  6428. worker: null
  6429. }, params)
  6430. this.timer = new Timer({ isManager: true, delaySeconds: 30, uuid: this.uuid, webType: null });
  6431. }
  6432.  
  6433. static schedules = [];
  6434.  
  6435. static getAll() {
  6436. return Schedule.schedules;
  6437. }
  6438.  
  6439. static getById(scheduleId) {
  6440. return Schedule.getAll().find(x => x.uuid == scheduleId) || false;
  6441. }
  6442.  
  6443. static add(newSchedule) {
  6444. Schedule.getAll().push(newSchedule);
  6445. }
  6446.  
  6447. static getAllForCrud() {
  6448. return Schedule.getAll().map(x => {
  6449. return {
  6450. uuid: x.uuid,
  6451. name: x.name,
  6452. hasSites: x.sites && x.sites.length > 0
  6453. };
  6454. });
  6455. }
  6456.  
  6457. static async initialize() {
  6458.  
  6459. Schedule.loadAll();
  6460.  
  6461. let defaultSchedule = new Schedule({ uuid: '4a70e0', name: 'Default' });
  6462. let sampleSchedule = new Schedule({ uuid: '65329c', name: 'CF' });
  6463. if (Schedule.getAll().length == 0) {
  6464. Schedule.add(defaultSchedule);
  6465. Schedule.add(sampleSchedule);
  6466. return;
  6467. }
  6468.  
  6469. let idxDefault = Schedule.getAll().findIndex(x => x.uuid == '4a70e0');
  6470. if (idxDefault == -1) {
  6471. Schedule.add(defaultSchedule);
  6472. }
  6473. };
  6474.  
  6475. static saveAll() {
  6476. persistence.save('schedules', Schedule.schedules.map(x => {
  6477. return {
  6478. uuid: x.uuid,
  6479. name: x.name
  6480. };
  6481. }), true);
  6482. }
  6483.  
  6484. static loadAll() {
  6485. Schedule.schedules = [];
  6486. let schedulesJson = persistence.load('schedules', true) || [];
  6487. schedulesJson.forEach(function(element) {
  6488. Schedule.getAll().push(new Schedule({
  6489. uuid: element.uuid,
  6490. name: element.name,
  6491. }));
  6492. });
  6493. }
  6494.  
  6495. sortSites() {
  6496. this.sites.sort( function(a,b) {
  6497. if (a === b) {
  6498. return 0;
  6499. } else if (a.nextRoll === null && b.nextRoll === null) {
  6500. let aHasLoginError = a.stats?.errors?.errorType == 2;
  6501. let bHasLoginError = b.stats?.errors?.errorType == 2;
  6502. if (aHasLoginError) {
  6503. return -1;
  6504. } else if (bHasLoginError) {
  6505. return 1;
  6506. }
  6507. return a.id > b.id ? -1 : 1
  6508. } else if (a.nextRoll === null) {
  6509. return 1;
  6510. } else if (b.nextRoll === null) {
  6511. return -1;
  6512. } else {
  6513. return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
  6514. }
  6515. });
  6516. }
  6517.  
  6518. static crud(data) {
  6519. let isInvalid = false;
  6520. try {
  6521. const orphanSites = [];
  6522. data.forEach(x => {
  6523. if (x.added) {
  6524. if (Schedule.getById(x.uuid)) {
  6525. isInvalid = true;
  6526. } else {
  6527. let newSchedule = new Schedule({
  6528. uuid: x.uuid,
  6529. name: x.name,
  6530. order: x.order
  6531. })
  6532. Schedule.getAll().push(newSchedule);
  6533. newSchedule.start();
  6534. }
  6535. } else if (x.removed) {
  6536. let pos = Schedule.getAll().findIndex(s => s.uuid == x.originals.uuid);
  6537. orphanSites.push(...Schedule.getAll()[pos].sites);
  6538. Schedule.getAll().splice(pos, 1);
  6539. } else {
  6540. let sch = Schedule.getAll().find(s => s.uuid == x.originals.uuid);
  6541. if (Schedule.getById(x.uuid) && (Schedule.getById(x.uuid) != sch)) {
  6542. isInvalid = true;
  6543. } else {
  6544. sch.uuid = x.uuid;
  6545. }
  6546. sch.name = x.name;
  6547. sch.order = x.order;
  6548. }
  6549. });
  6550.  
  6551. Schedule.getAll().sort((a, b) => a.order - b.order);
  6552.  
  6553. if (orphanSites.length > 0) {
  6554. orphanSites.forEach(x => {
  6555. x.schedule = Schedule.getAll()[0].uuid;
  6556. });
  6557.  
  6558. Schedule.getAll()[0].sites.push(...orphanSites);
  6559. }
  6560. Schedule.saveAll();
  6561. } catch (err) {
  6562. console.error(err);
  6563. return false;
  6564. }
  6565. if (isInvalid) {
  6566. return false;
  6567. }
  6568. return true;
  6569. }
  6570.  
  6571. addSite(site) { this.sites.push(site) }
  6572. removeSite(siteId) {
  6573. if (this.sites.findIndex(x => x.id === siteId) > -1) {
  6574. this.sites = this.sites.filter(x => x.id !== siteId);
  6575. this.setCurrentSite();
  6576. }
  6577. }
  6578.  
  6579. setCurrentSite() {
  6580. this.currentSite = this.sites[0];
  6581. }
  6582.  
  6583. start() {
  6584. this.status = STATUS.IDLE;
  6585. this.worker = setTimeout(() => {
  6586. this.checkNextRoll();
  6587. }, 2000);
  6588. }
  6589.  
  6590. checkNextRoll() {
  6591. if (this.status != STATUS.IDLE) {
  6592. return;
  6593. }
  6594. this.timer.stopCheck();
  6595. clearTimeout(this.worker);
  6596. if(!this.currentSite || this.currentSite.nextRoll == null) {
  6597. document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', 'UNDEFINED');
  6598. this.status = STATUS.IDLE;
  6599. return;
  6600. }
  6601.  
  6602. if(this.currentSite.nextRoll.getTime() < Date.now()) {
  6603. ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Opening ${this.currentSite.name}`});
  6604. document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', 'RUNNING');
  6605. this.open();
  6606. this.timeUntilNext = null;
  6607. return;
  6608. } else {
  6609. this.timeUntilNext = this.currentSite.nextRoll.getTime() - Date.now() + helpers.randomMs(1000, 2000);
  6610.  
  6611. document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', this.currentSite.nextRoll.getTime());
  6612. this.worker = setTimeout(() => {
  6613. this.checkNextRoll();
  6614. }, this.timeUntilNext);
  6615. this.status = STATUS.IDLE;
  6616. }
  6617. }
  6618.  
  6619. getCustomOrDefaultVal(param, useOverride = false) {
  6620. let val;
  6621.  
  6622. if (useOverride) {
  6623. if (this.currentSite.params && this.currentSite.params.hasOwnProperty(param)) {
  6624. val = this.currentSite.params[param];
  6625. if (val != -1) {
  6626. return val;
  6627. }
  6628. }
  6629. }
  6630.  
  6631. return shared.getConfig()[param];
  6632. }
  6633.  
  6634. useOverride(param) {
  6635. let overrideFlag = param + '.override';
  6636. return this.currentSite.params && this.currentSite.params[overrideFlag];
  6637. }
  6638.  
  6639. closeTab() {
  6640. try {
  6641. this.tab.close();
  6642. } catch (err) {
  6643. console.warn('Error while trying to close tab', err);
  6644. }
  6645. };
  6646.  
  6647. reopenTab() {
  6648. this.tab = GM_openInTab(this.currentSite.url, { active: !this.getCustomOrDefaultVal('defaults.workInBackground', this.useOverride('defaults.workInBackground')) });
  6649. };
  6650.  
  6651. open(promoCodes) {
  6652. this.status = STATUS.CLAIMING;
  6653. let navUrl = this.currentSite.url;
  6654. try {
  6655. let params = this.currentSite.params || {};
  6656. params.siteParams = this.currentSite.siteParams || { "test": "test_value" };
  6657.  
  6658. if(promoCodes) {
  6659. navUrl = new URL('promotion/' + promoCodes[0], this.currentSite.url.origin);
  6660. ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Opening ${this.currentSite.name} with ${promoCodes.length} Promo Codes [${promoCodes.join(',')}]`});
  6661. params.promoCodes = promoCodes;
  6662. }
  6663.  
  6664. if (this.currentSite.firstRun) {
  6665. if(Array.isArray(this.currentSite.rf) && this.currentSite.rf.length > 0) {
  6666. navUrl = new URL(navUrl.href + this.currentSite.rf[helpers.randomInt(0, this.currentSite.rf.length - 1)]);
  6667. }
  6668. }
  6669.  
  6670. if (this.currentSite.wallet) {
  6671. try {
  6672. params.address = manager.userWallet.find(x => x.type == this.currentSite.wallet)?.address;
  6673. if (!params.address) {
  6674. throw new Error('Address is not defined.');
  6675. }
  6676. } catch {
  6677. ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Unable to launch ${this.currentSite.name}: Address not detected > add it to the wallet.`});
  6678. this.moveNextAfterTimeoutOrError();
  6679. return;
  6680. }
  6681. }
  6682. if(this.currentSite.type == K.WebType.BESTCHANGE) {
  6683. params.address = shared.getConfig()['bestchange.address'] == '1' ? manager.userWallet.find(x => x.type == 1).address : params.address;
  6684. }
  6685. params.timeout = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout'));
  6686. params.cmc = this.currentSite.cmc;
  6687.  
  6688. if(this.currentSite.type == K.WebType.FPB) {
  6689. switch(this.currentSite.id) {
  6690. case '77':
  6691. params.sitePrefix = 'fpb';
  6692. break;
  6693. case '83':
  6694. params.sitePrefix = 'fbch';
  6695. break;
  6696. case '92':
  6697. params.sitePrefix = 'shost';
  6698. break;
  6699. }
  6700. }
  6701.  
  6702. if(this.currentSite.type == K.WebType.VIE) {
  6703. params.credentials = {
  6704. mode: shared.getConfig()['jtfey.credentials.mode'],
  6705. username: shared.getConfig()['jtfey.credentials.username'],
  6706. password: shared.getConfig()['jtfey.credentials.password']
  6707. };
  6708. }
  6709.  
  6710. shared.setFlowControl(this.uuid, this.currentSite.id, navUrl, this.currentSite.type, params);
  6711. setTimeout(() => {
  6712. this.waitForResult();
  6713. }, 15000);
  6714.  
  6715. if (this.tab && !this.tab.closed) {
  6716. this.closeTab(); // this.tab.close();
  6717. } else {
  6718. }
  6719.  
  6720. this.timer.startCheck(this.currentSite.type);
  6721. let noSignUpList = [ K.WebType.BESTCHANGE, K.WebType.CBG, K.WebType.G8, K.WebType.O24, K.WebType.CDIVERSITY, K.WebType.CTOP, K.WebType.AUTOCML, K.WebType.CCLICKS ];
  6722. let hrefOpener = navUrl.href;
  6723. if (noSignUpList.includes(this.currentSite.type)) {
  6724. hrefOpener = (new URL(this.currentSite.clId, 'https://criptologico.com/goto/')).href;
  6725. }
  6726.  
  6727. this.tab = GM_openInTab(hrefOpener, { active: !this.getCustomOrDefaultVal('defaults.workInBackground', this.useOverride('defaults.workInBackground')) });
  6728. } catch(err) {
  6729. ui.log({ schedule: this.uuid, msg: `Error opening tab: ${err}`});
  6730. }
  6731. };
  6732.  
  6733. waitForResult() {
  6734. if(manager.isObsolete()) {
  6735. return;
  6736. }
  6737.  
  6738. if(shared.isCompleted(this.currentSite.id)) {
  6739. this.analyzeResult(); // rename to something else...
  6740. return;
  6741. }
  6742.  
  6743. this.timeWaiting += 15;
  6744. if(shared.isIncompleted(this.currentSite.id) && this.hasTimedOut()) {
  6745. this.analyzeResult(); // rename to something else...
  6746. return;
  6747. }
  6748.  
  6749. this.waitOrMoveNext(); // this should just be the error and timeout check
  6750. return;
  6751.  
  6752. };
  6753.  
  6754. analyzeResult() {
  6755.  
  6756. let currentSchedule = shared.getCurrent(this.uuid);
  6757. currentSchedule.result = currentSchedule.result || {};
  6758. currentSchedule.runStatus = currentSchedule.runStatus || false;
  6759.  
  6760. if (currentSchedule.result) {
  6761. this.updateWebListItem(currentSchedule);
  6762.  
  6763. if (currentSchedule.result.closeParentWindow) {
  6764. ui.log({ schedule: this.uuid, msg: `Closing working tab per process request` });
  6765. this.closeTab();
  6766. }
  6767.  
  6768. if (shared.getConfig()['cf.usePromoCodes'] && this.currentSite.type == K.WebType.CRYPTOSFAUCETS) {
  6769. let promoCode = CFPromotions.hasPromoAvailable(this.currentSite.id);
  6770. if (promoCode) {
  6771. this.timeWaiting = 0;
  6772.  
  6773. this.currentSite.nextRoll = new Date(754000 + +this.currentSite.id);
  6774. manager.update(false);
  6775. this.open(promoCode);
  6776. return;
  6777. }
  6778. }
  6779. } else {
  6780. ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Unable to read last run result, for ID: ${this.currentSite.id} > ${this.currentSite.name}`});
  6781. }
  6782.  
  6783. this.timeWaiting = 0;
  6784. this.status = STATUS.IDLE;
  6785. shared.clearFlowControl(this.uuid);
  6786. manager.update(true);
  6787. manager.readUpdateValues(true);
  6788. return;
  6789. }
  6790.  
  6791. waitOrMoveNext() {
  6792. if (this.currentSite.isExternal) {
  6793. if (!this.tab || (this.tab && this.tab.closed)) {
  6794. this.timeWaiting = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout')) * 60 + 9999;
  6795. }
  6796. }
  6797. if (!shared.hasErrors(this.currentSite.id) && !this.hasTimedOut()) {
  6798. ui.log({ schedule: this.uuid,
  6799. siteName: this.currentSite.name,
  6800. elapsed: this.timeWaiting,
  6801. msg: `Waiting for ${this.currentSite.name} results...`});
  6802. setTimeout(() => {
  6803. this.waitForResult();
  6804. }, 15000);
  6805. return;
  6806. }
  6807.  
  6808. if (shared.hasErrors(this.currentSite.id)) {
  6809. this.currentSite.stats.errors = shared.getResult(this.uuid); // shared.getResult(this.uuid);
  6810.  
  6811. ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
  6812. msg: `${this.currentSite.name} closed with error: ${helpers.getEnumText(K.ErrorType,this.currentSite.stats.errors.errorType)} ${this.currentSite.stats.errors.errorMessage}`});
  6813.  
  6814. if(this.sleepIfBan()) {
  6815. return;
  6816. }
  6817. }
  6818.  
  6819. if (this.hasTimedOut()) {
  6820. if (this.currentSite.isExternal) {
  6821. this.currentSite.stats.countTimeouts = 0;
  6822. this.currentSite.stats.errors = null;
  6823. ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
  6824. msg: `Closing ${this.currentSite.name}` });
  6825. try {
  6826. this.closeTab();
  6827. } catch (err) { console.error('Unable to close working tab', err); }
  6828. this.moveAfterNormalRun();
  6829. return;
  6830. } else {
  6831. if(this.currentSite.stats.countTimeouts) {
  6832. this.currentSite.stats.countTimeouts += 1;
  6833. } else {
  6834. this.currentSite.stats.countTimeouts = 1;
  6835. }
  6836.  
  6837. ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
  6838. msg: `Waited too much time for ${this.currentSite.name} results: triggering timeout` });
  6839. }
  6840. }
  6841.  
  6842. this.moveNextAfterTimeoutOrError();
  6843. return;
  6844. }
  6845.  
  6846. hasTimedOut() { // here or on a site level???
  6847. let val = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout')) * 60;
  6848. return (this.timeWaiting > val);
  6849. };
  6850.  
  6851. sleepIfBan() { // This should be a SiteType hook
  6852. if( (this.currentSite.stats.errors.errorType == K.ErrorType.IP_BAN && shared.getConfig()['cf.sleepHoursIfIpBan'] > 0)
  6853. || ( (this.currentSite.stats.errors.errorType == K.ErrorType.IP_RESTRICTED || this.currentSite.stats.errors.errorType == K.ErrorType.IP_BAN) && shared.getConfig()['bk.sleepMinutesIfIpBan'] > 0) ) {
  6854. if(this.currentSite.type == K.WebType.CRYPTOSFAUCETS) {
  6855. Site.getAll().filter(x => x.enabled && x.type == K.WebType.CRYPTOSFAUCETS)
  6856. .forEach( function(el) {
  6857. el.nextRoll = this.sleepCheck(helpers.addMs(helpers.getRandomMs(shared.getConfig()['cf.sleepHoursIfIpBan'] * 60, 2)).toDate());
  6858. });
  6859. }
  6860.  
  6861. shared.clearFlowControl(this.uuid);
  6862. manager.update(true);
  6863. this.timeWaiting = 0;
  6864. this.status = STATUS.IDLE;
  6865. shared.clearFlowControl(this.uuid);
  6866. manager.readUpdateValues(true);
  6867. return true;
  6868. }
  6869. return false;
  6870. }
  6871.  
  6872. updateWebListItem(currentSchedule) {
  6873. let result = currentSchedule.result;
  6874.  
  6875. ui.log({ schedule: this.uuid,
  6876. msg: `Updating data: ${JSON.stringify(result)}` });
  6877. this.currentSite.stats.countTimeouts = 0;
  6878. this.currentSite.stats.errors = null;
  6879.  
  6880. if (result.claimed) {
  6881. try {
  6882. result.claimed = parseFloat(result.claimed);
  6883. } catch { }
  6884. if(!isNaN(result.claimed)) {
  6885. this.currentSite.lastClaim = result.claimed;
  6886. this.currentSite.aggregate += result.claimed;
  6887. }
  6888. }
  6889. if(result.balance) {
  6890. this.currentSite.balance = result.balance;
  6891. }
  6892. this.currentSite.nextRoll = this.getNextRun(result.nextRoll ? result.nextRoll.toDate() : null);
  6893. if(result.promoCodeResults) { // TODO: move to a processResult hook
  6894. for(let i = 0; i < result.promoCodeResults.length; i++) {
  6895. let item = result.promoCodeResults[i];
  6896. CFPromotions.updateFaucetForCode(item.promoCode, this.currentSite.id, item.promoStatus);
  6897. }
  6898. }
  6899. if(result.rolledNumber) {
  6900. CFHistory.addRoll(result.rolledNumber);
  6901. }
  6902. }
  6903.  
  6904. getNextRun(nextRollFromCountdown) {
  6905. let useCustom = this.useOverride('defaults.nextRun');
  6906. let useCountdown = this.getCustomOrDefaultVal('defaults.nextRun.useCountdown', useCustom);
  6907. let nextRunMode = this.getCustomOrDefaultVal('defaults.nextRun', useCustom);
  6908. let min = this.getCustomOrDefaultVal('defaults.nextRun.min', useCustom);
  6909. let max = this.getCustomOrDefaultVal('defaults.nextRun.max', useCustom);
  6910. let nextRun;
  6911.  
  6912. if (useCountdown && nextRollFromCountdown) {
  6913. nextRun = nextRollFromCountdown;
  6914. } else {
  6915. let minutes = (nextRunMode == 0) ? helpers.randomInt(min, max) : nextRunMode;
  6916. let msDelay = helpers.getRandomMs(minutes, 1);
  6917.  
  6918. nextRun = helpers.addMs(msDelay).toDate();
  6919. }
  6920. nextRun = this.sleepCheck(nextRun)
  6921.  
  6922. return nextRun;
  6923. }
  6924.  
  6925. errorTreatment() { // Move to group custom getNextRoll
  6926. try {
  6927. switch(this.currentSite.stats.errors.errorType) {
  6928. case K.ErrorType.NEED_TO_LOGIN:
  6929. this.currentSite.enabled = false;
  6930. this.currentSite.nextRoll = null;
  6931. return true;
  6932. case K.ErrorType.FAUCET_EMPTY: // retry in 8 hours
  6933. this.currentSite.enabled = true;
  6934. this.currentSite.nextRoll = new Date(new Date().setHours(new Date().getHours() + 8));
  6935. return true;
  6936. }
  6937. } catch {}
  6938. return false;
  6939. }
  6940.  
  6941. sleepCheck(nextRun) {
  6942. let useCustom = this.useOverride('defaults.sleepMode');
  6943. let sleepMode = this.getCustomOrDefaultVal('defaults.sleepMode', useCustom);
  6944.  
  6945. if (sleepMode) {
  6946. let intNextRunTime = nextRun.getHours() * 100 + nextRun.getMinutes();
  6947. let min = this.getCustomOrDefaultVal('defaults.sleepMode.min', useCustom).replace(':', '');
  6948. let max = this.getCustomOrDefaultVal('defaults.sleepMode.max', useCustom).replace(':', '');
  6949.  
  6950. if (+min < +max) {
  6951. if (+min < intNextRunTime && intNextRunTime < +max) {
  6952. nextRun.setHours(max.slice(0, 2), max.slice(-2), 10, 10);
  6953. ui.log({ schedule: this.uuid,
  6954. msg: `Next run adjusted by Sleep Mode: ${helpers.getPrintableDateTime(nextRun)}` });
  6955. }
  6956. } else if (+min > +max) {
  6957. if (intNextRunTime > +min || intNextRunTime < +max) {
  6958. nextRun.setHours(max.slice(0, 2), max.slice(-2), 10, 10);
  6959. if (nextRun.getTime() < Date.now()) {
  6960. nextRun.setDate(nextRun.getDate() + 1);
  6961. }
  6962. ui.log({ schedule: this.uuid,
  6963. msg: `Next run adjusted by Sleep Mode: ${helpers.getPrintableDateTime(nextRun)}` });
  6964. }
  6965. }
  6966. }
  6967. return nextRun;
  6968. }
  6969.  
  6970. moveAfterNormalRun() {
  6971. this.currentSite.nextRoll = this.getNextRun(null);
  6972.  
  6973. shared.clearFlowControl(this.uuid);
  6974. manager.update(true);
  6975. this.timeWaiting = 0;
  6976. this.status = STATUS.IDLE;
  6977. shared.clearFlowControl(this.uuid);
  6978. manager.readUpdateValues(true);
  6979. }
  6980.  
  6981. moveNextAfterTimeoutOrError() {
  6982. let useCustom = this.useOverride('defaults.postponeMinutes');
  6983.  
  6984. let mode = this.getCustomOrDefaultVal('defaults.postponeMinutes', useCustom);
  6985. let min = this.getCustomOrDefaultVal('defaults.postponeMinutes.min', useCustom);
  6986. let max = this.getCustomOrDefaultVal('defaults.postponeMinutes.max', useCustom);
  6987.  
  6988. let minutes = (mode == 0) ? helpers.randomInt(min, max) : mode;
  6989. let msDelay = helpers.getRandomMs(minutes, 5);
  6990.  
  6991. this.currentSite.nextRoll = this.sleepCheck(helpers.addMs(msDelay).toDate());
  6992. if(this.errorTreatment()) {
  6993. }
  6994.  
  6995. shared.clearFlowControl(this.uuid);
  6996. manager.update(true);
  6997. this.timeWaiting = 0;
  6998. this.status = STATUS.IDLE;
  6999. shared.clearFlowControl(this.uuid);
  7000. manager.readUpdateValues(true);
  7001. }
  7002. }
  7003.  
  7004. function createManager() {
  7005. let timestamp = null;
  7006. let intervalUiUpdate;
  7007. let getFeedInterval;
  7008.  
  7009. let userWallet = [];
  7010.  
  7011. const sites = [
  7012. { id: '1', name: 'CF ADA', cmc: '2010', coinRef: 'ADA', url: new URL('https://app.freecardano.com/free'), rf: '?ref=335463', type: K.WebType.CRYPTOSFAUCETS, clId: 45 },
  7013. { id: '2', name: 'CF BNB', cmc: '1839', coinRef: 'BNB', url: new URL('https://app.freebinancecoin.com/free'), rf: '?ref=161127', type: K.WebType.CRYPTOSFAUCETS, clId: 42 },
  7014. { id: '3', name: 'CF BTC', cmc: '1', coinRef: 'BTC', url: new URL('https://app.freebitcoin.io/free'), rf: '?ref=490252', type: K.WebType.CRYPTOSFAUCETS, clId: 40 },
  7015. { id: '4', name: 'CF DASH', cmc: '131', coinRef: 'DASH', url: new URL('https://app.freedash.io/free'), rf: '?ref=124083', type: K.WebType.CRYPTOSFAUCETS, clId: 156 },
  7016. { id: '5', name: 'CF ETH', cmc: '1027', coinRef: 'ETH', url: new URL('https://app.freeethereum.com/free'), rf: '?ref=204076', type: K.WebType.CRYPTOSFAUCETS, clId: 44 },
  7017. { id: '6', name: 'CF LINK', cmc: '1975', coinRef: 'LINK', url: new URL('https://app.freecryptom.com/free'), rf: '?ref=78652', type: K.WebType.CRYPTOSFAUCETS, clId: 157 },
  7018. { id: '7', name: 'CF LTC', cmc: '2', coinRef: 'LTC', url: new URL('https://app.free-ltc.com/free'), rf: '?ref=117042', type: K.WebType.CRYPTOSFAUCETS, clId: 47 },
  7019. { id: '8', name: 'CF NEO', cmc: '1376', coinRef: 'NEO', url: new URL('https://app.freeneo.io/free'), rf: '?ref=100529', type: K.WebType.CRYPTOSFAUCETS, clId: 158 },
  7020. { id: '9', name: 'CF STEAM', cmc: '825', coinRef: 'STEEM', url: new URL('https://app.freesteam.io/free'), rf: '?ref=117686', type: K.WebType.CRYPTOSFAUCETS, clId: 49 },
  7021. { id: '10', name: 'CF TRX', cmc: '1958', coinRef: 'TRX', url: new URL('https://app.free-tron.com/free'), rf: '?ref=145047', type: K.WebType.CRYPTOSFAUCETS, clId: 41 },
  7022. { id: '11', name: 'CF USDC', cmc: '3408', coinRef: 'USDC', url: new URL('https://app.freeusdcoin.com/free'), rf: '?ref=100434', type: K.WebType.CRYPTOSFAUCETS, clId: 51 },
  7023. { id: '12', name: 'CF USDT', cmc: '825', coinRef: 'USDT', url: new URL('https://app.freetether.com/free'), rf: '?ref=181230', type: K.WebType.CRYPTOSFAUCETS, clId: 43 },
  7024. { id: '13', name: 'CF XEM', cmc: '873', coinRef: 'XEM', url: new URL('https://app.freenem.com/free'), rf: '?ref=295274', type: K.WebType.CRYPTOSFAUCETS, clId: 46 },
  7025. { id: '14', name: 'CF XRP', cmc: '52', coinRef: 'XRP', url: new URL('https://app.coinfaucet.io/free'), rf: '?ref=808298', type: K.WebType.CRYPTOSFAUCETS, clId: 48 },
  7026. { id: '15', name: 'StormGain', cmc: '1', url: new URL('https://app.stormgain.com/crypto-miner/'), rf: 'friend/BNS27140552', type: K.WebType.STORMGAIN, clId: 35 },
  7027. { id: '16', name: 'CF DOGE', cmc: '74', coinRef: 'DOGE', url: new URL('https://app.free-doge.com/free'), rf: '?ref=97166', type: K.WebType.CRYPTOSFAUCETS, clId: 50 },
  7028. { id: '17', name: 'FreeBitco.in', cmc: '1', url: new URL('https://freebitco.in/'), rf: '?r=41092365', type: K.WebType.FREEBITCOIN, clId: 36 },
  7029. { id: '18', name: 'FaucetPay PTC', cmc: '825', url: new URL('https://faucetpay.io/ptc'), rf: '?r=41092365', type: K.WebType.FAUCETPAY, clId: 159 },
  7030. { id: '52', name: 'BigBtc', cmc: '1', wallet: K.WalletType.FP_BTC, url: new URL('https://bigbtc.win/'), rf: '?id=39255652', type: K.WebType.BIGBTC, clId: 200 },
  7031. { id: '53', name: 'BestChange', cmc: '1', url: new URL('https://www.bestchange.com/'), rf: ['index.php?nt=bonus&p=1QCD6cWJNVH4Cdnz85SQ2qtTkAwGr9fvUk'], type: K.WebType.BESTCHANGE, clId: 163 },
  7032. { id: '58', name: 'BF BTC', cmc: '1', url: new URL('https://betfury.io/boxes/all'), rf: ['?r=608c5cfcd91e762043540fd9'], type: K.WebType.BFBOX, clId: 1 },
  7033. { id: '61', name: 'Dutchy', cmc: '-1', url: new URL('https://autofaucet.dutchycorp.space/roll.php'), rf: '?r=corecrafting', type: K.WebType.DUTCHYROLL, clId: 141 },
  7034. { id: '62', name: 'Dutchy Monthly Coin', cmc: '-1', url: new URL('https://autofaucet.dutchycorp.space/coin_roll.php'), rf: '?r=corecrafting', type: K.WebType.DUTCHYROLL, clId: 141 },
  7035. { id: '68', name: 'CF SHIBA', cmc: '5994', coinRef: 'SHIBA', url: new URL('https://app.freeshibainu.com/free'), rf: '?ref=18226', type: K.WebType.CRYPTOSFAUCETS, clId: 167 },
  7036. { id: '78', name: 'CF Cake', cmc: '7186', coinRef: 'CAKE', url: new URL('https://app.freepancake.com/free'), rf: '?ref=699', type: K.WebType.CRYPTOSFAUCETS, clId: 197 },
  7037. { id: '80', name: 'FreeGRC', cmc: '833', url: new URL('https://freegridco.in/#free_roll'), rf: '', type: K.WebType.FREEGRC, clId: 207 },
  7038. { id: '81', name: 'CF Matic', cmc: '3890', coinRef: 'MATIC', url: new URL('https://app.freematic.com/free'), rf: '?ref=6435', type: K.WebType.CRYPTOSFAUCETS, clId: 210 },
  7039. { id: '84', name: 'JTFey', cmc: '-1', url: new URL('https://james-trussy.com/faucet'), rf: ['?r=corecrafting'], type: K.WebType.VIE, clId: 213 },
  7040. { id: '85', name: 'O24', cmc: '1', wallet: K.WalletType.FP_BTC, url: new URL('https://www.only1024.com/f'), rf: ['?r=1QCD6cWJNVH4Cdnz85SQ2qtTkAwGr9fvUk'], type: K.WebType.O24, clId: 97 },
  7041. { id: '87', name: 'CF BTT', cmc: '16086', coinRef: 'BTT', url: new URL('https://app.freebittorrent.com/free'), rf: '?ref=2050', type: K.WebType.CRYPTOSFAUCETS, clId: 218 },
  7042. { id: '89', name: 'CF BFG', cmc: '11038', coinRef: 'BFG', url: new URL('https://app.freebfg.com/free'), rf: '?ref=117', type: K.WebType.CRYPTOSFAUCETS, clId: 219 },
  7043. { id: '93', name: 'YCoin', cmc: '1', url: new URL('https://yescoiner.com/faucet'), rf: ['?ref=4729452'], type: K.WebType.YCOIN, clId: 234 },
  7044. { id: '94', name: 'CDiversity', cmc: '-1', wallet: K.WalletType.FP_MAIL, url: new URL('http://coindiversity.io/free-coins'), rf: ['?r=1J3sLBZAvY5Vk9x4RY2qSFyL7UHUszJ4DJ'], type: K.WebType.CDIVERSITY, clId: 235 },
  7045. { id: '96', name: 'Top Ltc', cmc: '2', wallet: K.WalletType.FP_LTC, url: new URL('https://ltcfaucet.top/'), rf: ['?r=MWSsGAQTYD7GH5o4oAehC8Et5PyMBfhnKK'], type: K.WebType.CTOP, clId: 239 },
  7046. { id: '97', name: 'Top Bnb', cmc: '1839', wallet: K.WalletType.FP_BNB, url: new URL('https://bnbfaucet.top/'), rf: ['?r=0x1e8CB8A79E347C54aaF21C0502892B58F97CC07A'], type: K.WebType.CTOP, clId: 240 },
  7047. { id: '98', name: 'Top Doge', cmc: '74', wallet: K.WalletType.FP_DOGE, url: new URL('https://dogecoinfaucet.top/'), rf: ['?r=D8Xgghu5gCryukwmxidFpSmw8aAKon2mEQ'], type: K.WebType.CTOP, clId: 241 },
  7048. { id: '99', name: 'Top Trx', cmc: '1958', wallet: K.WalletType.FP_TRX, url: new URL('https://tronfaucet.top/'), rf: ['?r=TK3ofbD3AyXotN2111UvnwCzr2YaW8Qmx7'], type: K.WebType.CTOP, clId: 242 },
  7049. { id: '100', name: 'Top Eth', cmc: '1027', wallet: K.WalletType.FP_ETH, url: new URL('https://ethfaucet.top/'), rf: ['?r=0xC21FD989118b8C0Db6Ac2eC944B53C09F7293CC8'], type: K.WebType.CTOP, clId: 243 },
  7050. { id: '101', name: 'Top Bch', cmc: '1831', wallet: K.WalletType.FP_BCH, url: new URL('https://freebch.club/'), rf: ['?r=qq2qlpzs4rsn30utrumezpkzezpteqj92ykdgfeq5u'], type: K.WebType.CTOP, clId: 244 },
  7051. { id: '102', name: 'Top Zec', cmc: '1437', wallet: K.WalletType.FP_ZEC, url: new URL('https://zecfaucet.net/'), rf: ['?r=t1erPs9qw3SgnX7kJPmR4uKFnLaoVww2jCy'], type: K.WebType.CTOP, clId: 245 },
  7052. { id: '103', name: 'FMonster', cmc: '825', wallet: K.WalletType.FP_USDT, url: new URL('https://faucet.monster/'), rf: '', type: K.WebType.O24, clId: 246 },
  7053. { id: '104', name: 'Auto-C BNB', cmc: '1839', wallet: K.WalletType.FP_BNB, url: new URL('https://auto-crypto.click/'), rf: ['?r=0x1e8CB8A79E347C54aaF21C0502892B58F97CC07A'], type: K.WebType.AUTOCML, clId: 247 },
  7054. { id: '105', name: 'Auto-C DOGE', cmc: '74', wallet: K.WalletType.FP_DOGE, url: new URL('https://freeshiba.cf/'), rf: ['?r=D8Xgghu5gCryukwmxidFpSmw8aAKon2mEQ'], type: K.WebType.AUTOCML, clId: 248 },
  7055. { id: '106', name: 'ClClicks DOGE', cmc: '74', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/doge/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 61 },
  7056. { id: '107', name: 'ClClicks LTC', cmc: '2', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/ltc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 62 },
  7057. { id: '108', name: 'ClClicks TRX', cmc: '1958', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/trx/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 63 },
  7058. { id: '109', name: 'ClClicks BTC', cmc: '1', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/btc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 252 },
  7059. { id: '110', name: 'ClClicks SOL', cmc: '5426', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/sol/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 253 },
  7060. { id: '111', name: 'ClClicks BNB', cmc: '1839', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/bnb/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 254 },
  7061. { id: '112', name: 'CrClicks DOGE', cmc: '74', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/doge/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 257 },
  7062. { id: '113', name: 'CrClicks LTC', cmc: '2', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/ltc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 258 },
  7063. { id: '114', name: 'CrClicks TRX', cmc: '1958', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/trx/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 259 },
  7064. { id: '115', name: 'CrClicks BTC', cmc: '1', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/btc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 256 },
  7065. { id: '116', name: 'CrClicks SOL', cmc: '5426', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/sol/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 261 },
  7066. { id: '117', name: 'CrClicks BNB', cmc: '1839', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/bnb/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 260 },
  7067. ];
  7068.  
  7069. const wallet = [
  7070. { id: '99', name: 'FaucetPay Username', type: K.WalletType.FP_USERNAME },
  7071. { id: '100', name: 'FaucetPay Email', type: K.WalletType.FP_MAIL },
  7072. { id: '101', name: 'FaucetPay BTC (Bitcoin)', type: K.WalletType.FP_BTC },
  7073. { id: '102', name: 'FaucetPay BNB (Binance Coin)', type: K.WalletType.FP_BNB },
  7074. { id: '103', name: 'FaucetPay BCH (Bitcoin Cash)', type: K.WalletType.FP_BCH },
  7075. { id: '104', name: 'FaucetPay DASH (Dash)', type: K.WalletType.FP_DASH },
  7076. { id: '105', name: 'FaucetPay DGB (DigiByte)', type: K.WalletType.FP_DGB },
  7077. { id: '106', name: 'FaucetPay DOGE (Dogecoin)', type: K.WalletType.FP_DOGE },
  7078. { id: '107', name: 'FaucetPay ETH (Ethereum)', type: K.WalletType.FP_ETH },
  7079. { id: '108', name: 'FaucetPay FEY (Feyorra)', type: K.WalletType.FP_FEY },
  7080. { id: '109', name: 'FaucetPay LTC (Litecoin)', type: K.WalletType.FP_LTC },
  7081. { id: '110', name: 'FaucetPay TRX (Tron)', type: K.WalletType.FP_TRX },
  7082. { id: '111', name: 'FaucetPay USDT (Tether TRC20)', type: K.WalletType.FP_USDT },
  7083. { id: '112', name: 'FaucetPay ZEC (Zcash)', type: K.WalletType.FP_ZEC },
  7084. { id: '113', name: 'FaucetPay SOL (Solana)', type: K.WalletType.FP_SOL },
  7085. { id: '114', name: 'FaucetPay MATIC (Polygon)', type: K.WalletType.FP_MATIC },
  7086. { id: '116', name: 'FaucetPay ADA (Cardano)', type: K.WalletType.FP_ADA },
  7087. { id: '200', name: 'ExpressCrypto (EC-UserId-XXXXXX)', type: K.WalletType.EC },
  7088. { id: '1', name: 'BTC Alternative Address', type: K.WalletType.BTC }
  7089. ];
  7090.  
  7091. async function start() {
  7092. await loader.initialize();
  7093. ui.init(getCFlist(), Schedule.getAll());
  7094. uiRenderer.appendEventListeners();
  7095. shared.purgeFlowControlSchedules(Schedule.getAll().map(x => x.uuid));
  7096. update();
  7097. uiRenderer.wallet.legacyRenderWalletTable(userWallet);
  7098. intervalUiUpdate = setInterval(readUpdateValues, 10000);
  7099. Schedule.getAll().forEach(x => {
  7100. x.start();
  7101. });
  7102. if (document.querySelector('#console-log').innerText == 'Loading...') {
  7103. document.querySelector('#console-log').innerHTML = '<table><tr><td><b>Running...</b></td></tr></table>';
  7104. }
  7105. getFeedInterval = setInterval(getCodesFeed, 25000);
  7106. };
  7107.  
  7108. let loader = function() {
  7109. async function initialize() {
  7110. setTimestamp();
  7111. await Schedule.initialize();
  7112. await initializeSites();
  7113. initializeUserWallet();
  7114. initializePromotions();
  7115. initializeHistory();
  7116. };
  7117. async function initializeSites() {
  7118. Site.createFromDataArray(sites);
  7119. await updateSitesWithStoredData();
  7120. await addSitesToSchedules();
  7121. };
  7122. async function updateSitesWithStoredData() {
  7123. let storedData = persistence.load('webList', true);
  7124. if (storedData) {
  7125. storedData.forEach( function (stored) {
  7126. if (stored.isExternal) {
  7127. stored.url = new URL(stored.url);
  7128. Site.add(stored);
  7129. }
  7130. let site = Site.getById(stored.id);
  7131. if (!site) {
  7132. return;
  7133. }
  7134. for (const prop in stored) {
  7135. site[prop] = stored[prop];
  7136. }
  7137. if (!site.enabled) {
  7138. site.nextRoll = null;
  7139. } else {
  7140. site.nextRoll = site.nextRoll ? new Date(site.nextRoll) : new Date();
  7141. }
  7142. if (site.aggregate || site.balance) {
  7143. site.firstRun = false;
  7144. }
  7145. })
  7146. }
  7147. };
  7148. async function addSitesToSchedules() {
  7149. Site.getAll().forEach(site => {
  7150. let scheduleOfSite = Schedule.getById(site.schedule);
  7151. if (!scheduleOfSite) {
  7152. console.warn(`Attention! Site ${site.name} has a reference to a schedule that does not exist: (${site.schedule})`);
  7153. scheduleOfSite = Schedule.getAll()[0];
  7154. console.warn(`Assigning it to first schedule (${scheduleOfSite.uuid}) instead.`);
  7155. site.schedule = scheduleOfSite.uuid; // use .changeSchedule to save the change???
  7156. }
  7157. scheduleOfSite.addSite(site);
  7158. });
  7159. };
  7160. function initializeUserWallet() {
  7161. addWallets();
  7162. addStoredWalletData();
  7163. };
  7164. function addWallets() {
  7165. wallet.forEach(x => userWallet.push(x));
  7166. userWallet.forEach(function (element, idx, arr) {
  7167. arr[idx].address = '';
  7168. });
  7169. };
  7170. function addStoredWalletData() {
  7171. let storedData = persistence.load('userWallet', true);
  7172. if(storedData) {
  7173. storedData.forEach( function (element) {
  7174. let idx = userWallet.findIndex(x => x.id == element.id);
  7175. if(idx != -1) {
  7176. userWallet[idx].address = element.address ?? userWallet[idx].address;
  7177. }
  7178. });
  7179. }
  7180. };
  7181. function initializePromotions() {
  7182. let storedData = persistence.load('CFPromotions', true);
  7183. if (storedData) {
  7184. let mig00200799 = false;
  7185. try {
  7186. mig00200799 = shared.getConfig().migrations.find(x => x.version == '00200799' && !x.applied);
  7187. } catch (err) {}
  7188.  
  7189. let allCFs = manager.getFaucetsForPromotion().map( cf => cf.id );
  7190. storedData.forEach( function (element, idx, arr) {
  7191. arr[idx].added = new Date(element.added);
  7192. arr[idx].statusPerFaucet.forEach( function (el, i, a) {
  7193. a[i].execTimeStamp = (el.execTimeStamp != null) ? new Date(el.execTimeStamp) : null;
  7194. if (mig00200799 && el.status == 4) {
  7195. a[i].status = 1;
  7196. }
  7197. });
  7198. allCFs.forEach( function (cf) {
  7199. if (!arr[idx].statusPerFaucet.find( x => x.id == cf )) {
  7200. let newCf = { id: cf, status: 1, execTimeStamp: null };
  7201. arr[idx].statusPerFaucet.push(newCf);
  7202. }
  7203. });
  7204. });
  7205. if (mig00200799) {
  7206. shared.migrationApplied('00200799');
  7207. }
  7208. CFPromotions.load(storedData);
  7209. }
  7210. };
  7211. function initializeHistory() {
  7212. CFHistory.initOrLoad();
  7213. };
  7214. function setTimestamp() {
  7215. timestamp = Date.now();
  7216. persistence.save('timestamp', timestamp);
  7217. };
  7218. return {
  7219. initialize: initialize
  7220. };
  7221. }();
  7222. function getCodesFeed(force = false) {
  7223. clearInterval(getFeedInterval);
  7224. if (!force) {
  7225. let tryGet = shared.getConfig()['cf.tryGetCodes'] || false;
  7226. if (!tryGet) {
  7227. return;
  7228. }
  7229. }
  7230.  
  7231. let nextFeed = helpers.randomMs(2 * 60 * 60 * 1000, 4 * 60 * 60 * 1000);
  7232. getFeedInterval = setInterval(getCodesFeed, nextFeed)
  7233.  
  7234. GM_xmlhttpRequest({
  7235. method: "GET",
  7236. url: "https://criptologico.com/api/?key=XI2HV-1P9PQ-W637F-68B9B-A248&requests[cf_codes]",
  7237. timeout: 10000,
  7238. onload: function(response) {
  7239. try {
  7240. let txt = response.responseText;
  7241. let parsed = JSON.parse(txt);
  7242. if (parsed.success) {
  7243. let newCodes = [];
  7244. for(let i = 0; i < parsed.cf_codes.length; i++) {
  7245. let item = parsed.cf_codes[i];
  7246. let newCode = {};
  7247. newCode.code = item.code;
  7248. newCode.oneTimeOnly = item.is_one_time == '1';
  7249. newCode['expiration' + 'Date'] = item.expiration_date.replace(' ', 'T') + 'Z';
  7250. newCode['expiration' + 'Date'] = new Date(newCode['expiration' + 'Date']);
  7251. newCodes.push(newCode);
  7252. }
  7253. CFPromotions.includeNewCodes(newCodes);
  7254. uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
  7255. }
  7256. } catch(err) {
  7257. console.error('unexpected error parsing codes list');
  7258. console.error(err);
  7259. }
  7260. },
  7261. onerror: function(e) {
  7262. console.error('error getting codes');
  7263. console.error(e);
  7264. },
  7265. ontimeout: function() {
  7266. console.error('timeout getting codes');
  7267. },
  7268. });
  7269. }
  7270. function readUpdateValues(forceCheck = false) {
  7271. readPromoCodeValues();
  7272. readModalData();
  7273.  
  7274. if(true) {
  7275. let updateDataElement = document.getElementById('update-data');
  7276. let updateValues = updateDataElement.innerText.clean();
  7277.  
  7278. if (updateValues != '') {
  7279. updateDataElement.innerText = '';
  7280. let updateObj = JSON.parse(updateValues);
  7281. if(updateObj.editSingle.changed) {
  7282. updateObj.editSingle.items.forEach(function (element, idx, arr) {
  7283. try {
  7284. let site = Site.getById(element.id);
  7285.  
  7286. site.name = element.displayName;
  7287.  
  7288. if (site.enabled != element.enabled) {
  7289. site.enabled = element.enabled;
  7290. if(site.enabled) {
  7291. site.nextRoll = new Date(idx);
  7292. } else {
  7293. site.nextRoll = null;
  7294. }
  7295. }
  7296. ui.log({ schedule: site.schedule,
  7297. msg: `Faucet updated. New name: ${element.displayName}. Active: ${element.enabled}` });
  7298. } catch (err) {
  7299. ui.log({ schedule: this.uuid,
  7300. msg: `Error updating faucet data: ${err}` });
  7301. }
  7302. });
  7303. }
  7304.  
  7305. if(updateObj.wallet.changed) {
  7306. updateObj.wallet.items.forEach(function (element) {
  7307. try {
  7308. let itemIndex = userWallet.findIndex(x => x.id == element.id);
  7309. userWallet[itemIndex].address = element.address;
  7310.  
  7311. ui.log({ msg: `Wallet Address updated [${userWallet[itemIndex].name}]: ${userWallet[itemIndex].address}` });
  7312. } catch (err) {
  7313. ui.log({ msg: `Error updating wallet/address: ${err}` });
  7314. }
  7315. });
  7316.  
  7317. uiRenderer.wallet.legacyRenderWalletTable(userWallet);
  7318. saveUserWallet();
  7319. }
  7320.  
  7321. if(updateObj.config.changed) {
  7322. try {
  7323. shared.updateConfig(updateObj.config.items);
  7324. ui.log({ msg: `Config updated. Reloading in a few seconds...` });
  7325. window.location.reload();
  7326. return;
  7327. } catch (err) {
  7328. ui.log({ msg: `Error updating config: ${err}` });
  7329. }
  7330.  
  7331. }
  7332.  
  7333. if(updateObj.site.changed) {
  7334. updateObj.site.list.forEach( (x) => {
  7335. try {
  7336. updateSite(x.id, x.items);
  7337. } catch (err) {
  7338. ui.log({ msg: `Error updating site: ${err}` });
  7339. }
  7340. });
  7341. }
  7342.  
  7343. if(updateObj.runAsap.changed || updateObj.editSingle.changed || updateObj.site.changed) {
  7344. resyncAll({ withUpdate: true });
  7345. return;
  7346. }
  7347. }
  7348. }
  7349. if(forceCheck) {
  7350. resyncAll({ withUpdate: false });
  7351. }
  7352. };
  7353. function resyncAll(options = { withUpdate: false} ) {
  7354. if (options.withUpdate) {
  7355. update(true);
  7356. }
  7357. Schedule.getAll().forEach(x => {
  7358. x.checkNextRoll();
  7359. });
  7360. }
  7361. function updateSite(id, items) {
  7362. let site = Site.getById(id);
  7363. if (site) {
  7364. site.params = site.params || {};
  7365. items.forEach( (item) => {
  7366. site.params[item.prop] = item.value;
  7367. });
  7368.  
  7369. ui.log({ schedule: site.schedule, siteName: site.name,
  7370. msg: `Site ${site.name} updated` });
  7371. }
  7372. }
  7373. function readModalData() { // This should be migrated and dissapear!
  7374. if(document.getElementById('modal-spinner').isVisible()) {
  7375. let targetObject = JSON.parse(document.getElementById('target-spinner').innerHTML);
  7376. let target = targetObject.id;
  7377. if (target == 'modal-ereport') {
  7378. let temp = shared.getDevLog();
  7379. document.getElementById('log-textarea').value = temp.join('\n');
  7380. } else if (target == 'modal-config') {
  7381. uiRenderer.config.legacyRenderConfigData(shared.getConfig());
  7382. } else if (target == 'modal-site') {
  7383. let site = Site.getById(targetObject.siteId);
  7384. uiRenderer.sites.legacyRenderSiteData(site, shared.getConfig());
  7385. }
  7386. document.getElementById('modal-spinner').classList.toggle('d-none');
  7387. document.getElementById(target).classList.toggle('d-none');
  7388. document.getElementById('target-spinner').innerHTML = '';
  7389. }
  7390. }
  7391. function sortSites () { // Temporary, just to decouple it...
  7392. Site.sortAll();
  7393. Schedule.getAll().forEach( schedule => schedule.sortSites() );
  7394. };
  7395. function update(sortIt = true) {
  7396. if(sortIt) {
  7397. sortSites();
  7398. Schedule.getAll().forEach( schedule => schedule.setCurrentSite() );
  7399. }
  7400.  
  7401. Site.saveAll();
  7402. Site.getAll().forEach(site => {
  7403. uiRenderer.sites.renderSiteRow(site);
  7404. });
  7405. uiRenderer.sites.removeDeletedSitesRows(Site.getAll().map(x => x.id));
  7406. convertToFiat();
  7407. uiRenderer.sites.sortSitesTable(); // y reordenar
  7408. uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
  7409. updateRollStatsSpan();
  7410. };
  7411.  
  7412. function saveUserWallet() {
  7413. const data = userWallet.map(x => {
  7414. return {
  7415. id: x.id,
  7416. address: x.address
  7417. };});
  7418.  
  7419. persistence.save('userWallet', data, true);
  7420. }
  7421.  
  7422. function isObsolete() {
  7423. let savedTimestamp = persistence.load('timestamp');
  7424. if (savedTimestamp && savedTimestamp > timestamp) {
  7425. ui.log({ msg: '<b>STOPING EXECUTION!<b> A new Manager UI window was opened. Process should continue there' });
  7426. clearInterval(intervalUiUpdate);
  7427. return true;
  7428. }
  7429. return false;
  7430. };
  7431.  
  7432. function readPromoCodeValues() {
  7433. let promoCodeElement = document.getElementById('promo-code-new');
  7434. let promoDataStr = promoCodeElement.innerText.clean();
  7435.  
  7436. if (promoDataStr == '') {
  7437. return;
  7438. }
  7439.  
  7440. let promoData = JSON.parse(promoDataStr);
  7441.  
  7442. if(promoData.action) {
  7443. switch (promoData.action) {
  7444. case 'FORCESTOPFAUCET':
  7445. Schedule.getAll().forEach(s => {
  7446. if (s.status != STATUS.IDLE) {
  7447. s.currentSite.enabled = false;
  7448. s.closeTab();
  7449. }
  7450. });
  7451.  
  7452. update(true);
  7453. shared.clearFlowControl('all');
  7454. setTimeout(() => {
  7455. window.location.reload();
  7456. }, 3000);
  7457.  
  7458. promoCodeElement.innerText = '';
  7459. break;
  7460. case 'ADD':
  7461. CFPromotions.addNew(promoData.code, promoData.repeatDaily);
  7462. promoCodeElement.innerText = '';
  7463. document.getElementById('promo-text-input').value = '';
  7464. uiRenderer.toast("Code " + promoData.code + " added!");
  7465. ui.log({ msg: `Promo code ${promoData.code} added` });
  7466. uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
  7467. break;
  7468. case 'REMOVEALLPROMOS':
  7469. CFPromotions.removeAll();
  7470. promoCodeElement.innerText = '';
  7471. uiRenderer.toast("Promo codes removed!");
  7472. ui.log({ msg: `Promo codes removed` });
  7473. uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
  7474. break;
  7475. case 'REMOVE':
  7476. if(CFPromotions.remove(promoData.id, promoData.code) != -1) {
  7477. ui.log({ msg: `Promo code ${promoData.code} removed` });
  7478. } else {
  7479. ui.log({ msg: `Unable to remove code ${promoData.code}` });
  7480. }
  7481. promoCodeElement.innerText = '';
  7482. uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
  7483. break;
  7484. case 'TRYGETCODES':
  7485. getCodesFeed(true);
  7486. promoCodeElement.innerText = '';
  7487. uiRenderer.toast("Looking for new codes!");
  7488. break;
  7489. }
  7490. }
  7491. };
  7492.  
  7493. function updateRollStatsSpan() {
  7494. let rollsSpanElement = document.getElementById('rolls-span');
  7495. rollsSpanElement.innerText = CFHistory.getRollsMeta().join(',');
  7496. };
  7497.  
  7498. function getCFlist() {
  7499. let items;
  7500. items = Site.getAll().filter(f => f.type === K.WebType.CRYPTOSFAUCETS);
  7501. items = items.map(x => {
  7502. return {
  7503. id: x.id,
  7504. name: x.coinRef
  7505. };});
  7506. items.sort((a, b) => (a.name > b.name) ? 1 : -1);
  7507.  
  7508. return items;
  7509. };
  7510.  
  7511. function closeWorkingTab(schedule) {
  7512. let sc = Schedule.getAll().find(x => x.uuid == schedule);
  7513. if (sc) sc.closeTab()
  7514. };
  7515. function reloadWorkingTab(schedule) {
  7516. let sc = Schedule.getAll().find(x => x.uuid == schedule);
  7517. if (sc) {
  7518. sc.closeTab();
  7519. sc.reopenTab();
  7520. }
  7521. };
  7522. function getAllSites() {
  7523. return Site.getAll();
  7524. }
  7525. return{
  7526. start: start,
  7527. getFaucetsForPromotion: getCFlist,
  7528. closeWorkingTab: closeWorkingTab,
  7529. reloadWorkingTab: reloadWorkingTab,
  7530. getAllSites: getAllSites,
  7531. resyncAll: resyncAll,
  7532. isObsolete: isObsolete,
  7533. update: update,
  7534. userWallet: userWallet,
  7535. readUpdateValues: readUpdateValues
  7536. };
  7537. }
  7538. function createUi() {
  7539.  
  7540. let injectables = {
  7541. managerJs: function () {
  7542.  
  7543. window.myBarChart = null;
  7544. window.landing = window.location.host;
  7545.  
  7546. window.sendErrorReport = function sendErrorReport() {
  7547. try {
  7548. let header = new Headers();
  7549. header.append("Content-Type", "application/json");
  7550. let description = document.getElementById("log-message").value;
  7551. let log = document.getElementById("log-textarea").value.split('\n');
  7552. let content = {"description":description, "log":log};
  7553. let opt = { method: "POST", header, mode: "cors", body: JSON.stringify(content) };
  7554. fetch("https://1d0103ec5a621b87ea27ffed3c072796.m.pipedream.net", opt).then(response => {
  7555. }).catch(err => {
  7556. console.error("[error] " + err.message);
  7557. });
  7558. } catch { }
  7559. };
  7560.  
  7561. window.getUpdateObject = function getUpdateObject() {
  7562. let updateObject;
  7563. var updateData = document.getElementById("update-data");
  7564. if (updateData.innerHTML != "") {
  7565. updateObject = JSON.parse(updateData.innerHTML);
  7566. } else {
  7567. updateObject = { runAsap: { ids: [], changed: false}, editSingle: { changed: false, items: [] }, wallet: { changed: false, items: []}, config: { changed: false, items: []}, site: { changed: false, list: []} };
  7568. }
  7569. return updateObject;
  7570. };
  7571.  
  7572. window.removePromoCode = function removePromoCode(id, code) {
  7573. var promoCode = document.getElementById("promo-code-new");
  7574. var promoObject = { action: "REMOVE", id: id, code: code };
  7575. promoCode.innerHTML =JSON.stringify(promoObject);
  7576. };
  7577.  
  7578. window.editWallet = {
  7579. save: function() {
  7580. let updateObject = getUpdateObject();
  7581. document.querySelectorAll("#wallet-table-body tr").forEach( function(row) {
  7582. let textInput = row.querySelector(".em-input input");
  7583. if(textInput.dataset.original != textInput.value) {
  7584. let single = { id: row.dataset.id, address: textInput.value.trim() };
  7585. updateObject.wallet.items.push(single);
  7586. updateObject.wallet.changed = true;
  7587. }
  7588. });
  7589. if(updateObject.wallet.changed) {
  7590. document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
  7591. toastr["info"]("Wallet will be updated as soon as possible");
  7592. }
  7593. },
  7594. toggleJson: function(val) {
  7595. if (document.querySelector('#wallet-json').isVisible()) {
  7596. if(val != 'cancel') {
  7597. editWallet.fromJson();
  7598. }
  7599. } else {
  7600. editWallet.toJson();
  7601. }
  7602. document.querySelector('.footer-json').classList.toggle('d-none');
  7603. document.querySelector('.footer-table').classList.toggle('d-none');
  7604. document.querySelector('#wallet-table').classList.toggle('d-none');
  7605. document.querySelector('#wallet-json').classList.toggle('d-none');
  7606. },
  7607. toJson: function() {
  7608. let j = [];
  7609. document.querySelectorAll('#wallet-table-body tr').forEach(function (row) {
  7610. j.push({ id: row.dataset.id, address: row.querySelector('.em-input input').value });
  7611. });
  7612. document.querySelector('#wallet-json').value = JSON.stringify(j);
  7613. },
  7614. fromJson: function() {
  7615. let j = JSON.parse(document.querySelector('#wallet-json').value);
  7616. document.querySelectorAll('#wallet-table-body tr').forEach(function (row) {
  7617. let element = j.find(x => x.id == row.dataset.id);
  7618. if (element) {
  7619. row.querySelector('.em-input input').value = element.address;
  7620. }
  7621. });
  7622. },
  7623. cancel: function() {
  7624. document.querySelectorAll("#wallet-table-body .em-input input").forEach( function(x) {
  7625. x.value = x.dataset.original;
  7626. });
  7627. }
  7628. };
  7629.  
  7630. window.editConfig = {
  7631. save: function() {
  7632. let updateObject = getUpdateObject();
  7633. document.querySelectorAll("#modal-config [data-original][data-prop]").forEach(function(elm) {
  7634. let single = { prop: elm.dataset.prop, value: elm.dataset.value };
  7635. if(elm.dataset.original != elm.value && (elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") ) {
  7636. single.value = elm.value;
  7637. updateObject.config.items.push(single);
  7638. updateObject.config.changed = true;
  7639. } else if (elm.type == "checkbox" && ((elm.dataset.original == "0" && elm.checked) || (elm.dataset.original == "1" && !elm.checked)) ) {
  7640. single.value = elm.checked;
  7641. updateObject.config.items.push(single);
  7642. updateObject.config.changed = true;
  7643. }
  7644. });
  7645. if(updateObject.config.changed) {
  7646. document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
  7647. toastr["info"]("Config will be updated as soon as possible");
  7648. }
  7649. },
  7650. cancel: function() {
  7651. document.querySelectorAll("#modal-config [data-original][data-prop]").forEach(function(elm) {
  7652. if(elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") {
  7653. elm.value = elm.dataset.original;
  7654. } else if (elm.type == "checkbox") {
  7655. elm.checked = (elm.dataset.original == "1" ? true : false)
  7656. }
  7657. });
  7658. }
  7659. };
  7660.  
  7661. window.editSite = {
  7662. save: function() {
  7663. let updateObject = getUpdateObject();
  7664. let faucet = { id: document.querySelector("#faucet-name").dataset.id, items: [] };
  7665. document.querySelectorAll("#modal-site [data-original][data-site-prop]").forEach(function(elm) {
  7666. let single = { prop: elm.dataset.siteProp, value: elm.dataset.original };
  7667. if(elm.dataset.original != elm.value && (elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") ) {
  7668. single.value = elm.value;
  7669. faucet.items.push(single);
  7670. updateObject.site.changed = true;
  7671. } else if (elm.type == "checkbox" && ((elm.dataset.original == "0" && elm.checked) || (elm.dataset.original == "1" && !elm.checked)) ) {
  7672. single.value = elm.checked;
  7673. faucet.items.push(single);
  7674. updateObject.site.changed = true;
  7675. }
  7676. });
  7677. if(updateObject.site.changed) {
  7678. updateObject.site.list.push(faucet);
  7679. document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
  7680. toastr["info"]("Site will be updated as soon as possible");
  7681. }
  7682.  
  7683. },
  7684. cancel: function() {
  7685. document.querySelectorAll("#modal-site [data-original][data-site-prop]").forEach(function(elm) {
  7686. if(elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") {
  7687. elm.value = elm.dataset.original;
  7688. } else if (elm.type == "checkbox") {
  7689. elm.checked = (elm.dataset.original == "1" ? true : false)
  7690. }
  7691. });
  7692. }
  7693. };
  7694.  
  7695. window.editEreport = {
  7696. save: function() {
  7697. sendErrorReport();
  7698. },
  7699. cancel: function() {
  7700. }
  7701. };
  7702.  
  7703. window.modalSave = function modalSave(content) {
  7704. switch(content) {
  7705. case "wallet":
  7706. editWallet.save();
  7707. break;
  7708. case "ereport":
  7709. editEreport.save();
  7710. break;
  7711. case "config":
  7712. editConfig.save();
  7713. break;
  7714. case "site":
  7715. editSite.save();
  7716. break;
  7717. case "slAlert":
  7718. shortlinkAlert.save();
  7719. break;
  7720. }
  7721. };
  7722.  
  7723. window.modalCancel = function modalCancel(content) {
  7724. if(content == "wallet") {
  7725. editWallet.cancel();
  7726. } else if ("ereport") {
  7727. editEreport.cancel();
  7728. }
  7729. document.querySelectorAll("modal-content").forEach(x => x.classList.add("d-none"));
  7730. };
  7731.  
  7732. window.updateValues = function updateValues(type, values) {
  7733. let updateObject = getUpdateObject();
  7734. if (type == "runAsap") {
  7735. updateObject.runAsap.ids.push(values.id);
  7736. updateObject.runAsap.changed = true;
  7737. document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
  7738. uiRenderer.toast("Faucet will be updated to run as soon as possible");
  7739. }
  7740. };
  7741.  
  7742. window.schedulesInterval = null;
  7743. window.startSchedulesInterval = function startSchedulesInterval(uuids) {
  7744. if (window.schedulesInterval) {
  7745. clearInterval(window.schedulesInterval);
  7746. }
  7747.  
  7748. let innerWaitTimes = '';
  7749. uuids.forEach(x => {
  7750. innerWaitTimes += `<span data-schedule="${x}" data-nextroll="UNDEFINED" class="mx-1"><i class="fas fa-square pr-1" style="color: #${x};"></i><span></span></span>`;
  7751. });
  7752.  
  7753. let container = document.querySelector('#wait-times');
  7754. container.innerHTML = innerWaitTimes;
  7755. window.schedulesInterval = setInterval(() => {
  7756. [...document.querySelectorAll('#wait-times > span')].forEach(sp => {
  7757. let nroll = sp.getAttribute('data-nextroll');
  7758. let spanScheduleId = sp.getAttribute('data-schedule');
  7759. if (nroll == 'UNDEFINED') {
  7760. sp.querySelector('span').innerText = '-';
  7761. } else if (nroll == 'RUNNING') {
  7762. sp.querySelector('span').innerText = 'Running';
  7763. let inUseElm = document.querySelector(`#schedule-table tr[data-schedule="${spanScheduleId}"]`);
  7764. if (inUseElm) {
  7765. inUseElm.classList.add('in-use');
  7766. }
  7767. } else {
  7768. let timeVal = +nroll - Date.now();
  7769. sp.querySelector('span').innerText = timeVal.msToCountdown();
  7770. if (timeVal < -60000) {
  7771. console.info(`Resync required: ${timeVal}`);
  7772. }
  7773. }
  7774. })
  7775. }, 1000);
  7776. }
  7777. window.confirmable = {
  7778. open: function (req, details = null, params = null) {
  7779. let btn = document.getElementById("confirm-req-btn");
  7780. btn.setAttribute('data-request', req);
  7781. btn.setAttribute('data-params', params ? JSON.stringify(params) : '{}');
  7782.  
  7783. if(details) {
  7784. document.querySelector("#confirmable-modal p").innerText = details;
  7785. }
  7786. return;
  7787. },
  7788. accept: function () {
  7789. let btn = document.getElementById("confirm-req-btn");
  7790. let req = { type: '', params: {}};
  7791. req.type = btn.getAttribute('data-request');
  7792. req.params = JSON.parse(btn.getAttribute('data-params'));
  7793. switch(req.type) {
  7794. case 'removeAllPromos':
  7795. window.removeAllPromos();
  7796. break;
  7797. case 'forceStopFaucet':
  7798. window.forceStopFaucet();
  7799. break;
  7800. default:
  7801. break;
  7802. }
  7803. }
  7804. }
  7805.  
  7806. window.removeAllPromos = function removeAllPromos() {
  7807. var promoCode = document.getElementById("promo-code-new");
  7808. var promoObject = { action: "REMOVEALLPROMOS" };
  7809. promoCode.innerHTML =JSON.stringify(promoObject);
  7810. toastr["info"]("Removing all promo codes... please wait");
  7811. };
  7812.  
  7813. window.forceStopFaucet = function forceStopFaucet() {
  7814. var promoCode = document.getElementById("promo-code-new");
  7815. var promoObject = { action: "FORCESTOPFAUCET" };
  7816. promoCode.innerHTML =JSON.stringify(promoObject);
  7817. toastr["info"]("Trying to stop... Please wait for reload");
  7818. };
  7819.  
  7820. window.openStatsChart = function openStatsChart() {
  7821. if(myBarChart) { myBarChart.destroy(); }
  7822. let statsFragment = document.getElementById("stats-fragment");
  7823. if (statsFragment.style.display === "block") { statsFragment.style.display = "none"; document.getElementById("stats-button").innerText = "Lucky Number Stats"; } else {
  7824. statsFragment.style.display = "block"; document.getElementById("stats-button").innerText = "Close Stats";
  7825. var canvas = document.getElementById("barChart");
  7826. var ctx = canvas.getContext("2d");
  7827. var dataSpan = document.getElementById("rolls-span");
  7828. var data = {
  7829. labels: ["0000-9885", "9886-9985", "9986-9993", "9994-9997", "9998-9999", "10000"],
  7830. datasets: [ { fill: false, backgroundColor: [ "#990000", "#660066", "#000099", "#ff8000", "#ffff00", "#00ff00"],
  7831. data: dataSpan.innerText.split(",") } ] };
  7832. var options = { plugins: { legend: { display: false } }, title: { display: true, text: "Rolled Numbers", position: "top" }, rotation: -0.3 * Math.PI };
  7833. myBarChart = new Chart(ctx, { type: "doughnut", data: data, options: options });
  7834. }
  7835. };
  7836.  
  7837. window.shortlinkAlert = {
  7838. load: function(id, destination) {
  7839. let hideShortlinkAlerts = localStorage.getItem("hideShortlinkAlerts");
  7840. hideShortlinkAlerts = hideShortlinkAlerts ? JSON.parse(hideShortlinkAlerts) : false;
  7841.  
  7842. if (hideShortlinkAlerts) {
  7843. } else {
  7844. document.getElementById(id).classList.remove("d-none");
  7845. }
  7846. },
  7847. save: function () {
  7848. localStorage.setItem("hideShortlinkAlerts", JSON.stringify(document.getElementById("hideShortlinkAlerts").checked));
  7849. window.open("https://example.com", "_blank");
  7850. }
  7851. }
  7852. }
  7853. };
  7854.  
  7855. let logLines = [];
  7856. function init(cfFaucets, schedules) {
  7857. appendJavaScript();
  7858. appendHtml(schedules);
  7859. updateSchedulesToggler();
  7860. appendEventListeners();
  7861. appendWidgets();
  7862. setupEventerListeners();
  7863.  
  7864. createPromoTable(cfFaucets);
  7865. try {
  7866. document.querySelector('.page-title h1').innerHTML = 'Auto Claim';
  7867. } catch (err) {}
  7868. };
  7869. function setupEventerListeners() {
  7870. eventer.on('siteUpdated', (site) => {
  7871. Site.sortAll(); // en todos los sites...
  7872. let schedule = Schedule.getById(site.schedule);
  7873. schedule.sortSites(); // solo en el schedule de este site
  7874. schedule.setCurrentSite(); // solo en el schedule de este site
  7875. Site.saveAll();
  7876. uiRenderer.sites.renderSiteRow(site); // solo la row de este site
  7877. uiRenderer.sites.sortSitesTable(); // y reordenar
  7878.  
  7879. schedule.checkNextRoll(); // solo en el schedule de este site
  7880. convertToFiat();
  7881. });
  7882. }
  7883. function appendWidgets() {
  7884. $('.tableSortable').sortable({
  7885. placeholder:'sort-highlight',
  7886. handle:'.row-handle',
  7887. cursor: 'grabbing',
  7888. axis: 'y',
  7889. stop: function(event, ui) {
  7890. $("tbody.ui-sortable tr").each(function(index) {
  7891. $(this).attr("data-order", index);
  7892. });
  7893. }
  7894. });
  7895. $('#promo-daily').bootstrapSwitch();
  7896. $('#bss-log').bootstrapSwitch({
  7897. onSwitchChange(event, state) {
  7898. $('#console-log').collapse('toggle');
  7899. },
  7900. onInit: function(event, state) {
  7901. this.$element.closest('.bootstrap-switch-container').find('.bootstrap-switch-handle-on').first().addClass('fa fa-eye').text('');
  7902. this.$element.closest('.bootstrap-switch-container').find('.bootstrap-switch-handle-off').first().addClass('fa fa-eye-slash').text('');
  7903. }
  7904. });
  7905. };
  7906. function updateSchedulesToggler() {
  7907. let container = document.querySelector('#schedules-toggler');
  7908. let html = '<label class="btn btn-outline-primary active" data-schedule="all"><input type="radio" name="options" autocomplete="off" checked="true"> All</label>';
  7909. Schedule.getAll().forEach(x => {
  7910. html += `<label class="btn btn-outline-primary" data-schedule="${x.uuid}">
  7911. <i class="fas fa-square pr-1" style="color: #${x.uuid};"></i>${x.name}
  7912. <input type="radio" name="options" autocomplete="off">
  7913. </label>`;
  7914. });
  7915. container.innerHTML = html;
  7916. startSchedulesInterval(Schedule.getAllForCrud().map(x => x.uuid));
  7917. uiRenderer.schedules.toggleSchedule('all');
  7918. };
  7919. function appendEventListeners() {
  7920. document.querySelector('.dropdown-settings-menu').addEventListener('click', function(e) {
  7921. let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
  7922. if (actionElement.dataset.target) {
  7923. e.stopPropagation();
  7924. uiRenderer.openModal(actionElement.dataset.target);
  7925. }
  7926. });
  7927.  
  7928. const modalSchedules = document.querySelector('#modal-schedules');
  7929. modalSchedules.addEventListener('click', function(e) {
  7930. let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
  7931. if (actionElement.classList.contains('action-schedule-add')) {
  7932. e.stopPropagation();
  7933. let rows = modalSchedules.querySelectorAll('table tbody tr');
  7934. let rndColor = helpers.randomHexColor();
  7935. let rowTemplate = uiRenderer.schedules.renderRow({
  7936. uuid: rndColor,
  7937. name: rndColor,
  7938. order: rows.length,
  7939. added: true
  7940. });
  7941. $(modalSchedules.querySelector('table tbody tr:last-child')).after(rowTemplate);
  7942. uiRenderer.appendColorPickers('table tbody tr:last-child .color-picker');
  7943. } else if (actionElement.classList.contains('action-schedule-remove')) {
  7944. let rows = modalSchedules.querySelectorAll('table tbody tr:not(.d-none)');
  7945. if (rows.length <= 1) {
  7946. alert('You need to keep at least 1 schedule');
  7947. } else {
  7948. let current = actionElement.closest('tr');
  7949. if (current.dataset.added === 'true') {
  7950. current.remove();
  7951. } else {
  7952. current.dataset.removed = 'true';
  7953. current.classList.add('d-none');
  7954. }
  7955. }
  7956. } else if (actionElement.classList.contains('modal-save')) {
  7957. let data = uiRenderer.parseTable(modalSchedules.querySelector('table'));
  7958. let isValid = Schedule.crud(data);
  7959. updateSchedulesToggler();
  7960. manager.resyncAll({withUpdate: true});
  7961. if (!isValid) {
  7962. uiRenderer.toast('Some schedules might have errors/invalid colors', 'warning');
  7963. }
  7964. }
  7965. });
  7966. };
  7967. function appendJavaScript() {
  7968. addJS_Node (null, null, injectables.managerJs);
  7969. };
  7970. function addCardHtml(obj) {
  7971. return `<div class="card m-1"><div class="card-header">${obj.header}</div><div class="card-body px-4">${obj.body}</div></div>`;
  7972. };
  7973. function addRandomBetween(propSelect, propMin, propMax) {
  7974. return `<table><tr><td>
  7975. <select class="form-control" ${propSelect.name}="${propSelect.value}">
  7976. <option value="0">Random between...</option><option value="15">15 minutes</option><option value="30">30 minutes</option><option value="35">35 minutes</option><option value="45">45 minutes</option><option value="65">65 minutes</option><option value="90">90 minutes</option><option value="120">120 minutes</option>
  7977. </select></td>
  7978. <td><input type="number" data-original="" ${propMin.name}="${propMin.value}" min="1" value="15" step="5" class="form-control"></td><td>and</td><td><input type="number" data-original="" ${propMax.name}="${propMax.value}" value="65" step="5" class="form-control"></td><td>minutes</td></tr></table>`;
  7979. }
  7980. function appendHtml(schedules) {
  7981. let html ='';
  7982. let tgt = document.querySelector('div.row.py-3');
  7983. if (tgt) {
  7984. let rowDiv = document.createElement('div');
  7985. rowDiv.innerHTML = '<div class="row py-3 ac-log"><div class="col-12 justify-content-center"><div class="card"><div class="card-body" id="referral-table"></div></div></div></div>';
  7986. tgt.after(rowDiv);
  7987. }
  7988.  
  7989. html += '<div class="modal fade" id="confirmable-modal" tabindex="-1" role="dialog" aria-hidden="true">';
  7990. html += '<div class="modal-dialog modal-sm modal-dialog-centered"><div class="modal-content">';
  7991. html += '<div class="modal-header"><h4 class="modal-title">Are you sure?</h4><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
  7992. html += '<div class="modal-body"><p></p></div>';
  7993. html += '<div class="modal-footer justify-content-between"><button type="button" class="btn btn-default" data-dismiss="modal">No</button>';
  7994. html += '<button type="button" class="btn btn-primary" data-dismiss="modal" id="confirm-req-btn" onclick="confirmable.accept()">Yes</button></div>';
  7995. html += '</div></div>';
  7996. html += '</div>';
  7997.  
  7998. html += '<div class="modal fade" id="modal-dlg" tabindex="-1" role="dialog" data-backdrop="static" aria-hidden="true">';
  7999. html += ' <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable" role="document">';
  8000.  
  8001. html += '<div class="modal-content bg-beige" id="modal-spinner"><div class="modal-body"><div class="d-flex justify-content-center"><span id="target-spinner" class="d-none"></span><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>Loading data</div></div></div>';
  8002.  
  8003. html += ' <div class="modal-content bg-beige d-none" id="modal-ereport">';
  8004. html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-history"></i> Submit an Error</h5></div>';
  8005. html += ' <div class="modal-body">';
  8006. html += ' <div class="alert alert-danger">Don\'t send private information as data might be publicly access.</div>';
  8007. html += ' <textarea rows="4" id="log-message" class="form-control" placeholder="PLEASE do not send logs without describing here the issue you are facing..."></textarea>';
  8008. html += ' <label for="log-textarea">Log</label>';
  8009. html += ' <textarea rows="10" id="log-textarea" class="form-control"></textarea>';
  8010. html += ' </div>';
  8011. html += ' <div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'ereport\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8012. html += ' <a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'ereport\')" data-dismiss="modal"><i class="fa fa-paper-plane"></i> Send</a></div>';
  8013. html += ' </div>';
  8014.  
  8015. html += ' <div class="modal-content bg-beige d-none" id="modal-wallet">';
  8016. html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-wallet"></i> Your Addresses</h5></div>';
  8017. html += ' <div class="modal-body">';
  8018. html += ' <div><table class="table custom-table-striped" id="wallet-table">';
  8019. html += ' <thead><tr><th class="">Name</th><th class="">Address</th></tr></thead>';
  8020. html += ' <tbody class="overflow-auto" id="wallet-table-body"></tbody></table><textarea rows="14" id="wallet-json" class="d-none w-100"></textarea>';
  8021. html += ' </div>';
  8022. html += ' </div>';
  8023. html += '<div class="modal-footer">';
  8024. html += '<div class="footer-json d-none">';
  8025. html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="editWallet.toggleJson(\'cancel\')"><i class="fa fa-times-circle"></i> Cancel</a>';
  8026. html += '<a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editWallet.toggleJson()"><i class="fa fa-edit"></i> Confirm</a></div>';
  8027. html += '<div class="footer-table"><a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editWallet.toggleJson()"><i class="fa fa-edit"></i> Edit as JSON</a>';
  8028. html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'wallet\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8029. html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'wallet\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div></div>';
  8030. html += ' </div>';
  8031.  
  8032. html += ' <div class="modal-content bg-beige d-none" id="modal-info">';
  8033. html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-info"></i> Info</h5></div>';
  8034. html += ' <div class="modal-body">';
  8035. html += '<ul>';
  8036. html += '<li>First of all, make sure you visit our <a href="https://discord.gg/gaYYBjJUhP" target="_blank">discord</a> server for specific issues with the script. Unfortunately, our original server and user account was disabled after +2 years. We are trying to bring the community together in a new one now.</li>';
  8037. html += `<li>The script comes with <b>2 schedules</b> (Default and CF). You can add more from <i>Settings > Schedules...</i><br>About the <i>Schedules</i>:`;
  8038. html += `<ul><li>Each schedule will open a new tab, so:<br>N schedules = N simultaneous tabs.</li>`;
  8039. html += `<li>Each schedule has it's own list of sites.<br>You can have N sites per schedule, but each site can be in just 1 schedule to avoid overlapping.</li>`;
  8040. html += `<li>We suggest you to test how many tabs you can run simultaneously before creating too many schedules.<br>Usually, with 4 or 5 it will run smoothly.</li></ul>`;
  8041. html += `</li>`;
  8042. html += '<li>Almost all sites in the list require an external hCaptcha solver or similar scripts/extensions. You can find our free suggestions in Settings > Other requirements...</li>';
  8043. html += '<li>Stormgain requires a GeeTest solver. You can use <a href="https://greasyfork.org/en/scripts/444560" target="_blank">this script</a> to solve the captchas through 2Captcha API service.</li>';
  8044. html += `<li>Some sites pay directly to <a href="https://faucetpay.io/?r=freebtc" target="_blank"><i class="fa fa-external-link-alt"></i> FaucetPay</a>. You need to add your FP addresses at <i>Settings > Wallet...</i> to claim from those sites.</li>`;
  8045. html += `<li>You can set default configurations at <i>Settings > Defaults...</i></li>`;
  8046. html += `<li>At <i>Settings > Defaults</i>, you will also find <i>Site Specific</i> settings like credentials for auto login.</li>`;
  8047. html += '<li>You can override configurations for a specific site using the edit (<i class="fa fa-clock"></i>) buttons</li>';
  8048. html += '<li>When enabling a new site, try it first with the tab on focus, to detect potential issues</li>';
  8049. html += '</ul>';
  8050. html += ' </div>';
  8051. html += '<div class="modal-footer">';
  8052. html += '<a class="btn m-2 anchor btn-outline-warning align-middle" data-dismiss="modal"><i class="fa fa-edit"></i> Close</a></div>';
  8053. html += ' </div>';
  8054.  
  8055. html += '<div class="modal-content bg-beige" id="modal-schedules">';
  8056. html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-stopwatch"></i> Schedules</h5>';
  8057. html += ' <div class="ml-auto"><button type="button" class="btn btn-default btn-sm action-schedule-add">';
  8058. html += ' <i class="fa fa-plus"></i> Add Schedule';
  8059. html += ' </button></div>';
  8060. html += ' </div>';
  8061. html += ' <div class="modal-body">';
  8062. html += '<div class="callout callout-warning m-0"><p class="text-justify">Each schedule opens sites in a new/different tab.<br>Colors must be unique.</p></div>';
  8063. html += ' <table class="table">';
  8064. html += ' <thead>';
  8065. html += ' <tr><th></th><th class="text-center" width="35%">Color</th><th class="text-center">Name</th><th></th></tr>';
  8066. html += ' </thead>';
  8067. html += ' <tbody class="tableSortable">';
  8068. html += ' </tbody>';
  8069. html += ' </table>';
  8070. html += ' </div>';
  8071. html += ' <div class="modal-footer">';
  8072. html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8073. html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
  8074. html += ' </div>';
  8075. html += '</div>';
  8076.  
  8077. html += '<div class="modal-content bg-beige" id="modal-assign-schedule">';
  8078. html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-exchange-alt"></i> Move to...</h5>';
  8079. html += ' </div>';
  8080. html += ' <div class="modal-body">';
  8081. html += ' <div class="form-container">';
  8082. html += ' <input type="hidden" name="site_id" value="not_set">';
  8083. html += ' <input type="hidden" name="original_schedule_id" value="not_set">';
  8084. html += ' <label class="control-label">Schedule</label>';
  8085. html += ' <select class="form-control" name="schedule">';
  8086. html += ' </select>';
  8087. html += ' </div>';
  8088. html += ' </div>';
  8089. html += ' <div class="modal-footer">';
  8090. html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8091. html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
  8092. html += ' </div>';
  8093. html += '</div>';
  8094.  
  8095. html += '<div class="modal-content bg-beige" id="modal-add-site">';
  8096. html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-code"></i> Add Site...</h5>';
  8097. html += ' </div>';
  8098. html += ' <div class="modal-body">';
  8099. html += ' <div class="form-container">';
  8100. html += uiRenderer.addInputTextHtml({ required: true, name: 'site_name', value: '', text: 'Display name'});
  8101. html += uiRenderer.addInputTextHtml({ required: true, name: 'site_url', value: '', text: 'Url to open', placeholder: 'Example: https://freebitcoin.io/free' });
  8102. html += ' <label class="control-label">Schedule</label>';
  8103. html += ' <select class="form-control" name="schedule">';
  8104. html += ' </select>';
  8105. html += ' </div>';
  8106. html += ' </div>';
  8107. html += ' <div class="modal-footer">';
  8108. html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8109. html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
  8110. html += ' </div>';
  8111. html += '</div>';
  8112.  
  8113. html += '<div class="modal-content bg-beige" id="modal-site-parameters">';
  8114. html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-edit"></i> Edit Site Arguments...</h5>';
  8115. html += ' </div>';
  8116. html += ' <div class="modal-body">';
  8117. html += ' <div class="form-container"><form action="">';
  8118. html += ` <div>Soon you'll be able to edit the site's specific settings here (credentials, withdrawal configuration, etc.)<br>`;
  8119. html += `You'll also see the site specific requirements, like required captcha solvers.<br>Meanwhile, go to Settings > Defaults > Site Specifics.<br>If there's something to configurate for this site, it'll be listed there.`;
  8120. html += `<br>You can find a general requirements list in Settings > Other requirements...</div>`;
  8121. html += ' </form></div>';
  8122. html += ' </div>';
  8123. html += ' <div class="modal-footer">';
  8124. html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Close</a>';
  8125. html += ' </div>';
  8126. html += '</div>';
  8127.  
  8128. html += ' <div class="modal-content bg-beige d-none" id="modal-slAlert">';
  8129. html += ' <div class="modal-header"><h5 class="modal-title">Attention</h5></div>';
  8130. html += ' <div class="modal-body">';
  8131. html += ' <div class="alert alert-warning">You will be redirected to a shortlink, and after completing it the new Twitter Daily Promo Code will be added to your table.<br>';
  8132. html += 'This is an optional contribution. You can still get the code the old fashion way.</div>';
  8133. html += uiRenderer.addLegacySliderHtml('id', 'hideShortlinkAlerts', `Stop warning me before a shortlink`);
  8134. html += ' </div>';
  8135. html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'slAlert\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8136. html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'slAlert\')" data-dismiss="modal"><i class="fa fa-external-link-alt"></i> Lets Go!</a></div>';
  8137. html += ' </div>';
  8138.  
  8139. html += ' <div class="modal-content bg-beige d-none" id="modal-site">';
  8140. html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-clock"></i> <span id="faucet-name" data-id=""></span> Schedule Parameters</h5></div>';
  8141. html += ' <div class="modal-body">';
  8142. html += ' <div class="alert alert-warning">Override Settings for the selected faucet.<br>Faucet-specific configurations will be moved here soon.</div>';
  8143. html += ' <div class="row">';
  8144.  
  8145. html += ' <div class="col-md-12 col-sm-12">';
  8146. html += addCardHtml({
  8147. header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.workInBackground.override', 'Override Work Mode'),
  8148. body: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.workInBackground', 'Open tab in background')
  8149. });
  8150. html += addCardHtml({
  8151. header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.nextRun.override', 'Override Next Run'),
  8152. body: `<div>${uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.nextRun.useCountdown', 'Use faucet countdown when possible')}</div>` +
  8153. `<label class="control-label">Otherwise wait:</label>` +
  8154. addRandomBetween({ name: 'data-site-prop', value: 'defaults.nextRun' }, { name: 'data-site-prop', value: 'defaults.nextRun.min' }, { name: 'data-site-prop', value: 'defaults.nextRun.max' })
  8155. });
  8156. html += addCardHtml({
  8157. header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.sleepMode.override', 'Override Sleep Mode'),
  8158. body: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.sleepMode', 'Sleep mode') +
  8159. `<table><tr><td>Don't claim between </td><td><input type="time" data-original="" data-site-prop="defaults.sleepMode.min" class="form-control"></td><td>and</td>
  8160. <td><input type="time" data-original="" data-site-prop="defaults.sleepMode.max" class="form-control"></td></tr></table>`
  8161. });
  8162. html += ' <div class="card m-1"><div class="card-header">Timeout</div>';
  8163. html += ' <div class="card-body px-4">';
  8164. html += addCardHtml({
  8165. header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.timeout.override', 'Override Timeout'),
  8166. body: `<table><tr><td>After</td><td><input type="number" data-original="" data-site-prop="defaults.timeout" min="2" value="5" step="1" class="form-control"></td><td>minutes</td></tr></table>`
  8167. });
  8168. html += addCardHtml({
  8169. header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.postponeMinutes.override', 'Override Postpone'),
  8170. body: `<label class="control-label">After timeout/error, postpone for:</label>` +
  8171. addRandomBetween({ name: 'data-site-prop', value: 'defaults.postponeMinutes' }, { name: 'data-site-prop', value: 'defaults.postponeMinutes.min' }, { name: 'data-site-prop', value: 'defaults.postponeMinutes.max' })
  8172. });
  8173. html += ' </div>';
  8174. html += ' </div>';
  8175. html += ' </div>';
  8176. html += ' </div>';
  8177. html += ' </div>';
  8178. html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'site\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8179. html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'site\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div>';
  8180. html += ' </div>';
  8181.  
  8182. html += '<div class="modal-content bg-beige d-none" id="modal-config">';
  8183. html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-cog"></i> Settings</h5></div>';
  8184. html += ' <div class="modal-body">';
  8185. html += ' <div class="row">';
  8186.  
  8187. html += ' <div class="col-md-12 col-sm-12">';
  8188. html += ' <div class="card card-info m-1"><div class="card-header">Defaults<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div></div>';
  8189. html += ' <div class="card-body px-4">';
  8190. html += `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.workInBackground', 'Open tabs in background')}</div>`;
  8191. html += `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.extraInterval', 'Use extra timer to detect ad redirects faster')}</div>`;
  8192.  
  8193. html += addCardHtml({
  8194. header: 'Next Run',
  8195. body: `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.nextRun.useCountdown', 'Use faucet countdown when possible')}</div>` +
  8196. `<label class="control-label">Otherwise wait:</label>` +
  8197. addRandomBetween({ name: 'data-prop', value: 'defaults.nextRun' }, { name: 'data-prop', value: 'defaults.nextRun.min' }, { name: 'data-prop', value: 'defaults.nextRun.max' })
  8198. });
  8199. html += addCardHtml({
  8200. header: 'Timeout',
  8201. body: `<table><tr><td>After</td><td><input type="number" data-original="" data-prop="defaults.timeout" min="2" value="5" step="1" class="form-control"></td><td>minutes</td></tr></table>` +
  8202. `<label class="control-label">After timeout/error, postpone for:</label>` +
  8203. addRandomBetween({ name: 'data-prop', value: 'defaults.postponeMinutes' }, { name: 'data-prop', value: 'defaults.postponeMinutes.min' }, { name: 'data-prop', value: 'defaults.postponeMinutes.max' })
  8204. });
  8205. html += addCardHtml({
  8206. header: 'Logging',
  8207. body: `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'devlog.enabled', 'Store log (enables the \'Log\' button)')}</div>` +
  8208. `<table><tr><td>Max log size in lines:</td><td><input type="number" data-original="" data-prop="devlog.maxLines" min="100" step="100" class="form-control"></td></tr></table>`
  8209. });
  8210. html += addCardHtml({
  8211. header: uiRenderer.addLegacySliderHtml('data-prop', 'defaults.sleepMode', 'Sleep mode'),
  8212. body: `<table><tr><td>Don't claim between </td><td><input type="time" data-original="" data-prop="defaults.sleepMode.min" class="form-control"></td><td>and</td>
  8213. <td><input type="time" data-original="" data-prop="defaults.sleepMode.max" class="form-control"></td></tr></table>`
  8214. });
  8215. html += ' </div></div>';
  8216. html += ' </div>';
  8217.  
  8218. html += ' <div class="col-md-12 col-sm-12">';
  8219. html += ' <div class="card card-info m-1"><div class="card-header">Site Specifics<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div></div>';
  8220. html += ' <div class="card-body px-4">';
  8221.  
  8222. html += ' <div class="card m-1 collapsed-card"><div class="card-header">CryptosFaucets<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8223. html += ' <div class="card-body px-4" style="display: none;">';
  8224. html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.rollOnce" ><span class="slider round"></span></label> Roll once per round </div>';
  8225. html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.usePromoCodes" ><span class="slider round"></span></label> Try to use promo codes every day (disable it if you are facing too many captcha timeouts) </div>';
  8226. html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.tryGetCodes" ><span class="slider round"></span></label> Auto update promo codes </div>';
  8227. html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.autologin" ><span class="slider round"></span></label> Autologin when necessary</div>';
  8228. html += ' <select class="form-control" data-prop="cf.credentials.mode">';
  8229. html += ' <option value="1">Use Email and Password</option><option value="2">Filled by 3rd party software/extension</option>';
  8230. html += ' </select>';
  8231. html += ' <label class="control-label">E-Mail</label>';
  8232. html += ' <input maxlength="200" type="text" data-prop="cf.credentials.email" required="required" class="form-control" placeholder="Email address..."/>';
  8233. html += ' <label class="control-label">Password</label>';
  8234. html += ' <input maxlength="200" type="password" data-prop="cf.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
  8235. html += ' <label class="control-label">Hours to wait If IP is banned:</label>';
  8236. html += ' <select class="form-control" data-prop="cf.sleepHoursIfIpBan">';
  8237. html += ' <option value="0">Disabled</option><option value="2">2</option><option value="4">4</option><option value="8">8</option><option value="16">16</option><option value="24">24</option><option value="26">26</option>';
  8238. html += ' </select>';
  8239. html += ' </div></div>';
  8240.  
  8241. html += ' <div class="card m-1 collapsed-card"><div class="card-header">JTFey<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8242. html += ' <div class="card-body px-4" style="display: none;">';
  8243. html += ' <label class="control-label">Login Mode</label>';
  8244. html += ' <select class="form-control" data-prop="jtfey.credentials.mode">';
  8245. html += ' <option value="1">Use Username and Password</option><option value="2">Filled by 3rd party software/extension</option>';
  8246. html += ' </select>';
  8247. html += ' <label class="control-label">E-Mail</label>';
  8248. html += ' <input maxlength="200" type="text" data-prop="jtfey.credentials.username" required="required" class="form-control" placeholder="Email address..."/>';
  8249. html += ' <label class="control-label">Password</label>';
  8250. html += ' <input maxlength="200" type="password" data-prop="jtfey.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
  8251. html += ' </div></div>';
  8252.  
  8253. html += ' <div class="card m-1 collapsed-card"><div class="card-header">FaucetPay PTC<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8254. html += ' <div class="card-body px-4" style="display: none;">';
  8255. html += ' <div><label class="switch"><input type="checkbox" data-prop="fp.randomPtcOrder" ><span class="slider round"></span></label> Random PTC order </div>';
  8256. html += ' <label class="control-label">Max duration per run:</label>';
  8257. html += ' <select class="form-control" data-prop="fp.maxTimeInMinutes">';
  8258. html += ' <option value="5">5 minutes</option><option value="10">10 minutes</option><option value="15">15 minutes</option><option value="30">30 minutes</option>';
  8259. html += ' </select>';
  8260. html += ' </div></div>';
  8261.  
  8262. html += ' <div class="card m-1 collapsed-card"><div class="card-header">Dutchy<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8263. html += ' <div class="card-body px-4" style="display: none;">';
  8264. html += ' <div><label class="switch"><input type="checkbox" data-prop="dutchy.useBoosted" ><span class="slider round"></span></label> Try boosted roll </div>';
  8265. html += ' </div></div>';
  8266.  
  8267. html += ' <div class="card m-1 collapsed-card"><div class="card-header">BestChange<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8268. html += ' <div class="card-body px-4" style="display: none;">';
  8269. html += ' <label class="control-label">BTC Address:</label>';
  8270. html += ' <select class="form-control" data-prop="bestchange.address">';
  8271. html += ' <option value="101">Faucet Pay BTC</option><option value="1">BTC Alt Address</option>';
  8272. html += ' </select>';
  8273. html += ' </div></div>';
  8274.  
  8275. html += ' <div class="card m-1 collapsed-card"><div class="card-header">Yes Coiner<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
  8276. html += ' <div class="card-body px-4" style="display: none;">';
  8277. html += ' <label class="control-label">Login Mode</label>';
  8278. html += ' <select class="form-control" data-prop="ycoin.credentials.mode">';
  8279. html += ' <option value="1">Use Username and Password</option><option value="2">Filled by 3rd party software/extension</option>';
  8280. html += ' </select>';
  8281. html += ' <label class="control-label">E-Mail</label>';
  8282. html += ' <input maxlength="200" type="text" data-prop="ycoin.credentials.username" required="required" class="form-control" placeholder="Account number..."/>';
  8283. html += ' <label class="control-label">Password</label>';
  8284. html += ' <input maxlength="200" type="password" data-prop="ycoin.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
  8285. html += ' </div></div>';
  8286.  
  8287. html += ' </div></div>';
  8288. html += ' </div>';
  8289. html += ' </div>';
  8290. html += '</div>';
  8291. html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'config\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  8292. html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'config\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div>';
  8293. html += ' </div>';
  8294.  
  8295. html += '</div>';
  8296. html += '</div>';
  8297.  
  8298. html += '<section id="table-struct" class="fragment "><div class="container-fluid "><div class="py-1 "><div class="row mx-0 justify-content-center">';
  8299. html += '<a class="btn m-2 anchor btn-outline-danger align-middle" data-toggle="modal" data-target="#confirmable-modal" onclick="confirmable.open(\'forceStopFaucet\', \'Running faucet will be disabled and the manager will reload.\')"><i class="fa fa-stop-circle"></i>Force Stop</a>';
  8300. html += '</div>';
  8301.  
  8302. html += '<div class="card">';
  8303.  
  8304. html += '<div class="card-header">';
  8305. html += '<div class="d-flex p-0">';
  8306.  
  8307. html += '<div id="schedules-toggler" class="btn-group btn-group-toggle" data-toggle="buttons">';
  8308.  
  8309. html += '</div>';
  8310.  
  8311. html += '<div class="card-tools ml-auto mt-2 mr-1">';
  8312. html += '<input type="checkbox" data-toggle="switch" data-label-text="Log" title="Show/Hide Log" id="bss-log" checked>';
  8313.  
  8314. html += `<button type="button" class="btn btn-flat btn-sm btn-outline-primary mx-1 dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-cog"></i> Settings</button>
  8315. <div class="dropdown-menu text-sm dropdown-settings-menu" style="">
  8316. <a class="dropdown-item btn-open-dialog" data-target="modal-config"><i class="fa fa-cog"></i>&nbsp;Defaults...</a>
  8317. <div class="dropdown-divider"></div>
  8318. <a class="dropdown-item btn-open-dialog" data-target="modal-schedules"><i class="fa fa-stopwatch"></i>&nbsp;Schedules...</a>
  8319. <a class="dropdown-item btn-open-dialog" data-target="modal-wallet"><i class="fa fa-wallet"></i>&nbsp;Wallets...</a>
  8320. <a class="dropdown-item btn-open-dialog" data-target="modal-requirements"><i class="fa fa-exclamation-circle"></i>&nbsp;Other requirements...</a>
  8321. <!-- <a class="dropdown-item btn-open-dialog" data-target="modal-sites"><i class="fa fa-window-restore"></i>&nbsp;Sites...</a> -->
  8322. <div class="dropdown-divider"></div>
  8323. <a class="dropdown-item btn-open-dialog" data-target="modal-info"><i class="fa fa-info"></i>&nbsp;Help/Info...</a>
  8324. </div>`;
  8325.  
  8326. html += '<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>';
  8327. html += '<button type="button" class="btn btn-tool mx-1" data-card-widget="maximize"><i class="fas fa-expand"></i></button>';
  8328. html += '</div></div>';
  8329. html += '<div id="wait-times" class="row mx-0 p-0 justify-content-center"></div>';
  8330. html += '</div>';
  8331.  
  8332. html += '<div class="card-body table-responsive p-0" style="height: 400px;" id="schedule-container">';
  8333. html += '<pre class="collapse show" id="console-log"><b>Loading...</b></pre>';
  8334. html += '</div>';
  8335.  
  8336. html += '</div>';
  8337.  
  8338. html += '</div>';
  8339. html += '<span id="update-data" style="display:none;"></span></section>';
  8340. html += '<section id="table-struct-promo" class="fragment "><div class="container-fluid "><div class="py-1 ">';
  8341.  
  8342. html += '<div class="card"><div class="card-header"><h3 class="card-title font-weight-bold">Promo Codes</h3><span id="promo-code-new" style="display:none;"></span>';
  8343. html += '<div class="card-tools">';
  8344.  
  8345. html += '<div class="input-group input-group-sm btn-tool">';
  8346. html += '<input id="promo-text-input" type="text" name="table_search" class="form-control float-right" placeholder="CF Promo Code..." style="width:130px;">';
  8347. html += '<input type="checkbox" data-toggle="switch" title="Check if the code can be reused every 24hs" id="promo-daily" data-on-text="Daily" data-off-text="1 Time">';
  8348. html += '<div class="input-group-append"><button type="submit" class="btn btn-default" id="promo-button""><i class="fas fa-plus"></i> Add</button></div>';
  8349. html += '<div class="input-group-append"><button type="submit" class="btn btn-default btn-outline-danger mx-1" data-toggle="modal" data-target="#confirmable-modal" onclick="confirmable.open(\'removeAllPromos\', \'All promo codes will be removed.\')"><i class="fas fa-times-circle"></i> Remove All</button></div>';
  8350. html += '<div class="input-group-append"><button type="submit" class="btn btn-default btn-outline-primary" id="button-try-get-codes"><i class="fas fa-bolt"></i> Try to Get Codes</button></div>';
  8351. html += '<div class="input-group-append"><button type="button" class="btn btn-tool btn-sm mx-1" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div>';
  8352. html += '<div class="input-group-append"><button type="button" class="btn btn-tool btn-sm mx-1" data-card-widget="maximize" title="Maximize"><i class="fas fa-expand"></i></button></div>';
  8353. html += '</div>';
  8354. html += '</div>';
  8355.  
  8356. html += '</div>';
  8357. html += '<div class="card-body table-responsive p-0" id="promo-container">';
  8358. html += '</div></div>';
  8359.  
  8360. html +='</div></div></section>';
  8361. html += '<section class="fragment"><div class="container-fluid ">';
  8362. html += '<div class="row justify-content-center"><a class="btn m-2 anchor btn-outline-primary" id="stats-button" onclick="openStatsChart()">CF Lucky Number Stats</a></div>';
  8363. html +='<div class="py-1" id="stats-fragment" style="display:none;"><div class="row align-items-center text-center justify-content-center">';
  8364. html += '<div class="col-md-12 col-lg-8"><canvas id="barChart"></canvas><span id="rolls-span" style="display:none;"></span></div></div></div></div></div></section>';
  8365.  
  8366. let wrapper = document.createElement('div');
  8367. wrapper.innerHTML = html.trim();
  8368.  
  8369. let target = document.getElementById('referral-table');
  8370. target.parentNode.insertBefore(wrapper, target);
  8371. document.getElementById('schedule-container').appendChild( createScheduleTable() );
  8372.  
  8373. if (document.querySelector('.main-header .navbar-nav.ml-auto')) {
  8374. let discord = document.createElement('li');
  8375. discord.classList.add('nav-item');
  8376. discord.innerHTML = '<a class="btn btn-primary btn-sm m-1" href="https://discord.gg/gaYYBjJUhP" target="_blank"><div class=""><span class="badge badge-pill badge-warning mr-2" title="">(new)</span>discord</div></a>';
  8377. document.querySelector('.main-header .navbar-nav.ml-auto').prepend(discord);
  8378. } else {
  8379. let discord = document.createElement('div');
  8380. discord.innerHTML = '<a class="btn m-2 btn-primary" href="https://discord.gg/gaYYBjJUhP" target="_blank"><div class=""><span class="badge badge-pill badge-warning mr-2" title="">(new)</span>discord</div></a>';
  8381. document.querySelector('.navbar-nav').prepend(discord);
  8382. }
  8383. addHtml({
  8384. target: '#modal-dlg .modal-dialog',
  8385. where: 'afterbegin',
  8386. content: `<div class="modal-content bg-beige d-none" id="modal-requirements">
  8387. <div class="modal-header"><h5 class="modal-title"><i class="fa fa-exclamation-circle"></i> Other requirements</h5></div>
  8388. <div class="modal-body">
  8389. <div class="callout callout-warning m-3">
  8390. <p class="text-justify">Some sites might require specific tools like captcha solvers that are not including in the script.</p>
  8391. </div>
  8392. <div>
  8393. <table class="table custom-table-striped" id="requirements-table">
  8394. <thead><tr><th class="">Name</th><th class="">Description</th><th class="">Suggestion</th></tr></thead>
  8395. <tbody class="overflow-auto" id="requirements-table-body">
  8396. </tbody>
  8397. </table>
  8398. </div>
  8399. </div>
  8400. <div class="modal-footer">
  8401. <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Close</a>
  8402. </div>
  8403. </div>`
  8404. });
  8405. addTemplateTag({
  8406. id: 'tpl-requirement-row',
  8407. content: `<tr><td>{name}</td><td>{description}</td><td>{suggestion}</td></tr>`
  8408. });
  8409. const tempRequirementsList = [
  8410. { id: '1', name: 'HCaptcha Solver', description: 'A solver for HCaptcha challenges', suggestion: `Latest github version of hektCaptcha extension (free)<br><a href="https://bit.ly/3Y24vg5" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
  8411. { id: '2', name: 'Recaptcha Solver', description: 'A solver for ReCaptcha challenges', suggestion: `Latest github version of hektCaptcha extension (free)<br><a href="https://bit.ly/3Y24vg5" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
  8412. { id: '3', name: 'Cloudflare Challenge Bypass', description: 'A solver for Cloudflare/Turnstile challenges', suggestion: `Auto clicker user script (free)<br><a href="https://sharetext.me/knpmyolewq" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
  8413. { id: '6', name: 'Active Tab/Window', description: 'The site requires the tab to be active. A good option is Tab Revolver Extension, which will loop the tabs opened in a specific window.', suggestion: `<a href="https://bit.ly/3Y28lpA" target="_blank"><i class="fa fa-external-link-alt"></i> User Script</a> or <a href="https://bit.ly/3q0H4Ht" target="_blank"><i class="fa fa-external-link-alt"></i> Extension</a>` },
  8414. ];
  8415. for(let r=0; r< tempRequirementsList.length; r++) {
  8416. let req = tempRequirementsList[r];
  8417. useTemplate({
  8418. templateId: 'tpl-requirement-row',
  8419. target: '#requirements-table-body',
  8420. where: 'afterbegin',
  8421. replacements: req
  8422. });
  8423. }
  8424. };
  8425. function createPromoTable(faucets) {
  8426. let table = document.createElement('table');
  8427. let inner = '';
  8428. table.classList.add('table', 'custom-table-striped');
  8429. table.setAttribute('id','promo-table');
  8430.  
  8431. inner += '<caption style="text-align: -webkit-center;">⏳ Pending ✔️ Accepted 🕙 Used Before ❌ Invalid code ❗ Unknown error ⚪ No code</caption>';
  8432. inner += '<thead><tr><th class="">Code</th><th class="">Added</th>';
  8433.  
  8434. for (let i = 0, all = faucets.length; i < all; i++) {
  8435. inner += '<th data-faucet-id="' + faucets[i].id + '">' + faucets[i].name + '</th>';
  8436. }
  8437.  
  8438. inner += '</tr></thead><tbody id="promo-table-body"></tbody></table>';
  8439.  
  8440. table.innerHTML = inner
  8441. document.getElementById('promo-container').appendChild( table );
  8442. };
  8443. function createScheduleTable() {
  8444. let table = document.createElement('table');
  8445. let inner;
  8446. table.classList.add('table', 'custom-table-striped', 'table-head-fixed', 'text-nowrap');
  8447. table.setAttribute('id','schedule-table');
  8448.  
  8449. inner = '<thead><tr>';
  8450. inner += '<th scope="col" class="edit-status d-none em-only" style="">Active</th><th class="">Next Roll</th><th class=""></th><th class="">Name</th><th class="text-center">Last Claim</th>';
  8451. inner += '<th class="text-center">Aggregate</th><th class="text-center">Balance</th><th class="text-center em-hide" id="converted-balance-col">FIAT</th>';
  8452. inner += '<th scope="col" class="text-center em-hide">Msgs</th>';
  8453. inner += '<th scope="col" class="" style="">';
  8454. inner += `<div class="btn-group btn-group-sm">
  8455. <button type="button" data-toggle="tooltip" title="Add site..." class="btn btn-default action-add-external-site em-hide">
  8456. <i class="fa fa-plus"></i>
  8457. </button>
  8458. <button type="button" title="Cancel" class="btn btn-danger action-edit-all-sites-cancel em-only d-none"><i class="fa fa-times-circle"></i> Cancel</button>
  8459. <button type="button" title="Save" class="btn btn-success action-edit-all-sites-save em-only d-none"><i class="fa fa-check-circle"></i> Save</button>
  8460. <button type="button" data-toggle="tooltip" title="Edit all..." class="btn btn-default action-edit-all-sites em-hide"><i class="fa fa-toggle-off"></i></button>
  8461. </div>`;
  8462. inner += '</th></tr></thead><tbody id="schedule-table-body"></tbody>';
  8463. table.innerHTML = inner;
  8464.  
  8465. return table;
  8466. };
  8467. function renderLogRow(data) {
  8468. let tr = document.createElement('tr');
  8469. tr.dataset.schedule = data.schedule;
  8470. tr.dataset.ts = data.ts.getTime();
  8471. tr.dataset.siteName = data.siteName || '';
  8472. tr.dataset.elapsed = data.elapsed || '';
  8473. let color = data.schedule ? `#${data.schedule}` : `transparent`;
  8474. let showIt = !data.schedule || !uiRenderer.schedules.selectedSchedule
  8475. || uiRenderer.schedules.selectedSchedule == 'all' || uiRenderer.schedules.selectedSchedule == data.schedule;
  8476. if (!showIt) {
  8477. tr.classList.add('d-none');
  8478. }
  8479.  
  8480. let tds = '';
  8481. tds += `<td>${helpers.getPrintableTime(data.ts)}</td>`;
  8482. tds += `<td><i class="fas fa-square pr-1" style="color: ${color};"></i></td>`;
  8483. if (data.elapsed) {
  8484. tds += `<td>${data.msg} [Elapsed time: ${data.elapsed} seconds]</td>`;
  8485. } else {
  8486. tds += `<td>${data.msg}</td>`;
  8487. }
  8488. tr.innerHTML = tds;
  8489.  
  8490. document.querySelector('#console-log table').appendChild(tr);
  8491. };
  8492. function log(data) {
  8493. if (!data || !data.msg) {
  8494. console.warn(`Log attempt without data or msg!`, data);
  8495. return;
  8496. }
  8497. data.ts = new Date();
  8498. data.schedule = data.schedule || false;
  8499. data.siteName = data.siteName || false;
  8500. data.elapsed = data.elapsed || false;
  8501.  
  8502. if(shared.getConfig()['devlog.enabled']) {
  8503. if (data.schedule) {
  8504. } else {
  8505. }
  8506. };
  8507.  
  8508. if (data.elapsed) {
  8509. let previous = logLines.find(x => x.msg == data.msg && x.schedule == data.schedule);
  8510. if (previous) {
  8511. previous.elapsed = data.elapsed;
  8512. previous.ts = data.ts;
  8513. logLines.sort( (a, b) => b.ts.getTime() - a.ts.getTime());
  8514. } else {
  8515. logLines.unshift(data);
  8516. }
  8517. } else {
  8518. logLines.unshift(data);
  8519. }
  8520. while(logLines.length > 30) {
  8521. logLines.pop();
  8522. }
  8523.  
  8524. document.querySelector('#console-log table').innerHTML = '';
  8525. logLines.forEach(r => renderLogRow(r));
  8526. };
  8527. function legacyLog(data, elapsed = false) {
  8528. if (!data || !data.msg) {
  8529. return;
  8530. }
  8531. elapsed = data.elapsed || false;
  8532. let msg = data.msg;
  8533. if (data.schedule) {
  8534. msg = `[${data.schedule}] ${data.msg}`;
  8535. }
  8536.  
  8537. if(shared.getConfig()['devlog.enabled']) { shared.devlog(msg, elapsed) };
  8538. if(msg) {
  8539. let waitingIdx = logLines.findIndex(line => {
  8540. let waitingMsg= line.split('&nbsp')[1];
  8541. if (waitingMsg == msg) {
  8542. return true;
  8543. }
  8544. });
  8545.  
  8546. let previous = waitingIdx > -1 ? logLines[waitingIdx].split('&nbsp')[1] : '';
  8547. if (elapsed && (previous == msg)) {
  8548. logLines[waitingIdx] = helpers.getPrintableTime() + '&nbsp' + msg + '&nbsp[Elapsed time:&nbsp' + elapsed + '&nbspseconds]';
  8549. } else {
  8550. while(logLines.length > 20) {
  8551. logLines.pop();
  8552. }
  8553. logLines.unshift(helpers.getPrintableTime() + '&nbsp' + msg);
  8554. }
  8555.  
  8556. document.getElementById('console-log').innerHTML = logLines.map(x => {
  8557. const regex = /\[([0-9a-fA-F]+)\]/;
  8558. const match = regex.exec(x);
  8559. let colorNumber = null;
  8560. if (match !== null) {
  8561. colorNumber = match[1];
  8562. }
  8563.  
  8564. let showIt = !colorNumber || !window.selectedSchedule || window.selectedSchedule == 'all' || window.selectedSchedule == colorNumber;
  8565.  
  8566. const formattedMsg = x.replace(/\[([0-9a-fA-F]+)\]/, '<i class="fas fa-square pr-1" style="color: #$1;"></i>');
  8567.  
  8568. let line = `<span data-schedule="${colorNumber ? colorNumber : ''}" class="${showIt ? '' : 'd-none'}">${formattedMsg}</span>`;
  8569. return line;
  8570. }).join('');
  8571. }
  8572. };
  8573. return {
  8574. init: init,
  8575. log: log
  8576. }
  8577. }
  8578.  
  8579. async function init() {
  8580. eventer = new EventEmitter();
  8581. persistence = new Persistence();
  8582. shared = objectGenerator.createShared();
  8583. useTimer = shared.getConfig()['defaults.extraInterval'];
  8584. if (location.href.startsWith('https://criptologico.com/tools/cc')) {
  8585. landing = window.location.host;
  8586. instance = K.LOCATION.MANAGER;
  8587. manager = createManager();
  8588. CFPromotions = objectGenerator.createCFPromotions();
  8589. uiRenderer = new UiRenderer();
  8590. uiRenderer.initialize();
  8591. ui = createUi();
  8592. CFHistory = objectGenerator.createCFHistory();
  8593.  
  8594. await manager.start();
  8595. try {
  8596. if (!document.body.classList.contains('sidebar-collapse')) document.querySelector('a[data-widget="pushmenu"]').click()
  8597. } catch {}
  8598. setTimeout( () => { window.stop(); }, 10000);
  8599. } else {
  8600. instance = K.LOCATION.UNKNOWN;
  8601. detectWeb();
  8602. }
  8603. }
  8604. init();
  8605. })();