skywalker-1/tui/scripts/fetch_art.py
Ryan Malloy 6dcb6b693a Add radar scope, splash screen, Star Wars easter egg, and harden TUI
New features:
- P1 green phosphor radar scope widget on Track screen with LUT-optimized rendering
- Splash screen with pre-baked ANSI half-block art from 16colo.rs/Mistigris
- Star Wars ASCII animation via telnet (ctrl+w) with IPv6 happy eyeballs and offline fallback
- Dark Side / New Hope toast notifications on theme toggle
- Kitty terminal detection with cat emoji on splash

Robustness (from Apollo code review):
- Circuit breaker in track loop after 10 consecutive errors
- Input validation for frequency, symbol rate, step size across scan/spectrum/track
- Consolidated sys.path manipulation into __init__.py
- Radar scope pre-computes dist/angle LUT per pixel on resize

Cleanup:
- Removed unused imports across lband, monitor, scan, signal_gauge
- Moved Pillow/textual-image to optional dev deps (splash uses pre-baked ANSI)
- Added 41-test pytest suite covering telnet IAC parsing, radar geometry, splash assets
2026-02-14 09:51:58 -07:00

100 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""Download splash art from 16colo.rs for SkyWalker-1 TUI.
Fetches pixel/teletext art from Mistigris packs on 16colo.rs and saves
them as bundled assets for the splash screen.
Usage:
python scripts/fetch_art.py
"""
import urllib.request
import sys
from pathlib import Path
ASSETS_DIR = Path(__file__).resolve().parent.parent / "src" / "skywalker_tui" / "assets" / "splash"
ART_SOURCES = [
{
"url": "https://16colo.rs/pack/mist0717/raw/ILLARTERATE-SETI-100_02_SATELLITE.PNG",
"filename": "seti-satellite.png",
"artist": "Illarterate",
"title": "S.E.T.I. Satellite",
"pack": "mist0717",
},
{
"url": "https://16colo.rs/pack/mist1119/raw/192.168.10.13-DIALTONE.JPG",
"filename": "dialtone.jpg",
"artist": "192.168.10.13",
"title": "Dialtone",
"pack": "mist1119",
},
{
"url": "https://16colo.rs/pack/mist0523/raw/BLIPPYPIXEL-SO_FAR_AWAY.GIF",
"filename": "so-far-away.gif",
"artist": "Blippypixel",
"title": "So Far Away",
"pack": "mist0523",
},
{
"url": "https://16colo.rs/pack/mist0121/raw/JELLICA_JAKE-PRODIGY.JPG",
"filename": "prodigy-out-of-space.jpg",
"artist": "Jellica Jake",
"title": "Prodigy / Out of Space",
"pack": "mist0121",
},
{
"url": "https://16colo.rs/pack/mist1120/raw/BLIPPYPIXEL-SPACE_DOCKER.GIF",
"filename": "space-docker.gif",
"artist": "Blippypixel",
"title": "Space Docker",
"pack": "mist1120",
},
]
def fetch_all():
ASSETS_DIR.mkdir(parents=True, exist_ok=True)
downloaded = 0
for art in ART_SOURCES:
dest = ASSETS_DIR / art["filename"]
if dest.exists():
print(f" exists: {art['filename']}", file=sys.stderr)
downloaded += 1
continue
print(f" fetch: {art['filename']} from {art['url']}", file=sys.stderr)
try:
req = urllib.request.Request(art["url"], headers={"User-Agent": "SkyWalker-1-TUI/0.1"})
with urllib.request.urlopen(req, timeout=30) as resp:
data = resp.read()
dest.write_bytes(data)
print(f" {len(data):,} bytes -> {dest.name}", file=sys.stderr)
downloaded += 1
except Exception as e:
print(f" FAIL: {art['filename']}: {e}", file=sys.stderr)
# Write CREDITS.md
credits = ASSETS_DIR / "CREDITS.md"
lines = ["# Splash Art Credits\n", ""]
lines.append("All artwork sourced from [16colo.rs](https://16colo.rs) /")
lines.append("[Mistigris](https://mistigris.com) art packs.\n")
lines.append("| File | Artist | Title | Pack |")
lines.append("|------|--------|-------|------|")
for art in ART_SOURCES:
pack_url = f"https://16colo.rs/pack/{art['pack']}"
lines.append(
f"| `{art['filename']}` | {art['artist']} "
f"| {art['title']} | [{art['pack']}]({pack_url}) |"
)
lines.append("")
credits.write_text("\n".join(lines))
print(f"\n {downloaded}/{len(ART_SOURCES)} images downloaded to {ASSETS_DIR}", file=sys.stderr)
return downloaded
if __name__ == "__main__":
fetch_all()