]> jfr.im git - z_archive/twitter.git/blobdiff - twitter/cmdline.py
Another Line
[z_archive/twitter.git] / twitter / cmdline.py
index 0338ffd0bb825468d9acb5f1d4ffcc73d9a00f3f..ec07cd44b092bbad0c05119eacd6a0e8f5449d18 100644 (file)
@@ -22,7 +22,11 @@ OPTIONS:
  -R --refresh-rate <rate>   set the refresh rate (in seconds)
  -f --format <format>       specify the output format for status updates
  -c --config <filename>     read username and password from given config
-                              file (default ~/.twitter)
+                            file (default ~/.twitter)
+ -l --length <count>        specify number of status updates shown
+                            (default: 20, max: 200)
+ -t --timestamp             show time before status lines
+ -d --datestamp             shoe date before status lines
 
 FORMATS for the --format option
 
@@ -50,6 +54,7 @@ from getpass import getpass
 import re
 import os.path
 from ConfigParser import SafeConfigParser
+import datetime
 
 from api import Twitter, TwitterError
 import ansi
@@ -67,14 +72,17 @@ OPTIONS = {
     'format': 'default',
     'prompt': '[cyan]twitter[R]> ',
     'config_filename': os.environ.get('HOME', '') + os.sep + '.twitter',
+    'length': 20,
+    'timestamp': False,
+    'datestamp': False,
     'extra_args': []
 }
 
 def parse_args(args, options):
     long_opts = ['email', 'password', 'help', 'format', 'refresh',
-                 'refresh-rate', 'config']
-    short_opts = "e:p:f:h?rR:c:"
-    opts, extra_args = getopt(args, short_opts, long_opts)
+                 'refresh-rate', 'config', 'length', 'timestamp', 'datestamp']
+    short_opts = "e:p:f:h?rR:c:l:td"
+    opts, extra_args = getopt(args, short_opts, long_opts)        
 
     for opt, arg in opts:
         if opt in ('-e', '--email'):
@@ -87,6 +95,12 @@ def parse_args(args, options):
             options['refresh'] = True
         elif opt in ('-R', '--refresh-rate'):
             options['refresh_rate'] = int(arg)
+        elif opt in ('-l', '--length'):
+            options["length"] = int(arg)
+        elif opt in ('-t', '--timestamp'):
+            options["timestamp"] = True
+        elif opt in ('-d', '--datestamp'):
+            options["datestamp"] = True
         elif opt in ('-?', '-h', '--help'):
             options['action'] = 'help'
         elif opt in ('-c', '--config'):
@@ -95,24 +109,44 @@ def parse_args(args, options):
     if extra_args and not ('action' in options and options['action'] == 'help'):
         options['action'] = extra_args[0]
     options['extra_args'] = extra_args[1:]
+    
+def get_time_string(status, options):
+    timestamp = options["timestamp"]
+    datestamp = options["datestamp"]
+    t = time.strptime(status['created_at'], "%a %b %d %H:%M:%S +0000 %Y")
+    i_hate_timezones = time.timezone
+    if (time.daylight):
+        i_hate_timezones = time.altzone
+    dt = datetime.datetime(*t[:-3]) - datetime.timedelta(
+        seconds=i_hate_timezones)
+    t = dt.timetuple()
+    if timestamp and datestamp:
+        return time.strftime("%Y-%m-%d %H:%M:%S ", t)
+    elif timestamp:
+        return time.strftime("%H:%M:%S ", t)
+    elif datestamp:
+        return time.strftime("%Y-%m-%d ", t)
+    return ""                             
 
 class StatusFormatter(object):
