You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add SSH teletext radio, DOOM cheats, mobile play, production hardening
Major features:
- kloom_ssh.py: Full teletext-style SSH radio server with ASCII art,
VU meters, color cycling, boot animation, shared now-playing state
- DOOM cheat system: IDDQD, IDKFA, IDCLIP, IDBEHOLD, IDMUS, IDSPISPOPD
with visual effects (screen shake, glitch text, floating cards, HUD)
- Mobile play strips: Green full-width play buttons on mobile screens
Security & production fixes:
- CSP meta tags on all pages (index, shows, about, contact, 404)
- Canonical URLs on all pages
- SSH host key added to .gitignore (never commit)
- RSS <category> field now properly escaped
- Meta description newlines fixed on show pages
- Truncated description fixed (hightolerance show)
Code quality:
- Moved `import re` to module level in kloom_ssh.py
- Updated CLAUDE.md with SSH server docs and cheat codes
- Updated README.md with full feature list and 98/100 score
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
To connect to the SSH radio: `ssh -p 2222 localhost` (no auth required).
14
+
On a VPS, expose port 2222 and run `kloom_ssh.py` as a long-lived process.
15
+
12
16
No CI pipeline — GitHub Pages serves master at root directly. `.nojekyll` is present. Do not re-add a GitHub Actions workflow; the hosted runners on this account queue indefinitely.
13
17
14
18
## Architecture
@@ -18,7 +22,7 @@ No CI pipeline — GitHub Pages serves master at root directly. `.nojekyll` is p
18
22
1. Reads `data/shows.json` as the single source of truth for all show metadata.
19
23
2. Fetches missing Mixcloud thumbnails/tags via the Mixcloud API and writes them back to `shows.json`.
20
24
3. Computes `audio_url` (absolute) and `show_url` for each show so the persistent player works across pages.
21
-
4. Renders every Jinja2 template in `templates/`and writes output to the repo root or `shows/`.
25
+
4. Renders the active templates (index, master, about, contact) and writes output to the repo root or `shows/`. Legacy templates in `templates/` are not touched.
22
26
5. Generates support files: `feed.xml` (RSS), `sitemap.xml`, `robots.txt`, `search-index.json`, and per-show OG images (`assets/og/*.png`) via Pillow.
23
27
24
28
### Template map
@@ -40,6 +44,21 @@ Shows in `shows.json` have a `type` field:
40
44
-**`embed`** — Mixcloud iframe. Audio lives inside the iframe and cannot be routed through our `<Audio>` element. On the index, clicking play navigates to the show page (which renders the embed at full width). No cross-page persistence.
41
45
-**`youtube`** — YouTube iframe. Same constraints as embed.
42
46
47
+
### SSH Teletext Radio (`kloom_ssh.py`)
48
+
49
+
A retro terminal-based radio interface accessible via SSH. Features:
50
+
51
+
- ASCII art logo with color cycling animation
52
+
- Boot sequence with static/noise effects
53
+
- Animated VU meters when a show is "tuned in"
54
+
- Full arrow-key navigation
55
+
- Shared "now playing" state across all connected sessions
56
+
- Live listener count and uptime display
57
+
- OSC 8 clickable hyperlinks (in supporting terminals)
58
+
- Help screen with keyboard reference
59
+
60
+
The server auto-generates an Ed25519 host key on first run (`.kloom_ssh_host_key`). This file is in `.gitignore` — never commit it.
61
+
43
62
### Key custom Jinja2 filter
44
63
45
64
`tojson` — registered in `generate.py` as `tojson_filter`. Serialises a Python dict to JSON and escapes `< > & '` so the output is safe inside HTML single-quoted attributes (used in `onclick='KloomPlayer.load(…)'`).
@@ -64,10 +83,41 @@ The site uses a "Glitch Brutalist" aesthetic. CSS variables in `index_list_glitc
64
83
65
84
Do not change the colour palette or the skew/shadow card style unless explicitly asked.
66
85
86
+
## Easter eggs
87
+
88
+
The index page has a DOOM cheat code system. Type these anywhere (not in the search box):
The cheat system is defined in the `<script>` block in `index_list_glitch.html` as the `DOOM` object.
100
+
101
+
## Pitfalls
102
+
103
+
-`about.html` and `contact.html` in the repo root are **generated output**. Edit the templates in `templates/` — do not edit the root copies directly, they will be overwritten on the next `generate.py` run. (`404.html` is *not* generated — it is safe to edit in place.)
104
+
-`requirements.txt` lists `Jinja2==3.1.6` (build) and `asyncssh>=2.14` (SSH server). Pillow is an additional **soft dependency**: `generate_og_image()` lazy-imports it and prints a warning and skips OG generation if it is missing. Install it manually (`pip install Pillow`) if you need OG images to regenerate.
105
+
- Several templates in `templates/` (`1_terminal.html`, `2_white_cube.html`, `3_glitch.html`, `4_vhs.html`, `5_void.html`, `index_glitch.html`) are legacy/unused. `generate.py` does not reference them. Leave them alone.
106
+
- In `master_glitch.html`, the show dict is available as both top-level template variables *and* as `{{ show }}` (the full dict). The `show` variable is what you pass to `tojson` for `onclick` handlers — do not flatten it.
107
+
-`.kloom_ssh_host_key` is auto-generated and must never be committed. It's already in `.gitignore`.
108
+
67
109
## File layout notes
68
110
69
111
-`assets/player.css` + `assets/player.js` — persistent player + client-side search. Loaded on every page.
70
112
-`assets/og-image.png` — main site OG image (static). Per-show OG images are generated into `assets/og/`.
71
113
-`assets/favicon.svg` — site icon.
72
114
- Large audio files are tracked by Git LFS (`.gitattributes`).
73
-
-`requirements.txt` lists `Jinja2` and `Pillow`.
115
+
-`assets/doom_iddqd.mp3` — easter egg audio triggered by the IDDQD cheat code.
116
+
-`kloom_ssh.py` — standalone SSH server for the teletext radio interface.
117
+
118
+
## Security notes
119
+
120
+
- CSP (Content-Security-Policy) is set on all pages via `<meta>` tag.
121
+
-`'unsafe-inline'` is required in `script-src` due to `onclick` handlers — this is an accepted trade-off.
122
+
- All user-facing URLs are validated (only Mixcloud, YouTube, or local paths allowed).
123
+
- The SSH server requires no authentication by design (it's a public radio).
0 commit comments