twitter.go (7940B)
1 package twitter 2 3 import ( 4 "encoding/csv" 5 "encoding/json" 6 "fmt" 7 "github.com/SocialNetworkNews/SocialNetworkNews_API/config" 8 "github.com/SocialNetworkNews/anaconda" 9 "github.com/dghubble/oauth1" 10 "github.com/dghubble/oauth1/twitter" 11 "net/url" 12 "os" 13 "path/filepath" 14 "strconv" 15 "strings" 16 "sync" 17 "time" 18 ) 19 20 var apiOnce sync.Once 21 var api *TwitterAPI 22 23 type Tweets struct { 24 Tweets []Tweet `json:"tweets,omitempty"` 25 } 26 27 type Tweet struct { 28 Username string `json:"username"` 29 UserID string `json:"user_id"` 30 DisplayName string `json:"display_name"` 31 UserProfileLink string `json:"userprofile_link"` 32 RetweetByUsername string `json:"retweetby_username"` 33 RetweetByUserID string `json:"retweetby_user_id"` 34 RetweetByDisplayName string `json:"retweetby_display_name"` 35 RetweetByUserProfileLink string `json:"retweetby_userprofile_link"` 36 TweetLink string `json:"tweet_link"` 37 Text string `json:"text"` 38 IMGUrls []string `json:"image_urls"` 39 CreatedAt string `json:"created_at"` 40 Favorites string `json:"favorites"` 41 Retweets string `json:"retweets"` 42 Retweet bool `json:"retweet"` 43 } 44 45 type TwitterAPI struct { 46 api *anaconda.TwitterApi 47 stream *anaconda.Stream 48 } 49 50 func NewTwitterAPIStruct() *TwitterAPI { 51 apiOnce.Do(func() { 52 api = &TwitterAPI{} 53 }) 54 return api 55 } 56 57 func (t *TwitterAPI) getTokens(config *oauth1.Config) (string, string, error) { 58 requestToken, requestSecret, TokenErr := config.RequestToken() 59 if TokenErr != nil { 60 return "", "", TokenErr 61 } 62 63 authorizationURL, URLErr := config.AuthorizationURL(requestToken) 64 if URLErr != nil { 65 return "", "", URLErr 66 } 67 68 fmt.Println(authorizationURL.String()) 69 fmt.Print("Enter PinCode: ") 70 var pin string 71 fmt.Scanln(&pin) 72 73 accessToken, accessSecret, ATErr := config.AccessToken(requestToken, requestSecret, pin) 74 if ATErr != nil { 75 return "", "", ATErr 76 } 77 78 return accessToken, accessSecret, nil 79 80 } 81 82 func (t *TwitterAPI) Login(consumerKey, consumerSecret string) (err error) { 83 oauthConfig := &oauth1.Config{ 84 ConsumerKey: consumerKey, 85 ConsumerSecret: consumerSecret, 86 Endpoint: twitter.AuthorizeEndpoint, 87 } 88 accessToken, accessSecret, ATErr := t.getTokens(oauthConfig) 89 if ATErr != nil { 90 err = ATErr 91 return 92 } 93 94 anaconda.SetConsumerKey(consumerKey) 95 anaconda.SetConsumerSecret(consumerSecret) 96 t.api = anaconda.NewTwitterApi(accessToken, accessSecret) 97 return 98 } 99 100 func (t *TwitterAPI) StartListening(lists []string, hashtags []string) error { 101 fmt.Println("StartListening") 102 Alists, AListErr := t.getLists(lists) 103 if AListErr != nil { 104 return AListErr 105 } 106 usersS, MembersErr := t.getListMembersS(Alists) 107 if MembersErr != nil { 108 return MembersErr 109 } 110 111 hastagsS := strings.Join(hashtags, ",") 112 113 v := url.Values{} 114 v.Set("follow", usersS) 115 v.Set("track", hastagsS) 116 117 t.stream = t.api.PublicStreamFilter(v) 118 for tw := range t.stream.C { 119 switch v := tw.(type) { 120 case anaconda.Tweet: 121 currentTime := time.Now().Local() 122 t.writeCSV([]string{v.IdStr, currentTime.String()}) 123 fmt.Printf("%-15s: %s\n", v.User.ScreenName, v.FullText) 124 default: 125 fmt.Println("Got some other Type: ", v) 126 } 127 } 128 return nil 129 } 130 131 func (t *TwitterAPI) writeCSV(tweet []string) error { 132 currentTime := time.Now().Local() 133 dataPath := filepath.Join(".", "data") 134 if _, err := os.Stat(dataPath); os.IsNotExist(err) { 135 os.Mkdir(dataPath, os.ModePerm) 136 } 137 filename := fmt.Sprintf("tweets_%s.csv", currentTime.Format("2006_01_02")) 138 filePath := config.ConfigPath() 139 dataFilePath := filepath.Join(filePath, "data", filename) 140 141 // write the file 142 f, err := os.OpenFile(dataFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) 143 if err != nil { 144 return err 145 } 146 w := csv.NewWriter(f) 147 w.Write(tweet) 148 w.Flush() 149 defer f.Close() 150 return nil 151 } 152 153 func (t *TwitterAPI) getLists(lists []string) ([]anaconda.List, error) { 154 var Alists []anaconda.List 155 for _, l := range lists { 156 s := strings.Split(l, "/") 157 v := url.Values{} 158 list, err := t.api.GetListBySlug(s[1], s[0], v) 159 if err != nil { 160 return nil, err 161 } 162 Alists = append(Alists, list) 163 } 164 165 return Alists, nil 166 } 167 168 func (t *TwitterAPI) getListMembersS(lists []anaconda.List) (string, error) { 169 var users []anaconda.User 170 var usersSS []string 171 for _, l := range lists { 172 v := url.Values{} 173 members, err := t.api.GetListMembers(l.Id, v) 174 if err != nil { 175 return "", err 176 } 177 178 users = append(users, members...) 179 } 180 181 for _, u := range users { 182 usersSS = append(usersSS, u.IdStr) 183 } 184 185 usersS := strings.Join(usersSS, ",") 186 return usersS, nil 187 } 188 189 func (t *TwitterAPI) GetTweets(tweets []int64) ([]byte, error) { 190 v := url.Values{} 191 v.Set("include_entities", "true") 192 retweets := make(map[string]bool) 193 tweetsSlice := make(map[string]bool) 194 195 var divided [][]int64 196 197 chunkSize := 99 198 199 for i := 0; i < len(tweets); i += chunkSize { 200 end := i + chunkSize 201 202 if end > len(tweets) { 203 end = len(tweets) 204 } 205 206 divided = append(divided, tweets[i:end]) 207 } 208 209 var JTweets []Tweet 210 211 for _, chunk := range divided { 212 tweetsR, tweetErr := t.api.GetTweetsLookupByIds(chunk, v) 213 if tweetErr != nil { 214 return nil, tweetErr 215 } 216 217 for _, t := range tweetsR { 218 JT := Tweet{} 219 if tweetsSlice[t.IdStr] { 220 continue 221 } 222 if t.RetweetedStatus != nil { 223 JT.Retweet = true 224 if retweets[t.RetweetedStatus.IdStr] { 225 continue 226 } else { 227 retweets[t.RetweetedStatus.IdStr] = true 228 } 229 } else { 230 JT.Retweet = false 231 } 232 tweetsSlice[t.IdStr] = true 233 // If we got a retweet get the data of the original tweet 234 if JT.Retweet { 235 JT.Username = t.RetweetedStatus.User.ScreenName 236 JT.UserID = t.RetweetedStatus.User.IdStr 237 238 JT.DisplayName = t.RetweetedStatus.User.Name 239 JT.UserProfileLink = "https://twitter.com/" + t.RetweetedStatus.User.ScreenName 240 241 JT.RetweetByUsername = t.User.ScreenName 242 JT.RetweetByUserID = t.User.IdStr 243 JT.RetweetByDisplayName = t.User.Name 244 JT.RetweetByUserProfileLink = "https://twitter.com/" + t.User.ScreenName 245 246 JT.TweetLink = "https://twitter.com/" + t.RetweetedStatus.User.ScreenName + "/status/" + t.RetweetedStatus.IdStr 247 if t.RetweetedStatus.ExtendedTweet.FullText != "" { 248 JT.Text = t.RetweetedStatus.ExtendedTweet.FullText 249 } else if t.RetweetedStatus.FullText != "" { 250 JT.Text = t.RetweetedStatus.FullText 251 } else { 252 JT.Text = t.RetweetedStatus.Text 253 } 254 255 tweetTime, err := t.RetweetedStatus.CreatedAtTime() 256 if err != nil { 257 return nil, err 258 } 259 JT.CreatedAt = tweetTime.Format("02.01.2006") 260 JT.Favorites = strconv.Itoa(t.RetweetedStatus.FavoriteCount) 261 JT.Retweets = strconv.Itoa(t.RetweetedStatus.RetweetCount) 262 263 for _, i := range t.RetweetedStatus.Entities.Media { 264 if i.Type == "photo" { 265 JT.IMGUrls = append(JT.IMGUrls, i.Media_url_https) 266 } 267 } 268 } else { 269 JT.Username = t.User.ScreenName 270 JT.UserID = t.User.IdStr 271 272 JT.DisplayName = t.User.Name 273 JT.UserProfileLink = "https://twitter.com/" + t.User.ScreenName 274 JT.TweetLink = "https://twitter.com/" + t.User.ScreenName + "/status/" + t.IdStr 275 if t.ExtendedTweet.FullText != "" { 276 JT.Text = t.ExtendedTweet.FullText 277 } else if t.FullText != "" { 278 JT.Text = t.FullText 279 } else { 280 JT.Text = t.Text 281 } 282 283 tweetTime, err := t.CreatedAtTime() 284 if err != nil { 285 return nil, err 286 } 287 JT.CreatedAt = tweetTime.Format("02.01.2006") 288 JT.Favorites = strconv.Itoa(t.FavoriteCount) 289 JT.Retweets = strconv.Itoa(t.RetweetCount) 290 291 for _, i := range t.Entities.Media { 292 if i.Type == "photo" { 293 JT.IMGUrls = append(JT.IMGUrls, i.Media_url_https) 294 } 295 } 296 } 297 298 JTweets = append(JTweets, JT) 299 } 300 } 301 302 tweetsS := Tweets{} 303 tweetsS.Tweets = JTweets 304 305 tweetObject, err := json.Marshal(tweetsS) 306 if err != nil { 307 return nil, err 308 } 309 310 return tweetObject, nil 311 }