view timeline, reply, delete
[rainbowstream.git] / rainbowstream / rainbow.py
CommitLineData
91476ec3
O
1"""
2Colorful user's timeline stream
3"""
4
5from __future__ import print_function
54277114 6from multiprocessing import Process
91476ec3 7
22be990e 8import os
9import os.path
10import argparse
11import sys
12import time
13import signal
91476ec3
O
14
15from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 16from twitter.api import *
91476ec3 17from twitter.oauth import OAuth, read_token_file
8c840a83 18from twitter.oauth_dance import oauth_dance
91476ec3
O
19from twitter.util import printNicely
20from dateutil import parser
91476ec3 21
2a6238f5
O
22from .colors import *
23from .config import *
24
f405a7d0 25g = {}
91476ec3 26
22be990e 27
28def draw(t, keyword=None):
91476ec3
O
29 """
30 Draw the rainbow
31 """
32 # Retrieve tweet
829cc2d8 33 tid = t['id']
91476ec3
O
34 text = t['text']
35 screen_name = t['user']['screen_name']
36 name = t['user']['name']
37 created_at = t['created_at']
38 date = parser.parse(created_at)
39 time = date.strftime('%Y/%m/%d %H:%M:%S')
40
41 # Format info
54277114 42 user = cycle_color(name) + grey(' ' + '@' + screen_name + ' ')
7b674cef 43 meta = grey('[' + time + '] [id=' + str(tid) + ']')
8c840a83 44 tweet = text.split()
b8dda704 45 # Highlight RT
2a6238f5 46 tweet = map(lambda x: grey(x) if x == 'RT' else x, tweet)
b8dda704 47 # Highlight screen_name
2a6238f5 48 tweet = map(lambda x: cycle_color(x) if x[0] == '@' else x, tweet)
b8dda704 49 # Highlight link
2a6238f5 50 tweet = map(lambda x: cyan(x) if x[0:7] == 'http://' else x, tweet)
b8dda704 51 # Highlight search keyword
7a431249 52 if keyword:
22be990e 53 tweet = map(
54 lambda x: on_yellow(x) if
55 ''.join(c for c in x if c.isalnum()).lower() == keyword.lower()
56 else x,
57 tweet
58 )
8c840a83 59 tweet = ' '.join(tweet)
91476ec3
O
60
61 # Draw rainbow
06773ffe 62 line1 = u"{u:>{uw}}:".format(
2a6238f5
O
63 u=user,
64 uw=len(user) + 2,
91476ec3 65 )
06773ffe 66 line2 = u"{c:>{cw}}".format(
829cc2d8
O
67 c=meta,
68 cw=len(meta) + 2,
06773ffe
O
69 )
70 line3 = ' ' + tweet
91476ec3 71
f405a7d0
O
72 printNicely(line1)
73 printNicely(line2)
74 printNicely(line3)
829cc2d8 75 printNicely('')
91476ec3
O
76
77
78def parse_arguments():
79 """
80 Parse the arguments
81 """
91476ec3 82 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
83 parser.add_argument(
84 '-to',
85 '--timeout',
86 help='Timeout for the stream (seconds).')
87 parser.add_argument(
88 '-ht',
89 '--heartbeat-timeout',
90 help='Set heartbeat timeout.',
91 default=90)
92 parser.add_argument(
93 '-nb',
94 '--no-block',
95 action='store_true',
96 help='Set stream to non-blocking.')
97 parser.add_argument(
98 '-tt',
99 '--track-keywords',
100 help='Search the stream for specific text.')
91476ec3
O
101 return parser.parse_args()
102
103
54277114
O
104def authen():
105 """
7b674cef 106 Authenticate with Twitter OAuth
54277114 107 """
8c840a83 108 # When using rainbow stream you must authorize.
2a6238f5
O
109 twitter_credential = os.environ.get(
110 'HOME',
111 os.environ.get(
112 'USERPROFILE',
113 '')) + os.sep + '.rainbow_oauth'
8c840a83
O
114 if not os.path.exists(twitter_credential):
115 oauth_dance("Rainbow Stream",
116 CONSUMER_KEY,
117 CONSUMER_SECRET,
118 twitter_credential)
119 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 120 return OAuth(
2a6238f5
O
121 oauth_token,
122 oauth_token_secret,
123 CONSUMER_KEY,
124 CONSUMER_SECRET)
91476ec3 125
54277114
O
126
127def get_decorated_name():
128 """
129 Beginning of every line
130 """
131 t = Twitter(auth=authen())
132 name = '@' + t.statuses.user_timeline()[-1]['user']['screen_name']
f405a7d0 133 g['decorated_name'] = grey('[') + grey(name) + grey(']: ')
54277114 134
f405a7d0 135
7b674cef 136def home():
137 """
138 Home
139 """
140 t = Twitter(auth=authen())
141 count = HOME_TWEET_NUM
142 if g['stuff'].isdigit():
143 count = g['stuff']
144 for tweet in reversed(t.statuses.home_timeline(count=count)):
145 draw(t=tweet)
146
147
148def view():
149 """
150 Friend view
151 """
152 t = Twitter(auth=authen())
153 user = g['stuff'].split()[0]
154 try:
155 count = int(g['stuff'].split()[1])
156 except:
157 count = HOME_TWEET_NUM
158 for tweet in reversed(t.statuses.user_timeline(count=count, screen_name=user)):
159 draw(t=tweet)
160
161
f405a7d0 162def tweet():
54277114 163 """
7b674cef 164 Tweet
54277114
O
165 """
166 t = Twitter(auth=authen())
f405a7d0
O
167 t.statuses.update(status=g['stuff'])
168
169
7b674cef 170def reply():
829cc2d8 171 """
7b674cef 172 Reply
829cc2d8
O
173 """
174 t = Twitter(auth=authen())
7b674cef 175 try:
176 id = int(g['stuff'].split()[0])
177 user = t.statuses.show(id=id)['user']['screen_name']
178 status = ' '.join(g['stuff'].split()[1:])
179 status = '@' + user + ' ' + status.decode('utf-8')
180 t.statuses.update(status=status, in_reply_to_status_id=id)
181 except:
182 print(red('Sorry I can\'t understand.'))
183
184
185def delete():
186 """
187 Delete
188 """
189 t = Twitter(auth=authen())
190 try:
191 id = int(g['stuff'].split()[0])
192 t.statuses.destroy(id=id)
193 print(green('Okay it\'s gone.'))
194 except:
195 print(red('Sorry I can\'t delete this tweet for you.'))
829cc2d8
O
196
197
f405a7d0
O
198def search():
199 """
7b674cef 200 Search
f405a7d0
O
201 """
202 t = Twitter(auth=authen())
203 rel = t.search.tweets(q='#' + g['stuff'])['statuses']
2a911483 204 h, w = os.popen('stty size', 'r').read().split()
205
22be990e 206 printNicely(grey('*' * int(w) + '\n'))
207 print('Newest', SEARCH_MAX_RECORD, 'tweet: \n')
f405a7d0 208 for i in xrange(5):
22be990e 209 draw(t=rel[i], keyword=g['stuff'].strip())
210 printNicely(grey('*' * int(w) + '\n'))
f405a7d0
O
211
212
843647ad
O
213def friend():
214 """
215 List of friend (following)
216 """
217 t = Twitter(auth=authen())
218 g['friends'] = t.friends.ids()['ids']
219 for i in g['friends']:
220 screen_name = t.users.lookup(user_id=i)[0]['screen_name']
22be990e 221 user = cycle_color('@' + screen_name)
843647ad 222 print(user, end=' ')
22be990e 223 print('\n')
843647ad
O
224
225
226def follower():
227 """
228 List of follower
229 """
230 t = Twitter(auth=authen())
231 g['followers'] = t.followers.ids()['ids']
232 for i in g['followers']:
233 screen_name = t.users.lookup(user_id=i)[0]['screen_name']
22be990e 234 user = cycle_color('@' + screen_name)
843647ad 235 print(user, end=' ')
22be990e 236 print('\n')
843647ad
O
237
238
f405a7d0
O
239def help():
240 """
7b674cef 241 Help
f405a7d0
O
242 """
243 usage = '''
244 Hi boss! I'm ready to serve you right now!
245 ----------------------------------------------------
7b674cef 246 "home" will show your timeline. "home 7" will print 7 tweet.
247 "view bob" will show your friend @bob's home.
248 "t oops" will tweet "oops" immediately.
249 "rep 12345 oops" will reply "oops" to tweet with id "12345" .
250 "del 12345" will delete tweet with id "12345".
251 "s AKB48" will search for "AKB48" and return 5 newest tweet
843647ad
O
252 "fr" will list out your following people
253 "fl" will list out your followers
829cc2d8 254 "h" or "help" will print this help once again
b8dda704 255 "c" will clear the terminal
f405a7d0
O
256 "q" will exit
257 ----------------------------------------------------
843647ad 258 Have fun and hang tight!
f405a7d0
O
259 '''
260 printNicely(usage)
261 sys.stdout.write(g['decorated_name'])
262
263
843647ad 264def clear():
f405a7d0 265 """
7b674cef 266 Clear screen
f405a7d0 267 """
843647ad 268 os.system('clear')
f405a7d0
O
269
270
843647ad 271def quit():
b8dda704
O
272 """
273 Exit all
274 """
843647ad
O
275 os.kill(g['stream_pid'], signal.SIGKILL)
276 sys.exit()
b8dda704
O
277
278
843647ad 279def process(cmd):
f405a7d0 280 """
7b674cef 281 Process switch
f405a7d0
O
282 """
283 return {
7b674cef 284 'home': home,
285 'view': view,
286 't': tweet,
287 'rep': reply,
288 'del': delete,
289 's': search,
290 'fr': friend,
291 'fl': follower,
292 'h': help,
293 'help': help,
294 'c': clear,
295 'q': quit,
22be990e 296 }.get(cmd, lambda: sys.stdout.write(g['decorated_name']))
54277114
O
297
298
299def listen(stdin):
300 """
301 Listen to user's input
302 """
303 for line in iter(stdin.readline, ''):
843647ad
O
304 try:
305 cmd = line.split()[0]
306 except:
307 cmd = ''
f405a7d0 308 # Save cmd to global variable and call process
843647ad
O
309 g['stuff'] = ' '.join(line.split()[1:])
310 process(cmd)()
54277114
O
311 stdin.close()
312
313
314def stream():
315 """
f405a7d0 316 Track the stream
54277114
O
317 """
318 args = parse_arguments()
319
320 # The Logo
321 ascii_art()
91476ec3
O
322 # These arguments are optional:
323 stream_args = dict(
324 timeout=args.timeout,
325 block=not args.no_block,
326 heartbeat_timeout=args.heartbeat_timeout)
327
328 # Track keyword
329 query_args = dict()
330 if args.track_keywords:
331 query_args['track'] = args.track_keywords
332
333 # Get stream
2a6238f5 334 stream = TwitterStream(
22be990e 335 auth=authen(),
336 domain='userstream.twitter.com',
2a6238f5 337 **stream_args)
91476ec3
O
338 tweet_iter = stream.user(**query_args)
339
340 # Iterate over the sample stream.
341 for tweet in tweet_iter:
342 if tweet is None:
343 printNicely("-- None --")
344 elif tweet is Timeout:
345 printNicely("-- Timeout --")
346 elif tweet is HeartbeatTimeout:
347 printNicely("-- Heartbeat Timeout --")
348 elif tweet is Hangup:
349 printNicely("-- Hangup --")
350 elif tweet.get('text'):
f405a7d0 351 draw(t=tweet)
54277114
O
352
353
354def fly():
355 """
356 Main function
357 """
358 get_decorated_name()
22be990e 359 p = Process(target=stream)
54277114 360 p.start()
f405a7d0 361 g['stream_pid'] = p.pid
54277114 362 listen(sys.stdin)