Skip to content

fix(playback): prevent stale stream URLs from stalling playback - #4132

Open
jahruz67 wants to merge 3 commits into
MetrolistGroup:mainfrom
jahruz67:main
Open

fix(playback): prevent stale stream URLs from stalling playback#4132
jahruz67 wants to merge 3 commits into
MetrolistGroup:mainfrom
jahruz67:main

Conversation

@jahruz67

@jahruz67 jahruz67 commented Jul 15, 2026

Copy link
Copy Markdown

Problem

Playback and downloads can become stuck loading after the app remains in the background long enough for a YouTube stream URL to expire.

Cause

Download URL expiration was stored as a relative duration instead of an absolute timestamp, and the validity comparison was reversed. This caused expired URLs to be reused. Stream validation responses were also not closed, potentially leaking network resources.

Solution

  • Add a bounded, thread-safe cache for stream URLs.
  • Store and validate absolute expiration timestamps.
  • Share consistent cache behavior between playback and downloads.
  • Invalidate download URLs after HTTP 403 or 410 failures.
  • Invalidate cached URLs when downloads are removed.
  • Close HTTP responses after stream URL validation.
  • Add tests for expiration, invalidation, eviction, and concurrent access.

Testing

  • Added unit tests covering the stream URL cache behavior.
  • Verified the patch with git diff --check.
  • Build and unit tests were not run because the required Java and Android SDK toolchains are unavailable in the current environment.

Related Issues

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of expired stream links during playback and downloads.
    • Automatically refreshes invalid links after relevant playback or download failures.
    • Removed stream links are now cleared when downloads are deleted.
    • Ensured network responses are properly closed during link validation.
  • Performance

    • Added efficient caching with expiration and least-recently-used eviction to reduce repeated stream URL lookups.
  • Tests

    • Added coverage for expiration, invalidation, capacity limits, and concurrent cache access.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89ff31cb-e1f7-4956-b4cf-1e9c64cf8263

📥 Commits

Reviewing files that changed from the base of the PR and between d161254 and e0936cc.

📒 Files selected for processing (5)
  • app/src/main/kotlin/com/metrolist/music/playback/DownloadUtil.kt
  • app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt
  • app/src/main/kotlin/com/metrolist/music/playback/StreamUrlCache.kt
  • app/src/main/kotlin/com/metrolist/music/utils/YTPlayerUtils.kt
  • app/src/test/kotlin/com/metrolist/music/playback/StreamUrlCacheTest.kt

📝 Walkthrough

Walkthrough

The PR adds a synchronized expiring LRU StreamUrlCache, updates playback and download flows to use it for stream URL resolution and invalidation, detects expired-stream download failures, and scopes HTTP validation responses for proper closure.

Changes

Stream URL cache lifecycle

Layer / File(s) Summary
Expiring LRU cache contract
app/src/main/kotlin/com/metrolist/music/playback/StreamUrlCache.kt, app/src/test/kotlin/com/metrolist/music/playback/StreamUrlCacheTest.kt
Adds synchronized expiry-aware caching, overflow-safe TTL calculation, LRU eviction, explicit invalidation, and tests for expiry, capacity, invalidation, and concurrency.
Playback and download cache integration
app/src/main/kotlin/com/metrolist/music/playback/MusicService.kt, app/src/main/kotlin/com/metrolist/music/playback/DownloadUtil.kt
Replaces manual URL/expiry maps with StreamUrlCache, updates stream resolution and insertion, and invalidates entries during quality changes, recovery, expired failures, and download removal.
HTTP response lifecycle cleanup
app/src/main/kotlin/com/metrolist/music/utils/YTPlayerUtils.kt
Scopes validateStatus responses with use while retaining status checks and logging.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MusicService
  participant StreamUrlCache
  participant DownloadUtil
  MusicService->>StreamUrlCache: Request cached stream URL
  StreamUrlCache-->>MusicService: Return fresh URL or null
  DownloadUtil->>StreamUrlCache: Store fetched URL with TTL
  DownloadUtil->>StreamUrlCache: Invalidate URL after expiry or removal
Loading

Possibly related PRs

Suggested reviewers: mostafaalagamy, nyxiereal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main playback fix and matches the changeset.
Description check ✅ Passed The PR description matches the template and includes problem, cause, solution, testing, and related issues.
Linked Issues check ✅ Passed The changes address issue #4093 by preventing expired stream URLs from being reused and invalidating them on failure.
Out of Scope Changes check ✅ Passed All code changes are consistent with the playback/download cache fix and its supporting tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@novakjakov2

Copy link
Copy Markdown

Can I download the apk with the fixed issues?

@jahruz67

Copy link
Copy Markdown
Author

@novakjakov2 did you try the latest APK release, it fixes most playback issues

@novakjakov2

Copy link
Copy Markdown

@novakjakov2 did you try the latest APK release, it fixes most playback issues

Yes, playing certain songs does not work. The player just keeps spinning but not loading the song.

@jahruz67

jahruz67 commented Jul 21, 2026

Copy link
Copy Markdown
Author

@novakjakov2 did you try the latest APK release, it fixes most playback issues

Yes, playing certain songs does not work. The player just keeps spinning but not loading the song.

Maybe you could fork my fork and build that APK or go to actions and download the build from latest from the latest commit. https://github.com/MetrolistGroup/Metrolist/actions/workflows/build.yml

Also, make sure when you update it to the latest release that you have cleared the app storage and cleared the cache. Because sometimes that may affect your update.

@novakjakov2

Copy link
Copy Markdown

@novakjakov2 did you try the latest APK release, it fixes most playback issues

Yes, playing certain songs does not work. The player just keeps spinning but not loading the song.

Maybe you could fork my fork and build that APK or go to actions and download the build from latest from the latest commit. https://github.com/MetrolistGroup/Metrolist/actions/workflows/build.yml

Also, make sure when you update it to the latest release that you have cleared the app storage and cleared the cache. Because sometimes that may affect your update.

I installed the app for the first time. Should I try reinstalling?

@jahruz67

Copy link
Copy Markdown
Author

@novakjakov2 did you try the latest APK release, it fixes most playback issues

Yes, playing certain songs does not work. The player just keeps spinning but not loading the song.

Maybe you could fork my fork and build that APK or go to actions and download the build from latest from the latest commit. https://github.com/MetrolistGroup/Metrolist/actions/workflows/build.yml
Also, make sure when you update it to the latest release that you have cleared the app storage and cleared the cache. Because sometimes that may affect your update.

I installed the app for the first time. Should I try reinstalling?

That may help

@nyxiereal nyxiereal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please rebase and resolve the playback conflicts while preserving current recovery logic. Stream URL expiry should use a monotonic clock such as elapsedRealtime(), followed by a current build and stale URL retry tests.

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.

The music isn't playing for some reason.

3 participants