howmuchdoesthesims4cost.lol/static/script.js
2024-03-12 11:46:58 +00:00

184 lines
6.4 KiB
JavaScript
Executable file

// This code is licensed under GNU GPLv3.
const BASE_URL = "/api/appinfo";
var TS4_APP_ID = 1222670;
const APPID_REGEX = /#(\d{5,10})/
if(APPID_REGEX.test(window.location.hash)===true) {
let matches = APPID_REGEX.exec(window.location.hash);
TS4_APP_ID = parseInt(matches[1])
console.debug("Set app ID to " + TS4_APP_ID);
} else {
console.debug("No custom ID set or does not match regex.");
}
const PRICE_ELEMENT = document.getElementById("price");
const NAME_ELEMENT = document.getElementById("name");
/*
* These prices are gathered from a range of sources, such as Tesco, Amazon, and CeX.
* Some prices may no longer be correct. They do not include discounts.
*
* Last updated: 10/12/2023
*/
const PRICES = {
"Freddo (18g)": 0.25,
"Skittles (136G)": 1.25,
"Cadbury Fingers (114G)": 1.70,
"howmuchdoesthesims4cost.lol": 1.78,
"Pepsi Max (2L)": 2.00,
"Pringles (Salt & Vinegar, 185g)": 2.25,
"BLÅHAJ Soft toy, shark (40 cm)": 22.00,
"Dell Optiplex 7040 USFF (6th generation Intel i5)": 25.00,
"Tenda AC10 V3.0 AC1200 Dual Band Gigabit Wireless Cable Router": 27.99,
"Seagate SkyHawk 4TB 3.5\" 7200RPM HDD": 30.00,
"Dell Optiplex 3020 USFF (4th generation Intel i5)": 39.99,
"TP-Link AX1800 WiFi 6 Router": 39.99,
"KIOXIA EXERIA NVMe M.2 SSD (1TB)": 43.20,
"Seagate BarraCuda,Internal Hard Drive 2.5 Inch (1TB)": 49.99,
"Kingston NV2 NVMe PCIe 4.0 Internal SSD (1TB)": 59.99,
"NVIDIA GeForce GTX 1650": 117.96,
"AMD Radeon RX 5700 8GB (Second hand from CeX)": 150.00,
"TP-Link AX5400 WiFi 6 Router": 159.99,
"Intel Core i5-13400F": 191.99,
"Apple Watch SE (1st generation)": 219.00,
"iPhone SE (3rd generation/5G/2022)": 499.00,
"My custom PC (https://uk.pcpartpicker.com/user/nexy7574/saved/#view=cKYV4D)": 800.00,
"NVIDIA GeForce RTX 4090": 1519.00,
}
function compare(price, item) {
let n = Math.floor((price / PRICES[item]) * 100) / 100;
if(n>=1) {
n = Math.floor(n);
};
return n
}
function update(n, unit="$") {
PRICE_ELEMENT.textContent = unit + n;
console.debug("Updated price to: " + n);
}
function ids_to_body(ids) {
return JSON.stringify({"app_ids": ids})
}
function ratelimited(response) {
let retry_after = response.headers.get("retry-after");
console.warn("Rate-limited for " + retry_after + " seconds.");
setTimeout(() => {window.location.reload()}, retry_after * 1000);
setInterval(
() => {
let element = document.getElementById("retry-after");
let value = parseFloat(element.textContent);
value -= 0.1;
element.textContent = value.toFixed(1);
},
100
)
let element = document.getElementById("retrying");
element.hidden = false;
document.getElementById("retry-after").textContent = (retry_after * 1).toFixed(1);
document.querySelector("main").hidden = true;
document.querySelector("main").style.display = "none";
}
async function get_app_info(id) {
const response = await fetch(BASE_URL, {method: "POST", body: ids_to_body([id]), headers: {"Content-Type": "application/json"}});
if(response.status === 429) {
ratelimited(response);
return {id: {"name": "<rate limited>"}}
}
const data = await response.json();
console.debug(data);
return data;
}
async function calculate_price(ids) {
console.debug("Calculating price for: " + ids);
const response = await fetch(BASE_URL, {method: "POST", body: ids_to_body(ids), headers: {"Content-Type": "application/json"}});
if(response.status === 429) {
ratelimited(response);
let o = {}
for (let id of ids) {
o[id] = {"price_overview": {"final": 0.0}}
}
return o
}
const data = await response.json();
console.debug("mass price data:", data);
let _price = 0.0;
let unit = "£";
for (let value of Object.values(data)) {
console.debug("Value:", value)
if (value.price_overview == null) {
continue;
}
let new_unit = value.price_overview.final_formatted.slice(0, 1);
if((/\d/).test(new_unit)) {
//new_unit = value.price_overview.final_formatted.slice(-2, -1);
new_unit = value.price_overview.currency || '£'
}
unit = new_unit
_price += parseFloat(value.price_overview.final / 100);
}
return [_price, unit];
}
function find_unit(formatted) {
let unit = "£";
if((/\d/).test(formatted.slice(0, 1))) {
unit = formatted.slice(-2, -1);
}
return unit;
}
async function main() {
console.debug("Fetching app info for base game");
let root;
try {
root = await get_app_info(TS4_APP_ID);
} catch (e) {
alert(`Error fetching information from Steam: ${e}`);
window.location.reload();
};
console.debug("Fetching app info for DLCs");
let key = Object.keys(root)[0];
NAME_ELEMENT.textContent = root[key].name;
console.debug("Checking key: " + key);
let dlc_price = (root[key].price_overview || {final: 0.0}).final / 100;
let unit = find_unit((root[key].price_overview || {final_formatted: "£0.00"}).final_formatted);
if(root[key].dlc && root[key].dlc.length >= 0) {
document.getElementById("dlcs").hidden = false;
document.getElementById("dlc-count").textContent = root[key].dlc.length + " ";
let _result= await calculate_price(root[key].dlc)
dlc_price += _result[0];
}
if(root[key].header_image && root[key].capsule_image) {
let element2 = document.createElement("img");
element2.src = root[key].header_image;
element2.alt = root[key].name;
element2.style.height = "2em"
NAME_ELEMENT.textContent = null;
NAME_ELEMENT.appendChild(element2);
}
update(dlc_price.toFixed(2), unit);
let element = document.getElementById("comparison");
element.hidden = false;
for(let item of Object.keys(PRICES)) {
let price = compare(dlc_price, item);
if(price >= 0.95) {
let li = document.createElement("li");
li.textContent = `${price}x ${item} (${unit}${PRICES[item]}/pc)`;
element.children[1].appendChild(li);
}
};
}
main();