fix(youtube): refresh rejected SABR player contexts#88
Conversation
|
I think there is a mismatch. The main issue here is PipePipe doesn't currently pass potoken to the player extraction. And even if we pass it,the potoken won't be cached (unlike sabr_po_token) so the retry mechanism doesn't really add value - the potoken should always be fresh :) |
|
I went back through PipePipe Client and I mixed up two different token flows here. PipePipe fetches the player response without a PO token. The Local DOM provider only runs afterwards, using the visitor data from that response to mint the video-bound token used for SABR requests. So there is no cached player token to refresh in PipePipe, and the retry path I added only makes sense with how TypeType currently manages its player context. My bad, I should have checked the Client flow before opening this PR. I’m closing it and keeping this recovery on the TypeType side. |
fix(youtube): refresh rejected SABR player contexts
Summary
While investigating current WEB and MWEB player responses that return
LOGIN_REQUIREDbefore exposing anystreamingData, I found that the SABR path was treating two different PO-token roles as if they were one piece of state.The Innertube
/playerrequest needs a visitor/session-bound PO token sent throughserviceIntegrityDimensions.poToken. That token has to stay attached to thevisitorDatafrom the same player context. The later SABR media requests use a different, video ID-bound token inStreamerContextfield 2.The extractor already accepted raw player token and visitor values for the initial probe, but it could not refresh them after YouTube rejected the player request. A later SABR session reload also called the anonymous probe overload and silently discarded the context that had admitted the original request.
This hotfix keeps both token roles separate, preserves the player context across SABR reloads and adds one bounded refresh when YouTube explicitly rejects player admission as bot verification.
Problem
The failure happens before the SABR protocol starts:
The SABR probe previously checked for
streamingDatafirst, so this became a generic protocol error. The caller could not distinguish an expired or rejected player context from a malformed SABR response.There were also two recovery problems:
visitorDataand player PO token had no refresh contract;YoutubeSabrSessionreloaded metadata anonymously, even when the session had originally been opened with valid player admission material.Refreshing only one value is not sufficient. The visitor data and player PO token are route-affine and must be replaced together. Reusing the video ID-bound SABR media token for
/playeris also invalid because it has a different binding and wire role.Without an extractor-level distinction, downstream callers either lose the original session context or have to recover around a generic missing-
streamingDataerror.Changes
YoutubePlayerAdmissionExceptionwith the rejected client profile, playability status and non-sensitive context-presence diagnostics.YoutubeSabrPlayerContextto keepvisitorDataand its player PO token as one atomic value.YoutubeSabrPlayerContextProviderso callers can supply the current context and explicitly refresh it when rejected./playerexactly once after an admission rejection, then preserve both failures if the refreshed request or provider still fails.YoutubeSabrInfofor metadata reloads.contentPoTokenand document that it belongs only inStreamerContext.setPoTokenandgetPoTokenas deprecated compatibility aliases.Recovery behavior
The provider-backed flow is now bounded:
Compatibility
Existing callers can continue using the anonymous probe or the overload that accepts raw player values. Existing
YoutubeSabrStreamState#setPoTokenandgetPoTokencalls also continue to work.Automatic admission refresh is available only through
YoutubeSabrPlayerContextProvider, because the extractor cannot mint or renew caller-owned BotGuard material by itself.The SABR request wire format is unchanged.
StreamerContextfield 2 still carries the video ID-bound media token; the change makes that role explicit and prevents it from being confused with the/playertoken.Validation
Build:
./gradlew clean buildgit diff --checkLocal admission harness using captured official WEB and MWEB player responses:
LOGIN_REQUIREDresponses before the generic missing-streamingDatapath;Notes
This change does not make PipePipeExtractor responsible for BotGuard execution or token minting. It defines the missing player-admission boundary: callers provide one atomic context, and the extractor knows when and how often that context may be refreshed.
The media-token provider remains separate because a token bound to the video ID cannot replace the visitor/session-bound token required by
/player.