-Fixes age-gated video info retrieval.
-Fixes youtube video stream test passing even when no stream is fetched on age-gated videos.
This commit is contained in:
parent
d6a00228e8
commit
e0315ca2af
|
@ -543,8 +543,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
private static final String HTTPS = "https:";
|
private static final String HTTPS = "https:";
|
||||||
private static final String CONTENT = "content";
|
private static final String CONTENT = "content";
|
||||||
private static final String DECRYPTION_FUNC_NAME = "decrypt";
|
private static final String DECRYPTION_FUNC_NAME = "decrypt";
|
||||||
private static final String GET_VIDEO_INFO_URL = "https://www.youtube.com/get_video_info?video_id=" + "%s" +
|
|
||||||
"&el=info&ps=default&eurl=&gl=US&hl=en";
|
|
||||||
|
|
||||||
private volatile String decryptionCode = "";
|
private volatile String decryptionCode = "";
|
||||||
|
|
||||||
|
@ -559,19 +557,21 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
String pageContent = getPageHtml(downloader);
|
final String pageContent = getPageHtml(downloader);
|
||||||
doc = Jsoup.parse(pageContent, getCleanUrl());
|
doc = Jsoup.parse(pageContent, getCleanUrl());
|
||||||
|
|
||||||
|
final String playerUrl;
|
||||||
String playerUrl;
|
// TODO: use embedded videos to fetch DASH manifest for all videos
|
||||||
// Check if the video is age restricted
|
// Check if the video is age restricted
|
||||||
if (pageContent.contains("<meta property=\"og:restrictions:age")) {
|
if (pageContent.contains("<meta property=\"og:restrictions:age")) {
|
||||||
String infoPageResponse = downloader.download(String.format(GET_VIDEO_INFO_URL, getId()));
|
final EmbeddedInfo info = getEmbeddedInfo();
|
||||||
|
final String videoInfoUrl = getVideoInfoUrl(getId(), info.sts);
|
||||||
|
final String infoPageResponse = downloader.download(videoInfoUrl);
|
||||||
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
||||||
playerUrl = getPlayerUrlFromRestrictedVideo();
|
playerUrl = info.url;
|
||||||
isAgeRestricted = true;
|
isAgeRestricted = true;
|
||||||
} else {
|
} else {
|
||||||
JsonObject ytPlayerConfig = getPlayerConfig(pageContent);
|
final JsonObject ytPlayerConfig = getPlayerConfig(pageContent);
|
||||||
playerArgs = getPlayerArgs(ytPlayerConfig);
|
playerArgs = getPlayerArgs(ytPlayerConfig);
|
||||||
playerUrl = getPlayerUrl(ytPlayerConfig);
|
playerUrl = getPlayerUrl(ytPlayerConfig);
|
||||||
isAgeRestricted = false;
|
isAgeRestricted = false;
|
||||||
|
@ -643,24 +643,26 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPlayerUrlFromRestrictedVideo() throws ParsingException, ReCaptchaException {
|
@Nonnull
|
||||||
|
private EmbeddedInfo getEmbeddedInfo() throws ParsingException, ReCaptchaException {
|
||||||
try {
|
try {
|
||||||
Downloader downloader = NewPipe.getDownloader();
|
final Downloader downloader = NewPipe.getDownloader();
|
||||||
String playerUrl = "";
|
final String embedUrl = "https://www.youtube.com/embed/" + getId();
|
||||||
String embedUrl = "https://www.youtube.com/embed/" + getId();
|
final String embedPageContent = downloader.download(embedUrl);
|
||||||
String embedPageContent = downloader.download(embedUrl);
|
|
||||||
//todo: find out if this can be reapaced by Parser.matchGroup1()
|
|
||||||
Pattern assetsPattern = Pattern.compile("\"assets\":.+?\"js\":\\s*(\"[^\"]+\")");
|
|
||||||
Matcher patternMatcher = assetsPattern.matcher(embedPageContent);
|
|
||||||
while (patternMatcher.find()) {
|
|
||||||
playerUrl = patternMatcher.group(1);
|
|
||||||
}
|
|
||||||
playerUrl = playerUrl.replace("\\", "").replace("\"", "");
|
|
||||||
|
|
||||||
|
// Get player url
|
||||||
|
final String assetsPattern = "\"assets\":.+?\"js\":\\s*(\"[^\"]+\")";
|
||||||
|
String playerUrl = Parser.matchGroup1(assetsPattern, embedPageContent)
|
||||||
|
.replace("\\", "").replace("\"", "");
|
||||||
if (playerUrl.startsWith("//")) {
|
if (playerUrl.startsWith("//")) {
|
||||||
playerUrl = HTTPS + playerUrl;
|
playerUrl = HTTPS + playerUrl;
|
||||||
}
|
}
|
||||||
return playerUrl;
|
|
||||||
|
// Get embed sts
|
||||||
|
final String stsPattern = "\"sts\"\\s*:\\s*(\\d+)";
|
||||||
|
final String sts = Parser.matchGroup1(stsPattern, embedPageContent);
|
||||||
|
|
||||||
|
return new EmbeddedInfo(playerUrl, sts);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ParsingException(
|
throw new ParsingException(
|
||||||
"Could load decryption code form restricted video for the Youtube service.", e);
|
"Could load decryption code form restricted video for the Youtube service.", e);
|
||||||
|
@ -730,10 +732,31 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
return result == null ? "" : result.toString();
|
return result == null ? "" : result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data Class
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private class EmbeddedInfo {
|
||||||
|
final String url;
|
||||||
|
final String sts;
|
||||||
|
|
||||||
|
EmbeddedInfo(final String url, final String sts) {
|
||||||
|
this.url = url;
|
||||||
|
this.sts = sts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private String getVideoInfoUrl(final String id, final String sts) {
|
||||||
|
return "https://www.youtube.com/get_video_info?" + "video_id=" + id +
|
||||||
|
"&eurl=https://youtube.googleapis.com/v/" + id +
|
||||||
|
"&sts=" + sts + "&ps=default&gl=US&hl=en";
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, ItagItem> getItags(String encodedUrlMapKey, ItagItem.ItagType itagTypeWanted) throws ParsingException {
|
private Map<String, ItagItem> getItags(String encodedUrlMapKey, ItagItem.ItagType itagTypeWanted) throws ParsingException {
|
||||||
Map<String, ItagItem> urlAndItags = new LinkedHashMap<>();
|
Map<String, ItagItem> urlAndItags = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import org.schabi.newpipe.extractor.stream.SubtitlesFormat;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
@ -103,7 +105,12 @@ public class YoutubeStreamExtractorRestrictedTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetVideoStreams() throws IOException, ExtractionException {
|
public void testGetVideoStreams() throws IOException, ExtractionException {
|
||||||
for (VideoStream s : extractor.getVideoStreams()) {
|
List<VideoStream> streams = new ArrayList<>();
|
||||||
|
streams.addAll(extractor.getVideoStreams());
|
||||||
|
streams.addAll(extractor.getVideoOnlyStreams());
|
||||||
|
|
||||||
|
assertTrue(streams.size() > 0);
|
||||||
|
for (VideoStream s : streams) {
|
||||||
assertTrue(s.getUrl(),
|
assertTrue(s.getUrl(),
|
||||||
s.getUrl().contains(HTTPS));
|
s.getUrl().contains(HTTPS));
|
||||||
assertTrue(s.resolution.length() > 0);
|
assertTrue(s.resolution.length() > 0);
|
||||||
|
|
Loading…
Reference in New Issue