Skip to content

Commit e0315ca

Browse files
committed
-Fixes age-gated video info retrieval.
-Fixes youtube video stream test passing even when no stream is fetched on age-gated videos.
1 parent d6a0022 commit e0315ca

2 files changed

Lines changed: 53 additions & 23 deletions

File tree

src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,6 @@ public String getErrorMessage() {
543543
private static final String HTTPS = "https:";
544544
private static final String CONTENT = "content";
545545
private static final String DECRYPTION_FUNC_NAME = "decrypt";
546-
private static final String GET_VIDEO_INFO_URL = "https://www.youtube.com/get_video_info?video_id=" + "%s" +
547-
"&el=info&ps=default&eurl=&gl=US&hl=en";
548546

549547
private volatile String decryptionCode = "";
550548

@@ -559,19 +557,21 @@ private String getPageHtml(Downloader downloader) throws IOException, Extraction
559557

560558
@Override
561559
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
562-
String pageContent = getPageHtml(downloader);
560+
final String pageContent = getPageHtml(downloader);
563561
doc = Jsoup.parse(pageContent, getCleanUrl());
564562

565-
566-
String playerUrl;
563+
final String playerUrl;
564+
// TODO: use embedded videos to fetch DASH manifest for all videos
567565
// Check if the video is age restricted
568566
if (pageContent.contains("<meta property=\"og:restrictions:age")) {
569-
String infoPageResponse = downloader.download(String.format(GET_VIDEO_INFO_URL, getId()));
567+
final EmbeddedInfo info = getEmbeddedInfo();
568+
final String videoInfoUrl = getVideoInfoUrl(getId(), info.sts);
569+
final String infoPageResponse = downloader.download(videoInfoUrl);
570570
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
571-
playerUrl = getPlayerUrlFromRestrictedVideo();
571+
playerUrl = info.url;
572572
isAgeRestricted = true;
573573
} else {
574-
JsonObject ytPlayerConfig = getPlayerConfig(pageContent);
574+
final JsonObject ytPlayerConfig = getPlayerConfig(pageContent);
575575
playerArgs = getPlayerArgs(ytPlayerConfig);
576576
playerUrl = getPlayerUrl(ytPlayerConfig);
577577
isAgeRestricted = false;
@@ -643,24 +643,26 @@ private String getPlayerUrl(JsonObject playerConfig) throws ParsingException {
643643
}
644644
}
645645

646-
private String getPlayerUrlFromRestrictedVideo() throws ParsingException, ReCaptchaException {
646+
@Nonnull
647+
private EmbeddedInfo getEmbeddedInfo() throws ParsingException, ReCaptchaException {
647648
try {
648-
Downloader downloader = NewPipe.getDownloader();
649-
String playerUrl = "";
650-
String embedUrl = "https://www.youtube.com/embed/" + getId();
651-
String embedPageContent = downloader.download(embedUrl);
652-
//todo: find out if this can be reapaced by Parser.matchGroup1()
653-
Pattern assetsPattern = Pattern.compile("\"assets\":.+?\"js\":\\s*(\"[^\"]+\")");
654-
Matcher patternMatcher = assetsPattern.matcher(embedPageContent);
655-
while (patternMatcher.find()) {
656-
playerUrl = patternMatcher.group(1);
657-
}
658-
playerUrl = playerUrl.replace("\\", "").replace("\"", "");
659-
649+
final Downloader downloader = NewPipe.getDownloader();
650+
final String embedUrl = "https://www.youtube.com/embed/" + getId();
651+
final String embedPageContent = downloader.download(embedUrl);
652+
653+
// Get player url
654+
final String assetsPattern = "\"assets\":.+?\"js\":\\s*(\"[^\"]+\")";
655+
String playerUrl = Parser.matchGroup1(assetsPattern, embedPageContent)
656+
.replace("\\", "").replace("\"", "");
660657
if (playerUrl.startsWith("//")) {
661658
playerUrl = HTTPS + playerUrl;
662659
}
663-
return playerUrl;
660+
661+
// Get embed sts
662+
final String stsPattern = "\"sts\"\\s*:\\s*(\\d+)";
663+
final String sts = Parser.matchGroup1(stsPattern, embedPageContent);
664+
665+
return new EmbeddedInfo(playerUrl, sts);
664666
} catch (IOException e) {
665667
throw new ParsingException(
666668
"Could load decryption code form restricted video for the Youtube service.", e);
@@ -730,10 +732,31 @@ private String decryptSignature(String encryptedSig, String decryptionCode) thro
730732
return result == null ? "" : result.toString();
731733
}
732734

735+
/*//////////////////////////////////////////////////////////////////////////
736+
// Data Class
737+
//////////////////////////////////////////////////////////////////////////*/
738+
739+
private class EmbeddedInfo {
740+
final String url;
741+
final String sts;
742+
743+
EmbeddedInfo(final String url, final String sts) {
744+
this.url = url;
745+
this.sts = sts;
746+
}
747+
}
748+
733749
/*//////////////////////////////////////////////////////////////////////////
734750
// Utils
735751
//////////////////////////////////////////////////////////////////////////*/
736752

753+
@Nonnull
754+
private String getVideoInfoUrl(final String id, final String sts) {
755+
return "https://www.youtube.com/get_video_info?" + "video_id=" + id +
756+
"&eurl=https://youtube.googleapis.com/v/" + id +
757+
"&sts=" + sts + "&ps=default&gl=US&hl=en";
758+
}
759+
737760
private Map<String, ItagItem> getItags(String encodedUrlMapKey, ItagItem.ItagType itagTypeWanted) throws ParsingException {
738761
Map<String, ItagItem> urlAndItags = new LinkedHashMap<>();
739762

src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractorRestrictedTest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import org.schabi.newpipe.extractor.stream.VideoStream;
1313

1414
import java.io.IOException;
15+
import java.util.ArrayList;
16+
import java.util.List;
1517

1618
import static org.junit.Assert.*;
1719
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
@@ -103,7 +105,12 @@ public void testGetAudioStreams() throws IOException, ExtractionException {
103105

104106
@Test
105107
public void testGetVideoStreams() throws IOException, ExtractionException {
106-
for (VideoStream s : extractor.getVideoStreams()) {
108+
List<VideoStream> streams = new ArrayList<>();
109+
streams.addAll(extractor.getVideoStreams());
110+
streams.addAll(extractor.getVideoOnlyStreams());
111+
112+
assertTrue(streams.size() > 0);
113+
for (VideoStream s : streams) {
107114
assertTrue(s.getUrl(),
108115
s.getUrl().contains(HTTPS));
109116
assertTrue(s.resolution.length() > 0);

0 commit comments

Comments
 (0)