Adding Torrents and Existing Data FR - Kheopsian/Hydranos GitHub Wiki

🇬🇧 English · 🇫🇷 Français

Ajouter des torrents et des données existantes

S'applique à Hydranos 4.4.

Cette page s'adresse à quiconque met des torrents dans Hydranos : à la main, depuis un script, depuis Sonarr/Radarr/autobrr, depuis une règle RSS, depuis un client IA ou via un dossier surveillé. Elle couvre toutes les façons d'ajouter, les options que chacune respecte, comment ajouter un torrent par-dessus des données déjà présentes sur disque sans les retélécharger, ce qui se passe quand un autre torrent nomme déjà les mêmes fichiers, l'ordre dans lequel un torrent se télécharge, et pourquoi un ajout peut être refusé. Les termes employés ici sont définis sur Concepts & glossaire.

Le pipeline d'ajout

Tous les chemins d'ajout aboutissent à la même fonction : les mêmes règles s'appliquent donc partout. Les magnets font un détour : ils sont vérifiés, enregistrés et résolus en arrière-plan, puis entrent dans le pipeline une fois leurs métadonnées arrivées.

flowchart LR
    UI["Onglet d'ajout : envoi ou chemin serveur"] --> SF
    REST["REST : POST /api/torrents/upload, POST /api/torrents (chemin ou URL)"] --> SF
    QB["Shim qBit : POST /api/v2/torrents/add"] --> SF
    RSS["Règle RSS ou Téléchargement de l'onglet RSS"] --> SF
    SF["Option sous-dossier : un torrent mono-fichier<br/>reçoit un dossier à son nom"] --> P
    MCP["Outil MCP add_torrent"] --> P
    WF["Dossier surveillé : fichier .torrent"] --> P
    NF["Rapatriement depuis un nœud : bring it here"] --> P
    IMP["Assistant d'import"] --> P
    MIN["Magnet depuis l'onglet d'ajout, REST, shim, RSS, MCP ou un fichier .magnet"] --> MQ{"Lien valide, chemin de sauvegarde connu,<br/>absent du moteur cible ?"}
    MQ -- non --> MR["Refusé immédiatement"]
    MQ -- oui --> MS["Enregistré, résolu en arrière-plan (BEP 9)"]
    MS -- "métadonnées arrivées, option sous-dossier du shim appliquée" --> P
    P["Analyse du .torrent"] --> PL["Placement : moteur explicite, sinon mode,<br/>sinon mode de la catégorie, sinon race"]
    PL --> SP{"Chemin de sauvegarde : explicite, sinon celui de la catégorie"}
    SP -- aucun --> R1["Refusé : no save path"]
    SP -- trouvé --> EN{"Le moteur existe ?"}
    EN -- non --> R0["Refusé : no engine"]
    EN -- oui --> RA{"Moteur de rôle race, add_block_enabled<br/>et espace projeté insuffisant ?"}
    RA -- oui --> R2["Refusé : race disk full"]
    RA -- non --> PC{"Revendication de chemin : un autre torrent<br/>nomme ces fichiers avec d'autres octets ?"}
    PC -- "oui, refuse" --> R3["Refusé : écraserait"]
    PC -- "oui, isolate" --> ISO["Dossier propre NAME [hash8], retenu en pause,<br/>mode seed abandonné"]
    PC -- "non, legacy, ou mode seed<br/>avec toutes les tailles identiques" --> ST["Ligne du store et clé de contenu écrites"]
    ISO --> ST
    ST --> DD{"[dedup] enabled ?"}
    DD -- oui --> DL["Tenter un hardlink du contenu identique déjà détenu"]
    DD -- non --> EA
    DL --> EA{"Hash déjà dans ce moteur ?"}
    EA -- oui --> AA["Refusé : already added"]
    EA -- non --> HOLD{"Retenu par la revendication de chemin ?"}
    HOLD -- oui --> PR["Preuve de revendication en arrière-plan,<br/>voir Fichiers qu'un autre torrent détient déjà"]
    HOLD -- non --> SM{"Mode seed ?"}
    SM -- oui --> SEED["Seed, sans vérification des hashs"]
    SM -- non --> DOD{"Un fichier présent au chemin de sauvegarde ?"}
    DOD -- oui --> RC["Revérification : seed, ou téléchargement des pièces manquantes"]
    DOD -- non --> DLD["Téléchargement"]
    PR --> WK
    SEED --> WK["Les workflows 'quand un torrent est ajouté' se déclenchent<br/>(pas pour l'assistant d'import)"]
    RC --> WK
    DLD --> WK
Loading

Ce que le diagramme signifie en pratique :

  • Le placement (quel moteur, quel dossier) est décidé par la catégorie ; la règle complète est sur Catégories & routage. Un engine explicite (ou mode, race ou hoard, sur les routes natives et l'onglet d'ajout) l'emporte sur la catégorie. Une catégorie inconnue ou vide part vers le moteur race sans chemin de sauvegarde : elle est donc refusée, sauf si vous fournissez explicitement un chemin de sauvegarde.
  • Il n'y a pas de chemin de sauvegarde par défaut, à une exception près sur le shim qBit : un dossier qu'un client a réglé avec save_path de setPreferences est utilisé quand un ajout ne nomme ni chemin de sauvegarde ni catégorie qui en a un (vide tant qu'aucun client ne l'a réglé).
  • La revendication de chemin (path claim) empêche un nouveau torrent d'écrire dans des fichiers qu'un autre torrent nomme avec d'autres octets ; voir Fichiers qu'un autre torrent détient déjà.
  • Le contrôle « déjà ajouté » se fait par moteur. Ajouter un hash qu'un autre moteur détient déjà crée une seconde copie dans le moteur cible. Seuls l'assistant d'import et bring it here (rapatriement depuis un nœud, qui répond 409 this node already has that torrent) vérifient tous les moteurs.
  • Les workflows « quand un torrent est ajouté » (when a torrent is added) se déclenchent pour tous les chemins sauf l'assistant d'import (voir Workflows) ; ajouts RSS compris.

