// Kühlfinder-Scraper-Runner. Läuft als Coolify Scheduled Task (z.B. alle 30 Min). // Holt aktuelle Bestände direkt von den Händlern, schreibt availability.json + // hängt Restock-Events an history.json (Basis für die Prognose). import { readFile, writeFile } from 'node:fs/promises'; import * as obi from './adapters/obi.mjs'; import * as toom from './adapters/toom.mjs'; import * as bauhaus from './adapters/bauhaus.mjs'; import * as hornbach from './adapters/hornbach.mjs'; const ADAPTERS = [obi, toom, bauhaus, hornbach /*, mediamarkt, saturn, expert, euronics, amazon */]; const OUT = new URL('../public/data/', import.meta.url); async function loadJson(name, fallback) { try { return JSON.parse(await readFile(new URL(name, OUT))); } catch { return fallback; } } async function main() { const stores = await loadJson('stores.json', []); const prev = await loadJson('availability.json', { offers: [] }); const prevMap = new Map(prev.offers.map(o => [o.storeId + '|' + o.productId, o])); const history = await loadJson('history.json', { events: [] }); const offers = []; for (const ad of ADAPTERS) { for (const productId of Object.keys(ad.products || {})) { // Online-/Default-Markt-Check (Per-Markt-Loop sobald marketId-Mapping steht) try { const r = await ad.fetchProduct(productId, {}); if (r) { offers.push(r); const key = (r.marketId || ad.meta.id) + '|' + productId; const before = prevMap.get(key); // Restock-Event: war nicht verfügbar -> jetzt verfügbar if (before && before.availability === 'out_of_stock' && r.availability !== 'out_of_stock') { history.events.push({ storeId: r.marketId || ad.meta.id, productId, chain: ad.meta.name, at: r.checkedAt }); } } } catch (e) { console.error(ad.meta.id, productId, e.message); } await new Promise(r => setTimeout(r, 800 + Math.random() * 1200)); // höflich: Jitter } } const snapshot = { generatedAt: new Date().toISOString(), source: 'kuehlfinder-scraper', offers }; await writeFile(new URL('availability.json', OUT), JSON.stringify(snapshot)); await writeFile(new URL('history.json', OUT), JSON.stringify(history)); console.log('scraped offers:', offers.length, 'history events:', history.events.length); } main();