2
0
mirror of https://github.com/TeamNewPipe/NewPipeExtractor synced 2025-08-22 01:48:58 +00:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Stypox
88ff8972e5
Release v0.24.8
v0.24.7 accidentally pointed at v0.24.6 and JitPack had already built so we had to make a new release
2025-07-31 23:38:02 +02:00
Stypox
d376c94bd5
Release v0.24.7 2025-07-31 23:28:24 +02:00
Stypox
0a7b72aec6
Merge pull request #1354 from AudricV/yt_more_kiosks_and_trending_deprecation 2025-07-31 23:24:13 +02:00
Stypox
426a227047
Merge pull request #1347 from litetex/fix-yt-channel-id-resolution 2025-07-31 22:28:07 +02:00
AudricV
2cccf48d6c
Add an UnsupportedContentInCountryException and use it in YouTube Charts
This allows client to distinguish of a generic
ContentNotSupportedException, which hasn't fully its place for its usage
in YouTube Charts.
2025-07-31 21:10:38 +02:00
AudricV
25e30b745a
[YouTube] Set running lives as new default kiosk
Also move YoutubeKioskExtractorTest.Trending at the bottom of the file
and add deprecation notice on test class too.
2025-07-31 21:10:38 +02:00
AudricV
5c7abeeab0
[YouTube] Add mocks for new kiosks' tests 2025-07-31 21:10:37 +02:00
AudricV
0687977690
[YouTube] Add tests for new kiosks 2025-07-31 21:00:41 +02:00
AudricV
9f7690823d
[YouTube] Move Trending kiosk to kiosk package, add deprecation comment
Trending is still working at the time this commit is made, it has been
just removed from the interface.

Also remove getInstance method of YoutubeTrendingLinkHandlerFactory to
make the INSTANCE static field public, for consistency with other
kiosks of the service.
2025-07-31 21:00:41 +02:00
AudricV
21c3aad320
[YouTube] Add trending music extractor
This kiosk is meant to return official music videos, but it also
returns unofficial content and autogenerated tracks, hence the
kiosk name.

Making requests with an unsupported YouTube Charts country leads to a
400 HTTP error, so for these countries a ContentNotSupportedException
is thrown by the extractor.
2025-07-31 21:00:41 +02:00
AudricV
f4203e632d
[YouTube] Add trending movies and shows trailers extractor
This kiosk also returns some videos for unsupported YouTube Charts
countries, even if there are fewer than in a supported country.
2025-07-31 21:00:41 +02:00
AudricV
e643024ff0
[YouTube] Add base class to parse trending videos' charts responses 2025-07-31 21:00:40 +02:00
AudricV
a4aeedff90
[YouTube] Add WEB_MUSIC_ANALYTICS constants, make some methods public
This is the client for YouTube Charts (charts.youtube.com).

Also change nullability of two fields and fix wrong client constant
usage in ofWebEmbeddedPlayerClient method in InnertubeClientRequestInfo.

Usages in YoutubeParsingHelper have been updated, getClientHeaders and
prepareJsonBuilder methods in this class have been made public.
2025-07-31 21:00:40 +02:00
TobiGr
6397b2ec3f Fix missing paranthesis in condition and improve null-safety 2025-07-31 11:19:33 +02:00
litetex
aa70b5a04b Create `YouTubeChannelHelperTest` 2025-07-31 11:19:17 +02:00
litetex
b05347d68d Redirection doesn't always seem to happen
Ref: https://github.com/TeamNewPipe/NewPipeExtractor/pull/1347#issuecomment-3123364807
Co-Authored-By: Audric V. <74829229+AudricV@users.noreply.github.com>
2025-07-31 11:10:33 +02:00
litetex
f91454d24f [YT] Correctly resolve redirects when resolving channel ids 2025-07-31 10:57:11 +02:00
litetex
4701c56e86 [YT] Build correct handle 2025-07-31 10:57:11 +02:00
AudricV
f4b0a7d97e
[YouTube] Add trending gaming videos extractor from Gaming system channel 2025-07-28 21:45:54 +02:00
AudricV
a870e3767d
[YouTube] Add trending podcasts episodes extractor from Podcasts page 2025-07-28 21:45:54 +02:00
AudricV
d38d64708d
[YouTube] Add running lives extractor from Live system channel 2025-07-28 21:45:54 +02:00
AudricV
3d0e302230
[YouTube] Add base class to parse kiosks from WEB InnerTube client
Kiosks structure work in a very similar way to channel tabs, so
YoutubeChannelHelper is used in this abstract class.
2025-07-28 21:45:53 +02:00
45 changed files with 7478 additions and 72 deletions

View File

