diff --git a/README.md b/README.md index 5aed79f..6865ded 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,45 @@ -## AlwaysWin-ntsmhf Bookmarklet +# AlwaysWin-ntsmhf Tampermonkey + +To load the Tampermonkey script: +* Install the [Tampermonkey Chrome Extension] (https://www.tampermonkey.net/) +* Click on the Extension and select **Create a new script...** +* Copy the contents of [tampermonkey.js](tampermonkey.js) into the editor and save the changes +* Modify the *countiesToWin[]* array to contain the countyId's you wish to win the bid on. + +## Wishlist / Todo + [] Bidcap for any row + [x] Save settings to local storage + [x] Retrieve settings from local storage + [x] Inject div + [] start/stop buttons + [x] How often should the status check be performed? + [x] randomize refresh value to avoid detection + [] show rowAction1 array //AlwaysWin + [] show rowAction2 array //AlwaysTie + [] show rowAction3 array //WatchTie + [] PriceChangeOverTime Chart + [] For each countyRow inject + [] "rowAction" dropdown with options: + 0 - Ignore + 1 - Ensure I am highest bidder + 2 - Make sure I am Tied + 3 - Only watch tied bid + [] save to analytics checkbox + [] county bidcap + [] Option to sell leads that don't fit your criteria but you can't return on the secondary market. + [] Store tie values for statistical analysis over time. + + + +# AlwaysWin-ntsmhf Bookmarklet - Original route (probably abandoning) + Version: 0.1 To load the bookmark go to the [AlwaysWin-ntsmhf Bookmarklet site](https://info.qhrei.com/temp/alwayswin-ntsmhf/index.htm) -Drag & drop the above link into your bookmarks to save it. +Drag & drop the above link into your bookmarks to save it. Compiled JavaScript thanks to [Google's Closure Compiler](https://closure-compiler.appspot.com/home) + + + diff --git a/tampermonkey.js b/tampermonkey.js new file mode 100644 index 0000000..8dea7cc --- /dev/null +++ b/tampermonkey.js @@ -0,0 +1,224 @@ +// ==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/app +// @require https://code.jquery.com/jquery-3.7.1.min.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, "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() { + if(reloadIsEnabled()) { + return "checked"; + } + 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 saveSettings() { + let isReloadEnabledValue = document.querySelector("[name='isReloadEnabled']").checked; + let minSecondsBetweenReloadsValue = document.querySelector("[name='minSecondsBetweenReloads']").value; + let maxSecondsBetweenReloadsValue = document.querySelector("[name='maxSecondsBetweenReloads']").value; + + const latestSettings = { + "isReloadEnabled": isReloadEnabledValue, + "minSecondsBetweenReloads": minSecondsBetweenReloadsValue, + "maxSecondsBetweenReloads": maxSecondsBetweenReloadsValue + }; + const latestSettingsString = JSON.stringify(latestSettings); + localStorage.setItem('alwayswin_settings',latestSettingsString); + + alwaysWinSettingsString = latestSettings; + + return latestSettings; +} + +function reload() { + console.log("Saving settings..."); + let alwaysWinSettings = saveSettings(); + + console.log("Its time to perform a reload."); + console.log("isEnabled: "+ alwaysWinSettings.isReloadEnabled); + console.log("secondsBetweenReloads:"+ alwaysWinSettings.minSecondsBetweenReloads +" - "+ alwaysWinSettings.maxSecondsBetweenReloads); + if(!reloadIsEnabled() ) { + console.log("Reload is not enabled"); + return; + } + console.log("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; +} + +//////////////////////////////////////////////////////////////////////////////////// +// Always win code to find and take the highest/tie bid +//////////////////////////////////////////////////////////////////////////////////// +function getCountyInfo(countyId){ + //
+ //
+ //
+ //
+ //
 Top Bid + //
+ // + //
+ // + // + //
+ + 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.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"); + } else if(countyJson.clicksToMinWin > 0) { + console.log(countyInfo +" is currently loosing. 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"); + 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(); + } + } +} + +jQuery(window).on('load',function() { + console.log("Page loaded at: "+ new Date()); + + let minSecondsBetweenReloads = alwaysWinSettings.minSecondsBetweenReloads ?? 30; + let maxSecondsBetweenReloads = alwaysWinSettings.maxSecondsBetweenReloads ?? 60; + let isReloadEnabled = alwaysWinSettings.isReloadEnabled ?? false; + + let secondsBetweenReloads = getRandomNumberBetween(minSecondsBetweenReloads, maxSecondsBetweenReloads); + console.log("Next reload should occur in "+ secondsBetweenReloads +" seconds"); + + //Inject our controls + var newHTML = document.createElement ('div'); + newHTML.innerHTML = '

: to seconds
'; + + addAlwaysWinStyle('#alwaysWin-ntsmhf { position: fixed; top: 0px; left: 0px; background-color: #DDDDDD; border-radius: 5px; padding:2px; box-shadow: 5px 5px 3px #777777;}'); + document.body.appendChild (newHTML); + + //// Now do the winning + var countiesToWin = []; + countiesToWin.push("84035"); //washington, OR + countiesToWin.push("87833"); //marion, OR + //countiesToWin.push("84038"); //benton, OR + //countiesToWin.push("84037"); //clackamas, OR + + //var countiesToTie = []; + //countiesToTie.push("84034"); //cascade, MT + //countiesToTie.push("84038"); //benton, OR + //countiesToTie.push("84037"); //clackamas, OR + //tieCounty(getCountyInfo(countiesToTie[0].id); + + let okToSaveChanges = true; + let countiesToWinCount = countiesToWin.length; + for(var i = 0; i < countiesToWinCount; i++) { + let currentEntity = getCountyInfo(countiesToWin[i]) + winCounty(currentEntity,okToSaveChanges); + } + + //Refresh the page when we are suposed to + let interval = setInterval(reload, secondsBetweenReloads*1000); + +});