@@ -2,6 +2,7 @@ package twitterscraper
22
33import (
44 "strconv"
5+ "strings"
56)
67
78type tweet struct {
@@ -74,12 +75,16 @@ func (result *userResult) parse() Profile {
7475}
7576
7677type item struct {
77- Item struct {
78+ EntryID string `json:"entryId"`
79+ Item struct {
7880 ItemContent struct {
81+ ItemType string `json:"itemType"`
7982 TweetDisplayType string `json:"tweetDisplayType"`
8083 TweetResults struct {
8184 Result result `json:"result"`
8285 } `json:"tweet_results"`
86+ CursorType string `json:"cursorType"`
87+ Value string `json:"value"`
8388 } `json:"itemContent"`
8489 } `json:"item"`
8590}
@@ -90,6 +95,7 @@ type entry struct {
9095 Value string `json:"value"`
9196 Items []item `json:"items"`
9297 ItemContent struct {
98+ ItemType string `json:"itemType"`
9399 TweetDisplayType string `json:"tweetDisplayType"`
94100 TweetResults struct {
95101 Result result `json:"result"`
@@ -98,6 +104,8 @@ type entry struct {
98104 UserResults struct {
99105 Result userResult `json:"result"`
100106 } `json:"user_results"`
107+ CursorType string `json:"cursorType"`
108+ Value string `json:"value"`
101109 } `json:"itemContent"`
102110 } `json:"content"`
103111}
@@ -221,16 +229,18 @@ type threadedConversation struct {
221229 Data struct {
222230 ThreadedConversationWithInjectionsV2 struct {
223231 Instructions []struct {
224- Type string `json:"type"`
225- Entries []entry `json:"entries"`
226- Entry entry `json:"entry"`
232+ Type string `json:"type"`
233+ Entry entry `json:"entry"`
234+ Entries []entry `json:"entries"`
235+ ModuleItems []item `json:"moduleItems"`
227236 } `json:"instructions"`
228237 } `json:"threaded_conversation_with_injections_v2"`
229238 } `json:"data"`
230239}
231240
232- func (conversation * threadedConversation ) parse () []* Tweet {
241+ func (conversation * threadedConversation ) parse (focalTweetID string ) ( []* Tweet , [] * ThreadCursor ) {
233242 var tweets []* Tweet
243+ var cursors []* ThreadCursor
234244 for _ , instruction := range conversation .Data .ThreadedConversationWithInjectionsV2 .Instructions {
235245 for _ , entry := range instruction .Entries {
236246 if entry .Content .ItemContent .TweetResults .Result .Typename == "Tweet" || entry .Content .ItemContent .TweetResults .Result .Typename == "TweetWithVisibilityResults" {
@@ -241,6 +251,16 @@ func (conversation *threadedConversation) parse() []*Tweet {
241251 tweets = append (tweets , tweet )
242252 }
243253 }
254+
255+ if entry .Content .ItemContent .CursorType != "" && entry .Content .ItemContent .Value != "" {
256+ cursors = append (cursors , & ThreadCursor {
257+ FocalTweetID : focalTweetID ,
258+ ThreadID : focalTweetID ,
259+ Cursor : entry .Content .ItemContent .Value ,
260+ CursorType : entry .Content .ItemContent .CursorType ,
261+ })
262+ }
263+
244264 for _ , item := range entry .Content .Items {
245265 if item .Item .ItemContent .TweetResults .Result .Typename == "Tweet" || item .Item .ItemContent .TweetResults .Result .Typename == "TweetWithVisibilityResults" {
246266 if tweet := item .Item .ItemContent .TweetResults .Result .parse (); tweet != nil {
@@ -250,9 +270,56 @@ func (conversation *threadedConversation) parse() []*Tweet {
250270 tweets = append (tweets , tweet )
251271 }
252272 }
273+
274+ if item .Item .ItemContent .CursorType != "" && item .Item .ItemContent .Value != "" {
275+ threadID := ""
276+
277+ entryId := strings .Split (item .EntryID , "-" )
278+ if len (entryId ) > 1 && entryId [0 ] == "conversationthread" {
279+ if i , _ := strconv .Atoi (entryId [1 ]); i != 0 {
280+ threadID = entryId [1 ]
281+ }
282+ }
283+
284+ cursors = append (cursors , & ThreadCursor {
285+ FocalTweetID : focalTweetID ,
286+ ThreadID : threadID ,
287+ Cursor : item .Item .ItemContent .Value ,
288+ CursorType : item .Item .ItemContent .CursorType ,
289+ })
290+ }
291+ }
292+ }
293+ for _ , item := range instruction .ModuleItems {
294+ if item .Item .ItemContent .TweetResults .Result .Typename == "Tweet" || item .Item .ItemContent .TweetResults .Result .Typename == "TweetWithVisibilityResults" {
295+ if tweet := item .Item .ItemContent .TweetResults .Result .parse (); tweet != nil {
296+ if item .Item .ItemContent .TweetDisplayType == "SelfThread" {
297+ tweet .IsSelfThread = true
298+ }
299+ tweets = append (tweets , tweet )
300+ }
301+ }
302+
303+ if item .Item .ItemContent .CursorType != "" && item .Item .ItemContent .Value != "" {
304+ threadID := ""
305+
306+ entryId := strings .Split (item .EntryID , "-" )
307+ if len (entryId ) > 1 && entryId [0 ] == "conversationthread" {
308+ if i , _ := strconv .Atoi (entryId [1 ]); i != 0 {
309+ threadID = entryId [1 ]
310+ }
311+ }
312+
313+ cursors = append (cursors , & ThreadCursor {
314+ FocalTweetID : focalTweetID ,
315+ ThreadID : threadID ,
316+ Cursor : item .Item .ItemContent .Value ,
317+ CursorType : item .Item .ItemContent .CursorType ,
318+ })
253319 }
254320 }
255321 }
322+
256323 for _ , tweet := range tweets {
257324 if tweet .InReplyToStatusID != "" {
258325 for _ , parentTweet := range tweets {
@@ -273,7 +340,7 @@ func (conversation *threadedConversation) parse() []*Tweet {
273340 }
274341 }
275342 }
276- return tweets
343+ return tweets , cursors
277344}
278345
279346type tweetResult struct {
0 commit comments