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