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