synq-core-os/scripts/prefetch_satellite_regions.py
cavalier8030 3f95f239be feat(mobile): Synq Mobile v0.1 scaffold — multi-profile Tauri app with Kids PIN setup
- Full Tauri v2 mobile scaffold (Rust backend + React frontend + Android)
- Multi-profile architecture: Business / Personal / Family / Kids
- Per-profile encrypted SQLite isolation via rusqlite
- Kids profile: persistent PIN storage (SHA-256 + salt), setup flow, PIN lock
- Desktop dev mode working (GTK/WebKit) on ARM64 Linux
- Android APK build working (arm64, 17MB unsigned)
- Phase 2 stubs: Jitsi SDK, cpal/hound audio, Beam voice commands
- QEMU x86_64 emulation for Google Android SDK tools on ARM64 host
- Workspace integration with synq-protocol, synq-security, synq-core
2026-05-06 18:12:13 -07:00

149 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Pre-fetch satellite (MODIS/VIIRS TrueColor) tiles for key regions.
Downloads directly from NASA GIBS with concurrent workers and local caching.
Regions: Southern California, GCC, Iran, Israel
"""
import math
import requests
from pathlib import Path
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from threading import Lock
CACHE_DIR = Path("/home/raider1984/synq-data/pmtiles/tiles/satellite")
TILE_URL = "https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/GoogleMapsCompatible_Level9/{z}/{x}/{y}.jpeg"
MAX_ZOOM = 9
REGIONS = {
"southern_california": (32.0, 35.5, -121.0, -114.0),
"gcc": (16.0, 32.5, 47.0, 57.0),
"iran": (25.0, 40.0, 44.0, 63.5),
"israel": (29.5, 34.0, 34.0, 36.5),
}
ZOOM_LEVELS = [5, 6, 7, 8, 9]
MAX_WORKERS = 16
SESSION = requests.Session()
SESSION.headers.update({"User-Agent": "Synq-Intel-TilePrefetch/1.0"})
stats_lock = Lock()
def latlng_to_tile(lat, lng, zoom):
n = 2 ** zoom
x = int((lng + 180.0) / 360.0 * n)
lat_rad = math.radians(lat)
y = int((1.0 - math.log(math.tan(lat_rad) + 1.0 / math.cos(lat_rad)) / math.pi) / 2.0 * n)
return x, y
def get_tile_range(lat_min, lat_max, lng_min, lng_max, zoom):
x1, y1 = latlng_to_tile(lat_max, lng_min, zoom)
x2, y2 = latlng_to_tile(lat_min, lng_max, zoom)
return min(x1, x2), max(x1, x2), min(y1, y2), max(y1, y2)
def fetch_tile(z, x, y):
cache_path = CACHE_DIR / str(z) / str(x) / f"{y}.jpg"
if cache_path.exists():
return True, "cached", z
url = TILE_URL.format(z=z, x=x, y=y)
try:
r = SESSION.get(url, timeout=20)
if r.status_code == 200:
cache_path.parent.mkdir(parents=True, exist_ok=True)
with open(cache_path, "wb") as f:
f.write(r.content)
return True, "downloaded", z
else:
return False, f"http_{r.status_code}", z
except Exception as e:
return False, str(e)[:50], z
def prefetch_region(name, lat_min, lat_max, lng_min, lng_max, zoom_levels):
print(f"\n📍 {name.upper()}")
print(f" Bounds: lat {lat_min}{lat_max}, lng {lng_min}{lng_max}")
sys.stdout.flush()
all_tiles = []
for z in zoom_levels:
if z > MAX_ZOOM:
continue
x_min, x_max, y_min, y_max = get_tile_range(lat_min, lat_max, lng_min, lng_max, z)
max_tile = (2 ** z) - 1
x_min = max(0, x_min)
x_max = min(max_tile, x_max)
y_min = max(0, y_min)
y_max = min(max_tile, y_max)
for x in range(x_min, x_max + 1):
for y in range(y_min, y_max + 1):
all_tiles.append((z, x, y))
zoom_stats = {z: {"total": 0, "downloaded": 0, "cached": 0, "errors": 0} for z in zoom_levels if z <= MAX_ZOOM}
total_tiles = len(all_tiles)
completed = 0
downloaded = 0
cached = 0
errors = 0
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
future_to_tile = {executor.submit(fetch_tile, z, x, y): (z, x, y) for z, x, y in all_tiles}
for future in as_completed(future_to_tile):
success, status, z = future.result()
with stats_lock:
completed += 1
zoom_stats[z]["total"] += 1
if success:
if status == "downloaded":
downloaded += 1
zoom_stats[z]["downloaded"] += 1
else:
cached += 1
zoom_stats[z]["cached"] += 1
else:
errors += 1
zoom_stats[z]["errors"] += 1
if completed % 100 == 0 or completed == total_tiles:
pct = completed * 100 // total_tiles if total_tiles > 0 else 0
print(f"\r Progress: {completed}/{total_tiles} ({pct}%) | DL:{downloaded} | Cache:{cached} | Err:{errors}", end="")
sys.stdout.flush()
print()
for z in zoom_levels:
if z > MAX_ZOOM:
continue
st = zoom_stats[z]
if st["total"] > 0:
print(f" Zoom {z:2d}: {st['total']:5d} tiles | {st['downloaded']:5d} downloaded | {st['cached']:5d} cached | {st['errors']:3d} errors")
print(f" TOTAL: {total_tiles} tiles | {downloaded} downloaded | {cached} cached | {errors} errors")
return total_tiles, downloaded, cached, errors
if __name__ == "__main__":
print("=" * 70)
print("NASA GIBS SATELLITE TILE PREFETCH (VIIRS SNPP TrueColor)")
print(f"Workers: {MAX_WORKERS} | Zooms: {ZOOM_LEVELS} | MaxZoom: {MAX_ZOOM}")
print("=" * 70)
sys.stdout.flush()
grand_total = [0, 0, 0, 0]
for name, (lat_min, lat_max, lng_min, lng_max) in REGIONS.items():
counts = prefetch_region(name, lat_min, lat_max, lng_min, lng_max, ZOOM_LEVELS)
for i in range(4):
grand_total[i] += counts[i]
print("\n" + "=" * 70)
print("GRAND TOTAL")
print(f" {grand_total[0]} tiles checked")
print(f" {grand_total[1]} downloaded")
print(f" {grand_total[2]} already cached")
print(f" {grand_total[3]} errors")
print(f"\nCache location: {CACHE_DIR}")
print("=" * 70)