open url and quote
[rainbowstream.git] / rainbowstream / rainbow.py
... / ...
CommitLineData
1"""
2Colorful user's timeline stream
3"""
4from multiprocessing import Process
5
6import os
7import os.path
8import sys
9import signal
10import argparse
11import time
12import requests
13import webbrowser
14
15from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
16from twitter.api import *
17from twitter.oauth import OAuth, read_token_file
18from twitter.oauth_dance import oauth_dance
19from twitter.util import printNicely
20from StringIO import StringIO
21
22from .draw import *
23from .colors import *
24from .config import *
25from .consumer import *
26from .interactive import *
27from .db import *
28from .c_image import *
29
30g = {}
31db = RainbowDB()
32cmdset = [
33 'switch',
34 'trend',
35 'home',
36 'view',
37 'mentions',
38 't',
39 'rt',
40 'quote',
41 'allrt',
42 'fav',
43 'rep',
44 'del',
45 'ufav',
46 's',
47 'mes',
48 'show',
49 'open',
50 'ls',
51 'inbox',
52 'sent',
53 'trash',
54 'whois',
55 'fl',
56 'ufl',
57 'mute',
58 'unmute',
59 'muting',
60 'block',
61 'unblock',
62 'report',
63 'cal',
64 'theme',
65 'h',
66 'c',
67 'q'
68]
69
70
71def parse_arguments():
72 """
73 Parse the arguments
74 """
75 parser = argparse.ArgumentParser(description=__doc__ or "")
76 parser.add_argument(
77 '-to',
78 '--timeout',
79 help='Timeout for the stream (seconds).')
80 parser.add_argument(
81 '-ht',
82 '--heartbeat-timeout',
83 help='Set heartbeat timeout.',
84 default=90)
85 parser.add_argument(
86 '-nb',
87 '--no-block',
88 action='store_true',
89 help='Set stream to non-blocking.')
90 parser.add_argument(
91 '-tt',
92 '--track-keywords',
93 help='Search the stream for specific text.')
94 parser.add_argument(
95 '-fil',
96 '--filter',
97 help='Filter specific screen_name.')
98 parser.add_argument(
99 '-ig',
100 '--ignore',
101 help='Ignore specific screen_name.')
102 parser.add_argument(
103 '-iot',
104 '--image-on-term',
105 action='store_true',
106 help='Display all image on terminal.')
107 return parser.parse_args()
108
109
110def authen():
111 """
112 Authenticate with Twitter OAuth
113 """
114 # When using rainbow stream you must authorize.
115 twitter_credential = os.environ.get(
116 'HOME',
117 os.environ.get(
118 'USERPROFILE',
119 '')) + os.sep + '.rainbow_oauth'
120 if not os.path.exists(twitter_credential):
121 oauth_dance("Rainbow Stream",
122 CONSUMER_KEY,
123 CONSUMER_SECRET,
124 twitter_credential)
125 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
126 return OAuth(
127 oauth_token,
128 oauth_token_secret,
129 CONSUMER_KEY,
130 CONSUMER_SECRET)
131
132
133def get_decorated_name():
134 """
135 Beginning of every line
136 """
137 t = Twitter(auth=authen())
138 name = '@' + t.account.verify_credentials()['screen_name']
139 g['original_name'] = name[1:]
140 g['decorated_name'] = color_func(c['DECORATED_NAME'])('[' + name + ']: ')
141 g['ascii_art'] = True
142
143 files = os.listdir(os.path.dirname(__file__)+'/colorset')
144 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
145 themes += ['custom']
146 g['themes'] = themes
147 db.theme_store(c['theme'])
148
149
150def switch():
151 """
152 Switch stream
153 """
154 try:
155 target = g['stuff'].split()[0]
156
157 # Filter and ignore
158 args = parse_arguments()
159 try:
160 if g['stuff'].split()[-1] == '-f':
161 only = raw_input('Only nicks: ')
162 ignore = raw_input('Ignore nicks: ')
163 args.filter = filter(None, only.split(','))
164 args.ignore = filter(None, ignore.split(','))
165 elif g['stuff'].split()[-1] == '-d':
166 args.filter = c['ONLY_LIST']
167 args.ignore = c['IGNORE_LIST']
168 except:
169 printNicely(red('Sorry, wrong format.'))
170 return
171
172 # Public stream
173 if target == 'public':
174 keyword = g['stuff'].split()[1]
175 if keyword[0] == '#':
176 keyword = keyword[1:]
177 # Kill old process
178 os.kill(g['stream_pid'], signal.SIGKILL)
179 args.track_keywords = keyword
180 # Start new process
181 p = Process(
182 target=stream,
183 args=(
184 c['PUBLIC_DOMAIN'],
185 args))
186 p.start()
187 g['stream_pid'] = p.pid
188
189 # Personal stream
190 elif target == 'mine':
191 # Kill old process
192 os.kill(g['stream_pid'], signal.SIGKILL)
193 # Start new process
194 p = Process(
195 target=stream,
196 args=(
197 c['USER_DOMAIN'],
198 args,
199 g['original_name']))
200 p.start()
201 g['stream_pid'] = p.pid
202 printNicely('')
203 if args.filter:
204 printNicely(cyan('Only: ' + str(args.filter)))
205 if args.ignore:
206 printNicely(red('Ignore: ' + str(args.ignore)))
207 printNicely('')
208 g['ascii_art'] = True
209 except:
210 printNicely(red('Sorry I can\'t understand.'))
211
212
213def trend():
214 """
215 Trend
216 """
217 t = Twitter(auth=authen())
218 # Get country and town
219 try:
220 country = g['stuff'].split()[0]
221 except:
222 country = ''
223 try:
224 town = g['stuff'].split()[1]
225 except:
226 town = ''
227
228 avail = t.trends.available()
229 # World wide
230 if not country:
231 trends = t.trends.place(_id=1)[0]['trends']
232 print_trends(trends)
233 else:
234 for location in avail:
235 # Search for country and Town
236 if town:
237 if location['countryCode'] == country \
238 and location['placeType']['name'] == 'Town' \
239 and location['name'] == town:
240 trends = t.trends.place(_id=location['woeid'])[0]['trends']
241 print_trends(trends)
242 # Search for country only
243 else:
244 if location['countryCode'] == country \
245 and location['placeType']['name'] == 'Country':
246 trends = t.trends.place(_id=location['woeid'])[0]['trends']
247 print_trends(trends)
248
249
250def home():
251 """
252 Home
253 """
254 t = Twitter(auth=authen())
255 num = c['HOME_TWEET_NUM']
256 if g['stuff'].isdigit():
257 num = int(g['stuff'])
258 for tweet in reversed(t.statuses.home_timeline(count=num)):
259 draw(t=tweet, iot=g['iot'])
260 printNicely('')
261
262
263def view():
264 """
265 Friend view
266 """
267 t = Twitter(auth=authen())
268 user = g['stuff'].split()[0]
269 if user[0] == '@':
270 try:
271 num = int(g['stuff'].split()[1])
272 except:
273 num = c['HOME_TWEET_NUM']
274 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
275 draw(t=tweet, iot=g['iot'])
276 printNicely('')
277 else:
278 printNicely(red('A name should begin with a \'@\''))
279
280
281def mentions():
282 """
283 Mentions timeline
284 """
285 t = Twitter(auth=authen())
286 num = c['HOME_TWEET_NUM']
287 if g['stuff'].isdigit():
288 num = int(g['stuff'])
289 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
290 draw(t=tweet, iot=g['iot'])
291 printNicely('')
292
293
294def tweet():
295 """
296 Tweet
297 """
298 t = Twitter(auth=authen())
299 t.statuses.update(status=g['stuff'])
300
301
302def retweet():
303 """
304 ReTweet
305 """
306 t = Twitter(auth=authen())
307 try:
308 id = int(g['stuff'].split()[0])
309 except:
310 printNicely(red('Sorry I can\'t understand.'))
311 return
312 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
313 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
314
315
316def quote():
317 """
318 Quote a tweet
319 """
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 = db.rainbow_to_tweet_query(id)[0].tweet_id
327 tweet = t.statuses.show(id=tid)
328 screen_name = tweet['user']['screen_name']
329 text = tweet['text']
330 quote = '\"@' + screen_name + ': ' + text + '\"'
331 quote = quote.encode('utf8')
332 printNicely(light_magenta('Compose mode:'))
333 extra = raw_input(quote)
334 if extra:
335 t.statuses.update(status=quote+extra)
336 else:
337 printNicely(light_magenta('No text added.'))
338
339
340def allretweet():
341 """
342 List all retweet
343 """
344 t = Twitter(auth=authen())
345 # Get rainbow id
346 try:
347 id = int(g['stuff'].split()[0])
348 except:
349 printNicely(red('Sorry I can\'t understand.'))
350 return
351 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
352 # Get display num if exist
353 try:
354 num = int(g['stuff'].split()[1])
355 except:
356 num = c['RETWEETS_SHOW_NUM']
357 # Get result and display
358 rt_ary = t.statuses.retweets(id=tid, count=num)
359 if not rt_ary:
360 printNicely(magenta('This tweet has no retweet.'))
361 return
362 for tweet in reversed(rt_ary):
363 draw(t=tweet, iot=g['iot'])
364 printNicely('')
365
366
367def favorite():
368 """
369 Favorite
370 """
371 t = Twitter(auth=authen())
372 try:
373 id = int(g['stuff'].split()[0])
374 except:
375 printNicely(red('Sorry I can\'t understand.'))
376 return
377 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
378 t.favorites.create(_id=tid, include_entities=False)
379 printNicely(green('Favorited.'))
380 draw(t.statuses.show(id=tid), iot=g['iot'])
381 printNicely('')
382
383
384def reply():
385 """
386 Reply
387 """
388 t = Twitter(auth=authen())
389 try:
390 id = int(g['stuff'].split()[0])
391 except:
392 printNicely(red('Sorry I can\'t understand.'))
393 return
394 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
395 user = t.statuses.show(id=tid)['user']['screen_name']
396 status = ' '.join(g['stuff'].split()[1:])
397 status = '@' + user + ' ' + status.decode('utf-8')
398 t.statuses.update(status=status, in_reply_to_status_id=tid)
399
400
401def delete():
402 """
403 Delete
404 """
405 t = Twitter(auth=authen())
406 try:
407 rid = int(g['stuff'].split()[0])
408 except:
409 printNicely(red('Sorry I can\'t understand.'))
410 return
411 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
412 t.statuses.destroy(id=tid)
413 printNicely(green('Okay it\'s gone.'))
414
415
416def unfavorite():
417 """
418 Unfavorite
419 """
420 t = Twitter(auth=authen())
421 try:
422 id = int(g['stuff'].split()[0])
423 except:
424 printNicely(red('Sorry I can\'t understand.'))
425 return
426 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
427 t.favorites.destroy(_id=tid)
428 printNicely(green('Okay it\'s unfavorited.'))
429 draw(t.statuses.show(id=tid), iot=g['iot'])
430 printNicely('')
431
432
433def search():
434 """
435 Search
436 """
437 t = Twitter(auth=authen())
438 if g['stuff'].startswith('#'):
439 rel = t.search.tweets(q=g['stuff'])['statuses']
440 if rel:
441 printNicely('Newest tweets:')
442 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
443 draw(t=rel[i],
444 iot=g['iot'],
445 keyword=g['stuff'].strip()[1:])
446 printNicely('')
447 else:
448 printNicely(magenta('I\'m afraid there is no result'))
449 else:
450 printNicely(red('A keyword should be a hashtag (like \'#AKB48\')'))
451
452
453def message():
454 """
455 Send a direct message
456 """
457 t = Twitter(auth=authen())
458 user = g['stuff'].split()[0]
459 if user[0].startswith('@'):
460 try:
461 content = g['stuff'].split()[1]
462 except:
463 printNicely(red('Sorry I can\'t understand.'))
464 t.direct_messages.new(
465 screen_name=user[1:],
466 text=content
467 )
468 printNicely(green('Message sent.'))
469 else:
470 printNicely(red('A name should begin with a \'@\''))
471
472
473def show():
474 """
475 Show image
476 """
477 t = Twitter(auth=authen())
478 try:
479 target = g['stuff'].split()[0]
480 if target != 'image':
481 return
482 id = int(g['stuff'].split()[1])
483 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
484 tweet = t.statuses.show(id=tid)
485 media = tweet['entities']['media']
486 for m in media:
487 res = requests.get(m['media_url'])
488 img = Image.open(StringIO(res.content))
489 img.show()
490 except:
491 printNicely(red('Sorry I can\'t show this image.'))
492
493
494def open():
495 """
496 Open url
497 """
498 t = Twitter(auth=authen())
499 try:
500 if not g['stuff'].isdigit():
501 return
502 tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id
503 tweet = t.statuses.show(id=tid)
504 link_ary = [u for u in tweet['text'].split() if u.startswith('http://')]
505 if not link_ary:
506 printNicely(light_magenta('No url here @.@!'))
507 return
508 for link in link_ary:
509 webbrowser.open(link)
510 except:
511 printNicely(red('Sorry I can\'t open url in this tweet.'))
512
513
514def list():
515 """
516 List friends for followers
517 """
518 t = Twitter(auth=authen())
519 # Get name
520 try:
521 name = g['stuff'].split()[1]
522 if name.startswith('@'):
523 name = name[1:]
524 else:
525 printNicely(red('A name should begin with a \'@\''))
526 raise Exception('Invalid name')
527 except:
528 name = g['original_name']
529 # Get list followers or friends
530 try:
531 target = g['stuff'].split()[0]
532 except:
533 printNicely(red('Omg some syntax is wrong.'))
534 # Init cursor
535 d = {'fl': 'followers', 'fr': 'friends'}
536 next_cursor = -1
537 rel = {}
538 # Cursor loop
539 while next_cursor != 0:
540 list = getattr(t, d[target]).list(
541 screen_name=name,
542 cursor=next_cursor,
543 skip_status=True,
544 include_entities=False,
545 )
546 for u in list['users']:
547 rel[u['name']] = '@' + u['screen_name']
548 next_cursor = list['next_cursor']
549 # Print out result
550 printNicely('All: ' + str(len(rel)) + ' people.')
551 for name in rel:
552 user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ')
553 printNicely(user)
554
555
556def inbox():
557 """
558 Inbox direct messages
559 """
560 t = Twitter(auth=authen())
561 num = c['MESSAGES_DISPLAY']
562 rel = []
563 if g['stuff'].isdigit():
564 num = g['stuff']
565 cur_page = 1
566 # Max message per page is 20 so we have to loop
567 while num > 20:
568 rel = rel + t.direct_messages(
569 count=20,
570 page=cur_page,
571 include_entities=False,
572 skip_status=False
573 )
574 num -= 20
575 cur_page += 1
576 rel = rel + t.direct_messages(
577 count=num,
578 page=cur_page,
579 include_entities=False,
580 skip_status=False
581 )
582 # Display
583 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
584 for m in reversed(rel):
585 print_message(m)
586 printNicely('')
587
588
589def sent():
590 """
591 Sent direct messages
592 """
593 t = Twitter(auth=authen())
594 num = c['MESSAGES_DISPLAY']
595 rel = []
596 if g['stuff'].isdigit():
597 num = int(g['stuff'])
598 cur_page = 1
599 # Max message per page is 20 so we have to loop
600 while num > 20:
601 rel = rel + t.direct_messages.sent(
602 count=20,
603 page=cur_page,
604 include_entities=False,
605 skip_status=False
606 )
607 num -= 20
608 cur_page += 1
609 rel = rel + t.direct_messages.sent(
610 count=num,
611 page=cur_page,
612 include_entities=False,
613 skip_status=False
614 )
615 # Display
616 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
617 for m in reversed(rel):
618 print_message(m)
619 printNicely('')
620
621
622def trash():
623 """
624 Remove message
625 """
626 t = Twitter(auth=authen())
627 try:
628 rid = int(g['stuff'].split()[0])
629 except:
630 printNicely(red('Sorry I can\'t understand.'))
631 mid = db.rainbow_to_message_query(rid)[0].message_id
632 t.direct_messages.destroy(id=mid)
633 printNicely(green('Message deleted.'))
634
635
636def whois():
637 """
638 Show profile of a specific user
639 """
640 t = Twitter(auth=authen())
641 screen_name = g['stuff'].split()[0]
642 if screen_name.startswith('@'):
643 try:
644 user = t.users.show(
645 screen_name=screen_name[1:],
646 include_entities=False)
647 show_profile(user, g['iot'])
648 except:
649 printNicely(red('Omg no user.'))
650 else:
651 printNicely(red('A name should begin with a \'@\''))
652
653
654def follow():
655 """
656 Follow a user
657 """
658 t = Twitter(auth=authen())
659 screen_name = g['stuff'].split()[0]
660 if screen_name.startswith('@'):
661 t.friendships.create(screen_name=screen_name[1:], follow=True)
662 printNicely(green('You are following ' + screen_name + ' now!'))
663 else:
664 printNicely(red('A name should begin with a \'@\''))
665
666
667def unfollow():
668 """
669 Unfollow a user
670 """
671 t = Twitter(auth=authen())
672 screen_name = g['stuff'].split()[0]
673 if screen_name.startswith('@'):
674 t.friendships.destroy(
675 screen_name=screen_name[1:],
676 include_entities=False)
677 printNicely(green('Unfollow ' + screen_name + ' success!'))
678 else:
679 printNicely(red('A name should begin with a \'@\''))
680
681
682def mute():
683 """
684 Mute a user
685 """
686 t = Twitter(auth=authen())
687 try:
688 screen_name = g['stuff'].split()[0]
689 except:
690 printNicely(red('A name should be specified. '))
691 return
692 if screen_name.startswith('@'):
693 rel = t.mutes.users.create(screen_name=screen_name[1:])
694 if isinstance(rel, dict):
695 printNicely(green(screen_name + ' is muted.'))
696 else:
697 printNicely(red(rel))
698 else:
699 printNicely(red('A name should begin with a \'@\''))
700
701
702def unmute():
703 """
704 Unmute a user
705 """
706 t = Twitter(auth=authen())
707 try:
708 screen_name = g['stuff'].split()[0]
709 except:
710 printNicely(red('A name should be specified. '))
711 return
712 if screen_name.startswith('@'):
713 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
714 if isinstance(rel, dict):
715 printNicely(green(screen_name + ' is unmuted.'))
716 else:
717 printNicely(red(rel))
718 else:
719 printNicely(red('A name should begin with a \'@\''))
720
721
722def muting():
723 """
724 List muting user
725 """
726 t = Twitter(auth=authen())
727 # Init cursor
728 next_cursor = -1
729 rel = {}
730 # Cursor loop
731 while next_cursor != 0:
732 list = t.mutes.users.list(
733 screen_name=g['original_name'],
734 cursor=next_cursor,
735 skip_status=True,
736 include_entities=False,
737 )
738 for u in list['users']:
739 rel[u['name']] = '@' + u['screen_name']
740 next_cursor = list['next_cursor']
741 # Print out result
742 printNicely('All: ' + str(len(rel)) + ' people.')
743 for name in rel:
744 user = ' ' + cycle_color(name) + grey(' ' + rel[name] + ' ')
745 printNicely(user)
746
747
748def block():
749 """
750 Block a user
751 """
752 t = Twitter(auth=authen())
753 screen_name = g['stuff'].split()[0]
754 if screen_name.startswith('@'):
755 t.blocks.create(
756 screen_name=screen_name[1:],
757 include_entities=False,
758 skip_status=True)
759 printNicely(green('You blocked ' + screen_name + '.'))
760 else:
761 printNicely(red('A name should begin with a \'@\''))
762
763
764def unblock():
765 """
766 Unblock a user
767 """
768 t = Twitter(auth=authen())
769 screen_name = g['stuff'].split()[0]
770 if screen_name.startswith('@'):
771 t.blocks.destroy(
772 screen_name=screen_name[1:],
773 include_entities=False,
774 skip_status=True)
775 printNicely(green('Unblock ' + screen_name + ' success!'))
776 else:
777 printNicely(red('A name should begin with a \'@\''))
778
779
780def report():
781 """
782 Report a user as a spam account
783 """
784 t = Twitter(auth=authen())
785 screen_name = g['stuff'].split()[0]
786 if screen_name.startswith('@'):
787 t.users.report_spam(
788 screen_name=screen_name[1:])
789 printNicely(green('You reported ' + screen_name + '.'))
790 else:
791 printNicely(red('Sorry I can\'t understand.'))
792
793
794def cal():
795 """
796 Unix's command `cal`
797 """
798 # Format
799 rel = os.popen('cal').read().split('\n')
800 month = rel.pop(0)
801 date = rel.pop(0)
802 show_calendar(month, date, rel)
803
804
805def theme():
806 """
807 List and change theme
808 """
809 if not g['stuff']:
810 # List themes
811 for theme in g['themes']:
812 line = ''
813 # Detect custom config
814 if theme == 'custom':
815 line += light_magenta('custom')
816 custom_path = os.environ.get(
817 'HOME',
818 os.environ.get('USERPROFILE',
819 '')) + os.sep + '.rainbow_config.json'
820 if not os.path.exists(custom_path):
821 line += light_magenta(' (create your own config file at ~/.rainbow_config.json)')
822 else:
823 line += light_magenta(' (loaded)')
824 else:
825 line += light_magenta(theme)
826 if c['theme'] == theme :
827 line = ' '*2 + light_yellow('* ') + line
828 else:
829 line = ' '*4 + line
830 printNicely(line)
831 elif g['stuff'] == 'current_as_default':
832 path = os.path.dirname(__file__) + '/colorset/init'
833 f = open(path,'w')
834 f.write(c['theme'])
835 f.close()
836 printNicely(light_green('Okay it will be applied from next time :)'))
837 else:
838 # Change theme
839 try:
840 # Load new config
841 if g['stuff'] != 'custom':
842 new_config = os.path.dirname(__file__) + '/colorset/' + g['stuff'] + '.json'
843 else:
844 new_config = os.environ.get(
845 'HOME',os.environ.get(
846 'USERPROFILE',
847 '')) + os.sep + '.rainbow_config.json'
848 new_config = load_config(new_config)
849 if new_config:
850 for nc in new_config:
851 c[nc] = new_config[nc]
852 # Update db and reset colors
853 db.theme_update(g['stuff'])
854 c['theme'] = g['stuff']
855 reset_cycle()
856 g['decorated_name'] = color_func(
857 c['DECORATED_NAME'])(
858 '[@' + g['original_name'] + ']: ')
859 printNicely(green('Theme changed.'))
860 except:
861 if g['stuff'] == 'custom':
862 printNicely(red('~/.rainbow_config.json is not exists!'))
863 else:
864 printNicely(red('No such theme exists.'))
865
866
867def help():
868 """
869 Help
870 """
871 s = ' ' * 2
872 h, w = os.popen('stty size', 'r').read().split()
873
874 # Start
875 usage = '\n'
876 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
877 usage += s + '-' * (int(w) - 4) + '\n'
878 usage += s + 'You are ' + \
879 light_yellow('already') + ' on your personal stream.\n'
880 usage += s + 'Any update from Twitter will show up ' + \
881 light_yellow('immediately') + '.\n'
882 usage += s + 'In addtion, following commands are available right now:\n'
883
884 # Discover the world
885 usage += '\n'
886 usage += s + grey(u'\u266A' + ' Discover the world \n')
887 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
888 'You can try ' + light_green('trend US') + ' or ' + \
889 light_green('trend JP Tokyo') + '.\n'
890 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
891 light_green('home 7') + ' will show 7 tweets.\n'
892 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
893 light_green('mentions 7') + ' will show 7 mention tweets.\n'
894 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
895 magenta('@mdo') + '.\n'
896 usage += s * 2 + light_green('view @mdo') + \
897 ' will show ' + magenta('@mdo') + '\'s home.\n'
898 usage += s * 2 + light_green('s #AKB48') + ' will search for "' + \
899 light_yellow('AKB48') + '" and return 5 newest tweet.\n'
900
901 # Tweet
902 usage += '\n'
903 usage += s + grey(u'\u266A' + ' Tweets \n')
904 usage += s * 2 + light_green('t oops ') + \
905 'will tweet "' + light_yellow('oops') + '" immediately.\n'
906 usage += s * 2 + \
907 light_green('rt 12 ') + ' will retweet to tweet with ' + \
908 light_yellow('[id=12]') + '.\n'
909 usage += s * 2 + \
910 light_green('quote 12 ') + ' will quote the tweet with ' + \
911 light_yellow('[id=12]') + '. If no extra text is added, ' + \
912 'the quote will be canceled.\n'
913 usage += s * 2 + \
914 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
915 light_yellow('[id=12]') + '.\n'
916 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
917 light_yellow('oops') + '" to tweet with ' + \
918 light_yellow('[id=12]') + '.\n'
919 usage += s * 2 + \
920 light_green('fav 12 ') + ' will favorite the tweet with ' + \
921 light_yellow('[id=12]') + '.\n'
922 usage += s * 2 + \
923 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
924 light_yellow('[id=12]') + '.\n'
925 usage += s * 2 + \
926 light_green('del 12 ') + ' will delete tweet with ' + \
927 light_yellow('[id=12]') + '.\n'
928 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
929 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
930 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
931 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
932
933 # Direct message
934 usage += '\n'
935 usage += s + grey(u'\u266A' + ' Direct messages \n')
936 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
937 light_green('inbox 7') + ' will show newest 7 messages.\n'
938 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
939 light_green('sent 7') + ' will show newest 7 messages.\n'
940 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
941 magenta('@dtvd88') + '.\n'
942 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
943 light_yellow('[message_id=5]') + '.\n'
944
945 # Follower and following
946 usage += '\n'
947 usage += s + grey(u'\u266A' + ' Fiends and followers \n')
948 usage += s * 2 + \
949 light_green('ls fl') + \
950 ' will list all followers (people who are following you).\n'
951 usage += s * 2 + \
952 light_green('ls fr') + \
953 ' will list all friends (people who you are following).\n'
954 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
955 magenta('@dtvd88') + '.\n'
956 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
957 magenta('@dtvd88') + '.\n'
958 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
959 magenta('@dtvd88') + '.\n'
960 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
961 magenta('@dtvd88') + '.\n'
962 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
963 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
964 magenta('@dtvd88') + '.\n'
965 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
966 magenta('@dtvd88') + '.\n'
967 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
968 magenta('@dtvd88') + ' as a spam account.\n'
969
970 # Switch
971 usage += '\n'
972 usage += s + grey(u'\u266A' + ' Switching streams \n')
973 usage += s * 2 + light_green('switch public #AKB') + \
974 ' will switch to public stream and follow "' + \
975 light_yellow('AKB') + '" keyword.\n'
976 usage += s * 2 + light_green('switch mine') + \
977 ' will switch to your personal stream.\n'
978 usage += s * 2 + light_green('switch mine -f ') + \
979 ' will prompt to enter the filter.\n'
980 usage += s * 3 + light_yellow('Only nicks') + \
981 ' filter will decide nicks will be INCLUDE ONLY.\n'
982 usage += s * 3 + light_yellow('Ignore nicks') + \
983 ' filter will decide nicks will be EXCLUDE.\n'
984 usage += s * 2 + light_green('switch mine -d') + \
985 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
986
987 # Smart shell
988 usage += '\n'
989 usage += s + grey(u'\u266A' + ' Smart shell\n')
990 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
991 'will be evaluate by Python interpreter.\n'
992 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
993 ' for current month.\n'
994
995 # Screening
996 usage += '\n'
997 usage += s + grey(u'\u266A' + ' Screening \n')
998 usage += s * 2 + light_green('theme') + ' will list available theme.' + \
999 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
1000 ' theme immediately.\n'
1001 usage += s * 2 + light_green('h') + ' will show this help again.\n'
1002 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1003 usage += s * 2 + light_green('q') + ' will quit.\n'
1004
1005 # End
1006 usage += '\n'
1007 usage += s + '-' * (int(w) - 4) + '\n'
1008 usage += s + 'Have fun and hang tight! \n'
1009 printNicely(usage)
1010
1011
1012def clear():
1013 """
1014 Clear screen
1015 """
1016 os.system('clear')
1017
1018
1019def quit():
1020 """
1021 Exit all
1022 """
1023 save_history()
1024 os.system('rm -rf rainbow.db')
1025 os.kill(g['stream_pid'], signal.SIGKILL)
1026 sys.exit()
1027
1028
1029def reset():
1030 """
1031 Reset prefix of line
1032 """
1033 if g['reset']:
1034 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
1035 g['reset'] = False
1036 try:
1037 printNicely(str(eval(g['cmd'])))
1038 except Exception:
1039 pass
1040
1041
1042def process(cmd):
1043 """
1044 Process switch
1045 """
1046 return dict(zip(
1047 cmdset,
1048 [
1049 switch,
1050 trend,
1051 home,
1052 view,
1053 mentions,
1054 tweet,
1055 retweet,
1056 quote,
1057 allretweet,
1058 favorite,
1059 reply,
1060 delete,
1061 unfavorite,
1062 search,
1063 message,
1064 show,
1065 open,
1066 list,
1067 inbox,
1068 sent,
1069 trash,
1070 whois,
1071 follow,
1072 unfollow,
1073 mute,
1074 unmute,
1075 muting,
1076 block,
1077 unblock,
1078 report,
1079 cal,
1080 theme,
1081 help,
1082 clear,
1083 quit
1084 ]
1085 )).get(cmd, reset)
1086
1087
1088def listen():
1089 """
1090 Listen to user's input
1091 """
1092 d = dict(zip(
1093 cmdset,
1094 [
1095 ['public', 'mine'], # switch
1096 [], # trend
1097 [], # home
1098 ['@'], # view
1099 [], # mentions
1100 [], # tweet
1101 [], # retweet
1102 [], # quote
1103 [], # allretweet
1104 [], # favorite
1105 [], # reply
1106 [], # delete
1107 [], # unfavorite
1108 ['#'], # search
1109 ['@'], # message
1110 ['image'], # show image
1111 [''], # open url
1112 ['fl', 'fr'], # list
1113 [], # inbox
1114 [], # sent
1115 [], # trash
1116 ['@'], # whois
1117 ['@'], # follow
1118 ['@'], # unfollow
1119 ['@'], # mute
1120 ['@'], # unmute
1121 ['@'], # muting
1122 ['@'], # block
1123 ['@'], # unblock
1124 ['@'], # report
1125 [], # cal
1126 g['themes'] + ['current_as_default'], # theme
1127 [], # help
1128 [], # clear
1129 [], # quit
1130 ]
1131 ))
1132 init_interactive_shell(d)
1133 read_history()
1134 reset()
1135 while True:
1136 if g['prefix']:
1137 line = raw_input(g['decorated_name'])
1138 else:
1139 line = raw_input()
1140 try:
1141 cmd = line.split()[0]
1142 except:
1143 cmd = ''
1144 g['cmd'] = cmd
1145 # Save cmd to global variable and call process
1146 try:
1147 g['stuff'] = ' '.join(line.split()[1:])
1148 process(cmd)()
1149 except Exception:
1150 printNicely(red('OMG something is wrong with Twitter right now.'))
1151 # Not redisplay prefix
1152 if cmd in ['switch', 't', 'rt', 'rep']:
1153 g['prefix'] = False
1154 else:
1155 g['prefix'] = True
1156
1157
1158def stream(domain, args, name='Rainbow Stream'):
1159 """
1160 Track the stream
1161 """
1162
1163 # The Logo
1164 art_dict = {
1165 c['USER_DOMAIN']: name,
1166 c['PUBLIC_DOMAIN']: args.track_keywords,
1167 c['SITE_DOMAIN']: 'Site Stream',
1168 }
1169 if g['ascii_art']:
1170 ascii_art(art_dict[domain])
1171
1172 # These arguments are optional:
1173 stream_args = dict(
1174 timeout=args.timeout,
1175 block=not args.no_block,
1176 heartbeat_timeout=args.heartbeat_timeout)
1177
1178 # Track keyword
1179 query_args = dict()
1180 if args.track_keywords:
1181 query_args['track'] = args.track_keywords
1182
1183 # Get stream
1184 stream = TwitterStream(
1185 auth=authen(),
1186 domain=domain,
1187 **stream_args)
1188
1189 try:
1190 if domain == c['USER_DOMAIN']:
1191 tweet_iter = stream.user(**query_args)
1192 elif domain == c['SITE_DOMAIN']:
1193 tweet_iter = stream.site(**query_args)
1194 else:
1195 if args.track_keywords:
1196 tweet_iter = stream.statuses.filter(**query_args)
1197 else:
1198 tweet_iter = stream.statuses.sample()
1199
1200 # Iterate over the stream.
1201 for tweet in tweet_iter:
1202 if tweet is None:
1203 printNicely("-- None --")
1204 elif tweet is Timeout:
1205 printNicely("-- Timeout --")
1206 elif tweet is HeartbeatTimeout:
1207 printNicely("-- Heartbeat Timeout --")
1208 elif tweet is Hangup:
1209 printNicely("-- Hangup --")
1210 elif tweet.get('text'):
1211 draw(
1212 t=tweet,
1213 iot=args.image_on_term,
1214 keyword=args.track_keywords,
1215 fil=args.filter,
1216 ig=args.ignore,
1217 )
1218 except TwitterHTTPError:
1219 printNicely('')
1220 printNicely(
1221 magenta("We have maximum connection problem with twitter'stream API right now :("))
1222
1223
1224def fly():
1225 """
1226 Main function
1227 """
1228 # Spawn stream process
1229 args = parse_arguments()
1230 try:
1231 get_decorated_name()
1232
1233 except TwitterHTTPError:
1234 printNicely('')
1235 printNicely(
1236 magenta("I'm afraid we have maximum connection problem with twitter right now :("))
1237 printNicely(magenta("Let's try again later."))
1238 save_history()
1239 os.system('rm -rf rainbow.db')
1240 sys.exit()
1241
1242 p = Process(
1243 target=stream,
1244 args=(
1245 c['USER_DOMAIN'],
1246 args,
1247 g['original_name']))
1248 p.start()
1249
1250 # Start listen process
1251 time.sleep(0.5)
1252 g['reset'] = True
1253 g['prefix'] = True
1254 g['stream_pid'] = p.pid
1255 g['iot'] = args.image_on_term
1256 listen()