48 lines
2.0 KiB
TypeScript
48 lines
2.0 KiB
TypeScript
// Converts a Steam2 id ("STEAM_0:1:12345678", as stored by the plugin) into
|
|
// a Steam64 id, which is what profile URLs and avatar lookups need.
|
|
const STEAM64_BASE = 76561197960265728n;
|
|
|
|
export function steam2ToSteam64(steamId2: string): string | null {
|
|
const match = /^STEAM_[0-5]:([01]):(\d+)$/.exec(steamId2.trim());
|
|
if (!match) return null;
|
|
const y = BigInt(match[1]);
|
|
const z = BigInt(match[2]);
|
|
return (STEAM64_BASE + y + z * 2n).toString();
|
|
}
|
|
|
|
export function steamProfileUrl(steamId2: string): string | null {
|
|
const id64 = steam2ToSteam64(steamId2);
|
|
return id64 ? `https://steamcommunity.com/profiles/${id64}` : null;
|
|
}
|
|
|
|
// Formats total minutes as "123h 45m" for display. Negative values (which
|
|
// shouldn't be possible, but have shown up from anomalous underlying data —
|
|
// e.g. a player_time counter that decreased between two session snapshots)
|
|
// are shown as "—" rather than a nonsensical negative duration.
|
|
export function formatMinutes(totalMinutes: number | null): string {
|
|
if (totalMinutes == null || Number.isNaN(totalMinutes) || totalMinutes < 0) return '—';
|
|
const h = Math.floor(totalMinutes / 60);
|
|
const m = totalMinutes % 60;
|
|
return `${h}h ${m}m`;
|
|
}
|
|
|
|
// ISO 3166-1 alpha-2 -> flag emoji, e.g. "DE" -> "🇩🇪". No external assets needed.
|
|
export function countryCodeToFlag(code: string | null): string {
|
|
if (!code || code.length !== 2) return '🏳️';
|
|
const codePoints = [...code.toUpperCase()].map((c) => 0x1f1a5 + c.charCodeAt(0));
|
|
return String.fromCodePoint(...codePoints);
|
|
}
|
|
|
|
// ISO 3166-1 alpha-2 -> English display name, e.g. "DE" -> "Germany".
|
|
// Uses the built-in Intl.DisplayNames (Node 14+ / all modern browsers) —
|
|
// no extra dependency or lookup table needed.
|
|
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
|
|
export function countryCodeToName(code: string | null): string {
|
|
if (!code || code.length !== 2) return 'Unknown';
|
|
try {
|
|
return regionNames.of(code.toUpperCase()) ?? code;
|
|
} catch {
|
|
return code;
|
|
}
|
|
}
|