feat: AniList reading status integration

- 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>
This commit is contained in:
2026-03-24 17:08:11 +01:00
parent 2a7881ac6e
commit e94a4a0b13
29 changed files with 2352 additions and 40 deletions

View File

@@ -193,6 +193,23 @@ const fr = {
"libraryActions.metadataRefreshSchedule": "Rafraîchissement auto",
"libraryActions.metadataRefreshDesc": "Re-télécharger périodiquement les métadonnées existantes",
"libraryActions.saving": "Enregistrement...",
"libraryActions.sectionReadingStatus": "État de lecture",
"libraryActions.readingStatusProvider": "Provider d'état de lecture",
"libraryActions.readingStatusProviderDesc": "Synchronise les états de lecture (lu / en cours / planifié) avec un service externe",
// Reading status modal
"readingStatus.button": "État de lecture",
"readingStatus.linkTo": "Lier à {{provider}}",
"readingStatus.search": "Rechercher",
"readingStatus.searching": "Recherche en cours…",
"readingStatus.searchPlaceholder": "Titre de la série…",
"readingStatus.noResults": "Aucun résultat.",
"readingStatus.link": "Lier",
"readingStatus.unlink": "Délier",
"readingStatus.changeLink": "Changer",
"readingStatus.status.linked": "lié",
"readingStatus.status.synced": "synchronisé",
"readingStatus.status.error": "erreur",
// Library sub-page header
"libraryHeader.libraries": "Bibliothèques",
@@ -600,6 +617,59 @@ const fr = {
"settings.telegramHelpChat": "Envoyez un message à votre bot, puis ouvrez <code>https://api.telegram.org/bot&lt;TOKEN&gt;/getUpdates</code> dans votre navigateur. Le <b>chat id</b> apparaît dans <code>message.chat.id</code>.",
"settings.telegramHelpGroup": "Pour un groupe : ajoutez le bot au groupe, envoyez un message, puis consultez la même URL. Les IDs de groupe sont négatifs (ex: <code>-123456789</code>).",
// Settings - AniList
"settings.anilist": "État de lecture",
"settings.anilistTitle": "Synchronisation AniList",
"settings.anilistDesc": "Synchronisez votre progression de lecture avec AniList. Obtenez un token d'accès personnel sur anilist.co/settings/developer.",
"settings.anilistToken": "Token d'accès personnel",
"settings.anilistTokenPlaceholder": "Token AniList...",
"settings.anilistUserId": "ID utilisateur AniList",
"settings.anilistUserIdPlaceholder": "Numérique (ex: 123456)",
"settings.anilistConnected": "Connecté en tant que",
"settings.anilistNotConnected": "Non connecté",
"settings.anilistTestConnection": "Tester la connexion",
"settings.anilistLibraries": "Bibliothèques",
"settings.anilistLibrariesDesc": "Activer la synchronisation AniList pour chaque bibliothèque",
"settings.anilistEnabled": "Sync AniList activée",
"settings.anilistLocalUserTitle": "Utilisateur local",
"settings.anilistLocalUserDesc": "Choisir l'utilisateur local dont la progression est synchronisée avec ce compte AniList",
"settings.anilistLocalUserNone": "— Sélectionner un utilisateur —",
"settings.anilistSyncTitle": "Synchronisation",
"settings.anilistSyncDesc": "Envoyer la progression locale vers AniList. Règles : aucun lu → PLANNING · au moins 1 lu → CURRENT (progression = nbre de tomes lus) · tous les tomes publiés lus (total_volumes connu) → COMPLETED.",
"settings.anilistSyncButton": "Synchroniser vers AniList",
"settings.anilistPullButton": "Importer depuis AniList",
"settings.anilistPullDesc": "Importer votre liste de lecture AniList et mettre à jour la progression locale. Règles : COMPLETED/CURRENT/REPEATING → livres marqués lus jusqu'au volume de progression · PLANNING/PAUSED/DROPPED → non lus.",
"settings.anilistSyncing": "Synchronisation...",
"settings.anilistPulling": "Import...",
"settings.anilistSynced": "{{count}} série(s) synchronisée(s)",
"settings.anilistUpdated": "{{count}} série(s) mise(s) à jour",
"settings.anilistSkipped": "{{count}} ignorée(s)",
"settings.anilistErrors": "{{count}} erreur(s)",
"settings.anilistLinks": "Liens AniList",
"settings.anilistLinksDesc": "Séries associées à AniList",
"settings.anilistNoLinks": "Aucune série liée à AniList",
"settings.anilistUnlink": "Délier",
"settings.anilistSyncStatus": "synced",
"settings.anilistLinkedStatus": "linked",
"settings.anilistErrorStatus": "error",
"settings.anilistUnlinkedTitle": "{{count}} série(s) non liée(s)",
"settings.anilistUnlinkedDesc": "Ces séries appartiennent à des bibliothèques activées mais n'ont pas encore de lien AniList. Recherchez chacune pour la lier.",
"settings.anilistSearchButton": "Rechercher",
"settings.anilistSearchNoResults": "Aucun résultat AniList.",
"settings.anilistLinkButton": "Lier",
"settings.anilistRedirectUrlLabel": "URL de redirection à configurer dans votre app AniList :",
"settings.anilistRedirectUrlHint": "Collez cette URL dans le champ « Redirect URL » de votre application sur anilist.co/settings/developer.",
"settings.anilistTokenPresent": "Token présent — non vérifié",
"settings.anilistPreviewButton": "Prévisualiser",
"settings.anilistPreviewing": "Chargement...",
"settings.anilistPreviewTitle": "{{count}} série(s) à synchroniser",
"settings.anilistPreviewEmpty": "Aucune série à synchroniser (liez des séries à AniList d'abord).",
"settings.anilistClientId": "Client ID AniList",
"settings.anilistClientIdPlaceholder": "Ex: 37777",
"settings.anilistConnectButton": "Connecter avec AniList",
"settings.anilistConnectDesc": "Utilisez OAuth pour vous connecter automatiquement. Le Client ID se trouve dans vos applications AniList (anilist.co/settings/developer).",
"settings.anilistManualToken": "Token manuel (avancé)",
// Settings - Language
"settings.language": "Langue",
"settings.languageDesc": "Choisir la langue de l'interface",