Skip to content

Commit 57bd120

Browse files
[YouTube] Refactor some extraction code using Optional
1 parent 39b9482 commit 57bd120

22 files changed

Lines changed: 276 additions & 447 deletions

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,22 +519,23 @@ public static String getChannelName(@Nullable final ChannelHeader channelHeader,
519519
}
520520

521521
return Optional.ofNullable(channelHeader)
522-
.map(header -> {
522+
.flatMap(header -> {
523523
final JsonObject channelJson = header.json;
524524
switch (header.headerType) {
525525
case PAGE:
526-
return channelJson.getObject(CONTENT)
526+
final String pageTitle = channelJson.getObject(CONTENT)
527527
.getObject(PAGE_HEADER_VIEW_MODEL)
528528
.getObject(TITLE)
529529
.getObject("dynamicTextViewModel")
530530
.getObject("text")
531531
.getString(CONTENT, channelJson.getString("pageTitle"));
532+
return Optional.ofNullable(pageTitle);
532533
case CAROUSEL:
533534
case INTERACTIVE_TABBED:
534535
return getTextFromObject(channelJson.getObject(TITLE));
535536
case C4_TABBED:
536537
default:
537-
return channelJson.getString(TITLE);
538+
return Optional.ofNullable(channelJson.getString(TITLE));
538539
}
539540
})
540541
// The channel name from a microformatDataRenderer may be different from the one

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

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObjectOrThrow;
66
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getUrlFromNavigationEndpoint;
77
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isGoogleURL;
8-
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
98
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
109

1110
import com.grack.nanojson.JsonArray;
@@ -67,14 +66,11 @@ public static List<MetaInfo> getMetaInfo(@Nonnull final JsonArray contents)
6766
private static MetaInfo getInfoPanelContent(@Nonnull final JsonObject infoPanelContentRenderer)
6867
throws ParsingException {
6968
final MetaInfo metaInfo = new MetaInfo();
70-
final StringBuilder sb = new StringBuilder();
71-
for (final Object paragraph : infoPanelContentRenderer.getArray("paragraphs")) {
72-
if (sb.length() != 0) {
73-
sb.append("<br>");
74-
}
75-
sb.append(getTextFromObject((JsonObject) paragraph));
76-
}
77-
metaInfo.setContent(new Description(sb.toString(), Description.HTML));
69+
final String description = infoPanelContentRenderer.getArray("paragraphs")
70+
.streamAsJsonObjects()
71+
.map(paragraph -> getTextFromObject(paragraph).orElse(""))
72+
.collect(Collectors.joining("<br>"));
73+
metaInfo.setContent(new Description(description, Description.HTML));
7874
if (infoPanelContentRenderer.has("sourceEndpoint")) {
7975
final String metaInfoLinkUrl = getUrlFromNavigationEndpoint(
8076
infoPanelContentRenderer.getObject("sourceEndpoint"));
@@ -86,10 +82,9 @@ private static MetaInfo getInfoPanelContent(@Nonnull final JsonObject infoPanelC
8682
}
8783

8884
final String metaInfoLinkText = getTextFromObject(
89-
infoPanelContentRenderer.getObject("inlineSource"));
90-
if (isNullOrEmpty(metaInfoLinkText)) {
91-
throw new ParsingException("Could not get metadata info link text.");
92-
}
85+
infoPanelContentRenderer.getObject("inlineSource"))
86+
.orElseThrow(() ->
87+
new ParsingException("Could not get metadata info link text."));
9388
metaInfo.addUrlText(metaInfoLinkText);
9489
}
9590

@@ -101,13 +96,12 @@ private static MetaInfo getClarificationRenderer(
10196
@Nonnull final JsonObject clarificationRenderer) throws ParsingException {
10297
final MetaInfo metaInfo = new MetaInfo();
10398

104-
final String title = getTextFromObject(clarificationRenderer
105-
.getObject("contentTitle"));
106-
final String text = getTextFromObject(clarificationRenderer
107-
.getObject("text"));
108-
if (title == null || text == null) {
109-
throw new ParsingException("Could not extract clarification renderer content");
110-
}
99+
final String title = getTextFromObject(clarificationRenderer.getObject("contentTitle"))
100+
.orElseThrow(() ->
101+
new ParsingException("Could not extract clarification renderer content"));
102+
final String text = getTextFromObject(clarificationRenderer.getObject("text"))
103+
.orElseThrow(() ->
104+
new ParsingException("Could not extract clarification renderer content"));
111105
metaInfo.setTitle(title);
112106
metaInfo.setContent(new Description(text, Description.PLAIN_TEXT));
113107

@@ -122,11 +116,9 @@ private static MetaInfo getClarificationRenderer(
122116
throw new ParsingException("Could not get metadata info URL", e);
123117
}
124118

125-
final String metaInfoLinkText = getTextFromObject(
126-
actionButton.getObject("text"));
127-
if (isNullOrEmpty(metaInfoLinkText)) {
128-
throw new ParsingException("Could not get metadata info link text.");
129-
}
119+
final String metaInfoLinkText = getTextFromObject(actionButton.getObject("text"))
120+
.orElseThrow(() ->
121+
new ParsingException("Could not get metadata info link text."));
130122
metaInfo.addUrlText(metaInfoLinkText);
131123
}
132124

@@ -138,9 +130,9 @@ private static MetaInfo getClarificationRenderer(
138130
if (url != null && !isGoogleURL(url)) {
139131
try {
140132
metaInfo.addUrl(new URL(url));
141-
final String description = getTextFromObject(clarificationRenderer
142-
.getObject("secondarySource"));
143-
metaInfo.addUrlText(description == null ? url : description);
133+
final String urlText = getTextFromObject(clarificationRenderer
134+
.getObject("secondarySource")).orElse(url);
135+
metaInfo.addUrlText(urlText);
144136
} catch (final MalformedURLException e) {
145137
throw new ParsingException("Could not get metadata info secondary URL", e);
146138
}

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

Lines changed: 62 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -776,125 +776,80 @@ public static String getUrlFromNavigationEndpoint(
776776
*
777777
* @param textObject JSON object to get the text from
778778
* @param html whether to return HTML, by parsing the {@code navigationEndpoint}
779-
* @return text in the JSON object or {@code null}
779+
* @return text in the JSON object as an {@link Optional}
780780
*/
781-
@Nullable
782-
public static String getTextFromObject(final JsonObject textObject, final boolean html) {
783-
if (isNullOrEmpty(textObject)) {
784-
return null;
785-
}
786-
787-
if (textObject.has("simpleText")) {
788-
return textObject.getString("simpleText");
789-
}
790-
791-
final JsonArray runs = textObject.getArray("runs");
792-
if (runs.isEmpty()) {
793-
return null;
794-
}
795-
796-
final StringBuilder textBuilder = new StringBuilder();
797-
for (final Object o : runs) {
798-
final JsonObject run = (JsonObject) o;
799-
String text = run.getString("text");
800-
801-
if (html) {
802-
if (run.has("navigationEndpoint")) {
803-
final String url = getUrlFromNavigationEndpoint(
804-
run.getObject("navigationEndpoint"));
805-
if (!isNullOrEmpty(url)) {
806-
text = "<a href=\"" + Entities.escape(url) + "\">" + Entities.escape(text)
807-
+ "</a>";
781+
@Nonnull
782+
public static Optional<String> getTextFromObject(@Nonnull final JsonObject textObject,
783+
final boolean html) {
784+
return Optional.ofNullable(textObject.getString("simpleText"))
785+
.or(() -> {
786+
final var runs = textObject.getArray("runs");
787+
final String text = runs.streamAsJsonObjects()
788+
.map(run -> {
789+
String textString = run.getString("text");
790+
791+
if (html) {
792+
final String url = getUrlFromNavigationEndpoint(
793+
run.getObject("navigationEndpoint"));
794+
if (!isNullOrEmpty(url)) {
795+
textString = "<a href=\"" + Entities.escape(url) + "\">"
796+
+ Entities.escape(textString) + "</a>";
797+
}
798+
799+
if (run.getBoolean("strikethrough")) {
800+
textString = "<s>" + textString + "</s>";
801+
}
802+
if (run.getBoolean("italics")) {
803+
textString = "<i>" + textString + "</i>";
804+
}
805+
if (run.getBoolean("bold")) {
806+
textString = "<b>" + textString + "</b>";
807+
}
808+
}
809+
810+
return textString;
811+
})
812+
.collect(Collectors.joining());
813+
814+
final String string;
815+
if (html) {
816+
string = text.replaceAll("\\n", "<br>")
817+
.replaceAll(" {2}", " &nbsp;");
818+
} else {
819+
string = text;
808820
}
809-
}
810-
811-
final boolean bold = run.has("bold")
812-
&& run.getBoolean("bold");
813-
final boolean italic = run.has("italics")
814-
&& run.getBoolean("italics");
815-
final boolean strikethrough = run.has("strikethrough")
816-
&& run.getBoolean("strikethrough");
817-
818-
if (bold) {
819-
textBuilder.append("<b>");
820-
}
821-
if (italic) {
822-
textBuilder.append("<i>");
823-
}
824-
if (strikethrough) {
825-
textBuilder.append("<s>");
826-
}
827-
828-
textBuilder.append(text);
829-
830-
if (strikethrough) {
831-
textBuilder.append("</s>");
832-
}
833-
if (italic) {
834-
textBuilder.append("</i>");
835-
}
836-
if (bold) {
837-
textBuilder.append("</b>");
838-
}
839-
} else {
840-
textBuilder.append(text);
841-
}
842-
}
843-
844-
String text = textBuilder.toString();
845-
846-
if (html) {
847-
text = text.replaceAll("\\n", "<br>");
848-
text = text.replaceAll(" {2}", " &nbsp;");
849-
}
850-
851-
return text;
821+
return Optional.of(string);
822+
})
823+
.filter(text -> !text.isEmpty());
852824
}
853825

854826
@Nonnull
855827
public static String getTextFromObjectOrThrow(final JsonObject textObject, final String error)
856828
throws ParsingException {
857-
final String result = getTextFromObject(textObject);
858-
if (result == null) {
859-
throw new ParsingException("Could not extract text: " + error);
860-
}
861-
return result;
829+
return getTextFromObject(textObject)
830+
.orElseThrow(() -> new ParsingException("Could not extract text: " + error));
862831
}
863832

864-
@Nullable
865-
public static String getTextFromObject(final JsonObject textObject) {
833+
@Nonnull
834+
public static Optional<String> getTextFromObject(@Nonnull final JsonObject textObject) {
866835
return getTextFromObject(textObject, false);
867836
}
868837

869-
@Nullable
870-
public static String getUrlFromObject(final JsonObject textObject) {
871-
if (isNullOrEmpty(textObject)) {
872-
return null;
873-
}
874-
875-
final JsonArray runs = textObject.getArray("runs");
876-
if (runs.isEmpty()) {
877-
return null;
878-
}
879-
880-
for (final Object textPart : runs) {
881-
final String url = getUrlFromNavigationEndpoint(((JsonObject) textPart)
882-
.getObject("navigationEndpoint"));
883-
if (!isNullOrEmpty(url)) {
884-
return url;
885-
}
886-
}
887-
888-
return null;
838+
@Nonnull
839+
public static Optional<String> getUrlFromObject(@Nonnull final JsonObject textObject) {
840+
return textObject.getArray("runs").streamAsJsonObjects()
841+
.map(textPart -> getUrlFromNavigationEndpoint(textPart
842+
.getObject("navigationEndpoint")))
843+
.filter(url -> !isNullOrEmpty(url))
844+
.findFirst();
889845
}
890846

891-
@Nullable
892-
public static String getTextAtKey(@Nonnull final JsonObject jsonObject, final String theKey) {
893-
if (jsonObject.isString(theKey)) {
894-
return jsonObject.getString(theKey);
895-
} else {
896-
return getTextFromObject(jsonObject.getObject(theKey));
897-
}
847+
@Nonnull
848+
public static Optional<String> getTextAtKey(@Nonnull final JsonObject jsonObject,
849+
final String theKey) {
850+
return Optional.ofNullable(jsonObject.getString(theKey))
851+
.filter(text -> !text.isEmpty())
852+
.or(() -> getTextFromObject(jsonObject.getObject(theKey)));
898853
}
899854

900855
public static String fixThumbnailUrl(@Nonnull final String thumbnailUrl) {
@@ -1222,7 +1177,8 @@ public static void defaultAlertsCheck(@Nonnull final JsonObject initialData)
12221177
final JsonArray alerts = initialData.getArray("alerts");
12231178
if (!isNullOrEmpty(alerts)) {
12241179
final JsonObject alertRenderer = alerts.getObject(0).getObject("alertRenderer");
1225-
final String alertText = getTextFromObject(alertRenderer.getObject("text"));
1180+
final String alertText = getTextFromObject(alertRenderer.getObject("text"))
1181+
.orElse(null);
12261182
final String alertType = alertRenderer.getString("type", "");
12271183
if (alertType.equalsIgnoreCase("ERROR")) {
12281184
if (alertText != null

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@ public long getStreamCount() throws ParsingException {
4949
final String streamCountText = getTextFromObject(
5050
showRenderer.getObject("thumbnailOverlays")
5151
.getObject("thumbnailOverlayBottomPanelRenderer")
52-
.getObject("text"));
53-
if (streamCountText == null) {
54-
throw new ParsingException("Could not get stream count");
55-
}
52+
.getObject("text"))
53+
.orElseThrow(() -> new ParsingException("Could not get stream count"));
5654

5755
try {
5856
// The data returned could be a human/shortened number, but no show with more than 1000

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public long getSubscriberCount() throws ParsingException {
257257

258258
if (textObject != null) {
259259
try {
260-
return Utils.mixedNumberWordToLong(getTextFromObject(textObject));
260+
return Utils.mixedNumberWordToLong(getTextFromObject(textObject).orElse(""));
261261
} catch (final NumberFormatException e) {
262262
throw new ParsingException("Could not get subscriber count", e);
263263
}
@@ -321,7 +321,8 @@ public String getDescription() throws ParsingException {
321321
The description extracted is incomplete and the original one can be only
322322
accessed from the About tab
323323
*/
324-
return getTextFromObject(channelHeader.json.getObject("description"));
324+
return getTextFromObject(channelHeader.json.getObject("description"))
325+
.orElse(null);
325326
}
326327

327328
return jsonResponse.getObject(METADATA)

0 commit comments

Comments
 (0)