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