feat: publish approved RF4 media catalog
This commit is contained in:
@@ -136,6 +136,27 @@ def reconcile_queued_duplicates(path: Path) -> dict:
|
||||
return {"duplicates": duplicates, "queued": sum(item.get("status") == "queued" for item in manifest.get("assets", []))}
|
||||
|
||||
|
||||
def approve_stored_assets(path: Path, *, note: str) -> dict:
|
||||
"""Publish every stored asset after an explicit owner-level approval."""
|
||||
manifest = json.loads(path.read_text(encoding="utf-8"))
|
||||
reviewed_at = datetime.now(timezone.utc).isoformat()
|
||||
approved = 0
|
||||
for item in manifest.get("assets", []):
|
||||
if item.get("status") != "stored":
|
||||
continue
|
||||
stable_id = item.get("external_id") or item.get("sha256") or hashlib.sha256(item["asset_url"].encode()).hexdigest()
|
||||
item.update({
|
||||
"status": "approved",
|
||||
"entity_key": f"{item.get('entity_type', 'reference')}:{stable_id}",
|
||||
"reviewed_at": reviewed_at,
|
||||
"review_note": note,
|
||||
})
|
||||
approved += 1
|
||||
manifest["updated_at"] = reviewed_at
|
||||
path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
return {"approved": approved}
|
||||
|
||||
|
||||
def reclassify_manifest(path: Path) -> dict:
|
||||
manifest = json.loads(path.read_text(encoding="utf-8"))
|
||||
for item in manifest.get("assets", []):
|
||||
|
||||
@@ -8,7 +8,7 @@ import urllib.error
|
||||
import urllib.request
|
||||
|
||||
from .community_cli import MIN_FETCH_INTERVAL_SECONDS, USER_AGENT, _StrictRedirectHandler, _read_state, _validate_url_before_io, check_and_reserve, fetch_html, fetch_site_key
|
||||
from .media_assets import audit_media_catalog, extract_media_candidates, media_coverage, merge_manifest, reconcile_queued_duplicates, reclassify_manifest, review_asset, store_asset
|
||||
from .media_assets import approve_stored_assets, audit_media_catalog, extract_media_candidates, media_coverage, merge_manifest, reconcile_queued_duplicates, reclassify_manifest, review_asset, store_asset
|
||||
|
||||
|
||||
DEFAULT_ROOT = Path("data/media")
|
||||
@@ -182,6 +182,7 @@ def main(argv: list[str] | None = None) -> int:
|
||||
parser.add_argument("--asset-url", help="Download this exact queued asset instead of the first queue item")
|
||||
parser.add_argument("--reclassify", action="store_true", help="Reapply current conservative classifier without network access")
|
||||
parser.add_argument("--dedupe-queue", action="store_true", help="Mark queued label matches to stored assets as duplicates without network access")
|
||||
parser.add_argument("--approve-stored", action="store_true", help="Publish all stored assets after explicit owner approval")
|
||||
parser.add_argument("--review-url", help="Review an asset already present in the manifest")
|
||||
parser.add_argument("--decision", choices=("approved", "rejected"))
|
||||
parser.add_argument("--entity-type", choices=("fish", "waterbody", "tackle", "reference"))
|
||||
@@ -217,6 +218,11 @@ def main(argv: list[str] | None = None) -> int:
|
||||
if args.dedupe_queue:
|
||||
print(json.dumps(reconcile_queued_duplicates(args.root / "manifest.json"), ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
if args.approve_stored:
|
||||
if not args.note:
|
||||
parser.error("--note is required with --approve-stored")
|
||||
print(json.dumps(approve_stored_assets(args.root / "manifest.json", note=args.note), ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
if args.download_one:
|
||||
print(_download_one(args.root, args.state_file, args.asset_url))
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user