refactoring
[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 except:
524 printNicely(red('Sorry I can\'t understand.'))
525 return
526 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
527 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
528
529
530 def favorite():
531 """
532 Favorite
533 """
534 t = Twitter(auth=authen())
535 try:
536 id = int(g['stuff'].split()[0])
537 except:
538 printNicely(red('Sorry I can\'t understand.'))
539 return
540 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
541 t.favorites.create(_id=tid, include_entities=False)
542 printNicely(green('Favorited.'))
543 draw(t.statuses.show(id=tid), iot=g['iot'])
544 printNicely('')
545
546
547 def reply():
548 """
549 Reply
550 """
551 t = Twitter(auth=authen())
552 try:
553 id = int(g['stuff'].split()[0])
554 except:
555 printNicely(red('Sorry I can\'t understand.'))
556 return
557 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
558 user = t.statuses.show(id=tid)['user']['screen_name']
559 status = ' '.join(g['stuff'].split()[1:])
560 status = '@' + user + ' ' + status.decode('utf-8')
561 t.statuses.update(status=status, in_reply_to_status_id=tid)
562
563
564 def delete():
565 """
566 Delete
567 """
568 t = Twitter(auth=authen())
569 try:
570 rid = int(g['stuff'].split()[0])
571 except:
572 printNicely(red('Sorry I can\'t understand.'))
573 return
574 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
575 t.statuses.destroy(id=tid)
576 printNicely(green('Okay it\'s gone.'))
577
578
579 def unfavorite():
580 """
581 Unfavorite
582 """
583 t = Twitter(auth=authen())
584 try:
585 id = int(g['stuff'].split()[0])
586 except:
587 printNicely(red('Sorry I can\'t understand.'))
588 return
589 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
590 t.favorites.destroy(_id=tid)
591 printNicely(green('Okay it\'s unfavorited.'))
592 draw(t.statuses.show(id=tid), iot=g['iot'])
593 printNicely('')
594
595
596 def search():
597 """
598 Search
599 """
600 t = Twitter(auth=authen())
601 if g['stuff'].startswith('#'):
602 rel = t.search.tweets(q=g['stuff'])['statuses']
603 if len(rel):
604 printNicely('Newest tweets:')
605 for i in reversed(xrange(SEARCH_MAX_RECORD)):
606 draw(t=rel[i],
607 iot=g['iot'],
608 keyword=g['stuff'].strip()[1:])
609 printNicely('')
610 else:
611 printNicely(magenta('I\'m afraid there is no result'))
612 else:
613 printNicely(red('A keyword should be a hashtag (like \'#AKB48\')'))
614
615
616 def message():
617 """
618 Send a direct message
619 """
620 t = Twitter(auth=authen())
621 user = g['stuff'].split()[0]
622 if user[0].startswith('@'):
623 try:
624 content = g['stuff'].split()[1]
625 except:
626 printNicely(red('Sorry I can\'t understand.'))
627 t.direct_messages.new(
628 screen_name=user[1:],
629 text=content
630 )
631 printNicely(green('Message sent.'))
632 else:
633 printNicely(red('A name should begin with a \'@\''))
634
635
636 def show():
637 """
638 Show image
639 """
640 t = Twitter(auth=authen())
641 try:
642 target = g['stuff'].split()[0]
643 if target != 'image':
644 return
645 id = int(g['stuff'].split()[1])
646 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
647 tweet = t.statuses.show(id=tid)
648 media = tweet['entities']['media']
649 for m in media:
650 res = requests.get(m['media_url'])
651 img = Image.open(StringIO(res.content))
652 img.show()
653 except:
654 printNicely(red('Sorry I can\'t show this image.'))
655
656
657 def list():
658 """
659 List friends for followers
660 """
661 t = Twitter(auth=authen())
662 # Get name
663 try:
664 name = g['stuff'].split()[1]
665 if name.startswith('@'):
666 name = name[1:]
667 else:
668 printNicely(red('A name should begin with a \'@\''))
669 raise Exception('Invalid name')
670 except:
671 name = g['original_name']
672 # Get list followers or friends
673 try:
674 target = g['stuff'].split()[0]
675 except:
676 printNicely(red('Omg some syntax is wrong.'))
677 # Init cursor
678 d = {'fl': 'followers', 'fr': 'friends'}
679 next_cursor = -1
680 rel = {}
681 # Cursor loop
682 while next_cursor != 0:
683 list = getattr(t, d[target]).list(
684 screen_name=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 inbox():
700 """
701 Inbox direct messages
702 """
703 t = Twitter(auth=authen())
704 num = MESSAGES_DISPLAY
705 rel = []
706 if g['stuff'].isdigit():
707 num = g['stuff']
708 cur_page = 1
709 # Max message per page is 20 so we have to loop
710 while num > 20:
711 rel = rel + t.direct_messages(
712 count=20,
713 page=cur_page,
714 include_entities=False,
715 skip_status=False
716 )
717 num -= 20
718 cur_page += 1
719 rel = rel + t.direct_messages(
720 count=num,
721 page=cur_page,
722 include_entities=False,
723 skip_status=False
724 )
725 # Display
726 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
727 for m in reversed(rel):
728 print_message(m)
729 printNicely('')
730
731
732 def sent():
733 """
734 Sent direct messages
735 """
736 t = Twitter(auth=authen())
737 num = MESSAGES_DISPLAY
738 rel = []
739 if g['stuff'].isdigit():
740 num = int(g['stuff'])
741 cur_page = 1
742 # Max message per page is 20 so we have to loop
743 while num > 20:
744 rel = rel + t.direct_messages.sent(
745 count=20,
746 page=cur_page,
747 include_entities=False,
748 skip_status=False
749 )
750 num -= 20
751 cur_page += 1
752 rel = rel + t.direct_messages.sent(
753 count=num,
754 page=cur_page,
755 include_entities=False,
756 skip_status=False
757 )
758 # Display
759 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
760 for m in reversed(rel):
761 print_message(m)
762 printNicely('')
763
764
765 def trash():
766 """
767 Remove message
768 """
769 t = Twitter(auth=authen())
770 try:
771 rid = int(g['stuff'].split()[0])
772 except:
773 printNicely(red('Sorry I can\'t understand.'))
774 mid = db.rainbow_to_message_query(rid)[0].message_id
775 t.direct_messages.destroy(id=mid)
776 printNicely(green('Message deleted.'))
777
778
779 def whois():
780 """
781 Show profile of a specific user
782 """
783 t = Twitter(auth=authen())
784 screen_name = g['stuff'].split()[0]
785 if screen_name.startswith('@'):
786 try:
787 user = t.users.show(
788 screen_name=screen_name[1:],
789 include_entities=False)
790 show_profile(user)
791 except:
792 printNicely(red('Omg no user.'))
793 else:
794 printNicely(red('A name should begin with a \'@\''))
795
796
797 def follow():
798 """
799 Follow a user
800 """
801 t = Twitter(auth=authen())
802 screen_name = g['stuff'].split()[0]
803 if screen_name.startswith('@'):
804 t.friendships.create(screen_name=screen_name[1:], follow=True)
805 printNicely(green('You are following ' + screen_name + ' now!'))
806 else:
807 printNicely(red('A name should begin with a \'@\''))
808
809
810 def unfollow():
811 """
812 Unfollow a user
813 """
814 t = Twitter(auth=authen())
815 screen_name = g['stuff'].split()[0]
816 if screen_name.startswith('@'):
817 t.friendships.destroy(
818 screen_name=screen_name[1:],
819 include_entities=False)
820 printNicely(green('Unfollow ' + screen_name + ' success!'))
821 else:
822 printNicely(red('A name should begin with a \'@\''))
823
824
825 def block():
826 """
827 Block a user
828 """
829 t = Twitter(auth=authen())
830 screen_name = g['stuff'].split()[0]
831 if screen_name.startswith('@'):
832 t.blocks.create(
833 screen_name=screen_name[1:],
834 include_entities=False,
835 skip_status=True)
836 printNicely(green('You blocked ' + screen_name + '.'))
837 else:
838 printNicely(red('A name should begin with a \'@\''))
839
840
841 def unblock():
842 """
843 Unblock a user
844 """
845 t = Twitter(auth=authen())
846 screen_name = g['stuff'].split()[0]
847 if screen_name.startswith('@'):
848 t.blocks.destroy(
849 screen_name=screen_name[1:],
850 include_entities=False,
851 skip_status=True)
852 printNicely(green('Unblock ' + screen_name + ' success!'))
853 else:
854 printNicely(red('A name should begin with a \'@\''))
855
856
857 def report():
858 """
859 Report a user as a spam account
860 """
861 t = Twitter(auth=authen())
862 screen_name = g['stuff'].split()[0]
863 if screen_name.startswith('@'):
864 t.users.report_spam(
865 screen_name=screen_name[1:])
866 printNicely(green('You reported ' + screen_name + '.'))
867 else:
868 printNicely(red('Sorry I can\'t understand.'))
869
870
871 def help():
872 """
873 Help
874 """
875 s = ' ' * 2
876 h, w = os.popen('stty size', 'r').read().split()
877
878 usage = '\n'
879 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
880 usage += s + '-' * (int(w) - 4) + '\n'
881 usage += s + 'You are ' + yellow('already') + ' on your personal stream.\n'
882
883 usage += s * 2 + green('trend') + ' will show global trending topics. ' + \
884 'You can try ' + green('trend US') + ' or ' + \
885 green('trend JP Tokyo') + '.\n'
886 usage += s * 2 + green('home') + ' will show your timeline. ' + \
887 green('home 7') + ' will show 7 tweets.\n'
888 usage += s * 2 + green('view @mdo') + \
889 ' will show ' + magenta('@mdo') + '\'s home.\n'
890 usage += s * 2 + green('mentions') + ' will show mentions timeline. ' + \
891 green('mentions 7') + ' will show 7 mention tweets.\n'
892 usage += s * 2 + green('t oops ') + \
893 'will tweet "' + yellow('oops') + '" immediately.\n'
894 usage += s * 2 + \
895 green('rt 12 ') + ' will retweet to tweet with ' + \
896 yellow('[id=12]') + '.\n'
897 usage += s * 2 + \
898 green('fav 12 ') + ' will favorite the tweet with ' + \
899 yellow('[id=12]') + '.\n'
900 usage += s * 2 + green('rep 12 oops') + ' will reply "' + \
901 yellow('oops') + '" to tweet with ' + yellow('[id=12]') + '.\n'
902 usage += s * 2 + \
903 green('del 12 ') + ' will delete tweet with ' + \
904 yellow('[id=12]') + '.\n'
905 usage += s * 2 + \
906 green('ufav 12 ') + ' will unfavorite tweet with ' + \
907 yellow('[id=12]') + '.\n'
908 usage += s * 2 + green('s #AKB48') + ' will search for "' + \
909 yellow('AKB48') + '" and return 5 newest tweet.\n'
910 usage += s * 2 + green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
911 magenta('@dtvd88') + '.\n'
912 usage += s * 2 + green('show image 12') + ' will show image in tweet with ' + \
913 yellow('[id=12]') + ' in your OS\'s image viewer.\n'
914 usage += s * 2 + \
915 green('ls fl') + \
916 ' will list all followers (people who are following you).\n'
917 usage += s * 2 + \
918 green('ls fr') + \
919 ' will list all friends (people who you are following).\n'
920 usage += s * 2 + green('inbox') + ' will show inbox messages. ' + \
921 green('inbox 7') + ' will show newest 7 messages.\n'
922 usage += s * 2 + green('sent') + ' will show sent messages. ' + \
923 green('sent 7') + ' will show newest 7 messages.\n'
924 usage += s * 2 + green('trash 5') + ' will remove message with ' + \
925 yellow('[message_id=5]') + '.\n'
926 usage += s * 2 + green('whois @dtvd88') + ' will show profile of ' + \
927 magenta('@dtvd88') + '.\n'
928 usage += s * 2 + green('fl @dtvd88') + ' will follow ' + \
929 magenta('@dtvd88') + '.\n'
930 usage += s * 2 + green('ufl @dtvd88') + ' will unfollow ' + \
931 magenta('@dtvd88') + '.\n'
932 usage += s * 2 + green('block @dtvd88') + ' will block ' + \
933 magenta('@dtvd88') + '.\n'
934 usage += s * 2 + green('unblock @dtvd88') + ' will unblock ' + \
935 magenta('@dtvd88') + '.\n'
936 usage += s * 2 + green('report @dtvd88') + ' will report ' + \
937 magenta('@dtvd88') + ' as a spam account.\n'
938 usage += s * 2 + green('h') + ' will show this help again.\n'
939 usage += s * 2 + green('c') + ' will clear the screen.\n'
940 usage += s * 2 + green('q') + ' will quit.\n'
941
942 usage += s + 'For switching streams: \n'
943 usage += s * 2 + green('switch public #AKB') + \
944 ' will switch to public stream and follow "' + \
945 yellow('AKB') + '" keyword.\n'
946 usage += s * 2 + green('switch mine') + \
947 ' will switch to your personal stream.\n'
948 usage += s * 2 + green('switch mine -f ') + \
949 ' will prompt to enter the filter.\n'
950 usage += s * 3 + yellow('Only nicks') + \
951 ' filter will decide nicks will be INCLUDE ONLY.\n'
952 usage += s * 3 + yellow('Ignore nicks') + \
953 ' filter will decide nicks will be EXCLUDE.\n'
954 usage += s * 2 + green('switch mine -d') + \
955 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
956 usage += s * 3 + '(see ' + grey('rainbowstream/config.py') + ').\n'
957
958 usage += s + '-' * (int(w) - 4) + '\n'
959 usage += s + 'Have fun and hang tight!\n'
960 printNicely(usage)
961
962
963 def clear():
964 """
965 Clear screen
966 """
967 os.system('clear')
968
969
970 def quit():
971 """
972 Exit all
973 """
974 save_history()
975 os.system('rm -rf rainbow.db')
976 os.kill(g['stream_pid'], signal.SIGKILL)
977 sys.exit()
978
979
980 def reset():
981 """
982 Reset prefix of line
983 """
984 if g['reset']:
985 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
986 g['reset'] = False
987
988
989 def process(cmd):
990 """
991 Process switch
992 """
993 return dict(zip(
994 cmdset,
995 [
996 switch,
997 trend,
998 home,
999 view,
1000 mentions,
1001 tweet,
1002 retweet,
1003 favorite,
1004 reply,
1005 delete,
1006 unfavorite,
1007 search,
1008 message,
1009 show,
1010 list,
1011 inbox,
1012 sent,
1013 trash,
1014 whois,
1015 follow,
1016 unfollow,
1017 block,
1018 unblock,
1019 report,
1020 help,
1021 clear,
1022 quit
1023 ]
1024 )).get(cmd, reset)
1025
1026
1027 def listen():
1028 """
1029 Listen to user's input
1030 """
1031 d = dict(zip(
1032 cmdset,
1033 [
1034 ['public', 'mine'], # switch
1035 [], # trend
1036 [], # home
1037 ['@'], # view
1038 [], # mentions
1039 [], # tweet
1040 [], # retweet
1041 [], # favorite
1042 [], # reply
1043 [], # delete
1044 [], # unfavorite
1045 ['#'], # search
1046 ['@'], # message
1047 ['image'], # show image
1048 ['fl', 'fr'], # list
1049 [], # inbox
1050 [], # sent
1051 [], # trash
1052 ['@'], # whois
1053 ['@'], # follow
1054 ['@'], # unfollow
1055 ['@'], # block
1056 ['@'], # unblock
1057 ['@'], # report
1058 [], # help
1059 [], # clear
1060 [], # quit
1061 ]
1062 ))
1063 init_interactive_shell(d)
1064 read_history()
1065 reset()
1066 while True:
1067 if g['prefix']:
1068 line = raw_input(g['decorated_name'])
1069 else:
1070 line = raw_input()
1071 try:
1072 cmd = line.split()[0]
1073 except:
1074 cmd = ''
1075 # Save cmd to global variable and call process
1076 try:
1077 g['stuff'] = ' '.join(line.split()[1:])
1078 process(cmd)()
1079 except Exception:
1080 printNicely(red('OMG something is wrong with Twitter right now.'))
1081 # Not redisplay prefix
1082 if cmd in ['switch', 't', 'rt', 'rep']:
1083 g['prefix'] = False
1084 else:
1085 g['prefix'] = True
1086
1087
1088 def stream(domain, args, name='Rainbow Stream'):
1089 """
1090 Track the stream
1091 """
1092
1093 # The Logo
1094 art_dict = {
1095 USER_DOMAIN: name,
1096 PUBLIC_DOMAIN: args.track_keywords,
1097 SITE_DOMAIN: 'Site Stream',
1098 }
1099 ascii_art(art_dict[domain])
1100
1101 # These arguments are optional:
1102 stream_args = dict(
1103 timeout=args.timeout,
1104 block=not args.no_block,
1105 heartbeat_timeout=args.heartbeat_timeout)
1106
1107 # Track keyword
1108 query_args = dict()
1109 if args.track_keywords:
1110 query_args['track'] = args.track_keywords
1111
1112 # Get stream
1113 stream = TwitterStream(
1114 auth=authen(),
1115 domain=domain,
1116 **stream_args)
1117
1118 if domain == USER_DOMAIN:
1119 tweet_iter = stream.user(**query_args)
1120 elif domain == SITE_DOMAIN:
1121 tweet_iter = stream.site(**query_args)
1122 else:
1123 if args.track_keywords:
1124 tweet_iter = stream.statuses.filter(**query_args)
1125 else:
1126 tweet_iter = stream.statuses.sample()
1127
1128 # Iterate over the stream.
1129 for tweet in tweet_iter:
1130 if tweet is None:
1131 printNicely("-- None --")
1132 elif tweet is Timeout:
1133 printNicely("-- Timeout --")
1134 elif tweet is HeartbeatTimeout:
1135 printNicely("-- Heartbeat Timeout --")
1136 elif tweet is Hangup:
1137 printNicely("-- Hangup --")
1138 elif tweet.get('text'):
1139 draw(
1140 t=tweet,
1141 iot=args.image_on_term,
1142 keyword=args.track_keywords,
1143 fil=args.filter,
1144 ig=args.ignore,
1145 )
1146
1147
1148 def fly():
1149 """
1150 Main function
1151 """
1152 # Spawn stream process
1153 args = parse_arguments()
1154 get_decorated_name()
1155 p = Process(target=stream, args=(USER_DOMAIN, args, g['original_name']))
1156 p.start()
1157
1158 # Start listen process
1159 time.sleep(0.5)
1160 g['reset'] = True
1161 g['prefix'] = True
1162 g['stream_pid'] = p.pid
1163 g['iot'] = args.image_on_term
1164 listen()