Jobs and Moving Data FR - Kheopsian/Hydranos GitHub Wiki

🇬🇧 English · 🇫🇷 Français

Jobs, actions groupées et déplacement des données

S'applique à Hydranos 4.4.

Cette page s'adresse à vous si vous agissez sur beaucoup de torrents à la fois, si vous déplacez des données entre dossiers ou disques, ou si vous supprimez des torrents. Vous y verrez ce que fait réellement chaque entrée du menu contextuel, comment un déplacement de données s'exécute et échoue, ce qu'affiche l'onglet Jobs, et quels fichiers exactement une suppression efface.

Deux mots ont ici un sens strict. Une tâche groupée (bulk task) est ce que lance une action du menu contextuel : elle vit en mémoire et dispose d'un panneau de progression. Un job (tâche de fond) est un déplacement persistant en arrière-plan (move_data, graduate, ou handoff pour un déplacement vers un autre nœud), listé dans l'onglet Jobs. Les autres termes (store, état de reprise, mode seed) sont définis sur Concepts & glossaire.

Actions groupées

Sélectionnez des lignes dans la liste Race ou Hoard, puis faites un clic droit. Un clic sélectionne une ligne, Ctrl/Cmd-clic en ajoute ou retire une, Maj-clic sélectionne une plage. Ctrl+A sur le tableau Hoard sélectionne tous les torrents qui correspondent au filtre en cours, pas seulement les 500 lignes affichées. Ctrl+A ne fait rien sur le tableau Race.