Façons d'ajouter

Chemin Fichiers Magnets URL .torrent Catégorie Chemin de sauvegarde Tags Démarrer arrêté Mode seed Moteur
Onglet + Ajouter un torrent, envoi oui, plusieurs (une requête chacun) — — oui oui — oui oui Mode (Race / Hoard)
Onglet + Ajouter un torrent, Chemin du fichier torrent un fichier sur le disque du démon — — oui oui — oui oui Mode
Onglet + Ajouter un torrent, Lien magnet — oui — oui oui — oui oui Mode
POST /api/torrents/upload (multipart) un par requête — — category savepath ou save_path tags paused ou stopped skip_checking, seed_mode ou skip_recheck engine ou mode (inconnu → 400)
POST /api/torrents (JSON) torrent_path (disque du démon) magnet_uri torrent_url category save_path tags stopped ou paused (bool) seed_mode ou skip_recheck (bool) engine ou mode (inconnu → 400)
Shim qBit POST /api/v2/torrents/add torrents, file ou fileselect, plusieurs urls urls category savepath tags paused ou stopped skip_checking —
Outil MCP add_torrent torrent_path magnet torrent_url obligatoire, doit exister save_path tags (tableau) paused jamais engine
Dossier surveillé .torrent .magnet — celle du dossier (obligatoire) celui de la catégorie — Ajouter arrêté (Add stopped) jamais API seulement

Les champs booléens de formulaire acceptent true ou 1 ; la route JSON veut de vrais booléens JSON. La route d'envoi prend le fichier sous le nom de champ multipart torrent, torrents ou file : les trois fonctionnent (avec plusieurs parties fichier, seule la dernière est ajoutée). mode (race ou hoard, casse indifférente) choisit le moteur de ce rôle, en priorité celui qui porte le nom du rôle ; engine l'emporte quand les deux sont envoyés. Les règles RSS et le bouton Téléchargement (Download) de l'onglet RSS ajoutent par le même pipeline, jamais en mode seed : voir RSS et téléchargements automatiques. Toutes les routes REST et du shim exigent la clé API (en-tête X-Api-Key ou paramètre de requête apikey) ou un cookie de session connectée (ce qu'utilisent Sonarr/Radarr via la connexion du shim) ; voir Sécurité & accès. Chaque route et chaque champ sont listés sur API REST ; l'activation et la connexion du point d'accès MCP sont décrites sur Serveur MCP.

Deux autres chemins réutilisent le pipeline : bring it here sur le torrent d'un nœud déclaré (Nœuds & plusieurs machines) et l'assistant d'import (Migrer depuis qBittorrent).

Exemples, avec une instance sur le port 8199 :

# Envoyer un .torrent dans la catégorie "tv", en faisant confiance aux données déjà sur disque
curl -H "X-Api-Key: YOUR_API_KEY" \
  -F "[email protected]" -F "category=tv" -F "seed_mode=true" \
  http://localhost:8199/api/torrents/upload

# Envoyer vers un moteur supplémentaire, avec un chemin de sauvegarde explicite, arrêté
curl -H "X-Api-Key: YOUR_API_KEY" \
  -F "[email protected]" -F "engine=vpn1" \
  -F "save_path=/data/vpn1" -F "stopped=true" \
  http://localhost:8199/api/torrents/upload

# Ajouter un magnet (répond 202 {"info_hash":...,"status":"resolving"})
curl -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"magnet_uri":"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&tr=https%3A%2F%2Ftracker.example.org%2Fannounce","category":"tv"}' \
  http://localhost:8199/api/torrents

# Ajouter depuis l'URL .torrent d'un tracker dans le moteur hoard, arrêté
curl -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"torrent_url":"https://tracker.example.org/download/123.torrent","mode":"hoard","category":"movies","stopped":true}' \
  http://localhost:8199/api/torrents

Sous Windows, dans PowerShell, appelez curl.exe (curl tout court est un alias de Invoke-WebRequest dans Windows PowerShell 5.1) et gardez la commande sur une seule ligne ; les chemins Windows fonctionnent après @ :

curl.exe -H "X-Api-Key: YOUR_API_KEY" -F "torrent=@D:\Torrents\Film (2020).torrent" -F "category=movies" -F "seed_mode=true" http://localhost:8199/api/torrents/upload

Réponses :

  • Route d'envoi : 200 {"info_hash","name","engine","mode"} (engine est le moteur où le torrent est allé, mode son rôle) ; 409 {"error"} quand ce moteur le détient déjà ; 400 {"error"} pour tout autre refus.
  • Route JSON : 200 {"info_hash","name","engine","mode"} pour un fichier ou une URL, 202 {"info_hash","status":"resolving"} pour un magnet. Un refus porte {"error","targets":[{"agent":"local","error"}]} : 409 quand le moteur le détient déjà et pour les autres refus (disque race plein, path_collision = "refuse"), 404 quand torrent_path n'existe pas, 400 pour les mauvaises requêtes listées dans Quand un ajout est refusé (y compris un hash de magnet mal formé, absent ou uniquement v2), 500 seulement pour une panne du store.
  • Shim : Ok. ou Fails. comme qBittorrent ; voir Shim qBittorrent & automatisation.

Les URL .torrent (torrent_url natif, shim urls, MCP torrent_url) sont récupérées par un simple GET, par la propre sortie du démon (voir VPN & sortie réseau) : http ou https uniquement (sinon torrent_url must be an http(s) URL), délai de 30 s, 15 MiB au maximum, sans cookies ni en-têtes supplémentaires. L'URL est remplacée par <url> dans le journal et dans l'erreur de la route native, car une URL de tracker contient généralement une passkey.

Téléchargement, revérification ou mode seed

Quand un torrent est ajouté, Hydranos décide quoi faire du chemin de sauvegarde :

