Rename project from TopDeck to Canon

- Module github.com/cdnutter/canon, binary/command cmd/canon, Docker
  image and compose project "canon"
- Environment variables now use the CANON_ prefix
- Default site title is "<Your name>'s Canon" (or "Canon" with no name);
  a Site title set in Settings still overrides it
- Existing topdeck.db (and WAL files) is renamed to canon.db on start
- README: upgrade notes, including moving the old compose volume

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-24 17:22:17 -07:00
1 parent 58a29b7339
commit 3923444b3b
26 files changed
+215 -120

No files matched your search

+39 -23
View File
@@ -1,7 +1,9 @@
# TopDeck
# Canon
A self-hosted page for **your** ranked favorites: movies, TV shows, albums, songs, video games, theater, and anything else you care to rank in a custom list. One owner, as many lists as you like, each with its own size (Top 5, Top 100, … up to 65,535), with proper posters and cover art pulled from the best free metadata sources.
Your page is titled **"*Your name*'s Canon"** by default. Set your name under Settings → Profile, or give the site any title you like there.
Visitors just see your lists. There's no sign-up, no feed and no login button. You manage everything from `/login`.
- **Ranked lists per category**: Movies, TV Shows, Albums, Songs, Video Games and Theater. Each list sets its own size, title, description and layout (artwork grid or ranked list).
@@ -18,24 +20,24 @@ Visitors just see your lists. There's no sign-up, no feed and no login button. Y
## Quick start (Docker Compose)
```sh
git clone https://git.iamchrisama.com/cdnutter/topdeck && cd topdeck
git clone https://git.iamchrisama.com/cdnutter/canon && cd canon
cp .env.example .env # optional: admin account + API keys
docker compose up -d
docker compose logs topdeck # shows the one-time setup code if you didn't set an admin in .env
docker compose logs canon # shows the one-time setup code if you didn't set an admin in .env
```
Open `http://localhost:4242/setup`, enter the setup code and create your account. Then go to **Settings → Integrations** to add API keys.
To skip the setup page, set `TOPDECK_ADMIN_USERNAME` and `TOPDECK_ADMIN_PASSWORD` in `.env` before the first start. They're only used when no account exists yet.
To skip the setup page, set `CANON_ADMIN_USERNAME` and `CANON_ADMIN_PASSWORD` in `.env` before the first start. They're only used when no account exists yet.
### Without Compose
```sh
docker build -t topdeck .
docker run -d --name topdeck -p 4242:4242 -v topdeck-data:/data topdeck
docker build -t canon .
docker run -d --name canon -p 4242:4242 -v canon-data:/data canon
```
Or from source (Go 1.26+): `go run ./cmd/topdeck` stores data in `./data`.
Or from source (Go 1.26+): `go run ./cmd/canon` stores data in `./data`.
## Data sources and API keys
@@ -50,7 +52,7 @@ Or from source (Go 1.26+): `go run ./cmd/topdeck` stores data in `./data`.
**Why these for music and theater?** Neither needs a key.
- **Music:** Deezer's public catalogue API has no key, generous limits (about 50 requests per 5 seconds) and 1000×1000 covers for both tracks and albums. MusicBrainz is the fully open alternative, but it's limited to one request per second and art coverage is patchier. Spotify, Apple Music and Last.fm all need keys or OAuth and have stricter terms.
- **Theater:** there's no open theater database with an API (IBDB and Playbill don't offer one). Wikipedia covers nearly every musical, play and opera, usually with poster or logo art. TopDeck filters search to pages that use the musical, play or opera infobox. Wikipedia describes the *work*, so you pick the production yourself and can swap in that production's poster.
- **Theater:** there's no open theater database with an API (IBDB and Playbill don't offer one). Wikipedia covers nearly every musical, play and opera, usually with poster or logo art. Canon filters search to pages that use the musical, play or opera infobox. Wikipedia describes the *work*, so you pick the production yourself and can swap in that production's poster.
Keys entered in the UI are stored in the SQLite database on your server. Keys set as environment variables take precedence and show as locked in the UI.
@@ -58,23 +60,23 @@ Keys entered in the UI are stored in the SQLite database on your server. Keys se
| Variable | Default | |
|---|---|---|
| `TOPDECK_PORT` | `4242` | Listen port |
| `TOPDECK_DATA_DIR` | `/data` (Docker), `./data` | Database + cached images |
| `TOPDECK_ADMIN_USERNAME` / `_PASSWORD` | | Create the owner account on first start |
| `TOPDECK_TMDB_API_KEY` | | |
| `TOPDECK_TVDB_API_KEY` / `TOPDECK_TVDB_PIN` | | The PIN is only for user-supported keys |
| `TOPDECK_IGDB_CLIENT_ID` / `_SECRET` | | Twitch app credentials |
| `TOPDECK_TRUST_PROXY` | `false` | Trust `X-Forwarded-*` headers (set behind a reverse proxy) |
| `TOPDECK_SECURE_COOKIES` | `false` | Force `Secure` cookies (set if served over HTTPS) |
| `TOPDECK_LOG_LEVEL` | `info` | `debug` logs every request |
| `CANON_PORT` | `4242` | Listen port |
| `CANON_DATA_DIR` | `/data` (Docker), `./data` | Database + cached images |
| `CANON_ADMIN_USERNAME` / `_PASSWORD` | | Create the owner account on first start |
| `CANON_TMDB_API_KEY` | | |
| `CANON_TVDB_API_KEY` / `CANON_TVDB_PIN` | | The PIN is only for user-supported keys |
| `CANON_IGDB_CLIENT_ID` / `_SECRET` | | Twitch app credentials |
| `CANON_TRUST_PROXY` | `false` | Trust `X-Forwarded-*` headers (set behind a reverse proxy) |
| `CANON_SECURE_COOKIES` | `false` | Force `Secure` cookies (set if served over HTTPS) |
| `CANON_LOG_LEVEL` | `info` | `debug` logs every request |
### Reverse proxy
TopDeck serves plain HTTP. Put it behind Caddy, Traefik or nginx for HTTPS, and set `TOPDECK_TRUST_PROXY=true` so logins are rate-limited per real client and cookies are marked secure. Caddy example:
Canon serves plain HTTP. Put it behind Caddy, Traefik or nginx for HTTPS, and set `CANON_TRUST_PROXY=true` so logins are rate-limited per real client and cookies are marked secure. Caddy example:
```
favorites.example.com {
reverse_proxy topdeck:4242
reverse_proxy canon:4242
}
```
@@ -107,25 +109,39 @@ Every list can be downloaded as its titles only, in rank order, one per line. Th
The Export menu appears in the list editor and, when you're signed in, on the list's public page. The links follow the list's visibility: anyone can download a public list, and only you can download a hidden one.
## Upgrading from TopDeck
Canon was called TopDeck, and upgrading keeps all your data:
- The database is renamed from `topdeck.db` to `canon.db` automatically on first start.
- Environment variables changed prefix from `TOPDECK_` to `CANON_`. Rename them in your `.env`.
- You'll be signed out once (the session cookie was renamed).
- Docker Compose now always uses the project name `canon`. If you ran the old compose file, your data is in the `topdeck_topdeck-data` volume. Copy it into the new one before starting:
```sh
docker volume create canon_canon-data
docker run --rm -v topdeck_topdeck-data:/from -v canon_canon-data:/to alpine cp -a /from/. /to/
```
## Backups
Everything lives in the data volume: `topdeck.db` (SQLite) and `images/`. Copy the volume, or while running:
Everything lives in the data volume: `canon.db` (SQLite) and `images/`. Copy the volume, or while running:
```sh
docker compose exec topdeck sh -c 'cd /data && tar c topdeck.db* images' > topdeck-backup.tar
docker compose exec canon sh -c 'cd /data && tar c canon.db* images' > canon-backup.tar
```
## Development
```sh
go run ./cmd/topdeck # http://localhost:4242
go run ./cmd/canon # http://localhost:4242
go test ./...
```
Templates and static assets in `web/` are embedded into the binary, so rebuild after editing them. The front end is plain ES modules with no build step.
```
cmd/topdeck entry point, first-run bootstrap
cmd/canon entry point, first-run bootstrap
internal/store SQLite schema, lists, items, ranking, settings, sessions
internal/providers TMDB, TheTVDB, IGDB, Deezer, MusicBrainz, Wikipedia
internal/imgcache downloads and stores artwork