Chaque entrée du menu, sauf le groupe Exporter (Export), envoie la sélection à POST /api/selection/<action> et lance une tâche groupée (l'export télécharge un fichier, voir Exporter). La sélection voyage sous l'une de deux formes :

  • Par lignes : les hash que vous avez choisis, chacun avec sa copie (local-hoard, local-race, ou <node>-<engine> pour une ligne distante).
  • Par filtre (Ctrl+A) : le filtre de la liste lui-même, plus expect, le nombre qui vous a été affiché. Si le filtre correspond maintenant à plus de torrents que expect, le serveur refuse avec un 409 grew et l'interface demande Le filtre correspond maintenant à {n} torrents, pas {m}. Appliquer aux {n} ? (The filter now matches {n} torrents, not {m}. Apply to all {n}?). Moins est accepté. Une sélection vide est toujours refusée ; elle ne signifie jamais « tout ».

Au-delà de 500 torrents, Arrêter (Stop), Démarrer (Start) et les deux entrées de suppression demandent d'abord une confirmation. Annuler (Cancel) dans le panneau de progression s'arrête entre deux torrents pour les actions torrent par torrent, entre deux lots de 10 000 torrents pour Arrêter, Démarrer, Forcer le téléchargement (Force download), Modifier les tags (Edit tags), Limites de partage… (Share limits…) et Changer de catégorie › (Change category ›) (modifications du store seul), et entre deux séries de 8 pour Re-annoncer (Reannounce). Le panneau et ses lignes de résultat sont décrits sur Visite de l'interface web. Une tâche groupée est perdue au redémarrage et n'apparaît jamais dans l'onglet Jobs.

Entrée du menu Ce qu'elle fait Lignes hoard Lignes race
Arrêter / Démarrer Enregistre votre intention d'arrêt/démarrage dans le store (elle survit aux redémarrages), puis arrête ou démarre la copie dans son moteur oui oui
Forcer le téléchargement / Ne plus forcer (Stop forcing) Marque un torrent incomplet comme forcé (filtre Forced) : la file de téléchargement le fait tourner au-delà de son plafond, voir File d'attente, limites de partage et de débit oui ignorée
Re-annoncer Demande au planificateur d'annonces d'annoncer tout de suite ; résultats ok, in_flight, cooldown, queued oui oui
Vérifier à nouveau (Recheck) Vérifie par hash la copie que désigne la ligne, dans son propre moteur ; protégée quand un autre torrent nomme les mêmes fichiers (voir Fichiers qu'un autre torrent détient déjà). Entrée affichée quand une ligne hoard est sélectionnée, ou après Ctrl+A oui oui
Changer de catégorie › Étiquette seulement, Aucune catégorie (No category) l'efface. Aucun fichier ne bouge, aucun changement de moteur oui oui
Changer de catégorie + déplacer les fichiers › (Change category + move files ›) Les données suivent le chemin de sauvegarde de la catégorie, sous forme de job ; une catégorie de l'autre mode est une graduation oui oui
Déplacer vers un dossier… (Set location…) Déplace les données vers un dossier que vous saisissez ; la catégorie ne change pas oui oui
Modifier les tags › (Edit tags ›) Ajoute ou retire un tag (entrée affichée quand une ligne hoard est sélectionnée, ou après Ctrl+A) oui ignorée
Limiter le débit… (Limit rate…) Le plafond d'envoi/réception propre à la copie (voir File d'attente, limites de partage et de débit) oui oui
Limites de partage… Les limites de ratio et de temps de seed du torrent (même page) oui oui
Téléchargement séquentiel (Sequential download), Première/dernière pièce d'abord (First/last piece first) Ordre de téléchargement de la copie (voir Ordre de téléchargement) oui oui
Duplicate to engine › Seede les mêmes fichiers depuis un second moteur (voir Copies dans plusieurs moteurs) oui oui
Move to engine › Confie le torrent à un autre moteur avec son état ; les fichiers ne bougent pas oui oui
Télécharger les .torrent (.zip) (Download .torrent files (.zip)), Télécharger la liste des hash (.txt) (Download hash list (.txt)), Télécharger en CSV (Download as CSV) Export (voir Exporter) oui oui
Retirer le torrent (Remove torrent) / Retirer + supprimer les fichiers (Remove + delete files) Retire uniquement la copie sélectionnée (voir Supprimer) oui oui

Les lignes « ignorées » sont comptées comme {n} non concernés ({n} not applicable) dans le panneau de progression. Chaque entrée propre à une copie agit sur la copie qu'est la ligne : la ligne d'un moteur supplémentaire (local-<id>) envoie ?engine=<id> (ou ?agent=local-<id>). Re-annoncer et Duplicate to engine › sont les exceptions : Re-annoncer annonce la première copie trouvée (ci-dessous), Duplicate pointe le nouveau moteur sur le chemin de sauvegarde de la première copie. Les lignes qui viennent d'un autre nœud sont relayées à ce nœud (Arrêter/Démarrer, Re-annoncer, Vérifier à nouveau, les deux entrées Changer de catégorie, Déplacer vers un dossier…, Limiter le débit…, ordre de téléchargement, suppression) ; Modifier les tags ›, Forcer le téléchargement et Limites de partage… sont comptés {n} absents de ce nœud ({n} not on this node). Sur les lignes distantes, les entrées de moteur ne proposent que local-<id> (bring it here, un rapatriement) et, sous Move to engine ›, les autres moteurs du nœud qui détient la ligne (there, no copy). Voir Nœuds & plusieurs machines.

Bug connu en 4.4 : un Re-annoncer groupé semble agir sur la copie qu'est la ligne, comme Arrêter, Vérifier à nouveau ou Limiter le débit… — il ne nomme aucun moteur, donc pour un hash détenu par deux moteurs il annonce la première copie trouvée, qui peut être l'autre. Constaté à la lecture du code, non reproduit — pour annoncer une seule copie, appelez POST /api/torrents/<hash>/reannounce?engine=<id>.

Vérifier à nouveau et Modifier les tags › sont masqués quand la sélection ne contient aucune ligne hoard, et Ctrl+A n'existe pas sur le tableau Race : depuis le seul onglet Race, le menu n'offre aucune revérification groupée. Passez par l'API (POST /api/selection/recheck, ci-dessous), qui revérifie aussi les copies race.

La même chose par l'API

# Stop every torrent of category "tv" in the hoard list (expect = the count you saw)
curl -X POST http://localhost:8199/api/selection/stop \
  -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"selection":{"filter":"category=tv","view":"hoard","expect":120},"params":{}}'
# -> 202 {"job":"sel…","total":120}

curl -H "X-Api-Key: YOUR_API_KEY" http://localhost:8199/api/selection/jobs/sel0123456789ab

Clés de filtre : search, category, category_not, tag, tag_not, tracker, tracker_not, error_class, error_class_not, state. Chaque corps de requête rejette les champs inconnus avec un 400 qui les nomme. La liste complète des actions est sur API REST.

Déplacer des données

