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