Trackers: ajoute le type torr9 (login JWT + /api/v1/users/me)

torr9 a une API Go dédiée (api.torr9.net) avec auth JWT (username/password).
Le ratio se calcule (total+bonus) up/down comme le frontend ; pas de champ
ratio dans l'API. Le passkey du compte ne sert qu'au RSS, pas au profil.
This commit is contained in:
jerem
2026-06-17 10:39:09 +02:00
parent 4680092f8a
commit 291a076759
2 changed files with 47 additions and 2 deletions

View File

@@ -41,12 +41,19 @@ MONITORINK_CODEX_TOKEN_FILE=/hermes/auth.json
# Liste des clés actives, puis UN bloc par tracker. v1 : type "unit3d_nuxt" (ex. c411).
# Le ratio n'est PAS lisible au token API -> login requis (username/password du compte).
# Laisser MONITORINK_TRACKERS vide pour masquer la section.
#MONITORINK_TRACKERS=c411
#MONITORINK_TRACKERS=c411,torr9
#MONITORINK_TRACKER_C411_LABEL=c411
#MONITORINK_TRACKER_C411_TYPE=unit3d_nuxt
#MONITORINK_TRACKER_C411_URL=https://c411.org
#MONITORINK_TRACKER_C411_USER=TonUsername
#MONITORINK_TRACKER_C411_PASS=TonMotDePasse
# torr9 : type "torr9" (API JWT dédiée). URL = sous-domaine API. Le passkey ne sert
# qu'au RSS, pas au ratio -> identifiant/mot de passe requis.
#MONITORINK_TRACKER_TORR9_LABEL=torr9
#MONITORINK_TRACKER_TORR9_TYPE=torr9
#MONITORINK_TRACKER_TORR9_URL=https://api.torr9.net
#MONITORINK_TRACKER_TORR9_USER=TonUsername
#MONITORINK_TRACKER_TORR9_PASS=TonMotDePasse
#MONITORINK_TRACKER_TTL=1800
# Home Assistant (optionnel) — laisser vide pour désactiver

View File

@@ -119,7 +119,45 @@ async def _fetch_unit3d(spec: TrackerSpec) -> TrackerStat:
)
_FETCHERS = {"unit3d_nuxt": _fetch_unit3d}
async def _fetch_torr9(spec: TrackerSpec) -> TrackerStat:
"""torr9 : API Go dédiée (`api.torr9.net`). Login JWT puis `/api/v1/users/me`.
Le profil n'a pas de champ `ratio` ; on le calcule comme le frontend :
(total_uploaded_bytes + bonus_uploaded) / (total_downloaded_bytes + bonus_downloaded).
NB : le passkey du compte ne sert qu'aux flux RSS, pas à ce profil."""
if not (spec.base_url and spec.username and spec.password):
return TrackerStat(spec.key, spec.label, ok=False, error="non configuré")
async with httpx.AsyncClient(
timeout=20, follow_redirects=True, headers={"User-Agent": _UA},
) as client:
r = await client.post(
f"{spec.base_url}/api/v1/auth/login",
json={"username": spec.username, "password": spec.password},
)
try:
d = r.json()
except ValueError:
raise _AuthError(f"login HTTP {r.status_code}")
token = d.get("token")
if not token:
raise _AuthError(str(d.get("error") or d.get("message") or "login refusé"))
me = await client.get(
f"{spec.base_url}/api/v1/users/me",
headers={"Authorization": f"Bearer {token}"},
)
if me.status_code != 200:
raise _AuthError(f"users/me HTTP {me.status_code}")
u = me.json()
up = int(u.get("total_uploaded_bytes", 0) or 0) + int(u.get("bonus_uploaded", 0) or 0)
down = int(u.get("total_downloaded_bytes", 0) or 0) + int(u.get("bonus_downloaded", 0) or 0)
return TrackerStat(
spec.key, spec.label, ok=True,
ratio=(up / down if down else 0.0), up_bytes=up, down_bytes=down,
)
_FETCHERS = {"unit3d_nuxt": _fetch_unit3d, "torr9": _fetch_torr9}
async def _fetch_one(spec: TrackerSpec) -> TrackerStat: