Automatic posting to Twitter

Don’t worry—it isn’t as bad as the title makes it seem.

A few weeks ago, I set up a Twitter account called drangposts so those misguided folks who use Twitter as a (poor) substitute for RSS could have an account to follow that would link to every post here. Although my regular Twitter account sometimes includes links to my posts, I don’t see that as its purpose, and I usually feel a little icky when I do it. With the drangposts account, I can spare those who follow my regular Twitter account and subscribe to the blog’s RSS feed a certain amount of duplication.

I don’t intend to use drangposts for anything other than blog links. I won’t be following anyone, I won’t be reading @-replies to it, I won’t even include the account in my Tweetbot settings. Each of its tweets will be just a post title and a link, generated by this script:

python:
 1:  #!/usr/bin/python
 2:  # -*- coding: utf-8 -*-
 3:  
 4:  import tweepy
 5:  import xmlrpclib
 6:  import keyring
 7:  
 8:  # The Twitter authentication information.
 9:  def setup_api():
10:    auth = tweepy.OAuthHandler('consumer_key',
11:             'consumer_secret')
12:    auth.set_access_token('access_token',
13:             'access_token_secret')
14:    return tweepy.API(auth)
15:  
16:  # The blog's XMLRPC URL and username.
17:  url = 'http://leancrew.com/path/to/xmlrpc.php'
18:  user = 'drdrang'
19:  
20:  # Get the blog password from Keychain.
21:  pw = keyring.get_password(url, user)
22:  
23:  # Connect.
24:  blog = xmlrpclib.Server(url)
25:  
26:  # Get the info for the most recent post.
27:  post = blog.metaWeblog.getRecentPosts(0, user, pw, 1)[0]
28:  link = post['link']
29:  title = post['title']
30:  
31:  # Authorize Twitter.
32:  api = setup_api()
33:  
34:  # How long will the shortened URL to the post be?
35:  short_length = api.configuration()['short_url_length']
36:  
37:  # Construct the tweet.
38:  max_title = 140 - short_length - 1
39:  if len(title) > max_title:
40:    title = title[:max_title-1] + u'…'
41:  tweet = '''%s
42:  %s''' % (title, link)
43:  
44:  # Send the tweet.
45:  out = api.update_status(tweet)
46:  print 'https://twitter.com/drangposts/status/%s' % out.id_str

The script is called tweetpost, and it does the following:

  1. Finds the most recent blog post and gets its title and a link to it.
  2. Constructs a tweet with the title and link.
  3. Posts the tweet.
  4. Returns a link to the tweet.

To get script access the drangposts Twitter account, I went to dev.twitter.com, signed in as drangposts, and registered a new app. After filling in the forms and clicking a few buttons, I got the four pieces of authentication necessary for tweetpost to work.

drangtweetpost

These are the strings I put in place of the four dummy values in Lines 10–13.

The script also needs administrator access to the blog, the password to which is stored in my Keychain. Lines 17–18 define the Keychain item to look for, and Line 21 pulls out the password.

(That the two authentication methods are handled so differently—one with the secrets right in the source code and the other with them tucked away in Keychain—bothers me. But Keychain doesn’t, as far as I know, have a way of saving four separate secrets in a single item. I could, I suppose, combine all four Twitter OAuth strings, separated by spaces, into a single string saved in the Keychain password field and then split them apart, but that seems like a hack. I haven’t decided yet whether it’s a hack worth doing.)

Line 24 connects to the blog, and Lines 27–29 pull out the title and link for the most recent post. WordPress uses the MetaWeblog API, so it’s easy to query it through the xmlrpclib library.

Because it’s possible that the combination of title and link will be too long for a tweet, we need to allow for the possibility of truncating the title. To do this, we first connect to Twitter on Line 32 and then get the length that Twitter will shorten the link to on Line 35.1 We then figure out the maximum length of the title on Line 38 and truncate it if necessary on Lines 39–40. The non-ASCII ellipsis in Line 40 is the reason for the encoding incantation in Line 2.

The tweet is then built in Lines 41–42 and posted on Line 45. The URL of the tweet is put together and printed out on Line 46.

If you remember this post from a week ago, in which I described the script I use to post to the blog from BBEdit, you may be wondering why I didn’t just include the logic of tweetpost at the end that code. That way I wouldn’t have to run a separate script after posting.2 I may do that eventually, but I’m keeping them separate for a while to see what bugs arise.

You might also be wondering what’s happened to the third post in that “Scripts for WordPress and BBEdit” series. The answer is that putting together a BBEdit package with scripts that call other scripts is a little trickier than I thought, and I’ve had to pick the brain of the ever-patient Patrick Woolsey at Bare Bones for some path-handling niceties that aren’t in the BBEdit manual. I think I have things worked out now, so I’ll write the final post and make the package available for download in the next day or two.


  1. I should mention here that I’m using my own version of the tweepy library—a version I forked away from the main repository long ago because it didn’t have certain features I needed. It’s possible that the official version now has a configuration method, but it didn’t back when I forked. 

  2. You might also be wondering why I don’t just use a WordPress plugin that posts to Twitter, as there are probably several that’ll do the job. But where’s the fun in that?