Skip to content

Commit 78f28a6

Browse files
committed
[YouTube] Only fetch the Android mobile API for video streams
Also fixes the double fetch of the desktop player API when the content is protected by signatureCiphers when we know the sts string. Format some code, remove an unused import.
1 parent 9c25cc4 commit 78f28a6

1 file changed

Lines changed: 48 additions & 36 deletions

File tree

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

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import java.time.format.DateTimeFormatter;
4343
import java.util.*;
4444

45-
import static org.schabi.newpipe.extractor.services.youtube.YoutubeDashManifestCreator.createDashManifestFromOtfStreamingUrl;
4645
import static org.schabi.newpipe.extractor.services.youtube.YoutubeDashManifestCreator.createDashManifestFromPostLiveStreamDvrStreamingUrl;
4746
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.*;
4847
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
@@ -80,7 +79,7 @@ public static class DeobfuscateException extends ParsingException {
8079
}
8180
}
8281

83-
/*//////////////////////////////////////////////////////////////////////////*/
82+
/*////////////////////////////////////////////////////////////////////////*/
8483

8584
@Nullable
8685
private static String cachedDeobfuscationCode = null;
@@ -91,6 +90,7 @@ public static class DeobfuscateException extends ParsingException {
9190

9291
private JsonObject playerResponse;
9392
private JsonObject nextResponse;
93+
private StreamType streamType;
9494

9595
@Nullable
9696
private JsonObject desktopStreamingData;
@@ -689,13 +689,7 @@ public List<SubtitlesStream> getSubtitles(final MediaFormat format) throws Parsi
689689
public StreamType getStreamType() {
690690
assertPageFetched();
691691

692-
if (playerResponse.getObject("playabilityStatus").has("liveStreamability")) {
693-
return StreamType.LIVE_STREAM;
694-
} else if (playerResponse.getObject("videoDetails").getBoolean("isPostLiveDvr", false)) {
695-
return StreamType.POST_LIVE_STREAM;
696-
} else {
697-
return StreamType.VIDEO_STREAM;
698-
}
692+
return streamType;
699693
}
700694

701695
@Nullable
@@ -792,18 +786,39 @@ public void onFetchPage(@Nonnull final Downloader downloader)
792786

793787
final JsonObject playabilityStatus = playerResponse.getObject("playabilityStatus");
794788

795-
boolean ageRestricted = playabilityStatus.getString("reason", EMPTY_STRING)
789+
final boolean isAgeRestricted = playabilityStatus.getString("reason", EMPTY_STRING)
796790
.contains("age");
797791

798792
if (!playerResponse.has("streamingData")) {
799793
try {
800794
fetchDesktopEmbedJsonPlayer(contentCountry, localization, videoId);
801795
} catch (final Exception ignored) {
802796
}
797+
798+
if (playerResponse.getObject("playabilityStatus").has("liveStreamability")) {
799+
streamType = StreamType.LIVE_STREAM;
800+
} else if (playerResponse.getObject("videoDetails").getBoolean("isPostLiveDvr",
801+
false)) {
802+
streamType = StreamType.POST_LIVE_STREAM;
803+
} else {
804+
streamType = StreamType.VIDEO_STREAM;
805+
}
806+
803807
try {
804-
fetchAndroidEmbedJsonPlayer(contentCountry, localization, videoId);
808+
if (streamType == StreamType.VIDEO_STREAM || desktopStreamingData == null) {
809+
fetchAndroidEmbedJsonPlayer(contentCountry, localization, videoId);
810+
}
805811
} catch (final Exception ignored) {
806812
}
813+
} else {
814+
if (playerResponse.getObject("playabilityStatus").has("liveStreamability")) {
815+
streamType = StreamType.LIVE_STREAM;
816+
} else if (playerResponse.getObject("videoDetails").getBoolean("isPostLiveDvr",
817+
false)) {
818+
streamType = StreamType.POST_LIVE_STREAM;
819+
} else {
820+
streamType = StreamType.VIDEO_STREAM;
821+
}
807822
}
808823

809824
if (desktopStreamingData == null && playerResponse.has("streamingData")) {
@@ -814,7 +829,7 @@ public void onFetchPage(@Nonnull final Downloader downloader)
814829
checkPlayabilityStatus(youtubePlayerResponse, playabilityStatus);
815830
}
816831

817-
if (ageRestricted) {
832+
if (isAgeRestricted) {
818833
final byte[] ageRestrictedBody = JsonWriter.string(prepareDesktopEmbedVideoJsonBuilder(
819834
localization, contentCountry, videoId)
820835
.done())
@@ -824,14 +839,15 @@ public void onFetchPage(@Nonnull final Downloader downloader)
824839
nextResponse = getJsonPostResponse("next", body, localization);
825840
}
826841

827-
if (!ageRestricted) {
842+
if (!isAgeRestricted && (streamType == StreamType.VIDEO_STREAM
843+
|| desktopStreamingData == null)) {
828844
try {
829845
fetchAndroidMobileJsonPlayer(contentCountry, localization, videoId);
830846
} catch (final Exception ignored) {
831847
}
832848
}
833849

834-
if (isCipherProtectedContent()) {
850+
if (!isAgeRestricted && isCipherProtectedContent() && sts == null) {
835851
fetchDesktopJsonPlayerWithSts(contentCountry, localization, videoId);
836852
}
837853
}
@@ -860,28 +876,24 @@ private void checkPlayabilityStatus(final JsonObject youtubePlayerResponse,
860876
"This age-restricted video cannot be watched.");
861877
}
862878
}
863-
if (status.equalsIgnoreCase("unplayable")) {
864-
if (reason != null) {
865-
if (reason.contains("Music Premium")) {
866-
throw new YoutubeMusicPremiumContentException();
867-
}
868-
if (reason.contains("payment")) {
869-
throw new PaidContentException("This video is a paid video");
870-
}
871-
if (reason.contains("members-only")) {
872-
throw new PaidContentException(
873-
"This video is only available for members of the channel of this video");
874-
}
875-
if (reason.contains("unavailable")) {
876-
final String detailedErrorMessage = getTextFromObject(playabilityStatus
877-
.getObject("errorScreen").getObject("playerErrorMessageRenderer")
878-
.getObject("subreason"));
879-
if (detailedErrorMessage != null) {
880-
if (detailedErrorMessage.contains("country")) {
881-
throw new GeographicRestrictionException(
882-
"This video is not available in user's country.");
883-
}
884-
}
879+
if (status.equalsIgnoreCase("unplayable") && reason != null) {
880+
if (reason.contains("Music Premium")) {
881+
throw new YoutubeMusicPremiumContentException();
882+
}
883+
if (reason.contains("payment")) {
884+
throw new PaidContentException("This video is a paid video");
885+
}
886+
if (reason.contains("members-only")) {
887+
throw new PaidContentException(
888+
"This video is only available for members of the channel of this video");
889+
}
890+
if (reason.contains("unavailable")) {
891+
final String detailedErrorMessage = getTextFromObject(playabilityStatus
892+
.getObject("errorScreen").getObject("playerErrorMessageRenderer")
893+
.getObject("subreason"));
894+
if (detailedErrorMessage != null && detailedErrorMessage.contains("country")) {
895+
throw new GeographicRestrictionException(
896+
"This video is not available in user's country.");
885897
}
886898
}
887899
}

0 commit comments

Comments
 (0)