Ensures you are the winning bidder if you want to be.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

404 lines
18 KiB

// ==UserScript==
// @name AlwaysWin-ntsmhf
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Make sure you are positioned where you want to be in the bidding for each county.
// @author Steven Allen
// @match https://leads.needtosellmyhousefast.com/*
// @require https://code.jquery.com/jquery-3.7.1.min.js
// @require http://crypto.stanford.edu/sjcl/sjcl.js
// @icon https://www.google.com/s2/favicons?sz=64&domain=needtosellmyhousefast.com
// @grant none
// ==/UserScript==
'use strict';
//Load our settings
//localStorage.removeItem('alwayswin_settings');
console.log("Loading settings");
var alwaysWinSettingsString = localStorage.getItem('alwayswin_settings');
//console.log(alwaysWinSettingsString);
if(alwaysWinSettingsString == null || alwaysWinSettingsString == undefined) {
const defaultSettings = {"isReloadEnabled":true, "isAutoLoginEnabled":false, "minSecondsBetweenReloads": 60, "maxSecondsBetweenReloads":300};
const defaultSettingsString = JSON.stringify(defaultSettings);
localStorage.setItem('alwayswin_settings',defaultSettingsString);
alwaysWinSettingsString = defaultSettingsString;
}
var alwaysWinSettings = JSON.parse(alwaysWinSettingsString);
//console.log(alwaysWinSettings);
////////////
// Div injection and auto reload functions
////////////
function getRandomNumberBetween(min, max) {
min = Number(min);
max = Number(max);
return Math.floor(Math.random() * (max - min) + min);
}
function getCheckedValue(fieldName) {
switch (fieldName) {
case "isReloadEnabled":
return reloadIsEnabled() ? "checked": "";
case "isAutoLoginEnabled":
return autoLoginIsEnabled() ? "checked": "";
default:
return "";
}
return "";
}
function addAlwaysWinStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
function handleSaveSettings() {
saveSettings();
location.reload();
}
function saveSettings() {
let isReloadEnabledValue = document.querySelector("[name='isReloadEnabled']").checked;
let isAutoLoginEnabledValue = document.querySelector("[name='isAutoLoginEnabled']").checked;
let minSecondsBetweenReloadsValue = document.querySelector("[name='minSecondsBetweenReloads']").value;
let maxSecondsBetweenReloadsValue = document.querySelector("[name='maxSecondsBetweenReloads']").value;
let bidCap = document.querySelector("[name='bidCap']").value;
var latestSettings = alwaysWinSettings;
latestSettings.isReloadEnabled = isReloadEnabledValue;
latestSettings.isAutoLoginEnabled = isAutoLoginEnabledValue;
latestSettings.minSecondsBetweenReloads = minSecondsBetweenReloadsValue;
latestSettings.maxSecondsBetweenReloads = maxSecondsBetweenReloadsValue;
latestSettings.bidCap = bidCap;
//console.log("latestSettings");
//console.log(latestSettings);
const latestSettingsString = JSON.stringify(latestSettings);
localStorage.setItem('alwayswin_settings',latestSettingsString);
alwaysWinSettingsString = latestSettings;
return latestSettings;
}
function saveCountyInfoStats(newStats) {
let existingStats = [];
//get existing stats if they exist
let existingStatsString = localStorage.getItem('alwayswin_stats');
if(existingStatsString != null && existingStatsString !== undefined) {
existingStats = JSON.parse(existingStatsString);
}
const combinedStats = existingStats.concat(newStats)
const updatedStatsString = JSON.stringify(combinedStats);
localStorage.setItem('alwayswin_stats',updatedStatsString);
//console.log(combinedStats);
}
function reload() {
console.log("Saving settings...");
let alwaysWinSettings = saveSettings();
awLog("Its time to perform a reload.");
awLog("isEnabled: "+ alwaysWinSettings.isReloadEnabled);
awLog("secondsBetweenReloads:"+ alwaysWinSettings.minSecondsBetweenReloads +" - "+ alwaysWinSettings.maxSecondsBetweenReloads);
if(!reloadIsEnabled() ) {
awLog("Reload is not enabled");
return;
}
awLog("Reload is enabled. Reloading...");
location.reload();
}
function reloadIsEnabled(){
var checkedValue = alwaysWinSettings.isReloadEnabled ?? false;// document.querySelector("[name='isReloadEnabled']").checked;
if(checkedValue == true) {
return true;
}
return false;
}
function autoLoginIsEnabled(){
var checkedValue = alwaysWinSettings.isAutoLoginEnabled ?? false;
var retVal = (checkedValue == true);
return retVal;
}
////////////////////////////////////////////////////////////////////////////////////
// Always win code to find and take the highest/tie bid
////////////////////////////////////////////////////////////////////////////////////
function getCountyInfo(countyId){
//<tr><th><div class="form-group form-row ml-1 mb-0"><label class="switch"><input class="subscription-status" type="checkbox" data-subscription_id="84035" checked=""><span class="async-slider round active"></span></label>
//<div class="ml-3"><label class="col-form-label"><a href="/app/subscription/84035">WASHINGTON, OR</a></label>
//</div></div></th>
//<td><div class="bid-controller input-group input-group-sm" data-subscription_id="84035" data-baseprice_default="75" data-base_price="75" data-top_bid="300" data-investor="24304">
//<div class="input-group-prepend"><span class="input-group-text bid-status top-bid" data-bid_status="&nbsp;Top Bid">&nbsp;Top Bid</span>
//<button class="btn btn-outline-primary bid-controller-btn bid-controller-btn--decrement" data-operation="decrement" type="button"><i class="icon ion-minus-round"></i></button></div>
//<input class="bid-controller--bid" readonly="readonly" size="4" style="text-align: center" type="text" value="425" name="investor_bid">
//<div class="input-group-append">
//<button class="btn btn-outline-primary bid-controller-btn bid-controller-btn--increment" data-operation="increment" type="button"><i class="icon ion-plus-round"></i></button>
//<button class="btn btn-primary btn-sm bid-controller-btn bid-controller-btn--save" type="button" data-operation="save" disabled="disabled">Save</button>
//</div></div></td></tr>
var county = document.querySelector('[data-subscription_id="'+ countyId +'"].subscription-status')
let countyRow = county.closest("tr");
let bidController = {};
bidController.countyRow = countyRow;
const bidIncriment = 25; //This is hard coded into site but could change later.
let num_bid = Number(countyRow.querySelector('.bid-controller--bid').value);
let num_tieBid = Number(countyRow.querySelector('.bid-controller').dataset.top_bid);
let num_floorBid = num_tieBid - bidIncriment;
let num_winningBid = num_tieBid + bidIncriment;
let num_clicksToMinWin = 1;
let winGap = (num_tieBid - num_bid);
if(winGap < 1) {
num_clicksToMinWin = (winGap / bidIncriment) + 1;
} else if(winGap > 0) {
num_clicksToMinWin = (winGap + bidIncriment) / bidIncriment;
}
bidController.readTimestamp = new Date();
bidController.isEnabled = county.checked;
bidController.id = county.dataset.subscription_id;
bidController.name = county.closest("div").getElementsByTagName('a')[0].innerText;
bidController.bid = num_bid;
bidController.tieBid = num_tieBid;
bidController.floorBid = num_floorBid;
bidController.winningBid = num_winningBid;
bidController.status = countyRow.querySelector(".bid-status").innerText;//.trim(); //countyRow.querySelector(".bid-status").dataset.bid_status;
bidController.isWinning = (num_bid > num_tieBid);
bidController.isWinningByTooMuch = (num_bid > num_winningBid);
bidController.clicksToMinWin = num_clicksToMinWin;
bidController.btnSave = countyRow.querySelector('.bid-controller-btn--save');
bidController.btnBidUp = countyRow.querySelector('.bid-controller-btn--increment');
bidController.btnBidDown = countyRow.querySelector('.bid-controller-btn--decrement');
return bidController;
}
function winCounty(countyJson, saveChanges) {
let countyInfo = countyJson.id + " "+ countyJson.name;
//console.log(countyJson.isWinning +" = "+ countyJson.tieBid +" > "+ countyJson.bid);
//console.log(countyJson.isWinningByTooMuch +" = "+ countyJson.bid +" > "+ countyJson.winningBid);
//console.log("clicksToMinWin: "+ countyJson.clicksToMinWin);
//console.log(countyJson);
if(countyJson.clicksToMinWin == 0) {
//if we made it here no changes were needed to win by just the right amount
//Nothing else to do to win optimally
//console.log(countyInfo +" is already winning by just the right amount");
awLog(countyInfo +" is already winning by just the right amount");
} else if(countyJson.clicksToMinWin > 0) {
//console.log(countyInfo +" is currently loosing. Increasing bid now");
awLog(countyInfo +" is currently loosing by "+countyJson.clicksToMinWin+" Increasing bid now");
for(var i = 0; i < countyJson.clicksToMinWin; i++) {
//console.log("calling btnBidUp.click() for "+ countyInfo);
countyJson.btnBidUp.click();
}
if(saveChanges) {
//console.log("calling btnSave.click() for "+ countyInfo);
countyJson.btnSave.click();
}
} else if (countyJson.clicksToMinWin < 0) {
//console.log(countyInfo +" is winning by too much. Decreasing bid now");
awLog(countyInfo +" is winning by too much. Decreasing bid now");
let clicksRemaining = Math.abs(countyJson.clicksToMinWin);
while(clicksRemaining > 0) {
//console.log("calling btnBidDown.click() for "+ countyInfo);
countyJson.btnBidDown.click();
clicksRemaining--;
}
if(saveChanges) {
//console.log("calling btnSave.click() for "+ countyInfo);
countyJson.btnSave.click();
}
}
}
function tieCounty(countyJson, saveChanges) {
//TODO: implemnt me
}
function awLog(message) {
console.log(message);
const currentContent = document.getElementById("awLog").innerHTML;
document.getElementById("awLog").innerHTML = currentContent +"<br/>"+ message;
}
function encryptAndStore(encryptionKey, clearText) {
return JSON.stringify(sjcl.encrypt(encryptionKey, clearText));
}
function unStoreAndDecrypt (encryptionKey, jsonObj) {
return sjcl.decrypt(encryptionKey, JSON.parse(jsonObj));
}
function loginIfNeeded(){
var div_signin = document.querySelector('.signin-box');
var loginIsNeeded = false;
if(div_signin != undefined && div_signin != null) {
loginIsNeeded = true;
if(!alwaysWinSettings.isAutoLoginEnabled) {
console.log("AutoLogin is turned off.");
awLog("AutoLogin is turned off.");
return loginIsNeeded;
}
console.log("A signin dialog exists");
var txt_email = div_signin.querySelector("[id='email']");
var txt_password = div_signin.querySelector("[id='inputPassword']");
var btn_signin = div_signin.querySelector('.btn-signin'); //btn btn-primary btn-block btn-signin
var encKey = alwaysWinSettings.encKey ?? "";
var ntsmhfUser = alwaysWinSettings.ntsmhfUser ?? "";
var ntsmhfPass = alwaysWinSettings.ntsmhfPass ?? "";
if (!encKey) {
encKey = prompt('Script key not set for ' + location.hostname + '. Please enter a random string:','');
alwaysWinSettings.encKey = encKey;
ntsmhfUser = "";
ntsmhfPass = "";
}
if(ntsmhfUser) {
ntsmhfUser = unStoreAndDecrypt(encKey, ntsmhfUser);
} else {
ntsmhfUser = prompt('UserName is not set for '+ location.hostname +'. Enter it now:','');
alwaysWinSettings.ntsmhfUser = encryptAndStore(encKey, ntsmhfUser);
}
if(ntsmhfPass) {
ntsmhfPass = unStoreAndDecrypt(encKey, ntsmhfPass);
} else {
ntsmhfPass = prompt('Password is not set for '+ location.hostname +'. Enter it now:','');
alwaysWinSettings.ntsmhfPass = encryptAndStore(encKey, ntsmhfPass);
}
const latestSettingsString = JSON.stringify(alwaysWinSettings);
localStorage.setItem('alwayswin_settings',latestSettingsString);
//////
txt_email.value = ntsmhfUser;
txt_password.value = ntsmhfPass;
btn_signin.click();
}
return loginIsNeeded;
}
const sleep = ms => new Promise(res => setTimeout(res, ms))
jQuery(window).on('load',function() {
console.log("Page loaded at: "+ new Date());
let minSecondsBetweenReloads = alwaysWinSettings.minSecondsBetweenReloads ?? 30;
let maxSecondsBetweenReloads = alwaysWinSettings.maxSecondsBetweenReloads ?? 180;
let isReloadEnabled = alwaysWinSettings.isReloadEnabled ?? false;
let isAutoLoginEnabled = alwaysWinSettings.isAutoLoginEnabled ?? false;
let bidCap = alwaysWinSettings.bidCap ?? 500;
let secondsBetweenReloads = getRandomNumberBetween(minSecondsBetweenReloads, maxSecondsBetweenReloads);
console.log("Next reload should occur in "+ secondsBetweenReloads +" seconds");
//Inject our controls
var newDiv = document.createElement ('div');
var newHtml = '<div class="alwaysWin-ntsmhf" id="alwaysWin-ntsmhf">';
newHtml += '<input type="checkbox" name="isReloadEnabled" '+ getCheckedValue("isReloadEnabled") +'/><label for="isReloadEnabled">AlwaysWin</label> | ';
newHtml += '<input type="checkbox" name="isAutoLoginEnabled" '+ getCheckedValue("isAutoLoginEnabled") +'/><label for="isAutoLoginEnabled">Auto Login</label> | ';
newHtml += '<button class="alwaysWinButton" id="alwaysWin-ntsmhf-save" type="button">Save</button>';
newHtml += '<br />';
newHtml += '<label for="minSecondsBetweenReloads">Reload Every</label>:<input id="minSecondsBetweenReloads" type="text" size="3" name="minSecondsBetweenReloads" value="'+minSecondsBetweenReloads+'" /> to <input id="maxSecondsBetweenReloads" type="text" size="3" name="maxSecondsBetweenReloads" value="'+maxSecondsBetweenReloads+'" /> seconds <br/>';
newHtml += '<label for="bidCap">Don&apos;t bid more than</label>: <input id="bidCap" type="text" size="5" name="bidCap" value="'+ bidCap+'"/> per county<br />';
newHtml += '<div id="reloaderData"><div id="countdown"></div><progress value="0" max="100" id="progressBar" style="width: 100%;"></progress></div><div id="awLog" class="alwaysWinLog">Log:</div>';
newHtml += '</div>';
newDiv.innerHTML = newHtml;
addAlwaysWinStyle('.alwaysWin-ntsmhf {position: fixed; top: 0px; left: 0px; background-color: #DDDDDD; border-radius: 5px; padding:2px; box-shadow: 5px 5px 3px #777777;}');
addAlwaysWinStyle('.alwaysWin-ntsmhf .alwaysWinLog {float:left; width:100%; overflow-y: auto; height: 100px; font-size: 0.75em; border-style:ridge; background-color:#FEFEFE;}');
addAlwaysWinStyle('.alwaysWin-ntsmhf .alwaysWinButton { border: none; color: #333333; padding: 1px 2px; text-align: center; text-decoration: none; display: inline-block; font-size: 8x; margin: 1px 1px; cursor: pointer;}');
addAlwaysWinStyle('.alwaysWin-ntsmhf .alwaysWinButton:hover {box-shadow: 0 2px 2px 0}');
addAlwaysWinStyle('.alwaysWin-ntsmhf .alwaysWinButton:active {position: relative; top: 1px;}');
document.body.appendChild (newDiv);
const alwaysWinSave = document.getElementById("alwaysWin-ntsmhf-save");
alwaysWinSave.addEventListener("click", handleSaveSettings);
//Only run our code on certain pages
//console.log(window.location.pathname);
switch (window.location.pathname) {
case "/app":
case "/signin":
break;
default:
return;
}
//Are we logged in?
var logWasNeeded = loginIfNeeded();
if (logWasNeeded) {
return; //don't execute any more code until we are logged in.
}
//// Now do the winning
var countiesToWin = [];
countiesToWin.push("84035"); //washington, OR
countiesToWin.push("87833"); //marion, OR
var countiesToTie = [];
countiesToTie.push("84034"); //cascade, MT
var countiesToWatch = [];
//countiesToWatch.push("84038"); //benton, OR
countiesToWatch.push("84037"); //clackamas, OR
let newStats = [];
let okToSaveChanges = true;
let countiesToWinCount = countiesToWin.length;
awLog("Checking "+ countiesToWinCount +" countiesToWin");
for(let i = 0; i < countiesToWinCount; i++) {
let currentEntity = getCountyInfo(countiesToWin[i])
winCounty(currentEntity,okToSaveChanges);
newStats.push(currentEntity);
}
okToSaveChanges = true;
let countiesToTieCount = countiesToTie.length;
awLog("Checking "+ countiesToTieCount +" countiesToTie");
for(let i = 0; i < countiesToTieCount; i++) {
let currentEntity = getCountyInfo(countiesToTie[i])
tieCounty(currentEntity,okToSaveChanges);
newStats.push(currentEntity);
}
okToSaveChanges = false;
let countiesToWatchCount = countiesToWatch.length;
awLog("Checking "+ countiesToWatchCount +" countiesToWatch");
for(let i = 0; i < countiesToWatchCount; i++) {
let currentEntity = getCountyInfo(countiesToWatch[i])
tieCounty(currentEntity,okToSaveChanges);
newStats.push(currentEntity);
}
//console.log("Saving county info stats");
const countyInfoStats = saveCountyInfoStats(newStats);
//Start our ui feedback for the enduser
var reloadTimeleft = secondsBetweenReloads;
var reloadTimer = setInterval(function() {
document.getElementById("countdown").innerHTML = "("+secondsBetweenReloads+") Next reload will occur in "+ reloadTimeleft +" seconds.";
var progressBarValue = 100 - Math.floor(100 * (reloadTimeleft / secondsBetweenReloads)); //Calculate percent complete
document.getElementById("progressBar").value = progressBarValue;
if(reloadTimeleft <= 0){
clearInterval(reloadTimer);
document.getElementById("countdown").innerHTML = secondsBetweenReloads +" second reload timer exhausted";
reload();
}
reloadTimeleft -= 1;
}, 1000);
});