Skip to content

Commit 306f836

Browse files
committed
Extractor is now able to detect if a video is blocked by country
1 parent cd81998 commit 306f836

3 files changed

Lines changed: 48 additions & 13 deletions

File tree

services/youtube/YoutubeStreamExtractor.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ private JSONObject getPlayerConfig(String pageContent) throws ParsingException {
260260
Parser.matchGroup1("ytplayer.config\\s*=\\s*(\\{.*?\\});", pageContent);
261261
return new JSONObject(ytPlayerConfigRaw);
262262
} catch (Parser.RegexException e) {
263-
String errorReason = findErrorReason(doc);
263+
String errorReason = getErrorMessage();
264264
switch(errorReason) {
265265
case "GEMA":
266266
throw new GemaException(errorReason);
@@ -948,15 +948,28 @@ private String decryptSignature(String encryptedSig, String decryptionCode)
948948
return result == null ? "" : result.toString();
949949
}
950950

951-
private String findErrorReason(Document doc) {
952-
String errorMessage = doc.select("h1[id=\"unavailable-message\"]").first().text();
953-
if(errorMessage.contains("GEMA")) {
951+
952+
/**
953+
* {@inheritDoc}
954+
*/
955+
public String getErrorMessage() {
956+
String errorMessage = doc.select("h1[id=\"unavailable-message\"]").first().text();
957+
StringBuilder errorReason;
958+
959+
if (errorMessage == null || errorMessage.isEmpty()) {
960+
errorReason = null;
961+
} else if(errorMessage.contains("GEMA")) {
954962
// Gema sometimes blocks youtube music content in germany:
955963
// https://www.gema.de/en/
956964
// Detailed description:
957965
// https://en.wikipedia.org/wiki/GEMA_%28German_organization%29
958-
return "GEMA";
966+
errorReason = new StringBuilder("GEMA");
967+
} else {
968+
errorReason = new StringBuilder(errorMessage);
969+
errorReason.append(" ");
970+
errorReason.append(doc.select("[id=\"unavailable-submessage\"]").first().text());
959971
}
960-
return "";
972+
973+
return errorReason != null ? errorReason.toString() : null;
961974
}
962975
}

stream_info/StreamExtractor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public ExtractorInitException(String message, Throwable cause) {
4949
}
5050
}
5151

52-
public class ContentNotAvailableException extends ParsingException {
52+
public static class ContentNotAvailableException extends ParsingException {
5353
public ContentNotAvailableException(String message) {
5454
super(message);
5555
}
@@ -101,4 +101,11 @@ public UrlIdHandler getUrlIdHandler() {
101101
public int getServiceId() {
102102
return serviceId;
103103
}
104+
105+
/**
106+
* Analyses the webpage's document and extracts any error message there might be.
107+
*
108+
* @return Error message; null if there is no error message.
109+
*/
110+
public abstract String getErrorMessage();
104111
}

stream_info/StreamInfo.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,34 @@ public void addException(Exception e) {
7474
/**Fills out the video info fields which are common to all services.
7575
* Probably needs to be overridden by subclasses*/
7676
public static StreamInfo getVideoInfo(StreamExtractor extractor)
77-
throws ExtractionException, IOException {
77+
throws ExtractionException, StreamExtractor.ContentNotAvailableException {
7878
StreamInfo streamInfo = new StreamInfo();
7979

80-
streamInfo = extractImportantData(streamInfo, extractor);
81-
streamInfo = extractStreams(streamInfo, extractor);
82-
streamInfo = extractOptionalData(streamInfo, extractor);
80+
try {
81+
streamInfo = extractImportantData(streamInfo, extractor);
82+
streamInfo = extractStreams(streamInfo, extractor);
83+
streamInfo = extractOptionalData(streamInfo, extractor);
84+
} catch (ExtractionException e) {
85+
// Currently YouTube does not distinguish between age restricted videos and videos blocked
86+
// by country. This means that during the initialisation of the extractor, the extractor
87+
// will assume that a video is age restricted while in reality it it blocked by country.
88+
//
89+
// We will now detect whether the video is blocked by country or not.
90+
String errorMsg = extractor.getErrorMessage();
91+
92+
if (errorMsg != null) {
93+
throw new StreamExtractor.ContentNotAvailableException(errorMsg);
94+
} else {
95+
throw e;
96+
}
97+
}
8398

8499
return streamInfo;
85100
}
86101

87102
private static StreamInfo extractImportantData(
88103
StreamInfo streamInfo, StreamExtractor extractor)
89-
throws ExtractionException, IOException {
104+
throws ExtractionException {
90105
/* ---- important data, withoug the video can't be displayed goes here: ---- */
91106
// if one of these is not available an exception is meant to be thrown directly into the frontend.
92107

@@ -112,7 +127,7 @@ private static StreamInfo extractImportantData(
112127

113128
private static StreamInfo extractStreams(
114129
StreamInfo streamInfo, StreamExtractor extractor)
115-
throws ExtractionException, IOException {
130+
throws ExtractionException {
116131
/* ---- stream extraction goes here ---- */
117132
// At least one type of stream has to be available,
118133
// otherwise an exception will be thrown directly into the frontend.

0 commit comments

Comments
 (0)