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