#!/usr/bin/env python3 """Generate the static site for Radio Susan from playlist.json. Outputs to /var/www/radio/. Run after generate_daily_playlist.py. """ import grp import json import os import sys from datetime import datetime from pathlib import Path PLAYLIST_JSON = Path("/var/lib/radio/playlist.json") OUTPUT_DIR = Path("/var/www/radio") STREAM_URL = "https://radio.jihakuz.xyz/stream" def set_mediaserver_perms(path): try: gid = grp.getgrnam("mediaserver").gr_gid os.chown(str(path), -1, gid) os.chmod(str(path), 0o664) except Exception: pass def generate_html(playlist): generated = playlist["generated_at"][:10] total_tracks = playlist["total_tracks"] duration = playlist["total_duration_hours"] shows = playlist["shows"] entries = playlist["entries"] # Build tracks-only list for the schedule tracks = [e for e in entries if e["type"] == "track"] # Group tracks by show show_tracks = {} for t in tracks: show_name = t.get("show", "Unknown") show_tracks.setdefault(show_name, []).append(t) # Mode stats mode_counts = {} for t in tracks: m = t.get("mode", "unknown") mode_counts[m] = mode_counts.get(m, 0) + 1 # Build show cards HTML show_cards = "" for show in shows: name = show["name"] trks = show_tracks.get(name, []) show_cards += f"""
{show['start']} — {show['end']}

{name}

{show['description']} · Energy {show['energy']} · {len(trks)} tracks
{''.join(f'
' f'{t["start_formatted"][:5]}' f'{_esc(t["artist"])}' f'' f'{_esc(t["title"])}' f'{_esc(t.get("album", ""))}' f'{t["mode"]}' f'
' for t in trks)}
""" html = f""" Radio Susan — 99.0

RADIO SUSAN

99.0 FM
Generated {generated} · {total_tracks} tracks · {duration}h
NOW PLAYING
Loading...

Up Next

{total_tracks}
Tracks
{len(shows)}
Shows
{mode_counts.get('full_album', 0)}
Album Tracks
{mode_counts.get('deep_cuts', 0)}
Deep Cuts
{mode_counts.get('new_to_library', 0)}
New

TODAY'S SCHEDULE

{show_cards}
""" return html def _esc(s): """Escape HTML entities.""" return (s or "").replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) def main(): if not PLAYLIST_JSON.exists(): print(f"ERROR: {PLAYLIST_JSON} not found. Run generate_daily_playlist.py first.") sys.exit(1) playlist = json.load(open(PLAYLIST_JSON)) print(f"Generating site from playlist ({playlist['total_tracks']} tracks)...") OUTPUT_DIR.mkdir(parents=True, exist_ok=True) # Generate index.html html = generate_html(playlist) index_path = OUTPUT_DIR / "index.html" index_path.write_text(html) set_mediaserver_perms(index_path) # Copy playlist.json for API access api_path = OUTPUT_DIR / "playlist.json" api_path.write_text(json.dumps(playlist, separators=(",", ":"))) set_mediaserver_perms(api_path) print(f"Site generated at {OUTPUT_DIR}") print(f" index.html: {index_path.stat().st_size / 1024:.1f}KB") print(f" playlist.json: {api_path.stat().st_size / 1024:.1f}KB") if __name__ == "__main__": main()