Merge pull request #1092 from Stypox/channel-tabs-improvements

Channel tabs code improvements
This commit is contained in:
Stypox 2023-08-06 21:44:10 +02:00 committed by GitHub
commit 7936987955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2573 additions and 2574 deletions

View File

@ -43,9 +43,9 @@ public final class YoutubeChannelHelper {
}
// If the URL is not a /channel URL, we need to use the navigation/resolve_url endpoint of
// the InnerTube API to get the channel id.
// Otherwise, we couldn't get information about the channel associated with this URL, if
// there is one.
// the InnerTube API to get the channel id. If this fails or if the URL is not a /channel
// 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)
@ -78,6 +78,7 @@ public final class YoutubeChannelHelper {
}
}
// return the unresolved URL
return channelId[1];
}
@ -110,11 +111,11 @@ public final class YoutubeChannelHelper {
* Fetch a YouTube channel tab response, using the given channel ID and tab parameters.
*
* <p>
* Redirections to other channels such as are supported to up to 3 redirects, which could
* happen for instance for localized channels or auto-generated ones such as the {@code Movies
* and Shows} (channel IDs {@code UCuJcl0Ju-gPDoksRjK1ya-w}, {@code UChBfWrfBXL9wS6tQtgjt_OQ}
* and {@code UCok7UTQQEP1Rsctxiv3gwSQ} of this channel redirect to the
* {@code UClgRkhTL3_hImCAmdLfDE4g} one).
* Redirections to other channels are supported to up to 3 redirects, which could happen for
* instance for localized channels or for auto-generated ones. For instance, there are three IDs
* of the auto-generated "Movies and Shows" channel, i.e. {@code UCuJcl0Ju-gPDoksRjK1ya-w},
* {@code UChBfWrfBXL9wS6tQtgjt_OQ} and {@code UCok7UTQQEP1Rsctxiv3gwSQ}, and they all redirect
* to the {@code UClgRkhTL3_hImCAmdLfDE4g} one.
* </p>
*
* @param channelId a valid YouTube channel ID
@ -177,7 +178,7 @@ public final class YoutubeChannelHelper {
}
if (ajaxJson == null) {
throw new ExtractionException("Got no channel response");
throw new ExtractionException("Got no channel response after 3 redirects");
}
defaultAlertsCheck(ajaxJson);

View File

@ -57,6 +57,7 @@ import javax.annotation.Nullable;
public class YoutubeChannelExtractor extends ChannelExtractor {
private JsonObject jsonResponse;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Optional<YoutubeChannelHelper.ChannelHeader> channelHeader;
@ -89,6 +90,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
"EgZ2aWRlb3PyBgQKAjoA", getExtractorLocalization(), getExtractorContentCountry());
jsonResponse = data.jsonResponse;
channelHeader = YoutubeChannelHelper.getChannelHeader(jsonResponse);
channelId = data.channelId;
channelAgeGateRenderer = getChannelAgeGateRenderer();
}
@ -115,12 +117,8 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
}
@Nonnull
private Optional<YoutubeChannelHelper.ChannelHeader> getChannelHeader() {
//noinspection OptionalAssignedToNull
if (channelHeader == null) {
channelHeader = YoutubeChannelHelper.getChannelHeader(jsonResponse);
}
return channelHeader;
private Optional<JsonObject> getChannelHeaderJson() {
return channelHeader.map(it -> it.json);
}
@Nonnull
@ -136,9 +134,9 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Nonnull
@Override
public String getId() throws ParsingException {
return getChannelHeader()
.flatMap(header -> Optional.ofNullable(header.json.getString("channelId"))
.or(() -> Optional.ofNullable(header.json.getObject("navigationEndpoint")
return getChannelHeaderJson()
.flatMap(header -> Optional.ofNullable(header.getString("channelId"))
.or(() -> Optional.ofNullable(header.getObject("navigationEndpoint")
.getObject("browseEndpoint")
.getString("browseId"))
))
@ -160,8 +158,8 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return metadataRendererTitle;
}
return getChannelHeader().flatMap(header -> {
final Object title = header.json.get("title");
return getChannelHeaderJson().flatMap(header -> {
final Object title = header.get("title");
if (title instanceof String) {
return Optional.of((String) title);
} else if (title instanceof JsonObject) {
@ -180,7 +178,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
if (channelAgeGateRenderer != null) {
avatarJsonObjectContainer = channelAgeGateRenderer;
} else {
avatarJsonObjectContainer = getChannelHeader().map(header -> header.json)
avatarJsonObjectContainer = getChannelHeaderJson()
.orElseThrow(() -> new ParsingException("Could not get avatar URL"));
}
@ -196,8 +194,8 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return "";
}
return getChannelHeader().flatMap(header -> Optional.ofNullable(
header.json.getObject("banner")
return getChannelHeaderJson().flatMap(header -> Optional.ofNullable(
header.getObject("banner")
.getArray("thumbnails")
.getObject(0)
.getString("url")))
@ -226,9 +224,9 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return UNKNOWN_SUBSCRIBER_COUNT;
}
final Optional<YoutubeChannelHelper.ChannelHeader> headerOpt = getChannelHeader();
final Optional<JsonObject> headerOpt = getChannelHeaderJson();
if (headerOpt.isPresent()) {
final JsonObject header = headerOpt.get().json;
final JsonObject header = headerOpt.get();
JsonObject textObject = null;
if (header.has("subscriberCountText")) {
@ -285,9 +283,8 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return false;
}
final Optional<YoutubeChannelHelper.ChannelHeader> headerOpt = getChannelHeader();
if (headerOpt.isPresent()) {
final YoutubeChannelHelper.ChannelHeader header = headerOpt.get();
if (channelHeader.isPresent()) {
final YoutubeChannelHelper.ChannelHeader header = channelHeader.get();
// The CarouselHeaderRenderer does not contain any verification badges.
// Since it is only shown on YT-internal channels or on channels of large organizations

View File

@ -23,7 +23,6 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeChannelHelper.getChannelResponse;
import static org.schabi.newpipe.extractor.services.youtube.YoutubeChannelHelper.resolveChannelId;
@ -299,20 +298,20 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
.getObject("content");
if (richItem.has("videoRenderer")) {
getCommitVideoConsumer(collector, timeAgoParser, channelIds).accept(
getCommitVideoConsumer(collector, timeAgoParser, channelIds,
richItem.getObject("videoRenderer"));
} else if (richItem.has("reelItemRenderer")) {
getCommitReelItemConsumer(collector, timeAgoParser, channelIds).accept(
getCommitReelItemConsumer(collector, timeAgoParser, channelIds,
richItem.getObject("reelItemRenderer"));
} else if (richItem.has("playlistRenderer")) {
getCommitPlaylistConsumer(collector, channelIds).accept(
getCommitPlaylistConsumer(collector, channelIds,
item.getObject("playlistRenderer"));
}
} else if (item.has("gridVideoRenderer")) {
getCommitVideoConsumer(collector, timeAgoParser, channelIds).accept(
getCommitVideoConsumer(collector, timeAgoParser, channelIds,
item.getObject("gridVideoRenderer"));
} else if (item.has("gridPlaylistRenderer")) {
getCommitPlaylistConsumer(collector, channelIds).accept(
getCommitPlaylistConsumer(collector, channelIds,
item.getObject("gridPlaylistRenderer"));
} else if (item.has("gridChannelRenderer")) {
collector.commit(new YoutubeChannelInfoItemExtractor(
@ -336,13 +335,12 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
return Optional.empty();
}
@Nonnull
private Consumer<JsonObject> getCommitVideoConsumer(
@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final TimeAgoParser timeAgoParser,
@Nonnull final List<String> channelIds) {
return videoRenderer -> collector.commit(
new YoutubeStreamInfoItemExtractor(videoRenderer, timeAgoParser) {
private void getCommitVideoConsumer(@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final TimeAgoParser timeAgoParser,
@Nonnull final List<String> channelIds,
@Nonnull final JsonObject jsonObject) {
collector.commit(
new YoutubeStreamInfoItemExtractor(jsonObject, timeAgoParser) {
@Override
public String getUploaderName() throws ParsingException {
if (channelIds.size() >= 2) {
@ -361,13 +359,12 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
});
}
@Nonnull
private Consumer<JsonObject> getCommitReelItemConsumer(
@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final TimeAgoParser timeAgoParser,
@Nonnull final List<String> channelIds) {
return reelItemRenderer -> collector.commit(
new YoutubeReelInfoItemExtractor(reelItemRenderer, timeAgoParser) {
private void getCommitReelItemConsumer(@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final TimeAgoParser timeAgoParser,
@Nonnull final List<String> channelIds,
@Nonnull final JsonObject jsonObject) {
collector.commit(
new YoutubeReelInfoItemExtractor(jsonObject, timeAgoParser) {
@Override
public String getUploaderName() throws ParsingException {
if (channelIds.size() >= 2) {
@ -386,12 +383,11 @@ public class YoutubeChannelTabExtractor extends ChannelTabExtractor {
});
}
@Nonnull
private Consumer<JsonObject> getCommitPlaylistConsumer(
@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final List<String> channelIds) {
return playlistRenderer -> collector.commit(
new YoutubePlaylistInfoItemExtractor(playlistRenderer) {
private void getCommitPlaylistConsumer(@Nonnull final MultiInfoItemsCollector collector,
@Nonnull final List<String> channelIds,
@Nonnull final JsonObject jsonObject) {
collector.commit(
new YoutubePlaylistInfoItemExtractor(jsonObject) {
@Override
public String getUploaderName() throws ParsingException {
if (channelIds.size() >= 2) {

View File

@ -1,6 +1,7 @@
package org.schabi.newpipe.extractor.services.youtube.extractors;
import org.schabi.newpipe.extractor.InfoItem;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
@ -12,14 +13,11 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
import javax.annotation.Nonnull;
/**
* A {@link ChannelTabExtractor} for YouTube system playlists using a
@ -74,35 +72,19 @@ public class YoutubeChannelTabPlaylistExtractor extends ChannelTabExtractor {
@Nonnull
@Override
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {
public InfoItemsPage getInitialPage() throws IOException, ExtractionException {
if (!playlistExisting) {
return InfoItemsPage.emptyPage();
}
final InfoItemsPage<StreamInfoItem> playlistInitialPage =
playlistExtractorInstance.getInitialPage();
// We can't provide the playlist page as it is due to a type conflict, we need to wrap the
// page items and provide a new InfoItemsPage
final List<InfoItem> infoItems = new ArrayList<>(playlistInitialPage.getItems());
return new InfoItemsPage<>(infoItems, playlistInitialPage.getNextPage(),
playlistInitialPage.getErrors());
return playlistExtractorInstance.getInitialPage();
}
@Override
public InfoItemsPage<InfoItem> getPage(final Page page)
throws IOException, ExtractionException {
public InfoItemsPage getPage(final Page page) throws IOException, ExtractionException {
if (!playlistExisting) {
return InfoItemsPage.emptyPage();
}
final InfoItemsPage<StreamInfoItem> playlistPage = playlistExtractorInstance.getPage(page);
// We can't provide the playlist page as it is due to a type conflict, we need to wrap the
// page items and provide a new InfoItemsPage
final List<InfoItem> infoItems = new ArrayList<>(playlistPage.getItems());
return new InfoItemsPage<>(infoItems, playlistPage.getNextPage(),
playlistPage.getErrors());
return playlistExtractorInstance.getPage(page);
}
/**

View File

@ -151,8 +151,8 @@ public class ExtractorAsserts {
"'" + shouldBeContained + "' should be contained inside '" + container + "'");
}
public static void assertTabsContained(@Nonnull final List<ListLinkHandler> tabs,
@Nonnull final String... expectedTabs) {
public static void assertTabsContain(@Nonnull final List<ListLinkHandler> tabs,
@Nonnull final String... expectedTabs) {
final Set<String> tabSet = tabs.stream()
.map(linkHandler -> linkHandler.getContentFilters().get(0))
.collect(Collectors.toUnmodifiableSet());

View File

@ -11,7 +11,7 @@ import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.services.BaseChannelExtractorTest;
import static org.junit.jupiter.api.Assertions.*;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContained;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContain;
import static org.schabi.newpipe.extractor.ServiceList.Bandcamp;
public class BandcampChannelExtractorTest implements BaseChannelExtractorTest {
@ -84,7 +84,7 @@ public class BandcampChannelExtractorTest implements BaseChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.ALBUMS);
assertTabsContain(extractor.getTabs(), ChannelTabs.ALBUMS);
}
@Test

View File

@ -3,22 +3,27 @@ package org.schabi.newpipe.extractor.services.bandcamp;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultListExtractorTest;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampChannelTabExtractor;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.Bandcamp;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
class BandcampChannelTabExtractorTest {
static class Tracks implements BaseListExtractorTest {
static class Tracks extends DefaultListExtractorTest<ChannelTabExtractor> {
private static BandcampChannelTabExtractor extractor;
@BeforeAll
@ -29,50 +34,17 @@ class BandcampChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() throws Exception {
assertEquals(Bandcamp.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.TRACKS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("2464198920", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://wintergatan.bandcamp.com/track", extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://wintergatan.bandcamp.com/track", extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
// Bandcamp only return a single page
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return Bandcamp; }
@Override public String expectedName() throws Exception { return ChannelTabs.TRACKS; }
@Override public String expectedId() throws Exception { return "2464198920"; }
@Override public String expectedUrlContains() throws Exception { return "https://wintergatan.bandcamp.com/track"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://wintergatan.bandcamp.com/track"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return false; }
}
static class Albums implements BaseListExtractorTest {
static class Albums extends DefaultListExtractorTest<ChannelTabExtractor> {
private static BandcampChannelTabExtractor extractor;
@BeforeAll
@ -83,46 +55,13 @@ class BandcampChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(Bandcamp.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.ALBUMS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("2450875064", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://toupie.bandcamp.com/album", extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://toupie.bandcamp.com/album", extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
// Bandcamp only return a single page
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return Bandcamp; }
@Override public String expectedName() throws Exception { return ChannelTabs.ALBUMS; }
@Override public String expectedId() throws Exception { return "2450875064"; }
@Override public String expectedUrlContains() throws Exception { return "https://toupie.bandcamp.com/album"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://toupie.bandcamp.com/album"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
@Override public boolean expectedHasMoreItems() { return false; }
}
}

View File

@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContained;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContain;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
/**
@ -103,7 +103,7 @@ public class PeertubeAccountExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.CHANNELS);
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.CHANNELS);
}
@Test
@ -192,7 +192,7 @@ public class PeertubeAccountExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.CHANNELS);
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.CHANNELS);
}
@Test

View File

@ -3,10 +3,14 @@ package org.schabi.newpipe.extractor.services.peertube;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultListExtractorTest;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeChannelTabExtractor;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -16,7 +20,7 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRela
class PeertubeAccountTabExtractorTest {
static class Videos implements BaseListExtractorTest {
static class Videos extends DefaultListExtractorTest<ChannelTabExtractor> {
private static PeertubeChannelTabExtractor extractor;
@BeforeAll
@ -29,60 +33,17 @@ class PeertubeAccountTabExtractorTest {
extractor.fetchPage();
}
/*//////////////////////////////////////////////////////////////////////////
// Extractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testServiceId() {
assertEquals(PeerTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws ParsingException {
assertEquals(ChannelTabs.VIDEOS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("accounts/framasoft", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://framatube.org/accounts/framasoft/videos",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws ParsingException {
assertEquals("https://framatube.org/accounts/framasoft/videos",
extractor.getOriginalUrl());
}
/*//////////////////////////////////////////////////////////////////////////
// ListExtractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return PeerTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.VIDEOS; }
@Override public String expectedId() throws Exception { return "accounts/framasoft"; }
@Override public String expectedUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/videos"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/videos"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Channels implements BaseListExtractorTest {
static class Channels extends DefaultListExtractorTest<ChannelTabExtractor> {
private static PeertubeChannelTabExtractor extractor;
@BeforeAll
@ -95,56 +56,13 @@ class PeertubeAccountTabExtractorTest {
extractor.fetchPage();
}
/*//////////////////////////////////////////////////////////////////////////
// Extractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testServiceId() {
assertEquals(PeerTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws ParsingException {
assertEquals(ChannelTabs.CHANNELS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("accounts/framasoft", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://framatube.org/accounts/framasoft/video-channels",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws ParsingException {
assertEquals("https://framatube.org/accounts/framasoft/video-channels",
extractor.getOriginalUrl());
}
/*//////////////////////////////////////////////////////////////////////////
// ListExtractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return PeerTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.CHANNELS; }
@Override public String expectedId() throws Exception { return "accounts/framasoft"; }
@Override public String expectedUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/video-channels"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/video-channels"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.CHANNEL; }
@Override public boolean expectedHasMoreItems() { return true; }
}
}

View File

@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContained;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContain;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
/**
@ -118,7 +118,7 @@ public class PeertubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS);
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS);
}
@Test
@ -223,7 +223,7 @@ public class PeertubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS);
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS);
}
@Test

View File

@ -1,25 +1,25 @@
package org.schabi.newpipe.extractor.services.peertube;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultListExtractorTest;
import org.schabi.newpipe.extractor.services.peertube.extractors.PeertubeChannelTabExtractor;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.*;
class PeertubeChannelTabExtractorTest {
static class Videos implements BaseListExtractorTest {
static class Videos extends DefaultListExtractorTest<ChannelTabExtractor> {
private static PeertubeChannelTabExtractor extractor;
@BeforeAll
@ -32,61 +32,14 @@ class PeertubeChannelTabExtractorTest {
extractor.fetchPage();
}
/*//////////////////////////////////////////////////////////////////////////
// Extractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testServiceId() {
assertEquals(PeerTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws ParsingException {
assertEquals(ChannelTabs.VIDEOS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("video-channels/lqdn_channel@video.lqdn.fr", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/videos",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws ParsingException {
assertEquals("https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/videos",
extractor.getOriginalUrl());
}
/*//////////////////////////////////////////////////////////////////////////
// ListExtractor
//////////////////////////////////////////////////////////////////////////*/
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
/*//////////////////////////////////////////////////////////////////////////
// Additional Testing
//////////////////////////////////////////////////////////////////////////*/
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return PeerTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.VIDEOS; }
@Override public String expectedId() throws Exception { return "video-channels/lqdn_channel@video.lqdn.fr"; }
@Override public String expectedUrlContains() throws Exception { return "https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/videos"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/videos"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
@Test
void testGetPageInNewExtractor() throws Exception {
@ -96,7 +49,7 @@ class PeertubeChannelTabExtractorTest {
}
}
static class Playlists implements BaseListExtractorTest {
static class Playlists extends DefaultListExtractorTest<ChannelTabExtractor> {
private static PeertubeChannelTabExtractor extractor;
@BeforeAll
@ -109,51 +62,17 @@ class PeertubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(PeerTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.PLAYLISTS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("video-channels/lqdn_channel@video.lqdn.fr", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/video-playlists",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/video-playlists",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return PeerTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.PLAYLISTS; }
@Override public String expectedId() throws Exception { return "video-channels/lqdn_channel@video.lqdn.fr"; }
@Override public String expectedUrlContains() throws Exception { return "https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/video-playlists"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://framatube.org/video-channels/lqdn_channel@video.lqdn.fr/video-playlists"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
@Override public boolean expectedHasMoreItems() { return false; }
}
static class Channels implements BaseListExtractorTest {
static class Channels extends DefaultListExtractorTest<ChannelTabExtractor> {
private static PeertubeChannelTabExtractor extractor;
@BeforeAll
@ -165,48 +84,13 @@ class PeertubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(PeerTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.CHANNELS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("accounts/framasoft", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://framatube.org/accounts/framasoft/video-channels",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://framatube.org/accounts/framasoft/video-channels",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return PeerTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.CHANNELS; }
@Override public String expectedId() throws Exception { return "accounts/framasoft"; }
@Override public String expectedUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/video-channels"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://framatube.org/accounts/framasoft/video-channels"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.CHANNEL; }
@Override public boolean expectedHasMoreItems() { return true; }
}
}

View File

@ -12,7 +12,7 @@ import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudCha
import static org.junit.jupiter.api.Assertions.*;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEmpty;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContained;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContain;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
/**
@ -96,7 +96,7 @@ public class SoundcloudChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.TRACKS, ChannelTabs.PLAYLISTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.TRACKS, ChannelTabs.PLAYLISTS,
ChannelTabs.ALBUMS);
}
@ -184,7 +184,7 @@ public class SoundcloudChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.TRACKS, ChannelTabs.PLAYLISTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.TRACKS, ChannelTabs.PLAYLISTS,
ChannelTabs.ALBUMS);
}

View File

@ -3,17 +3,21 @@ package org.schabi.newpipe.extractor.services.soundcloud;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultListExtractorTest;
import org.schabi.newpipe.extractor.services.soundcloud.extractors.SoundcloudChannelTabExtractor;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.schabi.newpipe.extractor.ServiceList.PeerTube;
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
@ -21,7 +25,7 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRela
class SoundcloudChannelTabExtractorTest {
static class Tracks implements BaseListExtractorTest {
static class Tracks extends DefaultListExtractorTest<ChannelTabExtractor> {
private static SoundcloudChannelTabExtractor extractor;
@BeforeAll
@ -32,51 +36,14 @@ class SoundcloudChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() throws Exception {
assertEquals(SoundCloud.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.TRACKS, extractor.getName());
}
@Test
@Override
public void testId() throws Exception {
assertEquals("10494998", extractor.getId());
}
@Test
@Override
public void testUrl() throws Exception {
assertEquals("https://soundcloud.com/liluzivert/tracks", extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://soundcloud.com/liluzivert/tracks", extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
/*//////////////////////////////////////////////////////////////////////////
// Additional Testing
//////////////////////////////////////////////////////////////////////////*/
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return SoundCloud; }
@Override public String expectedName() throws Exception { return ChannelTabs.TRACKS; }
@Override public String expectedId() throws Exception { return "10494998"; }
@Override public String expectedUrlContains() throws Exception { return "https://soundcloud.com/liluzivert/tracks"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://soundcloud.com/liluzivert/tracks"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
@Test
void testGetPageInNewExtractor() throws Exception {
@ -86,7 +53,7 @@ class SoundcloudChannelTabExtractorTest {
}
}
static class Playlists implements BaseListExtractorTest {
static class Playlists extends DefaultListExtractorTest<ChannelTabExtractor> {
private static SoundcloudChannelTabExtractor extractor;
@BeforeAll
@ -97,50 +64,17 @@ class SoundcloudChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(SoundCloud.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.PLAYLISTS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("323371733", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://soundcloud.com/trackaholic/sets", extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://soundcloud.com/trackaholic/sets", extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return SoundCloud; }
@Override public String expectedName() throws Exception { return ChannelTabs.PLAYLISTS; }
@Override public String expectedId() throws Exception { return "323371733"; }
@Override public String expectedUrlContains() throws Exception { return "https://soundcloud.com/trackaholic/sets"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://soundcloud.com/trackaholic/sets"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Albums implements BaseListExtractorTest {
static class Albums extends DefaultListExtractorTest<ChannelTabExtractor> {
private static SoundcloudChannelTabExtractor extractor;
@BeforeAll
@ -151,46 +85,13 @@ class SoundcloudChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(SoundCloud.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.ALBUMS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("4803918", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://soundcloud.com/bigsean-1/albums", extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://soundcloud.com/bigsean-1/albums", extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return SoundCloud; }
@Override public String expectedName() throws Exception { return ChannelTabs.ALBUMS; }
@Override public String expectedId() throws Exception { return "4803918"; }
@Override public String expectedUrlContains() throws Exception { return "https://soundcloud.com/bigsean-1/albums"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://soundcloud.com/bigsean-1/albums"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
@Override public boolean expectedHasMoreItems() { return true; }
}
}

View File

@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertContains;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContained;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertTabsContain;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestGetPageInNewExtractor;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
@ -233,8 +233,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS,
ChannelTabs.LIVESTREAMS, ChannelTabs.PLAYLISTS, ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -327,8 +330,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.LIVESTREAMS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.LIVESTREAMS,
ChannelTabs.SHORTS, ChannelTabs.PLAYLISTS, ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -424,8 +430,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.SHORTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.SHORTS,
ChannelTabs.PLAYLISTS, ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -545,8 +554,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS,
ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -639,8 +651,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.PLAYLISTS,
ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -730,8 +745,11 @@ public class YoutubeChannelExtractorTest {
@Test
@Override
public void testTabs() throws Exception {
assertTabsContained(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.SHORTS,
assertTabsContain(extractor.getTabs(), ChannelTabs.VIDEOS, ChannelTabs.SHORTS,
ChannelTabs.LIVESTREAMS, ChannelTabs.PLAYLISTS, ChannelTabs.CHANNELS);
assertTrue(extractor.getTabs().stream()
.filter(it -> ChannelTabs.VIDEOS.equals(it.getContentFilters().get(0)))
.allMatch(ReadyChannelTabListLinkHandler.class::isInstance));
}
@Test
@ -846,7 +864,7 @@ public class YoutubeChannelExtractorTest {
public void testTabs() throws Exception {
// Channel tabs which may be available and which will be extracted from channel system
// uploads playlists
assertTabsContained(extractor.getTabs(),
assertTabsContain(extractor.getTabs(),
ChannelTabs.VIDEOS, ChannelTabs.SHORTS, ChannelTabs.LIVESTREAMS);
// Check if all tabs are not classic tabs, so that link handlers are of the appropriate

View File

@ -1,34 +1,30 @@
package org.schabi.newpipe.extractor.services.youtube;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.schabi.newpipe.downloader.DownloaderFactory;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.BaseListExtractorTest;
import org.schabi.newpipe.extractor.services.DefaultListExtractorTest;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeChannelTabExtractor;
import java.io.IOException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestMoreItems;
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestRelatedItems;
class YoutubeChannelTabExtractorTest {
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH
+ "services/youtube/extractor/channelTabs/";
static class Videos implements BaseListExtractorTest {
static class Videos extends DefaultListExtractorTest<ChannelTabExtractor> {
private static YoutubeChannelTabExtractor extractor;
@BeforeAll
@ -40,52 +36,17 @@ class YoutubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.VIDEOS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UCTwECeGqMZee77BjdoYtI2Q", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UCTwECeGqMZee77BjdoYtI2Q/videos",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/user/creativecommons/videos",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.VIDEOS; }
@Override public String expectedId() throws Exception { return "UCTwECeGqMZee77BjdoYtI2Q"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UCTwECeGqMZee77BjdoYtI2Q/videos"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/user/creativecommons/videos"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Playlists implements BaseListExtractorTest {
static class Playlists extends DefaultListExtractorTest<ChannelTabExtractor> {
private static YoutubeChannelTabExtractor extractor;
@BeforeAll
@ -97,52 +58,17 @@ class YoutubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.PLAYLISTS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UC2DjFE7Xf11URZqWBigcVOQ", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/playlists",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/@EEVblog/playlists",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.PLAYLISTS; }
@Override public String expectedId() throws Exception { return "UC2DjFE7Xf11URZqWBigcVOQ"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/playlists"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/@EEVblog/playlists"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.PLAYLIST; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Channels implements BaseListExtractorTest {
static class Channels extends DefaultListExtractorTest<ChannelTabExtractor> {
private static YoutubeChannelTabExtractor extractor;
@BeforeAll
@ -154,52 +80,17 @@ class YoutubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.CHANNELS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UC2DjFE7Xf11URZqWBigcVOQ", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/channels",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/channels",
extractor.getUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.CHANNELS; }
@Override public String expectedId() throws Exception { return "UC2DjFE7Xf11URZqWBigcVOQ"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/channels"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/channel/UC2DjFE7Xf11URZqWBigcVOQ/channels"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.CHANNEL; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Livestreams implements BaseListExtractorTest {
static class Livestreams extends DefaultListExtractorTest<ChannelTabExtractor> {
private static YoutubeChannelTabExtractor extractor;
@BeforeAll
@ -211,52 +102,17 @@ class YoutubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.LIVESTREAMS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UCR-DXc1voovS8nhAvccRZhg", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UCR-DXc1voovS8nhAvccRZhg/streams",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/c/JeffGeerling/streams",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.LIVESTREAMS; }
@Override public String expectedId() throws Exception { return "UCR-DXc1voovS8nhAvccRZhg"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UCR-DXc1voovS8nhAvccRZhg/streams"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/c/JeffGeerling/streams"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class Shorts implements BaseListExtractorTest {
static class Shorts extends DefaultListExtractorTest<ChannelTabExtractor> {
private static YoutubeChannelTabExtractor extractor;
@BeforeAll
@ -268,130 +124,80 @@ class YoutubeChannelTabExtractorTest {
extractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.SHORTS, extractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UCh8gHdtzO2tXd593_bjErWg", extractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UCh8gHdtzO2tXd593_bjErWg/shorts",
extractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/channel/UCh8gHdtzO2tXd593_bjErWg/shorts",
extractor.getOriginalUrl());
}
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(extractor);
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(extractor);
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.SHORTS; }
@Override public String expectedId() throws Exception { return "UCh8gHdtzO2tXd593_bjErWg"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UCh8gHdtzO2tXd593_bjErWg/shorts"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/channel/UCh8gHdtzO2tXd593_bjErWg/shorts"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class AgeRestrictedTabs implements BaseListExtractorTest {
private static ChannelTabExtractor videosTabExtractor;
private static ChannelTabExtractor shortsTabExtractor;
// TESTS FOR TABS OF AGE RESTRICTED CHANNELS
// Fetching the tabs individually would use the standard tabs without fallback to
// system playlists for stream tabs, we need to fetch the channel extractor to get the
// channel playlist tabs
// TODO: implement system playlists fallback in YoutubeChannelTabExtractor for stream
// tabs
static class AgeRestrictedTabsVideos extends DefaultListExtractorTest<ChannelTabExtractor> {
private static ChannelTabExtractor extractor;
@BeforeAll
static void setUp() throws IOException, ExtractionException {
YoutubeTestsUtils.ensureStateless();
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "ageRestricted"));
final ChannelExtractor extractor = YouTube.getChannelExtractor(
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "ageRestrictedTabsVideos"));
final ChannelExtractor channelExtractor = YouTube.getChannelExtractor(
"https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig");
channelExtractor.fetchPage();
// the videos tab is the first one
extractor = YouTube.getChannelTabExtractor(channelExtractor.getTabs().get(0));
extractor.fetchPage();
// Fetching the tabs individually would use the standard tabs without fallback to
// system playlists for stream tabs, we need to fetch the channel extractor to get the
// channel playlist tabs
// TODO: implement system playlists fallback in YoutubeChannelTabExtractor for stream
// tabs
final List<ListLinkHandler> tabs = extractor.getTabs();
videosTabExtractor = YouTube.getChannelTabExtractor(tabs.get(0));
videosTabExtractor.fetchPage();
shortsTabExtractor = YouTube.getChannelTabExtractor(tabs.get(1));
shortsTabExtractor.fetchPage();
}
@Test
@Override
public void testServiceId() {
assertEquals(YouTube.getServiceId(), videosTabExtractor.getServiceId());
assertEquals(YouTube.getServiceId(), shortsTabExtractor.getServiceId());
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.VIDEOS; }
@Override public String expectedId() throws Exception { return "UCbfnHqxXs_K3kvaH-WlNlig"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/videos"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/videos"; }
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
@Override public boolean expectedHasMoreItems() { return true; }
}
static class AgeRestrictedTabsShorts extends DefaultListExtractorTest<ChannelTabExtractor> {
private static ChannelTabExtractor extractor;
@BeforeAll
static void setUp() throws IOException, ExtractionException {
YoutubeTestsUtils.ensureStateless();
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "ageRestrictedTabsShorts"));
final ChannelExtractor channelExtractor = YouTube.getChannelExtractor(
"https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig");
channelExtractor.fetchPage();
// the shorts tab is the second one
extractor = YouTube.getChannelTabExtractor(channelExtractor.getTabs().get(1));
extractor.fetchPage();
}
@Test
@Override
public void testName() throws Exception {
assertEquals(ChannelTabs.VIDEOS, videosTabExtractor.getName());
assertEquals(ChannelTabs.SHORTS, shortsTabExtractor.getName());
}
@Test
@Override
public void testId() throws ParsingException {
assertEquals("UCbfnHqxXs_K3kvaH-WlNlig", videosTabExtractor.getId());
assertEquals("UCbfnHqxXs_K3kvaH-WlNlig", shortsTabExtractor.getId());
}
@Test
@Override
public void testUrl() throws ParsingException {
assertEquals("https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/videos",
videosTabExtractor.getUrl());
assertEquals("https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/shorts",
shortsTabExtractor.getUrl());
}
@Test
@Override
public void testOriginalUrl() throws Exception {
assertEquals("https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/videos",
videosTabExtractor.getOriginalUrl());
assertEquals("https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/shorts",
shortsTabExtractor.getOriginalUrl());
}
@Override public ChannelTabExtractor extractor() throws Exception { return extractor; }
@Override public StreamingService expectedService() throws Exception { return YouTube; }
@Override public String expectedName() throws Exception { return ChannelTabs.SHORTS; }
@Override public String expectedId() throws Exception { return "UCbfnHqxXs_K3kvaH-WlNlig"; }
@Override public String expectedUrlContains() throws Exception { return "https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/shorts"; }
@Override public String expectedOriginalUrlContains() throws Exception { return "https://www.youtube.com/channel/UCbfnHqxXs_K3kvaH-WlNlig/shorts"; }
@Override public boolean expectedHasMoreItems() { return false; }
@Test
@Override
public void testRelatedItems() throws Exception {
defaultTestRelatedItems(videosTabExtractor);
// No shorts on this channel, the channel tab playlist extractor should return no
// streams
assertTrue(shortsTabExtractor.getInitialPage().getItems().isEmpty());
}
@Test
@Override
public void testMoreRelatedItems() throws Exception {
defaultTestMoreItems(videosTabExtractor);
// No shorts on this channel, the channel tab playlist extractor should return no
// streams
assertFalse(shortsTabExtractor.getInitialPage().hasNextPage());
// this channel has no shorts, so an empty page is returned by the playlist extractor
assertTrue(extractor.getInitialPage().getItems().isEmpty());
assertTrue(extractor.getInitialPage().getErrors().isEmpty());
}
}
}

View File

@ -0,0 +1,88 @@
{
"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-report-only": [
"require-trusted-types-for \u0027script\u0027;report-uri /cspreport"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Sun, 06 Aug 2023 11:54:54 GMT"
],
"expires": [
"Sun, 06 Aug 2023 11:54:54 GMT"
],
"origin-trial": [
"AvC9UlR6RDk2crliDsFl66RWLnTbHrDbp+DiY6AYz/PNQ4G4tdUTjrHYr2sghbkhGQAVxb7jaPTHpEVBz0uzQwkAAAB4eyJvcmlnaW4iOiJodHRwczovL3lvdXR1YmUuY29tOjQ0MyIsImZlYXR1cmUiOiJXZWJWaWV3WFJlcXVlc3RlZFdpdGhEZXByZWNhdGlvbiIsImV4cGlyeSI6MTcxOTUzMjc5OSwiaXNTdWJkb21haW4iOnRydWV9"
],
"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-factor\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\"}]}"
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003dIXSPROQ-CH8; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dMon, 09-Nov-2020 11:54:54 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"CONSENT\u003dPENDING+942; expires\u003dTue, 05-Aug-2025 11:54:54 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
],
"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

@ -41,10 +41,10 @@
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Mon, 17 Jul 2023 20:14:18 GMT"
"Sun, 06 Aug 2023 11:55:07 GMT"
],
"expires": [
"Mon, 17 Jul 2023 20:14:18 GMT"
"Sun, 06 Aug 2023 11:55:07 GMT"
],
"origin-trial": [
"AvC9UlR6RDk2crliDsFl66RWLnTbHrDbp+DiY6AYz/PNQ4G4tdUTjrHYr2sghbkhGQAVxb7jaPTHpEVBz0uzQwkAAAB4eyJvcmlnaW4iOiJodHRwczovL3lvdXR1YmUuY29tOjQ0MyIsImZlYXR1cmUiOiJXZWJWaWV3WFJlcXVlc3RlZFdpdGhEZXByZWNhdGlvbiIsImV4cGlyeSI6MTcxOTUzMjc5OSwiaXNTdWJkb21haW4iOnRydWV9"
@ -62,9 +62,9 @@
"ESF"
],
"set-cookie": [
"YSC\u003dgtpu5gh6Su4; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dTue, 20-Oct-2020 20:14:18 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"CONSENT\u003dPENDING+016; expires\u003dWed, 16-Jul-2025 20:14:18 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
"YSC\u003dqCdA3bmpLFQ; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dMon, 09-Nov-2020 11:55:07 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"CONSENT\u003dPENDING+717; expires\u003dTue, 05-Aug-2025 11:55:07 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
],
"strict-transport-security": [
"max-age\u003d31536000"