Six choses lancent un déplacement de données dans Hydranos :

  • Déplacer vers un dossier… : n'importe quel dossier absolu, catégorie inchangée.
  • Changer de catégorie + déplacer les fichiers › : le Chemin d'enregistrement (Save Path) de la catégorie. L'arbre de décision (changement d'étiquette, déplacement, ou graduation vers l'autre moteur) est dessiné sur Catégories & routage.
  • Une action de workflow move files to a folder (set_location) : mêmes vérifications que Déplacer vers un dossier… (voir Workflows).
  • L'outil MCP move_to_category, qui envoie la même requête que Changer de catégorie + déplacer les fichiers › (voir Serveur MCP).
  • POST /api/torrents/:hash/graduate {"engine":"hoard","category":"tv"} (ou un save_path ; sans lui, le Chemin d'enregistrement de la catégorie est utilisé, sinon 400 save_path is required (or a category that has one)). Elle effectue les mêmes vérifications qu'un déplacement par catégorie ci-dessous, accepte "allow_breaking_hardlinks": true, et répond 200 {"status":"queued","job":…,"plan":…}.
  • Le drain race, qui met en file des jobs graduate sans ces vérifications (voir Drain race & graduation).

Un déplacement vers un autre nœud n'est pas un déplacement de données sur cette machine : c'est un job handoff qui attend le nœud (voir L'onglet Jobs).

Déplacer vers un dossier (Set location)

L'invite indique Chemin absolu du dossier où déplacer les données. La catégorie ne change pas. Un torrent à plusieurs fichiers garde son propre dossier à l'intérieur de celui-ci. (Absolute path of the folder to move the data to. The category does not change. A torrent with several files keeps its own folder inside this one.) Avec une seule ligne sélectionnée, elle est préremplie avec le chemin de sauvegarde actuel.

  • Le chemin doit être absolu et .. est refusé (400) ; un . dans le chemin est supprimé sans avertissement (/data/./tv devient /data/tv). Un séparateur final est supprimé. L'API ne retire pas les espaces (un nom de dossier peut se terminer par un espace) ; l'interface retire ceux que vous tapez. Les chemins avec lecteur (D:\media) ne sont acceptés que sur la version Windows ; sous Linux ils sont refusés comme non absolus.
  • Un torrent multi-fichiers arrive dans <target>/<torrent name>/… ; un torrent à fichier unique arrive directement dans <target>.
  • Seuls les fichiers du torrent lui-même bougent, fichier par fichier. Les autres fichiers du même dossier restent. Les fichiers absents à la source sont ignorés.
  • Si le dossier cible est le chemin de sauvegarde actuel du torrent (une comparaison de chemins, pas un examen des fichiers), rien n'est mis en file : 200 {"status":"ok","moved":false}.
curl -X POST http://localhost:8199/api/hoard/torrents/0123456789abcdef0123456789abcdef01234567/location \
  -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"location":"/data/archive"}'
# -> 202 {"status":"moving","job":"job…","kind":"move_data","plan":{…}}

Utilisez /api/race/… pour une copie race, et ?engine=vpn1 pour une copie dans un moteur supplémentaire.

Vérifications avant la mise en file d'un déplacement

flowchart TD
    A["Set location, Change category + move files,<br/>workflow set_location"] --> K{"Changement vers une catégorie<br/>de l'autre mode ?"}
    K -->|"non, ou Set location"| N{"Dossier cible = chemin<br/>de sauvegarde actuel ?"}
    N -->|"oui"| N2["200, moved false<br/>rien en file"]
    N -->|"non"| B
    K -->|"oui, même si le chemin<br/>de sauvegarde ne change pas"| B{"unsafe_path, shared<br/>ou destination_taken ?"}
    G["POST /api/torrents/HASH/graduate"] --> B
    B -->|"oui"| X["409, refusé<br/>quelle que soit votre réponse"]
    B -->|"non"| C{"Des fichiers en hardlink doivent être copiés<br/>sans consentement donné ?"}
    C -->|"oui"| H["409 hardlinks<br/>l'interface demande : Les déplacer quand même ?"]
    H -->|"oui : renvoyé avec allow_breaking_hardlinks"| A
    C -->|"non"| D{"Assez d'espace libre<br/>à la cible ?"}
    D -->|"non"| S["409 space"]
    D -->|"oui"| Q{"Un déplacement déjà en file<br/>ou en cours pour ce torrent ?"}
    Q -->|"oui"| Q2["409 déjà en file"]
    Q -->|"non, même mode"| MD["202 : job move_data<br/>même moteur, vérifications refaites,<br/>retour arrière en cas d'échec"]
    Q -->|"non, autre mode, ou /graduate"| GR["job graduate en file<br/>202, ou 200 depuis /graduate"]
    DR["Drain race"] -->|"aucune vérification de chemin, partage, destination,<br/>hardlink ou espace ;<br/>ignoré si un déplacement est déjà en file"| GJ
    GR --> GJ["le job graduate s'exécute :<br/>retiré de la source d'abord,<br/>retour arrière en cas d'échec ou d'annulation"]
Loading

Pour Changer de catégorie + déplacer les fichiers ›, le test de mode passe en premier : une catégorie de l'autre mode met toujours en file un graduate, même quand son chemin de sauvegarde est celui où se trouvent déjà les données.

Refus HTTP Signification Pouvez-vous passer outre ?
chemin invalide 400 non absolu, ou contient .. non
unsafe_path 409 le .torrent nomme un fichier hors de son propre dossier non
shared 409 un autre torrent chargé, dans n'importe quel moteur, lit l'un des mêmes chemins de fichier (un cross-seed, par exemple), y compris la copie de ce même torrent dans un autre moteur (après Duplicate to engine ›) ; le déplacement le laisserait sans rien à servir non
destination_taken 409 un fichier existe déjà à la destination et ce n'est pas le même fichier (en général le fichier homonyme d'un autre torrent) : N file(s) already exist at the destination (…); moving onto them would overwrite them. Voir Fichiers qu'un autre torrent détient déjà non
hardlinks 409 un fichier qui doit être copié (cible sur un autre système de fichiers) a un autre nom sur le disque, en général dans votre bibliothèque Sonarr/Radarr ; la copie casserait le lien et doublerait l'espace occupé. Sous Docker, la cause habituelle est deux bind mounts séparés, ce que vous pouvez corriger : voir Un montage parent unique, pour les hardlinks sur Docker oui : "allow_breaking_hardlinks": true. L'interface demande une fois par sélection ; si vous répondez non, ces torrents sont comptés left in place (hardlinks)
space 409 l'espace libre à la cible est inférieur aux octets à copier (les renommages ne coûtent rien) non
déjà en file 409 un seul déplacement en attente par torrent, quel que soit son type attendez la fin du job

