Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/faraasaaay/innertube-v2/llms.txt

Use this file to discover all available pages before exploring further.

YouTubeExtractor is a Kotlin object that resolves YouTube’s stream URL protection. It fetches YouTube’s base.js player script, extracts the signature decipher and n-parameter transform functions, and caches them to disk so subsequent app launches require no network call.
YouTubeExtractor uses Mozilla Rhino — a pure JVM JavaScript engine — to execute the deobfuscation functions. No WebView is required. Scripts execute entirely in JVM memory in milliseconds.

Overview

YouTube protects stream URLs in two ways:
  1. Signature cipher — Some format entries have signatureCipher instead of a direct url. The signature must be decrypted before the URL becomes valid.
  2. n parameter throttling — All stream URLs include an n= query parameter that intentionally limits CDN download speed unless transformed using a JavaScript function from the player.
YouTubeExtractor handles both automatically. The typical call path is:
player response
    └── format.signatureCipher  →  decryptUrl()   →  full URL with decrypted signature + deobfuscated n
    └── format.url              →  deobfuscateUrlNParam()  →  URL with deobfuscated n

YouTubeExtractor.cacheDir: File?

var cacheDir: File? = null
Set this to a directory where decipher scripts will be persisted between app launches. The recommended value is context.cacheDir.
  • If null, deobfuscation scripts are held in memory only and must be re-fetched on every cold start.
  • Scripts are cached as plain text files (yt_sig_js.txt, yt_n_js.txt, etc.) alongside a timestamp file.
  • The cache is considered fresh for 24 hours. After that, the next call automatically re-fetches base.js.

YouTubeExtractor.isReady: Boolean

val isReady: Boolean
Returns true if both the signature decipher code and the n-transform code are loaded in memory (either from a prior network fetch or from disk cache). Use this to check initialization state without triggering a network call.

YouTubeExtractor.ensureInitialized()

fun ensureInitialized()
Pre-loads and fully compiles both deobfuscation functions. Call this once from Application.onCreate() on a background thread so the first song play has zero initialization latency. What it does:
  1. Checks for a fresh disk cache — if found, loads scripts and skips the network entirely.
  2. On cache miss: fetches https://www.youtube.com/iframe_api to discover the current player JS URL, then downloads base.js.
  3. Extracts the signature decipher function and its helper object from the player JS.
  4. Extracts the n-parameter transform function.
  5. Compiles both into persistent Rhino Function objects (reused on every call — no re-parsing overhead).
  6. Saves the extracted snippets to disk for the next 24 hours.
Thread safety: Protected by initLock. Concurrent calls block and return immediately once the first caller completes — no duplicate network work.

YouTubeExtractor.decryptSignature(s: String): String

fun decryptSignature(s: String): String
Decrypts an obfuscated YouTube stream signature. The signature is the s parameter extracted from a signatureCipher query string. In most cases you will not call this directly — use decryptUrl() instead, which handles full signatureCipher parsing automatically. Returns the original s string unchanged if decryption fails.

YouTubeExtractor.deobfuscateThrottling(n: String): String

fun deobfuscateThrottling(n: String): String
Transforms the raw n query parameter value into the deobfuscated version that removes CDN throttling. In most cases you will not call this directly — use deobfuscateUrlNParam() instead, which extracts and replaces the n parameter within a full URL. Returns the original n string unchanged if deobfuscation fails.

YouTubeExtractor.decryptUrl(signatureCipher: String): String

fun decryptUrl(signatureCipher: String): String
The primary entry point for ciphered formats. Parses the signatureCipher (or cipher) query string from a PlayerResponse.StreamingData.Format, decrypts the signature, appends it to the base URL, and then deobfuscates the n parameter. Parameters:
  • signatureCipher — The raw value of format.signatureCipher or format.cipher.
Returns: A complete, playable stream URL, or an empty string on failure. Parsing: Expects a URL-encoded query string with keys url, sp (signature parameter name, defaults to "signature"), and s (obfuscated signature).

YouTubeExtractor.deobfuscateUrlNParam(url: String): String

fun deobfuscateUrlNParam(url: String): String
Finds the n= parameter in a stream URL (via regex [?&]n=([^&]+)) and replaces it with its deobfuscated value.
  • If no n parameter is present, the URL is returned unchanged.
  • If deobfuscation fails, the original URL is returned unchanged (no-op on error).
Use this on direct format.url values that do not require signature decryption.

YouTubeExtractor.parseQueryParams(query: String): Map<String, String>

fun parseQueryParams(query: String): Map<String, String>
Parses a URL query string into a Map<String, String>. Keys and values are URL-decoded.
val params = YouTubeExtractor.parseQueryParams("url=https%3A%2F%2F...&sp=sig&s=abc123")
// params["url"] = "https://..."
// params["sp"]  = "sig"
// params["s"]   = "abc123"

Caching Behavior

ScenarioBehavior
First cold start (no cache)Fetches iframe_api → resolves player JS URL → downloads base.js → extracts + saves snippets
Cache hit (< 24 hours old)Loads snippets from disk files — no network call at all
Cache stale (≥ 24 hours)Re-fetches base.js and updates the cache files
Player JS URL changedAutomatically re-fetches — detected by comparing the cached URL to the resolved URL
cacheDir is nullNo disk caching; scripts are re-fetched on every cold start
Cache files written to cacheDir:
FileContents
yt_player_url.txtResolved player JS URL
yt_player_cache_time.txtUnix timestamp of last cache save (milliseconds)
yt_sig_js.txtSignature decipher JavaScript code
yt_sig_func.txtName of the signature decipher function
yt_n_js.txtn-parameter transform JavaScript code
yt_n_func.txtName of the n-transform function

Setup and Usage Example

Application Setup

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // Point YouTubeExtractor to the app's cache directory
        YouTubeExtractor.cacheDir = cacheDir

        // Pre-initialize on a background thread to avoid latency on first play
        thread(name = "YouTubeExtractor-init") {
            YouTubeExtractor.ensureInitialized()
        }
    }
}

During Playback

suspend fun resolveStreamUrl(format: PlayerResponse.StreamingData.Format): String? {
    return when {
        // Format has a direct URL — only the n param needs deobfuscation
        format.url != null -> {
            YouTubeExtractor.deobfuscateUrlNParam(format.url)
        }
        // Format is cipher-protected — decrypt signature and deobfuscate n
        format.signatureCipher != null -> {
            YouTubeExtractor.decryptUrl(format.signatureCipher).takeIf { it.isNotEmpty() }
        }
        format.cipher != null -> {
            YouTubeExtractor.decryptUrl(format.cipher).takeIf { it.isNotEmpty() }
        }
        else -> null
    }
}

Checking Readiness

if (!YouTubeExtractor.isReady) {
    // Initialization hasn't completed yet — either wait or call ensureInitialized()
    withContext(Dispatchers.IO) {
        YouTubeExtractor.ensureInitialized()
    }
}

Build docs developers (and LLMs) love