const fs = require("fs"); const path = require("path"); const { PDFDocument } = require("pdf-lib"); function clean(value) { if (value == null) return ""; return String(value).replace(/\0/g, "").replace(/\s+/g, " ").trim(); } function titleFromFilename(filePath) { return path .basename(filePath, path.extname(filePath)) .replace(/[_]+/g, " ") .replace(/\s+/g, " ") .trim(); } function parseKeywords(value) { if (!value) return []; const list = Array.isArray(value) ? value : String(value).split(/[,;]+/); return [...new Set(list.map(clean).filter(Boolean))]; } function uniqueDest(dir, originalName) { const ext = path.extname(originalName) || ".pdf"; const stem = path .basename(originalName, ext) .replace(/[<>:"/\\|?*]+/g, "-") .slice(0, 80) || "document"; let dest = path.join(dir, `${stem}${ext}`); let n = 2; while (fs.existsSync(dest)) { dest = path.join(dir, `${stem}-${n}${ext}`); n += 1; } return dest; } async function extractMetadata(filePath) { const bytes = fs.readFileSync(filePath); const pdf = await PDFDocument.load(bytes, { ignoreEncryption: true, updateMetadata: false, }); return { title: clean(pdf.getTitle()) || titleFromFilename(filePath), author: clean(pdf.getAuthor()), totalPages: pdf.getPageCount(), notes: clean(pdf.getSubject()), tags: parseKeywords(pdf.getKeywords()), }; } async function importPdfFiles(filePaths, destDir, existingNames) { fs.mkdirSync(destDir, { recursive: true }); const known = new Set((existingNames || []).map((name) => name.toLowerCase())); const imported = []; const skipped = []; const errors = []; for (const filePath of filePaths) { const sourceName = path.basename(filePath); if (!filePath.toLowerCase().endsWith(".pdf")) { skipped.push({ file: sourceName, reason: "not a PDF" }); continue; } if (known.has(sourceName.toLowerCase())) { skipped.push({ file: sourceName, reason: "already in catalog" }); continue; } try { const meta = await extractMetadata(filePath); const dest = uniqueDest(destDir, sourceName); fs.copyFileSync(filePath, dest); known.add(sourceName.toLowerCase()); imported.push({ ...meta, pdfPath: dest, sourceName, }); } catch (err) { errors.push({ file: sourceName, message: err.message }); } } return { imported, skipped, errors }; } module.exports = { importPdfFiles };