Skip to content

fix: play synced items without a reachable server (#970)#1022

Open
aviadlevy wants to merge 1 commit into
DonutWare:developfrom
aviadlevy:fix/970-offline-synced-playback
Open

fix: play synced items without a reachable server (#970)#1022
aviadlevy wants to merge 1 commit into
DonutWare:developfrom
aviadlevy:fix/970-offline-synced-playback

Conversation

@aviadlevy

@aviadlevy aviadlevy commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Resolve sync status and connectivity before the server item-fetch in createPlaybackModel, via a new pure useLocalSyncedCopy predicate. When offline, skip the server and play the local synced copy immediately. Otherwise bound the fetch with a 5s timeout and fall back to the local copy when the server is unreachable (e.g. LAN-only server while on cellular). Online, server-reachable behavior is unchanged.

Fixes #970
Fixes #713

Pull Request Description

Playing synced items previously always contacted the server before checking whether the item was available locally. createPlaybackModel awaited usersUserIdItemsItemIdGet unconditionally, and that call masks failures internally (returning the local item only after the underlying request hangs to its OS socket timeout). The result: browsing and playing synced content while the server was unreachable was very slow, which is the core complaint in #970.

Behavior

  • Playing a synced item no longer needs the server. When the device is offline, playback starts directly from the local file with no server round-trip.
  • When there is a network but the server is unreachable (e.g. a LAN-only server while commuting on cellular), the server item-fetch is bounded by a 5s timeout and falls back to the local copy.
  • Auto-advance to the next synced episode goes through the same path, so it no longer hangs offline either.
  • Online with a reachable server is unchanged — the existing quality-selection dialog (Direct Stream / Transcode / Offline) still appears for synced items, and non-synced playback is untouched.

Implementation

  • lib/models/playback/playback_model.dart: createPlaybackModel now resolves the synced item and connectivity before the server fetch. A new pure predicate useLocalSyncedCopy({required bool isSynced, required bool serverReachable}) (isSynced && !serverReachable) centralizes the source decision and is unit-tested in isolation. The fetch is wrapped with a 5s .timeout(...) (matching the existing reachability-check value) and falls back to the local copy when the server can't be reached.
  • The previously-duplicated synced-item lookup was removed; the lookup is now keyed on firstItemToPlay.id so a series/season resolves its actual resume episode.
  • test/models/playback/playback_model_test.dart: 4 unit tests for the predicate.

The "re-sync offline progress when back online" behavior already exists (SyncNotifier reacts to connectivity returning and flushes pending user-data), so no change was needed there.

Implementation notes

Implemented with the help of an AI coding assistant (Claude Code); all decisions, trade-offs, and review were human-driven. Generated code follows the project's conventions.

Issue Being Fixed

Resolves #970

Synced shows/movies load very slowly when the server isn't reachable because the app tries to contact the server before falling back to the local copy. This PR removes that dependency for synced playback. (The issue also mentions watch-history not advancing offline; offline progress is saved locally and pushed on reconnect via the existing sync path — worth confirming during testing.)

Screenshots / Recordings

Tested On

  • Android
  • Android TV
  • iOS
  • Linux
  • Windows
  • macOS
  • Web

(but this change applicable for all who supporting offline sync)

Checklist

  • If a new package was added, did you ensure it works for all supported platforms? Is the package well maintained — no new packages added.
  • Check that any changes are related to the issue at hand.

Resolve sync status and connectivity before the server item-fetch in
createPlaybackModel, via a new pure useLocalSyncedCopy predicate. When
offline, skip the server and play the local synced copy immediately.
Otherwise bound the fetch with a 5s timeout and fall back to the local
copy when the server is unreachable (e.g. LAN-only server while on
cellular). Online, server-reachable behavior is unchanged.

Fixes DonutWare#970
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.

Offline Synced data loading time very slow 🐛 Offline playback not working on android

1 participant