An unofficial RSS proxy for 2600's Off The Hook radio show. The official
feeds (oth-broadband.xml) only carry
the most recent ~10 regular episodes and omit the Overtime segments. This
service crawls the full archive at 2600.net and
serves a single RSS 2.0 feed with every episode, regular and Overtime.
- For each year in range it fetches the Apache directory index
(
/offthehook/<year>/) to find the monthly pages (MMYY.html). - It parses each monthly page for mp3 links. Episodes are identified straight
from the filenames, e.g.
off_the_hook__20260603-128.mp3— regular show, 128koff_the_hook_overtime__20260610-128.mp3— Overtime, 128k
- It de-duplicates by
(date, overtime), preferring 128k, and renders an RSS feed with an<enclosure>per episode.
The archive is crawled one year at a time, only on request:
- Past years never change, so once a year is crawled it is cached indefinitely and never re-fetched.
- The current year (
OTH_CURRENT_YEAR, defaults to the real current year) is re-crawled only when its cache is older thanOTH_CACHE_TTL_SECS(default 12h). Everything else is served straight from memory. - Crawls are single-flight: a burst of requests against a stale cache still causes just one crawl.
- Each year is persisted to disk as
OTH_CACHE_DIR/<year>.tsv, so a restart reuses prior crawls — only the current year is ever re-fetched, and only once it passes the TTL. - Note: the request that triggers a crawl blocks until that year (or years, on a cold start) finishes.
cargo run --release
# feed available at http://localhost:8080/feed.xml| Variable | Default | Description |
|---|---|---|
OTH_BIND_ADDR |
0.0.0.0:8080 |
Address to bind the HTTP server to |
OTH_START_YEAR |
1999 |
First archive year to crawl |
OTH_END_YEAR |
current year | Last archive year to crawl |
OTH_CACHE_TTL_SECS |
43200 (12h) |
Re-crawl interval for the current year only |
OTH_CURRENT_YEAR |
current year | Years >= this use the TTL; earlier years never expire |
OTH_CONCURRENCY |
8 |
Max monthly pages fetched in parallel |
OTH_PREFER_128K |
true |
Prefer 128k mp3 over 16k when both exist |
OTH_PUBLIC_URL |
http://localhost:8080 |
URL advertised in the feed's <link> |
OTH_CACHE_DIR |
oth_cache |
Directory for per-year persisted caches (<year>.tsv) |
Tip: to test quickly against only recent years, set OTH_START_YEAR=2026.
A multi-stage Dockerfile builds a small debian:bookworm-slim runtime image
that runs as an unprivileged user and stores its cache in /data.
docker build -t off-the-hook-rss .
docker run -p 8080:8080 -v oth-cache:/data off-the-hook-rss
# feed at http://localhost:8080/feed.xmlThe -v oth-cache:/data volume persists the per-year crawl cache across restarts.
.gitlab-ci.yml defines three stages:
- lint —
cargo fmt --all -- --checkandcargo clippy --all-targets --all-features -- -D warnings - test —
cargo test --all-features - build-oci — builds and pushes the OCI image to the GitLab Container
Registry (
$CI_REGISTRY_IMAGE/off-the-hook-rss:<sha>and:latest), on the default branch only.
GET /feed.xml— the podcast RSS feedGET /— plain-text info pageGET /health—ok
All audio is hosted by and © 2600 Enterprises. This proxy only re-indexes publicly listed files into a feed; it does not re-host any audio.