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