Skip to content

Bring SyncPlay up to develop + clean the #735 diff (series-queue & pause fixes)#3

Open
JenteJan wants to merge 52 commits into
irican-f:syncplayfrom
JenteJan:syncplay-merge-develop
Open

Bring SyncPlay up to develop + clean the #735 diff (series-queue & pause fixes)#3
JenteJan wants to merge 52 commits into
irican-f:syncplayfrom
JenteJan:syncplay-merge-develop

Conversation

@JenteJan

@JenteJan JenteJan commented Jun 8, 2026

Copy link
Copy Markdown

Heads-up on this PR's size: its own diff is large (~262 files) because it merges ~4 months of develop into syncplay — that is the point. Review it as "bring develop in + conflict resolutions + fixes," not as new SyncPlay code. The payoff is on DonutWare#735: once this merges into syncplay, DonutWare#735's diff to develop drops from 312 → ~91 files (SyncPlay-only), which is what PartyDonut asked for.

What this does

Brings syncplay up to current develop and shrinks the DonutWare#735 diff to only SyncPlay-related changes, addressing PartyDonut's latest review ("re-base it on develop, make sure all the changes are related to the sync-play functionality").

Net effect on the DonutWare#735 diff: 312 → ~91 files.

How it gets there

  • Merge develop into syncplay — resolves the divergence from the music rework etc. (conflicts resolved; see "Conflicts to sanity-check" below).
  • Regenerate all codegen against the develop toolchain — removes generated-file drift. Non-SyncPlay .g/.freezed/.mapper files (account, credentials, boxset, …) now match develop exactly and drop out of the diff (108 → 34 generated files, the remaining 34 are SyncPlay's own models).
  • Revert formatting-only churn in unrelated files (import order / wrapping / blank lines) so they stop showing as changes.

Fixes included

  • Series queue + resume on initiate (my earlier PR fix(syncplay): send full series queue and resume position on initiate #2, folded in): _playSyncPlay now sends the full series queue with the correct playingItemPosition + resume position, instead of a lone single-episode queue — official clients (web/webOS) wouldn't start the single-item queue. Also fixes "Continue Watching restarts at 0".
  • Desktop play/pause fired twice: the develop merge left both syncplay's onTap → userPlayOrPause and develop's new onHorizontalDragDown → playOrPause, so a desktop click toggled twice (mouse-pause "resumed"). Restored develop's gesture design (onTap null for pointer, drag handler does play/pause, wired to userPlayOrPause).

Review nits (from PartyDonut) also addressed

  • l10n: =1one plural category for syncPlayParticipants.
  • Removed docs/syncplay-implementation.md.

(Formatting/logging/pubspec-grouping nits were already done on syncplay.)

Conflicts to sanity-check (SyncPlay behaviour not fully regression-tested)

  • video_player_provider.loadPlaybackItem: kept your SyncPlay flow (waitForSyncPlayCommand, buffering/ready reports, stop-suppression, no-autoplay-during-sync) and folded in develop's useMinimizedPlayer + resolvedStartPosition (resume gated to non-SyncPlay loads so the group position wins).
  • media_control_wrapper.stateStream: took develop's _stateController redesign (non-null stream, survives player swaps) + kept your isNativePlayerActive/updateSyncPlayCommandState.
  • Re-applied userPlayOrPause to develop's new *_bar_content widgets + audio full screen.

Verified: compiles + flutter analyze clean on macOS, play/pause works. Did not run a full multi-client SyncPlay regression.

Merge vs rebase

This is a merge (not a literal rebase), but the Files-Changed diff — what gets reviewed — is the clean SyncPlay-only set. If PartyDonut specifically wants linear history, that's a separate rebase of the ~61 commits for the same review result.

Merge this into syncplay and DonutWare#735 updates automatically.

PartyDonut and others added 30 commits May 31, 2026 14:51
Currently translated at 100.0% (942 of 942 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/it/
Currently translated at 100.0% (942 of 942 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/zh_Hans/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/zh_Hans/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/ru/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/ar/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pl/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pl/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/de/
Currently translated at 98.1% (927 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt_BR/
Currently translated at 99.7% (942 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt_BR/
Currently translated at 97.7% (923 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt/
Currently translated at 99.8% (943 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/fa/
Currently translated at 99.8% (943 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/fa/
Currently translated at 99.8% (943 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/fa/
Currently translated at 99.8% (943 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt_BR/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/es/
Currently translated at 100.0% (944 of 944 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pl/
Currently translated at 99.7% (944 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/ru/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/de/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/ar/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/zh_Hans/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pl/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/id/
Currently translated at 99.3% (940 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt/
Currently translated at 99.3% (940 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/pt/
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/ru/
anuchainitdz-droid and others added 22 commits May 31, 2026 13:25
Currently translated at 100.0% (946 of 946 strings)

Translation: DonutWare/Fladder
Translate-URL: https://hosted.weblate.org/projects/fladder/fladder/nl/
Co-authored-by: Met <arcker95@gmail.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Co-authored-by: majorro <majorrowk@gmail.com>
Co-authored-by: Abdullah Khaled <dratiux@gmail.com>
Co-authored-by: Mateusz Lesiak <mateusz.lesiak01@gmail.com>
Co-authored-by: PhillyMay <mein.alias@outlook.com>
Co-authored-by: Tio <guilhermesilveira2007@gmail.com>
Co-authored-by: LibreTranslate <noreply-mt-libretranslate@weblate.org>
Co-authored-by: Aryan Moradi <aryanmoradi74@gmail.com>
Co-authored-by: Sergio Suarez <s.suarerez@gmail.com>
Co-authored-by: Arif Budiman <arifpedia@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: darkzoul5 <mihailv@inbox.lv>
Co-authored-by: Anucha Hlownonkor <anucha.initdz@gmail.com>
Co-authored-by: Hosted Weblate user 152666 <jobjuhh@users.noreply.hosted.weblate.org>
Co-authored-by: alex <alex@metasig.com.br>
Brings the SyncPlay feature branch up to current develop (46 develop
commits). Conflict resolutions of note (please review the flagged ones):

- Login widgets deleted by develop's login refactor: accepted deletion
  (unreferenced; syncplay only edited the old structure).
- play_item_helpers: kept develop's loading-dialog close + syncplay's
  diagnostic logs (union).
- media_control_wrapper: kept develop's _stateController/_previousPlayer
  state-stream redesign (non-null stateStream) AND syncplay's
  isNativePlayerActive/updateSyncPlayCommandState.
- video_player_provider.loadPlaybackItem: rewrote to keep syncplay's
  SyncPlay flow (waitForSyncPlayCommand, buffering/ready reports,
  stop-suppression, no-autoplay-during-sync) and fold in develop's
  useMinimizedPlayer + resolvedStartPosition (resume gated to
  non-SyncPlay loads).
- stateStream listener adapted to develop's non-null stream, keeping
  syncplay's user-action inference.
- Re-applied syncplay's userPlayOrPause to develop's new bar-content
  widgets (music/video bar, audio full screen, desktop drag).
- client_settings_model generated files regenerated from merged source.

Compiles + flutter analyze clean. SyncPlay behaviour not runtime-verified.
When starting playback in a SyncPlay group, _playSyncPlay sent a
single-item queue (PlayingQueue: [itemId], position 0, startPositionTicks
0). This broke playback for other participants, notably the official
Jellyfin clients (e.g. the webOS TV app):

- Episodes never started on other clients. The official client queues the
  whole series (with PlayingItemPosition pointing at the chosen episode);
  a lone single-episode queue is not started by those clients. Movies,
  being naturally single-item, worked - which made the bug look
  movie-vs-episode specific.
- The resume position was dropped. Continue Watching restarted the group
  from 0:00 because startPositionTicks fell back to 0 whenever no explicit
  startPosition was passed. The local playback path resolves this via
  model.startDuration(); the SyncPlay path did not.

Mirror the local playback path: build the queue via collectQueue (full
series for an episode/series/season, empty for a movie), resolve
Series/Season to their next-up episode, send the whole series with the
correct playingItemPosition, and fall back to the resolved item's saved
resume position.

Also document the matching cross-client regression scenarios per the
SyncPlay regression checklist (AGENTS.md rule 10).
The merge kept syncplay's onTap->userPlayOrPause AND develop's
onHorizontalDragDown->userPlayOrPause, so one desktop click toggled
play/pause twice (Pause immediately followed by Unpause), making
mouse-pause appear to resume. Restore develop's gesture design: pointer
onTap is null; onHorizontalDragDown handles play/pause (single fire).
Removes generated-file drift so the PR diff shows only SyncPlay-related
changes (per maintainer review on DonutWare#735). Non-SyncPlay generated files
(account/credentials/boxset/etc.) now match develop and drop out of the diff.
Revert files that syncplay only reformatted (import order, wrapping,
blank lines) with no functional change, so the PR diff contains only
SyncPlay-related changes (per maintainer review on DonutWare#735).
- l10n: use 'one' plural category instead of '=1' for syncPlayParticipants
  (matches existing conventions, per review).
- Remove docs/syncplay-implementation.md (LLM scratch doc, per review).
JenteJan added a commit to JenteJan/Fladder that referenced this pull request Jun 16, 2026
…can-f#3 DonutWare#10 DonutWare#4)

- DonutWare#9 connect() tears down the active session before switching, so e.g.
  AirPlay is actually stopped before Chromecast starts.
- #2 DlnaPlayer sends UPnP Stop on dispose so the TV session closes on
  disconnect.
- irican-f#3 DLNA play/pause are optimistic (snappy UI) behind a short command guard,
  after which the poll is authoritative again — so play/seek done on the TV
  itself is reflected on the client.
- DonutWare#10 external-end handling generalized: DLNA poll detects STOPPED/NO_MEDIA or
  an unreachable renderer; a native Chromecast session-disconnect listener
  (guarded to chromecast sessions) restores local playback when the receiver
  is taken over or turned off. (web SESSION_ENDED already covered.)
- Responsiveness: connecting/disconnecting states with the target name; picker
  shows progress and disables tiles during transitions.
- DonutWare#4 device tiles keyed by id so the tap ripple lands on the tapped row.
JenteJan added a commit to JenteJan/Fladder that referenced this pull request Jun 16, 2026
AirPlay played whatever track the initial transcode picked and couldn't switch.
Now selecting an audio/subtitle track rebuilds the HLS transcode with that track
(subtitle burned in — AVPlayer over HLS shows that most reliably) and reloads at
the current position. _airplayStreamUrl takes the track indices + mediaSourceId.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.