fix(youtube): use a browser UA for the watch-page caption scrape
The ANDROID InnerTube player now returns 0 captionTracks (PoToken-gated), so the watch-page scrape is the real path — but it sent an Android *app* User-Agent, which makes YouTube serve a page WITHOUT ytInitialPlayerResponse, so captions came back empty. Result: 87% of a live run skipped as 'no transcript' despite the videos having captions. A desktop-browser UA returns the player JSON with captionTracks. Confirmed live: app-UA=0 tracks, browser-UA=1.
This commit is contained in:
@@ -21,6 +21,11 @@ const defaultPlayerBaseURL = "https://www.youtube.com"
|
|||||||
// returns caption baseUrls without a PoToken requirement (ADR-010).
|
// returns caption baseUrls without a PoToken requirement (ADR-010).
|
||||||
const androidUserAgent = "com.google.android.youtube/20.10.38 (Linux; U; Android 11) gzip"
|
const androidUserAgent = "com.google.android.youtube/20.10.38 (Linux; U; Android 11) gzip"
|
||||||
|
|
||||||
|
// browserUserAgent is required for the watch-page scrape: with an app UA YouTube
|
||||||
|
// serves a page WITHOUT the embedded ytInitialPlayerResponse, so captionTracks
|
||||||
|
// come back empty. A desktop-browser UA returns the player JSON with captions.
|
||||||
|
const browserUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
||||||
|
|
||||||
// maxCaptionBytes bounds a single timedtext/player body read.
|
// maxCaptionBytes bounds a single timedtext/player body read.
|
||||||
const maxCaptionBytes = 16 << 20 // 16 MiB
|
const maxCaptionBytes = 16 << 20 // 16 MiB
|
||||||
|
|
||||||
@@ -134,7 +139,7 @@ const ytInitialMarker = "ytInitialPlayerResponse"
|
|||||||
// embedded ytInitialPlayerResponse JSON. Any failure degrades to no tracks.
|
// embedded ytInitialPlayerResponse JSON. Any failure degrades to no tracks.
|
||||||
func (a *Adapter) scrapeCaptionTracks(ctx context.Context, client *http.Client, videoID string) ([]captionTrack, error) {
|
func (a *Adapter) scrapeCaptionTracks(ctx context.Context, client *http.Client, videoID string) ([]captionTrack, error) {
|
||||||
body, status, err := a.httpGet(ctx, client, a.playerBaseURL+"/watch?v="+videoID, map[string]string{
|
body, status, err := a.httpGet(ctx, client, a.playerBaseURL+"/watch?v="+videoID, map[string]string{
|
||||||
"User-Agent": androidUserAgent,
|
"User-Agent": browserUserAgent,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Reference in New Issue
Block a user