from __future__ import annotations import json import os from pathlib import Path MEDIA_ROOT = Path(os.environ.get("MEDIA_ROOT", "data/media")).resolve() def published_assets(entity_type: str | None = None) -> list[dict]: manifest = json.loads((MEDIA_ROOT / "manifest.json").read_text(encoding="utf-8")) result = [] for item in manifest.get("assets", []): if item.get("status") != "approved" or not item.get("sha256") or not item.get("local_path"): continue if entity_type and item.get("entity_type") != entity_type: continue source_page = str(item.get("source_page") or "") source = "rf4db" if "rf4db.com" in source_page else "rf4map" if "rf4map.ru" in source_page else "rf4-official" result.append({ "id": item["sha256"], "entity_type": item.get("entity_type"), "entity_key": item.get("entity_key"), "label": item.get("label"), "width": item.get("width"), "height": item.get("height"), "content_type": item.get("content_type"), "image_url": f"/api/v1/media/assets/{item['sha256']}", "source_system": source, "source_url": source_page, "variants": [ { "role": variant.get("role"), "format": variant.get("format"), "width": variant.get("width"), "height": variant.get("height"), "url": f"/api/v1/media/assets/{variant['sha256']}", } for variant in item.get("derivatives", []) if variant.get("sha256") and variant.get("local_path") ], }) return sorted(result, key=lambda item: (str(item["entity_type"]), str(item["label"] or "").casefold(), item["id"])) def published_file(digest: str) -> tuple[Path, str] | None: if len(digest) != 64 or any(char not in "0123456789abcdef" for char in digest): return None manifest = json.loads((MEDIA_ROOT / "manifest.json").read_text(encoding="utf-8")) item = next((row for row in manifest.get("assets", []) if row.get("status") == "approved" and row.get("sha256") == digest), None) if not item: return None target = (MEDIA_ROOT / item["local_path"]).resolve() if not target.is_relative_to(MEDIA_ROOT.resolve()) or not target.is_file(): return None return target, str(item["content_type"]) def review_assets(entity_type: str | None = None, status: str | None = None) -> list[dict]: manifest = json.loads((MEDIA_ROOT / "manifest.json").read_text(encoding="utf-8")) result = [] for item in manifest.get("assets", []): item_status = str(item.get("status") or "") if item_status not in {"approved", "upgrade_queued", "upgrade_stored"} or (status and item_status != status): continue if entity_type and item.get("entity_type") != entity_type: continue digest = str(item.get("sha256") or "") if len(digest) != 64 or not item.get("local_path"): continue source_page = str(item.get("source_page") or "") source = "rf4db" if "rf4db.com" in source_page else "rf4map" if "rf4map.ru" in source_page else "rf4-official" result.append({ "id": digest, "status": item_status, "entity_type": item.get("entity_type"), "entity_key": item.get("entity_key"), "label": item.get("label"), "width": item.get("width"), "height": item.get("height"), "content_type": item.get("content_type"), "image_url": f"/api/v1/admin/media/assets/{digest}", "source_system": source, "source_url": source_page, "duplicate_of": item.get("duplicate_of"), "derivatives": [{ "role": variant.get("role"), "format": variant.get("format"), "width": variant.get("width"), "height": variant.get("height"), } for variant in item.get("derivatives", [])], }) return sorted(result, key=lambda item: (str(item["status"]), str(item["entity_type"]), str(item["label"] or "").casefold(), item["id"])) def review_file(digest: str) -> tuple[Path, str] | None: if len(digest) != 64 or any(char not in "0123456789abcdef" for char in digest): return None manifest = json.loads((MEDIA_ROOT / "manifest.json").read_text(encoding="utf-8")) item = next((row for row in manifest.get("assets", []) if row.get("sha256") == digest and row.get("status") in {"approved", "upgrade_queued", "upgrade_stored"}), None) if not item or not item.get("local_path"): return None target = (MEDIA_ROOT / item["local_path"]).resolve() if not target.is_relative_to(MEDIA_ROOT.resolve()) or not target.is_file(): return None return target, str(item.get("content_type") or "application/octet-stream")