@ -8,7 +8,7 @@ allprojects {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
version 'v0.24.6'
version 'v0.24.8'
group 'com.github.TeamNewPipe'
repositories {

View File

@ -0,0 +1,20 @@
package org.schabi.newpipe.extractor.exceptions;
/**
* Exception for contents not supported in a country.
*
* <p>
* Unsupported content means content is not intentionally geographically restricted such as for
* distribution rights, for which {@link GeographicRestrictionException} should be used instead.
* </p>
*/
public class UnsupportedContentInCountryException extends ContentNotAvailableException {
public UnsupportedContentInCountryException(final String message) {
super(message);
}
public UnsupportedContentInCountryException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -45,6 +45,12 @@ final class ClientsConstants {
static final String WEB_EMBEDDED_CLIENT_NAME = "WEB_EMBEDDED_PLAYER";
static final String WEB_EMBEDDED_CLIENT_VERSION = "1.20250121.00.00";
// WEB_MUSIC_ANALYTICS (YouTube charts)
static final String WEB_MUSIC_ANALYTICS_CLIENT_ID = "31";
static final String WEB_MUSIC_ANALYTICS_CLIENT_NAME = "WEB_MUSIC_ANALYTICS";
static final String WEB_MUSIC_ANALYTICS_CLIENT_VERSION = "2.0";
// IOS (iOS YouTube app) client fields
static final String IOS_CLIENT_ID = "5";

View File

@ -1,5 +1,8 @@
package org.schabi.newpipe.extractor.services.youtube;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_ID;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_NAME;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_VERSION;
@ -16,11 +19,11 @@ import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_CLIENT_NAME;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_ID;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_NAME;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_VERSION;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_HARDCODED_CLIENT_VERSION;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_REMIX_HARDCODED_CLIENT_VERSION;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_ID;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_NAME;
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_VERSION;
// TODO: add docs
@ -38,28 +41,28 @@ public final class InnertubeClientRequestInfo {
@Nonnull
public String clientVersion;
@Nonnull
public String clientScreen;
@Nullable
public String clientId;
@Nullable
public String clientScreen;
@Nullable
public String visitorData;
private ClientInfo(@Nonnull final String clientName,
@Nonnull final String clientVersion,
@Nonnull final String clientScreen,
@Nullable final String clientId,
@Nonnull final String clientId,
@Nullable final String clientScreen,
@Nullable final String visitorData) {
this.clientName = clientName;
this.clientVersion = clientVersion;
this.clientScreen = clientScreen;
this.clientId = clientId;
this.clientScreen = clientScreen;
this.visitorData = visitorData;
}
}
public static final class DeviceInfo {
@Nonnull
@Nullable
public String platform;
@Nullable
public String deviceMake;
@ -71,7 +74,7 @@ public final class InnertubeClientRequestInfo {
public String osVersion;
public int androidSdkVersion;
private DeviceInfo(@Nonnull final String platform,
private DeviceInfo(@Nullable final String platform,
@Nullable final String deviceMake,
@Nullable final String deviceModel,
@Nullable final String osName,
@ -96,8 +99,8 @@ public final class InnertubeClientRequestInfo {
public static InnertubeClientRequestInfo ofWebClient() {
return new InnertubeClientRequestInfo(
new InnertubeClientRequestInfo.ClientInfo(
WEB_CLIENT_NAME, WEB_HARDCODED_CLIENT_VERSION, WATCH_CLIENT_SCREEN,
WEB_CLIENT_ID, null),
WEB_CLIENT_NAME, WEB_HARDCODED_CLIENT_VERSION, WEB_CLIENT_ID,
WATCH_CLIENT_SCREEN, null),
new InnertubeClientRequestInfo.DeviceInfo(DESKTOP_CLIENT_PLATFORM, null, null,
null, null, -1));
}
@ -106,17 +109,27 @@ public final class InnertubeClientRequestInfo {
public static InnertubeClientRequestInfo ofWebEmbeddedPlayerClient() {
return new InnertubeClientRequestInfo(
new InnertubeClientRequestInfo.ClientInfo(WEB_EMBEDDED_CLIENT_NAME,
WEB_REMIX_HARDCODED_CLIENT_VERSION, EMBED_CLIENT_SCREEN,
WEB_EMBEDDED_CLIENT_ID, null),
WEB_EMBEDDED_CLIENT_VERSION, WEB_EMBEDDED_CLIENT_ID, EMBED_CLIENT_SCREEN,
null),
new InnertubeClientRequestInfo.DeviceInfo(DESKTOP_CLIENT_PLATFORM, null, null,
null, null, -1));
}
@Nonnull
public static InnertubeClientRequestInfo ofWebMusicAnalyticsChartsClient() {
return new InnertubeClientRequestInfo(
new InnertubeClientRequestInfo.ClientInfo(WEB_MUSIC_ANALYTICS_CLIENT_NAME,
WEB_MUSIC_ANALYTICS_CLIENT_VERSION, WEB_MUSIC_ANALYTICS_CLIENT_ID, null,
null),
new InnertubeClientRequestInfo.DeviceInfo(null, null, null,
null, null, -1));
}
@Nonnull
public static InnertubeClientRequestInfo ofAndroidClient() {
return new InnertubeClientRequestInfo(
new InnertubeClientRequestInfo.ClientInfo(ANDROID_CLIENT_NAME,
ANDROID_CLIENT_VERSION, WATCH_CLIENT_SCREEN, ANDROID_CLIENT_ID, null),
ANDROID_CLIENT_VERSION, ANDROID_CLIENT_ID, WATCH_CLIENT_SCREEN, null),
new InnertubeClientRequestInfo.DeviceInfo(MOBILE_CLIENT_PLATFORM, null, null,
"Android", "15", 35));
}
@ -125,7 +138,7 @@ public final class InnertubeClientRequestInfo {
public static InnertubeClientRequestInfo ofIosClient() {
return new InnertubeClientRequestInfo(
new InnertubeClientRequestInfo.ClientInfo(IOS_CLIENT_NAME, IOS_CLIENT_VERSION,
WATCH_CLIENT_SCREEN, IOS_CLIENT_ID, null),
IOS_CLIENT_ID, WATCH_CLIENT_SCREEN, null),
new InnertubeClientRequestInfo.DeviceInfo(MOBILE_CLIENT_PLATFORM, "Apple",
IOS_DEVICE_MODEL, "iOS", IOS_OS_VERSION, -1));
}

View File

@ -1,20 +1,5 @@
package org.schabi.newpipe.extractor.services.youtube;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonWriter;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.ContentCountry;
import org.schabi.newpipe.extractor.localization.Localization;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.defaultAlertsCheck;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonPostResponse;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
@ -22,6 +7,23 @@ import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareDesktopJsonBuilder;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonWriter;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.localization.ContentCountry;
import org.schabi.newpipe.extractor.localization.Localization;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Shared functions for extracting YouTube channel pages and tabs.
*/
@ -65,28 +67,47 @@ public final class YoutubeChannelHelper {
// URL, then no information about the channel associated with this URL was found,
// so the unresolved url will be returned.
if (!channelId[0].equals("channel")) {
final byte[] body = JsonWriter.string(
prepareDesktopJsonBuilder(Localization.DEFAULT, ContentCountry.DEFAULT)
.value("url", "https://www.youtube.com/" + idOrPath)
String urlToResolve = "https://www.youtube.com/" + idOrPath;
JsonObject endpoint = new JsonObject();
String webPageType = "";
// Try to resolve YT channel redirects
// It works like that:
// @TheDailyShow
// -> resolves to thedailyshow
// -> resolves to the id: UCwWhs_6x42TyRM4Wstoq8HA
// Please note that this is not always the case, some handles
// e.g. @google or @Gronkh directly resolve the id
for (int tries = 0;
urlToResolve != null && tries < 3;
tries++) {
final byte[] body = JsonWriter.string(
prepareDesktopJsonBuilder(Localization.DEFAULT, ContentCountry.DEFAULT)
.value("url", urlToResolve)
.done())
.getBytes(StandardCharsets.UTF_8);
final JsonObject jsonResponse = getJsonPostResponse(
final JsonObject jsonResponse = getJsonPostResponse(
"navigation/resolve_url", body, Localization.DEFAULT);
checkIfChannelResponseIsValid(jsonResponse);
checkIfChannelResponseIsValid(jsonResponse);
final JsonObject endpoint = jsonResponse.getObject("endpoint");
endpoint = jsonResponse.getObject("endpoint");
final String webPageType = endpoint.getObject("commandMetadata")
webPageType = endpoint.getObject("commandMetadata")
.getObject("webCommandMetadata")
.getString("webPageType", "");
.getString("webPageType");
final JsonObject browseEndpoint = endpoint.getObject(BROWSE_ENDPOINT);
final String browseId = browseEndpoint.getString(BROWSE_ID, "");
urlToResolve = "WEB_PAGE_TYPE_UNKNOWN".equals(webPageType)
? endpoint.getObject("urlEndpoint").getString("url")
: null;
}
if (webPageType.equalsIgnoreCase("WEB_PAGE_TYPE_BROWSE")
|| webPageType.equalsIgnoreCase("WEB_PAGE_TYPE_CHANNEL")
final String browseId = endpoint.getObject(BROWSE_ENDPOINT)
.getString(BROWSE_ID, "");
if (("WEB_PAGE_TYPE_BROWSE".equalsIgnoreCase(webPageType)
|| "WEB_PAGE_TYPE_CHANNEL".equalsIgnoreCase(webPageType))
&& !browseId.isEmpty()) {
if (!browseId.startsWith("UC")) {
throw new ExtractionException("Redirected id is not pointing to a channel");
@ -94,6 +115,11 @@ public final class YoutubeChannelHelper {
return browseId;
}
// Otherwise, the code after that will run into an IndexOutOfBoundsException
if (channelId.length < 2) {
throw new ExtractionException("Failed to resolve channelId for " + idOrPath);
}
}
// return the unresolved URL
@ -175,13 +201,13 @@ public final class YoutubeChannelHelper {
final String webPageType = endpoint.getObject("commandMetadata")
.getObject("webCommandMetadata")
.getString("webPageType", "");
.getString("webPageType");
final String browseId = endpoint.getObject(BROWSE_ENDPOINT)
.getString(BROWSE_ID, "");
if (webPageType.equalsIgnoreCase("WEB_PAGE_TYPE_BROWSE")
|| webPageType.equalsIgnoreCase("WEB_PAGE_TYPE_CHANNEL")
if (("WEB_PAGE_TYPE_BROWSE".equalsIgnoreCase(webPageType)
|| "WEB_PAGE_TYPE_CHANNEL".equalsIgnoreCase(webPageType))
&& !browseId.isEmpty()) {
if (!browseId.startsWith("UC")) {
throw new ExtractionException("Redirected id is not pointing to a channel");

View File

@ -1181,8 +1181,8 @@ public final class YoutubeParsingHelper {
* @param name The X-YouTube-Client-Name value.
* @param version X-YouTube-Client-Version value.
*/
static Map<String, List<String>> getClientHeaders(@Nonnull final String name,
@Nonnull final String version) {
public 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));
}
@ -1525,7 +1525,7 @@ public final class YoutubeParsingHelper {
}
@Nonnull
static JsonBuilder<JsonObject> prepareJsonBuilder(
public static JsonBuilder<JsonObject> prepareJsonBuilder(
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry,
@Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo,
@ -1534,9 +1534,15 @@ public final class YoutubeParsingHelper {
.object("context")
.object("client")
.value("clientName", innertubeClientRequestInfo.clientInfo.clientName)
.value("clientVersion", innertubeClientRequestInfo.clientInfo.clientVersion)
.value("clientScreen", innertubeClientRequestInfo.clientInfo.clientScreen)
.value("platform", innertubeClientRequestInfo.deviceInfo.platform);
.value("clientVersion", innertubeClientRequestInfo.clientInfo.clientVersion);
if (innertubeClientRequestInfo.clientInfo.clientScreen != null) {
builder.value("clientScreen", innertubeClientRequestInfo.clientInfo.clientScreen);
}
if (innertubeClientRequestInfo.deviceInfo.platform != null) {
builder.value("platform", innertubeClientRequestInfo.deviceInfo.platform);
}
if (innertubeClientRequestInfo.clientInfo.visitorData != null) {
builder.value("visitorData", innertubeClientRequestInfo.clientInfo.visitorData);

View File

@ -35,14 +35,24 @@ import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSearchExt
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSubscriptionExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSuggestionExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeLiveExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingGamingVideosExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMoviesAndShowsTrailersExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMusicExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingPodcastsEpisodesExtractor;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelTabLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeCommentsLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeLiveLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingGamingVideosLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingMusicLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingPodcastsEpisodesLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;
@ -154,20 +164,71 @@ public class YoutubeService extends StreamingService {
@Override
public KioskList getKioskList() throws ExtractionException {
final KioskList list = new KioskList(this);
final ListLinkHandlerFactory h = YoutubeTrendingLinkHandlerFactory.getInstance();
final ListLinkHandlerFactory trendingLHF = YoutubeTrendingLinkHandlerFactory.INSTANCE;
final ListLinkHandlerFactory runningLivesLHF =
YoutubeLiveLinkHandlerFactory.INSTANCE;
final ListLinkHandlerFactory trendingPodcastsEpisodesLHF =
YoutubeTrendingPodcastsEpisodesLinkHandlerFactory.INSTANCE;
final ListLinkHandlerFactory trendingGamingVideosLHF =
YoutubeTrendingGamingVideosLinkHandlerFactory.INSTANCE;
final ListLinkHandlerFactory trendingMoviesAndShowsLHF =
YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory.INSTANCE;
final ListLinkHandlerFactory trendingMusicLHF =
YoutubeTrendingMusicLinkHandlerFactory.INSTANCE;
// add kiosks here e.g.:
try {
list.addKioskEntry(
(streamingService, url, id) -> new YoutubeLiveExtractor(
YoutubeService.this,
runningLivesLHF.fromUrl(url),
id),
runningLivesLHF,
YoutubeLiveLinkHandlerFactory.KIOSK_ID
);
list.addKioskEntry(
(streamingService, url, id) -> new YoutubeTrendingPodcastsEpisodesExtractor(
YoutubeService.this,
trendingPodcastsEpisodesLHF.fromUrl(url),
id),
trendingPodcastsEpisodesLHF,
YoutubeTrendingPodcastsEpisodesLinkHandlerFactory.KIOSK_ID
);
list.addKioskEntry(
(streamingService, url, id) -> new YoutubeTrendingGamingVideosExtractor(
YoutubeService.this,
trendingGamingVideosLHF.fromUrl(url),
id),
trendingGamingVideosLHF,
YoutubeTrendingGamingVideosLinkHandlerFactory.KIOSK_ID
);
list.addKioskEntry(
(streamingService, url, id) ->
new YoutubeTrendingMoviesAndShowsTrailersExtractor(
YoutubeService.this,
trendingMoviesAndShowsLHF.fromUrl(url),
id),
trendingMoviesAndShowsLHF,
YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory.KIOSK_ID
);
list.addKioskEntry(
(streamingService, url, id) -> new YoutubeTrendingMusicExtractor(
YoutubeService.this,
trendingMusicLHF.fromUrl(url),
id),
trendingMusicLHF,
YoutubeTrendingMusicLinkHandlerFactory.KIOSK_ID
);
// Deprecated (i.e. removed from the interface of YouTube) since July 21, 2025
list.addKioskEntry(
(streamingService, url, id) -> new YoutubeTrendingExtractor(
YoutubeService.this,
h.fromUrl(url),
trendingLHF.fromUrl(url),
id
),
h,
trendingLHF,
YoutubeTrendingExtractor.KIOSK_ID
);
list.setDefaultKiosk(YoutubeTrendingExtractor.KIOSK_ID);
list.setDefaultKiosk(YoutubeLiveLinkHandlerFactory.KIOSK_ID);
} catch (final Exception e) {
throw new ExtractionException(e);
}

View File

@ -209,8 +209,10 @@ public class YoutubeStreamInfoItemLockupExtractor implements StreamInfoItemExtra
throw new ParsingException("Could not get uploader url");
}
private String resolveUploaderUrlFromRelativeUrl(final String url) throws ParsingException {
return YoutubeChannelLinkHandlerFactory.getInstance().getUrl("c" + url);
private String resolveUploaderUrlFromRelativeUrl(final String relativeUrl)
throws ParsingException {
return YoutubeChannelLinkHandlerFactory.getInstance().getUrl(
relativeUrl.startsWith("/") ? relativeUrl.substring(1) : relativeUrl);
}
@Nonnull

View File

@ -0,0 +1,239 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonWriter;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.localization.ContentCountry;
import org.schabi.newpipe.extractor.localization.DateWrapper;
import org.schabi.newpipe.extractor.localization.Localization;
import org.schabi.newpipe.extractor.services.youtube.InnertubeClientRequestInfo;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.DISABLE_PRETTY_PRINT_PARAMETER;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getClientHeaders;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getOriginReferrerHeaders;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getThumbnailsFromInfoItem;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getValidJsonResponseBody;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareJsonBuilder;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
/**
* Base class parsing responses from YouTube Charts for all trending video charts.
*
* <p>
* Note: YouTube Charts isn't officially supported in all YouTube supported countries (there are
* fewer countries in the {@code LAUNCHED_CHART_COUNTRIES} array of YouTube Charts' HTML responses
* than in the YouTube country selector).
* </p>
*
* <p>
* For some trends, some videos are still returned in unsupported countries, even if there are
* fewer than in a supported country, for others an HTTP 400 error is returned saying
* {@code Request contains an invalid argument.}.
* </p>
*/
abstract class YoutubeChartsBaseKioskExtractor extends KioskExtractor<StreamInfoItem> {
// Extracted from YouTube Charts' HTML, in the array named LAUNCHED_CHART_COUNTRIES
protected static final Set<String> YT_CHARTS_SUPPORTED_COUNTRY_CODES = Set.of(
"AE", "AR", "AT", "AU", "BE", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CZ", "DE",
"DK", "DO", "EC", "EE", "EG", "ES", "FI", "FR", "GB", "GT", "HN", "HU", "ID", "IE",
"IL", "IN", "IS", "IT", "JP", "KE", "KR", "LU", "MX", "NG", "NI", "NL", "NO", "NZ",
"PA", "PE", "PL", "PT", "PY", "RO", "RS", "RU", "SA", "SE", "SV", "TR", "TZ", "UA",
"UG", "US", "UY", "ZA", "ZW");
protected static final String YT_CHARTS_ENDPOINT =
"https://charts.youtube.com/youtubei/v1/browse?alt=json&"
+ DISABLE_PRETTY_PRINT_PARAMETER;
protected final String chartType;
protected JsonObject browseResponse;
protected YoutubeChartsBaseKioskExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId,
final String chartType) {
super(streamingService, linkHandler, kioskId);
this.chartType = chartType;
}
@Override
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
final Localization localization = getExtractorLocalization();
final ContentCountry contentCountry = getExtractorContentCountry();
final InnertubeClientRequestInfo innertubeClientRequestInfo =
InnertubeClientRequestInfo.ofWebMusicAnalyticsChartsClient();
final byte[] body = JsonWriter.string(prepareJsonBuilder(getExtractorLocalization(),
contentCountry, innertubeClientRequestInfo, null)
.value("browseId", "FEmusic_analytics_charts_home")
.value("query", "perspective=CHART_DETAILS&chart_params_country_code="
+ contentCountry.getCountryCode() + "&chart_params_chart_type="
+ chartType)
.done())
.getBytes(StandardCharsets.UTF_8);
final var headers = new HashMap<>(getOriginReferrerHeaders("https://charts.youtube.com"));
headers.putAll(getClientHeaders(innertubeClientRequestInfo.clientInfo.clientId,
innertubeClientRequestInfo.clientInfo.clientVersion));
browseResponse = JsonUtils.toJsonObject(getValidJsonResponseBody(
getDownloader().postWithContentTypeJson(
YT_CHARTS_ENDPOINT, headers, body, localization)));
}
@Nonnull
@Override
public abstract String getName() throws ParsingException;
@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
final JsonArray videos = browseResponse.getObject("contents")
.getObject("sectionListRenderer")
.getArray("contents")
.getObject(0)
.getObject("musicAnalyticsSectionRenderer")
.getObject("content")
.getArray("videos")
.getObject(0)
.getArray("videoViews");
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
videos.streamAsJsonObjects()
.forEachOrdered(video -> collector.commit(
new YoutubeChartsVideoInfoItemExtractor(video)));
return new InfoItemsPage<>(collector, null);
}
@Override
public InfoItemsPage<StreamInfoItem> getPage(final Page page) {
// There is no continuation in charts
return InfoItemsPage.emptyPage();
}
static final class YoutubeChartsVideoInfoItemExtractor
implements StreamInfoItemExtractor {
@Nonnull
private final JsonObject videoObject;
YoutubeChartsVideoInfoItemExtractor(@Nonnull final JsonObject videoObject) {
this.videoObject = videoObject;
}
@Override
public StreamType getStreamType() {
// There are only video streams in YouTube Charts, at least for now
return StreamType.VIDEO_STREAM;
}
@Override
public boolean isAd() {
return false;
}
@Override
public long getDuration() {
return videoObject.getInt("videoDuration", -1);
}
@Override
public long getViewCount() {
// View counts aren't returned, at least for now
return -1;
}
@Override
public String getUploaderName() {
return videoObject.getString("channelName");
}
@Override
public String getUploaderUrl() throws ParsingException {
final String channelId = videoObject.getString("externalChannelId");
if (isNullOrEmpty(channelId)) {
throw new ParsingException("Could not get channel ID");
}
return YoutubeChannelLinkHandlerFactory.getInstance().getUrl("channel/" + channelId);
}
@Override
public boolean isUploaderVerified() {
// We don't have any info on this, at least for now
return false;
}
@Nullable
@Override
public String getTextualUploadDate() {
return null;
}
@Nonnull
@Override
public DateWrapper getUploadDate() {
final JsonObject releaseDate = videoObject.getObject("releaseDate");
return new DateWrapper(OffsetDateTime.of(
releaseDate.getInt("year"),
releaseDate.getInt("month"),
releaseDate.getInt("day"),
0,
0,
0,
0,
// We request that times should be returned with 0 offset to UTC timezone in
// the JSON body, but YouTube charts does it only in its HTTP headers
ZoneOffset.UTC),
// We don't have more info than the release day
true);
}
@Override
public String getName() {
return videoObject.getString("title");
}
@Override
public String getUrl() throws ParsingException {
return YoutubeStreamLinkHandlerFactory.getInstance().getUrl(
videoObject.getString("id"));
}
@Nonnull
@Override
public List<Image> getThumbnails() throws ParsingException {
return getThumbnailsFromInfoItem(videoObject);
}
}
}

View File

@ -0,0 +1,208 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
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.getClientVersion;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonPostResponse;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.prepareJsonBuilder;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import com.grack.nanojson.JsonWriter;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
import org.schabi.newpipe.extractor.services.youtube.InnertubeClientRequestInfo;
import org.schabi.newpipe.extractor.services.youtube.YoutubeChannelHelper;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamInfoItemLockupExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
abstract class YoutubeDesktopBaseKioskExtractor extends KioskExtractor<StreamInfoItem> {
protected final String browseId;
protected final String params;
protected YoutubeChannelHelper.ChannelResponseData responseData;
protected YoutubeDesktopBaseKioskExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId,
final String browseId,
final String params) {
super(streamingService, linkHandler, kioskId);
this.browseId = browseId;
this.params = params;
}
@Override
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
responseData = YoutubeChannelHelper.getChannelResponse(
browseId,
params,
getExtractorLocalization(),
getExtractorContentCountry());
}
@Nonnull
@Override
public String getName() throws ParsingException {
return YoutubeChannelHelper.getChannelName(
YoutubeChannelHelper.getChannelHeader(responseData.jsonResponse),
null,
responseData.jsonResponse);
}
@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, ExtractionException {
final JsonObject tabRendererContent = responseData.jsonResponse.getObject("contents")
.getObject("twoColumnBrowseResultsRenderer")
.getArray("tabs")
.getObject(0)
.getObject("tabRenderer")
.getObject("content");
final JsonArray tabContents;
if (tabRendererContent.has("sectionListRenderer")) {
tabContents = tabRendererContent.getObject("sectionListRenderer")
.getArray("contents")
.getObject(0)
.getObject("itemSectionRenderer")
.getArray("contents")
.getObject(0)
.getObject("shelfRenderer")
.getObject("content")
.getObject("gridRenderer")
.getArray("items");
} else if (tabRendererContent.has("richGridRenderer")) {
tabContents = tabRendererContent.getObject("richGridRenderer")
.getArray("contents");
} else {
tabContents = new JsonArray();
}
return collectStreamItems(tabContents,
responseData.jsonResponse.getObject("responseContext")
.getString("visitorData"));
}
@Override
public InfoItemsPage<StreamInfoItem> getPage(final Page page)
throws IOException, ExtractionException {
if (page == null || page.getBody() == null) {
throw new IllegalArgumentException("Page is null or doesn't contain a body");
}
final JsonObject continuationResponse = getJsonPostResponse("browse", page.getBody(),
getExtractorLocalization());
final JsonArray continuationItems =
continuationResponse.getArray("onResponseReceivedActions")
.stream()
.filter(JsonObject.class::isInstance)
.map(JsonObject.class::cast)
.filter(jsonObject -> jsonObject.has("appendContinuationItemsAction"))
.map(jsonObject -> jsonObject.getObject("appendContinuationItemsAction"))
.findFirst()
.orElse(new JsonObject())
.getArray("continuationItems");
// The page ID is the visitor data
return collectStreamItems(continuationItems, page.getId());
}
private InfoItemsPage<StreamInfoItem> collectStreamItems(
@Nonnull final JsonArray items,
@Nullable final String visitorData) throws IOException, ExtractionException {
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
final Page nextPage;
if (items.isEmpty()) {
nextPage = null;
} else {
final TimeAgoParser timeAgoParser = getTimeAgoParser();
items.streamAsJsonObjects()
.forEachOrdered(content -> {
if (content.has("richItemRenderer")) {
final JsonObject richItem = content.getObject("richItemRenderer")
.getObject("content");
if (richItem.has("videoRenderer")) {
collector.commit(new YoutubeStreamInfoItemExtractor(
richItem.getObject("videoRenderer"), timeAgoParser));
}
} else if (content.has("gridVideoRenderer")) {
collector.commit(new YoutubeStreamInfoItemExtractor(
content.getObject("gridVideoRenderer"), timeAgoParser));
} else if (content.has("lockupViewModel")) {
// lockupViewModels are not used yet, but may be in the future
final JsonObject lockupViewModel = content.getObject("lockupViewModel");
if ("LOCKUP_CONTENT_TYPE_VIDEO".equals(
lockupViewModel.getString("contentType"))) {
collector.commit(new YoutubeStreamInfoItemLockupExtractor(
lockupViewModel, timeAgoParser));
}
}
});
final JsonObject lastContent = items.getObject(items.size() - 1);
if (lastContent.has("continuationItemRenderer")) {
nextPage = getNextPageFrom(
lastContent.getObject("continuationItemRenderer"), visitorData);
} else {
nextPage = null;
}
}
return new InfoItemsPage<>(collector, nextPage);
}
@Nullable
private Page getNextPageFrom(@Nullable final JsonObject continuation,
@Nullable final String visitorData)
throws IOException, ExtractionException {
if (isNullOrEmpty(continuation)) {
return null;
}
final JsonObject continuationEndpoint = continuation.getObject("continuationEndpoint");
final String continuationToken = continuationEndpoint.getObject("continuationCommand")
.getString("token");
// Visitor data is required to get videos in continuations, so we need to apply it to the
// next page and save it as an ID so it can be applied to future continuations
final InnertubeClientRequestInfo webClientRequestInfo =
InnertubeClientRequestInfo.ofWebClient();
webClientRequestInfo.clientInfo.clientVersion = getClientVersion();
webClientRequestInfo.clientInfo.visitorData = visitorData;
final byte[] body = JsonWriter.string(prepareJsonBuilder(getExtractorLocalization(),
getExtractorContentCountry(),
webClientRequestInfo,
null)
.value("continuation", continuationToken)
.done())
.getBytes(StandardCharsets.UTF_8);
// The URL is not needed and used, it is only provided to make Page.isValid return true
return new Page(YOUTUBEI_V1_URL + "browse?" + DISABLE_PRETTY_PRINT_PARAMETER, visitorData,
null, null, body);
}
}

View File

@ -0,0 +1,14 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
public class YoutubeLiveExtractor extends YoutubeDesktopBaseKioskExtractor {
public YoutubeLiveExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId) {
super(streamingService, linkHandler, kioskId, "UC4R8DWoMoI7CAwX8_LjQHig",
"EgdsaXZldGFikgEDCKEK");
}
}

View File

@ -18,7 +18,7 @@
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.extractor.services.youtube.extractors;
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonPostResponse;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextAtKey;
@ -36,6 +36,7 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;

View File

@ -0,0 +1,14 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
public class YoutubeTrendingGamingVideosExtractor extends YoutubeDesktopBaseKioskExtractor {
public YoutubeTrendingGamingVideosExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId) {
super(streamingService, linkHandler, kioskId, "UCOpNcN46UbXVtpKMrmU4Abg",
"Egh0cmVuZGluZw%3D%3D");
}
}

View File

@ -0,0 +1,24 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import javax.annotation.Nonnull;
public class YoutubeTrendingMoviesAndShowsTrailersExtractor
extends YoutubeChartsBaseKioskExtractor {
public YoutubeTrendingMoviesAndShowsTrailersExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId) {
super(streamingService, linkHandler, kioskId, "TRENDING_MOVIES");
}
@Nonnull
@Override
public String getName() throws ParsingException {
// This is the official YouTube Charts name, even if shows' trailers are returned too
return "Trending Movie Trailers";
}
}

View File

@ -0,0 +1,39 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.UnsupportedContentInCountryException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import javax.annotation.Nonnull;
import java.io.IOException;
public class YoutubeTrendingMusicExtractor extends YoutubeChartsBaseKioskExtractor {
public YoutubeTrendingMusicExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId) {
super(streamingService, linkHandler, kioskId, "TRENDING_VIDEOS");
}
@Override
public void onFetchPage(@Nonnull final Downloader downloader)
throws IOException, ExtractionException {
if (!YT_CHARTS_SUPPORTED_COUNTRY_CODES.contains(
getExtractorContentCountry().getCountryCode())) {
throw new UnsupportedContentInCountryException(
"YouTube Charts doesn't support this country for trending music videos charts");
}
super.onFetchPage(downloader);
}
@Nonnull
@Override
public String getName() throws ParsingException {
// This is the official YouTube Charts name, even if autogenerated tracks and unofficial
// contents are returned
return "Trending Music Videos";
}
}

View File

@ -0,0 +1,13 @@
package org.schabi.newpipe.extractor.services.youtube.extractors.kiosk;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
public class YoutubeTrendingPodcastsEpisodesExtractor extends YoutubeDesktopBaseKioskExtractor {
public YoutubeTrendingPodcastsEpisodesExtractor(final StreamingService streamingService,
final ListLinkHandler linkHandler,
final String kioskId) {
super(streamingService, linkHandler, kioskId, "FEpodcasts_destination", "qgcCCAM%3D");
}
}

View File

@ -0,0 +1,53 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isInvidiousURL;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeURL;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public final class YoutubeLiveLinkHandlerFactory extends ListLinkHandlerFactory {
public static final String KIOSK_ID = "live";
public static final YoutubeLiveLinkHandlerFactory INSTANCE =
new YoutubeLiveLinkHandlerFactory();
private static final String LIVE_CHANNEL_PATH = "/channel/UC4R8DWoMoI7CAwX8_LjQHig/livetab";
private static final String LIVE_CHANNEL_TAB_PARAMS = "ss=CKEK";
private YoutubeLiveLinkHandlerFactory() {
}
@Override
public String getUrl(final String id,
final List<String> contentFilters,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://www.youtube.com" + LIVE_CHANNEL_PATH + "?" + LIVE_CHANNEL_TAB_PARAMS;
}
@Override
public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return KIOSK_ID;
}
@Override
public boolean onAcceptUrl(final String url) {
final URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (final MalformedURLException e) {
return false;
}
return Utils.isHTTP(urlObj) && (isYoutubeURL(urlObj) || isInvidiousURL(urlObj))
&& LIVE_CHANNEL_PATH.equals(urlObj.getPath())
&& LIVE_CHANNEL_TAB_PARAMS.equals(urlObj.getQuery());
}
}

View File

@ -0,0 +1,49 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isInvidiousURL;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeURL;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public final class YoutubeTrendingGamingVideosLinkHandlerFactory extends ListLinkHandlerFactory {
public static final String KIOSK_ID = "trending_gaming";
public static final YoutubeTrendingGamingVideosLinkHandlerFactory INSTANCE =
new YoutubeTrendingGamingVideosLinkHandlerFactory();
private YoutubeTrendingGamingVideosLinkHandlerFactory() {
}
@Override
public String getUrl(final String id,
final List<String> contentFilters,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://www.youtube.com/gaming/trending";
}
@Override
public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return KIOSK_ID;
}
@Override
public boolean onAcceptUrl(final String url) {
final URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (final MalformedURLException e) {
return false;
}
return Utils.isHTTP(urlObj) && (isYoutubeURL(urlObj) || isInvidiousURL(urlObj))
&& "/gaming/trending".equals(urlObj.getPath());
}
}

View File

@ -33,16 +33,12 @@ import java.util.List;
public final class YoutubeTrendingLinkHandlerFactory extends ListLinkHandlerFactory {
private static final YoutubeTrendingLinkHandlerFactory INSTANCE =
public static final YoutubeTrendingLinkHandlerFactory INSTANCE =
new YoutubeTrendingLinkHandlerFactory();
private YoutubeTrendingLinkHandlerFactory() {
}
public static YoutubeTrendingLinkHandlerFactory getInstance() {
return INSTANCE;
}
public String getUrl(final String id,
final List<String> contentFilters,
final String sortFilter)

View File

@ -0,0 +1,51 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Locale;
public final class YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory
extends ListLinkHandlerFactory {
public static final String KIOSK_ID = "trending_movies_and_shows";
public static final YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory INSTANCE =
new YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory();
private static final String PATH = "/charts/TrendingTrailers";
private YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory() {
}
@Override
public String getUrl(final String id,
final List<String> contentFilter,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://charts.youtube.com" + PATH;
}
@Override
public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return KIOSK_ID;
}
@Override
public boolean onAcceptUrl(final String url) throws ParsingException {
final URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (final MalformedURLException e) {
return false;
}
return Utils.isHTTP(urlObj)
&& "charts.youtube.com".equals(urlObj.getHost().toLowerCase(Locale.ROOT))
&& PATH.equals(urlObj.getPath());
}
}

View File

@ -0,0 +1,52 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Locale;
public final class YoutubeTrendingMusicLinkHandlerFactory
extends ListLinkHandlerFactory {
public static final String KIOSK_ID = "trending_music";
public static final YoutubeTrendingMusicLinkHandlerFactory INSTANCE =
new YoutubeTrendingMusicLinkHandlerFactory();
private static final String PATH = "/charts/TrendingVideos";
private YoutubeTrendingMusicLinkHandlerFactory() {
}
@Override
public String getUrl(final String id,
final List<String> contentFilter,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://charts.youtube.com" + PATH + "/RightNow";
}
@Override
public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return KIOSK_ID;
}
@Override
public boolean onAcceptUrl(final String url) throws ParsingException {
final URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (final MalformedURLException e) {
return false;
}
return Utils.isHTTP(urlObj)
&& "charts.youtube.com".equals(urlObj.getHost().toLowerCase(Locale.ROOT))
// Accept URLs not containing the /RightNow part
&& urlObj.getPath().startsWith(PATH);
}
}

View File

@ -0,0 +1,52 @@
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isInvidiousURL;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeURL;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.utils.Utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public final class YoutubeTrendingPodcastsEpisodesLinkHandlerFactory
extends ListLinkHandlerFactory {
public static final String KIOSK_ID = "trending_podcasts_episodes";
public static final YoutubeTrendingPodcastsEpisodesLinkHandlerFactory INSTANCE =
new YoutubeTrendingPodcastsEpisodesLinkHandlerFactory();
private static final String PATH = "/podcasts/popularepisodes";
private YoutubeTrendingPodcastsEpisodesLinkHandlerFactory() {
}
@Override
public String getUrl(final String id,
final List<String> contentFilters,
final String sortFilter)
throws ParsingException, UnsupportedOperationException {
return "https://www.youtube.com" + PATH;
}
@Override
public String getId(final String url) throws ParsingException, UnsupportedOperationException {
return KIOSK_ID;
}
@Override
public boolean onAcceptUrl(final String url) {
final URL urlObj;
try {
urlObj = Utils.stringToURL(url);
} catch (final MalformedURLException e) {
return false;
}
return Utils.isHTTP(urlObj) && (isYoutubeURL(urlObj) || isInvidiousURL(urlObj))
&& PATH.equals(urlObj.getPath());
}
}

View File

@ -0,0 +1,45 @@
package org.schabi.newpipe.extractor.services.youtube;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
class YouTubeChannelHelperTest implements InitYoutubeTest {
@ParameterizedTest
@ValueSource(strings = {
"@TheDailyShow",
"thedailyshow",
"channel/UCwWhs_6x42TyRM4Wstoq8HA",
"UCwWhs_6x42TyRM4Wstoq8HA"
})
void resolveSuccessfulTheDailyShow(final String idOrPath) {
final String id = assertDoesNotThrow(
() -> YoutubeChannelHelper.resolveChannelId(idOrPath));
assertEquals("UCwWhs_6x42TyRM4Wstoq8HA", id);
}
@ParameterizedTest
@ValueSource(strings = {
"@Gronkh",
"gronkh",
"channel/UCYJ61XIK64sp6ZFFS8sctxw",
"UCYJ61XIK64sp6ZFFS8sctxw"
})
void resolveSuccessfulGronkh(final String idOrPath) {
final String id = assertDoesNotThrow(
() -> YoutubeChannelHelper.resolveChannelId(idOrPath));
assertEquals("UCYJ61XIK64sp6ZFFS8sctxw", id);
}
@Test
void resolveFailNonExistingTag() {
assertThrows(ExtractionException.class, () -> YoutubeChannelHelper.resolveChannelId(
"@nonExistingHandleThatWillNeverExist15464"));
}
}

View File

@ -3,22 +3,305 @@ package org.schabi.newpipe.extractor.services.youtube;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoMoreItems;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultSimpleExtractorTest;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeLiveExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingGamingVideosExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMoviesAndShowsTrailersExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMusicExtractor;
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingPodcastsEpisodesExtractor;
public class YoutubeKioskExtractorTest {
public static class Live extends DefaultSimpleExtractorTest<YoutubeLiveExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeLiveExtractor createExtractor() throws Exception {
return (YoutubeLiveExtractor) YouTube.getKioskList().getDefaultKioskExtractor();
}
@Override
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor().getServiceId());
}
@Override
@Test
public void testName() throws Exception {
assertEquals("Live", extractor().getName());
}
@Override
@Test
public void testId() throws Exception {
assertEquals("live", extractor().getId());
}
@Override
@Test
public void testUrl() throws Exception {
assertEquals(
"https://www.youtube.com/channel/UC4R8DWoMoI7CAwX8_LjQHig/livetab?ss=CKEK",
extractor().getUrl());
}
@Override
@Test
public void testOriginalUrl() throws Exception {
assertEquals(
"https://www.youtube.com/channel/UC4R8DWoMoI7CAwX8_LjQHig/livetab?ss=CKEK",
extractor().getOriginalUrl());
}
@Override
@Test
public void testRelatedItems() throws Exception {
// As there is sometimes very recently ended livestreams present, we can't test whether
// all streams are running live streams
defaultTestRelatedItems(extractor());
}
@Override
@Test
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor());
}
}
public static class TrendingPodcastsEpisodes extends
DefaultSimpleExtractorTest<YoutubeTrendingPodcastsEpisodesExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeTrendingPodcastsEpisodesExtractor createExtractor() throws Exception {
return (YoutubeTrendingPodcastsEpisodesExtractor) YouTube.getKioskList()
.getExtractorById("trending_podcasts_episodes", null);
}
@Override
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor().getServiceId());
}
@Override
@Test
public void testName() throws Exception {
// The name is the title of channel and not of the section
assertEquals("Podcasts", extractor().getName());
}
@Override
@Test
public void testId() throws Exception {
assertEquals("trending_podcasts_episodes", extractor().getId());
}
@Override
@Test
public void testUrl() throws Exception {
assertEquals("https://www.youtube.com/podcasts/popularepisodes", extractor().getUrl());
}
@Override
@Test
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/podcasts/popularepisodes",
extractor().getOriginalUrl());
}
@Override
@Test
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor());
}
@Override
@Test
public void testMoreRelatedItems() throws Exception {
assertNoMoreItems(extractor());
}
}
public static class TrendingGamingVideos extends
DefaultSimpleExtractorTest<YoutubeTrendingGamingVideosExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeTrendingGamingVideosExtractor createExtractor() throws Exception {
return (YoutubeTrendingGamingVideosExtractor) YouTube.getKioskList()
.getExtractorById("trending_gaming", null);
}
@Override
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor().getServiceId());
}
@Override
@Test
public void testName() throws Exception {
// The name is the title of channel and not of the section
assertEquals("Gaming", extractor().getName());
}
@Override
@Test
public void testId() throws Exception {
assertEquals("trending_gaming", extractor().getId());
}
@Override
@Test
public void testUrl() throws Exception {
assertEquals("https://www.youtube.com/gaming/trending", extractor().getUrl());
}
@Override
@Test
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/gaming/trending", extractor().getOriginalUrl());
}
@Override
@Test
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor());
}
@Override
@Test
public void testMoreRelatedItems() throws Exception {
assertNoMoreItems(extractor());
}
}
public static class TrendingMoviesAndShowsTrailers extends
DefaultSimpleExtractorTest<YoutubeTrendingMoviesAndShowsTrailersExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeTrendingMoviesAndShowsTrailersExtractor createExtractor() throws Exception {
return (YoutubeTrendingMoviesAndShowsTrailersExtractor) YouTube.getKioskList()
.getExtractorById("trending_movies_and_shows", null);
}
@Override
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor().getServiceId());
}
@Override
@Test
public void testName() throws Exception {
// The title is hardcoded in the extractor, as InnerTube responses don't provide it
// (handled client-side)
assertEquals("Trending Movie Trailers", extractor().getName());
}
@Override
@Test
public void testId() throws Exception {
assertEquals("trending_movies_and_shows", extractor().getId());
}
@Override
@Test
public void testUrl() throws Exception {
assertEquals("https://charts.youtube.com/charts/TrendingTrailers",
extractor().getUrl());
}
@Override
@Test
public void testOriginalUrl() throws Exception {
assertEquals("https://charts.youtube.com/charts/TrendingTrailers",
extractor().getOriginalUrl());
}
@Override
@Test
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor());
}
@Override
@Test
public void testMoreRelatedItems() throws Exception {
assertNoMoreItems(extractor());
}
}
public static class TrendingMusic extends
DefaultSimpleExtractorTest<YoutubeTrendingMusicExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeTrendingMusicExtractor createExtractor() throws Exception {
return (YoutubeTrendingMusicExtractor) YouTube.getKioskList()
.getExtractorById("trending_music", null);
}
@Override
@Test
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor().getServiceId());
}
@Override
@Test
public void testName() throws Exception {
// The title is hardcoded in the extractor, as InnerTube responses don't provide it
// (handled client-side)
assertEquals("Trending Music Videos", extractor().getName());
}
@Override
@Test
public void testId() throws Exception {
assertEquals("trending_music", extractor().getId());
}
@Override
@Test
public void testUrl() throws Exception {
assertEquals("https://charts.youtube.com/charts/TrendingVideos/RightNow",
extractor().getUrl());
}
@Override
@Test
public void testOriginalUrl() throws Exception {
assertEquals("https://charts.youtube.com/charts/TrendingVideos/RightNow",
extractor().getOriginalUrl());
}
@Override
@Test
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor());
}
@Override
@Test
public void testMoreRelatedItems() throws Exception {
assertNoMoreItems(extractor());
}
}
// Deprecated (i.e. removed from the interface of YouTube) since July 21, 2025
public static class Trending extends DefaultSimpleExtractorTest<YoutubeTrendingExtractor>
implements BaseListExtractorTest, InitYoutubeTest {
implements BaseListExtractorTest, InitYoutubeTest {
@Override
protected YoutubeTrendingExtractor createExtractor() throws Exception {
return (YoutubeTrendingExtractor) YouTube.getKioskList().getDefaultKioskExtractor();
return (YoutubeTrendingExtractor) YouTube.getKioskList().getExtractorById(
"Trending", null);
}
@Override

View File

@ -69,7 +69,7 @@ public class YoutubeServiceTest {
@Test
void testGetDefaultKiosk() throws Exception {
assertEquals("Trending", kioskList.getDefaultKioskExtractor(null).getId());
assertEquals("live", kioskList.getDefaultKioskExtractor(null).getId());
}

View File

@ -0,0 +1,96 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"access-control-allow-credentials": [
"true"
],
"access-control-allow-origin": [
"https://www.youtube.com"
],
"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-security-policy-report-only": [
"script-src \u0027unsafe-eval\u0027 \u0027self\u0027 \u0027unsafe-inline\u0027 https://www.google.com https://apis.google.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com https://www.google-analytics.com https://*.youtube.com https://*.google.com https://*.gstatic.com https://youtube.com https://www.youtube.com https://google.com https://*.doubleclick.net https://*.googleapis.com https://www.googleadservices.com https://tpc.googlesyndication.com https://www.youtubekids.com;report-uri /cspreport/allowlist"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Thu, 31 Jul 2025 09:08:16 GMT"
],
"document-policy": [
"include-js-call-stacks-in-crash-reports"
],
"expires": [
"Thu, 31 Jul 2025 09:08:16 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\"}]}"
],
"reporting-endpoints": [
"default\u003d\"/web-reports?context\u003deJwNz3tIU3EUB3Bv3zLdnbv3d4RCDRIRimyi0ymWJhQ-Ei2DInGWOt18NKfNuzXLIsIsSaKwUmsFFaRU2gMKZFr9ERiBFT7-yJQeIiFZ1h-ZZGXnjw-Hw5dzOEfnWzEWeUCqXqqRorOd0v2jB6WidS4p43W9lLdKk1ozNWn-lib1-DVpNtIjWaI8UseYR3K890qLU17pmlqwzB5esMzL_IU62O06_OzU4ceEDg1zOlhiZFCsjJEcGbM7ZDzukuF_KGPyswy3RY_vJXokuvWonddjJj8EA50hGB4JwcbdBqS2GtDdZ0D-oAHnWcUfA779NSApTUFvlgKPTUG3Q4HsUXC5RUF8u4IsFnRdweqXCgaiVQSVqNAx80UVw1dUBN9T4RtSMfFLxebfKvaFCmgbBPoTBUrNAkmbBJrSBXx7BLYXC0yyvAqBsmqBGw0CjY2cM-tJga1nBF61cj0rMNcmYLogsOWSwNPbApF3BN71CET0Ciw9EQh6wf2QQOiowPhbgTUzAslzAp8WBCoX2T-BcwEEQzChJozwLJzQF0HoWEvwsakowsB6QkICwcwCzYShFEJpKqE-ndC1jfAokzDOYrIJD9hSDqEwl1DE9rMSZmXlzM4qWTVzMCerYy6mMQ_zssOskV3dSQjYRWhmX_YSci2Ej0U8U0yoqOAdbJEFu_m-I5wfI4SdICywvGbCVyafIqSxptOElS2EgjbC8nb-8ybf1MW_dhM-9BAy_DzTT1AGCaQPOj5993mg-mZ6tAVRxoZat-a22mIP2axGu6vWqRltznJjmatKqyordRSb4kzmuGRTSmx8XHFd3H8KrcfX\""
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003dYhEHSiU9_R8; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dFri, 04-Nov-2022 09:08:16 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
"latestUrl": "https://www.youtube.com/sw.js"
}
}

View File

@ -0,0 +1,387 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
64,
84,
104,
101,
68,
97,
105,
108,
121,
83,
104,
111,
119,
34,
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": [
"Thu, 31 Jul 2025 09:08:18 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\":\"Cgtjakg2T2tKQ2V0cyiC5azEBjIKCgJERRIEEgAgNA%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250730.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0xab075da409b2d773\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"23804281,23986030,24004644,24077241,24166867,24290153,24378828,24453989,24490090,24499532,24699899,39325854,39328892,51010235,51025415,51037346,51037351,51063643,51072748,51095478,51098299,51115184,51141472,51152050,51178310,51178333,51178346,51178351,51183909,51204329,51222973,51227037,51237842,51242448,51256074,51272458,51285052,51300176,51300241,51311025,51311036,51313109,51313767,51314158,51338524,51340662,51341228,51342857,51343619,51349914,51353393,51354567,51355201,51355912,51357475,51359179,51362073,51366423,51367487,51372971,51375205,51386540,51389629,51404808,51404810,51404953,51412777,51414747,51432294,51432560,51433503,51436340,51437205,51440725,51441712,51444283,51445757,51447191,51448332,51452420,51452479,51452493,51456421,51456628,51458177,51459425,51459470,51460559,51462020,51463383,51463530,51465806,51467525,51467676,51468322,51471745,51471783,51472205,51472255,51473812,51475686,51477496,51477846,51478321,51478688,51478868,51479905,51483631,51484222,51487681,51489567,51490158,51490267,51490331,51491127,51492548,51494655,51495294,51495567,51496341,51496968,51498459,51500051,51501530,51501787,51505436,51506999,51509183,51509613,51509946,51510317,51510888,51511440,51511950,51512708,51513132,51513637,51516746,51518808,51518821,51519387,51520227,51520494,51521506,51521954,51524018,51524403,51526700,51526753,51528608,51529399,51529759,51529772,51530225,51530495,51530538,51530732,51531943,51532166,51532253,51533384,51533393,51533398,51533405,51533568,51533804,51534326,51534333,51534340,51534347,51534352,51534669,51535265,51535728,51537767,51537772,51538053,51538888,51539213,51539472,51539686,51540719,51541257,51541433,51541883,51542227,51543038,51543692,51544153,51544597,51545646,51545969,51546375,51546507,51546674,51546980,51547832,51548164,51548344,51548674,51549015,51549275,51549693,51549955,51550012,51552457,51552469,51552476,51552493,51553168,51553210,51553442,51553942,51553945,51554456,51556198,51557753,51559502,51560266,51561514,51562255,51562806,51562825\"},{\"key\":\"visitor_data\",\"value\":\"Cgtjakg2T2tKQ2V0cyiC5azEBjIKCgJERRIEEgAgNA%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250730\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMI7ILY29_mjgMVk2F6BR1XeAyDMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"https://www.youtube.com/thedailyshow\",\"webPageType\":\"WEB_PAGE_TYPE_UNKNOWN\",\"rootVe\":83769}},\"urlEndpoint\":{\"url\":\"https://www.youtube.com/thedailyshow\"}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,386 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
116,
104,
101,
100,
97,
105,
108,
121,
115,
104,
111,
119,
34,
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": [
"Thu, 31 Jul 2025 09:08:19 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\":\"CgthN0FnY2k5TVRtYyiD5azEBjIKCgJERRIEEgAgGw%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250730.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0xd54f798bde273aec\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"9453588,9453589,23804281,23848212,23853953,23906950,23986017,24004644,24077241,24108448,24166867,24290153,24378828,24453989,24699899,39325854,39328892,51010235,51025415,51037344,51037349,51063643,51072748,51095478,51098299,51115184,51141472,51152050,51178318,51178329,51178344,51178355,51183910,51204329,51222973,51227037,51237842,51242448,51256074,51272458,51285052,51300176,51300241,51311025,51311040,51313109,51313767,51314158,51338524,51340662,51341228,51342857,51349914,51353393,51354569,51355201,51355912,51362071,51366423,51367489,51372971,51375205,51386540,51389629,51404238,51404808,51404810,51404953,51414747,51414985,51423010,51432294,51432560,51433499,51436340,51437205,51440725,51441712,51444283,51445757,51447191,51448401,51452420,51452479,51452493,51456421,51456629,51459424,51460559,51462020,51463532,51467083,51467525,51467676,51468320,51471745,51472205,51473810,51475688,51477496,51477845,51478690,51478868,51479907,51483631,51484222,51487680,51490158,51490267,51490331,51491127,51492546,51494655,51495566,51496343,51498459,51500051,51501530,51501787,51505436,51506999,51509183,51509613,51510317,51510817,51510888,51511440,51511952,51512708,51513637,51513768,51516746,51518808,51518819,51519387,51520229,51521954,51524018,51524403,51526267,51526700,51526753,51528608,51529399,51529759,51529772,51529906,51530225,51530495,51530538,51530732,51530745,51532166,51532253,51533382,51533391,51533400,51533403,51533566,51533802,51534324,51534331,51534338,51534345,51534354,51534669,51535265,51535423,51535728,51537767,51537772,51537875,51538053,51538888,51539470,51539686,51540717,51541257,51541435,51541883,51542227,51543038,51544153,51544597,51545644,51545969,51546375,51546507,51546674,51547832,51548672,51548737,51549275,51549695,51549955,51550139,51552457,51552469,51552475,51553442,51553942,51553945,51554456,51556722,51557393,51557755,51559501,51560266,51561515,51562255,51562805,51562825\"},{\"key\":\"visitor_data\",\"value\":\"CgthN0FnY2k5TVRtYyiD5azEBjIKCgJERRIEEgAgGw%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250730\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMIxov-29_mjgMVOSoGAB0AlB7hMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCwWhs_6x42TyRM4Wstoq8HA\",\"params\":\"EgC4AQCSAwDyBgQKAjIA\"}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,386 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
116,
104,
101,
100,
97,
105,
108,
121,
115,
104,
111,
119,
34,
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": [
"Thu, 31 Jul 2025 09:08:19 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\":\"CgtNSUlXcEF1dEtZcyiD5azEBjIKCgJERRIEEgAgNA%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250730.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0x9e4ed0e18e56e875\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"9453586,9453587,23804281,23986026,24004644,24077241,24166867,24290153,24378828,24425063,24453989,24499533,24699899,39325854,39328892,51010235,51025415,51037342,51037349,51063643,51072748,51095478,51098299,51115184,51141472,51152050,51178310,51178327,51178344,51178357,51183910,51204329,51222973,51227037,51237842,51242448,51256074,51272458,51285052,51300176,51300241,51311025,51311040,51313109,51313767,51314158,51338524,51340662,51341226,51342857,51349914,51353393,51354567,51355199,51355912,51362038,51362071,51366423,51367487,51372971,51375205,51386463,51386540,51389629,51404808,51404810,51404953,51407629,51407634,51414747,51414985,51420701,51432294,51432560,51433501,51436340,51437205,51441712,51444283,51445757,51447191,51448334,51452420,51452481,51452493,51456421,51456629,51459425,51460559,51462020,51463532,51467525,51467676,51468322,51471745,51471783,51472205,51472254,51473810,51475686,51476897,51477494,51477848,51478690,51478868,51479904,51483631,51484222,51487681,51489568,51490158,51490267,51490331,51491127,51492548,51494655,51495294,51495567,51496341,51496969,51500051,51501530,51501787,51503080,51505436,51506999,51507272,51509183,51509613,51509946,51510816,51510887,51511440,51511950,51512708,51513637,51516746,51518806,51518819,51519387,51520229,51521831,51521954,51524018,51524403,51526700,51526753,51528608,51529399,51529759,51529772,51530224,51530495,51530538,51530732,51532166,51532253,51533384,51533393,51533400,51533405,51533566,51533804,51534328,51534333,51534338,51534347,51534352,51534669,51535263,51535728,51537364,51537767,51537772,51537875,51538053,51538888,51539470,51539686,51539963,51540719,51541257,51541883,51542227,51543037,51544153,51544597,51545121,51545150,51545644,51545969,51546374,51546508,51546675,51546980,51547323,51547834,51548273,51548739,51549275,51549693,51549956,51550012,51550139,51552386,51552457,51552469,51552476,51553443,51553942,51553945,51554456,51557755,51559502,51561515,51561934,51562254\"},{\"key\":\"visitor_data\",\"value\":\"CgtNSUlXcEF1dEtZcyiD5azEBjIKCgJERRIEEgAgNA%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250730\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMI1fCj3N_mjgMVF3NBAh0GUyVFMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCwWhs_6x42TyRM4Wstoq8HA\",\"params\":\"EgC4AQCSAwDyBgQKAjIA\"}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,415 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
64,
110,
111,
110,
69,
120,
105,
115,
116,
105,
110,
103,
72,
97,
110,
100,
108,
101,
84,
104,
97,
116,
87,
105,
108,
108,
78,
101,
118,
101,
114,
69,
120,
105,
115,
116,
49,
53,
52,
54,
52,
34,
125
],
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 404,
"responseMessage": "",
"responseHeaders": {
"alt-svc": [
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000"
],
"content-type": [
"application/json; charset\u003dUTF-8"
],
"date": [
"Thu, 31 Jul 2025 09:08:20 GMT"
],
"server": [
"scaffolding on HTTPServer2"
],
"vary": [
"Origin",
"X-Origin",
"Referer"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "{\n \"error\": {\n \"code\": 404,\n \"message\": \"Requested entity was not found.\",\n \"errors\": [\n {\n \"message\": \"Requested entity was not found.\",\n \"domain\": \"global\",\n \"reason\": \"notFound\"\n }\n ],\n \"status\": \"NOT_FOUND\"\n }\n}\n",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,381 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
64,
71,
114,
111,
110,
107,
104,
34,
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": [
"Thu, 31 Jul 2025 09:08:20 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\":\"Cgt0UzBScldkTkJZOCiE5azEBjIKCgJERRIEEgAgWQ%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250730.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0x892dc39041f3e474\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"Cgt0UzBScldkTkJZOCiE5azEBjIKCgJERRIEEgAgWQ%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250730\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMI-Jvw3N_mjgMVz05BAh2InDKfMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCYJ61XIK64sp6ZFFS8sctxw\",\"params\":\"EgC4AQCSAwDyBgQKAjIA\"}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,380 @@
{
"request": {
"httpMethod": "POST",
"url": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Cookie": [
"SOCS\u003dCAE\u003d"
],
"X-YouTube-Client-Version": [
"2.20250730.01.00"
],
"X-YouTube-Client-Name": [
"1"
],
"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,
104,
108,
34,
58,
34,
101,
110,
45,
71,
66,
34,
44,
34,
103,
108,
34,
58,
34,
71,
66,
34,
44,
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,
51,
48,
46,
48,
49,
46,
48,
48,
34,
44,
34,
111,
114,
105,
103,
105,
110,
97,
108,
85,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
34,
44,
34,
112,
108,
97,
116,
102,
111,
114,
109,
34,
58,
34,
68,
69,
83,
75,
84,
79,
80,
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,
44,
34,
117,
114,
108,
34,
58,
34,
104,
116,
116,
112,
115,
58,
47,
47,
119,
119,
119,
46,
121,
111,
117,
116,
117,
98,
101,
46,
99,
111,
109,
47,
103,
114,
111,
110,
107,
104,
34,
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": [
"Thu, 31 Jul 2025 09:08:21 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\":\"CgtqakVONTBBU0JmMCiF5azEBjIKCgJERRIEEgAgHw%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20250730.01.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0x149f28ebbc0079df\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"visitor_data\",\"value\":\"CgtqakVONTBBU0JmMCiF5azEBjIKCgJERRIEEgAgHw%3D%3D\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20250730\"},{\"key\":\"client.name\",\"value\":\"WEB\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMIsraW3d_mjgMV8E5BAh2IrATlMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCYJ61XIK64sp6ZFFS8sctxw\",\"params\":\"EgC4AQCSAwDyBgQKAjIA\"}}}",
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?prettyPrint\u003dfalse"
}
}

View File

@ -0,0 +1,96 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"access-control-allow-credentials": [
"true"
],
"access-control-allow-origin": [
"https://www.youtube.com"
],
"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-security-policy-report-only": [
"script-src \u0027unsafe-eval\u0027 \u0027self\u0027 \u0027unsafe-inline\u0027 https://www.google.com https://apis.google.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com https://www.google-analytics.com https://*.youtube.com https://*.google.com https://*.gstatic.com https://youtube.com https://www.youtube.com https://google.com https://*.doubleclick.net https://*.googleapis.com https://www.googleadservices.com https://tpc.googlesyndication.com https://www.youtubekids.com;report-uri /cspreport/allowlist"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Thu, 31 Jul 2025 19:06:56 GMT"
],
"document-policy": [
"include-js-call-stacks-in-crash-reports"
],
"expires": [
"Thu, 31 Jul 2025 19:06:56 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\"}]}"
],
"reporting-endpoints": [
"default\u003d\"/web-reports?context\u003deJwNz1tIk3EYBvA-HxLdp9_3_V8vRA0yETroZGpTKC0oPGBpBoXiVi51m4e5mW1rlt2EWJZIYeUhkyRIEZQICWRaXQRS0AEPF5nSwQ4YonWhiWb2XvyuHt6H59V1bZ2KrpJqNqul2Gyn9OjSWcm8s1bKeHtOas50SysP3dKA3y0tRHslU4xXap_ySo6PPml9zid1a4UBtsjCAB_zF-lgs-mw3KHD7xkd6pZ0MMXJUBJkEJvIkbGQJ6PKLONJrwz_YxmzP2R4TCH4ZQmB0RMC10oI5vNDMdoRivGJUMSfUJDWrKBvWEH-mIKbzP5XweKGgpR0FYNZKrxWFf0OFbJXRWeTisQ2FVksqEdF-CsVo7EagiwadMx4W8P4XQ1drzXM_NGwf03DqTABzx6Bkb0CFqNAyj6BhoMCXScFZosFcu0CpZUCPXUC9fWcsfhrAm-aBQ61CCy1CiTdEjhwR-BZv8CHAYGoQYHNpwJhkwLT7wW2zQukLgl8WRUoXxew_xO4sYWgBBOuhxOqIwjPIwnDUYT27YQu9i2GMLqL8H03ITmZYGSBRoIljdB7mDCXQRjKJEyzuGzCZg5h5Qih6CjBzE4zCythZczGylklczAnq2G1zM28zMcusHp27xh35hMajxN-FhByTYTPZr4pJtjt3MEm2TpbcxGCPbzxIiHiMmGV7Wjgm0bCIku_Qmi4yvubCAWtBLQRljs57-afH_C-Xv67j_BpgJDpJ-SNENQxQstLAslB7zYGXwRq94e-Bsbo61wet6fEmnDeWqK31bqcbr3VWaYvra1wV5SecRQnGZKMhtRkQ0KiobjG8B-xPcol\""
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003d8-LUGALaWbw; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dFri, 04-Nov-2022 19:06:56 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
"latestUrl": "https://www.youtube.com/sw.js"
}
}

View File

@ -0,0 +1,96 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Referer": [
"https://www.youtube.com"
],
"Origin": [
"https://www.youtube.com"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"access-control-allow-credentials": [
"true"
],
"access-control-allow-origin": [
"https://www.youtube.com"
],
"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-security-policy-report-only": [
"script-src \u0027unsafe-eval\u0027 \u0027self\u0027 \u0027unsafe-inline\u0027 https://www.google.com https://apis.google.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com https://www.google-analytics.com https://*.youtube.com https://*.google.com https://*.gstatic.com https://youtube.com https://www.youtube.com https://google.com https://*.doubleclick.net https://*.googleapis.com https://www.googleadservices.com https://tpc.googlesyndication.com https://www.youtubekids.com;report-uri /cspreport/allowlist"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Thu, 31 Jul 2025 19:09:29 GMT"
],
"document-policy": [
"include-js-call-stacks-in-crash-reports"
],
"expires": [
"Thu, 31 Jul 2025 19:09:29 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\"}]}"
],
"reporting-endpoints": [
"default\u003d\"/web-reports?context\u003deJwNzl1Ik3EUx3H__kT0ebY9z_8YhBokIhTZZM6mVFpQtETUDArEWZsv23ydtrY1yyBCLEGi6EUtC7xJKZTwIpBpEUhRUIHmRab0CiWEq4tMWmnn4nNzOIfzVb4lzGU0i3OxZtG63iqyin3iwdkTonqLXxx4fVL02gNi5W5AjEYC4ntGSDgyQ6J_LiRa3odF7HNY3NEr4z1plfFhFqlS4PEo-DWg4OeCgo6oAke2CmOOCp3Nlqj4Xq7i4bCKyLiKxa8qgg4DfrgMsAUNaFsxYKnCiKkBI2Zmjdh-xITCXhNGJkyoeGbCFeb9a8LyPxPyizSMHdQQcmtQQxpu9mjI7dNgZ0lDGja-0DCVpSPJpUNhtus6Zm7pGHypY-G3jt1_dBxLkQhuk5jcIVFjk8jfJdG1V2LwqMSiU6LMK1HXJNHZyXP2qldi3yWJ6FUJ6zWJPTckHt-TyLgv8W5UIn1MYv2RRMobifm3EpuWJAqiEp9WJRpiEt41ictxBFMyIbqB0JpKeJJGmEgn9G8mDLKprYS8PIKNJdoIrkLC8H7CvJ2QXUwYZ-slhKpSQjU7zlysltUzD2tgTayF-Vg787MAC7EwO8062e1DhLjDhG5W5iB8rOZ9J8Hr5XsWY8lB7jlDSD1PWGWl3YRlVnSB8IV1XeTWHkJCHzcME_pGCB9G-fc4wR4hlE8S8p8TyJC0tDY2naivPh2ajs80d7QFA8Fad84pd63Z42_zBcxuX725zt8YaKyraXFaLVabpcC6MyfX4my3_Ad2QbxV\""
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003dfGO-_uyQPYc; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dFri, 04-Nov-2022 19:09:29 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
"latestUrl": "https://www.youtube.com/sw.js"
}
}

