Merge pull request #990 from FireMasterK/bold-italic-strikethrough

[YouTube] Implement bold/italic/strike-through support
This commit is contained in:
Kavin 2022-11-29 15:59:38 +00:00 committed by GitHub
commit abf08e1496
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1008 additions and 11 deletions

View File

@ -940,18 +940,50 @@ public final class YoutubeParsingHelper {
} }
final StringBuilder textBuilder = new StringBuilder(); final StringBuilder textBuilder = new StringBuilder();
for (final Object textPart : textObject.getArray("runs")) { for (final Object o : textObject.getArray("runs")) {
final String text = ((JsonObject) textPart).getString("text"); final JsonObject run = (JsonObject) o;
if (html && ((JsonObject) textPart).has("navigationEndpoint")) { String text = run.getString("text");
final String url = getUrlFromNavigationEndpoint(((JsonObject) textPart)
.getObject("navigationEndpoint")); if (html) {
if (!isNullOrEmpty(url)) { if (run.has("navigationEndpoint")) {
textBuilder.append("<a href=\"").append(url).append("\">").append(text) final String url = getUrlFromNavigationEndpoint(run
.append("</a>"); .getObject("navigationEndpoint"));
continue; if (!isNullOrEmpty(url)) {
text = "<a href=\"" + url + "\">" + text + "</a>";
}
} }
final boolean bold = run.has("bold")
&& run.getBoolean("bold");
final boolean italic = run.has("italics")
&& run.getBoolean("italics");
final boolean strikethrough = run.has("strikethrough")
&& run.getBoolean("strikethrough");
if (bold) {
textBuilder.append("<b>");
}
if (italic) {
textBuilder.append("<i>");
}
if (strikethrough) {
textBuilder.append("<s>");
}
textBuilder.append(text);
if (strikethrough) {
textBuilder.append("</s>");
}
if (italic) {
textBuilder.append("</i>");
}
if (bold) {
textBuilder.append("</b>");
}
} else {
textBuilder.append(text);
} }
textBuilder.append(text);
} }
String text = textBuilder.toString(); String text = textBuilder.toString();
@ -991,7 +1023,7 @@ public final class YoutubeParsingHelper {
final StringBuilder textBuilder = new StringBuilder(); final StringBuilder textBuilder = new StringBuilder();
int textStart = 0; int textStart = 0;
for (final Object commandRun: commandRuns) { for (final Object commandRun : commandRuns) {
if (!(commandRun instanceof JsonObject)) { if (!(commandRun instanceof JsonObject)) {
continue; continue;
} }

View File

@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertContains;
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertGreater; import static org.schabi.newpipe.extractor.ExtractorAsserts.assertGreater;
import static org.schabi.newpipe.extractor.ServiceList.YouTube; import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.comments.CommentsInfoItem.UNKNOWN_REPLY_COUNT; import static org.schabi.newpipe.extractor.comments.CommentsInfoItem.UNKNOWN_REPLY_COUNT;
@ -344,4 +345,32 @@ public class YoutubeCommentsExtractorTest {
assertGreater(300, firstComment.getReplyCount()); assertGreater(300, firstComment.getReplyCount());
} }
} }
public static class FormattingTest {
private final static String url = "https://www.youtube.com/watch?v=zYpyS2HaZHM";
private static YoutubeCommentsExtractor extractor;
@BeforeAll
public static void setUp() throws Exception {
YoutubeTestsUtils.ensureStateless();
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "formatting"));
extractor = (YoutubeCommentsExtractor) YouTube
.getCommentsExtractor(url);
extractor.fetchPage();
}
@Test
public void testGetCommentsFormatting() throws IOException, ExtractionException {
final InfoItemsPage<CommentsInfoItem> comments = extractor.getInitialPage();
DefaultTests.defaultTestListOfItems(YouTube, comments.getItems(), comments.getErrors());
final CommentsInfoItem firstComment = comments.getItems().get(0);
assertContains("<s>", firstComment.getCommentText());
assertContains("<b>", firstComment.getCommentText());
}
}
} }

View File

@ -0,0 +1,82 @@
{
"request": {
"httpMethod": "GET",
"url": "https://www.youtube.com/sw.js",
"headers": {
"Origin": [
"https://www.youtube.com"
],
"Referer": [
"https://www.youtube.com"
],
"Accept-Language": [
"en-GB, en;q\u003d0.9"
]
},
"localization": {
"languageCode": "en",
"countryCode": "GB"
}
},
"response": {
"responseCode": 200,
"responseMessage": "",
"responseHeaders": {
"access-control-allow-credentials": [
"true"
],
"access-control-allow-origin": [
"https://www.youtube.com"
],
"alt-svc": [
"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\""
],
"cache-control": [
"private, max-age\u003d0"
],
"content-type": [
"text/javascript; charset\u003dutf-8"
],
"cross-origin-opener-policy-report-only": [
"same-origin; report-to\u003d\"youtube_main\""
],
"date": [
"Mon, 28 Nov 2022 20:27:36 GMT"
],
"expires": [
"Mon, 28 Nov 2022 20:27:36 GMT"
],
"p3p": [
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
],
"permissions-policy": [
"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*"
],
"report-to": [
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
],
"server": [
"ESF"
],
"set-cookie": [
"YSC\u003ddaTQ98V-voQ; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dTue, 03-Mar-2020 20:27:36 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
"CONSENT\u003dPENDING+452; expires\u003dWed, 27-Nov-2024 20:27:36 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
],
"strict-transport-security": [
"max-age\u003d31536000"
],
"x-content-type-options": [
"nosniff"
],
"x-frame-options": [
"SAMEORIGIN"
],
"x-xss-protection": [
"0"
]
},
"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 ",
"latestUrl": "https://www.youtube.com/sw.js"
}
}