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.
 
 

569 lines
24 KiB

// ==UserScript==
// @name AlwaysWin-ntsmhf
// @namespace https://git.qhrei.com/steven/alwayswin-ntsmhf/
// @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, "bidCap":500, "oversight":{"all":[]}};
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;
let oversight = {};
//oversight.win = [];//["84035","87833"]; //win
//oversight.tie = [];//["84034"]; //tie
//oversight.watch = [];//["84038"]; //watch
//oversight.ignore = [];//["84037"]; //ignore
oversight.all = [];
var latestSettings = alwaysWinSettings;
latestSettings.isReloadEnabled = isReloadEnabledValue;
latestSettings.isAutoLoginEnabled = isAutoLoginEnabledValue;
latestSettings.minSecondsBetweenReloads = minSecondsBetweenReloadsValue;
latestSettings.maxSecondsBetweenReloads = maxSecondsBetweenReloadsValue;
latestSettings.bidCap = bidCap;
if(latestSettings.oversight == null || latestSettings == undefined) {
latestSettings.oversight = oversight;
}
//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;
}
function getBidCap(countyId) {
//Get the default bidcap from settings
var bidCap = alwaysWinSettings.bidCap;
const countyOversight = alwaysWinSettings.oversight.all.find(({ id }) => id === countyId);
if(countyFound(countyOversight)) {
bidCap = countyOversight.bidCap;
}
return bidCap;
}
////////////////////////////////////////////////////////////////////////////////////
// Always win code to find and take the highest/tie bid
////////////////////////////////////////////////////////////////////////////////////
function getCountyInfo(countyId){
var county = document.querySelector('[data-subscription_id="'+ countyId +'"].subscription-status');
if(county === null) {
console.log("county "+ countyId +" row not found");
return;
}
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;
}
let num_bidCap = getBidCap(countyId);
let num_clicksToBidCap = num_clicksToMinWin;
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.bidCap = num_bidCap;
bidController.clicksToBidCap = num_clicksToBidCap;
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 watchCounty(countyJson, saveChanges) {
//TODO: implemnt me
}
function awLog(message) {
console.log(message);
const currentContent = document.getElementById("awLog").innerHTML;
document.getElementById("awLog").innerHTML = currentContent +""+ message +"<br/>";
}
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;
}
function renderOption(value, selectedValue) {
var optionHtml = '<option value="'+ value +'"';
if(value == selectedValue) {
optionHtml += ' selected';
}
optionHtml += '>'+ value +'</option>';
return optionHtml;
}
function getOversightOptions(countyId, selectedAction) {
var optionsHtml = "";
optionsHtml += renderOption("win", selectedAction);
optionsHtml += renderOption("tie", selectedAction);
optionsHtml += renderOption("watch",selectedAction);
optionsHtml += renderOption("ignore",selectedAction);
return optionsHtml;
}
function countyFound(countyValue) {
return countyValue !== undefined;
}
function upsertOversight(countyOversightJson) {
//console.log(countyOversightJson);
const countyId = countyOversightJson.id;
//console.log("checking "+countyOversightJson.action+" for "+countyId);
/*
var countyValue;
switch (countyOversightJson.action) {
case "win":
countyValue = alwaysWinSettings.oversight.win.find((value, index) => value === countyId);
if(!countyFound){
alwaysWinSettings.oversight.win.push(countyId);
}
break;
case "tie":
countyValue = alwaysWinSettings.oversight.tie.find((value, index) => value === countyId);
if(!countyFound){
alwaysWinSettings.oversight.tie.push(countyId);
}
break;
case "watch":
countyValue = alwaysWinSettings.oversight.watch.find((value, index) => value === countyId);
if(!countyFound){
alwaysWinSettings.oversight.watch.push(countyId);
}
break;
case "ignore":
countyValue = alwaysWinSettings.oversight.ignore.find((value, index) => value === countyId);
if(!countyFound){
alwaysWinSettings.oversight.ignore.push(countyId);
}
break;
default:
break;
}
*/
var countyFoundAt = alwaysWinSettings.oversight.all.findIndex(({ id }) => id === countyId);
console.log(countyId +" countyFoundAt: "+countyFoundAt);
if(countyFoundAt == -1) {
alwaysWinSettings.oversight.all.push(countyOversightJson);
countyFoundAt = alwaysWinSettings.oversight.all.length;
}
//console.log(alwaysWinSettings.oversight.all[countyFoundAt]);
}
function convertToOversightJson(countyInfoJson, action, isBidCapEnabled){
const countyInfo = {
"id":countyInfoJson.id,
"bidCap": countyInfoJson.bidCap,
"isBidCapEnabled": isBidCapEnabled,
"action": action
};
return countyInfo;
}
function injectOversight(countyId, action) {
countyId += ""; //cast into string incase number was passed in
//console.log("injecting oversight into county "+countyId);
var countyJson = getCountyInfo(countyId);
if(countyJson === null || countyJson === undefined) {
console.log(" could not find the county row "+countyId);
return;
}
//// BEGIN TempCode TODO: figure out if I want this code to live here
const isBidCapEnabled = false;
const countyOversightJson = convertToOversightJson(countyJson, action, isBidCapEnabled);
upsertOversight(countyOversightJson);
//// END TempCode
let countyRow = countyJson.countyRow;
var oversightCountyDiv = document.createElement('div');
oversightCountyDiv.id = "oversight-county-"+countyId;
oversightCountyDiv.style = "border: 1px dotted gray; padding: 0; margin: 0; font-size: 12px; overflow-x: visible";
var countyDivHtml ='';
countyDivHtml += ''+ countyJson.id +'';
countyDivHtml += ' | <label>tie:'+ countyJson.tieBid +'</label>';
countyDivHtml += ' | <label>margin:'+ countyJson.clicksToMinWin +'</label>';
oversightCountyDiv.innerHTML = countyDivHtml;
var targetContainerCounty = countyRow.firstElementChild;
targetContainerCounty.appendChild(oversightCountyDiv);
var oversightPriceDiv = document.createElement('div');
oversightPriceDiv.id = "oversight-price-"+countyId;
oversightPriceDiv.style = "border: 1px dotted gray; padding: 0; margin: 0; font-size: 12px; overflow-x: visible";
var priceDivHtml ='';
//priceDivHtml += ''+ countyJson.id +'';
priceDivHtml += '<label><input disabled type="checkbox" style="transform:scale(.5);" name="enableBidCap-'+countyId+'" />cap:<input disabled type="text" name="bidCap-'+ countyId +'" id="bidCap-'+ countyId +'" style="font-size:10px; width:40px; height:12px;" value="'+ countyJson.bidCap +'" /></label>';
priceDivHtml += ' | <label for="oversightAction-'+countyId+'">act:</label><select disabled name="oversightAction-'+ countyId +'" id="oversightAction-'+ countyId +'">'+ getOversightOptions(countyId, action) +'</select>';
priceDivHtml += '<button disabled id="oversightSave-'+countyId+'" style="font-size:9px;background-color:#aaaaaa;color:#FFFFFF;padding:1px;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;margin:0px;">Apply</button>';
oversightPriceDiv.innerHTML = priceDivHtml;
var targetContainer = countyRow.lastElementChild;
targetContainer.appendChild(oversightPriceDiv);
}
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">Auto Refresh</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"></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.
}
//Inject our bits into the page for oversight
injectOversight("84035","win"); //washington, OR
injectOversight("87833","win"); //marion, OR
injectOversight("84034","tie"); //cascade, MT
injectOversight("84037","watch"); //clackamas, OR
injectOversight("84038","watch"); //benton, OR
//// Now do the winning
let newStats = [];
let countiesToWinCount = alwaysWinSettings.oversight.all.length;
awLog("Checking "+ countiesToWinCount +" counties");
for(let i = 0; i < countiesToWinCount; i++) {
let currentEntity = alwaysWinSettings.oversight.all[i];
const countyInfoJson = getCountyInfo(currentEntity.id);
//console.log(currentEntity);
switch (currentEntity.action) {
case "win":
winCounty(countyInfoJson,true);
break;
case "tie":
tieCounty(countyInfoJson,true);
break;
case "watch":
watchCounty(countyInfoJson,false);
break;
default:
break;
}
newStats.push(countyInfoJson);
}
/*
let okToSaveChanges = true;
let countiesToWinCount = alwaysWinSettings.oversight.win.length;
awLog("Checking "+ countiesToWinCount +" countiesToWin");
for(let i = 0; i < countiesToWinCount; i++) {
let currentEntity = getCountyInfo(alwaysWinSettings.oversight.win[i])
winCounty(currentEntity,okToSaveChanges);
newStats.push(currentEntity);
}
okToSaveChanges = true;
let countiesToTieCount = alwaysWinSettings.oversight.tie.length;
awLog("Checking "+ countiesToTieCount +" countiesToTie");
for(let i = 0; i < countiesToTieCount; i++) {
let currentEntity = getCountyInfo(alwaysWinSettings.oversight.tie[i])
tieCounty(currentEntity,okToSaveChanges);
newStats.push(currentEntity);
}
okToSaveChanges = false;
let countiesToWatchCount = alwaysWinSettings.oversight.watch.length;
awLog("Checking "+ countiesToWatchCount +" countiesToWatch");
for(let i = 0; i < countiesToWatchCount; i++) {
let currentEntity = getCountyInfo(alwaysWinSettings.oversight.watch[i])
watchCounty(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);
});