import pathlib,json,urllib.request,hashlib,concurrent.futures root=pathlib.Path.cwd(); folder=root/'assets/textures/quarry_realism'; folder.mkdir(parents=True,exist_ok=True) assets={'aerial_asphalt_01':2.0,'concrete_wall_007':3.0,'rusty_metal_02':2.0} def task(pair): a,meters=pair try: meta=json.load(urllib.request.urlopen(urllib.request.Request('https://api.polyhaven.com/files/'+a,headers={'User-Agent':'BLOCKLINE asset preparation'}),timeout=60)) except Exception as e: print(a,e,flush=True); return dest=folder/a; dest.mkdir(exist_ok=True); manifest={} for kind in ['Diffuse','nor_gl','Rough','Metal']: if kind not in meta: continue info=meta[kind]['4k']['jpg']; p=dest/(kind+'.jpg') if not p.exists(): p.write_bytes(urllib.request.urlopen(info['url'],timeout=120).read()) assert hashlib.md5(p.read_bytes()).hexdigest()==info['md5'];manifest[kind]=info (dest/'source.json').write_text(json.dumps({'source':'https://polyhaven.com/a/'+a,'license':'CC0-1.0','meters':meters,'files':manifest},indent=2)) print(a,'OK',flush=True) with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:list(ex.map(task,assets.items()))