Added basic element for travel item appraisal.
This commit is contained in:
+121
-40
@@ -1,11 +1,12 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Torn - Arrival Time Predictor
|
// @name Torn - Arrival Time Predictor
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 1.02
|
// @version 1.03
|
||||||
// @description Calculates and displays the exact local time you will land while traveling
|
// @description Calculates and displays the exact local time you will land while traveling
|
||||||
// @author You
|
// @author You
|
||||||
// @match https://www.torn.com/page.php?sid=travel
|
// @match https://www.torn.com/page.php?sid=travel
|
||||||
// @grant GM_addStyle
|
// @grant GM_addStyle
|
||||||
|
// @grant GM_xmlhttpRequest
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@@ -25,6 +26,13 @@
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
// Setup Formatter
|
||||||
|
const currencyFormatter = new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'USD',
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
});
|
||||||
|
|
||||||
//const flight_image = document.querySelector("#travel-root > div.viewport___cdEK9 > div.airspaceScene___euCKY.outboundFlight___rIvIA");
|
//const flight_image = document.querySelector("#travel-root > div.viewport___cdEK9 > div.airspaceScene___euCKY.outboundFlight___rIvIA");
|
||||||
//flight_image.remove();
|
//flight_image.remove();
|
||||||
|
|
||||||
@@ -40,48 +48,121 @@
|
|||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
function initClockExtension(timerElement) {
|
function initClockExtension(timerElement) {
|
||||||
// Create a custom UI box to display our text safely without breaking Torn's CSS
|
// Create a custom UI box to display our text safely without breaking Torn's CSS
|
||||||
const travelRoot = document.querySelector("#travel-root");
|
const travelRoot = document.querySelector("#travel-root");
|
||||||
const parentContainer = travelRoot.querySelector('[class^="progressText"]');
|
const parentContainer = travelRoot.querySelector(
|
||||||
// Remove travel fact
|
'[class^="progressText"]',
|
||||||
travelRoot.querySelector('[class^="factWrapper"]').remove();
|
);
|
||||||
// Remove flight scene
|
// Remove travel fact
|
||||||
travelRoot.querySelector('[class^="airspaceScene"]').remove();
|
travelRoot.querySelector('[class^="factWrapper"]').remove();
|
||||||
const ogTimer = document.querySelector("#travel-root > div.viewport___cdEK9 > div.flightProgressSection___OEJoR > div.progressText___BEQ0k > div > span");
|
// Remove flight scene
|
||||||
var timerContainer = null;
|
travelRoot.querySelector('[class^="airspaceScene"]').remove();
|
||||||
const timeDisplay = document.createElement('div');
|
const ogTimer = document.querySelector(
|
||||||
timeDisplay.style.cssText = 'padding: 10px; margin-top: 10px; color: #fff; text-align: center; border-radius: 5px; font-weight: bold; border: 1px solid #444; transition: color 0.5s ease; font-weight: bold; font-size: 1.5rem;';
|
"#travel-root > div.viewport___cdEK9 > div.flightProgressSection___OEJoR > div.progressText___BEQ0k > div > span",
|
||||||
//timerElement.parentNode.insertBefore(timeDisplay, timerElement.nextSibling);
|
);
|
||||||
parentContainer.insertAdjacentElement('beforebegin', timeDisplay);
|
var timerContainer = null;
|
||||||
timeDisplay.innerText = 'Calculating landing time...';
|
const timeDisplay = document.createElement("div");
|
||||||
timerContainer = timeDisplay;
|
timeDisplay.style.cssText =
|
||||||
|
"padding: 10px; margin-top: 10px; color: #fff; text-align: center; font-weight: bold; transition: color 0.5s ease; font-weight: bold; font-size: 1.5rem;";
|
||||||
|
//timerElement.parentNode.insertBefore(timeDisplay, timerElement.nextSibling);
|
||||||
|
parentContainer.insertAdjacentElement("beforebegin", timeDisplay);
|
||||||
|
timeDisplay.innerText = "Calculating landing time...";
|
||||||
|
timerContainer = timeDisplay;
|
||||||
|
|
||||||
// Update the landing time prediction every single second
|
|
||||||
setInterval(() => {
|
|
||||||
const timeString = timerElement.innerText; // Grabs 'HH:MM:SS' from the page
|
|
||||||
if (!timeString) return;
|
|
||||||
|
|
||||||
const timeParts = timeString.split(':');
|
|
||||||
if (timeParts.length === 3) {
|
|
||||||
const hours = parseInt(timeParts[0], 10);
|
|
||||||
const minutes = parseInt(timeParts[1], 10);
|
|
||||||
const seconds = parseInt(timeParts[2], 10);
|
|
||||||
|
|
||||||
// Convert countdown duration entirely to total milliseconds
|
|
||||||
const msRemaining = ((hours * 60 * 60) + (minutes * 60) + seconds) * 1000;
|
|
||||||
// Blink the text if time left is < 2 minutes.
|
|
||||||
if (msRemaining <= 120000) {
|
|
||||||
// Add the blinking class to the text.
|
|
||||||
timerContainer.classList.add('pulse-text');
|
|
||||||
|
|
||||||
|
// Enumerate Inventory items
|
||||||
|
var travelInventory = travelRoot.querySelectorAll('[class^="itemButton"]');
|
||||||
|
var iteminfo = [];
|
||||||
|
console.log(`${travelInventory.length} items found.`); // TODO: DEBUG: Remove.
|
||||||
|
if (travelInventory.length > 0) {
|
||||||
|
travelInventory.forEach((item) => {
|
||||||
|
let itemImg = item.querySelector("img"); // Use the image URL to get the item ID
|
||||||
|
if (itemImg) {
|
||||||
|
let splitUrl = itemImg.src.split("/"); // Split the URL by the forward slashes
|
||||||
|
const id = splitUrl[5]; // The 6th element is the Item ID
|
||||||
|
var itemIndex = iteminfo.findIndex(item => item.id === id);
|
||||||
|
if (itemIndex === -1) {
|
||||||
|
itemIndex = iteminfo.push( { id: id, qty: 0, item_name: "", market: 0, bazaar_min: 0, bazaar_average: 0}) - 1;
|
||||||
}
|
}
|
||||||
|
iteminfo[itemIndex].qty++;
|
||||||
// Add the flight duration to the current system date/time
|
|
||||||
const landingTime = new Date(Date.now() + msRemaining);
|
|
||||||
|
|
||||||
// Format the output neatly (e.g., "16:24:05")
|
|
||||||
timerContainer.innerText = `Estimated Landing: ${landingTime.toLocaleTimeString()}`;
|
|
||||||
}
|
}
|
||||||
}, 1000);
|
});
|
||||||
|
iteminfo.forEach(item => {
|
||||||
|
getPriceInfo(item.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Function to update the page with price info
|
||||||
|
function updatePriceInfo() {
|
||||||
|
var totalValue = 0;
|
||||||
|
var values = {
|
||||||
|
market: 0,
|
||||||
|
bazaar_average: 0,
|
||||||
|
bazaar_min: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const invPanel = travelRoot.querySelector('[class^="inventoryPanel"]');
|
||||||
|
const appraisePanel = document.createElement("div");
|
||||||
|
appraisePanel.style.cssText = "color: #0c0; font-weight: bold; font-size: 1.2rem;"
|
||||||
|
invPanel.parentNode.insertBefore(appraisePanel, invPanel.nextSibling);
|
||||||
|
appraisePanel.innerText = "Appraising items...";
|
||||||
|
iteminfo.forEach(item => {
|
||||||
|
console.log(`Market Value of ${item.qty} ${item.item_name}: ${item.market * item.qty}. Bazaar Avg: ${item.bazaar_average * item.qty}. Bazaar Min: ${item.bazaar_min * item.qty}`);
|
||||||
|
values.bazaar_min += currencyFormatter.format(item.bazaar_min * item.qty);
|
||||||
|
values.bazaar_average += currencyFormatter.format(item.bazaar_average * item.qty);
|
||||||
|
values.market += currencyFormatter.format(item.market * item.qty);
|
||||||
|
});
|
||||||
|
// TODO: Update UI Elements
|
||||||
|
appraisePanel.innerText = `Quick Sell: ${values.bazaar_min} | Market: ${values.market} | Bazaar Avg: ${values.bazaar_average}`;
|
||||||
|
}
|
||||||
|
// Function to get price information
|
||||||
|
function getPriceInfo(itemId) {
|
||||||
|
const w3bPriceUrl = "https://weav3r.dev/api/marketplace/" + itemId; // API Endpoint for W3B Market Information
|
||||||
|
var data = null;
|
||||||
|
GM_xmlhttpRequest({
|
||||||
|
method: "GET",
|
||||||
|
url: w3bPriceUrl,
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
onload: function(response) {
|
||||||
|
if (response.status === 200) {
|
||||||
|
data = JSON.parse(response.responseText);
|
||||||
|
// Start updating the item's information.
|
||||||
|
let index = iteminfo.findIndex(item => item.id === itemId);
|
||||||
|
iteminfo[index].item_name = data.item_name;
|
||||||
|
iteminfo[index].market = data.market_price;
|
||||||
|
iteminfo[index].bazaar_min = data.listings[0].price;
|
||||||
|
iteminfo[index].bazaar_average = data.bazaar_average;
|
||||||
|
|
||||||
|
updatePriceInfo(); // Update the UI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Update the landing time prediction every single second
|
||||||
|
setInterval(() => {
|
||||||
|
const timeString = timerElement.innerText; // Grabs 'HH:MM:SS' from the page
|
||||||
|
if (!timeString) return;
|
||||||
|
|
||||||
|
const timeParts = timeString.split(":");
|
||||||
|
if (timeParts.length === 3) {
|
||||||
|
const hours = parseInt(timeParts[0], 10);
|
||||||
|
const minutes = parseInt(timeParts[1], 10);
|
||||||
|
const seconds = parseInt(timeParts[2], 10);
|
||||||
|
|
||||||
|
// Convert countdown duration entirely to total milliseconds
|
||||||
|
const msRemaining = (hours * 60 * 60 + minutes * 60 + seconds) * 1000;
|
||||||
|
// Blink the text if time left is < 2 minutes.
|
||||||
|
if (msRemaining <= 120000) {
|
||||||
|
// Add the blinking class to the text.
|
||||||
|
timerContainer.classList.add("pulse-text");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the flight duration to the current system date/time
|
||||||
|
const landingTime = new Date(Date.now() + msRemaining);
|
||||||
|
|
||||||
|
// Format the output neatly (e.g., "16:24:05")
|
||||||
|
timerContainer.innerText = `Estimated Landing: ${landingTime.toLocaleTimeString()}`;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
Reference in New Issue
Block a user