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