22
33import com .grack .nanojson .JsonArray ;
44import com .grack .nanojson .JsonObject ;
5+ import com .grack .nanojson .JsonParser ;
6+ import com .grack .nanojson .JsonParserException ;
7+ import com .grack .nanojson .JsonWriter ;
8+
59import org .schabi .newpipe .extractor .InfoItem ;
610import org .schabi .newpipe .extractor .Page ;
711import org .schabi .newpipe .extractor .StreamingService ;
1418import org .schabi .newpipe .extractor .search .SearchExtractor ;
1519import org .schabi .newpipe .extractor .utils .JsonUtils ;
1620
17- import javax .annotation .Nonnull ;
1821import java .io .IOException ;
22+ import java .util .Collections ;
23+ import java .util .HashMap ;
24+ import java .util .List ;
25+ import java .util .Map ;
1926
27+ import javax .annotation .Nonnull ;
28+
29+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getClientVersion ;
2030import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getJsonResponse ;
31+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getKey ;
2132import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getTextFromObject ;
33+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getValidJsonResponseBody ;
2234import static org .schabi .newpipe .extractor .utils .Utils .isNullOrEmpty ;
2335
2436/*
@@ -96,20 +108,24 @@ public boolean isCorrectedSearch() {
96108
97109 @ Nonnull
98110 @ Override
99- public InfoItemsPage <InfoItem > getInitialPage () throws ExtractionException {
111+ public InfoItemsPage <InfoItem > getInitialPage () throws IOException , ExtractionException {
100112 final InfoItemsSearchCollector collector = new InfoItemsSearchCollector (getServiceId ());
101113
102114 final JsonArray sections = initialData .getObject ("contents" ).getObject ("twoColumnSearchResultsRenderer" )
103115 .getObject ("primaryContents" ).getObject ("sectionListRenderer" ).getArray ("contents" );
104116
105117 Page nextPage = null ;
106118
107- for (Object section : sections ) {
108- final JsonObject itemSectionRenderer = ((JsonObject ) section ).getObject ("itemSectionRenderer" );
119+ for (final Object section : sections ) {
120+ if (((JsonObject ) section ).has ("itemSectionRenderer" )) {
121+ final JsonObject itemSectionRenderer = ((JsonObject ) section ).getObject ("itemSectionRenderer" );
109122
110- collectStreamsFrom (collector , itemSectionRenderer .getArray ("contents" ));
123+ collectStreamsFrom (collector , itemSectionRenderer .getArray ("contents" ));
111124
112- nextPage = getNextPageFrom (itemSectionRenderer .getArray ("continuations" ));
125+ nextPage = getNextPageFrom (itemSectionRenderer .getArray ("continuations" ));
126+ } else if (((JsonObject ) section ).has ("continuationItemRenderer" )) {
127+ nextPage = getNewNextPageFrom (((JsonObject ) section ).getObject ("continuationItemRenderer" ));
128+ }
113129 }
114130
115131 return new InfoItemsPage <>(collector , nextPage );
@@ -122,15 +138,58 @@ public InfoItemsPage<InfoItem> getPage(final Page page) throws IOException, Extr
122138 }
123139
124140 final InfoItemsSearchCollector collector = new InfoItemsSearchCollector (getServiceId ());
125- final JsonArray ajaxJson = getJsonResponse (page .getUrl (), getExtractorLocalization ());
126141
127- final JsonObject itemSectionRenderer = ajaxJson .getObject (1 ).getObject ("response" )
128- .getObject ("continuationContents" ).getObject ("itemSectionContinuation" );
142+ if (page .getId () == null ) {
143+ final JsonArray ajaxJson = getJsonResponse (page .getUrl (), getExtractorLocalization ());
144+
145+ final JsonObject itemSectionContinuation = ajaxJson .getObject (1 ).getObject ("response" )
146+ .getObject ("continuationContents" ).getObject ("itemSectionContinuation" );
147+
148+ collectStreamsFrom (collector , itemSectionContinuation .getArray ("contents" ));
149+ final JsonArray continuations = itemSectionContinuation .getArray ("continuations" );
150+
151+ return new InfoItemsPage <>(collector , getNextPageFrom (continuations ));
152+ } else {
153+ // @formatter:off
154+ final byte [] json = JsonWriter .string ()
155+ .object ()
156+ .object ("context" )
157+ .object ("client" )
158+ .value ("hl" , "en" )
159+ .value ("gl" , getExtractorContentCountry ().getCountryCode ())
160+ .value ("clientName" , "WEB" )
161+ .value ("clientVersion" , getClientVersion ())
162+ .value ("utcOffsetMinutes" , 0 )
163+ .end ()
164+ .object ("request" ).end ()
165+ .object ("user" ).end ()
166+ .end ()
167+ .value ("continuation" , page .getId ())
168+ .end ().done ().getBytes ("UTF-8" );
169+ // @formatter:on
170+
171+ final Map <String , List <String >> headers = new HashMap <>();
172+ headers .put ("Origin" , Collections .singletonList ("https://www.youtube.com" ));
173+ headers .put ("Referer" , Collections .singletonList (this .getUrl ()));
174+ headers .put ("Content-Type" , Collections .singletonList ("application/json" ));
175+
176+ final String responseBody = getValidJsonResponseBody (getDownloader ().post (page .getUrl (), headers , json ));
177+
178+ final JsonObject ajaxJson ;
179+ try {
180+ ajaxJson = JsonParser .object ().from (responseBody );
181+ } catch (JsonParserException e ) {
182+ throw new ParsingException ("Could not parse JSON" , e );
183+ }
129184
130- collectStreamsFrom ( collector , itemSectionRenderer .getArray ("contents" ));
131- final JsonArray continuations = itemSectionRenderer . getArray ("continuations " );
185+ final JsonArray continuationItems = ajaxJson .getArray ("onResponseReceivedCommands" )
186+ . getObject ( 0 ). getObject ( "appendContinuationItemsAction" ). getArray ("continuationItems " );
132187
133- return new InfoItemsPage <>(collector , getNextPageFrom (continuations ));
188+ final JsonArray contents = continuationItems .getObject (0 ).getObject ("itemSectionRenderer" ).getArray ("contents" );
189+ collectStreamsFrom (collector , contents );
190+
191+ return new InfoItemsPage <>(collector , getNewNextPageFrom (continuationItems .getObject (1 ).getObject ("continuationItemRenderer" )));
192+ }
134193 }
135194
136195 private void collectStreamsFrom (final InfoItemsSearchCollector collector , final JsonArray videos ) throws NothingFoundException , ParsingException {
@@ -162,4 +221,17 @@ private Page getNextPageFrom(final JsonArray continuations) throws ParsingExcept
162221 return new Page (getUrl () + "&pbj=1&ctoken=" + continuation + "&continuation=" + continuation
163222 + "&itct=" + clickTrackingParams );
164223 }
224+
225+ private Page getNewNextPageFrom (final JsonObject continuationItemRenderer ) throws IOException , ExtractionException {
226+ if (isNullOrEmpty (continuationItemRenderer )) {
227+ return null ;
228+ }
229+
230+ final String token = continuationItemRenderer .getObject ("continuationEndpoint" )
231+ .getObject ("continuationCommand" ).getString ("token" );
232+
233+ final String url = "https://www.youtube.com/youtubei/v1/search?key=" + getKey ();
234+
235+ return new Page (url , token );
236+ }
165237}
0 commit comments