# Watch Party for Emby A standalone web app for watching the same title, in sync, with other users of the same Emby server. It reads your Emby catalog and streams your Emby media, but it's its own app with its own player — not an Emby plugin. See [docs/architecture.md](docs/architecture.md) for the full design, including why this replaced an earlier Emby-plugin attempt (still in [src/WatchParty/](src/WatchParty/) for reference — see below). ## How it works 1. Sign in with your Emby account (just username/password — the server address is fixed server-side, see Deploying below). 2. A sidebar lists your Emby libraries; the home page shows every ongoing watch party plus a "recently added" row per library, Emby-style. 3. Pick a movie/episode tile and hit "Lancer une watch party" (or drill into a Series' seasons/episodes first) — you become the host — or join one with a 6-character code. 4. The host's play/pause/seek drives everyone else's player automatically; starting from an episode queues the rest of the series so the host can just hit "Épisode suivant" instead of restarting a party each time. Everything — catalog, images, video, sync — flows through this app's own backend, which proxies whatever it needs from Emby server-side. The browser never talks to Emby directly and never holds an Emby access token; it only ever has a session cookie for this app. Music isn't part of this yet — it needs its own player and a collaborative playlist, different enough to be its own pass. The sidebar already lists a Music library if you have one; the page just says so for now. ## Status Login, and the rendering/navigation logic for the sidebar/home/library/series pages, have been exercised end to end (login against the real Emby server with intentionally-wrong credentials; the pages against mocked API responses). See [docs/architecture.md](docs/architecture.md#assumptions-to-verify) for exactly what that does and doesn't confirm — the real Emby response shapes this now depends on (library `CollectionType`, seasons/episodes, `PlaybackInfo`'s media streams) and actual HLS playback are still unverified. ## Project layout ``` server/ Node.js backend: proxies ALL Emby access (auth, catalog, images, HLS streaming) and coordinates party/room state + realtime sync. The browser only ever talks to this. src/index.js Express app + REST endpoints src/embyAuth.js server-side login against Emby + session cookies src/embyProxy.js generic Emby request/response proxying (incl. HLS) src/socketHandler.js Socket.IO protocol (see comments in the file) src/partyManager.js in-memory room state client/ Static frontend (plain JS, ES modules, no build step). Talks only to server/ - never to Emby directly. js/shell.js persistent sidebar + #mainContent the router swaps js/tiles.js poster-tile rendering shared by home.js and library.js js/embyApi.js calls our own /api/* routes (auth, catalog, playback options) js/party.js our own backend's party REST + Socket.IO client js/views/ one file per screen: login, home, library, series, player src/WatchParty/ The earlier Emby-plugin attempt. Builds fine and installs, but Emby has no supported extension point for a player button, and even menu integration required reverse- engineering undocumented internals - see docs/architecture.md for the full story. Kept for reference; not the active direction. docs/architecture.md full design doc for the standalone app ``` ## Running locally ```bash cd server npm install EMBY_SERVER_URL=https://your-emby-server npm start ``` Then open `http://localhost:3000`. ## Deploying Build the Docker image from the **repo root** (it needs both `server/` and `client/`): ```bash docker build -f server/Dockerfile -t watchparty . docker run -d --name watchparty -p 3000:3000 -e EMBY_SERVER_URL=https://theater.media.kyuno.fr watchparty ``` Then put it behind your existing reverse proxy like everything else (`theater.media.kyuno.fr`, `git.dev.kyuno.fr`, ...), e.g. `watchparty.kyuno.fr` → `http://:3000`. ## Roadmap - [x] Design + scaffold the standalone app - [x] Proxy all Emby access server-side; Emby-themed UI (sidebar, carousels) - [x] TV show navigation (Series → Seasons → Episodes) + episode auto-queue - [x] Player language/subtitle/quality pickers - [x] Socket.IO instead of raw WebSockets; fixed two real memory leaks (dead-connection cleanup server-side, view teardown on navigation client-side) — see docs/architecture.md - [ ] Try a full party end-to-end with two real accounts (still the main gap) - [ ] Music: dedicated player, artist/album browsing, collaborative playlist - [ ] Tune transcoding target / support direct play when possible No chat, no OIDC — deliberately out of scope (Emby-only auth was the explicit choice; see docs/architecture.md). ## License MIT — see [LICENSE](LICENSE).