Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ZemerTeam/zemer-cipher/llms.txt
Use this file to discover all available pages before exploring further.
CipherDeobfuscator is the object responsible for resolving obfuscated YouTube stream URLs. It fetches the player JavaScript, extracts the signature and n-transform functions, and executes them inside an Android WebView (referred to as the cipher WebView). The cipher WebView is the primary deciphering path — fallback clients are unreliable and should be treated as last resorts.
Package: com.zemer.cipher
All methods are suspend unless otherwise noted.
deobfuscateStreamUrl, transformNParamInUrl, and prewarm all share a single Mutex. They serialize — concurrent callers queue rather than execute in parallel. This is required because the underlying CipherWebView has single-shot continuation slots that cannot be used concurrently.Initialization
initialize
WebView. This is called internally by ZemerCipher.initialize() — you do not need to call it directly.
Application context.
applicationContext is stored internally to avoid leaks.Properties
lastUsedPlayerHash: String?
player_ias JavaScript last used to decipher a web stream (signature or n-param). Returns null if no web stream has been deciphered in the current process lifetime.
This is a diagnostic property — it is surfaced in debug UIs to help identify which player generation is active. Direct-URL clients (e.g. ANDROID_VR, IOS) never run the cipher, so this value only reflects the last web stream.
Functions
signatureTimestamp
signatureTimestamp (sts) embedded in the player JavaScript that the cipher WebView is currently using (or will use after a lazy fetch). This value must be included in the signatureTimestamp field of InnerTube /player requests.
During A/B player rollouts, different sources can resolve different player versions. Sending the sts from this function guarantees that the signature the /player endpoint mints is decipherable by the cipher WebView’s loaded player — mismatching versions causes the CDN to 403 the resulting URL.
The
signatureTimestamp integer, or null if the player JavaScript could not be fetched.prewarm
WebView in the background so that the first call to deobfuscateStreamUrl incurs no cold-start delay. This involves fetching player JavaScript (~2.8 MB), extracting function names, and loading the JS into a WebView.
Execution is guarded by the same mutex as deobfuscateStreamUrl — it will not race an in-flight deobfuscation request. On any failure (including renderer death), the error is swallowed and the WebView is created lazily on the next real request. Safe to call at any point after ZemerCipher.initialize().
deobfuscateStreamUrl
signatureCipher query string, deobfuscates the signature using the player JavaScript WebView, and returns the fully resolved stream URL.
The full
signatureCipher query string from a streaming format object, in the form s=<obfuscated_sig>&sp=<sig_param_name>&url=<base_url>. All three fields are percent-encoded.The YouTube video ID. Used for logging and diagnostics only — it is not sent over the network.
The resolved stream URL with the deobfuscated signature appended as a query parameter (e.g.
&signature=<sig>), or null on failure.null is returned.
Renderer death: If a CipherRendererGoneException is raised (the sandboxed WebView renderer was OOM-killed), the function returns null immediately without retrying. The dead WebView is discarded, and RendererRecoveryPolicy opens a short backoff window to avoid stalling subsequent songs on a doomed 2.8 MB player-JS re-parse under continued memory pressure.
This function never throws, except for CancellationException from coroutine cancellation.
transformNParamInUrl
n= parameter in a YouTube streaming URL to prevent CDN throttling and 403 errors. Uses the n-transform function discovered from the player JavaScript when the cipher WebView was initialized.
A YouTube streaming URL. This is typically the output of
deobfuscateStreamUrl, but any streaming URL with an n= parameter is valid.The URL with the
n= parameter replaced by its transformed value. The original URL is returned unchanged if:- No
n=parameter is present in the URL - The n-transform function was not successfully discovered when the cipher WebView was initialized
- The transform fails for any reason (exceptions are caught and logged)
onStreamRejected
deobfuscateStreamUrl. A 403 after successful deobfuscation typically indicates a stale or incorrect player config (e.g. the wrong signature function was selected due to an outdated remote config or a legacy-regex false positive). This kind of failure is invisible to deobfuscateStreamUrl’s own retry logic because no exception is thrown during deciphering — the bad signature is only detected when the CDN rejects it.
Internally, this triggers PlayerConfigStore.refreshAfterStreamRejection(), a rate-limited single-flight fetch of the remote player config table. If the config table changes (i.e. its epoch advances), the next call to deobfuscateStreamUrl will rebuild the cipher WebView with the corrected config, recovering the WEB client without requiring an app restart.
true if the remote config table changed (epoch advanced), indicating that retrying stream resolution with a fresh WebView may succeed. false if the config is unchanged or the refresh was rate-limited.