Chaque 409, sauf « déjà en file », contient un objet plan : from, to, files, bytes, missing_files, rename_files, copy_files, copy_bytes, hardlinked_files, hardlinked_bytes, free_bytes, enough_space, unsafe_path, shared_with, occupied (les fichiers déjà présents à la destination), et un reason qui nomme la ligne du tableau ci-dessus. « Le même fichier » signifie le même inode sous Linux (un hardlink de ce fichier convient) et le même chemin canonique sous Windows.

Un job move_data refait ces vérifications (unsafe_path, shared, destination_taken, hardlinks, espace) quand son tour vient, et échoue avec …; nothing was moved si l'une d'elles ne passe plus. Un job graduate ne les refait pas : il refuse seulement, fichier par fichier, un fichier en hardlink à copier sans consentement ou un fichier plus gros que l'espace libre, et revient en arrière.

Simulation. GET /api/{race,hoard}/torrents/:hash/move-preview?category=tv renvoie kind (relabel, move_data ou graduate), engine, target_engine et, pour move_data et graduate, le même plan (une réponse relabel n'en a pas), sans rien déplacer. category est obligatoire (400 sans). Elle ne prévisualise qu'un déplacement par catégorie ; il n'existe pas d'aperçu pour un emplacement libre.

Jobs

Un job est une ligne de la table jobs du store. Il survit aux redémarrages. Deux types déplacent des données sur cette machine :

move_data graduate
Lancé par Déplacer vers un dossier…, Changer de catégorie + déplacer les fichiers › (même mode), workflow set_location Changer de catégorie + déplacer les fichiers › vers une catégorie de l'autre mode, le drain race, POST /api/torrents/:hash/graduate
Moteur reste le même passe à l'autre moteur
Seed pendant la copie oui, depuis les originaux non : le torrent quitte le moteur source avant que le moindre fichier bouge
Comment les fichiers bougent même système de fichiers : renommage ; autre système de fichiers : tout copier d'abord, supprimer les originaux à la fin fichier par fichier : renommage, ou copie puis suppression immédiate de la source
Le torrent ensuite son propre enregistrement de reprise réimporté au nouveau dossier, tel qu'il était (voir Après un déplacement) adopté avec son propre enregistrement de reprise, tel qu'il était
En cas d'échec retour arrière retour arrière : fichiers remis en place, torrent de nouveau dans son moteur source tel qu'il était
Annuler en cours d'exécution refusé (409) : il va jusqu'au bout s'arrête après le fichier en cours, puis retour arrière

Un troisième type, handoff, ne déplace rien ici : c'est un déplacement vers un autre nœud qui attend que ce nœud détienne une copie complète (voir L'onglet Jobs).

