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