GroupMe Stats

My friends from college and I all stay in touch by using the popular messaging app, GroupMe. We have one main group, and then a number of smaller groups for things like fantasy football, investing, etc.. After talking with a friend one day, I thought it would be fun to create a CLI app that pulls stats down and crunches some numbers by using the GroupMe API. An afternoon later I had a nice working demo, and some fun information to share with my friends. All this code is hosted on GitHub if you would like to take it for a spin.

The API

I tried to keep things nice and OOP, and embarked on this project right after watching a great screencast on API wrapping by Gary Bernhardt on his site Destroy All Software. After getting my developer key from GroupMe (2 mins), I played around a little with the end points and decided that I would need 3 resources from GroupMe; Groups, Members, and Messages. The end goal is a CLI where the user can run the program, be prompted with a display of all the groups that they are members of, and then select one to generate the stats. Starting from that step 1, we need to get groups. I really like the gem HTTParty for HTTP requests in ruby, so I will be using that. Also, my GroupMe Access Token is stored in a constant up at the top of the file.

Groups


class Groups

  attr_reader :options
  attr_writer :groups

  def initialize
    @options = { :query => { :access_token => ACCESS_TOKEN } }
  end

  def groups
    @groups ||= HTTParty.get(url, options)["response"]
  end

  def url
    "http://api.groupme.com/v3/groups"
  end

  def list_groups
    puts "Please select the number of the group you want to see stats for"
    groups.each_with_index do |group, i|
      puts "#{(i + 1).to_s}. #{group["name"]}"
    end
  end

end

Now we can prompt the user when the program runs and print a nice little list of the users groups. We will get the input, strip it of white space, and decrease it by 1 (because in the groups class we increased the index by one for more user friendly numbering).


groups = Groups.new groups.list_groups
group_index = gets.chomp.to_i
group_id = groups.groups[group_index-1]['group_id']

Running it to test


GroupMeStats master => ruby stats.rb
Please select the number of the group you want to see stats for 
1. Vandy Friends
2. Fantasy Football
3. Investor Club

Success!

Fetching Messages

You can see in the code that I do a similar class for both Members and Messages, but then I have a 4th class for fetching the messages. This is because the rate limit of the GroupMe API for fetching messages is 100, so I need to make multiple calls to fetch my full history. The rescue clause is because we don't know how many messages there will be in the history, so its easiest to just break when we encounter a nil caused error.


class FetchMessages

  attr_accessor :messages
  attr_reader :group_id

  RATE_LIMIT = 100

  def initialize(num, group_id)
    @messages = []
    @num = num
    @group_id = group_id
    populate_last_x_messages(num)
  end

  def populate_last_x_messages(num)
    before_id = nil
    while messages.count < num
      begin 
        self.messages += Messages.new(group_id, RATE_LIMIT, before_id).messages
        before_id = messages.last['id']
      rescue
        break
      end
    end
  end

end

Stats

There is a main stats class where I do the actual processing of and displaying of stats built from the other objects. If I were to refactor this, the first thing I would do would be to separate the processing from the displaying within this class. I did a number of different stats but here are a couple of them.

1) Group Member and their Messages to Likes ratios:


  def print_message_stats
    messages_by_members.each do |member, messages|
      total_likes = messages.reduce(0) do |sum, message|
        sum += message['favorited_by'].count
      end
      puts 'Member: #{member['nickname']}: #{messages.count} messages and #{total_likes} likes for a ratio of #{(total_likes.to_f / messages.count).round(2)} likes per message'
    end
    return nil
  end

2) Self Likes (How many of times has each person liked their own posts :D)


  def print_self_likes
    puts 'Self Likes Given'
    members.each do |member|
      puts '#{member['nickname']}: #{self.self_likes[member['user_id']]}' if self.self_likes[member['user_id']] <> 0
    end
  end

and so on…

At the end we can put our final execution code

puts 'Loading Stats for Group: #{groups.groups[group_index-1]['name']} '
stats = Stats.new(MAX_MESSAGES_FETCHED, group_id)
puts 'Last #{stats.messages.count} Messages'
stats.run

And we give it a run!


Please select the number of the group you want to see stats for
1. Vandy Friends
2. Fantasy Football
3. Investor Club

1
Loading Stats for Group: Vandy Friends 
Last 2000 Messages

Member: Matt: 166 messages and 331 likes for a ratio of 1.99 likes per message
Member: Luke: 93 messages and 419 likes for a ratio of 4.51 likes per message
Member: Todd: 127 messages and 472 likes for a ratio of 3.72 likes per message
Member: Rick: 53 messages and 253 likes for a ratio of 4.77 likes per message
Member: Rory: 20 messages and 107 likes for a ratio of 5.35 likes per message

Top 25 Messages
1. redacted
2. redacted
...

Total Likes Given
Matt: 169
Luke: 508
Todd: 425
Rick: 323
Rory: 253

Self Likes Given
Luke: 2
Todd: 7
Rick: 2
Kevin: 17
Rory: 2

Conclusion

This was a fun afternoon exercise that gave my group of friends a good laugh. Please feel free to take it for a spin: Github Repo and let me know if you have any questions.

-Jack

comments powered by Disqus