Intermediate results for refactoring :V

This commit is contained in:
Alessio 2022-01-30 17:48:03 -08:00
parent f0b1acd595
commit 4708ffc3c9
2 changed files with 371 additions and 30 deletions

View File

@ -27,7 +27,110 @@ func (u APIV2UserResult) ToUser() User {
return user return user
} }
type APIV2Result struct {
Result struct {
ID int64 `json:"rest_id,string"`
Legacy APIV2Tweet `json:"legacy"`
Tombstone *struct {
Text struct {
Text string `json:"text"`
} `json:"text"`
} `json:"tombstone"`
Core *APIV2UserResult `json:"core"`
QuotedStatusResult *APIV2Result `json:"quoted_status_result"`
} `json:"result"`
}
func (api_result APIV2Result) ToTweetTrove() TweetTrove {
ret := NewTweetTrove()
if api_result.Result.Core != nil {
main_user := api_result.Result.Core.ToUser()
ret.Users[main_user.ID] = main_user
} else {
// TODO
}
main_tweet_trove := api_result.Result.Legacy.ToTweetTrove()
ret.MergeWith(main_tweet_trove)
// Handle quoted tweet
if api_result.Result.QuotedStatusResult != nil {
quoted_api_result := api_result.Result.QuotedStatusResult
// Quoted tweets might be tombstones!
if quoted_api_result.Result.Tombstone != nil {
tombstoned_tweet := &quoted_api_result.Result.Legacy.APITweet
tombstoned_tweet.TombstoneText = quoted_api_result.Result.Tombstone.Text.Text
tombstoned_tweet.ID = int64(int_or_panic(api_result.Result.Legacy.APITweet.QuotedStatusIDStr))
handle, err := ParseHandleFromTweetUrl(api_result.Result.Legacy.APITweet.QuotedStatusPermalink.ExpandedURL)
if err != nil {
panic(err)
}
tombstoned_tweet.UserHandle = string(handle)
ret.TombstoneUsers = append(ret.TombstoneUsers, handle)
}
quoted_trove := api_result.Result.QuotedStatusResult.ToTweetTrove()
ret.MergeWith(quoted_trove)
}
return ret
}
type APIV2Tweet struct { type APIV2Tweet struct {
// For some reason, retweets are nested *inside* the Legacy tweet, whereas
// quoted-tweets are next to it, as their own tweet
RetweetedStatusResult *APIV2Result `json:"retweeted_status_result"`
APITweet
}
func (api_v2_tweet APIV2Tweet) ToTweetTrove() TweetTrove {
ret := NewTweetTrove()
// If there's a retweet, we ignore the main tweet except for posted_at and retweeting UserID
if api_v2_tweet.RetweetedStatusResult != nil {
orig_tweet_trove := api_v2_tweet.RetweetedStatusResult.ToTweetTrove()
ret.MergeWith(orig_tweet_trove)
retweet := Retweet{}
var err error
retweet.RetweetID = TweetID(api_v2_tweet.ID)
retweet.TweetID = TweetID(api_v2_tweet.RetweetedStatusResult.Result.ID)
retweet.RetweetedByID = UserID(api_v2_tweet.APITweet.UserID)
retweet.RetweetedAt, err = time.Parse(time.RubyDate, api_v2_tweet.APITweet.CreatedAt)
if err != nil {
fmt.Printf("%v\n", api_v2_tweet)
panic(err)
}
ret.Retweets[retweet.RetweetID] = retweet
} else {
main_tweet, err := ParseSingleTweet(api_v2_tweet.APITweet)
if err != nil {
panic(err)
}
ret.Tweets[main_tweet.ID] = main_tweet
}
return ret
}
type APIV2Response struct {
Data struct {
User struct {
Result struct {
Timeline struct {
Timeline struct {
Instructions []struct {
Type string `json:"type"`
Entries []struct {
EntryID string `json:"entryId"`
SortIndex int64 `json:"sortIndex,string"`
Content struct {
ItemContent struct {
EntryType string `json:"entryType"`
TweetResults struct {
Result struct {
Legacy struct {
APITweet APITweet
RetweetedStatusResult struct { RetweetedStatusResult struct {
Result struct { Result struct {
@ -57,25 +160,7 @@ type APIV2Tweet struct {
} `json:"quoted_status_result"` } `json:"quoted_status_result"`
} `json:"result"` } `json:"result"`
} `json:"retweeted_status_result"` } `json:"retweeted_status_result"`
} } `json:"legacy"`
type APIV2Response struct {
Data struct {
User struct {
Result struct {
Timeline struct {
Timeline struct {
Instructions []struct {
Type string `json:"type"`
Entries []struct {
EntryID string `json:"entryId"`
SortIndex int64 `json:"sortIndex,string"`
Content struct {
ItemContent struct {
EntryType string `json:"entryType"`
TweetResults struct {
Result struct {
Legacy APIV2Tweet `json:"legacy"`
Core struct { Core struct {
UserResults struct { UserResults struct {
Result struct { Result struct {
@ -87,7 +172,37 @@ type APIV2Response struct {
QuotedStatusResult struct { // Same as "Result" QuotedStatusResult struct { // Same as "Result"
Result struct { Result struct {
ID int64 `json:"rest_id,string"` ID int64 `json:"rest_id,string"`
Legacy APIV2Tweet `json:"legacy"` Legacy struct {
APITweet
RetweetedStatusResult struct {
Result struct {
ID int `json:"rest_id,string"`
Legacy APITweet `json:"legacy"`
Core struct {
UserResults struct {
Result struct {
ID int64 `json:"rest_id,string"`
Legacy APIUser `json:"legacy"`
} `json:"result"`
} `json:"user_results"`
} `json:"core"`
QuotedStatusResult struct {
Result struct {
ID int64 `json:"rest_id,string"`
Legacy APITweet `json:"legacy"`
Core struct {
UserResults struct {
Result struct {
ID int64 `json:"rest_id,string"`
Legacy APIUser `json:"legacy"`
} `json:"result"`
} `json:"user_results"`
} `json:"core"`
} `json:"result"`
} `json:"quoted_status_result"`
} `json:"result"`
} `json:"retweeted_status_result"`
} `json:"legacy"`
Core struct { Core struct {
UserResults struct { UserResults struct {
Result struct { Result struct {

View File

@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
/** /**
* Parse an APIV2User * Parse an APIV2User
*/ */
@ -46,6 +47,231 @@ func TestAPIV2ParseUser(t *testing.T) {
assert.Equal(user.PinnedTweetID, TweetID(1477347403023982596)) assert.Equal(user.PinnedTweetID, TweetID(1477347403023982596))
} }
/**
* Parse a plain text tweet
*/
func TestAPIV2ParseTweet(t *testing.T) {
data, err := ioutil.ReadFile("test_responses/api_v2/tweet_plaintext.json")
if err != nil {
panic(err)
}
assert := assert.New(t)
var tweet_result APIV2Result
err = json.Unmarshal(data, &tweet_result)
assert.NoError(err)
trove := tweet_result.ToTweetTrove()
assert.Equal(1, len(trove.Tweets))
tweet, ok := trove.Tweets[1485708879174508550]
assert.True(ok)
assert.Equal(tweet.ID, TweetID(1485708879174508550))
assert.Equal(tweet.UserID, UserID(44067298))
assert.Equal(tweet.Text, "If Boris Johnson is driven out of office, it wouldn't mark the first time the Tories had four PMs in a row\nThey had previously governed the UK for 13 years with 4 PMs, from 1951-1964")
assert.Equal(tweet.PostedAt.Unix(), int64(1643055574))
assert.Equal(tweet.QuotedTweetID, TweetID(0))
assert.Equal(tweet.InReplyToID, TweetID(0))
assert.Equal(tweet.NumLikes, 38)
assert.Equal(tweet.NumRetweets, 2)
assert.Equal(tweet.NumReplies, 2)
assert.Equal(tweet.NumQuoteTweets, 1)
assert.Equal(0, len(tweet.Images))
assert.Equal(0, len(tweet.Videos))
assert.Equal(0, len(tweet.Polls))
assert.Equal(0, len(tweet.Mentions))
assert.Equal(0, len(tweet.ReplyMentions))
assert.Equal(0, len(tweet.Hashtags))
assert.Equal(0, len(tweet.Polls))
assert.Equal("", tweet.TombstoneType)
assert.False(tweet.IsStub)
assert.Equal(1, len(trove.Users))
user, ok := trove.Users[44067298]
assert.True(ok)
assert.Equal(UserID(44067298), user.ID)
assert.Equal(UserHandle("michaelmalice"), user.Handle)
assert.Equal(0, len(trove.Retweets))
}
/**
* Parse a tweet with a quoted tweet
*/
func TestAPIV2ParseTweetWithQuotedTweet(t *testing.T) {
assert := assert.New(t)
data, err := ioutil.ReadFile("test_responses/api_v2/tweet_with_quoted_tweet.json")
if err != nil {
panic(err)
}
var tweet_result APIV2Result
err = json.Unmarshal(data, &tweet_result)
assert.NoError(err)
trove := tweet_result.ToTweetTrove()
// Should be 2 tweets: quote-tweet and quoted-tweet
assert.Equal(2, len(trove.Tweets))
quoted_tweet, ok := trove.Tweets[1485690069079846915]
assert.True(ok)
assert.Equal(TweetID(1485690069079846915), quoted_tweet.ID)
assert.Equal(UserID(892155218292617217), quoted_tweet.UserID)
assert.Equal("The Left hates the Right so much that they won't let them leave the Union. I don't get it.", quoted_tweet.Text)
assert.Equal(int64(1643051089), quoted_tweet.PostedAt.Unix())
assert.Equal(TweetID(1485689207435710464), quoted_tweet.InReplyToID)
assert.Equal(TweetID(0), quoted_tweet.QuotedTweetID)
assert.Equal(1, len(quoted_tweet.ReplyMentions))
assert.Contains(quoted_tweet.ReplyMentions, UserHandle("michaelmalice"))
assert.Equal(1, quoted_tweet.NumReplies)
assert.Equal(12, quoted_tweet.NumLikes)
quote_tweet, ok := trove.Tweets[1485690410899021826]
assert.True(ok)
assert.Equal(TweetID(1485690410899021826), quote_tweet.ID)
assert.Equal(TweetID(1485690069079846915), quote_tweet.QuotedTweetID)
assert.Equal("Hatred is powerless in and of itself despite all the agitprop to the contrary\nHatred didnt stop Trump's election, for example", quote_tweet.Text)
// Should be 2 users: quoter and quoted
assert.Equal(2, len(trove.Users))
user_quoting, ok := trove.Users[44067298]
assert.True(ok)
assert.Equal(UserHandle("michaelmalice"), user_quoting.Handle)
user_quoted, ok := trove.Users[892155218292617217]
assert.True(ok)
assert.Equal(UserHandle("baalzimon"), user_quoted.Handle)
// No retweets
assert.Equal(0, len(trove.Retweets))
}
/**
* Parse a retweet
*/
func TestAPIV2ParseRetweet(t *testing.T) {
assert := assert.New(t)
data, err := ioutil.ReadFile("test_responses/api_v2/retweet.json")
if err != nil {
panic(err)
}
var tweet_result APIV2Result
err = json.Unmarshal(data, &tweet_result)
assert.NoError(err)
trove := tweet_result.ToTweetTrove()
// Should only be 1 tweet, the retweeted one
assert.Equal(1, len(trove.Tweets))
tweet, ok := trove.Tweets[1485694028620316673]
assert.True(ok)
assert.Equal(TweetID(1485694028620316673), tweet.ID)
assert.Equal(UserID(1326229737551912960), tweet.UserID)
assert.Equal("More mask madness, this time in an elevator. The mask police are really nuts https://t.co/3BpvLjdJwD", tweet.Text)
assert.Equal(int64(1643052033), tweet.PostedAt.Unix())
assert.Equal(5373, tweet.NumLikes)
assert.Equal(TweetID(0), tweet.InReplyToID)
assert.Equal(1, len(tweet.Videos))
// Check the video
v := tweet.Videos[0]
assert.Equal("https://pbs.twimg.com/ext_tw_video_thumb/1485627274594590721/pu/img/O6mMKrsqWl8WcMy1.jpg", v.ThumbnailRemoteUrl)
assert.Equal(0, v.ViewCount) // TODO: make this work
assert.Equal(720, v.Height)
assert.Equal(720, v.Width)
assert.Equal(30066, v.Duration)
// Should fetch both the retweeting and retweeted users
assert.Equal(2, len(trove.Users))
retweeted_user, ok := trove.Users[1326229737551912960]
assert.True(ok)
assert.Equal(UserID(1326229737551912960), retweeted_user.ID)
assert.Equal(UserHandle("libsoftiktok"), retweeted_user.Handle)
retweeting_user, ok := trove.Users[44067298]
assert.True(ok)
assert.Equal(UserID(44067298), retweeting_user.ID)
assert.Equal(UserHandle("michaelmalice"), retweeting_user.Handle)
// Should be 1 retweet
assert.Equal(1, len(trove.Retweets))
retweet, ok := trove.Retweets[1485699748514476037]
assert.True(ok)
assert.Equal(TweetID(1485699748514476037), retweet.RetweetID)
assert.Equal(TweetID(1485694028620316673), retweet.TweetID)
assert.Equal(int64(1643053397), retweet.RetweetedAt.Unix())
assert.Equal(UserID(44067298), retweet.RetweetedByID)
}
/**
* Parse a retweeted quote tweet
*/
func TestAPIV2ParseRetweetedQuoteTweet(t *testing.T) {
assert := assert.New(t)
data, err := ioutil.ReadFile("test_responses/api_v2/retweet_with_quote_tweet.json")
if err != nil {
panic(err)
}
var tweet_result APIV2Result
err = json.Unmarshal(data, &tweet_result)
assert.NoError(err)
trove := tweet_result.ToTweetTrove()
// Quoted tweet and quoting tweet
assert.Equal(2, len(trove.Tweets))
quoted_tweet, ok := trove.Tweets[1484900469482962944]
assert.True(ok)
assert.Equal(TweetID(1484900469482962944), quoted_tweet.ID)
assert.Equal(UserID(14347972), quoted_tweet.UserID)
assert.Equal(TweetID(1484643409130397702), quoted_tweet.QuotedTweetID)
quoting_tweet, ok := trove.Tweets[1485272859102621697]
assert.True(ok)
assert.Equal(TweetID(1485272859102621697), quoting_tweet.ID)
assert.Equal(UserID(1434720042193760256), quoting_tweet.UserID)
assert.Equal(TweetID(1484900469482962944), quoting_tweet.QuotedTweetID)
assert.Equal(200, quoting_tweet.NumLikes)
// 3 Users: quoted, quoter, and retweeter
assert.Equal(3, len(trove.Users))
retweeting_user, ok := trove.Users[599817378]
assert.True(ok)
assert.Equal(UserID(599817378), retweeting_user.ID)
assert.Equal(UserHandle("ScottMGreer"), retweeting_user.Handle)
retweeted_user, ok := trove.Users[1434720042193760256]
assert.True(ok)
assert.Equal(UserID(1434720042193760256), retweeted_user.ID)
assert.Equal(UserHandle("LatinxPutler"), retweeted_user.Handle)
quoted_user, ok := trove.Users[14347972]
assert.True(ok)
assert.Equal(UserID(14347972), quoted_user.ID)
assert.Equal(UserHandle("Heminator"), quoted_user.Handle)
// Should be 1 retweet
assert.Equal(1, len(trove.Retweets))
retweet, ok := trove.Retweets[1485273090665984000]
assert.True(ok)
assert.Equal(TweetID(1485273090665984000), retweet.RetweetID)
assert.Equal(TweetID(1485272859102621697), retweet.TweetID)
assert.Equal(int64(1642951674), retweet.RetweetedAt.Unix())
assert.Equal(UserID(599817378), retweet.RetweetedByID)
}
// Check a plain old tweet // Check a plain old tweet
func TestAPIV2FeedSimpleTweet(t *testing.T) { func TestAPIV2FeedSimpleTweet(t *testing.T) {
data, err := ioutil.ReadFile("test_responses/api_v2/feed_simple_tweet.json") data, err := ioutil.ReadFile("test_responses/api_v2/feed_simple_tweet.json")