const fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer'); const storage = require('./utils/storage'); function fileToDataUri(fullPath) { try { const buf = fs.readFileSync(fullPath); const ext = path.extname(fullPath).toLowerCase().replace('.', ''); const mime = { jpg: 'jpeg', jpeg: 'jpeg', png: 'png', gif: 'gif', webp: 'webp' }[ext] || 'jpeg'; return `data:image/${mime};base64,${buf.toString('base64')}`; } catch (e) { return null; } } function esc(str) { return String(str || '').replace(/[&<>"']/g, (c) => ( { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c] )); } const ROTATIONS = [-4, 3, -2, 5, -3, 2, -5, 4]; function buildFriendPageHtml(friend, folder) { const uploadsDir = path.join(storage.friendFolderPath(folder), 'uploads'); const profileUri = friend.profileImage ? fileToDataUri(path.join(uploadsDir, friend.profileImage)) : null; const steckbriefRows = Object.entries(friend.steckbrief || {}) .filter(([, v]) => v && String(v).trim()) .map(([k, v]) => `
${esc(k)}${esc(v)}
`) .join(''); const blocks = [...(friend.blocks || [])].sort((a, b) => a.order - b.order); const blockHtml = blocks .map((b, i) => { const rot = ROTATIONS[i % ROTATIONS.length]; if (b.type === 'text') { return `

${esc(b.content).replace(/\n/g, '
')}

${b.caption ? `
${esc(b.caption)}
` : ''}
`; } if (b.type === 'image') { const uri = fileToDataUri(path.join(uploadsDir, b.filename)); if (!uri) return ''; return `
${b.caption ? `
${esc(b.caption)}
` : ''}
`; } if (b.type === 'audio') { return `
🎵 Audio-Erinnerung${b.caption ? ': ' + esc(b.caption) : ''}
(im Web-Freundesbuch anhörbar)
`; } return ''; }) .join('\n'); return `
${profileUri ? `` : '
?
'}

${esc(friend.name)}

Steckbrief

${steckbriefRows || '

Noch nichts eingetragen.

'}
${blockHtml || '

Noch keine Erinnerungen hinzugefügt.

'}
`; } function buildFullHtml(friends) { const pages = friends .map((f) => buildFriendPageHtml(f, f.folderName)) .join('\n'); return ` ${pages || '

Noch keine Freunde angelegt.

'} `; } async function generateBookPdf() { const friends = storage.getAllFriendsMeta(); const html = buildFullHtml(friends); const browser = await puppeteer.launch({ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined, headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }); try { const page = await browser.newPage(); await page.setContent(html, { waitUntil: 'networkidle0' }); const buffer = await page.pdf({ format: 'A4', printBackground: true }); return buffer; } finally { await browser.close(); } } module.exports = { generateBookPdf, buildFullHtml };