Règles communes :

  • Un seul job à la fois pour toute l'instance, le plus ancien d'abord. L'exécuteur cherche du travail toutes les 5 s. Un job handoff n'occupe pas cette place.
  • Les copies sont une simple boucle lecture/écriture avec des tampons de 4 MiB et un fsync par fichier. Elle évite volontairement copy_file_range, pour que ZFS ne fasse jamais de block-cloning des données. Il n'y a pas de limite de débit, ni de clé de configuration pour en fixer une.
  • « Même système de fichiers » signifie même identifiant de périphérique sous Linux et même numéro de série de volume sous Windows.
  • Après un redémarrage, les jobs qui étaient running ou cancelling repassent en queued avec une progression remise à zéro, et sont relancés depuis le début. Ils ne reprennent pas là où ils s'étaient arrêtés, et une annulation inachevée est oubliée : annulez de nouveau le job. Les jobs waiting (handoff) continuent d'attendre.
  • La progression compte les octets des fichiers copiés ou renommés.

Ce que fait un job move_data

sequenceDiagram
    participant U as Vous
    participant A as API Hydranos
    participant R as Exécuteur de jobs
    participant E as Moteur
    participant D as Disque
    participant S as Store
    U->>A: POST .../location ou .../category avec move_files
    A->>A: vérifications (chemin dangereux, partage, destination occupée, hardlinks, espace, déjà en file)
    A-->>U: 202 + id du job
    Note over R: un seul job à la fois
    R->>R: nouveau plan et nouvelle vérification du partage, de la destination occupée, des hardlinks, de l'espace libre
    R->>D: copie des fichiers dont la cible est sur un autre système de fichiers
    Note over E,D: le torrent continue de seeder depuis les originaux
    alt une copie échoue
        R->>D: suppression des copies déjà faites
        R->>S: job en échec, rien n'a bougé
    else copies terminées
        R->>E: capture de l'enregistrement de reprise, retrait du torrent, données conservées
        R->>D: renommage des fichiers sur le même système de fichiers
        R->>E: réimport de l'enregistrement au nouveau dossier
        alt le renommage ou le réimport échoue
            R->>D: annulation des renommages, suppression des copies
            R->>E: réimport de l'enregistrement à l'ancien dossier
            R->>S: job en échec, retour arrière effectué
        else réimporté
            R->>S: chemin de sauvegarde (et catégorie) mis à jour
            R->>D: suppression des originaux copiés, nettoyage des sous-dossiers vidés
            R->>S: job terminé
        end
    end
Loading

Il n'y a pas d'étape de vérification par hash : la copie est considérée comme fiable. Les sous-dossiers vidés sous l'ancien chemin de sauvegarde sont supprimés, jamais l'ancien chemin de sauvegarde lui-même (d'autres torrents peuvent le partager). Si un original ne peut pas être supprimé à la fin, le job réussit quand même et le journal affiche un avertissement.

Ce que fait un job graduate

  1. Capture l'enregistrement de reprise du torrent (pièces détenues, trackers modifiés, compteurs d'octets, temps de seed, état d'arrêt, ses propres plafonds de débit et son ordre de téléchargement), puis le retire du moteur source, en conservant ses données.
  2. Déplace chaque fichier : renommage sur le même système de fichiers ; sinon vérifie l'espace libre et les hardlinks pour ce fichier, le copie, puis supprime le fichier source. Une Annulation est prise en compte entre deux fichiers.
  3. Le moteur cible adopte le torrent au nouveau dossier à partir de cet enregistrement, comme le relit un redémarrage : pas de revérification, rien de remis à zéro, un torrent arrêté reste arrêté.
  4. Met à jour le store : moteur, chemin de sauvegarde, catégorie.

Tout échec après l'étape 1 (un fichier en hardlink sans consentement, un disque plein, une cible qui refuse le torrent) et toute Annulation sont défaits : les fichiers déjà déplacés sont remis en place, le moteur source adopte de nouveau l'enregistrement, et le job se termine avec la raison suivie de l'une de ces fins :

Fin du message État
rolled back, the torrent is in <engine> as before revenu où il était
back in <engine>, but these files did not move back: … de nouveau dans son moteur ; les fichiers listés sont encore à la destination, remettez-les en place à la main
ROLLBACK FAILED, re-add it by hand at <folder>: … dans aucun moteur ; ses données sont sur disque. Ajoutez à nouveau le .torrent (depuis Télécharger les .torrent (.zip) ou une sauvegarde) à ce dossier

Une graduation annulée se termine en Annulé (Cancelled), une graduation en échec en Échec.

Une graduation planifie d'abord ses fichiers comme un déplacement : si un fichier du même nom se trouve déjà à la destination (en général celui d'un autre torrent), le job est refusé (… already exist …; nothing was moved) et le torrent reste où il est. Le drain race vérifie la même chose avant de mettre une graduation en file, et journalise par catégorie les torrents qu'il laisse en place pour cette raison, en WARN not graduated: files of the same name already sit at the destination….

