The library of the BBS network: thousands of public-domain books from Project Gutenberg, cut into pageable chapters for a modern terminal or a Commodore 64.
Live at
teletypegames.org:2330, in the browser on bbsweb, and through TTG Gate BBS
A Ruby app on the rubbs gem, like the Teletype BBS, Alexandria BBS and Commodex BBS.
It has two faces on one port:
A call starts with rubbs' BBS::Terminal question: RETURN takes the guess, 1 picks the modern face, 2 the C64.
pg_catalog.csv.gz (about 78,000 texts and 400 bookshelves). The board imports it into SQLite with a full-text index on titles and authors and reads it again every week; the old catalog serves until the new one is ready. Every search word matches as a word prefix, accents do not matter (bronte finds Brontë), and lang:fr keeps one language.config/classics.yml); it works even before the first catalog import.Every book page credits it: eBook #N from Project Gutenberg, gutenberg.org/ebooks/N — public domain in the USA.
On a modern terminal:
| Key | Action |
|---|---|
| F2 | The Classics shelf |
| F3 | Search by title or author |
| F4 | Project Gutenberg's bookshelves |
| F7 | Most read on this board |
| Enter or Alt-R | Open a book / read a chapter |
| PgUp, PgDn, Home, End | Page in the reader |
| ← → or P, N | Previous / next chapter |
| F5 or Alt-Enter | Full screen and back |
| Alt-X | Log off |
On a Commodore 64 the menu has 1 the Classics, 2 the bookshelves, 3 search, 4 most read, A about, Q log off. A book has an info page and a numbered chapter list; in the reader RETURN gives the next page (and at the end the next chapter), B goes back a page, N/P change chapter, Q goes back to the list. Curly quotes, dashes and accented letters are turned into what a C64 can show.
| Variable | Default | |
|---|---|---|
SCRIPTORIUM_BBS_MIRROR |
https://www.gutenberg.org |
where the texts come from; a mirror works too |
SCRIPTORIUM_BBS_CATALOG_URL |
https://www.gutenberg.org/cache/epub/feeds/pg_catalog.csv.gz |
the catalog |
SCRIPTORIUM_BBS_CATALOG_TTL |
7 |
days before the catalog is read again |
SCRIPTORIUM_BBS_CLASSICS |
config/classics.yml |
the Classics shelf |
SCRIPTORIUM_BBS_DB |
data/catalog.sqlite3 |
the imported catalog |
SCRIPTORIUM_BBS_CATALOG_FILE |
data/pg_catalog.csv.gz |
the downloaded catalog |
SCRIPTORIUM_BBS_TEXTS |
data/texts |
the text cache |
SCRIPTORIUM_BBS_CACHE_MB |
300 |
the text cache's size |
SCRIPTORIUM_BBS_BOOK_MAX |
8388608 |
the largest book fetched, in bytes |
SCRIPTORIUM_BBS_READS |
data/reads.jsonl |
the reads, one JSON line each |
The board has no secrets. After a change to the chapter rules, clear data/texts so the cached books are cut again.
A push to master deploys it from Woodpecker (RuboCop, compose check, ci-deploy scriptorium-bbs); the container is scriptorium-bbs, in /srv/stacks/scriptorium-bbs, and data/ stays between deploys. The entrypoint updates rubbs on start.
The code follows the house layering: lib/domain (the book, shelf, chapter and text models; the Gutenberg, catalog, classics, read and text-cache repositories; ChapterService, LibraryService, ReadingService; the composition root ScriptoriumBBS) knows nothing of telnet, and lib/ui holds UI::Modern with its ReaderWindow and UI::Petscii. A book is fetched and cut one at a time, so a burst of new books cannot blow the memory limit.