Auto Claim with Monitor/Manager UI: StormGain Miner + 15 Faucets + Promo Codes processing


SUBMITTED BY: thelostcarlos

DATE: May 15, 2021, 4:50 p.m.

FORMAT: Text only

SIZE: 64.7 kB

HITS: 550

  1. // ==UserScript==
  2. // @name Auto Claim with Monitor/Manager UI: StormGain Miner + 15 Faucets + Promo Codes processing
  3. // @namespace satology.onrender.com
  4. // @version 1.0.7
  5. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  6. // @description MAIN FEATURES:
  7. // @description > Automatic hourly rolls for 15 faucets (ADA, BNB, BTC, DASH, DOGE, ETH, LINK, LTC, NEO, STEAM, TRX, USDC, USDT, XEM, XRP)
  8. // @description > Automatic activation of StormGain Miner (free BTC every 4 hours)
  9. // @description > Accepts promotion codes (http://twitter.com/cryptosfaucets, free roll shortlinks) for the 15 faucets
  10. // @description > Simple Monitor UI on top of a website to track progress (claims, next rolls, promo codes)
  11. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  12. // @description > The idea is to release future versions with more faucets & PTC (some for FaucetPay/ExpressCrypto) and user-friendly configurations
  13. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  14. // @description IMPORTANT CONSIDERATIONS:
  15. // @description 0. You need to enable popups on the Manager UI website to be able to open the faucets
  16. // @description 1. Promo codes (for now) must be manually added through the Manager UI:
  17. // @description You can add multiple codes and will be processed for each faucet after rolling.
  18. // @description After adding a new promo code, it will take a minute or so to save it. Then will
  19. // @description try to activate it right AFTER the next scheduled roll for each faucet and roll again.
  20. // @description For a smoother perfomance, once in a while click Remove ALL to delete the codes if the faucets already processed them.
  21. // @description 2. FAUCETS WEBSITES MUST OPEN IN ENGLISH TO BE ABLE TO RECOGNIZE IF THE PROMO CODE WAS ACCEPTED
  22. // @description In case you don't want to have them in English, you need to change the 3 strings the code uses for validation
  23. // @description (Search for localeStrings in the code and replace them)
  24. // @description 3. Autorolls will trigger ONLY when the faucet was opened by the Manager UI.
  25. // @description This is to allow users to navigate the websites to get the ShortLinks extra rolls, for example,
  26. // @description without having to stop the script.
  27. // @description 4. No AutoLogin implemented yet, so YOU MUST BE LOGGED IN
  28. // @description 5. You can disable faucets from the script in case you need to or you are not registered yet.
  29. // @description It would be great if you could use my referral links listed below if you need an account.
  30. // @description To disable them, just set enabled: false in the webList array, save the script & refresh the manager
  31. // @description 6. All data stored for tracking and to be displayed is stored locally in your environment. Nothing is uploaded.
  32. // @description
  33. // @description Always opened 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
  34. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  35. // @note [@1.0.7] Added 3 variables to a config object, to avoid endless waits:
  36. // @note > maxRefreshAttempts [default 4]: how many times a faucet will refresh if the roll fails in case of errors such as "Please refresh the
  37. // @note page to prove you are not a robot" alert; before moving to the next one.
  38. // @note > timeout [default 5 min]: time to wait for a faucet result after opening one
  39. // @note > moveAfterTimeout [default true]: to skip the faucet for 20 minutes if it timed out
  40. // @note More details about how these are used can be found in comments next to their declaration.
  41. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  42. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  43. // @description About the code:
  44. // @description Manager UI (monitor):
  45. // @description - Let's you keep track of last claimed amount, accumulated claims, total balance and next rolls.
  46. // @description - Controls the 'flow'. Opens a new tab to roll when needed and reads the results.
  47. // @description - Let's you add the promo codes and shows you the status of them for each faucet
  48. // @description - Everything is stored locally, but the Manager UI runs on top of a personal website with some ads
  49. // @description You can, of course, replace it with another URL, but please consider keeping it as a 'thank you' if you find the script useful/helpful
  50. // @description - HTML and CSS are basic/simple as the goal is only to show status data and I'm not a UI/UX expert
  51. // @description SGProcessor:
  52. // @description - Works on StormGain website
  53. // @description - Activates the miner whenever is stopped (every 4 hours)
  54. // @description - Saves the balance to be displayed on the Manager UI
  55. // @description CFProcessor:
  56. // @description - Works on the 15 faucets (.../free)
  57. // @description - Creates some random 'interaction'. You can disable interactions or adjust them a little.
  58. // @description Search for RandomInteractionLevel
  59. // @description - After clicking the roll button, waits for the countdown or reloads the page if the invisible captcha validation fails
  60. // @description - Stores the claimed amount, balance, rolled number and time for the Manager UI to update itself
  61. // @description - If the Roll button is not there, stores the countdown value to adjust the Manager UI next roll time
  62. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  63. // @description For upcoming updates:
  64. // @description - Keep a second window always opened to do all the navigation
  65. // @description - Extra antibot random actions like going back and forward from a random page in the website (FAQ, Stats, etc.)
  66. // @description - Display a message in the faucets UI to let the user know the process current status
  67. // @description - AutoLogin using local variables to store the credentials
  68. // @description - Enable/Disable faucet from the Manager UI
  69. // @description - Code refactor
  70. // @description - Implement FaucetPay PTC autoclicker (https://faucetpay.io/?r=1140585)
  71. // @description - Implement Freebitco.in autoclaim (https://freebitco.in/?r=41092365)
  72. // @description - Implement autonavigator for captcha faucets to automatically open and prompt for input when you can claim
  73. // @description - Implement auto claim for other faucets with 'weak' captcha validations
  74. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  75. // @description Links to create a new account using my referral:
  76. https://app.stormgain.com/friend/BNS17722452
  77. https://freecardano.com/?ref=346495
  78. https://freebinancecoin.com/?ref=176633
  79. https://freebitcoin.io/?ref=506599
  80. https://freedash.io/?ref=132684
  81. https://free-doge.com/?ref=199022
  82. https://freeethereum.com/?ref=218020
  83. https://freechainlink.io/?ref=84537
  84. https://free-ltc.com/?ref=127524
  85. https://freeneo.io/?ref=107888
  86. https://freesteam.io/?ref=122086
  87. https://free-tron.com/?ref=237317
  88. https://freeusdcoin.com/?ref=139322
  89. https://freetether.com/?ref=190533
  90. https://freenem.com/?ref=300886
  91. https://coinfaucet.io/?ref=822473
  92. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  93. // @description If you wanna team up or just share some ideas, you can contact me at satology@protonmail.com
  94. // @description ------------------------------------------------------------------------------------------------------------------------------------------------
  95. // @author satology
  96. // @grant GM_setValue
  97. // @grant GM_getValue
  98. // @grant window.close
  99. // @grant GM_openInTab
  100. // @icon https://www.google.com/s2/favicons?domain=stormgain.com
  101. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
  102. // @match https://satology.onrender.com/faucets/referrals*
  103. // @match https://app.stormgain.com/crypto-miner/
  104. // @match https://freecardano.com/free
  105. // @match https://freebinancecoin.com/free
  106. // @match https://freebitcoin.io/free
  107. // @match https://freedash.io/free
  108. // @match https://free-doge.com/free
  109. // @match https://freeethereum.com/free
  110. // @match https://freechainlink.io/free
  111. // @match https://free-ltc.com/free
  112. // @match https://freeneo.io/free
  113. // @match https://freesteam.io/free
  114. // @match https://free-tron.com/free
  115. // @match https://freeusdcoin.com/free
  116. // @match https://freetether.com/free
  117. // @match https://freenem.com/free
  118. // @match https://coinfaucet.io/free
  119. // @match https://freecardano.com/promotion/*
  120. // @match https://freebinancecoin.com/promotion/*
  121. // @match https://freebitcoin.io/promotion/*
  122. // @match https://free-doge.com/promotion/*
  123. // @match https://freedash.io/promotion/*
  124. // @match https://freeethereum.com/promotion/*
  125. // @match https://freechainlink.io/promotion/*
  126. // @match https://free-ltc.com/promotion/*
  127. // @match https://freeneo.io/promotion/*
  128. // @match https://freesteam.io/promotion/*
  129. // @match https://free-tron.com/promotion/*
  130. // @match https://freeusdcoin.com/promotion/*
  131. // @match https://freetether.com/promotion/*
  132. // @match https://freenem.com/promotion/*
  133. // @match https://coinfaucet.io/promotion/*
  134. // ==/UserScript==
  135. (function() {
  136. 'use strict';
  137. /**
  138. * Specific string values to check if a promotion code was succesfully processed (used via indexOf).
  139. * Defaults are set for English.
  140. * If you are viewing the faucets in another language, you will need to change them or
  141. * switch the faucets to English
  142. */
  143. const localeConfig = {
  144. stringSearches: {
  145. promoCodeAccepted: 'roll',
  146. promoCodeUsed: 'already used',
  147. promoCodeInvalid: 'not found',
  148. promoCodeInvalid2: 'only alphanumeric'
  149. }
  150. };
  151. const WebType = {
  152. CRYPTOSFAUCETS: 1,
  153. STORMGAIN: 2
  154. };
  155. const PromoStatus = {
  156. NOCODE: 0,
  157. PENDING: 1,
  158. ACCEPTED: 2,
  159. USEDBEFORE: 3,
  160. INVALID: 4,
  161. UNKNOWNERROR: 5
  162. };
  163. const RandomInteractionLevel = {
  164. NONE: 0,
  165. LOW: 1,
  166. MEDIUM: 2,
  167. HIGH: 3
  168. };
  169. let config = {
  170. maxRefreshAttempts: 4, // Use -1 to do unlimit attempts. Is the number of consecutive times it will try to refresh a faucet when failing to roll due to invisible captcha
  171. // ("Please Refresh the page to prove you are not a robot")
  172. // After reaching maxRefreshAttempts, the script will move to the next faucet, to prevent being flagged which could ban the IP for 24hs in that specific faucet.
  173. timeout: 5, // Use -1 to disable the timeout functionality. In minutes. Max time the monitor will wait for a result/roll.
  174. // After timeout is reached, the Manager/Monitor will assume something is wrong
  175. // (usually faucet tab being accidentally closed or failed to connect)
  176. // Will trigger a refresh on the Monitor website and carry on the process
  177. moveAfterTimeout: true, // If set to true, after a timeout the Monitor will skip the faucet, move to the next one and refresh itself
  178. }
  179. let persistence, shared, manager, ui, CFPromotions, interactions, SGProcessor, CFProcessor, CFHistory;
  180. let helpers = {
  181. cleanString: function(input) {
  182. var output = "";
  183. for (var i=0; i<input.length; i++) {
  184. if (input.charCodeAt(i) <= 127) {
  185. output += input.charAt(i);
  186. }
  187. }
  188. return output;
  189. },
  190. shuffle: function (array) {
  191. let currentIndex = array.length, temporaryValue, randomIndex;
  192. while (0 !== currentIndex) {
  193. randomIndex = Math.floor(Math.random() * currentIndex);
  194. currentIndex -= 1;
  195. temporaryValue = array[currentIndex];
  196. array[currentIndex] = array[randomIndex];
  197. array[randomIndex] = temporaryValue;
  198. }
  199. return array;
  200. },
  201. getPrintableTime: function (date = new Date()) {
  202. return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2)
  203. },
  204. getPrintableDateTime: function (date) {
  205. return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
  206. },
  207. getEnumText: function (enm, value) {
  208. return Object.keys(enm).find(key => enm[key] === value);
  209. },
  210. randomMs: function (a, b){
  211. return a + (b - a) * Math.random();
  212. },
  213. addMinutes: function(date, mins) {
  214. return date.setMinutes(date.getMinutes() + parseInt(mins) + 1);
  215. },
  216. randomInt: function(min, max) {
  217. return Math.floor(Math.random() * (max - min + 1) + min);
  218. },
  219. addMilliseconds: function(date, ms) {
  220. return date.setMilliseconds(date.getMilliseconds() + ms);
  221. },
  222. getEmojiForPromoStatus: function(promoStatus) {
  223. switch (promoStatus) {
  224. case PromoStatus.NOCODE:
  225. return '⚪';
  226. break;
  227. case PromoStatus.PENDING:
  228. return '⏳';
  229. break;
  230. case PromoStatus.ACCEPTED:
  231. return '✔️';
  232. break;
  233. case PromoStatus.USEDBEFORE:
  234. return '🕙';
  235. break;
  236. case PromoStatus.INVALID:
  237. return '❌';
  238. break;
  239. case PromoStatus.UNKNOWNERROR:
  240. return '❗';
  241. break;
  242. }
  243. }
  244. }
  245. let objectGenerator = {
  246. createPersistence: function() {
  247. const prefix = 'autoWeb_';
  248. function save(key, value, parseIt = false) {
  249. GM_setValue(prefix + key, parseIt ? JSON.stringify(value) : value);
  250. };
  251. function load(key, parseIt = false) {
  252. let value = GM_getValue(prefix + key);
  253. if(value && parseIt) {
  254. value = JSON.parse(value);
  255. }
  256. return value;
  257. };
  258. return {
  259. save: save,
  260. load: load
  261. };
  262. },
  263. createShared: function() {
  264. let flowControl;
  265. function isOpenedByManager(currentUrl) {
  266. loadFlowControl();
  267. if(!flowControl) {
  268. return false;
  269. }
  270. let millisecondsDistance = new Date() - flowControl.requestedTime;
  271. if(flowControl.opened || flowControl.url != currentUrl || millisecondsDistance > 120000) {
  272. return false;
  273. }
  274. return true;
  275. };
  276. function setFlowControl(id, url, webType) {
  277. flowControl = {
  278. id: id,
  279. url: url,
  280. type: webType,
  281. requestedTime: new Date(),
  282. opened: false,
  283. maxRefreshAttempts: config.maxRefreshAttempts,
  284. refreshAttempts: 0,
  285. maxRefreshReached: false,
  286. result: {}
  287. };
  288. persistence.save('flowControl', flowControl, true);
  289. };
  290. function wasVisited(expectedId) {
  291. loadFlowControl();
  292. return flowControl.id == expectedId && flowControl.opened;
  293. };
  294. function wasMaxRefreshReached(expectedId) {
  295. loadFlowControl();
  296. return flowControl.id == expectedId && flowControl.maxRefreshReached;
  297. };
  298. function getResult() {
  299. return flowControl.result;
  300. };
  301. function getCurrent() {
  302. let current = {};
  303. current.url = flowControl.url;
  304. current.type = flowControl.type;
  305. return current;
  306. };
  307. function saveAndclose(runDetails, delay = 0) {
  308. markAsVisited(runDetails);
  309. if(delay) {
  310. setTimeout(window.close, delay);
  311. } else {
  312. window.close();
  313. }
  314. };
  315. function closeWithMaxRefreshReached(delay = 0) {
  316. markAsMaxRefreshReached();
  317. if(delay) {
  318. setTimeout(window.close, delay);
  319. } else {
  320. window.close();
  321. }
  322. };
  323. function loadFlowControl() {
  324. flowControl = persistence.load('flowControl', true);
  325. };
  326. function markAsVisited(runDetails) {
  327. flowControl.opened = true;
  328. flowControl.result = runDetails;
  329. persistence.save('flowControl', flowControl, true);
  330. };
  331. function markAsMaxRefreshReached() {
  332. flowControl.maxRefreshReached = true;
  333. persistence.save('flowControl', flowControl, true);
  334. };
  335. function canDoRefresh() {
  336. flowControl.refreshAttempts++;
  337. persistence.save('flowControl', flowControl, true);
  338. if (flowControl.maxRefreshAttempts == -1 || flowControl.maxRefreshAttempts >= flowControl.refreshAttempts) {
  339. return true;
  340. } else {
  341. return false;
  342. }
  343. }
  344. return {
  345. setFlowControl: setFlowControl,
  346. wasVisited: wasVisited,
  347. isOpenedByManager: isOpenedByManager,
  348. getCurrent: getCurrent,
  349. getResult: getResult,
  350. closeWindow: saveAndclose,
  351. wasMaxRefreshReached: wasMaxRefreshReached,
  352. closeWithMaxRefreshReached: closeWithMaxRefreshReached,
  353. canDoRefresh: canDoRefresh
  354. };
  355. },
  356. createManager: function() {
  357. let timestamp = null;
  358. let timeWaiting = 0;
  359. let promoInterval;
  360. let webList = [
  361. { id: '1', name: 'ADA', url: 'https://freecardano.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  362. { id: '2', name: 'BNB', url: 'https://freebinancecoin.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  363. { id: '3', name: 'BTC', url: 'https://freebitcoin.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  364. { id: '4', name: 'DASH', url: 'https://freedash.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  365. { id: '5', name: 'ETH', url: 'https://freeethereum.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  366. { id: '6', name: 'LINK', url: 'https://freechainlink.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  367. { id: '7', name: 'LTC', url: 'https://free-ltc.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  368. { id: '8', name: 'NEO', url: 'https://freeneo.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  369. { id: '9', name: 'STEAM', url: 'https://freesteam.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  370. { id: '10', name: 'TRX', url: 'https://free-tron.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  371. { id: '11', name: 'USDC', url: 'https://freeusdcoin.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  372. { id: '12', name: 'USDT', url: 'https://freetether.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  373. { id: '13', name: 'XEM', url: 'https://freenem.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  374. { id: '14', name: 'XRP', url: 'https://coinfaucet.io/free', type: WebType.CRYPTOSFAUCETS, enabled: true },
  375. { id: '15', name: 'StormGain', url: 'https://app.stormgain.com/crypto-miner/', type: WebType.STORMGAIN, enabled: true },
  376. { id: '16', name: 'DOGE', url: 'https://free-doge.com/free', type: WebType.CRYPTOSFAUCETS, enabled: true }
  377. ];
  378. function start(){
  379. loader.initialize();
  380. ui.init(getCFlist());
  381. update();
  382. promoInterval = setInterval(manager.readNewPromoCode, 5000);
  383. setTimeout(manager.process, 10000);
  384. };
  385. let loader = function() {
  386. function initialize() {
  387. setTimestamp();
  388. initializeWebList();
  389. initializePromotions();
  390. initializeHistory();
  391. };
  392. function initializeWebList() {
  393. let storedData = persistence.load('webList', true);
  394. if(storedData) {
  395. let newOnes = addNewOnes(storedData);
  396. if (newOnes) {
  397. newOnes.forEach( function (element, idx, arr) {
  398. storedData.push(element);
  399. });
  400. }
  401. let disabledList = webList.filter( x => !x.enabled ).map( x => x.id );
  402. storedData.forEach( function (element, idx, arr) {
  403. arr[idx].nextRoll = element.nextRoll ? new Date(element.nextRoll) : new Date();
  404. arr[idx].enabled = !disabledList.includes(element.id);
  405. });
  406. webList = storedData;
  407. setup();
  408. } else {
  409. setup(true);
  410. }
  411. };
  412. function addNewOnes(storedData) {
  413. let allIds = webList.map( x => x.id );
  414. let storedIds = storedData.map( x => x.id );
  415. let newOnes = allIds.filter( x => !storedIds.includes(x) );
  416. return webList.filter( x => newOnes.includes(x.id) );
  417. };
  418. function initializePromotions() {
  419. let storedData = persistence.load('CFPromotions', true);
  420. if (storedData) {
  421. storedData.forEach( function (element, idx, arr) {
  422. arr[idx].added = new Date(element.added);
  423. });
  424. CFPromotions.load(storedData);
  425. }
  426. };
  427. function initializeHistory() {
  428. CFHistory.initOrLoad();
  429. };
  430. function setTimestamp() {
  431. timestamp = new Date().getTime();
  432. persistence.save('timestamp', timestamp);
  433. };
  434. function removeDisabledFaucets() {
  435. webList = webList.filter(x => x.enabled);
  436. };
  437. function setup(reset = false) {
  438. removeDisabledFaucets();
  439. if(reset) {
  440. helpers.shuffle(webList);
  441. }
  442. let timeDistance = 0;
  443. webList.forEach( function (element, idx, arr) {
  444. if (reset || !element.lastClaim) {
  445. arr[idx].lastClaim = 0;
  446. }
  447. if (reset || !element.aggregate) {
  448. arr[idx].aggregate = 0;
  449. }
  450. if (reset || !element.balance) {
  451. arr[idx].balance = 0;
  452. }
  453. if (reset || !element.nextRoll) {
  454. timeDistance += helpers.randomMs(10000, 15000);
  455. arr[idx].nextRoll = new Date(helpers.addMilliseconds(new Date(), timeDistance));
  456. }
  457. });
  458. };
  459. return {
  460. initialize: initialize
  461. };
  462. }();
  463. function update(sortIt = true) {
  464. if(sortIt) {
  465. webList.sort((a,b) => a.nextRoll.getTime() - b.nextRoll.getTime());
  466. }
  467. persistence.save('webList', webList, true);
  468. ui.refresh(webList, CFPromotions.getAll());
  469. updateRollStatsSpan();
  470. };
  471. function process() {
  472. if(isObsolete()) {
  473. return;
  474. }
  475. if(webList[0].nextRoll.getTime() < (new Date()).getTime()) {
  476. ui.log('Opening: ' + webList[0].name);
  477. open();
  478. } else {
  479. let timeUntilNext = webList[0].nextRoll.getTime() - (new Date()).getTime() + helpers.randomMs(1000, 2000);
  480. ui.log('Waiting ' + (timeUntilNext/1000/60).toFixed(2) + ' minutes...');
  481. setTimeout(manager.process, timeUntilNext);
  482. }
  483. };
  484. function isObsolete() {
  485. let savedTimestamp = persistence.load('timestamp');
  486. if (savedTimestamp && savedTimestamp > timestamp) {
  487. ui.log('<b>STOPING EXECUTION!<b> A new Manager UI window was opened. Process should continue there');
  488. clearInterval(promoInterval);
  489. return true;
  490. }
  491. return false;
  492. };
  493. function open(promoCode) {
  494. let navUrl = webList[0].url;
  495. if(promoCode) {
  496. navUrl = getPromoUrl(promoCode);
  497. }
  498. shared.setFlowControl(webList[0].id, navUrl, webList[0].type);
  499. setTimeout(manager.resultReader, 15000);
  500. // var win = window.open(navUrl, '', 'noopener,noreferrer');
  501. GM_openInTab(navUrl, 'loadInBackground');
  502. };
  503. function getPromoUrl(promoCode) {
  504. ui.log('Creating Promo Code URL...');
  505. let url = webList[0].url;
  506. url = url.slice(0, url.length - 4);
  507. return url + "promotion/" + promoCode;
  508. }
  509. function resultReader() {
  510. if(isObsolete()) {
  511. return;
  512. }
  513. if(shared.wasVisited(webList[0].id)) {
  514. timeWaiting = 0;
  515. let result = shared.getResult();
  516. if (result) {
  517. updateWebListItem(result);
  518. if ( (webList[0].type == WebType.CRYPTOSFAUCETS) &&
  519. ( (result.claimed) || (result.promoStatus && result.promoStatus != PromoStatus.ACCEPTED) )) {
  520. let promoCode = CFPromotions.hasPromoAvailable(webList[0].id);
  521. if (promoCode) {
  522. update(false);
  523. open(promoCode);
  524. return;
  525. }
  526. }
  527. } else {
  528. ui.log('Unable to read last run result, for ID: ' + webList[0].id + ' > ' + webList[0].name);
  529. }
  530. update(true);
  531. process();
  532. return;
  533. } else if (shared.wasMaxRefreshReached(webList[0].id)) {
  534. timeWaiting = 0;
  535. webList[0].nextRoll = new Date(helpers.addMinutes(new Date(), "20"));
  536. ui.log('Skipping ' + webList[0].name + ': too many unsuccessful attempts to roll');
  537. update(true);
  538. process();
  539. return;
  540. } else {
  541. timeWaiting += 15;
  542. if (config.timeout != -1 && (timeWaiting > (config.timeout * 60)) ) {
  543. ui.log('Waited too much time for ' + webList[0].name + ' results: triggering timeout');
  544. if (config.moveAfterTimeout) {
  545. webList[0].nextRoll = new Date(helpers.addMinutes(new Date(), "20"));
  546. update(true);
  547. }
  548. window.location.reload();
  549. return;
  550. }
  551. ui.log('Waiting for ' + webList[0].name + ' results...', timeWaiting);
  552. setTimeout(manager.resultReader, 15000);
  553. }
  554. };
  555. function updateWebListItem(result) {
  556. ui.log('Updating data: ' + JSON.stringify(result));
  557. if (result.claimed) {
  558. result.claimed = parseFloat(result.claimed);
  559. if(!isNaN(result.claimed)) {
  560. webList[0].lastClaim = result.claimed;
  561. webList[0].aggregate += result.claimed;
  562. }
  563. }
  564. if(result.balance) {
  565. webList[0].balance = result.balance;
  566. }
  567. if(result.nextRoll) {
  568. webList[0].nextRoll = new Date(result.nextRoll);
  569. }
  570. if(result.promoStatus) {
  571. CFPromotions.updateFaucetForCode(result.promoCode, webList[0].id, result.promoStatus);
  572. }
  573. if(result.rolledNumber) {
  574. CFHistory.addRoll(result.rolledNumber);
  575. }
  576. };
  577. function readNewPromoCode() {
  578. let promoCodeElement = $('#promo-code-new')[0];
  579. let promoCode = helpers.cleanString(promoCodeElement.innerText);
  580. let promoDisplayStatus = $('#promo-display-status')[0];
  581. if (promoCode == 'REMOVEALLPROMOS' ) {
  582. CFPromotions.removeAll();
  583. promoCodeElement.innerText = '';
  584. promoDisplayStatus.innerHTML = 'Promo codes removed!';
  585. ui.refresh(null, CFPromotions.getAll());
  586. } else if(promoCode != '') {
  587. CFPromotions.addNew(promoCode);
  588. promoCodeElement.innerText = '';
  589. $('#promo-text-input').val('');
  590. promoDisplayStatus.innerHTML = 'Code ' + promoCode + ' added!';
  591. ui.log('Promo code ' + promoCode + ' added');
  592. ui.refresh(null, CFPromotions.getAll());
  593. }
  594. };
  595. function updateRollStatsSpan() {
  596. let rollsSpanElement = $('#rolls-span')[0];
  597. rollsSpanElement.innerText = CFHistory.getRollsMeta().join(',');
  598. };
  599. function getCFlist() {
  600. let items;
  601. items = webList.filter(f => f.type === WebType.CRYPTOSFAUCETS);
  602. items = items.map(x => {
  603. return {
  604. id: x.id,
  605. name: x.name
  606. };});
  607. items.sort((a, b) => (a.name > b.name) ? 1 : -1);
  608. return items;
  609. };
  610. return{
  611. init:start,
  612. process: process,
  613. resultReader: resultReader,
  614. getFaucetsForPromotion: getCFlist,
  615. readNewPromoCode: readNewPromoCode
  616. };
  617. },
  618. createUi: function() {
  619. let logLines = ['', '', '', '', ''];
  620. function init(cfFaucets) {
  621. appendCSS();
  622. appendJavaScript();
  623. appendHtml();
  624. createPromoTable(cfFaucets);
  625. };
  626. function appendCSS() {
  627. let css = '';
  628. $('head').append(css);
  629. };
  630. function appendJavaScript() {
  631. let js = '';
  632. js += '<script language="text/javascript">';
  633. js += 'var myBarChart;';
  634. js += 'function savePromoCode() {';
  635. js += 'var promoText = document.getElementById("promo-text-input");';
  636. js += 'var promoCode = document.getElementById("promo-code-new");';
  637. js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
  638. js += 'promoCode.innerHTML = promoText.value.trim();';
  639. js += 'promoDisplayStatus.innerHTML = "Adding code&nbsp&quot;<b>" + promoCode.innerHTML + "</b>&quot;... This could take around a minute. Please wait..."';
  640. js += '}';
  641. js += 'function removeAllPromos() {';
  642. js += 'var promoCode = document.getElementById("promo-code-new");';
  643. js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
  644. js += 'promoCode.innerHTML = "REMOVEALLPROMOS";';
  645. js += 'promoDisplayStatus.innerHTML = "Removing all promotion codes... This could take around a minute. Please wait..."';
  646. js += '}';
  647. js += 'function openStatsChart() {';
  648. js += 'if(myBarChart) { myBarChart.destroy(); }';
  649. js += 'let statsFragment = document.getElementById("stats-fragment");';
  650. js += 'if (statsFragment.style.display === "block") { statsFragment.style.display = "none"; document.getElementById("stats-button").innerText = "Lucky Number Stats"; } else {';
  651. js += 'statsFragment.style.display = "block"; document.getElementById("stats-button").innerText = "Close Stats";';
  652. js += 'var canvas = document.getElementById("barChart");';
  653. js += 'var ctx = canvas.getContext("2d");';
  654. js += 'var dataSpan = document.getElementById("rolls-span");';
  655. js += 'var data = {';
  656. js += 'labels: ["0000-9885", "9886-9985", "9986-9993", "9994-9997", "9998-9999", "10000"],';
  657. js += 'datasets: [ { fill: false, backgroundColor: [ "#990000", "#660066", "#000099", "#ff8000", "#ffff00", "#00ff00"],';
  658. js += 'data: dataSpan.innerText.split(",") } ] };';
  659. js += 'var options = { plugins: { legend: { display: false } }, title: { display: true, text: "Rolled Numbers", position: "top" }, rotation: -0.3 * Math.PI };';
  660. js += 'myBarChart = new Chart(ctx, { type: "pie", data: data, options: options }); } }';
  661. js += '</script>';
  662. $('head').append(js);
  663. };
  664. function appendHtml() {
  665. let html ='';
  666. html += '<pre style="width:100%;" id="console-log"><b>Loading...</b></pre>';
  667. html += '<section id="stats-fragment" class="fragment" style="display:none;"><div class="container-fluid bg-dark "><div class="container py-1 "><div class="row align-items-center text-center justify-content-center">';
  668. html += '<div class="col-md-3"><canvas id="barChart"></canvas><span id="rolls-span" style="display:none;"></span></div></div></div></div></div></section>';
  669. 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>';
  670. html += '<div class="title col-6 w-100 text-white"></div><div class="title col-3 text-right"><a class="btn m-2 anchor btn-outline-primary" id="stats-button" onclick="openStatsChart()">Lucky Number Stats</a></div></div>';
  671. html += '<div class="row align-items-center text-center justify-content-end">';
  672. 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></section>';
  673. html +='<section id="table-struct-promo" class="fragment "><div class="container-fluid bg-dark "><div class="container py-1 "><div class="row mx-0">';
  674. html +='<div class="title col-3 px-0 text-white"><h2>Promo Codes</h2></div><div class="title col-3 w-100 text-white">';
  675. html +='<div class="input-group my-0"><input type="text" class="form-control py-1" id="promo-text-input" placeholder="Type a Promo code...">';
  676. html +='<div class="input-group-append"><button class="btn btn-success" id="promo-button" onclick="savePromoCode()"><i class="fa fa-plus"></i></button>';
  677. html +='</div></div></div><div class="title col-4 text-white justify-content-end"><span id="promo-display-status" class="text-white"></span>';
  678. 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>';
  679. html +='</div></div><div class="row align-items-center text-center justify-content-end"><div class="col-12 order-lg-1 text-center">';
  680. html +='<div class="row justify-content-center"><div class="col table-responsive" id="promo-container"></div></div></div></div></div></div></section>';
  681. $('#referral-table').before(html);
  682. $('#schedule-container').append( createScheduleTable() );
  683. };
  684. function createPromoTable(faucets) {
  685. let tableStructure = '';
  686. tableStructure += '<table class="table table-bordered text-white" id="promo-table">';
  687. tableStructure += '<caption style="text-align: -webkit-center;">⏳ Pending ✔️ Accepted 🕙 Used Before ❌ Invalid code ❗ Unknown error ⚪ No code</caption>';
  688. tableStructure += '<thead><tr><th class="">Code</th><th class="">Added</th>';
  689. for (let i = 0, all = faucets.length; i < all; i++) {
  690. tableStructure += '<th data-faucet-id="' + faucets[i].id + '">' + faucets[i].name + '</th>';
  691. }
  692. tableStructure += '</tr></thead><tbody id="promo-table-body"></tbody></table>';
  693. $('#promo-container').append( tableStructure );
  694. };
  695. function createScheduleTable() {
  696. let tableStructure = '';
  697. tableStructure += '<table class="table table-bordered text-white" id="schedule-table"><thead><tr>';
  698. tableStructure += '<th class="hide-on-mobile">#</th><th class="">Name</th><th class="">Last Claim</th>';
  699. tableStructure += '<th class="hide-on-mobile">Aggregate</th><th class="hide-on-mobile">Balance</th><th class="">Next Roll</th>';
  700. tableStructure += '</tr></thead><tbody id="schedule-table-body"></tbody></table>';
  701. return tableStructure;
  702. };
  703. function loadScheduleTable(data) {
  704. let tableBody = '';
  705. for(let i=0, all = data.length; i < all; i++) {
  706. tableBody += '<tr class="align-middle" data-id="' + data[i].id + '">';
  707. tableBody +='<td class="align-middle hide-on-mobile">' + (i + 1).toString() + '</td>';
  708. tableBody +='<td class="align-middle">' + data[i].name + '</td>';
  709. tableBody +='<td class="align-middle">' + data[i].lastClaim.toFixed(8) + '</td>';
  710. tableBody +='<td class="align-middle hide-on-mobile">' + data[i].aggregate.toFixed(8) + '</td>';
  711. tableBody +='<td class="align-middle hide-on-mobile">' + (data[i].balance ? data[i].balance.split(' ')[0] : "") + '</td>';
  712. tableBody +='<td class="align-middle">' + helpers.getPrintableTime(data[i].nextRoll) + '</td>';
  713. tableBody +='</tr>';
  714. }
  715. $('#schedule-table-body').html(tableBody);
  716. };
  717. function loadPromotionTable(codes) {
  718. let tableBody = '';
  719. for(let c=0; c < codes.length; c++) {
  720. let data = codes[c];
  721. tableBody += '<tr data-promotiobn-id="' + data.id + '">';
  722. tableBody += '<td class="align-middle">' + data.code + '</td>';
  723. tableBody +='<td class="align-middle">' + helpers.getPrintableDateTime(data.added) + '</td>';
  724. for(let i=0, all = data.statusPerFaucet.length; i < all; i++) {
  725. tableBody +='<td class="align-middle">' + helpers.getEmojiForPromoStatus(data.statusPerFaucet[i].status ?? 0) + '</td>';
  726. }
  727. tableBody +='</tr>';
  728. }
  729. $('#promo-table-body').html(tableBody);
  730. };
  731. function refresh(scheduleData, promotionData) {
  732. if (scheduleData) {
  733. loadScheduleTable(scheduleData);
  734. }
  735. if (promotionData) {
  736. loadPromotionTable(promotionData);
  737. }
  738. };
  739. function log(msg, elapsed = false) {
  740. if(msg) {
  741. let previous = logLines[0].split('&nbsp')[1];
  742. if(elapsed && (previous == msg)) {
  743. logLines[0] = helpers.getPrintableTime() + '&nbsp' + msg + '&nbsp[Elapsed time:&nbsp' + elapsed + '&nbspseconds]';
  744. } else {
  745. logLines.pop();
  746. logLines.unshift(helpers.getPrintableTime() + '&nbsp' + msg);
  747. }
  748. $('#console-log').html(logLines.join('<br>'));
  749. }
  750. };
  751. return {
  752. init: init,
  753. refresh: refresh,
  754. loadPromotionTable: loadPromotionTable,
  755. log: log
  756. }
  757. },
  758. createCFPromotions: function() {
  759. let codes = [];
  760. function PromotionCode(id, code) {
  761. this.id = id;
  762. this.code = code;
  763. this.added = new Date();
  764. this.statusPerFaucet = [];
  765. };
  766. function updateFaucetStatusInPromo(promo, faucetId, newStatus) {
  767. };
  768. function getFaucetStatusInPromo(promo, faucetId) {
  769. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  770. return faucet.status ?? PromoStatus.NOCODE;
  771. };
  772. function addNew(code) {
  773. let newPromo = new PromotionCode(codes.length, code);
  774. newPromo.statusPerFaucet = manager.getFaucetsForPromotion();
  775. newPromo.statusPerFaucet.forEach(function (element, idx, arr) {
  776. arr[idx].status = PromoStatus.PENDING;
  777. });
  778. codes.push(newPromo);
  779. codes.sort((a, b) => (a.id < b.id) ? 1 : -1);
  780. save();
  781. };
  782. function getAll() {
  783. return codes;
  784. };
  785. function updateFaucetForCode(code, faucetId, newStatus) {
  786. let promo = codes.find(x => x.code == code);
  787. let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
  788. if(faucet) {
  789. faucet.status = newStatus;
  790. }
  791. save();
  792. };
  793. function hasPromoAvailable(faucetId) {
  794. let resp = false;
  795. codes.forEach(function (promotion, idx, arr) {
  796. let status = getFaucetStatusInPromo(promotion, faucetId);
  797. if (status == PromoStatus.PENDING) {
  798. resp = promotion.code;
  799. return;
  800. }
  801. });
  802. return resp;
  803. };
  804. function save() {
  805. persistence.save('CFPromotions', getAll(), true);
  806. };
  807. function load(data) {
  808. codes = data;
  809. };
  810. function removeAll() {
  811. codes = [];
  812. save();
  813. };
  814. return {
  815. addNew: addNew,
  816. removeAll: removeAll,
  817. getAll: getAll,
  818. load: load,
  819. updateFaucetForCode: updateFaucetForCode,
  820. hasPromoAvailable: hasPromoAvailable
  821. }
  822. },
  823. createInteractions: function(){
  824. let randomInteractionLevel = RandomInteractionLevel.LOW;
  825. let maxActions = 0;
  826. let performedActions = -1;
  827. let selectableElements;
  828. let actions = {
  829. available: [
  830. function() {
  831. $('html, body').animate({
  832. scrollTop: helpers.randomInt(0, $('html, body').get(0).scrollHeight)
  833. }, {
  834. complete: setTimeout(interactions.addPerformed, helpers.randomMs(100, 3000)),
  835. duration: helpers.randomMs(100, 1500)
  836. });
  837. },
  838. function() {
  839. let element = interactions.selectableElements[helpers.randomInt(0, interactions.selectableElements.length - 1)];
  840. try {
  841. if (document.body.createTextRange) {
  842. const range = document.body.createTextRange();
  843. range.moveToElementText(element);
  844. range.select();
  845. } else if (window.getSelection) {
  846. const selection = window.getSelection();
  847. const range = document.createRange();
  848. range.selectNodeContents(element);
  849. selection.removeAllRanges();
  850. selection.addRange(range);
  851. }
  852. } catch (err) { }
  853. interactions.addPerformed();
  854. }
  855. ]
  856. };
  857. function start(selectableElements) {
  858. performedActions = 0;
  859. switch(randomInteractionLevel) {
  860. case RandomInteractionLevel.NONE:
  861. maxActions = 0;
  862. break;
  863. case RandomInteractionLevel.LOW:
  864. maxActions = helpers.randomInt(2, 4);
  865. break;
  866. case RandomInteractionLevel.MEDIUM:
  867. maxActions = helpers.randomInt(5, 8);
  868. break;
  869. case RandomInteractionLevel.HIGH:
  870. maxActions = helpers.randomInt(12, 16);
  871. break;
  872. }
  873. interactions.selectableElements = selectableElements;
  874. performActions();
  875. }
  876. function performActions() {
  877. if(performedActions >= maxActions) {
  878. return;
  879. }
  880. let delay = 0;
  881. for(let i = 0; i < maxActions; i++) {
  882. delay += helpers.randomMs(350, 1500);
  883. setTimeout(actions.available[helpers.randomInt(0, actions.available.length - 1)], delay);
  884. }
  885. }
  886. function addPerformed() {
  887. performedActions++;
  888. }
  889. function completed() {
  890. return (performedActions >= maxActions);
  891. }
  892. return {
  893. start: start,
  894. completed: completed,
  895. addPerformed: addPerformed,
  896. selectableElements: selectableElements
  897. };
  898. },
  899. createSGProcessor: function() {
  900. let timerSpans;
  901. function run() {
  902. if(isLoading()) {
  903. setTimeout(SGProcessor.run, helpers.randomMs(5000, 10000));
  904. return;
  905. } else {
  906. if(isMinerActive()) {
  907. processRunDetails();
  908. } else {
  909. activateMiner();
  910. }
  911. }
  912. };
  913. function isLoading() {
  914. return $('#loader-logo').length;
  915. };
  916. function isMinerActive() {
  917. timerSpans = $('.mb-8 .wrapper .mb-1 span');
  918. if(timerSpans.length > 0) {
  919. return true;
  920. } else {
  921. return false;
  922. }
  923. return (timerSpans.length === 0);
  924. };
  925. function activateMiner() {
  926. const activateButton = document.querySelector('.mb-8 .wrapper button');
  927. if (activateButton) {
  928. activateButton.click();
  929. setTimeout(SGProcessor.processRunDetails, helpers.randomMs(10000, 20000));
  930. } else {
  931. if(!is404Error()) {
  932. SGProcessor.processRunDetails()
  933. }
  934. }
  935. };
  936. function is404Error() {
  937. const h1 = document.getElementsByTagName('h1');
  938. if (h1.length > 0 && h1[0].innerText.includes('404')) {
  939. window.location.reload();
  940. return true;
  941. }
  942. return false;
  943. }
  944. function processRunDetails() {
  945. let result = {};
  946. result.nextRoll = helpers.addMinutes(new Date(), readCountdown().toString());
  947. result.balance = readBalance();
  948. shared.closeWindow(result);
  949. };
  950. function readCountdown() {
  951. let mins = 241;
  952. try {
  953. let timeLeft = timerSpans.last().text().split(':');
  954. if(timeLeft.length === 3) {
  955. mins = parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
  956. }
  957. } catch (err) { }
  958. return mins;
  959. };
  960. function readBalance() {
  961. let balance = "";
  962. try {
  963. balance = $('span.text-accent').first().text() + " BTC";
  964. } catch (err) { }
  965. return balance;
  966. };
  967. return {
  968. run: run,
  969. processRunDetails: processRunDetails
  970. };
  971. },
  972. createCFProcessor: function() {
  973. const NavigationProcess = {
  974. ROLLING: 1,
  975. PROCESSING_PROMOTION: 2
  976. };
  977. let navigationProcess;
  978. let countdown;
  979. let rollButton;
  980. let promotionTag;
  981. let timeWaiting= 0;
  982. function run() {
  983. navigationProcess = NavigationProcess.ROLLING;
  984. displayStatusUi();
  985. setTimeout(CFProcessor.findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  986. };
  987. function runPromotion() {
  988. navigationProcess = NavigationProcess.PROCESSING_PROMOTION
  989. displayStatusUi();
  990. setTimeout(CFProcessor.findPromotionTag, helpers.randomMs(1000, 3000));
  991. };
  992. function findCountdownOrRollButton() {
  993. if( isCountdownVisible() && !isRollButtonVisible() ) {
  994. timeWaiting = 0;
  995. processRunDetails();
  996. } else if ( !isCountdownVisible() && isRollButtonVisible() ) {
  997. timeWaiting = 0;
  998. interact();
  999. } else {
  1000. if (timeWaiting/1000 > helpers.randomInt(5, 65)) {
  1001. if (shared.canDoRefresh()) {
  1002. window.location.reload();
  1003. } else {
  1004. shared.closeWithMaxRefreshReached();
  1005. }
  1006. return;
  1007. }
  1008. timeWaiting += 3000;
  1009. setTimeout(CFProcessor.findCountdownOrRollButton, helpers.randomMs(2000, 5000));
  1010. }
  1011. };
  1012. function interact() {
  1013. let selectables = []
  1014. selectables = selectables.concat($('td').toArray());
  1015. selectables = selectables.concat($('p').toArray());
  1016. selectables = selectables.concat($('th').toArray());
  1017. interactions.start(selectables);
  1018. setTimeout(CFProcessor.waitInteractions, helpers.randomMs(2000, 4000));
  1019. }
  1020. function waitInteractions() {
  1021. if(interactions.completed()) {
  1022. roll();
  1023. } else {
  1024. setTimeout(CFProcessor.waitInteractions, helpers.randomMs(2000, 4000));
  1025. }
  1026. }
  1027. function isCountdownVisible() {
  1028. countdown = $('.timeout-wrapper');
  1029. return ($(countdown).length > 0 && $(countdown[0]).is(':visible'));
  1030. };
  1031. function isRollButtonVisible() {
  1032. rollButton = $('.main-button-2.roll-button.bg-2');
  1033. return ($(rollButton).length > 0 && $(rollButton[0]).is(':visible'));
  1034. };
  1035. function roll() {
  1036. $(rollButton[0]).click();
  1037. setTimeout(CFProcessor.findCountdownOrRollButton, helpers.randomMs(2000, 3000));
  1038. }
  1039. function isPromotionTagVisible() {
  1040. let pTags = $('p');
  1041. if (pTags.length > 0) {
  1042. promotionTag = $('p')[0];
  1043. return true;
  1044. }
  1045. return false;
  1046. };
  1047. function findPromotionTag() {
  1048. if( isPromotionTagVisible() ) {
  1049. processRunDetails();
  1050. } else {
  1051. setTimeout(CFProcessor.findPromotionTag, helpers.randomMs(2000, 5000));
  1052. }
  1053. };
  1054. function processRunDetails() {
  1055. let result = {};
  1056. if(navigationProcess == NavigationProcess.ROLLING) {
  1057. result.nextRoll = readCountdown();
  1058. result.claimed = readClaimed();
  1059. result.balance = readBalance();
  1060. if(result.claimed != 0) {
  1061. result.rolledNumber = readRolledNumber();
  1062. }
  1063. result.balance = readBalance();
  1064. } else if (navigationProcess == NavigationProcess.PROCESSING_PROMOTION) {
  1065. result.promoStatus = readPromoStatus();
  1066. result.promoCode = readPromoCode();
  1067. if (result.promoStatus == PromoStatus.ACCEPTED) {
  1068. result.nextRoll = helpers.addMinutes(new Date(), "-120");
  1069. }
  1070. }
  1071. shared.closeWindow(result);
  1072. };
  1073. function readCountdown() {
  1074. let minsElement = $('.timeout-container .minutes .digits');
  1075. let mins = "0";
  1076. if ($(minsElement).length > 0) {
  1077. mins = $(minsElement)[0].innerHTML;
  1078. }
  1079. if (mins) {
  1080. return helpers.addMinutes(new Date(), mins.toString());
  1081. } else {
  1082. return null;
  1083. }
  1084. };
  1085. function readClaimed() {
  1086. let claimed = 0;
  1087. try {
  1088. claimed = $('.result')[0].innerHTML;
  1089. claimed = claimed.trim();
  1090. claimed = claimed.slice(claimed.lastIndexOf(" ") + 1);
  1091. } catch(err) { }
  1092. return claimed;
  1093. };
  1094. function readRolledNumber() {
  1095. let number = 0;
  1096. try {
  1097. number = $('.lucky-number').toArray().map(x => x.innerText).join('');
  1098. number = parseInt(number);
  1099. } catch(err) { }
  1100. return number;
  1101. };
  1102. function readBalance() {
  1103. let balance = "";
  1104. try {
  1105. balance = $('.navbar-coins.bg-1 a').first().text();
  1106. } catch(err) { }
  1107. return balance;
  1108. };
  1109. function readPromoStatus() {
  1110. let promoStatus = PromoStatus.UNKNOWNERROR;
  1111. try {
  1112. if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeAccepted) > 0) {
  1113. return PromoStatus.ACCEPTED;
  1114. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeUsed) > 0) {
  1115. return PromoStatus.USEDBEFORE;
  1116. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeInvalid) > 0) {
  1117. return PromoStatus.INVALID;
  1118. } else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeInvalid) > 0) {
  1119. return PromoStatus.INVALID;
  1120. }
  1121. } catch ( err ) { }
  1122. return promoStatus;
  1123. };
  1124. function readPromoCode() {
  1125. var urlSplit = window.location.href.split('/');
  1126. return urlSplit[urlSplit.length - 1];
  1127. };
  1128. function displayStatusUi() {
  1129. $( 'body' ).prepend( '<div class="withdraw-button bg-2" style="top:30%; z-index:1500;" href="#">⚙️ Processing</div>' );
  1130. };
  1131. return {
  1132. run: run,
  1133. runPromotion: runPromotion,
  1134. findCountdownOrRollButton: findCountdownOrRollButton,
  1135. findPromotionTag: findPromotionTag,
  1136. waitInteractions: waitInteractions
  1137. };
  1138. },
  1139. createCFHistory: function() {
  1140. let rollsMeta = [
  1141. { id: 0, range: '0000-9885', count: 0 },
  1142. { id: 1, range: '9886-9985', count: 0 },
  1143. { id: 2, range: '9986-9993', count: 0 },
  1144. { id: 3, range: '9994-9997', count: 0 },
  1145. { id: 4, range: '9998-9999', count: 0 },
  1146. { id: 5, range: '10000', count: 0 }
  1147. ];
  1148. function initOrLoad() {
  1149. let storedData = persistence.load('CFHistory', true);
  1150. if(storedData) {
  1151. rollsMeta = storedData;
  1152. }
  1153. };
  1154. function addRoll(number) {
  1155. switch(true) {
  1156. case (number <= 9885):
  1157. rollsMeta[0].count++;
  1158. break;
  1159. case (number <= 9985):
  1160. rollsMeta[1].count++;
  1161. break;
  1162. case (number <= 9993):
  1163. rollsMeta[2].count++;
  1164. break;
  1165. case (number <= 9997):
  1166. rollsMeta[3].count++;
  1167. break;
  1168. case (number <= 9999):
  1169. rollsMeta[4].count++;
  1170. break;
  1171. case (number == 10000):
  1172. rollsMeta[5].count++;
  1173. break;
  1174. default:
  1175. break;
  1176. }
  1177. save();
  1178. };
  1179. function getRollsMeta() {
  1180. return rollsMeta.map(x => x.count);
  1181. };
  1182. function save() {
  1183. persistence.save('CFHistory', rollsMeta, true);
  1184. };
  1185. return {
  1186. initOrLoad: initOrLoad,
  1187. addRoll: addRoll,
  1188. getRollsMeta: getRollsMeta
  1189. }
  1190. }
  1191. };
  1192. /**
  1193. * Prevents alert popups to be able to reload the faucet if invisible captcha validation fails
  1194. */
  1195. function overrideSelectNativeJS_Functions () {
  1196. window.alert = function alert (message) {
  1197. console.log (message);
  1198. }
  1199. }
  1200. function addJS_Node (text, s_URL, funcToRun) {
  1201. var scriptNode= document.createElement ('script');
  1202. scriptNode.type= "text/javascript";
  1203. if (text)scriptNode.textContent= text;
  1204. if (s_URL)scriptNode.src= s_URL;
  1205. if (funcToRun)scriptNode.textContent = '(' + funcToRun.toString() + ')()';
  1206. var element = document.getElementsByTagName ('head')[0] || document.body || document.documentElement;
  1207. element.appendChild (scriptNode);
  1208. }
  1209. function detectWeb() {
  1210. if(!shared.isOpenedByManager(window.location.href)) {
  1211. return;
  1212. }
  1213. addJS_Node (null, null, overrideSelectNativeJS_Functions);
  1214. if(window.location.href.indexOf('promotion') > 0) {
  1215. CFProcessor = objectGenerator.createCFProcessor();
  1216. interactions = objectGenerator.createInteractions();
  1217. setTimeout(CFProcessor.runPromotion, helpers.randomMs(5000, 10000));
  1218. } else if (shared.getCurrent().type == WebType.CRYPTOSFAUCETS) {
  1219. CFProcessor = objectGenerator.createCFProcessor();
  1220. interactions = objectGenerator.createInteractions();
  1221. setTimeout(CFProcessor.run, helpers.randomMs(1000, 3000));
  1222. } else if (shared.getCurrent().type == WebType.STORMGAIN) {
  1223. SGProcessor = objectGenerator.createSGProcessor();
  1224. setTimeout(SGProcessor.run, helpers.randomMs(10000, 20000));
  1225. }
  1226. }
  1227. function init() {
  1228. shared = objectGenerator.createShared();
  1229. persistence = objectGenerator.createPersistence();
  1230. if(window.location.host === 'satology.onrender.com') {
  1231. manager = objectGenerator.createManager();
  1232. CFPromotions = objectGenerator.createCFPromotions();
  1233. ui = objectGenerator.createUi();
  1234. CFHistory = objectGenerator.createCFHistory();
  1235. manager.init();
  1236. } else {
  1237. detectWeb();
  1238. }
  1239. }
  1240. init();
  1241. })();

comments powered by Disqus