// ==UserScript== // @name iR Forum user stats // @namespace http://tampermonkey.net/ // @version 2.2_2026-03-17 // @description Show user stats in the iRacing forum // @author Max (refactored MR ver // @match https://forums.iracing.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=iracing.com // @downloadURL https://raw.githubusercontent.com/exenza/iracing_forum_browser_addon_drivers_stats/refs/heads/main/tampermonkey/ifbads_source.js // @updateURL https://raw.githubusercontent.com/exenza/iracing_forum_browser_addon_drivers_stats/refs/heads/main/tampermonkey/ifbads_source.js // ==/UserScript== 'use strict'; // Start User Configuration const CACHE_TTL = 5 * 60 * 1000; // 5 minutes const RECENT_EVENTS_COUNT = 2; // Number of recent events to display const RECENT_EVENTS_TYPES = ['RACE']; // Event types to display: 'RACE', 'PRACTICE', 'HOSTED', 'LEAGUE' // End user configuration const API_ENDPOINT = 'https://lrm4on1eih.execute-api.eu-west-2.amazonaws.com/prod'; const cache = new Map(); // Simple API fetch for single driver async function fetchSingleDriver(name) { if (!name || !name.trim()) { console.log('No valid name provided to fetchSingleDriver'); return null; } const url = `${API_ENDPOINT}/drivers?names=${encodeURIComponent(name.trim())}`; console.log('Fetching driver:', name); try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); return data[name] || null; } catch (error) { console.error('API Error for', name, ':', error); return null; } } // Cache helpers function getCached(name) { const cached = cache.get(name); if (cached && Date.now() - cached.timestamp < CACHE_TTL) { return cached.data; } cache.delete(name); return null; } function setCached(name, data) { cache.set(name, { data, timestamp: Date.now() }); }// SVG icons for license categories const svgIcons = { oval: ' viewBox="-2 -1.55 28 18">', sports_car: ' viewBox="-2 -2 28 18">', formula_car: ' viewBox="-2 -1 28 18">', sports_car: ' viewBox="-2 -2 28 18">', formula_car: ' viewBox="-2 -1 28 18">', dirt_oval: ' viewBox="-2 0 28 18">', dirt_road: ' viewBox="-2 0 28 18">', undefined: ' viewBox="0 0 1 18">' }; // Simple category detection from car name function getCarCategory(carName) { const name = carName.toLowerCase(); if (name.includes('formula') || name.includes('f1') || name.includes('f2') || name.includes('f3') || name.includes('indy') || name.includes('dallara') || name.includes('skip barber') || name.includes('lotus 79') || name.includes('williams') || name.includes('mclaren mp4')) { return 'formula_car'; } if (name.includes('dirt') && (name.includes('oval') || name.includes('sprint') || name.includes('late model') || name.includes('modified') || name.includes('midget') || name.includes('street stock'))) { return 'dirt_oval'; } if (name.includes('dirt') || name.includes('rally') || name.includes('beetle') || name.includes('fiesta') || name.includes('wrx') || name.includes('pro 2') || name.includes('pro 4')) { return 'dirt_road'; } if (name.includes('nascar') || name.includes('oval') || name.includes('legends') || name.includes('modified') || name.includes('sprint car') || name.includes('silver crown') || name.includes('street stock') || name.includes('late model') || name.includes('truck')) { return 'oval'; } return 'sports_car'; // Default for GT3, GTE, sports cars, etc. } // Helper functions function yearsSince(dateStr) { const years = (Date.now() - new Date(dateStr)) / (1000 * 60 * 60 * 24 * 365.25); return Math.floor(years); } // Generate license display function renderLicenses(driver) { if (!driver.member_info?.licenses) return ''; const licenses = driver.member_info.licenses.map(lic => { const className = lic.group_name.replace('Class ', '').replace('Rookie', 'R').replace('Pro', 'P'); const category = lic.category || 'undefined'; return `