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