-    def __call__(self, status):
-        return (u"%s %s" %(
+    def __call__(self, status, options):
+        return (u"%s%s %s" %(
+            get_time_string(status, options),
             status['user']['screen_name'], status['text']))
 
 class AnsiStatusFormatter(object):
     def __init__(self):
         self._colourMap = ansi.ColourMap()
-
-    def __call__(self, status):
+        
+    def __call__(self, status, options):
         colour = self._colourMap.colourFor(status['user']['screen_name'])
-        return (u"%s%s%s %s" %(
+        return (u"%s%s%s%s %s" %(
+            get_time_string(status, options),
             ansi.cmdColour(colour), status['user']['screen_name'],
             ansi.cmdReset(), status['text']))
 
 class VerboseStatusFormatter(object):
-    def __call__(self, status):
+    def __call__(self, status, options):
         return (u"-- %s (%s) on %s\n%s\n" %(
             status['user']['screen_name'],
             status['user']['location'],
@@ -121,7 +155,7 @@ class VerboseStatusFormatter(object):
 
 class URLStatusFormatter(object):
     urlmatch = re.compile(r'https?://\S+')
-    def __call__(self, status):
+    def __call__(self, status, options):
         urls = self.urlmatch.findall(status['text'])
         return u'\n'.join(urls) if urls else ""
 
@@ -170,35 +204,35 @@ def get_admin_formatter(options):
     return sf()
 
 class Action(object):
-    @staticmethod
-    def ask(subject='perform this action', careful=False):
+
+    def ask(self, subject='perform this action', careful=False):
         '''
         Requests fromt he user using `raw_input` if `subject` should be
         performed. When `careful`, the default answer is NO, otherwise YES.
         Returns the user answer in the form `True` or `False`.
         '''
-        sample = '(y/N)' if careful else '(Y/n)'
+        sample = '(y/N)'
+        if not careful:
+            sample = '(Y/n)'
+        
         prompt = 'You really want to %s %s? ' %(subject, sample)
         try:
             answer = raw_input(prompt).lower()
             if careful:
-                if answer not in ('yes', 'y'):
-                    return False
-                else:
-                    return True
+                return answer in ('yes', 'y')
             else:
-                if answer in ('no', 'n'):
-                    return False
-                else:
-                    return True
+                return answer not in ('no', 'n')
         except EOFError:
             print >>sys.stderr # Put Newline since Enter was never pressed
             # TODO:
                 #   Figure out why on OS X the raw_input keeps raising
                 #   EOFError and is never able to reset and get more input
                 #   Hint: Look at how IPython implements their console
-            default = False if careful else True
+            default = True
+            if careful:
+                default = False
             return default
+        
     def __call__(self, twitter, options):
         action = actions.get(options['action'], NoSuchAction)()
         try:
@@ -220,52 +254,58 @@ class NoSuchAction(Action):
     def __call__(self, twitter, options):
         raise NoSuchActionError("No such action: %s" %(options['action']))
 
+def printNicely(string):        
+    if sys.stdout.encoding:
+        print string.encode(sys.stdout.encoding, 'replace')
+    else:
+        print string.encode('utf-8')
+        
 class StatusAction(Action):
     def __call__(self, twitter, options):
-        statuses = self.getStatuses(twitter)
+        statuses = self.getStatuses(twitter, options)
         sf = get_status_formatter(options)
         for status in statuses:
-            statusStr = sf(status)
+            statusStr = sf(status, options)
             if statusStr.strip():
-                print statusStr.encode(sys.stdout.encoding, 'replace')
+                printNicely(statusStr)
 
 class AdminAction(Action):
     def __call__(self, twitter, options):
-        if not options['extra_args'][0]:
+        if not (options['extra_args'] and options['extra_args'][0]):
             raise TwitterError("You need to specify a user (screen name)")
         af = get_admin_formatter(options)
         try:
             user = self.getUser(twitter, options['extra_args'][0])
         except TwitterError, e:
             print "There was a problem following or leaving the specified user."
-            print "  You may be trying to follow a user you are already following;"
-            print "  Leaving a user you are not currently following;"
-            print "  Or the user may not exist."
-            print "  Sorry."
+            print "You may be trying to follow a user you are already following;"
+            print "Leaving a user you are not currently following;"
+            print "Or the user may not exist."
+            print "Sorry."
             print
             print e
         else:
-            print af(options['action'], user).encode(sys.stdout.encoding, 'replace')
+            printNicely(af(options['action'], user))
 
 class FriendsAction(StatusAction):
-    def getStatuses(self, twitter):
-        return reversed(twitter.statuses.friends_timeline())
+    def getStatuses(self, twitter, options):
+        return reversed(twitter.statuses.friends_timeline(count=options["length"]))
 
 class PublicAction(StatusAction):
-    def getStatuses(self, twitter):
-        return reversed(twitter.statuses.public_timeline())
+    def getStatuses(self, twitter, options):
+        return reversed(twitter.statuses.public_timeline(count=options["length"]))
 
 class RepliesAction(StatusAction):
-    def getStatuses(self, twitter):
-        return reversed(twitter.statuses.replies())
+    def getStatuses(self, twitter, options):
+        return reversed(twitter.statuses.replies(count=options["length"]))
 
 class FollowAction(AdminAction):
     def getUser(self, twitter, user):
-        return twitter.notifications.follow(id=user)
+        return twitter.friendships.create(id=user)
 
 class LeaveAction(AdminAction):
     def getUser(self, twitter, user):
-        return twitter.notifications.leave(id=user)
+        return twitter.friendships.destroy(id=user)
 
 class SetStatusAction(Action):
     def __call__(self, twitter, options):
@@ -276,8 +316,8 @@ class SetStatusAction(Action):
         twitter.statuses.update(status=status)
 
 class TwitterShell(Action):
-    @staticmethod
-    def render_prompt(prompt):
+
+    def render_prompt(self, prompt):
         '''Parses the `prompt` string and returns the rendered version'''
         prompt = prompt.strip("'").replace("\\'","'")
         for colour in ansi.COLOURS_NAMED:
@@ -286,9 +326,11 @@ class TwitterShell(Action):
                             '[%s]' %(colour), ansi.cmdColourNamed(colour))
         prompt = prompt.replace('[R]', ansi.cmdReset())
         return prompt
+    
     def __call__(self, twitter, options):
         prompt = self.render_prompt(options.get('prompt', 'twitter> '))
         while True:
+            options['action'] = ""
             try:
                 args = raw_input(prompt).split()
                 parse_args(args, options)
@@ -384,4 +426,3 @@ def main(args=sys.argv[1:]):
         print >> sys.stderr, e.args[0]
         print >> sys.stderr, "Use 'twitter -h' for help."
         raise SystemExit(1)
-