IB Lineage Verifyer

Adds option to verify lineages in IB

  1. // ==UserScript==
  2. // @name IB Lineage Verifyer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @license MIT
  6. // @description Adds option to verify lineages in IB
  7. // @icon https://i.imgur.com/WlkWOkU.png
  8. // @author @activetutorial on discord
  9. // @match https://infinibrowser.wiki/item/*
  10. // @run-at document-end
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. (window.AT ||= {}).lineagefverify = {
  18. lineage: null,
  19. getLineage: async function() {
  20. const itemID = location.href.split("item/")[1];
  21. const custom = document.getElementById("item_footer")?.textContent == "This is an unverified user-submitted element";
  22. const baseURL = (custom ? "https://infinibrowser.wiki/api/recipe/custom?id=" : "https://infinibrowser.wiki/api/recipe?id=");
  23. const response = await fetch(baseURL + itemID);
  24. this.lineage = (await response.json()).steps;
  25. },
  26. createElements: async function() { // Create the button and popup
  27. document.querySelector("h3").insertAdjacentHTML
  28. ('afterend',
  29. '<div style="margin-top:1rem"><button id="verify-recipe" class="btn">Verify Recipe</button></div>'
  30. );
  31. this.verifyButton = document.getElementById("verify-recipe");
  32.  
  33. // Import required CSS
  34. document.head.appendChild(Object.assign(document.createElement("style"), {
  35. textContent: await (await fetch(
  36. "https://infinibrowser.wiki/static/bundle/search.css"
  37. )).text()
  38. }));
  39.  
  40. // Make Popup
  41. document.querySelector("main").insertAdjacentHTML(
  42. "beforeend",
  43. `<div id="modal_wrapper" class="modal_wrapper" style="display: none;">
  44. <div class="modal" id="modal">
  45. <div class="top">
  46. <h1>${document.querySelector("h1").innerHTML}</h1>
  47. <button id="close" name="Close" class="close_modal" onclick="document.getElementById('modal_wrapper').style.display = 'none';">
  48. <img src="/static/icon/button/close.svg" alt="Close" draggable="false" class="close_modal">
  49. </button>
  50. </div>
  51. <div id="a_item_footer"></div>
  52. </div>
  53. </div>`
  54. );
  55. this.boxInput = document.getElementById("a_item_footer");
  56. },
  57. openPopUp: function () {
  58. document.querySelector(".modal_wrapper").style = "";
  59. },
  60. getUncrafted: async function() {
  61. const uncrafted = new Set();
  62. this.lineage.forEach((step, i) => {
  63. const partLineage = this.lineage.slice(0, i); // Slice lineage to avoid circular recipes
  64. // Verify if ingredients have been crafted
  65. const ingredientAValid = !partLineage.every(partStep => !(
  66. step.a.id.toLowerCase() === partStep.result.id.toLowerCase()
  67. ));
  68. const ingredientBValid = !partLineage.every(partStep => !(
  69. step.b.id.toLowerCase() === partStep.result.id.toLowerCase()
  70. ));
  71.  
  72. if (!ingredientAValid) uncrafted.add(step.a.id);
  73. if (!ingredientBValid) uncrafted.add(step.b.id);
  74. });
  75. return [...uncrafted];
  76. },
  77. check: async function (first, second, result, mainneal=false) {
  78. // Either proxy or neals server
  79. const baseURL = (mainneal ? "https://neal.fun/api/infinite-craft/pair?ref=app&" : "https://infiniteback.active-tutorial-video.workers.dev/?");
  80. const response = await fetch(`${baseURL}first=${encodeURIComponent(first)}&second=${encodeURIComponent(second)}`);
  81. const data = await response?.json()
  82. return data?.result?.toLowerCase() === result?.toLowerCase(); // Return if its true
  83. },
  84. verifyLineage: async function() {
  85. let uncrafted = await this.getUncrafted();
  86. const incorrectCrafts = [];
  87. const allowedUncrafted = ["Water", "Fire", "Earth", "Wind"]; // Allowed missing items
  88. uncrafted = uncrafted.filter(item => !allowedUncrafted.includes(item)); // Subtract allowed items
  89. console.log(uncrafted);
  90. this.boxInput.innerHTML = "";
  91. this.openPopUp();
  92. this.boxInput.innerHTML += "Uncrafted items: <br>" + JSON.stringify(uncrafted);
  93. this.lineage.forEach(async step => {
  94. await this.check(step.a.id, step.b.id, step.result.id, false) ||
  95. await this.check(step.a.id, step.b.id, step.result.id, true) ||
  96. incorrectCrafts.push(step); // If false both times, craft is incorrect
  97. });
  98. console.log(incorrectCrafts);
  99. this.boxInput.innerHTML += "<br>Incorrect lineage steps: <br>" + JSON.stringify(incorrectCrafts).replace(/,/g, '<br>');
  100.  
  101. if (!(incorrectCrafts.length || uncrafted.length)) {
  102. this.boxInput.innerHTML += "<br>Lineage fully valid!";
  103. } else {
  104. this.boxInput.innerHTML += "<br>Lineage invalid!";
  105. }
  106. },
  107. start: function () {
  108. if (document.querySelector('.step')) { // Wait for IB to load
  109. this.createElements();
  110. // Button event listener
  111. this.verifyButton.addEventListener("click", this.verifyLineage.bind(this));
  112. // Get current lineage
  113. this.getLineage();
  114.  
  115. } else {
  116. setTimeout(this.start.bind(this), 200);
  117. }
  118. }
  119. };
  120.  
  121. window.AT.lineagefverify.start();
  122. })();