Skip to content

fix(android): skip addon stream warmup when prepare links is off#1303

Open
DynamycSound wants to merge 1 commit into
NuvioMedia:cmp-rewritefrom
DynamycSound:fix/warmup-respect-prepare-links
Open

fix(android): skip addon stream warmup when prepare links is off#1303
DynamycSound wants to merge 1 commit into
NuvioMedia:cmp-rewritefrom
DynamycSound:fix/warmup-respect-prepare-links

Conversation

@DynamycSound

Copy link
Copy Markdown
Contributor

Summary

With "Resolve playable links" enabled but "Prepare links" turned off (links-to-prepare count = 0), opening a movie/episode details page still fired stream requests to every enabled add-on. This PR makes the ahead-of-time add-on stream warmup respect the "Prepare links" setting, so no add-on requests are sent on the details page until the user presses Play.

Why

AddonStreamWarmupRepository warms add-on streams on the details screen (MetaDetailsScreen calls AddonStreamWarmupRepository.preload(...) in a LaunchedEffect). Its only purpose is to feed DirectDebridStreamPreparer.prepare(), which prepares debrid links ahead of playback.

DirectDebridStreamPreparer.prepare() already early-returns when the prepare-links limit is 0:

val limit = settings.instantPlaybackPreparationLimit
if (!settings.canResolvePlayableLinks || limit <= 0) return

But the warmup gate (AddonStreamWarmupRepository.currentKey) only checked canResolvePlayableLinks and the TorBox key — it never checked instantPlaybackPreparationLimit. So with "Prepare links" disabled, the warmup still queried every enabled add-on for streams on details-page open, then handed them to a preparer that immediately did nothing. This produces premature add-on requests, and pressing Play shortly after opening the page issues a second, duplicate stream request (the warmup fetch plus the streams-screen fetch), hammering indexers twice.

The "Prepare links" setting description states "Resolve playable links before playback starts," and its warning explicitly documents that "opening a movie or episode can count toward those limits even if you do not press Watch, because the links are prepared ahead of time." Disabling it should therefore stop all ahead-of-time work, including the add-on warmup.

The fix adds a DebridSettings.instantPlaybackPreparationEnabled property (canResolvePlayableLinks && instantPlaybackPreparationLimit > 0) — mirroring the gate DirectDebridStreamPreparer.prepare() already enforces — and makes the warmup gate use it. The warmup-cache consumers (StreamsRepository, PlayerStreamsRepository) already treat a missing warmup cache as a normal cache miss (.orEmpty() → loading placeholders), so disabling the warmup simply falls back to fetching streams when the user opens the stream list.

Issue or approval

Fixes #1299

UI / behavior impact

  • No UI change
  • No behavior change
  • UI changed only to fix a documented glitch/bug
  • Behavior changed only to fix a documented bug/regression
  • UI change has explicit maintainer approval
  • Behavior change has explicit maintainer approval

Policy check

  • I have read and understood CONTRIBUTING.md.
  • This PR is small, focused, and limited to one problem.
  • This PR is not cosmetic-only.
  • Any UI change fixes a linked glitch/bug and includes visual proof, or this PR has no UI change.
  • Any behavior change fixes a linked bug/regression or has explicit approval, or this PR has no behavior change.
  • This PR does not bundle unrelated refactors, cleanups, formatting, or drive-by changes.
  • This PR does not add dependencies, architecture changes, migrations, or product-direction changes without explicit approval.
  • I listed the testing performed below.

UI polish, cosmetic-only changes, minor behavior tweaks, and unapproved product changes will be closed without review.

PR type

  • Reproducible bug fix
  • UI glitch/bug fix
  • Behavior bug/regression fix
  • Small maintenance only, with no UI or behavior change
  • Docs accuracy fix
  • Translation/localization only
  • Approved larger or directional change

Scope boundaries

  • composeApp/src/commonMain/kotlin/com/nuvio/app/features/debrid/DebridSettings.kt — adds the instantPlaybackPreparationEnabled computed property (canResolvePlayableLinks && instantPlaybackPreparationLimit > 0).
  • composeApp/src/commonMain/kotlin/com/nuvio/app/features/streams/AddonStreamWarmupRepository.kt — the warmup gate in currentKey() now returns null (no warmup) unless instantPlaybackPreparationEnabled is true (TorBox-key requirement unchanged).
  • composeApp/src/commonTest/kotlin/com/nuvio/app/features/debrid/DebridSettingsTest.kt — adds two tests for the new property.

No other behavior is touched; when "Prepare links" is enabled (limit > 0) the warmup behaves exactly as before.

Testing

  • Build: ./gradlew :composeApp:assembleFullDebug — ✅ BUILD SUCCESSFUL
  • Unit tests: ./gradlew :composeApp:testFullDebugUnitTest — ✅ all passing
  • New tests in DebridSettingsTest:
    • instant playback preparation stays disabled when the prepare links count is zero — asserts canResolvePlayableLinks == true but instantPlaybackPreparationEnabled == false when instantPlaybackPreparationLimit = 0 (reproduces the bug condition: warmup would previously have run).
    • instant playback preparation requires a positive prepare links count and a resolver — asserts it's enabled only with a positive limit and a configured resolver.

STATIC ANALYSIS:

  • Before fix: MetaDetailsScreenAddonStreamWarmupRepository.preload(...)currentKey() returned a non-null key whenever canResolvePlayableLinks and a TorBox key were present, regardless of instantPlaybackPreparationLimit. The warmup then fetched streams from every enabled add-on, even though DirectDebridStreamPreparer.prepare() immediately returns when the limit is 0 — so the add-on requests were sent for no effect.
  • After fix: currentKey() returns null when instantPlaybackPreparationLimit <= 0, so preload() performs no add-on requests. Add-on stream requests are then only issued when the user opens the stream list / presses Play.
  • Edge cases: limit > 0 → unchanged behavior; "Resolve playable links" off → already returned null (still does, since instantPlaybackPreparationEnabled implies canResolvePlayableLinks); no TorBox key → still returns null.
  • Regression risk: minimal. The new gate is strictly stronger than the old one, and warmup-cache consumers already handle the absence of a warmed cache as a normal miss.

Screenshots / Video

Not a UI change.

Breaking changes

None.

Linked issues

Fixes #1299

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.

[Bug]: Nuvio on andoid mobile sending requests to add-ons before 'Play' is even pressed

1 participant