([\s\S]*?)<\/tr>/g;
let m: RegExpExecArray | null;
while ((m = rowRe.exec(html)) !== null) {
if (m[1] !== undefined) {
// ── Ligne séparateur de date : "Wednesday, Jul 01" ──────────────────
const dm = m[1].match(/([A-Za-z]+)\s+(\d{1,2})/);
if (!dm) continue;
const monIdx = MONTHS[dm[1].slice(0, 3).toLowerCase()];
if (monIdx === undefined) continue;
const day = parseInt(dm[2], 10);
if (lastMonth !== -1 && monIdx < lastMonth) currentYear += 1; // rollover déc → jan
lastMonth = monIdx;
currentDateStr = `${currentYear}-${String(monIdx + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
continue;
}
// ── Ligne événement ────────────────────────────────────────────────────
const [, , eventDateId, , , , , , countryName, body] = m;
if (!currentDateStr) continue;
const ccy = FX_NAME_TO_CURRENCY[countryName];
const code = FX_NAME_TO_CODE[countryName];
if (!ccy || !code) continue;
const cells = Array.from(body.matchAll(/| ]*>([\s\S]*?)<\/td>/g), c => c[1]);
if (cells.length < 7) continue;
const timeM = cells[0].match(/(\d{1,2}):(\d{2})/);
const time24 = timeM ? `${timeM[1].padStart(2, "0")}:${timeM[2]}` : "00:00";
const isoDate = `${currentDateStr}T${time24}:00Z`;
const evDate = new Date(isoDate);
const title = stripTags(cells[2]);
if (!title) continue;
const volM = stripTags(cells[3]).match(/\d+/);
const impact = impactFromVolatility(volM ? parseInt(volM[0], 10) : 0);
const actual = stripTags(cells[4]) || null;
const forecast = stripTags(cells[5]) || null;
const previous = stripTags(cells[6]) || null;
events.push({
id: `il_${eventDateId}`,
date: isoDate,
currency: ccy,
countryCode: code,
category: fxCategory(title),
title,
impact,
actual,
forecast,
previous,
isPublished: actual !== null || evDate < now,
});
}
events.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
return events;
}
// ── Fetch ──────────────────────────────────────────────────────────────────
// fromDate / toDate au format YYYY-MM-DD
export async function fetchFXStreetCalendar(fromDate: string, toDate: string): Promise {
const start = fromDate.replace(/-/g, "");
const end = toDate.replace(/-/g, "");
const url =
`https://calendar.fxstreet.com/EventDateWidget/GetMain` +
`?culture=en-US&timezone=UTC&start=${start}&end=${end}&view=range&rows=5000` +
`&countrycode=${FXSTREET_COUNTRYCODES}`;
try {
const res = await fetch(url, {
next: { revalidate: 1800 },
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://investinglive.com/EconomicCalendar",
},
});
if (!res.ok) { console.warn("[fxstreet] HTTP", res.status); return []; }
const html = await res.text();
return parseFXStreetHTML(html, fromDate);
} catch (err) {
console.error("[fxstreet] error:", err);
return [];
}
}
|