fix(captions): don't ask youtube for a translation when none was asked for

The timedtext request carries tlang whether or not a translation was
requested, and youtube now turns down anything that asks for one: it
answers with its block page instead of the subtitle. Auto-generated
captions come out as a WebVTT file with no cues in it, every other track
as a page of html.

Auto-generated tracks also have to name format 3. Left to itself youtube
answers in the older <transcript> dialect these days, which the parser
below doesn't read and quietly turns into an empty file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
volcanic001 2026-10-09 09:58:47 -06:00
parent 381c6e8c92
commit 0c604ef4a8

View File

@ -105,12 +105,21 @@ module Invidious::Routes::API::V1::Videos
webvtt = transcript.to_vtt webvtt = transcript.to_vtt
else else
# Timedtext API handling # Timedtext API handling
url = URI.parse("#{caption.base_url}&tlang=#{tlang}").request_target url = URI.parse(caption.base_url).request_target
# Youtube turns down anything that asks for a translation, and an empty
# tlang still counts as asking: it answers with its block page instead
# of the subtitle, whatever the rest of the request says. So it only
# goes on when a translation was actually asked for.
url += "&tlang=#{tlang}" if tlang && !tlang.empty?
# Auto-generated captions often have cues that aren't aligned properly with the video, # Auto-generated captions often have cues that aren't aligned properly with the video,
# as well as some other markup that makes it cumbersome, so we try to fix that here # as well as some other markup that makes it cumbersome, so we try to fix that here
if caption.name.includes? "auto-generated" if caption.name.includes? "auto-generated"
caption_xml = YT_POOL.client &.get(url).body # The parser below reads timedtext format 3. Left to itself youtube
# now answers in the older <transcript> dialect, which comes out as a
# WebVTT file with no cues in it.
caption_xml = YT_POOL.client &.get("#{url}&fmt=srv3").body
settings_field = { settings_field = {
"Kind" => "captions", "Kind" => "captions",