#!/usr/bin/env python """ TwitterCmd - Interactive, console prompt to twitter written on top of the python-twitter API. A lot of credit to DeWitt Clinton and his team of developers for the excellent 'python-twitter' API on top of which, this program is written on. Author: Anand B Pillai ('pythonhacker') License: BSD License """ from twitter import Api from cmd import Cmd import sys, os import re import urllib2 import optparse import time import glob import cPickle import subprocess __version__ = 0.3 __author__ = 'Anand B Pillai' __lastmodified__ = "Thu Oct 8 14:39:24 IST 2009" __modifications__ = """This version gets session save feature and ability to enter Python prompt from TwitterCmd and back while keeping state same across both. Basically you get the simplicity of TwitterCmd plus the power of python-twitter in one go! Oct 8 - Bug in api attribute fixed, loading it fresh always. Reduced stuff printed in inspecting timeline & user. """ LOADER=""" from twittercmd import * from twitter import Api import cPickle, urllib2 obj=cPickle.load(open('%s', 'rb')) if obj.username: obj.api=Api(obj.username) else: obj.api=Api() g=globals() g.update(obj.__dict__) """ INTRO="""Welcome to TwitterCmd, a command line interface to twitter, written in Python. TwitterCmd provides a simple, interactive interface to Twitter with short, easy to remember commands. For a full set of commands, type "help" on the prompt. For help for a specific command try "help ". Please send comments/bug reports to or tweet them to the ID 'pythonhacker'. """ HELP=""" The following commands are available. User commands 1. l - Set login credentials. 2. u - Get details of a user. 3. f - Get friend's details. 4. fo - Get followers' details. Timeline commands 1. pt - Get public timeline. 2. ut [] - Get current user timeline (given no arguments), or timeline of given user. 3. ft - Get all friends' timeline. Message commands 1. m - Post a status message. 2. im - Post a direct message to user. 3. r - Get replies to messages. 4. dm - Get all direct messages. You can also use the 'inspect' or 'i' command to inspect live objects. The following object types are supported as argument. 1. s/status - Inspect current msg status. 2. f/p/friends/peers - Inspect current friends status. 3. t/tl/tline - Inspect current timeline. 4. u/user - Inspect current user. Version 0.2 also adds the power of entering Python prompt while keeping state intact. To enter Python prompt use any of 'shell','py' or 'python' commands. Examples: # Post a message Twitter> l user pass Twitter> m Hey, I love twitter! # Get direct messages Twitter> dm ["'No problem. :-)' => dloss"] # Get names of all friends Twitter> f ['dloss', 'gvanrossum', 'MallikaLA', 'BarackObama', 'ShashiTharoor'] # Use Python prompt from TwitterCmd Twitter> py Entering Python shell... >>> # Inspect objects in shell and use python-twitter # directly by using the 'api' object. >>> api # All state of TwitterCmd is available as globals # in the interpreter... >>> tline [, ] >>> status >>> status.text 'Completed session saving and entering Python shell and back from TwitterCmd\ , code will be up in a while, Hooray!' # Use api just as you would before...! >>> [s.text for s in api.GetPublicTimeline()] ['tweeting from gravity',...] # Exit Python prompt >>> ^D Exiting Python shell... Twitter> To exit a session, type q/quit/exit or Ctrl-D. """ class TwitterCmdException(Exception): pass class TwitterCmd(Cmd): """ Python command interpreter to Twitter API. Allows a simple interactive interface to Twitter to those who prefer twittering from their *nix console, while providing the flexibility to switch back and forth from Python interactive prompt keeping state intact """ commands = {'m' : 'PostUpdate', 'im': 'PostDirectMessage', 'ut': 'GetUserTimeline', 'pt': 'GetPublicTimeline', 'ft': 'GetFriendsTimeline', 'fo': 'GetFollowers', 'f': 'GetFriends', 'r': 'GetReplies', 'dm': 'GetDirectMessages', 'u':'GetUser', 'l': 'SetCredentials'} prompt = 'Twitter> ' intro = INTRO onecmd = lambda self, line: (line==None) and True emptyline = lambda self: None default = lambda self, line: None def __init__(self, user='', passwd=''): self.api = Api() if user and passwd: self.api.SetCredentials(user, passwd) # Current username self.username = user # Current command self.cmd = '' # Current message status self.status = None # Current timeline self.tline = None # Current user object self.user = None # Current friends/followers self.peers = None # System stuff # Python executable self.python = sys.executable Cmd.__init__(self) # Load previous session self.load_session() def __getstate__(self): odict = self.__dict__.copy() del odict['stdin'] del odict['stdout'] del odict['api'] return odict def __setstate__(self, dict): # Don't update api object... try: del dict['api'] except KeyError: pass self.__dict__.update(dict) def precmd(self, line): line = line.strip() if len(line)==0: return line if line.lower() in ('q','quit','exit','eof'): print self.save_session() return None if line.lower().startswith('help'): self.print_help(line) return line if line.lower() in ('shell','py','python'): # Start Python interpreter with current state self.run_wild() return line l = line.split(' ') cmd, rest = l[0], l[1:] # Inspect objects ? if cmd.lower() in ('i','inspect'): self.inspect(' '.join(l[1:]).lower()) return line elif cmd not in self.commands: print "Command '%s' not understood" % cmd return line self.cmd = cmd.strip() try: self.action(*rest) except IndexError, e: print 'Command "%s" requires arguments!' % self.cmd except urllib2.HTTPError, e: print 'Twitter says:',e # Any other exception except Exception, e: print 'Twitter API says:',e return line def inspect(self, obj_type): """ Inspect our objects """ if obj_type in ('status', 's', 'st'): if type(self.status) is list: if self.status: print [str(i) for i in self.status] else: print str(self.status) elif obj_type in ('tline','t','tl'): if self.tline: print [i.text for i in self.tline] elif obj_type in ('user','u'): print self.user elif obj_type in ('peers','friends','p','f'): if self.peers: print [(i.name, i.screen_name) for i in self.peers] else: print 'Unknown object type',obj_type def action(self, *args): """ Perform a twitter action """ f = getattr(self.api, self.commands.get(self.cmd, None)) if self.cmd == 'l': if len(args)>=2: f(args[0], args[1]) else: f(args[0], '') print 'Set login credentials' elif self.cmd == 'm': # Force IndexError x = args[0] self.status = f(' '.join(args)) print repr(self.status) elif self.cmd == 'im': # Force IndexError x = args[0] self.status = f(args[0], ' '.join(args[1:])) print repr(self.status) elif self.cmd == 'ut': self.tline = [f(args[0]) if len(args) else f()][0] print [s.text for s in self.tline] elif self.cmd == 'pt': self.tline = f() print [s.text for s in self.tline] elif self.cmd == 'ft': self.tline = f() print [s.text for s in self.tline] elif self.cmd == 'r': self.status = f() print [s.text for s in self.status] elif self.cmd == 'dm': self.status = f() print [' => '.join(("'" + s.text + "'", s._sender_screen_name)) \ for s in self.status] elif self.cmd in ('f','fo'): self.peers = f() print [s.screen_name for s in self.peers] elif self.cmd=='u': self.user = f(args[0]) print self.user.name def load_session(self): """ Load most recent session from disk, if present """ fnames = glob.glob(os.path.join(os.path.expanduser('~'),'.twitter_session_*')) if len(fnames): print 'Loading saved session...' try: obj = cPickle.load(open(fnames[0], 'rb')) self.__setstate__(obj.__dict__) except cPickle.UnpicklingError, e: print 'Error loading saved session' def save_session(self): """ Save current session to disk """ fname = os.path.join(os.path.expanduser('~'), '.twitter_session_%d' % int(time.time())) try: # Remove older sessions olds = glob.glob(os.path.join(os.path.expanduser('~'),'.twitter_session_*')) cPickle.dump(self, open(fname, 'wb')) # Remove older sessions for f in olds: try: os.remove(f) except OSError, e: pass except cPickle.PicklingError, e: print 'Error saving current session to disk:',e return fname def run_wild(self): session = self.save_session() # Create a module that will load the saved session loader = LOADER % session module = '.twitter_loader.py' open(module,'w').write(loader) print 'Entering Python shell...' subprocess.call([self.python,"-i", module]) print 'Exiting Python shell...' def print_help(self, line): if line.lower()=='help': print HELP else: l = line.split(' ') cmd, rest = l[0], ' '.join(l[1:]) if cmd.lower() != 'help': return if rest=='m': print 'm : Post status message ' elif rest=='im': print 'm : Post direct message to user ' elif rest=='ut': print 'ut []: Get current user timeline without arguments\n\ and given user timeline with arguments' elif rest=='pt': print 'pt: Get twitter public timeline' elif rest=='ft': print "ft: Get all friends' timelines" elif rest=='fo': print 'fo: Get all follower details' elif rest=='f': print "f: Get all friends' details" elif rest=='dm': print 'dm: Get all direct messages' elif rest=='r': print 'r: Get all replies to direct messages' elif rest=='u': print 'u : Get a given user details' elif rest=='l': print 'l : Set current user credentials' elif rest in ('i','inspect'): print 'i : Inspect object of given type' else: print 'No such command "%s"' % rest if __name__ == "__main__": p = optparse.OptionParser() p.add_option('-u','--user',dest='user',default='',help='Optional Twitter username') p.add_option('-p','--passwd',dest='passw',default='',help='Optional Twitter password') options, args = p.parse_args() user, passwd = options.user, options.passw TwitterCmd(user, passwd).cmdloop()