#!/usr/bin/env python3 """Fetch free motion-capture libraries into library/downloads/. Sources live in library/manifest.json. Entries marked "verified": false have not been confirmed reachable yet — the script reports what it can and skips what it can't, it never fails the whole run on one dead mirror. Usage: python3 library/fetch.py # fetch everything in the manifest python3 library/fetch.py --only cmu_sample python3 library/fetch.py --url https://... --name mypack # ad-hoc """ import argparse import json import os import sys import urllib.request import zipfile HERE = os.path.dirname(os.path.abspath(__file__)) DOWNLOADS = os.path.join(HERE, "downloads") def fetch_one(name, url, unpack): os.makedirs(DOWNLOADS, exist_ok=True) dest_dir = os.path.join(DOWNLOADS, name) fname = os.path.join(DOWNLOADS, os.path.basename(url.split("?")[0]) or name) if os.path.exists(dest_dir) and os.listdir(dest_dir): print(f"[skip] {name}: already downloaded") return True print(f"[get ] {name}: {url}") try: req = urllib.request.Request(url, headers={"User-Agent": "mirpamo/0.1"}) with urllib.request.urlopen(req, timeout=60) as r, open(fname, "wb") as f: while True: chunk = r.read(1 << 20) if not chunk: break f.write(chunk) except Exception as e: print(f"[fail] {name}: {e}") return False if unpack and fname.endswith(".zip"): os.makedirs(dest_dir, exist_ok=True) with zipfile.ZipFile(fname) as z: z.extractall(dest_dir) os.remove(fname) print(f"[ok ] {name}: unpacked to {dest_dir}") else: os.makedirs(dest_dir, exist_ok=True) os.rename(fname, os.path.join(dest_dir, os.path.basename(fname))) print(f"[ok ] {name}") return True def main(): ap = argparse.ArgumentParser() ap.add_argument("--only") ap.add_argument("--url") ap.add_argument("--name", default="adhoc") args = ap.parse_args() if args.url: ok = fetch_one(args.name, args.url, unpack=True) sys.exit(0 if ok else 1) with open(os.path.join(HERE, "manifest.json")) as f: manifest = json.load(f) results = [] for entry in manifest["sources"]: if args.only and entry["name"] != args.only: continue if entry.get("url", "").startswith("TODO"): print(f"[todo] {entry['name']}: no URL yet — {entry.get('notes','')}") continue results.append(fetch_one(entry["name"], entry["url"], entry.get("unpack", True))) print(f"\n{sum(results)}/{len(results)} sources fetched") if __name__ == "__main__": main()