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 };