@@ -5,7 +5,7 @@ const firstSession = { id: "first" } as unknown as YoutubeInnertube;
55const secondSession = { id : "second" } as unknown as YoutubeInnertube ;
66
77describe ( "YouTube caption tracks" , ( ) => {
8- it ( "loads and normalizes tracks through the MWEB player contract" , async ( ) => {
8+ it ( "loads and normalizes tracks through the WEB player contract" , async ( ) => {
99 const { fetchCaptionTracks } = await import (
1010 "../src/youtube-caption-tracks.ts?caption-contract"
1111 ) ;
@@ -32,12 +32,12 @@ describe("YouTube caption tracks", () => {
3232 fetchPlayer,
3333 } ) ;
3434
35- expect ( getInnertube ) . toHaveBeenCalledWith ( "MWEB " , "visitor" ) ;
35+ expect ( getInnertube ) . toHaveBeenCalledWith ( "WEB " , "visitor" ) ;
3636 expect ( fetchPlayer ) . toHaveBeenCalledWith ( "video" , firstSession , "visitor-pot" ) ;
3737 expect ( invalidateInnertube ) . not . toHaveBeenCalled ( ) ;
3838 expect ( tracks ) . toEqual ( [
3939 {
40- baseUrl : "https://m .youtube.com/api/timedtext?v=video&lang=en" ,
40+ baseUrl : "https://www .youtube.com/api/timedtext?v=video&lang=en" ,
4141 name : { simpleText : "English" } ,
4242 languageCode : "en" ,
4343 kind : undefined ,
@@ -46,7 +46,42 @@ describe("YouTube caption tracks", () => {
4646 ] ) ;
4747 } ) ;
4848
49- it ( "recreates a rejected anonymous MWEB session only once" , async ( ) => {
49+ it ( "falls back to MWEB when WEB does not return caption tracks" , async ( ) => {
50+ const { fetchCaptionTracks } = await import (
51+ "../src/youtube-caption-tracks.ts?caption-fallback"
52+ ) ;
53+ const getInnertube = mock ( async ( client : "WEB" | "MWEB" ) =>
54+ client === "WEB" ? firstSession : secondSession ,
55+ ) ;
56+ const invalidateInnertube = mock ( async ( ) => undefined ) ;
57+ const fetchPlayer = mock ( async ( _videoId : string , session : YoutubeInnertube ) => ( {
58+ playability_status : { status : "OK" } ,
59+ captions :
60+ session === secondSession
61+ ? {
62+ caption_tracks : [
63+ {
64+ base_url : "/api/timedtext?v=video&lang=en" ,
65+ name : { toString : ( ) => "English" } ,
66+ language_code : "en" ,
67+ vss_id : ".en" ,
68+ } ,
69+ ] ,
70+ }
71+ : undefined ,
72+ } ) ) ;
73+
74+ const tracks = await fetchCaptionTracks ( "video" , "visitor" , "visitor-pot" , {
75+ getInnertube,
76+ invalidateInnertube,
77+ fetchPlayer,
78+ } ) ;
79+
80+ expect ( getInnertube . mock . calls . map ( ( [ client ] ) => client ) ) . toEqual ( [ "WEB" , "MWEB" ] ) ;
81+ expect ( tracks [ 0 ] ?. baseUrl ) . toBe ( "https://m.youtube.com/api/timedtext?v=video&lang=en" ) ;
82+ } ) ;
83+
84+ it ( "recreates a rejected anonymous WEB session only once" , async ( ) => {
5085 const { fetchCaptionTracks } = await import (
5186 "../src/youtube-caption-tracks.ts?caption-contract"
5287 ) ;
@@ -62,7 +97,19 @@ describe("YouTube caption tracks", () => {
6297 reason : "Sign in to confirm you are not a bot" ,
6398 } ,
6499 }
65- : { playability_status : { status : "OK" } } ,
100+ : {
101+ playability_status : { status : "OK" } ,
102+ captions : {
103+ caption_tracks : [
104+ {
105+ base_url : "/api/timedtext?v=video&lang=en" ,
106+ name : { toString : ( ) => "English" } ,
107+ language_code : "en" ,
108+ vss_id : ".en" ,
109+ } ,
110+ ] ,
111+ } ,
112+ } ,
66113 ) ;
67114
68115 await fetchCaptionTracks ( "video" , "visitor" , "visitor-pot" , {
@@ -72,7 +119,7 @@ describe("YouTube caption tracks", () => {
72119 } ) ;
73120
74121 expect ( getInnertube ) . toHaveBeenCalledTimes ( 2 ) ;
75- expect ( invalidateInnertube ) . toHaveBeenCalledWith ( "MWEB " , "visitor" , firstSession ) ;
122+ expect ( invalidateInnertube ) . toHaveBeenCalledWith ( "WEB " , "visitor" , firstSession ) ;
76123 expect ( fetchPlayer ) . toHaveBeenCalledTimes ( 2 ) ;
77124 } ) ;
78125} ) ;
0 commit comments