fix: use build_catalog.sh as single source of truth for catalog

This commit is contained in:
Hermes committed 2026-08-09 23:32:12 +02:00
1 parent 7a078319a6
commit e0bfb2e8ed
2 files changed
+33 -71

No files matched your search

Binary file not shown.
+33 -71
View File
@@ -25,7 +25,7 @@ from pydantic import BaseModel
APP_DIR = Path(os.environ.get("APP_DIR", "/data/app"))
MOVIES_DIR = APP_DIR / "movies"
CATALOG = APP_DIR / "catalog.json"
CATALOG = MOVIES_DIR / "catalog.json"
WEBHOOK = os.environ.get("DEPLOY_WEBHOOK", "")
WEBHOOK_TOKEN = os.environ.get("COOLIFY_TOKEN", "")
@@ -48,10 +48,6 @@ def load_catalog():
return {"movies": []}
return json.loads(CATALOG.read_text(encoding="utf-8"))
def save_catalog(cat):
cat["updated"] = datetime.date.today().isoformat()
CATALOG.write_text(json.dumps(cat, ensure_ascii=False, indent=2), encoding="utf-8")
def deploy():
if not WEBHOOK:
return {"deployed": False, "reason": "no webhook configured"}
@@ -100,50 +96,18 @@ def torrent_hash(path: Path):
return hashlib.sha1(enc(info)).hexdigest()
def rebuild_catalog():
"""Rebuild catalog.json from /movies folders (port of build_catalog.sh)."""
movies = []
if MOVIES_DIR.exists():
for entry in sorted(os.listdir(MOVIES_DIR)):
d = MOVIES_DIR / entry
if not d.is_dir() or entry.startswith("."):
continue
meta = {"id": entry}
mf = d / "meta.txt"
if mf.exists():
for line in mf.read_text(encoding="utf-8", errors="replace").splitlines():
line = line.strip()
if not line or ":" not in line:
continue
k, v = line.split(":", 1)
k, v = k.strip(), v.strip()
if k in ("title", "original_title", "description"):
meta[k] = v
elif k == "year":
meta["year"] = int(v) if v.isdigit() else v
elif k == "genre":
meta["genre"] = [g.strip() for g in v.split(",") if g.strip()]
elif k == "rating":
try: meta["rating"] = float(v)
except: pass
# poster
for ext in ("jpg", "png", "jpeg", "webp"):
p = d / ("poster." + ext)
if p.exists():
meta["poster"] = "movies/%s/poster.%s" % (entry, ext)
break
# torrent
tors = list(d.glob("*.torrent"))
if tors:
try:
meta["hash"] = torrent_hash(tors[0])
meta["torrent"] = "movies/%s/%s" % (entry, tors[0].name)
except Exception as e:
meta["torrent_error"] = str(e)
movies.append(meta)
"""Rebuild catalog.json by running the project's build_catalog.sh
(keeps a single source of truth for catalog generation)."""
script = MOVIES_DIR.parent / "build_catalog.sh"
if not script.exists():
raise HTTPException(500, "build_catalog.sh not found at %s" % script)
try:
subprocess.run(["bash", str(script)], check=True,
capture_output=True, text=True, timeout=120)
except subprocess.CalledProcessError as e:
raise HTTPException(500, "build failed: " + (e.stderr or e.stdout or str(e)))
cat = load_catalog()
cat["movies"] = movies
save_catalog(cat)
return len(movies)
return len(cat.get("movies", []))
# ---------- endpoints ----------
@@ -247,16 +211,27 @@ class PatchBody(BaseModel):
@app.patch("/movie/{fid}")
def patch_movie(fid: str, body: PatchBody):
fid = valid_id(fid)
cat = load_catalog()
m = next((x for x in cat.get("movies", []) if x.get("id") == fid), None)
if not m:
d = MOVIES_DIR / fid
if not d.exists():
raise HTTPException(404, "no such film")
mf = d / "meta.txt"
# update meta.txt fields (source of truth for build_catalog.sh)
fields = {}
if mf.exists():
for line in mf.read_text(encoding="utf-8", errors="replace").splitlines():
line = line.strip()
if not line or ":" not in line:
continue
k, v = line.split(":", 1)
fields[k.strip()] = v.strip()
for k in ("title", "year", "description", "poster", "original_title"):
v = getattr(body, k)
if v is not None:
m[k] = v
save_catalog(cat)
return {"updated": fid, "deploy": deploy()}
fields[k] = str(v)
mf.write_text("\n".join("%s: %s" % (k, v) for k, v in fields.items()) + "\n",
encoding="utf-8")
n = rebuild_catalog()
return {"updated": fid, "catalog_movies": n, "deploy": deploy()}
@app.post("/movie/{fid}/meta")
def post_meta(fid: str, meta: UploadFile = File(None)):
@@ -283,13 +258,8 @@ def post_poster(fid: str, poster: UploadFile = File(...)):
if ext not in ("jpg", "jpeg", "png", "webp"):
raise HTTPException(400, "bad poster ext")
(d / ("poster." + ext)).write_bytes(poster.file.read())
# update catalog poster ref
cat = load_catalog()
m = next((x for x in cat.get("movies", []) if x.get("id") == fid), None)
if m:
m["poster"] = "movies/%s/poster.%s" % (fid, ext)
save_catalog(cat)
return {"poster_updated": fid, "deploy": deploy()}
n = rebuild_catalog()
return {"poster_updated": fid, "catalog_movies": n, "deploy": deploy()}
@app.post("/movie/{fid}/torrent")
def post_torrent(fid: str, torrent: UploadFile = File(...)):
@@ -317,16 +287,8 @@ def rename_movie(fid: str, body: RenameBody):
if (MOVIES_DIR / new).exists():
raise HTTPException(409, "target %s exists" % new)
d.rename(MOVIES_DIR / new)
cat = load_catalog()
for m in cat.get("movies", []):
if m.get("id") == fid:
m["id"] = new
if "poster" in m:
m["poster"] = m["poster"].replace("movies/%s/" % fid, "movies/%s/" % new)
if "torrent" in m:
m["torrent"] = m["torrent"].replace("movies/%s/" % fid, "movies/%s/" % new)
save_catalog(cat)
return {"renamed": fid, "to": new, "deploy": deploy()}
n = rebuild_catalog()
return {"renamed": fid, "to": new, "catalog_movies": n, "deploy": deploy()}
@app.get("/check")
def check():