Skip to content

Plex Connect: refactor and fixes plugin#3510

Open
anatosun wants to merge 8 commits intomusic-assistant:devfrom
anatosun:refactor/plex-connect-v2
Open

Plex Connect: refactor and fixes plugin#3510
anatosun wants to merge 8 commits intomusic-assistant:devfrom
anatosun:refactor/plex-connect-v2

Conversation

@anatosun
Copy link
Copy Markdown
Contributor

This PR refactors the Plex Connect plugin and fixes several issues encountered during
testing.

Refactor

The monolithic player_remote.py has been split into focused modules for better
readability and easier contributions:

  • server.py — HTTP server setup and shared state
  • timeline.py — Plex timeline XML generation and broadcasting
  • playback.py — Playback control handlers (play, pause, seek, skip, etc.)
  • queue_commands.py — Play queue command handlers (playMedia, createPlayQueue,
    refreshPlayQueue)
  • queue_sync.py — Queue synchronisation between MA and Plex

The plugin stage has also been updated from alpha to beta.

Bug fixes

  • Infinite loop on refreshPlayQueue: the refreshPlayQueue handler was missing the
    _updating_from_plex guard, causing a loop when features like Guest DJ were used.
  • Play queue truncated at 50 items: the default Plex API window of 50 was used when
    fetching play queues. The fetch now paginates through the full queue using
    playQueueTotalCount.
  • Queue ownership: own=True is now passed on the initial PlayQueue.get() call so MA
    takes full control of the queue.
  • Shuffle not propagated to Plex: toggling shuffle from Plexamp now triggers a
    _create_plex_playqueue_from_ma call to sync the new order back.
  • Double-shuffle on shuffled Plex queues: when a shuffled PlayQueue is loaded, the
    original source is now fetched via playQueueSourceURI and loaded into MA in its
    natural order. MA then applies its own shuffle and propagates the result back to
    Plex, avoiding double-shuffling an already-shuffled list.
  • Stale MA shuffle corrupting unshuffled queues: the shuffle state is now always
    explicitly synced from Plex on every playMedia command, preventing a previously
    enabled MA shuffle from silently reordering a non-shuffled queue.

handle_refresh_play_queue was missing the _updating_from_plex guard that
all other command handlers use. Without it, any queue refresh from Plex
would modify the MA queue, triggering _handle_queue_items_updated, which
would recreate the Plex PlayQueue, causing another refreshPlayQueue — an
infinite loop. The stale PlayQueue 404 errors were also a symptom of this.
Addresses style fixes and better segregation of functionalities to make
the plugin easier to maintain and for others to contribute to.

The monolithic player_remote.py is split into focused modules:

- server.py         — core HTTP server, routing, lifecycle
- timeline.py       — timeline XML building and broadcasting
- playback.py       — playback control command handlers
- queue_commands.py — play queue HTTP command handlers
- queue_sync.py     — background queue loading and MA↔Plex sync logic

Also promotes the plugin stage from alpha to beta, and fixes several
bugs discovered during the refactor: a missing _updating_from_plex guard
in handle_create_play_queue, a race condition in background queue loading,
and shuffle changes not being synced back to the Plex play queue.
Replace direct PlayQueue.get() calls with a _fetch_full_play_queue helper
that paginates past the Plex server's per-request cap (~200 items).

The helper claims ownership of the queue (own=True) on the first fetch,
then uses center + includeBefore=False to walk forward page by page until
playQueueTotalCount items have been collected.
Remove the unconditional set_shuffle(False) in handle_refresh_play_queue
(it was a workaround for the old infinite-loop bug, now fixed) and replace
it with a sync of playqueue.playQueueShuffled after the queue is loaded.

_play_from_plex_queue also now uses playqueue.playQueueShuffled as the
authoritative shuffle state, falling back to the request parameter.
When a Plex play queue is flagged as shuffled, fetch the original source
collection via playQueueSourceURI, load it into MA in its natural order,
then apply MA's own shuffle and propagate the resulting order back to Plex
via a new PlayQueue. This avoids double-shuffling an already-shuffled list.

Also ensure MA shuffle is always explicitly synced to the Plex queue's
shuffle state on playMedia, so a leftover enabled shuffle cannot silently
reorder a non-shuffled queue.
Copilot AI review requested due to automatic review settings March 30, 2026 15:19
@github-actions
Copy link
Copy Markdown
Contributor

🔒 Dependency Security Report

✅ No dependency changes detected in this PR.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Plex Connect plugin by splitting the former monolithic player_remote.py into smaller modules, while also addressing play-queue sync issues (pagination, ownership, shuffle propagation, and refresh-loop protection).

Changes:

  • Split remote-control server responsibilities into focused modules (server, timeline, playback, queue_commands, queue_sync) and removed player_remote.py.
  • Improved Plex PlayQueue handling (pagination past server window caps, own=True initial fetch, shuffle/source handling).
  • Updated plugin stage to beta and adjusted imports to use the new module layout.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
music_assistant/providers/plex_connect/timeline.py Builds/broadcasts Plex timeline XML and posts timeline updates to controllers/server.
music_assistant/providers/plex_connect/server.py New per-player HTTP server wiring/routes and MA event subscriptions.
music_assistant/providers/plex_connect/queue_sync.py MA↔Plex queue synchronization and MA event handlers.
music_assistant/providers/plex_connect/queue_commands.py Implements Plex play queue HTTP commands and full-queue fetching/pagination.
music_assistant/providers/plex_connect/playback.py Implements playback control endpoints (play/pause/seek/skip/etc.).
music_assistant/providers/plex_connect/init.py Switches provider import to the new server.PlayerRemoteInstance.
music_assistant/providers/plex_connect/manifest.json Moves plugin stage from alpha to beta.
music_assistant/providers/plex_connect/player_remote.py Removed (functionality replaced by the new split modules).

Comment thread music_assistant/providers/plex_connect/queue_sync.py
Comment thread music_assistant/providers/plex_connect/timeline.py
Comment thread music_assistant/providers/plex_connect/timeline.py
Comment thread music_assistant/providers/plex_connect/server.py
Comment thread music_assistant/providers/plex_connect/playback.py
Comment thread music_assistant/providers/plex_connect/queue_sync.py
Comment thread music_assistant/providers/plex_connect/queue_sync.py
@anatosun anatosun marked this pull request as draft March 30, 2026 16:16
@anatosun anatosun marked this pull request as draft March 30, 2026 16:16
@OzGav OzGav added the bugfix label Apr 21, 2026
@anatosun anatosun marked this pull request as ready for review May 3, 2026 09:13
Copilot AI review requested due to automatic review settings May 3, 2026 09:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Comment thread music_assistant/providers/plex_connect/playback.py
Comment thread music_assistant/providers/plex_connect/queue_commands.py
Comment thread music_assistant/providers/plex_connect/queue_sync.py
Comment thread music_assistant/providers/plex_connect/queue_sync.py
Comment thread music_assistant/providers/plex_connect/server.py
@OzGav OzGav added dependencies-reviewed Indication that any added or modified/updated dependencies on a PR have been reviewed labels May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix dependencies-reviewed Indication that any added or modified/updated dependencies on a PR have been reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants