feat: KöPi - nur spezifische Filialen anzeigen

This commit is contained in:
2026-07-09 00:02:57 +02:00
parent c544e14171
commit 73ce4264ae
2 changed files with 37 additions and 10 deletions

View File

@@ -56,12 +56,33 @@ function extractNextData(html) {
try { return JSON.parse(html.slice(start, end)); } catch { return null; }
}
// ── Händler-Filter ────────────────────────────────────────────────────────────
const TARGET_PUBLISHERS = ['rewe','edeka','netto','trinkgut','getränke','penny','aldi','lidl'];
// ── Gewünschte Filialen ──────────────────────────────────────────────────────
const TARGET_STORES = [
{ name: 'edeka', street: 'düsseldorfer landstr', label: 'EDEKA E center Angerbogen' },
{ name: 'edeka', street: 'angerbogen', label: 'EDEKA E center Angerbogen' },
{ name: 'e center', street: 'düsseldorfer', label: 'EDEKA E center Angerbogen' },
{ name: 'rewe', street: 'mündelheimer', label: 'REWE Mündelheimer Str.' },
{ name: 'rewe', street: 'keniastr', label: 'REWE XXL Schwinning' },
{ name: 'netto', street: 'bonnefeld', label: 'Netto Im Bonnefeld' },
{ name: 'kaufland', street: 'auf der höhe', label: 'Kaufland Kaßlerfeld' },
{ name: 'penny', street: 'sittardsberger', label: 'Penny Sittardsberger Allee' },
{ name: 'trinkgut', street: 'keniastr', label: 'Trinkgut Keniastraße' },
];
function matchesTargetStore(publisherName, storeName, street) {
const p = (publisherName || '').toLowerCase();
const s = (storeName || '').toLowerCase();
const r = (street || '').toLowerCase();
for (const t of TARGET_STORES) {
if ((p.includes(t.name) || s.includes(t.name)) && r.includes(t.street)) return t.label;
}
return null;
}
function isTargetPublisher(name) {
if (!name) return false;
const n = name.toLowerCase();
return TARGET_PUBLISHERS.some(p => n.includes(p));
return ['rewe','edeka','e center','netto','kaufland','penny','trinkgut'].some(p => n.includes(p));
}
// ── Angebote via Puppeteer (BrochureBox_Basic + OfferGrid) ──────────────────
@@ -171,10 +192,12 @@ async function scrapeProspekte() {
const cached = cacheGet(cacheKey);
if (cached) return cached;
// Koordinaten rund um deine Filialen (alle im Süden Duisburgs)
const locations = [
{ lat: 51.4332, lng: 6.7625, city: 'Duisburg', zip: '47051' },
{ lat: 51.5167, lng: 6.9833, city: 'Essen', zip: '45127' },
{ lat: 51.2217, lng: 6.7762, city: 'Düsseldorf', zip: '40213' },
{ lat: 51.3750, lng: 6.7680, city: 'Duisburg', zip: '47259' }, // Im Bonnefeld / Netto
{ lat: 51.4020, lng: 6.7616, city: 'Duisburg', zip: '47055' }, // REWE Mündelheimer
{ lat: 51.4406, lng: 6.7555, city: 'Duisburg', zip: '47059' }, // Kaufland / REWE Kenia / Trinkgut
{ lat: 51.3900, lng: 6.7900, city: 'Duisburg', zip: '47259' }, // Penny Sittardsberger
];
const allBrochures = new Map();
@@ -199,20 +222,24 @@ async function scrapeProspekte() {
const publisher = c.publisher?.name || '';
const store = c.closestStore;
const storeStreet = store ? `${store.street || ''} ${store.streetNumber || ''}`.trim() : '';
const matchLabel = matchesTargetStore(publisher, store?.name, storeStreet);
allBrochures.set(id, {
id,
publisher,
title: c.title || '',
store: store?.name || publisher,
storeLabel: matchLabel || store?.name || publisher,
city: store?.city || loc.city,
street: store ? `${store.street || ''} ${store.streetNumber || ''}`.trim() : '',
street: storeStreet,
zip: store?.zip || loc.zip,
image: c.brochureImages?.find(i => i.size === '260x270')?.url || c.brochureImage?.url || null,
validFrom: c.validFrom || null,
validTo: c.validUntil || null,
pageCount: c.pageCount || null,
url: `https://www.kaufda.de/webapp/brochure/${id}`,
isTarget: isTargetPublisher(publisher),
isTarget: !!matchLabel,
badges: c.contentBadges?.map(b => b.name) || [],
});
}

View File

@@ -183,11 +183,11 @@ function ProspektCard({ b }) {
<div style={{ display:'inline-block', background:`${color}22`, border:`1px solid ${color}44`,
borderRadius:4, padding:'2px 8px', marginBottom:6,
color, fontFamily:'monospace', fontSize:10, fontWeight:700 }}>
{b.publisher}
{b.storeLabel || b.publisher}
</div>
<div style={{ color:'#fff', fontFamily:'monospace', fontSize:11, marginBottom:3, lineHeight:1.4 }}>{b.title}</div>
<div style={{ color:'rgba(255,255,255,0.4)', fontFamily:'monospace', fontSize:10, marginBottom:2 }}>
📍 {b.store}{b.city && b.store !== b.city ? ` · ${b.city}` : ''}
📍 {b.street || b.store}{b.city ? ` · ${b.city}` : ''}
</div>
{b.street && <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9 }}>{b.street}</div>}
{(b.validFrom || b.validTo) && (