Swipe. Decide. Watch. — a self-hosted swipe-to-match film picker for your Plex library.
Report Bug
·
Request Feature
Table of Contents
Movie night has a deadline, and "what shall we watch?" shouldn't eat half of it. decide turns the choice into a game: two to four people swipe through the same small deck of films from your Plex library; when everyone says "Tonight" to the same one, it's a match — and a ticket stub prints.
- Small decks, not endless scrolling. Filter by mood, runtime, rating, certificate — or build the deck from a Plex collection; swipe 20–50 cards, not 3,000.
- Together or apart. Everyone swipes the same frozen deck in the same order, live on the sofa or hours apart on the train. Matches land the moment you agree.
- It actually decides. Too many matches? The Final Round runs them head-to-head until one film is crowned — then open it in Plex, or send it straight to the TV.
- Nights worth keeping. Every session ends with a taste-compatibility score ("You and Dee agreed on 7 of 30 — 23% tonight"), and stubs you keep live on in the album long after sessions expire.
- Private by design. Your Plex token never leaves the server — every Plex call, including artwork, is proxied by the backend. Once synced, it works on the LAN with no internet at all.
- Feels like an app. Installable PWA with offline swiping that syncs back exactly once when the connection returns. Dark and light themes.
decide is an independent project that works with Plex Media Server. It is not affiliated with or endorsed by Plex, Inc.
decide runs as a single Docker container alongside your Plex Media Server — one image, one port, one SQLite file.
- Docker (or any OCI runtime) on a machine that can reach your Plex server — a Pi, NAS or home server on the same LAN is ideal
- A Plex Media Server with at least one movie library
-
Create a
compose.yaml:services: decide: image: ghcr.io/hk21x/decide:latest container_name: decide ports: - "8080:8080" volumes: - ./data:/data environment: - PUID=1000 - PGID=1000 restart: unless-stopped
-
Start it:
docker compose up -d
-
Open
http://<host>:8080and follow the setup wizard: sign in with Plex (a 4-character code at plex.tv/link — decide never asks for your password), pick your server and film libraries, and let the first sync run.
Unraid: a Community Applications template ships in hk21x/unraid-templates — once accepted you'll find decide in the Apps tab; until then, the template XML works with Unraid's "Add Container → Template" as well.
- Start a session — pick a mood (or fine-tune genres), a runtime cap, a minimum rating, a certificate ceiling for family nights, or a Plex collection to deal from. A live counter shows how many films match.
- Share the code — a six-character join code, a copyable link, and a QR for whoever's on the sofa next to you.
- Swipe — right means "I'd watch this tonight". Tap ⓘ for the synopsis, cast and backdrop. Undo within five seconds if your thumb betrayed you.
- Match — unanimous right-swipes print a ticket stub in the shared shortlist, along with how compatible your taste turned out to be tonight.
- Crown one — the Final Round puts the matches head-to-head; pass the phone, argue, tap winners until one film is crowned for everyone. Open it in Plex, or play it on any Plex client the server can see.
- Keep the stub — kept stubs (and crowned winners) go to the 🎟 album, a ticket wallet of past movie nights that outlives the sessions.
On iPhone or Android, open the site and Add to Home Screen — decide installs as an app, and swipes made offline sync back when you reconnect. There's a light theme in Settings if the auditorium look isn't yours.
Everything is optional — the wizard covers the lot. Env vars exist for declarative setups:
| Variable | Default | Purpose |
|---|---|---|
PORT |
8080 |
Listen port |
DATA_DIR |
/data |
SQLite database + artwork cache |
PUID / PGID |
1000 |
Run as this user/group |
ART_CACHE_MB |
500 |
Artwork disk-cache cap |
PLEX_URL |
— | Skip the wizard: server address |
PLEX_TOKEN |
— | Skip the wizard: auth token |
PLEX_SECTIONS |
— | Comma-separated movie section ids |
SECRET_KEY |
auto-generated | Cookie-signing key override |
decide uses a WebSocket at /api/sessions/*/live — make sure upgrades pass
through your reverse proxy.
Caddy (WebSockets work out of the box):
decide.example.com {
reverse_proxy 127.0.0.1:8080
}
nginx:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Remote access is deliberately out of scope — bring whatever already works for the rest of your self-hosted stack. Tailscale is the easiest route if you have nothing yet.
If your Plex server runs in Docker and LAN clients appear as remote (source-IP NAT), that's a Plex networking quirk, not a decide one — see the Plex forum thread on Docker and local network discovery.
- Final Round — head-to-head bracket that crowns tonight's film
- Taste-compatibility stats
- The stub album — kept tickets that outlive sessions
- Decks from Plex collections
- Play the crowned film on a Plex client (TV, etc.)
- Jellyfin support (media access already sits behind a
MediaSourceprotocol — aJellyfinSourcedrops in without touching the rest) - Per-person Plex sign-in, so "unwatched" means your unwatched
- Save the shortlist to a Plex playlist
See the open issues for the full list of proposed features and known issues.
Deliberately not planned: video playback (that's Plex's job), TV shows, more than four people, recommendations, or accounts.
No build step magic — a Python backend and a Vite frontend.
Backend (Python 3.12, FastAPI, SQLite — managed with uv):
cd backend
uv sync
DATA_DIR=.dev-data uv run uvicorn decide.main:app --reload --port 8080
uv run pytestFrontend (React 18 + Vite + TypeScript + Tailwind):
cd frontend
npm install
npm run dev # proxies /api to :8080Verified Plex endpoint behaviour is documented in docs/plex-notes.md.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
Harry — @hk21x
Project Link: https://github.com/hk21x/decide
- python-plexapi
- Fontsource (Archivo, Public Sans, Space Mono)
- Best-README-Template
