Skip to content

Use YouTube player clients that are not bot-checked - #25

Merged
Isma-L154 merged 1 commit into
mainfrom
fix/youtube-player-clients
Aug 23, 2026
Merged

Use YouTube player clients that are not bot-checked#25
Isma-L154 merged 1 commit into
mainfrom
fix/youtube-player-clients

Conversation

@Isma-L154

Copy link
Copy Markdown
Owner

Closes #24

The problem

Five of every six YouTube tracks failed to load. Measured on the production host:

Rick Astley    OK
Queen          FAILED -> blocked
Gangnam Style  FAILED -> blocked
Despacito      FAILED -> blocked
Nirvana        FAILED -> blocked
Coldplay       FAILED -> blocked
               === 1/6 ===

yt-dlp's real error: sign in to confirm you're not a bot.

This is not experienced as "tracks fail" — it is experienced as the bot being slow. A track fails, the bot reports it and skips, and you retry until one works.

Root cause

The chain was default,android_vr,tv_embedded. Testing every client yt-dlp offers, against the same video, from the same host:

Client Result
default, web, android_vr, tv_embedded, tv, ios, android_music bot-checked
mweb works
web_embedded works

Every entry in the configured chain was blocked, so yt-dlp exhausted it and gave up.

The fix

-_PLAYER_CLIENTS = "default,android_vr,tv_embedded"
+_PLAYER_CLIENTS = ("web_embedded", "mweb", "tv_embedded")

Validated across all six videos:

Chain Success Mean
mweb 6/6 9.3s
web_embedded 6/6 3.2s

Order is latency, not preference. yt-dlp tries each client in turn, so a blocked client at the front costs a full round trip before anything can play. web_embedded first, mweb behind it, and tv_embedded stays last because it needs no JS runtime — making it the only thing that can work on a host where Deno failed to install.

The duplication that let this rot

The client list existed twice: as a comma-joined string for the streaming subprocess, and as a list inside YTDL_OPTIONS["extractor_args"] for metadata extraction. Nothing kept them in sync, so an edit to one could silently change search without changing playback.

Both now derive from a single tuple, and test_the_two_client_usages_cannot_drift asserts it.

Verification

Against the real bot code, on the production host:

cadena en uso: web_embedded,mweb,tv_embedded

  Rick Astley  OK     3.68s
  Queen        OK     3.02s
  Gangnam      OK     3.22s
  Despacito    OK     8.11s
  Nirvana      OK     3.29s
  Coldplay     OK     3.20s

  === 6/6 exitosos, media 4.09s ===

243 passed locally. The suite cannot test YouTube itself — CI runs on a datacenter IP where everything is bot-checked — so the new tests pin the configuration: that the two usages agree, that a working client is first, that each client measured as blocked is absent, and that a JS-free fallback remains.

A correction this PR carries

The comments previously implied a residential IP defeats YouTube's bot-checking. That claim came from three successful samples and is too strong — six samples show 1/6. A residential IP reduces bot-checking but does not eliminate it. The comments now say so, cookies remain supported, and getting the client chain right avoids needing them.

Not changed, and why

Two other hypotheses were measured and rejected:

  • WiFi: 0 retries, 0 failures, 0 beacon loss, −54 dBm. Not the network.
  • CPU governor: performance vs powersave made no difference (4.76s vs 4.78s). The bottleneck is round trips to YouTube, not clock speed. Left alone.

Five of every six YouTube tracks failed to load. The error was "sign in to
confirm you're not a bot", and it reads to a user as the bot being slow: a
track fails, the bot reports it and skips, and they retry until one works.

The chain was "default,android_vr,tv_embedded". Testing every client yt-dlp
offers against the same video from the production host, all three of those are
now bot-checked - so yt-dlp exhausted the chain and gave up. Only two clients
still work:

  web_embedded  6/6 tracks, 3.2s mean
  mweb          6/6 tracks, 9.3s mean

Order is latency, not preference: yt-dlp tries each client in turn, so a
blocked client at the front costs a full round trip before anything plays.
web_embedded goes first, mweb behind it, and tv_embedded stays last because it
needs no JS runtime and is the only option on a host where Deno is missing.

The list was also duplicated - once as a comma-joined string for the streaming
subprocess, once as a list for metadata extraction - with nothing keeping them
in sync. Both now derive from one definition, and a test asserts they agree.

Verified against the real bot code on the host: 6/6, 4.09s mean.

Also corrects an overstated claim in the previous comments: a residential IP
reduces YouTube's bot-checking but does not eliminate it. Cookies remain
supported; a correct client chain avoids needing them.

Closes #24
@Isma-L154
Isma-L154 merged commit ab04549 into main Aug 23, 2026
3 checks passed
@Isma-L154
Isma-L154 deleted the fix/youtube-player-clients branch August 23, 2026 05:43
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.

YouTube blocks 5 of 6 tracks: the configured player_client chain is entirely bot-checked

1 participant