3 minmurerkinnrss原文 ↗

Bookshelf

BookshelfA self-hosted library for the ebooks you already own. One server-rendered page
lists them, filters them with a search box, serves downloads, and reads them in

the browser — EPUB and PDF, each with its own reader — as a Cloudflare Worker

over R2, or as a Node server over a directory on disk.Everything above is npm run demo — a generated shelf of public-domain titles,

so the screenshots can be reproduced without finding books first.Getting startedNode 24 or newer, and a Unix-like system: the sync tool finds its image tools

with which, so Windows is not supported. Covers come out better with cwebp

and pdftoppm installed — see publishing, or use

Docker, which ships both.Put some books — EPUB or PDF — in books/, then choose where the library

should live.With DockerThe shortest path, and the image brings its own cwebp and pdftoppm so

covers come out right without installing anything on the host.The shelf is then on http://localhost:3000. Flags pass through, so

docker compose run --rm sync --force and --dry-run behave as they do

locally.One named volume, library, holds the published books and everything the app

writes to them — profiles and reading positions — so it is the only thing to

back up.The image is built for the filesystem provider: it is a Node server, and

Cloudflare needs no container. It runs as a non-root user, and creates /data

owned by that user so a named volume inherits an ownership the app can write

to. If you would rather bind-mount a host directory, chown it first:On a machine you own, without DockerNo account anywhere. Point bookshelf.config.json at a directory, publish into

it, and run the app:library/ is the tree the sync tool builds; directory is where it publishes

to, and it holds the books being served. Keep it out of the repository —

shelf-data/ already is.On CloudflareNeeds a Cloudflare account and npx wrangler login. Two checked-in files

carry this project's own bucket and Worker name and are meant to be edited —

see the R2 provider.The two must agree about which bucket holds the library, or the app will serve

an empty shelf. They are checked against each other before anything uploads,

and a mismatch is reported rather than published through.A demo shelfNo books to hand, or want something worth screenshotting? Nine generated

public-domain titles — eight EPUBs and a PDF, so both readers are one click from

the shelf — downloading nothing:Then publish and serve by whichever route above. The titles and authors are real

works long out of copyright so a shelf of them looks like a shelf; the prose

inside is placeholder. Note that the config in this repository points at R2, so

npm run sync goes there unless you change it.A public instanceAnything reachable by strangers should refuse to be changed:Storage keeps serving and stops accepting. Profiles cannot be added, renamed or

deleted, and reading positions go back to living in the browser — the same

degradation as a provider that cannot write, because to the app it is the same

situation. Switching between existing profiles still works; that is a cookie,

not a change.It is enforced where the writing happens, not by hiding the forms, so posting

the actions directly gets the same refusal.There is no authentication. Anyone who can reach the app can read and

download the whole library, so put it on a network you trust or behind

something that asks who is calling. See Not done yet.CommandsAll of these run from the repository root; Turborepo builds whatever the task

depends on first.npm run cf-typegen -w @bookshelf/app regenerates cloudflare-env.d.ts after

editing wrangler.jsonc.DocumentationNot done yetThere is no authentication. Anyone with the URL can read and download the

whole library — and pick any profile while doing it. Profiles are a way to

keep housemates' bookmarks apart, not a way to keep anyone out.Two devices reading as one profile at the same time is last-write-wins.ContributingSee CONTRIBUTING.md. The short version: Node 24, npm install, and npm run lint, npm run check-types and npm test before you

push. The tests reach the packages and the app's service layer but not its

pages, so say what you ran as well.Storage providers are the extension point and do not have to live here: a

package published by anyone can be installed and named in the config.LicenseMIT — see LICENSE.That covers the code. It says nothing about the books you put in a library

built with it, whose copyright is between you and their publishers.

如果可以重来,你还愿意花这段时间读它吗?

· 匿名阅读记录只用于改进推荐