Skip to content

Commit aa9a8ca

Browse files
committed
[YouTube] Make non-extraction of videoPrimaryInfoRenderer and/or videoSecondaryInfoRenderer not fatal
Also de-duplicated common code related to the obtain of these video info renderers. This change allows extraction of videos without visual metadata.
1 parent eb07d70 commit aa9a8ca

1 file changed

Lines changed: 56 additions & 73 deletions

File tree

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

Lines changed: 56 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -204,45 +204,48 @@ public String getTextualUploadDate() throws ParsingException {
204204
return null;
205205
}
206206

207-
if (getTextFromObject(getVideoPrimaryInfoRenderer().getObject("dateText"))
208-
.startsWith("Premiered")) {
209-
final String time = getTextFromObject(
210-
getVideoPrimaryInfoRenderer().getObject("dateText")).substring(13);
211-
212-
try { // Premiered 20 hours ago
213-
final TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(
214-
Localization.fromLocalizationCode("en"));
215-
final OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime();
216-
return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime);
217-
} catch (final Exception ignored) {
218-
}
207+
final String videoPrimaryInfoRendererDateText =
208+
getTextFromObject(getVideoPrimaryInfoRenderer().getObject("dateText"));
209+
210+
if (videoPrimaryInfoRendererDateText != null) {
211+
if (videoPrimaryInfoRendererDateText.startsWith("Premiered")) {
212+
final String time = videoPrimaryInfoRendererDateText.substring(13);
213+
214+
try { // Premiered 20 hours ago
215+
final TimeAgoParser timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(
216+
Localization.fromLocalizationCode("en"));
217+
final OffsetDateTime parsedTime = timeAgoParser.parse(time).offsetDateTime();
218+
return DateTimeFormatter.ISO_LOCAL_DATE.format(parsedTime);
219+
} catch (final Exception ignored) {
220+
}
219221

220-
try { // Premiered Feb 21, 2020
221-
final LocalDate localDate = LocalDate.parse(time,
222-
DateTimeFormatter.ofPattern("MMM dd, yyyy", Locale.ENGLISH));
223-
return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate);
224-
} catch (final Exception ignored) {
222+
try { // Premiered Feb 21, 2020
223+
final LocalDate localDate = LocalDate.parse(time,
224+
DateTimeFormatter.ofPattern("MMM dd, yyyy", Locale.ENGLISH));
225+
return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate);
226+
} catch (final Exception ignored) {
227+
}
228+
229+
try { // Premiered on 21 Feb 2020
230+
final LocalDate localDate = LocalDate.parse(time,
231+
DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH));
232+
return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate);
233+
} catch (final Exception ignored) {
234+
}
225235
}
226236

227-
try { // Premiered on 21 Feb 2020
228-
final LocalDate localDate = LocalDate.parse(time,
237+
try {
238+
// TODO: this parses English formatted dates only, we need a better approach to
239+
// parse the textual date
240+
final LocalDate localDate = LocalDate.parse(videoPrimaryInfoRendererDateText,
229241
DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH));
230242
return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate);
231-
} catch (final Exception ignored) {
243+
} catch (final Exception e) {
244+
throw new ParsingException("Could not get upload date", e);
232245
}
233246
}
234247

235-
try {
236-
// TODO: this parses English formatted dates only, we need a better approach to parse
237-
// the textual date
238-
final LocalDate localDate = LocalDate.parse(getTextFromObject(
239-
getVideoPrimaryInfoRenderer().getObject("dateText")),
240-
DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH));
241-
return DateTimeFormatter.ISO_LOCAL_DATE.format(localDate);
242-
} catch (final Exception e) {
243-
throw new ParsingException("Could not get upload date", e);
244-
}
245-
248+
throw new ParsingException("Could not get upload date");
246249
}
247250

