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