Situation Ce qui se passe
Mode seed non demandé, aucun fichier du torrent présent Téléchargement normal.
Mode seed non demandé, au moins un fichier présent Revérification (recheck) en arrière-plan : chaque pièce est hachée ; le torrent finit en seed si toutes les pièces sont valides, ou ne télécharge que ce qui manque.
Mode seed demandé (skip_checking / seed_mode / skip_recheck, la case Skip the hash check… de l'onglet d'ajout) Commence à seeder immédiatement. Rien n'est vérifié : ni l'existence des fichiers, ni leur taille.
Un autre torrent nomme certains de ces fichiers avec d'autres octets, ou des fichiers sur disque ont un hardlink ailleurs Avec path_collision = "isolate" (par défaut) : déplacé dans son propre dossier, retenu en pause le temps de prouver les fichiers de même taille, puis revérifié. refuse : refusé. legacy : revérifié par-dessus. Mode seed sur des fichiers de même taille uniquement : fait confiance, ajouté tout de suite. Fichiers sur disque ayant un hardlink ailleurs et nommés par aucun torrent : retenu sur place jusqu'à preuve (pas en mode seed). Voir Fichiers qu'un autre torrent détient déjà.

Le comportement par défaut — la revérification — est le plus sûr : ajouter un torrent par-dessus une copie complète des données coûte une lecture des données et aucun téléchargement. Il s'applique aussi à un torrent ajouté arrêté : il est revérifié et reste arrêté, ce qui vous permet de voir ce qui se trouve sur disque avant qu'il ne touche au réseau.

N'utilisez le mode seed que si vous savez que les données sont complètes et exactement au bon chemin, typiquement pour le cross-seed (cross-seed envoie skip_checking=true via le shim) ou pour l'import scripté d'une bibliothèque vérifiée. Si vous vous trompez, le torrent annonce des pièces qu'il ne peut pas servir. En cas de doute, ajoutez sans mode seed, ou lancez plus tard Vérifier à nouveau (Recheck) (menu contextuel, affiché quand la sélection contient un torrent hoard ; ou POST /api/hoard/torrents/<hash>/verify, qui trouve le torrent dans n'importe quel moteur malgré le préfixe /hoard/ et répond {"status":"ok","checking":true,"paused":…}). Chaque revérification est gardée par la revendication de chemin (voir Fichiers qu'un autre torrent détient déjà).

La disposition sur disque, qui doit correspondre exactement pour qu'une revérification ou le mode seed trouve les données :

  • torrent multi-fichiers : <save path>/<torrent name>/<files>
  • torrent mono-fichier : <save path>/<file>
  • torrent mono-fichier avec l'option sous-dossier : <save path>/<file name without its extension>/<file>

Le nom du torrent et les noms des fichiers sont utilisés exactement comme le .torrent les écrit ; rien n'est renommé ni rapproché approximativement. L'option sous-dossier est Put the payload in its own subfolder sur l'onglet d'ajout, create_subfolder sur les deux routes natives, contentLayout / root_folder sur le shim, avec [daemon] create_torrent_folder (par défaut false) comme valeur par défaut pour tous et pour les ajouts RSS. Elle ne change que les torrents mono-fichier (un torrent multi-fichiers a déjà son dossier). Il n'existe aucun moyen de supprimer le dossier de premier niveau d'un torrent multi-fichiers (le shim refuse contentLayout=NoSubfolder sur un tel torrent). Si votre dossier porte un autre nom (un renommage façon Plex, un autre format d'année), les données ne sont pas trouvées : sans mode seed, le torrent retélécharge tout dans un nouveau dossier au bon nom ; avec le mode seed, il annonce des données qu'il n'a pas. Renommez le dossier au nom du torrent avant l'ajout, ou gardez une copie disposée comme le torrent l'attend.

Exemple sous Windows : vous avez déjà D:\Media\Movies\Film (2020)\Film.2020.mkv et un torrent multi-fichiers nommé Film (2020) contenant Film.2020.mkv. Donnez à la catégorie le Chemin d'enregistrement (Save Path) D:\Media\Movies (le parent, pas le dossier du film) et ajoutez le .torrent avec la ligne PowerShell de Façons d'ajouter ci-dessus. Avec seed_mode=true, il seed immédiatement ; sans, Hydranos lit le fichier en entier une fois pour le vérifier (durée ≈ taille des données ÷ vitesse de lecture du disque), puis seed. Dans les champs de l'interface (chemin de sauvegarde, dossier surveillé, Chemin du fichier torrent (Torrent File Path)), tapez les chemins Windows avec des barres obliques inverses comme d'habitude ; le conseil sur les barres obliques de Windows concerne les chaînes à l'intérieur de default.toml.

Accepté mais ignoré en 4.4 : l'option sous-dossier (create_subfolder, [daemon] create_torrent_folder) sur un magnet ajouté par POST /api/torrents ou l'onglet d'ajout, et sur les dossiers surveillés, les ajouts MCP, les magnets RSS, les rapatriements depuis un nœud et l'assistant d'import — ceux-là gardent la disposition simple — envoyez plutôt le .torrent, ou ajoutez le magnet par le shim avec contentLayout=Subfolder.

Le mode seed sur un magnet est conservé avec la requête et appliqué à l'arrivée des métadonnées (seed_mode / skip_recheck natifs, la case de l'onglet d'ajout, skip_checking du shim). Un .magnet dans un dossier surveillé, un magnet MCP et un magnet RSS ne sont jamais ajoutés en mode seed.

Ordre de téléchargement

Un torrent télécharge toujours tous ses fichiers. Ce que vous pouvez changer, c'est l'ordre dans lequel les pièces sont récupérées ; Hydranos n'a pas de « ne pas télécharger » (la priorité 0 de qBittorrent), volontairement : un torrent laissé incomplet est un torrent qu'il ne pourra jamais seeder.

  • Priorités de fichiers : Normale (Normal), Haute (High), Maximale (Maximum) (1, 6, 7 chez qBittorrent). Une pièce est classée selon la plus haute priorité des fichiers qu'elle couvre ; le rang le plus haut est récupéré en premier.
  • Première/dernière pièce d'abord (First/last piece first) : la première et la dernière pièce de chaque fichier passent avant tout le reste, au-dessus de toute priorité (comme dans qBittorrent).
  • Téléchargement séquentiel (Sequential download) : au sein d'un même rang, les pièces sont récupérées dans l'ordre de leur index plutôt que les plus rares d'abord. Plusieurs pièces restent en cours à la fois, et la fin de partie (endgame : les 16 dernières pièces, demandées à plus d'un pair) fonctionne comme d'habitude.
  • Par défaut : rien de réglé signifie simplement les plus rares d'abord ; rien n'est enregistré pour cela.
  • Conservé : un changement s'applique tout de suite et est écrit dans la base de reprise du moteur (state.db), il survit donc à un redémarrage et suit le torrent quand il passe dans un autre moteur. Un torrent complet garde et affiche ses réglages ; ils agissent de nouveau si une revérification trouve des pièces manquantes.

