Initial TopDeck: self-hosted ranked favorites
A single Go binary with SQLite that serves a public page of the owner's ranked lists (movies, TV, albums, songs, video games, theater) and a login-gated editor. - Lists of 1–65,535 entries (100 recommended), several per category - Search-to-add via TMDB, TheTVDB, IGDB, Deezer/MusicBrainz, Wikipedia; manual entry as a fallback - Theater entries carry a production (Broadway, tour, …), venue and cast - Artwork cached locally; URL override and uploads - Drag, arrow and type-a-rank reordering; paginated for long lists - 12 theme presets plus custom CSS - First-run setup code or env-provided admin; bcrypt, rate-limited login, CSRF-guarded JSON API - Dockerfile and docker-compose.yml Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
e9a75a968a
53 files changed
+7078
No files matched your search
@@ -0,0 +1,122 @@
|
||||
# TopDeck
|
||||
|
||||
A self-hosted page for **your** ranked favorites: movies, TV shows, albums, songs, video games and theater. 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.
|
||||
|
||||
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).
|
||||
- **Search-to-add** from TMDB, TheTVDB, IGDB, Deezer/MusicBrainz and Wikipedia, with add-manually as a fallback for anything they miss.
|
||||
- **Theater by production**: record *which* staging you mean (Broadway, West End, North American Tour, a revival…) plus venue and cast, and use that production's own poster.
|
||||
- **Drag to rank**, or use the arrow buttons or type a new number. Paginated editing keeps huge lists usable.
|
||||
- **Art is cached on your server**, so pages never hotlink and keep working if a source changes. You can also paste an image URL or upload your own.
|
||||
- **Personal notes** on any entry, shown in a detail view (toggleable).
|
||||
- **12 theme presets** plus a custom CSS box. Every color is a CSS variable.
|
||||
- **Single binary + SQLite**, no external database. Around 15 MB, and it runs anywhere Docker does.
|
||||
|
||||
## Quick start (Docker Compose)
|
||||
|
||||
```sh
|
||||
git clone https://git.iamchrisama.com/cdnutter/topdeck && cd topdeck
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Without Compose
|
||||
|
||||
```sh
|
||||
docker build -t topdeck .
|
||||
docker run -d --name topdeck -p 4242:4242 -v topdeck-data:/data topdeck
|
||||
```
|
||||
|
||||
Or from source (Go 1.26+): `go run ./cmd/topdeck` stores data in `./data`.
|
||||
|
||||
## Data sources and API keys
|
||||
|
||||
| Category | Source | Key? | Get one |
|
||||
|---|---|---|---|
|
||||
| Movies | [TMDB](https://www.themoviedb.org) | Yes (free) | [themoviedb.org/settings/api](https://www.themoviedb.org/settings/api). The v3 key or the v4 Read Access Token both work. |
|
||||
| TV Shows | [TheTVDB](https://thetvdb.com) (default) or TMDB | Yes | [thetvdb.com/api-information](https://thetvdb.com/api-information). Switch TV to TMDB in Settings to reuse your TMDB key. |
|
||||
| Video Games | [IGDB](https://www.igdb.com) | Yes (free, via Twitch) | Register an app at [dev.twitch.tv/console](https://dev.twitch.tv/console/apps) and use its Client ID + Secret ([guide](https://api-docs.igdb.com/#account-creation)). |
|
||||
| Albums & Songs | [Deezer](https://developers.deezer.com/api) (default) or [MusicBrainz](https://musicbrainz.org) + [Cover Art Archive](https://coverartarchive.org) | No | Nothing to set up. |
|
||||
| Theater | [Wikipedia](https://en.wikipedia.org) | No | Nothing to set up. |
|
||||
|
||||
**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.
|
||||
|
||||
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.
|
||||
|
||||
## Configuration
|
||||
|
||||
| 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 |
|
||||
|
||||
### 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:
|
||||
|
||||
```
|
||||
favorites.example.com {
|
||||
reverse_proxy topdeck:4242
|
||||
}
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
Pick a preset under **Settings → Appearance**: Midnight, Obsidian, Nord, Dracula, Mocha, Rosé Pine, Gruvbox, Forest, Synthwave, Daylight, Paper or Latte. Then add your own CSS if you like. It loads after the theme on every page, so overriding variables is enough for a whole new look:
|
||||
|
||||
```css
|
||||
:root, [data-theme] {
|
||||
--bg: #0d0b12;
|
||||
--surface: #16131d;
|
||||
--accent: #ff5a7a;
|
||||
--font-display: "Georgia", serif;
|
||||
--radius-art: 14px;
|
||||
}
|
||||
```
|
||||
|
||||
See [`web/static/css/themes.css`](web/static/css/themes.css) for every variable.
|
||||
|
||||
## List sizes
|
||||
|
||||
A list can hold 1 to 65,535 entries. The editor recommends **100 or fewer** and warns past 1,000. Long lists work (public pages and the editor paginate at 100), but they're hard for visitors to take in.
|
||||
|
||||
## Backups
|
||||
|
||||
Everything lives in the data volume: `topdeck.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
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
go run ./cmd/topdeck # 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
|
||||
internal/store SQLite schema, lists, items, ranking, settings, sessions
|
||||
internal/providers TMDB, TheTVDB, IGDB, Deezer, MusicBrainz, Wikipedia
|
||||
internal/imgcache downloads and stores artwork
|
||||
internal/server HTTP routes, auth, JSON API, page rendering
|
||||
web/ templates, CSS themes, JS, icons
|
||||
```
|
||||
Reference in new issue
Block a user