]> jfr.im git - z_archive/twitter.git/blame - twitter/cmdline.py
Add reply action (patch by Wes Devauld)
[z_archive/twitter.git] / twitter / cmdline.py
CommitLineData
7364ea65 1"""
5251ea48 2USAGE:
7364ea65 3
5251ea48 4 twitter [action] [options]
5
6ACTIONS:
7
8 friends get latest tweets from your friends (default action)
9 public get latest public tweets
9a9f7ae7 10 replies get latest replies
5251ea48 11 set set your twitter status
12
13OPTIONS:
14
15 -e --email <email> your email to login to twitter
16 -p --password <password> your twitter password
0ea01db7 17 -r --refresh run this command forever, polling every once
18 in a while (default: every 5 minutes)
19 -R --refresh-rate <rate> set the refresh rate (in seconds)
20 -f --format <format> specify the output format for status updates
21e3bd23 21 -c --config <filename> read username and password from given config
22 file (default ~/.twitter)
0ea01db7 23
24FORMATS for the --format option
25
26 default one line per status
27 verbose multiple lines per status, more verbose status info
28 urls nothing but URLs. Dare you click them?
21e3bd23 29
30CONFIG FILES
31
32 The config file should contain your email and password like so:
33
34[twitter]
35email: <username>
36password: <password>
7364ea65 37"""
38
5251ea48 39import sys
0ea01db7 40import time
5251ea48 41from getopt import getopt
f068ff42 42from getpass import getpass
0ea01db7 43import re
21e3bd23 44import os.path
45from ConfigParser import SafeConfigParser
5251ea48 46
47from api import Twitter, TwitterError
48
49options = {
50 'email': None,
51 'password': None,
52 'action': 'friends',
0ea01db7 53 'refresh': False,
54 'refresh_rate': 600,
55 'format': 'default',
21e3bd23 56 'config_filename': os.environ.get('HOME', '') + os.sep + '.twitter',
5251ea48 57 'extra_args': []
58}
59
60def parse_args(args, options):
0ea01db7 61 long_opts = ['email', 'password', 'help', 'format', 'refresh',
21e3bd23 62 'refresh-rate', 'config']
63 short_opts = "e:p:f:h?rR:c:"
ae1d86aa 64 opts, extra_args = getopt(args, short_opts, long_opts)
5251ea48 65
66 for opt, arg in opts:
67 if opt in ('-e', '--email'):
68 options['email'] = arg
69 elif opt in ('-p', '--password'):
70 options['password'] = arg
0ea01db7 71 elif opt in ('-f', '--format'):
72 options['format'] = arg
73 elif opt in ('-r', '--refresh'):
74 options['refresh'] = True
75 elif opt in ('-R', '--refresh-rate'):
76 options['refresh_rate'] = int(arg)
5251ea48 77 elif opt in ('-?', '-h', '--help'):
78 print __doc__
79 sys.exit(0)
21e3bd23 80 elif opt in ('-c', '--config'):
81 options['config_filename'] = arg
ae1d86aa 82
83 if extra_args:
84 options['action'] = extra_args[0]
85 options['extra_args'] = extra_args[1:]
5251ea48 86
87class StatusFormatter(object):
88 def __call__(self, status):
f068ff42 89 return (u"%s %s" %(
0ea01db7 90 status['user']['screen_name'], status['text']))
5251ea48 91
f068ff42 92class VerboseStatusFormatter(object):
93 def __call__(self, status):
94 return (u"-- %s (%s) on %s\n%s\n" %(
95 status['user']['screen_name'],
96 status['user']['location'],
97 status['created_at'],
0ea01db7 98 status['text']))
f068ff42 99
0ea01db7 100class URLStatusFormatter(object):
101 urlmatch = re.compile(r'https?://\S+')
102 def __call__(self, status):
103 urls = self.urlmatch.findall(status['text'])
104 return u'\n'.join(urls) if urls else ""
105
106formatters = {
107 'default': StatusFormatter,
108 'verbose': VerboseStatusFormatter,
109 'urls': URLStatusFormatter
110}
f068ff42 111
0ea01db7 112def get_status_formatter(options):
113 sf = formatters.get(options['format'])
114 if (not sf):
115 raise TwitterError(
116 "Unknown formatter '%s'" %(options['format']))
117 return sf()
118
119class Action(object):
120 pass
121
122class NoSuchAction(Action):
123 def __call__(self, twitter, options):
124 print >> sys.stderr, "No such action: ", options['action']
125 sys.exit(1)
126
127class StatusAction(Action):
128 def __call__(self, twitter, options):
129 statuses = self.getStatuses(twitter)
130 sf = get_status_formatter(options)
131 for status in statuses:
132 statusStr = sf(status)
133 if statusStr.strip():
134 print statusStr.encode(sys.stdout.encoding, 'replace')
135
136class FriendsAction(StatusAction):
137 def getStatuses(self, twitter):
138 return reversed(twitter.statuses.friends_timeline())
9a9f7ae7 139
0ea01db7 140class PublicAction(StatusAction):
141 def getStatuses(self, twitter):
142 return reversed(twitter.statuses.public_timeline())
143
9a9f7ae7
MV
144class RepliesAction(StatusAction):
145 def getStatuses(self, twitter):
146 return reversed(twitter.statuses.replies())
147
0ea01db7 148class SetStatusAction(Action):
149 def __call__(self, twitter, options):
772fbdd1 150 statusTxt = (u" ".join(options['extra_args'])
151 if options['extra_args']
152 else unicode(raw_input("message: ")))
153 status = (statusTxt.encode('utf8', 'replace'))
0ea01db7 154 twitter.statuses.update(status=status)
5251ea48 155
156actions = {
0ea01db7 157 'friends': FriendsAction,
158 'public': PublicAction,
9a9f7ae7 159 'replies': RepliesAction,
0ea01db7 160 'set': SetStatusAction,
5251ea48 161}
162
21e3bd23 163def loadConfig(filename):
164 email = None
165 password = None
166 if os.path.exists(filename):
167 cp = SafeConfigParser()
168 cp.read([filename])
169 email = cp.get('twitter', 'email', None)
170 password = cp.get('twitter', 'password', None)
171 return email, password
ae1d86aa 172
7364ea65 173def main():
ae1d86aa 174 return main_with_args(sys.argv[1:])
175
176def main_with_args(args):
5251ea48 177 parse_args(args, options)
21e3bd23 178
179 email, password = loadConfig(options['config_filename'])
180 if not options['email']: options['email'] = email
181 if not options['password']: options['password'] = password
182
0ea01db7 183 if options['refresh'] and options['action'] == 'set':
184 print >> sys.stderr, "You can't repeatedly set your status, silly"
185 print >> sys.stderr, "Use 'twitter -h' for help."
186 sys.exit(1)
f068ff42 187 if options['email'] and not options['password']:
188 options['password'] = getpass("Twitter password: ")
5251ea48 189 twitter = Twitter(options['email'], options['password'])
0ea01db7 190 action = actions.get(options['action'], NoSuchAction)()
5251ea48 191 try:
0ea01db7 192 doAction = lambda : action(twitter, options)
193 if (options['refresh']):
194 while True:
195 doAction()
196 time.sleep(options['refresh_rate'])
197 else:
198 doAction()
5251ea48 199 except TwitterError, e:
f1a8ed67 200 print >> sys.stderr, e.args[0]
5251ea48 201 print >> sys.stderr, "Use 'twitter -h' for help."
202 sys.exit(1)
0ea01db7 203 except KeyboardInterrupt:
204 pass
205