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