- HTML 54.2%
- Elixir 30.5%
- TypeScript 9%
- CSS 5.8%
- Dockerfile 0.3%
- Other 0.1%
| assets | ||
| config | ||
| importers | ||
| lib | Add error section | |
| priv | ||
| test | ||
| .check.exs | ||
| .credo.exs | ||
| .dockerignore | ||
| .env.example | ||
| .formatter.exs | ||
| .gitignore | ||
| CODE_OF_CONDUCT | ||
| docker-compose.yml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| justfile | ||
| LICENSE | ||
| mix.exs | ||
| mix.lock | ||
| README.md | ||
Bookpile
Enter an ISBN, get a list of bookshops and libraries near you. No affiliate links, no cookies. AGPL-3.0-or-later.
How it works
bookpile.org/b/<isbn> looks up book metadata, detects the visitor's location
from their IP address (server-side, using a local MaxMind database), and returns
nearby shops and libraries. The URL works for everyone - each visitor sees
results for their own location.
The list of shops and libraries lives in
priv/data/websites.json. Pull requests to add or fix
entries are welcome.
websites.json format
See priv/data/websites.md for the full format reference.
Dependencies
- Elixir ≥ 1.14 and Erlang/OTP ≥ 25
- PostgreSQL ≥ 14
- Node.js and yarn (for esbuild asset bundling and importers)
- A Google Books API key
- A MaxMind GeoLite2-City database file (free, requires registration)
Running locally
# 1. Install Elixir dependencies
mix deps.get
# 2. Copy the environment template and fill in your values
cp .env.example .env
# Set BOOKPILE_GOOGLE_API_KEY in .env
# 3. Place the MaxMind database
mkdir -p priv/geo
cp /path/to/GeoLite2-City.mmdb priv/geo/
# 4. Create and migrate the database
mix ecto.setup
# 5. Start the server
mix phx.server
Visit localhost:4000.
S3 cover image caching (optional)
Set these environment variables to have book cover images downloaded and stored in S3 instead of served from external sources:
| Variable | Description |
|---|---|
BOOKPILE_S3_BUCKET |
Bucket name — setting this enables the feature |
BOOKPILE_S3_REGION |
Region (default: us-east-1) |
BOOKPILE_S3_ENDPOINT |
S3 API host for non-AWS providers (e.g. fsn1.your-objectstorage.com) |
BOOKPILE_S3_PUBLIC_URL |
Public base URL for stored files (e.g. https://my-bucket.fsn1.your-objectstorage.com) — defaults to the AWS URL pattern |
AWS_ACCESS_KEY_ID |
Access key |
AWS_SECRET_ACCESS_KEY |
Secret key |
Covers are stored as covers/<isbn>.<ext> with public-read ACL. If the bucket
variable is not set the feature is disabled and external image URLs are used
as-is. Works with any S3-compatible storage (AWS, Hetzner, etc.).
Development
mix test # run tests
mix check # tests + credo + dialyzer + formatter (run before committing)
mix format # format code
Assets are bundled with esbuild - no separate Node build step needed during development.