Twitter bot with Django for marketing

So having recently put live Photobrix, we didn't want to spend a great deal of time marketting it - mainly because that takes a lot of time to really do properly. With lots of social code lying around I tied together the Photobrix CLI tool with twitter and made a simple management command in django that let me grab images or profiles and tweet back the user in question.

We often got ignored and a few times Twitter banned the account when I let it rip on some search terms (Twitter doesn't like you doing a lot of directed tweets without any sort of inbound interaction).

But every now and again someone of 'influence' would actually tweet back, here's Spencer Kelly of the BBC's Click technology programme:

import twitter  
import requests  
import os

from django.conf import settings  
from django.core.management.base import BaseCommand  
from subprocess import call  
from optparse import make_option

from lego.models import BotTweet


class Command(BaseCommand):  
    help = 'Interact with a tweet or profile with a Photobrix image'
    option_list = BaseCommand.option_list + (
        make_option('--tweet',
            dest='tweet',
            help='Tweet to reply to &/or pull media from'
        ),        
        make_option('--file',
            dest='input_ids',
            help='File to pull tweet url or status IDs from'
        ),       
        make_option('--msg',
            dest='msg',
            help='Custom message to use (will swap for @user if present)'
        ),      
        make_option('--dummy',
            dest='dont_send',
            action='store_true',
            help='Don\'t actually send tweets - dummy'
        ),      
        make_option('--size',
            dest='size',
            default='48',
            help='Size of output brick grid'
        ),      
        make_option('--profile',
            dest='profile',
            action='store_true',
            help='Use the profile picture of the user'
        ),     
        make_option('--url',
            dest='image_url',
            help='An image URL to use as source instead of a tweet'
        ),     
        make_option('--default-msg',
            dest='default_msg',
            help='Which default to use'
        ),     
        make_option('--no-reply',
            action='store_true',
            dest='no_reply',
            help='Don\'t set a reply-to status id'
        ),
    )

    msgs = {
        None: '{}You have been Photobrixed! Checkout http://photobrix.com to make your own! #LEGO #photobrix',
        'profile': '{}That\'s an awesome profile photo, and even better in #LEGO by http://photobrix.com',
        'image': '{}This image needs more bricks. Done. #LEGO #photobrix. Make yours at http://photobrix.com',
    }

    def __init__(self):
        super(Command, self).__init__()
        self.api = twitter.Api(consumer_key=settings.TWITTER_CONSUMER_KEY,
            consumer_secret=settings.TWITTER_CONSUMER_SECRET,
            access_token_key='XXX',
            access_token_secret='XXX'
        )

    def handle(self, *args, **options):
        try:
            infile = args[0]
        except IndexError:
            infile = None

        default_msg = self.msgs[options['default_msg']]

        use_tweet = options.get('tweet', False)
        no_reply = options.get('no_reply', False)
        input_ids_file = options.get('input_ids', False)

        def _clean_tweet(tweet):
            if tweet is None:
                return

            if tweet.strip().startswith('http'):
                tweet = tweet.split('/')[-1]
            return tweet   

        def _get_image(url):
            infile = '/tmp/{}'.format(os.path.basename(media))
            with open(infile, 'w') as f:
                f.write(requests.get(media).content)   
            return infile

        if input_ids_file:
            urls = open(input_ids_file).readlines()
        else:
            if use_tweet:
                urls = (use_tweet, )
            elif options.get('image_url', None) is not None:
                urls = (options['image_url'], )
            else:
                urls = (None, )

        for cnt, _url in enumerate(urls):
            media, tweet, target, source = None, None, '', None

            if options.get('image_url', None) is None:
                tweet = _clean_tweet(_url)
            else:
                media = options['image_url']

            if tweet is not None:
                source = self.api.GetStatus(tweet)
                target = '@{} '.format(source.user.screen_name)

                if options.get('profile', False):
                    media = source.user.profile_image_url.replace('_normal', '')
                else:
                    # Pull the media from the tweet itself
                    try:
                        media = source.media[0]['media_url']
                    except IndexError:
                        self.stdout.write('No media to use for tweet {}, skipping'.format(source.id))
                        continue

            if media is not None:
                infile = _get_image(media)

            msg = default_msg.format(target)
            supplied_msg = options.get('msg', False)
            dont_send = options.get('dont_send', False)
            size = options.get('size', '48')

            if supplied_msg:
                if source is not None:
                    msg = supplied_msg.replace('@user', '@{}'.format(source.user.screen_name))
                else:
                    msg = supplied_msg

            outfile = '{}.legofy.overlay.png'.format(infile)

            if source is not None:
                existing = BotTweet.objects.filter(source_tweet=source.id).count()

                if existing > 0:
                    self.stdout.write('Already tweeted {}, skipping'.format(source.id))
                    continue

                call(['lego', '--watermark', '-c', '25', '-s', size, infile])

                if not dont_send:
                    if no_reply:
                        status = self.api.PostMedia(
                            msg, 
                            outfile
                        )
                    else:
                        status = self.api.PostMedia(
                            msg, 
                            outfile, 
                            in_reply_to_status_id=source.id
                        )

            else:
                call(['lego', '--watermark', '-c', '25', '-s', size, infile])

                if not dont_send:
                    status = self.api.PostMedia(msg, outfile)

            if not dont_send:

                # Create a log of this now in the admin
                bot_tweet = BotTweet(
                    source_tweet=source.id,
                    source_user=source.user.screen_name,
                    source_followers=source.user.followers_count,
                    content=msg,
                    status_id=status.id
                )
                bot_tweet.save()

                self.stdout.write("Sent tweet: http://twitter.com/photobrixbot/status/{}".format(status.id))
                self.stdout.write("Added log: {}".format(bot_tweet.pk))

            else:
                self.stdout.write("Skipping sending: {}".format(msg))