Merge pull request #986 from Isira-Seneviratne/Static_maps

Use immutable Map factory methods.
This commit is contained in:
Stypox 2023-01-02 18:11:14 +01:00 committed by GitHub
commit 45636b0d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 115 deletions

View File

@ -4,8 +4,6 @@ import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory; import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -14,27 +12,16 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac
private static final PeertubeTrendingLinkHandlerFactory INSTANCE private static final PeertubeTrendingLinkHandlerFactory INSTANCE
= new PeertubeTrendingLinkHandlerFactory(); = new PeertubeTrendingLinkHandlerFactory();
public static final Map<String, String> KIOSK_MAP;
public static final Map<String, String> REVERSE_KIOSK_MAP;
public static final String KIOSK_TRENDING = "Trending"; public static final String KIOSK_TRENDING = "Trending";
public static final String KIOSK_MOST_LIKED = "Most liked"; public static final String KIOSK_MOST_LIKED = "Most liked";
public static final String KIOSK_RECENT = "Recently added"; public static final String KIOSK_RECENT = "Recently added";
public static final String KIOSK_LOCAL = "Local"; public static final String KIOSK_LOCAL = "Local";
static { public static final Map<String, String> KIOSK_MAP = Map.of(
final Map<String, String> map = new HashMap<>(); KIOSK_TRENDING, "%s/api/v1/videos?sort=-trending",
map.put(KIOSK_TRENDING, "%s/api/v1/videos?sort=-trending"); KIOSK_MOST_LIKED, "%s/api/v1/videos?sort=-likes",
map.put(KIOSK_MOST_LIKED, "%s/api/v1/videos?sort=-likes"); KIOSK_RECENT, "%s/api/v1/videos?sort=-publishedAt",
map.put(KIOSK_RECENT, "%s/api/v1/videos?sort=-publishedAt"); KIOSK_LOCAL, "%s/api/v1/videos?sort=-publishedAt&filter=local");
map.put(KIOSK_LOCAL, "%s/api/v1/videos?sort=-publishedAt&filter=local");
KIOSK_MAP = Collections.unmodifiableMap(map);
final Map<String, String> reverseMap = new HashMap<>();
for (final Map.Entry<String, String> entry : KIOSK_MAP.entrySet()) {
reverseMap.put(entry.getValue(), entry.getKey());
}
REVERSE_KIOSK_MAP = Collections.unmodifiableMap(reverseMap);
}
public static PeertubeTrendingLinkHandlerFactory getInstance() { public static PeertubeTrendingLinkHandlerFactory getInstance() {
return INSTANCE; return INSTANCE;
@ -66,10 +53,12 @@ public final class PeertubeTrendingLinkHandlerFactory extends ListLinkHandlerFac
return KIOSK_RECENT; return KIOSK_RECENT;
} else if (cleanUrl.contains("/videos/local")) { } else if (cleanUrl.contains("/videos/local")) {
return KIOSK_LOCAL; return KIOSK_LOCAL;
} else if (REVERSE_KIOSK_MAP.containsKey(cleanUrl)) {
return REVERSE_KIOSK_MAP.get(cleanUrl);
} else { } else {
throw new ParsingException("no id found for this url"); return KIOSK_MAP.entrySet().stream()
.filter(entry -> cleanUrl.equals(entry.getValue()))
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() -> new ParsingException("no id found for this url"));
} }
} }

View File

