Change TweetID to be an int64
instead of a string
This commit is contained in:
parent
529c181397
commit
c803794a0f
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"},
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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": "<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>",
|
||||
"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":"<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>","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"}
|
||||
|
1
scraper/test_responses/tweet_with_quoted_tweet.json
Normal file
1
scraper/test_responses/tweet_with_quoted_tweet.json
Normal file
@ -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":"<a href=\"https://mobile.twitter.com\" rel=\"nofollow\">Twitter Web App</a>","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"}
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user