All apps · 0 apps
decide
Docker app from hk21x's Repository
Overview
Readme
View on GitHubdecide
Swipe. Decide. Watch. — a self-hosted swipe-to-match film picker for your Plex library.
Report Bug
·
Request Feature
Table of Contents
About The Project
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.
Built With
Getting Started
decide runs as a single Docker container alongside your Plex Media Server — one image, one port, one SQLite file.
Prerequisites
- 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
Installation
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-stoppedStart it:
docker compose up -dOpen
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.
Usage
- 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.
Configuration
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 |
Deployment Notes
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.
Roadmap
- 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.
Development
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 pytest
Frontend (React 18 + Vite + TypeScript + Tailwind):
cd frontend
npm install
npm run dev # proxies /api to :8080
Verified Plex endpoint behaviour is documented in docs/plex-notes.md.
Contributing
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
License
Distributed under the MIT License. See LICENSE for more information.
Contact
Harry — @hk21x
Project Link: https://github.com/hk21x/decide
Acknowledgments
- python-plexapi
- Fontsource (Archivo, Public Sans, Space Mono)
- Best-README-Template
Install Decide on Unraid in a few clicks.
Find Decide in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/hk21x/decide:latestRuntime arguments
- Web UI
http://[IP]:[PORT:8080]- Network
bridge- Shell
sh- Privileged
- false
Template configuration
Port for the decide web app.
- Target
- 8080
- Default
- 8080
- Value
- 8080
SQLite database and artwork cache.
- Target
- /data
- Default
- /mnt/user/appdata/decide
- Value
- /mnt/user/appdata/decide
User ID to run as (99 = nobody on Unraid).
- Default
- 99
- Value
- 99
Group ID to run as (100 = users on Unraid).
- Default
- 100
- Value
- 100
Disk cap for the poster/backdrop cache under /data/art.
- Target
- ART_CACHE_MB
- Default
- 500
- Value
- 500
Optional declarative setup: your Plex server address (e.g. http://192.168.1.10:32400). Leave empty to use the in-browser setup wizard instead.
- Target
- PLEX_URL
Optional declarative setup: an X-Plex-Token. Leave empty to sign in with the wizard's plex.tv/link flow instead.
- Target
- PLEX_TOKEN
Optional declarative setup: comma-separated movie library section ids (e.g. 1,4).
- Target
- PLEX_SECTIONS