Fixing the Twitter Timeline in Octopress
On June 11th 2013, Twitter shut down the old 1.0 API and the Twitter sidebar widget of Octopress, the software that powers this blog, suddenly stopped working.
In the 1.1 version of the API, every single call is authenticated by OAuth. The intended goal for Twitter was to shutdown third party Twitter clients, in order to monetize content by shoving ads into the face of their users. This controversial move was announced about a year ago and has already made some victims.
Jason McIntosh published on his blog a technique to replace the built-in Octopress widget by an official Twitter timeline widget. It works, but I think the widget looks very gross, and since it hurts my feelings to use any kind of official twitter “client”, I decided to fix the original Octopress widget instead.
The most obvious way to fix the problem, is to update the twitter.js
file to use the new API. However, it is probably not a good idea to put your OAuth tokens in JavaScript, where anybody could grab them and abuse them. These OAuth tokens need to be kept on the server side. The solution I describe below does this in a very straightforward manner.
1. Register as a Twitter developer and get OAuth credentials
- Log into https://dev.twitter.com/apps with your Twitter credentials (eg:
bartheph
). - Create a new application. (eg:
blog.barthe.ph
). - Accept the controversial rules of the road.
- Click on “Create my access token”.
- Write down the following values:
- Consumer key
- Consumer secret
- Access token
- Access token secret
2. Set up a cron job to generate a static timeline.json file
-
This file will contain the timeline, and be loaded by Octopress’ slightly modified JavaScript code
-
Install
ruby
with theoauth
gem. On Ubuntu, you do something like that:sudo apt-get install ruby rubygems sudo gem install oauth
-
Create a ruby file on the server. You need to put your Twitter OAuth token and choose an output path.
#!/usr/bin/env ruby require 'rubygems' require 'oauth' # Edit config to suit your needs config = { :consumer_key => 'xxxxx', :consumer_secret => 'xxxxxx', :oauth_token => 'xxxx-xxxxxx', :oauth_token_secret => 'xxxxx', :output_path => '/srv/blog.barthe.ph/www/timeline.json' } # Create OAuth context oauth = OAuth::Consumer.new( config[:consumer_key], config[:consumer_secret], { :site => "https://twitter.com", :scheme => :header } ) access_token = OAuth::AccessToken.from_hash( oauth, { :oauth_token => config[:oauth_token], :oauth_token_secret => config[:oauth_token_secret] } ) # Get timeline url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=bartheph&trim_user=true&count=22&include_entities=1&exclude_replies=1' response = access_token.request(:get, url) # Write response into output file with JSONP wrapper File.open(config[:output_path], 'w') { |file| file.write('processTweeter(') file.write(response.body) file.write(');') }
-
Make sure the file is executable and not readable by anyone but the web server, since it contains OAuth tokens.
chmod 700 /srv/blog.barthe.ph/cron/update_twitter.rb
-
Add the ruby script to crontab to run it periodically. Type
crontab -e
and add a line similar to what follows.# Update every 10 minutes */10 * * * * /srv/blog.barthe.ph/cron/update_twitter.rb
3. Modify Octopress to use timeline.json
instead of the Twitter API
- Edit your local version of source/javascripts/twitter.js.
- Edit the
getTwitterFeed()
function. Add ajasonp
attribute and change the value ofurl
.
function getTwitterFeed(user, count, replies) {
count = parseInt(count, 10);
$.ajax({
// REMOVED url: "http://api.twitter.com/1/statuses/user_timeline/" + user + ".json?trim_user=true&count=" + (count + 20) + "&include_entities=1&exclude_replies=" + (replies ? "0" : "1") + "&callback=?"
/* ADDED */ url: 'http://blog.barthe.ph/timeline.json?callback=processTweeter'
, type: 'jsonp'
/* ADDED */, jsonp: 'processTweeter'
, error: function (err) { $('#tweets li.loading').addClass('error').text("Twitter's busted"); }
, success: function(data) { showTwitterFeed(data.slice(0, count), user); }
})
}
That’s all. As you can see, on my blog, it looks just like before the old API was shut down. Using dynamic server side code goes a bit against the spirit of Octopress, but it’s a very tiny self contained change.