watchparty/src/WatchParty/Parties/PartyMember.cs
Nicolas 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

52 lines
1.7 KiB
C#

using System;
namespace WatchParty.Parties
{
public class PartyMember
{
public Guid UserId { get; set; }
public string UserName { get; set; }
/// <summary>
/// The Emby session this member is watching from. Resolved at join time
/// from the caller's active sessions - see
/// docs/architecture.md#which-session-is-mine for the current, fairly
/// blunt, v1 heuristic.
/// </summary>
public string SessionId { get; set; }
public DateTime JoinedUtc { get; set; }
/// <summary>Last position reported for this member, in ticks (100ns units, Emby convention).</summary>
public long LastKnownPositionTicks { get; set; }
public bool LastKnownIsPaused { get; set; }
/// <summary>When LastKnownPositionTicks/LastKnownIsPaused were last updated.</summary>
public DateTime LastUpdatedUtc { get; set; }
/// <summary>When we last sent this member a corrective command, for cooldown purposes.</summary>
public DateTime? LastResyncUtc { get; set; }
/// <summary>
/// Extrapolates where this member's playback should be *right now*,
/// assuming unchanged play/pause state since LastUpdatedUtc.
/// </summary>
public long EstimatedPositionTicks(DateTime utcNow)
{
if (LastKnownIsPaused)
{
return LastKnownPositionTicks;
}
var elapsed = utcNow - LastUpdatedUtc;
if (elapsed <= TimeSpan.Zero)
{
return LastKnownPositionTicks;
}
return LastKnownPositionTicks + elapsed.Ticks;
}
}
}