Skip to content

Commit abf08e1

Browse files
authored
Merge pull request #990 from FireMasterK/bold-italic-strikethrough
[YouTube] Implement bold/italic/strike-through support
2 parents 72d5ed3 + 57e7a6f commit abf08e1

6 files changed

Lines changed: 1008 additions & 11 deletions

File tree

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -940,18 +940,50 @@ public static String getTextFromObject(final JsonObject textObject, final boolea
940940
}
941941

942942
final StringBuilder textBuilder = new StringBuilder();
943-
for (final Object textPart : textObject.getArray("runs")) {
944-
final String text = ((JsonObject) textPart).getString("text");
945-
if (html && ((JsonObject) textPart).has("navigationEndpoint")) {
946-
final String url = getUrlFromNavigationEndpoint(((JsonObject) textPart)
947-
.getObject("navigationEndpoint"));
948-
if (!isNullOrEmpty(url)) {
949-
textBuilder.append("<a href=\"").append(url).append("\">").append(text)
950-
.append("</a>");
951-
continue;
943+
for (final Object o : textObject.getArray("runs")) {
944+
final JsonObject run = (JsonObject) o;
945+
String text = run.getString("text");
946+
947+
if (html) {
948+
if (run.has("navigationEndpoint")) {
949+
final String url = getUrlFromNavigationEndpoint(run
950+
.getObject("navigationEndpoint"));
951+
if (!isNullOrEmpty(url)) {
952+
text = "<a href=\"" + url + "\">" + text + "</a>";
953+
}
954+
}
955+
956+
final boolean bold = run.has("bold")
957+
&& run.getBoolean("bold");
958+
final boolean italic = run.has("italics")
959+
&& run.getBoolean("italics");
960+
final boolean strikethrough = run.has("strikethrough")
961+
&& run.getBoolean("strikethrough");
962+
963+
if (bold) {
964+
textBuilder.append("<b>");
965+
}
966+
if (italic) {
967+
textBuilder.append("<i>");
968+
}
969+
if (strikethrough) {
970+
textBuilder.append("<s>");
971+
}
972+
973+
textBuilder.append(text);
974+
975+
if (strikethrough) {
976+
textBuilder.append("</s>");
977+
}
978+
if (italic) {
979+
textBuilder.append("</i>");
980+
}
981+
if (bold) {
982+
textBuilder.append("</b>");
952983
}
984+
} else {
985+
textBuilder.append(text);
953986
}
954-
textBuilder.append(text);
955987
}
956988

957989
String text = textBuilder.toString();
@@ -991,7 +1023,7 @@ public static String getAttributedDescription(
9911023
final StringBuilder textBuilder = new StringBuilder();
9921024
int textStart = 0;
9931025

994-
for (final Object commandRun: commandRuns) {
1026+
for (final Object commandRun : commandRuns) {
9951027
if (!(commandRun instanceof JsonObject)) {
9961028
continue;
9971029
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static org.junit.jupiter.api.Assertions.assertNotEquals;
66
import static org.junit.jupiter.api.Assertions.assertNotNull;
77
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertContains;
89
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertGreater;
910
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
1011
import static org.schabi.newpipe.extractor.comments.CommentsInfoItem.UNKNOWN_REPLY_COUNT;
@@ -344,4 +345,32 @@ public void testGetCommentsReplyCount() throws IOException, ExtractionException
344345
assertGreater(300, firstComment.getReplyCount());
345346
}
346347
}
348+
349+
public static class FormattingTest {
350+
351+
private final static String url = "https://www.youtube.com/watch?v=zYpyS2HaZHM";
352+
353+
private static YoutubeCommentsExtractor extractor;
354+
355+
@BeforeAll
356+
public static void setUp() throws Exception {
357+
YoutubeTestsUtils.ensureStateless();
358+
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "formatting"));
359+
extractor = (YoutubeCommentsExtractor) YouTube
360+
.getCommentsExtractor(url);
361+
extractor.fetchPage();
362+
}
363+
364+
@Test
365+
public void testGetCommentsFormatting() throws IOException, ExtractionException {
366+
final InfoItemsPage<CommentsInfoItem> comments = extractor.getInitialPage();
367+
368+
DefaultTests.defaultTestListOfItems(YouTube, comments.getItems(), comments.getErrors());
369+
370+
final CommentsInfoItem firstComment = comments.getItems().get(0);
371+
372+
assertContains("<s>", firstComment.getCommentText());
373+
assertContains("<b>", firstComment.getCommentText());
374+
}
375+
}
347376
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"request": {
3+
"httpMethod": "GET",
4+
"url": "https://www.youtube.com/sw.js",
5+
"headers": {
6+
"Origin": [
7+
"https://www.youtube.com"
8+
],
9+
"Referer": [
10+
"https://www.youtube.com"
11+
],
12+
"Accept-Language": [
13+
"en-GB, en;q\u003d0.9"
14+
]
15+
},
16+
"localization": {
17+
"languageCode": "en",
18+
"countryCode": "GB"
19+
}
20+
},
21+
"response": {
22+
"responseCode": 200,
23+
"responseMessage": "",
24+
"responseHeaders": {
25+
"access-control-allow-credentials": [
26+
"true"
27+
],
28+
"access-control-allow-origin": [
29+
"https://www.youtube.com"
30+
],
31+
"alt-svc": [
32+
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000,h3-Q050\u003d\":443\"; ma\u003d2592000,h3-Q046\u003d\":443\"; ma\u003d2592000,h3-Q043\u003d\":443\"; ma\u003d2592000,quic\u003d\":443\"; ma\u003d2592000; v\u003d\"46,43\""
33+
],
34+
"cache-control": [
35+
"private, max-age\u003d0"
36+
],
37+
"content-type": [
38+
"text/javascript; charset\u003dutf-8"
39+
],
40+
"cross-origin-opener-policy-report-only": [
41+
"same-origin; report-to\u003d\"youtube_main\""
42+
],
43+
"date": [
44+
"Mon, 28 Nov 2022 20:27:36 GMT"
45+
],
46+
"expires": [
47+
"Mon, 28 Nov 2022 20:27:36 GMT"
48+
],
49+
"p3p": [
50+
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
51+
],
52+
"permissions-policy": [
53+
"ch-ua-arch\u003d*, ch-ua-bitness\u003d*, ch-ua-full-version\u003d*, ch-ua-full-version-list\u003d*, ch-ua-model\u003d*, ch-ua-wow64\u003d*, ch-ua-platform\u003d*, ch-ua-platform-version\u003d*"
54+
],
55+
"report-to": [
56+
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
57+
],
58+
"server": [
59+
"ESF"
60+
],
61+
"set-cookie": [
62+
"YSC\u003ddaTQ98V-voQ; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
63+
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dTue, 03-Mar-2020 20:27:36 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
64+
"CONSENT\u003dPENDING+452; expires\u003dWed, 27-Nov-2024 20:27:36 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
65+
],
66+
"strict-transport-security": [
67+
"max-age\u003d31536000"
68+
],
69+
"x-content-type-options": [
70+
"nosniff"
71+
],
72+
"x-frame-options": [
73+
"SAMEORIGIN"
74+
],
75+
"x-xss-protection": [
76+
"0"
77+
]
78+
},
79+
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
80+
"latestUrl": "https://www.youtube.com/sw.js"
81+
}
82+
}

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/comments/formatting/generated_mock_1.json

Lines changed: 76 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)