refactoring
[rainbowstream.git] / rainbowstream / rainbow.py
CommitLineData
91476ec3
O
1"""
2Colorful user's timeline stream
3"""
b2b933a9 4import os
5import os.path
6import sys
7import signal
8import argparse
9import time
92983945 10import threading
991c30af 11import requests
80b70d60 12import webbrowser
91476ec3 13
91476ec3 14from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 15from twitter.api import *
91476ec3 16from twitter.oauth import OAuth, read_token_file
8c840a83 17from twitter.oauth_dance import oauth_dance
91476ec3 18from twitter.util import printNicely
91476ec3 19
7500d90b 20from .draw import *
2a6238f5
O
21from .colors import *
22from .config import *
777c52d4 23from .consumer import *
94a5f62e 24from .interactive import *
991c30af 25from .c_image import *
c3bab4ef 26from .py3patch import *
27
531f5682 28# Global values
f405a7d0 29g = {}
531f5682 30
92983945 31# Lock for streams
92983945
BS
32StreamLock = threading.Lock()
33
c075e6dc 34
91476ec3
O
35def parse_arguments():
36 """
37 Parse the arguments
38 """
91476ec3 39 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
40 parser.add_argument(
41 '-to',
42 '--timeout',
43 help='Timeout for the stream (seconds).')
44 parser.add_argument(
45 '-ht',
46 '--heartbeat-timeout',
47 help='Set heartbeat timeout.',
48 default=90)
49 parser.add_argument(
50 '-nb',
51 '--no-block',
52 action='store_true',
53 help='Set stream to non-blocking.')
54 parser.add_argument(
55 '-tt',
56 '--track-keywords',
57 help='Search the stream for specific text.')
d51b4107
O
58 parser.add_argument(
59 '-fil',
60 '--filter',
61 help='Filter specific screen_name.')
62 parser.add_argument(
63 '-ig',
64 '--ignore',
65 help='Ignore specific screen_name.')
88af38d8 66 parser.add_argument(
c1fa7c94
O
67 '-iot',
68 '--image-on-term',
69 action='store_true',
70 help='Display all image on terminal.')
91476ec3
O
71 return parser.parse_args()
72
73
54277114
O
74def authen():
75 """
7b674cef 76 Authenticate with Twitter OAuth
54277114 77 """
8c840a83 78 # When using rainbow stream you must authorize.
2a6238f5
O
79 twitter_credential = os.environ.get(
80 'HOME',
81 os.environ.get(
82 'USERPROFILE',
83 '')) + os.sep + '.rainbow_oauth'
8c840a83
O
84 if not os.path.exists(twitter_credential):
85 oauth_dance("Rainbow Stream",
86 CONSUMER_KEY,
87 CONSUMER_SECRET,
88 twitter_credential)
89 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 90 return OAuth(
2a6238f5
O
91 oauth_token,
92 oauth_token_secret,
93 CONSUMER_KEY,
94 CONSUMER_SECRET)
91476ec3 95
54277114 96
e3927852
O
97def build_mute_dict(dict_data=False):
98 """
99 Build muting list
100 """
101 t = Twitter(auth=authen())
102 # Init cursor
103 next_cursor = -1
104 screen_name_list = []
105 name_list = []
106 # Cursor loop
107 while next_cursor != 0:
108 list = t.mutes.users.list(
109 screen_name=g['original_name'],
110 cursor=next_cursor,
111 skip_status=True,
112 include_entities=False,
113 )
114 screen_name_list += ['@' + u['screen_name'] for u in list['users']]
115 name_list += [u['name'] for u in list['users']]
116 next_cursor = list['next_cursor']
117 # Return dict or list
118 if dict_data:
119 return dict(zip(screen_name_list, name_list))
120 else:
121 return screen_name_list
122
123
fe9bb33b 124def init(args):
54277114 125 """
9683e61d 126 Init function
54277114 127 """
64156ac4
O
128 # Handle Ctrl C
129 ctrl_c_handler = lambda signum, frame: quit()
130 signal.signal(signal.SIGINT, ctrl_c_handler)
9683e61d 131 # Get name
54277114 132 t = Twitter(auth=authen())
c5ff542b 133 name = '@' + t.account.verify_credentials()['screen_name']
ceec8593 134 if not get_config('PREFIX'):
135 set_config('PREFIX', name)
42fde775 136 g['original_name'] = name[1:]
ceec8593 137 g['decorated_name'] = lambda x: color_func(
a8e71259 138 c['DECORATED_NAME'])('[' + x + ']: ')
9683e61d 139 # Theme init
422dd385 140 files = os.listdir(os.path.dirname(__file__) + '/colorset')
c075e6dc 141 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
632c6fa5 142 g['themes'] = themes
4824b181 143 # Startup cmd
f1c1dfea 144 g['cmd'] = ''
9683e61d 145 # Semaphore init
99b52f5f
O
146 c['lock'] = False
147 c['pause'] = False
148 # Init tweet dict and message dict
149 c['tweet_dict'] = []
150 c['message_dict'] = []
fe9bb33b 151 # Image on term
152 c['IMAGE_ON_TERM'] = args.image_on_term
62686013 153 set_config('IMAGE_ON_TERM', str(c['IMAGE_ON_TERM']))
e3927852
O
154 # Mute dict
155 c['IGNORE_LIST'] += build_mute_dict()
f405a7d0 156
ceec8593 157
42fde775 158def switch():
159 """
160 Switch stream
161 """
162 try:
163 target = g['stuff'].split()[0]
d51b4107
O
164 # Filter and ignore
165 args = parse_arguments()
7e4ccbf3 166 try:
d51b4107 167 if g['stuff'].split()[-1] == '-f':
14db58c7 168 guide = 'To ignore an option, just hit Enter key.'
169 printNicely(light_magenta(guide))
170 only = raw_input('Only nicks [Ex: @xxx,@yy]: ')
171 ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
7e4ccbf3 172 args.filter = filter(None, only.split(','))
173 args.ignore = filter(None, ignore.split(','))
d51b4107 174 elif g['stuff'].split()[-1] == '-d':
632c6fa5
O
175 args.filter = c['ONLY_LIST']
176 args.ignore = c['IGNORE_LIST']
d51b4107
O
177 except:
178 printNicely(red('Sorry, wrong format.'))
179 return
42fde775 180 # Public stream
181 if target == 'public':
182 keyword = g['stuff'].split()[1]
183 if keyword[0] == '#':
184 keyword = keyword[1:]
92983945
BS
185 # Kill old thread
186 g['stream_stop'] = True
42fde775 187 args.track_keywords = keyword
92983945 188 # Start new thread
baec5f50 189 th = threading.Thread(
190 target=stream,
191 args=(
192 c['PUBLIC_DOMAIN'],
193 args))
92983945
BS
194 th.daemon = True
195 th.start()
42fde775 196 # Personal stream
197 elif target == 'mine':
92983945
BS
198 # Kill old thread
199 g['stream_stop'] = True
200 # Start new thread
baec5f50 201 th = threading.Thread(
202 target=stream,
203 args=(
204 c['USER_DOMAIN'],
205 args,
206 g['original_name']))
92983945
BS
207 th.daemon = True
208 th.start()
d51b4107 209 printNicely('')
d51b4107
O
210 if args.filter:
211 printNicely(cyan('Only: ' + str(args.filter)))
212 if args.ignore:
213 printNicely(red('Ignore: ' + str(args.ignore)))
214 printNicely('')
49514d7e 215 except:
42fde775 216 printNicely(red('Sorry I can\'t understand.'))
42fde775 217
218
4592d231 219def trend():
220 """
221 Trend
222 """
223 t = Twitter(auth=authen())
48a25fe8 224 # Get country and town
4592d231 225 try:
226 country = g['stuff'].split()[0]
227 except:
228 country = ''
48a25fe8 229 try:
230 town = g['stuff'].split()[1]
231 except:
232 town = ''
48a25fe8 233 avail = t.trends.available()
234 # World wide
235 if not country:
236 trends = t.trends.place(_id=1)[0]['trends']
237 print_trends(trends)
238 else:
239 for location in avail:
240 # Search for country and Town
241 if town:
242 if location['countryCode'] == country \
243 and location['placeType']['name'] == 'Town' \
244 and location['name'] == town:
245 trends = t.trends.place(_id=location['woeid'])[0]['trends']
246 print_trends(trends)
247 # Search for country only
248 else:
249 if location['countryCode'] == country \
250 and location['placeType']['name'] == 'Country':
251 trends = t.trends.place(_id=location['woeid'])[0]['trends']
252 print_trends(trends)
4592d231 253
254
7b674cef 255def home():
256 """
257 Home
258 """
259 t = Twitter(auth=authen())
632c6fa5 260 num = c['HOME_TWEET_NUM']
7b674cef 261 if g['stuff'].isdigit():
305ce127 262 num = int(g['stuff'])
94a5f62e 263 for tweet in reversed(t.statuses.home_timeline(count=num)):
fe9bb33b 264 draw(t=tweet)
94a5f62e 265 printNicely('')
7b674cef 266
267
268def view():
269 """
270 Friend view
271 """
272 t = Twitter(auth=authen())
273 user = g['stuff'].split()[0]
b8fbcb70 274 if user[0] == '@':
275 try:
94a5f62e 276 num = int(g['stuff'].split()[1])
b8fbcb70 277 except:
632c6fa5 278 num = c['HOME_TWEET_NUM']
94a5f62e 279 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
fe9bb33b 280 draw(t=tweet)
94a5f62e 281 printNicely('')
b8fbcb70 282 else:
c91f75f2 283 printNicely(red('A name should begin with a \'@\''))
7b674cef 284
285
305ce127 286def mentions():
287 """
288 Mentions timeline
289 """
290 t = Twitter(auth=authen())
632c6fa5 291 num = c['HOME_TWEET_NUM']
305ce127 292 if g['stuff'].isdigit():
293 num = int(g['stuff'])
294 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
fe9bb33b 295 draw(t=tweet)
305ce127 296 printNicely('')
297
298
f405a7d0 299def tweet():
54277114 300 """
7b674cef 301 Tweet
54277114
O
302 """
303 t = Twitter(auth=authen())
f405a7d0 304 t.statuses.update(status=g['stuff'])
f405a7d0 305
b2b933a9 306
1ba4abfd
O
307def retweet():
308 """
309 ReTweet
310 """
311 t = Twitter(auth=authen())
312 try:
313 id = int(g['stuff'].split()[0])
1ba4abfd 314 except:
b8c1f42a
O
315 printNicely(red('Sorry I can\'t understand.'))
316 return
99b52f5f 317 tid = c['tweet_dict'][id]
b8c1f42a 318 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
1ba4abfd
O
319
320
80b70d60
O
321def quote():
322 """
323 Quote a tweet
324 """
325 t = Twitter(auth=authen())
326 try:
327 id = int(g['stuff'].split()[0])
328 except:
329 printNicely(red('Sorry I can\'t understand.'))
330 return
99b52f5f 331 tid = c['tweet_dict'][id]
80b70d60
O
332 tweet = t.statuses.show(id=tid)
333 screen_name = tweet['user']['screen_name']
334 text = tweet['text']
335 quote = '\"@' + screen_name + ': ' + text + '\"'
336 quote = quote.encode('utf8')
595fdb16
O
337 notice = light_magenta('Compose mode ')
338 notice += light_yellow('(Enter nothing will cancel the quote)')
339 notice += light_magenta(':')
340 printNicely(notice)
80b70d60
O
341 extra = raw_input(quote)
342 if extra:
422dd385 343 t.statuses.update(status=quote + extra)
80b70d60
O
344 else:
345 printNicely(light_magenta('No text added.'))
346
347
1f24a05a 348def allretweet():
349 """
350 List all retweet
351 """
352 t = Twitter(auth=authen())
353 # Get rainbow id
354 try:
355 id = int(g['stuff'].split()[0])
356 except:
357 printNicely(red('Sorry I can\'t understand.'))
358 return
99b52f5f 359 tid = c['tweet_dict'][id]
1f24a05a 360 # Get display num if exist
361 try:
362 num = int(g['stuff'].split()[1])
363 except:
632c6fa5 364 num = c['RETWEETS_SHOW_NUM']
1f24a05a 365 # Get result and display
d8e901a4 366 rt_ary = t.statuses.retweets(id=tid, count=num)
1f24a05a 367 if not rt_ary:
368 printNicely(magenta('This tweet has no retweet.'))
369 return
370 for tweet in reversed(rt_ary):
fe9bb33b 371 draw(t=tweet)
1f24a05a 372 printNicely('')
373
374
7e4ccbf3 375def favorite():
376 """
377 Favorite
378 """
379 t = Twitter(auth=authen())
380 try:
381 id = int(g['stuff'].split()[0])
7e4ccbf3 382 except:
b8c1f42a
O
383 printNicely(red('Sorry I can\'t understand.'))
384 return
99b52f5f 385 tid = c['tweet_dict'][id]
b8c1f42a
O
386 t.favorites.create(_id=tid, include_entities=False)
387 printNicely(green('Favorited.'))
fe9bb33b 388 draw(t.statuses.show(id=tid))
b8c1f42a 389 printNicely('')
7e4ccbf3 390
391
7b674cef 392def reply():
829cc2d8 393 """
7b674cef 394 Reply
829cc2d8
O
395 """
396 t = Twitter(auth=authen())
7b674cef 397 try:
398 id = int(g['stuff'].split()[0])
7b674cef 399 except:
c91f75f2 400 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a 401 return
99b52f5f 402 tid = c['tweet_dict'][id]
b8c1f42a
O
403 user = t.statuses.show(id=tid)['user']['screen_name']
404 status = ' '.join(g['stuff'].split()[1:])
612d6863 405 status = '@' + user + ' ' + unc(status)
b8c1f42a 406 t.statuses.update(status=status, in_reply_to_status_id=tid)
7b674cef 407
408
409def delete():
410 """
411 Delete
412 """
413 t = Twitter(auth=authen())
414 try:
99b52f5f 415 id = int(g['stuff'].split()[0])
7b674cef 416 except:
305ce127 417 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a 418 return
99b52f5f 419 tid = c['tweet_dict'][id]
b8c1f42a
O
420 t.statuses.destroy(id=tid)
421 printNicely(green('Okay it\'s gone.'))
829cc2d8
O
422
423
7e4ccbf3 424def unfavorite():
425 """
426 Unfavorite
427 """
428 t = Twitter(auth=authen())
429 try:
430 id = int(g['stuff'].split()[0])
7e4ccbf3 431 except:
b8c1f42a
O
432 printNicely(red('Sorry I can\'t understand.'))
433 return
99b52f5f 434 tid = c['tweet_dict'][id]
b8c1f42a
O
435 t.favorites.destroy(_id=tid)
436 printNicely(green('Okay it\'s unfavorited.'))
fe9bb33b 437 draw(t.statuses.show(id=tid))
b8c1f42a 438 printNicely('')
7e4ccbf3 439
440
f405a7d0
O
441def search():
442 """
7b674cef 443 Search
f405a7d0
O
444 """
445 t = Twitter(auth=authen())
59262e95
O
446 g['stuff'] = g['stuff'].strip()
447 rel = t.search.tweets(q=g['stuff'])['statuses']
448 if rel:
449 printNicely('Newest tweets:')
450 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
451 draw(t=rel[i],
59262e95
O
452 keyword=g['stuff'])
453 printNicely('')
b8c1f42a 454 else:
59262e95 455 printNicely(magenta('I\'m afraid there is no result'))
b2b933a9 456
f405a7d0 457
305ce127 458def message():
459 """
460 Send a direct message
461 """
462 t = Twitter(auth=authen())
463 user = g['stuff'].split()[0]
b8c1f42a 464 if user[0].startswith('@'):
305ce127 465 try:
466 content = g['stuff'].split()[1]
305ce127 467 except:
468 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
469 t.direct_messages.new(
470 screen_name=user[1:],
471 text=content
472 )
473 printNicely(green('Message sent.'))
305ce127 474 else:
475 printNicely(red('A name should begin with a \'@\''))
476
477
f5677fb1 478def show():
843647ad 479 """
f5677fb1 480 Show image
843647ad
O
481 """
482 t = Twitter(auth=authen())
f5677fb1
O
483 try:
484 target = g['stuff'].split()[0]
485 if target != 'image':
486 return
487 id = int(g['stuff'].split()[1])
99b52f5f 488 tid = c['tweet_dict'][id]
f5677fb1
O
489 tweet = t.statuses.show(id=tid)
490 media = tweet['entities']['media']
491 for m in media:
492 res = requests.get(m['media_url'])
b3164e62 493 img = Image.open(BytesIO(res.content))
f5677fb1
O
494 img.show()
495 except:
496 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
497
498
80bb2040 499def urlopen():
80b70d60
O
500 """
501 Open url
502 """
503 t = Twitter(auth=authen())
504 try:
505 if not g['stuff'].isdigit():
506 return
8101275e 507 tid = c['tweet_dict'][int(g['stuff'])]
80b70d60 508 tweet = t.statuses.show(id=tid)
422dd385
O
509 link_ary = [
510 u for u in tweet['text'].split() if u.startswith('http://')]
80b70d60
O
511 if not link_ary:
512 printNicely(light_magenta('No url here @.@!'))
513 return
514 for link in link_ary:
515 webbrowser.open(link)
516 except:
517 printNicely(red('Sorry I can\'t open url in this tweet.'))
518
519
2d341029 520def ls():
0f6e4daf 521 """
522 List friends for followers
523 """
524 t = Twitter(auth=authen())
e2b81717
O
525 # Get name
526 try:
527 name = g['stuff'].split()[1]
b8c1f42a 528 if name.startswith('@'):
e2b81717
O
529 name = name[1:]
530 else:
531 printNicely(red('A name should begin with a \'@\''))
532 raise Exception('Invalid name')
533 except:
534 name = g['original_name']
535 # Get list followers or friends
0f6e4daf 536 try:
537 target = g['stuff'].split()[0]
0f6e4daf 538 except:
539 printNicely(red('Omg some syntax is wrong.'))
b8c1f42a
O
540 # Init cursor
541 d = {'fl': 'followers', 'fr': 'friends'}
542 next_cursor = -1
543 rel = {}
544 # Cursor loop
545 while next_cursor != 0:
546 list = getattr(t, d[target]).list(
547 screen_name=name,
548 cursor=next_cursor,
549 skip_status=True,
550 include_entities=False,
551 )
552 for u in list['users']:
553 rel[u['name']] = '@' + u['screen_name']
554 next_cursor = list['next_cursor']
555 # Print out result
2d341029 556 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
b8c1f42a 557 for name in rel:
2d341029 558 user = ' ' + cycle_color(name)
422dd385 559 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
b8c1f42a 560 printNicely(user)
0f6e4daf 561
562
305ce127 563def inbox():
564 """
565 Inbox direct messages
566 """
567 t = Twitter(auth=authen())
632c6fa5 568 num = c['MESSAGES_DISPLAY']
305ce127 569 rel = []
570 if g['stuff'].isdigit():
571 num = g['stuff']
572 cur_page = 1
573 # Max message per page is 20 so we have to loop
574 while num > 20:
575 rel = rel + t.direct_messages(
576 count=20,
577 page=cur_page,
578 include_entities=False,
579 skip_status=False
48a25fe8 580 )
305ce127 581 num -= 20
582 cur_page += 1
583 rel = rel + t.direct_messages(
584 count=num,
585 page=cur_page,
586 include_entities=False,
587 skip_status=False
48a25fe8 588 )
e2b81717 589 # Display
305ce127 590 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
591 for m in reversed(rel):
592 print_message(m)
593 printNicely('')
594
e2b81717 595
305ce127 596def sent():
597 """
598 Sent direct messages
599 """
600 t = Twitter(auth=authen())
632c6fa5 601 num = c['MESSAGES_DISPLAY']
305ce127 602 rel = []
603 if g['stuff'].isdigit():
604 num = int(g['stuff'])
605 cur_page = 1
606 # Max message per page is 20 so we have to loop
607 while num > 20:
608 rel = rel + t.direct_messages.sent(
609 count=20,
610 page=cur_page,
611 include_entities=False,
612 skip_status=False
48a25fe8 613 )
305ce127 614 num -= 20
615 cur_page += 1
616 rel = rel + t.direct_messages.sent(
617 count=num,
618 page=cur_page,
619 include_entities=False,
620 skip_status=False
48a25fe8 621 )
e2b81717 622 # Display
305ce127 623 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
624 for m in reversed(rel):
625 print_message(m)
626 printNicely('')
e2b81717 627
305ce127 628
629def trash():
630 """
631 Remove message
632 """
633 t = Twitter(auth=authen())
634 try:
99b52f5f 635 id = int(g['stuff'].split()[0])
305ce127 636 except:
637 printNicely(red('Sorry I can\'t understand.'))
99b52f5f 638 mid = c['message_dict'][id]
b8c1f42a
O
639 t.direct_messages.destroy(id=mid)
640 printNicely(green('Message deleted.'))
305ce127 641
642
e2b81717
O
643def whois():
644 """
645 Show profile of a specific user
646 """
647 t = Twitter(auth=authen())
648 screen_name = g['stuff'].split()[0]
b8c1f42a 649 if screen_name.startswith('@'):
e2b81717
O
650 try:
651 user = t.users.show(
652 screen_name=screen_name[1:],
653 include_entities=False)
fe9bb33b 654 show_profile(user)
e2b81717
O
655 except:
656 printNicely(red('Omg no user.'))
657 else:
b8c1f42a 658 printNicely(red('A name should begin with a \'@\''))
e2b81717
O
659
660
f5677fb1 661def follow():
843647ad 662 """
f5677fb1 663 Follow a user
843647ad
O
664 """
665 t = Twitter(auth=authen())
f5677fb1 666 screen_name = g['stuff'].split()[0]
b8c1f42a
O
667 if screen_name.startswith('@'):
668 t.friendships.create(screen_name=screen_name[1:], follow=True)
669 printNicely(green('You are following ' + screen_name + ' now!'))
f5677fb1 670 else:
b8c1f42a 671 printNicely(red('A name should begin with a \'@\''))
f5677fb1
O
672
673
674def unfollow():
675 """
676 Unfollow a user
677 """
678 t = Twitter(auth=authen())
679 screen_name = g['stuff'].split()[0]
b8c1f42a
O
680 if screen_name.startswith('@'):
681 t.friendships.destroy(
682 screen_name=screen_name[1:],
683 include_entities=False)
684 printNicely(green('Unfollow ' + screen_name + ' success!'))
f5677fb1 685 else:
b8c1f42a 686 printNicely(red('A name should begin with a \'@\''))
843647ad
O
687
688
5b2c4faf 689def mute():
690 """
691 Mute a user
692 """
693 t = Twitter(auth=authen())
694 try:
695 screen_name = g['stuff'].split()[0]
696 except:
697 printNicely(red('A name should be specified. '))
698 return
699 if screen_name.startswith('@'):
e3927852
O
700 try:
701 rel = t.mutes.users.create(screen_name=screen_name[1:])
702 if isinstance(rel, dict):
703 printNicely(green(screen_name + ' is muted.'))
612d6863 704 c['IGNORE_LIST'] += [unc(screen_name)]
e3927852
O
705 c['IGNORE_LIST'] = list(set(c['IGNORE_LIST']))
706 else:
707 printNicely(red(rel))
708 except:
709 printNicely(red('Something is wrong, can not mute now :('))
5b2c4faf 710 else:
711 printNicely(red('A name should begin with a \'@\''))
712
713
714def unmute():
715 """
716 Unmute a user
717 """
718 t = Twitter(auth=authen())
719 try:
720 screen_name = g['stuff'].split()[0]
721 except:
722 printNicely(red('A name should be specified. '))
723 return
724 if screen_name.startswith('@'):
e3927852
O
725 try:
726 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
727 if isinstance(rel, dict):
728 printNicely(green(screen_name + ' is unmuted.'))
729 c['IGNORE_LIST'].remove(screen_name)
730 else:
731 printNicely(red(rel))
732 except:
733 printNicely(red('Maybe you are not muting this person ?'))
5b2c4faf 734 else:
735 printNicely(red('A name should begin with a \'@\''))
736
737
738def muting():
739 """
740 List muting user
741 """
e3927852
O
742 # Get dict of muting users
743 md = build_mute_dict(dict_data=True)
744 printNicely('All: ' + str(len(md)) + ' people.')
745 for name in md:
746 user = ' ' + cycle_color(md[name])
747 user += color_func(c['TWEET']['nick'])(' ' + name + ' ')
5b2c4faf 748 printNicely(user)
e3927852
O
749 # Update from Twitter
750 c['IGNORE_LIST'] = [n for n in md]
5b2c4faf 751
752
305ce127 753def block():
754 """
755 Block a user
756 """
757 t = Twitter(auth=authen())
758 screen_name = g['stuff'].split()[0]
b8c1f42a
O
759 if screen_name.startswith('@'):
760 t.blocks.create(
5b2c4faf 761 screen_name=screen_name[1:],
762 include_entities=False,
763 skip_status=True)
b8c1f42a 764 printNicely(green('You blocked ' + screen_name + '.'))
305ce127 765 else:
b8c1f42a 766 printNicely(red('A name should begin with a \'@\''))
305ce127 767
768
769def unblock():
770 """
771 Unblock a user
772 """
773 t = Twitter(auth=authen())
774 screen_name = g['stuff'].split()[0]
b8c1f42a
O
775 if screen_name.startswith('@'):
776 t.blocks.destroy(
777 screen_name=screen_name[1:],
778 include_entities=False,
779 skip_status=True)
780 printNicely(green('Unblock ' + screen_name + ' success!'))
305ce127 781 else:
b8c1f42a 782 printNicely(red('A name should begin with a \'@\''))
305ce127 783
784
785def report():
786 """
787 Report a user as a spam account
788 """
789 t = Twitter(auth=authen())
790 screen_name = g['stuff'].split()[0]
b8c1f42a
O
791 if screen_name.startswith('@'):
792 t.users.report_spam(
793 screen_name=screen_name[1:])
794 printNicely(green('You reported ' + screen_name + '.'))
305ce127 795 else:
796 printNicely(red('Sorry I can\'t understand.'))
797
798
8b8566d1
O
799def get_slug():
800 """
801 Get Slug Decorator
802 """
a8c5fce4 803 # Get list name
8b8566d1
O
804 list_name = raw_input(light_magenta('Give me the list\'s name: '))
805 # Get list name and owner
806 try:
807 owner, slug = list_name.split('/')
808 if slug.startswith('@'):
809 slug = slug[1:]
810 return owner, slug
811 except:
a8c5fce4
O
812 printNicely(
813 light_magenta('List name should follow "@owner/list_name" format.'))
8b8566d1
O
814 raise Exception('Wrong list name')
815
816
2d341029
O
817def show_lists(t):
818 """
422dd385 819 List list
2d341029
O
820 """
821 rel = t.lists.list(screen_name=g['original_name'])
822 if rel:
823 print_list(rel)
824 else:
825 printNicely(light_magenta('You belong to no lists :)'))
826
827
828def list_home(t):
829 """
830 List home
831 """
8b8566d1 832 owner, slug = get_slug()
2d341029 833 res = t.lists.statuses(
422dd385
O
834 slug=slug,
835 owner_screen_name=owner,
836 count=c['LIST_MAX'],
2d341029
O
837 include_entities=False)
838 for tweet in res:
839 draw(t=tweet)
840 printNicely('')
841
842
843def list_members(t):
844 """
845 List members
846 """
8b8566d1 847 owner, slug = get_slug()
422dd385 848 # Get members
2d341029
O
849 rel = {}
850 next_cursor = -1
422dd385 851 while next_cursor != 0:
2d341029 852 m = t.lists.members(
422dd385
O
853 slug=slug,
854 owner_screen_name=owner,
855 cursor=next_cursor,
2d341029
O
856 include_entities=False)
857 for u in m['users']:
858 rel[u['name']] = '@' + u['screen_name']
859 next_cursor = m['next_cursor']
860 printNicely('All: ' + str(len(rel)) + ' members.')
861 for name in rel:
862 user = ' ' + cycle_color(name)
422dd385 863 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
864 printNicely(user)
865
866
867def list_subscribers(t):
868 """
869 List subscribers
870 """
8b8566d1 871 owner, slug = get_slug()
422dd385 872 # Get subscribers
2d341029
O
873 rel = {}
874 next_cursor = -1
422dd385 875 while next_cursor != 0:
2d341029 876 m = t.lists.subscribers(
422dd385
O
877 slug=slug,
878 owner_screen_name=owner,
879 cursor=next_cursor,
2d341029
O
880 include_entities=False)
881 for u in m['users']:
882 rel[u['name']] = '@' + u['screen_name']
883 next_cursor = m['next_cursor']
884 printNicely('All: ' + str(len(rel)) + ' subscribers.')
885 for name in rel:
886 user = ' ' + cycle_color(name)
422dd385 887 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
888 printNicely(user)
889
890
422dd385
O
891def list_add(t):
892 """
893 Add specific user to a list
894 """
8b8566d1 895 owner, slug = get_slug()
422dd385
O
896 # Add
897 user_name = raw_input(light_magenta('Give me name of the newbie: '))
898 if user_name.startswith('@'):
899 user_name = user_name[1:]
900 try:
901 t.lists.members.create(
902 slug=slug,
903 owner_screen_name=owner,
904 screen_name=user_name)
d6cc4c67 905 printNicely(green('Added.'))
422dd385
O
906 except:
907 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
908
909
2d341029
O
910def list_remove(t):
911 """
912 Remove specific user from a list
913 """
8b8566d1 914 owner, slug = get_slug()
2d341029 915 # Remove
422dd385
O
916 user_name = raw_input(light_magenta('Give me name of the unlucky one: '))
917 if user_name.startswith('@'):
918 user_name = user_name[1:]
2d341029
O
919 try:
920 t.lists.members.destroy(
422dd385
O
921 slug=slug,
922 owner_screen_name=owner,
923 screen_name=user_name)
d6cc4c67 924 printNicely(green('Gone.'))
422dd385
O
925 except:
926 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
927
928
929def list_subscribe(t):
930 """
931 Subscribe to a list
932 """
8b8566d1 933 owner, slug = get_slug()
422dd385
O
934 # Subscribe
935 try:
936 t.lists.subscribers.create(
937 slug=slug,
938 owner_screen_name=owner)
d6cc4c67 939 printNicely(green('Done.'))
422dd385
O
940 except:
941 printNicely(
942 light_magenta('I\'m sorry you can not subscribe to this list.'))
943
944
945def list_unsubscribe(t):
946 """
947 Unsubscribe a list
948 """
8b8566d1 949 owner, slug = get_slug()
422dd385
O
950 # Subscribe
951 try:
952 t.lists.subscribers.destroy(
953 slug=slug,
954 owner_screen_name=owner)
d6cc4c67 955 printNicely(green('Done.'))
422dd385
O
956 except:
957 printNicely(
958 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
959
960
961def list_own(t):
962 """
963 List own
964 """
965 rel = []
966 next_cursor = -1
967 while next_cursor != 0:
968 res = t.lists.ownerships(
969 screen_name=g['original_name'],
970 cursor=next_cursor)
971 rel += res['lists']
972 next_cursor = res['next_cursor']
973 if rel:
974 print_list(rel)
975 else:
976 printNicely(light_magenta('You own no lists :)'))
977
978
979def list_new(t):
980 """
981 Create a new list
982 """
983 name = raw_input(light_magenta('New list\'s name: '))
984 mode = raw_input(light_magenta('New list\'s mode (public/private): '))
985 description = raw_input(light_magenta('New list\'s description: '))
986 try:
987 t.lists.create(
988 name=name,
989 mode=mode,
990 description=description)
d6cc4c67 991 printNicely(green(name + ' list is created.'))
422dd385
O
992 except:
993 printNicely(red('Oops something is wrong with Twitter :('))
994
995
996def list_update(t):
997 """
998 Update a list
999 """
1000 slug = raw_input(light_magenta('Your list that you want to update: '))
1001 name = raw_input(light_magenta('Update name (leave blank to unchange): '))
1002 mode = raw_input(light_magenta('Update mode (public/private): '))
1003 description = raw_input(light_magenta('Update description: '))
1004 try:
1005 if name:
1006 t.lists.update(
1007 slug='-'.join(slug.split()),
1008 owner_screen_name=g['original_name'],
1009 name=name,
1010 mode=mode,
1011 description=description)
1012 else:
1013 t.lists.update(
1014 slug=slug,
1015 owner_screen_name=g['original_name'],
1016 mode=mode,
1017 description=description)
d6cc4c67 1018 printNicely(green(slug + ' list is updated.'))
3c85d8fc 1019 except:
422dd385
O
1020 printNicely(red('Oops something is wrong with Twitter :('))
1021
1022
1023def list_delete(t):
1024 """
1025 Delete a list
1026 """
1027 slug = raw_input(light_magenta('Your list that you want to update: '))
1028 try:
1029 t.lists.destroy(
1030 slug='-'.join(slug.split()),
1031 owner_screen_name=g['original_name'])
d6cc4c67 1032 printNicely(green(slug + ' list is deleted.'))
2d341029 1033 except:
422dd385 1034 printNicely(red('Oops something is wrong with Twitter :('))
2d341029
O
1035
1036
e3927852 1037def twitterlist():
2d341029
O
1038 """
1039 Twitter's list
1040 """
1041 t = Twitter(auth=authen())
1042 # List all lists or base on action
1043 try:
1044 g['list_action'] = g['stuff'].split()[0]
1045 except:
1046 show_lists(t)
1047 return
422dd385 1048 # Sub-function
2d341029
O
1049 action_ary = {
1050 'home': list_home,
1051 'all_mem': list_members,
1052 'all_sub': list_subscribers,
422dd385 1053 'add': list_add,
2d341029 1054 'rm': list_remove,
422dd385
O
1055 'sub': list_subscribe,
1056 'unsub': list_unsubscribe,
1057 'own': list_own,
1058 'new': list_new,
1059 'update': list_update,
1060 'del': list_delete,
2d341029
O
1061 }
1062 try:
1063 return action_ary[g['list_action']](t)
3c85d8fc 1064 except:
8b8566d1 1065 printNicely(red('Please try again.'))
2d341029
O
1066
1067
813a5d80 1068def cal():
1069 """
1070 Unix's command `cal`
1071 """
1072 # Format
1073 rel = os.popen('cal').read().split('\n')
1074 month = rel.pop(0)
813a5d80 1075 date = rel.pop(0)
2a0cabee 1076 show_calendar(month, date, rel)
813a5d80 1077
1078
29fd0be6
O
1079def config():
1080 """
1081 Browse and change config
1082 """
1083 all_config = get_all_config()
1084 g['stuff'] = g['stuff'].strip()
1085 # List all config
1086 if not g['stuff']:
1087 for k in all_config:
a8c5fce4 1088 line = ' ' * 2 + \
d6cc4c67 1089 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1090 printNicely(line)
1091 guide = 'Detailed explanation can be found at ' + \
a8c5fce4
O
1092 color_func(c['TWEET']['link'])(
1093 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
29fd0be6
O
1094 printNicely(guide)
1095 # Print specific config
1096 elif len(g['stuff'].split()) == 1:
1097 if g['stuff'] in all_config:
1098 k = g['stuff']
a8c5fce4 1099 line = ' ' * 2 + \
d6cc4c67 1100 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1101 printNicely(line)
1102 else:
fe9bb33b 1103 printNicely(red('No such config key.'))
29fd0be6
O
1104 # Print specific config's default value
1105 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'default':
1106 key = g['stuff'].split()[0]
fe9bb33b 1107 try:
1108 value = get_default_config(key)
d6cc4c67 1109 line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
fe9bb33b 1110 printNicely(line)
a8e71259 1111 except Exception as e:
1112 printNicely(red(e))
fe9bb33b 1113 # Delete specific config key in config file
1114 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop':
1115 key = g['stuff'].split()[0]
1116 try:
1117 delete_config(key)
d6cc4c67 1118 printNicely(green('Config key is dropped.'))
a8e71259 1119 except Exception as e:
1120 printNicely(red(e))
29fd0be6 1121 # Set specific config
a8c5fce4 1122 elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=':
29fd0be6
O
1123 key = g['stuff'].split()[0]
1124 value = g['stuff'].split()[-1]
ceec8593 1125 if key == 'THEME' and not validate_theme(value):
1126 printNicely(red('Invalid theme\'s value.'))
1127 return
3c01ba57 1128 try:
a8c5fce4 1129 set_config(key, value)
ceec8593 1130 # Apply theme immediately
1131 if key == 'THEME':
baec5f50 1132 c['THEME'] = reload_theme(value, c['THEME'])
ceec8593 1133 g['decorated_name'] = lambda x: color_func(
a8e71259 1134 c['DECORATED_NAME'])('[' + x + ']: ')
1135 reload_config()
d6cc4c67 1136 printNicely(green('Updated successfully.'))
a8e71259 1137 except Exception as e:
1138 printNicely(red(e))
29fd0be6
O
1139 else:
1140 printNicely(light_magenta('Sorry I can\'s understand.'))
1141
1142
632c6fa5
O
1143def theme():
1144 """
1145 List and change theme
1146 """
1147 if not g['stuff']:
1148 # List themes
1149 for theme in g['themes']:
1f2f6159
O
1150 line = light_magenta(theme)
1151 if c['THEME'] == theme:
422dd385 1152 line = ' ' * 2 + light_yellow('* ') + line
ddb1e615 1153 else:
422dd385 1154 line = ' ' * 4 + line
632c6fa5
O
1155 printNicely(line)
1156 else:
1157 # Change theme
c075e6dc 1158 try:
ceec8593 1159 # Load new theme
baec5f50 1160 c['THEME'] = reload_theme(g['stuff'], c['THEME'])
ceec8593 1161 # Redefine decorated_name
1162 g['decorated_name'] = lambda x: color_func(
c075e6dc 1163 c['DECORATED_NAME'])(
ceec8593 1164 '[' + x + ']: ')
632c6fa5 1165 printNicely(green('Theme changed.'))
7f4a813a 1166 except:
1f2f6159 1167 printNicely(red('No such theme exists.'))
632c6fa5
O
1168
1169
2d341029 1170def help_discover():
f405a7d0 1171 """
2d341029 1172 Discover the world
f405a7d0 1173 """
7e4ccbf3 1174 s = ' ' * 2
1f24a05a 1175 # Discover the world
2d341029 1176 usage = '\n'
8bc30efd 1177 usage += s + grey(u'\u266A' + ' Discover the world \n')
c075e6dc
O
1178 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1179 'You can try ' + light_green('trend US') + ' or ' + \
1180 light_green('trend JP Tokyo') + '.\n'
1181 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1182 light_green('home 7') + ' will show 7 tweets.\n'
1183 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1184 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1185 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
8bc30efd 1186 magenta('@mdo') + '.\n'
c075e6dc 1187 usage += s * 2 + light_green('view @mdo') + \
8bc30efd 1188 ' will show ' + magenta('@mdo') + '\'s home.\n'
03e08f86
O
1189 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1190 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1191 'Search can be performed with or without hashtag.\n'
2d341029
O
1192 printNicely(usage)
1193
8bc30efd 1194
2d341029
O
1195def help_tweets():
1196 """
1197 Tweets
1198 """
1199 s = ' ' * 2
1f24a05a 1200 # Tweet
2d341029 1201 usage = '\n'
8bc30efd 1202 usage += s + grey(u'\u266A' + ' Tweets \n')
c075e6dc
O
1203 usage += s * 2 + light_green('t oops ') + \
1204 'will tweet "' + light_yellow('oops') + '" immediately.\n'
7e4ccbf3 1205 usage += s * 2 + \
c075e6dc
O
1206 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1207 light_yellow('[id=12]') + '.\n'
80b70d60
O
1208 usage += s * 2 + \
1209 light_green('quote 12 ') + ' will quote the tweet with ' + \
1210 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1211 'the quote will be canceled.\n'
1f24a05a 1212 usage += s * 2 + \
c075e6dc
O
1213 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1214 light_yellow('[id=12]') + '.\n'
1215 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
1216 light_yellow('oops') + '" to tweet with ' + \
1217 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1218 usage += s * 2 + \
c075e6dc
O
1219 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1220 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1221 usage += s * 2 + \
c075e6dc
O
1222 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1223 light_yellow('[id=12]') + '.\n'
8bc30efd 1224 usage += s * 2 + \
c075e6dc
O
1225 light_green('del 12 ') + ' will delete tweet with ' + \
1226 light_yellow('[id=12]') + '.\n'
1227 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1228 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
80b70d60
O
1229 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1230 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
2d341029 1231 printNicely(usage)
8bc30efd 1232
2d341029
O
1233
1234def help_messages():
1235 """
1236 Messages
1237 """
1238 s = ' ' * 2
5b2c4faf 1239 # Direct message
2d341029 1240 usage = '\n'
8bc30efd 1241 usage += s + grey(u'\u266A' + ' Direct messages \n')
c075e6dc
O
1242 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1243 light_green('inbox 7') + ' will show newest 7 messages.\n'
1244 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
1245 light_green('sent 7') + ' will show newest 7 messages.\n'
1246 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
8bc30efd 1247 magenta('@dtvd88') + '.\n'
c075e6dc
O
1248 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1249 light_yellow('[message_id=5]') + '.\n'
2d341029 1250 printNicely(usage)
8bc30efd 1251
2d341029
O
1252
1253def help_friends_and_followers():
1254 """
1255 Friends and Followers
1256 """
1257 s = ' ' * 2
8bc30efd 1258 # Follower and following
2d341029 1259 usage = '\n'
cdccb0d6 1260 usage += s + grey(u'\u266A' + ' Friends and followers \n')
8bc30efd 1261 usage += s * 2 + \
c075e6dc 1262 light_green('ls fl') + \
8bc30efd 1263 ' will list all followers (people who are following you).\n'
1264 usage += s * 2 + \
c075e6dc 1265 light_green('ls fr') + \
8bc30efd 1266 ' will list all friends (people who you are following).\n'
c075e6dc 1267 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
305ce127 1268 magenta('@dtvd88') + '.\n'
c075e6dc 1269 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 1270 magenta('@dtvd88') + '.\n'
c075e6dc 1271 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
5b2c4faf 1272 magenta('@dtvd88') + '.\n'
c075e6dc 1273 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
5b2c4faf 1274 magenta('@dtvd88') + '.\n'
c075e6dc
O
1275 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1276 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
305ce127 1277 magenta('@dtvd88') + '.\n'
c075e6dc 1278 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
305ce127 1279 magenta('@dtvd88') + '.\n'
c075e6dc 1280 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
305ce127 1281 magenta('@dtvd88') + ' as a spam account.\n'
2d341029
O
1282 printNicely(usage)
1283
1284
1285def help_list():
1286 """
1287 Lists
1288 """
1289 s = ' ' * 2
1290 # Twitter list
1291 usage = '\n'
1292 usage += s + grey(u'\u266A' + ' Twitter list\n')
1293 usage += s * 2 + light_green('list') + \
1294 ' will show all lists you are belong to.\n'
1295 usage += s * 2 + light_green('list home') + \
bef33491 1296 ' will show timeline of list. You will be asked for list\'s name.\n'
a65bd34c 1297 usage += s * 2 + light_green('list all_mem') + \
2d341029 1298 ' will show list\'s all members.\n'
a65bd34c 1299 usage += s * 2 + light_green('list all_sub') + \
2d341029 1300 ' will show list\'s all subscribers.\n'
422dd385
O
1301 usage += s * 2 + light_green('list add') + \
1302 ' will add specific person to a list owned by you.' + \
1303 ' You will be asked for list\'s name and person\'s name.\n'
2d341029
O
1304 usage += s * 2 + light_green('list rm') + \
1305 ' will remove specific person from a list owned by you.' + \
1306 ' You will be asked for list\'s name and person\'s name.\n'
422dd385
O
1307 usage += s * 2 + light_green('list sub') + \
1308 ' will subscribe you to a specific list.\n'
1309 usage += s * 2 + light_green('list unsub') + \
1310 ' will unsubscribe you from a specific list.\n'
1311 usage += s * 2 + light_green('list own') + \
1312 ' will show all list owned by you.\n'
1313 usage += s * 2 + light_green('list new') + \
1314 ' will create a new list.\n'
1315 usage += s * 2 + light_green('list update') + \
1316 ' will update a list owned by you.\n'
1317 usage += s * 2 + light_green('list del') + \
1318 ' will delete a list owned by you.\n'
2d341029 1319 printNicely(usage)
8bc30efd 1320
2d341029
O
1321
1322def help_stream():
1323 """
1324 Stream switch
1325 """
1326 s = ' ' * 2
8bc30efd 1327 # Switch
2d341029 1328 usage = '\n'
8bc30efd 1329 usage += s + grey(u'\u266A' + ' Switching streams \n')
c075e6dc 1330 usage += s * 2 + light_green('switch public #AKB') + \
48a25fe8 1331 ' will switch to public stream and follow "' + \
c075e6dc
O
1332 light_yellow('AKB') + '" keyword.\n'
1333 usage += s * 2 + light_green('switch mine') + \
48a25fe8 1334 ' will switch to your personal stream.\n'
c075e6dc 1335 usage += s * 2 + light_green('switch mine -f ') + \
48a25fe8 1336 ' will prompt to enter the filter.\n'
c075e6dc 1337 usage += s * 3 + light_yellow('Only nicks') + \
48a25fe8 1338 ' filter will decide nicks will be INCLUDE ONLY.\n'
c075e6dc 1339 usage += s * 3 + light_yellow('Ignore nicks') + \
48a25fe8 1340 ' filter will decide nicks will be EXCLUDE.\n'
c075e6dc 1341 usage += s * 2 + light_green('switch mine -d') + \
48a25fe8 1342 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
2d341029
O
1343 printNicely(usage)
1344
1345
1346def help():
1347 """
1348 Help
1349 """
1350 s = ' ' * 2
1351 h, w = os.popen('stty size', 'r').read().split()
2d341029
O
1352 # Start
1353 usage = '\n'
1354 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1355 usage += s + '-' * (int(w) - 4) + '\n'
1356 usage += s + 'You are ' + \
1357 light_yellow('already') + ' on your personal stream.\n'
1358 usage += s + 'Any update from Twitter will show up ' + \
1359 light_yellow('immediately') + '.\n'
1360 usage += s + 'In addtion, following commands are available right now:\n'
2d341029
O
1361 # Twitter help section
1362 usage += '\n'
1363 usage += s + grey(u'\u266A' + ' Twitter help\n')
1364 usage += s * 2 + light_green('h discover') + \
1365 ' will show help for discover commands.\n'
1366 usage += s * 2 + light_green('h tweets') + \
1367 ' will show help for tweets commands.\n'
1368 usage += s * 2 + light_green('h messages') + \
1369 ' will show help for messages commands.\n'
1370 usage += s * 2 + light_green('h friends_and_followers') + \
1371 ' will show help for friends and followers commands.\n'
1372 usage += s * 2 + light_green('h list') + \
1373 ' will show help for list commands.\n'
1374 usage += s * 2 + light_green('h stream') + \
1375 ' will show help for stream commands.\n'
1f24a05a 1376 # Smart shell
1377 usage += '\n'
1378 usage += s + grey(u'\u266A' + ' Smart shell\n')
c075e6dc 1379 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1f24a05a 1380 'will be evaluate by Python interpreter.\n'
c075e6dc 1381 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1f24a05a 1382 ' for current month.\n'
29fd0be6 1383 # Config
1f24a05a 1384 usage += '\n'
29fd0be6
O
1385 usage += s + grey(u'\u266A' + ' Config \n')
1386 usage += s * 2 + light_green('theme') + ' will list available theme. ' + \
c075e6dc 1387 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
632c6fa5 1388 ' theme immediately.\n'
29fd0be6
O
1389 usage += s * 2 + light_green('config') + ' will list all config.\n'
1390 usage += s * 3 + \
1391 light_green('config ASCII_ART') + ' will output current value of ' +\
a8c5fce4 1392 light_yellow('ASCII_ART') + ' config key.\n'
29fd0be6 1393 usage += s * 3 + \
fe9bb33b 1394 light_green('config TREND_MAX default') + ' will output default value of ' + \
1395 light_yellow('TREND_MAX') + ' config key.\n'
1396 usage += s * 3 + \
1397 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1398 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
29fd0be6 1399 usage += s * 3 + \
fe9bb33b 1400 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1401 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1402 light_yellow('True') + '.\n'
29fd0be6
O
1403 # Screening
1404 usage += '\n'
1405 usage += s + grey(u'\u266A' + ' Screening \n')
c075e6dc 1406 usage += s * 2 + light_green('h') + ' will show this help again.\n'
d6cc4c67
O
1407 usage += s * 2 + light_green('p') + ' will pause the stream.\n'
1408 usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
c075e6dc
O
1409 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1410 usage += s * 2 + light_green('q') + ' will quit.\n'
8bc30efd 1411 # End
1412 usage += '\n'
7e4ccbf3 1413 usage += s + '-' * (int(w) - 4) + '\n'
8bc30efd 1414 usage += s + 'Have fun and hang tight! \n'
2d341029
O
1415 # Show help
1416 d = {
422dd385
O
1417 'discover': help_discover,
1418 'tweets': help_tweets,
1419 'messages': help_messages,
1420 'friends_and_followers': help_friends_and_followers,
1421 'list': help_list,
1422 'stream': help_stream,
2d341029
O
1423 }
1424 if g['stuff']:
baec5f50 1425 d.get(
1426 g['stuff'].strip(),
1427 lambda: printNicely(red('No such command.'))
3d48702f 1428 )()
2d341029
O
1429 else:
1430 printNicely(usage)
f405a7d0
O
1431
1432
d6cc4c67
O
1433def pause():
1434 """
1435 Pause stream display
1436 """
99b52f5f 1437 c['pause'] = True
d6cc4c67
O
1438 printNicely(green('Stream is paused'))
1439
1440
1441def replay():
1442 """
1443 Replay stream
1444 """
99b52f5f 1445 c['pause'] = False
d6cc4c67
O
1446 printNicely(green('Stream is running back now'))
1447
1448
843647ad 1449def clear():
f405a7d0 1450 """
7b674cef 1451 Clear screen
f405a7d0 1452 """
843647ad 1453 os.system('clear')
f405a7d0
O
1454
1455
843647ad 1456def quit():
b8dda704
O
1457 """
1458 Exit all
1459 """
4c025026 1460 try:
1461 save_history()
4c025026 1462 printNicely(green('See you next time :)'))
1463 except:
1464 pass
843647ad 1465 sys.exit()
b8dda704
O
1466
1467
94a5f62e 1468def reset():
f405a7d0 1469 """
94a5f62e 1470 Reset prefix of line
f405a7d0 1471 """
c91f75f2 1472 if g['reset']:
a8e71259 1473 if c.get('USER_JSON_ERROR'):
1474 printNicely(red('Your ~/.rainbow_config.json is messed up:'))
1475 printNicely(red('>>> ' + c['USER_JSON_ERROR']))
1476 printNicely('')
e3885f55 1477 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 1478 g['reset'] = False
d0a726d6 1479 try:
779b0640 1480 printNicely(str(eval(g['cmd'])))
2a0cabee 1481 except Exception:
d0a726d6 1482 pass
54277114
O
1483
1484
f1c1dfea
O
1485# Command set
1486cmdset = [
1487 'switch',
1488 'trend',
1489 'home',
1490 'view',
1491 'mentions',
1492 't',
1493 'rt',
1494 'quote',
1495 'allrt',
1496 'fav',
1497 'rep',
1498 'del',
1499 'ufav',
1500 's',
1501 'mes',
1502 'show',
1503 'open',
1504 'ls',
1505 'inbox',
1506 'sent',
1507 'trash',
1508 'whois',
1509 'fl',
1510 'ufl',
1511 'mute',
1512 'unmute',
1513 'muting',
1514 'block',
1515 'unblock',
1516 'report',
1517 'list',
1518 'cal',
1519 'config',
1520 'theme',
1521 'h',
1522 'p',
1523 'r',
1524 'c',
1525 'q'
1526]
1527
1528# Handle function set
1529funcset = [
1530 switch,
1531 trend,
1532 home,
1533 view,
1534 mentions,
1535 tweet,
1536 retweet,
1537 quote,
1538 allretweet,
1539 favorite,
1540 reply,
1541 delete,
1542 unfavorite,
1543 search,
1544 message,
1545 show,
1546 urlopen,
1547 ls,
1548 inbox,
1549 sent,
1550 trash,
1551 whois,
1552 follow,
1553 unfollow,
1554 mute,
1555 unmute,
1556 muting,
1557 block,
1558 unblock,
1559 report,
1560 twitterlist,
1561 cal,
1562 config,
1563 theme,
1564 help,
1565 pause,
1566 replay,
1567 clear,
1568 quit
1569]
1570
1571
94a5f62e 1572def process(cmd):
54277114 1573 """
94a5f62e 1574 Process switch
54277114 1575 """
f1c1dfea 1576 return dict(zip(cmdset, funcset)).get(cmd, reset)
94a5f62e 1577
1578
1579def listen():
42fde775 1580 """
1581 Listen to user's input
1582 """
d51b4107
O
1583 d = dict(zip(
1584 cmdset,
1585 [
affcb149 1586 ['public', 'mine'], # switch
4592d231 1587 [], # trend
7e4ccbf3 1588 [], # home
1589 ['@'], # view
305ce127 1590 [], # mentions
7e4ccbf3 1591 [], # tweet
1592 [], # retweet
80b70d60 1593 [], # quote
1f24a05a 1594 [], # allretweet
f5677fb1 1595 [], # favorite
7e4ccbf3 1596 [], # reply
1597 [], # delete
f5677fb1 1598 [], # unfavorite
7e4ccbf3 1599 ['#'], # search
305ce127 1600 ['@'], # message
f5677fb1 1601 ['image'], # show image
80b70d60 1602 [''], # open url
305ce127 1603 ['fl', 'fr'], # list
1604 [], # inbox
1605 [], # sent
1606 [], # trash
e2b81717 1607 ['@'], # whois
affcb149
O
1608 ['@'], # follow
1609 ['@'], # unfollow
5b2c4faf 1610 ['@'], # mute
1611 ['@'], # unmute
1612 ['@'], # muting
305ce127 1613 ['@'], # block
1614 ['@'], # unblock
1615 ['@'], # report
422dd385
O
1616 [
1617 'home',
1618 'all_mem',
1619 'all_sub',
1620 'add',
1621 'rm',
1622 'sub',
1623 'unsub',
1624 'own',
1625 'new',
1626 'update',
1627 'del'
1628 ], # list
813a5d80 1629 [], # cal
a8c5fce4 1630 [key for key in dict(get_all_config())], # config
ceec8593 1631 g['themes'], # theme
422dd385
O
1632 [
1633 'discover',
1634 'tweets',
1635 'messages',
1636 'friends_and_followers',
1637 'list',
1638 'stream'
1639 ], # help
d6cc4c67
O
1640 [], # pause
1641 [], # reconnect
7e4ccbf3 1642 [], # clear
1643 [], # quit
d51b4107 1644 ]
7e4ccbf3 1645 ))
d51b4107 1646 init_interactive_shell(d)
f5677fb1 1647 read_history()
819569e8 1648 reset()
b2b933a9 1649 while True:
99b52f5f 1650 # raw_input
1dd312f5 1651 if g['prefix']:
ceec8593 1652 line = raw_input(g['decorated_name'](c['PREFIX']))
1dd312f5
O
1653 else:
1654 line = raw_input()
f1c1dfea
O
1655 # Save cmd to compare with readline buffer
1656 g['cmd'] = line.strip()
1657 # Get short cmd to pass to handle function
843647ad
O
1658 try:
1659 cmd = line.split()[0]
1660 except:
1661 cmd = ''
b8c1f42a 1662 try:
9683e61d 1663 # Lock the semaphore
99b52f5f 1664 c['lock'] = True
9683e61d 1665 # Save cmd to global variable and call process
b8c1f42a 1666 g['stuff'] = ' '.join(line.split()[1:])
9683e61d 1667 # Process the command
b8c1f42a 1668 process(cmd)()
9683e61d 1669 # Not re-display
99b52f5f 1670 if cmd in ['switch', 't', 'rt', 'rep']:
9683e61d
O
1671 g['prefix'] = False
1672 else:
1673 g['prefix'] = True
1674 # Release the semaphore lock
99b52f5f 1675 c['lock'] = False
eadd85a8 1676 except Exception:
b8c1f42a 1677 printNicely(red('OMG something is wrong with Twitter right now.'))
54277114
O
1678
1679
42fde775 1680def stream(domain, args, name='Rainbow Stream'):
54277114 1681 """
f405a7d0 1682 Track the stream
54277114 1683 """
54277114 1684 # The Logo
42fde775 1685 art_dict = {
632c6fa5
O
1686 c['USER_DOMAIN']: name,
1687 c['PUBLIC_DOMAIN']: args.track_keywords,
1f2f6159 1688 c['SITE_DOMAIN']: name,
42fde775 1689 }
687567eb 1690 if c['ASCII_ART']:
c075e6dc 1691 ascii_art(art_dict[domain])
91476ec3
O
1692 # These arguments are optional:
1693 stream_args = dict(
e3927852 1694 timeout=0.5, # To check g['stream_stop'] after each 0.5 s
a1222228 1695 block=not args.no_block,
91476ec3 1696 heartbeat_timeout=args.heartbeat_timeout)
91476ec3
O
1697 # Track keyword
1698 query_args = dict()
1699 if args.track_keywords:
1700 query_args['track'] = args.track_keywords
91476ec3 1701 # Get stream
2a6238f5 1702 stream = TwitterStream(
22be990e 1703 auth=authen(),
42fde775 1704 domain=domain,
2a6238f5 1705 **stream_args)
2a0cabee
O
1706 try:
1707 if domain == c['USER_DOMAIN']:
1708 tweet_iter = stream.user(**query_args)
1709 elif domain == c['SITE_DOMAIN']:
1710 tweet_iter = stream.site(**query_args)
42fde775 1711 else:
2a0cabee
O
1712 if args.track_keywords:
1713 tweet_iter = stream.statuses.filter(**query_args)
1714 else:
1715 tweet_iter = stream.statuses.sample()
92983945
BS
1716 # Block new stream until other one exits
1717 StreamLock.acquire()
1718 g['stream_stop'] = False
72c02928
VNM
1719 for tweet in tweet_iter:
1720 if tweet is None:
a1222228 1721 printNicely("-- None --")
72c02928 1722 elif tweet is Timeout:
335e7803
O
1723 if(g['stream_stop']):
1724 StreamLock.release()
1725 break
72c02928
VNM
1726 elif tweet is HeartbeatTimeout:
1727 printNicely("-- Heartbeat Timeout --")
1728 elif tweet is Hangup:
1729 printNicely("-- Hangup --")
1730 elif tweet.get('text'):
1731 draw(
1732 t=tweet,
72c02928 1733 keyword=args.track_keywords,
9683e61d 1734 check_semaphore=True,
72c02928
VNM
1735 fil=args.filter,
1736 ig=args.ignore,
1737 )
4824b181
O
1738 # Current readline buffer
1739 current_buffer = readline.get_line_buffer().strip()
335e7803 1740 # There is an unexpected behaviour in MacOSX readline + Python 2:
3d48702f
O
1741 # after completely delete a word after typing it,
1742 # somehow readline buffer still contains
1743 # the 1st character of that word
f1c1dfea 1744 if current_buffer and g['cmd'] != current_buffer:
3d48702f 1745 sys.stdout.write(
2a857ef4 1746 g['decorated_name'](c['PREFIX']) + unc(current_buffer))
4824b181 1747 sys.stdout.flush()
335e7803
O
1748 elif not c['HIDE_PROMPT']:
1749 sys.stdout.write(g['decorated_name'](c['PREFIX']))
1750 sys.stdout.flush()
14db58c7 1751 elif tweet.get('direct_message'):
8141aca6 1752 print_message(tweet['direct_message'], check_semaphore=True)
2a0cabee
O
1753 except TwitterHTTPError:
1754 printNicely('')
c075e6dc 1755 printNicely(
2a0cabee 1756 magenta("We have maximum connection problem with twitter'stream API right now :("))
54277114
O
1757
1758
1759def fly():
1760 """
1761 Main function
1762 """
531f5682 1763 # Initial
42fde775 1764 args = parse_arguments()
2a0cabee 1765 try:
fe9bb33b 1766 init(args)
2a0cabee
O
1767 except TwitterHTTPError:
1768 printNicely('')
1769 printNicely(
e3927852 1770 magenta("We have connection problem with twitter'stream API right now :("))
4c025026 1771 printNicely(magenta("Let's try again later."))
2a0cabee 1772 save_history()
2a0cabee 1773 sys.exit()
92983945 1774 # Spawn stream thread
baec5f50 1775 th = threading.Thread(
1776 target=stream,
1777 args=(
1778 c['USER_DOMAIN'],
1779 args,
1780 g['original_name']))
92983945
BS
1781 th.daemon = True
1782 th.start()
42fde775 1783 # Start listen process
819569e8 1784 time.sleep(0.5)
c91f75f2 1785 g['reset'] = True
1dd312f5 1786 g['prefix'] = True
0f6e4daf 1787 listen()