@ -64,8 +64,7 @@ public final class SoundcloudParsingHelper {
// The one containing the client id will likely be the last one // The one containing the client id will likely be the last one
Collections.reverse(possibleScripts); Collections.reverse(possibleScripts);
final Map<String, List<String>> headers = Collections.singletonMap("Range", final var headers = Map.of("Range", List.of("bytes=0-50000"));
Collections.singletonList("bytes=0-50000"));
for (final Element element : possibleScripts) { for (final Element element : possibleScripts) {
final String srcUrl = element.attr("src"); final String srcUrl = element.attr("src");

View File

@ -25,7 +25,6 @@ import static org.schabi.newpipe.extractor.utils.Utils.HTTP;
import static org.schabi.newpipe.extractor.utils.Utils.HTTPS; import static org.schabi.newpipe.extractor.utils.Utils.HTTPS;
import static org.schabi.newpipe.extractor.utils.Utils.getStringResultFromRegexArray; import static org.schabi.newpipe.extractor.utils.Utils.getStringResultFromRegexArray;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import static java.util.Collections.singletonList;
import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonBuilder; import com.grack.nanojson.JsonBuilder;
@ -61,7 +60,6 @@ import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -92,6 +90,11 @@ public final class YoutubeParsingHelper {
public static final String YOUTUBEI_V1_GAPIS_URL = public static final String YOUTUBEI_V1_GAPIS_URL =
"https://youtubei.googleapis.com/youtubei/v1/"; "https://youtubei.googleapis.com/youtubei/v1/";
/**
* The base URL of YouTube Music.
*/
private static final String YOUTUBE_MUSIC_URL = "https://music.youtube.com";
/** /**
* A parameter to disable pretty-printed response of InnerTube requests, to reduce response * A parameter to disable pretty-printed response of InnerTube requests, to reduce response
* sizes. * sizes.
@ -554,9 +557,7 @@ public final class YoutubeParsingHelper {
.end().done().getBytes(StandardCharsets.UTF_8); .end().done().getBytes(StandardCharsets.UTF_8);
// @formatter:on // @formatter:on
final Map<String, List<String>> headers = new HashMap<>(); final var headers = getClientHeaders("1", HARDCODED_CLIENT_VERSION);
headers.put("X-YouTube-Client-Name", singletonList("1"));
headers.put("X-YouTube-Client-Version", singletonList(HARDCODED_CLIENT_VERSION));
// This endpoint is fetched by the YouTube website to get the items of its main menu and is // This endpoint is fetched by the YouTube website to get the items of its main menu and is
// pretty lightweight (around 30kB) // pretty lightweight (around 30kB)
@ -578,9 +579,7 @@ public final class YoutubeParsingHelper {
return; return;
} }
final String url = "https://www.youtube.com/sw.js"; final String url = "https://www.youtube.com/sw.js";
final Map<String, List<String>> headers = new HashMap<>(); final var headers = getOriginReferrerHeaders("https://www.youtube.com");
headers.put("Origin", singletonList("https://www.youtube.com"));
headers.put("Referer", singletonList("https://www.youtube.com"));
final String response = getDownloader().get(url, headers).responseBody(); final String response = getDownloader().get(url, headers).responseBody();
try { try {
clientVersion = getStringResultFromRegexArray(response, clientVersion = getStringResultFromRegexArray(response,
@ -799,11 +798,9 @@ public final class YoutubeParsingHelper {
.end().done().getBytes(StandardCharsets.UTF_8); .end().done().getBytes(StandardCharsets.UTF_8);
// @formatter:on // @formatter:on
final Map<String, List<String>> headers = new HashMap<>(); final var headers = new HashMap<>(getOriginReferrerHeaders(YOUTUBE_MUSIC_URL));
headers.put("X-YouTube-Client-Name", singletonList(HARDCODED_YOUTUBE_MUSIC_KEY[1])); headers.putAll(getClientHeaders(HARDCODED_YOUTUBE_MUSIC_KEY[1],
headers.put("X-YouTube-Client-Version", singletonList(HARDCODED_YOUTUBE_MUSIC_KEY[2])); HARDCODED_YOUTUBE_MUSIC_KEY[2]));
headers.put("Origin", singletonList("https://music.youtube.com"));
headers.put("Referer", singletonList("https://music.youtube.com"));
final Response response = getDownloader().postWithContentTypeJson(url, headers, json); final Response response = getDownloader().postWithContentTypeJson(url, headers, json);
// Ensure to have a valid response // Ensure to have a valid response
@ -826,9 +823,7 @@ public final class YoutubeParsingHelper {
try { try {
final String url = "https://music.youtube.com/sw.js"; final String url = "https://music.youtube.com/sw.js";
final Map<String, List<String>> headers = new HashMap<>(); final var headers = getOriginReferrerHeaders("https://music.youtube.com");
headers.put("Origin", singletonList("https://music.youtube.com"));
headers.put("Referer", singletonList("https://music.youtube.com"));
final String response = getDownloader().get(url, headers).responseBody(); final String response = getDownloader().get(url, headers).responseBody();
musicClientVersion = getStringResultFromRegexArray(response, musicClientVersion = getStringResultFromRegexArray(response,
INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES, 1); INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES, 1);
@ -1176,8 +1171,7 @@ public final class YoutubeParsingHelper {
final byte[] body, final byte[] body,
final Localization localization) final Localization localization)
throws IOException, ExtractionException { throws IOException, ExtractionException {
final Map<String, List<String>> headers = new HashMap<>(); final var headers = getYouTubeHeaders();
addYouTubeHeaders(headers);
return JsonUtils.toJsonObject(getValidJsonResponseBody( return JsonUtils.toJsonObject(getValidJsonResponseBody(
getDownloader().postWithContentTypeJson(YOUTUBEI_V1_URL + endpoint + "?key=" getDownloader().postWithContentTypeJson(YOUTUBEI_V1_URL + endpoint + "?key="
@ -1209,9 +1203,8 @@ public final class YoutubeParsingHelper {
@Nonnull final String userAgent, @Nonnull final String userAgent,
@Nonnull final String innerTubeApiKey, @Nonnull final String innerTubeApiKey,
@Nullable final String endPartOfUrlRequest) throws IOException, ExtractionException { @Nullable final String endPartOfUrlRequest) throws IOException, ExtractionException {
final Map<String, List<String>> headers = new HashMap<>(); final var headers = Map.of("User-Agent", List.of(userAgent),
headers.put("User-Agent", singletonList(userAgent)); "X-Goog-Api-Format-Version", List.of("2"));
headers.put("X-Goog-Api-Format-Version", singletonList("2"));
final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?key=" + innerTubeApiKey final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?key=" + innerTubeApiKey
+ DISABLE_PRETTY_PRINT_PARAMETER; + DISABLE_PRETTY_PRINT_PARAMETER;
@ -1423,40 +1416,60 @@ public final class YoutubeParsingHelper {
+ ")"; + ")";
} }
/**
* Returns a {@link Map} containing the required YouTube Music headers.
*/
@Nonnull @Nonnull
public static Map<String, List<String>> getYoutubeMusicHeaders() { public static Map<String, List<String>> getYoutubeMusicHeaders() {
final Map<String, List<String>> headers = new HashMap<>(); final var headers = new HashMap<>(getOriginReferrerHeaders(YOUTUBE_MUSIC_URL));
headers.put("X-YouTube-Client-Name", Collections.singletonList(youtubeMusicKey[1])); headers.putAll(getClientHeaders(youtubeMusicKey[1], youtubeMusicKey[2]));
headers.put("X-YouTube-Client-Version", Collections.singletonList(youtubeMusicKey[2]));
headers.put("Origin", Collections.singletonList("https://music.youtube.com"));
headers.put("Referer", Collections.singletonList("https://music.youtube.com"));
return headers; return headers;
} }
/** /**
* Add required headers and cookies to an existing headers Map. * Returns a {@link Map} containing the required YouTube headers, including the
* @see #addClientInfoHeaders(Map) * <code>CONSENT</code> cookie to prevent redirects to <code>consent.youtube.com</code>
* @see #addCookieHeader(Map)
*/ */
public static void addYouTubeHeaders(final Map<String, List<String>> headers) public static Map<String, List<String>> getYouTubeHeaders()
throws IOException, ExtractionException { throws ExtractionException, IOException {
addClientInfoHeaders(headers); final var headers = getClientInfoHeaders();
addCookieHeader(headers); headers.put("Cookie", List.of(generateConsentCookie()));
return headers;
} }
/** /**
* Add the <code>X-YouTube-Client-Name</code>, <code>X-YouTube-Client-Version</code>, * Returns a {@link Map} containing the {@code X-YouTube-Client-Name},
* <code>Origin</code>, and <code>Referer</code> headers. * {@code X-YouTube-Client-Version}, {@code Origin}, and {@code Referer} headers.
* @param headers The headers which should be completed
*/ */
public static void addClientInfoHeaders(@Nonnull final Map<String, List<String>> headers) public static Map<String, List<String>> getClientInfoHeaders()
throws IOException, ExtractionException { throws ExtractionException, IOException {
headers.computeIfAbsent("Origin", k -> singletonList("https://www.youtube.com")); final var headers = new HashMap<>(getOriginReferrerHeaders("https://www.youtube.com"));
headers.computeIfAbsent("Referer", k -> singletonList("https://www.youtube.com")); headers.putAll(getClientHeaders("1", getClientVersion()));
headers.computeIfAbsent("X-YouTube-Client-Name", k -> singletonList("1")); return headers;
if (headers.get("X-YouTube-Client-Version") == null) {
headers.put("X-YouTube-Client-Version", singletonList(getClientVersion()));
} }
/**
* Returns an unmodifiable {@link Map} containing the {@code Origin} and {@code Referer}
* headers set to the given URL.
*
* @param url The URL to be set as the origin and referrer.
*/
private static Map<String, List<String>> getOriginReferrerHeaders(@Nonnull final String url) {
final var urlList = List.of(url);
return Map.of("Origin", urlList, "Referer", urlList);
}
/**
* Returns an unmodifiable {@link Map} containing the {@code X-YouTube-Client-Name} and
* {@code X-YouTube-Client-Version} headers.
*
* @param name The X-YouTube-Client-Name value.
* @param version X-YouTube-Client-Version value.
*/
private static Map<String, List<String>> getClientHeaders(@Nonnull final String name,
@Nonnull final String version) {
return Map.of("X-YouTube-Client-Name", List.of(name),
"X-YouTube-Client-Version", List.of(version));
} }
/** /**
@ -1464,19 +1477,7 @@ public final class YoutubeParsingHelper {
* @return A singleton map containing the header. * @return A singleton map containing the header.
*/ */
public static Map<String, List<String>> getCookieHeader() { public static Map<String, List<String>> getCookieHeader() {
return Collections.singletonMap("Cookie", singletonList(generateConsentCookie())); return Map.of("Cookie", List.of(generateConsentCookie()));
}
/**
* Add the <code>CONSENT</code> cookie to prevent redirect to <code>consent.youtube.com</code>
* @param headers the headers which should be completed
*/
public static void addCookieHeader(@Nonnull final Map<String, List<String>> headers) {
if (headers.get("Cookie") == null) {
headers.put("Cookie", Collections.singletonList(generateConsentCookie()));
} else {
headers.get("Cookie").add(generateConsentCookie());
}
} }
@Nonnull @Nonnull

View File

@ -1,5 +1,14 @@
package org.schabi.newpipe.extractor.services.youtube.dashmanifestcreators; package org.schabi.newpipe.extractor.services.youtube.dashmanifestcreators;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getAndroidUserAgent;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getClientInfoHeaders;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getIosUserAgent;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isAndroidStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isIosStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isTvHtml5SimplyEmbeddedPlayerStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isWebStreamingUrl;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Downloader;
@ -13,6 +22,14 @@ import org.w3c.dom.DOMException;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
@ -25,24 +42,6 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getAndroidUserAgent;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getIosUserAgent;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isAndroidStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isIosStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isTvHtml5SimplyEmbeddedPlayerStreamingUrl;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isWebStreamingUrl;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
/** /**
* Utilities and constants for YouTube DASH manifest creators. * Utilities and constants for YouTube DASH manifest creators.
* *
@ -583,9 +582,9 @@ public final class YoutubeDashManifestCreatorsUtils {
} }
} else if (isAndroidStreamingUrl || isIosStreamingUrl) { } else if (isAndroidStreamingUrl || isIosStreamingUrl) {
try { try {
final Map<String, List<String>> headers = Collections.singletonMap("User-Agent", final var headers = Map.of("User-Agent",
Collections.singletonList(isAndroidStreamingUrl List.of(isAndroidStreamingUrl ? getAndroidUserAgent(null)
? getAndroidUserAgent(null) : getIosUserAgent(null))); : getIosUserAgent(null)));
final byte[] emptyBody = "".getBytes(StandardCharsets.UTF_8); final byte[] emptyBody = "".getBytes(StandardCharsets.UTF_8);
return downloader.post(baseStreamingUrl, headers, emptyBody); return downloader.post(baseStreamingUrl, headers, emptyBody);
} catch (final IOException | ExtractionException e) { } catch (final IOException | ExtractionException e) {
@ -705,9 +704,7 @@ public final class YoutubeDashManifestCreatorsUtils {
@Nonnull final String responseMimeTypeExpected) @Nonnull final String responseMimeTypeExpected)
throws CreationException { throws CreationException {
try { try {
final Map<String, List<String>> headers = new HashMap<>(); final var headers = getClientInfoHeaders();
headers.put("Origin", Collections.singletonList("https://www.youtube.com"));
headers.put("Referer", Collections.singletonList("https://www.youtube.com"));
String responseMimeType = ""; String responseMimeType = "";

View File

@ -2,11 +2,11 @@ package org.schabi.newpipe.extractor.services.youtube.extractors;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.DISABLE_PRETTY_PRINT_PARAMETER; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.DISABLE_PRETTY_PRINT_PARAMETER;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.YOUTUBEI_V1_URL; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.YOUTUBEI_V1_URL;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.addYouTubeHeaders;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.extractCookieValue; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.extractCookieValue;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.extractPlaylistTypeFromPlaylistId; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.extractPlaylistTypeFromPlaylistId;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getKey; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getKey;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getValidJsonResponseBody; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getValidJsonResponseBody;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getYouTubeHeaders;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareDesktopJsonBuilder; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareDesktopJsonBuilder;
import static org.schabi.newpipe.extractor.utils.Utils.getQueryValue; import static org.schabi.newpipe.extractor.utils.Utils.getQueryValue;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
@ -88,9 +88,8 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
final byte[] body = JsonWriter.string(jsonBody.done()).getBytes(StandardCharsets.UTF_8); final byte[] body = JsonWriter.string(jsonBody.done()).getBytes(StandardCharsets.UTF_8);
final Map<String, List<String>> headers = new HashMap<>();
// Cookie is required due to consent // Cookie is required due to consent
addYouTubeHeaders(headers); final var headers = getYouTubeHeaders();
final Response response = getDownloader().postWithContentTypeJson( final Response response = getDownloader().postWithContentTypeJson(
YOUTUBEI_V1_URL + "next?key=" + getKey() + DISABLE_PRETTY_PRINT_PARAMETER, YOUTUBEI_V1_URL + "next?key=" + getKey() + DISABLE_PRETTY_PRINT_PARAMETER,
@ -222,9 +221,8 @@ public class YoutubeMixPlaylistExtractor extends PlaylistExtractor {
} }
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId()); final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
final Map<String, List<String>> headers = new HashMap<>();
// Cookie is required due to consent // Cookie is required due to consent
addYouTubeHeaders(headers); final var headers = getYouTubeHeaders();
final Response response = getDownloader().postWithContentTypeJson(page.getUrl(), headers, final Response response = getDownloader().postWithContentTypeJson(page.getUrl(), headers,
page.getBody(), getExtractorLocalization()); page.getBody(), getExtractorLocalization());

View File

@ -14,6 +14,7 @@ import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonWriter; import com.grack.nanojson.JsonWriter;
import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.extractor.downloader.Downloader;
@ -29,11 +30,12 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class YoutubePlaylistExtractor extends PlaylistExtractor { public class YoutubePlaylistExtractor extends PlaylistExtractor {
// Names of some objects in JSON response frequently used in this class // Names of some objects in JSON response frequently used in this class
private static final String PLAYLIST_VIDEO_RENDERER = "playlistVideoRenderer"; private static final String PLAYLIST_VIDEO_RENDERER = "playlistVideoRenderer";