A rewrite of Poly+, my quality-of-life browser extension for Polytoria. Built entirely fresh using the WXT extension framework, Typescript, and with added better overall code quality.
extension
1import { cache } from "./storage"; 2import { cacheInterface } from "./types"; 3import * as currencyPackages from "./currencyPackages.json" 4 5export async function pullCache(key: string, replenish: Function, expiry: number, forceReplenish: boolean) { 6 const cacheStorage: cacheInterface = await cache.getValue(); 7 const metadata = await cache.getMeta() as { [key: string]: number; }; 8 9 const overlap = Date.now() - metadata[key]; 10 if (!cacheStorage[key] || forceReplenish || (overlap >= expiry)) { 11 console.info('[Poly+] "' + key + '" cache is stale replenishing...', timeAgo(overlap)); 12 13 const replenishedCache = await replenish(); 14 cacheStorage[key] = replenishedCache; 15 metadata[key] = Date.now(); 16 17 cache.setValue(cacheStorage); 18 cache.setMeta(metadata); 19 } 20 21 return cacheStorage[key]; 22}; 23 24export async function expireCache(key: string) { 25 console.info('[Poly+] Forcefully expiring "' + key + '" cache...'); 26 27 const metadata = await cache.getMeta() as { [key: string]: number }; 28 metadata[key] = 0; 29 cache.setMeta(metadata); 30}; 31 32function timeAgo(overlap: number) { 33 const units = [ 34 { label: 'day', value: 24 * 60 * 60 * 1000 }, 35 { label: 'hour', value: 60 * 60 * 1000 }, 36 { label: 'min', value: 60 * 1000 }, 37 { label: 'sec', value: 1000 }, 38 ]; 39 40 for (const { label, value } of units) { 41 const count = Math.floor(overlap / value); 42 if (count > 0) { 43 return `${count} ${label}${count > 1 ? 's' : ''} ago`; 44 } 45 overlap %= value; 46 } 47 48 return 'just now'; 49}; 50 51export async function getUserDetails() { 52 const profileLink: HTMLLinkElement = document.querySelector('.navbar a.text-reset[href^="/users/"]')!; 53 const brickBalance = document.getElementsByClassName('brickBalanceCount')[0]; 54 55 if (!profileLink || !brickBalance) return null; 56 return { 57 username: profileLink.innerText.trim(), 58 userId: parseInt(profileLink.href.split('/')[4]), 59 bricks: parseInt(brickBalance.textContent!.replace(/,/g, "")) 60 } 61}; 62 63export function bricksToCurrency(bricks: number, currency: string): string | null { 64 if (isNaN(bricks) || bricks == 0) return null; 65 66 const _currencyPackages = currencyPackages as Record<string, Array<Array<number>>>; 67 const packages = _currencyPackages[currency].toSorted((a, b) => b[1] - a[1]); 68 69 if (!packages) { 70 console.warn('[Poly+] Missing currency package data for selected currency!'); 71 return null; 72 } 73 74 let totalValue = 0; 75 for (const [currencyValue, bricksValue] of packages) { 76 while (bricks >= bricksValue) { 77 bricks -= bricksValue; 78 totalValue += currencyValue; 79 } 80 } 81 82 if (bricks > 0) { 83 const cheapestPackage = packages[packages.length - 1]; 84 const [currencyValue, bricksValue] = cheapestPackage; 85 const unitPrice = currencyValue / bricksValue; 86 totalValue += bricks * unitPrice; 87 } 88 89 return `~${totalValue.toFixed(2)} ${currency}`; 90};