Build a Fantasy Football Hotline with Ruby and Twilio Voice

September 06, 2016
Written by

tom-brady-phone

A phone was once the fastest way for a sports fan to get their news. In the 70s, 80s and 90s a business called Sports Phone served as a fan’s lifeline for up-to-the minute sports reports.

Grantland recently ran this fascinating piece on the rise and fall of Sports Phone:

The concept couldn’t be simpler: You call a number and hear a minute-long message with the latest scores and sports news. A half hour later, if you want another update, you call again — and pay another dime.

By 1979, the service was averaging about 100,000 calls per day… the company could get upward of 300,000 calls on a good college football Saturday or an NFL Sunday…

Sports Phone enjoyed an impressive run from 1972 to 2000 but was ultimately crushed by cable news and, of course, the Internet. In fact, it took us less than 30 minutes to create our own Fantasy Football Sports Phone using an RSS feed, Twilio Voice, and 31 lines of Ruby.

The gist is that we call a number and a robot voice reads us the headlines from one of RotoWorld‘s RSS feeds. Want to give it a try? Call 888.808.4929.

Here’s what the final code looks like:

require 'rss'
require 'open-uri'
require 'sinatra'

def get_news
  twiml = ""
  url = 'http://www.rotoworld.com/rss/feed.aspx?sport=nfl&ftype=news&count=10&format=rss'
  open(url) do |rss|
    feed = RSS::Parser.parse(rss)
    feed.items.each do |item|
      twiml += "<Say voice='alice'> #{item.description}</Say>"
      twiml += "<Pause length='1'/>"
    end
  end
  
  puts twiml
  twiml
end

post '/call' do
  content_type "text/xml"

  "<Response>
    <Say voice='alice'>
      Thanks for calling the Fantasy Football news line powered by Roto World and Twillio.
    </Say>
    <Pause length='1'/>
    #{get_news}
    <Say voice='alice'>Goodbye.</Say>
    </Response>"
end

In the rest of this post, we’ll break down the two steps you need to create your own “Dial an RSS Feed” hotline:

  1. Parse an RSS feed with Ruby
  2. Answer a phone call with Twilio and Ruby

Parse an RSS feed in Ruby

Our first step is to parse RotoWorld’s Player News RSS Feed. Fortunately, that functionality is baked into the standard library. The code below is straight out of the Ruby documentation on how to parse an RSS feed, though we’ve made three small modifications:

  1. Grab the item description
  2. Wrap the description in TwiML (more on that later)
  3. Collect all of the TwiML into the twiml variable and return it

require 'rss'
require 'open-uri'

def get_news
  twiml = ''
  url = 'http://www.rotoworld.com/rss/feed.aspx?sport=nfl&ftype=news&count=10&format=rss'
  open(url) do |rss|
    feed = RSS::Parser.parse(rss)
    feed.items.each do |item|
      twiml += "<Say voice='alice'> #{item.description}</Say>"
      twiml += "<Pause length='1'/>"
    end
  end

  puts twiml
  twiml
end

get_news

Create a new directory called sports-phone and cd into it. Save the above code to app.rb, and run ruby app.rb. You’ll see a bunch of headlines wrapped in XML. That’s how we’re going to make Twilio talk.

news-twiml

Great! Now let’s get a phone number hooked up to this RSS reader.

Answer a phone call in Ruby

Sign up for a free Twilio account if you don’t have one. Buy a phone number, then click Setup Number. Find the field in the Voice section that says “A Call Comes In.”

When someone calls our Twilio number, Twilio makes an HTTP request to the URL we punch into this field. In return, Twilio expects an HTTP response in the of TwiML – a simple set of XML tags that tell Twilio what to do next.

We’ll use Sinatra, the lightweight web framework, to handle that POST request. Before we install that gem though, you’ll probably want to use rbenv or rvm to keep the gems for this project secluded from all your others (though, strictly speaking, it’s not essential to make the code run):

echo "2.3.1" > .ruby-version
echo "sports-phone" > .ruby-gemset
cd ..
cd sports-phone

Then install Sinatra.

gem install sinatra

And require it at the top of app.rb:

require 'sinatra'

We need a route that responds to a POST request on /call with TwiML that tells Twilio to:

  1. <Say> a greeting
  2. <Say> the news and <Pause> between each headline
  3. <Say> goodbye

To do this, delete the last line in your code: get_news. Replace it with:

post '/call' do
  content_type "text/xml"
  "<Response>
    <Say voice='alice'>
      Thanks for calling the Fantasy Football news line powered by Roto World and Twillio.
    </Say>
    <Pause length='1'/>
    #{get_news}
    <Say voice='alice'>Goodbye.</Say>
  </Response>"
end

Side note: for more complicated logic, you may want to use the Twilio Ruby gem to generate TwiML, but for simple stuff I prefer to write the XML by hand.

Your app’s going to need a publicly accessible URL so that Twilio can send it that POST request. Easiest way to do this on your local machine is to use ngrok. Alternatively, you can deploy your app to the cloud, but that means re-deploying every time you make a change.

Run ngrok to accept HTTP requests on Sinatra’s default port: 4567.

ngrok http 4567

Grab the URL ngrok gives you and paste it into the “a call comes in” field, and append the /call endpoint.

call-comes-in-ngrok

Restart your app, call your number, and listen to that smooth robot voice read you the latest fantasy news.

Next Steps

Grantland’s article talks about how the success of Sports Phone spawned “a number of similar Dial-It services, as they were called — time, weather, horoscopes, Dial-a-Joke, a Dr. Joyce Brothers hotline, and so on.” You’ve now got a Sinatra app that can answer a phone call and read off an RSS feed. Go nuts.

And since you’ve got the infrastructure in place, it’s pretty easy to toss in a little extra TwiML to build more complicated voice apps. For instance, you could use the verb to turn this into an IVR (“phone tree” in layman’s terms) that lets the caller “Press 1 to…” choose the news they want to hear. You could use the re-create the methodology of the original Sports Line by using TwiML to a short message, and then that recording for subsequent callers.

If you’d like to learn more about all the crazy stuff you can build with Twilio Voice and Ruby, check out:

I’d love to hear from you if you have any questions or want to show off what you build. Drop me a line at gb@twilio.com.