- Add metadata_batch job type with background processing via tokio::spawn
- Auto-apply metadata only when single result at 100% confidence
- Support primary + fallback provider per library, "none" to opt out
- Add batch report/results API endpoints and job detail UI
- Add series_status and has_missing filters to both series listing pages
- Add GET /series/statuses endpoint for dynamic filter options
- Normalize series_metadata status values (migration 0036)
- Hide ComicVine provider tab when no API key configured
- Translate entire backoffice UI from English to French
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add series status concept (ongoing/ended/hiatus/cancelled/upcoming)
with normalization across all providers
- Add status field to series_metadata table (migration 0033)
- AniList: use chapters as fallback for volume count on ongoing series,
add books_message when both volumes and chapters are null
- Bedetheque: extract description from meta tag, genres, parution status,
origin/language; rewrite book parsing with itemprop microdata for
clean ISBN, dates, page counts, covers; filter placeholder authors
- Add comprehensive e2e provider tests with field coverage reporting
- Wire status into EditSeriesForm, MetadataSearchModal, and series page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When books have no volume number, use their 1-based position in the
backoffice sort order (volume ASC NULLS LAST, natural title sort) as
effective volume for matching against external provider books.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-fetch all local books in one query instead of N queries per external
book. Match by volume number first, then bidirectional title containment
(external in local OR local in external). Track matched IDs to prevent
double-matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Replace sccache with a two-stage build strategy: dummy source files cache
dependency compilation in a separate layer, and --mount=type=cache for
Cargo registry/git/target directories. Source-only changes now skip
full dependency recompilation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Meilisearch indexing to use authors[] array instead of scalar author field
- Join series_metadata to include series-level authors in search documents
- Configure searchable attributes (title, authors, series) in Meilisearch
- Convert EditSeriesForm and EditBookForm from inline forms to modals
- Add tabbed navigation (General / Integrations) to Settings page
- Add Force Search Resync button (POST /settings/search/resync)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds Komga sync feature to import read status from a Komga server.
Books are matched by title (case-insensitive) with series+title primary
match and title-only fallback. Sync reports are persisted with matched,
newly marked, and unmatched book lists. UI shows check icon for newly
marked books, sorted to top. Credentials (URL+username) are saved
between sessions. Uses HashSet for O(1) lookups to handle large libraries.
Closes#2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The total_authors stat now combines distinct values from the legacy
author column and the new authors array column.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Nouveaux endpoints PATCH /books/:id et PATCH /libraries/:id/series/:name pour éditer les métadonnées
- GET /libraries/:id/series/:name/metadata pour récupérer les métadonnées de série
- Ajout du champ `authors` (Vec<String>) sur les structs Book/BookDetails
- 3 migrations : table series_metadata, colonne authors sur series_metadata et books
- Composants EditBookForm et EditSeriesForm dans le backoffice
- Routes API Next.js correspondantes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remplace REGEXP_REPLACE(title, '[0-9]+', '', 'g') par
REGEXP_REPLACE(title, '[0-9].*$', '') pour n'extraire que le préfixe
avant le premier chiffre.
L'ancienne regex supprimait TOUS les chiffres du titre entier, y compris
dans les sous-titres. Quand chaque volume a un sous-titre différent
(ex: "Deadpool marvel deluxe 3 - Je suis ton homme"), la partie texte
restante variait → l'ordre alphabétique des sous-titres prenait le dessus.
Avec le nouveau préfixe "deadpool marvel deluxe " identique pour tous,
le numéro de volume (2ème clé) dicte correctement l'ordre.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ajout de `b.volume NULLS LAST` comme première clé de tri dans list_books
et dans tous les ROW_NUMBER() OVER (...) des CTEs series, pour corriger
l'ordre des volumes dont les titres varient en format (ex: "Round" vs "R")
- Suppression de l'ancienne extract_page publique et de ses 4 helpers
(extract_cbz_page_n, extract_cbz_page_n_streaming, extract_cbr_page_n,
extract_pdf_page_n) remplacés par la nouvelle implémentation avec cache
- Suppression de archive_index_cache dans AppState (remplacé par le cache
statique CBZ_INDEX_CACHE dans parsers), import StdMutex nettoyé
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chaque cold render ré-énumérait toutes les entrées ZIP/RAR pour construire
la liste triée des images. Maintenant la liste est mise en cache dans l'AppState
(LruCache<String, Arc<Vec<String>>>, std::sync::Mutex pour accès spawn_blocking).
Nouvelles fonctions dans parsers :
- list_archive_images(path, format) -> Vec<String>
- extract_image_by_name(path, format, name) -> Vec<u8>
Mesures avant/après (cache disque froid, n=20) :
- CBZ cold : 43ms → 11.9ms (-73%)
- CBR cold : 46ms → 11.0ms (-76%)
- Warm/concurrent : identique
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Expose `extract_page(path, format, page_number, render_width)` dans parsers
- Rend `is_image_name` publique, ajoute gif/bmp/tif/tiff
- Supprime ~250 lignes dupliquées dans pages.rs (CBZ/CBR/PDF extract)
- Retire zip/unrar/pdfium-render/natord de api, remplacé par parsers
Perf avant/après : stable (±5%, dans le bruit de mesure).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add sort=latest option to GET /books and GET /series API endpoints,
and expose a Sort select in the backoffice books and series pages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GET /stats API endpoint with collection overview, reading status,
format/library breakdowns, top series, and monthly additions.
Replace static home page with interactive dashboard featuring donut
charts, bar charts, and progress bars. Use distinct colors for series
(warning/yellow) across nav, page titles, and quick links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- API: add POST /series/mark-read to batch mark all books in a series
- API: add GET /series cross-library endpoint with search, library and status filters
- API: add library_id to SeriesItem response
- Backoffice: mark book as read/unread button on book detail page
- Backoffice: mark series as read/unread button on series cards
- Backoffice: new /series top-level page with search and filters
- Backoffice: new /libraries/[id]/series/[name] series detail page
- Backoffice: opacity on fully read books and series cards
- Backoffice: live search with debounce on books and series pages
- Backoffice: reading status filter on books and series pages
- Fix $2 -> $1 parameter binding in mark-series-read SQL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two new read routes for the home screen:
- /series/ongoing: partially read series sorted by last activity
- /books/ongoing: next unread book per ongoing series
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add POST /admin/tokens/{id}/delete endpoint that permanently removes
a token from the database (only if already revoked). Add delete button
in backoffice UI for revoked tokens.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extraction par batches de 200 livres (libère mémoire entre chaque batch)
- Limiter tokio spawn_blocking à 8 threads (défaut 512, chaque thread ~8MB stack)
- Réduire concurrence extraction de 8 à 2 max
- Supprimer raw_bytes.clone() inutile (passage par ownership)
- Ajouter log RSS entre chaque batch pour diagnostic mémoire
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remplacer by_index() par file_names() pour lister les pages ZIP (zero I/O)
- Ajouter vérification magic bytes avant fallback RAR
- Ajouter tracing debug logs dans parsers
- Script docker-push avec version bump interactif
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>
- Indexer: ajout du champ `warnings` dans JobStats pour les erreurs
non-fatales (fichiers inaccessibles, permissions)
- Indexer: skip les fichiers dont le stat échoue au lieu de faire
crasher tout le scan de la library
- Backoffice: affichage des warnings dans le détail job (summary,
timeline, Index Statistics) et dans la popin jobs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>