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