Merge pull request #1320 from litetex/add-support-for-LOCKUP_CONTENT_TYPE_VIDEO

pull/1321/head
Stypox 2025-07-16 13:22:54 +02:00 zatwierdzone przez GitHub
commit a94a6e0dcb
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
15 zmienionych plików z 2473 dodań i 2872 usunięć

Wyświetl plik

@ -27,7 +27,7 @@ allprojects {
}
ext {
nanojsonVersion = "1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
nanojsonVersion = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996"
jsr305Version = "3.0.2"
junitVersion = "5.13.3"
checkstyleVersion = "10.4"

Wyświetl plik

@ -759,10 +759,13 @@ public class YoutubeStreamExtractor extends StreamExtractor {
result.getObject("compactPlaylistRenderer"));
} else if (result.has("lockupViewModel")) {
final JsonObject lockupViewModel = result.getObject("lockupViewModel");
if ("LOCKUP_CONTENT_TYPE_PLAYLIST".equals(
lockupViewModel.getString("contentType"))) {
final String contentType = lockupViewModel.getString("contentType");
if ("LOCKUP_CONTENT_TYPE_PLAYLIST".equals(contentType)) {
return new YoutubeMixOrPlaylistLockupInfoItemExtractor(
lockupViewModel);
} else if ("LOCKUP_CONTENT_TYPE_VIDEO".equals(contentType)) {
return new YoutubeStreamInfoItemLockupExtractor(
lockupViewModel, timeAgoParser);
}
}
return null;

Wyświetl plik

@ -0,0 +1,398 @@
package org.schabi.newpipe.extractor.services.youtube.extractors;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Utils;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Note:
* This extractor is currently (2025-07) only used to extract related video streams.<br/>
* The following features are currently not implemented because they have never been observed:
* <ul>
* <li>Shorts</li>
* <li>Premieres</li>
* <li>Paid content (Premium, members first or only)</li>
* </ul>
*/
public class YoutubeStreamInfoItemLockupExtractor implements StreamInfoItemExtractor {
private static final String NO_VIEWS_LOWERCASE = "no views";
private final JsonObject lockupViewModel;
private final TimeAgoParser timeAgoParser;
private StreamType cachedStreamType;
private String cachedName;
private Optional<String> cachedTextualUploadDate;
private ChannelImageViewModel cachedChannelImageViewModel;
private JsonArray cachedMetadataRows;
/**
* Creates an extractor of StreamInfoItems from a YouTube page.
*
* @param lockupViewModel The JSON page element
* @param timeAgoParser A parser of the textual dates or {@code null}.
*/
public YoutubeStreamInfoItemLockupExtractor(final JsonObject lockupViewModel,
@Nullable final TimeAgoParser timeAgoParser) {
this.lockupViewModel = lockupViewModel;
this.timeAgoParser = timeAgoParser;
}
@Override
public StreamType getStreamType() throws ParsingException {
if (cachedStreamType == null) {
cachedStreamType = determineStreamType();
}
return cachedStreamType;
}
private StreamType determineStreamType() throws ParsingException {
if (JsonUtils.getArray(lockupViewModel, "contentImage.thumbnailViewModel.overlays")
.streamAsJsonObjects()
.flatMap(overlay -> overlay
.getObject("thumbnailOverlayBadgeViewModel")
.getArray("thumbnailBadges")
.streamAsJsonObjects())
.map(thumbnailBadge -> thumbnailBadge.getObject("thumbnailBadgeViewModel"))
.anyMatch(thumbnailBadgeViewModel -> {
if ("THUMBNAIL_OVERLAY_BADGE_STYLE_LIVE".equals(
thumbnailBadgeViewModel.getString("badgeStyle"))) {
return true;
}
// Fallback: Check if there is a live icon
return thumbnailBadgeViewModel
.getObject("icon")
.getArray("sources")
.streamAsJsonObjects()
.map(source -> source
.getObject("clientResource")
.getString("imageName"))
.anyMatch("LIVE"::equals);
})) {
return StreamType.LIVE_STREAM;
}
return StreamType.VIDEO_STREAM;
}
@Override
public boolean isAd() throws ParsingException {
final String name = getName();
return "[Private video]".equals(name)
|| "[Deleted video]".equals(name);
}
@Override
public String getUrl() throws ParsingException {
try {
String videoId = lockupViewModel.getString("contentId");
if (isNullOrEmpty(videoId)) {
videoId = JsonUtils.getString(lockupViewModel,
"rendererContext.commandContext.onTap.innertubeCommand.watchEndpoint.videoId");
}
return YoutubeStreamLinkHandlerFactory.getInstance().getUrl(videoId);
} catch (final Exception e) {
throw new ParsingException("Could not get url", e);
}
}
@Override
public String getName() throws ParsingException {
if (cachedName != null) {
return cachedName;
}
final String name = JsonUtils.getString(lockupViewModel,
"metadata.lockupMetadataViewModel.title.content");
if (!isNullOrEmpty(name)) {
this.cachedName = name;
return name;
}
throw new ParsingException("Could not get name");
}
@Override
public long getDuration() throws ParsingException {
// Duration cannot be extracted for live streams, but only for normal videos
if (isLive()) {
return -1;
}
final List<String> potentialDurations = JsonUtils.getArray(lockupViewModel,
"contentImage.thumbnailViewModel.overlays")
.streamAsJsonObjects()
.flatMap(jsonObject -> jsonObject
.getObject("thumbnailOverlayBadgeViewModel")
.getArray("thumbnailBadges")
.streamAsJsonObjects())
.map(jsonObject -> jsonObject
.getObject("thumbnailBadgeViewModel")
.getString("text"))
.collect(Collectors.toList());
if (potentialDurations.isEmpty()) {
throw new ParsingException("Could not get duration: No parsable durations detected");
}
ParsingException parsingException = null;
for (final String potentialDuration : potentialDurations) {
try {
return YoutubeParsingHelper.parseDurationString(potentialDuration);
} catch (final ParsingException ex) {
parsingException = ex;
}
}
throw new ParsingException("Could not get duration", parsingException);
}
@Override
public String getUploaderName() throws ParsingException {
return metadataPart(0, 0)
.map(this::getTextContentFromMetadataPart)
.filter(s -> !isNullOrEmpty(s))
.orElseThrow(() -> new ParsingException("Could not get uploader name"));
}
@Override
public String getUploaderUrl() throws ParsingException {
final String channelId = channelImageViewModel()
.forUploaderUrlExtraction()
.getObject("rendererContext")
.getObject("commandContext")
.getObject("onTap")
.getObject("innertubeCommand")
.getObject("browseEndpoint")
.getString("browseId");
if (isNullOrEmpty(channelId)) {
throw new ParsingException("Could not get uploader url");
}
return YoutubeChannelLinkHandlerFactory.getInstance().getUrl(channelId);
}
@Nonnull
@Override
public List<Image> getUploaderAvatars() throws ParsingException {
return YoutubeParsingHelper.getImagesFromThumbnailsArray(
JsonUtils.getArray(
channelImageViewModel().forAvatarExtraction(),
"avatarViewModel.image.sources"));
}
@Override
public boolean isUploaderVerified() throws ParsingException {
return metadataPart(0, 0)
.map(jsonObject -> jsonObject
.getObject("text")
.getArray("attachmentRuns"))
.map(YoutubeParsingHelper::hasArtistOrVerifiedIconBadgeAttachment)
.orElse(false);
}
@Nullable
@Override
public String getTextualUploadDate() throws ParsingException {
if (cachedTextualUploadDate != null) {
return cachedTextualUploadDate.orElse(null);
}
// Live streams have no upload date
if (isLive()) {
cachedTextualUploadDate = Optional.empty();
return null;
}
// This might be null e.g. for live streams
this.cachedTextualUploadDate = metadataPart(1, 1)
.map(this::getTextContentFromMetadataPart);
return cachedTextualUploadDate.orElse(null);
}
@Nullable
@Override
public DateWrapper getUploadDate() throws ParsingException {
if (timeAgoParser == null) {
return null;
}
final String textualUploadDate = getTextualUploadDate();
// Prevent NPE when e.g. a live stream is shown
if (textualUploadDate == null) {
return null;
}
return timeAgoParser.parse(textualUploadDate);
}
@Override
public long getViewCount() throws ParsingException {
final Optional<String> optTextContent = metadataPart(1, 0)
.map(this::getTextContentFromMetadataPart);
// We could do this inline if the ParsingException would be a RuntimeException -.-
if (optTextContent.isPresent()) {
return getViewCountFromViewCountText(optTextContent.get());
}
return !isLive()
? -1
// Live streams don't have the metadata row present if there are 0 viewers
// https://github.com/TeamNewPipe/NewPipeExtractor/pull/1320#discussion_r2205837528
: 0;
}
private long getViewCountFromViewCountText(@Nonnull final String viewCountText)
throws NumberFormatException, ParsingException {
// These approaches are language dependent
if (viewCountText.toLowerCase().contains(NO_VIEWS_LOWERCASE)) {
return 0;
} else if (viewCountText.toLowerCase().contains("recommended")) {
return -1;
}
return Utils.mixedNumberWordToLong(viewCountText);
}
@Nonnull
@Override
public List<Image> getThumbnails() throws ParsingException {
return YoutubeParsingHelper.getImagesFromThumbnailsArray(
JsonUtils.getArray(lockupViewModel,
"contentImage.thumbnailViewModel.image.sources"));
}
private ChannelImageViewModel channelImageViewModel() throws ParsingException {
if (cachedChannelImageViewModel == null) {
cachedChannelImageViewModel = determineChannelImageViewModel();
}
return cachedChannelImageViewModel;
}
private ChannelImageViewModel determineChannelImageViewModel() throws ParsingException {
final JsonObject image = lockupViewModel
.getObject("metadata")
.getObject("lockupMetadataViewModel")
.getObject("image");
final JsonObject single = image
.getObject("decoratedAvatarViewModel", null);
if (single != null) {
return new SingleChannelImageViewModel(single);
}
final JsonObject multi = image.getObject("avatarStackViewModel", null);
if (multi != null) {
return new MultiChannelImageViewModel(multi);
}
throw new ParsingException("Failed to determine channel image view model");
}
private Optional<JsonObject> metadataPart(final int rowIndex, final int partIndex)
throws ParsingException {
if (cachedMetadataRows == null) {
cachedMetadataRows = JsonUtils.getArray(lockupViewModel,
"metadata.lockupMetadataViewModel.metadata"
+ ".contentMetadataViewModel.metadataRows");
}
return cachedMetadataRows
.streamAsJsonObjects()
.skip(rowIndex)
.limit(1)
.flatMap(jsonObject -> jsonObject.getArray("metadataParts")
.streamAsJsonObjects()
.skip(partIndex)
.limit(1))
.findFirst();
}
private String getTextContentFromMetadataPart(final JsonObject metadataPart) {
return metadataPart.getObject("text").getString("content");
}
private boolean isLive() throws ParsingException {
return getStreamType() != StreamType.VIDEO_STREAM;
}
abstract static class ChannelImageViewModel {
protected JsonObject viewModel;
protected ChannelImageViewModel(final JsonObject viewModel) {
this.viewModel = viewModel;
}
public abstract JsonObject forUploaderUrlExtraction();
public abstract JsonObject forAvatarExtraction();
}
static class SingleChannelImageViewModel extends ChannelImageViewModel {
SingleChannelImageViewModel(final JsonObject viewModel) {
super(viewModel);
}
@Override
public JsonObject forUploaderUrlExtraction() {
return viewModel;
}
@Override
public JsonObject forAvatarExtraction() {
return viewModel.getObject("avatar");
}
}
static class MultiChannelImageViewModel extends ChannelImageViewModel {
MultiChannelImageViewModel(final JsonObject viewModel) {
super(viewModel);
}
@Override
public JsonObject forUploaderUrlExtraction() {
return viewModel
.getObject("rendererContext")
.getObject("commandContext")
.getObject("onTap")
.getObject("innertubeCommand")
.getObject("showDialogCommand")
.getObject("panelLoadingStrategy")
.getObject("inlineContent")
.getObject("dialogViewModel")
.getObject("customContent")
.getObject("listViewModel")
.getArray("listItems")
.streamAsJsonObjects()
.map(item -> item.getObject("listItemViewModel"))
.findFirst()
.orElse(null);
}
@Override
public JsonObject forAvatarExtraction() {
return viewModel.getArray("avatars")
.getObject(0);
}
}
}

Wyświetl plik

@ -56,9 +56,10 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
long getDuration() throws ParsingException;
/**
* Parses the number of views
* Parses the number of views (or of current viewers in case of live streams)
*
* @return the number of views or -1 for live streams
* @return the number of views (or of current viewers in case of live streams) or -1 if not
* available
* @throws ParsingException if there is an error in the extraction
*/
long getViewCount() throws ParsingException;

Wyświetl plik

@ -3,10 +3,10 @@
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Origin": [
"Referer": [
"https://www.youtube.com"
],
"Referer": [
"Origin": [
"https://www.youtube.com"
],
"Accept-Language": [
@ -44,10 +44,13 @@
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Tue, 11 Feb 2025 21:28:36 GMT"
"Thu, 10 Jul 2025 20:58:08 GMT"
],
"document-policy": [
"include-js-call-stacks-in-crash-reports"
],
"expires": [
"Tue, 11 Feb 2025 21:28:36 GMT"
"Thu, 10 Jul 2025 20:58:08 GMT"
],
"origin-trial": [
"AmhMBR6zCLzDDxpW+HfpP67BqwIknWnyMOXOQGfzYswFmJe+fgaI6XZgAzcxOrzNtP7hEDsOo1jdjFnVr2IdxQ4AAAB4eyJvcmlnaW4iOiJodHRwczovL3lvdXR1YmUuY29tOjQ0MyIsImZlYXR1cmUiOiJXZWJWaWV3WFJlcXVlc3RlZFdpdGhEZXByZWNhdGlvbiIsImV4cGlyeSI6MTc1ODA2NzE5OSwiaXNTdWJkb21haW4iOnRydWV9"
@ -61,12 +64,15 @@
"report-to": [
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
],
"reporting-endpoints": [
"default\u003d\"/web-reports?context\u003deJwNzn9MzHEcx_E-vcbqvtd9P-83hjKSG6Fr57hUKoRKoxi2VlFXusRV5O6k5T-Mrfn96_Jr_lGzyY9NWIXNH5ofs0UzYkyj2fLrDz-myPuPx3_P1_ayDI7qjd2i0n3VyjNSrew5Nerqrm2qeEadWvZ0u2rK8qufF_3qcodfNT8OqMHYoCqKC6pTvUF1vi-ofG_r1VB_vTqnC8K90QXh9aJ0UkF4R6EFXq8FP0IWfH9twc6vFhTNNhCVaECLZ7kGBvMMbC420N5ioOO6gTcDBgJFVnwrtWJewIran1Z8WhWFrlAUep5FIWGtDWlNNrTetmHVAxsOi8phG778tSEp3URbtolghYlWnwkjaKJ5v4k5J030h0xEXDAx_qGJfe9NdNk1Pi7WSFmpsSxfI6JUwyLcxzV6TmtEXtFY_VjjzBONsx80Xv_SWPBHo2ZYY_0YQmAWoXMeweMmJKUSGtIJuxcSzqwjvCkhxJcTVlYSrlURyjcTborGRmmEZ49smwiZBwhfjxJcxwgZJwh9F2XbQrh7iRDTRshvl-YWYeQOIaKbkCuMRwR-Tnj1ktA7QJj0ifBlkPD-N8H6h2ATLMaKCSJaTBaxwi6mi1kiQTiFSySJZJEmMkSmWCo2DcnfYcKUf4RDYQxDMQbCGbZIxo5xjOqJjG_RjNsxjMhYRvZUxgvRH8fIn8ZYZGd0xTPsM6VPYIS5GHPnMtziiAiJAjejVXxOYfxLZUxLY7QsYTRkMW6IV-J6DsOxnDGSyyhcwdggysRG4RU-USeCokF05THO5jP2rmbkrWGkehiVlYxOMSTYiHjXc-_-aN29_-DUOMfO2oA_UFaRuKOizOGtq63xOypqNjrK66r8VeUeX4nL6XI75zuTE50pJVud_wEKCuGI\""
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003deU0n7izFRiw; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dWed, 18-May-2022 21:28:36 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
"YSC\u003d8hfV7UKGZi4; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dFri, 14-Oct-2022 20:58:08 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"

Wyświetl plik

@ -3,17 +3,17 @@
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse",
"headers": {
"Origin": [
"Referer": [
"https://www.youtube.com"
],
"Referer": [
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250210.02.00"
"2.20250710.01.00"
],
"X-YouTube-Client-Name": [
"1"
@ -39,6 +39,159 @@
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,
87,
69,
66,
34,
44,
34,
99,
108,
105,
101,
110,
116,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
50,
46,
50,
48,
50,
53,
48,
55,
49,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
99,
108,
105,
101,
110,
116,
83,
99,
114,
101,
101,
110,
34,
58,
34,
87,
65,
84,
67,
72,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
34,
44,
34,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
34,
117,
116,
99,
79,
102,
102,
115,
101,
116,
77,
105,
110,
117,
116,
101,
115,
34,
58,
48,
125,
44,
34,
114,
101,
113,
@ -94,159 +247,6 @@
125,
44,
34,
99,
108,
105,
101,
110,
116,
34,
58,
123,
34,
117,
116,
99,
79,
102,
102,
115,
101,
116,
77,
105,
110,
117,
116,
101,
115,
34,
58,
48,
44,
34,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
99,
108,
105,
101,
110,
116,
78,
97,
109,
101,
34,
58,
34,
87,
69,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
34,
99,
108,
105,
101,
110,
116,
83,
99,
114,
101,
101,
110,
34,
58,
34,
87,
65,
84,
67,
72,
34,
44,
34,
99,
108,
105,
101,
110,
116,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
50,
46,
50,
48,
50,
53,
48,
50,
49,
48,
46,
48,
50,
46,
48,
48,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
34,
125,
44,
34,
117,
115,
101,
@ -298,7 +298,7 @@
"application/json; charset\u003dUTF-8"
],
"date": [
"Tue, 11 Feb 2025 21:28:38 GMT"
"Thu, 10 Jul 2025 20:58:09 GMT"
],
"server": [
"scaffolding on HTTPServer2"
@ -318,7 +318,7 @@
"0"
]
},
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgttQ0k5NmJXbzJUVSiGgq-9BjIKCgJERRIEEgAgaw%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250210.02.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetVisitorId_rid\",\"value\":\"0x2fc898cdc76f026e\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"CgttQ0k5NmJXbzJUVSiGgq-9BjIKCgJERRIEEgAgaw%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250210\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}}}",
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgthREJJOGpSSkpqQSjh0sDDBjIKCgJERRIEEgAgPg%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250710.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetVisitorId_rid\",\"value\":\"0x31bc4894a59acd12\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"CgthREJJOGpSSkpqQSjh0sDDBjIKCgJERRIEEgAgPg%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250710\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse"
}
}

