584d8e2c68cfefaf0fa3810e2d7f9449e7ef5281
[rainbowstream.git] / rainbowstream / rainbow.py
1 """
2 Colorful user's timeline stream
3 """
4 from multiprocessing import Process
5
6 import os
7 import os.path
8 import sys
9 import signal
10 import argparse
11 import time
12 import requests
13 import webbrowser
14
15 from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
16 from twitter.api import *
17 from twitter.oauth import OAuth, read_token_file
18 from twitter.oauth_dance import oauth_dance
19 from twitter.util import printNicely
20 from StringIO import StringIO
21
22 from .draw import *
23 from .colors import *
24 from .config import *
25 from .consumer import *
26 from .interactive import *
27 from .db import *
28 from .c_image import *
29
30 g = {}
31 db = RainbowDB()
32 cmdset = [
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
71 def 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
110 def 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
133 def 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
150 def 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
213 def 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
250 def 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
263 def 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
281 def 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
294 def tweet():
295 """
296 Tweet
297 """
298 t = Twitter(auth=authen())
299 t.statuses.update(status=g['stuff'])
300
301
302 def 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
316 def 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
340 def 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
367 def 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
384 def 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
401 def 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
416 def 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
433 def 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
453 def 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
473 def 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
494 def urlopen():
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
514 def 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
556 def 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
589 def 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
622 def 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
636 def 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
654 def 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
667 def 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
682 def 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
702 def 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
722 def 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
748 def 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
764 def 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
780 def 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
794 def 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
805 def 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 # Set default
833 path = os.path.dirname(__file__) + '/colorset/init'
834 f = open(path,'w')
835 f.write(c['theme'])
836 f.close()
837 printNicely(light_green('Okay it will be applied from next time :)'))
838 else:
839 # Change theme
840 try:
841 # Load new config
842 if g['stuff'] != 'custom':
843 new_config = os.path.dirname(__file__) + '/colorset/' + g['stuff'] + '.json'
844 else:
845 new_config = os.environ.get(
846 'HOME',os.environ.get(
847 'USERPROFILE',
848 '')) + os.sep + '.rainbow_config.json'
849 new_config = load_config(new_config)
850 if new_config:
851 for nc in new_config:
852 c[nc] = new_config[nc]
853 # Update db and reset colors
854 db.theme_update(g['stuff'])
855 c['theme'] = g['stuff']
856 reset_cycle()
857 g['decorated_name'] = color_func(
858 c['DECORATED_NAME'])(
859 '[@' + g['original_name'] + ']: ')
860 printNicely(green('Theme changed.'))
861 except:
862 if g['stuff'] == 'custom':
863 printNicely(red('~/.rainbow_config.json is not exists!'))
864 else:
865 printNicely(red('No such theme exists.'))
866
867
868 def help():
869 """
870 Help
871 """
872 s = ' ' * 2
873 h, w = os.popen('stty size', 'r').read().split()
874
875 # Start
876 usage = '\n'
877 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
878 usage += s + '-' * (int(w) - 4) + '\n'
879 usage += s + 'You are ' + \
880 light_yellow('already') + ' on your personal stream.\n'
881 usage += s + 'Any update from Twitter will show up ' + \
882 light_yellow('immediately') + '.\n'
883 usage += s + 'In addtion, following commands are available right now:\n'
884
885 # Discover the world
886 usage += '\n'
887 usage += s + grey(u'\u266A' + ' Discover the world \n')
888 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
889 'You can try ' + light_green('trend US') + ' or ' + \
890 light_green('trend JP Tokyo') + '.\n'
891 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
892 light_green('home 7') + ' will show 7 tweets.\n'
893 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
894 light_green('mentions 7') + ' will show 7 mention tweets.\n'
895 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
896 magenta('@mdo') + '.\n'
897 usage += s * 2 + light_green('view @mdo') + \
898 ' will show ' + magenta('@mdo') + '\'s home.\n'
899 usage += s * 2 + light_green('s #AKB48') + ' will search for "' + \
900 light_yellow('AKB48') + '" and return 5 newest tweet.\n'
901
902 # Tweet
903 usage += '\n'
904 usage += s + grey(u'\u266A' + ' Tweets \n')
905 usage += s * 2 + light_green('t oops ') + \
906 'will tweet "' + light_yellow('oops') + '" immediately.\n'
907 usage += s * 2 + \
908 light_green('rt 12 ') + ' will retweet to tweet with ' + \
909 light_yellow('[id=12]') + '.\n'
910 usage += s * 2 + \
911 light_green('quote 12 ') + ' will quote the tweet with ' + \
912 light_yellow('[id=12]') + '. If no extra text is added, ' + \
913 'the quote will be canceled.\n'
914 usage += s * 2 + \
915 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
916 light_yellow('[id=12]') + '.\n'
917 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
918 light_yellow('oops') + '" to tweet with ' + \
919 light_yellow('[id=12]') + '.\n'
920 usage += s * 2 + \
921 light_green('fav 12 ') + ' will favorite the tweet with ' + \
922 light_yellow('[id=12]') + '.\n'
923 usage += s * 2 + \
924 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
925 light_yellow('[id=12]') + '.\n'
926 usage += s * 2 + \
927 light_green('del 12 ') + ' will delete tweet with ' + \
928 light_yellow('[id=12]') + '.\n'
929 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
930 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
931 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
932 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
933
934 # Direct message
935 usage += '\n'
936 usage += s + grey(u'\u266A' + ' Direct messages \n')
937 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
938 light_green('inbox 7') + ' will show newest 7 messages.\n'
939 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
940 light_green('sent 7') + ' will show newest 7 messages.\n'
941 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
942 magenta('@dtvd88') + '.\n'
943 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
944 light_yellow('[message_id=5]') + '.\n'
945
946 # Follower and following
947 usage += '\n'
948 usage += s + grey(u'\u266A' + ' Fiends and followers \n')
949 usage += s * 2 + \
950 light_green('ls fl') + \
951 ' will list all followers (people who are following you).\n'
952 usage += s * 2 + \
953 light_green('ls fr') + \
954 ' will list all friends (people who you are following).\n'
955 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
956 magenta('@dtvd88') + '.\n'
957 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
958 magenta('@dtvd88') + '.\n'
959 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
960 magenta('@dtvd88') + '.\n'
961 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
962 magenta('@dtvd88') + '.\n'
963 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
964 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
965 magenta('@dtvd88') + '.\n'
966 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
967 magenta('@dtvd88') + '.\n'
968 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
969 magenta('@dtvd88') + ' as a spam account.\n'
970
971 # Switch
972 usage += '\n'
973 usage += s + grey(u'\u266A' + ' Switching streams \n')
974 usage += s * 2 + light_green('switch public #AKB') + \
975 ' will switch to public stream and follow "' + \
976 light_yellow('AKB') + '" keyword.\n'
977 usage += s * 2 + light_green('switch mine') + \
978 ' will switch to your personal stream.\n'
979 usage += s * 2 + light_green('switch mine -f ') + \
980 ' will prompt to enter the filter.\n'
981 usage += s * 3 + light_yellow('Only nicks') + \
982 ' filter will decide nicks will be INCLUDE ONLY.\n'
983 usage += s * 3 + light_yellow('Ignore nicks') + \
984 ' filter will decide nicks will be EXCLUDE.\n'
985 usage += s * 2 + light_green('switch mine -d') + \
986 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
987
988 # Smart shell
989 usage += '\n'
990 usage += s + grey(u'\u266A' + ' Smart shell\n')
991 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
992 'will be evaluate by Python interpreter.\n'
993 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
994 ' for current month.\n'
995
996 # Screening
997 usage += '\n'
998 usage += s + grey(u'\u266A' + ' Screening \n')
999 usage += s * 2 + light_green('theme') + ' will list available theme.' + \
1000 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
1001 ' theme immediately.\n'
1002 usage += s * 2 + light_green('h') + ' will show this help again.\n'
1003 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1004 usage += s * 2 + light_green('q') + ' will quit.\n'
1005
1006 # End
1007 usage += '\n'
1008 usage += s + '-' * (int(w) - 4) + '\n'
1009 usage += s + 'Have fun and hang tight! \n'
1010 printNicely(usage)
1011
1012
1013 def clear():
1014 """
1015 Clear screen
1016 """
1017 os.system('clear')
1018
1019
1020 def quit():
1021 """
1022 Exit all
1023 """
1024 save_history()
1025 os.system('rm -rf rainbow.db')
1026 os.kill(g['stream_pid'], signal.SIGKILL)
1027 sys.exit()
1028
1029
1030 def reset():
1031 """
1032 Reset prefix of line
1033 """
1034 if g['reset']:
1035 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
1036 g['reset'] = False
1037 try:
1038 printNicely(str(eval(g['cmd'])))
1039 except Exception:
1040 pass
1041
1042
1043 def process(cmd):
1044 """
1045 Process switch
1046 """
1047 return dict(zip(
1048 cmdset,
1049 [
1050 switch,
1051 trend,
1052 home,
1053 view,
1054 mentions,
1055 tweet,
1056 retweet,
1057 quote,
1058 allretweet,
1059 favorite,
1060 reply,
1061 delete,
1062 unfavorite,
1063 search,
1064 message,
1065 show,
1066 urlopen,
1067 list,
1068 inbox,
1069 sent,
1070 trash,
1071 whois,
1072 follow,
1073 unfollow,
1074 mute,
1075 unmute,
1076 muting,
1077 block,
1078 unblock,
1079 report,
1080 cal,
1081 theme,
1082 help,
1083 clear,
1084 quit
1085 ]
1086 )).get(cmd, reset)
1087
1088
1089 def listen():
1090 """
1091 Listen to user's input
1092 """
1093 d = dict(zip(
1094 cmdset,
1095 [
1096 ['public', 'mine'], # switch
1097 [], # trend
1098 [], # home
1099 ['@'], # view
1100 [], # mentions
1101 [], # tweet
1102 [], # retweet
1103 [], # quote
1104 [], # allretweet
1105 [], # favorite
1106 [], # reply
1107 [], # delete
1108 [], # unfavorite
1109 ['#'], # search
1110 ['@'], # message
1111 ['image'], # show image
1112 [''], # open url
1113 ['fl', 'fr'], # list
1114 [], # inbox
1115 [], # sent
1116 [], # trash
1117 ['@'], # whois
1118 ['@'], # follow
1119 ['@'], # unfollow
1120 ['@'], # mute
1121 ['@'], # unmute
1122 ['@'], # muting
1123 ['@'], # block
1124 ['@'], # unblock
1125 ['@'], # report
1126 [], # cal
1127 g['themes'] + ['current_as_default'], # theme
1128 [], # help
1129 [], # clear
1130 [], # quit
1131 ]
1132 ))
1133 init_interactive_shell(d)
1134 read_history()
1135 reset()
1136 while True:
1137 if g['prefix']:
1138 line = raw_input(g['decorated_name'])
1139 else:
1140 line = raw_input()
1141 try:
1142 cmd = line.split()[0]
1143 except:
1144 cmd = ''
1145 g['cmd'] = cmd
1146 # Save cmd to global variable and call process
1147 try:
1148 g['stuff'] = ' '.join(line.split()[1:])
1149 process(cmd)()
1150 except Exception,e :
1151 print e
1152 printNicely(red('OMG something is wrong with Twitter right now.'))
1153 # Not redisplay prefix
1154 if cmd in ['switch', 't', 'rt', 'rep']:
1155 g['prefix'] = False
1156 else:
1157 g['prefix'] = True
1158
1159
1160 def stream(domain, args, name='Rainbow Stream'):
1161 """
1162 Track the stream
1163 """
1164
1165 # The Logo
1166 art_dict = {
1167 c['USER_DOMAIN']: name,
1168 c['PUBLIC_DOMAIN']: args.track_keywords,
1169 c['SITE_DOMAIN']: 'Site Stream',
1170 }
1171 if g['ascii_art']:
1172 ascii_art(art_dict[domain])
1173
1174 # These arguments are optional:
1175 stream_args = dict(
1176 timeout=args.timeout,
1177 block=not args.no_block,
1178 heartbeat_timeout=args.heartbeat_timeout)
1179
1180 # Track keyword
1181 query_args = dict()
1182 if args.track_keywords:
1183 query_args['track'] = args.track_keywords
1184
1185 # Get stream
1186 stream = TwitterStream(
1187 auth=authen(),
1188 domain=domain,
1189 **stream_args)
1190
1191 try:
1192 if domain == c['USER_DOMAIN']:
1193 tweet_iter = stream.user(**query_args)
1194 elif domain == c['SITE_DOMAIN']:
1195 tweet_iter = stream.site(**query_args)
1196 else:
1197 if args.track_keywords:
1198 tweet_iter = stream.statuses.filter(**query_args)
1199 else:
1200 tweet_iter = stream.statuses.sample()
1201
1202 # Iterate over the stream.
1203 for tweet in tweet_iter:
1204 if tweet is None:
1205 printNicely("-- None --")
1206 elif tweet is Timeout:
1207 printNicely("-- Timeout --")
1208 elif tweet is HeartbeatTimeout:
1209 printNicely("-- Heartbeat Timeout --")
1210 elif tweet is Hangup:
1211 printNicely("-- Hangup --")
1212 elif tweet.get('text'):
1213 draw(
1214 t=tweet,
1215 iot=args.image_on_term,
1216 keyword=args.track_keywords,
1217 fil=args.filter,
1218 ig=args.ignore,
1219 )
1220 except TwitterHTTPError:
1221 printNicely('')
1222 printNicely(
1223 magenta("We have maximum connection problem with twitter'stream API right now :("))
1224
1225
1226 def fly():
1227 """
1228 Main function
1229 """
1230 # Spawn stream process
1231 args = parse_arguments()
1232 try:
1233 get_decorated_name()
1234
1235 except TwitterHTTPError:
1236 printNicely('')
1237 printNicely(
1238 magenta("I'm afraid we have maximum connection problem with twitter right now :("))
1239 printNicely(magenta("Let's try again later."))
1240 save_history()
1241 os.system('rm -rf rainbow.db')
1242 sys.exit()
1243
1244 p = Process(
1245 target=stream,
1246 args=(
1247 c['USER_DOMAIN'],
1248 args,
1249 g['original_name']))
1250 p.start()
1251
1252 # Start listen process
1253 time.sleep(0.5)
1254 g['reset'] = True
1255 g['prefix'] = True
1256 g['stream_pid'] = p.pid
1257 g['iot'] = args.image_on_term
1258 listen()