Utilise useTransition pour wrapper les router.replace dans LiveSearchForm.
Affiche un petit spinner à droite du champ de recherche pendant que les
résultats se chargent (books, series, authors).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Cover w-48 → w-40 (cohérent avec la page série)
- Titre séparé, auteur + série + statut de lecture regroupés en badges
- Métadonnées (format, pages, langue, ISBN, date) en ligne texte
au lieu de pills (style série)
- Toolbar d'actions groupée en bas (Edit, MarkRead, Convert, Delete)
- Tous les boutons d'action (MarkBookRead, Convert, Delete) alignés en
py-1.5 au lieu de Button size=sm (h-9)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ProwlarrSearchModal: py-2 → py-1.5, gap-2 → gap-1.5 (aligné avec les autres)
- DeleteSeriesButton: remplace Button size=sm (h-9) par bouton inline
avec py-1.5 cohérent avec le reste de la toolbar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Quand on fait un replace sans volumes manquants, expected_volumes n'était
pas envoyé → is_managed=false → pas d'insertion dans torrent_downloads
→ le torrent n'apparaissait pas dans la page downloads.
Maintenant un replace avec libraryId envoie toujours expected_volumes
(même vide) pour garantir le tracking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alwaysShowReplace suffit maintenant à montrer le bouton replace,
même quand allVolumes est vide (série complète sans volumes manquants).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- Ajoute DELETE /libraries/:id/series/:name dans series.rs
- Supprime tous les fichiers physiques des livres de la série
- Supprime le dossier de la série (remove_dir_all)
- Nettoie en DB : books, series_metadata, external_metadata_links,
anilist_series_links, available_downloads
- Queue un scan job pour cohérence
Frontend:
- Crée DeleteSeriesButton.tsx avec modale de confirmation
- Ajouté dans la toolbar de la page détail série
- i18n fr/en pour les textes de confirmation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Prowlarr search modal : les releases avec le même titre sont groupées
avec rowSpan sur la colonne titre, sources listées en sous-lignes
- Downloads page : même logique, titre + volumes affichés une seule fois,
sources (indexer, seeders, taille, boutons) en lignes compactes
- Fonction utilitaire groupReleasesByTitle() dans les deux composants
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Ajout DELETE /books/:id : supprime le fichier physique, la thumbnail,
le book en DB et queue un scan de la lib. Bouton avec confirmation
sur la page de détail du livre.
- L'import torrent utilise unaccent() en SQL pour matcher les séries
indépendamment des accents (ex: "les géants" = "les geants").
- Fallback filesystem avec strip_accents pour les séries sans livre en DB.
- Migration 0069: activation de l'extension PostgreSQL unaccent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
La recherche utilise désormais le endpoint paginé /books avec un filtre
ILIKE sur title/series/author, ce qui permet la pagination des résultats.
Les series_hits sont toujours récupérés en parallèle via searchBooks.
Corrige aussi le remount du LiveSearchForm lors de la navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Modale Prowlarr (page série) : remplacé le bouton qBittorrent brut
par QbittorrentDownloadButton avec suivi managé (libraryId,
seriesName, expectedVolumes) et bouton "télécharger et remplacer".
- Ajout de alwaysShowReplace pour la modale Prowlarr (toujours montrer
le bouton remplacer) vs la page downloads (seulement si allVolumes >
expectedVolumes).
- Fix parseur : les tags de version entre crochets [V2], [V3] ne sont
plus extraits comme volumes (le préfixe "v" est ignoré après "[").
- Progression qBittorrent : utilise directement le champ progress
(completed et amount_left sont non-fiables sur qBittorrent 4.3.2).
- Référence import : ne plus exclure les volumes attendus de la
recherche de référence (corrige le mauvais dossier/nommage quand
tous les volumes sont dans expected_volumes).
- allVolumes ajouté à ProwlarrRelease (backend + frontend).
- flex-wrap sur les pastilles volumes dans la modale Prowlarr.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Ajout d'un bouton "télécharger et remplacer" avec popup de
confirmation, qui passe tous les volumes du pack (pas seulement
les manquants) et replace_existing=true à l'API.
- Nouvelle colonne replace_existing dans torrent_downloads.
- Fix critique du parseur de volumes : le pass 2 mélangeait les
indices d'octets (String::find) avec les indices de caractères
(Vec<char>), causant un décalage quand le titre contenait des
caractères multi-octets (é, à...). "Tome #097" extrayait 9
au lieu de 97. Réécrit en indexation char pure.
- Le préfixe "tome" skip désormais "#" (tome #097 → 97).
- Protection intra-batch : si une destination est déjà utilisée,
le fichier garde son nom original au lieu d'écraser.
- Alerte WARN si N fichiers source donnent N/3 volumes uniques.
- Nettoyage du répertoire sl-{id} et de la catégorie qBittorrent
après import.
- Badges volumes en flex-wrap dans la page downloads.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le bouton revient à son état initial après l'icône verte de
confirmation, permettant de relancer un téléchargement si besoin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Serveur : envoie toujours les données (plus de skip si identiques),
ajoute un heartbeat toutes les 15s pour garder la connexion vivante
- Client : détecte les connexions mortes (timeout 30s sans message)
et reconnecte automatiquement, reconnexion plus rapide (3s vs 5s)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le QbittorrentProvider expose un callback onDownloadStarted qui est
appelé quand un téléchargement est lancé avec succès. Sur la page
downloads, ce callback déclenche un refresh de la liste.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Les metadata providers sont récupérés côté serveur et les providers
sans API key sont passés en prop initialHiddenProviders, supprimant
le fetch client useEffect qui causait un layout shift.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Les configs Prowlarr et qBittorrent sont récupérées côté serveur et
passées en props au ProwlarrSearchModal, évitant les deux fetchs
client qui causaient l'apparition tardive du bouton.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
La config qBittorrent est maintenant récupérée côté serveur et passée
en prop au QbittorrentProvider, évitant le fetch client qui causait
l'apparition tardive des boutons de téléchargement.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Après import torrent, refresh automatique des métadonnées uniquement
sur la série importée (via refresh_link) au lieu d'un job complet
- Nouvel endpoint POST /metadata/refresh-link/:id pour rafraîchir un
seul lien metadata approuvé
- Bouton "Rafraîchir" dans la modale metadata (état linked) avec
spinner et confirmation visuelle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remplace localStorage par des cookies pour la persistance des filtres.
Le proxy restaure les filtres sauvegardés côté serveur, éliminant le flash au chargement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Nouvelle table `torrent_downloads` pour suivre les téléchargements gérés
- API : endpoint POST /torrent-downloads/notify (webhook optionnel) et GET /torrent-downloads
- Poller background toutes les 30s qui interroge qBittorrent pour détecter
les torrents terminés — aucune config "run external program" nécessaire
- Import automatique : déplacement des fichiers vers la série cible,
renommage selon le pattern existant (détection de la largeur des digits),
support packs multi-volumes, scan job déclenché après import
- Page /downloads dans le backoffice : filtres, auto-refresh, carte par download
- Toggle auto-import intégré dans la card qBittorrent des settings
- Erreurs de détection download affichées dans le détail des jobs
- Volume /downloads monté dans docker-compose
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Filter jobs by type, status, or library with dropdowns above the table.
Shows filtered count and a clear button when filters are active.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add download_detection to replayable job types and replay route handler.
Give each job type a unique colored background badge for better visual
distinction in the jobs table.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show a download button on each available release in the detection report
when qBittorrent is configured, matching the Prowlarr search modal behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove dashboard link from desktop/tablet nav (logo already links to /).
Move user switcher into hamburger menu as inline clickable items on mobile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a standalone toast notification system (no Provider needed) and use it
for settings save feedback. Skip save when fields are empty. Remove save
button on Anilist local user select in favor of auto-save on change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a configurable schedule (manual/hourly/daily/weekly) for the
download detection job in the library settings modal. The indexer
scheduler triggers the job automatically, and the API job poller
processes it — consistent with the reading_status_push pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For each series with missing volumes and an approved metadata link,
calls Prowlarr to find available matching releases and stores them in
a report (no auto-download). Includes per-series detail page, Telegram
notifications with per-event toggles, and stats display in the jobs table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Push reading statuses (PLANNING/CURRENT/COMPLETED) to AniList for all
linked series that changed since last sync, or have new books/no sync yet.
- Migration 0057: adds reading_status_push to index_jobs type constraint
- Migration 0058: creates reading_status_push_results table (pushed/skipped/no_books/error)
- API: new reading_status_push module with start_push, get_push_report, get_push_results
- Differential detection: synced_at IS NULL OR reading progress updated OR new books added
- Same 429 retry logic as reading_status_match (wait 10s, retry once, abort on 2nd 429)
- Notifications: ReadingStatusPushCompleted/Failed events
- Backoffice: push button in reading status group, job detail report with per-series list
- Replay support, badge label, i18n (FR + EN)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add /api/jobs/list endpoint and fetch the updated list right after
a successful replay so the new job appears instantly instead of
waiting for the next SSE poll (up to 15s when idle).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows a "Replay" button on non-active jobs that re-creates a new job
of the same type and library. Supports all replayable job types:
rebuild, full_rebuild, rescan, scan, thumbnail_rebuild,
thumbnail_regenerate, metadata_batch, metadata_refresh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow switching between number of books and number of pages on the
dashboard reading activity chart. Adds pages_read to the stats API
response and a MetricToggle component alongside the existing PeriodToggle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add full AniList integration: OAuth connect, series linking, push/pull sync
- Push: PLANNING/CURRENT/COMPLETED based on books read vs total_volumes (never auto-complete from owned books alone)
- Pull: update local reading progress from AniList list (per-user)
- Detailed sync/pull reports with per-series status and progress
- Local user selector in settings to scope sync to a specific user
- Rename "AniList" tab/buttons to generic "État de lecture" / "Reading status"
- Make Bédéthèque and AniList badges clickable links on series detail page
- Fix ON CONFLICT error on series link (provider column in PK)
- Migration 0054: fix series_metadata missing columns (authors, publishers, locked_fields, total_volumes, status)
- Align button heights on series detail page; move MarkSeriesReadButton to action row
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Scope all reading progress (books, series, stats) by user via
Option<Extension<AuthUser>> — admin sees aggregate, read token sees own data
- Fix duplicate book rows when admin views lists (IS NOT NULL guard on JOIN)
- Add X-As-User header support: admin can impersonate any user from backoffice
- UserSwitcher dropdown in nav header (persisted via as_user_id cookie)
- Per-user filter pills on "Currently reading" and "Recently read" dashboard sections
- Inline username editing (UsernameEdit component with optimistic update)
- PATCH /admin/users/:id endpoint to rename a user
- Unassigned read tokens row in users table
- Komga sync now requires a user_id — reading progress attributed to selected user
- Migration 0051: add user_id column to komga_sync_reports
- Nav breakpoints: icons-only from md, labels from xl, hamburger until md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add login page with logo background, glassmorphism card
- Add session management via JWT (jose) with httpOnly cookie
- Add Next.js proxy middleware to protect all routes
- Add logout button in nav
- Restructure app into (app) route group to isolate login layout
- Add ADMIN_USERNAME, ADMIN_PASSWORD, SESSION_SECRET env vars
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Metadata refresh now skips series with ended/cancelled status
- Add xs size to Button component
- Unify view/cancel button sizes (h-7) with icons (eye & cross)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Tooltip UI component for styled hover tooltips
- Replace native title attributes with Tooltip on all job stats
- Add refresh icon (green) showing actual refreshed count for metadata refresh
- Add icon+tooltip to scanned files stat
- Add icon prop to StatBox component
- Add refreshed field to stats_json types
- Distinct tooltip labels for total links vs refreshed count
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add multi-line chart showing job runs over time by type (scan,
rebuild, thumbnails, other) with the same day/week/month toggle
- Limit currently reading and recently read lists to 3 visible items
with a scrollbar for overflow
- Fix NUMERIC→BIGINT cast for SUM/COALESCE in jobs SQL queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a period selector (day, week, month) to the reading activity and
books added charts. The API now accepts a ?period= query param and
returns gap-filled data using generate_series so all time slots appear
even with zero values. Labels are locale-aware (short month, weekday).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace relative time formatting (which incorrectly showed "just now"
for many jobs due to negative time diffs from server/client timezone
mismatch) with absolute locale-formatted date/time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add currently reading, recently read, and reading activity sections to
the dashboard. Replace all custom SVG/CSS charts with recharts library
(donut, area, stacked bar, horizontal bar). Reorganize layout: libraries
and popular series side by side, books added chart full width below.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add notifications crate shared between API and indexer to send Telegram
messages on scan/thumbnail/conversion completion/failure, metadata linking,
batch and refresh events. Configurable via a new Notifications tab in the
backoffice settings with per-event toggle switches grouped by category.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>