You've already forked tf2wikipricing
feat: fetch currency exchange rate
exchange rates are fetched at script startup, and at most once daily, then cached. attribution is added as per ExchangeRate-API's requirements
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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('%@', '<a rel="nofollow" class="external text" href="https://prices.tf">prices.tf</a>');
|
||||
label.innerHTML = `${updateText}<br>${attributionText}`;
|
||||
const exchangeRateAttribution = `<a rel="nofollow" class="external text" href="https://www.exchangerate-api.com">Rates By Exchange Rate API</a>.`;
|
||||
label.innerHTML = `${updateText}<br>${attributionText}<br>${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
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error);
|
||||
})
|
||||
55
src/content/exchangeRateService.ts
Normal file
55
src/content/exchangeRateService.ts
Normal file
@@ -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<Response>
|
||||
import './GM_fetch'
|
||||
|
||||
export interface ExchangeRates {
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export async function wipeExchangeRates(): Promise<void> {
|
||||
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<ExchangeRates> {
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user