Wyświetl plik

@ -1,12 +1,332 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/iframe_api",
"httpMethod": "POST",
"url": "https://youtubei.googleapis.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse",
"headers": {
"User-Agent": [
"com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
],
"X-Goog-Api-Format-Version": [
"2"
],
"Content-Type": [
"application/json"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"dataToSend": [
123,
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,
65,
78,
68,
82,
79,
73,
68,
34,
44,
34,
99,
108,
105,
101,
110,
116,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
49,
57,
46,
50,
56,
46,
51,
53,
34,
44,
34,
99,
108,
105,
101,
110,
116,
83,
99,
114,
101,
101,
110,
34,
58,
34,
87,
65,
84,
67,
72,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
77,
79,
66,
73,
76,
69,
34,
44,
34,
111,
115,
78,
97,
109,
101,
34,
58,
34,
65,
110,
100,
114,
111,
105,
100,
34,
44,
34,
111,
115,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
49,
53,
34,
44,
34,
97,
110,
100,
114,
111,
105,
100,
83,
100,
107,
86,
101,
114,
115,
105,
111,
110,
34,
58,
51,
53,
44,
34,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
34,
117,
116,
99,
79,
102,
102,
115,
101,
116,
77,
105,
110,
117,
116,
101,
115,
34,
58,
48,
125,
44,
34,
114,
101,
113,
117,
101,
115,
116,
34,
58,
123,
34,
105,
110,
116,
101,
114,
110,
97,
108,
69,
120,
112,
101,
114,
105,
109,
101,
110,
116,
70,
108,
97,
103,
115,
34,
58,
91,
93,
44,
34,
117,
115,
101,
83,
115,
108,
34,
58,
116,
114,
117,
101,
125,
44,
34,
117,
115,
101,
114,
34,
58,
123,
34,
108,
111,
99,
107,
101,
100,
83,
97,
102,
101,
116,
121,
77,
111,
100,
101,
34,
58,
102,
97,
108,
115,
101,
125,
125,
125
],
"localization": {
"languageCode": "en",
"countryCode": "GB"
@ -19,50 +339,19 @@
"alt-svc": [
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000"
],
"cache-control": [
"private, max-age\u003d0"
],
"content-security-policy": [
"require-trusted-types-for \u0027script\u0027"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy-report-only": [
"same-origin; report-to\u003d\"youtube_main\""
],
"cross-origin-resource-policy": [
"cross-origin"
"application/json; charset\u003dUTF-8"
],
"date": [
"Tue, 11 Feb 2025 21:28:39 GMT"
],
"expires": [
"Tue, 11 Feb 2025 21:28:39 GMT"
],
"origin-trial": [
"AmhMBR6zCLzDDxpW+HfpP67BqwIknWnyMOXOQGfzYswFmJe+fgaI6XZgAzcxOrzNtP7hEDsOo1jdjFnVr2IdxQ4AAAB4eyJvcmlnaW4iOiJodHRwczovL3lvdXR1YmUuY29tOjQ0MyIsImZlYXR1cmUiOiJXZWJWaWV3WFJlcXVlc3RlZFdpdGhEZXByZWNhdGlvbiIsImV4cGlyeSI6MTc1ODA2NzE5OSwiaXNTdWJkb21haW4iOnRydWV9"
],
"p3p": [
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
],
"permissions-policy": [
"ch-ua-arch\u003d*, ch-ua-bitness\u003d*, ch-ua-full-version\u003d*, ch-ua-full-version-list\u003d*, ch-ua-model\u003d*, ch-ua-wow64\u003d*, ch-ua-form-factors\u003d*, ch-ua-platform\u003d*, ch-ua-platform-version\u003d*"
],
"report-to": [
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
"Thu, 10 Jul 2025 20:58:10 GMT"
],
"server": [
"ESF"
"scaffolding on HTTPServer2"
],
"set-cookie": [
"YSC\u003dK78wcg9RsOo; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"__Secure-ROLLOUT_TOKEN\u003dCKuGncX16JS6IBCMg4eRyLyLAxiMg4eRyLyLAw%3D%3D; Domain\u003dyoutube.com; Expires\u003dSun, 10-Aug-2025 21:28:39 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone; Partitioned",
"VISITOR_INFO1_LIVE\u003dIxRYFI7un0c; Domain\u003d.youtube.com; Expires\u003dSun, 10-Aug-2025 21:28:39 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_PRIVACY_METADATA\u003dCgJERRIEEgAgIg%3D%3D; Domain\u003d.youtube.com; Expires\u003dSun, 10-Aug-2025 21:28:39 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"
"vary": [
"Origin",
"X-Origin",
"Referer"
],
"x-content-type-options": [
"nosniff"
@ -74,7 +363,7 @@
"0"
]
},
"responseBody": "var scriptUrl \u003d \u0027https:\\/\\/www.youtube.com\\/s\\/player\\/af7f576f\\/www-widgetapi.vflset\\/www-widgetapi.js\u0027;try{var ttPolicy\u003dwindow.trustedTypes.createPolicy(\"youtube-widget-api\",{createScriptURL:function(x){return x}});scriptUrl\u003dttPolicy.createScriptURL(scriptUrl)}catch(e){}var YT;if(!window[\"YT\"])YT\u003d{loading:0,loaded:0};var YTConfig;if(!window[\"YTConfig\"])YTConfig\u003d{\"host\":\"https://www.youtube.com\"};\nif(!YT.loading){YT.loading\u003d1;(function(){var l\u003d[];YT.ready\u003dfunction(f){if(YT.loaded)f();else l.push(f)};window.onYTReady\u003dfunction(){YT.loaded\u003d1;var i\u003d0;for(;i\u003cl.length;i++)try{l[i]()}catch(e){}};YT.setConfig\u003dfunction(c){var k;for(k in c)if(c.hasOwnProperty(k))YTConfig[k]\u003dc[k]};var a\u003ddocument.createElement(\"script\");a.type\u003d\"text/javascript\";a.id\u003d\"www-widgetapi-script\";a.src\u003dscriptUrl;a.async\u003dtrue;var c\u003ddocument.currentScript;if(c){var n\u003dc.nonce||c.getAttribute(\"nonce\");if(n)a.setAttribute(\"nonce\",\nn)}var b\u003ddocument.getElementsByTagName(\"script\")[0];b.parentNode.insertBefore(a,b)})()};\n",
"latestUrl": "https://www.youtube.com/iframe_api"
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgtrNzZUdHlLc1RoWSji0sDDBjIKCgJERRIEEgAgKzoMCAEgmtul2aesirhoWPuB2unJkKbHdmLgAgrdAjEwLllURT1QMERtaHdzellScll1bDRhMlcwcWUxenpOQTZEdHBIUlNBS3ExNkpTQUs0Wmo2VzIwQzZZRFZXb1JUdVFQSjJLdEx0Zng2MHVUTmRYZW55cnVFcTF1NHZOUFpsMG1PSFA3ZkszQ2hqU2d5b01KVmtuSTQwRDRWTkNOTEk3SWJtY1FqNGZ4UXRNeEdxTDVtTzdtMEhuek9nR1VySzhUajFNWktLdVl1ZXR4X1dsUlV4SG9HOE5GbFlDa1F6cDluUmxIbU8tMFY5ZndoRFh6WXk4eVJIaE5wZXFLSTdzZ2hzNUxEaVJyQnFscUw2VlBfb05QN01jbmdWY0ZzbVpjNm9ud1czdG5mYTNXUlNVZ2pGUlpKLV9xRWRMYlFscVVfU3p5NkRKNFI1Ri0wS0cwUllZdVdUTXJSa2pBeXJpRE9PSHV3MVNCcjhxZVU5UUtJTVYtMUhHM2c%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"ANDROID\"},{\"key\":\"cver\",\"value\":\"19.28.35\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetVisitorId_rid\",\"value\":\"0xe8c241c3dd563e7b\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"CgtrNzZUdHlLc1RoWSji0sDDBjIKCgJERRIEEgAgKzoMCAEgmtul2aesirho\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"19.28\"},{\"key\":\"client.name\",\"value\":\"ANDROID\"}]}]}}",
"latestUrl": "https://youtubei.googleapis.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse"
}
}

Wyświetl plik

@ -1,369 +0,0 @@
{
"request": {
"httpMethod": "POST",
"url": "https://youtubei.googleapis.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse",
"headers": {
"User-Agent": [
"com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
],
"X-Goog-Api-Format-Version": [
"2"
],
"Content-Type": [
"application/json"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"dataToSend": [
123,
34,
99,
111,
110,
116,
101,
120,
116,
34,
58,
123,
34,
114,
101,
113,
117,
101,
115,
116,
34,
58,
123,
34,
105,
110,
116,
101,
114,
110,
97,
108,
69,
120,
112,
101,
114,
105,
109,
101,
110,
116,
70,
108,
97,
103,
115,
34,
58,
91,
93,
44,
34,
117,
115,
101,
83,
115,
108,
34,
58,
116,
114,
117,
101,
125,
44,
34,
99,
108,
105,
101,
110,
116,
34,
58,
123,
34,
97,
110,
100,
114,
111,
105,
100,
83,
100,
107,
86,
101,
114,
115,
105,
111,
110,
34,
58,
51,
53,
44,
34,
117,
116,
99,
79,
102,
102,
115,
101,
116,
77,
105,
110,
117,
116,
101,
115,
34,
58,
48,
44,
34,
111,
115,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
49,
53,
34,
44,
34,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
99,
108,
105,
101,
110,
116,
78,
97,
109,
101,
34,
58,
34,
65,
78,
68,
82,
79,
73,
68,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
34,
99,
108,
105,
101,
110,
116,
83,
99,
114,
101,
101,
110,
34,
58,
34,
87,
65,
84,
67,
72,
34,
44,
34,
99,
108,
105,
101,
110,
116,
86,
101,
114,
115,
105,
111,
110,
34,
58,
34,
49,
57,
46,
50,
56,
46,
51,
53,
34,
44,
34,
111,
115,
78,
97,
109,
101,
34,
58,
34,
65,
110,
100,
114,
111,
105,
100,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
77,
79,
66,
73,
76,
69,
34,
125,
44,
34,
117,
115,
101,
114,
34,
58,
123,
34,
108,
111,
99,
107,
101,
100,
83,
97,
102,
101,
116,
121,
77,
111,
100,
101,
34,
58,
102,
97,
108,
115,
101,
125,
125,
125
],
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"alt-svc": [
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000"
],
"content-type": [
"application/json; charset\u003dUTF-8"
],
"date": [
"Tue, 11 Feb 2025 21:28:41 GMT"
],
"server": [
"scaffolding on HTTPServer2"
],
"vary": [
"Origin",
"X-Origin",
"Referer"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgtEcTJxazhKVFBEdyiJgq-9BjIKCgJERRIEEgAgVToMCAEgituIoZSh8NVn\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"ANDROID\"},{\"key\":\"cver\",\"value\":\"19.28.35\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"GetVisitorId_rid\",\"value\":\"0x27d205bc9d46ed6e\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"CgtEcTJxazhKVFBEdyiJgq-9BjIKCgJERRIEEgAgVToMCAEgituIoZSh8NVn\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"19.28\"},{\"key\":\"client.name\",\"value\":\"ANDROID\"}]}]}}",
"latestUrl": "https://youtubei.googleapis.com/youtubei/v1/visitor_id?prettyPrint\u003dfalse"
}
}