BOOK-LIBRARY: импорт, метаданные и каталог
Самая интересная часть BOOK-LIBRARY находится не в самой карточке книги, а в пути от файла до этой карточки. Проект принимает разные форматы книг, пытается достать из них метаданные, при нехватке данных обращается к LLM и ищет обложку во внешних источниках.
Это хорошо подходит для реальной коллекции: файлы часто называются по-разному, внутри могут быть неполные метаданные, а руками заполнять каждую запись долго.
Одиночная загрузка
Форма добавления книги находится в frontend/src/routes/admin/add-book/+page.svelte. Она отправляет multipart form на /api/admin/books.
Поля устроены практично:
- файл книги обязателен;
- категория в форме отмечена как обязательная;
- название, автор, описание и обложка могут быть заполнены вручную;
- подсказка в интерфейсе говорит, что часть информации можно оставить пустой для автоматического заполнения.
На backend это обрабатывает createBook в backend/controllers/adminController.js. Если каких-то данных не хватает, запускается processBookFile. После этого backend выбирает итоговые значения: берёт ручной ввод, а пустые поля дополняет результатом автоимпорта.
Извлечение метаданных из файлов
Сервис backend/services/metadataParser.js подтверждает поддержку нескольких форматов:
- FB2 — XML-разбор через
xml2js, с учётом кодировки и извлечениемtitle-info; - EPUB — разбор как ZIP-архива через
yauzl, поиск OPF-метаданных и текста; - PDF — извлечение текста через
pdf-parse.
Для FB2 проект отдельно нормализует HTML/XML-сущности и пытается собрать автора из доступных полей: имя, отчество, фамилия или nickname. Для текста берётся фрагмент первых секций, чтобы дальше дать LLM контекст.
Это не «магический» импорт. Это последовательная попытка получить нормальный минимум: название, автор, описание и текстовый фрагмент, который помогает уточнить карточку.
LLM-обогащение
Сервис backend/services/llmService.js использует OpenAI-compatible клиент и Polza AI endpoint. Prompt просит вернуть строгий JSON с полями:
title;author;category;description;coverSearchQuery.
В prompt передаются предполагаемые название и автор, имя файла, существующие категории и фрагмент текста. Это важная деталь: проект не просто просит «описать книгу», а даёт модели контекст и список уже заведённых категорий, чтобы уменьшить хаос в классификации.
В статьях про проект лучше формулировать это осторожно. LLM помогает подготовить черновые метаданные, но не гарантирует безошибочную библиографическую точность. Для личной библиотеки это нормально: администратор может проверить карточку после импорта.
Поиск обложек
Обложки ищутся в backend/services/imageSearchService.js. Сервис пробует несколько источников по очереди:
- Open Library;
- Google Books;
- DuckDuckGo Images.
Если URL найден, autoImportService скачивает изображение во временную папку, а затем обложка обрабатывается через Sharp и сохраняется как WebP. Для каталога это удобно: frontend всегда может запросить /uploads/covers/<id>.webp и не думать о формате исходной картинки.
Пакетный ZIP-импорт
Batch upload нужен, когда книг много. Администратор загружает ZIP-архив на /api/admin/books/batch. Контроллер распаковывает архив и работает в одном из двух режимов:
- если внутри есть
books.json, берёт список и возможные ручные поля оттуда; - если
books.jsonнет, сам находит файлы с расширениямиpdf,epub,mobi,fb2,djvu.
Каждая книга проходит через автоимпорт. Ответ отправляется как NDJSON-поток: frontend получает сообщения о статусе, прогрессе, логах и финальной статистике. Это хороший UX для долгой операции, потому что пользователь видит, что процесс не завис.
Как карточка попадает в каталог
После успешной обработки backend создаёт запись в таблице books, переносит файл в uploads/books под именем id и расширения, а обложку кладёт в uploads/covers/<id>.webp.
Публичный API /api/categories/:id/books возвращает книги категории и добавляет к каждой карточке:
coverUrl;- порядковый номер внутри выдачи;
- title, author, description и file_extension.
Frontend уже не занимается тяжёлой логикой. Он просто показывает список карточек, а кнопку «Скачать» связывает с запросом временной ссылки.
Что стоит проверять при развитии
У этого слоя есть несколько мест, которые особенно важно держать под контролем:
- валидация ZIP-путей при распаковке;
- проверка реального MIME/magic bytes, а не только расширения;
- аккуратная обработка больших файлов;
- защита внешних запросов при скачивании обложек;
- журналирование ошибок LLM и источников обложек;
- ручная правка карточки после автоматического импорта.
Часть этих рисков уже описана в docs/SECURITY.md как рекомендации. Поэтому в портфолио лучше показывать проект честно: рабочий импорт и каталог есть, а усиление безопасности и production-процессов — отдельное направление развития.