diff --git a/src/content/config.ts b/src/content/config.ts index 41e0477..282de8d 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -3,6 +3,9 @@ export const storage_lastUpdateTime = 'tf2wikipricing_lastUpdate'; export const storage_schema = 'tf2wikipricing_schema'; export const storage_version = 'tf2wikipricing_version'; export const storage_priceprefix = 'tf2wikipricing_sku_'; +export const storage_exchangerates = 'tf2wikipricing_exchangerates'; +export const storage_exchangerates_update = 'tf2wikipricing_exchangerates_update'; +export const storage_exchangerates_next = 'tf2wikipricing_exchangerates_next'; export const conversion_ref_usd = 0.0265; export const defindex_key = 5021; export const defindex_metal_refined = 5002; diff --git a/src/content/content.ts b/src/content/content.ts index 1d8cbb5..288fe02 100644 --- a/src/content/content.ts +++ b/src/content/content.ts @@ -9,7 +9,9 @@ import { fetchPrice, fetchKeyPrice, ItemPriceData } from './priceService' import { createPriceRow, createStoreButton } from './uiRenderer' import { findFirstElement, findFirstChildElement } from './utils/dom' import { extractPageTitleFromURL } from './utils/url'; +import { ExchangeRates, prepareExchangeRates } from './exchangeRateService'; var itemSchema: ItemSchema | null; +var exchangeRates: ExchangeRates | null; var locale: string = 'en' @@ -425,7 +427,8 @@ async function inject() { label.style.fontSize = "85%"; const updateText = $T("Updated %@.", locale).replace('%@', updateTime.toLocaleString(locale, { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' })) const attributionText = $T("Trade prices sourced from %@. Currency conversions are approximate.", locale).replace('%@', 'prices.tf'); - label.innerHTML = `${updateText}
${attributionText}`; + const exchangeRateAttribution = `Rates By Exchange Rate API.`; + label.innerHTML = `${updateText}
${attributionText}
${exchangeRateAttribution}`; row.appendChild(label); priceProgressRow.insertAdjacentElement('afterend', row); @@ -440,15 +443,22 @@ function addStyles() { style.innerHTML = styleCss; } -prepareSchema().then(function (schema) { +prepareSchema() +.then(schema => { itemSchema = schema; if (!itemSchema) { - logError("No item schema ready, exiting."); wipeSchema(); // FIXME: ugly hack. requires additional page reload. if prepareSchema returns null, we should handle it properly - return; + throw new Error("No item schema ready"); } +}) +.then(prepareExchangeRates) +.then(rates => exchangeRates = rates) +.then(() => { locale = extractLocaleFromURL(document.URL) addStyles(); inject(); // TODO: Purge expired price data -}); \ No newline at end of file +}) +.catch((error) => { + logError(error); +}) \ No newline at end of file diff --git a/src/content/exchangeRateService.ts b/src/content/exchangeRateService.ts new file mode 100644 index 0000000..fe3a24a --- /dev/null +++ b/src/content/exchangeRateService.ts @@ -0,0 +1,55 @@ +import { getStorageValue, setStorageValue } from './storage' +import { logDebug, log, logError } from './utils/log' +import { storage_exchangerates, storage_exchangerates_next, storage_exchangerates_update } from './config' +declare function GM_fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise +import './GM_fetch' + +export interface ExchangeRates { + [key: string]: number; +} + +export async function wipeExchangeRates(): Promise { + await setStorageValue(storage_exchangerates, null) + await setStorageValue(storage_exchangerates_update, new Date().toISOString()) + await setStorageValue(storage_exchangerates_next, new Date().toISOString()) + logDebug(`Exchange rates wiped`) +} + +export async function prepareExchangeRates(): Promise { + var needsUpdate: Boolean = false + var rates: ExchangeRates | null = null + + rates = await getStorageValue(storage_exchangerates, null); + const update = await getStorageValue(storage_exchangerates_update, null) + const nextUpdate = await getStorageValue(storage_exchangerates_next, null) + if (update && nextUpdate) { + const lastUpdateTime = new Date(update); + const nextUpdateTime = new Date(nextUpdate); + log(`Exchange rates updated at ${lastUpdateTime}`); + if (rates == null || Object.keys(rates).length === 0 || lastUpdateTime.getTime() > nextUpdateTime.getTime()) { + needsUpdate = true + } + } else { + needsUpdate = true + } + + if(needsUpdate) { + log("Exchange rates out of Date. Rebuilding..."); + const url = "https://open.er-api.com/v6/latest/USD" + const response = await GM_fetch(url); + if (response.ok) { + await setStorageValue(storage_exchangerates_update, new Date().toISOString()) + var json = await response.json() + if(json != null){ + rates = json['rates'] + await setStorageValue(storage_exchangerates, rates) + await setStorageValue(storage_exchangerates_next, json['time_next_update_utc']) + } + logDebug(`Exchange rates updated at ${new Date()}`) + } else { + logError(`Failed to fetch exchange rates. Status code: ${response.status}`, response) + } + } + + return rates +}