Ebooks
Find every ebook on your machine, detect its bibliographic metadata, resolve authors and titles against Wikipedia + Wikidata, and render a browsable HTML page linking each file to its location on disk. WHAT IT DOES
Turns a filesystem full of ebooks into a catalogued, browsable library. It
walks the tree for ebook files, derives author/title/ISBN/publish dates from
the path, filename and file contents, then resolves each author and title
against Wikipedia and Wikidata so the rendered pages show canonical names —
and only links names actually classified as people. The scan is resumable:
each run continues from where the last stopped and stops itself after a
five-minute budget, so a million-file home directory is catalogued across
several runs without ever re-walking ground already covered. It fetches
nothing itself — all network I/O is delegated (transitively) to
@svendowideit/web-cache, which paces and caches, so re-analysing an
already-resolved name costs no network traffic.
It can also publish those pages over HTTP(S): when @svendowideit/caddy is
installed, the workflow's final step declares a Caddy file_server route
serving the render directory at ebooks.<host>.<domain>, reading the host
and domain from the caddy model that already owns this machine. The route
lives on a dedicated ebooks-caddy model that caddy merges with the models
it already runs, and caddy derives the A record and certificate for the name
— so nothing is hardcoded and nothing is duplicated. With caddy absent the
step skips with a log and the pages remain on disk.
INSTALL
swamp extension pull @svendowideit/ebooksDEPENDENCIES
@svendowideit/web-cache, @svendowideit/wikipedia, and
@svendowideit/wikidata, declared in this manifest's dependencies: — the
single swamp extension pull above installs them automatically. Nothing is
installed on the host.
@svendowideit/caddy is an optional dependency, declared in this
manifest's optionalDependencies:. It is not installed for you: pull it
separately to enable the HTTP(S) serving step, which is skipped when it is
absent.
RUN
# Scan, detect, resolve, and render — re-run to continue a long scan in
# five-minute increments; the HTML page regenerates each time.
swamp workflow run @svendowideit/ebook-scan
# Point the scan at a specific directory instead of $HOME.
swamp workflow run @svendowideit/ebook-scan --input root=/home/me/books
# Re-detect and re-render the already-found paths without re-walking the
# filesystem — use after changing metadata detection or rendering.
swamp workflow run @svendowideit/ebook-scan --input skipScan=true
# Raise the per-call origin-fetch cap to drain the resolution backlog
# faster (cached hits do not count).
swamp workflow run @svendowideit/ebook-scan --input maxFetches=50
# Read the discovered ebooks and their detected metadata as JSON.
swamp data get ebook-scan state --json
# (Re)declare the Caddy file_server route on its own — normally the last
# step of @svendowideit/ebook-scan does this for you. Needs
# @svendowideit/caddy and a caddy model that already owns this machine; it
# serves the render directory at ebooks.<host>.<domain>.
swamp model method run ebooks ensure-caddy-serveCONFIGURE
All workflow inputs are optional:
root Filesystem path to scan (default ~)
outputPath HTML listing output path (default ~/.swamp/ebooks/ebooks.html)
authorsOutputPath Author-index output path (default ~/.swamp/ebooks/index.html)
title Page title (default "Ebooks")
cacheDir Shared web-cache directory (default ~/.swamp/web-cache)
maxFetches Origin fetches per get-many call (default 20)
skipScan Skip the directory scan (default false)The ebooks model also reads global arguments:
extensions Ebook file extensions to match
excludePatterns Directory names to skip
cacheDir Shared web-cache directory
caddyModelName @svendowideit/caddy model to read the ebooks host and
domain from, for ensure-caddy-serve
(default: auto-discover the model owning this machine)
caddyRouteHostname Override the served hostname
(default: ebooks.<host>.<domain>)See the README for values and defaults.
WHAT IT INSTALLS
Nothing on the host — no services, daemons, cron triggers, or webhooks. It
reads the filesystem and the shared web-cache and writes swamp data plus the
two HTML files named by outputPath and authorsOutputPath.
If @svendowideit/caddy is installed and a caddy model already owns this
machine, the final ebook-scan step also declares a Caddy file_server
route serving that directory at ebooks.<host>.<domain>, on a dedicated
ebooks-caddy model that caddy merges with the models it already runs.
Nothing new is installed by ebooks itself — no service, no daemon.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| root? | string | Filesystem path to scan for ebooks (default ~) |
| outputPath? | string | Filesystem path for the generated HTML listing |
| authorsOutputPath? | string | Filesystem path for the author-grouped index (only ebooks with a |
| extensions? | array | File extensions to treat as ebooks (without the dot) |
| excludePatterns? | array | Directory names to skip while scanning |
| cacheDir? | string | Shared web-cache directory to read cached Wikipedia/Wikidata responses |
| caddyModelName? | string | Name of the @svendowideit/caddy model whose base domain and host record |
| caddyRouteHostname? | string | Override the full hostname the ebooks pages are served under. Empty |
| Argument | Type | Description |
|---|---|---|
| maxDurationMs? | number | Self-imposed wall-clock budget per scan run (default 5 minutes) |
| Argument | Type | Description |
|---|---|---|
| file? | string | Specific ebook file to detect metadata for. Omit to detect metadata |
| maxDurationMs? | number | Self-imposed wall-clock budget per detect run (default 5 minutes) |
| Argument | Type | Description |
|---|---|---|
| maxNames? | number | Cap on the number of names emitted this run. Already-resolved names are |
| Argument | Type | Description |
|---|---|---|
| name | string | |
| expectKind | enum | |
| key? | string | Filesystem-safe instance key for this name (defaults to nameKey(name)) |
| results? | array | |
| pages? | record |
| Argument | Type | Description |
|---|---|---|
| name | string | |
| expectKind | enum | |
| key? | string | Filesystem-safe instance key for this name (defaults to nameKey(name)) |
| title? | string | |
| url? | string | |
| description? | string | |
| wikidataId? | string | |
| infoboxTemplate? | string | |
| instanceOf? | array |
| Argument | Type | Description |
|---|---|---|
| title? | string | Page title |
| Argument | Type | Description |
|---|---|---|
| title? | string | Page title |
| Argument | Type | Description |
|---|---|---|
| model? | string | Source @svendowideit/caddy model whose base domain and host record supply |
| serveModel? | string | |
| hostname? | string | Full hostname to serve the pages on. Defaults to the global |
| serveRoot? | string | Directory to serve over HTTP(S). Defaults to the directory of the |
Resources
| Argument | Type | Description |
|---|---|---|
| file | string | Path to the book file to detect metadata from |
| Argument | Type | Description |
|---|---|---|
| title? | string | |
| author? | string | |
| isbn? | string | |
| publishedAt? | string | |
| editionPublishedAt? | string | |
| publisher? | string | |
| language? | string | |
| description? | string | |
| series? | string | |
| sourcePath? | string | Link back to a source file/record |
| sourceName? | string |
Resources
Incrementally scan the local filesystem for ebooks, detect bibliographic metadata, resolve authors/titles against Wikipedia/Wikidata, and render an HTML page linking to each file's location on disk. The scan-disk step is resumable and self-terminating: each run enumerates directories for up to 5 minutes, then hands off to the next step. Re-run the workflow to continue scanning from where it left off (state is persisted in swamp data). Once the whole tree is covered, the scan restarts fresh. Re
Resolve and classify one name (an author or a book title) against Wikipedia and Wikidata, through the shared cache, transparently. Emits a single per-name `resolution` record owned by @svendowideit/ebooks. The whole pipeline is workflow composition — this workflow knows nothing about fetching or caching. It calls the wikipedia/wikidata workflows, which in turn call web-cache; cache-hit vs fetch is invisible here (only surfaced as metadata). wikipedia-search → candidate titles wikipedi
Fan out over a list of names (authors + book titles), resolving and classifying each via @svendowideit/ebooks-resolve-name. This is the typed boundary between the parent (which computes the name list) and the per-name resolution pipeline — the list is passed as a typed input, so forEach expands only after the parent's plan-resolution step has completed. Inputs: items — array of { name, expectKind, key } objects to resolve cacheDir — shared cache dir (default ~/.swamp/web-cache)
Modified 1 behaviors
Modified 1 behaviors. Added 2 workflows. updated dependencies
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit1/2partial
- @std/path--jsr:@std/path@1 is a range; audited 1.1.6, the version the registry resolved
2 dependencies found
- jsr:@std/path@1 -- audited 1.1.6
- npm:fflate@0.8.3 -- audited 0.8.3
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned
Spawns a subprocess with Deno.Command().
- models/ebooks.ts:1005 — optional caddy peer discovered at runtime; args are fixed literals or globals of this model, never untrusted input — see README.