Où le régler :

Où Quoi
Panneau de détail › onglet Contenu (Content) Colonne Priorité (Priority), un sélecteur par fichier (Normale / Haute / Maximale). La ligne de résumé ajoute séquentiel et première/dernière pièce d'abord quand ils sont réglés. Une ligne venant d'un autre nœud affiche les priorités en lecture seule. Un échec affiche Priorité inchangée : … (Priority not changed: …).
Menu contextuel, groupe Torrent Téléchargement séquentiel et Première/dernière pièce d'abord, cochés quand tous les torrents sélectionnés l'ont activé (lu pour 50 torrents sélectionnés au plus ; une sélection plus grande, par filtre ou distante s'affiche décochée) ; un clic règle l'inverse sur toute la sélection. Il n'y a pas de priorité de fichier groupée.
GET / POST /api/torrents/<hash>/download-order GET répond {"info_hash","copies":[{"engine","sequential","first_last_piece","file_priorities","complete"}]}. POST prend n'importe lesquels de sequential, first_last_piece, et file_ids (indices venant de GET /api/torrents/<hash>/files, champ index) accompagné de priority. S'applique à toutes les copies locales sauf si ?engine= en nomme une. Priorité 0 → 409 (Hydranos always downloads the whole torrent…) ; tout autre corps invalide → 400 qui dit pourquoi ; hash inconnu → 404.
Action de sélection download_order {"sequential","first_last_piece"} (au moins un) ; voir API REST.
Shim qBit torrents/filePrio (1, 6, 7 ; 0 → 409), torrents/toggleSequentialDownload, torrents/toggleFirstLastPiecePrio ; à l'ajout, sequentialDownload et firstLastPiecePrio, conservés avec un magnet jusqu'à l'arrivée de ses métadonnées. Voir Shim qBittorrent & automatisation.
# Lire le fichier 2 en premier, et récupérer tôt les extrémités de chaque fichier
curl -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"file_ids":[2],"priority":7,"first_last_piece":true}' \
  http://localhost:8199/api/torrents/<hash>/download-order

Non implémenté en 4.4 : un réglage d'ordre de téléchargement au moment de l'ajout sur l'onglet d'ajout, POST /api/torrents, la route d'envoi, MCP ou un dossier surveillé — seul le shim en lit un — réglez-le juste après l'ajout (menu contextuel ou download-order), ou ajoutez par le shim.

L'onglet d'ajout

L'onglet intitulé + Ajouter un torrent (+ Add Torrent) (titre Ajouter un torrent (Add Torrent)) comporte ces champs :

