Repository navigation
Releases: gsoulat/sortilege
Release list
v0.16.0
v0.16.0 (2026-09-08)
This release is published under the MIT License.
Features
- destinations: Dossier separe pour les gros fichiers, et gabarits relatifs (
527dc78)
Correction prealable, plus importante que la fonctionnalite ---------------------------------------------------------- Les gabarits commencaient par « Films/ », « Series/ », alors que la destination par type est deja reglable dans l interface. Les deux se superposaient : passer la destination de « Series » a « Series TV » n avait AUCUN effet, le gabarit imposant son prefixe. Le reglage existait et ne servait a rien.
Les gabarits sont desormais relatifs a la destination du type. Une seule source de verite pour le premier niveau d arborescence.
Dossier des fichiers volumineux ------------------------------- Au-dela d un seuil reglable, un fichier part dans une destination distincte — souvent sur un autre volume, ou simplement isole pour etre repere. Un remux 4K de 60 Go et un episode de 800 Mo n ont pas les memes contraintes.
La resolution de destination est INJECTEE dans le pipeline plutot que codee dedans : il n a pas a connaitre les preferences, et le routage par taille devient testable sans configuration.
Un test a rattrape une faute au passage : j avais fusionne les deux tables de destinations par cle pour les valider, ce qui faisait ecraser une destination par son homologue « volumineux ». La premiere echappait alors silencieusement a la validation de confinement. Les deux tables sont desormais parcourues separement.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.15.0...v0.16.0
v0.15.0
v0.15.0 (2026-09-08)
This release is published under the MIT License.
Features
- auto: Surveillance, chaine complete, affiches et correction par serie (
93ccc1b)
Surveillance et traitement automatique ------------------------------------- Une boucle detecte les nouveaux fichiers, scanne, identifie et remplit la file. Elle enchaine les MEMES etapes que les boutons : aucun chemin parallele, donc aucun risque que l automatique et le manuel divergent.
Le piege d une surveillance de dossier n est pas de reperer un fichier nouveau mais de savoir qu il est FINI — un fichier existe des le premier octet ecrit. Deux conditions cumulatives : la taille n a pas bouge entre deux observations, et la derniere modification remonte a plus de N secondes. La premiere detecte une extraction d archive en cours, pendant laquelle le fichier porte deja son nom definitif ; la seconde rattrape une ecriture lente qui donnerait deux mesures identiques par hasard.
Attendre trop coute un cycle. Traiter trop tot coute un fichier incomplet deplace et un journal d annulation qui pointe vers du vide.
Le deplacement reel reste OPT-IN : par defaut la boucle prepare la file et s arrete la. Ranger sans personne devant est un engagement plus lourd qu identifier. Un cycle ne chevauche jamais le precedent, et les preferences sont relues a chaque tour pour qu activer la surveillance ne demande pas de redemarrage.
Correction par serie -------------------- Choisir la bonne oeuvre corrige desormais TOUS les episodes du groupe. L identification porte sur l oeuvre, pas sur le fichier — corriger episode par episode revenait a repondre douze fois a la meme question. Chaque episode recoit une copie du candidat, sinon l enrichissement ecraserait le titre d episode des precedents.
Affiches dans la file --------------------- La vignette de l oeuvre retenue apparait sur chaque ligne. On reconnait une erreur d identification bien plus vite sur une image que sur un titre.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.14.0...v0.15.0
v0.14.0
v0.14.0 (2026-09-08)
This release is published under the MIT License.
Features
- ia: Choix du fournisseur, et progression du calcul des plans (
9096198)
Fournisseurs ------------ ChatGPT, Mistral, OpenRouter, Ollama, Groq, LM Studio et Gemini exposent tous une API compatible OpenAI. Une seule implementation avec une URL de base configurable les couvre donc tous ; seul Claude a un protocole different et garde son SDK. Deux implementations pour sept services — et une entree « Autre » qui accueillera ceux que je n ai pas prevus.
Aucun SDK supplementaire : httpx est deja une dependance, et chaque paquet proprietaire en ajouterait un pour une seule requete POST.
Le prompt, le schema de reponse et les garde-fous sont partages : il n y a aucune raison que la qualite d identification depende de qui heberge le modele. Seul le transport change.
La lecture de reponse est tolerante sur la forme et stricte sur le fond — beaucoup de modeles entourent leur JSON de texte, ce qui est sans importance, mais une proposition dont l index n existe pas dans le lot est ecartee.
Seuil dedie (80 % par defaut) plutot que « tout ce qui n est pas automatique » : entre ce seuil et celui d application, le score est deja bon et une revue humaine suffit. C est ce qui borne la depense.
La cle vit dans les preferences et non dans l environnement — changer de fournisseur ne doit pas imposer de modifier la stack. Elle n est JAMAIS renvoyee au navigateur : l API n expose qu un booleen « configuree », et un champ vide signifie « ne change pas » plutot que « efface ».
Progression du calcul --------------------- Meme defaut que le scan avant sa correction : sur 426 fichiers le calcul dure des minutes et le bouton restait fige. Barre d avancement, compteur, temps restant estime, et annonce de la seconde passe IA qui n a pas d avancement fin.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.13.1...v0.14.0
v0.13.1
v0.13.1 (2026-09-08)
This release is published under the MIT License.
Bug Fixes
- Supprimer SORTILEGE_DRY_RUN, les boutons suffisent (
ec8027b)
Une configuration qui contredit l interface est un piege, et c est exactement ce qui s est produit : un bouton « Executer ces 88 » bien visible, mais refuse au clic par une variable posee ailleurs. L information arrivait trop tard, et au mauvais endroit.
Depuis que « Simuler » et « Executer » sont deux boutons distincts, le mode est un choix explicite a chaque action — la variable ne faisait que dupliquer cette decision, avec le pouvoir de la contredire.
La seule protection conservee est le DEFAUT de la requete : simuler. Une requete qui omet le champ ne deplace rien. Ce defaut-la ne peut pas se desynchroniser de l interface, puisqu il vit dans le meme appel.
Le badge « verrouille » et le mode affiche dans l entete disparaissent avec elle : ils decrivaient un etat qui n existe plus.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.13.0...v0.13.1
v0.13.0
v0.13.0 (2026-09-08)
This release is published under the MIT License.
Features
- revue: Choisir la bonne oeuvre parmi les candidats, avec les jaquettes (
ce284a8)
Le cas qui a motive ce travail : « Dark Matter » 2015 et « Dark Matter » 2024 sont deux series reelles, meme titre, meme type. AUCUN signal automatique ne les separe — ni l'annee (absente du nom), ni la notoriete, ni l'accord des fournisseurs. Le score avait raison de ne pas trancher ; ce qui manquait, c'etait le moyen de trancher a la main.
Les candidats etaient calcules puis JETES : seul le gagnant survivait. C'est exactement a l'inverse de ce dont on a besoin, puisqu'un score bas signifie « plusieurs possibilites » et que ces possibilites etaient perdues au moment ou elles devenaient utiles.
Le plan garde donc jusqu'a huit alternatives, avec leur jaquette. Au-dela, une grille d'affiches cesse d'aider a decider et redevient une liste a lire.
Les jaquettes ne sont pas decoratives : entre deux oeuvres homonymes, une affiche tranche en une seconde la ou une date demande de reflechir. C'est le seul endroit de l'application ou une image a une valeur fonctionnelle.
POST /api/review/{id}/choose impose un candidat et recalcule la destination. Le score n'est PAS recalcule : un choix humain explicite n'est pas une hypothese a evaluer, et sur un cas d'homonymie le calcul avait deja montre qu'il ne savait pas. Le plan est marque manual et passe en application automatique.
L'ancien candidat rejoint les alternatives : changer d'avis ne doit pas imposer de relancer un scan.
Cote interface, un bouton « Ce n'est pas ca » ouvre la grille. Sur une serie il porte sur l'ensemble : l'identification est la meme pour tous les episodes, la corriger episode par episode reviendrait a repondre douze fois a la meme question.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.12.0...v0.13.0
v0.12.0
v0.12.0 (2026-09-08)
This release is published under the MIT License.
Features
- revue: Boutons Simuler/Executer, selection par serie, zone explorable elargie (
efe3564)
Simuler et executer deviennent deux boutons ------------------------------------------- Le mode venait de SORTILEGE_DRY_RUN, donc changer d'avis imposait de modifier la stack et de redemarrer le conteneur. Les deux boutons sont maintenant cote a cote : on simule une selection, on lit le resultat, on execute la meme selection.
La variable devient un VERROU qui ne sait que RESTREINDRE : elle peut forcer la simulation, jamais l'autoriser a l'inverse. Sans cette regle, un verrou pose volontairement sur une instance serait contourne par un clic. Quand elle refuse, l'interface le dit au lieu d'annoncer une simulation sans motif.
Le defaut de la requete est la simulation : une requete qui omettrait le champ ne deplace rien. Le defaut d'une operation irreversible doit etre l'inaction.
Une simulation conserve la selection, une execution la vide — pour pouvoir enchainer les deux sur les memes lignes.
Selection par serie ------------------- Cocher episode par episode etait inutilisable : une bibliotheque reelle produit des centaines de lignes pour quelques dizaines de series. La file de revue est donc regroupee par serie, et une case coche toute la serie.
C'est aussi plus juste que pratique : la decision porte sur l'IDENTIFICATION, qui est la meme pour tous les episodes d'une serie. Soit elle est bonne, soit elle ne l'est pas. Les films restent a plat, chacun etant une decision independante.
Une selection partielle affiche un etat indetermine et se COMPLETE au clic plutot que de se vider : une case a moitie cochee signifie qu'on etait en train de composer.
Zone explorable --------------- Nouvelle variable SORTILEGE_ALLOWED_ROOTS. Un NAS monte souvent un volume entier (« /volume1:/storage ») dont seuls quelques dossiers servent de source ; les autres etaient montes mais invisibles dans l'explorateur et impossibles a ajouter. La zone parcourable est desormais declarable independamment des sources par defaut.
Corrige aussi ApplyRequest, qui avait perdu son champ dry_run dans un patch interrompu a mi-chemin : l'endpoint aurait leve une AttributeError des le premier appel.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.11.0...v0.12.0
v0.11.0
v0.11.0 (2026-09-08)
This release is published under the MIT License.
Features
- tmdb: Accepter la cle d' API comme le jeton d' acces en lecture (
fb9b942)
TMDB propose les deux cote a cote dans les parametres du compte : une « Cle d API » (32 caracteres hexa, authentification v3, en parametre d URL) et un « Jeton d acces en lecture » (JWT v4, en en-tete Authorization). Ils ne sont pas interchangeables et se tromper donne un 401 sans la moindre explication.
Le format est desormais reconnu a la forme du secret et achemine correctement.
Un appel avait ete oublie au passage — la relance de recherche sans annee, qui ne portait pas les en-tetes. Avec un jeton v4 elle aurait echoue en 401 precisement dans le cas ou le premier essai n a rien donne, donc sur les fichiers les plus difficiles. Un test couvre chaque route.
Le jeton ne part jamais dans l URL : les URL finissent dans les journaux d accces et les en-tetes de referent.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.10.0...v0.11.0
v0.10.0
v0.10.0 (2026-09-08)
This release is published under the MIT License.
Features
- Compagnons, nettoyage en corbeille, et correction d'une ruee sur le cache (
2016c9b)
Compagnons ---------- Seul le fichier video etait deplace : les sous-titres restaient en arriere. Perte de donnees silencieuse — Jellyfin affiche un film sans VOSTFR et personne ne s'en apercoit avant de lancer la lecture.
Les sous-titres et les jaquettes suivent desormais la video en etant renommes comme elle. Le suffixe distinctif est preserve (« .fr.srt », « .eng.forced.srt ») sans quoi deux pistes se recouvriraient sous le meme nom. Une jaquette au nom canonique (poster.jpg) n'est emportee que si la video est seule dans son dossier : sinon elle n'appartient a personne en particulier.
Nettoyage --------- Les restes de release vont dans une corbeille datee sous la racine de bibliotheque. RIEN N'EST JAMAIS SUPPRIME, hormis les dossiers devenus vides — un dossier vide ne contient rien a recuperer.
La liste des dechets reconnus est volontairement CONSERVATRICE : tout ce qui n'y figure pas reste en place. Oublier un dechet coute un peu de desordre ; evacuer un fichier qui comptait coute bien plus.
L'annulation ramene tout : video, compagnons et restes. Chaque deplacement est journalise separement, une annulation partielle serait pire que pas d'annulation du tout.
Ruee sur le cache ----------------- Trouve en MESURANT le volume de requetes plutot qu'en le supposant : 96 recherches pour 6 series. Le cache existait mais n'etait rempli QU'APRES la reponse ; les 96 fichiers etant traites en parallele, tous consultaient le cache avant la premiere reponse, tous manquaient, et tous partaient. Le cache ne servait qu'aux scans suivants.
SingleFlight deduplique les requetes identiques en vol : le premier appelant lance, les suivants attendent la meme tache. 6 requetes au lieu de 96, verifie au niveau du transport HTTP sur le vrai fournisseur — une imitation contournerait justement les caches qu'on veut tester.
Deux autres reductions du meme ordre : une saison entiere est recuperee en une requete au lieu d'une par episode (400 requetes -> 60 sur une bibliotheque reelle), et les sagas de films sont mises en cache.
Ajout d'un limiteur de debit a 20 requetes/seconde. Le semaphore bornait les appels SIMULTANES, pas le debit : six requetes concurrentes de 50 ms enchainees font 120 requetes par seconde.
Titre des series ---------------- « Avatar The Last Airbender 2024 » gardait l'annee dans le titre — vu sur une vraie bibliotheque. Pour un film le titre est coupe a l'annee, mais pour un episode il est coupe au motif SxxExx, donc une annee placee avant restait collee et faisait echouer la recherche. Elle est retiree, sauf si elle EST le titre (« 2012 »).
Interface --------- Explorateur de dossiers pour choisir les destinations par type, extrait en composant reutilisable partage avec le selecteur de sources. Le chemin choisi est converti en relatif a la racine de bibliotheque, et un dossier hors de cette racine est refuse avec le motif — c'est elle qui garantit le confinement.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.9.1...v0.10.0
v0.9.1
v0.9.1 (2026-09-08)
This release is published under the MIT License.
Bug Fixes
- scan: Passer le scan en tache de fond avec progression (
ddd0cbd)
Le scan etait synchrone : la requete HTTP ne repondait qu'une fois toute la bibliotheque analysee. Sur un NAS reel avec ffprobe actif, cela represente plusieurs minutes pendant lesquelles l'utilisateur ne voyait qu'un bouton fige, sans savoir si l'outil travaillait ou etait bloque. Pire : un delai d'attente du navigateur ou d'un proxy faisait perdre le resultat d'un scan qui avait pourtant abouti.
Le POST demarre desormais un thread et rend la main immediatement (12 ms mesurees au lieu de la duree complete). GET /api/library/scan/status expose phase, avance, fichier en cours, temps ecoule et estimation du restant.
Le recensement est separe de l'analyse : une premiere passe rapide parcourt l'arborescence sans ffprobe pour connaitre le TOTAL. Sans elle, une barre de progression n'aurait pas de denominateur et on ne pourrait afficher qu'un compteur qui monte sans fin visible.
L'estimation du restant est une extrapolation lineaire, donc imprecise — les fichiers ne coutent pas tous pareil a ffprobe. Elle repond neanmoins a la seule question qui compte pendant l'attente : des secondes ou des minutes.
Un second clic sur « Lancer un scan » renvoie l'etat du scan en cours au lieu d'une erreur « un scan est deja en cours ». Voir la progression est utile ; lire un refus ne l'est pas.
L'interface reprend le suivi d'un scan deja lance si on recharge la page ou qu'on revient depuis un autre onglet, plutot que de laisser croire qu'il ne se passe rien.
Une exception dans le thread est capturee et exposee dans le statut : sans cela le thread mourrait en silence et l'interface attendrait indefiniment un scan qui n'existe plus.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.9.0...v0.9.1
v0.9.0
v0.9.0 (2026-09-08)
This release is published under the MIT License.
Features
- ai: Brancher le resolveur en seconde passe sur les cas ambigus (
79fe337)
Le module existait, teste, mais aucun code ne l'appelait. Il est desormais integre au pipeline, avec une place volontairement etroite.
Quand il est appele ------------------- JAMAIS sur le tout-venant. Une premiere passe deterministe traite la bibliotheque a cout nul ; seuls les fichiers qui n'ont PAS obtenu une application automatique sont soumis au modele. On ne paie donc un appel que pour ce qui allait de toute facon demander une intervention humaine. Les appels sont groupes par lot : un appel par fichier couterait dix fois le prix.
Ce qu'on fait de sa reponse --------------------------- Le modele ne fournit pas la reponse, il fournit une meilleure REQUETE. Son titre relance une recherche chez les fournisseurs, et les candidats continuent de venir d'eux. Sa confiance entre dans le scoring comme un PLAFOND, pas comme un terme additif : elle dit « je crois reconnaitre cette oeuvre », pas « les donnees concordent ».
Ce qu'on lui refuse ------------------- - Une proposition ne remplace le resultat deterministe que si elle score MIEUX. Sans cette regle, un modele qui se trompe ferait perdre une identification deja correcte. - Un titre vide ne declenche rien : le modele qui avoue ne pas savoir est respecte, pas contourne. - Une panne du resolveur laisse le lot exactement dans l'etat ou la premiere passe l'a mis. C'est un bonus, jamais une dependance.
Le SDK Anthropic etant synchrone, l'appel passe par asyncio.to_thread : l'invoquer directement figerait la boucle d'evenements et donc tout le scan.
L'import d'anthropic reste tardif et son absence est rattrapee proprement — une installation sans l'extra « ai » doit fonctionner normalement plutot que de planter au chargement du module.
Les utilitaires de test partages sont sortis dans tests/helpers.py : importer un fichier de test depuis un autre creait un couplage ou renommer l'un cassait l'autre, et tests/ n'etant pas un paquet l'import relatif echouait de toute facon.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Detailed Changes: v0.8.0...v0.9.0