248251
@Override
@@ -565,19 +568,13 @@ public boolean isUploaderVerified() throws ParsingException {
565568
public String getUploaderAvatarUrl() throws ParsingException {
566569
assertPageFetched();
567570

568-
String url = null;
569-
570-
try {
571-
url = getVideoSecondaryInfoRenderer()
572-
.getObject("owner")
573-
.getObject("videoOwnerRenderer")
574-
.getObject("thumbnail")
575-
.getArray("thumbnails")
576-
.getObject(0)
577-
.getString("url");
578-
} catch (final ParsingException ignored) {
579-
// Age-restricted videos cause a ParsingException here
580-
}
571+
final String url = getVideoSecondaryInfoRenderer()
572+
.getObject("owner")
573+
.getObject("videoOwnerRenderer")
574+
.getObject("thumbnail")
575+
.getArray("thumbnails")
576+
.getObject(0)
577+
.getString("url");
581578

582579
if (isNullOrEmpty(url)) {
583580
if (ageLimit == NO_AGE_LIMIT) {
@@ -1212,54 +1209,40 @@ private String deobfuscateSignature(final String obfuscatedSig) throws ParsingEx
12121209
// Utils
12131210
//////////////////////////////////////////////////////////////////////////*/
12141211

1215-
private JsonObject getVideoPrimaryInfoRenderer() throws ParsingException {
1212+
@Nonnull
1213+
private JsonObject getVideoPrimaryInfoRenderer() {
12161214
if (videoPrimaryInfoRenderer != null) {
12171215
return videoPrimaryInfoRenderer;
12181216
}
12191217

1220-
final JsonArray contents = nextResponse.getObject("contents")
1221-
.getObject("twoColumnWatchNextResults").getObject("results").getObject("results")
1222-
.getArray("contents");
1223-
JsonObject theVideoPrimaryInfoRenderer = null;
1224-
1225-
for (final Object content : contents) {
1226-
if (((JsonObject) content).has("videoPrimaryInfoRenderer")) {
1227-
theVideoPrimaryInfoRenderer = ((JsonObject) content)
1228-
.getObject("videoPrimaryInfoRenderer");
1229-
break;
1230-
}
1231-
}
1232-
1233-
if (isNullOrEmpty(theVideoPrimaryInfoRenderer)) {
1234-
throw new ParsingException("Could not find videoPrimaryInfoRenderer");
1235-
}
1236-
1237-
videoPrimaryInfoRenderer = theVideoPrimaryInfoRenderer;
1238-
return theVideoPrimaryInfoRenderer;
1218+
videoPrimaryInfoRenderer = getVideoInfoRenderer("videoPrimaryInfoRenderer");
1219+
return videoPrimaryInfoRenderer;
12391220
}
12401221

12411222
@Nonnull
1242-
private JsonObject getVideoSecondaryInfoRenderer() throws ParsingException {
1223+
private JsonObject getVideoSecondaryInfoRenderer() {
12431224
if (videoSecondaryInfoRenderer != null) {
12441225
return videoSecondaryInfoRenderer;
12451226
}
12461227

1247-
videoSecondaryInfoRenderer = nextResponse
1248-
.getObject("contents")
1228+
videoSecondaryInfoRenderer = getVideoInfoRenderer("videoSecondaryInfoRenderer");
1229+
return videoSecondaryInfoRenderer;
1230+
}
1231+
1232+
@Nonnull
1233+
private JsonObject getVideoInfoRenderer(@Nonnull final String videoRendererName) {
1234+
return nextResponse.getObject("contents")
12491235
.getObject("twoColumnWatchNextResults")
12501236
.getObject("results")
12511237
.getObject("results")
12521238
.getArray("contents")
12531239
.stream()
12541240
.filter(JsonObject.class::isInstance)
12551241
.map(JsonObject.class::cast)
1256-
.filter(content -> content.has("videoSecondaryInfoRenderer"))
1257-
.map(content -> content.getObject("videoSecondaryInfoRenderer"))
1242+
.filter(content -> content.has(videoRendererName))
1243+
.map(content -> content.getObject(videoRendererName))
12581244
.findFirst()
1259-
.orElseThrow(
1260-
() -> new ParsingException("Could not find videoSecondaryInfoRenderer"));
1261-
1262-
return videoSecondaryInfoRenderer;
1245+
.orElse(new JsonObject());
12631246
}
12641247

12651248
@Nonnull

0 commit comments

Comments
 (0)