Après un déplacement : ce qui change

Chaque déplacement transporte le torrent tel qu'il était. Une graduation et Move to engine › passent son enregistrement de reprise au moteur cible ; un job move_data (Déplacer vers un dossier…, un Changer de catégorie + déplacer les fichiers › du même mode, workflow set_location) réimporte l'enregistrement propre au torrent au nouveau dossier. Les pièces détenues, les trackers modifiés, les compteurs d'octets (donc le ratio), le temps de seed, l'état d'arrêt, ses propres plafonds de débit et son ordre de téléchargement sont conservés, avec la catégorie, les tags et les limites de partage ; rien n'est revérifié, et un torrent inachevé continue de se télécharger au nouvel endroit.

Duplicate to engine › ajoute une seconde copie en mode seed, sur les mêmes fichiers. Il est refusé (409 … does not hold all of it yet; duplicate it once it is complete) tant que la source n'est pas complète ou est en cours de vérification.

Le crédit chez votre tracker, pour tous les types de déplacement : le moteur source lâche le torrent sans annoncer stopped (une suppression, elle, l'annonce), donc l'envoi effectué depuis sa dernière annonce n'est jamais déclaré. Le torrent déplacé démarre ensuite une nouvelle session d'annonce à partir de 0, comme après un redémarrage (voir Trackers & annonces). L'envoi déjà annoncé est crédité par le tracker et reste acquis.

L'onglet Jobs

L'onglet Jobs indique Travaux de longue haleine : le déplacement des données d'un torrent entre systèmes de fichiers continue ici, et le torrent continue de partager pendant ce temps. (Long-running work: moving a torrent's data between filesystems keeps running here, and the torrent keeps seeding while it does.) Cette phrase n'est vraie que pour move_data : un job graduate cesse de seeder pendant la copie, et un job handoff ne copie rien ici. Il liste les 200 jobs les plus récents, rafraîchis toutes les 2 s tant que l'onglet est ouvert, plus un bouton Rafraîchir (Refresh). Actifs seulement (Active only) garde les jobs pas encore terminés (queued, running, cancelling, waiting).

Colonne Contenu
État (State) En cours (Running), En attente du node (Waiting for the node) (handoff), Terminé (Done), Échec (Failed), Annulé ; un job qui attend son tour affiche le mot brut queued, un job en cours d'annulation le mot brut cancelling
Type move_data, graduate ou handoff
Torrent nom enregistré au moment de la mise en file du job, et le hash
Progression (Progress) barre avec octets traités / total (pour handoff, la progression du nœud) ; un job en échec affiche ici son texte d'erreur à la place
Destination dossier cible ; pour handoff, <node>-<engine> (ou <node>)
Démarré (Started) moment où le job a été mis en file
(bouton) Annuler, sur les jobs queued, running et waiting

Sans aucune ligne, le tableau affiche Rien en cours. (Nothing running.) Les jobs terminés restent dans la liste.

Annuler demande Annuler ce job ? Un job en attente est abandonné. Un déplacement vers un autre engine s'arrête après le fichier en cours et tout est remis comme avant ; un autre déplacement en cours ne peut pas être interrompu et se termine. Un déplacement vers un node cesse d'attendre : les deux copies sont gardées. (Cancel this job? A waiting job is dropped. A move to another engine stops after the current file and is put back as it was; another running move cannot be interrupted and finishes. A move to a node stops waiting: both copies are kept.) Ce que fait le serveur :

Job Réponse Effet
queued (tout type) 200 {"status":"cancelled"} abandonné avant de démarrer ; état Annulé
graduate, running 200 {"status":"cancelling"} s'arrête après le fichier en cours et revient en arrière (voir Ce que fait un job graduate) ; puis Annulé
move_data, running 409 a running move cannot be interrupted safely; it will finish aucun : le job va jusqu'au bout (l'interface affiche le message)
handoff, waiting 200 {"status":"cancelled"} cesse d'attendre : la copie locale est conservée, le nœud garde celle qu'il a reçue
terminé 409 the job is already <state> aucun
id inconnu 404 no such job <id> aucun

Déplacements vers un nœud (handoff)

Move to engine › avec une cible de type nœud (<node>-<engine>) envoie le torrent au nœud, puis met en file un job handoff à l'état waiting (la tâche groupée le compte {n} envoyé(s) ; la copie locale part quand le node l'a en entier (Jobs) ({n} sent; the local copy goes once the node holds it (Jobs))). Toutes les 30 s, le job demande au nœud ce qu'il détient. À 100 %, il retire chaque copie locale avec ses fichiers (sauf les fichiers que lit un torrent d'un autre hash). Si le nœud est retiré, ou ne déclare pas de copie complète dans les 6 heures (l'échéance est enregistrée dans le job, donc un redémarrage la conserve), le job échoue et la copie locale est conservée. Un second déplacement du même torrent pendant qu'un premier attend est refusé (409 a move of this torrent to a node is already waiting; see Jobs). Duplicate to engine › vers un nœud ne crée aucun job. Détails : Nœuds & plusieurs machines.

API : GET /api/jobs?limit= (100 par défaut, les plus récents d'abord) et GET /api/jobs/:id, chaque job avec id, type, state (queued, running, cancelling, waiting, done, failed, cancelled), info_hash, params, progress_bytes, total_bytes, percent, error, created_at, updated_at. DELETE /api/jobs/:id est Annuler, avec les réponses ci-dessus. POST /api/jobs/move-remote a disparu : toute requête reçoit un 410 qui renvoie vers POST /api/selection/handoff (voir Mettre à jour depuis la 3.x).

Copies dans plusieurs moteurs

Un même torrent peut être détenu par plusieurs moteurs de la même instance. Chaque copie a sa propre catégorie, son propre état d'arrêt et son propre peer id, et les copies partagent les mêmes fichiers.

Duplicate to engine › → local-<id> (same files, second identity) (mêmes fichiers, seconde identité) Move to engine › → local-<id> (here, no copy) (ici, sans copie)
Route POST /api/torrents/:hash/copy {"engine":"vpn1"} POST /api/torrents/:hash/engine?engine=<source> {"engine":"vpn1"}
Copies ensuite deux : la source continue de seeder une : la source lâche le torrent
Copie lue la première copie trouvée (?engine= ignoré) celle que nomme ?engine= (le menu envoie celle de la ligne)
La nouvelle copie ajoutée depuis le .torrent stocké au même chemin de sauvegarde, en mode seed, démarrée : complète parce que la source l'est, trackers du .torrent, compteurs à 0 adoptée avec l'enregistrement de reprise de la source : pièces, trackers, compteurs, temps de seed, état d'arrêt
Ordre ajout à la cible la cible adopte d'abord, puis la source lâche ; si la cible refuse, 500 the target engine refused it; nothing was changed ; si la source refuse ensuite de lâcher, la copie cible est défaite
Fichiers rien n'est copié ni déplacé sur le disque rien n'est copié ni déplacé sur le disque
Refus 409 <engine> already seeds it ; 409 … does not hold all of it yet; duplicate it once it is complete tant que la source est incomplète ou en cours de vérification 400 already in <engine>, no engine named <engine> on this node
  • Deux copies sur les mêmes fichiers sont désormais liées : Déplacer vers un dossier… ou un déplacement par catégorie de l'une ou l'autre est refusé avec shared (le déplacement laisserait l'autre sans rien à servir), et Retirer + supprimer les fichiers sur l'une conserve les fichiers que lit l'autre (voir Supprimer).
  • Sur la plupart des routes propres à une copie, ?engine=<id> désigne la copie visée (?agent=local-<id> est l'ancienne écriture de la même chose). /graduate et /copy l'ignorent et utilisent la première copie trouvée.
  • Les cibles de type nœud (<node>-<engine>) sont un handoff via BitTorrent : Move to engine › vers un nœud est un job handoff (voir Déplacements vers un nœud), Duplicate to engine › vers un nœud n'est pas un job. Voir Nœuds & plusieurs machines.

Le groupe de menu Node qui contient ces deux entrées s'affiche dès que cette instance a deux moteurs (toujours, avec race et hoard par défaut) ou qu'un nœud est déclaré. Plus d'informations sur les moteurs supplémentaires : Moteurs : race & hoard.

Exporter

Le groupe Exporter télécharge la sélection (Ctrl+A compris) sous forme d'un seul fichier envoyé en flux :

Entrée Fichier Contenu
Télécharger les .torrent (.zip) hydranos-<n>-torrents.zip un <name> [<first 8 hash chars>].torrent par torrent, tiré du store ; missing.txt liste les hash que cette instance ne détient pas
Télécharger la liste des hash (.txt) hydranos-<n>-hashes.txt un hash par ligne, sans consultation du store (lignes distantes comprises)
Télécharger en CSV hydranos-<n>-torrents.csv en-tête info_hash,name,size,category,tags,trackers,added_unix,save_path ; les hash inconnus ont quand même une ligne qui ne contient que le hash (<hash>,,,,,,,)

Pour le zip, une boîte de dialogue avertit que le .torrent d'un tracker privé contient votre passkey dans son URL d'annonce (a private tracker's .torrent carries your passkey in its announce URL) et propose Garder les trackers (Keep trackers) ou Retirer les trackers (Remove trackers). Retirer les trackers supprime uniquement announce et announce-list ; l'info hash ne change pas. Un fichier qui ne peut pas être réécrit est écarté et listé dans missing.txt plutôt qu'exporté avec sa passkey. Le .torrent exporté est celui stocké au moment de l'ajout : les modifications de trackers faites dans Hydranos n'y figurent pas.

curl -X POST "http://localhost:8199/api/torrents/export" -H "X-Api-Key: YOUR_API_KEY" \
  -d format=zip -d strip_trackers=1 \
  -d hashes=0123456789abcdef0123456789abcdef01234567 -o export.zip

Le formulaire accepte selection (le même JSON que pour une action groupée) ou hashes (séparés par des virgules), et format=zip|txt|csv.

Supprimer

Retirer le torrent conserve les fichiers ; Retirer + supprimer les fichiers les supprime. Depuis le menu contextuel, chacune retire uniquement la copie sélectionnée. La route REST DELETE /api/torrents/:hash?delete_files=true sans engine retire toutes les copies, tout comme torrents/delete du shim qBittorrent.

Ce qui est supprimé sur le disque :

  • Fichier par fichier, uniquement les fichiers que le torrent nomme. Jamais de suppression récursive de dossier. Les sous-dossiers vidés d'un torrent multi-fichiers sont supprimés de bas en haut ; un dossier qui contient encore un fichier étranger reste.
  • Les fichiers qu'un autre torrent chargé lit exactement au même chemin sont conservés, dans n'importe quel moteur : un cross-seed, un upload seedé depuis ses fichiers sources, ou la copie de ce même torrent dans un autre moteur pointée sur le même dossier (Duplicate to engine ›). Le journal indique files kept: another torrent reads them. La comparaison porte sur les chemins, pas sur les inodes : un hardlink dans votre médiathèque est un autre nom et conserve de toute façon ses octets.
  • Une copie qui a ses propres données ne protège rien. Si la copie race et la copie hoard d'un même torrent sont dans deux dossiers différents (la même release récupérée deux fois), en retirer une avec + supprimer les fichiers (+ delete files) supprime les fichiers de son dossier, quoi que détienne l'autre copie.
  • Retirer toutes les copies d'un coup (DELETE sans engine) supprime les fichiers propres à chaque copie, moins ce que lit un torrent d'un autre hash ; deux copies sur le même chemin perdent ce chemin quand la dernière d'entre elles part.
  • Un fichier absent n'est pas une erreur.

Pour deux torrents au contenu différent sous les mêmes noms de fichiers, voir Fichiers qu'un autre torrent détient déjà : depuis la 4.4, un ajout ne les laisse plus partager un chemin (sauf avec [dedup] path_collision = "legacy").

Le moteur envoie stopped aux trackers, retire le torrent, puis reporte ses octets cumulés dans les compteurs globaux de l'instance et supprime la ligne du store. L'état de reprise du moteur pour ce torrent est effacé. POST /api/race/torrents/:hash/purge retire la copie race de la même façon, avec ses fichiers (moins les fichiers qu'une autre copie ou un autre torrent lit), et laisse toute copie hoard intacte : voir API REST. L'outil MCP delete_torrents n'existe que si [mcp] allow_destructive = true (voir Serveur MCP).

Voir aussi

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