Skip to content

Fix download errors by using mostly VISIONOS agent - #965

Open
mysteryx93 wants to merge 2 commits into
Tyrrrz:primefrom
mysteryx93:prime
Open

Fix download errors by using mostly VISIONOS agent#965
mysteryx93 wants to merge 2 commits into
Tyrrrz:primefrom
mysteryx93:prime

Conversation

@mysteryx93

@mysteryx93 mysteryx93 commented Aug 19, 2026

Copy link
Copy Markdown

Closes #902 #962 #964

The downloader has been broken for some time, and that's the kind of issues that are extremely time-consuming to diagnose.

I have put Grok Build to the task, so this is AI-generated, and I have manually reviewed every line modified. All tests are now passing. 2 were still failing: Live Stream and Upscaler, because of outdated videos. The code is fine. I updated the video IDs. All tests now pass. So far Grok passed every test I gave it; it just keeps going until the tests pass.

Summary of changes

The failure was not the video. YouTube’s current ANDROID_VR 1.60.19 client (what YoutubeExplode still used) now returns LOGIN_REQUIRED / “Sign in to confirm you’re not a bot” for public videos, including u9Dg-g7t2l4. That makes the main cipher-less path fail, then the #902 cipher fallback also fails because player JS is no longer parseable.

yt-dlp already moved off that client. Its JS-less default is now VISIONOS, which still returns progressive URLs without a PO token.

What changed

  1. Primary client: VISIONOS 1.02 — same client yt-dlp uses without Deno. No signature deciphering, and stream URLs actually work (HEAD 200).
  2. Fallback: ANDROID 21.26.364 — for “made for kids” videos, which VISIONOS still cannot play. ANDROID still returns muxed itag 18.
  3. SABR streams are skipped instead of aborting the whole manifest (Failed to extract the stream URL).

Still broken (unchanged YouTube limits)
• Age-restricted videos still need the cipher client. Player JS is still unparseable.

@mysteryx93

Copy link
Copy Markdown
Author

To clarify: the agent fallback works for age-restricted.
Kids videos still fail. These are 2 separate cases.

Comment on lines +258 to +271
[Fact]
public async Task I_can_get_the_list_of_available_streams_of_a_video_blocked_by_android_vr()
{
// Arrange
using var youtube = new YoutubeClient();

// Act
var manifest = await youtube.Videos.Streams.GetManifestAsync(VideoIds.AndroidVrBotCheck);

// Assert
manifest.Streams.Should().NotBeEmpty();
manifest.GetAudioStreams().Should().NotBeEmpty();
manifest.GetVideoStreams().Should().NotBeEmpty();
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to test this separately

public const string WithMultipleAudioLanguages = "ngqcjXfggHQ";
public const string WithUpscaledStreams = "IFACrIx5SZ0";
public const string WithUpscaledStreams = "0N1_0SUGlDQ";
public const string AndroidVrBotCheck = "u9Dg-g7t2l4";

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this

public const string WithUpscaledStreams = "IFACrIx5SZ0";
public const string WithUpscaledStreams = "0N1_0SUGlDQ";
public const string AndroidVrBotCheck = "u9Dg-g7t2l4";
public const string MadeForKids = "nQuzyJ-C1Fc";

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this to just ForKids and move it below ContentCheck* videos


public async ValueTask<PlayerResponse> GetPlayerResponseAsync(
VideoId videoId,
private async ValueTask<PlayerResponse> SendPlayerRequestAsync(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this should be inlined. The indirection causes more cognitive overhead than duplication.

return PlayerResponse.Parse(await response.Content.ReadAsStringAsync(cancellationToken));
}

public async ValueTask<PlayerResponse> GetPlayerResponseAsync(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be refactored into GetPlayerResponseForVisionOsAsync and GetPlayerResponseForAndroidAsync. GetPlayerResponseAsync would then just handle retrying.

@mysteryx93

Copy link
Copy Markdown
Author

Do you want me to edit the PR or you handle it from here?

@Tyrrrz

Tyrrrz commented Aug 23, 2026

Copy link
Copy Markdown
Owner

@mysteryx93 yes, please fix as much as you can youself, I'll clean up afterward

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed to extract cipher manifest

2 participants