View File

@ -0,0 +1,96 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Origin": [
"https://www.youtube.com"
],
"Referer": [
"https://www.youtube.com"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"access-control-allow-credentials": [
"true"
],
"access-control-allow-origin": [
"https://www.youtube.com"
],
"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-security-policy-report-only": [
"script-src \u0027unsafe-eval\u0027 \u0027self\u0027 \u0027unsafe-inline\u0027 https://www.google.com https://apis.google.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com https://www.google-analytics.com https://*.youtube.com https://*.google.com https://*.gstatic.com https://youtube.com https://www.youtube.com https://google.com https://*.doubleclick.net https://*.googleapis.com https://www.googleadservices.com https://tpc.googlesyndication.com https://www.youtubekids.com;report-uri /cspreport/allowlist"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Thu, 31 Jul 2025 19:09:22 GMT"
],
"document-policy": [
"include-js-call-stacks-in-crash-reports"
],
"expires": [
"Thu, 31 Jul 2025 19:09:22 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\"}]}"
],
"reporting-endpoints": [
"default\u003d\"/web-reports?context\u003deJwNzltIk3EYBnD_PiG60_f9X6NQg8SEIpvM2ZRKC4qWSCuDAnHW5mGbmk5b39YqgwixBJGig8eKCJoUSnQRyLS6CDrQATxcZEplFyFYVpBKmvZe_G5enufl0S2tGks9LgIrdSK9wC8enjshSjcGRLg5IPa-PykcazTRatfE3D1N9EU10fUmKGZSQ8KZFhIdYyFR-yksFr-GxS21ONabXBwbZtESHbxeHf506vBrQofwrA7ODD2MmXpINlKox8wBPR5H9Ig-0mPymx5BpwE_3QbYggbUzxkwXWTEUKcRwyNGbDlsQl6rCb0DJhS9MOEK8y2Z8OOfCTn5Cvr3KQh5FOhDCrpaFGS1K7Cz-DsKNkQUrH2tYChdRbxbhY7ZrqsY7lbR81bFxLyKHX9VHE2U0DZL3M2QGNwqUWaTaGM52yWadkn0HJGYdEk4fBIVNRKNjXxn71oldrdJzF6VsF6T2HlD4ul9idQHEh_7JFL6JVaeSCSOSox_kFg3LZE7KzG1IFG1KOFblrgcQzAlEH6vJtQlEZ4lEwZSCB3rCd1saBMhO5tgY3E2gjuPENlDGLcTMgoIK4WEkv2EUnaMuVk5q2ReVsVqWC3zswYWYBoLsTA7wxrZzYOEmEOEZuZwEr6Uct5F8Pm4zxZZQpC3nCWI84SkC4QF5mgmfGf5FwlNl3hnCwHthJ7bvCNCaO8lfO4j2KOcHeSfrO0VgQzxU8v9z-PUl_MzoyLNfLo-qAXLPZmnPOVmb6Der5k9_kpzRaBaq64oq3VZLVabJde6LTPL4mqw_AeG9sFO\""
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003dXasVls-aAZw; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dFri, 04-Nov-2022 19:09:22 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone"
],
"strict-transport-security": [
"max-age\u003d31536000"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
"latestUrl": "https://www.youtube.com/sw.js"
}
}