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