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