]>
jfr.im git - z_archive/twitter.git/blob - twitter/cmdline.py
4 twitter [action] [options]
7 follow add the specified user to your follow list
8 friends get latest tweets from your friends (default action)
9 leave remove the specified user from your following list
10 public get latest public tweets
11 replies get latest replies
12 set set your twitter status
16 -e --email <email> your email to login to twitter
17 -p --password <password> your twitter password
18 -r --refresh run this command forever, polling every once
19 in a while (default: every 5 minutes)
20 -R --refresh-rate <rate> set the refresh rate (in seconds)
21 -f --format <format> specify the output format for status updates
22 -c --config <filename> read username and password from given config
23 file (default ~/.twitter)
25 FORMATS for the --format option
27 default one line per status
28 verbose multiple lines per status, more verbose status info
29 urls nothing but URLs. Dare you click them?
33 The config file should contain a [twitter] header, your email and password
43 from getopt
import getopt
44 from getpass
import getpass
47 from ConfigParser
import SafeConfigParser
49 from api
import Twitter
, TwitterError
58 'config_filename': os
.environ
.get('HOME', '') + os
.sep
+ '.twitter',
62 def parse_args(args
, options
):
63 long_opts
= ['email', 'password', 'help', 'format', 'refresh',
64 'refresh-rate', 'config']
65 short_opts
= "e:p:f:h?rR:c:"
66 opts
, extra_args
= getopt(args
, short_opts
, long_opts
)
69 if opt
in ('-e', '--email'):
70 options
['email'] = arg
71 elif opt
in ('-p', '--password'):
72 options
['password'] = arg
73 elif opt
in ('-f', '--format'):
74 options
['format'] = arg
75 elif opt
in ('-r', '--refresh'):
76 options
['refresh'] = True
77 elif opt
in ('-R', '--refresh-rate'):
78 options
['refresh_rate'] = int(arg
)
79 elif opt
in ('-?', '-h', '--help'):
82 elif opt
in ('-c', '--config'):
83 options
['config_filename'] = arg
86 options
['action'] = extra_args
[0]
87 options
['extra_args'] = extra_args
[1:]
89 class StatusFormatter(object):
90 def __call__(self
, status
):
92 status
['user']['screen_name'], status
['text']))
94 class VerboseStatusFormatter(object):
95 def __call__(self
, status
):
96 return (u
"-- %s (%s) on %s\n%s\n" %(
97 status
['user']['screen_name'],
98 status
['user']['location'],
102 class URLStatusFormatter(object):
103 urlmatch
= re
.compile(r
'https?://\S+')
104 def __call__(self
, status
):
105 urls
= self
.urlmatch
.findall(status
['text'])
106 return u
'\n'.join(urls
) if urls
else ""
108 class AdminFormatter(object):
109 def __call__(self
, action
, user
):
111 "Following" if action
== "follow" else "Leaving", user
['name']))
113 class VerboseAdminFormatter(object):
114 def __call__(self
, action
, user
):
115 return(u
"-- %s: %s (%s): %s" % (
116 "Following" if action
== "follow" else "Leaving",
121 class URLAdminFormatter(object):
122 def __call__(self
, action
, user
):
123 return("Admin actions do not support the URL formatter")
125 status_formatters
= {
126 'default': StatusFormatter
,
127 'verbose': VerboseStatusFormatter
,
128 'urls': URLStatusFormatter
132 'default': AdminFormatter
,
133 'verbose': VerboseAdminFormatter
,
134 'urls': URLAdminFormatter
137 def get_status_formatter(options
):
138 sf
= status_formatters
.get(options
['format'])
141 "Unknown formatter '%s'" %(options
['format']))
144 def get_admin_formatter(options
):
145 sf
= admin_formatters
.get(options
['format'])
148 "Unknown formatter '%s'" %(options
['format']))
151 class Action(object):
154 class NoSuchAction(Action
):
155 def __call__(self
, twitter
, options
):
156 print >> sys
.stderr
, "No such action: ", options
['action']
159 class StatusAction(Action
):
160 def __call__(self
, twitter
, options
):
161 statuses
= self
.getStatuses(twitter
)
162 sf
= get_status_formatter(options
)
163 for status
in statuses
:
164 statusStr
= sf(status
)
165 if statusStr
.strip():
166 print statusStr
.encode(sys
.stdout
.encoding
, 'replace')
168 class AdminAction(Action
):
169 def __call__(self
, twitter
, options
):
170 if (not options
['extra_args'][0]):
171 raise TwitterError("You need to specify a User (Screen Name)")
172 af
= get_admin_formatter(options
)
173 user
= self
.getUser(twitter
, options
['extra_args'][0])
175 print af(options
['action'], user
).encode(sys
.stdout
.encoding
, 'replace')
177 class FriendsAction(StatusAction
):
178 def getStatuses(self
, twitter
):
179 return reversed(twitter
.statuses
.friends_timeline())
181 class PublicAction(StatusAction
):
182 def getStatuses(self
, twitter
):
183 return reversed(twitter
.statuses
.public_timeline())
185 class RepliesAction(StatusAction
):
186 def getStatuses(self
, twitter
):
187 return reversed(twitter
.statuses
.replies())
189 class FollowAction(AdminAction
):
190 def getUser(self
, twitter
, user
):
191 # Twitter wants /notifications/follow/user.json?id=user
192 return twitter
.notifications
.follow
.__getattr
__(user
)(id=user
)
194 class LeaveAction(AdminAction
):
195 def getUser(self
, twitter
, user
):
196 return twitter
.notifications
.leave
.__getattr
__(user
)(id=user
)
198 class SetStatusAction(Action
):
199 def __call__(self
, twitter
, options
):
200 statusTxt
= (u
" ".join(options
['extra_args'])
201 if options
['extra_args']
202 else unicode(raw_input("message: ")))
203 status
= (statusTxt
.encode('utf8', 'replace'))
204 twitter
.statuses
.update(status
=status
)
207 'follow': FollowAction
,
208 'friends': FriendsAction
,
209 'leave': LeaveAction
,
210 'public': PublicAction
,
211 'replies': RepliesAction
,
212 'set': SetStatusAction
,
215 def loadConfig(filename
):
218 if os
.path
.exists(filename
):
219 cp
= SafeConfigParser()
221 email
= cp
.get('twitter', 'email', None)
222 password
= cp
.get('twitter', 'password', None)
223 return email
, password
226 return main_with_args(sys
.argv
[1:])
228 def main_with_args(args
):
229 parse_args(args
, options
)
231 email
, password
= loadConfig(options
['config_filename'])
232 if not options
['email']: options
['email'] = email
233 if not options
['password']: options
['password'] = password
235 #Maybe check for AdminAction here, but whatever you do, don't write TODO
236 if options
['refresh'] and options
['action'] == 'set':
237 print >> sys
.stderr
, "You can't repeatedly set your status, silly"
238 print >> sys
.stderr
, "Use 'twitter -h' for help."
240 if options
['email'] and not options
['password']:
241 options
['password'] = getpass("Twitter password: ")
242 twitter
= Twitter(options
['email'], options
['password'])
243 action
= actions
.get(options
['action'], NoSuchAction
)()
245 doAction
= lambda : action(twitter
, options
)
247 if (options
['refresh'] and isinstance(action
, StatusAction
)):
250 time
.sleep(options
['refresh_rate'])
254 except TwitterError
, e
:
255 print >> sys
.stderr
, e
.args
[0]
256 print >> sys
.stderr
, "Use 'twitter -h' for help."
258 except KeyboardInterrupt: