#!/usr/bin/env python3
import json
import time
import urllib.parse
import urllib.request
from pathlib import Path

PUBLIC_URL = "https://disk.yandex.ru/d/NjkmlkTUnYawKA"
API = "https://cloud-api.yandex.net/v1/disk/public/resources"
OUT = Path("/home/spazio/ksd30_transcription/downloads")
CHUNK = 4 * 1024 * 1024


def listing():
    q = urllib.parse.urlencode({"public_key": PUBLIC_URL, "limit": 1000})
    with urllib.request.urlopen(f"{API}?{q}", timeout=60) as r:
        return json.load(r)


def fresh_href(path):
    q = urllib.parse.urlencode({"public_key": PUBLIC_URL, "path": path})
    with urllib.request.urlopen(f"{API}/download?{q}", timeout=60) as r:
        return json.load(r)["href"]


data = listing()
items = [x for x in data.get("_embedded", {}).get("items", [])
         if x.get("type") == "file" and x.get("name", "").lower().endswith(".mp3")]

for idx, item in enumerate(items, 1):
    name, expected = item["name"], int(item.get("size") or 0)
    target = OUT / name
    if target.exists() and target.stat().st_size == expected:
        print(f"SKIP {idx}/{len(items)} {name}", flush=True)
        continue
    part = target.with_suffix(target.suffix + ".part")
    if part.exists() and part.stat().st_size > expected:
        part.unlink()
    while (part.stat().st_size if part.exists() else 0) < expected:
        start = part.stat().st_size if part.exists() else 0
        end = min(start + CHUNK - 1, expected - 1)
        ok = False
        for attempt in range(1, 11):
            try:
                href = fresh_href(item["path"])
                req = urllib.request.Request(href, headers={"Range": f"bytes={start}-{end}"})
                with urllib.request.urlopen(req, timeout=180) as src:
                    payload = src.read()
                wanted = end - start + 1
                if len(payload) != wanted:
                    raise RuntimeError(f"chunk size {len(payload)} != {wanted}")
                with part.open("ab") as dst:
                    dst.write(payload)
                print(f"CHUNK {idx}/{len(items)} {name}: {end + 1}/{expected}", flush=True)
                ok = True
                break
            except Exception as exc:
                print(f"RETRY {name} {start}-{end} attempt={attempt}: {type(exc).__name__}: {exc}", flush=True)
                time.sleep(min(30, attempt * 2))
        if not ok:
            raise RuntimeError(f"Could not download chunk {start}-{end} of {name}")
    if part.stat().st_size != expected:
        raise RuntimeError(f"Size mismatch {name}")
    part.replace(target)
    print(f"DONE_FILE {name}", flush=True)

manifest = {
    "folder": data.get("name"),
    "count": len(items),
    "files": [{"name": x["name"], "bytes": int(x.get("size") or 0), "local": str(OUT / x["name"])} for x in items]
}
Path("/home/spazio/ksd30_transcription/manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), "utf-8")
print(f"DONE files={len(items)}", flush=True)
