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