Champ Ce qu'il fait réellement
Catégorie (Category) (avec + Nouveau (+ New)) Envoyée avec l'ajout. En choisir une remplace Chemin d'enregistrement par le chemin de la catégorie (vide si elle n'en a pas) et bascule Mode sur le mode de la catégorie. La première entrée est - none -.
Chemin du fichier torrent (Torrent File Path) Chemin d'un .torrent sur la machine qui exécute Hydranos (sous Docker : dans le conteneur), pas sur votre ordinateur. Sur une installation Windows, un chemin normal comme D:\Torrents\release.torrent fonctionne.
Ou envoyer un .torrent (Or Upload .torrent) Un ou plusieurs fichiers depuis votre ordinateur, envoyés une requête chacun. Prioritaire sur les champs chemin et magnet.
Prévisualiser le contenu avant d'ajouter (Preview contents before adding) Lit les fichiers sélectionnés dans votre navigateur et les affiche dans la colonne Contenu (Contents). Rien n'est envoyé.
Lien magnet (Magnet link) Utilisé seulement si aucun fichier n'est sélectionné et que Chemin du fichier torrent est vide.
Avancé : forcer le mode et le chemin (Advanced, override mode & save path) › Chemin d'enregistrement (Save Path) Envoyé comme chemin de sauvegarde ; remplace celui de la catégorie. Ce qu'affiche le champ est ce qui est envoyé.
Mode (Race / Hoard) Envoyé avec chaque ajout (mode) ; choisit le moteur de ce rôle, en priorité celui nommé race ou hoard. Commence sur Race ; il suit la catégorie choisie, et l'emporte sur elle si vous le changez ensuite.
Put the payload in its own subfolder create_subfolder : un torrent mono-fichier va dans <save path>/<file name without extension>/. Pré-cochée d'après [daemon] create_torrent_folder (lu par GET /api/torrents/add-defaults ; si cette lecture échoue, rien n'est envoyé et le réglage du démon s'applique). Non appliquée à un Lien magnet.
Skip the hash check, the data is already on disk Mode seed, pour un envoi, un chemin ou un magnet. Décochée au départ.
Add without starting Ajouté arrêté, pour un envoi, un chemin ou un magnet. Un ajout arrêté par-dessus des données existantes est quand même revérifié.

La ligne de succès affiche Added <name> → <mode>[ · <category>], avec le rôle du moteur où le torrent est allé. Une erreur est affichée telle que le serveur l'a envoyée.

L'onglet n'a ni champ tags ni champ d'URL .torrent (une URL tapée dans Chemin du fichier torrent est lue comme un chemin et refusée avec no such file ; utilisez torrent_url sur POST /api/torrents, le shim ou MCP), et le moteur ne se choisit que par rôle. Avec - none - et un Chemin d'enregistrement vide, l'ajout est refusé (no save path).

Bug connu en 4.4 : revenir à - none - dans Catégorie semble réinitialiser le formulaire — Chemin d'enregistrement et Mode gardent les valeurs de la catégorie précédente et sont envoyés — videz Chemin d'enregistrement et choisissez le mode à la main.

Bug connu en 4.4 : deux textes d'aide sous les cases ne décrivent pas le code — Put the payload in its own subfolder dit qu'elle s'applique « on the hoard agent » (elle s'applique à tout moteur), et Skip the hash check… dit que l'ajout est refusé quand un fichier manque ou n'a pas la bonne taille (rien n'est vérifié, le torrent annonce ce qu'il n'a pas) — fiez-vous à cette page.

Magnets

Un magnet est accepté en quelques secondes et résolu en arrière-plan :

  1. Vérifié immédiatement. Refusé tout de suite si le lien ne s'analyse pas, si aucun chemin de sauvegarde n'est trouvé, ou si le moteur cible a déjà le hash. Un engine (ou mode) qui n'existe pas est refusé (400) par POST /api/torrents ; depuis un magnet MCP, il est ignoré et le magnet va au moteur de la catégorie. Un dossier surveillé ne peut pas être enregistré avec un engine inconnu (PUT /api/watch répond 400 no engine "x") ; seul un moteur supprimé après l'enregistrement du dossier se rabat sur la catégorie. Les liens doivent avoir un info hash v1 (xt=urn:btih:, 40 hex ou 32 base32). Un magnet uniquement v2 (urn:btmh: seulement) est refusé avec add the .torrent file instead ; un magnet hybride convient. tr (y compris les numérotés tr.1…), dn et x.pe sont utilisés.
  2. Enregistré. La requête (catégorie, chemin de sauvegarde, tags, indicateur arrêté, mode seed, moteur, et les options d'ajout du shim : limites de débit, ordre de téléchargement, disposition du contenu) est écrite dans le store et survit à un redémarrage.
  3. Résolu. Les pairs viennent des trackers du magnet, de x.pe et de la DHT ; les métadonnées sont récupérées via BEP 9 et leur hash doit être égal à l'info hash. Le moteur doit être sur le réseau ; s'il ne l'est pas et que la requête a plus de 600 s (comptées depuis sa création, pas depuis le dernier redémarrage ni le dernier Réessayer (Retry)), la requête échoue.
  4. Réessayé. Jusqu'à 4 tentatives, avec des attentes de 0, 1, 5 puis 15 minutes ; après le quatrième échec, la requête est marquée failed avec le motif.
  5. Ajouté. Le .torrent est reconstruit (dictionnaire info octet pour octet, un palier (tier) de tracker par tr) et passe par le pipeline ci-dessus, en mode seed si la requête l'a demandé, avec les options du shim appliquées. Un contentLayout=NoSubfolder du shim sur ce qui s'avère être un torrent multi-fichiers fait échouer la requête (contentLayout NoSubfolder on a multi-file torrent is not supported). Si le pipeline le refuse, la requête est aussitôt marquée failed (sans nouvelle tentative) ; si le moteur le détient déjà, la requête est abandonnée sans bruit.
stateDiagram-v2
    state "Refusé immédiatement" as Refused
    state "resolving : récupération des métadonnées" as Fetching
    state "en attente de nouvelle tentative" as Waiting
    state "failed" as Failed
    state "Ajouté via le pipeline d'ajout" as Added
    state "Requête abandonnée, déjà dans le moteur" as Dropped
    [*] --> Refused: lien invalide, pas de chemin, déjà présent
    [*] --> Fetching: écrit dans le store, résolution lancée
    Fetching --> Added: métadonnées conformes à l'info hash, ajout accepté
    Fetching --> Dropped: l'ajout répond déjà ajouté
    Fetching --> Waiting: pas de métadonnées, ou non conformes
    Waiting --> Fetching: après 1, 5 puis 15 min
    Fetching --> Failed: 4e tentative échouée, NoSubfolder sur un torrent multi-fichiers, ou ajout refusé
    Fetching --> Failed: moteur hors réseau, requête de plus de 600 s
    Failed --> Fetching: Réessayer, tentatives remises à 0
    Failed --> [*]: Supprimer
    Waiting --> [*]: Supprimer
    Fetching --> [*]: Supprimer
    Added --> [*]
    Dropped --> [*]
    Refused --> [*]
Loading

Sur l'onglet d'ajout, la carte Magnets (masquée quand elle est vide) liste les requêtes en attente avec Nom (Name), Engine et État (State) (fetching metadata..., waiting to retry (N min), failed: …), un bouton Réessayer (Retry) sur celles en échec et Supprimer (Remove). La même chose via l'API :

curl -H "X-Api-Key: YOUR_API_KEY" http://localhost:8199/api/magnets
curl -X POST -H "X-Api-Key: YOUR_API_KEY" http://localhost:8199/api/magnets/<hash>/retry
curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" http://localhost:8199/api/magnets/<hash>

Réessayer repart de la première tentative (la limite de 600 s hors réseau n'est pas réinitialisée).

Dossiers surveillés

Onglet Config › Dossiers surveillés (Watched folders) : chaque ligne contient Dossier (Folder), Catégorie (Category), Ajouter arrêté (Add stopped), Actif (On) et Statut (Status) ; + Dossier (+ Folder) ajoute une ligne et Enregistrer (Save) remplace toute la liste (PUT /api/watch).

  • La catégorie est obligatoire et doit exister au moment de l'enregistrement ; elle décide du moteur et du chemin de sauvegarde. Le dossier doit être un chemin absolu vers un répertoire visible par le démon (Linux/macOS : commence par / ; Windows : X:\…, C:/… ou un partage UNC \\server\share\watch).
  • Analysé toutes les 10 secondes, premier niveau seulement (pas de sous-dossiers), fichiers se terminant par .torrent ou .magnet (casse indifférente). Un fichier est pris en compte dès que sa taille et sa date de modification n'ont pas changé entre deux analyses : comptez 10 à 20 s de latence. Les fichiers de plus de 64 MiB sont refusés.
  • Chaque dossier est analysé à part, si bien qu'un partage réseau qui ne répond plus ne bloque que sa propre ligne : au bout de 60 s sans réponse, cette ligne affiche une erreur (no answer from this folder for 60 s …), et les autres dossiers continuent.
  • Un fichier .magnet contient le lien sur sa première ligne non vide.
  • Résultat : un fichier ajouté, ou déjà présent dans le moteur, est déplacé dans <folder>/added/ (les conflits de nom reçoivent (2), (3)…). Un fichier refusé est renommé <name>.invalid, avec à côté <name>.invalid.txt qui donne le motif. Rien n'est supprimé. Pour un .magnet, « ajouté » signifie que la requête a été acceptée ; la résolution suit comme dans Magnets.
  • Jamais en mode seed : les données existantes sont toujours revérifiées. Pas de tags, pas d'option sous-dossier.
  • Statut affiche vus N · ajoutés N · refusés N (seen, added, refused) et le dernier refus : vus est le nombre de fichiers .torrent et .magnet que la dernière analyse a trouvés dans le dossier. Un dossier pas encore analysé depuis le démarrage affiche pas encore scanné (not scanned yet). Ces compteurs sont gardés en mémoire et remis à zéro au redémarrage.
  • L'API accepte aussi un engine par dossier. L'interface ne l'affiche pas, mais le conserve quand vous enregistrez la liste depuis l'onglet Config.

Sous Docker, le dossier est un chemin à l'intérieur du conteneur : montez-le. Sous Windows, tapez-le sous la forme D:\Watch\movies (ou \\server\share\watch) dans le champ Dossier.

Un dossier sur un partage réseau, sous Docker. Si le partage est monté sur l'hôte après le démarrage du conteneur, le conteneur voit toujours le point de montage vide qui est dessous : le dossier se lit sans erreur et rien n'est jamais pris. Le statut le montre : vus 0 alors que des fichiers y sont déposés. Montez le parent du point de montage avec la propagation rslave (- /mnt/remotes:/remotes:rslave, dossier /remotes/share/watch) pour qu'un montage ultérieur sur l'hôte atteigne le conteneur, ou redémarrez le conteneur une fois le partage monté.

flowchart TD
    S["Toutes les 10 s : chaque dossier actif, premier niveau seulement"] --> F{"Nom se terminant par .torrent ou .magnet ?"}
    F -- non --> IGN["Ignoré"]
    F -- oui --> ST{"Même taille et même mtime<br/>qu'à l'analyse précédente ?"}
    ST -- non --> WAIT["Mémorisé, examiné à l'analyse suivante"]
    ST -- oui --> BIG{"Plus de 64 MiB ?"}
    BIG -- oui --> INV["Renommé NAME.invalid,<br/>motif dans NAME.invalid.txt"]
    BIG -- non --> K{"Un fichier .magnet ?"}
    K -- oui --> MAG["Requête magnet, première ligne non vide,<br/>catégorie du dossier"]
    K -- non --> ADD["Pipeline d'ajout, catégorie du dossier,<br/>jamais en mode seed"]
    MAG --> R{"Accepté, ou déjà ajouté ?"}
    ADD --> R
    R -- oui --> OK["Déplacé dans FOLDER/added/"]
    R -- non --> INV
Loading

Données en double (dédup à l'ajout)

Si vous ajoutez un torrent dont vous détenez déjà le contenu sous un autre torrent (même contenu, info hash différent : un ré-upload sur un autre tracker, une release renommée), Hydranos crée des hardlinks des fichiers existants sous les noms du nouveau torrent avant que le moteur n'examine le chemin de sauvegarde. Rien n'est retéléchargé.

  • Activé par défaut : [dedup] enabled = true s'applique même quand la section est absente (le default.toml livré n'en a pas).
  • Correspondance = les hashs de pièces des torrents sont identiques octet pour octet et les tailles de fichiers correspondent une à une. Pas de correspondance partielle. Les torrents uniquement v2 ne correspondent jamais.
  • Chaque fichier source doit exister avec la bonne taille ; aucun fichier de destination ne doit déjà exister (la dédup n'écrase donc jamais rien, et un ajout par-dessus des données déjà présentes au chemin de sauvegarde suit simplement la voie de la revérification) ; source et destination doivent être sur le même système de fichiers tel que le démon le voit (même identifiant de périphérique sous Linux/macOS, même numéro de série de volume sous Windows : deux dossiers sur un même disque NTFS conviennent).
  • Tout échec est silencieux et sans conséquence : les liens créés sont supprimés et le torrent se télécharge normalement.

Docker, Sonarr et Radarr. Hydranos vérifie l'identifiant de périphérique, puis appelle link() du noyau. Linux refuse un hardlink entre deux points de montage différents (erreur EXDEV) même s'il s'agit du même disque : deux bind mounts distincts (/mnt/user/downloads:/data/downloads et /mnt/user/media:/data/media) font donc échouer tous les liens de dédup, et le torrent est téléchargé à la place. Montez le parent commun une seule fois (par exemple /mnt/user/data:/data) et placez dessous le chemin de sauvegarde de chaque catégorie. Les imports par hardlink de Sonarr et Radarr suivent la même règle du noyau dans leur propre conteneur : donnez-leur le même montage parent unique, au même chemin dans le conteneur que dans Hydranos, pour que le chemin de sauvegarde que Hydranos indique via le shim soit un chemin qu'ils peuvent ouvrir. Hydranos lui-même ne crée jamais de lien dans votre bibliothèque ; cet import est une étape propre à Sonarr ou Radarr (voir Shim qBittorrent & automatisation et Docker).

  • Le torrent lié est quand même revérifié (le mode seed n'est pas implicite), il lit donc les données une fois avant de seeder. Le texte de la carte disant qu'il « seed immédiatement » est optimiste.

Onglet Config › Duplicate data › On adding a torrent we already hold : case Link it instead of downloading, bouton Enregistrer et redémarrer (Save and restart). Le réglage est écrit dans default.toml et appliqué immédiatement ; le bouton redémarre quand même Hydranos (voir Exploiter Hydranos pour ce que fait un redémarrage depuis l'interface). La carte affiche aussi le nombre de groupes de contenu identique. API : POST /api/dedup/config {"enabled": false}, GET /api/dedup/stats. La clé est listée sur Config : démon, auth & global.

Fichiers qu'un autre torrent détient déjà

Deux torrents différents peuvent nommer le même fichier : un ré-upload qui a gardé le nom de la release, un REPACK qui n'a pas été renommé, le même titre encodé deux fois. Avant la 4.4, le second trouvait des fichiers à ses chemins, les revérifiait, téléchargeait les pièces différentes et les écrivait par-dessus le fichier du premier torrent, qui continuait à seeder un mélange. Depuis la 4.4, la revendication de chemin (path claim) contrôle chaque ajout, après l'admission race et avant que quoi que ce soit ne soit écrit, contre les torrents de tous les moteurs qui nomment les mêmes chemins (ses propres copies dans d'autres moteurs exclues). Par fichier :

  • personne d'autre ne nomme le chemin : rien à faire ;
  • un autre torrent le nomme avec les mêmes pièces et la même liste de fichiers (cross-seed des mêmes octets) : partagé, comme toujours ;
  • un autre torrent le nomme avec une autre taille : un conflit, le fichier ne peut pas être les deux ;
  • un autre torrent le nomme avec la même taille : non prouvé, car même taille ne veut pas dire mêmes octets ; il est haché avant tout partage.
flowchart TD
    A["Ajout après l'admission race :<br/>les fichiers de ce torrent à son chemin de sauvegarde"] --> C{"Un autre torrent, dans un moteur quelconque, nomme un de ces chemins,<br/>pas avec les mêmes pièces et la même liste de fichiers ?"}
    C -- non --> F{"Fichiers présents sur disque, nommés par aucun torrent,<br/>avec un nombre de hardlinks supérieur à 1 ?"}
    F -- "non, ou mode seed" --> GO["Ajouté là où il l'a demandé"]
    F -- oui --> HP["Ajouté en pause là où il l'a demandé"]
    HP --> PV{"Chacun de ces fichiers est valide<br/>contre les pièces de ce torrent ?"}
    PV -- oui --> RS["Revérification ; démarré sauf si l'ajout le voulait arrêté ;<br/>ce qui manque se télécharge"]
    PV -- non --> ER["Reste en pause en erreur, rien d'écrit"]
    C -- oui --> SZ{"Mode seed, et chaque chemin partagé<br/>à la taille attendue par ce torrent ?"}
    SZ -- oui --> GO
    SZ -- non --> M{"[dedup] path_collision"}
    M -- legacy --> LG["Ajouté là où il l'a demandé : la revérification peut écraser,<br/>signalé comme partagé"]
    M -- refuse --> RF["Refusé : les écraserait"]
    M -- isolate --> IS["Ajouté en pause dans SAVE/TOP [hash8],<br/>mode seed abandonné"]
    IS --> PI["Fichiers de même taille hachés contre ses pièces,<br/>ceux qui sont valides liés en hardlink"]
    PI --> RS
Loading

[dedup] path_collision tranche le cas de conflit :

Valeur Ce qui se passe
isolate (par défaut) Le torrent reçoit son propre dossier à côté de celui qu'il demandait : <save path>/<first component of its name> [<first 8 hex digits of its info hash>], par exemple /data/tv/Show.S01 [1a2b3c4d]. Les fichiers de même taille dont le hash correspond à ses pièces y sont liés en hardlink, de sorte que seuls les fichiers réellement différents sont téléchargés. Le mode seed est abandonné (le nouveau dossier commence vide). Le torrent indique ce dossier comme son chemin de sauvegarde, aux clients du shim aussi.
refuse L'ajout est refusé : N file(s) of this torrent are already another torrent's with other bytes (path, path, path, ...); adding it there would overwrite them.
legacy Le comportement d'avant la 4.4 : chemin partagé, la revérification écrase ce qui diffère. Journalisé et signalé à chaque fois.

La clé n'est pas dans le default.toml livré et la carte Duplicate data n'écrit que enabled : ajoutez path_collision = "refuse" (ou "legacy") sous [dedup] à la main et redémarrez.

  • Le mode seed (skip_checking, tel que cross-seed l'envoie) par-dessus des fichiers de même taille d'un autre torrent est pris pour argent comptant : l'ajout se fait là où il le demandait, avec une ligne de journal info (path claim: skip_checking over files another torrent holds at the same size), pas une anomalie. Un conflit de taille est isolé, refusé ou laissé passer selon le réglage, même en mode seed.
  • Hardlinks de bibliothèque. Les fichiers déjà au chemin qu'aucun torrent ne nomme mais qui ont un autre hardlink (typiquement un import Sonarr/Radarr) sont prouvés avant que quoi que ce soit puisse y écrire : le torrent est ajouté en pause, ces fichiers sont hachés, et il n'est libéré que s'ils sont tous valides. Sinon il reste en pause en erreur avec N file(s) on disk differ from this torrent and are hardlinked elsewhere; held paused rather than overwrite them. Pas fait en mode seed.
  • La preuve tourne en arrière-plan (thread pathclaim-proof) ; l'ajout répond tout de suite. Un redémarrage au milieu d'une isolation laisse au pire un torrent en pause avec un dossier vide (ou ne contenant que des fichiers déjà prouvés identiques), qui se télécharge quand on le démarre ; lancez d'abord Vérifier à nouveau (Recheck) pour que les fichiers déjà liés soient comptés. Un torrent retenu sur place (hardlinks de bibliothèque), ou arrêté par une revérification gardée, reste en pause et n'est pas prouvé de nouveau après un redémarrage : Démarrer (Start) le prouve d'abord, comme un ajout (le torrent reste en pause pendant que ces fichiers sont hachés et ne démarre que s'ils sont tous valides ; un torrent complet démarre tout de suite), et Vérifier à nouveau aussi.
  • Deux ajouts nommant le même dossier au même moment (la même release prise sur deux trackers) sont contrôlés l'un après l'autre ; un ajout attend au plus 30 s, puis passe avec un WARN path claim: waited too long on another add, going ahead.
  • Sous Windows, les chemins sont comparés sans tenir compte de la casse.
  • Les revérifications sont gardées, quoi que dise path_collision : Vérifier à nouveau dans l'interface, POST /api/hoard/torrents/<hash>/verify, les revérifications groupées et MCP, et torrents/recheck du shim arrêtent un torrent dont un autre torrent nomme les fichiers avec d'autres octets, hachent ces fichiers, et ne le revérifient (en le redémarrant s'il tournait) que s'ils sont tous valides. Sinon il reste en pause en erreur avec le message hardlinked elsewhere ci-dessus, même si l'autre nom est le fichier d'un torrent.
  • Où le voir : chaque événement isolated, refused, shared (legacy), held et proven est une ligne de journal WARN path collision: … et est gardé en mémoire (les 500 derniers, perdus au redémarrage) pour le type path_collision de GET /api/health/anomalies (voir Supervision & journaux). Il n'y a pas d'analyse périodique des torrents existants : seuls les ajouts, les revérifications et Démarrer sont contrôlés.

Quand un ajout est refusé

Message (abrégé) Cause Solution
no save path: category "x" is unknown and no savepath was given Pas de chemin de sauvegarde explicite, et la catégorie est inconnue, vide, ou a un chemin de sauvegarde vide (par exemple une catégorie créée via createCategory du shim sans savePath). Créez la catégorie avec un chemin de sauvegarde (Catégories & routage) ou envoyez un chemin de sauvegarde.
no save path: give one, or a category that has one L'option sous-dossier sur un torrent mono-fichier, sans chemin de sauvegarde où placer le dossier. Comme ci-dessus.
no engine … / no engine named … on this node Le moteur cible n'existe pas. Les deux routes natives refusent un engine inconnu (400), magnets compris ; les magnets MCP se rabattent sur la catégorie ; un dossier surveillé refuse un engine inconnu à l'enregistrement (400), et ne se rabat que si ce moteur a été supprimé ensuite. Vérifiez l'identifiant de moteur dans l'onglet Nodes.
mode must be race or hoard, not "x" / no engine has the hoard role mode n'est ni race ni hoard, ou aucun moteur ne porte ce rôle. Envoyez race ou hoard, ou nommez l'engine.
give exactly one of torrent_path, torrent_url or magnet_uri POST /api/torrents n'en a reçu aucun ou plusieurs. Envoyez-en un seul.
<path>: no such file (404) torrent_path n'existe pas sur le disque du démon (une URL tapée comme chemin finit ici aussi). Donnez un chemin que le démon voit, ou utilisez torrent_url.
torrent_url must be an http(s) URL / <url> answered 404 … L'URL .torrent n'est pas en http(s), ou la récupération a échoué. Vérifiez le lien et sa passkey.
race disk full: … GB free of disk, … GB already promised … Admission race : uniquement pour un moteur de rôle race, uniquement quand [race_drain] add_block_enabled = true (par défaut false). L'espace libre (du quota race quand il y en a un : of N.N TB quota), moins ce que les téléchargements acceptés doivent encore écrire, moins reserve_free_gb (par défaut 0), est inférieur à la taille du torrent. Un volume illisible laisse passer l'ajout. Libérez de l'espace, ou voir Drain race & graduation.
N file(s) of this torrent are already another torrent's with other bytes (…); adding it there would overwrite them [dedup] path_collision = "refuse" et un autre torrent nomme ces fichiers avec d'autres octets. Choisissez la release, donnez un autre chemin de sauvegarde, ou utilisez isolate.
torrent already added / already added Ce moteur détient déjà le hash. Rien à faire. Le shim répond Ok., un dossier surveillé déplace le fichier dans added/, un magnet résolu est abandonné sans bruit ; les routes natives (409) et MCP le signalent comme une erreur.
torrent file did not parse Pas un .torrent valide. —
this magnet has only a v2 info hash (btmh) Magnet uniquement v2. Ajoutez le fichier .torrent.
contentLayout NoSubfolder on a multi-file torrent is not supported Ajout par le shim (ou son magnet, une fois résolu) demandant de supprimer le dossier d'un torrent multi-fichiers. Utilisez Original ou Subfolder.

Importer toute une bibliothèque

Pour importer d'un coup une bibliothèque qBittorrent ou Transmission existante (catégories, états arrêtés, mode seed pour les torrents complets dont les données sont trouvées), utilisez l'assistant d'import : Config › Paramètres avancés (default.toml) (Advanced settings (default.toml)) › onglet Import › Importer… (Import…) (sous le titre Importer depuis un autre client (Import from another client)). Il est décrit pas à pas sur Migrer depuis qBittorrent.

⚠️ **GitHub.com Fallback** ⚠️