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