fix(trailer): resolve trailers without the rate-limited watch page and reject PO-token-gated stream URLs - #552
Open
aneeshtigga wants to merge 1 commit into
Open
aneeshtigga wants to merge 1 commit into
aneeshtigga wants to merge 1 commit into
Conversation
11 tasks
aneeshtigga
force-pushed
the
fix/trailer-resolution
branch
from
August 30, 2026 21:33
2ad0fed to
1a1dde6
Compare
4 tasks
…URLs Extraction fetched the 1.1-1.4 MB watch page before every player call just to scrape the public INNERTUBE_API_KEY, so a rate limited device failed with 429 before reaching a player endpoint that still worked. The constant key is used directly now and the page is a last resort. A head-only range probe cannot detect PO token gated URLs, so gated ANDROID and IOS formats passed validation and 403'd during playback. Probes check head and tail, gated clients are dropped after one rejection, and resolution falls back to ANDROID progressive itag 18. Also prefers ungated clients, skips the rest once one resolves, refreshes stale client versions, treats UNPLAYABLE as final, backs off after a 429, and raises the resolved URL cache TTL to 3 hours. Details and measurements in NuvioMedia#551.
aneeshtigga
force-pushed
the
fix/trailer-resolution
branch
from
September 1, 2026 21:35
1a1dde6 to
a8fb1e3
Compare
4 tasks
Member
|
Try to move this PR to NuvioMobile and get core code merged in NuvioMobile first and only include desktop-specific code in here. I'll merge your implementation if your code gets merged in NuvioMobile. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Trailer resolution no longer depends on the watch page, and stream URLs that YouTube has PO token gated are now rejected before they reach the player. Resolution falls back through HLS, separate audio/video and finally
ANDROIDprogressive itag 18, so trailers keep playing (at lower quality) instead of failing outright.PR type
Why
Two independent problems, both measured from a real machine and described in detail in #584.
1. Extraction required the watch page, which is the first thing YouTube rate limits.
extractPlaybackSourceInternalfetchedhttps://www.youtube.com/watch?v=<id>&hl=en(1.1-1.4 MB) before every player call, only to scrapeINNERTUBE_API_KEYandVISITOR_DATA, and threw if it failed:At that same moment the player endpoint still worked and the streams downloaded in full:
MAbjq7ydKDIOKwith and without a key8ZYhuvIv1pAOKwith and without a keyINNERTUBE_API_KEYis a public constant present in every YouTube page (the same value this code was already scraping), so it is used directly now and the watch page is only consulted if every client returns nothing.2. A single head range probe cannot detect PO token gating.
ANDROIDandIOSadaptive URLs serve the first range and then reject every later range, independent of User-Agent (tested Chrome, Safari,Lavfand each client's own UA):bytes=0-65535The head always succeeds, so gated URLs passed validation and then failed inside the player.
Desktop scope
Affects macOS, Windows and Linux equally: the change is in the shared trailer extractor plus the desktop
TrailerExtractionPlatformactual. Verified on macOS 26.6 (arm64).composeApp/src/androidFullandcomposeApp/src/iosFullare touched only becausebuildPlaybackSourcenow takes candidate lists instead of four pre-picked candidates. Those actuals live in this repository, so they have to match or the android and ios targets stop compiling. No behavior beyond the same fix was added there.Issue or approval
Fixes #584.
(The first filing, #551, was closed by the unlabeled-issue bot before triage because an outside contributor cannot set labels from the API. #584 is the same report submitted through the bug template so it carries the
buglabel.)UI / behavior impact
Policy check
CONTRIBUTING.md.What changed
WatchConfigCachescrapes the page only as a last resort when every client returned empty.clenis present), so gated URLs are rejected. One rejection condemns the rest of that client's adaptive formats.visionos,android_vr) are preferred, and remaining clients are skipped once one of them produced candidates. Typical extraction is now one player call instead of three.20.10.35to21.26.364, ios20.10.1to21.26.4, plusandroid_vradded. Stale versions attract bot challenges by themselves.UNPLAYABLEandERRORare treated as final for that video (geo blocks, removed videos) instead of being retried.googlevideoURLs carry their ownexpireof roughly 6 hours.Scope boundaries
Intentionally not included:
Testing
Manual, macOS 26.6 (Darwin 25.6.0), Apple Silicon:
packageReleaseDmg), installed, and played trailers across several titles. Also built from the0.1.21-alphatag to compare against the published release.Failed to fetch watch page (429).NUVIO_TRAILER_DEBUG=1shows the expected path:playability client=visionos status=LOGIN_REQUIRED, then a rejected android adaptive probe, thenselected mode=combined_fallbackon itag 18.blocked stage=unplayableand does not affect the next trailer../gradlew :composeApp:compileKotlinDesktoppasses.The same fix is filed for mobile as NuvioMedia/NuvioMobile#1857, where I also verified it in an iOS build.
Screenshots / Video
Not a UI change.
Breaking changes
None.
Linked issues
Fixes #584. Related context: NuvioMedia/NuvioMobile#1857, NuvioMedia/NuvioTV#2451.