A Drake Twitter-Bot - Automating the 6 God

I was at a bar with an old group of friends over the holidays. While we were waiting in line, one of them mentioned that he heard about a Twitter-bot that replied to tweets containing Biggie Smalls lyrics with other Biggie Smalls lyrics.

I thought the idea was hilarious, and after one or five beers decided it was something I had to build. However, I wanted to do things a little differently:

  1. I rep the 6 I am from Toronto, so the Twitter-bot would be for Drake - a.k.a the DrizzyBot
  2. The DrizzyBot would reply to tweets containing Drake lyrics with the next line of the song
  3. The DrizzyBot would run at regular intervals with no human interaction
  4. The DrizzyBot would not be flagged as spam by Twitter's (admittedly fairly impressive) spam filters

After a day of programming, tinkering, and giggling, the DrizzyBot was born.

Technical Requirements to Build the DrizzyBot

The following languages / software / packages are needed to build and run the DrizzyBot:

  1. Ruby (at least version 2.1)
  2. The (ruby) twitter gem
$ gem install twitter    
  1. Git
  2. OPTIONAL: a linux environment for scheduling recurring cron jobs; I use a (perpetually running) Raspberry Pi that my brother bought me for Christmas - thanks Tom!

Building the DrizzyBot

A. Initial Set Up

  • Create and save bot.rb file in root directory (I called my root directory twitter_bot)
  • In bot.rb file, require Twitter gem and standard library (Date) class we will be using:
require 'twitter'
require 'date'

B. Create a Twitter Application

  1. Consumer key
  2. Consumer secret
  3. Access token (generate first in Keys and Access Tokens)
  4. Access token secret (generate first in Keys and Access Tokens)

C. Create a File Containing Passwords

  • Create and save passwords file in root directory
  • Create a .gitignore file in root directory and add the passwords file to it:
# passwords
.passwords
  • In .passwords file, create constant variables for passwords (containing keys from step B.):
CONSUMER_KEY        = "consumer_key123456abcdef"
CONSUMER_SECRET     = "consumer_secret123456abcdef"
ACCESS_TOKEN        = "access_token123456abcdef"
ACCESS_TOKEN_SECRET = "access_token_secret123456abcdef"

D. Create DrizzyBot Class

  • In bot.rb file, require .passwords file and write initialize method:
require 'twitter'
require 'date'

# load passwords from dotfile here

class DrizzyBot
  def initialize
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = CONSUMER_KEY
      config.consumer_secret     = CONSUMER_SECRET
      config.access_token        = ACCESS_TOKEN
      config.access_token_secret = ACCESS_TOKEN_SECRET
    end
  end
end

E. Copy and Paste Lyrics to Various Drake Songs

  • Create lyrics.yaml file in root directory
  • Download song lyrics in the following format (album, song, lyric; please excuse syntax highlighting):
thank_me_later:
    over:
     - Bottles on me
     - Long as someone drink it
     - Never drop the ball
     - F!ck y'all thinking?
     - Making sure the young money ship is never sinking
     - Bout to set it off in this bitch Jada Pinkett
     - I shouldn't have drove
     - Tell me how I'm getting home
  • Create lyrics.rb file in root directory
  • In lyrics.rb file, load lyrics.yaml file:
require 'yaml'
lyrics = YAML.load_file(File.join(__dir__, './lyrics.yaml'))
ALBUMS = lyrics
  • In bot.rb file, import ALBUMS constant by requiring lyrics.rb file:
require 'twitter'
require 'date'
require_relative 'lyrics'

# load passwords from dotfile here

class DrizzyBot
  def initialize
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = CONSUMER_KEY
      config.consumer_secret     = CONSUMER_SECRET
      config.access_token        = ACCESS_TOKEN
      config.access_token_secret = ACCESS_TOKEN_SECRET
    end
  end
end

