77import java .util .HashMap ;
88import java .util .List ;
99import java .util .Map ;
10- import java .util .Optional ;
1110
1211import org .schabi .newpipe .extractor .DownloadResponse ;
1312import org .schabi .newpipe .extractor .Downloader ;
2120import org .schabi .newpipe .extractor .exceptions .ParsingException ;
2221import org .schabi .newpipe .extractor .exceptions .ReCaptchaException ;
2322import org .schabi .newpipe .extractor .linkhandler .ListLinkHandler ;
23+ import org .schabi .newpipe .extractor .utils .JsonUtils ;
2424
25- import com .fasterxml .jackson .databind .JsonNode ;
26- import com .fasterxml .jackson .databind .ObjectMapper ;
25+ import com .grack .nanojson .JsonArray ;
26+ import com .grack .nanojson .JsonObject ;
27+ import com .grack .nanojson .JsonParser ;
28+ import com .grack .nanojson .JsonParserException ;
2729
2830public class YoutubeCommentsExtractor extends CommentsExtractor {
2931
@@ -34,8 +36,6 @@ public class YoutubeCommentsExtractor extends CommentsExtractor {
3436 private String title ;
3537 private InfoItemsPage <CommentsInfoItem > initPage ;
3638
37- private ObjectMapper mapper = new ObjectMapper ();
38-
3939 public YoutubeCommentsExtractor (StreamingService service , ListLinkHandler uiHandler ) {
4040 super (service , uiHandler );
4141 }
@@ -57,16 +57,24 @@ public String getNextPageUrl() throws IOException, ExtractionException {
5757 return initPage .getNextPageUrl ();
5858 }
5959
60- private String getNextPageUrl (JsonNode ajaxJson ) throws IOException , ExtractionException {
61- Optional <JsonNode > element = Optional .ofNullable (ajaxJson .findValue ("itemSectionContinuation" ))
62- .map (e -> e .get ("continuations" )).map (e -> e .findValue ("continuation" ));
63-
64- if (element .isPresent ()) {
65- return getNextPageUrl (element .get ().asText ());
66- } else {
67- // no more comments
60+ private String getNextPageUrl (JsonObject ajaxJson ) throws IOException , ParsingException {
61+
62+ JsonArray arr ;
63+ try {
64+ arr = JsonUtils .getValue (ajaxJson , "response.continuationContents.itemSectionContinuation.continuations" );
65+ } catch (ParsingException e ) {
66+ return "" ;
67+ }
68+ if (null == arr || arr .isEmpty ()) {
6869 return "" ;
6970 }
71+ String continuation ;
72+ try {
73+ continuation = JsonUtils .getValue (arr .getObject (0 ), "nextContinuationData.continuation" );
74+ } catch (ParsingException e ) {
75+ return "" ;
76+ }
77+ return getNextPageUrl (continuation );
7078 }
7179
7280 private String getNextPageUrl (String continuation ) throws ParsingException {
@@ -88,121 +96,35 @@ public InfoItemsPage<CommentsInfoItem> getPage(String pageUrl) throws IOExceptio
8896 throw new ExtractionException (new IllegalArgumentException ("Page url is empty or null" ));
8997 }
9098 String ajaxResponse = makeAjaxRequest (pageUrl );
91- JsonNode ajaxJson = mapper .readTree (ajaxResponse );
99+ JsonObject ajaxJson ;
100+ try {
101+ ajaxJson = JsonParser .object ().from (ajaxResponse );
102+ } catch (JsonParserException e ) {
103+ throw new ParsingException ("Could not parse json data for comments" , e );
104+ }
92105 CommentsInfoItemsCollector collector = new CommentsInfoItemsCollector (getServiceId ());
93106 collectCommentsFrom (collector , ajaxJson , pageUrl );
94107 return new InfoItemsPage <>(collector , getNextPageUrl (ajaxJson ));
95108 }
96109
97- private void collectCommentsFrom (CommentsInfoItemsCollector collector , JsonNode ajaxJson , String pageUrl ) {
110+ private void collectCommentsFrom (CommentsInfoItemsCollector collector , JsonObject ajaxJson , String pageUrl ) throws ParsingException {
98111
99- fetchTitle (ajaxJson );
100112
101- List <JsonNode > comments = ajaxJson .findValues ("commentRenderer" );
102- comments .stream ().forEach (c -> {
103- CommentsInfoItemExtractor extractor = new CommentsInfoItemExtractor () {
104-
105- @ Override
106- public String getUrl () throws ParsingException {
107- return pageUrl ;
108- }
109-
110- @ Override
111- public String getThumbnailUrl () throws ParsingException {
112- try {
113- return c .get ("authorThumbnail" ).get ("thumbnails" ).get (2 ).get ("url" ).asText ();
114- } catch (Exception e ) {
115- throw new ParsingException ("Could not get thumbnail url" , e );
116- }
117- }
118-
119- @ Override
120- public String getName () throws ParsingException {
121- try {
122- return c .get ("authorText" ).get ("simpleText" ).asText ();
123- } catch (Exception e ) {
124- throw new ParsingException ("Could not get author name" , e );
125- }
126- }
127-
128- @ Override
129- public String getPublishedTime () throws ParsingException {
130- try {
131- return c .get ("publishedTimeText" ).get ("runs" ).get (0 ).get ("text" ).asText ();
132- } catch (Exception e ) {
133- throw new ParsingException ("Could not get publishedTimeText" , e );
134- }
135- }
136-
137- @ Override
138- public Integer getLikeCount () throws ParsingException {
139- try {
140- return c .get ("likeCount" ).intValue ();
141- } catch (Exception e ) {
142- throw new ParsingException ("Could not get like count" , e );
143- }
144- }
145-
146- @ Override
147- public String getCommentText () throws ParsingException {
148- try {
149- if (null != c .get ("contentText" ).get ("simpleText" )) {
150- return c .get ("contentText" ).get ("simpleText" ).asText ();
151- } else {
152- return c .get ("contentText" ).get ("runs" ).get (0 ).get ("text" ).asText ();
153- }
154- } catch (Exception e ) {
155- throw new ParsingException ("Could not get comment text" , e );
156- }
157- }
158-
159- @ Override
160- public String getCommentId () throws ParsingException {
161- try {
162- return c .get ("commentId" ).asText ();
163- } catch (Exception e ) {
164- throw new ParsingException ("Could not get comment id" , e );
165- }
166- }
167-
168- @ Override
169- public String getAuthorThumbnail () throws ParsingException {
170- try {
171- return c .get ("authorThumbnail" ).get ("thumbnails" ).get (2 ).get ("url" ).asText ();
172- } catch (Exception e ) {
173- throw new ParsingException ("Could not get author thumbnail" , e );
174- }
175- }
176-
177- @ Override
178- public String getAuthorName () throws ParsingException {
179- try {
180- return c .get ("authorText" ).get ("simpleText" ).asText ();
181- } catch (Exception e ) {
182- throw new ParsingException ("Could not get author name" , e );
183- }
184- }
185-
186- @ Override
187- public String getAuthorEndpoint () throws ParsingException {
188- try {
189- return "https://youtube.com"
190- + c .get ("authorEndpoint" ).get ("browseEndpoint" ).get ("canonicalBaseUrl" ).asText ();
191- } catch (Exception e ) {
192- throw new ParsingException ("Could not get author endpoint" , e );
193- }
194- }
195- };
196-
113+ JsonArray contents = JsonUtils .getValue (ajaxJson , "response.continuationContents.itemSectionContinuation.contents" );
114+ fetchTitle (contents );
115+ List <JsonObject > comments = JsonUtils .getValues (contents , "commentThreadRenderer.comment.commentRenderer" );
116+
117+ for (JsonObject c : comments ) {
118+ CommentsInfoItemExtractor extractor = new YoutubeCommentsInfoItemExtractor (c , pageUrl );
197119 collector .commit (extractor );
198- });
120+ }
199121
200122 }
201123
202- private void fetchTitle (JsonNode ajaxJson ) {
124+ private void fetchTitle (JsonArray contents ) {
203125 if (null == title ) {
204126 try {
205- title = ajaxJson . findValue ( "commentTargetTitle" ). get ( " simpleText"). asText ( );
127+ title = JsonUtils . getValue ( contents . getObject ( 0 ), "commentThreadRenderer.commentTargetTitle. simpleText" );
206128 } catch (Exception e ) {
207129 title = "Youtube Comments" ;
208130 }
0 commit comments