# Changelog All notable changes to Emby Watch Party will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Each release has a short user-facing summary on top and a longer **Technical details** section underneath for anyone who wants the full story. ### Special Thanks Special thanks to **[QuackMasterDan](https://emby.media/community/index.php?/profile/1658172-quackmasterdan/)** for his dedication in testing and providing valuable feedback throughout development! Thanks to **[wlowen](https://github.com/wlowen)** and **[JeslynMcKenzie](https://github.com/JeslynMcKenzie)** for testing, detailed bug reports, and providing mediainfo that helped track down the HEVC transcoding issues! Thanks to **[Christian Gillinger](https://github.com/cgillinger)** for the "Refined Cyber" design language that the 2.0 visual refresh is built on -- the cyan/magenta/violet palette, glass surface treatment, chip/pill control language, animated LIVE badge, and centred system-message pill in chat all come from his mockup. --- ## [2.0.1] - 2026-07-14 - Midnight Premiere A patch release focused on playback control and sync. In 2.0.0 only the host / video selector could play, pause, or seek; everyone else's controls silently did nothing. 2.0.1 makes control **democratic**: any member of the party can play, pause, seek, and skip the intro, and it syncs to the whole room. If one person pauses, everyone pauses -- the way a watch party is meant to work. The library panel also now closes for everyone when a video is picked, and the host's Hide/Show Library button once again follows on every client. The harder part was doing this without the room dissolving into a pause-storm. The old selector-only gate had quietly been absorbing every client's *synthetic* playback events (buffering pauses, HLS re-alignment seeks, stall-recovery nudges), so opening control to everyone surfaced a class of browser-noise bugs that had been masked for two years. Those guards are now re-established client-side, decoupled from the access model, so shared control and clean sync coexist. ### Changed - **Playback control is now democratic, not selector-only.** `_authorized_controller` was relaxed from a selector/host gate to a plain party-membership check: any joined member may drive play / pause / seek, and it broadcasts to the whole room. A stray / non-member socket (no registered `client_id`) is still rejected. This deliberately loosens the selector-only gate added during the 2.0.0 security audit -- shared control is the intended watch-party experience for a private, code-gated party. Seek stutter-loops remain guarded by the existing ready-check handshake, independent of who initiates the seek. - **Library visibility syncs across the party.** Picking a video now closes the library for **every** client (via the symmetric `currentVideo` watcher), not just the picker's own screen. The `toggle_library` client listener dropped in the Vue rewrite is restored, so the host's Hide / Show Library button once again follows on every client -- the server was already broadcasting it to no listener. ### Fixed - **"Something keeps pausing right after anyone hits play."** The play handler's stall-recovery nudge fires at 1000 ms, but the `isSyncing` guard that suppresses synthetic seeks was released at 500 ms. So the recovery's `hls.stopLoad()`/`startLoad()` re-seek dispatched a native `seeking` event that the player forwarded as a *user* seek, which the server's "seek during playback" path answered by force-pausing the whole room. A self-inflicted loop on the initiator's own client -- latent since the 2.0 rewrite, but unmasked once democratic control let every client's events reach the room. The stall-recovery re-seek is now wrapped in `isSyncing` so its synthetic events are swallowed. Diagnosed live from DEBUG server logs. - **Buffering no longer pauses the party.** Under democratic control, a client whose HLS stream stalls fires a native `pause` that would broadcast to everyone. A genuine user pause leaves the element fully buffered (`readyState >= 3`); a stall drops below it. The pause emit is now suppressed while buffering, so one person's connection hiccup can't pause the room. - **Spectator desync self-corrects.** A resume-only heartbeat safety net re-asserts the authoritative play state when a client's `