11package org .schabi .newpipe .extractor .services .youtube ;
22
3+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .defaultAlertsCheck ;
4+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getJsonPostResponse ;
5+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getTextFromObject ;
6+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .hasArtistOrVerifiedIconBadgeAttachment ;
7+ import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .prepareDesktopJsonBuilder ;
8+ import static org .schabi .newpipe .extractor .utils .Utils .isNullOrEmpty ;
9+
310import com .grack .nanojson .JsonObject ;
411import com .grack .nanojson .JsonWriter ;
12+
513import org .schabi .newpipe .extractor .exceptions .ContentNotAvailableException ;
614import org .schabi .newpipe .extractor .exceptions .ExtractionException ;
715import org .schabi .newpipe .extractor .exceptions .ParsingException ;
816import org .schabi .newpipe .extractor .localization .ContentCountry ;
917import org .schabi .newpipe .extractor .localization .Localization ;
1018
11- import javax .annotation .Nonnull ;
12- import javax .annotation .Nullable ;
1319import java .io .IOException ;
1420import java .io .Serializable ;
1521import java .nio .charset .StandardCharsets ;
1622import java .util .Optional ;
1723
18- import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .defaultAlertsCheck ;
19- import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getJsonPostResponse ;
20- import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getTextFromObject ;
21- import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .hasArtistOrVerifiedIconBadgeAttachment ;
22- import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .prepareDesktopJsonBuilder ;
23- import static org .schabi .newpipe .extractor .utils .Utils .isNullOrEmpty ;
24+ import javax .annotation .Nonnull ;
25+ import javax .annotation .Nullable ;
2426
2527/**
2628 * Shared functions for extracting YouTube channel pages and tabs.
@@ -65,25 +67,42 @@ public static String resolveChannelId(@Nonnull final String idOrPath)
6567 // URL, then no information about the channel associated with this URL was found,
6668 // so the unresolved url will be returned.
6769 if (!channelId [0 ].equals ("channel" )) {
68- final byte [] body = JsonWriter .string (
69- prepareDesktopJsonBuilder (Localization .DEFAULT , ContentCountry .DEFAULT )
70- .value ("url" , "https://www.youtube.com/" + idOrPath )
70+ String urlToResolve = "https://www.youtube.com/" + idOrPath ;
71+
72+ JsonObject endpoint = new JsonObject ();
73+ String webPageType = "" ;
74+ // Try to resolve YT channel redirects
75+ // It works like that:
76+ // @TheDailyShow
77+ // -> resolves to thedailyshow
78+ // -> resolves to the id: UCwWhs_6x42TyRM4Wstoq8HA
79+ for (int tries = 0 ;
80+ urlToResolve != null && tries < 3 ;
81+ tries ++) {
82+ final byte [] body = JsonWriter .string (
83+ prepareDesktopJsonBuilder (Localization .DEFAULT , ContentCountry .DEFAULT )
84+ .value ("url" , urlToResolve )
7185 .done ())
7286 .getBytes (StandardCharsets .UTF_8 );
7387
74- final JsonObject jsonResponse = getJsonPostResponse (
88+ final JsonObject jsonResponse = getJsonPostResponse (
7589 "navigation/resolve_url" , body , Localization .DEFAULT );
7690
77- checkIfChannelResponseIsValid (jsonResponse );
91+ checkIfChannelResponseIsValid (jsonResponse );
7892
79- final JsonObject endpoint = jsonResponse .getObject ("endpoint" );
93+ endpoint = jsonResponse .getObject ("endpoint" );
8094
81- final String webPageType = endpoint .getObject ("commandMetadata" )
95+ webPageType = endpoint .getObject ("commandMetadata" )
8296 .getObject ("webCommandMetadata" )
8397 .getString ("webPageType" , "" );
8498
85- final JsonObject browseEndpoint = endpoint .getObject (BROWSE_ENDPOINT );
86- final String browseId = browseEndpoint .getString (BROWSE_ID , "" );
99+ urlToResolve = "WEB_PAGE_TYPE_UNKNOWN" .equals (webPageType )
100+ ? endpoint .getObject ("urlEndpoint" ).getString ("url" )
101+ : null ;
102+ }
103+
104+ final String browseId = endpoint .getObject (BROWSE_ENDPOINT )
105+ .getString (BROWSE_ID , "" );
87106
88107 if (webPageType .equalsIgnoreCase ("WEB_PAGE_TYPE_BROWSE" )
89108 || webPageType .equalsIgnoreCase ("WEB_PAGE_TYPE_CHANNEL" )
@@ -94,6 +113,11 @@ public static String resolveChannelId(@Nonnull final String idOrPath)
94113
95114 return browseId ;
96115 }
116+
117+ // Otherwise the code after that will run into an IndexOutOfBoundsException
118+ if (channelId .length < 2 ) {
119+ throw new ExtractionException ("Failed to resolve channelId for " + idOrPath );
120+ }
97121 }
98122
99123 // return the unresolved URL
0 commit comments