feat: mirror Stairway to Hell archive into S3#688
Draft
mattgodbolt-molty wants to merge 2 commits into
Draft
Conversation
Adds tooling and a manual GitHub workflow to snapshot the upstream STH BBC Micro software archive into s3://bbc.xania.org/archive/sth/. The mirror exists so jsbeeb's sth: URLs and the in-app archive browser keep working if the volunteer-run upstream site disappears. The client (src/sth.js) is intentionally not changed in this commit; that swap will follow in a separate PR after the mirror has been populated and spot-checked. * tools/mirror-sth.js scrapes four categories (disk images, tape images, sthcollection, educational) plus a handful of changelog/index files for provenance, writes per-category and top-level manifests in a versioned JSON format, and is resumable by size. * .github/workflows/mirror-sth.yml is workflow_dispatch only with a dry_run input that defaults to true. The S3 sync is strictly additive — no --delete — to make a typo on the destination URL safe against wiping the live app served from the same bucket. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
Adds six more categories so the snapshot covers the full set of downloadable archive areas STH hosts, not just the BBC Micro disc and tape sections: * roms/ — 50 BBC + Electron sideways ROMs from /roms/homepage.html * electron/uefarchive/ — ~890 Electron tape image zips, ~15 MB, via reclist.php with the same parser as the BBC tape archive * electron/dfs/ — ~230 Electron DFS disk images * electron/adfs/ — ~23 Electron ADFS disk images * electron/multiplexing/ — single curiosity file * electron/t2p3/ — 4 curiosity files The total mirror grows from ~3,330 to ~4,500 objects and from ~50 MB to ~80 MB; still trivial for S3. S3 paths follow the upstream layout exactly (e.g. archive/sth/electron/uefarchive/Hewson/Uridium-FIXED_E.zip), so provenance is preserved. Generalises parseSthCollection into a reusable parseHomepage that handles any hand-rolled HTML index page, filtering out external, absolute, and upward (../) hrefs and optionally stripping a directory prefix. While doing this, fixes a latent bug where sthcollection's fileBase was set to /bbc/ instead of /bbc/sthcollection/, which would have produced 404s on the first non-quick scrape — not caught by the earlier smoke test because that test only ran the educational category. Adds three new meta files (roms-homepage.html, electron-homepage.html, electron-other.html) and renames the existing bbc/* meta files with a bbc- prefix to disambiguate from the new electron- and roms- ones. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds tooling and a manual GitHub Actions workflow to snapshot the upstream
Stairway to Hell BBC Micro, Acorn
Electron, and sideways-ROM archives into
s3://bbc.xania.org/archive/sth/.The mirror exists so jsbeeb's
sth:URLs and the in-app archive browserkeep working if the volunteer-run upstream site disappears — STH has been
effectively frozen since around 2008 (see
meta/bbc-disklog.txt/meta/bbc-tapelog.txtonce mirrored), so this is a one-shot snapshotrather than a continuous sync.
The client (
src/sth.js) is intentionally not changed in this PR. Thatswap follows in #689 once the mirror has been populated and spot-checked.
What gets mirrored
diskimages/bbc/archive/diskimages/reclist.php?sort=name&filter=.ziptapeimages/bbc/archive/tapeimages/reclist.php?sort=name&filter=.zipsthcollection/bbc/sthcollection.htmlother/educational/bbc/other/educational/reclist.php?sort=name&filter=.ziproms/roms/homepage.html(BBC + Electron sideways ROMs)electron/uefarchive/electron/uefarchive/reclist.php?sort=name&filter=.zipelectron/dfs/electron/dfs/homepage.htmlelectron/adfs/electron/adfs/homepage.htmlelectron/multiplexing/electron/multiplexing/homepage.htmlelectron/t2p3/electron/t2p3/homepage.htmlmeta/*Total ~4,525 objects, expected ~80 MB after HEAD requests fill in sizes
for the homepage-indexed categories. Still trivial for S3.
The Electron categories and the
roms/category are mirrored even thoughjsbeeb does not currently emulate the Electron and already ships its own
copy of the BBC ROMs in
public/roms/— the goal is a complete archivalsnapshot of what STH hosts, not just what the running app uses today.
Layout in S3
Top-level prefix is
archive/sth/so future mirrors of other archives cansit alongside as
archive/<id>/with their own top-level manifests.Within
archive/sth/the layout mirrors STH's own URL structure exactly:Manifest schema (
schemaVersion: 1) and per-category manifest layout aredocumented in
tools/README-sth-mirror.md.Safety choices worth flagging
--deleteon the S3 sync. Strictly additive uploads only. STH filesdon't actually disappear (frozen archive), and a typo on the destination URL
with
--deletecould wipe the live app served from the same bucket. Ifpruning ever becomes needed, add it behind an explicit
prune: trueinputin a follow-up.
workflow_dispatchonly, with adry_runinput that defaults totrue. First run scrapes only, prints the top-level manifest summary, andstops short of touching S3. Re-run with
dry_run: falseonce the dry-runoutput looks right.
public, max-age=31536000, immutable(pathsare content-stable); manifests +
meta/*getmax-age=300.Test plan
npm run ci-checksis cleannode tools/mirror-sth.js --out /tmp/sth-mirror --quickparses all 10 catalogs (1608/1502/143/75/50/888/231/23/1/4 entries
— counts match hand-counted upstream totals)
electron/t2p3(4 files) and
sthcollectionsample, byte-identity verified bysha256sumagainst upstream URLspresent at the expected size
[](e.g.Unreleased/Daxis[droids]-demo.zip)round-trip cleanly via the scraper's
encodePathparseHomepagecorrectly filters../cross-refs (the one../electron/uefarchive/...link on/roms/homepage.htmldoesn'tget double-counted; that file lives in the
electron/uefarchivecategory)
dry_run: trueto confirm AWS creds resolve andthe top-level manifest summary looks sane
dry_run: falseand spot-checkhttps://bbc.xania.org/archive/sth/manifest.jsonand a sample ofzips from a few categories
Open question for review
The existing
update-webdeploy usesjakejarvis/s3-sync-actionwhich doesnot add
--delete(verified by reading the action'sentrypoint.sh), sothe regular deploy will leave anything under
archive/sth/alone. But thisPR assumes the IAM user behind
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYhas write access to the
archive/sth/prefix as well as the bucket rootused by
update-web. If the policy is scoped tighter than that, thedry_run: falserun will 403 and you'll need to widen the policy first.🤖 Generated with Claude Code