#!/usr/bin/env python3 """Generate a retro stats page for Susan. 90s CS professor homepage aesthetic. Pure HTML, no JS. Regenerate periodically via cron. """ import datetime import os import subprocess import re OUTPUT = "/var/www/webdav/obsidian/stats.html" def cmd(c): try: return subprocess.check_output(c, shell=True, stderr=subprocess.DEVNULL, timeout=10).decode().strip() except: return "" def get_uptime(): up = cmd("uptime -p") return up.replace("up ", "") if up else "unknown" def get_uptime_since(): return cmd("uptime -s") def get_load(): load = cmd("cat /proc/loadavg") return load.split()[:3] if load else ["?", "?", "?"] def get_memory(): mem = cmd("free -h | grep Mem") parts = mem.split() if len(parts) >= 7: return {"total": parts[1], "used": parts[2], "free": parts[3], "available": parts[6]} return {"total": "?", "used": "?", "free": "?", "available": "?"} def get_disk(): disks = [] for line in cmd("df -h /disks /home 2>/dev/null").split("\n")[1:]: parts = line.split() if len(parts) >= 6: disks.append({"fs": parts[0], "size": parts[1], "used": parts[2], "avail": parts[3], "pct": parts[4], "mount": parts[5]}) return disks def get_services(): services = [] lines = cmd("systemctl list-units --type=service --state=running --no-pager --no-legend").split("\n") targets = ["jellyfin", "navidrome", "qbittorrent", "sonarr", "radarr", "lidarr", "readarr", "prowlarr", "slskd", "nginx", "audiobookshelf", "openclaw-gateway"] for line in lines: for t in targets: if t in line.lower(): name = line.split()[0].replace(".service", "") services.append(name) return sorted(services) def get_media_counts(): films = int(cmd("find /disks/Plex/Films -maxdepth 1 -type d | wc -l") or 1) - 1 tv = int(cmd("find /disks/Plex/TV -maxdepth 1 -type d | wc -l") or 1) - 1 anime = int(cmd("find /disks/Plex/Anime -maxdepth 1 -type d | wc -l") or 1) - 1 tracks = int(cmd("find /disks/Plex/Music -type f \\( -name '*.flac' -o -name '*.mp3' -o -name '*.ogg' -o -name '*.opus' \\) | wc -l") or 0) artists = int(cmd("ls -1d /disks/Plex/Music/*/ 2>/dev/null | grep -v -E 'venv|lib|bin|data|include|_|pyvenv' | wc -l") or 0) return {"films": films, "tv": tv, "anime": anime, "tracks": tracks, "artists": artists} def get_cpu(): model = cmd("grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2").strip() cores = cmd("nproc") return model, cores def get_packages(): return cmd("dpkg -l | grep '^ii' | wc -l") def get_kernel(): return cmd("uname -r") def get_os(): return cmd("grep PRETTY_NAME /etc/os-release | cut -d'\"' -f2") def get_install_date(): d = cmd("stat -c %w /") if d and d != "-": return d.split(".")[0] return "unknown" COUNTER_FILE = os.path.join(os.path.dirname(__file__), "..", "data", "visitor_counter.txt") def get_and_increment_counter(): """Read and increment a persistent visitor counter.""" os.makedirs(os.path.dirname(COUNTER_FILE), exist_ok=True) count = 0 if os.path.exists(COUNTER_FILE): try: count = int(open(COUNTER_FILE).read().strip()) except: count = 0 count += 1 with open(COUNTER_FILE, "w") as f: f.write(str(count)) return count now = datetime.datetime.now() uptime = get_uptime() uptime_since = get_uptime_since() load = get_load() mem = get_memory() disks = get_disk() services = get_services() media = get_media_counts() cpu_model, cpu_cores = get_cpu() packages = get_packages() kernel = get_kernel() os_name = get_os() install_date = get_install_date() visitor_count = get_and_increment_counter() html = f""" Susan - System Status

Susan — System Status


General Information

Hostnamesusan
Operating System{os_name}
Kernel{kernel}
Processor{cpu_model} ({cpu_cores} cores)
Installed Packages{packages}
First Installed{install_date}

Uptime & Load

Uptime{uptime}
Up Since{uptime_since}
Load Average{load[0]}, {load[1]}, {load[2]} (1, 5, 15 min)

Memory

TotalUsedFreeAvailable
{mem['total']}{mem['used']}{mem['free']}{mem['available']}

Disk Usage

""" for d in disks: pct = int(d["pct"].replace("%", "")) if d["pct"].replace("%", "").isdigit() else 0 cls = "status-warn" if pct > 85 else "status-ok" html += f'\n' html += f"""
MountSizeUsedAvailableUse%
{d["mount"]}{d["size"]}{d["used"]}{d["avail"]}{d["pct"]}

Running Services

""" for s in services: html += f'\n' html += f"""
ServiceStatus
{s}running

Media Library

CategoryCount
Films{media['films']}
TV Shows{media['tv']}
Anime{media['anime']}
Music Artists{media['artists']}
Music Tracks{media['tracks']}

""" os.makedirs(os.path.dirname(OUTPUT), exist_ok=True) with open(OUTPUT, "w") as f: f.write(html) print(f"Generated stats page: {OUTPUT}") print(f" Uptime: {uptime}") print(f" Services: {len(services)}") print(f" Films: {media['films']}, TV: {media['tv']}, Anime: {media['anime']}") print(f" Music: {media['tracks']} tracks, {media['artists']} artists")