feat: KoePi Mobile-Buttons scrollbar, Prospekte chronologisch getrennt, exakte Bildauswahl-Tabelle, Sondermagazine ausgeblendet

This commit is contained in:
2026-07-18 02:31:35 +02:00
parent c7941b10ce
commit 263610b0bc
3 changed files with 69 additions and 40 deletions

View File

@@ -384,27 +384,39 @@ async function fetchOffersViaPuppeteer() {
}
}
// Prüft, ob "COUNT x VOL" (z.B. "20 x 0,5") in der Beschreibung vorkommt —
// robust gegen Leerzeichen um das "x", Komma/Punkt als Dezimaltrennzeichen,
// und verhindert Fehltreffer wie "0,5" innerhalb von "0,55"
function hasQty(desc, count, vol) {
const volPattern = vol.replace(',', '[,.]');
const re = new RegExp(`${count}\\s*x\\s*${volPattern}(?!\\d)`, 'i');
return re.test(desc);
}
// Bild pro Angebot exakt nach Mengenangabe wählen (siehe Vorgabe):
// 20x0,5 -> kasten_050 | 20x0,33 -> kasten_steini | 24x0,33 -> kasten_033
// 11x0,5 -> kasten_11er | 6x0,33 -> traeger | 24x0,5 -> palette_050
// 20x0,5 UND 24x0,33 gleichzeitig -> kasten_033_055 | sonst -> koepi_platzhalter
function pickOfferImage(description) {
const d = (description || '').toLowerCase();
const q2005 = hasQty(d, 20, '0,5');
const q2433 = hasQty(d, 24, '0,33');
if (q2005 && q2433) return '/koepi/kasten_033_055.png';
if (hasQty(d, 20, '0,33')) return '/koepi/kasten_steini.png';
if (q2433) return '/koepi/kasten_033.png';
if (hasQty(d, 11, '0,5')) return '/koepi/kasten_11er.png';
if (hasQty(d, 6, '0,33')) return '/koepi/traeger.png';
if (hasQty(d, 24, '0,5')) return '/koepi/palette_050.png';
if (q2005) return '/koepi/kasten_050.png';
return '/koepi/koepi_platzhalter.png';
}
// Gemeinsame Weiterverarbeitung, egal ob die Rohdaten über die API oder per
// Puppeteer/HTML-Scraping ermittelt wurden
function processOffers(offers) {
// Lokale Bilder auswählen basierend auf Beschreibung
for (const offer of offers) {
const desc = (offer.description || '').toLowerCase();
if (desc.includes('steini')) {
offer.imageLocal = '/koepi/kasten_steini.png';
} else if (desc.includes('11 x 0,5') || desc.includes('11x0,5')) {
offer.imageLocal = '/koepi/kasten_lang.png';
} else if (desc.includes('6 x') || desc.includes('6x') || (desc.includes('flasche') && !desc.includes('kasten'))) {
offer.imageLocal = '/koepi/traeger.png';
} else if (desc.includes('24 x 0,33') || desc.includes('24x0,33')) {
offer.imageLocal = '/koepi/kasten_033.png';
} else if (desc.includes('0,5')) {
offer.imageLocal = '/koepi/kasten_050.png';
} else if (desc.includes('0,33')) {
offer.imageLocal = '/koepi/kasten_033.png';
} else {
offer.imageLocal = '/koepi/kasten_050.png';
}
offer.imageLocal = pickOfferImage(offer.description);
offer.image = null; // CDN nicht mehr nötig
}
@@ -547,12 +559,30 @@ async function scrapeProspekte() {
for (const b of all) b.hasKoenigPilsener = false;
}
// "Sondermagazin"-Prospekte ausblenden (keine normalen Wochenangebote)
const withoutSondermagazin = all.filter(b => !(b.title || '').toLowerCase().includes('sondermagazin'));
const targeted = withoutSondermagazin.filter(b => b.isTarget);
// Chronologisch in "aktuell laufend" und "kommend" trennen
const todayIso = new Date().toISOString().slice(0, 10);
const isCurrent = b => {
const from = (b.validFrom || '').slice(0, 10);
const to = (b.validTo || '').slice(0, 10);
if (!from) return true; // ohne Datum lieber anzeigen als verstecken
if (from > todayIso) return false; // startet erst noch
if (to && to < todayIso) return false; // schon abgelaufen
return true;
};
const byValidFrom = (a, b) => (a.validFrom || '').localeCompare(b.validFrom || '');
const current = targeted.filter(isCurrent).sort(byValidFrom);
const future = targeted.filter(b => !isCurrent(b)).sort(byValidFrom);
const result = {
targeted: all.filter(b => b.isTarget),
others: all.filter(b => !b.isTarget),
current,
future,
scrapedAt: new Date().toISOString(),
};
console.log(`🍺 KöPi Prospekte: ${result.targeted.length} eigene Filiale(n), ${result.others.length} andere Filialen derselben Ketten, ${result.targeted.filter(b=>b.hasKoenigPilsener).length} davon mit König Pilsener im Angebot`);
console.log(`🍺 KöPi Prospekte: ${current.length} aktuell laufend, ${future.length} kommend, ${current.filter(b=>b.hasKoenigPilsener).length} davon aktuell mit König Pilsener im Angebot`);
cacheSet(cacheKey, result);
return result;
}