F. Write DrizzyBot Rap Logic

  1. Add method to (like and) reply to tweets containing (case insensitive) lyrics from a specified album and song with the next line of the song: see reply_to_tweets(album, song)
  • Must create method that finds matching tweets (contains lyrics without matching next phrase of song): see find_tweets(phrase, next_phrase)
  • Must create method that finds the most popular tweet, as replying to too many tweets will flag us as a bot: see most_popular_tweet(phrase, next_phrase)
  • Must create method that likes tweet and generates reply with the next phrase of the song, the song name, and the album name: see reply_to_matching_tweets(phrase, next_phrase, album, song)

2. Add method to tweet random lyrics to circumvent being identified as a bot (only replying to tweets will flag you, as will tweeting the same content consecutively): see tweet_phrase_from_song(album, song)

After adding the above logic, your bot.rb file will look like this:

require 'twitter'
require 'date'
require_relative 'lyrics'

# load passwords from dotfile here

class DrizzyBot
  def initialize
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = CONSUMER_KEY
      config.consumer_secret     = CONSUMER_SECRET
      config.access_token        = ACCESS_TOKEN
      config.access_token_secret = ACCESS_TOKEN_SECRET
    end
  end

  def reply_to_tweets(album, song)
    phrase_arr = ALBUMS[album][song]

    phrase_arr[0...-1].each_with_index do |phrase, idx| # can't reply to last phrase with next phrase
      reply_to_matching_tweets(phrase, phrase_arr[idx + 1], album, song)
    end
  end

  def tweet_phrase_from_song(album, song)
    phrase_arr = ALBUMS[album][song]
    phrase = phrase_arr.sample

    puts "DrizzyBot tweeted: #{phrase} ##{album} ##{song}"

    @client.update("#{phrase} ##{album} ##{song}")
  end

  private

  def find_tweets(phrase, next_phrase)
    tweets = @client.search(phrase, {result_type: 'recent'}).take(500) # limits to 500
  
    tweets.select do |tweet|
      today = Date.today === Date.parse(tweet.created_at.to_s)

      tweet.full_text.match(/#{phrase}/i) && 
      !tweet.full_text.match(/#{next_phrase}/i) &&
      today
    end
  end

  def most_popular_tweet(phrase, next_phrase)
    tweets = find_tweets(phrase, next_phrase)

    if tweets.empty?
      false
    else
      tweets.sort! do |a, b|
        b.favorite_count <=> a.favorite_count
      end
      
      tweets.first
    end
  end

  def reply_to_matching_tweets(phrase, next_phrase, album, song)
    tweet = most_popular_tweet(phrase, next_phrase)

    if tweet && !tweet.user.screen_name.match(/The110God/i) # tweet exists and isn't my account
      screen_name = '@' + tweet.user.screen_name
      album = album.gsub('_', '')
      song = song.gsub('_', '')

      puts "Favorited then tweeted at: #{screen_name}"

      @client.favorite(tweet)
      @client.update("#{screen_name} #{next_phrase} ##{song} ##{album} #drizzybot", 
                    in_reply_to_status_id: tweet.id)
      
      sleep(rand(300) + 180) # add 3 - 8 minute gap between tweets
    end
  end
end

G. Create DrizzyBot Object and Prepare it to Tweet

At the bottom of your bot.rb file (after the last 'end'), instantiate a DrizzyBot object and instruct it to (1) reply to tweets and (2) tweet random lyrics from a given album / song (song must be in lyrics.yaml file):

drizzy_bot = DrizzyBot.new
drizzy_bot.reply_to_tweets('views', 'one_dance') # 1
drizzy_bot.tweet_phrase_from_song('views', 'one_dance') # 2

H. Execute bot.rb File

From your terminal, change into your root directory and type:

$ ruby bot.rb

And that's it! Your very own DrizzyBot.

I. OPTIONAL: Set up Crontab

If you want to have your Twitter-bot send tweets without having to lift a finger, and you have a linux environment on your computer, open your crontab:

$ crontab -e

And add the following code to execute your Twitter-bot every day at 12:01 pm (your file paths will differ; please excuse the syntax highlighting):

1 12 * * * cd /home/pi/programming/twitter_bot && ruby bot.rb

Now you have a DrizzyBot that lives on its own!

Subscribe to Charlie Reese

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe