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