// ==UserScript==
// @name [satology] Auto Claim Multiple Faucets with Monitor UI
// @description Automatic rolls and claims for 50+ crypto faucets/PTC/miners (Freebitco.in BTC, auto promo code for 16 CryptosFaucet, FaucetPay, StormGain, etc)
// @description Claim free ADA, BNB, BCH, BTC, DASH, DGB, DOGE, ETH, FEY, LINK, LTC, NEO, SHIB, STEAM, TRX, USDC, USDT, XEM, XRP, ZEC, ETC
// @version 3.0.57
// @author satology
// @namespace satology.onrender.com
// @homepage https://criptologico.com/tools/cc
// @noframes
// @grant GM_info
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// @grant window.close
// @grant GM_openInTab
// @grant window.onurlchange
// @connect criptologico.com
// @note IMPORTANT
// @note - To start the script you need to navigate to https://criptologico.com/tools/cc
// @note - Each schedule will open it's own tab to allow multiclaiming
// @icon https://www.google.com/s2/favicons?domain=criptologico.com
// @require https://cdnjs.cloudflare.com/ajax/libs/nearest-color/0.4.4/nearestColor.js
// @match https://app.stormgain.com/crypto-miner/
// @match https://app.freecardano.com/*
// @match https://app.freebinancecoin.com/*
// @match https://app.freebitcoin.io/*
// @match https://app.freedash.io/*
// @match https://app.free-doge.com/*
// @match https://app.freeethereum.com/*
// @match https://app.freecryptom.com/*
// @match https://app.free-ltc.com/*
// @match https://app.freeneo.io/*
// @match https://app.freesteam.io/*
// @match https://app.free-tron.com/*
// @match https://app.freeusdcoin.com/*
// @match https://app.freetether.com/*
// @match https://app.freenem.com/*
// @match https://app.freeshibainu.com/*
// @match https://app.coinfaucet.io/*
// @match https://app.freepancake.com/*
// @match https://app.freematic.com/*
// @match https://app.freebittorrent.com/*
// @match https://app.freebfg.com/*
// @match https://freebitco.in/*
// @match https://faucetpay.io/*
// @match https://bigbtc.win/*
// @match https://www.bestchange.com/*
// @match https://faucetok.net/*
// @match https://betfury.io/boxes/all*
// @match https://www.free-doge.io/
// @match https://www.free-doge.io/free/
// @match https://autofaucet.dutchycorp.space/login.php*
// @match https://autofaucet.dutchycorp.space/roll.php*
// @match https://autofaucet.dutchycorp.space/coin_roll.php*
// @match https://express.dutchycorp.space/index.php*
// @match https://express.dutchycorp.space/roll.php*
// @match https://express.dutchycorp.space/coin_roll.php*
// @match https://faucetcrypto.com/dashboard
// @match https://faucetcrypto.com/task/faucet-claim
// @match https://faucetcrypto.com/ptc/*
// @match https://faucetcrypto.com/task/ptc-advertisement/*
// @match https://faupig-bit.online/page/dashboard*
// @match https://faupig-bit.online/account/login/not-logged-in
// @match https://freegridco.in/*
// @match https://james-trussy.com/*
// @match https://www.only1024.com/f*
// @match https://criptologico.com/tools/cc*
// @match https://yescoiner.com/*
// @match https://coindiversity.io/*
// @match https://ltcfaucet.top/*
// @match https://bnbfaucet.top/*
// @match https://dogecoinfaucet.top/*
// @match https://tronfaucet.top/*
// @match https://ethfaucet.top/*
// @match https://freebch.club/*
// @match https://zecfaucet.net/*
// @match https://faucet.monster/*
// @match https://auto-crypto.ml/*
// @match https://claimclicks.com/*
// @match https://cryptoclicks.net/*
// @match https://freeshiba.cf/*
// @match https://auto-crypto.click/*
// ==/UserScript==
(function() {
'use strict';
const localeConfig = {
setToEnglish: true, // will set the faucets to English
stringSearches: {
promoCodeAccepted: 'roll',
promoCodeUsed: 'already used',
promoCodeInvalid: ['not found', 'only alphanumeric'],
promoCodeExpired: ['ended']
}
};
const STATUS = {
INITIALIZING: 0,
IDLE: 1,
CLAIMING: 2
};
const K = Object.freeze({
WebType: {
UNDEFINED: 0,
CRYPTOSFAUCETS: 1,
STORMGAIN: 2,
FREEBITCOIN: 3,
FAUCETPAY: 4,
FREELITECOIN: 5,
FREEETHEREUMIO: 6,
BAGIKERAN: 7,
OKFAUCET: 8,
BIGBTC: 9,
BESTCHANGE: 10,
KINGBIZ: 11,
BFBOX: 13,
FREEDOGEIO: 14,
DUTCHYROLL: 15,
FCRYPTO: 16,
CPU: 17,
CBG: 18,
FPB: 19,
G8: 20,
FREEGRC: 21,
HELI: 22,
VIE: 23,
O24: 24,
YCOIN: 25,
CDIVERSITY: 26,
BSCADS: 27,
CTOP: 28,
AUTOCML: 29,
CCLICKS: 30
},
CF: {
UrlType: {
HOME: 0,
FREE: 1,
CONTACTTWITTER: 2,
PROMOTION: 3,
STATS: 4,
SETTINGS: 5,
FREEROLLS: 6,
LOGIN: 7,
GAMES: 8,
IGNORE: 99
},
PromoStatus: {
NOCODE: 0,
PENDING: 1,
ACCEPTED: 2,
USEDBEFORE: 3,
INVALID: 4,
UNKNOWNERROR: 5,
EXPIRED: 6
},
},
RandomInteractionLevel: {
NONE: 0,
LOW: 1,
MEDIUM: 2,
HIGH: 3
},
Integers: {
HS_26_IN_MILLISECONDS: 93600000, //Using 26 hs instead of 24hs
HS_2_IN_MILLISECONDS: 7200000 //and 2hs gap retry when code is flagged as USEDBEFORE
},
WalletType: {
FP_USERNAME: 99,
FP_MAIL: 100,
FP_BTC: 101,
FP_BNB: 102,
FP_BCH: 103,
FP_DASH: 104,
FP_DGB: 105,
FP_DOGE: 106,
FP_ETH: 107,
FP_FEY: 108,
FP_LTC: 109,
FP_TRX: 110,
FP_USDT: 111,
FP_ZEC: 112,
FP_SOL: 113,
FP_MATIC: 114,
FP_XRP: 115,
FP_ADA: 116,
EC: 200,
BTC: 1,
LTC: 2
},
ErrorType: {
ERROR: 0,
TIMEOUT: 1,
NEED_TO_LOGIN: 2,
ROLL_ERROR: 3,
CLICK_ROLL_ERROR: 4,
LOGIN_ERROR: 5,
CLAIM_ERROR: 6,
ADDRESS_ERROR: 7,
MIN_WITHDRAW_ERROR: 8,
IP_BAN: 9,
IP_RESTRICTED: 10,
IP_ERROR: 11,
FORCE_CLOSED: 12,
NO_FUNDS: 13,
VERIFY_EMAIL: 14,
NO_ADDRESS: 15,
FAUCET_EMPTY: 16
},
CMC: {
MULT: '-1',
BTC: '1',
LTC: '2',
XRP: '52',
DOGE: '74',
DGB: '109',
DASH: '131',
USDT: '825',
XEM: '873',
ETH: '1027',
STEEM: '1230',
NEO: '1376',
ZEC: '1437',
BCH: '1831',
BNB: '1839',
TRX: '1958',
LINK: '1975',
ADA: '2010',
USDC: '3408',
SOL: '5426',
SHIB: '5994',
FEY: '10361',
BFG: '11038',
CAKE: '7186',
GRC: '833',
MATIC: '3890',
BABY: '10334',
BTT: '16086',
BSW: '10746',
},
LOCATION: {
UNKNOWN: 0,
MANAGER: 1,
SITE: 2
}
});
let persistence, shared, manager, ui, CFPromotions, interactions, CFHistory, SiteProcessor, eventer;
let uiRenderer;
Element.prototype.isVisible = function() {
return !!(this.offsetWidth||this.offsetHeight||this.getClientRects().length);
};
Element.prototype.isUserFriendly = function(selector) {
let e = selector ? this.querySelector(selector) : this;
return e && e.isVisible() ? e : null;
};
Document.prototype.isUserFriendly = Element.prototype.isUserFriendly;
Number.prototype.toDate = function() {
return new Date(this);
};
Number.prototype.msToCountdown = function() {
const remainingSeconds = Math.ceil(this / 1000);
const hours = Math.floor(remainingSeconds / 3600).toString().padStart(2, '0');
const minutes = Math.floor((remainingSeconds % 3600) / 60).toString().padStart(2, '0');
const seconds = (remainingSeconds % 60).toString().padStart(2, '0');
return `${hours}:${minutes}:${seconds}`;
};
String.prototype.clean = function() {
let output = "";
for (let i = 0; i < this.length; i++) {
if (this.charCodeAt(i) <= 127) {
output += this.charAt(i);
}
}
return output;
};
String.prototype.formatUnicorn = function () {
"use strict";
var str = this.toString();
if (arguments.length) {
var t = typeof arguments[0];
var key;
var args = ("string" === t || "number" === t) ?
Array.prototype.slice.call(arguments)
: arguments[0];
for (key in args) {
str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
}
}
return str;
};
Array.prototype.shuffle = function () {
let currentIndex = this.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = this[currentIndex];
this[currentIndex] = this[randomIndex];
this[randomIndex] = temporaryValue;
}
return this;
};
let helpers = {
typer: function(inputElm, value) {
let lastValue = inputElm.value;
inputElm.value = value;
let event = new Event('input', { bubbles: true });
event.simulated = true;
let tracker = inputElm._valueTracker;
if (tracker) {
tracker.setValue(lastValue);
}
inputElm.dispatchEvent(event);
},
hasValue: function (val) {
return val !== null && val !== undefined;
},
getTdPrintableTime: function (date = new Date()) {
if (date != null) {
return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);
}
return '';
},
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) || '_ERR';
},
randomMs: function (a, b){
return a + (b - a) * Math.random();
},
addMinutes: function(mins, date = new Date()) {
return date.setMinutes(date.getMinutes() + +mins);
},
addSeconds: function(secs, date = new Date()) {
return date.setSeconds(date.getSeconds() + +secs);
},
randomHexColor: function() {
const hexChars = '0123456789abcdef';
let color = '';
for (let i = 0; i < 6; i++) {
color += hexChars[Math.floor(Math.random() * hexChars.length)];
}
return color;
},
randomString: function(length) {
let str = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
str += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return str;
},
randomInt: function(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
},
addMs: function(ms, date = new Date()) {
return date.setMilliseconds(date.getMilliseconds() + ms);
},
getRandomMs: function(minute, rangeDiffInPercentage) { // Now will be a random value between minute and minute + rangeDiffPercentage%; Example if minute = 30 and rangeDiffPercentage = 5 => random in the range [30, 31.5]
let msMin = minute * 60 * 1000;
let msMax = msMin + rangeDiffInPercentage/100 * msMin;
return helpers.randomMs(msMin, msMax);
},
hsToMs: function(hours) {
return hours * 60 * 60 * 1000;
},
minToMs: function(min) {
return min * 60 * 1000;
},
getEmojiForPromoStatus: function(promoStatus) {
switch (promoStatus) {
case K.CF.PromoStatus.NOCODE:
return '⚪';
case K.CF.PromoStatus.PENDING:
return '⏳';
case K.CF.PromoStatus.ACCEPTED:
return '✔️';
case K.CF.PromoStatus.USEDBEFORE:
return '🕙';
case K.CF.PromoStatus.INVALID:
return '❌';
case K.CF.PromoStatus.EXPIRED:
return '📅';
case K.CF.PromoStatus.UNKNOWNERROR:
return '❗';
}
},
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-rolls')) {
return K.CF.UrlType.FREEROLLS;
}
if (url.split('?')[0].endsWith('/free')) {
return K.CF.UrlType.FREE;
}
if (url.includes('/promotion/')) {
return K.CF.UrlType.PROMOTION;
}
if (url.endsWith('/contact-twitter')) {
return K.CF.UrlType.CONTACTTWITTER;
}
if (url.endsWith('/settings')) {
return K.CF.UrlType.SETTINGS;
}
if (url.endsWith('/stats')) {
return K.CF.UrlType.STATS;
}
if (url.endsWith('/games')) {
return K.CF.UrlType.GAMES;
}
if (url.endsWith('/')) {
url = url.slice(0, -1);
if (url == helpers.getHost(url, true)) {
return K.CF.UrlType.HOME;
}
}
if (url.endsWith('/login')) {
return K.CF.UrlType.LOGIN;
}
return K.CF.UrlType.IGNORE;
}
},
triggerMouseEvent: function (elm, eventType) {
let clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent (eventType, true, true);
elm.dispatchEvent (clickEvent);
},
alternativeClick: function (elm) {
helpers.triggerMouseEvent (elm, "mouseover");
helpers.triggerMouseEvent (elm, "mousedown");
helpers.triggerMouseEvent (elm, "mouseup");
helpers.triggerMouseEvent (elm, "click");
},
textQuerySelector: function (selector, text) {
let all = [...document.querySelectorAll(selector)].filter(x => x.innerText.toLowerCase() == text.toLowerCase())
if (all.length == 1) {
return all[0];
}
return undefined;
}
}
class Persistence {
constructor(prefix = 'autoWeb_') {
this.prefix = prefix;
}
save(key, value, parseIt = false) {
GM_setValue(this.prefix + key, parseIt ? JSON.stringify(value) : value);
}
load(key, parseIt = false) {
let value = GM_getValue(this.prefix + key);
if(value && parseIt) {
value = JSON.parse(value);
}
return value;
}
}
let objectGenerator = {
createShared: function() {
let config = {};
function initializeConfig() {
config = {
'devlog.enabled': false,
'devlog.maxLines': 200,
'defaults.extraInterval': true,
'defaults.timeout': 4,
'defaults.postponeMinutes': 65,
'defaults.postponeMinutes.min': 65,
'defaults.postponeMinutes.max': 65,
'defaults.workInBackground': true,
'defaults.nextRun.useCountdown': true,
'defaults.nextRun': 60,
'defaults.nextRun.min': 60,
'defaults.nextRun.max': 60,
'defaults.sleepMode': false,
'defaults.sleepMode.min': "00:00",
'defaults.sleepMode.max': "01:00",
'cf.tryGetCodes': false,
'cf.usePromoCodes': true,
'cf.rollOnce': false,
'cf.autologin': false,
'cf.credentials.mode': 1,
'cf.credentials.email': 'YOUR@EMAIL.com',
'cf.credentials.password': 'YOURPASSWORD',
'cf.sleepHoursIfIpBan': 8,
'fp.maxTimeInMinutes': 15,
'fp.randomPtcOrder': true,
'dutchy.useBoosted': false,
'bk.withdrawMode': "0",
'bk.hoursBetweenWithdraws': 4,
'bk.sleepMinutesIfIpBan': 75,
'bestchange.address': '101',
'ui.runtime': 0,
'bigbtc.postponeMinutes': '0',
'jtfey.credentials.mode': 2,
'jtfey.credentials.username': 'YOUR_USERNAME',
'jtfey.credentials.password': 'YOURPASSWORD',
'ycoin.credentials.mode': 2,
'ycoin.credentials.username': 'YOUR_ACCOUNT_NUMBER',
'ycoin.credentials.password': 'YOURPASSWORD',
'bkclass.coin': 'LTC',
'bkclass.bcoin': 'LTC',
'migrations': [
{version: '00200799', applied: false} // migration to change pcodes status from error to usable due to ui changes
]
};
let storedData = persistence.load('config', true);
if(storedData) {
for (const prop in config) {
if(storedData.hasOwnProperty(prop)) {
config[prop] = storedData[prop];
}
}
}
config.version = GM_info.script.version;
};
function getConfig() {
return config;
};
function updateConfig(items) {
items.forEach( function (item) {
config[item.prop] = item.value;
});
persistence.save('config', config, true);
};
function migrationApplied(migrationVersion) {
try {
let mig = config.migrations.find(x => x.version == migrationVersion);
mig.applied = true;
persistence.save('config', config, true);
} catch (err) {
console.warn('Error saving migration as applied');
console.error(err);
}
};
function devlog(msg, elapsed = false, reset = false) {
if(!config['devlog.enabled']) {
return;
}
let log;
if(reset) {
log = [`${helpers.getPrintableTime()}|Log cleared`];
} else {
log = persistence.load('devlog', true);
log = log ?? [];
}
if(msg) {
msg = scheduleUuid ? `[${scheduleUuid}] ${msg}` : msg;
let previous;
try {
previous = log[log.length - 1].split('|')[1];
} catch {}
if(elapsed && (previous == msg)) {
log[log.length - 1] = `${helpers.getPrintableTime()}|${msg}|[Elapsed time: ${elapsed} seconds]`;
} else {
log.push(`${helpers.getPrintableTime()}|${msg}`);
}
}
if(log.length > 200) {
log.splice(0, log.length - 200);
}
persistence.save('devlog', log, true);
};
function getDevLog() {
let log;
log = persistence.load('devlog', true);
if(log) {
return log;
}
};
function getRunningSites() {
let ret = [];
loadFlowControl();
if(!runningSites || runningSites == {}) {
return ret;
}
for (const sch in runningSites) {
if (runningSites[sch].host) {
ret.push(runningSites[sch].host);
}
}
return ret;
}
let runningSites = {}
let scheduleUuid = null;
function isOpenedByManager() {
loadFlowControl();
if(!runningSites || runningSites == {}) {
return false;
}
let uuid = null;
for (const sch in runningSites) {
if ( (runningSites[sch].host && runningSites[sch].host == window.location.host) ||
(runningSites[sch].params && runningSites[sch].params.trackUrl && window.location.href.includes(runningSites[sch].params.trackUrl))
) {
uuid = sch;
break;
}
}
if (!uuid) {
return false;
}
if (runningSites[uuid].runStatus == 'COMPLETED') {
return false;
} else {
scheduleUuid = uuid;
return true;
}
};
function loadFlowControl() {
runningSites = persistence.load('runningSites', true) || {};
};
function setFlowControl(schedule, id, url, webType, params = null) {
runningSites[schedule] = {
id: id,
changedAt: Date.now(),
url: url,
host: url.host,
type: webType,
opened: false,
error: false,
result: {}
};
if(params) {
runningSites[schedule].params = params;
} else {
runningSites[schedule].params = {};
}
saveFlowControl(schedule);
};
function isCompleted(expectedId) {
loadFlowControl();
for(const sch in runningSites) {
if (runningSites[sch].id == expectedId) {
if (runningSites[sch].runStatus == 'COMPLETED') {
return true;
} else {
return false;
}
}
}
return false;
};
function isIncompleted(expectedId) {
loadFlowControl();
for(const sch in runningSites) {
if (runningSites[sch].id == expectedId) {
if (runningSites[sch].runStatus == 'WORKING') {
return true;
} else {
return false;
}
}
}
return false;
};
function hasErrors(expectedId) {
for(const sch in runningSites) {
if (runningSites[sch].id == expectedId && runningSites[sch].error) {
return true;
}
}
return false;
};
function getResult(schedule) {
if (schedule) {
return runningSites.hasOwnProperty(schedule) ? runningSites[schedule].result : {};
}
return runningSites.hasOwnProperty(scheduleUuid) ? runningSites[scheduleUuid].result : {};
};
function getCurrent(schedule) {
if (schedule) {
return runningSites.hasOwnProperty(schedule) ? runningSites[schedule] : {};
}
return runningSites.hasOwnProperty(scheduleUuid) ? runningSites[scheduleUuid] : {};
};
function saveAndclose(runDetails, delay = 0) {
markAsVisited(runDetails);
if(delay) {
setTimeout(window.close, delay);
} else {
setTimeout(window.close, 1000);
}
};
function purgeFlowControlSchedules(validSchedules) {
loadFlowControl();
let deletables = [];
for (var sch in runningSites) {
if (!validSchedules.includes(sch)) {
deletables.push(sch);
}
}
deletables.forEach(x => {
delete runningSites[sch];
});
persistence.save('runningSites', runningSites, true);
};
function saveFlowControl(schedule) {
schedule = schedule ? schedule : scheduleUuid;
if (!schedule) {
persistence.save('runningSites', runningSites, true);
return;
}
let tempFlow = persistence.load('runningSites', true);
tempFlow[schedule] = runningSites[schedule];
persistence.save('runningSites', tempFlow, true);
};
function markAsVisited(runDetails, runStatus = 'COMPLETED') {
if (!scheduleUuid) {
return;
}
runningSites[scheduleUuid].opened = true;
runningSites[scheduleUuid].runStatus = runStatus;
runningSites[scheduleUuid].result = runDetails ? runDetails : runningSites[scheduleUuid].result;
saveFlowControl(scheduleUuid);
};
function addError(errorType, errorMessage, schedule) {
if (schedule) {
runningSites[schedule].error = true;
runningSites[schedule].result.errorType = errorType;
runningSites[schedule].result.errorMessage = errorMessage;
} else {
runningSites[scheduleUuid].error = true;
runningSites[scheduleUuid].result.errorType = errorType;
runningSites[scheduleUuid].result.errorMessage = errorMessage;
}
saveFlowControl(schedule ? schedule : scheduleUuid);
};
function closeWithError(errorType, errorMessage) {
addError(errorType, errorMessage);
window.close();
setInterval(() => {
window.close();
}, 15000);
};
function clearFlowControl(schedule) {
if (schedule && schedule != 'all') {
runningSites[schedule] = {};
saveFlowControl(schedule);
} else if (schedule == 'all') {
runningSites = {};
persistence.save('runningSites', {}, true);
}
};
function clearRetries() {
loadFlowControl();
runningSites[scheduleUuid].retrying = false;
saveFlowControl(scheduleUuid);
return false;
};
function isRetrying() {
if(runningSites[scheduleUuid].retrying) {
return true;
}
runningSites[scheduleUuid].retrying = true;
saveFlowControl(scheduleUuid);
return false;
};
function setProp(key, val) {
runningSites[scheduleUuid][key] = val;
saveFlowControl(scheduleUuid);
};
function getProp(key) {
return runningSites[scheduleUuid][key];
};
function getParam(key) {
try {
} catch {}
return runningSites[scheduleUuid].params[key];
};
initializeConfig();
return {
devlog: devlog,
getDevLog: getDevLog,
setFlowControl: setFlowControl,
isCompleted: isCompleted,
isIncompleted: isIncompleted,
isOpenedByManager: isOpenedByManager,
saveFlowControl: saveFlowControl,
getCurrent: getCurrent,
getResult: getResult,
addError: addError,
closeWindow: saveAndclose,
closeWithError: closeWithError,
updateWithoutClosing: markAsVisited,
hasErrors: hasErrors,
clearFlowControl: clearFlowControl,
getConfig: getConfig,
updateConfig: updateConfig,
clearRetries: clearRetries,
isRetrying: isRetrying,
setProp: setProp,
getProp: getProp,
getParam: getParam,
migrationApplied: migrationApplied,
purgeFlowControlSchedules: purgeFlowControlSchedules,
getRunningSites: getRunningSites
};
},
createCFPromotions: function() {
let codes = [];
function PromotionCode(id, code, repeatDaily = false, expiration = null, isRemoved = false) {
this.id = id;
this.code = code;
this.added = new Date();
this.statusPerFaucet = [];
this.repeatDaily = repeatDaily;
this.lastExecTimeStamp = null;
this['expiration' + 'Date'] = expiration;
this.isRemoved = isRemoved;
};
function getFaucetStatusInPromo(promo, faucetId) {
let faucet = promo.statusPerFaucet.find(x => x.id == faucetId);
if (faucet.status && promo.repeatDaily) {
if((faucet.status == K.CF.PromoStatus.ACCEPTED && (Date.now() - faucet.execTimeStamp.getTime()) > K.Integers.HS_26_IN_MILLISECONDS)
|| (faucet.status == K.CF.PromoStatus.USEDBEFORE && (Date.now() - faucet.execTimeStamp.getTime()) > K.Integers.HS_2_IN_MILLISECONDS)) {
faucet.status = K.CF.PromoStatus.PENDING;
}
}
return faucet.status ?? K.CF.PromoStatus.NOCODE;
};
function addNew(code, repeatDaily = false, expiration = null) {
let found = codes.find(x => x.code == code);
if (found) {
found.repeatDaily = repeatDaily;
found['expiration' + 'Date'] = expiration;
found.isRemoved = false;
} else {
found = new PromotionCode(codes.length, code, repeatDaily, expiration);
codes.push(found);
}
found.statusPerFaucet = manager.getFaucetsForPromotion().map(x => {
return {
id: x.id,
};});
found.statusPerFaucet.forEach(function (element, idx, arr) {
arr[idx].status = K.CF.PromoStatus.PENDING;
arr[idx].execTimeStamp = null;
});
save();
};
function includeNewCodes(newCodes) {
for(let i=0; i<newCodes.length; i++) {
let item = newCodes[i];
let exists = codes.find(x => x.code.toLowerCase() == item.code.toLowerCase());
if (!exists) {
addNew(item.code, !item.oneTimeOnly, item['expiration' + 'Date']);
} else {
}
}
};
function getAll() {
return codes.filter(x => !x.isRemoved);
};
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 = [];
codes.forEach(function (promotion, idx, arr) {
let status = getFaucetStatusInPromo(promotion, faucetId);
if (status == K.CF.PromoStatus.PENDING && !promotion.isRemoved) {
resp.push(promotion.code);
}
});
if (resp.length > 0) {
return resp;
} else {
return false;
}
};
function save() {
persistence.save('CFPromotions', codes, true);
};
function load(data) {
codes = data;
save();
};
function removeAll() {
codes.forEach(x => x.isRemoved = true);
codes = codes.filter(x => x['expiration' + 'Date'] && Date.parse(x['expiration' + 'Date']) > Date.now());
save();
};
function remove(id, code) {
let idx = codes.findIndex(x => x.id == id && x.code == code);
if(idx != -1) {
codes[idx].isRemoved = true;
save();
}
return idx;
};
return {
addNew: addNew,
removeAll: removeAll,
remove: remove,
getAll: getAll,
load: load,
updateFaucetForCode: updateFaucetForCode,
hasPromoAvailable: hasPromoAvailable,
includeNewCodes: includeNewCodes
}
},
createInteractions: function(){
let randomInteractionLevel = K.RandomInteractionLevel.MEDIUM;
let maxActions = 0;
let performedActions = -1;
let selectableElements;
let actions = {
available: [
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 K.RandomInteractionLevel.NONE:
maxActions = 0;
break;
case K.RandomInteractionLevel.LOW:
maxActions = helpers.randomInt(2, 4);
break;
case K.RandomInteractionLevel.MEDIUM:
maxActions = helpers.randomInt(5, 8);
break;
case K.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
};
},
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;
let tempRollNumber = null;
let firstRollCompleted = false;
function init() {
let urlType = helpers.cf.getUrlType(window.location.href);
console.log('URL TYPE:', urlType)
switch(urlType) {
case K.CF.UrlType.FREE:
if(localeConfig.setToEnglish) {
document.querySelector('.locale-changer .p-dropdown-trigger')?.click();
setTimeout(() => {
document.querySelector("#pv_id_3_3")?.click();
}, 1000);
}
addJS_Node (null, null, overrideSelectNativeJS_Functions);
interactions = objectGenerator.createInteractions();
run();
break;
case K.CF.UrlType.PROMOTION:
interactions = objectGenerator.createInteractions();
runPromotion();
break;
case K.CF.UrlType.GAMES:
location.replace('/free');
break;
case K.CF.UrlType.HOME:
case K.CF.UrlType.LOGIN:
if (shared.getConfig()['cf.autologin']) {
addJS_Node (null, null, overrideSelectNativeJS_Functions);
doLogin();
} else {
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
}
break;
case K.CF.UrlType.CONTACTTWITTER:
shared.closeWithError(K.ErrorType.IP_BAN, '');
break;
default:
break;
}
return;
}
function run() {
navigationProcess = NavigationProcess.ROLLING;
setInterval(tryClosePopup, helpers.randomMs(3000, 6000));
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
};
function doLogin() {
navigationProcess = NavigationProcess.LOGIN;
setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
};
function isFullyLoaded() { //Waits 55 seconds max
if(document.readyState == 'complete' || timeWaiting == -1) {
timeWaiting = 0;
if (firstRollCompleted) {
roll();
} else {
interact();
}
} else {
timeWaiting = -1;
setTimeout(isFullyLoaded, helpers.randomMs(15000, 25000));
}
};
function runPromotion() {
navigationProcess = NavigationProcess.PROCESSING_PROMOTION
setTimeout(findPromotionTag, helpers.randomMs(1000, 3000));
};
function tryClosePopup() {
let popupBtn = document.querySelector('.p-dialog .p-dialog-header-close');
if (popupBtn && popupBtn.isVisible()) {
popupBtn.click();
}
};
function isRollResultVisible() {
let rollDiv = document.querySelector('.result');
if (rollDiv && rollDiv.isVisible() && rollDiv.innerText != '') {
}
};
let waitRollNumberCount = 0;
function closeToast() {
document.querySelector('.p-toast-icon-close')?.click();
}
async function waitForRollNumber() {
let newNumber = -1;
try { // intento leer el rolled number
newNumber = [...document.querySelectorAll('.lucky-number-wrapper img')].map(x => x.src.split('/').slice(-1)[0].split('.').slice(-3)[0]).join('');
newNumber = parseInt(newNumber)
} catch(err) {
newNumber = null;
}
if (newNumber === null) { // si no logro leerlo, bajo 1 en tempRollNumber
if (tempRollNumber < 0) {
tempRollNumber -= 1;
} else {
tempRollNumber = -1;
}
if (tempRollNumber < -5) {
processRunDetails();
return;
} else {
await wait(3000);
return waitForRollNumber();
}
}
if (newNumber == tempRollNumber) {
timeWaiting = 0;
if (shared.getConfig()['cf.rollOnce']) {
processRunDetails();
return;
} else {
firstRollCompleted = true;
closeToast();
setTimeout(findCountdownOrRollButton, helpers.randomMs(1000, 2000));
return;
}
} else {
waitRollNumberCount++;
if (waitRollNumberCount > 15) {
setTimeout(() => { location.reload(); }, 5000);
return;
}
tempRollNumber = newNumber;
await wait(3000);
return waitForRollNumber();
}
};
function isLoggedIn() {
return !!document.querySelector('[data-icon="user"]');
}
function findCountdownOrRollButton() {
if (!isLoggedIn()) {
location.reload();
}
if( isCountdownVisible() && !isRollButtonVisible() ) {
timeWaiting = 0;
processRunDetails();
} else if ( !isCountdownVisible() && isRollButtonVisible() ) {
timeWaiting = 0;
setTimeout(isFullyLoaded, helpers.randomMs(1000, 5000));
} else if ( isCountdownVisible() && isRollButtonVisible() ) {
try {
let minLeft = document.querySelector('.minutes .digits').innerText;
if (minLeft < 1) {
timeWaiting = 0;
setTimeout(isFullyLoaded, helpers.randomMs(1000, 5000));
}
} catch (err) { console.log(`Error on alt logic of CF roll: ${err}`); }
} else {
if (timeWaiting/1000 > shared.getConfig()['defaults.timeout'] * 60) {
shared.closeWithError(K.ErrorType.TIMEOUT, '');
return;
}
timeWaiting += 3000;
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
}
};
function addUrlChangeListener() {
if (window.onurlchange === null) {
window.addEventListener('urlchange', (data) => {
if (navigationProcess == NavigationProcess.LOGIN && !window.location.href.includes('/login')) {
loopingForErrors = false;
init();
}
});
}
};
function findLoginForm() {
if ( document.querySelector('#email')?.isVisible() && document.querySelector('#password')?.isVisible() ) {
addUrlChangeListener();
let errElement = document.querySelector('.login-wrapper .error');
if( errElement && errElement.innerHTML != '') {
let errorMessage = errElement.innerText;
shared.closeWithError(K.ErrorType.LOGIN_ERROR, errorMessage);
return;
}
if(!loopingForErrors) {
if(shared.getConfig()['cf.credentials.mode'] == 1) {
timeWaiting = 0;
helpers.typer(document.querySelector('.login-wrapper input[name="email"],#email'), shared.getConfig()['cf.credentials.email']);
helpers.typer(document.querySelector('.login-wrapper input[name="password"],#password'), shared.getConfig()['cf.credentials.password']);
document.querySelector('#password')?.closest('div')?.querySelector('button')?.click();
loopingForErrors = true;
} else {
if(document.querySelector('.login-wrapper input[name="email"],#email').value != '' && document.querySelector('.login-wrapper input[name="password"],#password').value != '') {
document.querySelector('#password')?.closest('div')?.querySelector('button')?.click();
loopingForErrors = true;
} else {
if (timeWaiting/1000 > (shared.getConfig()['defaults.timeout'] / 1.5) * 60) {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
return;
}
}
}
}
}
if (timeWaiting/1000 > shared.getConfig()['defaults.timeout'] * 60) {
shared.closeWithError(K.ErrorType.TIMEOUT, '');
return;
}
timeWaiting += 3000;
setTimeout(findLoginForm, helpers.randomMs(2000, 5000));
};
function interact() {
let selectables = [].concat([...document.querySelectorAll('td')], [...document.querySelectorAll('p')], [...document.querySelectorAll('th')]);
interactions.start(selectables);
setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
}
function waitInteractions() {
if(interactions.completed()) {
roll();
} else {
setTimeout(waitInteractions, helpers.randomMs(2000, 4000));
}
}
function isCountdownVisible() {
countdown = document.querySelectorAll('.minutes .digits');
return (countdown.length > 0 && countdown[0].isVisible());
};
function isRollButtonVisible() {
let rollButtonIcon = document.querySelector('.p-button [data-icon="gift"]');
if (!rollButtonIcon) {
return false;
}
rollButton = rollButtonIcon.closest('button');
return rollButton && !rollButton.disabled && rollButton.isVisible();
};
function roll() {
rollButton.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
rollButton.click();
tempRollNumber = -1;
setTimeout(waitForRollNumber, helpers.randomMs(4000, 7000));
}
function isPromotionTagVisible() {
let pTag;
try {
pTag = document.querySelectorAll('.p-message-text.p-message-text')[0];
} catch(err) {
return false;
}
if (pTag) {
promotionTag = pTag;
return true;
}
return false;
};
function findPromotionTag() {
if( isPromotionTagVisible() ) {
processRunDetails();
} else {
setTimeout(findPromotionTag, helpers.randomMs(2000, 5000));
}
};
function processRunDetails() {
let result = {};
if(navigationProcess == NavigationProcess.ROLLING) {
result.claimed = readClaimed();
result.balance = readBalance();
if(result.claimed != 0) {
result.rolledNumber = readRolledNumber();
}
let minOneHour = result.rolledNumber && result.rolledNumber != 0;
result.nextRoll = readCountdown(minOneHour);
result.balance = readBalance();
} else if (navigationProcess == NavigationProcess.PROCESSING_PROMOTION) {
result = shared.getResult() || {};
if (!result.promoCodeResults) {
result.promoCodeResults = [];
}
let pc = {
promoCode: readPromoCode(),
promoStatus: readPromoStatus()
};
result.promoCodeResults.push(pc);
shared.updateWithoutClosing(result, 'WORKING');
setTimeout(gotoNextPromoCode, helpers.randomMs(1000, 2500));
return;
}
shared.closeWindow(result);
};
function gotoNextPromoCode() {
let codes = shared.getCurrent().params.promoCodes;
if (!codes) {
shared.closeWindow();
return;
}
let pc = readPromoCode();
let pcIdx = codes.findIndex(x => x == pc);
if (pcIdx == -1 || pcIdx == codes.length - 1) {
shared.closeWindow();
return;
}
window.location.href = '/promotion/' + codes[pcIdx + 1];
};
function readCountdown(minOneHour = false) {
let minsElement = document.querySelector('.minutes .digits');
let mins = "0";
if (minsElement) {
mins = minsElement.innerHTML;
}
if (mins) {
let estimated = helpers.addMinutes(+mins + 1);
let oneHour = Date.now() + (60*60*1000);
if (minOneHour && (oneHour > estimated) ) {
return oneHour;
}
return estimated;
} else {
return null;
}
};
function readClaimed() {
let claimed = 0;
try {
claimed = document.querySelector('.p-toast-message-text .p-toast-detail').innerHTML;
claimed = claimed.trim();
claimed = claimed.split(' ').slice(-2)[0]
} catch(err) { }
return claimed;
};
function readRolledNumber() {
let number = 0;
try {
number = [...document.querySelectorAll('.lucky-number-wrapper img')].map(x => x.src.split('/').slice(-1)[0].split('.').slice(-3)[0]).join('');
number = parseInt(number);
} catch(err) { }
return number;
};
function readBalance() {
let balance = "";
try {
balance = document.querySelectorAll('header div div div > span span')[1].innerText.trim().split(' ')[0];
} catch(err) { }
return balance;
};
function readPromoStatus() {
let promoStatus = K.CF.PromoStatus.UNKNOWNERROR;
try {
if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeAccepted) > 0) {
return K.CF.PromoStatus.ACCEPTED;
} else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeUsed) > 0) {
return K.CF.PromoStatus.USEDBEFORE;
} else if(promotionTag.innerHTML.indexOf(localeConfig.stringSearches.promoCodeExpired) > 0) {
return K.CF.PromoStatus.EXPIRED;
} else if(localeConfig.stringSearches.promoCodeInvalid.findIndex(x => promotionTag.innerHTML.indexOf(x) > -1) == -1) {
return K.CF.PromoStatus.INVALID;
}
} catch ( err ) { }
return promoStatus;
};
function validatePromoString() {
};
function readPromoCode() {
var urlSplit = window.location.href.split('/');
return urlSplit[urlSplit.length - 1];
};
function displayStatusUi() {
let wrapper = document.createElement('div');
wrapper.innerHTML = '<div class="withdraw-button bg-2" style="top:30%; z-index:1500;" href="#">⚙️ <span id="process-status">Processing</span></div>';
document.querySelector( 'body' ).prepend( wrapper.firstChild );
};
return {
init: init
};
},
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
}
},
};
function overrideSelectNativeJS_Functions () {
window.alert = function alert (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 addHtml(data) { // data = { target: '', where: '', content: '' }
document.querySelector(data.target).insertAdjacentHTML(data.where, data.content);
}
function addTemplateTag(data) {
let templateTag = document.createElement('template');
templateTag.id = data.id;
templateTag.innerHTML = data.content;
let container = document.body || document.documentElement;
container.appendChild(templateTag);
}
function useTemplate(data) { // data = { templateId: '', target: '', where: '', replacements: {} }
let template = document.querySelector(`#${data.templateId}`).innerHTML;
let content = template.formatUnicorn(data.replacements);
addHtml({
target: data.target,
where: data.where,
content: content
});
}
function isExpectedPtc() {
let runningList = shared.getRunningSites();
let ptcHosts = ['faucetpay.io'];
for (let i = 0; i < ptcHosts.length; i++) {
if (document.referrer.includes(`//${ptcHosts[i]}`) && runningList.includes(ptcHosts[i])) {
waitForCloseSignal(ptcHosts[i]);
return true;
}
}
return false;
}
async function waitForCloseSignal(host) {
await wait(3000);
const signal = GM_getValue(`ptc-close-signal-${host}`) || null;
if (signal) {
window.close();
}
return waitForCloseSignal(host);
}
function detectWeb() {
if (isExpectedPtc()) {
return;
}
if(!shared.isOpenedByManager()) {
return;
}
instance = K.LOCATION.SITE;
let typeFromManager = shared.getCurrent().type;
siteTimer = new Timer({ isManager: false, delaySeconds: 20, uuid: shared.getProp('schedule'), webType: typeFromManager });
switch( typeFromManager ) {
case K.WebType.STORMGAIN:
SiteProcessor = createSGProcessor();
setTimeout(SiteProcessor.run, helpers.randomMs(10000, 20000));
break;
case K.WebType.CRYPTOSFAUCETS:
SiteProcessor = objectGenerator.createCFProcessor();
setTimeout(SiteProcessor.init, helpers.randomMs(1000, 3000));
break;
case K.WebType.FREEBITCOIN:
SiteProcessor = createFBProcessor();
setTimeout(SiteProcessor.run, helpers.randomMs(2000, 5000));
break;
case K.WebType.FAUCETPAY:
SiteProcessor = new FPPtc();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
break;
case K.WebType.BIGBTC:
SiteProcessor = createBigBtcProcessor();
setTimeout(SiteProcessor.init, helpers.randomMs(2000, 4000));
break;
case K.WebType.BESTCHANGE:
SiteProcessor = createBestChangeProcessor();
setTimeout(SiteProcessor.init, helpers.randomMs(4000, 6000));
break;
case K.WebType.BFBOX:
SiteProcessor = new BFRoll(helpers.getEnumText(K.CMC, shared.getCurrent().params.cmc).toLowerCase());
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
break;
case K.WebType.DUTCHYROLL:
SiteProcessor = new DutchyRoll();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
break;
case K.WebType.FCRYPTO:
SiteProcessor = new FCryptoRoll();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(2000, 5000));
break;
case K.WebType.FPB:
SiteProcessor = new FPB(shared.getCurrent().params.sitePrefix);
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.FREEGRC:
SiteProcessor = new GRCRoll();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.VIE:
SiteProcessor = new VieRoll();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.O24:
SiteProcessor = new O24Roll();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.YCOIN:
SiteProcessor = new YCoin();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.CDIVERSITY:
SiteProcessor = new CDiversity();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.CTOP:
SiteProcessor = new CTop();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.AUTOCML:
SiteProcessor = new AutoCMl();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
case K.WebType.CCLICKS:
SiteProcessor = new CClicks();
setTimeout(() => { SiteProcessor.init() }, helpers.randomMs(3000, 5000));
break;
default:
break;
}
}
class UiBaseRenderer {
constructor(uiRenderer) { this.uiRenderer = uiRenderer; }
}
class UiSitesRenderer extends UiBaseRenderer {
appendEventListeners() {
document.querySelector('#modal-assign-schedule').addEventListener('click', this.onClickOnModalAssignSchedule.bind(this));
eventer.on('siteChangedSchedule', (e) => {
this.uiRenderer.toast(`Site moved to schedule ${e.scheduleId}`);
manager.resyncAll({withUpdate: true}); // should act based on data only
});
document.querySelector('#schedule-table-body').addEventListener('click', this.onClickOnSitesTableBody.bind(this));
document.querySelector('.action-edit-all-sites').addEventListener('click', this.onClickOnEditAllSites.bind(this));
document.querySelector('.action-edit-all-sites-cancel').addEventListener('click', this.onClickOnCancelEditAllSites.bind(this));
document.querySelector('.action-edit-all-sites-save').addEventListener('click', this.onClickOnSaveEditAllSites.bind(this));
document.querySelector('.action-add-external-site').addEventListener('click', this.onClickOnAddSiteButton.bind(this));
document.querySelector('#modal-add-site').addEventListener('click', this.onClickOnModalAddSite.bind(this));
eventer.on('siteAdded', (e) => {
this.uiRenderer.toast(`Site ${e.siteName} added`);
manager.resyncAll({withUpdate: true}); // should act based on data only
});
eventer.on('siteRemoved', (e) => {
this.uiRenderer.toast(`Site ${e.siteName} removed`);
manager.resyncAll({withUpdate: true}); // should act based on data only
});
}
_legacyAddBadges(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}">${helpers.getEnumText(K.ErrorType, otherErrors.errorType)}</span>`;
}
return html;
}
removeDeletedSitesRows(validSiteIds) {
let removableRows = [...document.querySelectorAll('#schedule-table-body tr')].filter(r => !validSiteIds.includes(r.dataset.id));
removableRows.forEach(r => {
r.remove();
});
}
renderSiteRow(site) {
let row = [...document.querySelectorAll('#schedule-table-body tr')]
.filter(r => r.dataset.id == site.id);
if (row.length == 0) {
row = document.createElement('tr');
document.querySelector('#schedule-table-body').appendChild(row);
row.setAttribute('aria-expanded', false);
row.classList.add('align-middle');
row.dataset.id = site.id;
row.dataset.cmc = site.cmc;
} else {
row = row[0];
}
row.dataset.json = `${JSON.stringify(site)}`;
row.dataset.schedule = site.schedule;
row.dataset.nextRollTimestamp = site.nextRoll ? site.nextRoll.getTime() : 'null';
row.dataset.enabled = site.enabled ? '1' : '0';
if (site.balance) {
if (typeof site.balance == 'string') {
row.dataset.balance = site.balance.split(' ')[0];
} else {
row.dataset.balance = site.balance.toFixed(8);
}
} else {
row.dataset.balance = '';
}
let tds = '';
tds += '<td class="align-middle edit-status d-none em-only"><label class="switch"><input type="checkbox" data-original="' + (site.enabled ? '1' : '0') + '" ' + (site.enabled ? 'checked' : ' ') + '><span class="slider round"></span></label></td>';
tds += '<td class="align-middle" title="' + helpers.getPrintableDateTime(site.nextRoll) + '"><span><i class="fas fa-square pr-1" style="color: #' + site.schedule + ';"></i></span>' + helpers.getTdPrintableTime(site.nextRoll) + '</td>';
if (site.isExternal && site.clId == -1) {
tds += '<td class="align-middle text-left"><a class="" title="Visit site" target="_blank" rel="noreferrer" href="' + site.url + '"><i class="fa fa-external-link-alt"></i></a></td>';
} else {
tds += '<td class="align-middle text-left"><a class="" title="Visit site" target="_blank" rel="noreferrer" href="' + (new URL(site.clId, 'https://criptologico.com/goto/')).href + '"><i class="fa fa-external-link-alt"></i></a></td>';
}
tds += '<td class="align-middle em-input text-left" data-field="displayName">';
if (site.cmc) {
tds +='<div class="input-group input-group-sm">';
tds += '<div class="input-group-prepend"><span class="input-group-text">';
if (site.cmc > 0) {
let cmcLower = helpers.getEnumText(K.CMC, site.cmc).toLowerCase();
tds += '<img loading="lazy" src="/static/c-icons/' + cmcLower + '.svg" height="20" alt="' + cmcLower + '">';
} else {
tds += '<i class="fa fa-question-circle"></i>';
}
tds += '</span></div>';
}
tds += ' <span class="site-name-container px-1">' + site.name + '</span></div></td>';
tds +='<td class="align-middle text-right">' + site.lastClaim.toFixed(Number.isInteger(site.lastClaim) ? 0 : 8) + '</td>';
tds +='<td class="align-middle text-right">' + site.aggregate.toFixed(Number.isInteger(site.aggregate) ? 0 : 8) + '</td>';
tds += '<td class="align-middle text-right">' + (+row.dataset.balance > 100 ? (+row.dataset.balance).toFixed(2) : row.dataset.balance) + '</td>';
tds +='<td class="align-middle text-right fiat-conversion em-hide"></td>';
tds +='<td class="align-middle">' + this._legacyAddBadges(site.stats) + '</td>';
tds +='<td class="align-middle justify-content-center em-hide">';
tds +=
`<div class="btn-group btn-group-sm">
<button type="button" title="Run ASAP" class="btn btn-default action-run-asap">
<i class="fa fa-bolt"></i>
</button>
<button type="button" title="Schedule parameters..."
class="btn btn-default action-edit-site ${Object.keys(site.params).some( k => k.endsWith('.override') && site.params[k] == true ) ? 'text-warning' : ''}">
<i class="fa fa-clock"></i>
</button>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-default dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
</button>
<div class="dropdown-menu dropdown-menu-right text-sm" style="">
<a class="dropdown-item action-site-edit-parameters"><i class="fa fa-edit"></i> Site arguments...</a>
<a class="dropdown-item action-site-assign-schedule"><i class="fa fa-exchange-alt"></i> Move to...</a>`;
if (site.isExternal) {
tds += `<a class="dropdown-item action-site-remove-external"><i class="fa fa-trash"></i> Remove site</a>`;
}
tds += `</div></div></div>`;
tds +='</td></tr>';
row.innerHTML = tds;
}
legacyRenderSiteData(site, config) {
document.querySelector('#faucet-name').innerHTML = site.name;
document.querySelector('#faucet-name').dataset.id = site.id;
let data = site.params || {};
for (const prop in config) {
let overrideElement = document.querySelector('[data-site-prop="' + prop + '.override"]');
if (overrideElement) {
overrideElement.dataset.original = (data[prop + '.override'] ? "1" : "0");
overrideElement.checked = data[prop + '.override'];
}
let element = document.querySelector('[data-site-prop="' + prop + '"]');
if(element) {
if(element.type == 'select-one' || element.type == 'text' || element.type == 'password' || element.type == 'number' || element.type == 'time') {
element.dataset.original = data[prop] ?? config[prop];
element.value = data[prop] ?? config[prop];
} else if (element.type == 'checkbox') {
element.dataset.original = ((data[prop] ?? config[prop]) ? "1" : "0");
element.checked = data[prop] ?? config[prop];
}
element.disabled = true;
}
}
let elWorkInBackgroundOverride = document.querySelector('[data-site-prop="defaults.workInBackground.override"]');
let elWorkInBackground = document.querySelector('[data-site-prop="defaults.workInBackground"]');
elWorkInBackground.disabled = !elWorkInBackgroundOverride.checked;
elWorkInBackgroundOverride.onchange = function (e) {
document.querySelector('[data-site-prop="defaults.workInBackground"]').disabled = !e.target.checked;
}
let elTimeoutOverride = document.querySelector('[data-site-prop="defaults.timeout.override"]');
let elTimeout = document.querySelector('[data-site-prop="defaults.timeout"]');
elTimeout.disabled = !elTimeoutOverride.checked;
elTimeoutOverride.onchange = function (e) {
document.querySelector('[data-site-prop="defaults.timeout"]').disabled = !e.target.checked;
}
let elPostponeOverride = document.querySelector('[data-site-prop="defaults.postponeMinutes.override"]');
let elPostpone = document.querySelector('[data-site-prop="defaults.postponeMinutes"]');
let elPostponeMin = document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]');
let elPostponeMax = document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]');
elPostpone.disabled = !elPostponeOverride.checked;
elPostponeMin.disabled = !elPostponeOverride.checked || (elPostpone.value > "0");
elPostponeMax.disabled = !elPostponeOverride.checked || (elPostpone.value > "0");
elPostponeOverride.onchange = function (e) {
let mode = document.querySelector('[data-site-prop="defaults.postponeMinutes"]');
mode.disabled = !e.target.checked;
document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').disabled = !e.target.checked || mode.value > 0;
document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').disabled = !e.target.checked || mode.value > 0;
}
elPostpone.onchange = function (e) {
document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').disabled = e.target.value > 0;
document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').disabled = e.target.value > 0;
if (e.target.value > 0) {
document.querySelector('[data-site-prop="defaults.postponeMinutes.min"]').value = e.target.value;
document.querySelector('[data-site-prop="defaults.postponeMinutes.max"]').value = e.target.value;
}
}
let elNextRunOverride = document.querySelector('[data-site-prop="defaults.nextRun.override"]');
let elNextRun = document.querySelector('[data-site-prop="defaults.nextRun"]');
let elNextRunMin = document.querySelector('[data-site-prop="defaults.nextRun.min"]');
let elNextRunMax = document.querySelector('[data-site-prop="defaults.nextRun.max"]');
let elNextRunUseCountdown = document.querySelector('[data-site-prop="defaults.nextRun.useCountdown"]');
elNextRun.disabled = !elNextRunOverride.checked;
elNextRunMin.disabled = !elNextRunOverride.checked || (elNextRun.value > "0");
elNextRunMax.disabled = !elNextRunOverride.checked || (elNextRun.value > "0");
elNextRunUseCountdown.disabled = !elNextRunOverride.checked;
elNextRunOverride.onchange = function (e) {
let mode = document.querySelector('[data-site-prop="defaults.nextRun"]');
mode.disabled = !e.target.checked;
document.querySelector('[data-site-prop="defaults.nextRun.min"]').disabled = !e.target.checked || mode.value > 0;
document.querySelector('[data-site-prop="defaults.nextRun.max"]').disabled = !e.target.checked || mode.value > 0;
document.querySelector('[data-site-prop="defaults.nextRun.useCountdown"]').disabled = !e.target.checked;
}
elNextRun.onchange = function (e) {
document.querySelector('[data-site-prop="defaults.nextRun.min"]').disabled = e.target.value > 0;
document.querySelector('[data-site-prop="defaults.nextRun.max"]').disabled = e.target.value > 0;
if (e.target.value > 0) {
document.querySelector('[data-site-prop="defaults.nextRun.min"]').value = e.target.value;
document.querySelector('[data-site-prop="defaults.nextRun.max"]').value = e.target.value;
}
}
let elSleepOverride = document.querySelector('[data-site-prop="defaults.sleepMode.override"]');
let elSleep = document.querySelector('[data-site-prop="defaults.sleepMode"]');
let elSleepMin = document.querySelector('[data-site-prop="defaults.sleepMode.min"]');
let elSleepMax = document.querySelector('[data-site-prop="defaults.sleepMode.max"]');
elSleep.disabled = !elSleepOverride.checked;
elSleepMin.disabled = !elSleepOverride.checked || !elSleep.checked;
elSleepMax.disabled = !elSleepOverride.checked || !elSleep.checked;
elSleepOverride.onchange = function (e) {
let mode = document.querySelector('[data-site-prop="defaults.sleepMode"]');
mode.disabled = !e.target.checked;
document.querySelector('[data-site-prop="defaults.sleepMode.min"]').disabled = !e.target.checked || !mode.checked;
document.querySelector('[data-site-prop="defaults.sleepMode.max"]').disabled = !e.target.checked || !mode.checked;
}
elSleep.onchange = function (e) {
document.querySelector('[data-site-prop="defaults.sleepMode.min"]').disabled = !e.target.checked;
document.querySelector('[data-site-prop="defaults.sleepMode.max"]').disabled = !e.target.checked;
}
return;
}
sortSitesTable() {
const tbody = document.querySelector('#schedule-table-body');
let rows, switching, i, shouldSwitch;
switching = true;
while (switching) {
switching = false;
rows = tbody.rows;
for (i = 0; i < (rows.length - 1); i++) {
shouldSwitch = false;
let aNextRoll, bNextRoll, aHasLoginError, bHasLoginError, aName, bName;
aNextRoll = rows[i].dataset.nextRollTimestamp;
bNextRoll = rows[i + 1].dataset.nextRollTimestamp;
if (aNextRoll == 'null' && bNextRoll == 'null') {
aName = rows[i].querySelector('.site-name-container').innerText;
bName = rows[i + 1].querySelector('.site-name-container').innerText;
if (aName.toLowerCase() > bName.toLowerCase()) {
shouldSwitch = true;
break;
}
} else if (aNextRoll == 'null' || (aNextRoll > bNextRoll)) {
shouldSwitch = true;
break;
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
}
}
}
onClickOnSitesTableBody(e) {
let actionElement = e.target;
if (actionElement.tagName === 'I') {
actionElement = actionElement.parentElement;
}
const row = actionElement.closest('tr');
if (actionElement.classList.contains('action-edit-site')) {
e.stopPropagation();
this.uiRenderer.openModal('modal-site', row.dataset.id);
} else if (actionElement.classList.contains('action-run-asap')) {
e.stopPropagation();
Site.setAsRunAsap(row.dataset.id);
} else if (actionElement.classList.contains('action-site-assign-schedule')) {
this.uiRenderer.openModal('modal-assign-schedule', { site_id: row.dataset.id, schedule_id: row.dataset.schedule });
} else if (actionElement.classList.contains('action-site-edit-parameters')) {
this.uiRenderer.openModal('modal-site-parameters', { site_id: row.dataset.id });
} else if (actionElement.classList.contains('action-site-remove-external')) {
Site.remove(row.dataset.id);
console.info('TODO: remove site and all the related configuration', row.dataset.id);
}
}
onClickOnModalAssignSchedule(e) {
const modalAssignScheduleToSite = document.querySelector('#modal-assign-schedule');
let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
if (actionElement.classList.contains('modal-save')) {
let data = this.uiRenderer.parseContainer(modalAssignScheduleToSite.querySelector('.form-container'));
if (data.original_schedule_id == data.schedule) {
} else {
Site.getById(data.site_id).changeSchedule(data.schedule);
}
}
}
onClickOnModalAddSite(e) {
const modal = document.querySelector('#modal-add-site');
let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
if (actionElement.classList.contains('modal-save')) {
let formData = this.uiRenderer.parseContainer(modal.querySelector('.form-container'));
let data = {};
data.name = formData.site_name;
data.url = new URL(formData.site_url);
data.schedule = formData.schedule;
data.clId = -1;
data.id = 'ext_rnd_id_' + helpers.randomString(8);
data.type = K.WebType.UNDEFINED;
data.cmc = -1;
data.rf = '';
data.isExternal = true;
console.warn('Savable new site');
Site.add(data);
return;
if (data.original_schedule_id == data.schedule) {
} else {
Site.getById(data.site_id).changeSchedule(data.schedule);
}
}
}
onClickOnEditAllSites(e) {
document.querySelectorAll("#schedule-table-body td.em-input .site-name-container").forEach(function (x) {
let val = x.innerHTML;
x.innerHTML = "<input type=\'text\' class=\'form-control form-control-sm\' data-original=\'" + val.trim() + "\' value=\'" + val.trim() + "\' />";
});
document.querySelectorAll("#schedule-table-body td.edit-status").forEach(function (x) {
x.classList.remove("d-none");
});
document.querySelectorAll(".em-only").forEach(x => x.classList.remove("d-none"));
document.querySelectorAll(".em-hide").forEach(x => x.classList.add("d-none"));
}
onClickOnCancelEditAllSites(e) {
document.querySelectorAll("#schedule-table-body td.em-input .site-name-container input").forEach(function(x) {
x.parentNode.innerHTML = x.dataset.original;
});
document.querySelectorAll(".em-only").forEach(x => x.classList.add("d-none"));
document.querySelectorAll(".em-hide").forEach(x => x.classList.remove("d-none"));
}
onClickOnSaveEditAllSites(e) {
let updateObject;
var updateData = document.getElementById("update-data");
if (updateData.innerHTML != "") {
updateObject = JSON.parse(updateData.innerHTML);
} else {
updateObject = {
runAsap: { ids: [], changed: false },
editSingle: { changed: false, items: [] },
wallet: { changed: false, items: [] },
config: { changed: false, items: [] },
site: { changed: false, list: [] }
};
}
document.querySelectorAll("#schedule-table-body tr").forEach(function (row) {
let textInputCell = row.querySelector(".em-input .site-name-container");
let textInput = textInputCell.querySelector("input");
let activeSwitch = row.querySelector("td.edit-status input");
let single = { id: row.dataset.id, displayName: textInput.dataset.original, enabled: activeSwitch.dataset.original };
textInputCell.innerHTML = textInput.value;
if(textInput.dataset.original != textInput.value) {
single.displayName = textInput.value;
}
if(activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {
single.enabled = Boolean(activeSwitch.checked);
}
if(textInput.dataset.original != textInput.value || activeSwitch.dataset.original != Boolean(activeSwitch.checked)) {
updateObject.editSingle.items.push(single);
updateObject.editSingle.changed = true;
}
});
if(updateObject.editSingle.changed) {
document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
this.uiRenderer.toast("Data will be updated as soon as possible");
}
document.querySelectorAll(".em-only").forEach(x => x.classList.add("d-none"));
document.querySelectorAll(".em-hide").forEach(x => x.classList.remove("d-none"));
}
onClickOnAddSiteButton(e) {
e.stopPropagation();
this.uiRenderer.openModal('modal-add-site');
}
renderAddExternalSite() {
const modalAssignSchedule = document.getElementById('modal-add-site');
let selectElm = modalAssignSchedule.querySelector('select');
let options = [];
let firstSchedule = '';
Schedule.getAllForCrud().forEach(sch => {
if (firstSchedule == '') {
firstSchedule = sch.uuid;
}
options.push(`<option value="${sch.uuid}"><i class="fas fa-square" style="color: #${sch.uuid}"></i>${sch.name}</option>`)
});
selectElm.innerHTML = options.join('');
selectElm.value = firstSchedule;
return;
}
renderAssignScheduleToSite(values) {
const modalAssignSchedule = document.getElementById('modal-assign-schedule');
modalAssignSchedule.querySelector('input[name="site_id"]').value = values.site_id;
modalAssignSchedule.querySelector('input[name="original_schedule_id"]').value = values.schedule_id;
let selectElm = modalAssignSchedule.querySelector('select');
let options = [];
Schedule.getAllForCrud().forEach(sch => {
options.push(`<option value="${sch.uuid}"><i class="fas fa-square" style="color: #${sch.uuid}"></i>${sch.name}</option>`)
});
selectElm.innerHTML = options.join('');
selectElm.value = values.schedule_id || "";
return;
}
}
class UiPromosRenderer extends UiBaseRenderer {
appendEventListeners() {
document.querySelector('#promo-button').addEventListener('click', this.onClickSavePromoCode.bind(this));
document.querySelector('#button-try-get-codes').addEventListener('click', this.onClickTryGetCodes.bind(this));
document.querySelector('#promo-table-body').addEventListener('click', this.onClickOnPromoTableBody.bind(this));
}
onClickSavePromoCode(e) {
var promoText = document.getElementById("promo-text-input");
var promoCode = document.getElementById("promo-code-new");
var promoDaily = document.getElementById("promo-daily");
var promoObject = { action: "ADD", code: promoText.value.trim(), repeatDaily: promoDaily.checked };
promoCode.innerHTML =JSON.stringify(promoObject);
this.uiRenderer.toast("Adding promo code: " + promoObject.code + "...");
promoText.value = '';
}
onClickTryGetCodes(e) {
var promoCode = document.getElementById("promo-code-new");
var promoObject = { action: "TRYGETCODES" };
promoCode.innerHTML =JSON.stringify(promoObject);
this.uiRenderer.toast("Fetching codes...");
}
_legacyRemoveUsedDailyCodes(codes) {
if(codes && codes.length) {
codes.forEach(code => {
if(!code.repeatDaily) {
let counter = 0;
for(let i = 0; i < code.statusPerFaucet.length; i++) {
if(code.statusPerFaucet[i].execTimeStamp) {
counter++;
}
}
if(counter == code.statusPerFaucet.length) {
setTimeout(() => removePromoCode(code.id, code.code), 20000);
}
}
});
}
}
legacyRenderPromotionTable(codes) {
let tableBody = '';
this._legacyRemoveUsedDailyCodes(codes);
for(let c=0; c < codes.length; c++) {
let data = codes[c];
tableBody += '<tr data-promotion-code="' + data.code + '" data-promotion-id="' + data.id + '">';
tableBody += '<td class="align-middle text-left ' + (data.repeatDaily ? 'text-warning' : '') + '">';
tableBody += `<a class="action-remove-promo-code" data-toggle="tooltip" data-placement="left" title="Remove" 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>';
}
document.getElementById('promo-table-body').innerHTML = tableBody;
}
onClickOnPromoTableBody(e) {
let actionElement = e.target;
if (actionElement.tagName === 'I') {
actionElement = actionElement.parentElement;
}
const row = actionElement.closest('tr');
if (actionElement.classList.contains('action-remove-promo-code')) {
e.stopPropagation();
var promoCode = document.getElementById("promo-code-new");
var promoObject = { action: "REMOVE", id: row.dataset.promotionId, code: row.dataset.promotionCode };
promoCode.innerHTML =JSON.stringify(promoObject);
}
}
}
class UiConfigRenderer extends UiBaseRenderer {
legacyRenderConfigData(data) {
for (const prop in data) {
let element = document.querySelector('[data-prop="' + prop + '"]');
if(element) {
if(element.type == 'select-one' || element.type == 'text' || element.type == 'password' || element.type == 'number' || element.type == 'time') {
element.dataset.original = data[prop];
element.value = data[prop];
} else if (element.type == 'checkbox') {
element.dataset.original = (data[prop] ? "1" : "0");
element.checked = data[prop];
}
}
}
let elCfTryGetCodes = document.querySelector('[data-prop="cf.tryGetCodes"]')
let elCredentialsAutologin = document.querySelector('[data-prop="cf.autologin"]');
let elCredentialsMode = document.querySelector('[data-prop="cf.credentials.mode"]');
let elCredentialsEmail = document.querySelector('[data-prop="cf.credentials.email"]');
let elCredentialsPassword = document.querySelector('[data-prop="cf.credentials.password"]');
let elDevlogEnabled = document.querySelector('[data-prop="devlog.enabled"]');
let elDevlogMaxLines = document.querySelector('[data-prop="devlog.maxLines"]');
let elJtfeyCredentialsMode = document.querySelector('[data-prop="jtfey.credentials.mode"]');
let elJtfeyCredentialsUsername = document.querySelector('[data-prop="jtfey.credentials.username"]');
let elJtfeyCredentialsPassword = document.querySelector('[data-prop="jtfey.credentials.password"]');
let elYCoinCredentialsMode = document.querySelector('[data-prop="ycoin.credentials.mode"]');
let elYCoinCredentialsUsername = document.querySelector('[data-prop="ycoin.credentials.username"]');
let elYCoinCredentialsPassword = document.querySelector('[data-prop="ycoin.credentials.password"]');
let elPostpone = document.querySelector('[data-prop="defaults.postponeMinutes"]');
let elPostponeMin = document.querySelector('[data-prop="defaults.postponeMinutes.min"]');
let elPostponeMax = document.querySelector('[data-prop="defaults.postponeMinutes.max"]');
elPostponeMin.disabled = (elPostpone.value > "0");
elPostponeMax.disabled = (elPostpone.value > "0");
if (elPostponeMin.disabled && elPostponeMax.disabled) {
elPostponeMin.value = elPostpone.value;
elPostponeMax.value = elPostpone.value;
}
elPostpone.onchange = function (e) {
document.querySelector('[data-prop="defaults.postponeMinutes.min"]').disabled = e.target.value > 0;
document.querySelector('[data-prop="defaults.postponeMinutes.max"]').disabled = e.target.value > 0;
if (e.target.value > 0) {
document.querySelector('[data-prop="defaults.postponeMinutes.min"]').value = e.target.value;
document.querySelector('[data-prop="defaults.postponeMinutes.max"]').value = e.target.value;
}
}
let elNextRun = document.querySelector('[data-prop="defaults.nextRun"]');
let elNextRunMin = document.querySelector('[data-prop="defaults.nextRun.min"]');
let elNextRunMax = document.querySelector('[data-prop="defaults.nextRun.max"]');
let elNextRunUseCountdown = document.querySelector('[data-prop="defaults.nextRun.useCountdown"]');
elNextRunMin.disabled = (elNextRun.value > "0");
elNextRunMax.disabled = (elNextRun.value > "0");
if (elNextRunMin.disabled && elNextRunMax.disabled) {
elNextRunMin.value = elNextRun.value;
elNextRunMax.value = elNextRun.value;
}
elNextRun.onchange = function (e) {
document.querySelector('[data-prop="defaults.nextRun.min"]').disabled = e.target.value > 0;
document.querySelector('[data-prop="defaults.nextRun.max"]').disabled = e.target.value > 0;
if (e.target.value > 0) {
document.querySelector('[data-prop="defaults.nextRun.min"]').value = e.target.value;
document.querySelector('[data-prop="defaults.nextRun.max"]').value = e.target.value;
}
}
let elSleepMode = document.querySelector('[data-prop="defaults.sleepMode"]');
let elSleepModeMin = document.querySelector('[data-prop="defaults.sleepMode.min"]');
let elSleepModeMax = document.querySelector('[data-prop="defaults.sleepMode.max"]');
elSleepModeMin.disabled = !elSleepMode.checked;
elSleepModeMax.disabled = !elSleepMode.checked;
elSleepMode.onchange = function (e) {
document.querySelector('[data-prop="defaults.sleepMode.min"]').disabled = !e.target.checked;
document.querySelector('[data-prop="defaults.sleepMode.max"]').disabled = !e.target.checked;
}
elCredentialsMode.disabled = !elCredentialsAutologin.checked;
elCredentialsEmail.disabled = ( (!elCredentialsAutologin.checked || elCredentialsMode.value == "2") ? true : false);
elCredentialsPassword.disabled = ( (!elCredentialsAutologin.checked || elCredentialsMode.value == "2") ? true : false);
elCredentialsAutologin.onchange = function (e) {
document.querySelector('[data-prop="cf.credentials.mode"]').disabled = !e.target.checked;
if (elCredentialsMode.value == "2") {
document.querySelector('[data-prop="cf.credentials.email"]').disabled = true;
document.querySelector('[data-prop="cf.credentials.password"]').disabled = true;
} else {
document.querySelector('[data-prop="cf.credentials.email"]').disabled = false;
document.querySelector('[data-prop="cf.credentials.password"]').disabled = false;
}
}
elCredentialsMode.onchange = function (e) {
if (e.target.value == "2") {
document.querySelector('[data-prop="cf.credentials.email"]').disabled = true;
document.querySelector('[data-prop="cf.credentials.password"]').disabled = true;
} else {
document.querySelector('[data-prop="cf.credentials.email"]').disabled = false;
document.querySelector('[data-prop="cf.credentials.password"]').disabled = false;
}
}
elYCoinCredentialsUsername.disabled = ( (elYCoinCredentialsMode.value == "2") ? true : false);
elYCoinCredentialsPassword.disabled = ( (elYCoinCredentialsMode.value == "2") ? true : false);
elYCoinCredentialsMode.onchange = function (e) {
if (e.target.value == "2") {
document.querySelector('[data-prop="ycoin.credentials.username"]').disabled = true;
document.querySelector('[data-prop="ycoin.credentials.password"]').disabled = true;
} else {
document.querySelector('[data-prop="ycoin.credentials.username"]').disabled = false;
document.querySelector('[data-prop="ycoin.credentials.password"]').disabled = false;
}
}
elJtfeyCredentialsUsername.disabled = ( (elJtfeyCredentialsMode.value == "2") ? true : false);
elJtfeyCredentialsPassword.disabled = ( (elJtfeyCredentialsMode.value == "2") ? true : false);
elJtfeyCredentialsMode.onchange = function (e) {
if (e.target.value == "2") {
document.querySelector('[data-prop="jtfey.credentials.username"]').disabled = true;
document.querySelector('[data-prop="jtfey.credentials.password"]').disabled = true;
} else {
document.querySelector('[data-prop="jtfey.credentials.username"]').disabled = false;
document.querySelector('[data-prop="jtfey.credentials.password"]').disabled = false;
}
}
elDevlogMaxLines.disabled = !elDevlogEnabled.checked;
elDevlogEnabled.onchange = function (e) {
document.querySelector('[data-prop="devlog.maxLines"]').disabled = !e.target.checked;
}
}
}
class UiWalletRenderer extends UiBaseRenderer {
legacyRenderWalletTable(data) {
let tableBody = '';
for(let i=0, all = data.length; i < all; i++) {
tableBody += '<tr class="align-middle" data-id="'+ data[i].id + '">';
tableBody += '<td class="align-middle">' + data[i].name + '</td>';
tableBody += '<td class="align-middle em-input"><input type="text" class="w-100" onfocus="this.select();" data-field="address" data-original="' + data[i].address + '" value="' + data[i].address + '"></td>';
tableBody += '</tr>';
}
document.getElementById('wallet-table-body').innerHTML = tableBody;
}
}
class UiSchedulesRenderer extends UiBaseRenderer {
appendEventListeners() {
document.querySelector('#schedules-toggler').addEventListener('change', this.onScheduleToggled.bind(this));
}
onScheduleToggled(e) {
e.stopPropagation();
let actionElement = e.target.tagName !== 'LABEL' ? e.target.closest('label') : e.target;
let otherActiveLabels = [...actionElement.parentElement.querySelectorAll('label.active')].filter(l => l.dataset.schedule != actionElement.dataset.schedule);
if (otherActiveLabels.length > 0) {
otherActiveLabels.forEach(l => l.classList.remove('active'));
}
this.toggleSchedule(actionElement.dataset.schedule);
}
toggleSchedule(uuid) {
if (uuid) {
this.selectedSchedule = uuid;
} else {
if (!this.selectedSchedule) {
this.selectedSchedule = 'all';
}
}
[...document.querySelectorAll('#schedule-table-body tr')].forEach((row) => {
if (this.selectedSchedule == 'all') {
row.classList.remove('d-none');
} else if (row.getAttribute('data-schedule') == this.selectedSchedule) {
row.classList.remove('d-none');
} else {
row.classList.add('d-none');
}
});
if (this.selectedSchedule == 'all') {
[...document.querySelectorAll('#console-log tr')].forEach(x => {
x.classList.remove('d-none');
})
} else {
[...document.querySelectorAll('#console-log tr')].forEach(x => {
if (x.getAttribute('data-schedule') == 'false' || x.getAttribute('data-schedule') == this.selectedSchedule) {
x.classList.remove('d-none');
} else {
x.classList.add('d-none');
}
})
}
};
renderTBody() {
let rows = [];
Schedule.getAllForCrud().forEach(sch => {
rows.push(this.renderRow(sch));
});
return rows.join('');
}
renderRow(sch) {
let row =
`<tr data-uuid="${sch.uuid}"
data-order="${sch.order}"
data-added="${sch.added ? 'true' : 'false'}"
data-removed="false"
data-updated="false"
data-originals='${!sch.added ? JSON.stringify(sch) : ""}'>
<td class="row-handle"><i class="fas fa-grip-vertical"></i></td>
<td><div class="input-group input-group-sm color-picker colorpicker-element" style="max-width: 125px;">
<div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-square" style="color: #${sch.uuid}"></i></span></div>
<input type="text" name="uuid" class="form-control" data-original-title="" value="${sch.uuid}">
</div></td>
<td><input type="text" name="name" class="form-control form-control-sm" value="${sch.name}"></td>
<td>
<button type="button" title="Remove" class="btn btn-default btn-sm action-schedule-remove"><i class="fa fa-trash"></i></button>
</td>
</tr>`;
return row;
}
}
class UiSiteParameterRenderer extends UiBaseRenderer {
static handlers = new Map();
static registerHandler(name, handler) {
UiSiteParameterRenderer.handlers.set(name, handler);
}
static getHandler(name) {
const handlerClass = UiSiteParameterRenderer.handlers.get(name);
return handlerClass || false;
}
appendEventListeners() {
document.querySelector('#modal-site-parameters').addEventListener('click', this.onClickOnModalSiteParameter.bind(this));
}
onClickOnModalSiteParameter(e) {
const modal = document.querySelector('#modal-site-parameters');
let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
if (actionElement.classList.contains('modal-save')) {
e.preventDefault();
let form = modal.querySelector('.form-container form');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
let data = this.uiRenderer.parseContainer(form);
$(modal).modal('hide');
}
}
renderFields(values) {
let fieldsHtml = '';
values.forEach( field => {
field.text = field.text || field.name.charAt(0).toUpperCase() + field.name.slice(1).toLowerCase().replaceAll('_', ' ');
switch (field.type) {
case 'credentials_or_autofilled': // TODO: will need to condition username/email/password!
break;
case 'email':
fieldsHtml += uiRenderer.addInputEmailHtml(field);
break;
case 'password':
fieldsHtml += uiRenderer.addInputPasswordHtml(field);
break;
case 'checkbox':
field.value = (field.value === true || field.value === 'true' || field.value === 1 || field.value === "1") ? true : false;
fieldsHtml += uiRenderer.addSliderHtml(field);
break;
case 'numberInput':
fieldsHtml += uiRenderer.addInputNumberHtml(field);
break;
case 'textInput':
case 'username':
field.required = 'true';
default:
fieldsHtml += uiRenderer.addInputTextHtml(field);
break;
}
});
const modalSiteParameters = document.getElementById('modal-site-parameters');
modalSiteParameters.querySelector('.form-container form').innerHTML = fieldsHtml;
}
renderEditSiteParameters(args) { // { site_id: 'x' }
const site = Site.getById(args.site_id);
const siteParameters = site.getSiteParameters(); // async? for external site parameters that need to be loaded from other stg...
if (!siteParameters) {
console.warn(`Site ${site.id} ${site.name} does not require parameters setup.`);
return;
}
if (!siteParameters.handler) {
console.warn(`Handler name is missing`);
return;
}
const handlerClass = UiSiteParameterRenderer.getHandler(siteParameters.handler);
if (!handlerClass) {
console.warn(`Invalid handler class name: ${siteParameters.handler}`);
return;
}
const handler = new handlerClass(siteParameters.values);
handler.preRender();
let fields = [
{ name: 'AUTO_UPDATE_PROMO_CODES', type: 'checkbox', value: 'false' },
{ name: 'MAX_ROLLS_PER_VISIT', type: 'numberInput', value: 1, min: 0 },
{ name: 'AUTO_LOGIN', type: 'checkbox', value: 'true' },
{ name: 'EMAIL', type: 'email', value: '' },
{ name: 'PASSWORD', type: 'password', value: '' }
];
fields.forEach( (f, idx) => {
if (f.order == null || f.order == undefined) {
f.order = idx;
}
});
let values = persistence.load(`site_parameters_${args.site_id}`, true) || [];
for(const field of fields) {
let vIdx = values.findIndex(v => v.name == field.name);
if (vIdx > -1) {
field.value = values[vIdx].value;
}
}
values = fields;
this.renderFields(values);
handler.postRender();
return;
}
}
class UiRenderer {
constructor () {
this.sites = new UiSitesRenderer(this);
this.siteParameters = new UiSiteParameterRenderer(this);
this.promos = new UiPromosRenderer(this);
this.config = new UiConfigRenderer(this);
this.wallet = new UiWalletRenderer(this);
this.schedules = new UiSchedulesRenderer(this);
this.selectedSchedule = null;
}
initialize() {
this.appendCSS();
}
toast(msg, msgType = "info") {
toastr[msgType](msg);
}
openModal(id, values = null) {
const dlg = document.querySelector('#modal-dlg');
dlg.querySelectorAll(".modal-content").forEach(x => x.classList.add('d-none'));
switch (id) {
case 'modal-backup':
console.info('TODO: GM_listValues => loop keys => save json as blob');
break;
case 'modal-ereport':
case 'modal-config':
case 'modal-site':
document.getElementById("target-spinner").innerHTML = JSON.stringify({id: id, siteId: values});
document.getElementById("modal-spinner").classList.remove("d-none");
dlg.querySelector('div').classList.add('modal-lg');
break;
case 'modal-add-site':
this.sites.renderAddExternalSite();
document.getElementById(id).classList.remove("d-none");
dlg.querySelector('div').classList.remove('modal-lg');
break;
case 'modal-slAlert':
shortlinkAlert.load(id);
dlg.querySelector('div').classList.add('modal-lg');
break;
case 'modal-schedules':
document.getElementById(id).querySelector('table tbody').innerHTML = this.schedules.renderTBody();
this.appendColorPickers('.color-picker');
dlg.querySelector('div').classList.remove('modal-lg');
document.getElementById(id).classList.remove("d-none");
break;
case 'modal-assign-schedule':
this.sites.renderAssignScheduleToSite(values);
document.getElementById(id).classList.remove("d-none");
dlg.querySelector('div').classList.remove('modal-lg');
break;
case 'modal-site-parameters':
this.siteParameters.renderEditSiteParameters(values);
document.getElementById(id).classList.remove("d-none");
dlg.querySelector('div').classList.remove('modal-lg');
break;
default:
dlg.querySelector('div').classList.add('modal-lg');
document.getElementById(id).classList.remove("d-none");
break;
}
$(dlg).modal('show');
}
appendEventListeners() {
for (const renderer in this) {
if (this[renderer] && typeof this[renderer].appendEventListeners === 'function') {
this[renderer].appendEventListeners();
}
}
$('[data-toggle="tooltip"]').tooltip({
trigger: 'hover'
});
}
appendCSS() {
let css = document.createElement('style');
css.innerHTML = `
td.em-input {
padding-top: 0;
padding-bottom: 0;
}
pre {
height: 145px;
width:100%;
white-space: pre-wrap;
padding-left: 1em;
}
pre span {
display: block;
}
.row-schedule-handle {
}
.grabbable:not(.d-none):not(.in-use) {
cursor: move;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.grabbable:not(.d-none):not(.in-use):active {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
}
.row-handle {
cursor: grab;
}
.dropdown-item {
cursor: pointer;
}
#schedule-table th,td {
vertical-align: middle;
padding-top: .25rem!important;
padding-bottom: .25rem!important;
}
#schedule-table-body td.em-input input[readonly] {
background-color:transparent;
border: 0;
font-size: 1em;
}
td[data-field="displayName"] .input-group-prepend .input-group-text {
background-color: transparent;
border-color: transparent;
font-size: 1em;
}
.custom-switch input,label {
cursor: pointer;
}
`;
document.head.appendChild(css);
}
addLegacySliderHtml(propName, propValue, text) {
return `<label class="switch"><input type="checkbox" ${propName}="${propValue}" data-original="1"><span class="slider round"></span></label> ${text}`;
}
addSliderHtml(field) {
const rndStr = helpers.randomString(8);
return `<div class="form-group"><div class="custom-control custom-switch custom-switch-off-danger custom-switch-on-success">
<input type="checkbox" class="custom-control-input" name="${field.name}" id="${rndStr}" ${field.value ? 'checked' : ''}>
<label class="custom-control-label" for="${rndStr}">${field.text}</label>
</div></div>`;
}
addInputEmailHtml(field) {
const rndStr = helpers.randomString(8);
const pattern = "[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$";
return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
<div class="col-sm-8">
<input type="email" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" pattern="${pattern}" value="${field.value || ''}">
</div></div>`;
}
addInputPasswordHtml(field) {
const rndStr = helpers.randomString(8);
return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
<div class="col-sm-8">
<input type="password" min="${field.min !== undefined ? field.min : ''}" min="${field.max !== undefined ? field.max : ''}" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
</div></div>`;
}
addInputTextHtml(field) {
const rndStr = helpers.randomString(8);
return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
<div class="col-sm-8">
<input type="text" class="form-control" required="${field.required || 'false'}" id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
</div></div>`;
}
addInputNumberHtml(field) {
const rndStr = helpers.randomString(8);
return `<div class="form-group row"><label for="${rndStr}" class="col-sm-4 col-form-label">${field.text}</label>
<div class="col-sm-8">
<input type="number" step="${field.step || 1}" class="form-control" required id="${rndStr}" placeholder="${field.placeholder || ' '}" name="${field.name}" value="${field.value || ''}">
</div></div>`;
}
parseContainer(container) {
let obj = {};
Object.assign(obj, container.dataset);
let inputs = container.querySelectorAll('input, select');
inputs.forEach(function (input) {
if (input.type == 'checkbox') {
obj[input.name] = input.checked ? 'true' : 'false';
} else if (input.type == 'number') {
obj[input.name] = +input.value;
} else {
obj[input.name] = input.value;
}
});
for (const p in obj) { // type converter. TODO: add int, float, etc.
if (obj[p] === 'true') { obj[p] = true }
if (obj[p] === 'false') { obj[p] = false }
if (p == 'uuid') {
obj[p] = obj[p].toLowerCase().replace('#', '');
}
if (p == 'originals') {
try {
obj[p] = JSON.parse(obj[p]);
} catch (err) { delete obj[p]; }
}
}
return obj;
}
parseTable(table) {
let rows = table.querySelectorAll('tbody tr');
let data = [];
rows.forEach( (r, idx) => {
let obj = this.parseContainer(r);
obj.order = '' + idx; // fix order
if (!(obj.added && obj.removed)) { // skip if it was just added and removed
data.push(obj);
}
});
return data;
}
appendColorPickers(selector) {
$(selector).each(function () {
$(this).colorpicker();
$(this).on('colorpickerChange', function(event) {
$(event.target.querySelector('.fa-square')).css('color', event.color.toString());
});
});
}
}
class EventEmitter {
constructor() {
this.events = {};
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
emit(eventName, data) {
const eventCallbacks = this.events[eventName];
if (eventCallbacks) {
eventCallbacks.forEach(callback => {
callback(data);
});
}
}
}
class Timeout {
constructor() {
this.startedAt;
this.interval;
this.cb = (() => { shared.closeWithError(K.ErrorType.TIMEOUT, '') });
let paramTimeout = shared.getParam('timeout');
if (paramTimeout) {
this.wait = paramTimeout * 60;
} else {
this.wait = shared.getConfig()['defaults.timeout'] * 60
}
this.wait += 30; // add a threshold
this.restart();
}
get elapsed() {
return Date.now() - this.startedAt;
}
restart(addSeconds = false) {
if(this.interval) {
clearTimeout(this.interval);
}
this.startedAt = Date.now();
if(addSeconds) {
this.wait = this.wait + addSeconds;
}
this.interval = setTimeout( () => { this.cb() }, this.wait * 1000);
}
}
class Timer {
constructor(params) {
Object.assign(this, params);
if(!useTimer || (this.webType && !Timer.webTypes().includes(this.webType))) {
return;
}
this.delay = this.delaySeconds * 1000;
}
static webTypes() {
return [K.WebType.FREELITECOIN, K.WebType.FREEETHEREUMIO, K.WebType.BIGBTC, K.WebType.FCRYPTO, K.WebType.FPB] // , K.WebType.BSCADS]
};
startCheck(webType) {
this.webType = webType;
if(!useTimer || (helpers.hasValue(webType) && !Timer.webTypes().includes(webType))) {
return;
}
persistence.save(this.uuid + '_lastAccess', Date.now());
this.interval = setInterval(() => {
this.isAlive();
}, this.delay);
}
stopCheck() {
if(!useTimer) {
return;
}
clearInterval(this.interval);
}
tick() {
if(!useTimer) {
return;
}
persistence.save(this.uuid + '_lastAccess', Date.now());
}
isAlive() {
return;
}
}
const wait = ms => new Promise(resolve => setTimeout(resolve, ms || 3000));
class CrawlerWidget {
constructor(params) {
if (!params || (!params.selector && !params.fnSelector)) {
throw new Error('CrawlerWidget requires a selector or a function selector parameter');
}
this.context = this.context || document;
Object.assign(this, params);
}
get isUserFriendly() {
if (this.selector) {
this.element = this.context.isUserFriendly(this.selector);
return this.element;
} else {
this.element = this.fnSelector();
return this.element;
}
}
}
class ReadableWidget extends CrawlerWidget {
constructor(params) {
if (params && !params.parser) {
params.parser = Parsers.innerText; //default parser
}
super(params);
}
get value() {
if (this.isUserFriendly) {
return this.parser(this.element, this.options);
} else {
return '';
}
}
}
class TextboxWidget extends CrawlerWidget {
get value() {
if (!this.isUserFriendly) {
return '';
}
return this.element.value;
}
set value(newValue) {
if (!this.isUserFriendly) {
return '';
}
this.element.value = newValue;
return '';
}
}
class ButtonWidget extends CrawlerWidget {
click() {
if (this.isUserFriendly) {
this.element.click();
return Promise.resolve(true);
} else {
}
}
}
class SubmitWidget extends CrawlerWidget {
click() {
if (this.isUserFriendly) {
let frm = this.element;
while(frm.nodeName != 'FORM' && frm.nodeName != null) {
frm = frm.parentElement;
}
if (frm.nodeName == 'FORM') {
frm.submit();
} else {
return;
}
return Promise.resolve(true);
} else {
}
}
}
class CountdownWidget extends CrawlerWidget {
constructor(params) {
if (params && !params.parser) {
params.parser = Parsers.innerText; //default parser
}
super(params);
}
get timeLeft() {
if (this.isUserFriendly) {
return this.parser(this.element, this.options);
} else {
throw new Error(`CountdownWidget (selector: '${this.selector}') cannot be read`);
}
}
}
class Parsers {
static innerText(elm) { // '0.12341234' => '0.12341234'
try {
return elm.innerText;
} catch (err) { }
}
static trimNaNs(elm) { // 'You won 0.12341234 TRX' => '0.12341234'
try {
return elm.innerText.replace(/[^\d.-]/g, '');
} catch (err) { }
}
static splitAndIdxTrimNaNs(elm, options) { // '17.96 Coins (17.50 + 0.46)' => 17.96
try {
return elm.innerText.split(options.splitter)[options.idx].replace(/[^\d.-]/g, '');
} catch (err) { }
}
static innerTextIntToFloat(elm) { // 'You won 1234 satoshis' => 0.00001234
try {
let sats = elm.innerText.replace(/\D/g, '');
return sats / 100000000;
} catch (err) { }
}
static innerTextJoinedToInt(elm) { // '7|2|9|6' => 7296
try {
return parseInt([... elm].map( x => x.innerText).join(''));
} catch (err) { }
}
static stormGainCountdown(elm) { // '3:01:01' => 120000
try {
let timeLeft = elm.innerText.split(':');
if (timeLeft[0] == 'Synchronizing') {
}
if(timeLeft.length === 3) {
return parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
}
} catch (err) {
return null;
}
}
static kingBizCountdown(elm) { // '4|2' => 42
try {
let itms = elm.querySelectorAll('.flip-clock-active .up');
if (itms.length > 1 && itms[0].isVisible() && itms[1].isVisible()) {
return parseInt([itms[0].innerText, itms[1].innerText].join(''));
}
} catch (err) {
return null;
}
}
static freeGrcCountdown(elm) { // 'Wait for 53:31 before next roll' => 53
try {
let val = elm.innerText.split(':')[0];
val = val.replace(/[^\d.-]/g, '');
return parseInt(val);
} catch (err) {
return null;
}
}
static bestChangeCountdown(elm) { // '00:58:35' => 58
try {
if (elm.value) {
let timeLeft = elm.value.split(':');
if (timeLeft.length > 1) {
return parseInt(timeLeft[1]);
}
}
} catch (err) {
return null;
}
}
static freeEthereumIoClaimed(elm) { // 'You won 0.12341234 TRX and rolled number 7623' => 0.12341234
try {
let line = elm.innerHTML;
let idx = line.search(/0\./);
return parseFloat(line.slice(idx, idx + 10));
} catch (err) { }
}
static bfBoxClaimed(elm) {
try {
let currency = elm.querySelector('.free-box__withdraw-currency').innerText;
let val = elm.querySelector('.free-box__need-sum').innerText.replace(/ /g,'').split('/')[1];
if (currency == 'Satoshi') {
val = val/100000000;
}
return val;
} catch (err) {
return null;
}
}
static g8ClaimsLeft(elm) {
try {
if (elm.innerText.includes('\nYou have ')) { // 'Claim 183848 satoshi (0.00012 USD) every 20 Seconds\nYou have 70 claims left today.'
let val = elm.innerText.split('\nYou have ')[1].split(' ')[0];
return val;
} else {
return null;
}
} catch (err) {
return null;
}
}
static cbgClaimed(elm) {
try {
if (elm.innerText.includes('was sent to')) { //?? was sent to you on...
let val = elm.innerText.trim().split(' ')[0];
if (elm.innerText.includes('oshi') || elm.innerText.includes('gwei')) {
val = val/100000000;
}
return val;
} else {
return null;
}
} catch (err) {
return null;
}
}
static dutchysClaimed(elm) { // 'You Won :101 DUTCHY + 20 XP' => 101
try {
let splitted = elm.innerText.split('DUTCHY');
return splitted[0].replace(/[^\d.-]/g, '');
} catch (err) { shared.devlog(`@Parsers.dutchysClaimed, with element [${elm}] Error: ${err}`); }
}
static dutchysClaimedToFloat(elm) { // 'You Won :22437 ADA + 100 XP' => 0.00022437
try {
let sats = elm.innerText.split('+');
sats = sats[0].replace(/\D/g, '');
return sats / 100000000;
} catch (err) { shared.devlog(`@Parsers.dutchysClaimedToFloat, with element [${elm}] Error: ${err}`); }
}
static splitAndIdxToInt(elm, options) { // options: { splitter: ':', idx: 1} // '26 Minutes 23' w/spliiter='Minutes' => 26
try {
return parseInt(elm.innerText.split(options.splitter)[options.idx].trim());
} catch (err) { shared.devlog(`Error @Parsers.splitAndIdxToInt: ${err}`); }
}
static fromTextTimer(elm) { // '0 hours 11 minutes 1 seconds' => 12 minutes
try {
let hours, minutes;
hours = +elm.innerText.split(' hours')[0].trim();
minutes = +elm.innerText.split('hours ')[1].split('minutes')[0].trim();
return hours * 60 + minutes + 1;
} catch (err) { shared.devlog(`Error @Parsers.splitAndIdxToInt: ${err}`); }
}
}
class ImageProcessor {
constructor(img) {
this._img = img;
}
isImageComplete() {
return this._img && this._img.complete;
}
createDrawer(width, height) {
let canvas = document.createElement('canvas');
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
let ctx = canvas.getContext('2d');
return {
canvas: canvas,
ctx: ctx
};
}
getDrawer() {
return this._drawer;
}
toCanvas() {
this._drawer = this.createDrawer(this._img.width, this._img.height);
this._drawer.ctx.drawImage(this._img, 0, 0);
}
foreach(filter) {
let imgData = this._drawer.ctx.getImageData(0, 0, this._drawer.canvas.width, this._drawer.canvas.height);
for (var x = 0; x < imgData.width; x++) {
for (var y = 0; y < imgData.height; y++) {
var i = x * 4 + y * 4 * imgData.width;
var pixel = { r: imgData.data[i + 0], g: imgData.data[i + 1], b: imgData.data[i + 2] };
pixel = filter(pixel);
imgData.data[i + 0] = pixel.r;
imgData.data[i + 1] = pixel.g;
imgData.data[i + 2] = pixel.b;
imgData.data[i + 3] = 255;
}
}
this._drawer.ctx.putImageData(imgData, 0, 0);
}
binarize (threshold) {
var image = this._drawer.canvas.getContext('2d').getImageData(0, 0, this._drawer.canvas.width, this._drawer.canvas.height);
for (var x = 0; x < image.width; x++) {
for (var y = 0; y < image.height; y++) {
var i = x * 4 + y * 4 * image.width;
var brightness = 0.34 * image.data[i] + 0.5 * image.data[i + 1] + 0.16 * image.data[i + 2];
image.data[i] = brightness >= threshold ? 255 : 0;
image.data[i + 1] = brightness >= threshold ? 255 : 0;
image.data[i + 2] = brightness >= threshold ? 255 : 0;
image.data[i + 3] = 255;
}
}
this._drawer.canvas.getContext('2d').putImageData(image, 0, 0);
}
invert(filter) {
this.foreach(function (p) {
p.r = 255 - p.r;
p.g = 255 - p.g;
p.b = 255 - p.b;
return p;
});
}
imgDataToBool(imgData) {
let character = [];
const data = imgData.data;
for (let i = 0; i < imgData.data.length; i += 4) {
let val = data[i] + data[i+1] + data[i+2];
character.push(val == 0 ? true : false);
}
return character;
}
}
class CaptchaWidget extends CrawlerWidget {
constructor(params) {
super(params);
}
solve() { return true; }
async isSolved() { return false; }
}
class RecaptchaWidget extends CaptchaWidget {
constructor(params) {
let defaultParams = {
selector: function() { return grecaptcha },
waitMs: [1000, 5000],
timeoutMs: 4 * 60 * 1000
};
for (let p in params) {
defaultParams[p] = params[p];
}
super(defaultParams);
}
get isUserFriendly() {
this.element = grecaptcha;
return this.element;
}
async isSolved() {
return wait().then( () => {
try {
if (this.isUserFriendly && this.element.hasOwnProperty('getPageId') && this.element.getPageId() && this.element.hasOwnProperty('getResponse') && (typeof(this.element.getResponse) == 'function')
&& this.element.getResponse().length > 0) {
return Promise.resolve(true);
}
} catch (err) {}
return this.isSolved();
});
}
}
class HCaptchaWidget extends CaptchaWidget {
constructor(params) {
let defaultParams = {
selector: '.h-captcha > iframe',
waitMs: [1000, 5000],
timeoutMs: 4 * 60 * 1000
};
for (let p in params) {
defaultParams[p] = params[p];
}
super(defaultParams);
}
async isSolved() {
return wait().then( () => {
if (this.isUserFriendly && this.element.hasAttribute('data-hcaptcha-response') && this.element.getAttribute('data-hcaptcha-response').length > 0) {
return Promise.resolve(true);
}
return this.isSolved();
});
}
}
class BKCaptchaWidget extends CaptchaWidget {
constructor() {
let defaultParams = {
selector: 'img[src="antibot.php"]',
waitMs: [1000, 5000],
timeoutMs: 4 * 60 * 1000
};
super(defaultParams);
this._imgProcessor;
this._characters = [];
}
charList() {
return [{"answer":"g","width":8,"height":9,"bools":[false,true,true,true,true,true,false,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"5","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"W","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true]},
{"answer":"O","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"N","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,false,true,true,true,true,true,true,false,false,true,true,true,true,true,true,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,true,true,true,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,true,true,true,false,false,false,false,true,true]},
{"answer":"T","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
{"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
{"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
{"answer":"B","width":8,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false]},
{"answer":"3","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false]},
{"answer":"s","width":8,"height":7,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"L","width":7,"height":10,"bools":[true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
{"answer":"Z","width":7,"height":10,"bools":[false,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
{"answer":"F","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"T","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
{"answer":"8","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"P","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"J","width":6,"height":10,"bools":[false,false,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,true,false,false,false,true,true,true,true,false,true,true,false,false,true,true,true,false,false]},
{"answer":"y","width":8,"height":9,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,true,false,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"r","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"R","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,true,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"M","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"d","width":8,"height":10,"bools":[false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
{"answer":"E","width":7,"height":10,"bools":[true,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
{"answer":"7","width":8,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"Z","width":7,"height":10,"bools":[true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true]},
{"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
{"answer":"K","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true]},
{"answer":"6","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,false,false,false,false,true,true,true,true,false,false]},
{"answer":"H","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"5","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"Y","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
{"answer":"d","width":8,"height":10,"bools":[false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
{"answer":"p","width":8,"height":9,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false]},
{"answer":"z","width":6,"height":7,"bools":[true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true]},
{"answer":"n","width":8,"height":7,"bools":[true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
{"answer":"8","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"t","width":8,"height":9,"bools":[false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false]},
{"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
{"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
{"answer":"Z","width":7,"height":10,"bools":[true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,true,true]},
{"answer":"1","width":6,"height":10,"bools":[false,false,true,true,false,false,false,true,true,true,false,false,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
{"answer":"m","width":8,"height":7,"bools":[true,false,true,true,false,true,true,false,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true]},
{"answer":"l","width":4,"height":10,"bools":[true,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,true,true,true,true]},
{"answer":"q","width":8,"height":9,"bools":[false,false,true,true,true,false,true,true,false,true,true,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true]},
{"answer":"C","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"a","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,true,false,true,true,true,true,false,true,true]},
{"answer":"2","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true]},
{"answer":"h","width":8,"height":10,"bools":[true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"F","width":7,"height":10,"bools":[true,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false]},
{"answer":"c","width":8,"height":7,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"P","width":8,"height":10,"bools":[true,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,false,false,false,false,false,false,false]},
{"answer":"r","width":8,"height":7,"bools":[true,true,false,true,true,true,false,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false]},
{"answer":"Y","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false]},
{"answer":"S","width":8,"height":10,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"u","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,true,false,false,true,true,true,false,true,true]},
{"answer":"M","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"S","width":8,"height":10,"bools":[false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"g","width":8,"height":9,"bools":[false,true,true,true,true,true,false,true,true,true,false,false,false,true,true,true,true,true,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false,false,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,false,true,true,false,false,false,false,true,true,false,true,true,true,true,true,true,false]},
{"answer":"U","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"k","width":7,"height":10,"bools":[true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,true,true,false,true,true,false,true,true,false,false,true,true,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true]},
{"answer":"4","width":8,"height":10,"bools":[false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,false,false,true,true,false,false,true,true,false,true,true,false,false,false,true,true,false,true,true,true,true,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false]},
{"answer":"A","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"b","width":8,"height":10,"bools":[true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,true,true,true,false,false,true,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,true,false,false,true,true,false,true,true,false,true,true,true,false,false]},
{"answer":"I","width":6,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
{"answer":"o","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false]},
{"answer":"i","width":6,"height":10,"bools":[false,false,true,true,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,true,true,true,true,true,true]},
{"answer":"C","width":8,"height":10,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"w","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,false,true,true,false,true,true,true,true,true,true,true,true,true,true,false,true,true,false,false,true,true,false]},
{"answer":"f","width":8,"height":10,"bools":[false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false]},
{"answer":"j","width":7,"height":12,"bools":[false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,false]},
{"answer":"F","width":6,"height":10,"bools":[true,true,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false,true,true,false,false,false,false]},
{"answer":"x","width":8,"height":7,"bools":[true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true]},
{"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"G","width":8,"height":10,"bools":[false,false,true,true,true,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,true,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"0","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false]},
{"answer":"0","width":8,"height":10,"bools":[false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false]},
{"answer":"D","width":8,"height":10,"bools":[true,true,true,true,true,true,false,false,true,true,false,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,true,true,false,true,true,true,true,true,true,false,false]},
{"answer":"e","width":8,"height":7,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,true,false,false,false,false,false,false,false,true,true,false,false,false,true,true,false,false,true,true,true,true,true,false]},
{"answer":"X","width":8,"height":10,"bools":[true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,false,false,false,false,true,true,false,false,false,false,false,false,true,true,false,false,false,false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true]},
{"answer":"Q","width":8,"height":10,"bools":[false,false,true,true,true,true,false,false,false,true,true,false,false,true,true,false,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,true,true,true,true,false,false,true,true,true,true,false,true,true,false,false,true,true,false,false,false,true,true,true,true,false,true]}];
}
async isReady() {
return wait().then( () => {
let img = document.querySelector(this.selector);
if(img && img.complete) {
this._imgProcessor = new ImageProcessor(img);
return Promise.resolve(true);
}
return this.isReady();
});
}
async isSolved() {
return this.isReady()
.then( () => this.solve())
.then( (solution) => {
document.querySelector('input[name="kodecaptcha"]').value = solution;
return Promise.resolve(true);
})
.catch(err => {
return Promise.reject(`Error ${err}`);
});
}
preProcessImage() {
this._imgProcessor.toCanvas();
this._imgProcessor.binarize(200);
this._imgProcessor.invert();
}
cropCharacter(startFrom = 0) {
let imgData = this._imgProcessor.getDrawer().ctx.getImageData(startFrom, 0, this._imgProcessor.getDrawer().canvas.width - startFrom, this._imgProcessor.getDrawer().canvas.height);
let newBounds = { left: null, right:null, top: null, bottom: null };
let readingCharacter = false;
let endOfCharacter = null;
for (var x = 0; x < imgData.width; x++) {
if (endOfCharacter) {
newBounds.right = endOfCharacter;
break;
}
let isColumnEmpty = true;
for (var y = 0; y < imgData.height; y++) {
var i = x * 4 + y * 4 * imgData.width;
var pixel = { r: imgData.data[i + 0], g: imgData.data[i + 1], b: imgData.data[i + 2] };
if (pixel.r + pixel.g + pixel.b == 0) {
if (newBounds.left == null || newBounds.left > x) {
newBounds.left = x;
}
if (newBounds.right == null || newBounds.right < x) {
newBounds.right = x;
}
if (newBounds.top == null || newBounds.top > y) {
newBounds.top = y;
}
if (newBounds.bottom == null || newBounds.bottom < y) {
newBounds.bottom = y;
}
readingCharacter = true;
isColumnEmpty = false;
}
}
if (isColumnEmpty && readingCharacter) {
endOfCharacter = x - 1;
break;
}
}
return {
x: startFrom + newBounds.left,
y: newBounds.top,
width: newBounds.right - newBounds.left + 1,
height: newBounds.bottom - newBounds.top + 1,
nextBegins: startFrom + newBounds.right + 1
};
}
splitInCharacters() {
let chars = [];
let i =0;
do {
chars.push(this.cropCharacter( i== 0 ? 0 : chars[i-1].nextBegins ) );
let copy = document.createElement('canvas').getContext('2d');
copy.canvas.width = chars[i].width;
copy.canvas.height = chars[i].height;
let trimmedData = this._imgProcessor.getDrawer().ctx.getImageData(chars[i].x, chars[i].y, chars[i].width, chars[i].height);
copy.putImageData(trimmedData, 0, 0);
chars[i].bools = this._imgProcessor.imgDataToBool(trimmedData);
chars[i].dataUrl = copy.canvas.toDataURL("image/png");
i++;
} while(i < 5);
this._characters = chars;
}
guess(charElm) {
let bestGuess = {
answer: '',
blacksMatched: 0,
blacksMissed: 0,
percentageBlacks: 0,
exactMatch: false
};
let totalPixels = charElm.width * charElm.height;
let totalBlacks = charElm.bools.filter(x => x === true).length;
this.charList().filter(x => x.answer != '').forEach( function (elm) {
if (bestGuess.exactMatch) {
return;
}
if (charElm.width == elm.width && charElm.height == elm.height) {
if (charElm.bools.join(',') == elm.bools.join(',')) {
bestGuess = {
answer: elm.answer,
percentageBlacks: 100,
exactMatch: true
};
return;
}
let blacksMatched = 0;
let blacksMissed = 0;
let percentageBlacks = 0;
for (let p = 0; p < totalPixels; p++) {
if (charElm.bools[p] === true || elm.bools[p] === true) {
if (elm.bools[p] == charElm.bools[p]) {
blacksMatched++;
} else {
blacksMissed++;
}
}
}
if (blacksMatched != 0 || blacksMissed != 0) {
percentageBlacks = blacksMatched/(blacksMatched + blacksMissed);
}
if (percentageBlacks > bestGuess.percentageBlacks) {
bestGuess = {
answer: elm.answer,
blacksMatched: blacksMatched,
blacksMissed: blacksMissed,
percentageBlacks: percentageBlacks
};
}
}
});
return bestGuess;
}
async solve() {
let solution = '';
if(this._imgProcessor.isImageComplete()) {
this.preProcessImage();
this.splitInCharacters();
this._characters.forEach( ch => {
let bestGuess = this.guess(ch);
solution += bestGuess.answer;
});
}
return Promise.resolve(solution);
}
}
class NoCaptchaWidget extends CaptchaWidget {
constructor(params) {
let defaultParams = {
selector: 'svg.feather-check-circle',
waitMs: 10000
};
for (let p in params) {
defaultParams[p] = params[p];
}
super(defaultParams);
}
async isSolved() {
return wait().then( () => {
if (this.isUserFriendly) {
return Promise.resolve(true);
}
return this.isSolved();
});
}
}
class GeeTestCaptchaWidget extends CaptchaWidget {
constructor(params) {
let defaultParams = {
selector: '.geetest_captcha.geetest_lock_success,.geetest_ghost_success.geetest_success_animate',
waitMs: 2000
};
for (let p in params) {
defaultParams[p] = params[p];
}
super(defaultParams);
}
async isSolved() {
return wait().then( () => {
if (this.isUserFriendly) {
return Promise.resolve(true);
}
return this.isSolved();
});
}
}
class CBL01CaptchaWidget extends CaptchaWidget {
constructor(params) {
let defaultParams = {
selector: '',
waitMs: 2000
};
for (let p in params) {
defaultParams[p] = params[p];
}
super(defaultParams);
}
async isReady() {
return wait(1).then( () => {
if(this.isUserFriendly) {
return Promise.resolve(true);
}
return wait().then( () => { this.isReady(); });
});
}
async solve() {
let answer = document.getElementById('captchainput').value;
if (answer != '') {
if (answer.startsWith('JJJ')) {
answer = answer.slice(3);
document.getElementById('captchainput').value = answer;
}
if (answer.length != 6) {
document.getElementById('captchainput').value ='';
window.location.reload();
return wait(10000).then( () => { this.solve(); });
} else {
return wait().then( () => { return true; } );
}
} else {
return wait().then( () => { this.solve(); });
}
}
async isSolved() {
return this.isReady()
.then( () => this.solve())
.then( (solution) => {
return Promise.resolve(true);
})
.catch(err => { shared.devlog(err); })
}
}
class D1CaptchaWidget extends CaptchaWidget {
constructor() {
let defaultParams = {
selector: '#submit_captcha span',
waitMs: [1000, 5000],
timeoutMs: 4 * 60 * 1000
};
super(defaultParams);
this.selectors = {
submitButton: '#submit',
answerSpan: '#submit_captcha span'
}
this._elements = {
submitButton: new ButtonWidget({selector: '#submit'}),
answerSpan: new ReadableWidget({selector: '#submit_captcha span'})
};
}
async isReady() {
return wait().then( () => {
if(this._elements.submitButton.isUserFriendly) {
return Promise.resolve(true);
}
return this.isReady();
});
}
async solve() {
if (this._elements.answerSpan.isUserFriendly) {
let answer = this._elements.answerSpan.value;
answer = answer ? answer.trim() : answer;
let input = document.querySelector(`input[value="${answer}"`);
if (input) {
helpers.alternativeClick(input.parentElement.querySelector('i'));
return wait().then( () => { return true; } );
} else {
return Promise.reject(`@D1Captcha input NOT FOUND for answer: ${answer}`);
}
} else {
return Promise.reject('Answer span not found!!!');
}
}
async isSolved() {
return this.isReady()
.then( () => this.solve())
.then( (solution) => {
return Promise.resolve(true);
})
.catch(err => { shared.devlog(err); })
}
}
class Faucet {
constructor(elements, actions = {}) {
this._url = window.location.href;
this._timeout = new Timeout(); // this.maxSeconds);
this._elements = elements;
this._actions = {
preRun: false,
preRoll: false,
altValidation: false,
readClaimed: true,
readBalance: true,
readTimeLeft: true,
readRolledNumber: false,
isMultiClaim: false,
checkIfOutOfFunds: false,
preSaveResult: false
}
this._actions = { ...this._actions, ...actions };
this._params = shared.getCurrent().params || {};
this._result = this._actions.isMultiClaim ? (shared.getProp('tempResults') || {}) : (shared.getResult() || {});
}
hasCloudflare() {
let h2 = document.querySelector('h2#challenge-running');
let stage = document.querySelector('#challenge-stage');
if (h2 || stage) {
return true;
}
return false;
}
useUrlListener() {
if (window.onurlchange === null) {
window.addEventListener('urlchange', (data) => {
if (this._url != window.location.href) {
this._url = window.location.href;
this.resetRun();
}
});
}
}
resetRun() {
wait().then( () => { this.init(); });
}
init() {
throw new Error('Init not implemented!');
}
login() {
throw new Error('Login not implemented!'); //return NEED_TO_LOGIN
}
async run(action = false) {
if (this._actions.checkIfOutOfFunds) {
this.checkIfOutOfFunds();
}
if (this._actions.preRun) {
await wait().then( () => { this.preRun() } );;
}
if (!action) {
this.detectAction().then( (resolve) => {
this.perform(resolve.action);
});
} else {
this.perform(action);
}
}
perform(action) {
switch(action) {
case 'doRoll':
if(this._actions.preRoll) {
this.preRoll();
}
this._elements.captcha.isSolved().then(() => { this.clickRoll() });
break;
case 'needToWait':
this.updateResult();
break;
default:
break;
}
}
async detectAction() {
return wait().then( () => {
if ( this.isCountdownVisible() ) {
return Promise.resolve({action: 'needToWait'});
} else if ( this.isRollButtonVisible() ) {
return Promise.resolve({action: 'doRoll'});
} else {
return this.detectAction();
}
});
}
preRoll() {
throw new Error('PreRoll not implemented!');
}
preRun() {
throw new Error('PreRun not implemented!');
}
altValidation() {
throw new Error('AltValidation not implemented!');
}
isCountdownVisible() {
return this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly;
}
isRollButtonVisible() {
return this._elements.rollButton && this._elements.rollButton.isUserFriendly;
}
clickRoll() {
try {
this._elements.rollButton.element.scrollIntoView(false);
this._elements.rollButton.click();
this.validateRun();
} catch (err) {
shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
}
}
failureValidation() {
throw new Error('FailureValidation not implemented!');
}
async validateRun() {
return wait(this._actions.useFailureValidation ? 6000 : null).then( () => {
if (this._actions.useFailureValidation) {
if (this.failureValidation()) {
return;
}
}
if (this._elements.success?.isUserFriendly) {
return this.updateResult();
} else if(this._actions.altValidation) {
if(this.altValidation()) {
return this.updateResult();
}
}
return wait(2000).then( () => { this.validateRun() });
});
}
async updateResult() {
if(this._actions.readClaimed) {
this._result.claimed = this.readClaimed();
}
if(this._actions.readBalance) {
this._result.balance = this.readBalance();
}
if(this._actions.readTimeLeft) {
this._result.nextRoll = this.readNextRoll();
}
if(this._actions.readRolledNumber) {
this._result.rolledNumber = this.readRolledNumber();
}
if (this._actions.isMultiClaim) {
shared.setProp('tempResults', this._result);
return this._actions.postRun ? this.postRun() : true;
}
if (this._actions.preSaveResult) {
this.preSaveResult();
}
if (this._actions.updateWithoutClosing) {
shared.updateWithoutClosing(this._result);
return this._actions.postRun ? this.postRun() : true;
} else {
shared.closeWindow(this._result);
}
}
readNextRoll() {
try {
if (this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly) {
return helpers.addMinutes(this._elements.countdownMinutes.timeLeft);
}
} catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
return null;
}
readRolledNumber() {
let rolled = 0;
try {
if(this._elements.rolledNumber.isUserFriendly) {
rolled = this._elements.rolledNumber.value;
}
} catch (err) { shared.devlog(`@readRolledNumber: ${err}`); }
return rolled;
}
readBalance() {
let balance = 0;
try {
if(this._elements.balance.isUserFriendly) {
balance = this._elements.balance.value;
}
} catch (err) { shared.devlog(`@readBalance: ${err}`); }
return balance;
}
readClaimed() { //TODO: review if previous claimed should be received as arg
let claimed = this._result.claimed ?? 0;
if (this._actions.isMultiClaim) {
this._oldClaimed = claimed;
} else {
}
try {
if(this._elements.claimed.isUserFriendly) {
claimed = +claimed + +this._elements.claimed.value;
} else {
}
} catch (err) { shared.devlog(`@readClaimed: ${err}`); }
return claimed;
}
checkIfOutOfFunds() {
let divAlerts = [...document.querySelectorAll(this._elements.outOfFundsDivSelector)];
divAlerts.forEach( function (d) {
if (d.innerText.toLowerCase().includes('not have sufficient funds')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, d.innerText);
return;
}
});
}
setCurrentCaptcha() {
if ([...document.querySelectorAll('iframe')].map(x => x.src || '').filter(x => x.includes('hcaptcha.com')).length > 0) {
return;
}
this._elements.captcha = new RecaptchaWidget();
}
}
class BFRoll extends Faucet {
constructor(coinPrefix, trySpin = false) {
let elements = {
preRunButton: new ButtonWidget({selector: '.free-box.free-box__' + coinPrefix + ' button'}), //'#' + coinPrefix + '_free_box_withdraw_page'}),
captcha: new NoCaptchaWidget({ selector: '.free-box-withdraw__footer button' }), // .button_red.button_center.button_fullwidth' }),
rollButton: new ButtonWidget({selector: '.free-box-withdraw__footer button' }), // .button_red.button_center.button_fullwidth'}),
success: new ReadableWidget({selector: '.modal:not(.free-box-withdraw,fury-wheel-modal), .vue-notification-template.my-notify.success'}),
claimed: new ReadableWidget({selector: '.free-box.free-box__' + coinPrefix, parser: Parsers.bfBoxClaimed}),
progressBar: new ReadableWidget({selector: '.free-box.free-box__' + coinPrefix + ' .free-box__progress-bar progress'}),
};
let actions = {
preRun: true,
readClaimed: true,
readBalance: false,
readRolledNumber: false
};
super(elements, actions);
this.coinPrefix = coinPrefix;
this.trySpin = trySpin;
}
init() {
if (this._url.includes('https://betfury.io/boxes/all')) {
this.run();
return;
} else {
return;
}
}
async spin() {
let clickables = document.querySelectorAll('.fury-wheel__wheel-btn, .fury-wheel__btn-wrap, .fury-wheel__btn-content, .fury-wheel__btn-img');
if (clickables.length > 0) {
clickables[Math.floor(Math.random()*clickables.length)].click();
wait(15000).then ( () => { shared.closeWindow(this._result); } );
}
return;
}
async preRun() {
return wait().then( () => {
try {
let popup = document.querySelector('.modal-wrapper .modal:not(.free-box-withdraw,fury-wheel-modal) .modal__btn-close');
if (popup) {
popup.click();
popup.click(); // twice
}
} catch (err) {}
if (this.trySpin) {
let spinUnavailable = document.querySelector('.bonus.bonus_furywheel.wait');
if (spinUnavailable) {
} else {
let spinBtn = document.querySelector('.wheel-amin'); //bonus bonus_furywheel wait
if (spinBtn) {
spinBtn.click();
wait(10000).then ( () => { this.spin() } );
return wait(60000).then ( () => { this.preRun(); } );
}
}
}
if (!this._elements.progressBar || !this._elements.progressBar.isUserFriendly) {
return this.preRun();
}
if (this._elements.preRunButton.isUserFriendly) {
if (!this._elements.preRunButton.isUserFriendly.disabled) {
return this._elements.preRunButton.click();
} else {
this._timeout.restart();
shared.closeWindow(this._result);
return;
}
} else if (document.querySelectorAll('.free-box').length > 1) {
shared.closeWithError(K.ErrorType.ERROR, 'Box might not exist for your account.');
return;
}
return this.preRun();
});
}
async validateRun() {
return wait(7000).then( () => {
let gtHook = document.querySelector('div.geetest_slice_bg');
if (gtHook) {
if (gtHook.isUserFriendly()) {
return this.validateRun();
}
}
let popup = document.querySelector('.modal-wrapper .modal:not(.free-box-withdraw,fury-wheel-modal) .modal__btn-close');
if (!popup) {
if (this._elements.preRunButton.isUserFriendly && !this._elements.preRunButton.isUserFriendly.disabled) {
this._elements.preRunButton.click();
return this.validateRun();
}
} else {
try {
if (popup) {
popup.click();
popup.click();
}
} catch (err) {}
}
if (this._elements.success.isUserFriendly) {
return this.updateResult();
} else if(this._actions.altValidation) {
if(this.altValidation()) {
return this.updateResult();
}
}
return this.validateRun();
});
}
}
class DutchyRoll extends Faucet {
constructor() {
let elements = {
countdownMinutes: new CountdownWidget({selector: '#timer', parser: Parsers.splitAndIdxToInt, options: { splitter: 'Minutes', idx: 0} }), // "26 Minutes 23"
captcha: new HCaptchaWidget(),
rollButton: new ButtonWidget({selector: '#claim'}), //w/booster video: '#unlockbutton' & then #claim_boosted
success: new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse'}),
claimed: new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.freeEthereumIoClaimed}) //"You Won 0.00409070 TRX + 20 XP"
};
let actions = {
preRun: true,
readClaimed: true,
readBalance: false,
readRolledNumber: false
};
super(elements, actions);
}
init() {
switch(window.location.host) {
case 'autofaucet.dutchycorp.space':
if (this._url.includes('/roll.php')) {
this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimed})
} else if (this._url.includes('/login.php')) {
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
return;
}
break;
case 'express.dutchycorp.space':
if (this._url.includes('/roll.php')) {
this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimed})
} else if (this._url.includes('/coin_roll.php')) {
this._elements.claimed = new ReadableWidget({selector: '.card.green.pulse p,.card.blue.pulse,.card.green.animated,.card.green.pulse', parser: Parsers.dutchysClaimedToFloat})
} else if (this._url.includes('/index.php')) {
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'You need to login using ExpressCrypto (EC-UserId-XXXXXX).');
return;
}
break;
}
this.run();
return;
}
async preRun() {
if (this._elements.captcha.isUserFriendly) {
if (shared.getConfig()['dutchy.useBoosted']) {
this._elements.rollButton = new ButtonWidget({selector: '#unlockbutton'});
this._elements.confirmBoost = new ButtonWidget({selector: '#claim_boosted'});
setInterval(() => {
try {
if (this._elements.confirmBoost.isUserFriendly) {
this._elements.confirmBoost.click();
}
} catch (err) {}
}, 8000);
}
return true;
} else {
this.setCurrentCaptcha();
await wait();
return this.preRun();
}
}
}
class YCoin extends Faucet {
constructor() {
let elements = {
rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Get Free Crypto!"]'}),
claimed: new ReadableWidget({selector: 'div.alert.alert-info', parser: Parsers.freeEthereumIoClaimed}),
captcha: new HCaptchaWidget(),
balance: new ReadableWidget({selector: 'a.wha[href="/account?page=history"]', parser: Parsers.trimNaNs}),
success: new ReadableWidget({selector: 'div.alert.alert-info'}),
login: {
inputUser: new TextboxWidget({ selector: 'input[name="number"]' }),
inputPass: new TextboxWidget({ selector: 'input[name="pass"]' }),
inputSubmit: new SubmitWidget({ selector: 'input[type="submit"][value="Login!"]' }),
setCredentials: false
},
};
if(shared.getConfig()['ycoin.credentials.mode'] == 1) {
elements.login.setCredentials = {
username: shared.getConfig()['ycoin.credentials.username'],
password: shared.getConfig()['ycoin.credentials.password']
};
}
let actions = {
preRun: true,
readClaimed: true,
readBalance: true,
readRolledNumber: false,
checkIfOutOfFunds: false
};
super(elements, actions);
}
async preRun() {
let msgDiv;
msgDiv = document.querySelector('p.info.success');
if (msgDiv && msgDiv.innerText.includes('has been transferred')) {
let result = {};
if (msgDiv.innerText.includes('0 claims')) {
result.nextRoll = helpers.addMinutes(60 * 24 + helpers.randomInt(10, 50));
} else {
result.nextRoll = helpers.addMinutes('60');
}
result.claimed = +msgDiv.innerText.split(' ')[0];
result.balance = this.readBalance();
shared.closeWindow(result);
return;
}
msgDiv = document.querySelector('p.info.warn');
if (msgDiv) {
if (msgDiv.innerText.includes('can claim only')) {
let result = {};
result.nextRoll = helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
shared.closeWindow(result);
return;
} else if (msgDiv.innerText.includes('Please wait')) {
let result = {};
try {
let unit = msgDiv.innerText.includes(' seconds') ? ' seconds' : ' minutes';
let val = msgDiv.innerText.split('Please wait ')[1].replace(/\D/g, '');
if (unit == ' seconds') {
result.nextRoll = helpers.addSeconds(val);
} else {
result.nextRoll = helpers.addMinutes(val);
}
} catch {
result.nextRoll = helpers.addMinutes(60);
}
shared.closeWindow(result);
return;
}
}
msgDiv = document.querySelector('p.info.fail');
if (msgDiv) {
if (msgDiv.innerText.toLowerCase().includes('run out of bitcoin')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
return;
}
}
if (this._elements.captcha.isUserFriendly) {
} else {
if (this._elements.rollButton) {
this._elements.rollButton.click();
return;
}
}
}
async init() {
if (this._url.includes('/faucet')) {
let needToLoginButton = document.querySelector('input[type="submit"][value="Login / Signup"]');
if (needToLoginButton) {
needToLoginButton.click();
return;
}
this.run();
this.solveColorCaptcha();
return;
} else if (this._url.includes('/account')) {
this.doLogin();
return;
}
}
async doLogin() {
return wait().then( () => {
let container = document.querySelector('#cc');
if (container.innerText.includes('You are now logged in as account')) {
let toFaucetButton = document.querySelector('#mmenu a[href="/faucet"]');
if (toFaucetButton) {
toFaucetButton.click();
return;
}
return this.doLogin();
}
if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
return this.doLogin();
}
let loginErrorDiv = document.querySelector('#cc .info.fail');
if (loginErrorDiv && loginErrorDiv.innerText.includes('Invalid')) {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
return;
}
if (this._elements.login.setCredentials != false) {
this._elements.login.inputUser.value = this._elements.login.setCredentials.username;
this._elements.login.inputPass.value = this._elements.login.setCredentials.password;
}
try {
this._elements.login.rememberMe.isUserFriendly.checked = true;
} catch (err) {}
if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
this._elements.login.inputSubmit.click();
} else {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
return;
}
});
}
async solveColorCaptcha() {
await wait(2000);
let optionInputs = [...document.querySelectorAll('#newch input[type="submit"]')];
let options = optionInputs.map(x => x.style.background);
let wantedColor = document.querySelector('#newch p b');
if (options.length > 0 && wantedColor) {
try {
let knownColors = Object.keys(nearestColor.STANDARD_COLORS);
let toColorName = nearestColor.from(nearestColor.STANDARD_COLORS);
options = options.map(x => toColorName(x).name);
wantedColor = wantedColor.innerText.toLowerCase();
if (wantedColor == 'grey') { wantedColor = 'gray'; }
let solutionIdx = options.findIndex(x => x.includes(wantedColor));
if (solutionIdx > -1) {
optionInputs[solutionIdx].click();
return;
}
if (wantedColor == 'green') {
wantedColor = 'lime';
solutionIdx = options.findIndex(x => x.includes(wantedColor));
if (solutionIdx > -1) {
optionInputs[solutionIdx].click();
return;
}
}
await wait(5000);
location.reload();
} catch (err) {
await wait(15000);
location.reload();
}
} else {
return this.solveColorCaptcha();
}
}
}
class CDiversity extends Faucet {
constructor() {
let elements = {
claimed: new ReadableWidget({selector: 'p.success', parser: Parsers.trimNaNs}),
captcha: new HCaptchaWidget(),
rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Get Free Crypto!"]'}),
};
let actions = {
readTimeLeft: true,
readRolledNumber: false,
readBalance: false
};
super(elements, actions);
}
init() {
if(this.hasErrorMessage()) {
shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
return;
}
let claimed = this.readClaimed();
if (claimed != 0) {
let result = {
claimed: claimed,
nextRoll: this.readNextRoll()
};
shared.closeWindow(result);
return;
}
let nextRoll = this.readNextRoll();
if(nextRoll) {
let result = {
nextRoll: nextRoll
};
shared.closeWindow(result);
return;
}
this.solve();
}
hasErrorMessage() {
return document.body.innerText.toLowerCase().includes('suspicious activity');
}
isFirstStep() {
return document.querySelector('form select[name="coin"]') ? true : false;
}
async doFirstStep() {
let form = document.querySelector('form');
if (!form) {
this.updateResult();
return;
}
let coinSelect = form.querySelector('select[name="coin"]');
if (!coinSelect) {
this.updateResult();
return;
}
let userInput = form.querySelector('input[name="ado"]');
if (!userInput) {
this.updateResult();
return;
}
let submitButton = form.querySelector('input[type="submit"]');
if (!submitButton) {
this.updateResult();
return;
}
coinSelect.value = this.getCoin();
userInput.value = this._params.address;
submitButton.parentElement.submit();
return;
}
getCoin() {
try {
let tds = document.querySelectorAll('table tr td:nth-child(2)');
return tds[helpers.randomInt(0, 5)].innerText.split(' ')[1]
} catch (err) {
return 'BTC';
}
}
isSecondStep() {
let ps = [...document.querySelectorAll('p')];
return ps.findIndex(x => x.innerText.toLowerCase().includes('one more step...')) >= 0;
}
async solve() {
if (this.isSecondStep()) {
return this.run();
}
if (this.isFirstStep()) {
return this.doFirstStep();
}
}
isCountdownVisible() {
let successDiv = document.querySelector('p.success');
if (!successDiv) {
return false;
}
if (successDiv.innerText.includes('0 claims')) {
return true;
}
return false;
}
readClaimed() {
let successDiv = document.querySelector('p.success');
if (successDiv) {
return successDiv.innerText.split(' ')[0];
} else {
return 0;
}
}
readNextRoll() {
try {
let successDiv = document.querySelector('p.success');
if (successDiv && successDiv.innerText.includes('You have')) {
let claimsLeft;
try {
claimsLeft = successDiv.innerText.split(' claims')[0].split('have ')[1];
} catch (err) {}
if (claimsLeft) {
return helpers.addMinutes(helpers.randomInt(6, 22));
} else if (claimsLeft === '0') {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
}
} catch (err) { }
try {
let warnDiv = document.querySelector('p.warn');
if (warnDiv) {
if (warnDiv.innerText.includes('You can claim only')) {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
if (warnDiv.innerText.includes('Please wait ')) {
try {
let unit = warnDiv.innerText.includes(' seconds') ? ' seconds' : ' minutes';
let val = warnDiv.innerText.split('Please wait ')[1].split(unit)[0].replace(/\D/g, '');
if (unit == ' seconds') {
return helpers.addSeconds(val);
} else {
return helpers.addMinutes(val);
}
} catch { }
let claimsLeft;
try {
claimsLeft = warnDiv.innerText.split(' seconds')[0].split('wait ')[1];
} catch (err) {}
if (claimsLeft) {
return helpers.addMinutes(helpers.randomInt(6, 22));
}
}
}
} catch (err) { }
return null;
}
}
class CTop extends Faucet {
constructor() {
let elements = {
claimed: new ReadableWidget({selector: 'p.success', parser: Parsers.trimNaNs}),
captcha: new HCaptchaWidget(),
rollButton: new ButtonWidget({selector: 'input[type="submit"]'}),
addressInput: new TextboxWidget({ selector: 'form input[name="adr"], form input[name="a"]'})
};
let actions = {
readTimeLeft: true,
readRolledNumber: false,
readBalance: false
};
super(elements, actions);
}
init() {
if(this.hasErrorMessage('suspicious activity')) {
shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
return;
}
if(this.hasErrorMessage('no funds left')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
return;
}
if(this.hasErrorMessage('faucet is currently disabled')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Faucet is disabled');
return;
}
let claimed = this.readClaimed();
if (claimed != 0) {
let result = {
claimed: claimed,
nextRoll: this.readNextRoll()
};
shared.closeWindow(result);
return;
}
let nextRoll = this.readNextRoll();
if(nextRoll) {
let result = {
nextRoll: nextRoll
};
shared.closeWindow(result);
return;
}
this.solve();
}
hasErrorMessage(searchTerm) {
return document.body.innerText.toLowerCase().includes(searchTerm);
}
isFirstStep() {
return this._elements.addressInput.isUserFriendly;
}
async doFirstStep() {
let form = document.querySelector('form');
if (!form) {
this.updateResult();
return;
}
if (!this._elements.addressInput.isUserFriendly) {
this.updateResult();
return;
}
let submitButton = form.querySelector('input[type="submit"]');
if (!submitButton) {
this.updateResult();
return;
}
this._elements.addressInput.value = this._params.address;
submitButton.closest('form').submit();
return;
}
isSecondStep() {
let ps = [...document.querySelectorAll('p')];
return ps.findIndex(x => x.innerText.toLowerCase().includes('one more step...')) >= 0;
}
async solve() {
if (this.isSecondStep()) {
return this.run();
}
if (this.isFirstStep()) {
return this.doFirstStep();
}
}
isCountdownVisible() {
let successDiv = document.querySelector('p.success');
if (!successDiv) {
return false;
}
if (successDiv.innerText.includes('0 claims')) {
return true;
}
return false;
}
readClaimed() {
let successDiv = document.querySelector('p.success');
if (successDiv) {
return successDiv.innerText.split(' ')[0];
} else {
return 0;
}
}
readNextRoll() {
try {
let successDiv = document.querySelector('p.success');
if (successDiv && successDiv.innerText.includes('You have')) {
let claimsLeft;
try {
claimsLeft = successDiv.innerText.split(' claims')[0].split('have ')[1];
} catch (err) {}
if (claimsLeft) {
return helpers.addMinutes(helpers.randomInt(12, 22));
} else if (claimsLeft === '0') {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
}
} catch (err) { }
try {
let warnDiv = document.querySelector('p.warn');
if (warnDiv) {
if (warnDiv.innerText.includes('You can claim only')) {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
if (warnDiv.innerText.includes('Please wait ')) {
try {
let unit = warnDiv.innerText.includes(' seconds') ? ' seconds ' : ' minutes ';
let val = warnDiv.innerText.split('Please wait ')[1].split(unit)[0].replace(/\D/g, '');
if (unit == ' seconds ') {
return helpers.addSeconds(val + helpers.randomInt(90, 180));
} else {
return helpers.addMinutes(val + helpers.randomInt(1, 5));
}
} catch { }
let claimsLeft;
try {
claimsLeft = warnDiv.innerText.split(' seconds')[0].split('wait ')[1];
} catch (err) {}
if (claimsLeft) {
return helpers.addMinutes(helpers.randomInt(12, 22));
}
}
}
} catch (err) { }
return null;
}
}
class FPB extends Faucet {
constructor(sitePrefix = null) {
let elements = {
rollButton: new ButtonWidget({selector: 'input[type="submit"][value="Claim From Faucet"],input[type="submit"][name="claim"]'}),
claimed: new ReadableWidget({selector: 'div.alert.alert-info', parser: Parsers.freeEthereumIoClaimed}),
captcha: new HCaptchaWidget(),
success: new ReadableWidget({selector: 'div.alert.alert-info'}),
login: {
inputUser: new TextboxWidget({ selector: 'input[name="user_name"]' }),
inputPass: new TextboxWidget({ selector: 'input[name="password"]' }),
rememberMe: new TextboxWidget({ selector: 'input[name="remember_me"]' }),
inputSubmit: new ButtonWidget({ selector: 'input[type="submit"][name="login"]' }),
setCredentials: false
},
outOfFundsDivSelector: '.alert.alert-info'
};
if(shared.getConfig()[sitePrefix + '.credentials.mode'] == 1) {
elements.login.setCredentials = {
username: shared.getConfig()[sitePrefix + '.credentials.username'],
password: shared.getConfig()[sitePrefix + '.credentials.password']
};
}
let actions = {
readClaimed: true,
readBalance: false,
readRolledNumber: false,
checkIfOutOfFunds: true
};
super(elements, actions);
}
init() {
if (this._url.includes('/dashboard')) {
this.run();
return;
} else if (this._url.includes('/login')) {
this.doLogin();
return;
}
}
async doLogin() {
return wait().then( () => {
if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
return this.doLogin();
}
let loginErrorDiv = document.querySelector('div.alert.alert-info');
if (loginErrorDiv && loginErrorDiv.innerText.includes('not valid')) {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
return;
}
if (this._elements.login.setCredentials != false) {
this._elements.login.inputUser.value = this._elements.login.setCredentials.username;
this._elements.login.inputPass.value = this._elements.login.setCredentials.password;
}
try {
this._elements.login.rememberMe.isUserFriendly.checked = true;
} catch (err) {}
if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
this._elements.captcha.isSolved().then(() => {
this._elements.login.inputSubmit.click();
return;
});
} else {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
return;
}
});
}
async detectAction() {
return wait().then( () => {
if ( this.isCountdownVisible() ) {
return Promise.resolve({action: 'needToWait'});
} else if ( this._elements.success.isUserFriendly ) {
return this.updateResult();
} else if ( this.isRollButtonVisible() ) {
return Promise.resolve({action: 'doRoll'});
} else {
return this.detectAction();
}
});
}
clickRoll() {
try {
try {
window.scrollTo(0, document.body.scrollHeight);
} catch (err) { }
this._elements.rollButton.click();
setTimeout( () => { this._elements.rollButton.click(); }, 5000);
} catch (err) {
shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
}
}
}
class VieRoll extends Faucet {
constructor() {
let elements = {
rollButton: new SubmitWidget({selector: '.main-content button[type="submit"]'}),
claimed: new ReadableWidget({selector: '.swal2-html-container', parser: Parsers.trimNaNs}),
captcha: new HCaptchaWidget(),
success: new ReadableWidget({selector: '.swal2-success-ring'}),
login: {
inputUser: new TextboxWidget({ selector: '#email' }),
inputPass: new TextboxWidget({ selector: '#password' }),
inputSubmit: new SubmitWidget({ selector: 'button[type="submit"]' })
}
};
let actions = {
readClaimed: true,
readBalance: false,
readTimeLeft: false,
readRolledNumber: false,
preSaveResult: false,
preRun: true
};
super(elements, actions);
}
getClaimsQty() {
let statWidgets = document.querySelectorAll('.card.mini-stats-wid');
if (statWidgets.length < 4) return false;
let claimCounts = statWidgets[3].querySelector('p');
if (!claimCounts) return false;
claimCounts = claimCounts.innerText.split('/');
if (claimCounts.length != 2) return false;
return claimCounts[0];
}
async evalClaimsQty() {
let current = this.getClaimsQty();
if (current) {
current = +current;
} else {
return;
}
let previous = await shared.getProp('tempClaimsQty') || 0;
if (!isNaN(previous)) previous = +previous;
if (current == previous) {
return;
} else if (current < previous) {
return this.updateResult();
} else {
await shared.setProp('tempClaimsQty', current);
}
}
readClaimed() {
let claimed = 0.12;
try {
claimed = +document.querySelectorAll('.card.mini-stats-wid')[2].querySelector('p').innerText.split(' ')[0];
} catch (err) { }
return claimed;
}
async init() {
await this.evalClaimsQty();
if (window.location.pathname.includes('/faucet')) {
this.run();
return;
} else if (window.location.pathname.includes('/firewall')) {
this.solveFirewall();
return;
} else if (window.location.pathname.includes('/dashboard')) {
window.location.href = (new URL('faucet', window.location)).href;
return;
} else if (window.location.pathname == '/') {
let loginBtn = document.querySelector('.btn.btn-success');
if (loginBtn) {
loginBtn.click();
return;
} else {
window.location.href = (new URL('login', window.location)).href;
}
return;
} else if (this._url.includes('/login')) {
let credentialsMode = this._params.credentials.mode;
switch(credentialsMode) {
case -1:
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'Manual login required.');
break;
case 0:
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, 'Login required and autologin is not configured.');
break;
default:
this.doLogin();
break;
}
return;
}
}
async preRun() {
return;
}
async solveFirewall() {
this.closeSwal();
this._elements.captcha.isSolved().then(() => {
let btn = new SubmitWidget({selector: 'form:not(.p-3) button[type="submit"]'});
btn.click();
});
}
async doLogin() {
return wait().then( () => {
if (!this._elements.login.inputUser.isUserFriendly || !this._elements.login.inputPass.isUserFriendly || !this._elements.login.inputSubmit.isUserFriendly) {
return this.doLogin();
}
let loginErrorDiv = document.querySelector('div.alert.alert-danger');
if (loginErrorDiv) {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, loginErrorDiv.innerText);
return;
}
if (this._params.credentials.mode == 1) {
this._elements.login.inputUser.value = this._params.credentials.username;
this._elements.login.inputPass.value = this._params.credentials.password;
}
if (this._elements.login.inputUser.value != '' && this._elements.login.inputPass.value != '' ) {
this._elements.captcha.isSolved().then(() => {
this._elements.login.inputSubmit.click();
return;
});
} else {
shared.closeWithError(K.ErrorType.LOGIN_ERROR, 'No credentials were provided');
return;
}
});
}
preSaveResult() {
this.closeSwal();
}
closeSwal() {
let okButton = document.querySelector('button.swal2-confirm');
if (okButton) {
okButton.click();
}
}
}
class GRCRoll extends Faucet {
constructor() {
let elements = {
countdownMinutes: new CountdownWidget({selector: '#roll_wait_text', parser: Parsers.freeGrcCountdown}),
rollButton: new ButtonWidget({selector: 'input[id="roll_button"]'}),
balance: new ReadableWidget({selector: '#balance', parser: Parsers.trimNaNs}),
claimed: new ReadableWidget({selector: '#roll_comment .won', parser: Parsers.trimNaNs}),
rolledNumber: new ReadableWidget({selector: '#roll_result', parser: Parsers.trimNaNs}),
captcha: new NoCaptchaWidget({selector: '#roll_button'}),
success: new ReadableWidget({selector: '#roll_result'})
};
let actions = {
readTimeLeft: true,
readRolledNumber: true
};
super(elements, actions);
}
init() {
if (this._url.includes('#free_roll')) {
if (document.querySelectorAll('a[href="#login"]').length > 0) {
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
return;
} else {
this.run();
return;
}
} else {
return;
}
}
isCountdownVisible() {
return this._elements.countdownMinutes && this._elements.countdownMinutes.isUserFriendly && this._elements.countdownMinutes.isUserFriendly.innerText != '';
}
}
class O24Roll extends Faucet {
constructor() {
let elements = {
claimed: new ReadableWidget({selector: '#roll_comment .won', parser: Parsers.trimNaNs})
};
let actions = {
readTimeLeft: true,
readRolledNumber: false,
readBalance: false
};
super(elements, actions);
this._isFMonster = location.host === 'faucet.monster';
}
init() {
if(this.hasErrorMessage('no funds left')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
return;
}
if (this.isCountdownVisible() || this.readClaimed() != 0) {
this.updateResult();
return;
}
this.solve();
}
hasErrorMessage(searchTerm) {
return document.body.innerText.toLowerCase().includes(searchTerm);
}
getSpotsAvailable() {
try {
let soldSpots = document.querySelectorAll('.pos:not(.pfree)').length;
let available = 1024-soldSpots;
return {
sold: '' + soldSpots,
available: '' + available
}
} catch (err) {
}
}
isPrime(num) {
for(var i = 2; i < num; i++){
if(num % i === 0){
return false;
}
}
return num > 1;
}
async solve() {
let spots;
spots = this.getSpotsAvailable();
if(!this._isFMonster && !spots) {
this.updateResult();
return;
}
const findNotPrime = document.querySelector('select[name="pr"]').parentElement.innerText.includes('not a prime')
let numbers = [...document.querySelectorAll('select[name="pr"] option[value]')].map(x => x.innerText)
let prime = null;
if (findNotPrime) {
prime = numbers.find(x => {
return !this.isPrime(x)
});
} else {
prime = numbers.find(x => {
return this.isPrime(x)
});
}
if(!prime) {
this.updateResult();
return;
}
let addrInput = document.querySelector('label input[name="a"]');
if (addrInput) {
addrInput.value = this._params.address;
} else {
this.updateResult();
return;
}
await wait(helpers.randomInt(1500, 3000));
if (this._isFMonster) {
let usdtQuestion = document.querySelector('form p:nth-child(2)');
if (!usdtQuestion || !usdtQuestion.innerText.toLowerCase().includes('faucet monitor lists tether faucets')) {
this.updateResult();
return;
}
let usdtAnswersList = [...document.querySelectorAll('select[name="fm"] option')];
if (usdtAnswersList.length == 0) {
this.updateResult();
return;
}
usdtAnswersList = usdtAnswersList.map(x => x.value);
let idxCorrect = usdtAnswersList.findIndex(x => x.toLowerCase() == 'yes' || x.toLowerCase() == 'y');
if (idxCorrect === -1) {
this.updateResult();
return;
}
document.querySelector('select[name="fm"]').value = usdtAnswersList[idxCorrect];
} else {
let answersList = [...document.querySelectorAll('select[name="tt"] option')].map(x => x.value);
if (answersList.includes(spots.sold)) {
document.querySelector('select[name="tt"]').value=spots.sold;
} else if (answersList.includes(spots.available)) {
document.querySelector('select[name="tt"]').value=spots.available;
} else {
this.updateResult();
return;
}
}
await wait(helpers.randomInt(400, 5000));
let primeSelect = document.querySelector('select[name="pr"]');
helpers.triggerMouseEvent (primeSelect, "mouseenter");
await wait(helpers.randomInt(5600, 29000));
helpers.triggerMouseEvent (primeSelect, "mouseout");
primeSelect.value=prime.toString()
await wait(helpers.randomInt(1500, 5000));
let claimForm = document.querySelector('form');
if(claimForm) {
claimForm.submit();
}
}
isCountdownVisible() {
let pars = [...document.querySelectorAll('p')];
if (pars.find(x => x.innerText.includes('wait until next day'))) {
return true;
}
if (pars.find(x => x.innerText.includes('PROBLEM'))) {
return true;
}
return false;
}
readClaimed() {
let pars = [...document.querySelectorAll('p')];
let claimedElm = pars.find(x => x.innerText.includes('been transferred to your account'));
if (claimedElm) {
return claimedElm.innerText.split(' ')[0];
} else {
return 0;
}
}
readNextRoll() {
try {
let pars = [...document.querySelectorAll('p')];
if (pars.find(x => x.innerText.includes('until next day') || x.innerText.includes('ALL DAILY CLAIMS') || x.innerText.includes('You have 0 claims left'))) {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
if (pars.find(x => x.innerText.includes('PROBLEM'))) {
return helpers.addMinutes(helpers.randomInt(6, 22));
}
if (pars.find(x => x.innerText.includes('You have'))) {
return helpers.addMinutes(helpers.randomInt(6, 22));
}
} catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
}
class FCryptoRoll extends Faucet {
constructor() {
let elements = {
countdownMinutes: new CountdownWidget({selector: '.sidebar-links .cursor-not-allowed span.notranslate', parser: Parsers.splitAndIdxToInt, options: { splitter: ':', idx: 1} }), // '00:21:28'
rollButton: new ButtonWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'}),
balance: new ReadableWidget({selector: 'div.flex.badge.text-bg-yellow', parser: Parsers.trimNaNs}), // '405.81 Coins'
claimed: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium', parser: Parsers.splitAndIdxTrimNaNs, options: { splitter: '(', idx: 0} }), // '25.05 Coins (12 + 13.05)'
captcha: new HCaptchaWidget({selector: '#hcap-script > iframe'}),
success: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium'})
};
let actions = {
isMultiClaim: true,
preRoll: true,
postRun: true,
readRolledNumber: false,
};
super(elements, actions);
this._paths = {
faucet: '/task/faucet-claim',
dashboard: '/dashboard'
};
this._linkSelectors = {
Faucet: 'a[href="https://faucetcrypto.com/task/faucet-claim"]'
}
this.useUrlListener();
}
init() {
this._elements.captcha = new HCaptchaWidget({selector: '#hcap-script > iframe'});
this._elements.rollButton = new ButtonWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'});
if (this._url.endsWith(this._paths.dashboard)) {
return this.runDashboard();
} else if (this._url.includes(this._paths.faucet)) {
return wait().then( () => { this.run(); });
}
return;
}
readSections() {
let sections = {};
try {
for (var l in this._linkSelectors) {
sections[l] = {};
sections[l].elm = document.querySelector(this._linkSelectors[l]);
if (sections[l].elm) {
let qty = sections[l].elm.querySelector('span.ml-auto');
sections[l].qty = (qty && !isNaN(qty.innerText)) ? qty.innerText : 0;
}
}
} catch {}
this.sections = sections;
}
runDashboard() {
this.readSections();
if (this.sections['Faucet'].elm) {
this.sections['Faucet'].elm.click();
return;
} else {
return wait().then( () => { this.run(); });
}
}
scrollTo() {
let mainContainer = document.querySelector('main');
if (mainContainer) {
mainContainer.scrollTo(0, mainContainer.scrollHeight - mainContainer.offsetHeight);
}
}
preRoll() { // search for 'You don't need to solve any captcha! The system is telling me that you are a good person :)'
this.scrollTo();
let checkCircleSpan = document.querySelector('p.font-medium.flex.justify-center.leading-0 span.text-green-500.mr-3 svg');
if(checkCircleSpan) {
if (checkCircleSpan.parentElement.parentElement.innerText.toLowerCase().includes('the system is telling me that you are a good person')) {
this._elements.captcha = new NoCaptchaWidget({selector: '.flex.justify-center button.inline-flex.items-center:not(.hidden)'});
return;
}
}
}
postRun() {
if (this._url.endsWith(this._paths.dashboard) || this._oldClaimed != this._result.claimed) {
try {
this._elements.claimed.isUserFriendly.parentElement.parentElement.parentElement.querySelector('button');
} catch (err) {
}
this._oldClaimed = null;
this.readSections();
if (this.sections != {}) {
if (this.sections['Faucet'].elm) {
this.sections['Faucet'].elm.click();
return;
} else {
}
} else {
}
} else {
}
this._result = shared.getProp('tempResults');
shared.closeWindow(this._result);
return;
}
async runPtcList() {
let listItems = [...document.querySelectorAll('.grid.grid-responsive-3 .feather.feather-eye')].map(x => x.parentElement.parentElement).filter(x => x.isUserFriendly());
if (listItems.length > 0) {
listItems[0].click();
return;
} else {
return wait().then( () => { this.runPtcList() } );
}
}
runPtcSingleStart() {
return this.run('doRoll');
}
runPtcSingleWait() {
this._elements.captcha = new NoCaptchaWidget({selector: 'a.notranslate:not(.cursor-not-allowed)' });
this._elements.rollButton = new ButtonWidget({selector: 'a.notranslate:not(.cursor-not-allowed)' });
return this.run('doRoll');
}
}
class FPPtc extends Faucet {
constructor() {
let elements = {
claimButton: new ButtonWidget({selector: '#pop-up button.purpleButton:not([disabled])'}),
claimButtonDisabled: new ButtonWidget({selector: '#pop-up button.purpleButton'}),
openPtcButton: new ButtonWidget({fnSelector: function() {
let blacklistTitles = ['JOIN US ON WINTOMATO.COM'];
let btn = [...document.querySelectorAll('button')].filter(x => x.innerText.toLowerCase().includes('view'));
try {
btn = btn.filter(x => !blacklistTitles.includes(x.parentElement.parentElement.querySelector('h2').innerText.toUpperCase()));
} catch (err) {}
return (btn.length > 0) ? btn[0] : null;
}}),
claimed: new ReadableWidget({fnSelector: function() {
let divSpanSuccessClaim = [...document.querySelectorAll('div span')].filter(x => x.innerText.toLowerCase().includes('successfully credited with'));
return (divSpanSuccessClaim.length > 0) ? divSpanSuccessClaim[0] : null;
}, parser: Parsers.trimNaNs}),
captcha: new GeeTestCaptchaWidget(),
success: new ReadableWidget({selector: 'div.ml-3.w-0 p span.text-yellow-500.font-medium'})
};
let actions = {
isMultiClaim: true,
preRoll: true,
postRun: true,
readRolledNumber: false,
};
super(elements, actions);
this._paths = {
ptcList: '/ptc',
ptcSingleView: '/ptc/view',
login: '/account/login',
dashboard: '/user-admin'
};
this.useUrlListener();
}
init() {
if (this._url.includes(this._paths.ptcSingleView)) {
this.doPtcList(true);
return;
} else if (this._url.includes(this._paths.ptcList)) {
this.doPtcList();
return;
} else if (this._url.includes(this._paths.login)) {
this.doLogin();
return;
} else if (this._url.includes(this._paths.dashboard)) {
return;
}
return;
}
hasExpired() {
return document.body.innerText.includes('The session has expired');
}
hasError() {
return document.body.innerText.includes('must finish watching') || document.title.includes('Tab Closed Error');
}
getETAWaitSeconds(btn) {
try {
let seconds = btn.nextSibling.firstChild.innerText.split('s')[0];
return +seconds;
} catch (err) {
}
return 15;
}
getPayout(btn) {
this.lastClaimed = 0;
try {
let payout = btn.nextSibling.lastChild.innerText.split(' ')[0];
this.lastClaimed = +payout;
} catch (err) {
}
}
async validateClaim() {
await wait(1000);
if (this.hasExpired()) {
console.info('CLAIM => expired');
await wait(2000);
return false;
}
if (this._elements.claimed.isUserFriendly) {
let claimed = this._elements.claimed.value;
if (claimed) {
console.info('CLAIM => Returning claimed:', claimed);
await this.storeClaim();
await wait(2000);
return claimed;
}
}
console.info('@validateClaim => Still waiting...');
return this.validateClaim();
}
async storeClaim() {
let result = shared.getResult();
result.ptcsDone = (result.ptcsDone ?? 0) + 1;
result.claimed = +(result.claimed ?? 0) + +this.lastClaimed;
this.lastClaimed = 0;
shared.updateWithoutClosing(result, 'WORKING');
}
async confirmClaim() {
GM_setValue(`ptc-close-signal-faucetpay.io`, Date.now());
await wait(5000);
GM_deleteValue(`ptc-close-signal-faucetpay.io`);
let captcha = new GeeTestCaptchaWidget();
await captcha.isSolved();
if (!this._elements.claimButton.isUserFriendly) {
return;
}
this._elements.claimButton.click();
let validation = await this.validateClaim();
return this.doPtcList();
}
async startPtc() {
await wait(1000);
let minSeconds = this.getETAWaitSeconds(this._elements.openPtcButton.isUserFriendly);
this.getPayout(this._elements.openPtcButton.isUserFriendly);
this._elements.openPtcButton.click();
await wait(4000);
return this.waitPtcSeconds();
}
async waitPtcSeconds() {
if (this._elements.claimButtonDisabled.isUserFriendly) {
return this.confirmClaim();
}
if (!document.title.includes('PTC Ads') && document.title.includes('s |')) {
await wait(5000);
return this.waitPtcSeconds();
}
let iframe = document.querySelector('iframe[title="ptc-view"]');
if (document.title.includes('PTC Ads') && iframe) {
await wait(5000);
return this.waitPtcSeconds();
}
return this.confirmClaim();
}
async doPtcList(isSingle = false) {
if (document.title.includes('PTC Ads') || document.title.includes('Complete Visit')) {
if (this._elements.claimButtonDisabled.isUserFriendly) {
return this.confirmClaim();
} else {
if(isSingle) {
await wait(4000);
return this.doPtcList(true);
}
if (this._elements.openPtcButton.isUserFriendly) {
return this.startPtc();
} else {
shared.closeWindow();
return;
}
}
}
}
async doLogin() {
let username = document.querySelector('input');
let password = document.querySelector('input[type="password"]');
let captcha = new GeeTestCaptchaWidget();
let btn = document.querySelector('button[type="submit"');
if (username && password && btn && username.value != '' && password.value != '') {
await captcha.isSolved();
btn.click();
return;
} else {
shared.closeWithError(K.ErrorType.NEED_TO_LOGIN, '');
}
}
}
function createFBProcessor() {
let countdownMinutes;
let timeout = new Timeout(); // this.maxSeconds);
let captcha = new HCaptchaWidget();
function run() {
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
};
function findCountdownOrRollButton() {
if ( isCountdownVisible() ) {
timeout.restart();
countdownMinutes = +document.querySelectorAll('.free_play_time_remaining.hasCountdown .countdown_amount')[0].innerHTML + 1;
let result = {};
result.balance = readBalance();
result.nextRoll = helpers.addMinutes(countdownMinutes.toString());
shared.closeWindow(result);
return;
}
if ( isRollButtonVisible() ) {
try {
let doBonus = false; // true;
if (doBonus) {
if (!document.getElementById('bonus_span_free_wof')) {
RedeemRPProduct('free_wof_5');
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
return;
}
}
} catch { }
/* For 'Play without captcha accounts' */
if (!captcha.isUserFriendly) {
clickRoll()
} else {
captcha.isSolved().then(() => { clickRoll(); });
}
} else {
setTimeout(findCountdownOrRollButton, helpers.randomMs(2000, 5000));
}
};
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.isVisible()) {
return true;
}
return false;
};
function isRollButtonVisible() {
return document.getElementById('free_play_form_button').isVisible();
};
function clickRoll() {
try {
document.getElementById('free_play_form_button').click();
setTimeout(processRunDetails, helpers.randomMs(3000, 10000));
} catch (err) {
shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
}
};
function processRunDetails() {
if (document.getElementById('winnings').isVisible()) {
closePopup();
let result = {};
result.claimed = readClaimed();
result.balance = readBalance();
if(result.claimed != 0) {
result.rolledNumber = readRolledNumber();
}
shared.closeWindow(result);
return;
}
if (document.querySelector('.free_play_result_error').isVisible()) {
shared.closeWithError(K.ErrorType.ROLL_ERROR, document.querySelector('.free_play_result_error').innerHTML);
return;
}
if(document.getElementById('free_play_error').isVisible()) {
shared.closeWithError(K.ErrorType.ROLL_ERROR, document.querySelector('.free_play_error').innerHTML);
return;
}
if (document.getElementById('same_ip_error').isVisible()) {
shared.closeWithError(K.ErrorType.ROLL_ERROR, document.getElementById('same_ip_error').innerHTML);
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;
};
return {
run: run
};
}
function createBigBtcProcessor() {
let timeout = new Timeout(); // this.maxSeconds);
let countdownMinutes;
let captcha = new HCaptchaWidget();
let selectElement = {
loadingDiv: function() {
let loading = document.querySelector('#loading');
if (loading && loading.isVisible()) {
return true;
} else {
return false;
}
},
addressInput: function() {
return document.querySelector('#login input[name="address"]');
},
loginButton: function() {
return document.querySelector('#login input[type="submit"]');
},
claimButton: function() {
return document.getElementById('claimbutn');
},
countdown: function() { // "You have to wait\n60 minutes"
let cd = document.getElementById('countdown');
if(cd && cd.isVisible()) {
return parseInt(cd.innerText);
}
return null;
},
claimedAmount: function() {
let elm = document.querySelector('.alert.alert-success.pulse'); //"Yuppie! You won 2 satoshi!"
if(elm && elm.isVisible()) {
let val = parseInt(elm.innerText.replace(/\D/g, ''));
if (Number.isInteger(val)) {
val = val / 100000000;
}
return val;
} else {
return null;
}
},
balance: function() {
let elm = document.querySelector('a b');
if (elm && elm.isVisible()) {
let val = parseInt(elm.innerText.replace(',', ''));
if (Number.isInteger(val)) {
val = val / 100000000;
}
return val;
} else {
return null;
}
},
error: function () {
return null;
}
};
function init() {
window.scrollTo(0, document.body.scrollHeight);
let m = document.getElementById('main'); if (m) { m.style.display='block'; }
m = document.getElementById('block-adb-enabled'); if (m) { m.style.display='none'; }
m = document.getElementById('ielement'); if (m) { m.style.display='block'; }
setInterval(() => {
let frames = [...document.querySelectorAll('iframe')];
frames.forEach(x => {
if (!x.src.includes('hcaptcha')) {
x.remove()
}
});
}, 5000);
if (window.location.href.includes('/faucet')) {
setTimeout(runFaucet, helpers.randomMs(12000, 14000));
return;
} else {
setTimeout(run, helpers.randomMs(3000, 5000));
return;
}
}
function run() {
try {
setTimeout(waitIfLoading, helpers.randomMs(12000, 15000));
} catch (err) {
shared.closeWithErrors(K.ErrorType.ERROR, err);
}
};
function doLogin() {
let address = selectElement.addressInput();
if(address && address.value != shared.getCurrent().params.address) {
address.value = shared.getCurrent().params.address;
} else {
selectElement.loginButton().click();
return;
}
setTimeout( doLogin , helpers.randomMs(1000, 2000));
};
function waitIfLoading() {
if ( !selectElement.loadingDiv() ) {
doLogin();
return;
} else {
}
setTimeout(waitIfLoading, helpers.randomMs(5000, 7000));
};
function runFaucet() {
let claimedAmount = selectElement.claimedAmount();
if(claimedAmount) {
processRunDetails();
return;
} else if (selectElement.countdown()) {
let result = {};
shared.closeWindow(result);
} else {
captcha.isSolved().then(() => { clickClaim(); });
}
}
function clickClaim() {
try {
selectElement.claimButton().click();
return;
} catch (err) {
shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
}
};
function processRunDetails() {
let claimedAmount = selectElement.claimedAmount();
let balance = selectElement.balance();
let countdown = selectElement.countdown();
if (claimedAmount && balance) {
let result = {};
result.claimed = claimedAmount;
result.balance = balance;
shared.closeWindow(result);
return;
}
setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
};
return {
init: init
};
}
function createBestChangeProcessor() {
let timeout = new Timeout(); // this.maxSeconds);
let countdownMinutes;
let captcha = new HCaptchaWidget({selector: '.hcaptcha > iframe'});
let elements = {
captcha: function() {
return document.querySelector('.hcaptcha > iframe');
},
container: function() {
return document.querySelector('#info_bonus');
},
containerOpener: function() {
return document.querySelector('#tab_bonus a');
},
addressInput: function() {
return document.querySelector('#bonus_purse');
},
claimButton: function() {
return document.querySelector('#bonus_button');
},
countdown: function() { // Time left: mm:ss
let elm = document.querySelector('#bonus_button');
try {
if (elm.value) {
let timeLeft = elm.value.split(':');
if (timeLeft.length > 1) {
return parseInt(timeLeft[1]);
}
}
} catch (err) {
return null;
}
},
claimedAmount: function() {
let elm = document.querySelector("#bonus_status b");
try {
let sats = elm.innerText.replace(/\D/g, '');
return sats / 100000000;
} catch (err) {
return null;
}
},
balance: function() {
let elm = document.querySelector("#faucet_unpaid_balance b");
try {
let sats = elm.innerText.replace(/\D/g, '');
return sats / 100000000;
} catch (err) {
return null;
}
}
};
function init() {
run();
}
function run() {
try {
if (!elements.container().isUserFriendly()) {
let co = elements.containerOpener();
if(co.isUserFriendly()) {
co.onclick = co.onmousedown;
co.click();
}
}
setTimeout(findCountdownOrRoll, helpers.randomMs(4000, 5000));
} catch (err) {
shared.closeWithErrors(K.ErrorType.ERROR, err);
}
};
function findCountdownOrRoll() {
let countdown = elements.countdown();
if(countdown) {
let result = { };
result.nextRoll = helpers.addMinutes(countdown.toString());
shared.closeWindow(result);
return;
}
let ai = elements.addressInput();
if (ai.isUserFriendly()) {
if (ai.value != shared.getCurrent().params.address) {
ai.value = shared.getCurrent().params.address;
}
captcha.isSolved().then(() => { clickClaim(); });
return;
}
setTimeout(findCountdownOrRoll, helpers.randomMs(10000, 12000));
};
function clickClaim() {
try {
let btn = elements.claimButton();
if(btn.isUserFriendly()) {
btn.click();
setTimeout(processRunDetails, helpers.randomMs(4000, 8000));
} else {
setTimeout(clickClaim, helpers.randomMs(4000, 8000));
}
return;
} catch (err) {
shared.closeWithError(K.ErrorType.CLICK_ROLL_ERROR, err);
}
};
function processRunDetails() {
let claimedAmount = elements.claimedAmount();
let balance = elements.balance();
if (claimedAmount && balance) {
let result = {};
result.claimed = claimedAmount;
result.balance = balance;
shared.closeWindow(result);
return;
}
setTimeout(processRunDetails, helpers.randomMs(5000, 6000));
};
return {
init: init
};
}
function createSGProcessor() {
let timerSpans;
function run() {
if(isLoading()) {
setTimeout(run, helpers.randomMs(5000, 10000));
return;
} else if (hasPopup()) {
closePopup();
setTimeout(run, helpers.randomMs(5000, 10000));
} else {
if(isMinerActive()) {
processRunDetails();
} else {
setTimeout(run, helpers.randomMs(5000, 10000));
activateMiner();
}
}
};
function hasPopup() {
if (document.querySelector('div.absolute.flex.top-0.right-0.cursor-pointer.p-4.text-white.md-text-gray-1')) {
return true;
}
return false;
};
function closePopup() {
try {
document.querySelector("div.absolute.flex.top-0.right-0.cursor-pointer.p-4.text-white.md-text-gray-1").click();
document.querySelector('svg.flex.w-8.h-8.fill-current').parentElement.click();
} catch { shared.devlog(`@SG: error closing popup`); }
};
function isLoading() {
return document.getElementById('loader-logo') ? true : false;
};
function isMinerActive() {
timerSpans = document.querySelector('.font-bold.text-center.text-accent.w-11-12.text-18 span');
if(timerSpans) {
return true;
} else {
return false;
}
return (!!timerSpans);
};
function activateMiner() {
let activateButton = document.querySelector("#region-main button.activate.block.w-full.h-full.mx-auto.p-0.rounded-full.select-none.cursor-pointer.focus-outline-none.border-0.bg-transparent");
if (activateButton) {
activateButton.click();
setTimeout(run, helpers.randomMs(10000, 20000));
} else {
processRunDetails()
}
};
function processRunDetails() {
let result = {};
result.nextRoll = helpers.addMinutes(readCountdown().toString());
result.balance = readBalance();
shared.closeWindow(result);
};
function readCountdown() {
let synchronizing = document.querySelector('.text-15.font-bold.text-center.text-accent'); // use
let mins = 15;
try {
let timeLeft = timerSpans.innerText.split(':');
if (timeLeft[0] == 'Synchronizing') {
}
if(timeLeft.length === 3) {
mins = parseInt(timeLeft[0]) * 60 + parseInt(timeLeft[1]);
}
} catch (err) { shared.devlog(`SG Error reading countdown: ${err}`); }
return mins;
};
function readBalance() {
let balance = "";
try {
balance = document.querySelector('span.text-accent').innerText + " BTC";
} catch (err) { }
return balance;
};
return {
run: run,
processRunDetails: processRunDetails
};
}
class AutoCMl extends Faucet {
constructor() {
let elements = {
claimed: new ReadableWidget({selector: 'div.alert.alert-success', parser: Parsers.splitAndIdxTrimNaNs, options: { splitter: ' ', idx: 0} }),
captcha: new HCaptchaWidget(),
rollButton: new ButtonWidget({selector: 'input[type="submit"].claim-button'}),
addressInput: new TextboxWidget({ selector: 'form[role="form"] input[type="text"]'})
};
let actions = {
readTimeLeft: false,
readRolledNumber: false,
readBalance: false
};
super(elements, actions);
}
init() {
this.hideAdBlocker();
if(this.hasErrorMessage('suspicious activity')) {
shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
return;
}
if(this.hasErrorMessage('no funds left') || this.hasErrorMessage('not have sufficient funds')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
return;
}
if(this.hasErrorMessage('reached the daily claim limit')) {
let result = {
nextRoll: this.readNextRoll()
};
shared.closeWindow(result);
return;
}
let claimed = this.readClaimed();
if (claimed != 0) {
if (!location.href.includes('doge')) {
claimed = claimed/100000000;
}
let result = {
claimed: claimed,
nextRoll: this.readNextRoll()
};
shared.closeWindow(result);
return;
}
let waitTime = this.hasWaitTime();
if (waitTime) {
let result = {
nextRoll: helpers.addMinutes(waitTime + 1)
};
shared.closeWindow(result);
return;
}
if (this.changeCaptcha()) {
return;
}
this.setCurrentCaptcha();
if (this._elements.addressInput.isUserFriendly) {
if (this._elements.addressInput.value != this._params.address) {
this._elements.addressInput.value = this._params.address;
}
}
this.run();
}
hideAdBlocker() {
try {
document.getElementById("page-body").style.display = "block";
document.getElementById("blocker-enabled").style.display = "none";
} catch (err) {}
setInterval(() => {
try {
document.getElementById("page-body").style.display = "block";
document.getElementById("blocker-enabled").style.display = "none";
} catch (err) {}
}, 3000);
}
changeCaptcha() {
let selections = [...document.querySelectorAll('div.text-center b')];
if (selections.length == 0) {
return false;
}
if (selections.filter(x => x.innerText.toLowerCase().includes('hcaptcha')).length != 1) {
location.href = location.href.includes('?') ? (location.href + '&cc=hCaptcha') : (location.href + '?cc=hCaptcha');
return true;
}
return false;
}
hasErrorMessage(searchTerm) {
return document.body.innerText.toLowerCase().includes(searchTerm);
}
hasWaitTime() {
try {
let pInfos = [...document.querySelectorAll('p.alert.alert-info')].filter(x => x.innerText.toLowerCase().includes('you have to wait'));
if (pInfos.length == 1) {
let time = +pInfos[0].innerText.toLowerCase().replace('you have to wait ', '').split(' ')[0];
return time;
}
} catch (err) {}
return false;
}
readNextRoll() {
try {
let spans = [...document.querySelectorAll('div.row div.col-md-5ths span:not(.glyphicon)')];
let idxClaimsLeft = spans.findIndex(x => x.innerText.includes('daily claims left'));
if (idxClaimsLeft > -1) {
if (spans[idxClaimsLeft].innerText.includes('0')) {
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
} else {
return helpers.addMinutes(helpers.randomInt(5, 12));
}
}
} catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
return helpers.addMinutes(60 * 24 + helpers.randomInt(10, 160));
}
}
class CClicks extends Faucet {
constructor() {
let elements = {
claimed: new ReadableWidget({selector: 'div.alert.alert-success', parser: Parsers.cbgClaimed}),
captcha: new HCaptchaWidget(),
rollButton: new ButtonWidget({selector: '#myModal input[type="submit"].btnclaim'}),
addressInput: new TextboxWidget({ selector: '#myModal input[type="text"]'}),
openModalButton: new ButtonWidget({selector: 'button[data-target="#myModal"]'})
};
let actions = {
readTimeLeft: false,
readRolledNumber: false,
readBalance: false
};
super(elements, actions);
}
async init() {
if (this.hasCloudflare()) {
return;
}
if(this.hasErrorMessage('suspicious activity')) {
shared.closeWithError(K.ErrorType.ERROR, 'Suspicious Activity Message Displayed');
return;
}
if(this.hasErrorMessage('no funds left') || this.hasErrorMessage('not have sufficient funds')) {
shared.closeWithError(K.ErrorType.FAUCET_EMPTY, 'Out of Funds');
return;
}
if(this.hasErrorMessage('reached the daily claim limit') || this.hasErrorMessage('reached the daily limit')) {
let result = {
nextRoll: helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40))
};
shared.closeWindow(result);
return;
}
let claimed = this.readClaimed();
if (claimed != 0) {
let result = {
claimed: claimed,
nextRoll: this.readNextRoll()
};
shared.closeWindow(result);
return;
}
if (this.changeCaptcha()) {
return;
}
if (this._elements.openModalButton.isUserFriendly) {
this._elements.openModalButton.click();
await wait(helpers.randomInt(1000, 2000));
}
if (this._elements.addressInput.isUserFriendly) {
if (this._elements.addressInput.value != this._params.address) {
this._elements.addressInput.value = this._params.address;
}
}
this.run();
}
changeCaptcha() {
let selections = [...document.querySelectorAll('div.text-center b')];
if (selections.length == 0) {
return false;
}
if (selections.filter(x => x.innerText.toLowerCase().includes('hcaptcha')).length != 1) {
location.href = location.href.includes('?') ? (location.href + '&cc=hCaptcha') : (location.href + '?cc=hCaptcha');
return true;
}
return false;
}
hasErrorMessage(searchTerm) {
return document.body.innerText.toLowerCase().includes(searchTerm);
}
readNextRoll() {
try {
let p = document.querySelector('p.alert.alert-success');
if (p && p.innerText.toLowerCase().includes('daily')) {
p = p.innerText.split('\n')[1];
p = +p.split(' daily')[0];
if (p > 0) {
return helpers.addMinutes(helpers.randomInt(3, 9));
} else {
return helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40));
}
}
return helpers.addMinutes(helpers.randomInt(3, 9));
} catch (err) { shared.devlog(`@readNextRoll: ${err}`); }
return helpers.addMinutes(60 * 8 + helpers.randomInt(15, 40));
}
}
let landing, instance, siteTimer;
let useTimer;
class Site {
constructor(params) {
Object.assign(this, {
schedule: '4a70e0', // Owner!
id: null,
name: null,
cmc: null, // REVIEW LOCATION
coinRef: null, // REVIEW LOCATION. Only for CFs?
url: null, // REVIEW FORMAT. Only one/'start' url? What about complex scripts/rotators/SLs?
rf: null, // ...
type: null, // REVIEW DEFAULT. It should be something like 'Crawler' or 'Handler' and the site params should depend on this value
clId: null,
wallet: null, // should be part of site parameters/crawler based?
enabled: false,
lastClaim: 0,
aggregate: 0,
balance: 0,
stats: {},
nextRoll: null,
params: {}, // should have schedule overrides and be called customExecution, scheduleParamaters or something like that
firstRun: true,
isExternal: false,
}, params);
this.setLegacyConditionalDefaults();
}
setLegacyConditionalDefaults() {
if (this.type == K.WebType.CRYPTOSFAUCETS) {
this.schedule = '65329c';
}
if (this.type == K.WebType.FREEBITCOIN) {
this.params['custom.useWofRp'] = 0;
this.params['custom.useFunRp'] = 0;
}
if (this.type == K.WebType.STORMGAIN) {
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = true;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 15;
this.params['defaults.nextRun.max'] = 20;
}
if (this.type == K.WebType.FAUCETPAY) {
this.params['defaults.workInBackground.override'] = true;
this.params['defaults.workInBackground'] = false;
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = false;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 300;
this.params['defaults.nextRun.max'] = 360;
}
if (this.type == K.WebType.BIGBTC) {
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = false;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 15;
this.params['defaults.nextRun.max'] = 40;
}
if (this.type == K.WebType.DUTCHYROLL) {
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = true;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 30;
this.params['defaults.nextRun.max'] = 35;
}
if (this.type == K.WebType.FCRYPTO) {
this.params['defaults.workInBackground.override'] = true;
this.params['defaults.workInBackground'] = false;
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = false;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 26;
this.params['defaults.nextRun.max'] = 35;
this.params['defaults.timeout.override'] = true;
this.params['defaults.timeout'] = 3;
this.params['defaults.postponeMinutes.override'] = true;
this.params['defaults.postponeMinutes'] = 0;
this.params['defaults.postponeMinutes.min'] = 12;
this.params['defaults.postponeMinutes.max'] = 18;
}
if (this.type == K.WebType.FPB) {
this.params['defaults.nextRun.override'] = true;
this.params['defaults.nextRun.useCountdown'] = false;
this.params['defaults.nextRun'] = 0;
this.params['defaults.nextRun.min'] = 22;
this.params['defaults.nextRun.max'] = 45;
}
}
static _sites = [];
static getAll() {
return Site._sites;
}
static getById(siteId) {
return Site.getAll().find(x => x.id == siteId) || false;
}
static createFromDataArray(newSites) {
if (!Array.isArray(newSites)) {
newSites = [...newSites];
}
newSites.forEach(s => Site.getAll().push(new Site(s)));
}
static add(data) {
let newSite = new Site(data);
Site.getAll().push(newSite);
let schedule = Schedule.getById(newSite.schedule);
if (!schedule) {
try {
schedule = Schedule.getAll()[0];
} catch (err) {
console.warn('No schedules found! Reseting to default schedules');
let defaultSchedule = new Schedule({ uuid: '4a70e0', name: 'Default' });
let sampleSchedule = new Schedule({ uuid: '65329c', name: 'CF' });
if (Schedule.getAll().length == 0) {
Schedule.add(defaultSchedule);
Schedule.add(sampleSchedule);
}
schedule = Schedule.getAll()[0];
}
}
if (!schedule) {
console.warn('Schedule NOT found');
console.warn(data);
return;
}
schedule.addSite(newSite);
eventer.emit('siteAdded', {
siteId: newSite.id,
siteName: newSite.name,
scheduleId: newSite.schedule
});
}
static remove(siteId) {
let idx = this._sites.findIndex(x => x.id === siteId);
if (idx > -1 && this._sites[idx].isExternal) {
let siteName = this._sites[idx].name;
this._sites = Site.getAll().filter(x => x.id !== siteId);
Schedule.getAll().forEach(sch => {
sch.removeSite(siteId);
});
eventer.emit('siteRemoved', {
siteId: siteId,
siteName: siteName
});
}
}
static sortAll() {
Site.getAll().sort( function(a,b) {
if (a === b) {
return 0;
} else if (a.nextRoll === null && b.nextRoll === null) {
let aHasLoginError = a.stats?.errors?.errorType == 2;
let bHasLoginError = b.stats?.errors?.errorType == 2;
if (aHasLoginError) {
return -1;
} else if (bHasLoginError) {
return 1;
}
return a.id > b.id ? -1 : 1
} else if (a.nextRoll === null) {
return 1;
} else if (b.nextRoll === null) {
return -1;
} else {
return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
}
});
}
static setAsRunAsap(siteId) {
let site = Site.getById(siteId);
if (!site) return false;
try {
let schedule = Schedule.getById(site.schedule);
if (schedule.status == STATUS.CLAIMING) {
console.warn(`Setting ASAP as 1st in schedule time + 1`);
site.nextRoll = new Date(schedule.currentSite.nextRoll.getTime() + 1);
} else {
let now = new Date();
if (!schedule.currentSite?.nextRoll) {
console.warn(`Setting ASAP as now()`);
site.nextRoll = now;
} else if (now < schedule.currentSite.nextRoll) {
console.warn(`Setting ASAP as now()`);
site.nextRoll = now;
} else {
console.warn(`Setting ASAP as 1st in schedule time - 1`);
site.nextRoll = new Date(schedule.currentSite.nextRoll.getTime() - 1);
}
}
site.enabled = true;
console.warn(`[${site.schedule}] ${site.name} updated to run ASAP from Site`);
eventer.emit('siteUpdated', site);
return;
} catch (err) {
console.error(err);
ui.log({msg: `Error setting faucet to run ASAP from Site: ${err}`});
}
}
changeSchedule(newScheduleId) {
let oldScheduleId = null;
if (this.schedule) {
oldScheduleId = this.schedule;
Schedule.getById(this.schedule)?.removeSite(this.id);
}
this.schedule = newScheduleId;
let newSchedule = Schedule.getById(this.schedule);
newSchedule.addSite(this); // maybe use just the ids...
eventer.emit('siteChangedSchedule', {
siteId: this.id,
scheduleId: this.schedule,
oldScheduleId: oldScheduleId
});
}
static saveAll() {
persistence.save('webList', Site._sites.map(x => x.toStorage()), true);
}
toStorage() { // Single site
if (!this.isExternal) {
return {
id: this.id,
isExternal: this.isExternal || false,
name: this.name,
schedule:this.schedule,
lastClaim: this.lastClaim,
aggregate: this.aggregate,
balance: this.balance,
stats: this.stats,
nextRoll: this.nextRoll,
enabled: this.enabled,
params: this.params
};
} else {
return {
id: this.id,
url: this.url.href,
clId: this.clId,
type: this.type,
cmc: this.cmc,
rf: this.rf,
name: this.name,
isExternal: this.isExternal || false,
schedule:this.schedule,
lastClaim: this.lastClaim,
aggregate: this.aggregate,
balance: this.balance,
stats: this.stats,
nextRoll: this.nextRoll,
enabled: this.enabled,
params: this.params
};
}
}
update(items) { // this should be for Parameters or Execution (custom)
this.params = this.params || {};
items.forEach( item => {
this.params[item.prop] = item.value;
});
ui.log({schedule: this.schedule, siteName: this.name, msg: `Site ${this.name} updated`});
}
getSiteParameters() {
if (this.type == K.WebType.CRYPTOSFAUCETS) {
this.siteParameters = {
handler: 'CF',
fields: [
{ name: 'try_get_codes', type: 'checkbox', value: 'false', text: 'Auto update promo codes' },
{ name: 'max_rolls_per_visit', type: 'numberInput', value: 1, min: 0 },
{ name: 'autologin', type: 'checkbox', value: 'true', text: 'Autologin when necessary' },
{ name: 'credentials_mode', type: 'credentials_or_autofilled', value: '2' },
{ name: 'email', type: 'email', value: '' },
{ name: 'password', type: 'password', value: '' }
]
};
}
return this.siteParameters || false;
}
}
class Schedule {
constructor(params) {
Object.assign(this, {
uuid: '4a70e0',
name: 'default_schedule',
status: STATUS.INITIALIZING,
currentSite: null,
sites: [],
tab: null,
timer: null, // TBD
timeWaiting: 0,
timeUntilNext: null,
worker: null
}, params)
this.timer = new Timer({ isManager: true, delaySeconds: 30, uuid: this.uuid, webType: null });
}
static schedules = [];
static getAll() {
return Schedule.schedules;
}
static getById(scheduleId) {
return Schedule.getAll().find(x => x.uuid == scheduleId) || false;
}
static add(newSchedule) {
Schedule.getAll().push(newSchedule);
}
static getAllForCrud() {
return Schedule.getAll().map(x => {
return {
uuid: x.uuid,
name: x.name,
hasSites: x.sites && x.sites.length > 0
};
});
}
static async initialize() {
Schedule.loadAll();
let defaultSchedule = new Schedule({ uuid: '4a70e0', name: 'Default' });
let sampleSchedule = new Schedule({ uuid: '65329c', name: 'CF' });
if (Schedule.getAll().length == 0) {
Schedule.add(defaultSchedule);
Schedule.add(sampleSchedule);
return;
}
let idxDefault = Schedule.getAll().findIndex(x => x.uuid == '4a70e0');
if (idxDefault == -1) {
Schedule.add(defaultSchedule);
}
};
static saveAll() {
persistence.save('schedules', Schedule.schedules.map(x => {
return {
uuid: x.uuid,
name: x.name
};
}), true);
}
static loadAll() {
Schedule.schedules = [];
let schedulesJson = persistence.load('schedules', true) || [];
schedulesJson.forEach(function(element) {
Schedule.getAll().push(new Schedule({
uuid: element.uuid,
name: element.name,
}));
});
}
sortSites() {
this.sites.sort( function(a,b) {
if (a === b) {
return 0;
} else if (a.nextRoll === null && b.nextRoll === null) {
let aHasLoginError = a.stats?.errors?.errorType == 2;
let bHasLoginError = b.stats?.errors?.errorType == 2;
if (aHasLoginError) {
return -1;
} else if (bHasLoginError) {
return 1;
}
return a.id > b.id ? -1 : 1
} else if (a.nextRoll === null) {
return 1;
} else if (b.nextRoll === null) {
return -1;
} else {
return a.nextRoll.getTime() < b.nextRoll.getTime() ? -1 : 1;
}
});
}
static crud(data) {
let isInvalid = false;
try {
const orphanSites = [];
data.forEach(x => {
if (x.added) {
if (Schedule.getById(x.uuid)) {
isInvalid = true;
} else {
let newSchedule = new Schedule({
uuid: x.uuid,
name: x.name,
order: x.order
})
Schedule.getAll().push(newSchedule);
newSchedule.start();
}
} else if (x.removed) {
let pos = Schedule.getAll().findIndex(s => s.uuid == x.originals.uuid);
orphanSites.push(...Schedule.getAll()[pos].sites);
Schedule.getAll().splice(pos, 1);
} else {
let sch = Schedule.getAll().find(s => s.uuid == x.originals.uuid);
if (Schedule.getById(x.uuid) && (Schedule.getById(x.uuid) != sch)) {
isInvalid = true;
} else {
sch.uuid = x.uuid;
}
sch.name = x.name;
sch.order = x.order;
}
});
Schedule.getAll().sort((a, b) => a.order - b.order);
if (orphanSites.length > 0) {
orphanSites.forEach(x => {
x.schedule = Schedule.getAll()[0].uuid;
});
Schedule.getAll()[0].sites.push(...orphanSites);
}
Schedule.saveAll();
} catch (err) {
console.error(err);
return false;
}
if (isInvalid) {
return false;
}
return true;
}
addSite(site) { this.sites.push(site) }
removeSite(siteId) {
if (this.sites.findIndex(x => x.id === siteId) > -1) {
this.sites = this.sites.filter(x => x.id !== siteId);
this.setCurrentSite();
}
}
setCurrentSite() {
this.currentSite = this.sites[0];
}
start() {
this.status = STATUS.IDLE;
this.worker = setTimeout(() => {
this.checkNextRoll();
}, 2000);
}
checkNextRoll() {
if (this.status != STATUS.IDLE) {
return;
}
this.timer.stopCheck();
clearTimeout(this.worker);
if(!this.currentSite || this.currentSite.nextRoll == null) {
document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', 'UNDEFINED');
this.status = STATUS.IDLE;
return;
}
if(this.currentSite.nextRoll.getTime() < Date.now()) {
ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Opening ${this.currentSite.name}`});
document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', 'RUNNING');
this.open();
this.timeUntilNext = null;
return;
} else {
this.timeUntilNext = this.currentSite.nextRoll.getTime() - Date.now() + helpers.randomMs(1000, 2000);
document.querySelector(`#wait-times span[data-schedule="${this.uuid}"]`).setAttribute('data-nextroll', this.currentSite.nextRoll.getTime());
this.worker = setTimeout(() => {
this.checkNextRoll();
}, this.timeUntilNext);
this.status = STATUS.IDLE;
}
}
getCustomOrDefaultVal(param, useOverride = false) {
let val;
if (useOverride) {
if (this.currentSite.params && this.currentSite.params.hasOwnProperty(param)) {
val = this.currentSite.params[param];
if (val != -1) {
return val;
}
}
}
return shared.getConfig()[param];
}
useOverride(param) {
let overrideFlag = param + '.override';
return this.currentSite.params && this.currentSite.params[overrideFlag];
}
closeTab() {
try {
this.tab.close();
} catch (err) {
console.warn('Error while trying to close tab', err);
}
};
reopenTab() {
this.tab = GM_openInTab(this.currentSite.url, { active: !this.getCustomOrDefaultVal('defaults.workInBackground', this.useOverride('defaults.workInBackground')) });
};
open(promoCodes) {
this.status = STATUS.CLAIMING;
let navUrl = this.currentSite.url;
try {
let params = this.currentSite.params || {};
params.siteParams = this.currentSite.siteParams || { "test": "test_value" };
if(promoCodes) {
navUrl = new URL('promotion/' + promoCodes[0], this.currentSite.url.origin);
ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Opening ${this.currentSite.name} with ${promoCodes.length} Promo Codes [${promoCodes.join(',')}]`});
params.promoCodes = promoCodes;
}
if (this.currentSite.firstRun) {
if(Array.isArray(this.currentSite.rf) && this.currentSite.rf.length > 0) {
navUrl = new URL(navUrl.href + this.currentSite.rf[helpers.randomInt(0, this.currentSite.rf.length - 1)]);
}
}
if (this.currentSite.wallet) {
try {
params.address = manager.userWallet.find(x => x.type == this.currentSite.wallet)?.address;
if (!params.address) {
throw new Error('Address is not defined.');
}
} catch {
ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Unable to launch ${this.currentSite.name}: Address not detected > add it to the wallet.`});
this.moveNextAfterTimeoutOrError();
return;
}
}
if(this.currentSite.type == K.WebType.BESTCHANGE) {
params.address = shared.getConfig()['bestchange.address'] == '1' ? manager.userWallet.find(x => x.type == 1).address : params.address;
}
params.timeout = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout'));
params.cmc = this.currentSite.cmc;
if(this.currentSite.type == K.WebType.FPB) {
switch(this.currentSite.id) {
case '77':
params.sitePrefix = 'fpb';
break;
case '83':
params.sitePrefix = 'fbch';
break;
case '92':
params.sitePrefix = 'shost';
break;
}
}
if(this.currentSite.type == K.WebType.VIE) {
params.credentials = {
mode: shared.getConfig()['jtfey.credentials.mode'],
username: shared.getConfig()['jtfey.credentials.username'],
password: shared.getConfig()['jtfey.credentials.password']
};
}
shared.setFlowControl(this.uuid, this.currentSite.id, navUrl, this.currentSite.type, params);
setTimeout(() => {
this.waitForResult();
}, 15000);
if (this.tab && !this.tab.closed) {
this.closeTab(); // this.tab.close();
} else {
}
this.timer.startCheck(this.currentSite.type);
let noSignUpList = [ K.WebType.BESTCHANGE, K.WebType.CBG, K.WebType.G8, K.WebType.O24, K.WebType.CDIVERSITY, K.WebType.CTOP, K.WebType.AUTOCML, K.WebType.CCLICKS ];
let hrefOpener = navUrl.href;
if (noSignUpList.includes(this.currentSite.type)) {
hrefOpener = (new URL(this.currentSite.clId, 'https://criptologico.com/goto/')).href;
}
this.tab = GM_openInTab(hrefOpener, { active: !this.getCustomOrDefaultVal('defaults.workInBackground', this.useOverride('defaults.workInBackground')) });
} catch(err) {
ui.log({ schedule: this.uuid, msg: `Error opening tab: ${err}`});
}
};
waitForResult() {
if(manager.isObsolete()) {
return;
}
if(shared.isCompleted(this.currentSite.id)) {
this.analyzeResult(); // rename to something else...
return;
}
this.timeWaiting += 15;
if(shared.isIncompleted(this.currentSite.id) && this.hasTimedOut()) {
this.analyzeResult(); // rename to something else...
return;
}
this.waitOrMoveNext(); // this should just be the error and timeout check
return;
};
analyzeResult() {
let currentSchedule = shared.getCurrent(this.uuid);
currentSchedule.result = currentSchedule.result || {};
currentSchedule.runStatus = currentSchedule.runStatus || false;
if (currentSchedule.result) {
this.updateWebListItem(currentSchedule);
if (currentSchedule.result.closeParentWindow) {
ui.log({ schedule: this.uuid, msg: `Closing working tab per process request` });
this.closeTab();
}
if (shared.getConfig()['cf.usePromoCodes'] && this.currentSite.type == K.WebType.CRYPTOSFAUCETS) {
let promoCode = CFPromotions.hasPromoAvailable(this.currentSite.id);
if (promoCode) {
this.timeWaiting = 0;
this.currentSite.nextRoll = new Date(754000 + +this.currentSite.id);
manager.update(false);
this.open(promoCode);
return;
}
}
} else {
ui.log({ schedule: this.uuid, siteName: this.currentSite.name, msg: `Unable to read last run result, for ID: ${this.currentSite.id} > ${this.currentSite.name}`});
}
this.timeWaiting = 0;
this.status = STATUS.IDLE;
shared.clearFlowControl(this.uuid);
manager.update(true);
manager.readUpdateValues(true);
return;
}
waitOrMoveNext() {
if (this.currentSite.isExternal) {
if (!this.tab || (this.tab && this.tab.closed)) {
this.timeWaiting = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout')) * 60 + 9999;
}
}
if (!shared.hasErrors(this.currentSite.id) && !this.hasTimedOut()) {
ui.log({ schedule: this.uuid,
siteName: this.currentSite.name,
elapsed: this.timeWaiting,
msg: `Waiting for ${this.currentSite.name} results...`});
setTimeout(() => {
this.waitForResult();
}, 15000);
return;
}
if (shared.hasErrors(this.currentSite.id)) {
this.currentSite.stats.errors = shared.getResult(this.uuid); // shared.getResult(this.uuid);
ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
msg: `${this.currentSite.name} closed with error: ${helpers.getEnumText(K.ErrorType,this.currentSite.stats.errors.errorType)} ${this.currentSite.stats.errors.errorMessage}`});
if(this.sleepIfBan()) {
return;
}
}
if (this.hasTimedOut()) {
if (this.currentSite.isExternal) {
this.currentSite.stats.countTimeouts = 0;
this.currentSite.stats.errors = null;
ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
msg: `Closing ${this.currentSite.name}` });
try {
this.closeTab();
} catch (err) { console.error('Unable to close working tab', err); }
this.moveAfterNormalRun();
return;
} else {
if(this.currentSite.stats.countTimeouts) {
this.currentSite.stats.countTimeouts += 1;
} else {
this.currentSite.stats.countTimeouts = 1;
}
ui.log({ schedule: this.uuid, siteName: this.currentSite.name,
msg: `Waited too much time for ${this.currentSite.name} results: triggering timeout` });
}
}
this.moveNextAfterTimeoutOrError();
return;
}
hasTimedOut() { // here or on a site level???
let val = this.getCustomOrDefaultVal('defaults.timeout', this.useOverride('defaults.timeout')) * 60;
return (this.timeWaiting > val);
};
sleepIfBan() { // This should be a SiteType hook
if( (this.currentSite.stats.errors.errorType == K.ErrorType.IP_BAN && shared.getConfig()['cf.sleepHoursIfIpBan'] > 0)
|| ( (this.currentSite.stats.errors.errorType == K.ErrorType.IP_RESTRICTED || this.currentSite.stats.errors.errorType == K.ErrorType.IP_BAN) && shared.getConfig()['bk.sleepMinutesIfIpBan'] > 0) ) {
if(this.currentSite.type == K.WebType.CRYPTOSFAUCETS) {
Site.getAll().filter(x => x.enabled && x.type == K.WebType.CRYPTOSFAUCETS)
.forEach( function(el) {
el.nextRoll = this.sleepCheck(helpers.addMs(helpers.getRandomMs(shared.getConfig()['cf.sleepHoursIfIpBan'] * 60, 2)).toDate());
});
}
shared.clearFlowControl(this.uuid);
manager.update(true);
this.timeWaiting = 0;
this.status = STATUS.IDLE;
shared.clearFlowControl(this.uuid);
manager.readUpdateValues(true);
return true;
}
return false;
}
updateWebListItem(currentSchedule) {
let result = currentSchedule.result;
ui.log({ schedule: this.uuid,
msg: `Updating data: ${JSON.stringify(result)}` });
this.currentSite.stats.countTimeouts = 0;
this.currentSite.stats.errors = null;
if (result.claimed) {
try {
result.claimed = parseFloat(result.claimed);
} catch { }
if(!isNaN(result.claimed)) {
this.currentSite.lastClaim = result.claimed;
this.currentSite.aggregate += result.claimed;
}
}
if(result.balance) {
this.currentSite.balance = result.balance;
}
this.currentSite.nextRoll = this.getNextRun(result.nextRoll ? result.nextRoll.toDate() : null);
if(result.promoCodeResults) { // TODO: move to a processResult hook
for(let i = 0; i < result.promoCodeResults.length; i++) {
let item = result.promoCodeResults[i];
CFPromotions.updateFaucetForCode(item.promoCode, this.currentSite.id, item.promoStatus);
}
}
if(result.rolledNumber) {
CFHistory.addRoll(result.rolledNumber);
}
}
getNextRun(nextRollFromCountdown) {
let useCustom = this.useOverride('defaults.nextRun');
let useCountdown = this.getCustomOrDefaultVal('defaults.nextRun.useCountdown', useCustom);
let nextRunMode = this.getCustomOrDefaultVal('defaults.nextRun', useCustom);
let min = this.getCustomOrDefaultVal('defaults.nextRun.min', useCustom);
let max = this.getCustomOrDefaultVal('defaults.nextRun.max', useCustom);
let nextRun;
if (useCountdown && nextRollFromCountdown) {
nextRun = nextRollFromCountdown;
} else {
let minutes = (nextRunMode == 0) ? helpers.randomInt(min, max) : nextRunMode;
let msDelay = helpers.getRandomMs(minutes, 1);
nextRun = helpers.addMs(msDelay).toDate();
}
nextRun = this.sleepCheck(nextRun)
return nextRun;
}
errorTreatment() { // Move to group custom getNextRoll
try {
switch(this.currentSite.stats.errors.errorType) {
case K.ErrorType.NEED_TO_LOGIN:
this.currentSite.enabled = false;
this.currentSite.nextRoll = null;
return true;
case K.ErrorType.FAUCET_EMPTY: // retry in 8 hours
this.currentSite.enabled = true;
this.currentSite.nextRoll = new Date(new Date().setHours(new Date().getHours() + 8));
return true;
}
} catch {}
return false;
}
sleepCheck(nextRun) {
let useCustom = this.useOverride('defaults.sleepMode');
let sleepMode = this.getCustomOrDefaultVal('defaults.sleepMode', useCustom);
if (sleepMode) {
let intNextRunTime = nextRun.getHours() * 100 + nextRun.getMinutes();
let min = this.getCustomOrDefaultVal('defaults.sleepMode.min', useCustom).replace(':', '');
let max = this.getCustomOrDefaultVal('defaults.sleepMode.max', useCustom).replace(':', '');
if (+min < +max) {
if (+min < intNextRunTime && intNextRunTime < +max) {
nextRun.setHours(max.slice(0, 2), max.slice(-2), 10, 10);
ui.log({ schedule: this.uuid,
msg: `Next run adjusted by Sleep Mode: ${helpers.getPrintableDateTime(nextRun)}` });
}
} else if (+min > +max) {
if (intNextRunTime > +min || intNextRunTime < +max) {
nextRun.setHours(max.slice(0, 2), max.slice(-2), 10, 10);
if (nextRun.getTime() < Date.now()) {
nextRun.setDate(nextRun.getDate() + 1);
}
ui.log({ schedule: this.uuid,
msg: `Next run adjusted by Sleep Mode: ${helpers.getPrintableDateTime(nextRun)}` });
}
}
}
return nextRun;
}
moveAfterNormalRun() {
this.currentSite.nextRoll = this.getNextRun(null);
shared.clearFlowControl(this.uuid);
manager.update(true);
this.timeWaiting = 0;
this.status = STATUS.IDLE;
shared.clearFlowControl(this.uuid);
manager.readUpdateValues(true);
}
moveNextAfterTimeoutOrError() {
let useCustom = this.useOverride('defaults.postponeMinutes');
let mode = this.getCustomOrDefaultVal('defaults.postponeMinutes', useCustom);
let min = this.getCustomOrDefaultVal('defaults.postponeMinutes.min', useCustom);
let max = this.getCustomOrDefaultVal('defaults.postponeMinutes.max', useCustom);
let minutes = (mode == 0) ? helpers.randomInt(min, max) : mode;
let msDelay = helpers.getRandomMs(minutes, 5);
this.currentSite.nextRoll = this.sleepCheck(helpers.addMs(msDelay).toDate());
if(this.errorTreatment()) {
}
shared.clearFlowControl(this.uuid);
manager.update(true);
this.timeWaiting = 0;
this.status = STATUS.IDLE;
shared.clearFlowControl(this.uuid);
manager.readUpdateValues(true);
}
}
function createManager() {
let timestamp = null;
let intervalUiUpdate;
let getFeedInterval;
let userWallet = [];
const sites = [
{ id: '1', name: 'CF ADA', cmc: '2010', coinRef: 'ADA', url: new URL('https://app.freecardano.com/free'), rf: '?ref=335463', type: K.WebType.CRYPTOSFAUCETS, clId: 45 },
{ id: '2', name: 'CF BNB', cmc: '1839', coinRef: 'BNB', url: new URL('https://app.freebinancecoin.com/free'), rf: '?ref=161127', type: K.WebType.CRYPTOSFAUCETS, clId: 42 },
{ id: '3', name: 'CF BTC', cmc: '1', coinRef: 'BTC', url: new URL('https://app.freebitcoin.io/free'), rf: '?ref=490252', type: K.WebType.CRYPTOSFAUCETS, clId: 40 },
{ id: '4', name: 'CF DASH', cmc: '131', coinRef: 'DASH', url: new URL('https://app.freedash.io/free'), rf: '?ref=124083', type: K.WebType.CRYPTOSFAUCETS, clId: 156 },
{ id: '5', name: 'CF ETH', cmc: '1027', coinRef: 'ETH', url: new URL('https://app.freeethereum.com/free'), rf: '?ref=204076', type: K.WebType.CRYPTOSFAUCETS, clId: 44 },
{ id: '6', name: 'CF LINK', cmc: '1975', coinRef: 'LINK', url: new URL('https://app.freecryptom.com/free'), rf: '?ref=78652', type: K.WebType.CRYPTOSFAUCETS, clId: 157 },
{ id: '7', name: 'CF LTC', cmc: '2', coinRef: 'LTC', url: new URL('https://app.free-ltc.com/free'), rf: '?ref=117042', type: K.WebType.CRYPTOSFAUCETS, clId: 47 },
{ id: '8', name: 'CF NEO', cmc: '1376', coinRef: 'NEO', url: new URL('https://app.freeneo.io/free'), rf: '?ref=100529', type: K.WebType.CRYPTOSFAUCETS, clId: 158 },
{ id: '9', name: 'CF STEAM', cmc: '825', coinRef: 'STEEM', url: new URL('https://app.freesteam.io/free'), rf: '?ref=117686', type: K.WebType.CRYPTOSFAUCETS, clId: 49 },
{ id: '10', name: 'CF TRX', cmc: '1958', coinRef: 'TRX', url: new URL('https://app.free-tron.com/free'), rf: '?ref=145047', type: K.WebType.CRYPTOSFAUCETS, clId: 41 },
{ id: '11', name: 'CF USDC', cmc: '3408', coinRef: 'USDC', url: new URL('https://app.freeusdcoin.com/free'), rf: '?ref=100434', type: K.WebType.CRYPTOSFAUCETS, clId: 51 },
{ id: '12', name: 'CF USDT', cmc: '825', coinRef: 'USDT', url: new URL('https://app.freetether.com/free'), rf: '?ref=181230', type: K.WebType.CRYPTOSFAUCETS, clId: 43 },
{ id: '13', name: 'CF XEM', cmc: '873', coinRef: 'XEM', url: new URL('https://app.freenem.com/free'), rf: '?ref=295274', type: K.WebType.CRYPTOSFAUCETS, clId: 46 },
{ id: '14', name: 'CF XRP', cmc: '52', coinRef: 'XRP', url: new URL('https://app.coinfaucet.io/free'), rf: '?ref=808298', type: K.WebType.CRYPTOSFAUCETS, clId: 48 },
{ id: '15', name: 'StormGain', cmc: '1', url: new URL('https://app.stormgain.com/crypto-miner/'), rf: 'friend/BNS27140552', type: K.WebType.STORMGAIN, clId: 35 },
{ id: '16', name: 'CF DOGE', cmc: '74', coinRef: 'DOGE', url: new URL('https://app.free-doge.com/free'), rf: '?ref=97166', type: K.WebType.CRYPTOSFAUCETS, clId: 50 },
{ id: '17', name: 'FreeBitco.in', cmc: '1', url: new URL('https://freebitco.in/'), rf: '?r=41092365', type: K.WebType.FREEBITCOIN, clId: 36 },
{ id: '18', name: 'FaucetPay PTC', cmc: '825', url: new URL('https://faucetpay.io/ptc'), rf: '?r=41092365', type: K.WebType.FAUCETPAY, clId: 159 },
{ id: '52', name: 'BigBtc', cmc: '1', wallet: K.WalletType.FP_BTC, url: new URL('https://bigbtc.win/'), rf: '?id=39255652', type: K.WebType.BIGBTC, clId: 200 },
{ id: '53', name: 'BestChange', cmc: '1', url: new URL('https://www.bestchange.com/'), rf: ['index.php?nt=bonus&p=1QCD6cWJNVH4Cdnz85SQ2qtTkAwGr9fvUk'], type: K.WebType.BESTCHANGE, clId: 163 },
{ id: '58', name: 'BF BTC', cmc: '1', url: new URL('https://betfury.io/boxes/all'), rf: ['?r=608c5cfcd91e762043540fd9'], type: K.WebType.BFBOX, clId: 1 },
{ id: '61', name: 'Dutchy', cmc: '-1', url: new URL('https://autofaucet.dutchycorp.space/roll.php'), rf: '?r=corecrafting', type: K.WebType.DUTCHYROLL, clId: 141 },
{ id: '62', name: 'Dutchy Monthly Coin', cmc: '-1', url: new URL('https://autofaucet.dutchycorp.space/coin_roll.php'), rf: '?r=corecrafting', type: K.WebType.DUTCHYROLL, clId: 141 },
{ id: '68', name: 'CF SHIBA', cmc: '5994', coinRef: 'SHIBA', url: new URL('https://app.freeshibainu.com/free'), rf: '?ref=18226', type: K.WebType.CRYPTOSFAUCETS, clId: 167 },
{ id: '78', name: 'CF Cake', cmc: '7186', coinRef: 'CAKE', url: new URL('https://app.freepancake.com/free'), rf: '?ref=699', type: K.WebType.CRYPTOSFAUCETS, clId: 197 },
{ id: '80', name: 'FreeGRC', cmc: '833', url: new URL('https://freegridco.in/#free_roll'), rf: '', type: K.WebType.FREEGRC, clId: 207 },
{ id: '81', name: 'CF Matic', cmc: '3890', coinRef: 'MATIC', url: new URL('https://app.freematic.com/free'), rf: '?ref=6435', type: K.WebType.CRYPTOSFAUCETS, clId: 210 },
{ id: '84', name: 'JTFey', cmc: '-1', url: new URL('https://james-trussy.com/faucet'), rf: ['?r=corecrafting'], type: K.WebType.VIE, clId: 213 },
{ id: '85', name: 'O24', cmc: '1', wallet: K.WalletType.FP_BTC, url: new URL('https://www.only1024.com/f'), rf: ['?r=1QCD6cWJNVH4Cdnz85SQ2qtTkAwGr9fvUk'], type: K.WebType.O24, clId: 97 },
{ id: '87', name: 'CF BTT', cmc: '16086', coinRef: 'BTT', url: new URL('https://app.freebittorrent.com/free'), rf: '?ref=2050', type: K.WebType.CRYPTOSFAUCETS, clId: 218 },
{ id: '89', name: 'CF BFG', cmc: '11038', coinRef: 'BFG', url: new URL('https://app.freebfg.com/free'), rf: '?ref=117', type: K.WebType.CRYPTOSFAUCETS, clId: 219 },
{ id: '93', name: 'YCoin', cmc: '1', url: new URL('https://yescoiner.com/faucet'), rf: ['?ref=4729452'], type: K.WebType.YCOIN, clId: 234 },
{ id: '94', name: 'CDiversity', cmc: '-1', wallet: K.WalletType.FP_MAIL, url: new URL('http://coindiversity.io/free-coins'), rf: ['?r=1J3sLBZAvY5Vk9x4RY2qSFyL7UHUszJ4DJ'], type: K.WebType.CDIVERSITY, clId: 235 },
{ id: '96', name: 'Top Ltc', cmc: '2', wallet: K.WalletType.FP_LTC, url: new URL('https://ltcfaucet.top/'), rf: ['?r=MWSsGAQTYD7GH5o4oAehC8Et5PyMBfhnKK'], type: K.WebType.CTOP, clId: 239 },
{ id: '97', name: 'Top Bnb', cmc: '1839', wallet: K.WalletType.FP_BNB, url: new URL('https://bnbfaucet.top/'), rf: ['?r=0x1e8CB8A79E347C54aaF21C0502892B58F97CC07A'], type: K.WebType.CTOP, clId: 240 },
{ id: '98', name: 'Top Doge', cmc: '74', wallet: K.WalletType.FP_DOGE, url: new URL('https://dogecoinfaucet.top/'), rf: ['?r=D8Xgghu5gCryukwmxidFpSmw8aAKon2mEQ'], type: K.WebType.CTOP, clId: 241 },
{ id: '99', name: 'Top Trx', cmc: '1958', wallet: K.WalletType.FP_TRX, url: new URL('https://tronfaucet.top/'), rf: ['?r=TK3ofbD3AyXotN2111UvnwCzr2YaW8Qmx7'], type: K.WebType.CTOP, clId: 242 },
{ id: '100', name: 'Top Eth', cmc: '1027', wallet: K.WalletType.FP_ETH, url: new URL('https://ethfaucet.top/'), rf: ['?r=0xC21FD989118b8C0Db6Ac2eC944B53C09F7293CC8'], type: K.WebType.CTOP, clId: 243 },
{ id: '101', name: 'Top Bch', cmc: '1831', wallet: K.WalletType.FP_BCH, url: new URL('https://freebch.club/'), rf: ['?r=qq2qlpzs4rsn30utrumezpkzezpteqj92ykdgfeq5u'], type: K.WebType.CTOP, clId: 244 },
{ id: '102', name: 'Top Zec', cmc: '1437', wallet: K.WalletType.FP_ZEC, url: new URL('https://zecfaucet.net/'), rf: ['?r=t1erPs9qw3SgnX7kJPmR4uKFnLaoVww2jCy'], type: K.WebType.CTOP, clId: 245 },
{ id: '103', name: 'FMonster', cmc: '825', wallet: K.WalletType.FP_USDT, url: new URL('https://faucet.monster/'), rf: '', type: K.WebType.O24, clId: 246 },
{ id: '104', name: 'Auto-C BNB', cmc: '1839', wallet: K.WalletType.FP_BNB, url: new URL('https://auto-crypto.click/'), rf: ['?r=0x1e8CB8A79E347C54aaF21C0502892B58F97CC07A'], type: K.WebType.AUTOCML, clId: 247 },
{ id: '105', name: 'Auto-C DOGE', cmc: '74', wallet: K.WalletType.FP_DOGE, url: new URL('https://freeshiba.cf/'), rf: ['?r=D8Xgghu5gCryukwmxidFpSmw8aAKon2mEQ'], type: K.WebType.AUTOCML, clId: 248 },
{ id: '106', name: 'ClClicks DOGE', cmc: '74', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/doge/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 61 },
{ id: '107', name: 'ClClicks LTC', cmc: '2', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/ltc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 62 },
{ id: '108', name: 'ClClicks TRX', cmc: '1958', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/trx/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 63 },
{ id: '109', name: 'ClClicks BTC', cmc: '1', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/btc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 252 },
{ id: '110', name: 'ClClicks SOL', cmc: '5426', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/sol/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 253 },
{ id: '111', name: 'ClClicks BNB', cmc: '1839', wallet: K.WalletType.FP_USERNAME, url: new URL('https://claimclicks.com/bnb/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 254 },
{ id: '112', name: 'CrClicks DOGE', cmc: '74', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/doge/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 257 },
{ id: '113', name: 'CrClicks LTC', cmc: '2', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/ltc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 258 },
{ id: '114', name: 'CrClicks TRX', cmc: '1958', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/trx/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 259 },
{ id: '115', name: 'CrClicks BTC', cmc: '1', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/btc/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 256 },
{ id: '116', name: 'CrClicks SOL', cmc: '5426', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/sol/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 261 },
{ id: '117', name: 'CrClicks BNB', cmc: '1839', wallet: K.WalletType.FP_USERNAME, url: new URL('https://cryptoclicks.net/bnb/'), rf: ['?r=corecrafting'], type: K.WebType.CCLICKS, clId: 260 },
];
const wallet = [
{ id: '99', name: 'FaucetPay Username', type: K.WalletType.FP_USERNAME },
{ id: '100', name: 'FaucetPay Email', type: K.WalletType.FP_MAIL },
{ id: '101', name: 'FaucetPay BTC (Bitcoin)', type: K.WalletType.FP_BTC },
{ id: '102', name: 'FaucetPay BNB (Binance Coin)', type: K.WalletType.FP_BNB },
{ id: '103', name: 'FaucetPay BCH (Bitcoin Cash)', type: K.WalletType.FP_BCH },
{ id: '104', name: 'FaucetPay DASH (Dash)', type: K.WalletType.FP_DASH },
{ id: '105', name: 'FaucetPay DGB (DigiByte)', type: K.WalletType.FP_DGB },
{ id: '106', name: 'FaucetPay DOGE (Dogecoin)', type: K.WalletType.FP_DOGE },
{ id: '107', name: 'FaucetPay ETH (Ethereum)', type: K.WalletType.FP_ETH },
{ id: '108', name: 'FaucetPay FEY (Feyorra)', type: K.WalletType.FP_FEY },
{ id: '109', name: 'FaucetPay LTC (Litecoin)', type: K.WalletType.FP_LTC },
{ id: '110', name: 'FaucetPay TRX (Tron)', type: K.WalletType.FP_TRX },
{ id: '111', name: 'FaucetPay USDT (Tether TRC20)', type: K.WalletType.FP_USDT },
{ id: '112', name: 'FaucetPay ZEC (Zcash)', type: K.WalletType.FP_ZEC },
{ id: '113', name: 'FaucetPay SOL (Solana)', type: K.WalletType.FP_SOL },
{ id: '114', name: 'FaucetPay MATIC (Polygon)', type: K.WalletType.FP_MATIC },
{ id: '116', name: 'FaucetPay ADA (Cardano)', type: K.WalletType.FP_ADA },
{ id: '200', name: 'ExpressCrypto (EC-UserId-XXXXXX)', type: K.WalletType.EC },
{ id: '1', name: 'BTC Alternative Address', type: K.WalletType.BTC }
];
async function start() {
await loader.initialize();
ui.init(getCFlist(), Schedule.getAll());
uiRenderer.appendEventListeners();
shared.purgeFlowControlSchedules(Schedule.getAll().map(x => x.uuid));
update();
uiRenderer.wallet.legacyRenderWalletTable(userWallet);
intervalUiUpdate = setInterval(readUpdateValues, 10000);
Schedule.getAll().forEach(x => {
x.start();
});
if (document.querySelector('#console-log').innerText == 'Loading...') {
document.querySelector('#console-log').innerHTML = '<table><tr><td><b>Running...</b></td></tr></table>';
}
getFeedInterval = setInterval(getCodesFeed, 25000);
};
let loader = function() {
async function initialize() {
setTimestamp();
await Schedule.initialize();
await initializeSites();
initializeUserWallet();
initializePromotions();
initializeHistory();
};
async function initializeSites() {
Site.createFromDataArray(sites);
await updateSitesWithStoredData();
await addSitesToSchedules();
};
async function updateSitesWithStoredData() {
let storedData = persistence.load('webList', true);
if (storedData) {
storedData.forEach( function (stored) {
if (stored.isExternal) {
stored.url = new URL(stored.url);
Site.add(stored);
}
let site = Site.getById(stored.id);
if (!site) {
return;
}
for (const prop in stored) {
site[prop] = stored[prop];
}
if (!site.enabled) {
site.nextRoll = null;
} else {
site.nextRoll = site.nextRoll ? new Date(site.nextRoll) : new Date();
}
if (site.aggregate || site.balance) {
site.firstRun = false;
}
})
}
};
async function addSitesToSchedules() {
Site.getAll().forEach(site => {
let scheduleOfSite = Schedule.getById(site.schedule);
if (!scheduleOfSite) {
console.warn(`Attention! Site ${site.name} has a reference to a schedule that does not exist: (${site.schedule})`);
scheduleOfSite = Schedule.getAll()[0];
console.warn(`Assigning it to first schedule (${scheduleOfSite.uuid}) instead.`);
site.schedule = scheduleOfSite.uuid; // use .changeSchedule to save the change???
}
scheduleOfSite.addSite(site);
});
};
function initializeUserWallet() {
addWallets();
addStoredWalletData();
};
function addWallets() {
wallet.forEach(x => userWallet.push(x));
userWallet.forEach(function (element, idx, arr) {
arr[idx].address = '';
});
};
function addStoredWalletData() {
let storedData = persistence.load('userWallet', true);
if(storedData) {
storedData.forEach( function (element) {
let idx = userWallet.findIndex(x => x.id == element.id);
if(idx != -1) {
userWallet[idx].address = element.address ?? userWallet[idx].address;
}
});
}
};
function initializePromotions() {
let storedData = persistence.load('CFPromotions', true);
if (storedData) {
let mig00200799 = false;
try {
mig00200799 = shared.getConfig().migrations.find(x => x.version == '00200799' && !x.applied);
} catch (err) {}
let allCFs = manager.getFaucetsForPromotion().map( cf => cf.id );
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;
if (mig00200799 && el.status == 4) {
a[i].status = 1;
}
});
allCFs.forEach( function (cf) {
if (!arr[idx].statusPerFaucet.find( x => x.id == cf )) {
let newCf = { id: cf, status: 1, execTimeStamp: null };
arr[idx].statusPerFaucet.push(newCf);
}
});
});
if (mig00200799) {
shared.migrationApplied('00200799');
}
CFPromotions.load(storedData);
}
};
function initializeHistory() {
CFHistory.initOrLoad();
};
function setTimestamp() {
timestamp = Date.now();
persistence.save('timestamp', timestamp);
};
return {
initialize: initialize
};
}();
function getCodesFeed(force = false) {
clearInterval(getFeedInterval);
if (!force) {
let tryGet = shared.getConfig()['cf.tryGetCodes'] || false;
if (!tryGet) {
return;
}
}
let nextFeed = helpers.randomMs(2 * 60 * 60 * 1000, 4 * 60 * 60 * 1000);
getFeedInterval = setInterval(getCodesFeed, nextFeed)
GM_xmlhttpRequest({
method: "GET",
url: "https://criptologico.com/api/?key=XI2HV-1P9PQ-W637F-68B9B-A248&requests[cf_codes]",
timeout: 10000,
onload: function(response) {
try {
let txt = response.responseText;
let parsed = JSON.parse(txt);
if (parsed.success) {
let newCodes = [];
for(let i = 0; i < parsed.cf_codes.length; i++) {
let item = parsed.cf_codes[i];
let newCode = {};
newCode.code = item.code;
newCode.oneTimeOnly = item.is_one_time == '1';
newCode['expiration' + 'Date'] = item.expiration_date.replace(' ', 'T') + 'Z';
newCode['expiration' + 'Date'] = new Date(newCode['expiration' + 'Date']);
newCodes.push(newCode);
}
CFPromotions.includeNewCodes(newCodes);
uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
}
} catch(err) {
console.error('unexpected error parsing codes list');
console.error(err);
}
},
onerror: function(e) {
console.error('error getting codes');
console.error(e);
},
ontimeout: function() {
console.error('timeout getting codes');
},
});
}
function readUpdateValues(forceCheck = false) {
readPromoCodeValues();
readModalData();
if(true) {
let updateDataElement = document.getElementById('update-data');
let updateValues = updateDataElement.innerText.clean();
if (updateValues != '') {
updateDataElement.innerText = '';
let updateObj = JSON.parse(updateValues);
if(updateObj.editSingle.changed) {
updateObj.editSingle.items.forEach(function (element, idx, arr) {
try {
let site = Site.getById(element.id);
site.name = element.displayName;
if (site.enabled != element.enabled) {
site.enabled = element.enabled;
if(site.enabled) {
site.nextRoll = new Date(idx);
} else {
site.nextRoll = null;
}
}
ui.log({ schedule: site.schedule,
msg: `Faucet updated. New name: ${element.displayName}. Active: ${element.enabled}` });
} catch (err) {
ui.log({ schedule: this.uuid,
msg: `Error updating faucet data: ${err}` });
}
});
}
if(updateObj.wallet.changed) {
updateObj.wallet.items.forEach(function (element) {
try {
let itemIndex = userWallet.findIndex(x => x.id == element.id);
userWallet[itemIndex].address = element.address;
ui.log({ msg: `Wallet Address updated [${userWallet[itemIndex].name}]: ${userWallet[itemIndex].address}` });
} catch (err) {
ui.log({ msg: `Error updating wallet/address: ${err}` });
}
});
uiRenderer.wallet.legacyRenderWalletTable(userWallet);
saveUserWallet();
}
if(updateObj.config.changed) {
try {
shared.updateConfig(updateObj.config.items);
ui.log({ msg: `Config updated. Reloading in a few seconds...` });
window.location.reload();
return;
} catch (err) {
ui.log({ msg: `Error updating config: ${err}` });
}
}
if(updateObj.site.changed) {
updateObj.site.list.forEach( (x) => {
try {
updateSite(x.id, x.items);
} catch (err) {
ui.log({ msg: `Error updating site: ${err}` });
}
});
}
if(updateObj.runAsap.changed || updateObj.editSingle.changed || updateObj.site.changed) {
resyncAll({ withUpdate: true });
return;
}
}
}
if(forceCheck) {
resyncAll({ withUpdate: false });
}
};
function resyncAll(options = { withUpdate: false} ) {
if (options.withUpdate) {
update(true);
}
Schedule.getAll().forEach(x => {
x.checkNextRoll();
});
}
function updateSite(id, items) {
let site = Site.getById(id);
if (site) {
site.params = site.params || {};
items.forEach( (item) => {
site.params[item.prop] = item.value;
});
ui.log({ schedule: site.schedule, siteName: site.name,
msg: `Site ${site.name} updated` });
}
}
function readModalData() { // This should be migrated and dissapear!
if(document.getElementById('modal-spinner').isVisible()) {
let targetObject = JSON.parse(document.getElementById('target-spinner').innerHTML);
let target = targetObject.id;
if (target == 'modal-ereport') {
let temp = shared.getDevLog();
document.getElementById('log-textarea').value = temp.join('\n');
} else if (target == 'modal-config') {
uiRenderer.config.legacyRenderConfigData(shared.getConfig());
} else if (target == 'modal-site') {
let site = Site.getById(targetObject.siteId);
uiRenderer.sites.legacyRenderSiteData(site, shared.getConfig());
}
document.getElementById('modal-spinner').classList.toggle('d-none');
document.getElementById(target).classList.toggle('d-none');
document.getElementById('target-spinner').innerHTML = '';
}
}
function sortSites () { // Temporary, just to decouple it...
Site.sortAll();
Schedule.getAll().forEach( schedule => schedule.sortSites() );
};
function update(sortIt = true) {
if(sortIt) {
sortSites();
Schedule.getAll().forEach( schedule => schedule.setCurrentSite() );
}
Site.saveAll();
Site.getAll().forEach(site => {
uiRenderer.sites.renderSiteRow(site);
});
uiRenderer.sites.removeDeletedSitesRows(Site.getAll().map(x => x.id));
convertToFiat();
uiRenderer.sites.sortSitesTable(); // y reordenar
uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
updateRollStatsSpan();
};
function saveUserWallet() {
const data = userWallet.map(x => {
return {
id: x.id,
address: x.address
};});
persistence.save('userWallet', data, true);
}
function isObsolete() {
let savedTimestamp = persistence.load('timestamp');
if (savedTimestamp && savedTimestamp > timestamp) {
ui.log({ msg: '<b>STOPING EXECUTION!<b> A new Manager UI window was opened. Process should continue there' });
clearInterval(intervalUiUpdate);
return true;
}
return false;
};
function readPromoCodeValues() {
let promoCodeElement = document.getElementById('promo-code-new');
let promoDataStr = promoCodeElement.innerText.clean();
if (promoDataStr == '') {
return;
}
let promoData = JSON.parse(promoDataStr);
if(promoData.action) {
switch (promoData.action) {
case 'FORCESTOPFAUCET':
Schedule.getAll().forEach(s => {
if (s.status != STATUS.IDLE) {
s.currentSite.enabled = false;
s.closeTab();
}
});
update(true);
shared.clearFlowControl('all');
setTimeout(() => {
window.location.reload();
}, 3000);
promoCodeElement.innerText = '';
break;
case 'ADD':
CFPromotions.addNew(promoData.code, promoData.repeatDaily);
promoCodeElement.innerText = '';
document.getElementById('promo-text-input').value = '';
uiRenderer.toast("Code " + promoData.code + " added!");
ui.log({ msg: `Promo code ${promoData.code} added` });
uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
break;
case 'REMOVEALLPROMOS':
CFPromotions.removeAll();
promoCodeElement.innerText = '';
uiRenderer.toast("Promo codes removed!");
ui.log({ msg: `Promo codes removed` });
uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
break;
case 'REMOVE':
if(CFPromotions.remove(promoData.id, promoData.code) != -1) {
ui.log({ msg: `Promo code ${promoData.code} removed` });
} else {
ui.log({ msg: `Unable to remove code ${promoData.code}` });
}
promoCodeElement.innerText = '';
uiRenderer.promos.legacyRenderPromotionTable(CFPromotions.getAll());
break;
case 'TRYGETCODES':
getCodesFeed(true);
promoCodeElement.innerText = '';
uiRenderer.toast("Looking for new codes!");
break;
}
}
};
function updateRollStatsSpan() {
let rollsSpanElement = document.getElementById('rolls-span');
rollsSpanElement.innerText = CFHistory.getRollsMeta().join(',');
};
function getCFlist() {
let items;
items = Site.getAll().filter(f => f.type === K.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;
};
function closeWorkingTab(schedule) {
let sc = Schedule.getAll().find(x => x.uuid == schedule);
if (sc) sc.closeTab()
};
function reloadWorkingTab(schedule) {
let sc = Schedule.getAll().find(x => x.uuid == schedule);
if (sc) {
sc.closeTab();
sc.reopenTab();
}
};
function getAllSites() {
return Site.getAll();
}
return{
start: start,
getFaucetsForPromotion: getCFlist,
closeWorkingTab: closeWorkingTab,
reloadWorkingTab: reloadWorkingTab,
getAllSites: getAllSites,
resyncAll: resyncAll,
isObsolete: isObsolete,
update: update,
userWallet: userWallet,
readUpdateValues: readUpdateValues
};
}
function createUi() {
let injectables = {
managerJs: function () {
window.myBarChart = null;
window.landing = window.location.host;
window.sendErrorReport = function sendErrorReport() {
try {
let header = new Headers();
header.append("Content-Type", "application/json");
let description = document.getElementById("log-message").value;
let log = document.getElementById("log-textarea").value.split('\n');
let content = {"description":description, "log":log};
let opt = { method: "POST", header, mode: "cors", body: JSON.stringify(content) };
fetch("https://1d0103ec5a621b87ea27ffed3c072796.m.pipedream.net", opt).then(response => {
}).catch(err => {
console.error("[error] " + err.message);
});
} catch { }
};
window.getUpdateObject = function getUpdateObject() {
let updateObject;
var updateData = document.getElementById("update-data");
if (updateData.innerHTML != "") {
updateObject = JSON.parse(updateData.innerHTML);
} else {
updateObject = { runAsap: { ids: [], changed: false}, editSingle: { changed: false, items: [] }, wallet: { changed: false, items: []}, config: { changed: false, items: []}, site: { changed: false, list: []} };
}
return updateObject;
};
window.removePromoCode = function removePromoCode(id, code) {
var promoCode = document.getElementById("promo-code-new");
var promoObject = { action: "REMOVE", id: id, code: code };
promoCode.innerHTML =JSON.stringify(promoObject);
};
window.editWallet = {
save: function() {
let updateObject = getUpdateObject();
document.querySelectorAll("#wallet-table-body tr").forEach( function(row) {
let textInput = row.querySelector(".em-input input");
if(textInput.dataset.original != textInput.value) {
let single = { id: row.dataset.id, address: textInput.value.trim() };
updateObject.wallet.items.push(single);
updateObject.wallet.changed = true;
}
});
if(updateObject.wallet.changed) {
document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
toastr["info"]("Wallet will be updated as soon as possible");
}
},
toggleJson: function(val) {
if (document.querySelector('#wallet-json').isVisible()) {
if(val != 'cancel') {
editWallet.fromJson();
}
} else {
editWallet.toJson();
}
document.querySelector('.footer-json').classList.toggle('d-none');
document.querySelector('.footer-table').classList.toggle('d-none');
document.querySelector('#wallet-table').classList.toggle('d-none');
document.querySelector('#wallet-json').classList.toggle('d-none');
},
toJson: function() {
let j = [];
document.querySelectorAll('#wallet-table-body tr').forEach(function (row) {
j.push({ id: row.dataset.id, address: row.querySelector('.em-input input').value });
});
document.querySelector('#wallet-json').value = JSON.stringify(j);
},
fromJson: function() {
let j = JSON.parse(document.querySelector('#wallet-json').value);
document.querySelectorAll('#wallet-table-body tr').forEach(function (row) {
let element = j.find(x => x.id == row.dataset.id);
if (element) {
row.querySelector('.em-input input').value = element.address;
}
});
},
cancel: function() {
document.querySelectorAll("#wallet-table-body .em-input input").forEach( function(x) {
x.value = x.dataset.original;
});
}
};
window.editConfig = {
save: function() {
let updateObject = getUpdateObject();
document.querySelectorAll("#modal-config [data-original][data-prop]").forEach(function(elm) {
let single = { prop: elm.dataset.prop, value: elm.dataset.value };
if(elm.dataset.original != elm.value && (elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") ) {
single.value = elm.value;
updateObject.config.items.push(single);
updateObject.config.changed = true;
} else if (elm.type == "checkbox" && ((elm.dataset.original == "0" && elm.checked) || (elm.dataset.original == "1" && !elm.checked)) ) {
single.value = elm.checked;
updateObject.config.items.push(single);
updateObject.config.changed = true;
}
});
if(updateObject.config.changed) {
document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
toastr["info"]("Config will be updated as soon as possible");
}
},
cancel: function() {
document.querySelectorAll("#modal-config [data-original][data-prop]").forEach(function(elm) {
if(elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") {
elm.value = elm.dataset.original;
} else if (elm.type == "checkbox") {
elm.checked = (elm.dataset.original == "1" ? true : false)
}
});
}
};
window.editSite = {
save: function() {
let updateObject = getUpdateObject();
let faucet = { id: document.querySelector("#faucet-name").dataset.id, items: [] };
document.querySelectorAll("#modal-site [data-original][data-site-prop]").forEach(function(elm) {
let single = { prop: elm.dataset.siteProp, value: elm.dataset.original };
if(elm.dataset.original != elm.value && (elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") ) {
single.value = elm.value;
faucet.items.push(single);
updateObject.site.changed = true;
} else if (elm.type == "checkbox" && ((elm.dataset.original == "0" && elm.checked) || (elm.dataset.original == "1" && !elm.checked)) ) {
single.value = elm.checked;
faucet.items.push(single);
updateObject.site.changed = true;
}
});
if(updateObject.site.changed) {
updateObject.site.list.push(faucet);
document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
toastr["info"]("Site will be updated as soon as possible");
}
},
cancel: function() {
document.querySelectorAll("#modal-site [data-original][data-site-prop]").forEach(function(elm) {
if(elm.type == "select-one" || elm.type == "text" || elm.type == "password" || elm.type == "number" || elm.type == "time") {
elm.value = elm.dataset.original;
} else if (elm.type == "checkbox") {
elm.checked = (elm.dataset.original == "1" ? true : false)
}
});
}
};
window.editEreport = {
save: function() {
sendErrorReport();
},
cancel: function() {
}
};
window.modalSave = function modalSave(content) {
switch(content) {
case "wallet":
editWallet.save();
break;
case "ereport":
editEreport.save();
break;
case "config":
editConfig.save();
break;
case "site":
editSite.save();
break;
case "slAlert":
shortlinkAlert.save();
break;
}
};
window.modalCancel = function modalCancel(content) {
if(content == "wallet") {
editWallet.cancel();
} else if ("ereport") {
editEreport.cancel();
}
document.querySelectorAll("modal-content").forEach(x => x.classList.add("d-none"));
};
window.updateValues = function updateValues(type, values) {
let updateObject = getUpdateObject();
if (type == "runAsap") {
updateObject.runAsap.ids.push(values.id);
updateObject.runAsap.changed = true;
document.getElementById("update-data").innerHTML = JSON.stringify(updateObject);
uiRenderer.toast("Faucet will be updated to run as soon as possible");
}
};
window.schedulesInterval = null;
window.startSchedulesInterval = function startSchedulesInterval(uuids) {
if (window.schedulesInterval) {
clearInterval(window.schedulesInterval);
}
let innerWaitTimes = '';
uuids.forEach(x => {
innerWaitTimes += `<span data-schedule="${x}" data-nextroll="UNDEFINED" class="mx-1"><i class="fas fa-square pr-1" style="color: #${x};"></i><span></span></span>`;
});
let container = document.querySelector('#wait-times');
container.innerHTML = innerWaitTimes;
window.schedulesInterval = setInterval(() => {
[...document.querySelectorAll('#wait-times > span')].forEach(sp => {
let nroll = sp.getAttribute('data-nextroll');
let spanScheduleId = sp.getAttribute('data-schedule');
if (nroll == 'UNDEFINED') {
sp.querySelector('span').innerText = '-';
} else if (nroll == 'RUNNING') {
sp.querySelector('span').innerText = 'Running';
let inUseElm = document.querySelector(`#schedule-table tr[data-schedule="${spanScheduleId}"]`);
if (inUseElm) {
inUseElm.classList.add('in-use');
}
} else {
let timeVal = +nroll - Date.now();
sp.querySelector('span').innerText = timeVal.msToCountdown();
if (timeVal < -60000) {
console.info(`Resync required: ${timeVal}`);
}
}
})
}, 1000);
}
window.confirmable = {
open: function (req, details = null, params = null) {
let btn = document.getElementById("confirm-req-btn");
btn.setAttribute('data-request', req);
btn.setAttribute('data-params', params ? JSON.stringify(params) : '{}');
if(details) {
document.querySelector("#confirmable-modal p").innerText = details;
}
return;
},
accept: function () {
let btn = document.getElementById("confirm-req-btn");
let req = { type: '', params: {}};
req.type = btn.getAttribute('data-request');
req.params = JSON.parse(btn.getAttribute('data-params'));
switch(req.type) {
case 'removeAllPromos':
window.removeAllPromos();
break;
case 'forceStopFaucet':
window.forceStopFaucet();
break;
default:
break;
}
}
}
window.removeAllPromos = function removeAllPromos() {
var promoCode = document.getElementById("promo-code-new");
var promoObject = { action: "REMOVEALLPROMOS" };
promoCode.innerHTML =JSON.stringify(promoObject);
toastr["info"]("Removing all promo codes... please wait");
};
window.forceStopFaucet = function forceStopFaucet() {
var promoCode = document.getElementById("promo-code-new");
var promoObject = { action: "FORCESTOPFAUCET" };
promoCode.innerHTML =JSON.stringify(promoObject);
toastr["info"]("Trying to stop... Please wait for reload");
};
window.openStatsChart = function openStatsChart() {
if(myBarChart) { myBarChart.destroy(); }
let statsFragment = document.getElementById("stats-fragment");
if (statsFragment.style.display === "block") { statsFragment.style.display = "none"; document.getElementById("stats-button").innerText = "Lucky Number Stats"; } else {
statsFragment.style.display = "block"; document.getElementById("stats-button").innerText = "Close Stats";
var canvas = document.getElementById("barChart");
var ctx = canvas.getContext("2d");
var dataSpan = document.getElementById("rolls-span");
var data = {
labels: ["0000-9885", "9886-9985", "9986-9993", "9994-9997", "9998-9999", "10000"],
datasets: [ { fill: false, backgroundColor: [ "#990000", "#660066", "#000099", "#ff8000", "#ffff00", "#00ff00"],
data: dataSpan.innerText.split(",") } ] };
var options = { plugins: { legend: { display: false } }, title: { display: true, text: "Rolled Numbers", position: "top" }, rotation: -0.3 * Math.PI };
myBarChart = new Chart(ctx, { type: "doughnut", data: data, options: options });
}
};
window.shortlinkAlert = {
load: function(id, destination) {
let hideShortlinkAlerts = localStorage.getItem("hideShortlinkAlerts");
hideShortlinkAlerts = hideShortlinkAlerts ? JSON.parse(hideShortlinkAlerts) : false;
if (hideShortlinkAlerts) {
} else {
document.getElementById(id).classList.remove("d-none");
}
},
save: function () {
localStorage.setItem("hideShortlinkAlerts", JSON.stringify(document.getElementById("hideShortlinkAlerts").checked));
window.open("https://example.com", "_blank");
}
}
}
};
let logLines = [];
function init(cfFaucets, schedules) {
appendJavaScript();
appendHtml(schedules);
updateSchedulesToggler();
appendEventListeners();
appendWidgets();
setupEventerListeners();
createPromoTable(cfFaucets);
try {
document.querySelector('.page-title h1').innerHTML = 'Auto Claim';
} catch (err) {}
};
function setupEventerListeners() {
eventer.on('siteUpdated', (site) => {
Site.sortAll(); // en todos los sites...
let schedule = Schedule.getById(site.schedule);
schedule.sortSites(); // solo en el schedule de este site
schedule.setCurrentSite(); // solo en el schedule de este site
Site.saveAll();
uiRenderer.sites.renderSiteRow(site); // solo la row de este site
uiRenderer.sites.sortSitesTable(); // y reordenar
schedule.checkNextRoll(); // solo en el schedule de este site
convertToFiat();
});
}
function appendWidgets() {
$('.tableSortable').sortable({
placeholder:'sort-highlight',
handle:'.row-handle',
cursor: 'grabbing',
axis: 'y',
stop: function(event, ui) {
$("tbody.ui-sortable tr").each(function(index) {
$(this).attr("data-order", index);
});
}
});
$('#promo-daily').bootstrapSwitch();
$('#bss-log').bootstrapSwitch({
onSwitchChange(event, state) {
$('#console-log').collapse('toggle');
},
onInit: function(event, state) {
this.$element.closest('.bootstrap-switch-container').find('.bootstrap-switch-handle-on').first().addClass('fa fa-eye').text('');
this.$element.closest('.bootstrap-switch-container').find('.bootstrap-switch-handle-off').first().addClass('fa fa-eye-slash').text('');
}
});
};
function updateSchedulesToggler() {
let container = document.querySelector('#schedules-toggler');
let html = '<label class="btn btn-outline-primary active" data-schedule="all"><input type="radio" name="options" autocomplete="off" checked="true"> All</label>';
Schedule.getAll().forEach(x => {
html += `<label class="btn btn-outline-primary" data-schedule="${x.uuid}">
<i class="fas fa-square pr-1" style="color: #${x.uuid};"></i>${x.name}
<input type="radio" name="options" autocomplete="off">
</label>`;
});
container.innerHTML = html;
startSchedulesInterval(Schedule.getAllForCrud().map(x => x.uuid));
uiRenderer.schedules.toggleSchedule('all');
};
function appendEventListeners() {
document.querySelector('.dropdown-settings-menu').addEventListener('click', function(e) {
let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
if (actionElement.dataset.target) {
e.stopPropagation();
uiRenderer.openModal(actionElement.dataset.target);
}
});
const modalSchedules = document.querySelector('#modal-schedules');
modalSchedules.addEventListener('click', function(e) {
let actionElement = e.target.tagName === 'I' ? e.target.parentElement : e.target;
if (actionElement.classList.contains('action-schedule-add')) {
e.stopPropagation();
let rows = modalSchedules.querySelectorAll('table tbody tr');
let rndColor = helpers.randomHexColor();
let rowTemplate = uiRenderer.schedules.renderRow({
uuid: rndColor,
name: rndColor,
order: rows.length,
added: true
});
$(modalSchedules.querySelector('table tbody tr:last-child')).after(rowTemplate);
uiRenderer.appendColorPickers('table tbody tr:last-child .color-picker');
} else if (actionElement.classList.contains('action-schedule-remove')) {
let rows = modalSchedules.querySelectorAll('table tbody tr:not(.d-none)');
if (rows.length <= 1) {
alert('You need to keep at least 1 schedule');
} else {
let current = actionElement.closest('tr');
if (current.dataset.added === 'true') {
current.remove();
} else {
current.dataset.removed = 'true';
current.classList.add('d-none');
}
}
} else if (actionElement.classList.contains('modal-save')) {
let data = uiRenderer.parseTable(modalSchedules.querySelector('table'));
let isValid = Schedule.crud(data);
updateSchedulesToggler();
manager.resyncAll({withUpdate: true});
if (!isValid) {
uiRenderer.toast('Some schedules might have errors/invalid colors', 'warning');
}
}
});
};
function appendJavaScript() {
addJS_Node (null, null, injectables.managerJs);
};
function addCardHtml(obj) {
return `<div class="card m-1"><div class="card-header">${obj.header}</div><div class="card-body px-4">${obj.body}</div></div>`;
};
function addRandomBetween(propSelect, propMin, propMax) {
return `<table><tr><td>
<select class="form-control" ${propSelect.name}="${propSelect.value}">
<option value="0">Random between...</option><option value="15">15 minutes</option><option value="30">30 minutes</option><option value="35">35 minutes</option><option value="45">45 minutes</option><option value="65">65 minutes</option><option value="90">90 minutes</option><option value="120">120 minutes</option>
</select></td>
<td><input type="number" data-original="" ${propMin.name}="${propMin.value}" min="1" value="15" step="5" class="form-control"></td><td>and</td><td><input type="number" data-original="" ${propMax.name}="${propMax.value}" value="65" step="5" class="form-control"></td><td>minutes</td></tr></table>`;
}
function appendHtml(schedules) {
let html ='';
let tgt = document.querySelector('div.row.py-3');
if (tgt) {
let rowDiv = document.createElement('div');
rowDiv.innerHTML = '<div class="row py-3 ac-log"><div class="col-12 justify-content-center"><div class="card"><div class="card-body" id="referral-table"></div></div></div></div>';
tgt.after(rowDiv);
}
html += '<div class="modal fade" id="confirmable-modal" tabindex="-1" role="dialog" aria-hidden="true">';
html += '<div class="modal-dialog modal-sm modal-dialog-centered"><div class="modal-content">';
html += '<div class="modal-header"><h4 class="modal-title">Are you sure?</h4><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div>';
html += '<div class="modal-body"><p></p></div>';
html += '<div class="modal-footer justify-content-between"><button type="button" class="btn btn-default" data-dismiss="modal">No</button>';
html += '<button type="button" class="btn btn-primary" data-dismiss="modal" id="confirm-req-btn" onclick="confirmable.accept()">Yes</button></div>';
html += '</div></div>';
html += '</div>';
html += '<div class="modal fade" id="modal-dlg" tabindex="-1" role="dialog" data-backdrop="static" aria-hidden="true">';
html += ' <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable" role="document">';
html += '<div class="modal-content bg-beige" id="modal-spinner"><div class="modal-body"><div class="d-flex justify-content-center"><span id="target-spinner" class="d-none"></span><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>Loading data</div></div></div>';
html += ' <div class="modal-content bg-beige d-none" id="modal-ereport">';
html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-history"></i> Submit an Error</h5></div>';
html += ' <div class="modal-body">';
html += ' <div class="alert alert-danger">Don\'t send private information as data might be publicly access.</div>';
html += ' <textarea rows="4" id="log-message" class="form-control" placeholder="PLEASE do not send logs without describing here the issue you are facing..."></textarea>';
html += ' <label for="log-textarea">Log</label>';
html += ' <textarea rows="10" id="log-textarea" class="form-control"></textarea>';
html += ' </div>';
html += ' <div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'ereport\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += ' <a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'ereport\')" data-dismiss="modal"><i class="fa fa-paper-plane"></i> Send</a></div>';
html += ' </div>';
html += ' <div class="modal-content bg-beige d-none" id="modal-wallet">';
html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-wallet"></i> Your Addresses</h5></div>';
html += ' <div class="modal-body">';
html += ' <div><table class="table custom-table-striped" id="wallet-table">';
html += ' <thead><tr><th class="">Name</th><th class="">Address</th></tr></thead>';
html += ' <tbody class="overflow-auto" id="wallet-table-body"></tbody></table><textarea rows="14" id="wallet-json" class="d-none w-100"></textarea>';
html += ' </div>';
html += ' </div>';
html += '<div class="modal-footer">';
html += '<div class="footer-json d-none">';
html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="editWallet.toggleJson(\'cancel\')"><i class="fa fa-times-circle"></i> Cancel</a>';
html += '<a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editWallet.toggleJson()"><i class="fa fa-edit"></i> Confirm</a></div>';
html += '<div class="footer-table"><a class="btn m-2 anchor btn-outline-primary align-middle" onclick="editWallet.toggleJson()"><i class="fa fa-edit"></i> Edit as JSON</a>';
html += '<a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'wallet\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'wallet\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div></div>';
html += ' </div>';
html += ' <div class="modal-content bg-beige d-none" id="modal-info">';
html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-info"></i> Info</h5></div>';
html += ' <div class="modal-body">';
html += '<ul>';
html += '<li>First of all, make sure you visit our <a href="https://discord.gg/gaYYBjJUhP" target="_blank">discord</a> server for specific issues with the script. Unfortunately, our original server and user account was disabled after +2 years. We are trying to bring the community together in a new one now.</li>';
html += `<li>The script comes with <b>2 schedules</b> (Default and CF). You can add more from <i>Settings > Schedules...</i><br>About the <i>Schedules</i>:`;
html += `<ul><li>Each schedule will open a new tab, so:<br>N schedules = N simultaneous tabs.</li>`;
html += `<li>Each schedule has it's own list of sites.<br>You can have N sites per schedule, but each site can be in just 1 schedule to avoid overlapping.</li>`;
html += `<li>We suggest you to test how many tabs you can run simultaneously before creating too many schedules.<br>Usually, with 4 or 5 it will run smoothly.</li></ul>`;
html += `</li>`;
html += '<li>Almost all sites in the list require an external hCaptcha solver or similar scripts/extensions. You can find our free suggestions in Settings > Other requirements...</li>';
html += '<li>Stormgain requires a GeeTest solver. You can use <a href="https://greasyfork.org/en/scripts/444560" target="_blank">this script</a> to solve the captchas through 2Captcha API service.</li>';
html += `<li>Some sites pay directly to <a href="https://faucetpay.io/?r=freebtc" target="_blank"><i class="fa fa-external-link-alt"></i> FaucetPay</a>. You need to add your FP addresses at <i>Settings > Wallet...</i> to claim from those sites.</li>`;
html += `<li>You can set default configurations at <i>Settings > Defaults...</i></li>`;
html += `<li>At <i>Settings > Defaults</i>, you will also find <i>Site Specific</i> settings like credentials for auto login.</li>`;
html += '<li>You can override configurations for a specific site using the edit (<i class="fa fa-clock"></i>) buttons</li>';
html += '<li>When enabling a new site, try it first with the tab on focus, to detect potential issues</li>';
html += '</ul>';
html += ' </div>';
html += '<div class="modal-footer">';
html += '<a class="btn m-2 anchor btn-outline-warning align-middle" data-dismiss="modal"><i class="fa fa-edit"></i> Close</a></div>';
html += ' </div>';
html += '<div class="modal-content bg-beige" id="modal-schedules">';
html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-stopwatch"></i> Schedules</h5>';
html += ' <div class="ml-auto"><button type="button" class="btn btn-default btn-sm action-schedule-add">';
html += ' <i class="fa fa-plus"></i> Add Schedule';
html += ' </button></div>';
html += ' </div>';
html += ' <div class="modal-body">';
html += '<div class="callout callout-warning m-0"><p class="text-justify">Each schedule opens sites in a new/different tab.<br>Colors must be unique.</p></div>';
html += ' <table class="table">';
html += ' <thead>';
html += ' <tr><th></th><th class="text-center" width="35%">Color</th><th class="text-center">Name</th><th></th></tr>';
html += ' </thead>';
html += ' <tbody class="tableSortable">';
html += ' </tbody>';
html += ' </table>';
html += ' </div>';
html += ' <div class="modal-footer">';
html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
html += ' </div>';
html += '</div>';
html += '<div class="modal-content bg-beige" id="modal-assign-schedule">';
html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-exchange-alt"></i> Move to...</h5>';
html += ' </div>';
html += ' <div class="modal-body">';
html += ' <div class="form-container">';
html += ' <input type="hidden" name="site_id" value="not_set">';
html += ' <input type="hidden" name="original_schedule_id" value="not_set">';
html += ' <label class="control-label">Schedule</label>';
html += ' <select class="form-control" name="schedule">';
html += ' </select>';
html += ' </div>';
html += ' </div>';
html += ' <div class="modal-footer">';
html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
html += ' </div>';
html += '</div>';
html += '<div class="modal-content bg-beige" id="modal-add-site">';
html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-code"></i> Add Site...</h5>';
html += ' </div>';
html += ' <div class="modal-body">';
html += ' <div class="form-container">';
html += uiRenderer.addInputTextHtml({ required: true, name: 'site_name', value: '', text: 'Display name'});
html += uiRenderer.addInputTextHtml({ required: true, name: 'site_url', value: '', text: 'Url to open', placeholder: 'Example: https://freebitcoin.io/free' });
html += ' <label class="control-label">Schedule</label>';
html += ' <select class="form-control" name="schedule">';
html += ' </select>';
html += ' </div>';
html += ' </div>';
html += ' <div class="modal-footer">';
html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += ' <a class="btn m-2 anchor btn-outline-success align-middle modal-save" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a>';
html += ' </div>';
html += '</div>';
html += '<div class="modal-content bg-beige" id="modal-site-parameters">';
html += ' <div class="modal-header py-2"><h5 class="modal-title"><i class="fa fa-edit"></i> Edit Site Arguments...</h5>';
html += ' </div>';
html += ' <div class="modal-body">';
html += ' <div class="form-container"><form action="">';
html += ` <div>Soon you'll be able to edit the site's specific settings here (credentials, withdrawal configuration, etc.)<br>`;
html += `You'll also see the site specific requirements, like required captcha solvers.<br>Meanwhile, go to Settings > Defaults > Site Specifics.<br>If there's something to configurate for this site, it'll be listed there.`;
html += `<br>You can find a general requirements list in Settings > Other requirements...</div>`;
html += ' </form></div>';
html += ' </div>';
html += ' <div class="modal-footer">';
html += ' <a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Close</a>';
html += ' </div>';
html += '</div>';
html += ' <div class="modal-content bg-beige d-none" id="modal-slAlert">';
html += ' <div class="modal-header"><h5 class="modal-title">Attention</h5></div>';
html += ' <div class="modal-body">';
html += ' <div class="alert alert-warning">You will be redirected to a shortlink, and after completing it the new Twitter Daily Promo Code will be added to your table.<br>';
html += 'This is an optional contribution. You can still get the code the old fashion way.</div>';
html += uiRenderer.addLegacySliderHtml('id', 'hideShortlinkAlerts', `Stop warning me before a shortlink`);
html += ' </div>';
html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'slAlert\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'slAlert\')" data-dismiss="modal"><i class="fa fa-external-link-alt"></i> Lets Go!</a></div>';
html += ' </div>';
html += ' <div class="modal-content bg-beige d-none" id="modal-site">';
html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-clock"></i> <span id="faucet-name" data-id=""></span> Schedule Parameters</h5></div>';
html += ' <div class="modal-body">';
html += ' <div class="alert alert-warning">Override Settings for the selected faucet.<br>Faucet-specific configurations will be moved here soon.</div>';
html += ' <div class="row">';
html += ' <div class="col-md-12 col-sm-12">';
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.workInBackground.override', 'Override Work Mode'),
body: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.workInBackground', 'Open tab in background')
});
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.nextRun.override', 'Override Next Run'),
body: `<div>${uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.nextRun.useCountdown', 'Use faucet countdown when possible')}</div>` +
`<label class="control-label">Otherwise wait:</label>` +
addRandomBetween({ name: 'data-site-prop', value: 'defaults.nextRun' }, { name: 'data-site-prop', value: 'defaults.nextRun.min' }, { name: 'data-site-prop', value: 'defaults.nextRun.max' })
});
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.sleepMode.override', 'Override Sleep Mode'),
body: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.sleepMode', 'Sleep mode') +
`<table><tr><td>Don't claim between </td><td><input type="time" data-original="" data-site-prop="defaults.sleepMode.min" class="form-control"></td><td>and</td>
<td><input type="time" data-original="" data-site-prop="defaults.sleepMode.max" class="form-control"></td></tr></table>`
});
html += ' <div class="card m-1"><div class="card-header">Timeout</div>';
html += ' <div class="card-body px-4">';
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.timeout.override', 'Override Timeout'),
body: `<table><tr><td>After</td><td><input type="number" data-original="" data-site-prop="defaults.timeout" min="2" value="5" step="1" class="form-control"></td><td>minutes</td></tr></table>`
});
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-site-prop', 'defaults.postponeMinutes.override', 'Override Postpone'),
body: `<label class="control-label">After timeout/error, postpone for:</label>` +
addRandomBetween({ name: 'data-site-prop', value: 'defaults.postponeMinutes' }, { name: 'data-site-prop', value: 'defaults.postponeMinutes.min' }, { name: 'data-site-prop', value: 'defaults.postponeMinutes.max' })
});
html += ' </div>';
html += ' </div>';
html += ' </div>';
html += ' </div>';
html += ' </div>';
html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'site\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'site\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div>';
html += ' </div>';
html += '<div class="modal-content bg-beige d-none" id="modal-config">';
html += ' <div class="modal-header"><h5 class="modal-title"><i class="fa fa-cog"></i> Settings</h5></div>';
html += ' <div class="modal-body">';
html += ' <div class="row">';
html += ' <div class="col-md-12 col-sm-12">';
html += ' <div class="card card-info m-1"><div class="card-header">Defaults<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div></div>';
html += ' <div class="card-body px-4">';
html += `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.workInBackground', 'Open tabs in background')}</div>`;
html += `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.extraInterval', 'Use extra timer to detect ad redirects faster')}</div>`;
html += addCardHtml({
header: 'Next Run',
body: `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'defaults.nextRun.useCountdown', 'Use faucet countdown when possible')}</div>` +
`<label class="control-label">Otherwise wait:</label>` +
addRandomBetween({ name: 'data-prop', value: 'defaults.nextRun' }, { name: 'data-prop', value: 'defaults.nextRun.min' }, { name: 'data-prop', value: 'defaults.nextRun.max' })
});
html += addCardHtml({
header: 'Timeout',
body: `<table><tr><td>After</td><td><input type="number" data-original="" data-prop="defaults.timeout" min="2" value="5" step="1" class="form-control"></td><td>minutes</td></tr></table>` +
`<label class="control-label">After timeout/error, postpone for:</label>` +
addRandomBetween({ name: 'data-prop', value: 'defaults.postponeMinutes' }, { name: 'data-prop', value: 'defaults.postponeMinutes.min' }, { name: 'data-prop', value: 'defaults.postponeMinutes.max' })
});
html += addCardHtml({
header: 'Logging',
body: `<div>${uiRenderer.addLegacySliderHtml('data-prop', 'devlog.enabled', 'Store log (enables the \'Log\' button)')}</div>` +
`<table><tr><td>Max log size in lines:</td><td><input type="number" data-original="" data-prop="devlog.maxLines" min="100" step="100" class="form-control"></td></tr></table>`
});
html += addCardHtml({
header: uiRenderer.addLegacySliderHtml('data-prop', 'defaults.sleepMode', 'Sleep mode'),
body: `<table><tr><td>Don't claim between </td><td><input type="time" data-original="" data-prop="defaults.sleepMode.min" class="form-control"></td><td>and</td>
<td><input type="time" data-original="" data-prop="defaults.sleepMode.max" class="form-control"></td></tr></table>`
});
html += ' </div></div>';
html += ' </div>';
html += ' <div class="col-md-12 col-sm-12">';
html += ' <div class="card card-info m-1"><div class="card-header">Site Specifics<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div></div>';
html += ' <div class="card-body px-4">';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">CryptosFaucets<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.rollOnce" ><span class="slider round"></span></label> Roll once per round </div>';
html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.usePromoCodes" ><span class="slider round"></span></label> Try to use promo codes every day (disable it if you are facing too many captcha timeouts) </div>';
html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.tryGetCodes" ><span class="slider round"></span></label> Auto update promo codes </div>';
html += ' <div><label class="switch"><input type="checkbox" data-prop="cf.autologin" ><span class="slider round"></span></label> Autologin when necessary</div>';
html += ' <select class="form-control" data-prop="cf.credentials.mode">';
html += ' <option value="1">Use Email and Password</option><option value="2">Filled by 3rd party software/extension</option>';
html += ' </select>';
html += ' <label class="control-label">E-Mail</label>';
html += ' <input maxlength="200" type="text" data-prop="cf.credentials.email" required="required" class="form-control" placeholder="Email address..."/>';
html += ' <label class="control-label">Password</label>';
html += ' <input maxlength="200" type="password" data-prop="cf.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
html += ' <label class="control-label">Hours to wait If IP is banned:</label>';
html += ' <select class="form-control" data-prop="cf.sleepHoursIfIpBan">';
html += ' <option value="0">Disabled</option><option value="2">2</option><option value="4">4</option><option value="8">8</option><option value="16">16</option><option value="24">24</option><option value="26">26</option>';
html += ' </select>';
html += ' </div></div>';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">JTFey<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <label class="control-label">Login Mode</label>';
html += ' <select class="form-control" data-prop="jtfey.credentials.mode">';
html += ' <option value="1">Use Username and Password</option><option value="2">Filled by 3rd party software/extension</option>';
html += ' </select>';
html += ' <label class="control-label">E-Mail</label>';
html += ' <input maxlength="200" type="text" data-prop="jtfey.credentials.username" required="required" class="form-control" placeholder="Email address..."/>';
html += ' <label class="control-label">Password</label>';
html += ' <input maxlength="200" type="password" data-prop="jtfey.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
html += ' </div></div>';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">FaucetPay PTC<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <div><label class="switch"><input type="checkbox" data-prop="fp.randomPtcOrder" ><span class="slider round"></span></label> Random PTC order </div>';
html += ' <label class="control-label">Max duration per run:</label>';
html += ' <select class="form-control" data-prop="fp.maxTimeInMinutes">';
html += ' <option value="5">5 minutes</option><option value="10">10 minutes</option><option value="15">15 minutes</option><option value="30">30 minutes</option>';
html += ' </select>';
html += ' </div></div>';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">Dutchy<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <div><label class="switch"><input type="checkbox" data-prop="dutchy.useBoosted" ><span class="slider round"></span></label> Try boosted roll </div>';
html += ' </div></div>';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">BestChange<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <label class="control-label">BTC Address:</label>';
html += ' <select class="form-control" data-prop="bestchange.address">';
html += ' <option value="101">Faucet Pay BTC</option><option value="1">BTC Alt Address</option>';
html += ' </select>';
html += ' </div></div>';
html += ' <div class="card m-1 collapsed-card"><div class="card-header">Yes Coiner<div class="card-tools"><button type="button" class="btn btn-white btn-sm" data-card-widget="collapse" title="Collapse"><i class="fas fa-plus"></i></button></div></div>';
html += ' <div class="card-body px-4" style="display: none;">';
html += ' <label class="control-label">Login Mode</label>';
html += ' <select class="form-control" data-prop="ycoin.credentials.mode">';
html += ' <option value="1">Use Username and Password</option><option value="2">Filled by 3rd party software/extension</option>';
html += ' </select>';
html += ' <label class="control-label">E-Mail</label>';
html += ' <input maxlength="200" type="text" data-prop="ycoin.credentials.username" required="required" class="form-control" placeholder="Account number..."/>';
html += ' <label class="control-label">Password</label>';
html += ' <input maxlength="200" type="password" data-prop="ycoin.credentials.password" required="required" class="form-control" placeholder="Password..."/>';
html += ' </div></div>';
html += ' </div></div>';
html += ' </div>';
html += ' </div>';
html += '</div>';
html += '<div class="modal-footer"><a class="btn m-2 anchor btn-outline-danger align-middle" onclick="modalCancel(\'config\')" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</a>';
html += '<a class="btn m-2 anchor btn-outline-success align-middle" onclick="modalSave(\'config\')" data-dismiss="modal"><i class="fa fa-check-circle"></i> Save</a></div>';
html += ' </div>';
html += '</div>';
html += '</div>';
html += '<section id="table-struct" class="fragment "><div class="container-fluid "><div class="py-1 "><div class="row mx-0 justify-content-center">';
html += '<a class="btn m-2 anchor btn-outline-danger align-middle" data-toggle="modal" data-target="#confirmable-modal" onclick="confirmable.open(\'forceStopFaucet\', \'Running faucet will be disabled and the manager will reload.\')"><i class="fa fa-stop-circle"></i>Force Stop</a>';
html += '</div>';
html += '<div class="card">';
html += '<div class="card-header">';
html += '<div class="d-flex p-0">';
html += '<div id="schedules-toggler" class="btn-group btn-group-toggle" data-toggle="buttons">';
html += '</div>';
html += '<div class="card-tools ml-auto mt-2 mr-1">';
html += '<input type="checkbox" data-toggle="switch" data-label-text="Log" title="Show/Hide Log" id="bss-log" checked>';
html += `<button type="button" class="btn btn-flat btn-sm btn-outline-primary mx-1 dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-cog"></i> Settings</button>
<div class="dropdown-menu text-sm dropdown-settings-menu" style="">
<a class="dropdown-item btn-open-dialog" data-target="modal-config"><i class="fa fa-cog"></i> Defaults...</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item btn-open-dialog" data-target="modal-schedules"><i class="fa fa-stopwatch"></i> Schedules...</a>
<a class="dropdown-item btn-open-dialog" data-target="modal-wallet"><i class="fa fa-wallet"></i> Wallets...</a>
<a class="dropdown-item btn-open-dialog" data-target="modal-requirements"><i class="fa fa-exclamation-circle"></i> Other requirements...</a>
<!-- <a class="dropdown-item btn-open-dialog" data-target="modal-sites"><i class="fa fa-window-restore"></i> Sites...</a> -->
<div class="dropdown-divider"></div>
<a class="dropdown-item btn-open-dialog" data-target="modal-info"><i class="fa fa-info"></i> Help/Info...</a>
</div>`;
html += '<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>';
html += '<button type="button" class="btn btn-tool mx-1" data-card-widget="maximize"><i class="fas fa-expand"></i></button>';
html += '</div></div>';
html += '<div id="wait-times" class="row mx-0 p-0 justify-content-center"></div>';
html += '</div>';
html += '<div class="card-body table-responsive p-0" style="height: 400px;" id="schedule-container">';
html += '<pre class="collapse show" id="console-log"><b>Loading...</b></pre>';
html += '</div>';
html += '</div>';
html += '</div>';
html += '<span id="update-data" style="display:none;"></span></section>';
html += '<section id="table-struct-promo" class="fragment "><div class="container-fluid "><div class="py-1 ">';
html += '<div class="card"><div class="card-header"><h3 class="card-title font-weight-bold">Promo Codes</h3><span id="promo-code-new" style="display:none;"></span>';
html += '<div class="card-tools">';
html += '<div class="input-group input-group-sm btn-tool">';
html += '<input id="promo-text-input" type="text" name="table_search" class="form-control float-right" placeholder="CF Promo Code..." style="width:130px;">';
html += '<input type="checkbox" data-toggle="switch" title="Check if the code can be reused every 24hs" id="promo-daily" data-on-text="Daily" data-off-text="1 Time">';
html += '<div class="input-group-append"><button type="submit" class="btn btn-default" id="promo-button""><i class="fas fa-plus"></i> Add</button></div>';
html += '<div class="input-group-append"><button type="submit" class="btn btn-default btn-outline-danger mx-1" data-toggle="modal" data-target="#confirmable-modal" onclick="confirmable.open(\'removeAllPromos\', \'All promo codes will be removed.\')"><i class="fas fa-times-circle"></i> Remove All</button></div>';
html += '<div class="input-group-append"><button type="submit" class="btn btn-default btn-outline-primary" id="button-try-get-codes"><i class="fas fa-bolt"></i> Try to Get Codes</button></div>';
html += '<div class="input-group-append"><button type="button" class="btn btn-tool btn-sm mx-1" data-card-widget="collapse" title="Collapse"><i class="fas fa-minus"></i></button></div>';
html += '<div class="input-group-append"><button type="button" class="btn btn-tool btn-sm mx-1" data-card-widget="maximize" title="Maximize"><i class="fas fa-expand"></i></button></div>';
html += '</div>';
html += '</div>';
html += '</div>';
html += '<div class="card-body table-responsive p-0" id="promo-container">';
html += '</div></div>';
html +='</div></div></section>';
html += '<section class="fragment"><div class="container-fluid ">';
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="py-1" id="stats-fragment" style="display:none;"><div class="row align-items-center text-center justify-content-center">';
html += '<div class="col-md-12 col-lg-8"><canvas id="barChart"></canvas><span id="rolls-span" style="display:none;"></span></div></div></div></div></div></section>';
let wrapper = document.createElement('div');
wrapper.innerHTML = html.trim();
let target = document.getElementById('referral-table');
target.parentNode.insertBefore(wrapper, target);
document.getElementById('schedule-container').appendChild( createScheduleTable() );
if (document.querySelector('.main-header .navbar-nav.ml-auto')) {
let discord = document.createElement('li');
discord.classList.add('nav-item');
discord.innerHTML = '<a class="btn btn-primary btn-sm m-1" href="https://discord.gg/gaYYBjJUhP" target="_blank"><div class=""><span class="badge badge-pill badge-warning mr-2" title="">(new)</span>discord</div></a>';
document.querySelector('.main-header .navbar-nav.ml-auto').prepend(discord);
} else {
let discord = document.createElement('div');
discord.innerHTML = '<a class="btn m-2 btn-primary" href="https://discord.gg/gaYYBjJUhP" target="_blank"><div class=""><span class="badge badge-pill badge-warning mr-2" title="">(new)</span>discord</div></a>';
document.querySelector('.navbar-nav').prepend(discord);
}
addHtml({
target: '#modal-dlg .modal-dialog',
where: 'afterbegin',
content: `<div class="modal-content bg-beige d-none" id="modal-requirements">
<div class="modal-header"><h5 class="modal-title"><i class="fa fa-exclamation-circle"></i> Other requirements</h5></div>
<div class="modal-body">
<div class="callout callout-warning m-3">
<p class="text-justify">Some sites might require specific tools like captcha solvers that are not including in the script.</p>
</div>
<div>
<table class="table custom-table-striped" id="requirements-table">
<thead><tr><th class="">Name</th><th class="">Description</th><th class="">Suggestion</th></tr></thead>
<tbody class="overflow-auto" id="requirements-table-body">
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<a class="btn m-2 anchor btn-outline-danger align-middle" data-dismiss="modal"><i class="fa fa-times-circle"></i> Close</a>
</div>
</div>`
});
addTemplateTag({
id: 'tpl-requirement-row',
content: `<tr><td>{name}</td><td>{description}</td><td>{suggestion}</td></tr>`
});
const tempRequirementsList = [
{ id: '1', name: 'HCaptcha Solver', description: 'A solver for HCaptcha challenges', suggestion: `Latest github version of hektCaptcha extension (free)<br><a href="https://bit.ly/3Y24vg5" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
{ id: '2', name: 'Recaptcha Solver', description: 'A solver for ReCaptcha challenges', suggestion: `Latest github version of hektCaptcha extension (free)<br><a href="https://bit.ly/3Y24vg5" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
{ id: '3', name: 'Cloudflare Challenge Bypass', description: 'A solver for Cloudflare/Turnstile challenges', suggestion: `Auto clicker user script (free)<br><a href="https://sharetext.me/knpmyolewq" target="_blank"><i class="fa fa-external-link-alt"></i> Visit</a>` },
{ id: '6', name: 'Active Tab/Window', description: 'The site requires the tab to be active. A good option is Tab Revolver Extension, which will loop the tabs opened in a specific window.', suggestion: `<a href="https://bit.ly/3Y28lpA" target="_blank"><i class="fa fa-external-link-alt"></i> User Script</a> or <a href="https://bit.ly/3q0H4Ht" target="_blank"><i class="fa fa-external-link-alt"></i> Extension</a>` },
];
for(let r=0; r< tempRequirementsList.length; r++) {
let req = tempRequirementsList[r];
useTemplate({
templateId: 'tpl-requirement-row',
target: '#requirements-table-body',
where: 'afterbegin',
replacements: req
});
}
};
function createPromoTable(faucets) {
let table = document.createElement('table');
let inner = '';
table.classList.add('table', 'custom-table-striped');
table.setAttribute('id','promo-table');
inner += '<caption style="text-align: -webkit-center;">⏳ Pending ✔️ Accepted 🕙 Used Before ❌ Invalid code ❗ Unknown error ⚪ No code</caption>';
inner += '<thead><tr><th class="">Code</th><th class="">Added</th>';
for (let i = 0, all = faucets.length; i < all; i++) {
inner += '<th data-faucet-id="' + faucets[i].id + '">' + faucets[i].name + '</th>';
}
inner += '</tr></thead><tbody id="promo-table-body"></tbody></table>';
table.innerHTML = inner
document.getElementById('promo-container').appendChild( table );
};
function createScheduleTable() {
let table = document.createElement('table');
let inner;
table.classList.add('table', 'custom-table-striped', 'table-head-fixed', 'text-nowrap');
table.setAttribute('id','schedule-table');
inner = '<thead><tr>';
inner += '<th scope="col" class="edit-status d-none em-only" style="">Active</th><th class="">Next Roll</th><th class=""></th><th class="">Name</th><th class="text-center">Last Claim</th>';
inner += '<th class="text-center">Aggregate</th><th class="text-center">Balance</th><th class="text-center em-hide" id="converted-balance-col">FIAT</th>';
inner += '<th scope="col" class="text-center em-hide">Msgs</th>';
inner += '<th scope="col" class="" style="">';
inner += `<div class="btn-group btn-group-sm">
<button type="button" data-toggle="tooltip" title="Add site..." class="btn btn-default action-add-external-site em-hide">
<i class="fa fa-plus"></i>
</button>
<button type="button" title="Cancel" class="btn btn-danger action-edit-all-sites-cancel em-only d-none"><i class="fa fa-times-circle"></i> Cancel</button>
<button type="button" title="Save" class="btn btn-success action-edit-all-sites-save em-only d-none"><i class="fa fa-check-circle"></i> Save</button>
<button type="button" data-toggle="tooltip" title="Edit all..." class="btn btn-default action-edit-all-sites em-hide"><i class="fa fa-toggle-off"></i></button>
</div>`;
inner += '</th></tr></thead><tbody id="schedule-table-body"></tbody>';
table.innerHTML = inner;
return table;
};
function renderLogRow(data) {
let tr = document.createElement('tr');
tr.dataset.schedule = data.schedule;
tr.dataset.ts = data.ts.getTime();
tr.dataset.siteName = data.siteName || '';
tr.dataset.elapsed = data.elapsed || '';
let color = data.schedule ? `#${data.schedule}` : `transparent`;
let showIt = !data.schedule || !uiRenderer.schedules.selectedSchedule
|| uiRenderer.schedules.selectedSchedule == 'all' || uiRenderer.schedules.selectedSchedule == data.schedule;
if (!showIt) {
tr.classList.add('d-none');
}
let tds = '';
tds += `<td>${helpers.getPrintableTime(data.ts)}</td>`;
tds += `<td><i class="fas fa-square pr-1" style="color: ${color};"></i></td>`;
if (data.elapsed) {
tds += `<td>${data.msg} [Elapsed time: ${data.elapsed} seconds]</td>`;
} else {
tds += `<td>${data.msg}</td>`;
}
tr.innerHTML = tds;
document.querySelector('#console-log table').appendChild(tr);
};
function log(data) {
if (!data || !data.msg) {
console.warn(`Log attempt without data or msg!`, data);
return;
}
data.ts = new Date();
data.schedule = data.schedule || false;
data.siteName = data.siteName || false;
data.elapsed = data.elapsed || false;
if(shared.getConfig()['devlog.enabled']) {
if (data.schedule) {
} else {
}
};
if (data.elapsed) {
let previous = logLines.find(x => x.msg == data.msg && x.schedule == data.schedule);
if (previous) {
previous.elapsed = data.elapsed;
previous.ts = data.ts;
logLines.sort( (a, b) => b.ts.getTime() - a.ts.getTime());
} else {
logLines.unshift(data);
}
} else {
logLines.unshift(data);
}
while(logLines.length > 30) {
logLines.pop();
}
document.querySelector('#console-log table').innerHTML = '';
logLines.forEach(r => renderLogRow(r));
};
function legacyLog(data, elapsed = false) {
if (!data || !data.msg) {
return;
}
elapsed = data.elapsed || false;
let msg = data.msg;
if (data.schedule) {
msg = `[${data.schedule}] ${data.msg}`;
}
if(shared.getConfig()['devlog.enabled']) { shared.devlog(msg, elapsed) };
if(msg) {
let waitingIdx = logLines.findIndex(line => {
let waitingMsg= line.split(' ')[1];
if (waitingMsg == msg) {
return true;
}
});
let previous = waitingIdx > -1 ? logLines[waitingIdx].split(' ')[1] : '';
if (elapsed && (previous == msg)) {
logLines[waitingIdx] = helpers.getPrintableTime() + ' ' + msg + ' [Elapsed time: ' + elapsed + ' seconds]';
} else {
while(logLines.length > 20) {
logLines.pop();
}
logLines.unshift(helpers.getPrintableTime() + ' ' + msg);
}
document.getElementById('console-log').innerHTML = logLines.map(x => {
const regex = /\[([0-9a-fA-F]+)\]/;
const match = regex.exec(x);
let colorNumber = null;
if (match !== null) {
colorNumber = match[1];
}
let showIt = !colorNumber || !window.selectedSchedule || window.selectedSchedule == 'all' || window.selectedSchedule == colorNumber;
const formattedMsg = x.replace(/\[([0-9a-fA-F]+)\]/, '<i class="fas fa-square pr-1" style="color: #$1;"></i>');
let line = `<span data-schedule="${colorNumber ? colorNumber : ''}" class="${showIt ? '' : 'd-none'}">${formattedMsg}</span>`;
return line;
}).join('');
}
};
return {
init: init,
log: log
}
}
async function init() {
eventer = new EventEmitter();
persistence = new Persistence();
shared = objectGenerator.createShared();
useTimer = shared.getConfig()['defaults.extraInterval'];
if (location.href.startsWith('https://criptologico.com/tools/cc')) {
landing = window.location.host;
instance = K.LOCATION.MANAGER;
manager = createManager();
CFPromotions = objectGenerator.createCFPromotions();
uiRenderer = new UiRenderer();
uiRenderer.initialize();
ui = createUi();
CFHistory = objectGenerator.createCFHistory();
await manager.start();
try {
if (!document.body.classList.contains('sidebar-collapse')) document.querySelector('a[data-widget="pushmenu"]').click()
} catch {}
setTimeout( () => { window.stop(); }, 10000);
} else {
instance = K.LOCATION.UNKNOWN;
detectWeb();
}
}
init();
})();