diff --git a/.gitignore b/.gitignore index 0f950b1..71b65e3 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,5 @@ _testmain.go twitterConfig.json -build/twitterConfig.json +#build/twitterConfig.json temp diff --git a/README.md b/README.md index 58ba002..6db310c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +http://arnaucode.com/argos/ + # argos twitter analyzer written in Go lang, insipired on the Python tweets_analyzer by x0rz https://github.com/x0rz/tweets_analyzer @@ -13,18 +15,18 @@ https://en.wikipedia.org/wiki/Panopticon #### Current features 1. User analyzer - - word count - - weekly activity distribution - - daily activity distribution - - devices used - - hashtags most used count - - user mentions coun [not implemented yet] -2. Delete Tweets and Favs -3. Unfollow all [not implemented yet] -4. Random follow [not implemented yet] + - Word count + - Weekly activity distribution + - Daily activity distribution + - Devices used + - Hashtags most used count + - Interactions with other users count +2. Delete Tweets +3. Unfollow all +4. Random follow - selects n number of accounts to follow, and follows n random accounts -5. Random tweet [not implemented yet] - - post a tweet with random content (from newspaper) +5. Random tweet + - post a tweet with content from a selected account ![screen](https://raw.githubusercontent.com/arnaucode/argos/master/screen3.png "screen") diff --git a/analyzeUserInteractions.go b/analyzeUserInteractions.go new file mode 100644 index 0000000..abb2247 --- /dev/null +++ b/analyzeUserInteractions.go @@ -0,0 +1,17 @@ +package main + +import ( + "strings" + + "github.com/dghubble/go-twitter/twitter" +) + +func analyzeUserInteractions(tweets []twitter.Tweet, words map[string]int) map[string]int { + var userInteractions = make(map[string]int) + for v, k := range words { + if strings.Contains(v, "@") { + userInteractions[v] = k + } + } + return (userInteractions) +} diff --git a/analyzeWords.go b/analyzeWords.go index 3931e1e..2e2fb59 100644 --- a/analyzeWords.go +++ b/analyzeWords.go @@ -26,7 +26,6 @@ func analyzeWords(tweets []twitter.Tweet) map[string]int { words = mapWords(v.Text, words) } - fmt.Println(len(words)) //get sorted list of frequency words _ = printSortedMapStringInt(words, minNumWords) fmt.Println(" ") diff --git a/build/argos b/build/argos index 0ef217c..739e8d7 100755 Binary files a/build/argos and b/build/argos differ diff --git a/build/twitterConfig_DEMO.json b/build/twitterConfig_DEMO.json new file mode 100644 index 0000000..fa82368 --- /dev/null +++ b/build/twitterConfig_DEMO.json @@ -0,0 +1,6 @@ +{ + "consumer_key": "xxxxxxxxxxxxxxxx", + "consumer_secret": "xxxxxxxxxxxxxxxx", + "access_token_key": "xxxxxxxxxxxxxxxx", + "access_token_secret": "xxxxxxxxxxxxxxxx" +} diff --git a/main.go b/main.go index 56ffa9c..e23c106 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,8 @@ import ( const version = "0.1-dev" const minNumWords = 10 const minNumHashtag = 2 -const iterationsCount = 3 +const minNumUserInteractions = 1 +const iterationsCount = 1 func main() { c.Yellow("Argos Panoptes") @@ -25,9 +26,10 @@ func main() { fmt.Print("Please select command number") options := ` 1 - Analyze username - 2 - Delete Tweets & Rretweets - 3 - Unfollow all - 4 - Follow random + 2 - Unfollow all + 3 - Follow random + 4 - Delete Tweets + 5 - Tweet Random 0 - Exit script option to select: ` for { @@ -42,16 +44,20 @@ option to select: ` optionGetUserTweets(client) break case "2": - fmt.Println("selected 2 - Delete Tweets") - optionDeleteTweets(client) + fmt.Println("selected 2 - Unfollow all") + optionUnfollowAll(client) break case "3": - fmt.Println("selected 3 - Unfollow all") - optionUnfollowAll(client) + fmt.Println("selected 3 - Follow random") + optionFollowRandom(client) break case "4": - fmt.Println("selected 4 - Follow random") - optionFollowRandom(client) + fmt.Println("selected 4 - Delete Tweets") + optionDeleteTweets(client) + break + case "5": + fmt.Println("selected 5 - Tweet random") + optionTweetRandom(client) break case "0": fmt.Println("selected 0 - exit script") diff --git a/deleteTweets.go b/optionDeleteTweets.go similarity index 100% rename from deleteTweets.go rename to optionDeleteTweets.go diff --git a/followRandom.go b/optionFollowRandom.go similarity index 80% rename from followRandom.go rename to optionFollowRandom.go index 434dc0a..c5b36ac 100644 --- a/followRandom.go +++ b/optionFollowRandom.go @@ -11,10 +11,13 @@ import ( "github.com/dghubble/go-twitter/twitter" ) -/*func getUserByScreenName(ScreenName string) *twitter.User{ - - -}*/ +func waitTime(minutes int) { + //wait to avoid the twitter api limitation + timeToSleep := time.Duration(minutes) * time.Minute + fmt.Println("waiting " + strconv.Itoa(minutes) + " min to avoid twitter api limitation") + fmt.Println(time.Now().Local()) + time.Sleep(timeToSleep) +} func getUserToFollowFromUser(client *twitter.Client, fromUser string) string { friends, httpResp, err := client.Friends.List(&twitter.FriendListParams{ ScreenName: fromUser, @@ -27,14 +30,16 @@ func getUserToFollowFromUser(client *twitter.Client, fromUser string) string { c.Red(httpResp.Status) } //fmt.Println(friends.Users) - c.Green(friends.Users[0].ScreenName) + //c.Green("@" + friends.Users[0].ScreenName) return friends.Users[0].ScreenName } func followUser(client *twitter.Client, screenName string) { - _, _, _ = client.Friendships.Create(&twitter.FriendshipCreateParams{ + user, _, _ := client.Friendships.Create(&twitter.FriendshipCreateParams{ ScreenName: screenName, }) + fmt.Print("followed: ") + c.Green("@" + user.ScreenName + " - " + user.Description) } func followRandom(client *twitter.Client, nFollow int, screenName string) { @@ -44,10 +49,7 @@ func followRandom(client *twitter.Client, nFollow int, screenName string) { userToFollow := getUserToFollowFromUser(client, screenName) followUser(client, userToFollow) screenName = userToFollow - //wait to avoid the twitter api limitation - fmt.Println("waiting 1 min to avoid twitter api limitation") - fmt.Println(time.Now().Local()) - time.Sleep(1 * time.Minute) + waitTime(1) } } diff --git a/getUserTweets.go b/optionGetUserTweets.go similarity index 89% rename from getUserTweets.go rename to optionGetUserTweets.go index e329aa1..e81b3c8 100644 --- a/getUserTweets.go +++ b/optionGetUserTweets.go @@ -57,6 +57,11 @@ func optionGetUserTweets(client *twitter.Client) { printSortedMapStringInt(hashtags, minNumHashtag) fmt.Println("") + fmt.Println("Interactions with other users (more than " + strconv.Itoa(minNumUserInteractions) + " times): ") + userInteractions := analyzeUserInteractions(tweets, words) + printSortedMapStringInt(userInteractions, minNumUserInteractions) + fmt.Println("") + analyzeDates(tweets) fmt.Println("") fmt.Println("Devices:") diff --git a/optionTweetRandom.go b/optionTweetRandom.go new file mode 100644 index 0000000..aae6689 --- /dev/null +++ b/optionTweetRandom.go @@ -0,0 +1,73 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + + "github.com/dghubble/go-twitter/twitter" +) + +func postTweet(client *twitter.Client, content string) { + tweet, httpResp, err := client.Statuses.Update(content, nil) + if err != nil { + fmt.Println(err) + } + if httpResp.Status != "200 OK" { + c.Red("error: " + httpResp.Status) + } + fmt.Print("tweet posted: ") + c.Green(tweet.Text) +} +func tweetRandom(client *twitter.Client, nTweets int, screenName string) { + fmt.Println("Starting to publish " + strconv.Itoa(nTweets) + " tweets") + + tweets := getTweets(client, screenName, 1) + fmt.Println("the selected account have more than " + strconv.Itoa(len(tweets))) + + for i := 0; i < nTweets && i < len(tweets); i++ { + postTweet(client, tweets[i].Text) + waitTime(1) + } + +} + +func optionTweetRandom(client *twitter.Client) { + c.Red("ATTENTION!") + c.Purple("Publishing tweets from a bot can be banned by twitter!") + c.Cyan("Twitter can consider your account an spam account") + c.Red("Maybe you can publish the random tweets by hand") + c.Red("how many tweets to publish?") + newcommand := bufio.NewReader(os.Stdin) + answer, _ := newcommand.ReadString('\n') + answer = strings.TrimSpace(answer) + fmt.Print("Number of tweets to publish: ") + c.Purple(answer) + nTweets, err := strconv.Atoi(answer) + if err != nil { + fmt.Println("incorrect entry, need a positive number") + } + + fmt.Print("entry @username of a twitter account, the content of the tweets will be from the account tweets: @") + newcommand = bufio.NewReader(os.Stdin) + screenName, _ := newcommand.ReadString('\n') + screenName = strings.TrimSpace(screenName) + fmt.Print("user to get tweets content: @") + c.Purple(screenName) + + c.Red("Are you sure? [y/n]") + newcommand = bufio.NewReader(os.Stdin) + answer, _ = newcommand.ReadString('\n') + answer = strings.TrimSpace(answer) + switch answer { + case "y": + fmt.Println("ok, you are sure") + tweetRandom(client, nTweets, screenName) + break + default: + fmt.Println("Operation cancelled") + break + } +} diff --git a/unfollowAll.go b/optionUnfollowAll.go similarity index 100% rename from unfollowAll.go rename to optionUnfollowAll.go diff --git a/printSortedMapStringInt.go b/printSortedMapStringInt.go index 54b20eb..880b0d9 100644 --- a/printSortedMapStringInt.go +++ b/printSortedMapStringInt.go @@ -3,9 +3,12 @@ package main import ( "fmt" "sort" + "strconv" ) func printSortedMapStringInt(m map[string]int, threshold int) map[int][]string { + total := len(m) + fmt.Println("total: " + strconv.Itoa(total)) n := map[int][]string{} var a []int for k, v := range m { @@ -19,7 +22,8 @@ func printSortedMapStringInt(m map[string]int, threshold int) map[int][]string { sort.Sort(sort.Reverse(sort.IntSlice(a))) for _, k := range a { for _, s := range n[k] { - fmt.Printf("%d - %s,\n", k, s) + //fmt.Printf("%d (%d)- %s,\n", k, tantPerCent, s) + fmt.Println(strconv.Itoa(k) + " - " + s) } } return n