diff --git a/cmd/fetch_tweet_to_stdout/main.go b/cmd/fetch_tweet_to_stdout/main.go index 5a4b266..863e4f0 100644 --- a/cmd/fetch_tweet_to_stdout/main.go +++ b/cmd/fetch_tweet_to_stdout/main.go @@ -5,6 +5,7 @@ import ( "fmt" "offline_twitter/scraper" // "time" + "strconv" "log" "strings" ) @@ -15,12 +16,16 @@ const INCLUDE_REPLIES = true; func parse_tweet(url string) (scraper.TweetID, error) { parts := strings.Split(url, "/") if len(parts) != 6 { - return "", fmt.Errorf("Tweet format isn't right (%d)", len(parts)) + return 0, fmt.Errorf("Tweet format isn't right (%d)", len(parts)) } if parts[0] != "https:" || parts[1] != "" || parts[2] != "twitter.com" || parts[4] != "status" { - return "", fmt.Errorf("Tweet format isn't right") + return 0, fmt.Errorf("Tweet format isn't right") } - return scraper.TweetID(parts[5]), nil + id, err := strconv.Atoi(parts[5]) + if err != nil { + return 0, err + } + return scraper.TweetID(id), nil } func main() { diff --git a/cmd/twitter/helpers.go b/cmd/twitter/helpers.go index e2c339f..e63d5d2 100644 --- a/cmd/twitter/helpers.go +++ b/cmd/twitter/helpers.go @@ -6,6 +6,7 @@ import ( "offline_twitter/scraper" "offline_twitter/terminal_utils" "strings" + "strconv" ) @@ -51,10 +52,14 @@ func die(text string, display_help bool, exit_code int) { func extract_id_from(url string) (scraper.TweetID, error) { parts := strings.Split(url, "/") if len(parts) != 6 { - return "", fmt.Errorf("Tweet format isn't right (%d)", len(parts)) + return 0, fmt.Errorf("Tweet format isn't right (%d)", len(parts)) } if parts[0] != "https:" || parts[1] != "" || parts[2] != "twitter.com" || parts[4] != "status" { - return "", fmt.Errorf("Tweet format isn't right") + return 0, fmt.Errorf("Tweet format isn't right") } - return scraper.TweetID(parts[5]), nil + id, err := strconv.Atoi(parts[5]) + if err != nil { + return 0, err + } + return scraper.TweetID(id), nil } diff --git a/persistence/media_download_test.go b/persistence/media_download_test.go index 77d2c79..3a0e73d 100644 --- a/persistence/media_download_test.go +++ b/persistence/media_download_test.go @@ -6,24 +6,11 @@ import ( "offline_twitter/scraper" ) -/** - * Should return the base name (filename) of the remote URL - */ -func TestImageFilenameWhenDownloaded(t *testing.T) { - i := scraper.Image{IsDownloaded: false, Filename: "https://pbs.twimg.com/media/E7vG1kxWQAQrWGF.jpg"} - outpath := i.FilenameWhenDownloaded() - expected := "E7vG1kxWQAQrWGF.jpg" - if outpath != expected { - t.Errorf("Expected output path to be %q, but got %q", expected, outpath) - } -} - - /** * Should return an `.mp4`file matching its parent Tweet's ID */ func TestVideoFilenameWhenDownloaded(t *testing.T) { - v := scraper.Video{TweetID: scraper.TweetID("23"), IsDownloaded: false, Filename: "https://video.twimg.com/ext_tw_video/1418951950020845568/pu/vid/320x568/IXaQ5rPyf9mbD1aD.mp4?tag=12"} + v := scraper.Video{TweetID: scraper.TweetID(23), IsDownloaded: false, Filename: "https://video.twimg.com/ext_tw_video/1418951950020845568/pu/vid/320x568/IXaQ5rPyf9mbD1aD.mp4?tag=12"} outpath := v.FilenameWhenDownloaded() expected := "23.mp4" if outpath != expected { diff --git a/persistence/tweet_queries.go b/persistence/tweet_queries.go index 886feb9..0f68e60 100644 --- a/persistence/tweet_queries.go +++ b/persistence/tweet_queries.go @@ -120,10 +120,9 @@ func (p Profile) GetTweetById(id scraper.TweetID) (scraper.Tweet, error) { var postedAt int var mentions string var hashtags string - var tweet_id int64 row := stmt.QueryRow(id) - err = row.Scan(&tweet_id, &t.UserID, &t.Text, &postedAt, &t.NumLikes, &t.NumRetweets, &t.NumReplies, &t.NumQuoteTweets, &t.InReplyTo, &t.QuotedTweet, &mentions, &hashtags) + err = row.Scan(&t.ID, &t.UserID, &t.Text, &postedAt, &t.NumLikes, &t.NumRetweets, &t.NumReplies, &t.NumQuoteTweets, &t.InReplyTo, &t.QuotedTweet, &mentions, &hashtags) if err != nil { return t, err } @@ -133,7 +132,6 @@ func (p Profile) GetTweetById(id scraper.TweetID) (scraper.Tweet, error) { t.Mentions = append(t.Mentions, scraper.UserHandle(m)) } t.Hashtags = strings.Split(hashtags, ",") - t.ID = scraper.TweetID(fmt.Sprint(tweet_id)) imgs, err := p.GetImagesForTweet(t) if err != nil { diff --git a/persistence/tweet_queries_test.go b/persistence/tweet_queries_test.go index 0eadcaa..0c13b2f 100644 --- a/persistence/tweet_queries_test.go +++ b/persistence/tweet_queries_test.go @@ -48,7 +48,7 @@ func TestIsTweetInDatabase(t *testing.T) { exists := profile.IsTweetInDatabase(tweet.ID) if exists { - t.Errorf("It shouldn't exist, but it does: %s", tweet.ID) + t.Errorf("It shouldn't exist, but it does: %d", tweet.ID) } err := profile.SaveTweet(tweet) if err != nil { @@ -56,7 +56,7 @@ func TestIsTweetInDatabase(t *testing.T) { } exists = profile.IsTweetInDatabase(tweet.ID) if !exists { - t.Errorf("It should exist, but it doesn't: %s", tweet.ID) + t.Errorf("It should exist, but it doesn't: %d", tweet.ID) } } diff --git a/persistence/user_queries.go b/persistence/user_queries.go index d3f4708..0dec7a6 100644 --- a/persistence/user_queries.go +++ b/persistence/user_queries.go @@ -81,15 +81,13 @@ func (p Profile) UserExists(handle scraper.UserHandle) bool { func parse_user_from_row(row *sql.Row) (scraper.User, error) { var u scraper.User var joinDate int64 - var pinned_tweet_id int64 - err := row.Scan(&u.ID, &u.DisplayName, &u.Handle, &u.Bio, &u.FollowingCount, &u.FollowersCount, &u.Location, &u.Website, &joinDate, &u.IsPrivate, &u.IsVerified, &u.ProfileImageUrl, &u.BannerImageUrl, &pinned_tweet_id) + err := row.Scan(&u.ID, &u.DisplayName, &u.Handle, &u.Bio, &u.FollowingCount, &u.FollowersCount, &u.Location, &u.Website, &joinDate, &u.IsPrivate, &u.IsVerified, &u.ProfileImageUrl, &u.BannerImageUrl, &u.PinnedTweetID) if err != nil { return u, err } u.JoinDate = time.Unix(joinDate, 0) - u.PinnedTweetID = scraper.TweetID(fmt.Sprint(pinned_tweet_id)) return u, nil } diff --git a/persistence/utils_test.go b/persistence/utils_test.go index bc8e44e..04a25dd 100644 --- a/persistence/utils_test.go +++ b/persistence/utils_test.go @@ -54,7 +54,7 @@ func create_stable_user() scraper.User { IsPrivate: false, ProfileImageUrl: "stable profile image url", BannerImageUrl: "stable banner image url", - PinnedTweetID: scraper.TweetID("345"), + PinnedTweetID: scraper.TweetID(345), } } @@ -65,7 +65,7 @@ func create_image_from_id(id int) scraper.Image { filename := fmt.Sprintf("image%d.jpg", id) return scraper.Image{ ID: scraper.ImageID(id), - TweetID: "-1", + TweetID: -1, Filename: filename, IsDownloaded: false, } @@ -75,7 +75,7 @@ func create_image_from_id(id int) scraper.Image { * Create a stable tweet with a fixed ID and content */ func create_stable_tweet() scraper.Tweet { - tweet_id := scraper.TweetID("-1") + tweet_id := scraper.TweetID(-1) return scraper.Tweet{ ID: tweet_id, UserID: -1, @@ -117,7 +117,7 @@ func create_dummy_user() scraper.User { IsPrivate: true, ProfileImageUrl: "profile image url", BannerImageUrl: "banner image url", - PinnedTweetID: scraper.TweetID("234"), + PinnedTweetID: scraper.TweetID(234), } } @@ -127,7 +127,7 @@ func create_dummy_user() scraper.User { */ func create_dummy_tweet() scraper.Tweet { rand.Seed(time.Now().UnixNano()) - tweet_id := scraper.TweetID(fmt.Sprint(rand.Int())) + tweet_id := scraper.TweetID(rand.Int()) img1 := create_image_from_id(rand.Int()) img1.TweetID = tweet_id @@ -143,7 +143,7 @@ func create_dummy_tweet() scraper.Tweet { NumRetweets: 2, NumReplies: 3, NumQuoteTweets: 4, - Videos: []scraper.Video{scraper.Video{TweetID: tweet_id, Filename: "video" + string(tweet_id), IsDownloaded: false}}, + Videos: []scraper.Video{scraper.Video{TweetID: tweet_id, Filename: "video" + fmt.Sprint(tweet_id), IsDownloaded: false}}, Urls: []string{"url1", "url2"}, Images: []scraper.Image{img1, img2}, Mentions: []scraper.UserHandle{"mention1", "mention2"}, diff --git a/scraper/api_request_utils.go b/scraper/api_request_utils.go index fdb00b4..c91cd07 100644 --- a/scraper/api_request_utils.go +++ b/scraper/api_request_utils.go @@ -77,7 +77,7 @@ func (api API) GetMoreTweets(user_id UserID, response *TweetResponse, max_tweets func (api API) GetTweet(id TweetID, cursor string) (TweetResponse, error) { client := &http.Client{Timeout: 10 * time.Second} - req, err := http.NewRequest("GET", fmt.Sprintf("%s%s.json", API_CONVERSATION_BASE_PATH, id), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("%s%d.json", API_CONVERSATION_BASE_PATH, id), nil) if err != nil { return TweetResponse{}, err } diff --git a/scraper/api_types.go b/scraper/api_types.go index 977fd7b..e41b93c 100644 --- a/scraper/api_types.go +++ b/scraper/api_types.go @@ -4,6 +4,7 @@ import ( "time" "strings" "encoding/json" + "strconv" ) type SortableVariants []struct { @@ -22,8 +23,8 @@ type APIMedia struct { } type APITweet struct { - ID string `json:"id_str"` - ConversationIDStr string `json:"conversation_id_str"` + ID int64 `json:"id_str,string"` + ConversationID int64 `json:"conversation_id_str,string"` CreatedAt string `json:"created_at"` FavoriteCount int `json:"favorite_count"` FullText string `json:"full_text"` @@ -51,13 +52,15 @@ type APITweet struct { } `json:"video_info"` } `json:"media"` } `json:"extended_entities"` - InReplyToStatusIDStr string `json:"in_reply_to_status_id_str"` + InReplyToStatusID int64 `json:"in_reply_to_status_id_str,string"` InReplyToScreenName string `json:"in_reply_to_screen_name"` ReplyCount int `json:"reply_count"` RetweetCount int `json:"retweet_count"` QuoteCount int `json:"quote_count"` - RetweetedStatusIDStr string `json:"retweeted_status_id_str"` - QuotedStatusIDStr string `json:"quoted_status_id_str"` + RetweetedStatusIDStr string `json:"retweeted_status_id_str"` // Can be empty string + RetweetedStatusID int64 + QuotedStatusIDStr string `json:"quoted_status_id_str"` // Can be empty string + QuotedStatusID int64 Time time.Time `json:"time"` UserID int64 `json:"user_id_str,string"` } @@ -83,6 +86,15 @@ func (t *APITweet) NormalizeContent() { } } t.FullText = strings.TrimSpace(t.FullText) + + id, err := strconv.Atoi(t.QuotedStatusIDStr) + if err == nil { + t.QuotedStatusID = int64(id) + } + id, err = strconv.Atoi(t.RetweetedStatusIDStr) + if err == nil { + t.RetweetedStatusID = int64(id) + } } func (t APITweet) String() string { @@ -166,3 +178,12 @@ func (t *TweetResponse) GetCursor() string { } return "" } + + +func idstr_to_int(idstr string) int64 { + id, err := strconv.Atoi(idstr) + if err != nil { + panic(err) + } + return int64(id) +} diff --git a/scraper/api_types_test.go b/scraper/api_types_test.go index 1ed2120..8823dec 100644 --- a/scraper/api_types_test.go +++ b/scraper/api_types_test.go @@ -13,11 +13,16 @@ func TestNormalizeContent(t *testing.T) { test_cases := []struct { filename string eventual_full_text string + quoted_status_id scraper.TweetID + in_reply_to scraper.TweetID + retweeted_status_id scraper.TweetID } { - {"test_responses/tweet_with_gif_reply.json", ""}, - {"test_responses/tweet_with_image.json", "this saddens me every time"}, - {"test_responses/tweet_with_reply.json", "I always liked \"The Anarchist's Cookbook.\""}, - {"test_responses/tweet_with_4_images.json", "These are public health officials who are making decisions about your lifestyle because they know more about health, fitness and well-being than you do"}, + {"test_responses/tweet_with_gif_reply.json", "", 0, 1395882872729477131, 0}, + {"test_responses/tweet_with_image.json", "this saddens me every time", 0, 0, 0}, + {"test_responses/tweet_with_reply.json", "I always liked \"The Anarchist's Cookbook.\"", 0, 1395978577267593218, 0}, + {"test_responses/tweet_with_4_images.json", "These are public health officials who are making decisions about your lifestyle because they know more about health, fitness and well-being than you do", 0, 0, 0}, + {"test_responses/tweet_with_quoted_tweet.json", "", 1422680899670274048, 0, 0}, + {"test_responses/tweet_that_is_a_retweet.json", "RT @nofunin10ded: @michaelmalice We're dealing with people who will napalm your children and then laugh about it", 0, 0, 1404269989646028804}, } for _, v := range test_cases { data, err := ioutil.ReadFile(v.filename) @@ -35,6 +40,15 @@ func TestNormalizeContent(t *testing.T) { if tweet.FullText != v.eventual_full_text { t.Errorf("Expected %q, got %q", v.eventual_full_text, tweet.FullText) } + if scraper.TweetID(tweet.QuotedStatusID) != v.quoted_status_id { + t.Errorf("Expected quoted status %d, but got %d", v.quoted_status_id, tweet.QuotedStatusID) + } + if scraper.TweetID(tweet.InReplyToStatusID) != v.in_reply_to { + t.Errorf("Expected quoted status %d, but got %d", v.in_reply_to, tweet.InReplyToStatusID) + } + if scraper.TweetID(tweet.RetweetedStatusID) != v.retweeted_status_id { + t.Errorf("Expected quoted status %d, but got %d", v.retweeted_status_id, tweet.RetweetedStatusID) + } } } diff --git a/scraper/retweet.go b/scraper/retweet.go index 0c1771d..91e0a4d 100644 --- a/scraper/retweet.go +++ b/scraper/retweet.go @@ -14,8 +14,10 @@ type Retweet struct { } func ParseSingleRetweet(apiTweet APITweet) (ret Retweet, err error) { + apiTweet.NormalizeContent() + ret.RetweetID = TweetID(apiTweet.ID) - ret.TweetID = TweetID(apiTweet.RetweetedStatusIDStr) + ret.TweetID = TweetID(apiTweet.RetweetedStatusID) ret.RetweetedByID = UserID(apiTweet.UserID) ret.RetweetedAt, err = time.Parse(time.RubyDate, apiTweet.CreatedAt) return diff --git a/scraper/retweet_test.go b/scraper/retweet_test.go index f6718e8..616b576 100644 --- a/scraper/retweet_test.go +++ b/scraper/retweet_test.go @@ -23,14 +23,15 @@ func TestParseSingleRetweet(t *testing.T) { if err != nil { t.Errorf(err.Error()) } - - if retweet.RetweetID != "1404270043018448896" { - t.Errorf("Expected %q, got %q", "1404270043018448896", retweet.RetweetID) + expected_id := 1404270043018448896 + if retweet.RetweetID != scraper.TweetID(1404270043018448896) { + t.Errorf("Expected %d, got %d", expected_id, retweet.RetweetID) } - if retweet.TweetID != "1404269989646028804" { - t.Errorf("Expected %q, got %q", "1404269989646028804", retweet.TweetID) + expected_id = 1404269989646028804 + if retweet.TweetID != scraper.TweetID(expected_id) { + t.Errorf("Expected %d, got %d", expected_id, retweet.TweetID) } - expected_id := 44067298 + expected_id = 44067298 if retweet.RetweetedByID != scraper.UserID(expected_id) { t.Errorf("Expected %d, got %d", expected_id, retweet.RetweetedByID) } diff --git a/scraper/test_responses/tweet_that_is_a_retweet.json b/scraper/test_responses/tweet_that_is_a_retweet.json index 2d4e187..bb03cb5 100644 --- a/scraper/test_responses/tweet_that_is_a_retweet.json +++ b/scraper/test_responses/tweet_that_is_a_retweet.json @@ -1,34 +1 @@ -{ - "created_at": "Mon Jun 14 02:50:42 +0000 2021", - "id_str": "1404270043018448896", - "text": "RT @nofunin10ded: @michaelmalice We're dealing with people who will napalm your children and then laugh about it", - "entities": { - "user_mentions": [ - { - "screen_name": "nofunin10ded", - "name": "Adam", - "id_str": "1265866918835236865", - "indices": [ - 3, - 16 - ] - }, - { - "screen_name": "michaelmalice", - "name": "Michael Malice", - "id_str": "44067298", - "indices": [ - 18, - 32 - ] - } - ] - }, - "source": "Twitter Web App", - "user_id_str": "44067298", - "retweeted_status_id_str": "1404269989646028804", - "retweet_count": 17, - "favorite_count": 0, - "conversation_id_str": "1404270043018448896", - "lang": "en" -} +{"created_at":"Mon Jun 14 02:50:42 +0000 2021","id_str":"1404270043018448896","full_text":"RT @nofunin10ded: @michaelmalice We're dealing with people who will napalm your children and then laugh about it","display_text_range":[0,112],"entities":{"user_mentions":[{"screen_name":"nofunin10ded","name":"Adam","id_str":"1265866918835236865","indices":[3,16]},{"screen_name":"michaelmalice","name":"Michael Malice","id_str":"44067298","indices":[18,32]}]},"source":"Twitter Web App","user_id_str":"44067298","retweeted_status_id_str":"1404269989646028804","retweet_count":26,"favorite_count":0,"reply_count":0,"quote_count":0,"conversation_id_str":"1404270043018448896","lang":"en"} diff --git a/scraper/test_responses/tweet_with_quoted_tweet.json b/scraper/test_responses/tweet_with_quoted_tweet.json new file mode 100644 index 0000000..2de374d --- /dev/null +++ b/scraper/test_responses/tweet_with_quoted_tweet.json @@ -0,0 +1 @@ +{"created_at":"Tue Aug 03 23:56:40 +0000 2021","id_str":"1422708023768793091","full_text":"https://t.co/8FaOybk9Zz","display_text_range":[0,0],"entities":{"media":[{"id_str":"1422708017481531394","indices":[0,23],"media_url":"http://pbs.twimg.com/media/E755Z3EWQAIZ0Bf.jpg","media_url_https":"https://pbs.twimg.com/media/E755Z3EWQAIZ0Bf.jpg","url":"https://t.co/8FaOybk9Zz","display_url":"pic.twitter.com/8FaOybk9Zz","expanded_url":"https://twitter.com/michaelmalice/status/1422708023768793091/photo/1","type":"photo","original_info":{"width":2048,"height":1152,"focus_rects":[{"x":0,"y":0,"h":1147,"w":2048},{"x":499,"y":0,"h":1152,"w":1152},{"x":570,"y":0,"h":1152,"w":1011},{"x":787,"y":0,"h":1152,"w":576},{"x":0,"y":0,"h":1152,"w":2048}]},"sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"},"small":{"w":680,"h":383,"resize":"fit"}}}]},"extended_entities":{"media":[{"id_str":"1422708017481531394","indices":[0,23],"media_url":"http://pbs.twimg.com/media/E755Z3EWQAIZ0Bf.jpg","media_url_https":"https://pbs.twimg.com/media/E755Z3EWQAIZ0Bf.jpg","url":"https://t.co/8FaOybk9Zz","display_url":"pic.twitter.com/8FaOybk9Zz","expanded_url":"https://twitter.com/michaelmalice/status/1422708023768793091/photo/1","type":"photo","original_info":{"width":2048,"height":1152,"focus_rects":[{"x":0,"y":0,"h":1147,"w":2048},{"x":499,"y":0,"h":1152,"w":1152},{"x":570,"y":0,"h":1152,"w":1011},{"x":787,"y":0,"h":1152,"w":576},{"x":0,"y":0,"h":1152,"w":2048}]},"sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":1200,"h":675,"resize":"fit"},"large":{"w":2048,"h":1152,"resize":"fit"},"small":{"w":680,"h":383,"resize":"fit"}},"media_key":"3_1422708017481531394","ext_alt_text":null,"ext_media_availability":{"status":"available"},"ext_media_color":{"palette":[{"rgb":{"red":4,"green":0,"blue":0},"percentage":93.11},{"rgb":{"red":85,"green":61,"blue":32},"percentage":2.51},{"rgb":{"red":157,"green":151,"blue":143},"percentage":2.12},{"rgb":{"red":31,"green":33,"blue":45},"percentage":0.68},{"rgb":{"red":79,"green":33,"blue":11},"percentage":0.21}]},"ext":{"mediaStats":{"r":"Missing","ttl":-1}}}]},"source":"Twitter Web App","user_id_str":"44067298","is_quote_status":true,"quoted_status_id_str":"1422680899670274048","quoted_status_permalink":{"url":"https://t.co/6qm3rFL9V0","expanded":"https://twitter.com/steffdaz/status/1422680899670274048","display":"twitter.com/steffdaz/statu…"},"retweet_count":24,"favorite_count":352,"reply_count":9,"quote_count":1,"conversation_id_str":"1422708023768793091","possibly_sensitive_editable":true,"lang":"und"} diff --git a/scraper/tweet.go b/scraper/tweet.go index 91ad2c4..ecfac39 100644 --- a/scraper/tweet.go +++ b/scraper/tweet.go @@ -10,7 +10,7 @@ import ( const DEFAULT_MAX_REPLIES_EAGER_LOAD = 50 -type TweetID string +type TweetID int64 type Tweet struct { ID TweetID @@ -86,7 +86,7 @@ func ParseSingleTweet(apiTweet APITweet) (ret Tweet, err error) { ret.NumRetweets = apiTweet.RetweetCount ret.NumReplies = apiTweet.ReplyCount ret.NumQuoteTweets = apiTweet.QuoteCount - ret.InReplyTo = TweetID(apiTweet.InReplyToStatusIDStr) + ret.InReplyTo = TweetID(apiTweet.InReplyToStatusID) for _, url := range apiTweet.Entities.URLs { ret.Urls = append(ret.Urls, url.ExpandedURL) @@ -107,7 +107,7 @@ func ParseSingleTweet(apiTweet APITweet) (ret Tweet, err error) { ret.Mentions = append(ret.Mentions, UserHandle(mention.UserName)) } - ret.QuotedTweet = TweetID(apiTweet.QuotedStatusIDStr) + ret.QuotedTweet = TweetID(apiTweet.QuotedStatusID) for _, entity := range apiTweet.ExtendedEntities.Media { if entity.Type != "video" { @@ -133,7 +133,7 @@ func GetTweet(id TweetID) (Tweet, error) { return Tweet{}, fmt.Errorf("Error in API call: %s", err) } - single_tweet, ok := tweet_response.GlobalObjects.Tweets[string(id)] + single_tweet, ok := tweet_response.GlobalObjects.Tweets[fmt.Sprint(id)] if !ok { return Tweet{}, fmt.Errorf("Didn't get the tweet!\n%v", tweet_response) diff --git a/scraper/tweet_test.go b/scraper/tweet_test.go index af9278a..f7bdf5e 100644 --- a/scraper/tweet_test.go +++ b/scraper/tweet_test.go @@ -1,6 +1,7 @@ package scraper_test import ( + "fmt" "encoding/json" "io/ioutil" "testing" @@ -112,15 +113,15 @@ func TestParseSingleTweet2(t *testing.T) { if tweet2.InReplyTo != tweet1.ID { t.Errorf("Expected %q, got %q", tweet1.ID, tweet2.InReplyTo) } - if tweet1.QuotedTweet != "" { + if tweet1.QuotedTweet != 0 { t.Errorf("Incorrectly believes it quote-tweets %q", tweet1.QuotedTweet) } - if tweet2.QuotedTweet == "" { + if tweet2.QuotedTweet == 0 { t.Errorf("Should be a quoted tweet") } - quoted_tweet_, ok := tweets[string(tweet2.QuotedTweet)] + quoted_tweet_, ok := tweets[fmt.Sprint(tweet2.QuotedTweet)] if !ok { t.Errorf("Couldn't find the quoted tweet") } diff --git a/scraper/user.go b/scraper/user.go index 863a8ff..a31b988 100644 --- a/scraper/user.go +++ b/scraper/user.go @@ -92,7 +92,7 @@ func ParseSingleUser(apiUser APIUser) (ret User, err error) { ret.ProfileImageUrl = apiUser.ProfileImageURLHTTPS ret.BannerImageUrl = apiUser.ProfileBannerURL if len(apiUser.PinnedTweetIdsStr) > 0 { - ret.PinnedTweetID = TweetID(apiUser.PinnedTweetIdsStr[0]) + ret.PinnedTweetID = TweetID(idstr_to_int(apiUser.PinnedTweetIdsStr[0])) } return } diff --git a/scraper/user_test.go b/scraper/user_test.go index 00e4d12..3c137c1 100644 --- a/scraper/user_test.go +++ b/scraper/user_test.go @@ -68,7 +68,8 @@ func TestParseSingleUser(t *testing.T) { if user.BannerImageUrl != expectedBannerImage { t.Errorf("Expected %q, got %q", expectedBannerImage, user.BannerImageUrl) } - if user.PinnedTweetID != scraper.TweetID("1403835414373339136") { - t.Errorf("Expected %q, got %q", scraper.TweetID("1403835414373339136"), user.PinnedTweet) + expected_id = 1403835414373339136 + if user.PinnedTweetID != scraper.TweetID(expected_id) { + t.Errorf("Expected %q, got %q", expected_id, user.PinnedTweet) } } diff --git a/scraper/video.go b/scraper/video.go index 45ecf5d..406e9e1 100644 --- a/scraper/video.go +++ b/scraper/video.go @@ -14,5 +14,5 @@ type Video struct { } func (v Video) FilenameWhenDownloaded() string { - return fmt.Sprintf("%s.mp4", v.TweetID) + return fmt.Sprintf("%d.mp4", v.TweetID) }