From eed658ccc4c584486bd300c10e7068e7201e17d9 Mon Sep 17 00:00:00 2001 From: Dicken Date: Thu, 9 Jul 2026 09:02:47 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20K=C3=B6Pi=20-=20Bilder=20via=20Node+Cook?= =?UTF-8?q?ies,=20NEU=20Badge=20weg,=20Prospekt=20URLs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/tools/koepi/routes.js | 49 +++++++++++++++++-------------- frontend/src/tools/koepi.jsx | 9 +++--- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/backend/src/tools/koepi/routes.js b/backend/src/tools/koepi/routes.js index 74511ae..f952e75 100644 --- a/backend/src/tools/koepi/routes.js +++ b/backend/src/tools/koepi/routes.js @@ -89,27 +89,32 @@ async function scrapeMarktguru() { }); }); - // Bilder als Base64 laden (cdn.marktguru.de blockt externe Requests) - for (const offer of offers) { - if (!offer.image) continue; - try { - const imgData = await page.evaluate(async (url) => { - try { - const resp = await fetch(url, {credentials:'include'}); - if (!resp.ok) return null; - const blob = await resp.blob(); - return new Promise(resolve => { - const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result); - reader.onerror = () => resolve(null); - reader.readAsDataURL(blob); - }); - } catch { return null; } - }, offer.image); - if (imgData) offer.image = imgData; - else offer.image = null; - } catch { offer.image = null; } - } + // Bilder über Node https laden mit Cookies aus dem Browser + const cookies = await page.cookies('https://cdn.marktguru.de'); + const cookieStr = cookies.map(c => `${c.name}=${c.value}`).join('; '); + + await Promise.all(offers.map(offer => new Promise(resolve => { + if (!offer.image) return resolve(); + const req = require('https').get(offer.image, { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', + 'Referer': 'https://www.marktguru.de/', + 'Cookie': cookieStr, + } + }, res => { + if (res.statusCode !== 200) { offer.image = null; return resolve(); } + const chunks = []; + res.on('data', c => chunks.push(c)); + res.on('end', () => { + const b64 = Buffer.concat(chunks).toString('base64'); + const mime = res.headers['content-type'] || 'image/webp'; + offer.image = `data:${mime};base64,${b64}`; + resolve(); + }); + }); + req.on('error', () => { offer.image = null; resolve(); }); + req.setTimeout(8000, () => { req.destroy(); offer.image = null; resolve(); }); + }))); // Filtern auf Ziel-Händler + nur König Pilsener const filtered = offers.filter(o => { @@ -209,7 +214,7 @@ async function scrapeProspekte() { validFrom: c.validFrom || null, validTo: c.validUntil || null, pageCount: c.pageCount || null, - url: `https://www.kaufda.de/webapp/brochure/${id}`, + url: `https://www.kaufda.de/Prospekte/${encodeURIComponent(pub.replace(/\s+/g,'-'))}?brochureId=${id}`, isTarget: isTargetRetailer(pub), badges: c.contentBadges?.map(b => b.name) || [], }); diff --git a/frontend/src/tools/koepi.jsx b/frontend/src/tools/koepi.jsx index 9651e69..e28b962 100644 --- a/frontend/src/tools/koepi.jsx +++ b/frontend/src/tools/koepi.jsx @@ -128,10 +128,11 @@ function ProspektCard({ b }) { onError={e => { e.target.style.display='none'; }} /> )} -
- {isNew && NEU} - {expiring && ENDET BALD} -
+ {expiring && ( +
+ ENDET BALD +
+ )}