]>
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
):
110 user_str
= u
"%s (%s)" %(user
['screen_name'], user
['name'])
111 if action
== "follow":
112 return u
"You are now following %s" %(user_str)
114 return u
"You are no longer following %s" %(user_str)
116 class VerboseAdminFormatter(object):
117 def __call__(self
, action
, user
):
118 return(u
"-- %s: %s (%s): %s" % (
119 "Following" if action
== "follow" else "Leaving",
124 class URLAdminFormatter(object):
125 def __call__(self
, action
, user
):
126 return("Admin actions do not support the URL formatter")
128 status_formatters
= {
129 'default': StatusFormatter
,
130 'verbose': VerboseStatusFormatter
,
131 'urls': URLStatusFormatter
135 'default': AdminFormatter
,
136 'verbose': VerboseAdminFormatter
,
137 'urls': URLAdminFormatter
140 def get_status_formatter(options
):
141 sf
= status_formatters
.get(options
['format'])
144 "Unknown formatter '%s'" %(options
['format']))
147 def get_admin_formatter(options
):
148 sf
= admin_formatters
.get(options
['format'])
151 "Unknown formatter '%s'" %(options
['format']))
154 class Action(object):
157 class NoSuchAction(Action
):
158 def __call__(self
, twitter
, options
):
159 print >> sys
.stderr
, "No such action: ", options
['action']
162 class StatusAction(Action
):
163 def __call__(self
, twitter
, options
):
164 statuses
= self
.getStatuses(twitter
)
165 sf
= get_status_formatter(options
)
166 for status
in statuses
:
167 statusStr
= sf(status
)
168 if statusStr
.strip():
169 print statusStr
.encode(sys
.stdout
.encoding
, 'replace')
171 class AdminAction(Action
):
172 def __call__(self
, twitter
, options
):
173 if not options
['extra_args'][0]:
174 raise TwitterError("You need to specify a User (Screen Name)")
175 af
= get_admin_formatter(options
)
176 user
= self
.getUser(twitter
, options
['extra_args'][0])
178 print af(options
['action'], user
).encode(sys
.stdout
.encoding
, 'replace')
180 class FriendsAction(StatusAction
):
181 def getStatuses(self
, twitter
):
182 return reversed(twitter
.statuses
.friends_timeline())
184 class PublicAction(StatusAction
):
185 def getStatuses(self
, twitter
):
186 return reversed(twitter
.statuses
.public_timeline())
188 class RepliesAction(StatusAction
):
189 def getStatuses(self
, twitter
):
190 return reversed(twitter
.statuses
.replies())
192 class FollowAction(AdminAction
):
193 def getUser(self
, twitter
, user
):
194 return twitter
.notifications
.follow(id=user
)
196 class LeaveAction(AdminAction
):
197 def getUser(self
, twitter
, user
):
198 return twitter
.notifications
.leave(id=user
)
200 class SetStatusAction(Action
):
201 def __call__(self
, twitter
, options
):
202 statusTxt
= (u
" ".join(options
['extra_args'])
203 if options
['extra_args']
204 else unicode(raw_input("message: ")))
205 status
= (statusTxt
.encode('utf8', 'replace'))
206 twitter
.statuses
.update(status
=status
)
209 'follow': FollowAction
,
210 'friends': FriendsAction
,
211 'leave': LeaveAction
,
212 'public': PublicAction
,
213 'replies': RepliesAction
,
214 'set': SetStatusAction
,
217 def loadConfig(filename
):
220 if os
.path
.exists(filename
):
221 cp
= SafeConfigParser()
223 email
= cp
.get('twitter', 'email', None)
224 password
= cp
.get('twitter', 'password', None)
225 return email
, password
228 return main_with_args(sys
.argv
[1:])
230 def main_with_args(args
):
231 parse_args(args
, options
)
233 email
, password
= loadConfig(options
['config_filename'])
234 if not options
['email']: options
['email'] = email
235 if not options
['password']: options
['password'] = password
237 #Maybe check for AdminAction here, but whatever you do, don't write TODO
238 if options
['refresh'] and options
['action'] == 'set':
239 print >> sys
.stderr
, "You can't repeatedly set your status, silly"
240 print >> sys
.stderr
, "Use 'twitter -h' for help."
242 if options
['email'] and not options
['password']:
243 options
['password'] = getpass("Twitter password: ")
244 twitter
= Twitter(options
['email'], options
['password'])
245 action
= actions
.get(options
['action'], NoSuchAction
)()
247 doAction
= lambda : action(twitter
, options
)
249 if (options
['refresh'] and isinstance(action
, StatusAction
)):
252 time
.sleep(options
['refresh_rate'])
256 except TwitterError
, e
:
257 print >> sys
.stderr
, e
.args
[0]
258 print >> sys
.stderr
, "Use 'twitter -h' for help."
260 except KeyboardInterrupt: