Commit graph

4 commits

Author SHA1 Message Date
f25f719e5f Fix the real crash: partyPage.html was missing data-controller
Traced the exact "Cannot read properties of undefined (reading
lifeCycleAbortSignal)" error by fetching the target server's actual
viewmanager.js and pluginmanager.js directly (both are unauthenticated
static JS) instead of guessing further from docs.

Root cause: Emby's modern ViewManager (v4.10.0.40) only creates a
view.controller - required before it calls any lifecycle method on
the view - when the view's root element has a data-controller
attribute resolving to an AMD module via
pluginManager.getConfigurationResourceUrl(). partyPage.html never had
one (only the legacy data-role="page" attribute), so
newView.controller stayed undefined and getResumeOptions crashed
reading a property off it. configPage.html (the admin settings page)
apparently survives without this because dashboard pages go through a
different/older loading path.

Fix: added data-controller="__plugin/WatchPartyRoomController" to
partyPage.html, and a third PluginPageInfo/embedded resource
(partyPageController.js) - a minimal AMD module for it to resolve to.
ViewManager mixes in baseview.js's onResume/onPause/lifeCycleAbortSignal
automatically since this controller doesn't define its own, so it only
needs to exist.

Also checked (live JS probe, not a guess): pluginmanager.js has a
hardcoded plugin-id allowlist (allowPluginPages), but it's bypassed
whenever appHost.supports('restrictedplugins') is falsy - confirmed
falsy here, so it isn't blocking anything on this server's web client.

docs/architecture.md updated with the full trace for posterity.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 20:17:14 +02:00
6f22f72532 Integrate Watch Party into Emby's own UI instead of a standalone app
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>
2026-09-13 19:44:31 +02:00
db815df7d5 Fix plugin to build clean against real Emby 4.9.1.90 SDK
Installed .NET 8 SDK (per-user, winget needed admin elevation this
machine doesn't have) and restored the real MediaBrowser.Server.Core /
MediaBrowser.Common packages, then fixed everything the compiler and
a bit of reflection surfaced:

- PlaybackProgressEventArgs/PlaybackStopEventArgs are in
  MediaBrowser.Controller.Library, not ...Session
- IAuthorizationContext/AuthorizationInfo are in MediaBrowser.Controller.Net
- Item/user/session ids (SessionInfo.Id/UserId, BaseItemDto.Id) are plain
  string on this SDK version, not Guid - Party/PartyMember updated
  accordingly (Party.Id stays a Guid; it's minted by this plugin, not Emby)
- Reading the calling user needed an extra step:
  IAuthorizationContext.GetAuthorizationInfo(Request).UserId is a `long`
  (internal row id); .User.Id is the one matching SessionInfo.UserId,
  but it's a Guid so it's reformatted with .ToString("N")

docs/architecture.md's "Assumptions to verify" now reflects what was
actually confirmed vs. what's still only compile-checked (HTTP status
codes, content-type headers, the JS auth header format, the dashboard
config page) pending a run against a real server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 14:40:17 +02:00
66af05f259 Scaffold Emby Watch Party plugin
Design: coordinate parties on top of Emby's existing session
remote-control commands (SendPlaystateCommand) rather than building a
new player. Each member keeps their own Emby app/controls; the server
periodically corrects drift and mirrors pause/unpause against one
reference member's reported position.

- src/WatchParty: plugin skeleton (BasePlugin, IServerEntryPoint,
  IService/[Route] API, in-memory party store, drift-correction loop)
- web/control-panel: plain HTML/JS/CSS companion page to create/join
  parties and resync, served by the plugin itself
- docs/architecture.md: full design, sources consulted, and an
  explicit list of SDK details that still need verifying against a
  real build (no .NET SDK / Emby SDK assemblies available in this
  environment to compile against)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 14:02:43 +02:00