// ==UserScript==
// @name [satology] Auto Claim Multiple Faucets with Monitor UI
// @description Freebitco.in, StormGain Miner, 15 Faucets with Promo Codes + Autologin, FaucetPay PTC, etc.
// @description Automatic activation of StormGain Miner every 4 hours and hourly claim of free ADA, BNB, BTC, DASH, DOGE, ETH, LINK, LTC, NEO, STEAM, TRX, USDC, USDT, XEM, XRP
// @version 1.4.0
// @author satology
// @namespace satology.onrender.com
// @homepage https://satology.onrender.com/faucets/referrals
// @note - IMPORTANT ----------------------------------------------------------------------------------------------------------------------------------------------------
// @note YOU MUST HAVE A hCaptcha solver INSTALLED to claim from the faucets
// @note I recommend this script: https://greasyfork.org/en/scripts/425854-hcaptcha-solver-automatically-solves-hcaptcha-in-browser
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @note - LAST UPDATES -------------------------------------------------------------------------------------------------------------------------------------------------
// @note [@1.4.0] Added Free-Litecoin.com & Free-Ethereum.io
// @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:
// @note > Problem: The hCaptcha (despite being in English) displays what you need to look for with a character of the cyrillic unicode table
// @note in the word. For example: instead of train, it says trаin. Looks the same, but it's not. The 'a' is different.
// @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.
// @note > Solution/Workaround: Add the following 2 lines to the hCaptcha script, right after function getSynonyms(word) {
// @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 };
// @note word = (encodeURIComponent(word).indexOf('%') > -1) ? WORDS_WITH_CYRILLIC[word] : word;
// @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
// @note solution and share it. This is enough for me for now. It maps the word with the special character to the correct word.
// @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.
// @note Just remember that if you use it, at least the first time after opening Chrome, you'll get the MetaMask warning and you have to
// @note bypass/'accept the risk' manually. Just in case, use a unique password for that site.
// @note [@1.3.0] Added FaucetPay PTC. It runs on focus every 5 hs aprox (set by hoursBetweenRuns in config)
// @note [@1.2.1] Fixed BUG that didn't let new users enable the faucets, and changed the reusable promo codes interval
// @note [@1.2.0] What's new?
// @note > Activate/Deactivate faucets (from UI)
// @note > Run ASAP a specific faucet (from UI)
// @note > Change faucets 'display' name (from the UI)
// @note > Reusable promo codes option (by selecting 'Daily' from UI when adding a code)
// @note > Remove promo codes individually
// @note > FIAT conversion column, filled by the website using CMC Tickers
// @note > Some refactor on how the data is stored
// @note + Run ASAP and Faucet changes are not always immediate. If the script is claiming, it will wait until it's finished to avoid data errors.
// @note + FIAT conversion is done from the website as I was having some issues with the event listeners. Also, the ticker doesn't seem to be
// @note updating itself unless you change the fiat, so I'm open to suggestions if you know of other plug-n-play tickers
// @note + 'Reusable' promo codes are those codes that you can run every 24hs on every CF faucet. You might know that, at least for now,
// @note shortlink promo codes are always the same. I recommend doing the shortlinks daily anyway just to be safe.
// @note Reusable codes will be reprocessed automatically after 1 day for each faucet if their status is ACCEPTED or USEDBEFORE.
// @note You can verify the last run datetime by placing your mouse over the emojis.
// @note [@1.1.0] Added Freebitco.in and autologin for @cryptosfaucets
// @note > You can enable autologin/credentials in the config object
// @note > You can enable activation of daily RPBonus for FreeBitco.in in the config object
// @note > Added boolean setToEnglish (DEFAULT TRUE) at localeConfig object, to change the language of the faucets to English.
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @note - MAIN FEATURES ------------------------------------------------------------------------------------------------------------------------------------------------
// @note > Automatic hourly rolls for 16 faucets: Freebitco.in and @CryptosFaucets (ADA, BNB, BTC, DASH, DOGE, ETH, LINK, LTC, NEO, STEAM, TRX, USDC, USDT, XEM, XRP)
// @note > Automatic activation of StormGain Miner (free BTC every 4 hours)
// @note > FaucetPay PTC autoclaim
// @note > Accepts promotion codes (http://twitter.com/cryptosfaucets, free roll shortlinks) for CF 15 faucets
// @note > Simple Monitor UI on top of a website to track progress (claims, next rolls, promo codes)
// @note - IMPORTANT CONSIDERATIONS -------------------------------------------------------------------------------------------------------------------------------------
// @note 0. You need to enable popups on the Manager UI website to be able to open the faucets
// @note 1. FAUCETS WEBSITES MUST OPEN IN ENGLISH TO BE ABLE TO RECOGNIZE IF THE PROMO CODE WAS ACCEPTED
// @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
// @note (Search for localeStrings in the code)
// @note 2. Autorolls will trigger ONLY when the faucet was opened by the Manager UI.
// @note This is to allow users to navigate the websites to get the ShortLinks extra rolls, for example,
// @note without having to stop the script.
// @note 3. You can enable/disable faucets from the UI. By default they are all set to false.
// @note It would be great if you could use my referral links listed below if you need an account.
// @note To disable them, just set enabled: false in the webList array, save the script & refresh the manager
// @note 4. You can change the config object to enable autologin, RP free roll bonus, etc.
// @note 5. All data stored for tracking and to be displayed is stored locally in your environment. Nothing is uploaded.
// @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
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @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
// @note guarantee that the faucets won't ban your IP or account
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @note Requested for upcoming updates:
// @note - Add bagi.co.in
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @note If you wanna team up or just share some ideas, you can contact me at [email protected]
// @note ----------------------------------------------------------------------------------------------------------------------------------------------------------------
// @grant GM_setValue
// @grant GM_getValue
// @grant window.close
// @grant GM_openInTab
// @icon https://www.google.com/s2/favicons?domain=stormgain.com
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @match https://satology.onrender.com/faucets/referrals*
// @match https://app.stormgain.com/crypto-miner/
// @match https://freecardano.com/*
// @match https://freebinancecoin.com/*
// @match https://freebitcoin.io/*
// @match https://freedash.io/*
// @match https://free-doge.com/*
// @match https://freeethereum.com/*
// @match https://freechainlink.io/*
// @match https://free-ltc.com/*
// @match https://freeneo.io/*
// @match https://freesteam.io/*
// @match https://free-tron.com/*
// @match https://freeusdcoin.com/*
// @match https://freetether.com/*
// @match https://freenem.com/*
// @match https://coinfaucet.io/*
// @match https://freebitco.in/
// @match https://faucetpay.io/ptc
// @match https://faucetpay.io/ptc*
// @match https://faucetpay.io/account/login
// @match https://free-litecoin.com/*
// @match https://www.free-ethereum.io/
// @match https://www.free-ethereum.io/free/
// ==/UserScript==
(function() {
'use strict';
/**
* Specific string values to check if a promotion code was succesfully processed (used via indexOf).
* Defaults are set for English.
* If you want to view the faucets in another language, you will need to change the following values
*/
const localeConfig = {
setToEnglish: true, // will set the faucets to English
stringSearches: {
promoCodeAccepted: 'roll',
promoCodeUsed: 'already used',
promoCodeInvalid: ['not found', 'only alphanumeric'],
promoCodeExpired: ['ended']
}
};
const WebType = {
CRYPTOSFAUCETS: 1,
STORMGAIN: 2,
FREEBITCOIN: 3,
FAUCETPAY: 4,
FREELITECOIN: 5,
FREEETHEREUMIO: 6
};
const CFUrlType = {
HOME: 0,
FREE: 1,
CONTACTTWITTER: 2,
PROMOTION: 3,
STATS: 4,
SETTINGS: 5,
FREEROLLS: 6,
IGNORE: 99
};
const PromoStatus = {
NOCODE: 0,
PENDING: 1,
ACCEPTED: 2,
USEDBEFORE: 3,
INVALID: 4,
UNKNOWNERROR: 5,
EXPIRED: 6
};
const RandomInteractionLevel = {
NONE: 0,
LOW: 1,
MEDIUM: 2,
HIGH: 3
};
const HS_26_IN_MILLISECONDS = 93600000; //Using 26 hs instead of 24hs
const HS_2_IN_MILLISECONDS = 7200000; //and 2hs gap retry when code is flagged as USEDBEFORE
const USE_DEFAULT = -1;
let config = {
defaults: {
timeout: 4, // Use -1 to disable the timeout functionality. In minutes. Max time the monitor will wait for a result/roll.
// After timeout is reached, the Manager/Monitor will assume something is wrong
// (usually faucet tab being accidentally closed or failed to connect)
postponeMinutes: 65, // Minutes to wait before retrying a faucet that timed out
focusTab: false // If false the faucets will be opened in the background
},
cf: {
autologin: false,
credentials: {
mode: 1, // POSSIBLE VALUES:
// 1: Use email/password saved through the script
// 2: Waits for the credentials to be added manually or by a third party software/extension.
// Useful if you use different email/password combinations on each faucet
email: '[email protected]',
password: 'YOURPASSWORD'
}
},
fb: { // FreeBitco.in
activateRPBonus: false // will try to activate the highest RP Roll Bonus available for the account (100, 50 25, ... points per roll),
},
fp: { // FaucetPay.io
hoursBetweenRuns: 5 // how many hours to wait between each FaucetPay PTC run
}
}
let persistence, shared, manager, ui, CFPromotions, interactions, SGProcessor, CFProcessor, CFHistory, FBProcessor, FPProcessor, FreeLitecoinProcessor, FreeGenericFaucetProcessor;
let helpers = {
cleanString: function(input) {
var output = "";
for (var i=0; i<input.length; i++) {
if (input.charCodeAt(i) <= 127) {
output += input.charAt(i);
}
}
return output;
},
shuffle: function (array) {
let currentIndex = array.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
},
getPrintableTime: function (date = new Date()) {
if (date == null) {
return '';
}
return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2);
},
getPrintableDateTime: function (date) {
if (date != null) {
return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
} else {
return '';
}
},
getEnumText: function (enm, value) {
return Object.keys(enm).find(key => enm[key] === value);
},
randomMs: function (a, b){
return a + (b - a) * Math.random();
},
addMinutes: function(date, mins) {
return date.setMinutes(date.getMinutes() + parseInt(mins) + 1);
},
randomInt: function(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
},
addMilliseconds: function(date, ms) {
return date.setMilliseconds(date.getMilliseconds() + ms);
},
getRandomMillisecondsFromMinutesRange(minute, rangeDiffInPercentage) {
const msCenter = minute * 60 * 1000;
const msRangeDiff = Math.round(msCenter * rangeDiffInPercentage / 100);
return helpers.randomMs(msCenter - msRangeDiff, msCenter + msRangeDiff);
},
getEmojiForPromoStatus: function(promoStatus) {
switch (promoStatus) {
case PromoStatus.NOCODE:
return '⚪';
break;
case PromoStatus.PENDING:
return '⏳';
break;
case PromoStatus.ACCEPTED:
return '✔️';
break;
case PromoStatus.USEDBEFORE:
return '🕙';
break;
case PromoStatus.INVALID:
return '❌';
break;
case PromoStatus.EXPIRED:
return '📅';
break;
case PromoStatus.UNKNOWNERROR:
return '❗';
break;
}
},
getHost: function(url, withHttps = false) {
if (url.includes('//')) {
url = url.split('//')[1];
}
url = url.split('/')[0];
return withHttps ? ('https://' + url) : url;
},
cf: {
getUrlType: function(url) {
if (url.endsWith('/free')) {
return CFUrlType.FREE;
}
if (url.includes('/promotion/')) {
return CFUrlType.PROMOTION;
}
if (url.endsWith('/contact-twitter')) {
return CFUrlType.CONTACTTWITTER;
}
if (url.endsWith('/free-rolls')) {
return CFUrlType.FREEROLLS;
}
if (url.endsWith('/settings')) {
return CFUrlType.SETTINGS;
}
if (url.endsWith('/stats')) {
return CFUrlType.STATS;
}
if (url.endsWith('/')) {
url = url.slice(0, -1);
if (url == helpers.getHost(url, true)) {
return CFUrlType.HOME;
}
}
return CFUrlType.IGNORE;
}
}
}
let objectGenerator = {
createPersistence: function() {
const prefix = 'autoWeb_';
function save(key, value, parseIt = false) {
GM_setValue(prefix + key, parseIt ? JSON.stringify(value) : value);
};
function load(key, parseIt = false) {
let value = GM_getValue(prefix + key);
if(value && parseIt) {
value = JSON.parse(value);
}
return value;
};
return {
save: save,
load: load
};
},
createShared: function() {
let flowControl;
function isOpenedByManager(currentHost) {
loadFlowControl();
if(!flowControl) {
return false;
}
let millisecondsDistance = new Date() - flowControl.requestedTime;
if((flowControl.type != WebType.FAUCETPAY && flowControl.opened) || (flowControl.host != currentHost && !flowControl.expectedHosts.includes(currentHost)) || millisecondsDistance > 120000) {
return false;
}
return true;
};
function setFlowControl(id, url, webType, expectedHosts) {
flowControl = {
id: id,
url: url,
host: url.host,
type: webType,
requestedTime: new Date(),
opened: false,
expectedHosts: expectedHosts,
error: false,
result: {}
};
persistence.save('flowControl', flowControl, true);
};
function wasVisited(expectedId) {
loadFlowControl();
return flowControl.id == expectedId && flowControl.opened;
};
function hasErrors(expectedId) {
return flowControl.id == expectedId && flowControl.error;
};
function getResult() {
return flowControl.result;
};
function getCurrent() {
let current = {};
current.url = flowControl.url;
current.host = flowControl.host;
current.type = flowControl.type;
return current;
};
function saveAndclose(runDetails, delay = 0) {
markAsVisited(runDetails);
if(delay) {
setTimeout(window.close, delay);
} else {
window.close();
}
};
function loadFlowControl() {
flowControl = persistence.load('flowControl', true);
};
function markAsVisited(runDetails) {
flowControl.opened = true;
flowControl.result = runDetails;
persistence.save('flowControl', flowControl, true);
};
function closeWithError(errorType, errorMessage) {
flowControl.error = true;
flowControl.result.errorType = errorType;
flowControl.result.errorMessage = errorMessage;
persistence.save('flowControl', flowControl, true);
window.close();
};
function updateWithoutClosing(runDetails) {
markAsVisited(runDetails);
};
function clearFlowControl() {
flowControl = {};
persistence.save('flowControl', flowControl, true);
};
return {
setFlowControl: setFlowControl,
wasVisited: wasVisited,
isOpenedByManager: isOpenedByManager,
getCurrent: getCurrent,
getResult: getResult,
closeWindow: saveAndclose,
closeWithError: closeWithError,
updateWithoutClosing: updateWithoutClosing,
hasErrors: hasErrors,
clearFlowControl: clearFlowControl
};
},
createManager: function() {
const STATUS = {
INITIALIZING: 0,
IDLE: 1,
CLAIMING: 2
};
let timestamp = null;
let timeWaiting = 0;
let uiUpdatesInterval;
let status = STATUS.INITIALIZING;
let processTimer;
let workingTab;
let webList = [];
const sites = [
{ id: '1', name: 'CF ADA', cmc: '2010', coinRef: 'ADA', url: new URL('https://freecardano.com/free'), rf: '?ref=335463', type: WebType.CRYPTOSFAUCETS },
{ id: '2', name: 'CF BNB', cmc: '1839', coinRef: 'BNB', url: new URL('https://freebinancecoin.com/free'), rf: '?ref=161127', type: WebType.CRYPTOSFAUCETS },
{ id: '3', name: 'CF BTC', cmc: '1', coinRef: 'BTC', url: new URL('https://freebitcoin.io/free'), rf: '?ref=490252', type: WebType.CRYPTOSFAUCETS },
{ id: '4', name: 'CF DASH', cmc: '131', coinRef: 'DASH', url: new URL('https://freedash.io/free'), rf: '?ref=124083', type: WebType.CRYPTOSFAUCETS },
{ id: '5', name: 'CF ETH', cmc: '1027', coinRef: 'ETH', url: new URL('https://freeethereum.com/free'), rf: '?ref=204076', type: WebType.CRYPTOSFAUCETS },
{ id: '6', name: 'CF LINK', cmc: '1975', coinRef: 'LINK', url: new URL('https://freechainlink.io/free'), rf: '?ref=78652', type: WebType.CRYPTOSFAUCETS },
{ id: '7', name: 'CF LTC', cmc: '2', coinRef: 'LTC', url: new URL('https://free-ltc.com/free'), rf: '?ref=117042', type: WebType.CRYPTOSFAUCETS },
{ id: '8', name: 'CF NEO', cmc: '1376', coinRef: 'NEO', url: new URL('https://freeneo.io/free'), rf: '?ref=100529', type: WebType.CRYPTOSFAUCETS },
{ id: '9', name: 'CF STEAM', cmc: '1230', coinRef: 'STEEM', url: new URL('https://freesteam.io/free'), rf: '?ref=117686', type: WebType.CRYPTOSFAUCETS },
{ id: '10', name: 'CF TRX', cmc: '1958', coinRef: 'TRX', url: new URL('https://free-tron.com/free'), rf: '?ref=145047', type: WebType.CRYPTOSFAUCETS },
{ id: '11', name: 'CF USDC', cmc: '3408', coinRef: 'USDC', url: new URL('https://freeusdcoin.com/free'), rf: '?ref=100434', type: WebType.CRYPTOSFAUCETS },
{ id: '12', name: 'CF USDT', cmc: '825', coinRef: 'USDT', url: new URL('https://freetether.com/free'), rf: '?ref=181230', type: WebType.CRYPTOSFAUCETS },
{ id: '13', name: 'CF XEM', cmc: '873', coinRef: 'XEM', url: new URL('https://freenem.com/free'), rf: '?ref=295274', type: WebType.CRYPTOSFAUCETS },
{ id: '14', name: 'CF XRP', cmc: '52', coinRef: 'XRP', url: new URL('https://coinfaucet.io/free'), rf: '?ref=808298', type: WebType.CRYPTOSFAUCETS },
{ id: '15', name: 'StormGain', cmc: '1', coinRef: 'BTC', url: new URL('https://app.stormgain.com/crypto-miner/'), rf: 'friend/BNS27140552', type: WebType.STORMGAIN },
{ id: '16', name: 'CF DOGE', cmc: '74', coinRef: 'DOGE', url: new URL('https://free-doge.com/free'), rf: '?ref=97166', type: WebType.CRYPTOSFAUCETS },
{ id: '17', name: 'FreeBitco.in', cmc: '1', coinRef: 'BTC', url: new URL('https://freebitco.in/'), rf: '?r=41092365', type: WebType.FREEBITCOIN },
{ id: '18', name: 'FaucetPay PTC', cmc: '1', coinRef: 'BTC', url: new URL('https://faucetpay.io/ptc'), rf: '?r=41092365', type: WebType.FAUCETPAY },
{ id: '19', name: 'Free-Litecoin.com', cmc: '2', coinRef: 'LTC', url: new URL('https://free-litecoin.com/'), rf: 'login?referer=1332950', type: WebType.FREELITECOIN },
{ id: '20', name: 'Free-Ethereum.io', cmc: '1027', coinRef: 'ETH', url: new URL('https://www.free-ethereum.io/'), rf: '?referer=1064662', type: WebType.FREEETHEREUMIO }
];
function start() {
loader.initialize();
ui.init(getCFlist());
update();
uiUpdatesInterval = setInterval(readUpdateValues, 10000);
processTimer = setTimeout(manager.process, 2000);
};
let loader = function() {
function initialize() {
setTimestamp();
initializeWebList();
initializePromotions();
initializeHistory();
};
function initializeWebList() {
addSites();
addStoredData();
};
function addSites() {
sites.forEach(x => webList.push(x));
webList.forEach(function (element, idx, arr) {
arr[idx].enabled = false;
arr[idx].lastClaim = 0;
arr[idx].aggregate = 0;
arr[idx].balance = 0;
arr[idx].stats = {};
arr[idx].nextRoll = null;
arr[idx].focusTab = (element.id == '18' ? true : USE_DEFAULT);
});
};
function addStoredData() {
let storedData = persistence.load('webList', true);
if(storedData) {
storedData.forEach( function (element) {
let idx = webList.findIndex(x => x.id == element.id);
if(idx != -1) {
webList[idx].name = element.name ?? webList[idx].name;
webList[idx].lastClaim = element.lastClaim ?? webList[idx].lastClaim;
webList[idx].aggregate = element.aggregate ?? webList[idx].aggregate;
webList[idx].balance = element.balance ?? webList[idx].balance;
webList[idx].stats = element.stats ?? webList[idx].stats;
webList[idx].enabled = element.enabled ?? webList[idx].enabled;
if(!webList[idx].enabled) {
webList[idx].nextRoll = null;
} else {
webList[idx].nextRoll = element.nextRoll ? new Date(element.nextRoll) : new Date();
}
//webList[idx].focusTab = element.focusTab ?? webList[idx].focusTab;
}
});
} else {
// helpers.shuffle(webList);
}
};
function initializePromotions() {
let storedData = persistence.load('CFPromotions', true);
if (storedData) {
storedData.forEach( function (element, idx, arr) {
arr[idx].added = new Date(element.added);
arr[idx].statusPerFaucet.forEach( function (el, i, a) {
a[i].execTimeStamp = (el.execTimeStamp != null) ? new Date(el.execTimeStamp) : null;
});
});
CFPromotions.load(storedData);
}
};
function initializeHistory() {
CFHistory.initOrLoad();
};
function setTimestamp() {
timestamp = new Date().getTime();
persistence.save('timestamp', timestamp);
};
function removeDisabledFaucets() {
webList = webList.filter(x => x.enabled);
};
return {
initialize: initialize
};
}();
function readUpdateValues(forceCheck = false) {
readPromoCodeValues();
if(status == STATUS.IDLE || forceCheck) {
let updateDataElement = $('#update-data')[0];
let updateValues = helpers.cleanString(updateDataElement.innerText);
if (updateValues != '') {
updateDataElement.innerText = '';
let updateObj = JSON.parse(updateValues);
if(updateObj.runAsap.changed) {
updateObj.runAsap.ids.forEach(function (element, idx, arr) {
try {
let itemIndex = webList.findIndex(x => x.id == element)
webList[itemIndex].enabled = true;
webList[itemIndex].nextRoll = new Date(754000 + idx);
ui.log(`${webList[itemIndex].name} updated to run ASAP`);
} catch (err) {
ui.log(`Error setting faucet to run ASAP: ${err}`);
}
});
}
if(updateObj.editSingle.changed) {
updateObj.editSingle.items.forEach(function (element, idx, arr) {
try {
let itemIndex = webList.findIndex(x => x.id == element.id);
webList[itemIndex].name = element.displayName;
if (webList[itemIndex].enabled != element.enabled) {
webList[itemIndex].enabled = element.enabled;
if(webList[itemIndex].enabled) {
webList[itemIndex].nextRoll = new Date(idx);
} else {
webList[itemIndex].nextRoll = null;
}
}
ui.log(`Faucet updated. New name: ${element.displayName}. Active: ${element.enabled}`);
} catch (err) {
ui.log(`Error updating faucet data: ${err}`);
}
});
}
if(updateObj.runAsap.changed || updateObj.editSingle.changed) {
$('#faucets-display-status')[0].innerHTML = '';
update(true);
process();
return;
}
}
}
if(forceCheck) {
process();
}
};
function update(sortIt = true) {
if(sortIt) {
webList.sort( function(a,b) {
if (a === b) {
return 0;
} else if (a.nextRoll === null) {
return 1;
} else if (b.nextRoll === null) {
return -1;
} else {
return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
}
});
}
saveWebList();
ui.refresh(webList, CFPromotions.getAll());
updateRollStatsSpan();
};
function saveWebList() {
const data = webList.map(x => {
return {
id: x.id,
name: x.name,
lastClaim: x.lastClaim,
aggregate: x.aggregate,
balance: x.balance,
stats: x.stats,
nextRoll: x.nextRoll,
enabled: x.enabled
};});
persistence.save('webList', data, true);
}
function process() {
if(isObsolete()) {
return;
}
if(webList[0].nextRoll == null) {
ui.log(`All faucets are disabled. Click edit and select those you want to run...`);
clearTimeout(processTimer);
status = STATUS.IDLE;
return;
}
if(webList[0].nextRoll.getTime() < (new Date()).getTime()) {
ui.log(`Opening ${webList[0].name}`);
clearTimeout(processTimer);
status = STATUS.CLAIMING;
open();
} else {
let timeUntilNext = webList[0].nextRoll.getTime() - (new Date()).getTime() + helpers.randomMs(1000, 2000);
ui.log(`Waiting ${(timeUntilNext/1000/60).toFixed(2)} minutes...`);
clearTimeout(processTimer);
processTimer = setTimeout(manager.process, timeUntilNext);
status = STATUS.IDLE;
}
};
function isObsolete() {
let savedTimestamp = persistence.load('timestamp');
if (savedTimestamp && savedTimestamp > timestamp) {
ui.log('<b>STOPING EXECUTION!<b> A new Manager UI window was opened. Process should continue there');
clearInterval(uiUpdatesInterval);
return true;
}
return false;
};
function open(promoCode) {
let navUrl = webList[0].url;
try {
if(promoCode) {
navUrl = new URL('promotion/' + promoCode, webList[0].url.origin);
ui.log(`Opening ${webList[0].name} with Promo Code [${promoCode}]`);
}
let expectedHosts = [];
expectedHosts.push(navUrl.host);
if(webList[0].type == webList[0].type == WebType.STORMGAIN) {
expectedHosts.push((new URL('https://www.google.com').host));
expectedHosts.push((new URL('https://www.recaptcha.net').host));
}
shared.setFlowControl(webList[0].id, navUrl, webList[0].type, expectedHosts);
setTimeout(manager.resultReader, 15000);
// Try to close old workingTab if still opened
if (workingTab && !workingTab.closed) {
try {
workingTab.close();
} catch { }
}
workingTab = GM_openInTab(navUrl.href, { active: ((!webList[0].focusTab || webList[0].focusTab == USE_DEFAULT) ? config.defaults.focusTab : webList[0].focusTab) });
} catch(err) {
ui.log(`Error opening tab: ${err}`)
}
};
function getPromoUrl(promoCode) {
return new URL('promotion/' + promoCode, webList[0].origin);
}
// REFACTOR
function resultReader() {
if(isObsolete()) {
return;
}
if (webList[0].type == WebType.FAUCETPAY && workingTab && !workingTab.closed) {
timeWaiting += 15;
ui.log(`Waiting for ${webList[0].name} results...`, timeWaiting);
setTimeout(manager.resultReader, 15000);
return;
}
if(shared.wasVisited(webList[0].id)) {
timeWaiting = 0;
let result = shared.getResult();
if (result) {
updateWebListItem(result);
if ( (webList[0].type == WebType.CRYPTOSFAUCETS) &&
( (result.claimed) || (result.promoStatus && result.promoStatus != PromoStatus.ACCEPTED) )) {
let promoCode = CFPromotions.hasPromoAvailable(webList[0].id);
if (promoCode) {
update(false);
open(promoCode);
return;
}
}
} else {
ui.log(`Unable to read last run result, for ID: ${webList[0].id} > ${webList[0].name}`);
}
update(true);
readUpdateValues(true);
return;
} else {
timeWaiting += 15;
if (!shared.hasErrors(webList[0].id) && !hasTimedOut()) {
ui.log(`Waiting for ${webList[0].name} results...`, timeWaiting);
setTimeout(manager.resultReader, 15000);
return;
}
if (shared.hasErrors(webList[0].id)) {
webList[0].stats.errors = shared.getResult();
ui.log(`${webList[0].name} closed with error: ${webList[0].stats.errors.errorType} ${webList[0].stats.errors.errorMessage}`);
}
if (hasTimedOut()) {
if(webList[0].stats.countTimeouts) {
webList[0].stats.countTimeouts += 1;
} else {
webList[0].stats.countTimeouts = 1;
}
ui.log(`Waited too much time for ${webList[0].name} results: triggering timeout`);
}
let millisecondsDelay = helpers.getRandomMillisecondsFromMinutesRange(config.defaults.postponeMinutes, 5);
webList[0].nextRoll = new Date(helpers.addMilliseconds(new Date(), millisecondsDelay));
shared.clearFlowControl();
update(true);
timeWaiting = 0;
readUpdateValues(true);
return;
}
};
function hasTimedOut() {
return config.defaults.timeout != -1 && (timeWaiting > (config.defaults.timeout * 60));
};
function updateWebListItem(result) {
ui.log(`Updating data: ${JSON.stringify(result)}`);
webList[0].stats.countTimeouts = 0;
webList[0].stats.errors = null;
if (result.claimed) {
try {
result.claimed = parseFloat(result.claimed);
} catch { }
if(!isNaN(result.claimed)) {
webList[0].lastClaim = result.claimed;
webList[0].aggregate += result.claimed;
}
}
if(result.balance) {
webList[0].balance = result.balance;
}
if(result.nextRoll) {
webList[0].nextRoll = new Date(result.nextRoll);
}
if(result.promoStatus) {
CFPromotions.updateFaucetForCode(result.promoCode, webList[0].id, result.promoStatus);
}
if(result.rolledNumber) {
CFHistory.addRoll(result.rolledNumber);
}
};
function readPromoCodeValues() {
let promoCodeElement = $('#promo-code-new')[0];
let promoDataStr = helpers.cleanString(promoCodeElement.innerText);
let promoDisplayStatus = $('#promo-display-status')[0];
if (promoDataStr == '') {
promoDisplayStatus.innerHTML = '';
return;
}
let promoData = JSON.parse(promoDataStr);
if(promoData.action) {
switch (promoData.action) {
case 'ADD':
CFPromotions.addNew(promoData.code, promoData.repeatDaily);
promoCodeElement.innerText = '';
$('#promo-text-input').val('');
promoDisplayStatus.innerHTML = 'Code ' + promoData.code + ' added!';
ui.log(`Promo code ${promoData.code} added`);
ui.refresh(null, CFPromotions.getAll());
break;
case 'REMOVEALLPROMOS':
CFPromotions.removeAll();
promoCodeElement.innerText = '';
promoDisplayStatus.innerHTML = 'Promo codes removed!';
ui.log(`Promo codes removed`);
ui.refresh(null, CFPromotions.getAll());
break;
case 'REMOVE':
if(CFPromotions.remove(promoData.id, promoData.code) != -1) {
ui.log(`Promo code ${promoData.code} removed`);
} else {
ui.log(`Unable to remove code ${promoData.code}`);
}
promoCodeElement.innerText = '';
ui.refresh(null, CFPromotions.getAll());
break;
}
}
};
function updateRollStatsSpan() {
let rollsSpanElement = $('#rolls-span')[0];
rollsSpanElement.innerText = CFHistory.getRollsMeta().join(',');
};
function getCFlist() {
let items;
items = webList.filter(f => f.type === WebType.CRYPTOSFAUCETS);
items = items.map(x => {
return {
id: x.id,
name: x.coinRef
};});
items.sort((a, b) => (a.name > b.name) ? 1 : -1);
return items;
};
return{
init:start,
process: process,
resultReader: resultReader,
getFaucetsForPromotion: getCFlist,
readPromoCodeValues: readPromoCodeValues
};
},
createUi: function() {
let logLines = ['', '', '', '', ''];
function init(cfFaucets) {
appendCSS();
appendJavaScript();
appendHtml();
createPromoTable(cfFaucets);
document.querySelector('.page-title h1').innerHTML = 'Auto Claim';
};
function appendCSS() {
let css = '<style>';
css += 'td.em-input {';
css += 'padding-top: 0;';
css += 'padding-bottom: 0;';
css += '}';
css += 'td.em-input input {';
css += '}';
css += '</style>';
$('head').append(css);
};
function appendJavaScript() {
let js = '';
js += '<script language="text/javascript">';
js += 'var myBarChart;';
js += 'function savePromoCode() {';
js += 'var promoText = document.getElementById("promo-text-input");';
js += 'var promoCode = document.getElementById("promo-code-new");';
js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
js += 'var promoDaily = document.getElementById("promo-daily");';
js += 'var promoObject = { action: "ADD", code: promoText.value.trim(), repeatDaily: promoDaily.checked };'
js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
js += 'promoDisplayStatus.innerHTML = "Adding  "<b>" + promoObject.code + "</b>"...<br>This could take around a minute. Please wait..."';
js += '}';
js += 'function removePromoCode(id, code) {';
js += 'var promoCode = document.getElementById("promo-code-new");';
js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
js += 'var promoObject = { action: "REMOVE", id: id, code: code };'
js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
js += 'promoDisplayStatus.innerHTML = "Removing code  "<b>" + code + "</b>"...<br>This could take around a minute. Please wait..."';
js += '}';
js += 'function getUpdateObject() {';
js += 'let updateObject;';
js += 'var updateData = document.getElementById("update-data");';
js += 'if (updateData.innerHTML != "") {';
js += 'updateObject = JSON.parse(updateData.innerHTML);';
js += '} else {';
js += 'updateObject = { runAsap: { ids: [], changed: false}, editSingle: { changed: false, items: [] } };';
js += '}';
js += 'return updateObject;';
js += '}';
js += 'function editList() {';
js += '$.each($("#schedule-table-body td.em-input"), function(x, y) {';
js += 'let val = y.innerHTML;';
js += 'y.innerHTML = "<input type=\'text\' data-original=\'" + val + "\' value=\'" + val + "\' />";});';
js += '$.each($("#schedule-table-body td.edit-status"), function(x, y) {';
js += 'let activeSwitch = y.querySelector("input");';
js += 'y.classList.remove("d-none");';
js += '});';
js += '$.each($(".em-only"), (x, y) => y.classList.remove("d-none"));';
js += '$.each($(".em-hide"), (x, y) => y.classList.add("d-none"));';
js += '}';
js += 'function editListSave() {';
js += ' let updateObject = getUpdateObject();';
js += ' $.each($("#schedule-table-body tr"), function(x, row) {';
js += ' let textInputCell = row.querySelector(".em-input");';
js += ' let textInput = textInputCell.querySelector("input");';
js += ' let activeSwitch = row.querySelector("td.edit-status input");';
js += ' let single = { id: row.dataset.id, displayName: textInput.dataset.original, enabled: activeSwitch.dataset.original };';
js += ' textInputCell.innerHTML = textInput.value;';
js += ' if(textInput.dataset.original != textInput.value) {';
js += ' single.displayName = textInput.value;';
js += ' }';
js += ' if(activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {';
js += ' single.enabled = Boolean(activeSwitch.checked);';
js += ' }';
js += ' if(textInput.dataset.original != textInput.value || activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {';
js += ' updateObject.editSingle.items.push(single);';
js += ' updateObject.editSingle.changed = true;';
js += ' }';
js += ' });';
js += ' if(updateObject.editSingle.changed) {';
js += ' document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);';
js += ' document.getElementById("faucets-display-status").innerHTML = "Data will be updated as soon as possible...";';
js += ' }';
js += '$.each($(".em-only"), (x, y) => y.classList.add("d-none"));';
js += '$.each($(".em-hide"), (x, y) => y.classList.remove("d-none"));';
js += '}';
js += 'function editListCancel() {';
js += '$.each($("#schedule-table-body td.em-input input"), function(x, y) {';
js += 'let val = y.dataset.original;';
js += 'y.parentNode.innerHTML = val;});';
js += '$.each($(".em-only"), (x, y) => y.classList.add("d-none"));';
js += '$.each($(".em-hide"), (x, y) => y.classList.remove("d-none"));';
js += '}';
js += 'function updateValues(type, values) {';
js += 'let updateObject = getUpdateObject();';
js += 'if (type == "runAsap") {';
js += 'updateObject.runAsap.ids.push(values.id);';
js += 'updateObject.runAsap.changed = true;';
js += 'document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);';
js += 'document.getElementById("faucets-display-status").innerHTML = "Faucet will be updated to run as soon as possible...";';
js += '}';
js += '}';
js += 'function removeAllPromos() {';
js += 'var promoCode = document.getElementById("promo-code-new");';
js += 'var promoDisplayStatus = document.getElementById("promo-display-status");';
js += 'var promoObject = { action: "REMOVEALL" };'
js += 'promoCode.innerHTML =JSON.stringify(promoObject);';
js += 'promoDisplayStatus.innerHTML = "Removing all promotion codes...<br>This could take around a minute. Please wait..."';
js += '}';
js += 'function openStatsChart() {';
js += 'if(myBarChart) { myBarChart.destroy(); }';
js += 'let statsFragment = document.getElementById("stats-fragment");';
js += 'if (statsFragment.style.display === "block") { statsFragment.style.display = "none"; document.getElementById("stats-button").innerText = "Lucky Number Stats"; } else {';
js += 'statsFragment.style.display = "block"; document.getElementById("stats-button").innerText = "Close Stats";';
js += 'var canvas = document.getElementById("barChart");';
js += 'var ctx = canvas.getContext("2d");';
js += 'var dataSpan = document.getElementById("rolls-span");';
js += 'var data = {';
js += 'labels: ["0000-9885", "9886-9985", "9986-9993", "9994-9997", "9998-9999", "10000"],';
js += 'datasets: [ { fill: false, backgroundColor: [ "#990000", "#660066", "#000099", "#ff8000", "#ffff00", "#00ff00"],';
js += 'data: dataSpan.innerText.split(",") } ] };';
js += 'var options = { plugins: { legend: { display: false } }, title: { display: true, text: "Rolled Numbers", position: "top" }, rotation: -0.3 * Math.PI };';
js += 'myBarChart = new Chart(ctx, { type: "pie", data: data, options: options }); } }';
js += '</script>';
$('head').append(js);
};
function appendHtml() {
let html ='';
html += '<pre style="width:100%;" id="console-log"><b>Loading...</b></pre>';
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>';
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">';
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>';
html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="editListCancel()"><i class="fa fa-times-circle"></i> Cancel</a></div>';
html += '<div class="em-hide"><a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editList()"><i class="fa fa-edit"></i> Edit</a></div>';
html += '</div></div>';
html += '<div class="row align-items-center text-center justify-content-end">';
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>';
html += '<span id="update-data" style="display:none;"></span></section>';
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">';
html +='<div class="title col-3 px-0 text-white"><h2>Promo Codes</h2></div><div class="title col-3 w-100 text-white">';
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" placeholder="Type a Promo code...">';
html +='<div class="input-group-append"><button class="btn btn-success" id="promo-button" onclick="savePromoCode()"><i class="fa fa-plus"></i></button>';
html +='</div></div></div>';
html +='<div class="title col-4 text-white justify-content-end"><span id="promo-display-status" class="text-white"></span>';
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>';
html +='</div></div><div class="row align-items-center text-center justify-content-end"><div class="col-12 order-lg-1 text-center">';
html +='<div class="row justify-content-center"><div class="col table-responsive" id="promo-container"></div></div></div></div></div></div></section>';
html += '<section class="fragment"><div class="container-fluid bg-dark ">';
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>';
html +='<div class="container py-1" id="stats-fragment" style="display:none;"><div class="row align-items-center text-center justify-content-center">';
html += '<div class="col-md-3"><canvas id="barChart"></canvas><span id="rolls-span" style="display:none;"></span></div></div></div></div></div></section>';
$('#referral-table').before(html);
$('#schedule-container').append( createScheduleTable() );
};
function createPromoTable(faucets) {
let tableStructure = '';
tableStructure += '<table class="table table-striped table-dark" id="promo-table">';
tableStructure += '<caption style="text-align: -webkit-center;">⏳ Pending ✔️ Accepted 🕙 Used Before ❌ Invalid code ❗ Unknown error ⚪ No code</caption>';
tableStructure += '<thead><tr><th class="">Code</th><th class="">Added</th>';
for (let i = 0, all = faucets.length; i < all; i++) {
tableStructure += '<th data-faucet-id="' + faucets[i].id + '">' + faucets[i].name + '</th>';
}
tableStructure += '</tr></thead><tbody id="promo-table-body"></tbody></table>';
$('#promo-container').append( tableStructure );
};
function createScheduleTable() {
let tableStructure = '';
tableStructure += '<table class="table table-striped table-dark" id="schedule-table"><thead><tr>';
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>';
tableStructure += '<th class="">Aggregate</th><th class="">Balance</th><th class="" id="converted-balance-col">FIAT</th><th class="">Next Roll</th>';
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>';
return tableStructure;
};
function loadScheduleTable(data) {
let tableBody = '';
for(let i=0, all = data.length; i < all; i++) {
tableBody += '<tr class="align-middle" data-id="' + data[i].id + '" data-cmc="' + data.find(x => x.id == data[i].id).cmc + '" data-balance="' + (data[i].balance ? data[i].balance.split(' ')[0] : "") + '">';
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>';
tableBody +='<td class="align-middle">' + (data[i].enabled ? (i + 1).toString() : '-') + '</td>';
tableBody +='<td class="align-middle em-input" data-field="displayName">' + data[i].name + '</td>';
tableBody +='<td class="align-middle text-left" style="width: 20%">';
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> ';
tableBody +=data[i].url.host + '</td>';
tableBody +='<td class="align-middle">' + data[i].lastClaim.toFixed(8) + '</td>';
tableBody +='<td class="align-middle">' + data[i].aggregate.toFixed(8) + '</td>';
tableBody +='<td class="align-middle">' + (data[i].balance ? data[i].balance.split(' ')[0] : "") + '</td>';
tableBody +='<td class="align-middle fiat-conversion"></td>';
tableBody +='<td class="align-middle">' + helpers.getPrintableTime(data[i].nextRoll) + '</td>';
tableBody +='<td class="align-middle">' + addBadges(data[i].stats) + '</td>';
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>';
tableBody +='</tr>';
}
$('#schedule-table-body').html(tableBody);
location.href = 'javascript:convertToFiat();';
};
function addBadges(stats) {
let consecutiveTimeout = stats.countTimeouts;
let otherErrors = stats.errors;
let html = ' ';
if (consecutiveTimeout) {
html += `<span class="badge badge-pill badge-warning" title="${consecutiveTimeout} consecutive timeouts">${consecutiveTimeout}</span>`;
}
if (otherErrors) {
html += `<span class="badge badge-pill badge-warning" title="${otherErrors.errorMessage}">${otherErrors.errorType}</span>`;
}
return html;
}
function loadPromotionTable(codes) {
let tableBody = '';
for(let c=0; c < codes.length; c++) {
let data = codes[c];
tableBody += '<tr data-promotion-id="' + data.id + '">';
tableBody += '<td class="align-middle text-left ' + (data.repeatDaily ? 'text-warning' : '') + '">';
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> ';
tableBody += '<span title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + data.code + '</span></td>';
tableBody +='<td class="align-middle" title="' + (data.repeatDaily ? 'Reusable Code' : 'One-time-only Code') + '">' + helpers.getPrintableDateTime(data.added) + '</td>';
for(let i=0, all = data.statusPerFaucet.length; i < all; i++) {
tableBody +='<td class="align-middle" title="Runned @' + helpers.getPrintableDateTime(data.statusPerFaucet[i].execTimeStamp) + '">' + helpers.getEmojiForPromoStatus(data.statusPerFaucet[i].status ?? 0) + '</td>';
}
tableBody +='</tr>';
}
$('#promo-table-body').html(tableBody);
};
function refresh(scheduleData, promotionData) {
if (scheduleData) {
loadScheduleTable(scheduleData);
}
if (promotionData) {
loadPromotionTable(promotionData);
}
};
function log(msg, elapsed = false) {
if(msg) {
let previous = logLines[0].split(' ')[1];
if(elapsed && (previous == msg)) {
logLines[0] = helpers.getPrintableTime() + ' ' + msg + ' [Elapsed time: ' + elapsed + ' seconds]';
} else {
logLines.pop();
logLines.unshift(helpers.getPrintableTime() + ' ' + msg);
}
$('#console-log').html(logLines.join('<br>'));
}
};
return {
init: init,
refresh: refresh,
loadPromotionTable: loadPromotionTable,
log: log
}
},
createCFPromotions: function() {
let codes = [];
function PromotionCode(id, code, repeatDaily = false) {
this.id = id;
this.code = code;
this.added = new Date();
this.statusPerFaucet = [];
this.repeatDaily = repeatDaily;
this.lastExecTimeStamp = null;
};
function getFaucetStatusInPromo(promo, faucetId) {
let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
if (faucet.status && promo.repeatDaily) {
//Using 26 hs instead of 24hs, and 2hs gap retry when code is flagged as USEDBEFORE
if((faucet.status == PromoStatus.ACCEPTED && (Date.now() - faucet.execTimeStamp.getTime()) > HS_26_IN_MILLISECONDS)
|| (faucet.status == PromoStatus.USEDBEFORE && (Date.now() - faucet.execTimeStamp.getTime()) > HS_2_IN_MILLISECONDS)) {
faucet.status = PromoStatus.PENDING;
}
}
return faucet.status ?? PromoStatus.NOCODE;
};
function addNew(code, repeatDaily = false) {
let newPromo = new PromotionCode(codes.length, code, repeatDaily);
newPromo.statusPerFaucet = manager.getFaucetsForPromotion().map(x => {
return {
id: x.id,
};});
newPromo.statusPerFaucet.forEach(function (element, idx, arr) {
arr[idx].status = PromoStatus.PENDING;
arr[idx].execTimeStamp = null;
});
codes.push(newPromo);
codes.sort((a, b) => (a.id < b.id) ? 1 : -1);
save();
};
function getAll() {
return codes;
};
function updateFaucetForCode(code, faucetId, newStatus) {
let promo = codes.find(x => x.code == code);
let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
if(faucet) {
faucet.status = newStatus;
faucet.execTimeStamp = new Date();
promo.lastExecTimeStamp = faucet.execTimeStamp;
}
save();
};
function hasPromoAvailable(faucetId) {
let resp = false;
codes.forEach(function (promotion, idx, arr) {
let status = getFaucetStatusInPromo(promotion, faucetId);
if (status == PromoStatus.PENDING) {
resp = promotion.code;
return;
}
});
return resp;
};
function save() {
persistence.save('CFPromotions', getAll(), true);
};
function load(data) {
codes = data;
};
function removeAll() {
codes = [];
save();
};
function remove(id, code) {
let idx = codes.findIndex(x => x.id == id && x.code == code);
if(idx != -1) {
codes.splice(idx, 1);
save();
}
return idx;
};
return {
addNew: addNew,
removeAll: removeAll,
remove: remove,
getAll: getAll,
load: load,
updateFaucetForCode: updateFaucetForCode,
hasPromoAvailable: hasPromoAvailable
}
},
createInteractions: function(){
let randomInteractionLevel = RandomInteractionLevel.MEDIUM;
let maxActions = 0;
let performedActions = -1;
let selectableElements;
let actions = {
available: [
function() {
$('html, body').animate({
scrollTop: helpers.randomInt(0, $('html, body').get(0).scrollHeight)
}, {
complete: setTimeout(interactions.addPerformed, helpers.randomMs(100, 3000)),
duration: helpers.randomMs(100, 1500)
});
},
function() {
let element = interactions.selectableElements[helpers.randomInt(0, interactions.selectableElements.length - 1)];
try {
if (document.body.createTextRange) {
const range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
} catch (err) { }
interactions.addPerformed();
}
]
};
function start(selectableElements) {
performedActions = 0;
switch(randomInteractionLevel) {
case RandomInteractionLevel.NONE:
maxActions = 0;
break;
case RandomInteractionLevel.LOW:
maxActions = helpers.randomInt(2, 4);
break;
case RandomInteractionLevel.MEDIUM:
maxActions = helpers.randomInt(5, 8);
break;
case RandomInteractionLevel.HIGH:
maxActions = helpers.randomInt(12, 16);
break;
}
interactions.selectableElements = selectableElements;
performActions();
}
function performActions() {
if(performedActions >= maxActions) {
return;
}
let delay = 0;
for(let i = 0; i < maxActions; i++) {
delay += helpers.randomMs(350, 1500);
setTimeout(actions.available[helpers.randomInt(0, actions.available.length - 1)], delay);
}
}
function addPerformed() {
performedActions++;
}
function completed() {
return (performedActions >= maxActions);
}
return {
start: start,
completed: completed,
addPerformed: addPerformed,
selectableElements: selectableElements
};
},
createSGProcessor: function() {
let timerSpans;
function run() {
if(isLoading()) {
setTimeout(SGProcessor.run, helpers.randomMs(5000, 10000));
return;
} else if (hasPopup()) {
closePopup();
setTimeout(SGProcessor.run, helpers.randomMs(5000, 10000));
} else {
if(isMinerActive()) {
processRunDetails();
} else {
activateMiner();
}
}
};
function hasPopup() {
return $('.wrapper.grid.min-h-0.md-min-h-1-2.md-relative.md-rounded-lg.md-bg-dark-4 svg circle').length > 0;
};
function closePopup() {
try {
$('svg.flex.w-8.h-8.fill-current')[0].parentElement.click();
} catch { }
};
function isLoading() {
return $('#loader-logo').length;
};
function isMinerActive() {
timerSpans = $('.mb-8 .wrapper .mb-1 span');
if(timerSpans.length > 0) {
return true;
} else {
return false;
}
return (timerSpans.length === 0);
};
function activateMiner() {
const activateButton = document.querySelector('.mb-8 .wrapper button');
if (activateButton) {
activateButton.click();
setTimeout(SGProcessor.processRunDetails, helpers.randomMs(10000, 20000));
} else {
if(!is404Error()) {
SGProcessor.processRunDetails()
}
}
};
function is404Error() {
const h1 = document.getElementsByTagName('h1');
if (h1.length > 0 && h1[0].innerText.includes('404')) {
window.location.reload();
return true;
}
return false;
}
function processRunDetails() {
let result = {};
result.nextRoll = helpers.addMinutes(new Date(), readCountdown().toString());
result.balance = readBalance();
shared.closeWindow(result);
};
function readCountdown() {
let mins = 15;
try {
let timeLeft = timerSpans.last().text().split(':');
if(timeLeft.length === 3) {
mins = parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
}
} catch (err) { }
return mins;
};
function readBalance() {
let balance = "";
try {
balance = $('span.text-accent').first().text() + " BTC";
} catch (err) { }
return balance;
};
return {
run: run,
processRunDetails: processRunDetails
};
},
createCFProcessor: function() {
const NavigationProcess = {
ROLLING: 1,
PROCESSING_PROMOTION: 2,
LOGIN: 3
};
let navigationProcess;
let countdown;
let rollButton;
let promotionTag;
let timeWaiting= 0;
let loopingForErrors = false;
function run() {
navigationProcess = NavigationProcess.ROLLING;
displayStatusUi();
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
};
function doLogin() {
navigationProcess = NavigationProcess.LOGIN;
displayStatusUi();
setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
};
function isFullyLoaded() { //Waits 55 seconds max
if(document.readyState == 'complete' || timeWaiting == -1) {
$('#process-status')[0].innerHTML = 'Interacting';
timeWaiting = 0;
interact();
} else {
timeWaiting = -1;
$('#process-status')[0].innerHTML = 'Waiting for document fully loaded';
setTimeout(CFProcessor.isFullyLoaded, helpers.randomMs(45000, 55000));
}
};
function runPromotion() {
navigationProcess = NavigationProcess.PROCESSING_PROMOTION
displayStatusUi();
setTimeout(CFProcessor.findPromotionTag, helpers.randomMs(1000, 3000));
};
function findCountdownOrRollButton() {
if( isCountdownVisible() && !isRollButtonVisible() ) {
timeWaiting = 0;
processRunDetails();
} else if ( !isCountdownVisible() && isRollButtonVisible() ) {
timeWaiting = 0;
setTimeout(CFProcessor.isFullyLoaded, helpers.randomMs(1000, 5000));
} else {
if (timeWaiting/1000 > config.defaults.timeout * 60) {
shared.closeWithError('TIMEOUT', '');
return;
}
timeWaiting += 3000;
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
}
};
function findLoginForm() {
if ( $('div.login-wrapper').is(':visible') ) {
//Other possible error is if recaptcha did not load yet... so maybe wait til the web is fully loaded for low connection issues
if( $('.login-wrapper .error').length > 0 && $('.login-wrapper .error')[0].innerHTML != '') {
let errorMessage = $('.login-wrapper .error').text();
shared.closeWithError('LOGIN_ERROR', errorMessage);
return;
}
if(!loopingForErrors) {
if(config.cf.credentials.mode == 1) {
timeWaiting = 0;
$('.login-wrapper input[name="email"]').val(config.cf.credentials.email);
$('.login-wrapper input[name="password"]').val(config.cf.credentials.password);
$('.login-wrapper button.login').click();
loopingForErrors = true;
} else {
if($('.login-wrapper input[name="email"]').val() != '' && $('.login-wrapper input[name="password"]').val() != '') {
$('.login-wrapper button.login').click();
$('#process-status')[0].innerHTML = 'Processing';
loopingForErrors = true;
} else {
$('#process-status')[0].innerHTML = 'Waiting for credentials...';
if (timeWaiting/1000 > (config.defaults.timeout / 1.5) * 60) {
shared.closeWithError('LOGIN_ERROR', 'No credentials were provided');
return;
}
}
}
}
}
if (timeWaiting/1000 > config.defaults.timeout * 60) {
shared.closeWithError('TIMEOUT', '');
return;
}
timeWaiting += 3000;
setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
};
function interact() {
let selectables = []
selectables = selectables.concat($('td').toArray());
selectables = selectables.concat($('p').toArray());
selectables = selectables.concat($('th').toArray());
interactions.start(selectables);
setTimeout(CFProcessor.waitInteractions, helpers.randomMs(2000, 4000));
}
function waitInteractions() {
if(interactions.completed()) {
roll();
} else {
setTimeout(CFProcessor.waitInteractions, helpers.randomMs(2000, 4000));
}
}
function isCountdownVisible() {
countdown = $('.timeout-wrapper');
return ($(countdown).length > 0 && $(countdown[0]).is(':visible'));
};
function isRollButtonVisible() {
rollButton = $('.main-button-2.roll-button.bg-2');
return ($(rollButton).length > 0 && $(rollButton[0]).is(':visible'));
};
function roll() {
$('#process-status')[0].innerHTML = 'Roll triggered';
$(rollButton[0]).click();
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 3000));
}
function isPromotionTagVisible() {
let pTags = $('p');
if (pTags.length > 0) {
promotionTag = $('p')[0];
return true;
}
return false;
};
function findPromotionTag() {
if( isPromotionTagVisible() ) {
processRunDetails();
} else {
setTimeout(CFProcessor.findPromotionTag, helpers.randomMs(2000, 5000));
}
};
function processRunDetails() {
let result = {};
if(navigationProcess == NavigationProcess.ROLLING) {
result.nextRoll = readCountdown();
result.claimed = readClaimed();
result.balance = readBalance();
if(result.claimed != 0) {
result.rolledNumber = readRolledNumber();
}
result.balance = readBalance();
} else if (navigationProcess == NavigationProcess.PROCESSING_PROMOTION) {
result.promoStatus = readPromoStatus();
result.promoCode = readPromoCode();
if (result.promoStatus == PromoStatus.ACCEPTED) {
result.nextRoll = helpers.addMinutes(new Date(-20), "0");
}
}
shared.closeWindow(result);
};
function readCountdown() {
let minsElement = $('.timeout-container .minutes .digits');
let mins = "0";
if ($(minsElement).length > 0) {
mins = $(minsElement)[0].innerHTML;
}
if (mins) {
return helpers.addMinutes(new Date(), mins.toString());
} else {
return null;
}
};
function readClaimed() {
let claimed = 0;
try {
claimed = $('.result')[0].innerHTML;
claimed = claimed.trim();
claimed = claimed.slice(claimed.lastIndexOf(" ") + 1);
} catch(err) { }
return claimed;
};
function readRolledNumber() {
let number = 0;
try {
number = $('.lucky-number').toArray().map(x => x.innerText).join('');
number = parseInt(number);
} catch(err) { }
return number;
};
function readBalance() {
let balance = "";
try {
balance = $('.navbar-coins.bg-1 a').first().text();
} catch(err) { }
return balance;
};
function readPromoStatus() {
let promoStatus = PromoStatus.UNKNOWNERROR;
try {
if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeAccepted) > 0) {
return PromoStatus.ACCEPTED;
} else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeUsed) > 0) {
return PromoStatus.USEDBEFORE;
} else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeExpired) > 0) {
return PromoStatus.EXPIRED;
} else if(localeConfig.stringSearches.promoCodeInvalid.findIndex(x => promotionTag.innerHTML.indexOf(x) > -1) == -1) {
return PromoStatus.INVALID;
}
} catch ( err ) { }
return promoStatus;
};
function validatePromoString() {
};
function readPromoCode() {
var urlSplit = window.location.href.split('/');
return urlSplit[urlSplit.length - 1];
};
function displayStatusUi() {
$( 'body' ).prepend( '<div class="withdraw-button bg-2" style="top:30%; z-index:1500;" href="#">⚙️ <span id="process-status">Processing</span></div>' );
};
return {
run: run,
runPromotion: runPromotion,
findPromotionTag: findPromotionTag,
waitInteractions: waitInteractions,
isFullyLoaded: isFullyLoaded,
doLogin: doLogin
};
},
createCFHistory: function() {
let rollsMeta = [
{ id: 0, range: '0000-9885', count: 0 },
{ id: 1, range: '9886-9985', count: 0 },
{ id: 2, range: '9986-9993', count: 0 },
{ id: 3, range: '9994-9997', count: 0 },
{ id: 4, range: '9998-9999', count: 0 },
{ id: 5, range: '10000', count: 0 }
];
function initOrLoad() {
let storedData = persistence.load('CFHistory', true);
if(storedData) {
rollsMeta = storedData;
}
};
function addRoll(number) {
switch(true) {
case (number <= 9885):
rollsMeta[0].count++;
break;
case (number <= 9985):
rollsMeta[1].count++;
break;
case (number <= 9993):
rollsMeta[2].count++;
break;
case (number <= 9997):
rollsMeta[3].count++;
break;
case (number <= 9999):
rollsMeta[4].count++;
break;
case (number == 10000):
rollsMeta[5].count++;
break;
default:
break;
}
save();
};
function getRollsMeta() {
return rollsMeta.map(x => x.count);
};
function save() {
persistence.save('CFHistory', rollsMeta, true);
};
return {
initOrLoad: initOrLoad,
addRoll: addRoll,
getRollsMeta: getRollsMeta
}
},
createFBProcessor: function() {
let countdownMinutes;
let timeWaiting= 0;
function timedOut(addMs) {
if (timeWaiting/1000 > config.defaults.timeout * 60) {
shared.closeWithError('TIMEOUT', '');
return true;
}
timeWaiting += addMs;
return false;
}
function run() {
setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
};
function findCountdownOrRollButton() {
if ( isCountdownVisible() ) {
timeWaiting = 0;
countdownMinutes = +document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount')[0].innerHTML + 1;
let result = {};
result.balance = readBalance();
result.nextRoll = helpers.addMinutes(new Date(), countdownMinutes.toString());
shared.closeWindow(result);
return;
}
if ( isRollButtonVisible() ) {
if (config.fb.activateRPBonus) {
if (!document.getElementById('bonus_container_free_points')) {
document.querySelector('a.rewards_link').click();
activateBonus(0);
}
}
if (isHCaptchaVisible()) {
waitForCaptcha();
} else {
clickRoll();
}
} else {
setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
}
};
function isCountdownVisible() {
return document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount').length > 0;
};
function isHCaptchaVisible() {
let hCaptchaFrame = document.querySelector('.h-captcha > iframe');
if (hCaptchaFrame && $(hCaptchaFrame).is(':visible')) {
return true;
}
return false;
};
function isRollButtonVisible() {
return $(document.getElementById('free_play_form_button')).is(':visible');
};
function waitForCaptcha() {
if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0) {
clickRoll();
} else {
if (timedOut(10000)) {
return;
}
setTimeout(waitForCaptcha, helpers.randomMs(10000, 12000));
}
};
function clickRoll() {
try {
document.getElementById('free_play_form_button').click();
setTimeout(processRunDetails, helpers.randomMs(3000, 10000));
} catch (err) {
shared.closeWithError('CLICK_ROLL_ERROR', err);
}
};
function processRunDetails() {
if ($(document.getElementById('winnings')).is(':visible')) {
closePopup();
let result = {};
result.claimed = readClaimed();
result.balance = readBalance();
if(result.claimed != 0) {
result.rolledNumber = readRolledNumber();
result.nextRoll = helpers.addMinutes(new Date(), "60");
}
shared.closeWindow(result);
return;
}
if ($('.free_play_result_error').is(':visible')) {
shared.closeWithError('ROLL_ERROR', $('.free_play_result_error')[0].innerHTML);
return;
}
if($('#free_play_error').is(':visible')) {
shared.closeWithError('ROLL_ERROR', $('.free_play_error')[0].innerHTML);
return;
}
if ($(document.getElementById('same_ip_error')).is(':visible')) {
shared.closeWithError('ROLL_ERROR', document.getElementById('same_ip_error').innerHTML);
return;
}
if (timedOut(5000)) {
return;
}
setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
};
function closePopup() {
let closePopupBtn = document.querySelector('.reveal-modal.open .close-reveal-modal');
if (closePopupBtn) {
closePopupBtn.click();
}
};
function readRolledNumber() {
let rolled = 0;
try {
rolled = parseInt([... document.querySelectorAll('#free_play_digits span')].map( x => x.innerHTML).join(''));
} catch { }
return rolled;
};
function readBalance() {
let balance = 0;
try {
balance = document.getElementById('balance').innerHTML;
} catch { }
return balance;
};
function readClaimed() {
let claimed = 0;
try {
claimed = document.getElementById('winnings').innerHTML;
} catch { }
return claimed;
};
function activateBonus(i) {
if($(document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_error')).is(':visible')) {
let closeBtn = document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_box_close')
if ($(closeBtn).is(':visible')) {
closeBtn.click();
}
} else if ($(document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_success')).is(':visible')) {
let closeBtn = document.querySelector('#reward_point_redeem_result_container_div .reward_point_redeem_result_box_close')
if ($(closeBtn).is(':visible')) {
closeBtn.click();
document.querySelector('#free_play_link_li a');
setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
return;
}
}
try {
let redeemButtons = document.querySelectorAll('#free_points_rewards button');
redeemButtons[i].click();
i = i + 1;
} catch (err) {
}
if(i > 4) {
document.querySelector('#free_play_link_li a').click();
setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
return;
}
setTimeout(activateBonus.bind(null, i), 5000);
};
return {
run: run
};
},
createFPProcessor: function() {
let timeWaiting= 0;
function timedOut(addMs) {
if (timeWaiting/1000 > config.defaults.timeout * 60) {
shared.closeWithError('TIMEOUT', '');
return true;
}
timeWaiting += addMs;
return false;
}
function ptcList() {
let result;
let runMsgDiv = document.querySelector('.alert.alert-info');
if (runMsgDiv) {
let runMsg = runMsgDiv.innerHTML;
if (runMsg.includes('invalid captcha')) {
// Warn? Usually a error if ptcList is refreshed
} else if (runMsg.includes('Good job')) {
// "Good job! You have been credited with 0.00000001 BTC."
try {
let idx = runMsg.search(/\d/);
let claimed = parseFloat(runMsg.slice(idx, idx + 10));
result = shared.getResult();
result.claimed = (result.claimed ?? 0) + claimed;
result.nextRoll = helpers.addMilliseconds(new Date(), helpers.getRandomMillisecondsFromMinutesRange(config.fp.hoursBetweenRuns * 60, 2)); // Wait hoursBetweenRuns +/- 1%
shared.updateWithoutClosing(result);
} catch (err) {
// GM_log(`Error reading claimed amount: ${err}`);
}
}
}
if ($('b:contains("Whoops!")').length) {
result = shared.getResult();
result.nextRoll = helpers.addMilliseconds(new Date(), helpers.getRandomMillisecondsFromMinutesRange(config.fp.hoursBetweenRuns * 60, 2)); // Wait hoursBetweenRuns +/- 2%
shared.closeWindow(result);
return;
}
let adButtons = $('button').filter(function(idx) {
return this.innerHTML.includes('VISIT AD FOR') > 0;
});
if (adButtons.length > 0) {
adButtons[0].click();
return;
}
if (timedOut(10000)) {
return;
}
setTimeout(ptcList, helpers.randomMs(10000, 12000));
}
function ptcSingle() {
if($('input[name="complete"]').is(':visible')) {
setTimeout(waitForCaptcha, 15000);
} else {
if (timedOut(5000)) {
return;
}
setTimeout(ptcSingle, helpers.randomMs(5000, 6000));
}
}
function waitForCaptcha() {
if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0 ) {
clickClaim();
} else {
if (timedOut(9000)) {
return;
}
setTimeout(waitForCaptcha, helpers.randomMs(9000, 11000));
}
}
function clickClaim() {
$('input[name="complete"]').focus();
$($('input[name="complete"]')[0]).attr("onclick", "");
$('input[name="complete"]').click();
//force close with timeout in case it's still opened
setTimeout(shared.closeWithError.bind(null, 'TIMEOUT', 'Timed out after clicking a CLAIM button.'), config.defaults.timeout * 60 * 1000);
}
return {
ptcList: ptcList,
ptcSingle: ptcSingle
};
},
// TODO: refactor to add more faucets to this processor:
createGenericFaucetProcessor: function(wt) {
let webType = wt;
let countdownMinutes;
let timeWaiting= 0;
let selectElement = {
rollButton: function() {
switch (webType) {
case WebType.FREELITECOIN:
return document.getElementById('roll');
break;
case WebType.FREEETHEREUMIO:
return document.querySelector('#rollform button');
break;
default:
return;
break;
}
},
balance: function() {
switch (webType) {
case WebType.FREELITECOIN:
return document.getElementById('money');
break;
case WebType.FREEETHEREUMIO:
return document.getElementById('cryptovalue')
break;
default:
return;
break;
}
}
};
function timedOut(addMs) {
if (timeWaiting/1000 > config.defaults.timeout * 60) {
shared.closeWithError('TIMEOUT', '');
return true;
}
timeWaiting += addMs;
return false;
}
function run() {
setTimeout(findCountdownOrRollButton, helpers.randomMs(12000, 15000));
};
function findCountdownOrRollButton() {
if ( isCountdownVisible() ) {
timeWaiting = 0;
let countdownMinutes = document.getElementById('cislo1');
let result = {};
result.balance = readBalance();
result.nextRoll = helpers.addMinutes(new Date(), countdownMinutes.innerHTML.toString());
shared.closeWindow(result);
return;
}
if ( isRollButtonVisible() ) {
if (isHCaptchaVisible()) {
waitForCaptcha();
} else {
clickRoll();
}
} else {
setTimeout(findCountdownOrRollButton, helpers.randomMs(10000, 12000));
}
};
function isCountdownVisible() {
return $(document.getElementById('cislo1')).is(':visible') || $(document.getElementById('cislo2')).is(':visible');
};
function isHCaptchaVisible() {
let hCaptchaFrame = document.querySelector('.h-captcha > iframe');
if (hCaptchaFrame && $(hCaptchaFrame).is(':visible')) {
return true;
}
return false;
};
function isRollButtonVisible() {
let rollButton = selectElement.rollButton();
return rollButton && $(rollButton).is(':visible');
};
function waitForCaptcha() {
if ( document.querySelector('.h-captcha > iframe').getAttribute('data-hcaptcha-response').length > 0) {
clickRoll();
} else {
if (timedOut(10000)) {
return;
}
setTimeout(waitForCaptcha, helpers.randomMs(10000, 12000));
}
};
function clickRoll() {
try {
selectElement.rollButton().click();
setTimeout(processRunDetails, helpers.randomMs(10000, 12000));
} catch (err) {
shared.closeWithError('CLICK_ROLL_ERROR', err);
}
};
function processRunDetails() {
let info = document.getElementById('info');
if (info && $(info).is(':visible')) {
let result = {};
result.claimed = readClaimed();
result.balance = readBalance();
if(result.claimed != 0) {
result.rolledNumber = readRolledNumber();
result.nextRoll = helpers.addMinutes(new Date(), "60");
}
shared.closeWindow(result);
return;
}
if (timedOut(5000)) {
return;
}
setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
};
function readRolledNumber() {
let rolled = 0;
try {
rolled = parseInt(document.getElementById('numberroll').innerHTML);
} catch { }
return rolled;
};
function readBalance() {
let balance = 0;
try {
balance = selectElement.balance().innerHTML;
} catch { }
return balance;
};
function readClaimed() {
let claimed = 0;
try {
let info = document.getElementById('info').innerHTML;
let idx = info.search(/0\./);
claimed = parseFloat(info.slice(idx, idx + 10));
} catch { }
return claimed;
};
return {
run: run
};
}
};
/**
* Prevents alert popups to be able to reload the faucet if invisible captcha validation fails
*/
function overrideSelectNativeJS_Functions () {
window.alert = function alert (message) {
console.log (message);
}
}
function addJS_Node (text, s_URL, funcToRun) {
var scriptNode= document.createElement ('script');
scriptNode.type= "text/javascript";
if (text)scriptNode.textContent= text;
if (s_URL)scriptNode.src= s_URL;
if (funcToRun)scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var element = document.getElementsByTagName ('head')[0] || document.body || document.documentElement;
element.appendChild (scriptNode);
}
function detectWeb() {
if(!shared.isOpenedByManager(window.location.host)) {
return;
}
let currentFromManager = shared.getCurrent();
if (currentFromManager.type == WebType.STORMGAIN) {
SGProcessor = objectGenerator.createSGProcessor();
setTimeout(SGProcessor.run, helpers.randomMs(10000, 20000));
return;
}
if (currentFromManager.type == WebType.CRYPTOSFAUCETS) {
let expectedCfUrlType = helpers.cf.getUrlType(currentFromManager.url);
let realCfUrlType = helpers.cf.getUrlType(window.location.href);
switch(expectedCfUrlType) {
case CFUrlType.FREE:
switch(realCfUrlType) {
case CFUrlType.FREE:
if(localeConfig.setToEnglish) {
let refValue = $('.nav-item a')[4].innerHTML;
if (refValue != 'Settings') {
window.location.href = '/set-language/en';
}
}
addJS_Node (null, null, overrideSelectNativeJS_Functions);
CFProcessor = objectGenerator.createCFProcessor();
interactions = objectGenerator.createInteractions();
setTimeout(CFProcessor.run, helpers.randomMs(1000, 3000));
break;
case CFUrlType.CONTACTTWITTER:
//TODO: mark as possibly banned
break;
case CFUrlType.HOME:
if (config.cf.autologin) {
addJS_Node (null, null, overrideSelectNativeJS_Functions);
CFProcessor = objectGenerator.createCFProcessor();
setTimeout(CFProcessor.doLogin, helpers.randomMs(1000, 3000));
} else {
shared.closeWithError('NEED_TO_LOGIN', '');
}
break;
default:
break;
}
break;
case CFUrlType.PROMOTION:
CFProcessor = objectGenerator.createCFProcessor();
interactions = objectGenerator.createInteractions();
setTimeout(CFProcessor.runPromotion, helpers.randomMs(5000, 10000));
break;
}
return;
}
if (currentFromManager.type == WebType.FREEBITCOIN) {
FBProcessor = objectGenerator.createFBProcessor();
setTimeout(FBProcessor.run, helpers.randomMs(2000, 5000));
return;
}
if (currentFromManager.type == WebType.FREELITECOIN) {
FreeGenericFaucetProcessor = objectGenerator.createGenericFaucetProcessor(currentFromManager.type);
let url = new URL(window.location.href);
if (url.pathname == '/') {
setTimeout(FreeGenericFaucetProcessor.run, helpers.randomMs(2000, 5000));
} else if (url.pathname.includes('/login')) {
shared.closeWithError('NEED_TO_LOGIN', '');
}
return;
}
if (currentFromManager.type == WebType.FREEETHEREUMIO) {
FreeGenericFaucetProcessor = objectGenerator.createGenericFaucetProcessor(currentFromManager.type);
let url = new URL(window.location.href);
if (url.pathname == '/free/') {
setTimeout(FreeGenericFaucetProcessor.run(), helpers.randomMs(2000, 5000));
} else if (url.pathname == '/') {
shared.closeWithError('NEED_TO_LOGIN', '');
}
return;
}
if (currentFromManager.type == WebType.FAUCETPAY) {
FPProcessor = objectGenerator.createFPProcessor();
let url = new URL(window.location.href);
if(url.pathname.includes('ptc/view')) {
setTimeout(FPProcessor.ptcSingle, helpers.randomMs(2000, 5000));
} else if (url.pathname.includes('ptc')) {
setTimeout(FPProcessor.ptcList, helpers.randomMs(2000, 5000));
// } else if (url.pathname.includes('page/user-admin')) {
// // Try to claim Reward Points
} else if (url.pathname.includes('account/login')) {
shared.closeWithError('NEED_TO_LOGIN', '');
}
return;
}
}
function init() {
shared = objectGenerator.createShared();
persistence = objectGenerator.createPersistence();
if(window.location.host === 'satology.onrender.com') {
manager = objectGenerator.createManager();
CFPromotions = objectGenerator.createCFPromotions();
ui = objectGenerator.createUi();
CFHistory = objectGenerator.createCFHistory();
manager.init();
} else {
detectWeb();
}
}
init();
})();