Add a complete metadata synchronization system allowing users to search
and sync series/book metadata from external providers (Google Books,
Open Library, ComicVine, AniList, Bédéthèque). Each library can use a
different provider. Matching requires manual approval with detailed sync
reports showing what was updated or skipped (locked fields protection).
Key changes:
- DB migrations: external_metadata_links, external_book_metadata tables,
library metadata_provider column, locked_fields, total_volumes, book
metadata fields (summary, isbn, publish_date)
- Rust API: MetadataProvider trait + 5 provider implementations,
7 metadata endpoints (search, match, approve, reject, links, missing,
delete), sync report system, provider language preference support
- Backoffice: MetadataSearchModal, ProviderIcon, SafeHtml components,
settings UI for provider/language config, enriched book detail page,
edit forms with locked fields support, API proxy routes
- OpenAPI/Swagger documentation for all new endpoints and schemas
Closes#3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ajout de targets de log par domaine (scan, extraction, thumbnail, watcher)
contrôlables via RUST_LOG pour activer/désactiver les logs granulaires
- Ajout de logs détaillés dans extracting_pages (per-book timing en debug,
progression toutes les 25 books en info)
- Réduction de la consommation de fd: walkdir max_open(20/10), comptage
séquentiel au lieu de par_iter parallèle, suppression de rayon
- Détection ENFILE dans le scanner: abort après 10 erreurs IO consécutives
- Backoffice: settings dans le burger mobile, masquer "backoffice" et
icône settings en mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pages: mode Original (zero-transcoding), ETag/304, cache index CBZ,
préfetch next 2 pages, filtre Triangle par défaut
- Thumbnails: DCT scaling JPEG via jpeg-decoder (decode 7x plus rapide),
img.thumbnail() pour resize, support format Original, fix JPEG RGBA8
- API fallback thumbnail: OutputFormat::Original + DCT scaling au lieu
de WebP full-decode, retour (bytes, content_type) dynamique
- Watcher: remplacement notify par poll léger sans inotify/fd,
skip poll quand job actif, snapshots en mémoire
- Jobs: mutex exclusif corrigé (tous statuts actifs, tous types exclusifs)
- Robustesse: suppression fs::canonicalize (problèmes fd Docker),
list_folders avec erreurs explicites, has_children default true
- Backoffice: FormRow items-start pour alignement inputs avec helper text,
labels settings clarifiés
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parsers: raw ZIP reader (flate2) contournant la validation CRC32 des
Unicode extra fields (0x7075) qui bloquait certains CBZ
- Parsers: nouvelle API publique extract_page() pour extraire une page
par index depuis CBZ/CBR/PDF avec fallbacks automatiques
- API: suppression du code d'extraction dupliqué, délégation à parsers::extract_page()
- API: retrait des dépendances directes zip/unrar/pdfium-render/natord
- Indexer: nettoyage Meili systématique à chaque sync (au lieu de ~10%)
avec pagination pour supporter les grosses collections — corrige les
doublons dans la recherche
- Indexer: retrait de la dépendance rand (plus utilisée)
- Backoffice: popin jobs rendue via createPortal avec positionnement
dynamique — corrige le débordement desktop et le header cassé en mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Incremental rebuild: remplace le WalkDir de comptage par un COUNT(*) SQL
→ incrémental 67s → 25s (-62%) sur disque externe
- Full rebuild: conserve le WalkDir (DB vidée avant le comptage)
- Concurrence par défaut: num_cpus/2 clampé [2,8] au lieu de 2 fixe
- Ajoute num_cpus comme dépendance workspace
- Backoffice jobs: un seul formulaire avec formAction par bouton (icônes rétablies)
- infra/perf.sh: corrige l'endpoint /index/jobs/:id (pas /details), exporte BASE_API/TOKEN
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CBR: extract_cbr_page extrayait TOUT le CBR sur disque pour lire une
seule page. Reécrit avec le crate unrar : listing en mémoire + extraction
ciblée de la page demandée uniquement. Zéro subprocess, zéro temp dir.
PDF: render_pdf_page utilisait pdftoppm subprocess + temp dir. Reécrit
avec pdfium-render in-process. Zéro subprocess, zéro temp dir.
CBZ: sort naturel (natord) pour l'ordre des pages.
Dockerfile API: retire unar et poppler-utils, ajoute libpdfium.so.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CBR: remplace unrar/unar CLI par le crate `unrar` (bindings libunrar
vendorisé, zéro dépendance système). Supprime XADRegexException, les
forks de processus et les dossiers temporaires.
PDF: remplace pdfinfo + pdftoppm par pdfium-render. Le PDF est ouvert
une seule fois pour obtenir le nombre de pages ET rasteriser la première
page. lopdf reste pour parse_metadata (page count seul).
convert_cbr_to_cbz: reécrit sans subprocess ni dossier temporaire —
les images sont lues en mémoire via unrar puis packées directement en ZIP.
Dockerfile indexer: retire unrar-free, unar, poppler-utils. Télécharge
libpdfium.so depuis bblanchon/pdfium-binaries au build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CBR: contourner le bug XADRegexException de unar en appelant unar
avec un symlink à nom neutre (archive.cbr) au lieu du chemin réel,
qui peut contenir des caractères regex spéciaux comme [ ] ( )
- CBR/CBZ: remplacer le tri lexicographique par natord (tri naturel)
pour que page2.jpg soit trié avant page10.jpg
- PDF: brancher pdftoppm -scale-to sur config.width.max(config.height)
au lieu d'une valeur hardcodée (800px → 400px par défaut)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 1 (discovery): walkdir + filename-only metadata, zero archive I/O.
Books are visible immediately in the UI while Phase 2 runs in background.
Phase 2 (analysis): open each archive once via analyze_book() to extract
page_count and first page bytes, then generate WebP thumbnail directly in
the indexer — removing the HTTP roundtrip to the API checkup endpoint.
- Add parse_metadata_fast() (infallible, no archive I/O)
- Add analyze_book() returning (page_count, first_page_bytes) in one pass
- Add looks_like_image() magic bytes check for unrar p stdout validation
- Add lsar fallback in list_cbr_images() for UTF-16BE encoded filenames
- Add directory_mtimes table to skip unchanged dirs on incremental scans
- Add analyzer.rs: generate_thumbnail, analyze_library_books, regenerate_thumbnails
- Remove run_checkup() from API; indexer handles thumbnail jobs directly
- Remove api_base_url/api_bootstrap_token from IndexerConfig and AppState
- Add unar + poppler-utils to indexer Dockerfile
- Fix smoke.sh: wait for job completion, check thumbnail_url field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused image dependencies from Cargo.lock.
- Update API to handle thumbnail generation and checkup processes.
- Introduce new routes for rebuilding and regenerating thumbnails.
- Enhance job tracking with progress indicators for thumbnail jobs.
- Update front-end components to display thumbnail job status and progress.
- Add backend logic for managing thumbnail jobs and integrating with the API.
- Refactor existing code to accommodate new thumbnail functionalities.
- Batching BDD: group INSERT/UPDATE operations in batches of 100 using UNNEST
- Incremental MeiliSearch: only sync books modified since last sync
- Optimized fingerprint: use only size+mtime+filename (100x faster)
- Increased DB connections from 5 to 20
- Reduced progress update frequency (every 1s or 10 files)
- Add sync_metadata table to track last MeiliSearch sync
- Extend API /folders endpoint to support browsing subdirectories with path parameter
- Add depth and has_children fields to FolderItem
- Create FolderBrowser component with tree view navigation
- Create FolderPicker component with input, browse button and popup modal
- Add API proxy route for /api/folders
- Update LibraryForm to use new FolderPicker component
- Fix path handling to correctly resolve /libraries/ subdirectories
- Migration 0006: colonne watcher_enabled
- Crate notify pour surveillance FS temps réel (FSEvents/inotify)
- Watcher redémarré toutes les 30s si config change
- Détection instantanée création/modification/suppression
- Création job immédiate quand fichier détecté
- API: support watcher_enabled dans UpdateMonitoringRequest
- Backoffice: toggle Watcher avec indicateur ⚡
- Fonctionne en parallèle du scheduler auto-scan
Usage: Activer Watcher + Auto-scan pour réactivité max