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