Files
felhom.eu/documentation/audits/media-all-drives-2026-10-14/tools/landed.py
T

52 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""landed.py — Part E1: per imported episode/film, where the download was, where the library file is, hardlink or copy,
and which download app. Source: Sonarr's and Radarr's own `downloadFolderImported` history (droppedPath, importedPath,
downloadClientName) + a stat of both files NOW. Run INSIDE the guest (run_in_guest.py landed.py). Keys read at runtime,
never printed."""
import json, os, re, subprocess, urllib.request
def sh(c):
return subprocess.run(c, shell=True, capture_output=True, text=True).stdout.strip()
def get(app, port, path):
key = re.search(r"<ApiKey>([^<]+)</ApiKey>", open(f"/var/lib/docker/volumes/{app}_{app}_config/_data/config.xml").read()).group(1)
ip = sh(f"docker inspect {app} -f '{{{{range .NetworkSettings.Networks}}}}{{{{.IPAddress}}}}{{{{end}}}}'")
req = urllib.request.Request(f"http://{ip}:{port}/api/v3/{path}", headers={"X-Api-Key": key, "Host": app})
return json.load(urllib.request.urlopen(req, timeout=60))
def drive(p):
return p.split("/")[3] if p and p.startswith("/mnt/felhom-drives/") else "?"
def st(p):
try:
s = os.stat(p)
return (s.st_dev, s.st_ino, s.st_nlink)
except OSError:
return None
for app, port, kind in (("sonarr", 8989, "series"), ("radarr", 7878, "movie")):
tags = {t["id"]: t["label"] for t in get(app, port, "tag")}
items = {x["id"]: x for x in get(app, port, kind)}
hist = get(app, port, "history?pageSize=500&eventType=3")["records"] # 3 = downloadFolderImported
print(f"== {app}: {len(hist)} import(s)")
for x in items.values():
print(f" {kind} {x['title']}: root={drive(x.get('rootFolderPath') or x.get('path'))} tags={[tags.get(i, i) for i in x['tags']]}")
for h in sorted(hist, key=lambda h: h["date"]):
d = h["data"]
src, dst = d.get("droppedPath"), d.get("importedPath")
a, b = st(src), st(dst)
if a and b and a[:2] == b[:2]:
how = "HARDLINK"
elif b and b[2] == 1:
how = "COPY" if not a or a[:2] != b[:2] else "?"
else:
how = "library file gone" if not b else "?"
title = items.get(h.get("seriesId") or h.get("movieId"), {}).get("title", "?")
print(f" {title[:24]:24} {os.path.basename(dst or '')[:46]:46} client={d.get('downloadClientName'):22} "
f"download={drive(src)} library={drive(dst)} {how}")