import axios from 'axios'; import * as cheerio from 'cheerio'; export interface CooldownData { isActive: boolean; expiresAt?: Date; } // Custom error to identify session death export class SteamAuthError extends Error { constructor(message: string) { super(message); this.name = "SteamAuthError"; } } export const scrapeCooldown = async (steamId: string, steamLoginSecure: string): Promise => { const url = `https://steamcommunity.com/profiles/${steamId}/gcpd/730?tab=matchmaking`; try { const response = await axios.get(url, { headers: { 'Cookie': steamLoginSecure, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }, timeout: 10000, validateStatus: (status) => status < 500 // Allow redirects to handle them manually }); // If Steam redirects us to the login page, the cookie is dead if (response.data.includes('Sign In') || response.request.path.includes('/login')) { throw new SteamAuthError('Invalid or expired steamLoginSecure cookie'); } const $ = cheerio.load(response.data); if (!response.data.includes('Personal Game Data')) { throw new SteamAuthError('Session invalid: Personal Game Data not accessible'); } let expirationDate: Date | undefined = undefined; $('table').each((_, table) => { const headers = $(table).find('th').map((_, th) => $(th).text().trim()).get(); const expirationIndex = headers.findIndex(h => h.includes('Competitive Cooldown Expiration') || h.includes('Cooldown Expiration')); if (expirationIndex !== -1) { const rows = $(table).find('tr').not(':has(th)'); rows.each((_, row) => { const dateText = $(row).find('td').eq(expirationIndex).text().trim(); if (dateText && dateText !== '') { const cleanDateText = dateText.replace(' GMT', ' UTC'); const parsed = new Date(cleanDateText); if (!isNaN(parsed.getTime())) { if (!expirationDate || parsed > (expirationDate as Date)) expirationDate = parsed; } } }); } }); if (expirationDate && (expirationDate as Date).getTime() > Date.now()) { return { isActive: true, expiresAt: expirationDate }; } const content = $('#personal_game_data_content').text(); if (content.includes('Competitive Cooldown') || content.includes('Your account is currently')) { return { isActive: true }; } return { isActive: false }; } catch (error: any) { if (error instanceof SteamAuthError) throw error; console.error(`[Scraper] Network/Internal Error for ${steamId}:`, error.message); throw error; // Generic errors don't trigger re-auth } };