Per user feedback: no separate control panel, no chat. Found that PluginPageInfo has EnableInUserMenu/EnableInMainMenu (confirmed via reflection on the real MediaBrowser.Model assembly, plus an Emby community thread showing another plugin using EnableInUserMenu=true) - a real, if barely documented, way to surface a plugin page to regular users, not just admins, through the exact same IHasWebPages/GetPages() mechanism as the admin settings page. - Plugin.cs now registers a second page (partyPage.html) with EnableInUserMenu=true + EnableInMainMenu=true - partyPage.html replaces the old standalone control panel: no login form, it runs inside the already-authenticated Emby web client and calls the REST API via the global ApiClient - Removed web/control-panel/ (the standalone app, its own login flow, and the custom GET /WatchParty/app* static file routes in WatchPartyService.cs) - no longer needed - docs/architecture.md and README.md updated: the new mechanism, and the honest limitation that comes with it (reaches Web/Electron clients, not official mobile/TV apps - those allowlist plugin pages client-side) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
98 lines
4.2 KiB
Markdown
98 lines
4.2 KiB
Markdown
# Watch Party for Emby
|
|
|
|
An Emby Server plugin that lets a group of users on the same server watch the
|
|
same title together. Nobody switches players: everyone keeps using their
|
|
normal Emby app (web, mobile, TV, whatever), and the plugin nudges playback
|
|
back in sync using the same remote-control commands Emby already uses for
|
|
casting / "play on another device".
|
|
|
|
See [docs/architecture.md](docs/architecture.md) for the full design,
|
|
including which parts are solidly confirmed against Emby's SDK docs and which
|
|
still need verification against your exact server build.
|
|
|
|
## How it's meant to work
|
|
|
|
1. You start playing a title in your normal Emby app.
|
|
2. In Emby's web client (or the Electron desktop app), open **Watch Party**
|
|
from the menu and start a party. You get a 6-character join code. No
|
|
separate login — it's a real page inside Emby, using your existing session.
|
|
3. Friends open the same **Watch Party** menu item, start playing the *same*
|
|
title in their own Emby app, and enter the code to join.
|
|
4. The server treats one member (the host, by default) as the reference
|
|
position, and periodically nudges everyone else's session back in sync
|
|
(seek correction, and mirroring pause/unpause) — see
|
|
[docs/architecture.md](docs/architecture.md#sync-algorithm).
|
|
|
|
The Watch Party page is a companion panel, not a video player — it never
|
|
touches the actual video stream, playback stays in your normal Emby app.
|
|
|
|
**Known limitation**: the menu item shows up on Web and Electron clients.
|
|
Official mobile/TV apps don't surface arbitrary plugin pages, so Watch Party
|
|
won't appear there — see [docs/architecture.md](docs/architecture.md#components).
|
|
|
|
## Status
|
|
|
|
Builds clean (0 errors, 0 warnings) against the real `MediaBrowser.Server.Core`
|
|
/ `MediaBrowser.Common` 4.9.1.90 assemblies from NuGet, and is installed on a
|
|
real Emby Server (Docker) — the plugin loads and its admin page shows up.
|
|
The actual feature (`partyPage.html`, reached via `EnableInUserMenu`) hasn't
|
|
been exercised live yet. See
|
|
[docs/architecture.md](docs/architecture.md#assumptions-to-verify) for
|
|
exactly what was wrong on the first guess, what was fixed, and what's still
|
|
open.
|
|
|
|
## Requirements
|
|
|
|
- Emby Server (developed against 4.9.5.0; should work on nearby 4.9.x/4.8.x
|
|
builds, but the plugin ABI does shift between versions)
|
|
- [.NET SDK](https://dotnet.microsoft.com/download) 8.0 to build (installed
|
|
per-user under `%USERPROFILE%\.dotnet` in this environment, since the
|
|
machine-wide winget install needed admin elevation that wasn't available —
|
|
see git history if you need to redo this on another machine)
|
|
|
|
## Project layout
|
|
|
|
```
|
|
src/WatchParty/ the plugin itself (C#, netstandard2.0)
|
|
Plugin.cs plugin registration + both plugin pages
|
|
Configuration/ plugin settings, the admin settings page, and
|
|
partyPage.html - the actual user-facing feature,
|
|
integrated into Emby's own menu (not a separate app)
|
|
Parties/ Party / PartyMember model + in-memory PartyManager
|
|
Sync/ the drift-correction background loop
|
|
Api/ REST endpoints, called from partyPage.html
|
|
docs/architecture.md full design doc
|
|
```
|
|
|
|
## Building
|
|
|
|
```bash
|
|
dotnet build src/WatchParty/WatchParty.csproj
|
|
```
|
|
|
|
To have a build drop the DLL straight into a local Emby Server's plugin
|
|
folder, set `EMBY_PLUGINS_DIR` before building, e.g.:
|
|
|
|
```bash
|
|
EMBY_PLUGINS_DIR="C:/ProgramData/Emby-Server/programdata/plugins" dotnet build src/WatchParty/WatchParty.csproj
|
|
```
|
|
|
|
Adjust the path for however your server is installed (Windows service vs.
|
|
portable install vs. Docker volume).
|
|
|
|
## Roadmap
|
|
|
|
- [x] Design doc + scaffold
|
|
- [x] Build against the real SDK, fix whatever the `TODO(verify)` spots got wrong
|
|
- [x] Install on a real Emby Server (Docker)
|
|
- [x] Integrate into Emby's own UI instead of a standalone web app
|
|
(`EnableInUserMenu` — see [docs/architecture.md](docs/architecture.md#components))
|
|
- [ ] Try a full party end-to-end with two accounts
|
|
- [ ] Live (WebSocket) updates in the party page instead of polling
|
|
- [ ] Per-party override of sync settings instead of only server-wide defaults
|
|
|
|
No chat/reactions — deliberately out of scope, not just deferred.
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE).
|