Update client version, fix some tests, update mocks and do some improvements
Add the origin and the referer headers with the https://www.youtube.com value for YouTube JSON POST requests. Don't add the consent cookie header for the requests which use the youtubei/innertube API because it's uneeded. Fix some tests and update YouTube mocks
This commit is contained in:
parent
b49ae547a3
commit
e075dd5a63
182 changed files with 21404 additions and 6602 deletions
|
@ -63,7 +63,7 @@ public class YoutubeParsingHelper {
|
||||||
private YoutubeParsingHelper() {
|
private YoutubeParsingHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String HARDCODED_CLIENT_VERSION = "2.20210413.07.00";
|
private static final String HARDCODED_CLIENT_VERSION = "2.20210420.07.00";
|
||||||
private static final String HARDCODED_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";
|
private static final String HARDCODED_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";
|
||||||
private static String clientVersion;
|
private static String clientVersion;
|
||||||
private static String key;
|
private static String key;
|
||||||
|
@ -308,7 +308,6 @@ public class YoutubeParsingHelper {
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
headers.put("X-YouTube-Client-Name", Collections.singletonList("1"));
|
headers.put("X-YouTube-Client-Name", Collections.singletonList("1"));
|
||||||
headers.put("X-YouTube-Client-Version", Collections.singletonList(HARDCODED_CLIENT_VERSION));
|
headers.put("X-YouTube-Client-Version", Collections.singletonList(HARDCODED_CLIENT_VERSION));
|
||||||
addCookieHeader(headers);
|
|
||||||
|
|
||||||
// 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)
|
||||||
|
@ -328,7 +327,9 @@ public class YoutubeParsingHelper {
|
||||||
if (!keyAndVersionExtracted) return;
|
if (!keyAndVersionExtracted) return;
|
||||||
// Don't provide a search term in order to have a smaller response
|
// Don't provide a search term in order to have a smaller response
|
||||||
final String url = "https://www.youtube.com/results?search_query=";
|
final String url = "https://www.youtube.com/results?search_query=";
|
||||||
final String html = getDownloader().get(url).responseBody();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
addCookieHeader(headers);
|
||||||
|
final String html = getDownloader().get(url, headers).responseBody();
|
||||||
final JsonObject initialData = getInitialData(html);
|
final JsonObject initialData = getInitialData(html);
|
||||||
final JsonArray serviceTrackingParams = initialData.getObject("responseContext")
|
final JsonArray serviceTrackingParams = initialData.getObject("responseContext")
|
||||||
.getArray("serviceTrackingParams");
|
.getArray("serviceTrackingParams");
|
||||||
|
@ -483,7 +484,6 @@ public class YoutubeParsingHelper {
|
||||||
headers.put("Origin", Collections.singletonList("https://music.youtube.com"));
|
headers.put("Origin", Collections.singletonList("https://music.youtube.com"));
|
||||||
headers.put("Referer", Collections.singletonList("music.youtube.com"));
|
headers.put("Referer", Collections.singletonList("music.youtube.com"));
|
||||||
headers.put("Content-Type", Collections.singletonList("application/json"));
|
headers.put("Content-Type", Collections.singletonList("application/json"));
|
||||||
addCookieHeader(headers);
|
|
||||||
|
|
||||||
final Response response = getDownloader().post(url, headers, json);
|
final Response response = getDownloader().post(url, headers, json);
|
||||||
final String responseBody = response.responseBody();
|
final String responseBody = response.responseBody();
|
||||||
|
@ -497,7 +497,9 @@ public class YoutubeParsingHelper {
|
||||||
if (areHardcodedYoutubeMusicKeysValid()) return youtubeMusicKeys = HARDCODED_YOUTUBE_MUSIC_KEYS;
|
if (areHardcodedYoutubeMusicKeysValid()) return youtubeMusicKeys = HARDCODED_YOUTUBE_MUSIC_KEYS;
|
||||||
|
|
||||||
final String url = "https://music.youtube.com/";
|
final String url = "https://music.youtube.com/";
|
||||||
final String html = getDownloader().get(url).responseBody();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
|
addCookieHeader(headers);
|
||||||
|
final String html = getDownloader().get(url, headers).responseBody();
|
||||||
|
|
||||||
String key;
|
String key;
|
||||||
try {
|
try {
|
||||||
|
@ -701,7 +703,7 @@ public class YoutubeParsingHelper {
|
||||||
final Localization localization)
|
final Localization localization)
|
||||||
throws IOException, ExtractionException {
|
throws IOException, ExtractionException {
|
||||||
final Map<String, List<String>> headers = new HashMap<>();
|
final Map<String, List<String>> headers = new HashMap<>();
|
||||||
addYouTubeHeaders(headers);
|
addClientInfoHeaders(headers);
|
||||||
|
|
||||||
final Response response = getDownloader().post("https://youtubei.googleapis.com/youtubei/v1/"
|
final Response response = getDownloader().post("https://youtubei.googleapis.com/youtubei/v1/"
|
||||||
+ endpoint + "?key=" + getKey(), headers, body, localization);
|
+ endpoint + "?key=" + getKey(), headers, body, localization);
|
||||||
|
@ -756,11 +758,18 @@ public class YoutubeParsingHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the <code>X-YouTube-Client-Name</code> and <code>X-YouTube-Client-Version</code> headers.
|
* Add the <code>X-YouTube-Client-Name</code>, <code>X-YouTube-Client-Version</code>,
|
||||||
|
* <code>Origin</code>, and <code>Referer</code> headers.
|
||||||
* @param headers The headers which should be completed
|
* @param headers The headers which should be completed
|
||||||
*/
|
*/
|
||||||
public static void addClientInfoHeaders(final Map<String, List<String>> headers)
|
public static void addClientInfoHeaders(final Map<String, List<String>> headers)
|
||||||
throws IOException, ExtractionException {
|
throws IOException, ExtractionException {
|
||||||
|
if (headers.get("Origin") == null) {
|
||||||
|
headers.put("Origin", Collections.singletonList("https://www.youtube.com"));
|
||||||
|
}
|
||||||
|
if (headers.get("Referer") == null) {
|
||||||
|
headers.put("Referer", Collections.singletonList("https://www.youtube.com"));
|
||||||
|
}
|
||||||
if (headers.get("X-YouTube-Client-Name") == null) {
|
if (headers.get("X-YouTube-Client-Name") == null) {
|
||||||
headers.put("X-YouTube-Client-Name", Collections.singletonList("1"));
|
headers.put("X-YouTube-Client-Name", Collections.singletonList("1"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,9 +199,7 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
|
||||||
|
|
||||||
if (contents.getObject(0).has("playlistSegmentRenderer")) {
|
if (contents.getObject(0).has("playlistSegmentRenderer")) {
|
||||||
for (final Object segment : contents) {
|
for (final Object segment : contents) {
|
||||||
if (((JsonObject) segment).getObject("playlistSegmentRenderer").has("trailer")) {
|
if (((JsonObject) segment).getObject("playlistSegmentRenderer")
|
||||||
collectTrailerFrom(collector, ((JsonObject) segment));
|
|
||||||
} else if (((JsonObject) segment).getObject("playlistSegmentRenderer")
|
|
||||||
.has("videoList")) {
|
.has("videoList")) {
|
||||||
collectStreamsFrom(collector, ((JsonObject) segment)
|
collectStreamsFrom(collector, ((JsonObject) segment)
|
||||||
.getObject("playlistSegmentRenderer").getObject("videoList")
|
.getObject("playlistSegmentRenderer").getObject("videoList")
|
||||||
|
@ -287,83 +285,4 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectTrailerFrom(final StreamInfoItemsCollector collector,
|
|
||||||
final JsonObject segment) {
|
|
||||||
collector.commit(new StreamInfoItemExtractor() {
|
|
||||||
@Override
|
|
||||||
public String getName() throws ParsingException {
|
|
||||||
return getTextFromObject(segment.getObject("playlistSegmentRenderer")
|
|
||||||
.getObject("title"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUrl() throws ParsingException {
|
|
||||||
return YoutubeStreamLinkHandlerFactory.getInstance()
|
|
||||||
.fromId(segment.getObject("playlistSegmentRenderer").getObject("trailer")
|
|
||||||
.getObject("playlistVideoPlayerRenderer").getString("videoId"))
|
|
||||||
.getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getThumbnailUrl() {
|
|
||||||
return "";
|
|
||||||
/*final JsonArray thumbnails = initialAjaxJson.getObject(1)
|
|
||||||
.getObject("playerResponse")
|
|
||||||
.getObject("videoDetails").getObject("thumbnail").getArray("thumbnails");
|
|
||||||
// the last thumbnail is the one with the highest resolution
|
|
||||||
final String url = thumbnails.getObject(thumbnails.size() - 1).getString("url");
|
|
||||||
return fixThumbnailUrl(url);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamType getStreamType() {
|
|
||||||
return StreamType.VIDEO_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAd() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDuration() throws ParsingException {
|
|
||||||
return YoutubeParsingHelper.parseDurationString(
|
|
||||||
getTextFromObject(segment.getObject("playlistSegmentRenderer")
|
|
||||||
.getObject("segmentAnnotation")).split("•")[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getViewCount() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUploaderName() throws ParsingException {
|
|
||||||
return YoutubePlaylistExtractor.this.getUploaderName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUploaderUrl() throws ParsingException {
|
|
||||||
return YoutubePlaylistExtractor.this.getUploaderUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUploaderVerified() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public String getTextualUploadDate() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public DateWrapper getUploadDate() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,14 +101,14 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
final Set<String> urls = new HashSet<>();
|
final Set<String> urls = new HashSet<>();
|
||||||
|
|
||||||
//Should work infinitely, but for testing purposes only 3 times
|
// Should work infinitely, but for testing purposes only 3 times
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
|
||||||
for (final StreamInfoItem item : streams.getItems()) {
|
for (final StreamInfoItem item : streams.getItems()) {
|
||||||
// TODO Duplicates are appearing
|
// TODO Duplicates are appearing
|
||||||
// assertFalse(urls.contains(item.getUrl()));
|
// assertFalse(urls.contains(item.getUrl()));
|
||||||
urls.add(item.getUrl());
|
urls.add(item.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,13 +179,13 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
final Set<String> urls = new HashSet<>();
|
final Set<String> urls = new HashSet<>();
|
||||||
|
|
||||||
//Should work infinitely, but for testing purposes only 3 times
|
// Should work infinitely, but for testing purposes only 3 times
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
for (final StreamInfoItem item : streams.getItems()) {
|
for (final StreamInfoItem item : streams.getItems()) {
|
||||||
// TODO Duplicates are appearing
|
// TODO Duplicates are appearing
|
||||||
// assertFalse(urls.contains(item.getUrl()));
|
// assertFalse(urls.contains(item.getUrl()));
|
||||||
urls.add(item.getUrl());
|
urls.add(item.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,14 +255,14 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
final Set<String> urls = new HashSet<>();
|
final Set<String> urls = new HashSet<>();
|
||||||
|
|
||||||
//Should work infinitely, but for testing purposes only 3 times
|
// Should work infinitely, but for testing purposes only 3 times
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
assertTrue(streams.hasNextPage());
|
assertTrue(streams.hasNextPage());
|
||||||
assertFalse(streams.getItems().isEmpty());
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
|
||||||
for (final StreamInfoItem item : streams.getItems()) {
|
for (final StreamInfoItem item : streams.getItems()) {
|
||||||
// TODO Duplicates are appearing
|
// TODO Duplicates are appearing
|
||||||
// assertFalse(urls.contains(item.getUrl()));
|
// assertFalse(urls.contains(item.getUrl()));
|
||||||
urls.add(item.getUrl());
|
urls.add(item.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ public class YoutubeStreamExtractorAgeRestrictedTest extends DefaultStreamExtrac
|
||||||
@Override public long expectedDislikeCountAtLeast() { return 38000; }
|
@Override public long expectedDislikeCountAtLeast() { return 38000; }
|
||||||
@Override public boolean expectedHasRelatedItems() { return false; } // no related videos (!)
|
@Override public boolean expectedHasRelatedItems() { return false; } // no related videos (!)
|
||||||
@Override public int expectedAgeLimit() { return 18; }
|
@Override public int expectedAgeLimit() { return 18; }
|
||||||
@Nullable @Override public String expectedErrorMessage() { return "Sign in to confirm your age"; }
|
// Broken, video is available with the embedded player
|
||||||
|
// @Nullable @Override public String expectedErrorMessage() { return "Sign in to confirm your age"; }
|
||||||
@Override public boolean expectedHasSubtitles() { return false; }
|
@Override public boolean expectedHasSubtitles() { return false; }
|
||||||
|
|
||||||
@Override public String expectedCategory() { return ""; } // Unavailable on age restricted videos
|
@Override public String expectedCategory() { return ""; } // Unavailable on age restricted videos
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Ignore("Video is not available in specific countries. Someone else has to generate mocks")
|
|
||||||
public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtractorTest {
|
public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtractorTest {
|
||||||
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/stream/";
|
||||||
private static final String ID = "T4XJQO3qol8";
|
private static final String ID = "T4XJQO3qol8";
|
||||||
|
@ -32,6 +32,7 @@ public class YoutubeStreamExtractorControversialTest extends DefaultStreamExtrac
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
YoutubeParsingHelper.resetClientVersionAndKey();
|
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||||
|
YoutubeParsingHelper.setNumberGenerator(new Random(1));
|
||||||
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "controversial"));
|
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "controversial"));
|
||||||
extractor = YouTube.getStreamExtractor(URL);
|
extractor = YouTube.getStreamExtractor(URL);
|
||||||
extractor.fetchPage();
|
extractor.fetchPage();
|
||||||
|
|
|
@ -37,7 +37,6 @@ public class YoutubeStreamExtractorLivestreamTest extends DefaultStreamExtractor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Test
|
@Test
|
||||||
@Ignore("When visiting website it shows 'Lofi Girl', unknown why it's different in tests")
|
|
||||||
public void testUploaderName() throws Exception {
|
public void testUploaderName() throws Exception {
|
||||||
super.testUploaderName();
|
super.testUploaderName();
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,176 +0,0 @@
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"httpMethod": "POST",
|
|
||||||
"url": "https://youtubei.googleapis.com/youtubei/v1/browse?key\u003dAIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8",
|
|
||||||
"headers": {
|
|
||||||
"Accept-Language": [
|
|
||||||
"en-GB, en;q\u003d0.9"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"dataToSend": [
|
|
||||||
123,
|
|
||||||
34,
|
|
||||||
98,
|
|
||||||
114,
|
|
||||||
111,
|
|
||||||
119,
|
|
||||||
115,
|
|
||||||
101,
|
|
||||||
73,
|
|
||||||
100,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
34,
|
|
||||||
68,
|
|
||||||
79,
|
|
||||||
69,
|
|
||||||
83,
|
|
||||||
78,
|
|
||||||
84,
|
|
||||||
45,
|
|
||||||
69,
|
|
||||||
88,
|
|
||||||
73,
|
|
||||||
83,
|
|
||||||
84,
|
|
||||||
34,
|
|
||||||
44,
|
|
||||||
34,
|
|
||||||
99,
|
|
||||||
111,
|
|
||||||
110,
|
|
||||||
116,
|
|
||||||
101,
|
|
||||||
120,
|
|
||||||
116,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
123,
|
|
||||||
34,
|
|
||||||
99,
|
|
||||||
108,
|
|
||||||
105,
|
|
||||||
101,
|
|
||||||
110,
|
|
||||||
116,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
123,
|
|
||||||
34,
|
|
||||||
99,
|
|
||||||
108,
|
|
||||||
105,
|
|
||||||
101,
|
|
||||||
110,
|
|
||||||
116,
|
|
||||||
78,
|
|
||||||
97,
|
|
||||||
109,
|
|
||||||
101,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
34,
|
|
||||||
49,
|
|
||||||
34,
|
|
||||||
44,
|
|
||||||
34,
|
|
||||||
99,
|
|
||||||
108,
|
|
||||||
105,
|
|
||||||
101,
|
|
||||||
110,
|
|
||||||
116,
|
|
||||||
86,
|
|
||||||
101,
|
|
||||||
114,
|
|
||||||
115,
|
|
||||||
105,
|
|
||||||
111,
|
|
||||||
110,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
34,
|
|
||||||
50,
|
|
||||||
46,
|
|
||||||
50,
|
|
||||||
48,
|
|
||||||
50,
|
|
||||||
49,
|
|
||||||
48,
|
|
||||||
54,
|
|
||||||
48,
|
|
||||||
54,
|
|
||||||
34,
|
|
||||||
125,
|
|
||||||
125,
|
|
||||||
44,
|
|
||||||
34,
|
|
||||||
112,
|
|
||||||
97,
|
|
||||||
114,
|
|
||||||
97,
|
|
||||||
109,
|
|
||||||
115,
|
|
||||||
34,
|
|
||||||
58,
|
|
||||||
34,
|
|
||||||
69,
|
|
||||||
103,
|
|
||||||
90,
|
|
||||||
50,
|
|
||||||
97,
|
|
||||||
87,
|
|
||||||
82,
|
|
||||||
108,
|
|
||||||
98,
|
|
||||||
51,
|
|
||||||
77,
|
|
||||||
37,
|
|
||||||
51,
|
|
||||||
68,
|
|
||||||
34,
|
|
||||||
125
|
|
||||||
],
|
|
||||||
"localization": {
|
|
||||||
"languageCode": "en",
|
|
||||||
"countryCode": "GB"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"responseCode": 400,
|
|
||||||
"responseMessage": "",
|
|
||||||
"responseHeaders": {
|
|
||||||
"alt-svc": [
|
|
||||||
"h3-29\u003d\":443\"; ma\u003d2592000,h3-T051\u003d\":443\"; ma\u003d2592000,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\""
|
|
||||||
],
|
|
||||||
"cache-control": [
|
|
||||||
"private"
|
|
||||||
],
|
|
||||||
"content-type": [
|
|
||||||
"application/json; charset\u003dUTF-8"
|
|
||||||
],
|
|
||||||
"date": [
|
|
||||||
"Tue, 08 Jun 2021 13:18:50 GMT"
|
|
||||||
],
|
|
||||||
"server": [
|
|
||||||
"ESF"
|
|
||||||
],
|
|
||||||
"vary": [
|
|
||||||
"Origin",
|
|
||||||
"X-Origin",
|
|
||||||
"Referer"
|
|
||||||
],
|
|
||||||
"x-content-type-options": [
|
|
||||||
"nosniff"
|
|
||||||
],
|
|
||||||
"x-frame-options": [
|
|
||||||
"SAMEORIGIN"
|
|
||||||
],
|
|
||||||
"x-xss-protection": [
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"responseBody": "{\n \"error\": {\n \"code\": 400,\n \"message\": \"Request contains an invalid argument.\",\n \"errors\": [\n {\n \"message\": \"Request contains an invalid argument.\",\n \"domain\": \"global\",\n \"reason\": \"badRequest\"\n }\n ],\n \"status\": \"INVALID_ARGUMENT\"\n }\n}\n",
|
|
||||||
"latestUrl": "https://youtubei.googleapis.com/youtubei/v1/browse?key\u003dAIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -6,14 +6,20 @@
|
||||||
"Accept-Language": [
|
"Accept-Language": [
|
||||||
"en-GB, en;q\u003d0.9"
|
"en-GB, en;q\u003d0.9"
|
||||||
],
|
],
|
||||||
|
"Origin": [
|
||||||
|
"https://www.youtube.com"
|
||||||
|
],
|
||||||
"Cookie": [
|
"Cookie": [
|
||||||
"CONSENT\u003dPENDING+100285"
|
"CONSENT\u003dPENDING+100285"
|
||||||
],
|
],
|
||||||
"X-YouTube-Client-Name": [
|
"X-YouTube-Client-Name": [
|
||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
|
"Referer": [
|
||||||
|
"https://www.youtube.com"
|
||||||
|
],
|
||||||
"X-YouTube-Client-Version": [
|
"X-YouTube-Client-Version": [
|
||||||
"2.20210408.08.00"
|
"2.20210420.07.00"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"localization": {
|
"localization": {
|
||||||
|
@ -38,7 +44,7 @@
|
||||||
"application/json; charset\u003dutf-8"
|
"application/json; charset\u003dutf-8"
|
||||||
],
|
],
|
||||||
"date": [
|
"date": [
|
||||||
"Sun, 11 Apr 2021 15:57:14 GMT"
|
"Wed, 21 Apr 2021 17:45:11 GMT"
|
||||||
],
|
],
|
||||||
"expires": [
|
"expires": [
|
||||||
"Mon, 01 Jan 1990 00:00:00 GMT"
|
"Mon, 01 Jan 1990 00:00:00 GMT"
|
||||||
|
@ -53,8 +59,8 @@
|
||||||
"ESF"
|
"ESF"
|
||||||
],
|
],
|
||||||
"set-cookie": [
|
"set-cookie": [
|
||||||
"YSC\u003ddhXDf1Ev5bE; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
"YSC\u003d55xotGigykc; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||||
"CONSENT\u003dPENDING+790; expires\u003dFri, 01-Jan-2038 00:00:00 GMT; path\u003d/; domain\u003d.youtube.com"
|
"CONSENT\u003dPENDING+084; expires\u003dFri, 01-Jan-2038 00:00:00 GMT; path\u003d/; domain\u003d.youtube.com"
|
||||||
],
|
],
|
||||||
"strict-transport-security": [
|
"strict-transport-security": [
|
||||||
"max-age\u003d31536000"
|
"max-age\u003d31536000"
|
||||||
|
@ -75,7 +81,7 @@
|
||||||
"0"
|
"0"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"responseBody": "[\r\n{\"page\": \"watch\",\"rootVe\": \"3832\"},\r\n{\"page\": \"watch\",\"preconnect\": [\"https:\\/\\/r4---sn-hgn7rn7k.googlevideo.com\\/generate_204\",\"https:\\/\\/r4---sn-hgn7rn7k.googlevideo.com\\/generate_204?conn2\"]},\r\n{\"page\": \"watch\",\"playerResponse\": {\"responseContext\":{\"serviceTrackingParams\":[{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"is_viewed_live\",\"value\":\"False\"},{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"23970530,24005646,23968386,24005602,23918597,24011119,23934970,23744176,24022914,23890959,23974595,23983296,23857950,24007246,9407156,24016478,1714250,24022308,23976696,24006670,24009750,24001373,24022875,24006795,24012117,23885487,23940238,23891346,24014268,24002697,23966208,23987676,23804281,23946420,23884386,23882502,24024495,23969934,24025870,23986021,23944779,24002011,23748146,24022616,23891344,24010576,23981192,24021968\"}]},{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20210408.08.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetPlayer_rid\",\"value\":\"0xce87950a1c7b0640\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20210408\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"playabilityStatus\":{\"status\":\"ERROR\",\"reason\":\"Video unavailable\",\"errorScreen\":{\"playerErrorMessageRenderer\":{\"reason\":{\"simpleText\":\"Video unavailable\"},\"thumbnail\":{\"thumbnails\":[{\"url\":\"//s.ytimg.com/yts/img/meh7-vflGevej7.png\",\"width\":140,\"height\":100}]},\"icon\":{\"iconType\":\"ERROR_OUTLINE\"}}},\"contextParams\":\"Q0FBU0FnZ0E\u003d\"},\"trackingParams\":\"CAAQu2kiEwijlIybx_bvAhWnF_EFHZCGD0U\u003d\"}},\r\n{\"page\": \"watch\",\"response\": {\"responseContext\":{\"webResponseContextExtensionData\":{\"ytConfigData\":{\"visitorData\":\"CgtjdWVaRlB4MmUxRSjauMyDBg%3D%3D\",\"rootVisualElementType\":3832}}}},\"xsrf_token\": \"QUFFLUhqbjU0XzV6c3N4VDlZNXpGU3RuVW5IZ18wSkdsd3xBQ3Jtc0tuMkpBMjhqbEY2WEc5VTd3Mk1XZ3pMWXdVMmhQZzlXY3pOY05mV0FQQURJLVh3U3NqVHFSLUpsdmxtZnJURkhrOXdhTFE5T2RCV3dXSHQ2UlZVRHJnRjRmYkpvN1BGUEI3TllwZktBbnZyQ29LRVZwZw\\u003d\\u003d\",\"url\": \"/watch?v\\u003dabcde\\u0026list\\u003dRDabcde\",\"endpoint\": {\"clickTrackingParams\":\"IhMIs62Lm8f27wIVST_xBR3LIARZMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/watch?v\u003dabcde\",\"webPageType\":\"WEB_PAGE_TYPE_WATCH\",\"rootVe\":3832}},\"watchEndpoint\":{\"videoId\":\"abcde\"}}},\r\n{\"page\": \"watch\",\"timing\": {\"info\": {\"st\": 0.0 }}}]\r\n",
|
"responseBody": "[\r\n{\"page\": \"watch\",\"rootVe\": \"3832\"},\r\n{\"page\": \"watch\",\"preconnect\": [\"https:\\/\\/r4---sn-hgn7rn7k.googlevideo.com\\/generate_204\",\"https:\\/\\/r4---sn-hgn7rn7k.googlevideo.com\\/generate_204?conn2\"]},\r\n{\"page\": \"watch\",\"playerResponse\": {\"responseContext\":{\"serviceTrackingParams\":[{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"is_viewed_live\",\"value\":\"False\"},{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"23804281,23884386,23882502,24010466,23934970,23969934,23918597,24005646,23983296,23966208,9405964,24021967,23891346,23970529,23946420,23975058,23891344,24007246,24007613,24022927,24031409,24011119,1714255,24002010,23890959,23974595,24022914,23944779,23987676,23744176,23857949,24001373,24028580,23968386,24006795,24005802,24012117,24014268,24022875,23995927,24014442\"}]},{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20210420.07.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetPlayer_rid\",\"value\":\"0xbb641a161cfd5b01\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20210420\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"playabilityStatus\":{\"status\":\"ERROR\",\"reason\":\"Video unavailable\",\"errorScreen\":{\"playerErrorMessageRenderer\":{\"reason\":{\"simpleText\":\"Video unavailable\"},\"thumbnail\":{\"thumbnails\":[{\"url\":\"//s.ytimg.com/yts/img/meh7-vflGevej7.png\",\"width\":140,\"height\":100}]},\"icon\":{\"iconType\":\"ERROR_OUTLINE\"}}},\"contextParams\":\"Q0FBU0FnZ0E\u003d\"},\"trackingParams\":\"CAAQu2kiEwiMt9z-8Y_wAhUpNPEFHfXjBV0\u003d\"}},\r\n{\"page\": \"watch\",\"response\": {\"responseContext\":{\"webResponseContextExtensionData\":{\"ytConfigData\":{\"visitorData\":\"CgtUcGFUdS05TW5OSSinyYGEBg%3D%3D\",\"rootVisualElementType\":3832}}}},\"xsrf_token\": \"QUFFLUhqbHlBTEFxZDFZQlV2c2FKYjZyRDZkT0g3a0Y1Z3xBQ3Jtc0trTXNGLW5KSEhpUkJoR0xjcUN1RGZLUVROeDY2NWluUnBubGxWR0IzNUkwNXRyZlctRm1XaEs0dk9pVk9QM09iUzZRVFRRYVl3MVdvZ3BEVFBCcWRtd0MwdjZwOW5zenlVNlNNbzdaWXlJVmRLbC1tcw\\u003d\\u003d\",\"url\": \"/watch?v\\u003dabcde\\u0026list\\u003dRDabcde\",\"endpoint\": {\"clickTrackingParams\":\"IhMIlvHb_vGP8AIVBxjxBR0nGg62MghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/watch?v\u003dabcde\",\"webPageType\":\"WEB_PAGE_TYPE_WATCH\",\"rootVe\":3832}},\"watchEndpoint\":{\"videoId\":\"abcde\"}}},\r\n{\"page\": \"watch\",\"timing\": {\"info\": {\"st\": 0.0 }}}]\r\n",
|
||||||
"latestUrl": "https://www.youtube.com/watch?v\u003dabcde\u0026list\u003dRDabcde\u0026pbj\u003d1"
|
"latestUrl": "https://www.youtube.com/watch?v\u003dabcde\u0026list\u003dRDabcde\u0026pbj\u003d1"
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue