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