22
33import com .grack .nanojson .JsonArray ;
44import com .grack .nanojson .JsonObject ;
5-
65import org .schabi .newpipe .extractor .StreamingService ;
76import org .schabi .newpipe .extractor .channel .ChannelExtractor ;
87import org .schabi .newpipe .extractor .downloader .Downloader ;
1615import org .schabi .newpipe .extractor .stream .StreamInfoItemsCollector ;
1716import org .schabi .newpipe .extractor .utils .Utils ;
1817
19- import java .io .IOException ;
20-
2118import javax .annotation .Nonnull ;
19+ import java .io .IOException ;
2220
23- import static org .schabi .newpipe .extractor .services .youtube .linkHandler .YoutubeParsingHelper .fixThumbnailUrl ;
24- import static org .schabi .newpipe .extractor .services .youtube .linkHandler .YoutubeParsingHelper .getJsonResponse ;
25- import static org .schabi .newpipe .extractor .services .youtube .linkHandler .YoutubeParsingHelper .getTextFromObject ;
21+ import static org .schabi .newpipe .extractor .services .youtube .linkHandler .YoutubeParsingHelper .*;
22+ import static org .schabi .newpipe .extractor .utils .JsonUtils .*;
2623
2724/*
2825 * Created by Christian Schabesberger on 25.07.16.
@@ -49,15 +46,64 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
4946 private JsonObject initialData ;
5047 private JsonObject videoTab ;
5148
49+ /**
50+ * Some channels have response redirects and the only way to reliably get the id is by saving it.
51+ *<p>
52+ * "Movies & Shows":
53+ * <pre>
54+ * UCuJcl0Ju-gPDoksRjK1ya-w ┐
55+ * UChBfWrfBXL9wS6tQtgjt_OQ ├ UClgRkhTL3_hImCAmdLfDE4g
56+ * UCok7UTQQEP1Rsctxiv3gwSQ ┘
57+ * </pre>
58+ */
59+ private String redirectedChannelId ;
60+
5261 public YoutubeChannelExtractor (StreamingService service , ListLinkHandler linkHandler ) {
5362 super (service , linkHandler );
5463 }
5564
5665 @ Override
5766 public void onFetchPage (@ Nonnull Downloader downloader ) throws IOException , ExtractionException {
58- final String url = super .getUrl () + "/videos?pbj=1&view=0&flow=grid" ;
67+ String url = super .getUrl () + "/videos?pbj=1&view=0&flow=grid" ;
68+ JsonArray ajaxJson = null ;
69+
70+ int level = 0 ;
71+ while (level < 3 ) {
72+ final JsonArray jsonResponse = getJsonResponse (url , getExtractorLocalization ());
73+
74+ final JsonObject endpoint = jsonResponse .getObject (1 , EMPTY_OBJECT )
75+ .getObject ("response" , EMPTY_OBJECT ).getArray ("onResponseReceivedActions" , EMPTY_ARRAY )
76+ .getObject (0 , EMPTY_OBJECT ).getObject ("navigateAction" , EMPTY_OBJECT )
77+ .getObject ("endpoint" , EMPTY_OBJECT );
78+
79+ final String webPageType = endpoint
80+ .getObject ("commandMetadata" , EMPTY_OBJECT )
81+ .getObject ("webCommandMetadata" , EMPTY_OBJECT )
82+ .getString ("webPageType" , EMPTY_STRING );
83+
84+ final String browseId = endpoint
85+ .getObject ("browseEndpoint" , EMPTY_OBJECT )
86+ .getString ("browseId" , EMPTY_STRING );
87+
88+ if (webPageType .equalsIgnoreCase ("WEB_PAGE_TYPE_BROWSE" ) && !browseId .isEmpty ()) {
89+
90+ if (!browseId .startsWith ("UC" )) {
91+ throw new ExtractionException ("Redirected id is not pointing to a channel" );
92+ }
93+
94+ url = "https://www.youtube.com/channel/" + browseId + "/videos?pbj=1&view=0&flow=grid" ;
95+ redirectedChannelId = browseId ;
96+ level ++;
97+ } else {
98+ ajaxJson = jsonResponse ;
99+ break ;
100+ }
101+ }
102+
103+ if (ajaxJson == null ) {
104+ throw new ExtractionException ("Could not fetch initial JSON data" );
105+ }
59106
60- final JsonArray ajaxJson = getJsonResponse (url , getExtractorLocalization ());
61107 initialData = ajaxJson .getObject (1 ).getObject ("response" );
62108 YoutubeParsingHelper .defaultAlertsCheck (initialData );
63109 }
@@ -84,10 +130,17 @@ public String getUrl() throws ParsingException {
84130 @ Nonnull
85131 @ Override
86132 public String getId () throws ParsingException {
87- try {
88- return initialData .getObject ("header" ).getObject ("c4TabbedHeaderRenderer" ).getString ("channelId" );
89- } catch (Exception e ) {
90- throw new ParsingException ("Could not get channel id" , e );
133+ final String channelId = initialData
134+ .getObject ("header" , EMPTY_OBJECT )
135+ .getObject ("c4TabbedHeaderRenderer" , EMPTY_OBJECT )
136+ .getString ("channelId" , EMPTY_STRING );
137+
138+ if (!channelId .isEmpty ()) {
139+ return channelId ;
140+ } else if (redirectedChannelId != null && !redirectedChannelId .isEmpty ()) {
141+ return redirectedChannelId ;
142+ } else {
143+ throw new ParsingException ("Could not get channel id" );
91144 }
92145 }
93146
0 commit comments