perfect-postcode/pipeline/download/tiles.py
2026-03-15 21:22:28 +00:00

91 lines
2.7 KiB
Python

"""Download UK PMTiles extract from the latest Protomaps daily build."""
import argparse
import platform
import stat
import subprocess
import sys
import tarfile
import urllib.request
from datetime import datetime, timedelta
from io import BytesIO
from pathlib import Path
PROTOMAPS_BASE = "https://build.protomaps.com"
UK_BBOX = "-10.5,49.5,2.5,61"
MAX_AGE_DAYS = 14
def find_latest_build() -> str:
"""Find the most recent available Protomaps daily build."""
today = datetime.utcnow().date()
for i in range(MAX_AGE_DAYS):
d = today - timedelta(days=i)
url = f"{PROTOMAPS_BASE}/{d:%Y%m%d}.pmtiles"
req = urllib.request.Request(url, method="HEAD")
try:
urllib.request.urlopen(req)
print(f"Found build: {d:%Y%m%d}")
return url
except urllib.error.HTTPError:
continue
print(
f"ERROR: No Protomaps build found in the last {MAX_AGE_DAYS} days",
file=sys.stderr,
)
sys.exit(1)
def ensure_pmtiles_cli(bin_path: Path, version: str) -> None:
"""Download the pmtiles CLI if not already present."""
if bin_path.exists():
return
machine = platform.machine()
if machine == "x86_64":
arch = "x86_64"
elif machine == "aarch64":
arch = "arm64"
else:
arch = machine
url = (
f"https://github.com/protomaps/go-pmtiles/releases/download/"
f"v{version}/go-pmtiles_{version}_Linux_{arch}.tar.gz"
)
print(f"Downloading pmtiles CLI v{version}...")
data = urllib.request.urlopen(url).read()
with tarfile.open(fileobj=BytesIO(data), mode="r:gz") as tar:
member = tar.getmember("pmtiles")
f = tar.extractfile(member)
assert f is not None
bin_path.parent.mkdir(parents=True, exist_ok=True)
bin_path.write_bytes(f.read())
bin_path.chmod(bin_path.stat().st_mode | stat.S_IEXEC)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--output", type=Path, required=True, help="Output .pmtiles path"
)
parser.add_argument(
"--pmtiles-version", default="1.22.3", help="go-pmtiles release version"
)
args = parser.parse_args()
bin_path = args.output.parent / "pmtiles"
ensure_pmtiles_cli(bin_path, args.pmtiles_version)
source_url = find_latest_build()
print(f"Extracting UK tiles from {source_url}...")
subprocess.run(
[str(bin_path), "extract", source_url, str(args.output), f"--bbox={UK_BBOX}"],
check=True,
)
size_mb = args.output.stat().st_size / (1024 * 1024)
print(f"Wrote {args.output} ({size_mb:.1f} MB)")
if __name__ == "__main__":
main()