Skip to content

Fix download errors by using mostly VISIONOS agent - #965

Merged
Tyrrrz merged 3 commits into
Tyrrrz:primefrom
mysteryx93:prime
Aug 25, 2026
Merged

Fix download errors by using mostly VISIONOS agent#965
Tyrrrz merged 3 commits into
Tyrrrz:primefrom
mysteryx93:prime

Conversation

@mysteryx93

@mysteryx93 mysteryx93 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

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
Contributor Author

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

Comment thread YoutubeExplode.Tests/StreamSpecs.cs Outdated
Comment thread YoutubeExplode.Tests/TestData/VideoIds.cs Outdated
Comment thread YoutubeExplode.Tests/TestData/VideoIds.cs Outdated
Comment thread YoutubeExplode/Videos/VideoController.cs Outdated
Comment thread YoutubeExplode/Videos/VideoController.cs
@mysteryx93

Copy link
Copy Markdown
Contributor 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

@mysteryx93

Copy link
Copy Markdown
Contributor Author

I submitted the refactoring changes. It does considerably improve the code.

2 potentially major issues to look at before deploying.

The TVHTML5 code route is not being used at all; I tried all the unit tests and none hit that route. The new pathway was designed to handle the ForKids issue as well, making this one obsolete.

// The only client that can handle age-restricted videos without authentication is the
// TVHTML5_SIMPLY_EMBEDDED_PLAYER client.
// This client does require signature deciphering, so we only use it as a fallback.

Furthermore, looking at where it is called: StreamClient.GetStreamInfosAsync. We now have 2 separate places to handle fallback logic, which is definitely not ideal.

The whole "Retry with deciphering" fallback could perhaps be removed... but perhaps it would serve in the future too, so it's not an easy call.

@mysteryx93

Copy link
Copy Markdown
Contributor Author

btw I made some comment about HttpRequestMessage; never mind you're using HttpClient, everything is fine there.

@Tyrrrz

Tyrrrz commented Aug 24, 2026

Copy link
Copy Markdown
Owner

The TVHTML5 code route is not being used at all; I tried all the unit tests and none hit that route. The new pathway was designed to handle the ForKids issue as well, making this one obsolete.

// The only client that can handle age-restricted videos without authentication is the
// TVHTML5_SIMPLY_EMBEDDED_PLAYER client.
// This client does require signature deciphering, so we only use it as a fallback.

Furthermore, looking at where it is called: StreamClient.GetStreamInfosAsync. We now have 2 separate places to handle fallback logic, which is definitely not ideal.

The whole "Retry with deciphering" fallback could perhaps be removed... but perhaps it would serve in the future too, so it's not an easy call.

@mysteryx93 the TVHTML5 route was used for age-restricted videos, usually marked as such because of violence and/or sexual themes. So it's a separate issue.

@mysteryx93

Copy link
Copy Markdown
Contributor Author

ah and those 2 tests are set as "Skip" so they weren't run. Those tests fail with "Failed to extract the cipher manifest"; which I suppose is why you disabled the tests. But they work in practice?

Still. We have the retry logic split into 2 areas. It's not ideal but not really an issue either. Considering the 2nd retry path with cipher is a considerably more different/complicated route.

joeycih pushed a commit to joeycih/YoutubeExplode_AddChapter that referenced this pull request Aug 25, 2026
ANDROID_VR 1.60.19 已被 YouTube 判为过期客户端,player 接口返回
LOGIN_REQUIRED / "Sign in to confirm you're not a bot",不带 videoDetails,
于是几乎所有视频都抛 VideoUnavailableException。升到 1.65.10 后 player 恢复
正常,但流地址只放行开头约 6MB,尾部和深偏移一律 403,大视频仍然下不完。

改用上游 PR Tyrrrz#965 的方案:
- VISIONOS 1.02 主用。实测能完整拉下 36.7MB 的流,字节数精确匹配
- 儿童向视频 VISIONOS 放不了,退到 ANDROID 21.26.364,靠 muxed itag 18
- 年龄限制视频仍走 TVHTML5 cipher 兜底(该路径上游至今未修复)
- GetStreamInfosAsync 跳过没有直链的 SABR 流,而不是抛异常中断整个 manifest

另外 TryGetContentLengthAsync 把 403 与 404 同等对待、跳过该条流(上游没有
这一条):方法本身就叫 Try、调用方写了 continue,一条被限制的格式不该让整个
manifest 崩掉——这正是升级客户端版本后踩到的坑。

验证客户端时切记:player 接口返回 OK 且带 streamingData 并不代表可用,
必须另外确认整条流能下完。ANDROID_VR 1.65.10 就是 player 全绿但流被截断。

Tyrrrz#965

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016nxNn1d1qaCh278auwrnyb

@Tyrrrz Tyrrrz left a comment

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.

Thanks!

@Tyrrrz
Tyrrrz merged commit ea791ab into Tyrrrz:prime Aug 25, 2026
7 checks passed
@mysteryx93

Copy link
Copy Markdown
Contributor Author

@Tyrrrz what's your thoughts about using an extra dependency to support cookies and YouTube Premium streams, with the same method yt-dlp is using?

Do you plan to take care of that eventually? Do you want to keep it fully dependency-free?

Or would you like me to generate the bulk with AI then we refactor it proper, copying yt-dlp's proven path? BUT keeping the dependency fully optional.

As of right now, it seems the cookie-authentication path is useless without proper deciphering support, which can only be done with a real JavaScript engine.

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