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