Compare commits
16 commits
c589a2c1a2
...
7e793c11ae
Author | SHA1 | Date | |
---|---|---|---|
|
7e793c11ae | ||
|
e920ab3f5f | ||
|
3f7df9536e | ||
|
999fb7f812 | ||
|
3519d4c367 | ||
|
9aca710e86 | ||
|
76eeabac45 | ||
|
676622f6df | ||
|
2a24d407d5 | ||
|
0e4e6a9bac | ||
|
ba24976e41 | ||
|
57f850bc2d | ||
|
1f4ed9dce9 | ||
|
72573932cf | ||
|
5945057227 | ||
|
7293991832 |
16 changed files with 2397 additions and 93 deletions
|
@ -133,7 +133,7 @@ public class SoundcloudStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLikeCount() {
|
public long getLikeCount() {
|
||||||
return track.getLong("favoritings_count", -1);
|
return track.getLong("likes_count", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
|
|
@ -388,8 +388,7 @@ public final class YoutubeParsingHelper {
|
||||||
* @return Whether given id belongs to a YouTube Mix
|
* @return Whether given id belongs to a YouTube Mix
|
||||||
*/
|
*/
|
||||||
public static boolean isYoutubeMixId(@Nonnull final String playlistId) {
|
public static boolean isYoutubeMixId(@Nonnull final String playlistId) {
|
||||||
return playlistId.startsWith("RD")
|
return playlistId.startsWith("RD");
|
||||||
&& !isYoutubeMusicMixId(playlistId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -846,6 +845,14 @@ public final class YoutubeParsingHelper {
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getUrlFromNavigationEndpoint(@Nonnull final JsonObject navigationEndpoint)
|
public static String getUrlFromNavigationEndpoint(@Nonnull final JsonObject navigationEndpoint)
|
||||||
throws ParsingException {
|
throws ParsingException {
|
||||||
|
if (navigationEndpoint.has("webCommandMetadata")) {
|
||||||
|
// this case needs to be handled before the browseEndpoint,
|
||||||
|
// e.g. for hashtags in comments
|
||||||
|
final JsonObject metadata = navigationEndpoint.getObject("webCommandMetadata");
|
||||||
|
if (metadata.has("url")) {
|
||||||
|
return "https://www.youtube.com" + metadata.getString("url");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (navigationEndpoint.has("urlEndpoint")) {
|
if (navigationEndpoint.has("urlEndpoint")) {
|
||||||
String internUrl = navigationEndpoint.getObject("urlEndpoint").getString("url");
|
String internUrl = navigationEndpoint.getObject("urlEndpoint").getString("url");
|
||||||
if (internUrl.startsWith("https://www.youtube.com/redirect?")) {
|
if (internUrl.startsWith("https://www.youtube.com/redirect?")) {
|
||||||
|
|
|
@ -110,8 +110,7 @@ public class YoutubeService extends StreamingService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
|
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
|
||||||
if (YoutubeParsingHelper.isYoutubeMixId(linkHandler.getId())
|
if (YoutubeParsingHelper.isYoutubeMixId(linkHandler.getId())) {
|
||||||
&& !YoutubeParsingHelper.isYoutubeMusicMixId(linkHandler.getId())) {
|
|
||||||
return new YoutubeMixPlaylistExtractor(this, linkHandler);
|
return new YoutubeMixPlaylistExtractor(this, linkHandler);
|
||||||
} else {
|
} else {
|
||||||
return new YoutubePlaylistExtractor(this, linkHandler);
|
return new YoutubePlaylistExtractor(this, linkHandler);
|
||||||
|
|
|
@ -96,8 +96,12 @@ public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (withHandle) {
|
if (withHandle) {
|
||||||
|
if (channelInfoItem.has("videoCountText")) {
|
||||||
return Utils.mixedNumberWordToLong(getTextFromObject(
|
return Utils.mixedNumberWordToLong(getTextFromObject(
|
||||||
channelInfoItem.getObject("videoCountText")));
|
channelInfoItem.getObject("videoCountText")));
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils.mixedNumberWordToLong(getTextFromObject(
|
return Utils.mixedNumberWordToLong(getTextFromObject(
|
||||||
|
|
|
@ -22,6 +22,8 @@ import java.io.IOException;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class YoutubeFeedExtractor extends FeedExtractor {
|
public class YoutubeFeedExtractor extends FeedExtractor {
|
||||||
|
private static final String WEBSITE_CHANNEL_BASE_URL = "https://www.youtube.com/channel/";
|
||||||
|
|
||||||
public YoutubeFeedExtractor(final StreamingService service, final ListLinkHandler linkHandler) {
|
public YoutubeFeedExtractor(final StreamingService service, final ListLinkHandler linkHandler) {
|
||||||
super(service, linkHandler);
|
super(service, linkHandler);
|
||||||
}
|
}
|
||||||
|
@ -57,19 +59,40 @@ public class YoutubeFeedExtractor extends FeedExtractor {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return document.getElementsByTag("yt:channelId").first().text();
|
return getUrl().replace(WEBSITE_CHANNEL_BASE_URL, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return document.select("feed > author > uri").first().text();
|
final Element authorUriElement = document.select("feed > author > uri")
|
||||||
|
.first();
|
||||||
|
if (authorUriElement != null) {
|
||||||
|
final String authorUriElementText = authorUriElement.text();
|
||||||
|
if (!authorUriElementText.equals("")) {
|
||||||
|
return authorUriElementText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Element linkElement = document.select("feed > link[rel*=alternate]")
|
||||||
|
.first();
|
||||||
|
if (linkElement != null) {
|
||||||
|
return linkElement.attr("href");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return document.select("feed > author > name").first().text();
|
final Element nameElement = document.select("feed > author > name")
|
||||||
|
.first();
|
||||||
|
if (nameElement == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameElement.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,3 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Created by Christian Schabesberger on 02.02.16.
|
||||||
|
*
|
||||||
|
* Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org>
|
||||||
|
* YoutubeStreamLinkHandlerFactory.java is part of NewPipe Extractor.
|
||||||
|
*
|
||||||
|
* NewPipe Extractor is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPipe Extractor is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
|
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isHooktubeURL;
|
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isHooktubeURL;
|
||||||
|
@ -15,33 +35,13 @@ import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/*
|
|
||||||
* Created by Christian Schabesberger on 02.02.16.
|
|
||||||
*
|
|
||||||
* Copyright (C) Christian Schabesberger 2018 <chris.schabesberger@mailbox.org>
|
|
||||||
* YoutubeStreamLinkHandlerFactory.java is part of NewPipe.
|
|
||||||
*
|
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
|
|
||||||
private static final Pattern YOUTUBE_VIDEO_ID_REGEX_PATTERN
|
private static final Pattern YOUTUBE_VIDEO_ID_REGEX_PATTERN
|
||||||
|
@ -49,7 +49,7 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
private static final YoutubeStreamLinkHandlerFactory INSTANCE
|
private static final YoutubeStreamLinkHandlerFactory INSTANCE
|
||||||
= new YoutubeStreamLinkHandlerFactory();
|
= new YoutubeStreamLinkHandlerFactory();
|
||||||
private static final List<String> SUBPATHS
|
private static final List<String> SUBPATHS
|
||||||
= Arrays.asList("embed/", "shorts/", "watch/", "v/", "w/");
|
= List.of("embed/", "live/", "shorts/", "watch/", "v/", "w/");
|
||||||
|
|
||||||
private YoutubeStreamLinkHandlerFactory() {
|
private YoutubeStreamLinkHandlerFactory() {
|
||||||
}
|
}
|
||||||
|
@ -67,21 +67,24 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
private static String assertIsId(@Nullable final String id) throws ParsingException {
|
private static String assertIsId(@Nullable final String id) throws ParsingException {
|
||||||
final String extractedId = extractId(id);
|
final String extractedId = extractId(id);
|
||||||
if (extractedId != null) {
|
if (extractedId != null) {
|
||||||
return extractedId;
|
return extractedId;
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException("The given string is not a Youtube-Video-ID");
|
throw new ParsingException("The given string is not a YouTube video ID");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getUrl(final String id) {
|
public String getUrl(final String id) {
|
||||||
return "https://www.youtube.com/watch?v=" + id;
|
return "https://www.youtube.com/watch?v=" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("AvoidNestedBlocks")
|
@SuppressWarnings("AvoidNestedBlocks")
|
||||||
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getId(final String theUrlString)
|
public String getId(final String theUrlString)
|
||||||
throws ParsingException, IllegalArgumentException {
|
throws ParsingException, IllegalArgumentException {
|
||||||
|
@ -124,14 +127,14 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
if (!Utils.isHTTP(url) || !(isYoutubeURL(url) || isYoutubeServiceURL(url)
|
if (!Utils.isHTTP(url) || !(isYoutubeURL(url) || isYoutubeServiceURL(url)
|
||||||
|| isHooktubeURL(url) || isInvidiousURL(url) || isY2ubeURL(url))) {
|
|| isHooktubeURL(url) || isInvidiousURL(url) || isY2ubeURL(url))) {
|
||||||
if (host.equalsIgnoreCase("googleads.g.doubleclick.net")) {
|
if (host.equalsIgnoreCase("googleads.g.doubleclick.net")) {
|
||||||
throw new FoundAdException("Error found ad: " + urlString);
|
throw new FoundAdException("Error: found ad: " + urlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ParsingException("The url is not a Youtube-URL");
|
throw new ParsingException("The URL is not a YouTube URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (YoutubePlaylistLinkHandlerFactory.getInstance().acceptUrl(urlString)) {
|
if (YoutubePlaylistLinkHandlerFactory.getInstance().acceptUrl(urlString)) {
|
||||||
throw new ParsingException("Error no suitable url: " + urlString);
|
throw new ParsingException("Error: no suitable URL: " + urlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using uppercase instead of lowercase, because toLowercase replaces some unicode
|
// Using uppercase instead of lowercase, because toLowercase replaces some unicode
|
||||||
|
@ -154,9 +157,9 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
|
|
||||||
final URL decodedURL;
|
final URL decodedURL;
|
||||||
try {
|
try {
|
||||||
decodedURL = Utils.stringToURL("http://www.youtube.com" + uQueryValue);
|
decodedURL = Utils.stringToURL("https://www.youtube.com" + uQueryValue);
|
||||||
} catch (final MalformedURLException e) {
|
} catch (final MalformedURLException e) {
|
||||||
throw new ParsingException("Error no suitable url: " + urlString);
|
throw new ParsingException("Error: no suitable URL: " + urlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String viewQueryValue = Utils.getQueryValue(decodedURL, "v");
|
final String viewQueryValue = Utils.getQueryValue(decodedURL, "v");
|
||||||
|
@ -231,7 +234,7 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ParsingException("Error no suitable url: " + urlString);
|
throw new ParsingException("Error: no suitable URL: " + urlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -246,7 +249,8 @@ public final class YoutubeStreamLinkHandlerFactory extends LinkHandlerFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getIdFromSubpathsInPath(final String path) throws ParsingException {
|
@Nullable
|
||||||
|
private String getIdFromSubpathsInPath(@Nonnull final String path) throws ParsingException {
|
||||||
for (final String subpath : SUBPATHS) {
|
for (final String subpath : SUBPATHS) {
|
||||||
if (path.startsWith(subpath)) {
|
if (path.startsWith(subpath)) {
|
||||||
final String id = path.substring(subpath.length());
|
final String id = path.substring(subpath.length());
|
||||||
|
|
|
@ -22,7 +22,8 @@ import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
||||||
|
|
||||||
public class SoundcloudStreamExtractorTest {
|
public class SoundcloudStreamExtractorTest {
|
||||||
|
@ -64,7 +65,7 @@ public class SoundcloudStreamExtractorTest {
|
||||||
@Override public long expectedViewCountAtLeast() { return 43000; }
|
@Override public long expectedViewCountAtLeast() { return 43000; }
|
||||||
@Nullable @Override public String expectedUploadDate() { return "2019-05-16 16:28:45.000"; }
|
@Nullable @Override public String expectedUploadDate() { return "2019-05-16 16:28:45.000"; }
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2019-05-16 16:28:45"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2019-05-16 16:28:45"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return -1; }
|
@Override public long expectedLikeCountAtLeast() { return 600; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
||||||
@Override public boolean expectedHasAudioStreams() { return false; }
|
@Override public boolean expectedHasAudioStreams() { return false; }
|
||||||
@Override public boolean expectedHasVideoStreams() { return false; }
|
@Override public boolean expectedHasVideoStreams() { return false; }
|
||||||
|
@ -127,7 +128,7 @@ public class SoundcloudStreamExtractorTest {
|
||||||
@Override public long expectedViewCountAtLeast() { return 386000; }
|
@Override public long expectedViewCountAtLeast() { return 386000; }
|
||||||
@Nullable @Override public String expectedUploadDate() { return "2016-11-11 01:16:37.000"; }
|
@Nullable @Override public String expectedUploadDate() { return "2016-11-11 01:16:37.000"; }
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2016-11-11 01:16:37"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2016-11-11 01:16:37"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return -1; }
|
@Override public long expectedLikeCountAtLeast() { return 7350; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
||||||
@Override public boolean expectedHasAudioStreams() { return false; }
|
@Override public boolean expectedHasAudioStreams() { return false; }
|
||||||
@Override public boolean expectedHasVideoStreams() { return false; }
|
@Override public boolean expectedHasVideoStreams() { return false; }
|
||||||
|
@ -170,7 +171,7 @@ public class SoundcloudStreamExtractorTest {
|
||||||
@Override public long expectedViewCountAtLeast() { return 27000; }
|
@Override public long expectedViewCountAtLeast() { return 27000; }
|
||||||
@Nullable @Override public String expectedUploadDate() { return "2019-03-28 13:36:18.000"; }
|
@Nullable @Override public String expectedUploadDate() { return "2019-03-28 13:36:18.000"; }
|
||||||
@Nullable @Override public String expectedTextualUploadDate() { return "2019-03-28 13:36:18"; }
|
@Nullable @Override public String expectedTextualUploadDate() { return "2019-03-28 13:36:18"; }
|
||||||
@Override public long expectedLikeCountAtLeast() { return -1; }
|
@Override public long expectedLikeCountAtLeast() { return 25; }
|
||||||
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
@Override public long expectedDislikeCountAtLeast() { return -1; }
|
||||||
@Override public boolean expectedHasVideoStreams() { return false; }
|
@Override public boolean expectedHasVideoStreams() { return false; }
|
||||||
@Override public boolean expectedHasSubtitles() { return false; }
|
@Override public boolean expectedHasSubtitles() { return false; }
|
||||||
|
|
|
@ -23,22 +23,22 @@ import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.Page;
|
import org.schabi.newpipe.extractor.Page;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeMixPlaylistExtractor;
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeMixPlaylistExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "NewClassNamingConvention"})
|
||||||
public class YoutubeMixPlaylistExtractorTest {
|
public class YoutubeMixPlaylistExtractorTest {
|
||||||
|
|
||||||
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/mix/";
|
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH + "services/youtube/extractor/mix/";
|
||||||
private static final Map<String, String> dummyCookie = new HashMap<>();
|
private static final Map<String, String> dummyCookie = Map.of(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
||||||
|
|
||||||
private static YoutubeMixPlaylistExtractor extractor;
|
private static YoutubeMixPlaylistExtractor extractor;
|
||||||
|
|
||||||
public static class Mix {
|
public static class Mix {
|
||||||
|
@ -50,7 +50,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "mix"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "mix"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
||||||
+ "&list=RD" + VIDEO_ID);
|
+ "&list=RD" + VIDEO_ID);
|
||||||
|
@ -135,7 +134,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MixWithIndex {
|
public static class MixWithIndex {
|
||||||
|
|
||||||
private static final String VIDEO_ID = "FAqYW76GLPA";
|
private static final String VIDEO_ID = "FAqYW76GLPA";
|
||||||
private static final String VIDEO_TITLE = "Mix – ";
|
private static final String VIDEO_TITLE = "Mix – ";
|
||||||
private static final int INDEX = 7; // YT starts the index with 1...
|
private static final int INDEX = 7; // YT starts the index with 1...
|
||||||
|
@ -146,7 +144,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "mixWithIndex"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "mixWithIndex"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID_AT_INDEX
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID_AT_INDEX
|
||||||
+ "&list=RD" + VIDEO_ID + "&index=" + INDEX);
|
+ "&list=RD" + VIDEO_ID + "&index=" + INDEX);
|
||||||
|
@ -233,7 +230,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "myMix"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "myMix"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
||||||
+ "&list=RDMM" + VIDEO_ID);
|
+ "&list=RDMM" + VIDEO_ID);
|
||||||
|
@ -316,7 +312,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Invalid {
|
public static class Invalid {
|
||||||
|
|
||||||
private static final String VIDEO_ID = "QMVCAPd5cwBcg";
|
private static final String VIDEO_ID = "QMVCAPd5cwBcg";
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
|
@ -324,7 +319,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "invalid"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "invalid"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -348,7 +342,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ChannelMix {
|
public static class ChannelMix {
|
||||||
|
|
||||||
private static final String CHANNEL_ID = "UCXuqSBlHAE6Xw-yeJA0Tunw";
|
private static final String CHANNEL_ID = "UCXuqSBlHAE6Xw-yeJA0Tunw";
|
||||||
private static final String VIDEO_ID_OF_CHANNEL = "mnk6gnOBYIo";
|
private static final String VIDEO_ID_OF_CHANNEL = "mnk6gnOBYIo";
|
||||||
private static final String CHANNEL_TITLE = "Linus Tech Tips";
|
private static final String CHANNEL_TITLE = "Linus Tech Tips";
|
||||||
|
@ -359,7 +352,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "channelMix"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "channelMix"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID_OF_CHANNEL
|
||||||
+ "&list=RDCM" + CHANNEL_ID);
|
+ "&list=RDCM" + CHANNEL_ID);
|
||||||
|
@ -424,7 +416,6 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
YoutubeTestsUtils.ensureStateless();
|
YoutubeTestsUtils.ensureStateless();
|
||||||
YoutubeParsingHelper.setConsentAccepted(true);
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "genreMix"));
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "genreMix"));
|
||||||
dummyCookie.put(YoutubeMixPlaylistExtractor.COOKIE_NAME, "whatever");
|
|
||||||
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
extractor = (YoutubeMixPlaylistExtractor) YouTube
|
||||||
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
.getPlaylistExtractor("https://www.youtube.com/watch?v=" + VIDEO_ID
|
||||||
+ "&list=RDGMEMYH9CUrFO7CfLJpaD7UR85w");
|
+ "&list=RDGMEMYH9CUrFO7CfLJpaD7UR85w");
|
||||||
|
@ -504,4 +495,93 @@ public class YoutubeMixPlaylistExtractorTest {
|
||||||
assertEquals(PlaylistInfo.PlaylistType.MIX_GENRE, extractor.getPlaylistType());
|
assertEquals(PlaylistInfo.PlaylistType.MIX_GENRE, extractor.getPlaylistType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Music {
|
||||||
|
private static final String VIDEO_ID = "dQw4w9WgXcQ";
|
||||||
|
private static final String MIX_TITLE = "Mix – Rick Astley - Never Gonna Give You Up (Official Music Video)";
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
YoutubeTestsUtils.ensureStateless();
|
||||||
|
YoutubeParsingHelper.setConsentAccepted(true);
|
||||||
|
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "musicMix"));
|
||||||
|
extractor = (YoutubeMixPlaylistExtractor)
|
||||||
|
YouTube.getPlaylistExtractor("https://m.youtube.com/watch?v=" + VIDEO_ID
|
||||||
|
+ "&list=RDAMVM" + VIDEO_ID);
|
||||||
|
extractor.fetchPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getServiceId() {
|
||||||
|
assertEquals(YouTube.getServiceId(), extractor.getServiceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getName() throws Exception {
|
||||||
|
assertEquals(MIX_TITLE, extractor.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getThumbnailUrl() throws Exception {
|
||||||
|
final String thumbnailUrl = extractor.getThumbnailUrl();
|
||||||
|
assertIsSecureUrl(thumbnailUrl);
|
||||||
|
ExtractorAsserts.assertContains("yt", thumbnailUrl);
|
||||||
|
ExtractorAsserts.assertContains(VIDEO_ID, thumbnailUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getInitialPage() throws Exception {
|
||||||
|
final InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
assertTrue(streams.hasNextPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getPage() throws Exception {
|
||||||
|
final byte[] body = JsonWriter.string(prepareDesktopJsonBuilder(
|
||||||
|
NewPipe.getPreferredLocalization(), NewPipe.getPreferredContentCountry())
|
||||||
|
.value("videoId", VIDEO_ID)
|
||||||
|
.value("playlistId", "RD" + VIDEO_ID)
|
||||||
|
.value("params", "OAE%3D")
|
||||||
|
.done())
|
||||||
|
.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
final InfoItemsPage<StreamInfoItem> streams = extractor.getPage(new Page(
|
||||||
|
YOUTUBEI_V1_URL + "next?key=" + getKey(), null, null, dummyCookie, body));
|
||||||
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
assertTrue(streams.hasNextPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getContinuations() throws Exception {
|
||||||
|
InfoItemsPage<StreamInfoItem> streams = extractor.getInitialPage();
|
||||||
|
final Set<String> urls = new HashSet<>();
|
||||||
|
|
||||||
|
// Should work infinitely, but for testing purposes only 3 times
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
assertTrue(streams.hasNextPage());
|
||||||
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
|
||||||
|
for (final StreamInfoItem item : streams.getItems()) {
|
||||||
|
// TODO Duplicates are appearing
|
||||||
|
// assertFalse(urls.contains(item.getUrl()));
|
||||||
|
urls.add(item.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
streams = extractor.getPage(streams.getNextPage());
|
||||||
|
}
|
||||||
|
assertTrue(streams.hasNextPage());
|
||||||
|
assertFalse(streams.getItems().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getStreamCount() throws ParsingException {
|
||||||
|
assertEquals(ListExtractor.ITEM_COUNT_INFINITE, extractor.getStreamCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getPlaylistType() throws ParsingException {
|
||||||
|
assertEquals(PlaylistInfo.PlaylistType.MIX_MUSIC, extractor.getPlaylistType());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,14 @@ import org.schabi.newpipe.extractor.exceptions.FoundAdException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import java.util.List;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
* Test for {@link YoutubeStreamLinkHandlerFactory}
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("HttpUrlsUsage")
|
||||||
public class YoutubeStreamLinkHandlerFactoryTest {
|
public class YoutubeStreamLinkHandlerFactoryTest {
|
||||||
private static YoutubeStreamLinkHandlerFactory linkHandler;
|
private static YoutubeStreamLinkHandlerFactory linkHandler;
|
||||||
|
|
||||||
|
@ -53,25 +53,25 @@ public class YoutubeStreamLinkHandlerFactoryTest {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {
|
@ValueSource(strings = {
|
||||||
"https://www.youtube.com/watch?v=jZViOEv90dI",
|
"https://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"https://www.youtube.com/watch?v=jZViOEv90dI&t=100",
|
"https://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100",
|
"https://WWW.YouTube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100",
|
"HTTPS://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"https://youtu.be/jZViOEv90dI?t=9s",
|
"https://youtu.be/9Dpqou5cI08?t=9s",
|
||||||
"HTTPS://Youtu.be/jZViOEv90dI?t=9s",
|
"HTTPS://Youtu.be/9Dpqou5cI08?t=9s",
|
||||||
"https://www.youtube.com/embed/jZViOEv90dI",
|
"https://www.youtube.com/embed/9Dpqou5cI08",
|
||||||
"https://www.youtube-nocookie.com/embed/jZViOEv90dI",
|
"https://www.youtube-nocookie.com/embed/9Dpqou5cI08",
|
||||||
"http://www.youtube.com/watch?v=jZViOEv90dI",
|
"http://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"http://youtube.com/watch?v=jZViOEv90dI",
|
"http://youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"http://youtu.be/jZViOEv90dI?t=9s",
|
"http://youtu.be/9Dpqou5cI08?t=9s",
|
||||||
"http://www.youtube.com/embed/jZViOEv90dI",
|
"http://www.youtube.com/embed/9Dpqou5cI08",
|
||||||
"http://www.Youtube.com/embed/jZViOEv90dI",
|
"http://www.Youtube.com/embed/9Dpqou5cI08",
|
||||||
"http://www.youtube-nocookie.com/embed/jZViOEv90dI",
|
"http://www.youtube-nocookie.com/embed/9Dpqou5cI08",
|
||||||
"vnd.youtube://www.youtube.com/watch?v=jZViOEv90dI",
|
"vnd.youtube://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"vnd.youtube:jZViOEv90dI"
|
"vnd.youtube:9Dpqou5cI08"
|
||||||
})
|
})
|
||||||
void getId_jZViOEv90dI_fromYt(final String url) throws Exception {
|
void getId_9Dpqou5cI08_fromYt(final String url) throws Exception {
|
||||||
assertEquals("jZViOEv90dI", linkHandler.fromUrl(url).getId());
|
assertEquals("9Dpqou5cI08", linkHandler.fromUrl(url).getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
@ -117,27 +117,28 @@ public class YoutubeStreamLinkHandlerFactoryTest {
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(strings = {
|
@ValueSource(strings = {
|
||||||
"https://www.youtube.com/watch?v=jZViOEv90dI",
|
"https://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"https://www.youtube.com/watch?v=jZViOEv90dI&t=100",
|
"https://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"https://WWW.YouTube.com/watch?v=jZViOEv90dI&t=100",
|
"https://WWW.YouTube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"HTTPS://www.youtube.com/watch?v=jZViOEv90dI&t=100",
|
"HTTPS://www.youtube.com/watch?v=9Dpqou5cI08&t=100",
|
||||||
"https://youtu.be/jZViOEv90dI?t=9s",
|
"https://youtu.be/9Dpqou5cI08?t=9s",
|
||||||
"https://www.youtube.com/embed/jZViOEv90dI",
|
"https://www.youtube.com/embed/9Dpqou5cI08",
|
||||||
"https://www.youtube-nocookie.com/embed/jZViOEv90dI",
|
"https://www.youtube-nocookie.com/embed/9Dpqou5cI08",
|
||||||
"http://www.youtube.com/watch?v=jZViOEv90dI",
|
"http://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"http://youtu.be/jZViOEv90dI?t=9s",
|
"http://youtu.be/9Dpqou5cI08?t=9s",
|
||||||
"http://www.youtube.com/embed/jZViOEv90dI",
|
"http://www.youtube.com/embed/9Dpqou5cI08",
|
||||||
"http://www.youtube-nocookie.com/embed/jZViOEv90dI",
|
"http://www.youtube-nocookie.com/embed/9Dpqou5cI08",
|
||||||
"http://www.youtube.com/attribution_link?a=JdfC0C9V6ZI&u=%2Fwatch%3Fv%3DEhxJLojIE_o%26feature%3Dshare",
|
"http://www.youtube.com/attribution_link?a=JdfC0C9V6ZI&u=%2Fwatch%3Fv%3DEhxJLojIE_o%26feature%3Dshare",
|
||||||
"vnd.youtube://www.youtube.com/watch?v=jZViOEv90dI",
|
"vnd.youtube://www.youtube.com/watch?v=9Dpqou5cI08",
|
||||||
"vnd.youtube:jZViOEv90dI",
|
"vnd.youtube:9Dpqou5cI08",
|
||||||
"vnd.youtube.launch:jZViOEv90dI",
|
"vnd.youtube.launch:9Dpqou5cI08",
|
||||||
"https://music.youtube.com/watch?v=O0EDx9WAelc",
|
"https://music.youtube.com/watch?v=O0EDx9WAelc",
|
||||||
"https://www.youtube.com/shorts/IOS2fqxwYbA",
|
"https://www.youtube.com/shorts/IOS2fqxwYbA",
|
||||||
"http://www.youtube.com/shorts/IOS2fqxwYbA",
|
"http://www.youtube.com/shorts/IOS2fqxwYbA",
|
||||||
"http://www.youtube.com/v/IOS2fqxwYbA",
|
"http://www.youtube.com/v/IOS2fqxwYbA",
|
||||||
"https://www.youtube.com/w/IOS2fqxwYbA",
|
"https://www.youtube.com/w/IOS2fqxwYbA",
|
||||||
"https://www.youtube.com/watch/IOS2fqxwYbA"
|
"https://www.youtube.com/watch/IOS2fqxwYbA",
|
||||||
|
"https://www.youtube.com/live/rUxyKA_-grg"
|
||||||
})
|
})
|
||||||
void acceptYtUrl(final String url) throws ParsingException {
|
void acceptYtUrl(final String url) throws ParsingException {
|
||||||
assertTrue(linkHandler.acceptUrl(url));
|
assertTrue(linkHandler.acceptUrl(url));
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
{
|
||||||
|
"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,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\""
|
||||||
|
],
|
||||||
|
"cache-control": [
|
||||||
|
"private, max-age\u003d0"
|
||||||
|
],
|
||||||
|
"content-type": [
|
||||||
|
"text/javascript; charset\u003dutf-8"
|
||||||
|
],
|
||||||
|
"cross-origin-opener-policy-report-only": [
|
||||||
|
"same-origin; report-to\u003d\"youtube_main\""
|
||||||
|
],
|
||||||
|
"date": [
|
||||||
|
"Sun, 15 Jan 2023 22:30:06 GMT"
|
||||||
|
],
|
||||||
|
"expires": [
|
||||||
|
"Sun, 15 Jan 2023 22:30:06 GMT"
|
||||||
|
],
|
||||||
|
"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-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\u003d8TYEubKDjFA; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||||
|
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dMon, 20-Apr-2020 22:30:06 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||||
|
"CONSENT\u003dPENDING+835; expires\u003dTue, 14-Jan-2025 22:30:06 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"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue