Skip to content

Instantly share code, notes, and snippets.

@ljosberinn
Last active October 31, 2024 23:11
Show Gist options
  • Save ljosberinn/aef2effd93ee627f6c3a646df827c694 to your computer and use it in GitHub Desktop.
Save ljosberinn/aef2effd93ee627f6c3a646df827c694 to your computer and use it in GitHub Desktop.
Raidbots Sim Progress in Tab

example image

  • 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,
  });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment