]>
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 your email and password like so:
42 from getopt
import getopt
43 from getpass
import getpass
46 from ConfigParser
import SafeConfigParser
48 from api
import Twitter
, TwitterError
57 'config_filename': os
.environ
.get('HOME', '') + os
.sep
+ '.twitter',
61 def parse_args(args
, options
):
62 long_opts
= ['email', 'password', 'help', 'format', 'refresh',
63 'refresh-rate', 'config']
64 short_opts
= "e:p:f:h?rR:c:"
65 opts
, extra_args
= getopt(args
, short_opts
, long_opts
)
68 if opt
in ('-e', '--email'):
69 options
['email'] = arg
70 elif opt
in ('-p', '--password'):
71 options
['password'] = arg
72 elif opt
in ('-f', '--format'):
73 options
['format'] = arg
74 elif opt
in ('-r', '--refresh'):
75 options
['refresh'] = True
76 elif opt
in ('-R', '--refresh-rate'):
77 options
['refresh_rate'] = int(arg
)
78 elif opt
in ('-?', '-h', '--help'):
81 elif opt
in ('-c', '--config'):
82 options
['config_filename'] = arg
85 options
['action'] = extra_args
[0]
86 options
['extra_args'] = extra_args
[1:]
88 class StatusFormatter(object):
89 def __call__(self
, status
):
91 status
['user']['screen_name'], status
['text']))
93 class VerboseStatusFormatter(object):
94 def __call__(self
, status
):
95 return (u
"-- %s (%s) on %s\n%s\n" %(
96 status
['user']['screen_name'],
97 status
['user']['location'],
101 class URLStatusFormatter(object):
102 urlmatch
= re
.compile(r
'https?://\S+')
103 def __call__(self
, status
):
104 urls
= self
.urlmatch
.findall(status
['text'])
105 return u
'\n'.join(urls
) if urls
else ""
107 class AdminFormatter(object):
108 def __call__(self
, action
, user
):
110 "Following" if action
== "follow" else "Leaving", user
['name']))
112 class VerboseAdminFormatter(object):
113 def __call__(self
, action
, user
):
114 return(u
"-- %s: %s (%s): %s" % (
115 "Following" if action
== "follow" else "Leaving",
120 class URLAdminFormatter(object):
121 def __call__(self
, action
, user
):
122 return("Admin actions do not support the URL formatter")
124 status_formatters
= {
125 'default': StatusFormatter
,
126 'verbose': VerboseStatusFormatter
,
127 'urls': URLStatusFormatter
131 'default': AdminFormatter
,
132 'verbose': VerboseAdminFormatter
,
133 'urls': URLAdminFormatter
136 def get_status_formatter(options
):
137 sf
= status_formatters
.get(options
['format'])
140 "Unknown formatter '%s'" %(options
['format']))
143 def get_admin_formatter(options
):
144 sf
= admin_formatters
.get(options
['format'])
147 "Unknown formatter '%s'" %(options
['format']))
150 class Action(object):
153 class NoSuchAction(Action
):
154 def __call__(self
, twitter
, options
):
155 print >> sys
.stderr
, "No such action: ", options
['action']
158 class StatusAction(Action
):
159 def __call__(self
, twitter
, options
):
160 statuses
= self
.getStatuses(twitter
)
161 sf
= get_status_formatter(options
)
162 for status
in statuses
:
163 statusStr
= sf(status
)
164 if statusStr
.strip():
165 print statusStr
.encode(sys
.stdout
.encoding
, 'replace')
167 class AdminAction(Action
):
168 def __call__(self
, twitter
, options
):
169 if (not options
['extra_args'][0]):
170 raise TwitterError("You need to specify a User (Screen Name)")
171 af
= get_admin_formatter(options
)
172 user
= self
.getUser(twitter
, options
['extra_args'][0])
174 print af(options
['action'], user
).encode(sys
.stdout
.encoding
, 'replace')
176 class FriendsAction(StatusAction
):
177 def getStatuses(self
, twitter
):
178 return reversed(twitter
.statuses
.friends_timeline())
180 class PublicAction(StatusAction
):
181 def getStatuses(self
, twitter
):
182 return reversed(twitter
.statuses
.public_timeline())
184 class RepliesAction(StatusAction
):
185 def getStatuses(self
, twitter
):
186 return reversed(twitter
.statuses
.replies())
188 class FollowAction(AdminAction
):
189 def getUser(self
, twitter
, user
):
190 # Twitter wants /notifications/follow/user.json?id=user
191 return twitter
.notifications
.follow
.__getattr
__(user
)(id=user
)
193 class LeaveAction(AdminAction
):
194 def getUser(self
, twitter
, user
):
195 return twitter
.notifications
.leave
.__getattr
__(user
)(id=user
)
197 class SetStatusAction(Action
):
198 def __call__(self
, twitter
, options
):
199 statusTxt
= (u
" ".join(options
['extra_args'])
200 if options
['extra_args']
201 else unicode(raw_input("message: ")))
202 status
= (statusTxt
.encode('utf8', 'replace'))
203 twitter
.statuses
.update(status
=status
)
206 'follow': FollowAction
,
207 'friends': FriendsAction
,
208 'leave': LeaveAction
,
209 'public': PublicAction
,
210 'replies': RepliesAction
,
211 'set': SetStatusAction
,
214 def loadConfig(filename
):
217 if os
.path
.exists(filename
):
218 cp
= SafeConfigParser()
220 email
= cp
.get('twitter', 'email', None)
221 password
= cp
.get('twitter', 'password', None)
222 return email
, password
225 return main_with_args(sys
.argv
[1:])
227 def main_with_args(args
):
228 parse_args(args
, options
)
230 email
, password
= loadConfig(options
['config_filename'])
231 if not options
['email']: options
['email'] = email
232 if not options
['password']: options
['password'] = password
234 #Maybe check for AdminAction here, but whatever you do, don't write TODO
235 if options
['refresh'] and options
['action'] == 'set':
236 print >> sys
.stderr
, "You can't repeatedly set your status, silly"
237 print >> sys
.stderr
, "Use 'twitter -h' for help."
239 if options
['email'] and not options
['password']:
240 options
['password'] = getpass("Twitter password: ")
241 twitter
= Twitter(options
['email'], options
['password'])
242 action
= actions
.get(options
['action'], NoSuchAction
)()
244 doAction
= lambda : action(twitter
, options
)
246 if (options
['refresh'] and isinstance(action
, StatusAction
)):
249 time
.sleep(options
['refresh_rate'])
253 except TwitterError
, e
:
254 print >> sys
.stderr
, e
.args
[0]
255 print >> sys
.stderr
, "Use 'twitter -h' for help."
257 except KeyboardInterrupt: