Workflows FR - Kheopsian/Hydranos GitHub Wiki
S'applique à Hydranos 4.4.
Pour tous ceux qui veulent qu'Hydranos agisse sur les torrents sans script : arrêter le seed au bout d'un certain temps, poser des tags, appeler un webhook à la fin d'un téléchargement, ajouter des trackers. Vous verrez ce que fait chaque déclencheur, chaque condition et chaque action, comment tester une règle, et ce qui manque encore en 4.4. Vocabulaire : Concepts & glossaire.
Un workflow a trois parties :
- un déclencheur (le champ Se lance (Runs)) : à intervalle régulier (on a timer), quand un téléchargement se termine (when a download completes) ou quand un torrent est ajouté (when a torrent is added) ;
- un arbre de conditions (When) : des comparaisons de champs regroupées en ET / OU / NON ;
- une liste d'actions (Then), exécutées dans l'ordre sur chaque torrent qui correspond.
Les workflows vivent dans le store (hydra.db), pas dans default.toml. Un workflow enregistré sans "enabled": true est désactivé. Ils agissent sur les torrents des moteurs de cette instance (race, hoard, supplémentaires), jamais sur les lignes fusionnées depuis un nœud déclaré.
flowchart LR
T1["Minuterie (toutes les interval_secs, min 60)"] --> ALL["Chaque copie de torrent dans chaque moteur local"]
T2["Un téléchargement se termine"] --> EV["File d'événements (table du store workflow_events)"]
T3["Un torrent est ajouté"] --> EV
EV --> ONE["Ce seul torrent"]
ALL --> WHEN["When : arbre de conditions"]
ONE --> WHEN
WHEN -->|"pas de correspondance"| NOP["Rien, rien n'est journalisé"]
WHEN -->|"correspondance"| DONE{"Chaque action hors webhook<br/>déjà comme demandé ?"}
DONE -->|"oui, et aucun webhook à envoyer"| SKIP["Ignoré, rien n'est journalisé"]
DONE -->|"oui, déclencheur d'événement avec webhook"| THEN
DONE -->|"non"| CAP{"Minuterie : At most atteint<br/>sur ce passage ?"}
CAP -->|"oui"| STOP["Reste du passage remis à la fois suivante"]
CAP -->|"non"| THEN["Then : actions restant à faire, dans l'ordre,<br/>webhooks en dernier"]
THEN --> ACT["Journal Activity : applied ou failed"]
THEN -.->|"move files to a folder"| JOB["Onglet Jobs : job move_data"]
Onglet Workflows, bouton + New workflow : Nom (Name), Se lance (Runs), pour les minuteries Runs every (secondes, minimum 60, 900 par défaut) et At most (torrents par passage, 500 par défaut), puis When, Then, et Aperçu (Preview) / Enregistrer (Save) / Annuler (Cancel). Traduits dans toutes les langues : Name, Save, Cancel, l'en-tête Actions de la liste ; en français, également Runs, les choix de déclencheur, Preview, Every (on completion, when added), none of these (NOT), la case hardlink de move files to a folder, les notes d'action et le Remove d'un groupe. Les boutons de la liste, le Remove d'une ligne, all of these (AND) / any of these (OR), ainsi que les libellés de champs, d'opérateurs et d'actions restent en anglais.
| Se lance (Runs) | Valeur transmise | Quand il se déclenche | Ce qu'il évalue |
|---|---|---|---|
| à intervalle régulier (on a timer) |
schedule (par défaut) |
Quand now − last run ≥ interval_secs (plancher de 60 s). La minuterie fait son premier tic environ trois minutes après le démarrage, puis une fois par minute. Les workflows dus s'exécutent tour à tour. |
Chaque copie de torrent dans chaque moteur local. Au plus cap torrents ayant quelque chose à faire par passage. |
| quand un téléchargement se termine (when a download completes) | completed |
Une fois par téléchargement, quand sa dernière pièce est vérifiée. Un torrent ajouté avec ses données déjà sur le disque, ou revérifié complet, ne le déclenche jamais. | Ce seul torrent. |
| quand un torrent est ajouté (when a torrent is added) | added |
Une fois par torrent, dès que le moteur le détient. Se déclenche pour les ajouts depuis l'onglet + Ajouter un torrent (+ Add Torrent), l'API REST, le shim qBittorrent (Sonarr, Radarr, autobrr), les magnets une fois résolus, les dossiers surveillés, le serveur MCP, les règles RSS (et le Téléchargement (Download) de l'onglet RSS) et un rapatriement depuis un nœud déclaré. L'assistant d'import et les déplacements de données ne le déclenchent pas. | Ce seul torrent. |
Les détails qui comptent :
- Un workflow à minuterie converge : un torrent déjà « comme demandé » (arrêté, tagué…) est ignoré et non journalisé, jusqu'à ce qu'il s'en écarte de nouveau (démarrez à la main un torrent qu'un workflow arrête, et le passage suivant l'arrête de nouveau).
- La dernière exécution est enregistrée avant le passage, si bien qu'un passage lent n'est jamais lancé deux fois. Un workflow à minuterie nouvellement activé et qui n'a jamais tourné est dû au prochain tic.
- Les événements sont d'abord écrits dans le store, donc un redémarrage n'en perd aucun. Un événement dont le torrent n'est pas encore chargé attend jusqu'à une heure, puis est abandonné. Les workflows à événement n'ont ni intervalle ni plafond.
- Sur un déclencheur d'événement, un When vide est autorisé et signifie « chaque téléchargement qui se termine » ou « chaque torrent ajouté ». Pour l'obtenir dans l'éditeur, cliquez sur Remove sur la ligne de condition avec laquelle démarre un nouveau workflow. Sur une minuterie, un When vide est refusé (il correspondrait à tout le catalogue).
- Les champs de hardlinks (
link_count,external_links,freeable_bytes,data_missing) sont refusés sur les déclencheurs d'événement : l'index n'a pas mesuré un torrent qui vient d'arriver.
When commence par un groupe racine. Chaque groupe est all of these (AND), any of these (OR) ou aucune de ces conditions (NON) (none of these (NOT)). À l'intérieur, + Condition ajoute une ligne (champ, opérateur, valeur) et + Group ajoute un groupe imbriqué. Remove supprime une ligne ou un groupe (le groupe racine ne peut pas être supprimé). Les groupes vides sont éliminés à l'enregistrement.
aucune de ces conditions (NON) correspond quand aucune de ses lignes n'est vraie ; il est enregistré sous la forme {"kind":"not","of":{"kind":"any","of":[…]}}. Un NOT écrit via l'API s'ouvre comme un groupe aucune de ces conditions (NON) (ce qu'il enveloppe devient l'unique enfant de ce groupe quand ce n'est pas un OU), si bien que l'enregistrer depuis l'éditeur garde son sens.
L'éditeur construit ses listes à partir de GET /api/workflows/fields. Voici tous les champs :
| Libellé dans l'interface | Champ | Type | Ce qu'il lit |
|---|---|---|---|
| torrent name / info hash |
name / info_hash
|
text | Nom du métainfo / hash hexadécimal. |
| category | category |
text | La catégorie de cette copie. |
| tags | tags |
tags | Les tags du torrent. |
| state | state |
text | L'état affiché par la liste : seeding, downloading, stopped, queued, checking_files, error. |
| engine | engine |
text | Identifiant de moteur (race, hoard, vpn1…). |
| save path | save_path |
text | Chemin de sauvegarde enregistré pour cette copie. |
| tracker | tracker_host |
text | Hôte (sans schéma ni port) du premier tracker de la liste en cours uniquement. |
| has a tracker error | tracker_error |
bool | La dernière annonce a renvoyé une erreur. |
| tracker error message | tracker_error_msg |
text | Son texte. |
| has a torrent error | torrent_error |
bool | Le moteur marque le torrent en erreur. |
| stopped by hand | user_paused |
bool | Votre intention d'arrêt telle qu'enregistrée, pas l'état momentané du moteur. |
| has several files | multi_file |
bool | Plus d'un fichier. |
| private | private |
bool | Drapeau privé du métainfo. Affiché private, faute de libellé. |
| progress | progress |
percent | Part du contenu détenue : pièces vérifiées, (taille − octets restants) ÷ taille, 0-100. Un torrent vaut 100 pendant qu'il seede ; un torrent dont les pièces ne sont pas encore connues (encore en vérification) vaut 0 — tout comme un torrent arrêté sans carte des pièces (voir le bug connu plus bas). Utilisez completed_age pour dire « complet ». |
| ratio | ratio |
number | Le ratio de la liste : envoyé ÷ téléchargé, ou ÷ données détenues quand moins de 1 % a été téléchargé (un cross-seed). Conservé par tout déplacement (Déplacer vers un dossier… (Set location…), un déplacement de catégorie, move files to a folder, une graduation, un Move to engine ›) ; une copie faite par Duplicate to engine › part de 0 (Jobs). |
| size / uploaded / downloaded |
total_size / total_uploaded / total_downloaded
|
size | Compteurs du moteur. |
| upload rate / download rate |
upload_rate / download_rate
|
size (bytes/s) | Débits actuels. |
| connected peers | num_peers |
number | Pairs connectés en ce moment. |
| seeds the tracker reports | num_seeds |
number | Seeders rapportés par le tracker (identique à swarm_seeds), pas des pairs connectés. |
| seeds in swarm / leechers in swarm |
swarm_seeds / swarm_leechers
|
number | Seeders / leechers rapportés par le tracker. |
| time spent seeding | seeding_time |
duration | Le temps de seed cumulé par le moteur depuis la fin du téléchargement : n'augmente que pendant le seed et hors arrêt. |
| time since added | added_age |
duration | Maintenant − date d'ajout. |
| time since completed | completed_age |
duration | Maintenant − date de fin. Un torrent qui ne s'est jamais terminé n'en a pas. |
| free space where it is stored | free_space |
size | Espace libre sur le système de fichiers du chemin de sauvegarde. Sur une minuterie, mesuré seulement quand une condition l'utilise. |
| hardlinks to its files | link_count |
number | Tous les hardlinks, y compris ceux d'Hydranos. Deux cross-seeds l'un de l'autre valent tous deux 2. |
| hardlinks from outside Hydranos | external_links |
number | 0 signifie que seul Hydranos pointe vers ces fichiers. |
| space deleting would really free | freeable_bytes |
size | Uniquement les fichiers vers lesquels rien d'autre ne pointe. |
| its files are missing from disk | data_missing |
bool | Vrai quand l'index des hardlinks n'a trouvé aucun des fichiers du torrent. Un torrent dont seuls certains fichiers ont disparu vaut faux (la ligne Hardlink index les compte à part, en with some files missing). Pas encore mesuré = faux. |
Opérateurs (l'éditeur affiche le libellé, l'API prend l'identifiant) :
| Type | Opérateurs (libellé → identifiant) |
|---|---|
| text | is eq, is not ne, contains contains, does not contain not_contains, starts with starts_with, ends with ends_with, matches regex matches
|
| number, percent, size | is eq, is not ne, is more than gt, is at least ge, is less than lt, is at most le
|
| duration | is older than gt, is at least ge, is newer than lt, is at most le, is eq, is not ne
|
| bool | is eq, is not ne (valeur true / false) |
| tags | has tag has_tag, does not have tag not_has_tag
|
Valeurs :
-
Durées :
2d,36h,90m,45sou des secondes brutes (l'éditeur a un sélecteur d'unité). -
Tailles :
KB/MB/GB/TBsont des puissances de 1000,KiB/MiB/GiB/TiBdes puissances de 1024 :500GB≠500GiB. -
Booléens :
true,yesou1signifient vrai ; tout le reste signifie faux. -
Texte : les comparaisons ignorent la casse, sauf
matches, qui est une expression régulière sensible à la casse (syntaxe Rustregex; préfixez(?i)pour ignorer la casse). Les comparaisons de tags sont exactes, casse comprise. - Pour category, tags, tracker et engine, l'éditeur propose une liste déroulante des valeurs connues.
-
« Jamais arrivé » ne correspond à rien. Un torrent qui ne s'est jamais terminé échoue à toute comparaison sur
completed_age,is notcompris. Un torrent que l'index des hardlinks n'a pas encore mesuré échoue à toute condition surlink_count,external_linksetfreeable_bytes;data_missingvaut faux pour lui, doncdata_missing is falsele prend. Dans un groupe aucune de ces conditions (NON), le résultat s'inverse : NONcompleted_age is newer than 1dou NONexternal_links is more than 0prend chaque torrent jamais terminé ou pas encore mesuré. Écrivez plutôt la forme positive (external_links is 0) qu'un NON.
Index des hardlinks. Les champs de hardlinks viennent d'un index en arrière-plan (démarre ~3 min après le boot, re-mesure les entrées de plus de 24 h ; HYDRANOS_LINK_SCAN_THREADS, 16 par défaut). La ligne Hardlink index: X of Y torrents measured sous la liste montre son avancement. Un passage re-mesure ses candidats avant d'agir, et un delete décidé sur des faits de hardlinks est refusé si un nouveau lien est apparu entre-temps.
| Libellé dans Then |
type transmis et champs |
Ce qu'elle fait |
|---|---|---|
| stop the torrent | {"type":"pause"} |
Enregistre l'intention d'arrêt pour cette copie et l'arrête dans son moteur, comme le bouton Arrêter (Stop). Aucun effet sur le disque. |
| start the torrent | {"type":"resume"} |
L'inverse. |
| set category (files stay) | {"type":"set_category","to":"tv"} |
Change uniquement l'étiquette de catégorie de cette copie : aucun déplacement de fichiers, aucun changement de moteur (pour déplacer les données : move files to a folder ou Changer de catégorie + déplacer les fichiers › (Change category + move files ›)). |
| move files to a folder | {"type":"set_location","to":"/data/archive","allow_breaking_hardlinks":false} |
Met en file un job move_data (onglet Jobs), avec le même plan et les mêmes refus que Déplacer vers un dossier… (Set location…). « Déjà sur place »/« déjà en file » comptent comme un succès. Le chemin doit être absolu, avec des noms simples uniquement. Sous Windows, un chemin avec lettre de lecteur (D:\archive) ou UNC est accepté ; \archive n'y est pas absolu. Un fichier hardlinké qui exigerait une copie entre disques fait échouer le torrent, sauf si allow_breaking_hardlinks vaut true (case copier quand même les fichiers hardlinkés d'un disque à l'autre (casse le lien, double l'espace) (copy hardlinked files across disks anyway (breaks the link, uses the space twice))). |
| add trackers | {"type":"add_trackers","urls":["udp://tracker.example.org:6969/announce"],"list_url":""} |
Ajoute chaque nouvelle URL dans son propre palier. list_url récupère une liste (une URL par ligne, commentaires # ignorés, ≤ 500 URL, mise en cache 24 h). Jamais appliquée à un torrent privé. Chaque tracker ajouté apprend l'IP de cette instance. Voir Trackers & annonces. |
| add tags / remove tags | {"type":"add_tags","tags":["noHL"]} |
Réécrit les tags du torrent sur chaque copie. Dans l'éditeur, séparez les tags par des virgules. |
| delete the torrent | {"type":"delete","with_files":false} |
Supprime la copie qui correspond comme une suppression manuelle. also delete the files on disk positionne with_files. Les fichiers qu'un autre torrent chargé lit au même chemin sont conservés (la copie de ce torrent dans un autre moteur comprise, quand elle pointe vers le même dossier) ; une copie dont le contenu est ailleurs ne protège rien (voir Jobs, actions groupées & déplacement). Doit être la seule action.
|
| call a webhook | {"type":"webhook","url":"https://hooks.example.org/hydranos"} |
Envoie du JSON en POST (voir ci-dessous) par la sortie propre du démon ([daemon] egress, voir VPN & sortie réseau). L'URL doit être en http:// ou https://. |
Comment les actions s'exécutent :
- Les actions d'un torrent s'exécutent dans l'ordre. Le premier échec arrête les suivantes pour ce torrent, qui compte comme
failed. - Les webhooks s'exécutent toujours après les autres actions, quelle que soit leur position dans Then.
- Sur une minuterie, un webhook n'est envoyé que lors d'un passage où une autre action du même workflow modifie le torrent. Un workflow à minuterie dont les seules actions sont des webhooks est refusé (il appellerait l'URL à chaque passage). Sur un déclencheur d'événement, le webhook est toujours envoyé, et un webhook seul est autorisé.
- Si le webhook échoue après l'écriture d'un tag, le tag reste, et le passage suivant (torrent « comme demandé ») ne retente pas le webhook.
- Chaque tentative a un délai d'expiration de 10 s ; un échec est retenté après 2 s puis 5 s, un 4xx ne l'est pas. L'URL n'apparaît jamais dans les erreurs. Un endpoint mort ralentit le passage.
- Quand le kill switch ne laisse au démon aucune sortie, le webhook n'est pas envoyé du tout (pas de nouvelle tentative) : le torrent compte comme
failedavecwebhook: <reason>. - Il n'existe aucune action pour lancer une commande, revérifier, ré-annoncer, fixer des limites ou déplacer un torrent vers un autre moteur.
Corps du webhook :
{"event": "completed", "workflow": "Notify on completion", "at": 1790000000,
"content": "Some.Torrent finished downloading (4.37 GiB)", "text": "…same…", "message": "…same…",
"torrent": {"info_hash": "0123…", "name": "Some.Torrent", "category": "tv", "tags": [],
"engine": "race", "save_path": "/data/race/tv", "state": "seeding", "tracker": "tracker.example.org",
"size": 4692251443, "progress": 100, "ratio": 0.0, "uploaded": 0, "downloaded": 4692251443,
"seeding_time": 0}}event vaut matched (minuterie), completed ou added. Le résumé est répété sous content (Discord), text (Slack, Mattermost) et message (Gotify), si bien que ces services acceptent l'URL directement. Les nombres inconnus valent null.
| Contrôle | Où | Route | Ce qu'il fait |
|---|---|---|---|
| Aperçu (Preview) | éditeur |
POST /api/workflows/preview (corps = le workflow, enregistré ou non) |
Valide comme un enregistrement, exécute la même évaluation qu'un vrai passage, ne modifie aucun torrent. Minuterie : N matched, M would change, K already as asked, (capped), would free X GB pour une suppression, les 10 premiers noms. quand un téléchargement se termine (when a download completes) : sur chaque torrent dont progress est sous 100, arrêtés compris — ce qui prend aussi les torrents complets arrêtés sans carte des pièces (voir progress), si bien que le compte peut surestimer. quand un torrent est ajouté (when a torrent is added) : sur les torrents ajoutés dans les dernières 24 heures. |
| Dry-run | ligne de la liste (minuterie uniquement) | POST /api/workflows/:id/run?dry=1 |
Même évaluation, sur la version enregistrée. La réponse apparaît en JSON brut dans une alerte du navigateur : dry_run, matched, would_apply, skipped, capped, rechecked, no_longer_true. Un dry-run qui n'appliquerait rien (aucune correspondance, ou chaque correspondance déjà comme demandé) écrit une ligne Activity avec le résultat dry_run_no_match. |
| Run now | ligne de la liste (minuterie uniquement) | POST /api/workflows/:id/run |
Un vrai passage, activé ou non. Il enregistre la dernière exécution et renvoie matched, applied, skipped, failed, capped, rechecked, no_longer_true. |
Dry-run et Run now sont masqués pour les workflows à événement (l'API répond 400) : utilisez Aperçu (Preview). « Would free » additionne la taille complète de chaque torrent correspondant : il surestime pour les fichiers hardlinkés ou partagés. Pour une règle sur les hardlinks, Aperçu et Dry-run re-mesurent aussi les candidats et écrivent les valeurs fraîches dans l'index des hardlinks. C'est, avec la ligne dry_run_no_match, tout ce qu'ils écrivent.
Le tableau Activity sous la liste affiche le journal des workflows : When, Workflow, Torrent, Action, Outcome, Detail. Il charge les 500 lignes les plus récentes. Les lignes de plus de 7 jours sont purgées chaque minute.
- Une ligne par torrent traité. Action joint les actions effectuées par
+(pause,resume,category,add_tags,remove_tags,delete,webhook,set_location,add_trackers), par ex.add_tags+webhook. - Le même tableau contient ce qu'ont fait les règles RSS : Workflow
RSS: <rule name>(RSS: (manual)pour le Téléchargement de l'onglet RSS), Actionrss_add, Torrent le titre de l'article, Outcomeapplied,skipped(Detailalready in this client) oufailedavec la raison (un échec passager se termine par; tried again at the next pass). - Pour un workflow, Outcome vaut
appliedoufailed. Pourfailed, Detail donne l'erreur (par exemplewebhook: HTTP 500 after 3 tries; un 4xx donnewebhook: HTTP 404). Un torrent privé n'est jamais un échec : add trackers le saute comme « comme demandé ». - Les torrents déjà « comme demandé » et les passages qui ne correspondent à rien ne sont pas journalisés (sauf un Dry-run qui n'a rien à appliquer :
dry_run_no_match). -
appliedpour move files to a folder signifie « job mis en file » ; suivez le déplacement dans l'onglet Jobs.
Chaque exemple donne les étapes dans l'éditeur et le même workflow en JSON pour l'API. L'API accepte "enabled": true ; l'éditeur enregistre un nouveau workflow désactivé, donc cochez Enabled dans la liste après le premier enregistrement (enregistrer une modification garde l'état du workflow).
-
+ New workflow. Nom (Name) :
Stop after 14 days on tracker.example.org. Se lance (Runs) : à intervalle régulier (on a timer). Runs every :3600. -
When (all of these (AND)) : tracker · is ·
tracker.example.org. Cliquez sur + Condition : time spent seeding · is older than ·14jours. - Then : stop the torrent.
- Aperçu (Preview), puis Enregistrer (Save), puis cochez Enabled.
{
"name": "Stop after 14 days on tracker.example.org",
"enabled": true,
"trigger": "schedule",
"interval_secs": 3600,
"cap": 500,
"when": {"kind": "all", "of": [
{"kind": "cond", "field": "tracker_host", "op": "eq", "value": "tracker.example.org"},
{"kind": "cond", "field": "seeding_time", "op": "gt", "value": "14d"}
]},
"then": [{"type": "pause"}]
}tracker ne lit que le premier tracker. Hydranos a aussi des limites de partage intégrées, par moteur et par torrent (File d'attente, limites de partage et de débit) ; un workflow comme celui-ci sert aux règles qu'elles ne savent pas exprimer (par tracker, par catégorie, par tags…).
Repère les contenus que votre médiathèque n'utilise plus (par ex. après que Sonarr a supprimé son hardlink).
-
+ New workflow. Nom (Name) :
Tag noHL. Se lance (Runs) : à intervalle régulier (on a timer). Runs every :21600. -
When : hardlinks from outside Hydranos · is ·
0. + Condition : state · is ·seeding. -
Then : add tags ·
noHL. - Aperçu (Preview). Vérifiez la ligne Hardlink index sous la liste : les torrents pas encore mesurés ne correspondent jamais. Puis Enregistrer (Save) et cochez Enabled.
{
"name": "Tag noHL",
"enabled": true,
"trigger": "schedule",
"interval_secs": 21600,
"cap": 500,
"when": {"kind": "all", "of": [
{"kind": "cond", "field": "external_links", "op": "eq", "value": "0"},
{"kind": "cond", "field": "state", "op": "eq", "value": "seeding"}
]},
"then": [{"type": "add_tags", "tags": ["noHL"]}]
}Le tag reste quand la condition cesse d'être vraie ; un second workflow (external_links is more than 0, has tag noHL → remove tags) l'efface. Vérifiez avant de supprimer quoi que ce soit.
-
+ New workflow. Nom (Name) :
Notify on completion. Se lance (Runs) : quand un téléchargement se termine (when a download completes). -
When : cliquez sur Remove sur la ligne de condition de départ pour agir sur chaque téléchargement, ou gardez une condition comme category · is ·
tv. -
Then : call a webhook ·
https://hooks.example.org/hydranos. -
Aperçu (Preview) (il s'exécute sur les torrents dont
progressest sous 100, voir Aperçu), Enregistrer (Save), cochez Enabled.
{
"name": "Notify on completion",
"enabled": true,
"trigger": "completed",
"when": {"kind": "all", "of": []},
"then": [{"type": "webhook", "url": "https://hooks.example.org/hydranos"}]
}Le corps est le JSON montré sous Actions. Les torrents ajoutés avec leurs données déjà sur le disque ne le déclenchent jamais.
-
+ New workflow. Nom (Name) :
Public trackers on add. Se lance (Runs) : quand un torrent est ajouté (when a torrent is added). -
When : private · is ·
false. -
Then : add trackers. Saisissez une URL d'annonce par ligne, par ex.
udp://tracker.example.org:6969/announce, ou mettez l'URL d'une liste dans la seconde case. - Aperçu (Preview) (il montre ce qui serait arrivé aux arrivées du dernier jour), Enregistrer (Save), cochez Enabled.
{
"name": "Public trackers on add",
"enabled": true,
"trigger": "added",
"when": {"kind": "all", "of": [
{"kind": "cond", "field": "private", "op": "eq", "value": "false"}
]},
"then": [{"type": "add_trackers",
"urls": ["udp://tracker.example.org:6969/announce"],
"list_url": ""}]
}L'action saute les torrents privés même sans la condition. Donnez toujours un port pour les URL udp://. Une récupération de liste qui échoue se rabat sur la dernière copie valide ; s'il n'y en a aucune, l'action échoue.
L'éditeur ne peut pas réordonner les workflows (position n'est jamais envoyé).
Bug connu en 4.4 :
progresssemble valoir 100 pour tout torrent complet — il vaut 0 pour un torrent arrêté sans carte des pièces : un ajout en mode seed ou un cross-seed ajouté arrêté, ou un torrent complet rechargé après un redémarrage et arrêté (seul un torrent qui seede est connu pour tout détenir sans carte). Une règle commeprogress is 100les rate etprogress < 100les prend — pour dire « complet », testezcompleted_age(renseigné pour un ajout en mode seed et conservé après un redémarrage) ;state is seedinglaisse de côté les torrents arrêtés.
Toutes les routes exigent la clé API (en-tête X-Api-Key ou paramètre de requête apikey). Les conventions complètes sont sur API REST.
| Méthode et route | Corps / réponse |
|---|---|
GET /api/workflows |
Liste : id, name, enabled, position, trigger, interval_secs, last_run, when, then, cap. |
POST /api/workflows |
Création ou mise à jour (même id = mise à jour). Corps : name (obligatoire), enabled (false par défaut), trigger (schedule par défaut), interval_secs (900 par défaut, relevé à 60), cap (500 par défaut ; 0 devient 500), when, then, id et position facultatifs. Le workflow est d'abord compilé : un workflow invalide reçoit un 400 avec la raison. |
DELETE /api/workflows/:id |
Suppression ; 404 si inconnu. |
POST /api/workflows/preview |
Corps = un workflow. Réponse comme dans Aperçu ci-dessus, plus freed_bytes et sample (≤ 200 torrents) ; les déclencheurs d'événement ajoutent trigger et downloading / recent. |
POST /api/workflows/:id/run[?dry=1] |
Exécution immédiate ou dry-run (workflows à minuterie uniquement ; les workflows à événement reçoivent 400). |
GET /api/workflows/fields |
Le catalogue de champs qu'utilise l'éditeur (name, label, kind, operators, hint…). |
GET /api/workflows/activity |
Les 500 dernières lignes Activity : at, workflow_name, info_hash, torrent_name, action, outcome, detail. |
GET /api/workflows/links |
État de l'index des hardlinks (catalogue, measured, data_missing, sweep…). |
Arbre de conditions : {"kind":"all","of":[…]}, {"kind":"any","of":[…]}, {"kind":"not","of":{…}}, {"kind":"cond","field":"…","op":"…","value":"…"}.
Enregistrer et Aperçu refusent aussi un champ inconnu, une valeur qui ne se lit pas et une regex invalide, en plus des formes listées sous Déclencheurs et Actions.
# Preview a draft
curl -s -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d @stop-after-14d.json http://localhost:8199/api/workflows/preview
# Save it (enabled if the file says "enabled": true)
curl -s -H "X-Api-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d @stop-after-14d.json http://localhost:8199/api/workflowsPour modifier un workflow existant, faites un GET de la liste, modifiez l'objet et renvoyez-le entier en POST, avec son id (last_run est ignoré).