2525import static org .schabi .newpipe .extractor .utils .Utils .HTTPS ;
2626import static org .schabi .newpipe .extractor .utils .Utils .getStringResultFromRegexArray ;
2727import static org .schabi .newpipe .extractor .utils .Utils .isNullOrEmpty ;
28- import static java .util .Collections .singletonList ;
2928
3029import com .grack .nanojson .JsonArray ;
3130import com .grack .nanojson .JsonBuilder ;
6160import java .time .ZoneOffset ;
6261import java .time .format .DateTimeParseException ;
6362import java .util .ArrayList ;
64- import java .util .Collections ;
6563import java .util .HashMap ;
6664import java .util .List ;
6765import java .util .Locale ;
@@ -92,6 +90,11 @@ private YoutubeParsingHelper() {
9290 public static final String YOUTUBEI_V1_GAPIS_URL =
9391 "https://youtubei.googleapis.com/youtubei/v1/" ;
9492
93+ /**
94+ * The base URL of YouTube Music.
95+ */
96+ private static final String YOUTUBE_MUSIC_URL = "https://music.youtube.com" ;
97+
9598 /**
9699 * A parameter to disable pretty-printed response of InnerTube requests, to reduce response
97100 * sizes.
@@ -554,9 +557,7 @@ public static boolean areHardcodedClientVersionAndKeyValid()
554557 .end ().done ().getBytes (StandardCharsets .UTF_8 );
555558 // @formatter:on
556559
557- final Map <String , List <String >> headers = new HashMap <>();
558- headers .put ("X-YouTube-Client-Name" , singletonList ("1" ));
559- headers .put ("X-YouTube-Client-Version" , singletonList (HARDCODED_CLIENT_VERSION ));
560+ final var headers = getClientHeaders ("1" , HARDCODED_CLIENT_VERSION );
560561
561562 // This endpoint is fetched by the YouTube website to get the items of its main menu and is
562563 // pretty lightweight (around 30kB)
@@ -578,9 +579,7 @@ private static void extractClientVersionAndKeyFromSwJs()
578579 return ;
579580 }
580581 final String url = "https://www.youtube.com/sw.js" ;
581- final Map <String , List <String >> headers = new HashMap <>();
582- headers .put ("Origin" , singletonList ("https://www.youtube.com" ));
583- headers .put ("Referer" , singletonList ("https://www.youtube.com" ));
582+ final var headers = getOriginReferrerHeaders ("https://www.youtube.com" );
584583 final String response = getDownloader ().get (url , headers ).responseBody ();
585584 try {
586585 clientVersion = getStringResultFromRegexArray (response ,
@@ -799,11 +798,9 @@ public static boolean isHardcodedYoutubeMusicKeyValid() throws IOException,
799798 .end ().done ().getBytes (StandardCharsets .UTF_8 );
800799 // @formatter:on
801800
802- final Map <String , List <String >> headers = new HashMap <>();
803- headers .put ("X-YouTube-Client-Name" , singletonList (HARDCODED_YOUTUBE_MUSIC_KEY [1 ]));
804- headers .put ("X-YouTube-Client-Version" , singletonList (HARDCODED_YOUTUBE_MUSIC_KEY [2 ]));
805- headers .put ("Origin" , singletonList ("https://music.youtube.com" ));
806- headers .put ("Referer" , singletonList ("https://music.youtube.com" ));
801+ final var headers = new HashMap <>(getOriginReferrerHeaders (YOUTUBE_MUSIC_URL ));
802+ headers .putAll (getClientHeaders (HARDCODED_YOUTUBE_MUSIC_KEY [1 ],
803+ HARDCODED_YOUTUBE_MUSIC_KEY [2 ]));
807804
808805 final Response response = getDownloader ().postWithContentTypeJson (url , headers , json );
809806 // Ensure to have a valid response
@@ -826,14 +823,12 @@ public static String[] getYoutubeMusicKey()
826823
827824 try {
828825 final String url = "https://music.youtube.com/sw.js" ;
829- final Map <String , List <String >> headers = new HashMap <>();
830- headers .put ("Origin" , singletonList ("https://music.youtube.com" ));
831- headers .put ("Referer" , singletonList ("https://music.youtube.com" ));
826+ final var headers = getOriginReferrerHeaders ("https://music.youtube.com" );
832827 final String response = getDownloader ().get (url , headers ).responseBody ();
833- musicClientVersion = getStringResultFromRegexArray (response ,
834- INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
835- musicKey = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
836- musicClientName = Parser .matchGroup1 (INNERTUBE_CLIENT_NAME_REGEX , response );
828+ musicClientVersion = getStringResultFromRegexArray (response ,
829+ INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
830+ musicKey = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
831+ musicClientName = Parser .matchGroup1 (INNERTUBE_CLIENT_NAME_REGEX , response );
837832 } catch (final Exception e ) {
838833 final String url = "https://music.youtube.com/?ucbcb=1" ;
839834 final String html = getDownloader ().get (url , getCookieHeader ()).responseBody ();
@@ -1176,8 +1171,7 @@ public static JsonObject getJsonPostResponse(final String endpoint,
11761171 final byte [] body ,
11771172 final Localization localization )
11781173 throws IOException , ExtractionException {
1179- final Map <String , List <String >> headers = new HashMap <>();
1180- addYouTubeHeaders (headers );
1174+ final var headers = getYouTubeHeaders ();
11811175
11821176 return JsonUtils .toJsonObject (getValidJsonResponseBody (
11831177 getDownloader ().postWithContentTypeJson (YOUTUBEI_V1_URL + endpoint + "?key="
@@ -1209,9 +1203,8 @@ private static JsonObject getMobilePostResponse(
12091203 @ Nonnull final String userAgent ,
12101204 @ Nonnull final String innerTubeApiKey ,
12111205 @ Nullable final String endPartOfUrlRequest ) throws IOException , ExtractionException {
1212- final Map <String , List <String >> headers = new HashMap <>();
1213- headers .put ("User-Agent" , singletonList (userAgent ));
1214- headers .put ("X-Goog-Api-Format-Version" , singletonList ("2" ));
1206+ final var headers = Map .of ("User-Agent" , List .of (userAgent ),
1207+ "X-Goog-Api-Format-Version" , List .of ("2" ));
12151208
12161209 final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?key=" + innerTubeApiKey
12171210 + DISABLE_PRETTY_PRINT_PARAMETER ;
@@ -1423,60 +1416,68 @@ public static String getIosUserAgent(@Nullable final Localization localization)
14231416 + ")" ;
14241417 }
14251418
1419+ /**
1420+ * Returns a {@link Map} containing the required YouTube Music headers.
1421+ */
14261422 @ Nonnull
14271423 public static Map <String , List <String >> getYoutubeMusicHeaders () {
1428- final Map <String , List <String >> headers = new HashMap <>();
1429- headers .put ("X-YouTube-Client-Name" , Collections .singletonList (youtubeMusicKey [1 ]));
1430- headers .put ("X-YouTube-Client-Version" , Collections .singletonList (youtubeMusicKey [2 ]));
1431- headers .put ("Origin" , Collections .singletonList ("https://music.youtube.com" ));
1432- headers .put ("Referer" , Collections .singletonList ("https://music.youtube.com" ));
1424+ final var headers = new HashMap <>(getOriginReferrerHeaders (YOUTUBE_MUSIC_URL ));
1425+ headers .putAll (getClientHeaders (youtubeMusicKey [1 ], youtubeMusicKey [2 ]));
14331426 return headers ;
14341427 }
14351428
14361429 /**
1437- * Add required headers and cookies to an existing headers Map.
1438- * @see #addClientInfoHeaders(Map)
1439- * @see #addCookieHeader(Map)
1430+ * Returns a {@link Map} containing the required YouTube headers, including the
1431+ * <code>CONSENT</code> cookie to prevent redirects to <code>consent.youtube.com</code>
14401432 */
1441- public static void addYouTubeHeaders (final Map <String , List <String >> headers )
1442- throws IOException , ExtractionException {
1443- addClientInfoHeaders (headers );
1444- addCookieHeader (headers );
1433+ public static Map <String , List <String >> getYouTubeHeaders ()
1434+ throws ExtractionException , IOException {
1435+ final var headers = getClientInfoHeaders ();
1436+ headers .put ("Cookie" , List .of (generateConsentCookie ()));
1437+ return headers ;
14451438 }
14461439
14471440 /**
1448- * Add the <code>X-YouTube-Client-Name</code>, <code>X-YouTube-Client-Version</code>,
1449- * <code>Origin</code>, and <code>Referer</code> headers.
1450- * @param headers The headers which should be completed
1441+ * Returns a {@link Map} containing the {@code X-YouTube-Client-Name},
1442+ * {@code X-YouTube-Client-Version}, {@code Origin}, and {@code Referer} headers.
14511443 */
1452- public static void addClientInfoHeaders (@ Nonnull final Map <String , List <String >> headers )
1453- throws IOException , ExtractionException {
1454- headers .computeIfAbsent ("Origin" , k -> singletonList ("https://www.youtube.com" ));
1455- headers .computeIfAbsent ("Referer" , k -> singletonList ("https://www.youtube.com" ));
1456- headers .computeIfAbsent ("X-YouTube-Client-Name" , k -> singletonList ("1" ));
1457- if (headers .get ("X-YouTube-Client-Version" ) == null ) {
1458- headers .put ("X-YouTube-Client-Version" , singletonList (getClientVersion ()));
1459- }
1444+ public static Map <String , List <String >> getClientInfoHeaders ()
1445+ throws ExtractionException , IOException {
1446+ final var headers = new HashMap <>(getOriginReferrerHeaders ("https://www.youtube.com" ));
1447+ headers .putAll (getClientHeaders ("1" , getClientVersion ()));
1448+ return headers ;
14601449 }
14611450
14621451 /**
1463- * Create a map with the required cookie header.
1464- * @return A singleton map containing the header.
1452+ * Returns an unmodifiable {@link Map} containing the {@code Origin} and {@code Referer}
1453+ * headers set to the given URL.
1454+ *
1455+ * @param url The URL to be set as the origin and referrer.
14651456 */
1466- public static Map <String , List <String >> getCookieHeader () {
1467- return Collections .singletonMap ("Cookie" , singletonList (generateConsentCookie ()));
1457+ private static Map <String , List <String >> getOriginReferrerHeaders (@ Nonnull final String url ) {
1458+ final var urlList = List .of (url );
1459+ return Map .of ("Origin" , urlList , "Referer" , urlList );
14681460 }
14691461
14701462 /**
1471- * Add the <code>CONSENT</code> cookie to prevent redirect to <code>consent.youtube.com</code>
1472- * @param headers the headers which should be completed
1463+ * Returns an unmodifiable {@link Map} containing the {@code X-YouTube-Client-Name} and
1464+ * {@code X-YouTube-Client-Version} headers.
1465+ *
1466+ * @param name The X-YouTube-Client-Name value.
1467+ * @param version X-YouTube-Client-Version value.
14731468 */
1474- public static void addCookieHeader (@ Nonnull final Map <String , List <String >> headers ) {
1475- if (headers .get ("Cookie" ) == null ) {
1476- headers .put ("Cookie" , Collections .singletonList (generateConsentCookie ()));
1477- } else {
1478- headers .get ("Cookie" ).add (generateConsentCookie ());
1479- }
1469+ private static Map <String , List <String >> getClientHeaders (@ Nonnull final String name ,
1470+ @ Nonnull final String version ) {
1471+ return Map .of ("X-YouTube-Client-Name" , List .of (name ),
1472+ "X-YouTube-Client-Version" , List .of (version ));
1473+ }
1474+
1475+ /**
1476+ * Create a map with the required cookie header.
1477+ * @return A singleton map containing the header.
1478+ */
1479+ public static Map <String , List <String >> getCookieHeader () {
1480+ return Map .of ("Cookie" , List .of (generateConsentCookie ()));
14801481 }
14811482
14821483 @ Nonnull
0 commit comments