- as soon as a sim started, press F12
- this opens the browser developer tools
- navigate to the
Console
tab - click the line with the
>
. the cursor will start blinking - paste the following code and press enter:
(()=>{if(!location.origin.includes("raidbots"))return;function e(e){if(e.length<2)return"UKN";let t=e[0],n=e[e.length-1],l=(n.ts-t.ts)/1e3,r=n.percent-t.percent;if(r<=0)return"UKN";let o=100-n.percent,i=Math.round(o/(r/l)),u=Math.floor(i/3600),c=Math.floor(i%3600/60),$=[];return u>0&&$.push(`${u}h`),(c>0||u>0)&&$.push(`${c}m`),$.push(`${i%60}s`),$.join(" ")}function t(){let e=Array.from(document.querySelectorAll('.Box p[align="center"]')).map(e=>e.parentNode.style.backgroundColor).findIndex(e=>"rgb(0, 217, 247)"===e);return 0===e?1:e>3?3:e}let n=[],l=t(),r=null,o=Array.from(document.querySelectorAll(".Flex .Box .Button")).find(e=>e.textContent.includes("Simple Mode")),i=()=>{};function u(t,l){n.push({ts:Date.now(),percent:t}),document.title=`Stage ${l} | ${t}% | ETA ${e(n)}`}if(o){let c=Array.from(document.querySelectorAll(".Box .Flex .Box p.Text")).find(e=>e.textContent.includes("combinations"));function $(){let[e,t]=c.textContent.replace(" combinations complete","").trim().split(" of ").map(e=>e.replaceAll(".","")).map(Number);return{current:e,total:t}}r=c.parentElement;let s=$();i=()=>{let e=$();if(e.current!=s.current){s=e;let r=t();r!=l&&(n=[],l=r);let o=(e.current/e.total*100).toFixed(2);u(o,r)}}}else{let p=(r=document.querySelector(".Donut")).querySelector("span").textContent;i=()=>{if(r.textContent!=p){p=r.textContent;let e=t();e!=l&&(n=[],l=e);let o=Number(p.replace("%",""));u(o,e)}}}let f=new MutationObserver(i);f.observe(r,{childList:!0,attributes:!0,subtree:!0})})();
- press F12 again
- unfortunately you have to do this once per sim
For those capable of reading JS, here's the unminified version:
(() => {
if (!location.origin.includes("raidbots")) {
return;
}
function calculateRemainingTime(data) {
if (data.length < 2) {
return "UKN";
}
const first = data[0];
const last = data[data.length - 1];
const totalTime = (last.ts - first.ts) / 1000;
const totalPercent = last.percent - first.percent;
if (totalPercent <= 0) {
return "UKN";
}
const ratePerSecond = totalPercent / totalTime;
const remainingPercent = 100 - last.percent;
const secondsRemaining = Math.round(remainingPercent / ratePerSecond);
const hours = Math.floor(secondsRemaining / 3600);
const minutes = Math.floor((secondsRemaining % 3600) / 60);
const seconds = secondsRemaining % 60;
const timeParts = [];
if (hours > 0) timeParts.push(`${hours}h`);
if (minutes > 0 || hours > 0) timeParts.push(`${minutes}m`);
timeParts.push(`${seconds}s`);
return timeParts.join(" ");
}
function getCurrentStage() {
const stage = Array.from(
document.querySelectorAll('.Box p[align="center"]')
)
.map((p) => p.parentNode.style.backgroundColor)
.findIndex((bgColor) => bgColor === "rgb(0, 217, 247)");
if (stage === 0) {
return 1;
}
if (stage > 3) {
return 3;
}
return stage;
}
let progress = [];
let currentStage = getCurrentStage();
let targetNode = null;
const usesAdvancedMode = Array.from(
document.querySelectorAll(".Flex .Box .Button")
).find((button) => button.textContent.includes("Simple Mode"));
let mutationCallback = () => {};
function onUpdate(percent, stage) {
progress.push({ ts: Date.now(), percent });
document.title = `Stage ${stage} | ${percent}% | ETA ${calculateRemainingTime(
progress
)}`;
}
if (usesAdvancedMode) {
const combinationsP = Array.from(
document.querySelectorAll(".Box .Flex .Box p.Text")
).find((p) => p.textContent.includes("combinations"));
targetNode = combinationsP.parentElement;
function getCurrentAndTotalCombinations() {
const [current, total] = combinationsP.textContent
.replace(" combinations complete", "")
.trim()
.split(" of ")
.map((str) => str.replaceAll(".", ""))
.map(Number);
return {
current,
total,
};
}
let combinations = getCurrentAndTotalCombinations();
mutationCallback = () => {
const currentCombinations = getCurrentAndTotalCombinations();
if (currentCombinations.current != combinations.current) {
combinations = currentCombinations;
const stage = getCurrentStage();
if (stage != currentStage) {
progress = [];
currentStage = stage;
}
const percent = (
(currentCombinations.current / currentCombinations.total) *
100
).toFixed(2);
onUpdate(percent, stage);
}
};
} else {
targetNode = document.querySelector(".Donut");
let last = targetNode.querySelector("span").textContent;
mutationCallback = () => {
if (targetNode.textContent != last) {
last = targetNode.textContent;
const stage = getCurrentStage();
if (stage != currentStage) {
progress = [];
currentStage = stage;
}
const percent = Number(last.replace("%", ""));
onUpdate(percent, stage);
}
};
}
const observer = new MutationObserver(mutationCallback);
observer.observe(targetNode, {
childList: true,
attributes: true,
subtree: true,
});
})();