From 0ffcb32d9c76396469e3a4606ca84b69c7858a6b Mon Sep 17 00:00:00 2001 From: xz-dev <32761048+xz-dev@users.noreply.github.com> Date: Sat, 15 Oct 2022 18:40:06 +0800 Subject: [PATCH] [YouTube] Add comment reply count support (#936) Add comment reply count support for YouTube and introduce `CommentsInfoItem.UNKNOWN_REPLY_COUNT` constant Co-authored-by: AudricV <74829229+AudricV@users.noreply.github.com> Co-authored-by: Tobi --- .../extractor/comments/CommentsInfoItem.java | 14 +++++++++++++- .../comments/CommentsInfoItemExtractor.java | 16 ++++++++++++++-- .../comments/CommentsInfoItemsCollector.java | 6 ++++++ .../YoutubeCommentsInfoItemExtractor.java | 10 ++++++++++ .../youtube/YoutubeCommentsExtractorTest.java | 15 +++++++++++++++ 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItem.java b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItem.java index 0f4cbbc2..2c1e0dac 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItem.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItem.java @@ -22,12 +22,15 @@ public class CommentsInfoItem extends InfoItem { private boolean heartedByUploader; private boolean pinned; private int streamPosition; + private int replyCount; @Nullable private Page replies; public static final int NO_LIKE_COUNT = -1; public static final int NO_STREAM_POSITION = -1; + public static final int UNKNOWN_REPLY_COUNT = -1; + public CommentsInfoItem(final int serviceId, final String url, final String name) { super(InfoType.COMMENT, serviceId, url, name); } @@ -91,7 +94,7 @@ public class CommentsInfoItem extends InfoItem { /** * @return the comment's like count - * or {@link CommentsInfoItem#NO_LIKE_COUNT} if it is unavailable + * or {@link CommentsInfoItem#NO_LIKE_COUNT} if it is unavailable */ public int getLikeCount() { return likeCount; @@ -140,12 +143,21 @@ public class CommentsInfoItem extends InfoItem { /** * Get the playback position of the stream to which this comment belongs. * This is not supported by all services. + * * @return the playback position in seconds or {@link #NO_STREAM_POSITION} if not available */ public int getStreamPosition() { return streamPosition; } + public void setReplyCount(final int replyCount) { + this.replyCount = replyCount; + } + + public int getReplyCount() { + return replyCount; + } + public void setReplies(@Nullable final Page replies) { this.replies = replies; } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemExtractor.java index 900167cf..128235fc 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemExtractor.java @@ -16,14 +16,14 @@ public interface CommentsInfoItemExtractor extends InfoItemExtractor { * or {@link CommentsInfoItem#NO_LIKE_COUNT} if it is unavailable. * *
- * + *

* NOTE: Currently only implemented for YT {@link * YoutubeCommentsInfoItemExtractor#getLikeCount()} * with limitations (only approximate like count is returned) * - * @see StreamExtractor#getLikeCount() * @return the comment's like count * or {@link CommentsInfoItem#NO_LIKE_COUNT} if it is unavailable + * @see StreamExtractor#getLikeCount() */ default int getLikeCount() throws ParsingException { return CommentsInfoItem.NO_LIKE_COUNT; @@ -103,14 +103,26 @@ public interface CommentsInfoItemExtractor extends InfoItemExtractor { /** * The playback position of the stream to which this comment belongs. + * * @see CommentsInfoItem#getStreamPosition() */ default int getStreamPosition() throws ParsingException { return CommentsInfoItem.NO_STREAM_POSITION; } + /** + * The count of comment replies. + * + * @return the count of the replies + * or {@link CommentsInfoItem#UNKNOWN_REPLY_COUNT} if replies are not supported + */ + default int getReplyCount() throws ParsingException { + return CommentsInfoItem.UNKNOWN_REPLY_COUNT; + } + /** * The continuation page which is used to get comment replies from. + * * @return the continuation Page for the replies, or null if replies are not supported */ @Nullable diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemsCollector.java b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemsCollector.java index 0a5388d0..3afeb045 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemsCollector.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/comments/CommentsInfoItemsCollector.java @@ -89,6 +89,12 @@ public final class CommentsInfoItemsCollector addError(e); } + try { + resultItem.setReplyCount(extractor.getReplyCount()); + } catch (final Exception e) { + addError(e); + } + try { resultItem.setReplies(extractor.getReplies()); } catch (final Exception e) { diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeCommentsInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeCommentsInfoItemExtractor.java index 5f8415ec..d24ef5bd 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeCommentsInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeCommentsInfoItemExtractor.java @@ -1,5 +1,6 @@ package org.schabi.newpipe.extractor.services.youtube.extractors; +import static org.schabi.newpipe.extractor.comments.CommentsInfoItem.UNKNOWN_REPLY_COUNT; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject; import com.grack.nanojson.JsonArray; @@ -248,6 +249,15 @@ public class YoutubeCommentsInfoItemExtractor implements CommentsInfoItemExtract } } + @Override + public int getReplyCount() throws ParsingException { + final JsonObject commentRenderer = getCommentRenderer(); + if (commentRenderer.has("replyCount")) { + return commentRenderer.getInt("replyCount"); + } + return UNKNOWN_REPLY_COUNT; + } + @Override public Page getReplies() throws ParsingException { try { diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeCommentsExtractorTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeCommentsExtractorTest.java index b0bb6447..24c34b1d 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeCommentsExtractorTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeCommentsExtractorTest.java @@ -2,9 +2,12 @@ package org.schabi.newpipe.extractor.services.youtube; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertGreater; import static org.schabi.newpipe.extractor.ServiceList.YouTube; +import static org.schabi.newpipe.extractor.comments.CommentsInfoItem.UNKNOWN_REPLY_COUNT; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -328,5 +331,17 @@ public class YoutubeCommentsExtractorTest { assertEquals("First", replies.getItems().get(0).getCommentText(), "First reply comment did not match"); } + + @Test + public void testGetCommentsReplyCount() throws IOException, ExtractionException { + final InfoItemsPage comments = extractor.getInitialPage(); + + DefaultTests.defaultTestListOfItems(YouTube, comments.getItems(), comments.getErrors()); + + final CommentsInfoItem firstComment = comments.getItems().get(0); + + assertNotEquals(UNKNOWN_REPLY_COUNT, firstComment.getReplyCount(), "Could not get the reply count of the first comment"); + assertGreater(300, firstComment.getReplyCount()); + } } }