[satology] Auto Claim Multiple Faucets with Monitor UI

Freebitco.in, StormGain Miner, 15 Faucets with Promo Codes + Autologin, FaucetPay PTC, etc.

当前为 2021-07-10 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name [satology] Auto Claim Multiple Faucets with Monitor UI
  3. // @description Freebitco.in, StormGain Miner, 15 Faucets with Promo Codes + Autologin, FaucetPay PTC, etc.
  4. // @description Automatic activation of StormGain Miner every 4 hours and hourly claim of free ADA, BNB, BCH, BTC, DASH, DGB, DOGE, ETH, LINK, LTC, NEO, STEAM, TRX, USDC, USDT, XEM, XRP, ZEC
  5. // @version 1.5.0
  6. // @author satology
  7. // @namespace satology.onrender.com
  8. // @homepage https://satology.onrender.com/faucets/referrals
  9.  
  10. // @note - IMPORTANT -------------------------------------------------------------------------------------------------------------------------------------------------------------------
  11. // @note YOU MUST HAVE A hCaptcha solver INSTALLED to claim from the faucets
  12. // @note I recommend this script: https://greasyfork.org/en/scripts/425854-hcaptcha-solver-automatically-solves-hcaptcha-in-browser
  13.  
  14. // @note AND
  15. // @note to roll Free-ethereum.io you need to add the following two lines to hCaptcha Solver script, right at the beginning of function getSynonyms(word) [line 232 on version 3.5]:
  16.  
  17. // @note const WORDS_WITH_CYRILLIC = {'TBD': AIRPLANE, 'bіcycle': BICYCLE, 'bοat': BOAT, 'сar': CAR, 'mοtorbus': MOTORBUS, 'mοtorcycle': MOTORCYCLE, 'trаin': TRAIN, 'truсk': TRUCK };
  18. // @note word = (encodeURIComponent(word).indexOf('%') > -1) ? WORDS_WITH_CYRILLIC[word] : word;
  19. // @note -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  20.  
  21. // @note - LAST UPDATES ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  22. // @note [@1.5 BETA RELEASE] Added Wallet to fill with your FaucetPay addresses [from the UI], promo codes suggestions [reusables] and Bagi & Keran faucets
  23. // @note Please don't activate ALL of the bagi/keran faucets. Consider the time it takes to roll them. This is a beta release as some modifications
  24. // @note will be added: needs refactor, might add priority to make sure certain faucets are rolled when available, etc.
  25. // @note Withdraw options: never, after each claim or every X hours (default). Can be configured @config var
  26. // @note Aggregate holds the sats you have at Keran/Bagi. Balance will accumulate the amount you withdraw to Faucet Pay.
  27. // @note You will see badges (timeouts/errors). Please don't report them unless they are labeled as 'ERROR'.
  28. // @note Faucets have referral links which are randomize. It has my ref links and of some users who have contributed with the
  29. // @note coding (thanks nat & karl)
  30. // @note [@1.4.0] Added Free-Litecoin.com & Free-Ethereum.io
  31. // @note [IMPORTANT 1]: Free-Ethereum.io has an annoying issue in the hCaptcha (at least on my end). Here's the problem and my way of 'fixing' it:
  32. // @note > Problem: The hCaptcha (despite being in English) displays what you need to look for with a character of the cyrillic unicode table
  33. // @note in the word. For example: instead of train, it says trаin. Looks the same, but it's not. The 'a' is different.
  34. // @note (CTRL+F and look for train and you'll see it won't match the latter. So this makes the hCaptcha Solver script fail.
  35. // @note > Solution/Workaround: Add the following 2 lines to the hCaptcha script, right after function getSynonyms(word) {
  36.  
  37. // @note const WORDS_WITH_CYRILLIC = {'TBD': AIRPLANE, 'bіcycle': BICYCLE, 'bοat': BOAT, 'сar': CAR, 'mοtorbus': MOTORBUS, 'mοtorcycle': MOTORCYCLE, 'trаin': TRAIN, 'truсk': TRUCK };
  38. // @note word = (encodeURIComponent(word).indexOf('%') > -1) ? WORDS_WITH_CYRILLIC[word] : word;
  39.  
  40. // @note As you can see, I couldn't get an AIRPLANE, so I don't know which character is replaced in that word. You can come up with a more solid
  41. // @note solution and share it. This is enough for me for now. It maps the word with the special character to the correct word.
  42. // @note [IMPORTANT 2]: Free-Ethereum.io is flagged as a phishing site by MetaMask. So you can just not use it or use it at your own risk as I do.
  43. // @note Just remember that if you use it, at least the first time after reopening Chrome, you'll get the MetaMask warning and you have to
  44. // @note bypass/'accept the risk' manually. Just in case, use a unique password for that site.
  45. // @note [@1.3] Added FaucetPay PTC. It runs on focus every 5 hs aprox (set by hoursBetweenRuns in config)
  46. // @note [@1.2] UI Changes
  47. // @note [@1.1] Added Freebitco.in and autologin for @cryptosfaucets
  48. // @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  49.  
  50. // @note - MAIN FEATURES ------------------------------------------------------------------------------------------------------------------------------------------------
  51. // @note > Automatic rolls and claims for faucets/PTCs/miners
  52. // @note > Accepts promotion codes (http://twitter.com/cryptosfaucets, free roll shortlinks) for CF 15 faucets
  53. // @note > Simple Monitor UI on top of a website to track progress (claims, next rolls, promo codes)
  54.  
  55. // @note - IMPORTANT CONSIDERATIONS -------------------------------------------------------------------------------------------------------------------------------------
  56. // @note 0. You need to enable popups on the Manager UI website to be able to open the faucets
  57. // @note 1. CF FAUCETS WEBSITES MUST OPEN IN ENGLISH TO BE ABLE TO RECOGNIZE IF THE PROMO CODE WAS ACCEPTED
  58. // @note In case you don't want to have them in English, you need to change the 3 strings the code uses for validation and change setToEnglish to false
  59. // @note (Search for localeStrings in the code)
  60. // @note 2. Autorolls will trigger ONLY when the faucet was opened by the Manager UI.
  61. // @note This is to allow users to navigate the websites to get the ShortLinks extra rolls, for example,
  62. // @note without having to stop the script.
  63. // @note 3. You can enable/disable faucets from the UI. By default they are all set to false.
  64. // @note It would be great if you could use my referral links listed below if you need an account.
  65. // @note To disable them, just set enabled: false in the webList array, save the script & refresh the manager
  66. // @note 4. You can change the config object to enable autologin, RP free roll bonus, etc.
  67. // @note 5. All data stored for tracking and to be displayed is stored locally in your environment. Nothing is uploaded.
  68.  
  69. // @note Always open to feedback. I'd be glad to hear from you if you find any bugs, have suggestions or new enhancements/features you'd like to see
  70. // @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  71. // @note DISCLAIMER: This script is shared to help. Use at your own discretion. I've being using it for months and works fine but I cannot
  72. // @note guarantee that the faucets won't ban your IP or account
  73. // @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  74.  
  75. // @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  76. // @note If you wanna team up or just share some ideas, you can contact me at satology@protonmail.com
  77. // @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  78.  
  79. // @grant GM_setValue
  80. // @grant GM_getValue
  81. // @grant window.close
  82. // @grant GM_openInTab
  83. // @icon https://www.google.com/s2/favicons?domain=stormgain.com
  84. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
  85. // @match https://satology.onrender.com/faucets/referrals*
  86. // @match https://app.stormgain.com/crypto-miner/
  87. // @match https://freecardano.com/*
  88. // @match https://freebinancecoin.com/*
  89. // @match https://freebitcoin.io/*
  90. // @match https://freedash.io/*
  91. // @match https://free-doge.com/*
  92. // @match https://freeethereum.com/*
  93. // @match https://freechainlink.io/*
  94. // @match https://free-ltc.com/*
  95. // @match https://freeneo.io/*
  96. // @match https://freesteam.io/*
  97. // @match https://free-tron.com/*
  98. // @match https://freeusdcoin.com/*
  99. // @match https://freetether.com/*
  100. // @match https://freenem.com/*
  101. // @match https://coinfaucet.io/*
  102. // @match https://freebitco.in/
  103. // @match https://faucetpay.io/ptc
  104. // @match https://faucetpay.io/ptc*
  105. // @match https://faucetpay.io/account/login
  106. // @match https://free-litecoin.com/*
  107. // @match https://www.free-ethereum.io/
  108. // @match https://www.free-ethereum.io/free/
  109. // @match https://bagi.co.in/*
  110. // @match https://keran.co/*
  111. // ==/UserScript==
  112.  
  113. (function() {
  114. 'use strict';
  115.  
  116. /**
  117. * Specific string values to check if a promotion code was succesfully processed (used via indexOf).
  118. * Defaults are set for English.
  119. * If you want to view the faucets in another language, you will need to change the following values
  120. */
  121. const localeConfig = {
  122. setToEnglish: true, // will set the faucets to English
  123. stringSearches: {
  124. promoCodeAccepted: 'roll',
  125. promoCodeUsed: 'already used',
  126. promoCodeInvalid: ['not found', 'only alphanumeric'],
  127. promoCodeExpired: ['ended']
  128. }
  129. };
  130.  
  131. const WebType = {
  132. CRYPTOSFAUCETS: 1,
  133. STORMGAIN: 2,
  134. FREEBITCOIN: 3,
  135. FAUCETPAY: 4,
  136. FREELITECOIN: 5,
  137. FREEETHEREUMIO: 6,
  138. BAGIKERAN: 7
  139. };
  140. const CFUrlType = {
  141. HOME: 0,
  142. FREE: 1,
  143. CONTACTTWITTER: 2,
  144. PROMOTION: 3,
  145. STATS: 4,
  146. SETTINGS: 5,
  147. FREEROLLS: 6,
  148. IGNORE: 99
  149. };
  150. const PromoStatus = {
  151. NOCODE: 0,
  152. PENDING: 1,
  153. ACCEPTED: 2,
  154. USEDBEFORE: 3,
  155. INVALID: 4,
  156. UNKNOWNERROR: 5,
  157. EXPIRED: 6
  158. };
  159. const RandomInteractionLevel = {
  160. NONE: 0,
  161. LOW: 1,
  162. MEDIUM: 2,
  163. HIGH: 3
  164. };
  165. const HS_26_IN_MILLISECONDS = 93600000; //Using 26 hs instead of 24hs
  166. const HS_2_IN_MILLISECONDS = 7200000; //and 2hs gap retry when code is flagged as USEDBEFORE
  167. const USE_DEFAULT = -1;
  168. const CFReusableCodesSuggestion = ['55khv20st4', '90nq6mcmz2', 'lytovoap04', 'vmuph8j0c6', 'ykxlvmg9ja', 'd8fmqxjlma', 'rjnmzjs673'];
  169. const WalletType = {
  170. FP_MAIL: 100,
  171. FP_BTC: 101,
  172. FP_BNB: 102,
  173. FP_BCH: 103,
  174. FP_DASH: 104,
  175. FP_DGB: 105,
  176. FP_DOGE: 106,
  177. FP_ETH: 107,
  178. FP_FEY: 108,
  179. FP_LTC: 109,
  180. FP_TRX: 110,
  181. FP_USDT: 111,
  182. FP_ZEC: 112
  183. };
  184.  
  185. let config = {
  186. defaults: {
  187. timeout: 4, // Use -1 to disable the timeout functionality. In minutes. Max time the monitor will wait for a result/roll.
  188. // After timeout is reached, the Manager/Monitor will assume something is wrong
  189. // (usually faucet tab being accidentally closed or failed to connect)
  190. postponeMinutes: 65, // Minutes to wait before retrying a faucet that timed out
  191. focusTab: false // If false the faucets will be opened in the background
  192. },
  193. cf: {
  194. autologin: false,
  195. credentials: {
  196. mode: 1, // POSSIBLE VALUES:
  197. // 1: Use email/password saved through the script
  198. // 2: Waits for the credentials to be added manually or by a third party software/extension.
  199. // Useful if you use different email/password combinations on each faucet
  200. email: 'YOUR@EMAIL.com',
  201. password: 'YOURPASSWORD'
  202. }
  203. },
  204. fb: { // FreeBitco.in
  205. activateRPBonus: false // will try to activate the highest RP Roll Bonus available for the account (100, 50 25, ... points per roll),
  206. },
  207. fp: { // FaucetPay.io
  208. hoursBetweenRuns: 5 // how many hours to wait between each FaucetPay PTC run
  209. },
  210. bagikeran: { // Bagi.co.in & keran.co
  211. withdrawMode: 1, // POSSIBLE VALUES:
  212. // 0: Disables auto withdraw
  213. // 1: Withdraws once every 'hoursBetweenWithdraws' hours
  214. // 2: Withdraw after each successful claim
  215. hoursBetweenWithdraws: 6
  216. }
  217. }
  218.  
  219. // let persistence, shared, manager, ui, CFPromotions, interactions, SGProcessor, CFProcessor, CFHistory, FBProcessor, FPProcessor, FreeLitecoinProcessor, FreeGenericFaucetProcessor;
  220. let persistence, shared, manager, ui, CFPromotions, interactions, CFHistory, SiteProcessor;
  221.  
  222. let helpers = {
  223. cleanString: function(input) {
  224. var output = "";
  225. for (var i=0; i<input.length; i++) {
  226. if (input.charCodeAt(i) <= 127) {
  227. output += input.charAt(i);
  228. }
  229. }
  230. return output;
  231. },
  232. shuffle: function (array) {
  233. let currentIndex = array.length, temporaryValue, randomIndex;
  234.  
  235. while (0 !== currentIndex) {
  236. randomIndex = Math.floor(Math.random() * currentIndex);
  237. currentIndex -= 1;
  238. temporaryValue = array[currentIndex];
  239. array[currentIndex] = array[randomIndex];
  240. array[randomIndex] = temporaryValue;
  241. }
  242.  
  243. return array;
  244. },
  245. getPrintableTime: function (date = new Date()) {
  246. if (date == null) {
  247. return '';
  248. }
  249. return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2);
  250. },
  251. getPrintableDateTime: function (date) {
  252. if (date != null) {
  253. return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
  254. } else {
  255. return '';
  256. }
  257. },
  258. getEnumText: function (enm, value) {
  259. return Object.keys(enm).find(key => enm[key] === value);
  260. },
  261. randomMs: function (a, b){
  262. return a + (b - a) * Math.random();
  263. },
  264. addMinutes: function(date, mins) {
  265. return date.setMinutes(date.getMinutes() + parseInt(mins) + 1);
  266. },
  267. randomInt: function(min, max) {
  268. return Math.floor(Math.random() * (max - min + 1) + min);
  269. },
  270. addMilliseconds: function(date, ms) {
  271. return date.setMilliseconds(date.getMilliseconds() + ms);
  272. },
  273. getRandomMillisecondsFromMinutesRange(minute, rangeDiffInPercentage) {
  274. const msCenter = minute * 60 * 1000;
  275. const msRangeDiff = Math.round(msCenter * rangeDiffInPercentage / 100);
  276. return helpers.randomMs(msCenter - msRangeDiff, msCenter + msRangeDiff);
  277. },
  278. hsToMs: function(hours) {
  279. return hours * 60 * 60 * 1000;
  280. },
  281. minToMs: function(min) {
  282. return min * 60 * 1000;
  283. },
  284. getEmojiForPromoStatus: function(promoStatus) {
  285. switch (promoStatus) {
  286. case PromoStatus.NOCODE:
  287. return '⚪';
  288. break;
  289. case PromoStatus.PENDING:
  290. return '⏳';
  291. break;
  292. case PromoStatus.ACCEPTED:
  293. return '✔️';
  294. break;
  295. case PromoStatus.USEDBEFORE:
  296. return '🕙';
  297. break;
  298. case PromoStatus.INVALID:
  299. return '❌';
  300. break;
  301. case PromoStatus.EXPIRED:
  302. return '📅';
  303. break;
  304. case PromoStatus.UNKNOWNERROR:
  305. return '❗';
  306. break;
  307. }
  308. },
  309. getHost: function(url, withHttps = false) {
  310. if (url.includes('//')) {
  311. url = url.split('//')[1];
  312. }
  313. url = url.split('/')[0];
  314. return withHttps ? ('https://' + url) : url;
  315. },
  316. cf: {
  317. getUrlType: function(url) {
  318. if (url.endsWith('/free')) {
  319. return CFUrlType.FREE;
  320. }
  321. if (url.includes('/promotion/')) {
  322. return CFUrlType.PROMOTION;
  323. }
  324. if (url.endsWith('/contact-twitter')) {
  325. return CFUrlType.CONTACTTWITTER;
  326. }
  327. if (url.endsWith('/free-rolls')) {
  328. return CFUrlType.FREEROLLS;
  329. }
  330. if (url.endsWith('/settings')) {
  331. return CFUrlType.SETTINGS;
  332. }
  333. if (url.endsWith('/stats')) {
  334. return CFUrlType.STATS;
  335. }
  336. if (url.endsWith('/')) {
  337. url = url.slice(0, -1);
  338. if (url == helpers.getHost(url, true)) {
  339. return CFUrlType.HOME;
  340. }
  341. }
  342.  
  343. return CFUrlType.IGNORE;
  344. }
  345. }
  346. }
  347.  
  348.  
  349. let objectGenerator = {
  350. createPersistence: function() {
  351. const prefix = 'autoWeb_';
  352. function save(key, value, parseIt = false) {
  353. GM_setValue(prefix + key, parseIt ? JSON.stringify(value) : value);
  354. };
  355. function load(key, parseIt = false) {
  356. let value = GM_getValue(prefix + key);
  357. if(value && parseIt) {
  358. value = JSON.parse(value);
  359. }
  360. return value;
  361. };
  362. return {
  363. save: save,
  364. load: load
  365. };
  366. },
  367. createShared: function() {
  368. let flowControl;
  369. function devlog(value) {
  370. let log;
  371. if(value) {
  372. log = persistence.load('devlog', true);
  373. log = log ?? [];
  374. log.push(value);
  375. } else {
  376. log = [];
  377. }
  378. persistence.save('devlog', log, true);
  379. };
  380. function isOpenedByManager(currentHost) {
  381. loadFlowControl();
  382. if(!flowControl) {
  383. return false;
  384. }
  385. let millisecondsDistance = new Date() - flowControl.requestedTime;
  386.  
  387. if((flowControl.type != WebType.FAUCETPAY && flowControl.type != WebType.BAGIKERAN && flowControl.opened) || (flowControl.host != currentHost && !flowControl.expectedHosts.includes(currentHost)) || millisecondsDistance > 120000) {
  388. return false;
  389. }
  390. return true;
  391. };
  392. function setFlowControl(id, url, webType, expectedHosts, params = null) {
  393. flowControl = {
  394. id: id,
  395. url: url,
  396. host: url.host,
  397. type: webType,
  398. requestedTime: new Date(),
  399. opened: false,
  400. expectedHosts: expectedHosts,
  401. error: false,
  402. result: {}
  403. };
  404. if(params) {
  405. flowControl.params = params;
  406. }
  407. persistence.save('flowControl', flowControl, true);
  408. };
  409. function wasVisited(expectedId) {
  410. loadFlowControl();
  411. return flowControl.id == expectedId && flowControl.opened;
  412. };
  413. function hasErrors(expectedId) {
  414. return flowControl.id == expectedId && flowControl.error;
  415. };
  416. function getResult() {
  417. return flowControl.result;
  418. };
  419. function getCurrent() {
  420. let current = {};
  421. current.url = flowControl.url;
  422. current.host = flowControl.host;
  423. current.type = flowControl.type;
  424. if(flowControl.params) {
  425. current.params = flowControl.params;
  426. }
  427.  
  428. return current;
  429. };
  430. function saveAndclose(runDetails, delay = 0) {
  431. markAsVisited(runDetails);
  432. if(delay) {
  433. setTimeout(window.close, delay);
  434. } else {
  435. window.close();
  436. }
  437. };
  438. function loadFlowControl() {
  439. flowControl = persistence.load('flowControl', true);
  440. };
  441. function markAsVisited(runDetails) {
  442. flowControl.opened = true;
  443. flowControl.result = runDetails;
  444. persistence.save('flowControl', flowControl, true);
  445. };
  446. function closeWithError(errorType, errorMessage) {
  447. flowControl.error = true;
  448.  
  449. flowControl.result.errorType = errorType;
  450. flowControl.result.errorMessage = errorMessage;
  451.  
  452. persistence.save('flowControl', flowControl, true);
  453. window.close();
  454. };
  455. function clearFlowControl() {
  456. flowControl = {};
  457. persistence.save('flowControl', flowControl, true);
  458. };
  459. return {
  460. devlog: devlog,
  461. setFlowControl: setFlowControl,
  462. wasVisited: wasVisited,
  463. isOpenedByManager: isOpenedByManager,
  464. getCurrent: getCurrent,
  465. getResult: getResult,
  466. closeWindow: saveAndclose,
  467. closeWithError: closeWithError,
  468. updateWithoutClosing: markAsVisited,
  469. hasErrors: hasErrors,
  470. clearFlowControl: clearFlowControl
  471. };
  472. },
  473. createManager: function() {
  474. const STATUS = {
  475. INITIALIZING: 0,
  476. IDLE: 1,
  477. CLAIMING: 2
  478. };
  479.  
  480. let timestamp = null;
  481. let timeWaiting = 0;
  482. let uiUpdatesInterval;
  483. let status = STATUS.INITIALIZING;
  484. let processTimer;
  485. let workingTab;
  486.  
  487. let webList = [];
  488. let userWallet = [];
  489.  
  490. const sites = [
  491. { id: '1', name: 'CF ADA', cmc: '2010', coinRef: 'ADA', url: new URL('https://freecardano.com/free'), rf: '?ref=335463', type: WebType.CRYPTOSFAUCETS },
  492. { id: '2', name: 'CF BNB', cmc: '1839', coinRef: 'BNB', url: new URL('https://freebinancecoin.com/free'), rf: '?ref=161127', type: WebType.CRYPTOSFAUCETS },
  493. { id: '3', name: 'CF BTC', cmc: '1', coinRef: 'BTC', url: new URL('https://freebitcoin.io/free'), rf: '?ref=490252', type: WebType.CRYPTOSFAUCETS },
  494. { id: '4', name: 'CF DASH', cmc: '131', coinRef: 'DASH', url: new URL('https://freedash.io/free'), rf: '?ref=124083', type: WebType.CRYPTOSFAUCETS },
  495. { id: '5', name: 'CF ETH', cmc: '1027', coinRef: 'ETH', url: new URL('https://freeethereum.com/free'), rf: '?ref=204076', type: WebType.CRYPTOSFAUCETS },
  496. { id: '6', name: 'CF LINK', cmc: '1975', coinRef: 'LINK', url: new URL('https://freechainlink.io/free'), rf: '?ref=78652', type: WebType.CRYPTOSFAUCETS },
  497. { id: '7', name: 'CF LTC', cmc: '2', coinRef: 'LTC', url: new URL('https://free-ltc.com/free'), rf: '?ref=117042', type: WebType.CRYPTOSFAUCETS },
  498. { id: '8', name: 'CF NEO', cmc: '1376', coinRef: 'NEO', url: new URL('https://freeneo.io/free'), rf: '?ref=100529', type: WebType.CRYPTOSFAUCETS },
  499. { id: '9', name: 'CF STEAM', cmc: '1230', coinRef: 'STEEM', url: new URL('https://freesteam.io/free'), rf: '?ref=117686', type: WebType.CRYPTOSFAUCETS },
  500. { id: '10', name: 'CF TRX', cmc: '1958', coinRef: 'TRX', url: new URL('https://free-tron.com/free'), rf: '?ref=145047', type: WebType.CRYPTOSFAUCETS },
  501. { id: '11', name: 'CF USDC', cmc: '3408', coinRef: 'USDC', url: new URL('https://freeusdcoin.com/free'), rf: '?ref=100434', type: WebType.CRYPTOSFAUCETS },
  502. { id: '12', name: 'CF USDT', cmc: '825', coinRef: 'USDT', url: new URL('https://freetether.com/free'), rf: '?ref=181230', type: WebType.CRYPTOSFAUCETS },
  503. { id: '13', name: 'CF XEM', cmc: '873', coinRef: 'XEM', url: new URL('https://freenem.com/free'), rf: '?ref=295274', type: WebType.CRYPTOSFAUCETS },
  504. { id: '14', name: 'CF XRP', cmc: '52', coinRef: 'XRP', url: new URL('https://coinfaucet.io/free'), rf: '?ref=808298', type: WebType.CRYPTOSFAUCETS },
  505. { id: '15', name: 'StormGain', cmc: '1', url: new URL('https://app.stormgain.com/crypto-miner/'), rf: 'friend/BNS27140552', type: WebType.STORMGAIN },
  506. { id: '16', name: 'CF DOGE', cmc: '74', coinRef: 'DOGE', url: new URL('https://free-doge.com/free'), rf: '?ref=97166', type: WebType.CRYPTOSFAUCETS },
  507. { id: '17', name: 'FreeBitco.in', cmc: '1', url: new URL('https://freebitco.in/'), rf: '?r=41092365', type: WebType.FREEBITCOIN },
  508. { id: '18', name: 'FaucetPay PTC', cmc: '1', url: new URL('https://faucetpay.io/ptc'), rf: '?r=41092365', type: WebType.FAUCETPAY },
  509. { id: '19', name: 'Free-Litecoin.com', cmc: '2', url: new URL('https://free-litecoin.com/'), rf: 'login?referer=1332950', type: WebType.FREELITECOIN },
  510. { id: '20', name: 'Free-Ethereum.io', cmc: '1027', url: new URL('https://www.free-ethereum.io/'), rf: '?referer=1064662', type: WebType.FREEETHEREUMIO },
  511. { id: '21', name: 'Bagi BTC', cmc: '1', wallet: WalletType.FP_BTC, url: new URL('https://bagi.co.in/bitcoin/'), rf: ['?ref=53706', '?ref=63428', '?ref=54350'], type: WebType.BAGIKERAN },
  512. { id: '22', name: 'Bagi BNB', cmc: '1839', wallet: WalletType.FP_BNB, url: new URL('https://bagi.co.in/binance/'), rf: ['?ref=12529', '?ref=23852', 'ref=13847'], type: WebType.BAGIKERAN },
  513. { id: '23', name: 'Bagi BCH', cmc: '1831', wallet: WalletType.FP_BCH, url: new URL('https://bagi.co.in/bitcoincash/'), rf: ['?ref=44242', '?ref=50185', '?ref=41957'], type: WebType.BAGIKERAN },
  514. { id: '24', name: 'Bagi DASH', cmc: '131', wallet: WalletType.FP_DASH, url: new URL('https://bagi.co.in/dash/'), rf: ['?ref=32724', '?ref=38540', 'ref=40441'], type: WebType.BAGIKERAN },
  515. { id: '25', name: 'Bagi DGB', cmc: '109', wallet: WalletType.FP_DGB, url: new URL('https://bagi.co.in/digibyte/'), rf: ['?ref=22664', '?ref=27872', 'ref=29669'], type: WebType.BAGIKERAN },
  516. { id: '26', name: 'Bagi DOGE', cmc: '74', wallet: WalletType.FP_DOGE, url: new URL('https://bagi.co.in/dogecoin/'), rf: ['?ref=45047', '?ref=54217', '?ref=45568'], type: WebType.BAGIKERAN },
  517. { id: '27', name: 'Bagi ETH', cmc: '1027', wallet: WalletType.FP_ETH, url: new URL('https://bagi.co.in/ethereum/'), rf: ['?ref=24486', '?ref=27799', '?ref=24847'], type: WebType.BAGIKERAN },
  518. { id: '28', name: 'Bagi FEY', cmc: '10361', wallet: WalletType.FP_FEY, url: new URL('https://bagi.co.in/feyorra/'), rf: ['?ref=5049', '?ref=7433', 'ref=5318'], type: WebType.BAGIKERAN },
  519. { id: '29', name: 'Bagi LTC', cmc: '2', wallet: WalletType.FP_LTC, url: new URL('https://bagi.co.in/litecoin/'), rf: ['?ref=48335', '?ref=57196', '?ref=48878'], type: WebType.BAGIKERAN },
  520. { id: '30', name: 'Bagi TRX', cmc: '1958', wallet: WalletType.FP_TRX, url: new URL('https://bagi.co.in/tron/'), rf: ['?ref=22622', '?ref=31272', '?ref=23075'], type: WebType.BAGIKERAN },
  521. { id: '31', name: 'Bagi USDT', cmc: '825', wallet: WalletType.FP_USDT, url: new URL('https://bagi.co.in/tether/'), rf: ['?ref=25462', '?ref=32491', '?ref=25981'], type: WebType.BAGIKERAN },
  522. { id: '32', name: 'Bagi ZEC', cmc: '1437', wallet: WalletType.FP_ZEC, url: new URL('https://bagi.co.in/zcash/'), rf: ['?ref=9181', '?ref=15120', 'ref=9878'], type: WebType.BAGIKERAN },
  523. { id: '33', name: 'Keran BTC', cmc: '1', wallet: WalletType.FP_BTC, url: new URL('https://keran.co/BTC/'), rf: ['?ref=73729', '?ref=92353', '?ref=79321'], type: WebType.BAGIKERAN },
  524. { id: '34', name: 'Keran BNB', cmc: '1839', wallet: WalletType.FP_BNB, url: new URL('https://keran.co/BNB/'), rf: ['?ref=19287', '?ref=31242', 'ref=20659'], type: WebType.BAGIKERAN },
  525. { id: '35', name: 'Keran BCH', cmc: '1831', wallet: WalletType.FP_BCH, url: new URL('https://keran.co/BCH/'), rf: ['?ref=58232', '?ref=67326', 'ref=70759'], type: WebType.BAGIKERAN },
  526. { id: '36', name: 'Keran DASH', cmc: '131', wallet: WalletType.FP_DASH, url: new URL('https://keran.co/DASH/'), rf: ['?ref=45229', '?ref=53041', 'ref=55716'], type: WebType.BAGIKERAN },
  527. { id: '37', name: 'Keran DGB', cmc: '109', wallet: WalletType.FP_DGB, url: new URL('https://keran.co/DGB/'), rf: ['?ref=32788', '?ref=39527', 'ref=42014'], type: WebType.BAGIKERAN },
  528. { id: '38', name: 'Keran DOGE', cmc: '74', wallet: WalletType.FP_DOGE, url: new URL('https://keran.co/DOGE/'), rf: ['?ref=73512', '?ref=85779', 'ref=89613'], type: WebType.BAGIKERAN },
  529. { id: '39', name: 'Keran ETH', cmc: '1027', wallet: WalletType.FP_ETH, url: new URL('https://keran.co/ETH/'), rf: ['?ref=32226', '?ref=36427', 'ref=32676'], type: WebType.BAGIKERAN },
  530. { id: '40', name: 'Keran FEY', cmc: '10361', wallet: WalletType.FP_FEY, url: new URL('https://keran.co/FEY/'), rf: ['?ref=6269', '?ref=9019', 'ref=6569'], type: WebType.BAGIKERAN },
  531. { id: '41', name: 'Keran LTC', cmc: '2', wallet: WalletType.FP_LTC, url: new URL('https://keran.co/LTC/'), rf: ['?ref=69102', '?ref=80726', 'ref=84722'], type: WebType.BAGIKERAN },
  532. { id: '42', name: 'Keran TRX', cmc: '1958', wallet: WalletType.FP_TRX, url: new URL('https://keran.co/TRX/'), rf: ['?ref=49686', '?ref=46544', '?ref=34485'], type: WebType.BAGIKERAN },
  533. { id: '43', name: 'Keran USDT', cmc: '825', wallet: WalletType.FP_USDT, url: new URL('https://keran.co/USDT/'), rf: ['?ref=40582', '?ref=48907', '?ref=41009'], type: WebType.BAGIKERAN },
  534. { id: '44', name: 'Keran ZEC', cmc: '1437', wallet: WalletType.FP_ZEC, url: new URL('https://keran.co/ZEC/'), rf: ['?ref=11748', '?ref=18976', 'ref=12487'], type: WebType.BAGIKERAN }
  535. ];
  536.  
  537. const wallet = [
  538. { id: '101', name: 'FaucetPay BTC (Bitcoin)', type: WalletType.FP_BTC },
  539. { id: '102', name: 'FaucetPay BNB (Binance Coin)', type: WalletType.FP_BNB },
  540. { id: '103', name: 'FaucetPay BCH (Bitcoin Cash)', type: WalletType.FP_BCH },
  541. { id: '104', name: 'FaucetPay DASH (Dash)', type: WalletType.FP_DASH },
  542. { id: '105', name: 'FaucetPay DGB (DigiByte)', type: WalletType.FP_DGB },
  543. { id: '106', name: 'FaucetPay DOGE (Dogecoin)', type: WalletType.FP_DOGE },
  544. { id: '107', name: 'FaucetPay ETH (Ethereum)', type: WalletType.FP_ETH },
  545. { id: '108', name: 'FaucetPay FEY (Feyorra)', type: WalletType.FP_FEY },
  546. { id: '109', name: 'FaucetPay LTC (Litecoin)', type: WalletType.FP_LTC },
  547. { id: '110', name: 'FaucetPay TRX (Tron)', type: WalletType.FP_TRX },
  548. { id: '111', name: 'FaucetPay USDT (Tether TRC20)', type: WalletType.FP_USDT },
  549. { id: '112', name: 'FaucetPay ZEC (Zcash)', type: WalletType.FP_ZEC }
  550. ];
  551.  
  552. function start() {
  553. loader.initialize();
  554. ui.init(getCFlist());
  555. update();
  556. ui.refresh(null, null, userWallet);
  557. uiUpdatesInterval = setInterval(readUpdateValues, 10000);
  558. processTimer = setTimeout(manager.process, 2000);
  559. };
  560. let loader = function() {
  561. function initialize() {
  562. setTimestamp();
  563. initializeWebList();
  564. initializeUserWallet();
  565. initializePromotions();
  566. initializeHistory();
  567. };
  568. function initializeWebList() {
  569. addSites();
  570. addStoredSitesData();
  571. };
  572. function addSites() {
  573. sites.forEach(x => webList.push(x));
  574. webList.forEach(function (element, idx, arr) {
  575. arr[idx].enabled = false;
  576. arr[idx].lastClaim = 0;
  577. arr[idx].aggregate = 0;
  578. arr[idx].balance = 0;
  579. arr[idx].stats = {};
  580. arr[idx].nextRoll = null;
  581. arr[idx].focusTab = (element.id == '18' ? true : USE_DEFAULT);
  582. if(arr[idx].type == WebType.BAGIKERAN) {
  583. arr[idx].lastWithdraw = new Date();
  584. }
  585. });
  586. };
  587. function addStoredSitesData() {
  588. let storedData = persistence.load('webList', true);
  589. if(storedData) {
  590. storedData.forEach( function (element) {
  591. let idx = webList.findIndex(x => x.id == element.id);
  592. if(idx != -1) {
  593. webList[idx].name = element.name ?? webList[idx].name;
  594. webList[idx].lastClaim = element.lastClaim ?? webList[idx].lastClaim;
  595. webList[idx].aggregate = element.aggregate ?? webList[idx].aggregate;
  596. webList[idx].balance = element.balance ?? webList[idx].balance;
  597. webList[idx].stats = element.stats ?? webList[idx].stats;
  598. webList[idx].enabled = element.enabled ?? webList[idx].enabled;
  599. if(!webList[idx].enabled) {
  600. webList[idx].nextRoll = null;
  601. } else {
  602. webList[idx].nextRoll = element.nextRoll ? new Date(element.nextRoll) : new Date();
  603. }
  604. if(element.lastWithdraw) {
  605. webList[idx].lastWithdraw = new Date(element.lastWithdraw);
  606. }
  607. //webList[idx].focusTab = element.focusTab ?? webList[idx].focusTab;
  608. }
  609. });
  610. } else {
  611. // helpers.shuffle(webList);
  612. }
  613. };
  614. function initializeUserWallet() {
  615. addWallets();
  616. addStoredWalletData();
  617. };
  618. function addWallets() {
  619. wallet.forEach(x => userWallet.push(x));
  620. userWallet.forEach(function (element, idx, arr) {
  621. arr[idx].address = 'TK3ofbD3AyXotN2111UvnwCzr2YaW8Qmx7';
  622. });
  623. };
  624. function addStoredWalletData() {
  625. let storedData = persistence.load('userWallet', true);
  626. if(storedData) {
  627. storedData.forEach( function (element) {
  628. let idx = userWallet.findIndex(x => x.id == element.id);
  629. if(idx != -1) {
  630. userWallet[idx].address = element.address ?? webList[idx].address;
  631. }
  632. });
  633. }
  634. };
  635. function initializePromotions() {
  636. let storedData = persistence.load('CFPromotions', true);
  637. if (storedData) {
  638. storedData.forEach( function (element, idx, arr) {
  639. arr[idx].added = new Date(element.added);
  640. arr[idx].statusPerFaucet.forEach( function (el, i, a) {
  641. a[i].execTimeStamp = (el.execTimeStamp != null) ? new Date(el.execTimeStamp) : null;
  642. });
  643. });
  644. CFPromotions.load(storedData);
  645. }
  646. };
  647. function initializeHistory() {
  648. CFHistory.initOrLoad();
  649. };
  650. function setTimestamp() {
  651. timestamp = new Date().getTime();
  652. persistence.save('timestamp', timestamp);
  653. };
  654. function removeDisabledFaucets() {
  655. webList = webList.filter(x => x.enabled);
  656. };
  657. return {
  658. initialize: initialize
  659. };
  660. }();
  661. function readUpdateValues(forceCheck = false) {
  662. readPromoCodeValues();
  663.  
  664. if(status == STATUS.IDLE || forceCheck) {
  665. let updateDataElement = $('#update-data')[0];
  666. let updateValues = helpers.cleanString(updateDataElement.innerText);
  667.  
  668. if (updateValues != '') {
  669. updateDataElement.innerText = '';
  670. let updateObj = JSON.parse(updateValues);
  671. if(updateObj.runAsap.changed) {
  672. updateObj.runAsap.ids.forEach(function (element, idx, arr) {
  673. try {
  674. let itemIndex = webList.findIndex(x => x.id == element)
  675. webList[itemIndex].enabled = true;
  676. webList[itemIndex].nextRoll = new Date(754000 + idx);
  677. ui.log(`${webList[itemIndex].name} updated to run ASAP`);
  678. } catch (err) {
  679. ui.log(`Error setting faucet to run ASAP: ${err}`);
  680. }
  681. });
  682. }
  683. if(updateObj.editSingle.changed) {
  684. updateObj.editSingle.items.forEach(function (element, idx, arr) {
  685. try {
  686. let itemIndex = webList.findIndex(x => x.id == element.id);
  687. webList[itemIndex].name = element.displayName;
  688.  
  689. if (webList[itemIndex].enabled != element.enabled) {
  690. webList[itemIndex].enabled = element.enabled;
  691. if(webList[itemIndex].enabled) {
  692. webList[itemIndex].nextRoll = new Date(idx);
  693. } else {
  694. webList[itemIndex].nextRoll = null;
  695. }
  696. }
  697. ui.log(`Faucet updated. New name: ${element.displayName}. Active: ${element.enabled}`);
  698. } catch (err) {
  699. ui.log(`Error updating faucet data: ${err}`);
  700. }
  701. });
  702. }
  703.  
  704. if(updateObj.wallet.changed) {
  705. updateObj.wallet.items.forEach(function (element, idx, arr) {
  706. try {
  707. let itemIndex = userWallet.findIndex(x => x.id == element.id);
  708. userWallet[itemIndex].address = element.address;
  709.  
  710. ui.log(`Wallet Address updated [${userWallet[itemIndex].name}]: ${userWallet[itemIndex].address}`);
  711. } catch (err) {
  712. ui.log(`Error updating wallet/address: ${err}`);
  713. }
  714. });
  715. $('#faucets-display-status')[0].innerHTML = '';
  716. ui.refresh(null, null, userWallet);
  717. saveUserWallet();
  718. }
  719.  
  720. if(updateObj.runAsap.changed || updateObj.editSingle.changed) {
  721. $('#faucets-display-status')[0].innerHTML = '';
  722. update(true);
  723. process();
  724. return;
  725. }
  726. }
  727. }
  728. if(forceCheck) {
  729. process();
  730. }
  731. };
  732. function update(sortIt = true) {
  733. let updateRollStats = webList[0].type == WebType.CRYPTOSFAUCETS;
  734. if(sortIt) {
  735. webList.sort( function(a,b) {
  736. if (a === b) {
  737. return 0;
  738. } else if (a.nextRoll === null) {
  739. return 1;
  740. } else if (b.nextRoll === null) {
  741. return -1;
  742. } else {
  743. return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
  744. }
  745. });
  746. }
  747.  
  748. saveWebList();
  749. ui.refresh(webList, CFPromotions.getAll());
  750. if(updateRollStats) {
  751. updateRollStatsSpan();
  752. }
  753. };
  754. function saveWebList() {
  755. const data = webList.map(function(x) {
  756. let ret = {
  757. id: x.id,
  758. name: x.name,
  759. lastClaim: x.lastClaim,
  760. aggregate: x.aggregate,
  761. balance: x.balance,
  762. stats: x.stats,
  763. nextRoll: x.nextRoll,
  764. enabled: x.enabled
  765. };
  766.  
  767. if (x.lastWithdraw) {
  768. ret.lastWithdraw = x.lastWithdraw;
  769. }
  770.  
  771. return ret;
  772. });
  773.  
  774. persistence.save('webList', data, true);
  775. }
  776. function saveUserWallet() {
  777. const data = userWallet.map(x => {
  778. return {
  779. id: x.id,
  780. address: x.address
  781. };});
  782.  
  783. persistence.save('userWallet', data, true);
  784. }
  785. function process() {
  786. if(isObsolete()) {
  787. return;
  788. }
  789. if(webList[0].nextRoll == null) {
  790. ui.log(`All faucets are disabled. Click edit and select those you want to run...`);
  791. clearTimeout(processTimer);
  792. status = STATUS.IDLE;
  793. return;
  794. }
  795.  
  796. if(webList[0].nextRoll.getTime() < (new Date()).getTime()) {
  797. ui.log(`Opening ${webList[0].name}`);
  798. clearTimeout(processTimer);
  799. status = STATUS.CLAIMING;
  800. open();
  801. } else {
  802. let timeUntilNext = webList[0].nextRoll.getTime() - (new Date()).getTime() + helpers.randomMs(1000, 2000);
  803. ui.log(`Waiting ${(timeUntilNext/1000/60).toFixed(2)} minutes...`);
  804. clearTimeout(processTimer);
  805. processTimer = setTimeout(manager.process, timeUntilNext);
  806. status = STATUS.IDLE;
  807. }
  808. };
  809. function isObsolete() {
  810. let savedTimestamp = persistence.load('timestamp');
  811. if (savedTimestamp && savedTimestamp > timestamp) {
  812. ui.log('<b>STOPING EXECUTION!<b> A new Manager UI window was opened. Process should continue there');
  813. clearInterval(uiUpdatesInterval);
  814. return true;
  815. }
  816. return false;
  817. };
  818. function open(promoCode) {
  819. let navUrl = webList[0].url;
  820. try {
  821. if(promoCode) {
  822. navUrl = new URL('promotion/' + promoCode, webList[0].url.origin);
  823. ui.log(`Opening ${webList[0].name} with Promo Code [${promoCode}]`);
  824. }
  825.  
  826. if(Array.isArray(webList[0].rf)) {
  827. navUrl = new URL(navUrl.href + webList[0].rf[helpers.randomInt(0, webList[0].rf.length - 1)]);
  828. }
  829.  
  830. let expectedHosts = [];
  831. expectedHosts.push(navUrl.host);
  832. if(webList[0].type == WebType.STORMGAIN) {
  833. expectedHosts.push((new URL('https://www.google.com').host));
  834. expectedHosts.push((new URL('https://www.recaptcha.net').host));
  835. }
  836.  
  837. let params = {};
  838. if(webList[0].type == WebType.BAGIKERAN) {
  839. //TODO: VALIDATE THAT ADDRESS EXISTS AND IS VALID!!!
  840. try {
  841. params.address = userWallet.find(x => x.type == webList[0].wallet).address;
  842. } catch {
  843. params.address = '123'; //not available @ wallet
  844. }
  845. params.doWithdraw = getDoWithdraw(webList[0].lastWithdraw);
  846. }
  847.  
  848. shared.setFlowControl(webList[0].id, navUrl, webList[0].type, expectedHosts, params);
  849. setTimeout(manager.resultReader, 15000);
  850.  
  851. // Try to close old workingTab if still opened
  852. if (workingTab && !workingTab.closed) {
  853. try {
  854. workingTab.close();
  855. } catch { }
  856. }
  857.  
  858. workingTab = GM_openInTab(navUrl.href, { active: ((!webList[0].focusTab || webList[0].focusTab == USE_DEFAULT) ? config.defaults.focusTab : webList[0].focusTab) });
  859. } catch(err) {
  860. ui.log(`Error opening tab: ${err}`)
  861. }
  862. };
  863.  
  864. function getDoWithdraw(lastWithdraw) {
  865. switch (config.bagikeran.withdrawMode) {
  866. case 0:
  867. return false;
  868. break;
  869. case 2:
  870. return true;
  871. break;
  872. case 1:
  873. if(lastWithdraw == null) {
  874. return true;
  875. }
  876. return (lastWithdraw && ( (Date.now() - lastWithdraw.getTime()) > helpers.hsToMs(config.bagikeran.hoursBetweenWithdraws)))
  877. break;
  878. default:
  879. return false;
  880. }
  881. return false;
  882. }
  883.  
  884. // REFACTOR
  885. function resultReader() {
  886. if(isObsolete()) {
  887. return;
  888. }
  889.  
  890. if (webList[0].type == WebType.FAUCETPAY && workingTab && !workingTab.closed) {
  891. timeWaiting += 15;
  892. ui.log(`Waiting for ${webList[0].name} results...`, timeWaiting);
  893. setTimeout(manager.resultReader, 15000);
  894. return;
  895. }
  896.  
  897. if(shared.wasVisited(webList[0].id)) {
  898.  
  899. let result = shared.getResult();
  900.  
  901. if (result) {
  902. updateWebListItem(result);
  903.  
  904. if ( (webList[0].type == WebType.CRYPTOSFAUCETS) &&
  905. ( (result.claimed) || (result.promoStatus && result.promoStatus != PromoStatus.ACCEPTED) )) {
  906. let promoCode = CFPromotions.hasPromoAvailable(webList[0].id);
  907. if (promoCode) {
  908. timeWaiting = 0;
  909. update(false);
  910. open(promoCode);
  911. return;
  912. }
  913. }
  914.  
  915. if ( webList[0].type == WebType.BAGIKERAN && shared.getCurrent().params.doWithdraw && !result.withdrawnAmount) {
  916. if(!result.withdrawing) {
  917. shared.updateWithoutClosing({ withdrawing: true });
  918. update(false);
  919. timeWaiting = 0;
  920. }
  921. timeWaiting += 15;
  922. ui.log(`Waiting for ${webList[0].name} withdraw...`, timeWaiting);
  923. setTimeout(manager.resultReader, 15000);
  924. return;
  925. }
  926. } else {
  927. ui.log(`Unable to read last run result, for ID: ${webList[0].id} > ${webList[0].name}`);
  928. }
  929.  
  930. timeWaiting = 0;
  931. update(true);
  932. readUpdateValues(true);
  933. return;
  934. } else {
  935. timeWaiting += 15;
  936. if (!shared.hasErrors(webList[0].id) && !hasTimedOut()) {
  937. ui.log(`Waiting for ${webList[0].name} results...`, timeWaiting);
  938. setTimeout(manager.resultReader, 15000);
  939. return;
  940. }
  941.  
  942. if (shared.hasErrors(webList[0].id)) {
  943. webList[0].stats.errors = shared.getResult();
  944. ui.log(`${webList[0].name} closed with error: ${webList[0].stats.errors.errorType} ${webList[0].stats.errors.errorMessage}`);
  945. }
  946.  
  947. if (hasTimedOut()) {
  948. if(webList[0].stats.countTimeouts) {
  949. webList[0].stats.countTimeouts += 1;
  950. } else {
  951. webList[0].stats.countTimeouts = 1;
  952. }
  953.  
  954. ui.log(`Waited too much time for ${webList[0].name} results: triggering timeout`);
  955. }
  956.  
  957. let millisecondsDelay = helpers.getRandomMillisecondsFromMinutesRange(config.defaults.postponeMinutes, 5);
  958. webList[0].nextRoll = new Date(helpers.addMilliseconds(new Date(), millisecondsDelay));
  959. shared.clearFlowControl();
  960. update(true);
  961.  
  962. timeWaiting = 0;
  963. readUpdateValues(true);
  964. return;
  965. }
  966. };
  967.  
  968. function hasTimedOut() {
  969. return config.defaults.timeout != -1 && (timeWaiting > (config.defaults.timeout * 60));
  970. };
  971.  
  972. function updateWebListItem(result) {
  973. if (result.withdrawing) {
  974. return;
  975. }
  976.  
  977. ui.log(`Updating data: ${JSON.stringify(result)}`);
  978. webList[0].stats.countTimeouts = 0;
  979. webList[0].stats.errors = null;
  980.  
  981. if (result.withdrawnAmount && result.withdrawnAmount > 0) {
  982. webList[0].lastWithdraw = new Date();
  983. webList[0].balance += result.withdrawnAmount;
  984. webList[0].lastClaim = 0;
  985. webList[0].aggregate = 0;
  986. return;
  987. }
  988.  
  989. if (result.claimed) {
  990. try {
  991. result.claimed = parseFloat(result.claimed);
  992. } catch { }
  993. if(!isNaN(result.claimed)) {
  994. webList[0].lastClaim = result.claimed;
  995. webList[0].aggregate += result.claimed;
  996. }
  997. }
  998. if(result.balance) {
  999. webList[0].balance = result.balance;
  1000. }
  1001. if(result.nextRoll) {
  1002. webList[0].nextRoll = new Date(result.nextRoll);
  1003. }
  1004. if(result.promoStatus) {
  1005. CFPromotions.updateFaucetForCode(result.promoCode, webList[0].id, result.promoStatus);
  1006. }
  1007. if(result.rolledNumber) {
  1008. CFHistory.addRoll(result.rolledNumber);
  1009. }
  1010. };
  1011.  
  1012. function readPromoCodeValues() {
  1013. let promoCodeElement = $('#promo-code-new')[0];
  1014. let promoDataStr = helpers.cleanString(promoCodeElement.innerText);
  1015. let promoDisplayStatus = $('#promo-display-status')[0];
  1016. if (promoDataStr == '') {
  1017. promoDisplayStatus.innerHTML = '';
  1018. return;
  1019. }
  1020.  
  1021. let promoData = JSON.parse(promoDataStr);
  1022.  
  1023. if(promoData.action) {
  1024. switch (promoData.action) {
  1025. case 'ADD':
  1026. CFPromotions.addNew(promoData.code, promoData.repeatDaily);
  1027. promoCodeElement.innerText = '';
  1028. $('#promo-text-input').val('');
  1029. promoDisplayStatus.innerHTML = 'Code ' + promoData.code + ' added!';
  1030. ui.log(`Promo code ${promoData.code} added`);
  1031. ui.refresh(null, CFPromotions.getAll());
  1032. break;
  1033. case 'REMOVEALLPROMOS':
  1034. CFPromotions.removeAll();
  1035. promoCodeElement.innerText = '';
  1036. promoDisplayStatus.innerHTML = 'Promo codes removed!';
  1037. ui.log(`Promo codes removed`);
  1038. ui.refresh(null, CFPromotions.getAll());
  1039. break;
  1040. case 'REMOVE':
  1041. if(CFPromotions.remove(promoData.id, promoData.code) != -1) {
  1042. ui.log(`Promo code ${promoData.code} removed`);
  1043. } else {
  1044. ui.log(`Unable to remove code ${promoData.code}`);
  1045. }
  1046. promoCodeElement.innerText = '';
  1047. ui.refresh(null, CFPromotions.getAll());
  1048. break;
  1049. }
  1050. }
  1051. };
  1052.  
  1053. function updateRollStatsSpan() {
  1054. let rollsSpanElement = $('#rolls-span')[0];
  1055. rollsSpanElement.innerText = CFHistory.getRollsMeta().join(',');
  1056. };
  1057.  
  1058. function getCFlist() {
  1059. let items;
  1060. items = webList.filter(f => f.type === WebType.CRYPTOSFAUCETS);
  1061. items = items.map(x => {
  1062. return {
  1063. id: x.id,
  1064. name: x.coinRef
  1065. };});
  1066. items.sort((a, b) => (a.name > b.name) ? 1 : -1);
  1067.  
  1068. return items;
  1069. };
  1070. return{
  1071. init:start,
  1072. process: process,
  1073. resultReader: resultReader,
  1074. getFaucetsForPromotion: getCFlist,
  1075. readPromoCodeValues: readPromoCodeValues
  1076. };
  1077. },
  1078. createUi: function() {
  1079. let logLines = ['', '', '', '', ''];
  1080. function init(cfFaucets) {
  1081. appendCSS();
  1082. appendJavaScript();
  1083. appendHtml();
  1084. createPromoTable(cfFaucets);
  1085. document.querySelector('.page-title h1').innerHTML = 'Auto Claim';
  1086. };
  1087. function appendCSS() {
  1088. let css = '<style>';
  1089. css += 'td.em-input {';
  1090. css += 'padding-top: 0;';
  1091. css += 'padding-bottom: 0;';
  1092. css += '}';
  1093. css += 'td.em-input input {';
  1094. css += '}';
  1095. css += '</style>';
  1096. $('head').append(css);
  1097. };
  1098. function appendJavaScript() {
  1099. let js = '';
  1100. js += '<script language="text/javascript">';
  1101. js += 'var myBarChart;';
  1102. js += 'function savePromoCode() {';
  1103. js += 'var promoText = document.getElementById("promo-text-input");';
  1104. js += 'var promoCode = document.getElementById("promo-code-new");';
  1105. js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
  1106. js += 'var promoDaily = document.getElementById("promo-daily");';
  1107. js += 'var promoObject = { action: "ADD", code: promoText.value.trim(), repeatDaily: promoDaily.checked };'
  1108. js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
  1109. js += 'promoDisplayStatus.innerHTML = "Adding &nbsp&quot;<b>" + promoObject.code + "</b>&quot;...<br>This could take around a minute. Please wait..."';
  1110. js += '}';
  1111. js += 'function removePromoCode(id, code) {';
  1112. js += 'var promoCode = document.getElementById("promo-code-new");';
  1113. js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
  1114. js += 'var promoObject = { action: "REMOVE", id: id, code: code };'
  1115. js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
  1116. js += 'promoDisplayStatus.innerHTML = "Removing code &nbsp&quot;<b>" + code + "</b>&quot;...<br>This could take around a minute. Please wait..."';
  1117. js += '}';
  1118.  
  1119.  
  1120. js += 'function getUpdateObject() {';
  1121. js += 'let updateObject;';
  1122. js += 'var updateData = document.getElementById("update-data");';
  1123. js += 'if (updateData.innerHTML != "") {';
  1124. js += 'updateObject = JSON.parse(updateData.innerHTML);';
  1125. js += '} else {';
  1126. js += 'updateObject = { runAsap: { ids: [], changed: false}, editSingle: { changed: false, items: [] }, wallet: { changed: false, items: []} };';
  1127. js += '}';
  1128. js += 'return updateObject;';
  1129. js += '}';
  1130. js += 'function editList() {';
  1131. js += '$.each($("#schedule-table-body td.em-input"), function(x, y) {';
  1132. js += 'let val = y.innerHTML;';
  1133. js += 'y.innerHTML = "<input type=\'text\' data-original=\'" + val + "\' value=\'" + val + "\' />";});';
  1134. js += '$.each($("#schedule-table-body td.edit-status"), function(x, y) {';
  1135. js += 'let activeSwitch = y.querySelector("input");';
  1136. js += 'y.classList.remove("d-none");';
  1137. js += '});';
  1138. js += '$.each($(".em-only"), (x, y) => y.classList.remove("d-none"));';
  1139. js += '$.each($(".em-hide"), (x, y) => y.classList.add("d-none"));';
  1140. js += '}';
  1141. js += 'function editListSave() {';
  1142. js += ' let updateObject = getUpdateObject();';
  1143. js += ' $.each($("#schedule-table-body tr"), function(x, row) {';
  1144. js += ' let textInputCell = row.querySelector(".em-input");';
  1145. js += ' let textInput = textInputCell.querySelector("input");';
  1146. js += ' let activeSwitch = row.querySelector("td.edit-status input");';
  1147. js += ' let single = { id: row.dataset.id, displayName: textInput.dataset.original, enabled: activeSwitch.dataset.original };';
  1148. js += ' textInputCell.innerHTML = textInput.value;';
  1149. js += ' if(textInput.dataset.original != textInput.value) {';
  1150. js += ' single.displayName = textInput.value;';
  1151. js += ' }';
  1152. js += ' if(activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {';
  1153. js += ' single.enabled = Boolean(activeSwitch.checked);';
  1154. js += ' }';
  1155. js += ' if(textInput.dataset.original != textInput.value || activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {';
  1156. js += ' updateObject.editSingle.items.push(single);';
  1157. js += ' updateObject.editSingle.changed = true;';
  1158. js += ' }';
  1159. js += ' });';
  1160. js += ' if(updateObject.editSingle.changed) {';
  1161. js += ' document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);';
  1162. js += ' document.getElementById("faucets-display-status").innerHTML = "Data will be updated as soon as possible...";';
  1163. js += ' }';
  1164. js += '$.each($(".em-only"), (x, y) => y.classList.add("d-none"));';
  1165. js += '$.each($(".em-hide"), (x, y) => y.classList.remove("d-none"));';
  1166. js += '}';
  1167. js += 'function editListCancel() {';
  1168. js += '$.each($("#schedule-table-body td.em-input input"), function(x, y) {';
  1169. js += 'let val = y.dataset.original;';
  1170. js += 'y.parentNode.innerHTML = val;});';
  1171. js += '$.each($(".em-only"), (x, y) => y.classList.add("d-none"));';
  1172. js += '$.each($(".em-hide"), (x, y) => y.classList.remove("d-none"));';
  1173. js += '}';
  1174.  
  1175. js += 'function editWalletCancel() {';
  1176. js += '$.each($("#wallet-table-body .em-input input"), function(x, y) {';
  1177. js += 'y.value = y.dataset.original;});';
  1178. js += '}';
  1179.  
  1180. js += 'function editWalletSave() {';
  1181. js += ' let updateObject = getUpdateObject();';
  1182. js += ' $.each($("#wallet-table-body tr"), function(x, row) {';
  1183. js += ' let textInput = row.querySelector(".em-input input");';
  1184. js += ' if(textInput.dataset.original != textInput.value) {';
  1185. js += ' let single = { id: row.dataset.id, address: textInput.value.trim() };';
  1186. js += ' updateObject.wallet.items.push(single);';
  1187. js += ' updateObject.wallet.changed = true;';
  1188. js += ' }';
  1189. js += ' });';
  1190. js += ' if(updateObject.wallet.changed) {';
  1191. js += ' document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);';
  1192. js += ' document.getElementById("faucets-display-status").innerHTML = "Wallet will be updated as soon as possible...";';
  1193. js += ' }';
  1194. js += '}';
  1195.  
  1196. js += 'function updateValues(type, values) {';
  1197. js += 'let updateObject = getUpdateObject();';
  1198. js += 'if (type == "runAsap") {';
  1199. js += 'updateObject.runAsap.ids.push(values.id);';
  1200. js += 'updateObject.runAsap.changed = true;';
  1201. js += 'document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);';
  1202. js += 'document.getElementById("faucets-display-status").innerHTML = "Faucet will be updated to run as soon as possible...";';
  1203. js += '}';
  1204. js += '}';
  1205.  
  1206.  
  1207. js += 'function removeAllPromos() {';
  1208. js += 'var promoCode = document.getElementById("promo-code-new");';
  1209. js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
  1210. js += 'var promoObject = { action: "REMOVEALL" };'
  1211. js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
  1212. js += 'promoDisplayStatus.innerHTML = "Removing all promotion codes...<br>This could take around a minute. Please wait..."';
  1213. js += '}';
  1214. js += 'function openStatsChart() {';
  1215. js += 'if(myBarChart) { myBarChart.destroy(); }';
  1216. js += 'let statsFragment = document.getElementById("stats-fragment");';
  1217. js += 'if (statsFragment.style.display === "block") { statsFragment.style.display = "none"; document.getElementById("stats-button").innerText = "Lucky Number Stats"; } else {';
  1218. js += 'statsFragment.style.display = "block"; document.getElementById("stats-button").innerText = "Close Stats";';
  1219. js += 'var canvas = document.getElementById("barChart");';
  1220. js += 'var ctx = canvas.getContext("2d");';
  1221. js += 'var dataSpan = document.getElementById("rolls-span");';
  1222. js += 'var data = {';
  1223. js += 'labels: ["0000-9885", "9886-9985", "9986-9993", "9994-9997", "9998-9999", "10000"],';
  1224. js += 'datasets: [ { fill: false, backgroundColor: [ "#990000", "#660066", "#000099", "#ff8000", "#ffff00", "#00ff00"],';
  1225. js += 'data: dataSpan.innerText.split(",") } ] };';
  1226. js += 'var options = { plugins: { legend: { display: false } }, title: { display: true, text: "Rolled Numbers", position: "top" }, rotation: -0.3 * Math.PI };';
  1227. js += 'myBarChart = new Chart(ctx, { type: "pie", data: data, options: options }); } }';
  1228. js += '</script>';
  1229.  
  1230. $('head').append(js);
  1231. };
  1232. function appendHtml() {
  1233. let html ='';
  1234. html += '<div class="modal fade" id="modal-wallet" tabindex="-1" role="dialog" data-backdrop="static" aria-hidden="true">';
  1235. html += '<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable" role="document">';
  1236. html += '<div class="modal-content bg-beige" style="background-color: #f6fdd0!important;">';
  1237. html += '<div class="modal-header"><h5 class="modal-title">Your Addresses</h5></div>';
  1238. html += '<div class="modal-body"><div><table class="table table-striped" id="wallet-table">';
  1239. html += '<thead><tr><th class="">Name</th><th class="">Address</th></tr></thead>';
  1240. html += '<tbody class="overflow-auto" id="wallet-table-body"></tbody></table></div></div>';
  1241. html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="editWalletCancel()" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
  1242. html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="editWalletSave()" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div>';
  1243. html += '</div></div>';
  1244. html += '</div>';
  1245.  
  1246. html += '<pre style="width:100%;" id="console-log"><b>Loading...</b></pre>';
  1247. html += '<section id="table-struct" class="fragment "><div class="container-fluid bg-dark "><div class="container py-1 "><div class="row mx-0"><div class="title col-3 px-0 text-white"><h2>Schedule</h2></div>';
  1248. html += '<div class="title col-6 w-100 text-white"><span id="faucets-display-status" class="text-white"></span></div><div class="title col-3 text-right">';
  1249. html += '<div class="em-only d-none"><a class="btn m-2 anchor btn-outline-success align-middle" onclick="editListSave()"><i class="fa fa-check-circle"></i> Save</a>';
  1250. html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="editListCancel()"><i class="fa fa-times-circle"></i> Cancel</a></div>';
  1251. html += '<div class="em-hide"><a class="btn m-2 anchor btn-outline-primary align-middle" data-toggle="modal" data-target="#modal-wallet"><i class="fa fa-wallet"></i> Wallet</a><a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editList()"><i class="fa fa-edit"></i> Edit</a></div>';
  1252. html += '</div></div>';
  1253.  
  1254.  
  1255. html += '<div class="row align-items-center text-center justify-content-end">';
  1256. html += '<div class="col-12 order-lg-1 text-center"><div class="row justify-content-center"><div class="col table-responsive" id="schedule-container"></div></div></div></div></div></div>';
  1257. html += '<span id="update-data" style="display:none;"></span></section>';
  1258. html +='<section id="table-struct-promo" class="fragment "><div class="container-fluid bg-dark "><div class="container py-1 "><div class="row mx-0 mb-1">';
  1259. html +='<div class="title col-3 px-0 text-white"><h2>Promo Codes</h2></div><div class="title col-4 w-100 text-white">';
  1260. html +='<div class="input-group my-0"><div class="mx-2"><label class="switch" title="Check if the code can be reused every 24hs"><input id="promo-daily" type="checkbox"><span class="slider round"></span>Daily</label></div><input type="text" class="form-control py-1" id="promo-text-input" list="promoCode_list" placeholder="Type a Promo code...">';
  1261. html += '<datalist id="promoCode_list">';
  1262. CFReusableCodesSuggestion.forEach( function(x) { html += '<option>' + x + '</option>' });
  1263. html += '</datalist>';
  1264. html +='<div class="input-group-append"><button class="btn btn-success" id="promo-button" onclick="savePromoCode()"><i class="fa fa-plus"></i></button>';
  1265. html +='</div></div></div>';
  1266. html +='<div class="title col-3 text-white justify-content-end"><span id="promo-display-status" class="text-white"></span>';
  1267. html +='<span id="promo-code-new" style="display:none;"></span></div><div class="title col-2 text-right"><a class="btn m-2 anchor btn-outline-danger" id="promo-button" onclick="removeAllPromos()">Remove All</a>';
  1268. html +='</div></div><div class="row align-items-center text-center justify-content-end"><div class="col-12 order-lg-1 text-center">';
  1269. html +='<div class="row justify-content-center"><div class="col table-responsive" id="promo-container"></div></div></div></div></div></div></section>';
  1270. html += '<section class="fragment"><div class="container-fluid bg-dark ">';
  1271. 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>';
  1272. html +='<div class="container py-1" id="stats-fragment" style="display:none;"><div class="row align-items-center text-center justify-content-center">';
  1273. html += '<div class="col-md-3"><canvas id="barChart"></canvas><span id="rolls-span" style="display:none;"></span></div></div></div></div></div></section>';
  1274.  
  1275. $('#referral-table').before(html);
  1276. $('#schedule-container').append( createScheduleTable() );
  1277. };
  1278. function createPromoTable(faucets) {
  1279. let tableStructure = '';
  1280. tableStructure += '<table class="table table-striped table-dark" id="promo-table">';
  1281. tableStructure += '<caption style="text-align: -webkit-center;">⏳ Pending ✔️ Accepted 🕙 Used Before ❌ Invalid code ❗ Unknown error ⚪ No code</caption>';
  1282. tableStructure += '<thead><tr><th class="">Code</th><th class="">Added</th>';
  1283.  
  1284. for (let i = 0, all = faucets.length; i < all; i++) {
  1285. tableStructure += '<th data-faucet-id="' + faucets[i].id + '">' + faucets[i].name + '</th>';
  1286. }
  1287.  
  1288. tableStructure += '</tr></thead><tbody id="promo-table-body"></tbody></table>';
  1289.  
  1290. $('#promo-container').append( tableStructure );
  1291. };
  1292. function createScheduleTable() {
  1293. let tableStructure = '';
  1294. tableStructure += '<table class="table table-striped table-dark" id="schedule-table"><thead><tr>';
  1295. tableStructure += '<th scope="col" class="edit-status d-none em-only" style="">Active</th><th class="">#</th><th class="">Name</th><th class="">Site</th><th class="">Last Claim</th>';
  1296. tableStructure += '<th class="">Aggregate</th><th class="">Balance</th><th class="" id="converted-balance-col">FIAT</th><th class="">Next Roll</th>';
  1297. tableStructure += '<th scope="col" class="">Msgs</th><th scope="col" class="em-hide" style="">Run ASAP</th></tr></thead><tbody id="schedule-table-body"></tbody></table>';
  1298.  
  1299. return tableStructure;
  1300. };
  1301. function loadScheduleTable(data) {
  1302. let tableBody = '';
  1303.  
  1304. for(let i=0, all = data.length; i < all; i++) {
  1305. tableBody += '<tr class="align-middle" data-id="' + data[i].id + '" data-cmc="' + data.find(x => x.id == data[i].id).cmc + '" data-balance="';
  1306. if (data[i].balance) {
  1307. if(typeof data[i].balance == 'string') {
  1308. tableBody += data[i].balance.split(' ')[0];
  1309. } else {
  1310. tableBody += data[i].balance.toFixed(8);
  1311. }
  1312. }
  1313. tableBody += '">';
  1314. tableBody +='<td class="align-middle edit-status d-none em-only"><label class="switch"><input type="checkbox" data-original="' + (data[i].enabled ? '1' : '0') + '" ' + (data[i].enabled ? 'checked' : ' ') + '><span class="slider round"></span></label></td>';
  1315. tableBody +='<td class="align-middle">' + (data[i].enabled ? (i + 1).toString() : '-') + '</td>';
  1316. tableBody +='<td class="align-middle em-input" data-field="displayName">' + data[i].name + '</td>';
  1317. tableBody +='<td class="align-middle text-left" style="width: 20%">';
  1318. if (Array.isArray(data[i].rf)) {
  1319. tableBody +='<a class="edit-site" title="Visit site" target="_blank" href="' + data[i].url.href + data[i].rf[helpers.randomInt(0, data[i].rf.length -1)] + '"><i class="fa fa-external-link-alt"></i></a> ';
  1320. } else {
  1321. tableBody +='<a class="edit-site" title="Visit site" target="_blank" href="' + (new URL(data[i].rf, data[i].url.origin)).href + '"><i class="fa fa-external-link-alt"></i></a> ';
  1322. }
  1323. tableBody += (data[i].type == WebType.BAGIKERAN ? data[i].url.host + data[i].url.pathname : data[i].url.host) + '</td>';
  1324. tableBody +='<td class="align-middle">' + data[i].lastClaim.toFixed(8) + '</td>';
  1325. tableBody +='<td class="align-middle">' + data[i].aggregate.toFixed(8) + '</td>';
  1326. tableBody +='<td class="align-middle">';
  1327. if (data[i].balance) {
  1328. if(typeof data[i].balance == 'string') {
  1329. tableBody += data[i].balance.split(' ')[0];
  1330. } else {
  1331. tableBody += data[i].balance.toFixed(8);
  1332. }
  1333. }
  1334. tableBody + '</td>';
  1335. tableBody +='<td class="align-middle fiat-conversion"></td>';
  1336. tableBody +='<td class="align-middle">' + helpers.getPrintableTime(data[i].nextRoll) + '</td>';
  1337. tableBody +='<td class="align-middle">' + addBadges(data[i].stats) + '</td>';
  1338. tableBody +='<td class="align-middle em-hide"><a class="edit-site" data-toggle="tooltip" data-placement="left" title="Run ASAP" href="javascript:updateValues(\'runAsap\', { id: ' + data[i].id + ' })" onclick=""><i class="fa fa-redo"></i></a></td>';
  1339. tableBody +='</tr>';
  1340. }
  1341.  
  1342. $('#schedule-table-body').html(tableBody);
  1343.  
  1344. location.href = 'javascript:convertToFiat();';
  1345. };
  1346.  
  1347. function addBadges(stats) {
  1348. let consecutiveTimeout = stats.countTimeouts;
  1349. let otherErrors = stats.errors;
  1350. let html = ' ';
  1351.  
  1352. if (consecutiveTimeout) {
  1353. html += `<span class="badge badge-pill badge-warning" title="${consecutiveTimeout} consecutive timeouts">${consecutiveTimeout}</span>`;
  1354. }
  1355.  
  1356. if (otherErrors) {
  1357. html += `<span class="badge badge-pill badge-warning" title="${otherErrors.errorMessage}">${otherErrors.errorType}</span>`;
  1358. }
  1359. return html;
  1360. }
  1361. function loadPromotionTable(codes) {
  1362. let tableBody = '';
  1363.  
  1364. for(let c=0; c < codes.length; c++) {
  1365. let data = codes[c];
  1366. tableBody += '<tr data-promotion-id="' + data.id + '">';
  1367. tableBody += '<td class="align-middle text-left ' + (data.repeatDaily ? 'text-warning' : '') + '">';
  1368. tableBody += '<a data-toggle="tooltip" data-placement="left" title="Remove" href="javascript:removePromoCode(' + data.id + ', \'' + data.code + '\')" onclick=""><i class="fa fa-times-circle"></i></a> ';
  1369. tableBody += '<span title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + data.code + '</span></td>';
  1370. tableBody +='<td class="align-middle" title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + helpers.getPrintableDateTime(data.added) + '</td>';
  1371.  
  1372. for(let i=0, all = data.statusPerFaucet.length; i < all; i++) {
  1373. tableBody +='<td class="align-middle" title="Runned @' + helpers.getPrintableDateTime(data.statusPerFaucet[i].execTimeStamp) + '">' + helpers.getEmojiForPromoStatus(data.statusPerFaucet[i].status ?? 0) + '</td>';
  1374. }
  1375. tableBody +='</tr>';
  1376. }
  1377.  
  1378. $('#promo-table-body').html(tableBody);
  1379. };
  1380. function loadWalletTable(data) {
  1381. let tableBody = '';
  1382.  
  1383. for(let i=0, all = data.length; i < all; i++) {
  1384. tableBody += '<tr class="align-middle" data-id="'+ data[i].id + '">';
  1385. tableBody += '<td class="align-middle">' + data[i].name + '</td>';
  1386. tableBody += '<td class="align-middle em-input"><input type="text" class="w-100" data-field="address" data-original="' + data[i].address + '" value="' + data[i].address + '"></td>';
  1387. tableBody += '</tr>';
  1388. }
  1389.  
  1390. $('#wallet-table-body').html(tableBody);
  1391. };
  1392. function refresh(scheduleData, promotionData, walletData) {
  1393. if (scheduleData) {
  1394. loadScheduleTable(scheduleData);
  1395. }
  1396. if (promotionData) {
  1397. loadPromotionTable(promotionData);
  1398. }
  1399. if (walletData) {
  1400. loadWalletTable(walletData);
  1401. }
  1402. };
  1403. function log(msg, elapsed = false) {
  1404. if(msg) {
  1405. let previous = logLines[0].split('&nbsp')[1];
  1406. if(elapsed && (previous == msg)) {
  1407. logLines[0] = helpers.getPrintableTime() + '&nbsp' + msg + '&nbsp[Elapsed time:&nbsp' + elapsed + '&nbspseconds]';
  1408. } else {
  1409. logLines.pop();
  1410. logLines.unshift(helpers.getPrintableTime() + '&nbsp' + msg);
  1411. }
  1412. $('#console-log').html(logLines.join('<br>'));
  1413. }
  1414. };
  1415. return {
  1416. init: init,
  1417. refresh: refresh,
  1418. loadPromotionTable: loadPromotionTable,
  1419. log: log
  1420. }
  1421. },
  1422. createCFPromotions: function() {
  1423. let codes = [];
  1424.  
  1425. function PromotionCode(id, code, repeatDaily = false) {
  1426. this.id = id;
  1427. this.code = code;
  1428. this.added = new Date();
  1429. this.statusPerFaucet = [];
  1430. this.repeatDaily = repeatDaily;
  1431. this.lastExecTimeStamp = null;
  1432. };
  1433.  
  1434. function getFaucetStatusInPromo(promo, faucetId) {
  1435. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  1436. if (faucet.status && promo.repeatDaily) {
  1437. //Using 26 hs instead of 24hs, and 2hs gap retry when code is flagged as USEDBEFORE
  1438. if((faucet.status == PromoStatus.ACCEPTED && (Date.now() - faucet.execTimeStamp.getTime()) > HS_26_IN_MILLISECONDS)
  1439. || (faucet.status == PromoStatus.USEDBEFORE && (Date.now() - faucet.execTimeStamp.getTime()) > HS_2_IN_MILLISECONDS)) {
  1440. faucet.status = PromoStatus.PENDING;
  1441. }
  1442. }
  1443. return faucet.status ?? PromoStatus.NOCODE;
  1444. };
  1445.  
  1446. function addNew(code, repeatDaily = false) {
  1447. let newPromo = new PromotionCode(codes.length, code, repeatDaily);
  1448. newPromo.statusPerFaucet = manager.getFaucetsForPromotion().map(x => {
  1449. return {
  1450. id: x.id,
  1451. };});
  1452. newPromo.statusPerFaucet.forEach(function (element, idx, arr) {
  1453. arr[idx].status = PromoStatus.PENDING;
  1454. arr[idx].execTimeStamp = null;
  1455. });
  1456.  
  1457. codes.push(newPromo);
  1458. codes.sort((a, b) => (a.id < b.id) ? 1 : -1);
  1459. save();
  1460. };
  1461.  
  1462. function getAll() {
  1463. return codes;
  1464. };
  1465.  
  1466. function updateFaucetForCode(code, faucetId, newStatus) {
  1467. let promo = codes.find(x => x.code == code);
  1468. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  1469. if(faucet) {
  1470. faucet.status = newStatus;
  1471. faucet.execTimeStamp = new Date();
  1472. promo.lastExecTimeStamp = faucet.execTimeStamp;
  1473. }
  1474. save();
  1475. };
  1476.  
  1477. function hasPromoAvailable(faucetId) {
  1478. let resp = false;
  1479. codes.forEach(function (promotion, idx, arr) {
  1480. let status = getFaucetStatusInPromo(promotion, faucetId);
  1481. if (status == PromoStatus.PENDING) {
  1482. resp = promotion.code;
  1483. return;
  1484. }
  1485. });
  1486. return resp;
  1487. };
  1488.  
  1489. function save() {
  1490. persistence.save('CFPromotions', getAll(), true);
  1491. };
  1492.  
  1493. function load(data) {
  1494. codes = data;
  1495. };
  1496.  
  1497. function removeAll() {
  1498. codes = [];
  1499. save();
  1500. };
  1501.  
  1502. function remove(id, code) {
  1503. let idx = codes.findIndex(x => x.id == id && x.code == code);
  1504. if(idx != -1) {
  1505. codes.splice(idx, 1);
  1506. save();
  1507. }
  1508.  
  1509. return idx;
  1510. };
  1511.  
  1512. return {
  1513. addNew: addNew,
  1514. removeAll: removeAll,
  1515. remove: remove,
  1516. getAll: getAll,
  1517. load: load,
  1518. updateFaucetForCode: updateFaucetForCode,
  1519. hasPromoAvailable: hasPromoAvailable
  1520. }
  1521. },
  1522. createInteractions: function(){
  1523. let randomInteractionLevel = RandomInteractionLevel.MEDIUM;
  1524. let maxActions = 0;
  1525. let performedActions = -1;
  1526. let selectableElements;
  1527. let actions = {
  1528. available: [
  1529. function() {
  1530. $('html, body').animate({
  1531. scrollTop: helpers.randomInt(0, $('html, body').get(0).scrollHeight)
  1532. }, {
  1533. complete: setTimeout(interactions.addPerformed, helpers.randomMs(100, 3000)),
  1534. duration: helpers.randomMs(100, 1500)
  1535. });
  1536. },
  1537. function() {
  1538. let element = interactions.selectableElements[helpers.randomInt(0, interactions.selectableElements.length - 1)];
  1539.  
  1540. try {
  1541. if (document.body.createTextRange) {
  1542. const range = document.body.createTextRange();
  1543. range.moveToElementText(element);
  1544. range.select();
  1545. } else if (window.getSelection) {
  1546. const selection = window.getSelection();
  1547. const range = document.createRange();
  1548. range.selectNodeContents(element);
  1549. selection.removeAllRanges();
  1550. selection.addRange(range);
  1551. }
  1552. } catch (err) { }
  1553.  
  1554. interactions.addPerformed();
  1555. }
  1556. ]
  1557. };
  1558.  
  1559. function start(selectableElements) {
  1560. performedActions = 0;
  1561. switch(randomInteractionLevel) {
  1562. case RandomInteractionLevel.NONE:
  1563. maxActions = 0;
  1564. break;
  1565. case RandomInteractionLevel.LOW:
  1566. maxActions = helpers.randomInt(2, 4);
  1567. break;
  1568. case RandomInteractionLevel.MEDIUM:
  1569. maxActions = helpers.randomInt(5, 8);
  1570. break;
  1571. case RandomInteractionLevel.HIGH:
  1572. maxActions = helpers.randomInt(12, 16);
  1573. break;
  1574. }
  1575. interactions.selectableElements = selectableElements;
  1576. performActions();
  1577. }
  1578.  
  1579. function performActions() {
  1580. if(performedActions >= maxActions) {
  1581. return;
  1582. }
  1583. let delay = 0;
  1584. for(let i = 0; i < maxActions; i++) {
  1585. delay += helpers.randomMs(350, 1500);
  1586. setTimeout(actions.available[helpers.randomInt(0, actions.available.length - 1)], delay);
  1587. }
  1588. }
  1589.  
  1590. function addPerformed() {
  1591. performedActions++;
  1592. }
  1593. function completed() {
  1594. return (performedActions >= maxActions);
  1595. }
  1596.  
  1597. return {
  1598. start: start,
  1599. completed: completed,
  1600. addPerformed: addPerformed,
  1601. selectableElements: selectableElements
  1602. };
  1603. },
  1604. createSGProcessor: function() {
  1605. let timerSpans;
  1606. function run() {
  1607. if(isLoading()) {
  1608. setTimeout(run, helpers.randomMs(5000, 10000));
  1609. return;
  1610. } else if (hasPopup()) {
  1611. closePopup();
  1612. setTimeout(run, helpers.randomMs(5000, 10000));
  1613. } else {
  1614. if(isMinerActive()) {
  1615. processRunDetails();
  1616. } else {
  1617. activateMiner();
  1618. }
  1619. }
  1620. };
  1621. function hasPopup() {
  1622. return $('.wrapper.grid.min-h-0.md-min-h-1-2.md-relative.md-rounded-lg.md-bg-dark-4 svg circle').length > 0;
  1623. };
  1624. function closePopup() {
  1625. try {
  1626. $('svg.flex.w-8.h-8.fill-current')[0].parentElement.click();
  1627. } catch { }
  1628. };
  1629. function isLoading() {
  1630. return $('#loader-logo').length;
  1631. };
  1632. function isMinerActive() {
  1633. timerSpans = $('.mb-8 .wrapper .mb-1 span');
  1634. if(timerSpans.length > 0) {
  1635. return true;
  1636. } else {
  1637. return false;
  1638. }
  1639. return (timerSpans.length === 0);
  1640. };
  1641. function activateMiner() {
  1642. const activateButton = document.querySelector('.mb-8 .wrapper button');
  1643. if (activateButton) {
  1644. activateButton.click();
  1645. setTimeout(processRunDetails, helpers.randomMs(10000, 20000));
  1646. } else {
  1647. if(!is404Error()) {
  1648. processRunDetails()
  1649. }
  1650. }
  1651. };
  1652.  
  1653. function is404Error() {
  1654. const h1 = document.getElementsByTagName('h1');
  1655. if (h1.length > 0 && h1[0].innerText.includes('404')) {
  1656. window.location.reload();
  1657. return true;
  1658. }
  1659. return false;
  1660. }
  1661.  
  1662. function processRunDetails() {
  1663. let result = {};
  1664. result.nextRoll = helpers.addMinutes(new Date(), readCountdown().toString());
  1665. result.balance = readBalance();
  1666. shared.closeWindow(result);
  1667. };
  1668. function readCountdown() {
  1669. let mins = 15;
  1670. try {
  1671. let timeLeft = timerSpans.last().text().split(':');
  1672. if(timeLeft.length === 3) {
  1673. mins = parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
  1674. }
  1675. } catch (err) { }
  1676. return mins;
  1677. };
  1678. function readBalance() {
  1679. let balance = "";
  1680. try {
  1681. balance = $('span.text-accent').first().text() + " BTC";
  1682. } catch (err) { }
  1683. return balance;
  1684. };
  1685. return {
  1686. run: run,
  1687. processRunDetails: processRunDetails
  1688. };
  1689. },
  1690. createCFProcessor: function() {
  1691. const NavigationProcess = {
  1692. ROLLING: 1,
  1693. PROCESSING_PROMOTION: 2,
  1694. LOGIN: 3
  1695. };
  1696. let navigationProcess;
  1697. let countdown;
  1698. let rollButton;
  1699. let promotionTag;
  1700. let timeWaiting= 0;
  1701. let loopingForErrors = false;
  1702.  
  1703. function run() {
  1704. navigationProcess = NavigationProcess.ROLLING;
  1705. displayStatusUi();
  1706.  
  1707. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  1708. };
  1709.  
  1710. function doLogin() {
  1711. navigationProcess = NavigationProcess.LOGIN;
  1712. displayStatusUi();
  1713.  
  1714. setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
  1715. };
  1716.  
  1717. function isFullyLoaded() { //Waits 55 seconds max
  1718. if(document.readyState == 'complete' || timeWaiting == -1) {
  1719. $('#process-status')[0].innerHTML = 'Interacting';
  1720. timeWaiting = 0;
  1721. interact();
  1722. } else {
  1723. timeWaiting = -1;
  1724. $('#process-status')[0].innerHTML = 'Waiting for document fully loaded';
  1725. setTimeout(isFullyLoaded, helpers.randomMs(45000, 55000));
  1726. }
  1727. };
  1728. function runPromotion() {
  1729. navigationProcess = NavigationProcess.PROCESSING_PROMOTION
  1730. displayStatusUi();
  1731. setTimeout(findPromotionTag, helpers.randomMs(1000, 3000));
  1732. };
  1733. function findCountdownOrRollButton() {
  1734. if( isCountdownVisible() && !isRollButtonVisible() ) {
  1735. timeWaiting = 0;
  1736. processRunDetails();
  1737. } else if ( !isCountdownVisible() && isRollButtonVisible() ) {
  1738. timeWaiting = 0;
  1739. setTimeout(isFullyLoaded, helpers.randomMs(1000, 5000));
  1740. } else {
  1741. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  1742. shared.closeWithError('TIMEOUT', '');
  1743. return;
  1744. }
  1745.  
  1746. timeWaiting += 3000;
  1747. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  1748. }
  1749. };
  1750. function findLoginForm() {
  1751. if ( $('div.login-wrapper').is(':visible') ) {
  1752. //Other possible error is if recaptcha did not load yet... so maybe wait til the web is fully loaded for low connection issues
  1753. if( $('.login-wrapper .error').length > 0 && $('.login-wrapper .error')[0].innerHTML != '') {
  1754. let errorMessage = $('.login-wrapper .error').text();
  1755. shared.closeWithError('LOGIN_ERROR', errorMessage);
  1756. return;
  1757. }
  1758. if(!loopingForErrors) {
  1759. if(config.cf.credentials.mode == 1) {
  1760. timeWaiting = 0;
  1761. $('.login-wrapper input[name="email"]').val(config.cf.credentials.email);
  1762. $('.login-wrapper input[name="password"]').val(config.cf.credentials.password);
  1763. $('.login-wrapper button.login').click();
  1764. loopingForErrors = true;
  1765. } else {
  1766. if($('.login-wrapper input[name="email"]').val() != '' && $('.login-wrapper input[name="password"]').val() != '') {
  1767. $('.login-wrapper button.login').click();
  1768. $('#process-status')[0].innerHTML = 'Processing';
  1769. loopingForErrors = true;
  1770. } else {
  1771. $('#process-status')[0].innerHTML = 'Waiting for credentials...';
  1772. if (timeWaiting/1000 > (config.defaults.timeout / 1.5) * 60) {
  1773. shared.closeWithError('LOGIN_ERROR', 'No credentials were provided');
  1774. return;
  1775. }
  1776. }
  1777. }
  1778. }
  1779. }
  1780.  
  1781. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  1782. shared.closeWithError('TIMEOUT', '');
  1783. return;
  1784. }
  1785.  
  1786. timeWaiting += 3000;
  1787. setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
  1788. };
  1789. function interact() {
  1790. let selectables = []
  1791. selectables = selectables.concat($('td').toArray());
  1792. selectables = selectables.concat($('p').toArray());
  1793. selectables = selectables.concat($('th').toArray());
  1794.  
  1795. interactions.start(selectables);
  1796. setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
  1797. }
  1798. function waitInteractions() {
  1799. if(interactions.completed()) {
  1800. roll();
  1801. } else {
  1802. setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
  1803. }
  1804. }
  1805. function isCountdownVisible() {
  1806. countdown = $('.timeout-wrapper');
  1807. return ($(countdown).length > 0 && $(countdown[0]).is(':visible'));
  1808. };
  1809. function isRollButtonVisible() {
  1810. rollButton = $('.main-button-2.roll-button.bg-2');
  1811. return ($(rollButton).length > 0 && $(rollButton[0]).is(':visible'));
  1812. };
  1813. function roll() {
  1814. $('#process-status')[0].innerHTML = 'Roll triggered';
  1815. $(rollButton[0]).click();
  1816. setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 3000));
  1817. }
  1818. function isPromotionTagVisible() {
  1819. let pTags = $('p');
  1820. if (pTags.length > 0) {
  1821. promotionTag = $('p')[0];
  1822. return true;
  1823. }
  1824. return false;
  1825. };
  1826. function findPromotionTag() {
  1827. if( isPromotionTagVisible() ) {
  1828. processRunDetails();
  1829. } else {
  1830. setTimeout(cfProcessor.findPromotionTag, helpers.randomMs(2000, 5000));
  1831. }
  1832. };
  1833. function processRunDetails() {
  1834. let result = {};
  1835. if(navigationProcess == NavigationProcess.ROLLING) {
  1836. result.nextRoll = readCountdown();
  1837. result.claimed = readClaimed();
  1838. result.balance = readBalance();
  1839. if(result.claimed != 0) {
  1840. result.rolledNumber = readRolledNumber();
  1841. }
  1842. result.balance = readBalance();
  1843. } else if (navigationProcess == NavigationProcess.PROCESSING_PROMOTION) {
  1844. result.promoStatus = readPromoStatus();
  1845. result.promoCode = readPromoCode();
  1846. if (result.promoStatus == PromoStatus.ACCEPTED) {
  1847. result.nextRoll = helpers.addMinutes(new Date(-20), "0");
  1848. }
  1849. }
  1850. shared.closeWindow(result);
  1851. };
  1852. function readCountdown() {
  1853. let minsElement = $('.timeout-container .minutes .digits');
  1854. let mins = "0";
  1855. if ($(minsElement).length > 0) {
  1856. mins = $(minsElement)[0].innerHTML;
  1857. }
  1858. if (mins) {
  1859. return helpers.addMinutes(new Date(), mins.toString());
  1860. } else {
  1861. return null;
  1862. }
  1863. };
  1864. function readClaimed() {
  1865. let claimed = 0;
  1866. try {
  1867. claimed = $('.result')[0].innerHTML;
  1868. claimed = claimed.trim();
  1869. claimed = claimed.slice(claimed.lastIndexOf(" ") + 1);
  1870. } catch(err) { }
  1871. return claimed;
  1872. };
  1873. function readRolledNumber() {
  1874. let number = 0;
  1875. try {
  1876. number = $('.lucky-number').toArray().map(x => x.innerText).join('');
  1877. number = parseInt(number);
  1878. } catch(err) { }
  1879. return number;
  1880. };
  1881. function readBalance() {
  1882. let balance = "";
  1883. try {
  1884. balance = $('.navbar-coins.bg-1 a').first().text();
  1885. } catch(err) { }
  1886. return balance;
  1887. };
  1888. function readPromoStatus() {
  1889. let promoStatus = PromoStatus.UNKNOWNERROR;
  1890. try {
  1891. if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeAccepted) > 0) {
  1892. return PromoStatus.ACCEPTED;
  1893. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeUsed) > 0) {
  1894. return PromoStatus.USEDBEFORE;
  1895. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeExpired) > 0) {
  1896. return PromoStatus.EXPIRED;
  1897. } else if(localeConfig.stringSearches.promoCodeInvalid.findIndex(x => promotionTag.innerHTML.indexOf(x) > -1) == -1) {
  1898. return PromoStatus.INVALID;
  1899. }
  1900. } catch ( err ) { }
  1901. return promoStatus;
  1902. };
  1903. function validatePromoString() {
  1904.  
  1905. };
  1906. function readPromoCode() {
  1907. var urlSplit = window.location.href.split('/');
  1908. return urlSplit[urlSplit.length - 1];
  1909. };
  1910. function displayStatusUi() {
  1911. $( 'body' ).prepend( '<div class="withdraw-button bg-2" style="top:30%; z-index:1500;" href="#">⚙️ <span id="process-status">Processing</span></div>' );
  1912. };
  1913. return {
  1914. run: run,
  1915. runPromotion: runPromotion,
  1916. findPromotionTag: findPromotionTag,
  1917. waitInteractions: waitInteractions,
  1918. isFullyLoaded: isFullyLoaded,
  1919. doLogin: doLogin
  1920. };
  1921. },
  1922. createCFHistory: function() {
  1923. let rollsMeta = [
  1924. { id: 0, range: '0000-9885', count: 0 },
  1925. { id: 1, range: '9886-9985', count: 0 },
  1926. { id: 2, range: '9986-9993', count: 0 },
  1927. { id: 3, range: '9994-9997', count: 0 },
  1928. { id: 4, range: '9998-9999', count: 0 },
  1929. { id: 5, range: '10000', count: 0 }
  1930. ];
  1931.  
  1932. function initOrLoad() {
  1933. let storedData = persistence.load('CFHistory', true);
  1934. if(storedData) {
  1935. rollsMeta = storedData;
  1936. }
  1937. };
  1938.  
  1939. function addRoll(number) {
  1940. switch(true) {
  1941. case (number <= 9885):
  1942. rollsMeta[0].count++;
  1943. break;
  1944. case (number <= 9985):
  1945. rollsMeta[1].count++;
  1946. break;
  1947. case (number <= 9993):
  1948. rollsMeta[2].count++;
  1949. break;
  1950. case (number <= 9997):
  1951. rollsMeta[3].count++;
  1952. break;
  1953. case (number <= 9999):
  1954. rollsMeta[4].count++;
  1955. break;
  1956. case (number == 10000):
  1957. rollsMeta[5].count++;
  1958. break;
  1959. default:
  1960. break;
  1961. }
  1962. save();
  1963. };
  1964.  
  1965. function getRollsMeta() {
  1966. return rollsMeta.map(x => x.count);
  1967. };
  1968.  
  1969. function save() {
  1970. persistence.save('CFHistory', rollsMeta, true);
  1971. };
  1972.  
  1973. return {
  1974. initOrLoad: initOrLoad,
  1975. addRoll: addRoll,
  1976. getRollsMeta: getRollsMeta
  1977. }
  1978. },
  1979. createFBProcessor: function() {
  1980. let countdownMinutes;
  1981. let timeWaiting= 0;
  1982. function timedOut(addMs) {
  1983. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  1984. shared.closeWithError('TIMEOUT', '');
  1985. return true;
  1986. }
  1987.  
  1988. timeWaiting += addMs;
  1989. return false;
  1990. }
  1991.  
  1992. function run() {
  1993. setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
  1994. };
  1995. function findCountdownOrRollButton() {
  1996. if ( isCountdownVisible() ) {
  1997. timeWaiting = 0;
  1998. countdownMinutes = +document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount')[0].innerHTML + 1;
  1999. let result = {};
  2000. result.balance = readBalance();
  2001. result.nextRoll = helpers.addMinutes(new Date(), countdownMinutes.toString());
  2002.  
  2003. shared.closeWindow(result);
  2004. return;
  2005. }
  2006.  
  2007. if ( isRollButtonVisible() ) {
  2008. if (config.fb.activateRPBonus) {
  2009. if (!document.getElementById('bonus_container_free_points')) {
  2010. document.querySelector('a.rewards_link').click();
  2011. activateBonus(0);
  2012. }
  2013. }
  2014. if (isHCaptchaVisible()) {
  2015. waitForCaptcha();
  2016. } else {
  2017. clickRoll();
  2018. }
  2019. } else {
  2020. setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
  2021. }
  2022. };
  2023. function isCountdownVisible() {
  2024. return document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount').length > 0;
  2025. };
  2026. function isHCaptchaVisible() {
  2027. let hCaptchaFrame = document.querySelector('.h-captcha > iframe');
  2028. if (hCaptchaFrame && $(hCaptchaFrame).is(':visible')) {
  2029. return true;
  2030. }
  2031. return false;
  2032. };
  2033. function isRollButtonVisible() {
  2034. return $(document.getElementById('free_play_form_button')).is(':visible');
  2035. };
  2036. function waitForCaptcha() {
  2037. if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0) {
  2038. clickRoll();
  2039. } else {
  2040. if (timedOut(10000)) {
  2041. return;
  2042. }
  2043. setTimeout(waitForCaptcha, helpers.randomMs(10000, 12000));
  2044. }
  2045. };
  2046. function clickRoll() {
  2047. try {
  2048. document.getElementById('free_play_form_button').click();
  2049. setTimeout(processRunDetails, helpers.randomMs(3000, 10000));
  2050. } catch (err) {
  2051. shared.closeWithError('CLICK_ROLL_ERROR', err);
  2052. }
  2053. };
  2054. function processRunDetails() {
  2055. if ($(document.getElementById('winnings')).is(':visible')) {
  2056. closePopup();
  2057.  
  2058. let result = {};
  2059. result.claimed = readClaimed();
  2060. result.balance = readBalance();
  2061. if(result.claimed != 0) {
  2062. result.rolledNumber = readRolledNumber();
  2063. result.nextRoll = helpers.addMinutes(new Date(), "60");
  2064. }
  2065. shared.closeWindow(result);
  2066. return;
  2067. }
  2068.  
  2069. if ($('.free_play_result_error').is(':visible')) {
  2070. shared.closeWithError('ROLL_ERROR', $('.free_play_result_error')[0].innerHTML);
  2071. return;
  2072. }
  2073.  
  2074. if($('#free_play_error').is(':visible')) {
  2075. shared.closeWithError('ROLL_ERROR', $('.free_play_error')[0].innerHTML);
  2076. return;
  2077. }
  2078.  
  2079. if ($(document.getElementById('same_ip_error')).is(':visible')) {
  2080. shared.closeWithError('ROLL_ERROR', document.getElementById('same_ip_error').innerHTML);
  2081. return;
  2082. }
  2083.  
  2084. if (timedOut(5000)) {
  2085. return;
  2086. }
  2087. setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
  2088. };
  2089. function closePopup() {
  2090. let closePopupBtn = document.querySelector('.reveal-modal.open .close-reveal-modal');
  2091. if (closePopupBtn) {
  2092. closePopupBtn.click();
  2093. }
  2094. };
  2095. function readRolledNumber() {
  2096. let rolled = 0;
  2097. try {
  2098. rolled = parseInt([... document.querySelectorAll('#free_play_digits span')].map( x => x.innerHTML).join(''));
  2099. } catch { }
  2100. return rolled;
  2101. };
  2102. function readBalance() {
  2103. let balance = 0;
  2104. try {
  2105. balance = document.getElementById('balance').innerHTML;
  2106. } catch { }
  2107. return balance;
  2108. };
  2109. function readClaimed() {
  2110. let claimed = 0;
  2111. try {
  2112. claimed = document.getElementById('winnings').innerHTML;
  2113. } catch { }
  2114. return claimed;
  2115. };
  2116.  
  2117. function activateBonus(i) {
  2118. if($(document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_error')).is(':visible')) {
  2119. let closeBtn = document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_box_close')
  2120. if ($(closeBtn).is(':visible')) {
  2121. closeBtn.click();
  2122. }
  2123. } else if ($(document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_success')).is(':visible')) {
  2124. let closeBtn = document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_box_close')
  2125. if ($(closeBtn).is(':visible')) {
  2126. closeBtn.click();
  2127. document.querySelector('#free_play_link_li a').click();
  2128. setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
  2129. return;
  2130. }
  2131. }
  2132.  
  2133. try {
  2134. let redeemButtons = document.querySelectorAll('#free_points_rewards button');
  2135. redeemButtons[i].click();
  2136. i = i + 1;
  2137. } catch (err) {
  2138. }
  2139.  
  2140. if(i > 4) {
  2141. document.querySelector('#free_play_link_li a').click();
  2142. setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
  2143. return;
  2144. }
  2145. setTimeout(activateBonus.bind(null, i), 5000);
  2146. };
  2147. return {
  2148. run: run
  2149. };
  2150. },
  2151. createFPProcessor: function() {
  2152. let timeWaiting= 0;
  2153. function timedOut(addMs) {
  2154. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  2155. shared.closeWithError('TIMEOUT', '');
  2156. return true;
  2157. }
  2158.  
  2159. timeWaiting += addMs;
  2160. return false;
  2161. }
  2162.  
  2163. function ptcList() {
  2164. let result;
  2165. let runMsgDiv = document.querySelector('.alert.alert-info');
  2166. if (runMsgDiv) {
  2167. let runMsg = runMsgDiv.innerHTML;
  2168. if (runMsg.includes('invalid captcha')) {
  2169. // Warn? Usually a error if ptcList is refreshed
  2170. } else if (runMsg.includes('Good job')) {
  2171. // "Good job! You have been credited with 0.00000001 BTC."
  2172. try {
  2173. let idx = runMsg.search(/\d/);
  2174. let claimed = parseFloat(runMsg.slice(idx, idx + 10));
  2175. result = shared.getResult();
  2176. result.claimed = (result.claimed ?? 0) + claimed;
  2177. result.nextRoll = helpers.addMilliseconds(new Date(), helpers.getRandomMillisecondsFromMinutesRange(config.fp.hoursBetweenRuns * 60, 2)); // Wait hoursBetweenRuns +/- 1%
  2178. shared.updateWithoutClosing(result);
  2179. } catch { }
  2180. }
  2181. }
  2182.  
  2183. if ($('b:contains("Whoops!")').length) {
  2184. result = shared.getResult();
  2185. result.nextRoll = helpers.addMilliseconds(new Date(), helpers.getRandomMillisecondsFromMinutesRange(config.fp.hoursBetweenRuns * 60, 2)); // Wait hoursBetweenRuns +/- 2%
  2186. shared.closeWindow(result);
  2187. return;
  2188. }
  2189.  
  2190. let adButtons = $('button').filter(function(idx) {
  2191. return this.innerHTML.includes('VISIT AD FOR') > 0;
  2192. });
  2193.  
  2194. if (adButtons.length > 0) {
  2195. adButtons[0].click();
  2196. return;
  2197. }
  2198.  
  2199. if (timedOut(10000)) {
  2200. return;
  2201. }
  2202. setTimeout(ptcList, helpers.randomMs(10000, 12000));
  2203. }
  2204.  
  2205. function ptcSingle() {
  2206. if($('input[name="complete"]').is(':visible')) {
  2207. setTimeout(waitForCaptcha, 15000);
  2208. } else {
  2209. if (timedOut(5000)) {
  2210. return;
  2211. }
  2212. setTimeout(ptcSingle, helpers.randomMs(5000, 6000));
  2213. }
  2214. }
  2215.  
  2216. function waitForCaptcha() {
  2217. if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0 ) {
  2218. clickClaim();
  2219. } else {
  2220. if (timedOut(9000)) {
  2221. return;
  2222. }
  2223. setTimeout(waitForCaptcha, helpers.randomMs(9000, 11000));
  2224. }
  2225. }
  2226.  
  2227. function clickClaim() {
  2228. $('input[name="complete"]').focus();
  2229. $($('input[name="complete"]')[0]).attr("onclick", "");
  2230. $('input[name="complete"]').click();
  2231. //force close with timeout in case it's still opened
  2232. setTimeout(shared.closeWithError.bind(null, 'TIMEOUT', 'Timed out after clicking a CLAIM button.'), helpers.minToMs(config.defaults.timeout));
  2233. }
  2234.  
  2235. return {
  2236. ptcList: ptcList,
  2237. ptcSingle: ptcSingle
  2238. };
  2239. },
  2240. // TODO: refactor to add more faucets to this processor:
  2241. createGenericFaucetProcessor: function(wt) {
  2242. let webType = wt;
  2243. let countdownMinutes;
  2244. let timeWaiting= 0;
  2245. let selectElement = {
  2246. rollButton: function() {
  2247. switch (webType) {
  2248. case WebType.FREELITECOIN:
  2249. return document.getElementById('roll');
  2250. break;
  2251. case WebType.FREEETHEREUMIO:
  2252. return document.querySelector('#rollform button');
  2253. break;
  2254. default:
  2255. return;
  2256. break;
  2257. }
  2258. },
  2259. balance: function() {
  2260. switch (webType) {
  2261. case WebType.FREELITECOIN:
  2262. return document.getElementById('money');
  2263. break;
  2264. case WebType.FREEETHEREUMIO:
  2265. return document.getElementById('cryptovalue')
  2266. break;
  2267. default:
  2268. return;
  2269. break;
  2270. }
  2271. }
  2272. };
  2273.  
  2274. function timedOut(addMs) {
  2275. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  2276. shared.closeWithError('TIMEOUT', '');
  2277. return true;
  2278. }
  2279.  
  2280. timeWaiting += addMs;
  2281. return false;
  2282. }
  2283.  
  2284. function run() {
  2285. setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
  2286. };
  2287. function findCountdownOrRollButton() {
  2288. if ( isCountdownVisible() ) {
  2289. timeWaiting = 0;
  2290. let countdownMinutes = document.getElementById('cislo1');
  2291. let result = {};
  2292. result.balance = readBalance();
  2293. result.nextRoll = helpers.addMinutes(new Date(), countdownMinutes.innerHTML.toString());
  2294.  
  2295. shared.closeWindow(result);
  2296. return;
  2297. }
  2298.  
  2299. if ( isRollButtonVisible() ) {
  2300. if (isHCaptchaVisible()) {
  2301. waitForCaptcha();
  2302. } else {
  2303. clickRoll();
  2304. }
  2305. } else {
  2306. setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
  2307. }
  2308. };
  2309. function isCountdownVisible() {
  2310. return $(document.getElementById('cislo1')).is(':visible') || $(document.getElementById('cislo2')).is(':visible');
  2311. };
  2312. function isHCaptchaVisible() {
  2313. let hCaptchaFrame = document.querySelector('.h-captcha > iframe');
  2314. if (hCaptchaFrame && $(hCaptchaFrame).is(':visible')) {
  2315. return true;
  2316. }
  2317. return false;
  2318. };
  2319. function isRollButtonVisible() {
  2320. let rollButton = selectElement.rollButton();
  2321. return rollButton && $(rollButton).is(':visible');
  2322. };
  2323. function waitForCaptcha() {
  2324. if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0) {
  2325. clickRoll();
  2326. } else {
  2327. if (timedOut(10000)) {
  2328. return;
  2329. }
  2330.  
  2331. setTimeout(waitForCaptcha, helpers.randomMs(10000, 12000));
  2332. }
  2333. };
  2334. function clickRoll() {
  2335. try {
  2336. selectElement.rollButton().click();
  2337. setTimeout(processRunDetails, helpers.randomMs(10000, 12000));
  2338. } catch (err) {
  2339. shared.closeWithError('CLICK_ROLL_ERROR', err);
  2340. }
  2341. };
  2342. function processRunDetails() {
  2343. let info = document.getElementById('info');
  2344.  
  2345. if (info && $(info).is(':visible')) {
  2346. let result = {};
  2347. result.claimed = readClaimed();
  2348. result.balance = readBalance();
  2349. if(result.claimed != 0) {
  2350. result.rolledNumber = readRolledNumber();
  2351. result.nextRoll = helpers.addMinutes(new Date(), "60");
  2352. }
  2353. shared.closeWindow(result);
  2354. return;
  2355. }
  2356.  
  2357. if (timedOut(5000)) {
  2358. return;
  2359. }
  2360. setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
  2361. };
  2362. function readRolledNumber() {
  2363. let rolled = 0;
  2364. try {
  2365. rolled = parseInt(document.getElementById('numberroll').innerHTML);
  2366. } catch { }
  2367. return rolled;
  2368. };
  2369. function readBalance() {
  2370. let balance = 0;
  2371. try {
  2372. balance = selectElement.balance().innerHTML;
  2373. } catch { }
  2374. return balance;
  2375. };
  2376. function readClaimed() {
  2377. let claimed = 0;
  2378. try {
  2379. let info = document.getElementById('info').innerHTML;
  2380. let idx = info.search(/0\./);
  2381. claimed = parseFloat(info.slice(idx, idx + 10));
  2382. } catch { }
  2383. return claimed;
  2384. };
  2385.  
  2386. return {
  2387. run: run
  2388. };
  2389. },
  2390. createBagiKeranProcessor: function() {
  2391. let timeWaiting= 0;
  2392. let elements = {
  2393. errorDivs: function() {
  2394. return document.querySelectorAll('.alert.alert-danger');
  2395. },
  2396. warningDivs: function() {
  2397. return document.querySelectorAll('.alert.alert-warning');
  2398. },
  2399. successDivs: function() {
  2400. return document.querySelectorAll('.alert.alert-success');
  2401. },
  2402. errorCloudflare: function() {
  2403. return document.querySelector('#cf-error-details p');
  2404. },
  2405. openLoginModalButton: function() {
  2406. return document.getElementById('submit');
  2407. },
  2408. modal: function() {
  2409. return document.querySelector('#myModal.show');
  2410. },
  2411. addressInput: function() {
  2412. return document.querySelector('input[name="address"]');
  2413. },
  2414. submitButton: function() {
  2415. return document.querySelector('#myModal button[type="submit"]');
  2416. },
  2417. openClaimModalButton: function() {
  2418. return document.querySelector('form button[type="submit"]');
  2419. },
  2420. openWithdrawModal: function() {
  2421. return document.getElementById('submit');
  2422. },
  2423. linkWithdrawMinNotReached: function() {
  2424. return document.querySelector('a.btn.btn-primary.btn-block');
  2425. }
  2426. };
  2427.  
  2428. function timedOut(addMs) {
  2429. if (timeWaiting/1000 > config.defaults.timeout * 60) {
  2430. shared.closeWithError('TIMEOUT', '');
  2431. return true;
  2432. }
  2433.  
  2434. timeWaiting += addMs;
  2435. return false;
  2436. }
  2437.  
  2438. function run() {
  2439. readAlerts();
  2440. processIndex();
  2441. // setTimeout(processIndex, helpers.randomMs(1000, 3000));
  2442. };
  2443.  
  2444. function runCaptchaPage() {
  2445. readAlerts();
  2446. processCaptchaPage();
  2447. // setTimeout(processCaptchaPage, helpers.randomMs(1000, 3000));
  2448. }
  2449.  
  2450. function runWithdraw() {
  2451. readAlerts();
  2452. processWithdraw();
  2453. // setTimeout(processWithdraw, helpers.randomMs(1000, 3000));
  2454. }
  2455.  
  2456. function readAlerts() {
  2457. let elm;
  2458.  
  2459. elements.warningDivs().forEach(function (elem) {
  2460. if (elem && elem.innerText.includes('already claimed')) { // "You have already claimed in the last 60 minutes.<br>You can claim again in 59 minutes.<br>"
  2461. let result = {};
  2462. try {
  2463. let mins = elem.innerText.split('\n')[1].replace(/\D/g, '');
  2464. result.nextRoll = helpers.addMinutes(new Date(), mins);
  2465. } catch {
  2466. result.nextRoll = helpers.addMinutes(new Date(), "60");
  2467. }
  2468.  
  2469. if (shared.getCurrent().params.doWithdraw) {
  2470. shared.updateWithoutClosing(result);
  2471. window.location.href = (new URL('withdraw.php', window.location.href)).href;;
  2472. } else {
  2473. shared.closeWindow(result);
  2474. }
  2475. return;
  2476. }
  2477. });
  2478.  
  2479. elements.successDivs().forEach(function (elem) {
  2480. if (elem) {
  2481. if (elem.innerText.includes('claimed successfully')) { // "You've claimed successfully 2 Satoshi BTC." ...
  2482. let result = {};
  2483. result.nextRoll = helpers.addMinutes(new Date(), "60");
  2484. result.claimed = 0;
  2485.  
  2486. try {
  2487. let val = elem.innerText.split('\n')[0].replace(/\D/g, '');
  2488. if (typeof val == 'string') {
  2489. val = +val;
  2490. }
  2491. if (Number.isInteger(val)) {
  2492. val = val / 100000000;
  2493. }
  2494.  
  2495. result.claimed = val;
  2496. } catch { }
  2497.  
  2498. try {
  2499. let mins = elem.innerText.split('\n')[1].replace(/\D/g, '');
  2500. result.nextRoll = helpers.addMinutes(new Date(), mins);
  2501. } catch { }
  2502.  
  2503. if (shared.getCurrent().params.doWithdraw) {
  2504. shared.updateWithoutClosing(result);
  2505. let link = elem.querySelector('a');
  2506. if (link && link.innerText.includes('withdraw')) {
  2507. link.click();
  2508. return;
  2509. } else {
  2510. window.location.href = (new URL('withdraw.php', window.location.href)).href;;
  2511. }
  2512. }
  2513. shared.closeWindow(result);
  2514. return;
  2515. } else if (elem.innerText.includes('was sent to')) { //2 satoshi was sent to <a target="_blank" href="https://faucetpay.io/page/user-admin">your account at FaucetPay.io</a>
  2516. let result = {};
  2517. result.withdrawnAmount = 0;
  2518. let val = elem.innerHTML.split(' ')[0];
  2519. if (typeof val == 'string') {
  2520. val = +val;
  2521. }
  2522. if (Number.isInteger(val)) {
  2523. val = val / 100000000;
  2524. }
  2525.  
  2526. result.withdrawnAmount = val;
  2527. shared.closeWindow(result);
  2528. return;
  2529. }
  2530. }
  2531. });
  2532.  
  2533. elm = elements.errorCloudflare();
  2534. if (elm) {
  2535. // "Access denied | bagi.co.in used Cloudflare to restrict access" @document.title
  2536. shared.closeWithError('IP RESTRICTED', document.title + ' | ' + elm.innerText);
  2537. return;
  2538. }
  2539.  
  2540. elements.errorDivs().forEach(function (elem) {
  2541. if (elem) {
  2542. if (elem.innerText.includes('VPN/Proxy/Tor')) { // "VPN/Proxy/Tor is not allowed on this faucet." ...
  2543. shared.closeWithError('IP ERROR', elem.innerText);
  2544. return;
  2545. } else if (elem.innerText.includes('Claim not valid')) { // Claim not Valid, Please reClaim. <a href="index.php">Try again</a>
  2546. //might be a hcaptcha timeout (old hcaptcha solution). Maybe retry at least once
  2547. shared.closeWithError('INVALID CLAIM', elem.innerText);
  2548. return;
  2549. } else if (elem.innerText.includes('look valid')) { // The Bitcoin Address doesn't look valid
  2550. //invalid address
  2551. shared.closeWithError('INVALID ADDRESS', elem.innerText);
  2552. return;
  2553. } else if (elem.innerText.includes('Login Not Valid')) { // Login Not Valid, Please reLogin
  2554. // might be a login timeout (hCaptcha taking too long)
  2555. shared.closeWithError('LOGIN TIMEOUT', elem.innerText);
  2556. return;
  2557. } else if (elem.innerText.includes('Claim Not Valid')) { // Claim not Valid, Please reClaim. Try again
  2558. // might be a claim timeout (hCaptcha taking too long)
  2559. shared.closeWithError('CLAIM TIMEOUT', elem.innerText);
  2560. return;
  2561. } else {
  2562. // Unknown issue
  2563. shared.closeWithError('ERROR', elem.innerText);
  2564. return;
  2565. }
  2566. }
  2567. });
  2568. }
  2569.  
  2570. function processIndex() {
  2571. if (elements.modal() && elements.addressInput() && elements.submitButton()) { // 2. Fill address & click Login
  2572. elements.addressInput().value = shared.getCurrent().params.address;
  2573. elements.submitButton().click(); // shoud redirect but check for timeout
  2574. return;
  2575. }
  2576.  
  2577. if (elements.openLoginModalButton()) { // 1. Click the Get Started Button
  2578. elements.openLoginModalButton().click();
  2579. timeWaiting = 0;
  2580. setTimeout(processIndex, helpers.randomMs(1000, 3000));
  2581. return;
  2582. }
  2583.  
  2584. if (elements.openClaimModalButton()) { // Claim Bitcoin Button
  2585. elements.openClaimModalButton().click();
  2586. timeWaiting = 0;
  2587. setTimeout(processIndex, helpers.randomMs(2000, 4000));
  2588. return;
  2589. }
  2590.  
  2591. setTimeout(run, helpers.randomMs(2000, 4000));
  2592. };
  2593.  
  2594. function processCaptchaPage() {
  2595. if(elements.modal()) {
  2596. setTimeout(waitForCaptcha, helpers.randomMs(2000, 4000));
  2597. return;
  2598. }
  2599.  
  2600. if (elements.openLoginModalButton()) { // 1. Click the Claim Button to open the modal w/the hCaptcha
  2601. elements.openLoginModalButton().click();
  2602. timeWaiting = 0;
  2603. setTimeout(processCaptchaPage, helpers.randomMs(1000, 3000));
  2604. return;
  2605. }
  2606. setTimeout(runCaptchaPage, helpers.randomMs(2000, 4000));
  2607. }
  2608.  
  2609. function processWithdraw() {
  2610. if(elements.modal()) {
  2611. setTimeout(waitForCaptcha, helpers.randomMs(2000, 4000));
  2612. return;
  2613. }
  2614.  
  2615. if (elements.openWithdrawModal()) { // 1. Click the Withdraw to FaucetPay submit button to open the modal w/the hCaptcha
  2616. elements.openWithdrawModal().click();
  2617. timeWaiting = 0;
  2618. setTimeout(processWithdraw, helpers.randomMs(2000, 4000));
  2619. return;
  2620. }
  2621. setTimeout(runWithdraw, helpers.randomMs(2000, 4000));
  2622. }
  2623.  
  2624. function waitForCaptcha() {
  2625. //weird
  2626. let iframe = document.querySelector('.h-captcha > iframe');
  2627. if (!iframe) {
  2628. iframe = document.querySelector('.g-recaptcha > iframe');
  2629. }
  2630.  
  2631. if(iframe && iframe.getAttribute('data-hcaptcha-response').length > 0) {
  2632. //claim after hCaptcha
  2633. if(elements.submitButton()) {
  2634. elements.submitButton().click(); // should redirect
  2635. return;
  2636. }
  2637. }
  2638.  
  2639. if (timedOut(5000)) {
  2640. return;
  2641. }
  2642.  
  2643. setTimeout(waitForCaptcha, helpers.randomMs(5000, 6000));
  2644. };
  2645.  
  2646. return {
  2647. run: run,
  2648. runCaptchaPage: runCaptchaPage,
  2649. runWithdraw: runWithdraw
  2650. };
  2651. },
  2652. };
  2653.  
  2654. /**
  2655. * Prevents alert popups to be able to reload the faucet if invisible captcha validation fails
  2656. */
  2657. function overrideSelectNativeJS_Functions () {
  2658. window.alert = function alert (message) {
  2659. console.log (message);
  2660. }
  2661. }
  2662. function addJS_Node (text, s_URL, funcToRun) {
  2663. var scriptNode= document.createElement ('script');
  2664. scriptNode.type= "text/javascript";
  2665. if (text)scriptNode.textContent= text;
  2666. if (s_URL)scriptNode.src= s_URL;
  2667. if (funcToRun)scriptNode.textContent = '(' + funcToRun.toString() + ')()';
  2668.  
  2669. var element = document.getElementsByTagName ('head')[0] || document.body || document.documentElement;
  2670. element.appendChild (scriptNode);
  2671. }
  2672.  
  2673. function detectWeb() {
  2674. // TODO: Review for bagi/keran as it should consider the path too
  2675. if(!shared.isOpenedByManager(window.location.host)) {
  2676. return;
  2677. }
  2678.  
  2679. let currentFromManager = shared.getCurrent();
  2680.  
  2681. if (currentFromManager.type == WebType.STORMGAIN) {
  2682. SiteProcessor = objectGenerator.createSGProcessor();
  2683. setTimeout(SiteProcessor.run, helpers.randomMs(10000, 20000));
  2684. return;
  2685. }
  2686.  
  2687. if (currentFromManager.type == WebType.CRYPTOSFAUCETS) {
  2688. let expectedCfUrlType = helpers.cf.getUrlType(currentFromManager.url);
  2689. let realCfUrlType = helpers.cf.getUrlType(window.location.href);
  2690.  
  2691. switch(expectedCfUrlType) {
  2692. case CFUrlType.FREE:
  2693. switch(realCfUrlType) {
  2694. case CFUrlType.FREE:
  2695. if(localeConfig.setToEnglish) {
  2696. let refValue = $('.nav-item a')[4].innerHTML;
  2697. if (refValue != 'Settings') {
  2698. window.location.href = '/set-language/en';
  2699. }
  2700. }
  2701. addJS_Node (null, null, overrideSelectNativeJS_Functions);
  2702. SiteProcessor = objectGenerator.createCFProcessor();
  2703. interactions = objectGenerator.createInteractions();
  2704. setTimeout(SiteProcessor.run, helpers.randomMs(1000, 3000));
  2705. break;
  2706. case CFUrlType.CONTACTTWITTER:
  2707. //TODO: mark as possibly banned
  2708. break;
  2709. case CFUrlType.HOME:
  2710. if (config.cf.autologin) {
  2711. addJS_Node (null, null, overrideSelectNativeJS_Functions);
  2712. SiteProcessor = objectGenerator.createCFProcessor();
  2713. setTimeout(SiteProcessor.doLogin, helpers.randomMs(1000, 3000));
  2714. } else {
  2715. shared.closeWithError('NEED_TO_LOGIN', '');
  2716. }
  2717. break;
  2718. default:
  2719. break;
  2720. }
  2721. break;
  2722. case CFUrlType.PROMOTION:
  2723. SiteProcessor = objectGenerator.createCFProcessor();
  2724. interactions = objectGenerator.createInteractions();
  2725. setTimeout(SiteProcessor.runPromotion, helpers.randomMs(5000, 10000));
  2726. break;
  2727. }
  2728.  
  2729. return;
  2730. }
  2731.  
  2732. if (currentFromManager.type == WebType.FREEBITCOIN) {
  2733. SiteProcessor = objectGenerator.createFBProcessor();
  2734. setTimeout(SiteProcessor.run, helpers.randomMs(2000, 5000));
  2735. return;
  2736. }
  2737.  
  2738. if (currentFromManager.type == WebType.FREELITECOIN) {
  2739. SiteProcessor = objectGenerator.createGenericFaucetProcessor(currentFromManager.type);
  2740. let url = new URL(window.location.href);
  2741.  
  2742. if (url.pathname == '/') {
  2743. setTimeout(SiteProcessor.run, helpers.randomMs(2000, 5000));
  2744. } else if (url.pathname.includes('/login')) {
  2745. shared.closeWithError('NEED_TO_LOGIN', '');
  2746. }
  2747. return;
  2748. }
  2749.  
  2750. if (currentFromManager.type == WebType.FREEETHEREUMIO) {
  2751. SiteProcessor = objectGenerator.createGenericFaucetProcessor(currentFromManager.type);
  2752. let url = new URL(window.location.href);
  2753.  
  2754. if (url.pathname == '/free/') {
  2755. setTimeout(SiteProcessor.run(), helpers.randomMs(2000, 5000));
  2756. } else if (url.pathname == '/') {
  2757. shared.closeWithError('NEED_TO_LOGIN', '');
  2758. }
  2759. return;
  2760. }
  2761.  
  2762. if (currentFromManager.type == WebType.BAGIKERAN) {
  2763. SiteProcessor = objectGenerator.createBagiKeranProcessor();
  2764. let url = new URL(window.location.href);
  2765.  
  2766. if (url.href.includes('captha.php')) {
  2767. setTimeout(SiteProcessor.runCaptchaPage, helpers.randomMs(8000, 12000));
  2768. return;
  2769. } else if (url.href.includes('withdraw.php')) {
  2770. setTimeout(SiteProcessor.runWithdraw, helpers.randomMs(8000, 12000));
  2771. return;
  2772. } else {
  2773. setTimeout(SiteProcessor.run, helpers.randomMs(8000, 12000));
  2774. return;
  2775. }
  2776. return;
  2777. }
  2778.  
  2779. if (currentFromManager.type == WebType.FAUCETPAY) {
  2780. SiteProcessor = objectGenerator.createFPProcessor();
  2781. let url = new URL(window.location.href);
  2782.  
  2783. if(url.pathname.includes('ptc/view')) {
  2784. setTimeout(SiteProcessor.ptcSingle, helpers.randomMs(2000, 5000));
  2785. } else if (url.pathname.includes('ptc')) {
  2786. setTimeout(SiteProcessor.ptcList, helpers.randomMs(2000, 5000));
  2787. // } else if (url.pathname.includes('page/user-admin')) {
  2788. // // Try to claim Reward Points
  2789. } else if (url.pathname.includes('account/login')) {
  2790. shared.closeWithError('NEED_TO_LOGIN', '');
  2791. }
  2792. return;
  2793. }
  2794. }
  2795.  
  2796. function init() {
  2797. shared = objectGenerator.createShared();
  2798. persistence = objectGenerator.createPersistence();
  2799. if(window.location.host === 'satology.onrender.com') {
  2800. manager = objectGenerator.createManager();
  2801. CFPromotions = objectGenerator.createCFPromotions();
  2802. ui = objectGenerator.createUi();
  2803. CFHistory = objectGenerator.createCFHistory();
  2804.  
  2805. manager.init();
  2806. } else {
  2807. detectWeb();
  2808. }
  2809. }
  2810. init();
  2811. })();