handle ctrl+c
[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
80b70d60 13import webbrowser
91476ec3 14
91476ec3 15from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 16from twitter.api import *
91476ec3 17from twitter.oauth import OAuth, read_token_file
8c840a83 18from twitter.oauth_dance import oauth_dance
91476ec3 19from twitter.util import printNicely
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 *
c3bab4ef 28from .py3patch import *
29
531f5682 30# Global values
f405a7d0 31g = {}
531f5682
O
32
33# Database
18cab06a 34db = RainbowDB()
531f5682
O
35
36# Commands
94a5f62e 37cmdset = [
42fde775 38 'switch',
4592d231 39 'trend',
94a5f62e 40 'home',
41 'view',
305ce127 42 'mentions',
94a5f62e 43 't',
44 'rt',
80b70d60 45 'quote',
1f24a05a 46 'allrt',
7e4ccbf3 47 'fav',
94a5f62e 48 'rep',
49 'del',
7e4ccbf3 50 'ufav',
94a5f62e 51 's',
305ce127 52 'mes',
f5677fb1 53 'show',
80b70d60 54 'open',
0f6e4daf 55 'ls',
305ce127 56 'inbox',
57 'sent',
58 'trash',
e2b81717 59 'whois',
94a5f62e 60 'fl',
f5677fb1 61 'ufl',
5b2c4faf 62 'mute',
63 'unmute',
64 'muting',
305ce127 65 'block',
66 'unblock',
67 'report',
2d341029 68 'list',
813a5d80 69 'cal',
29fd0be6 70 'config',
632c6fa5 71 'theme',
94a5f62e 72 'h',
d6cc4c67
O
73 'p',
74 'r',
94a5f62e 75 'c',
76 'q'
77]
22be990e 78
c075e6dc 79
91476ec3
O
80def parse_arguments():
81 """
82 Parse the arguments
83 """
91476ec3 84 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
85 parser.add_argument(
86 '-to',
87 '--timeout',
88 help='Timeout for the stream (seconds).')
89 parser.add_argument(
90 '-ht',
91 '--heartbeat-timeout',
92 help='Set heartbeat timeout.',
93 default=90)
94 parser.add_argument(
95 '-nb',
96 '--no-block',
97 action='store_true',
98 help='Set stream to non-blocking.')
99 parser.add_argument(
100 '-tt',
101 '--track-keywords',
102 help='Search the stream for specific text.')
d51b4107
O
103 parser.add_argument(
104 '-fil',
105 '--filter',
106 help='Filter specific screen_name.')
107 parser.add_argument(
108 '-ig',
109 '--ignore',
110 help='Ignore specific screen_name.')
88af38d8 111 parser.add_argument(
c1fa7c94
O
112 '-iot',
113 '--image-on-term',
114 action='store_true',
115 help='Display all image on terminal.')
91476ec3
O
116 return parser.parse_args()
117
118
54277114
O
119def authen():
120 """
7b674cef 121 Authenticate with Twitter OAuth
54277114 122 """
8c840a83 123 # When using rainbow stream you must authorize.
2a6238f5
O
124 twitter_credential = os.environ.get(
125 'HOME',
126 os.environ.get(
127 'USERPROFILE',
128 '')) + os.sep + '.rainbow_oauth'
8c840a83
O
129 if not os.path.exists(twitter_credential):
130 oauth_dance("Rainbow Stream",
131 CONSUMER_KEY,
132 CONSUMER_SECRET,
133 twitter_credential)
134 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 135 return OAuth(
2a6238f5
O
136 oauth_token,
137 oauth_token_secret,
138 CONSUMER_KEY,
139 CONSUMER_SECRET)
91476ec3 140
54277114 141
fe9bb33b 142def init(args):
54277114 143 """
9683e61d 144 Init function
54277114 145 """
64156ac4
O
146 # Handle Ctrl C
147 ctrl_c_handler = lambda signum, frame: quit()
148 signal.signal(signal.SIGINT, ctrl_c_handler)
9683e61d 149 # Get name
54277114 150 t = Twitter(auth=authen())
c5ff542b 151 name = '@' + t.account.verify_credentials()['screen_name']
ceec8593 152 if not get_config('PREFIX'):
153 set_config('PREFIX', name)
42fde775 154 g['original_name'] = name[1:]
ceec8593 155 g['decorated_name'] = lambda x: color_func(
156 c['DECORATED_NAME'])(
157 '[' + x + ']: ')
9683e61d 158 # Theme init
422dd385 159 files = os.listdir(os.path.dirname(__file__) + '/colorset')
c075e6dc 160 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
632c6fa5 161 g['themes'] = themes
1f2f6159 162 db.theme_store(c['THEME'])
9683e61d 163 # Semaphore init
d6cc4c67 164 db.semaphore_store(False, False)
fe9bb33b 165 # Image on term
166 c['IMAGE_ON_TERM'] = args.image_on_term
f405a7d0 167
ceec8593 168
42fde775 169def switch():
170 """
171 Switch stream
172 """
173 try:
174 target = g['stuff'].split()[0]
d51b4107
O
175 # Filter and ignore
176 args = parse_arguments()
7e4ccbf3 177 try:
d51b4107 178 if g['stuff'].split()[-1] == '-f':
14db58c7 179 guide = 'To ignore an option, just hit Enter key.'
180 printNicely(light_magenta(guide))
181 only = raw_input('Only nicks [Ex: @xxx,@yy]: ')
182 ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
7e4ccbf3 183 args.filter = filter(None, only.split(','))
184 args.ignore = filter(None, ignore.split(','))
d51b4107 185 elif g['stuff'].split()[-1] == '-d':
632c6fa5
O
186 args.filter = c['ONLY_LIST']
187 args.ignore = c['IGNORE_LIST']
d51b4107
O
188 except:
189 printNicely(red('Sorry, wrong format.'))
190 return
42fde775 191 # Public stream
192 if target == 'public':
193 keyword = g['stuff'].split()[1]
194 if keyword[0] == '#':
195 keyword = keyword[1:]
42fde775 196 # Kill old process
197 os.kill(g['stream_pid'], signal.SIGKILL)
42fde775 198 args.track_keywords = keyword
42fde775 199 # Start new process
200 p = Process(
d51b4107 201 target=stream,
42fde775 202 args=(
632c6fa5 203 c['PUBLIC_DOMAIN'],
42fde775 204 args))
205 p.start()
206 g['stream_pid'] = p.pid
42fde775 207 # Personal stream
208 elif target == 'mine':
42fde775 209 # Kill old process
210 os.kill(g['stream_pid'], signal.SIGKILL)
42fde775 211 # Start new process
212 p = Process(
213 target=stream,
214 args=(
632c6fa5 215 c['USER_DOMAIN'],
42fde775 216 args,
217 g['original_name']))
218 p.start()
219 g['stream_pid'] = p.pid
d51b4107 220 printNicely('')
d51b4107
O
221 if args.filter:
222 printNicely(cyan('Only: ' + str(args.filter)))
223 if args.ignore:
224 printNicely(red('Ignore: ' + str(args.ignore)))
225 printNicely('')
42fde775 226 except:
227 printNicely(red('Sorry I can\'t understand.'))
42fde775 228
229
4592d231 230def trend():
231 """
232 Trend
233 """
234 t = Twitter(auth=authen())
48a25fe8 235 # Get country and town
4592d231 236 try:
237 country = g['stuff'].split()[0]
238 except:
239 country = ''
48a25fe8 240 try:
241 town = g['stuff'].split()[1]
242 except:
243 town = ''
48a25fe8 244 avail = t.trends.available()
245 # World wide
246 if not country:
247 trends = t.trends.place(_id=1)[0]['trends']
248 print_trends(trends)
249 else:
250 for location in avail:
251 # Search for country and Town
252 if town:
253 if location['countryCode'] == country \
254 and location['placeType']['name'] == 'Town' \
255 and location['name'] == town:
256 trends = t.trends.place(_id=location['woeid'])[0]['trends']
257 print_trends(trends)
258 # Search for country only
259 else:
260 if location['countryCode'] == country \
261 and location['placeType']['name'] == 'Country':
262 trends = t.trends.place(_id=location['woeid'])[0]['trends']
263 print_trends(trends)
4592d231 264
265
7b674cef 266def home():
267 """
268 Home
269 """
270 t = Twitter(auth=authen())
632c6fa5 271 num = c['HOME_TWEET_NUM']
7b674cef 272 if g['stuff'].isdigit():
305ce127 273 num = int(g['stuff'])
94a5f62e 274 for tweet in reversed(t.statuses.home_timeline(count=num)):
fe9bb33b 275 draw(t=tweet)
94a5f62e 276 printNicely('')
7b674cef 277
278
279def view():
280 """
281 Friend view
282 """
283 t = Twitter(auth=authen())
284 user = g['stuff'].split()[0]
b8fbcb70 285 if user[0] == '@':
286 try:
94a5f62e 287 num = int(g['stuff'].split()[1])
b8fbcb70 288 except:
632c6fa5 289 num = c['HOME_TWEET_NUM']
94a5f62e 290 for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])):
fe9bb33b 291 draw(t=tweet)
94a5f62e 292 printNicely('')
b8fbcb70 293 else:
c91f75f2 294 printNicely(red('A name should begin with a \'@\''))
7b674cef 295
296
305ce127 297def mentions():
298 """
299 Mentions timeline
300 """
301 t = Twitter(auth=authen())
632c6fa5 302 num = c['HOME_TWEET_NUM']
305ce127 303 if g['stuff'].isdigit():
304 num = int(g['stuff'])
305 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
fe9bb33b 306 draw(t=tweet)
305ce127 307 printNicely('')
308
309
f405a7d0 310def tweet():
54277114 311 """
7b674cef 312 Tweet
54277114
O
313 """
314 t = Twitter(auth=authen())
f405a7d0 315 t.statuses.update(status=g['stuff'])
f405a7d0 316
b2b933a9 317
1ba4abfd
O
318def retweet():
319 """
320 ReTweet
321 """
322 t = Twitter(auth=authen())
323 try:
324 id = int(g['stuff'].split()[0])
1ba4abfd 325 except:
b8c1f42a
O
326 printNicely(red('Sorry I can\'t understand.'))
327 return
328 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
329 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
1ba4abfd
O
330
331
80b70d60
O
332def quote():
333 """
334 Quote a tweet
335 """
336 t = Twitter(auth=authen())
337 try:
338 id = int(g['stuff'].split()[0])
339 except:
340 printNicely(red('Sorry I can\'t understand.'))
341 return
342 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
343 tweet = t.statuses.show(id=tid)
344 screen_name = tweet['user']['screen_name']
345 text = tweet['text']
346 quote = '\"@' + screen_name + ': ' + text + '\"'
347 quote = quote.encode('utf8')
595fdb16
O
348 notice = light_magenta('Compose mode ')
349 notice += light_yellow('(Enter nothing will cancel the quote)')
350 notice += light_magenta(':')
351 printNicely(notice)
80b70d60
O
352 extra = raw_input(quote)
353 if extra:
422dd385 354 t.statuses.update(status=quote + extra)
80b70d60
O
355 else:
356 printNicely(light_magenta('No text added.'))
357
358
1f24a05a 359def allretweet():
360 """
361 List all retweet
362 """
363 t = Twitter(auth=authen())
364 # Get rainbow id
365 try:
366 id = int(g['stuff'].split()[0])
367 except:
368 printNicely(red('Sorry I can\'t understand.'))
369 return
370 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
371 # Get display num if exist
372 try:
373 num = int(g['stuff'].split()[1])
374 except:
632c6fa5 375 num = c['RETWEETS_SHOW_NUM']
1f24a05a 376 # Get result and display
d8e901a4 377 rt_ary = t.statuses.retweets(id=tid, count=num)
1f24a05a 378 if not rt_ary:
379 printNicely(magenta('This tweet has no retweet.'))
380 return
381 for tweet in reversed(rt_ary):
fe9bb33b 382 draw(t=tweet)
1f24a05a 383 printNicely('')
384
385
7e4ccbf3 386def favorite():
387 """
388 Favorite
389 """
390 t = Twitter(auth=authen())
391 try:
392 id = int(g['stuff'].split()[0])
7e4ccbf3 393 except:
b8c1f42a
O
394 printNicely(red('Sorry I can\'t understand.'))
395 return
396 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
397 t.favorites.create(_id=tid, include_entities=False)
398 printNicely(green('Favorited.'))
fe9bb33b 399 draw(t.statuses.show(id=tid))
b8c1f42a 400 printNicely('')
7e4ccbf3 401
402
7b674cef 403def reply():
829cc2d8 404 """
7b674cef 405 Reply
829cc2d8
O
406 """
407 t = Twitter(auth=authen())
7b674cef 408 try:
409 id = int(g['stuff'].split()[0])
7b674cef 410 except:
c91f75f2 411 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
412 return
413 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
414 user = t.statuses.show(id=tid)['user']['screen_name']
415 status = ' '.join(g['stuff'].split()[1:])
416 status = '@' + user + ' ' + status.decode('utf-8')
417 t.statuses.update(status=status, in_reply_to_status_id=tid)
7b674cef 418
419
420def delete():
421 """
422 Delete
423 """
424 t = Twitter(auth=authen())
425 try:
305ce127 426 rid = int(g['stuff'].split()[0])
7b674cef 427 except:
305ce127 428 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
429 return
430 tid = db.rainbow_to_tweet_query(rid)[0].tweet_id
431 t.statuses.destroy(id=tid)
432 printNicely(green('Okay it\'s gone.'))
829cc2d8
O
433
434
7e4ccbf3 435def unfavorite():
436 """
437 Unfavorite
438 """
439 t = Twitter(auth=authen())
440 try:
441 id = int(g['stuff'].split()[0])
7e4ccbf3 442 except:
b8c1f42a
O
443 printNicely(red('Sorry I can\'t understand.'))
444 return
445 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
446 t.favorites.destroy(_id=tid)
447 printNicely(green('Okay it\'s unfavorited.'))
fe9bb33b 448 draw(t.statuses.show(id=tid))
b8c1f42a 449 printNicely('')
7e4ccbf3 450
451
f405a7d0
O
452def search():
453 """
7b674cef 454 Search
f405a7d0
O
455 """
456 t = Twitter(auth=authen())
59262e95
O
457 g['stuff'] = g['stuff'].strip()
458 rel = t.search.tweets(q=g['stuff'])['statuses']
459 if rel:
460 printNicely('Newest tweets:')
461 for i in reversed(xrange(c['SEARCH_MAX_RECORD'])):
462 draw(t=rel[i],
59262e95
O
463 keyword=g['stuff'])
464 printNicely('')
b8c1f42a 465 else:
59262e95 466 printNicely(magenta('I\'m afraid there is no result'))
b2b933a9 467
f405a7d0 468
305ce127 469def message():
470 """
471 Send a direct message
472 """
473 t = Twitter(auth=authen())
474 user = g['stuff'].split()[0]
b8c1f42a 475 if user[0].startswith('@'):
305ce127 476 try:
477 content = g['stuff'].split()[1]
305ce127 478 except:
479 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
480 t.direct_messages.new(
481 screen_name=user[1:],
482 text=content
483 )
484 printNicely(green('Message sent.'))
305ce127 485 else:
486 printNicely(red('A name should begin with a \'@\''))
487
488
f5677fb1 489def show():
843647ad 490 """
f5677fb1 491 Show image
843647ad
O
492 """
493 t = Twitter(auth=authen())
f5677fb1
O
494 try:
495 target = g['stuff'].split()[0]
496 if target != 'image':
497 return
498 id = int(g['stuff'].split()[1])
305ce127 499 tid = db.rainbow_to_tweet_query(id)[0].tweet_id
f5677fb1
O
500 tweet = t.statuses.show(id=tid)
501 media = tweet['entities']['media']
502 for m in media:
503 res = requests.get(m['media_url'])
b3164e62 504 img = Image.open(BytesIO(res.content))
f5677fb1
O
505 img.show()
506 except:
507 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
508
509
80bb2040 510def urlopen():
80b70d60
O
511 """
512 Open url
513 """
514 t = Twitter(auth=authen())
515 try:
516 if not g['stuff'].isdigit():
517 return
518 tid = db.rainbow_to_tweet_query(g['stuff'])[0].tweet_id
519 tweet = t.statuses.show(id=tid)
422dd385
O
520 link_ary = [
521 u for u in tweet['text'].split() if u.startswith('http://')]
80b70d60
O
522 if not link_ary:
523 printNicely(light_magenta('No url here @.@!'))
524 return
525 for link in link_ary:
526 webbrowser.open(link)
527 except:
528 printNicely(red('Sorry I can\'t open url in this tweet.'))
529
530
2d341029 531def ls():
0f6e4daf 532 """
533 List friends for followers
534 """
535 t = Twitter(auth=authen())
e2b81717
O
536 # Get name
537 try:
538 name = g['stuff'].split()[1]
b8c1f42a 539 if name.startswith('@'):
e2b81717
O
540 name = name[1:]
541 else:
542 printNicely(red('A name should begin with a \'@\''))
543 raise Exception('Invalid name')
544 except:
545 name = g['original_name']
546 # Get list followers or friends
0f6e4daf 547 try:
548 target = g['stuff'].split()[0]
0f6e4daf 549 except:
550 printNicely(red('Omg some syntax is wrong.'))
b8c1f42a
O
551 # Init cursor
552 d = {'fl': 'followers', 'fr': 'friends'}
553 next_cursor = -1
554 rel = {}
555 # Cursor loop
556 while next_cursor != 0:
557 list = getattr(t, d[target]).list(
558 screen_name=name,
559 cursor=next_cursor,
560 skip_status=True,
561 include_entities=False,
562 )
563 for u in list['users']:
564 rel[u['name']] = '@' + u['screen_name']
565 next_cursor = list['next_cursor']
566 # Print out result
2d341029 567 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
b8c1f42a 568 for name in rel:
2d341029 569 user = ' ' + cycle_color(name)
422dd385 570 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
b8c1f42a 571 printNicely(user)
0f6e4daf 572
573
305ce127 574def inbox():
575 """
576 Inbox direct messages
577 """
578 t = Twitter(auth=authen())
632c6fa5 579 num = c['MESSAGES_DISPLAY']
305ce127 580 rel = []
581 if g['stuff'].isdigit():
582 num = g['stuff']
583 cur_page = 1
584 # Max message per page is 20 so we have to loop
585 while num > 20:
586 rel = rel + t.direct_messages(
587 count=20,
588 page=cur_page,
589 include_entities=False,
590 skip_status=False
48a25fe8 591 )
305ce127 592 num -= 20
593 cur_page += 1
594 rel = rel + t.direct_messages(
595 count=num,
596 page=cur_page,
597 include_entities=False,
598 skip_status=False
48a25fe8 599 )
e2b81717 600 # Display
305ce127 601 printNicely('Inbox: newest ' + str(len(rel)) + ' messages.')
602 for m in reversed(rel):
603 print_message(m)
604 printNicely('')
605
e2b81717 606
305ce127 607def sent():
608 """
609 Sent direct messages
610 """
611 t = Twitter(auth=authen())
632c6fa5 612 num = c['MESSAGES_DISPLAY']
305ce127 613 rel = []
614 if g['stuff'].isdigit():
615 num = int(g['stuff'])
616 cur_page = 1
617 # Max message per page is 20 so we have to loop
618 while num > 20:
619 rel = rel + t.direct_messages.sent(
620 count=20,
621 page=cur_page,
622 include_entities=False,
623 skip_status=False
48a25fe8 624 )
305ce127 625 num -= 20
626 cur_page += 1
627 rel = rel + t.direct_messages.sent(
628 count=num,
629 page=cur_page,
630 include_entities=False,
631 skip_status=False
48a25fe8 632 )
e2b81717 633 # Display
305ce127 634 printNicely('Sent: newest ' + str(len(rel)) + ' messages.')
635 for m in reversed(rel):
636 print_message(m)
637 printNicely('')
e2b81717 638
305ce127 639
640def trash():
641 """
642 Remove message
643 """
644 t = Twitter(auth=authen())
645 try:
646 rid = int(g['stuff'].split()[0])
305ce127 647 except:
648 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a
O
649 mid = db.rainbow_to_message_query(rid)[0].message_id
650 t.direct_messages.destroy(id=mid)
651 printNicely(green('Message deleted.'))
305ce127 652
653
e2b81717
O
654def whois():
655 """
656 Show profile of a specific user
657 """
658 t = Twitter(auth=authen())
659 screen_name = g['stuff'].split()[0]
b8c1f42a 660 if screen_name.startswith('@'):
e2b81717
O
661 try:
662 user = t.users.show(
663 screen_name=screen_name[1:],
664 include_entities=False)
fe9bb33b 665 show_profile(user)
e2b81717
O
666 except:
667 printNicely(red('Omg no user.'))
668 else:
b8c1f42a 669 printNicely(red('A name should begin with a \'@\''))
e2b81717
O
670
671
f5677fb1 672def follow():
843647ad 673 """
f5677fb1 674 Follow a user
843647ad
O
675 """
676 t = Twitter(auth=authen())
f5677fb1 677 screen_name = g['stuff'].split()[0]
b8c1f42a
O
678 if screen_name.startswith('@'):
679 t.friendships.create(screen_name=screen_name[1:], follow=True)
680 printNicely(green('You are following ' + screen_name + ' now!'))
f5677fb1 681 else:
b8c1f42a 682 printNicely(red('A name should begin with a \'@\''))
f5677fb1
O
683
684
685def unfollow():
686 """
687 Unfollow a user
688 """
689 t = Twitter(auth=authen())
690 screen_name = g['stuff'].split()[0]
b8c1f42a
O
691 if screen_name.startswith('@'):
692 t.friendships.destroy(
693 screen_name=screen_name[1:],
694 include_entities=False)
695 printNicely(green('Unfollow ' + screen_name + ' success!'))
f5677fb1 696 else:
b8c1f42a 697 printNicely(red('A name should begin with a \'@\''))
843647ad
O
698
699
5b2c4faf 700def mute():
701 """
702 Mute a user
703 """
704 t = Twitter(auth=authen())
705 try:
706 screen_name = g['stuff'].split()[0]
707 except:
708 printNicely(red('A name should be specified. '))
709 return
710 if screen_name.startswith('@'):
711 rel = t.mutes.users.create(screen_name=screen_name[1:])
712 if isinstance(rel, dict):
713 printNicely(green(screen_name + ' is muted.'))
714 else:
715 printNicely(red(rel))
716 else:
717 printNicely(red('A name should begin with a \'@\''))
718
719
720def unmute():
721 """
722 Unmute a user
723 """
724 t = Twitter(auth=authen())
725 try:
726 screen_name = g['stuff'].split()[0]
727 except:
728 printNicely(red('A name should be specified. '))
729 return
730 if screen_name.startswith('@'):
731 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
732 if isinstance(rel, dict):
733 printNicely(green(screen_name + ' is unmuted.'))
734 else:
735 printNicely(red(rel))
736 else:
737 printNicely(red('A name should begin with a \'@\''))
738
739
740def muting():
741 """
742 List muting user
743 """
744 t = Twitter(auth=authen())
745 # Init cursor
5b2c4faf 746 next_cursor = -1
747 rel = {}
748 # Cursor loop
749 while next_cursor != 0:
750 list = t.mutes.users.list(
751 screen_name=g['original_name'],
752 cursor=next_cursor,
753 skip_status=True,
754 include_entities=False,
755 )
756 for u in list['users']:
757 rel[u['name']] = '@' + u['screen_name']
758 next_cursor = list['next_cursor']
759 # Print out result
760 printNicely('All: ' + str(len(rel)) + ' people.')
761 for name in rel:
2d341029 762 user = ' ' + cycle_color(name)
422dd385 763 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
5b2c4faf 764 printNicely(user)
765
766
305ce127 767def block():
768 """
769 Block a user
770 """
771 t = Twitter(auth=authen())
772 screen_name = g['stuff'].split()[0]
b8c1f42a
O
773 if screen_name.startswith('@'):
774 t.blocks.create(
5b2c4faf 775 screen_name=screen_name[1:],
776 include_entities=False,
777 skip_status=True)
b8c1f42a 778 printNicely(green('You blocked ' + screen_name + '.'))
305ce127 779 else:
b8c1f42a 780 printNicely(red('A name should begin with a \'@\''))
305ce127 781
782
783def unblock():
784 """
785 Unblock a user
786 """
787 t = Twitter(auth=authen())
788 screen_name = g['stuff'].split()[0]
b8c1f42a
O
789 if screen_name.startswith('@'):
790 t.blocks.destroy(
791 screen_name=screen_name[1:],
792 include_entities=False,
793 skip_status=True)
794 printNicely(green('Unblock ' + screen_name + ' success!'))
305ce127 795 else:
b8c1f42a 796 printNicely(red('A name should begin with a \'@\''))
305ce127 797
798
799def report():
800 """
801 Report a user as a spam account
802 """
803 t = Twitter(auth=authen())
804 screen_name = g['stuff'].split()[0]
b8c1f42a
O
805 if screen_name.startswith('@'):
806 t.users.report_spam(
807 screen_name=screen_name[1:])
808 printNicely(green('You reported ' + screen_name + '.'))
305ce127 809 else:
810 printNicely(red('Sorry I can\'t understand.'))
811
812
8b8566d1
O
813def get_slug():
814 """
815 Get Slug Decorator
816 """
a8c5fce4 817 # Get list name
8b8566d1
O
818 list_name = raw_input(light_magenta('Give me the list\'s name: '))
819 # Get list name and owner
820 try:
821 owner, slug = list_name.split('/')
822 if slug.startswith('@'):
823 slug = slug[1:]
824 return owner, slug
825 except:
a8c5fce4
O
826 printNicely(
827 light_magenta('List name should follow "@owner/list_name" format.'))
8b8566d1
O
828 raise Exception('Wrong list name')
829
830
2d341029
O
831def show_lists(t):
832 """
422dd385 833 List list
2d341029
O
834 """
835 rel = t.lists.list(screen_name=g['original_name'])
836 if rel:
837 print_list(rel)
838 else:
839 printNicely(light_magenta('You belong to no lists :)'))
840
841
842def list_home(t):
843 """
844 List home
845 """
8b8566d1 846 owner, slug = get_slug()
2d341029 847 res = t.lists.statuses(
422dd385
O
848 slug=slug,
849 owner_screen_name=owner,
850 count=c['LIST_MAX'],
2d341029
O
851 include_entities=False)
852 for tweet in res:
853 draw(t=tweet)
854 printNicely('')
855
856
857def list_members(t):
858 """
859 List members
860 """
8b8566d1 861 owner, slug = get_slug()
422dd385 862 # Get members
2d341029
O
863 rel = {}
864 next_cursor = -1
422dd385 865 while next_cursor != 0:
2d341029 866 m = t.lists.members(
422dd385
O
867 slug=slug,
868 owner_screen_name=owner,
869 cursor=next_cursor,
2d341029
O
870 include_entities=False)
871 for u in m['users']:
872 rel[u['name']] = '@' + u['screen_name']
873 next_cursor = m['next_cursor']
874 printNicely('All: ' + str(len(rel)) + ' members.')
875 for name in rel:
876 user = ' ' + cycle_color(name)
422dd385 877 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
878 printNicely(user)
879
880
881def list_subscribers(t):
882 """
883 List subscribers
884 """
8b8566d1 885 owner, slug = get_slug()
422dd385 886 # Get subscribers
2d341029
O
887 rel = {}
888 next_cursor = -1
422dd385 889 while next_cursor != 0:
2d341029 890 m = t.lists.subscribers(
422dd385
O
891 slug=slug,
892 owner_screen_name=owner,
893 cursor=next_cursor,
2d341029
O
894 include_entities=False)
895 for u in m['users']:
896 rel[u['name']] = '@' + u['screen_name']
897 next_cursor = m['next_cursor']
898 printNicely('All: ' + str(len(rel)) + ' subscribers.')
899 for name in rel:
900 user = ' ' + cycle_color(name)
422dd385 901 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
902 printNicely(user)
903
904
422dd385
O
905def list_add(t):
906 """
907 Add specific user to a list
908 """
8b8566d1 909 owner, slug = get_slug()
422dd385
O
910 # Add
911 user_name = raw_input(light_magenta('Give me name of the newbie: '))
912 if user_name.startswith('@'):
913 user_name = user_name[1:]
914 try:
915 t.lists.members.create(
916 slug=slug,
917 owner_screen_name=owner,
918 screen_name=user_name)
d6cc4c67 919 printNicely(green('Added.'))
422dd385
O
920 except:
921 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
922
923
2d341029
O
924def list_remove(t):
925 """
926 Remove specific user from a list
927 """
8b8566d1 928 owner, slug = get_slug()
2d341029 929 # Remove
422dd385
O
930 user_name = raw_input(light_magenta('Give me name of the unlucky one: '))
931 if user_name.startswith('@'):
932 user_name = user_name[1:]
2d341029
O
933 try:
934 t.lists.members.destroy(
422dd385
O
935 slug=slug,
936 owner_screen_name=owner,
937 screen_name=user_name)
d6cc4c67 938 printNicely(green('Gone.'))
422dd385
O
939 except:
940 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
941
942
943def list_subscribe(t):
944 """
945 Subscribe to a list
946 """
8b8566d1 947 owner, slug = get_slug()
422dd385
O
948 # Subscribe
949 try:
950 t.lists.subscribers.create(
951 slug=slug,
952 owner_screen_name=owner)
d6cc4c67 953 printNicely(green('Done.'))
422dd385
O
954 except:
955 printNicely(
956 light_magenta('I\'m sorry you can not subscribe to this list.'))
957
958
959def list_unsubscribe(t):
960 """
961 Unsubscribe a list
962 """
8b8566d1 963 owner, slug = get_slug()
422dd385
O
964 # Subscribe
965 try:
966 t.lists.subscribers.destroy(
967 slug=slug,
968 owner_screen_name=owner)
d6cc4c67 969 printNicely(green('Done.'))
422dd385
O
970 except:
971 printNicely(
972 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
973
974
975def list_own(t):
976 """
977 List own
978 """
979 rel = []
980 next_cursor = -1
981 while next_cursor != 0:
982 res = t.lists.ownerships(
983 screen_name=g['original_name'],
984 cursor=next_cursor)
985 rel += res['lists']
986 next_cursor = res['next_cursor']
987 if rel:
988 print_list(rel)
989 else:
990 printNicely(light_magenta('You own no lists :)'))
991
992
993def list_new(t):
994 """
995 Create a new list
996 """
997 name = raw_input(light_magenta('New list\'s name: '))
998 mode = raw_input(light_magenta('New list\'s mode (public/private): '))
999 description = raw_input(light_magenta('New list\'s description: '))
1000 try:
1001 t.lists.create(
1002 name=name,
1003 mode=mode,
1004 description=description)
d6cc4c67 1005 printNicely(green(name + ' list is created.'))
422dd385
O
1006 except:
1007 printNicely(red('Oops something is wrong with Twitter :('))
1008
1009
1010def list_update(t):
1011 """
1012 Update a list
1013 """
1014 slug = raw_input(light_magenta('Your list that you want to update: '))
1015 name = raw_input(light_magenta('Update name (leave blank to unchange): '))
1016 mode = raw_input(light_magenta('Update mode (public/private): '))
1017 description = raw_input(light_magenta('Update description: '))
1018 try:
1019 if name:
1020 t.lists.update(
1021 slug='-'.join(slug.split()),
1022 owner_screen_name=g['original_name'],
1023 name=name,
1024 mode=mode,
1025 description=description)
1026 else:
1027 t.lists.update(
1028 slug=slug,
1029 owner_screen_name=g['original_name'],
1030 mode=mode,
1031 description=description)
d6cc4c67 1032 printNicely(green(slug + ' list is updated.'))
3c85d8fc 1033 except:
422dd385
O
1034 printNicely(red('Oops something is wrong with Twitter :('))
1035
1036
1037def list_delete(t):
1038 """
1039 Delete a list
1040 """
1041 slug = raw_input(light_magenta('Your list that you want to update: '))
1042 try:
1043 t.lists.destroy(
1044 slug='-'.join(slug.split()),
1045 owner_screen_name=g['original_name'])
d6cc4c67 1046 printNicely(green(slug + ' list is deleted.'))
2d341029 1047 except:
422dd385 1048 printNicely(red('Oops something is wrong with Twitter :('))
2d341029
O
1049
1050
1051def list():
1052 """
1053 Twitter's list
1054 """
1055 t = Twitter(auth=authen())
1056 # List all lists or base on action
1057 try:
1058 g['list_action'] = g['stuff'].split()[0]
1059 except:
1060 show_lists(t)
1061 return
422dd385 1062 # Sub-function
2d341029
O
1063 action_ary = {
1064 'home': list_home,
1065 'all_mem': list_members,
1066 'all_sub': list_subscribers,
422dd385 1067 'add': list_add,
2d341029 1068 'rm': list_remove,
422dd385
O
1069 'sub': list_subscribe,
1070 'unsub': list_unsubscribe,
1071 'own': list_own,
1072 'new': list_new,
1073 'update': list_update,
1074 'del': list_delete,
2d341029
O
1075 }
1076 try:
1077 return action_ary[g['list_action']](t)
3c85d8fc 1078 except:
8b8566d1 1079 printNicely(red('Please try again.'))
2d341029
O
1080
1081
813a5d80 1082def cal():
1083 """
1084 Unix's command `cal`
1085 """
1086 # Format
1087 rel = os.popen('cal').read().split('\n')
1088 month = rel.pop(0)
813a5d80 1089 date = rel.pop(0)
2a0cabee 1090 show_calendar(month, date, rel)
813a5d80 1091
1092
29fd0be6
O
1093def config():
1094 """
1095 Browse and change config
1096 """
1097 all_config = get_all_config()
1098 g['stuff'] = g['stuff'].strip()
1099 # List all config
1100 if not g['stuff']:
1101 for k in all_config:
a8c5fce4 1102 line = ' ' * 2 + \
d6cc4c67 1103 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1104 printNicely(line)
1105 guide = 'Detailed explanation can be found at ' + \
a8c5fce4
O
1106 color_func(c['TWEET']['link'])(
1107 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
29fd0be6
O
1108 printNicely(guide)
1109 # Print specific config
1110 elif len(g['stuff'].split()) == 1:
1111 if g['stuff'] in all_config:
1112 k = g['stuff']
a8c5fce4 1113 line = ' ' * 2 + \
d6cc4c67 1114 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1115 printNicely(line)
1116 else:
fe9bb33b 1117 printNicely(red('No such config key.'))
29fd0be6
O
1118 # Print specific config's default value
1119 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'default':
1120 key = g['stuff'].split()[0]
fe9bb33b 1121 try:
1122 value = get_default_config(key)
d6cc4c67 1123 line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
fe9bb33b 1124 printNicely(line)
1125 except:
ceec8593 1126 printNicely(
1127 light_magenta('This config key does not exist in default.'))
fe9bb33b 1128 # Delete specific config key in config file
1129 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop':
1130 key = g['stuff'].split()[0]
1131 try:
1132 delete_config(key)
d6cc4c67 1133 printNicely(green('Config key is dropped.'))
fe9bb33b 1134 except:
1135 printNicely(red('No such config key.'))
29fd0be6 1136 # Set specific config
a8c5fce4 1137 elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=':
29fd0be6
O
1138 key = g['stuff'].split()[0]
1139 value = g['stuff'].split()[-1]
ceec8593 1140 if key == 'THEME' and not validate_theme(value):
1141 printNicely(red('Invalid theme\'s value.'))
1142 return
3c01ba57 1143 try:
a8c5fce4 1144 set_config(key, value)
ceec8593 1145 # Apply theme immediately
1146 if key == 'THEME':
1147 reload_theme(value)
1148 g['decorated_name'] = lambda x: color_func(
1149 c['DECORATED_NAME'])(
1150 '[' + x + ']: ')
d6cc4c67 1151 printNicely(green('Updated successfully.'))
3c01ba57
O
1152 except:
1153 printNicely(light_magenta('Not valid value.'))
1154 return
29fd0be6
O
1155 reload_config()
1156 else:
1157 printNicely(light_magenta('Sorry I can\'s understand.'))
1158
1159
632c6fa5
O
1160def theme():
1161 """
1162 List and change theme
1163 """
1164 if not g['stuff']:
1165 # List themes
1166 for theme in g['themes']:
1f2f6159
O
1167 line = light_magenta(theme)
1168 if c['THEME'] == theme:
422dd385 1169 line = ' ' * 2 + light_yellow('* ') + line
ddb1e615 1170 else:
422dd385 1171 line = ' ' * 4 + line
632c6fa5
O
1172 printNicely(line)
1173 else:
1174 # Change theme
c075e6dc 1175 try:
ceec8593 1176 # Load new theme
1177 reload_theme(g['stuff'])
1178 # Redefine decorated_name
1179 g['decorated_name'] = lambda x: color_func(
c075e6dc 1180 c['DECORATED_NAME'])(
ceec8593 1181 '[' + x + ']: ')
632c6fa5 1182 printNicely(green('Theme changed.'))
c075e6dc 1183 except:
1f2f6159 1184 printNicely(red('No such theme exists.'))
632c6fa5
O
1185
1186
2d341029 1187def help_discover():
f405a7d0 1188 """
2d341029 1189 Discover the world
f405a7d0 1190 """
7e4ccbf3 1191 s = ' ' * 2
1f24a05a 1192 # Discover the world
2d341029 1193 usage = '\n'
8bc30efd 1194 usage += s + grey(u'\u266A' + ' Discover the world \n')
c075e6dc
O
1195 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1196 'You can try ' + light_green('trend US') + ' or ' + \
1197 light_green('trend JP Tokyo') + '.\n'
1198 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1199 light_green('home 7') + ' will show 7 tweets.\n'
1200 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1201 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1202 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
8bc30efd 1203 magenta('@mdo') + '.\n'
c075e6dc 1204 usage += s * 2 + light_green('view @mdo') + \
8bc30efd 1205 ' will show ' + magenta('@mdo') + '\'s home.\n'
03e08f86
O
1206 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1207 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1208 'Search can be performed with or without hashtag.\n'
2d341029
O
1209 printNicely(usage)
1210
8bc30efd 1211
2d341029
O
1212def help_tweets():
1213 """
1214 Tweets
1215 """
1216 s = ' ' * 2
1f24a05a 1217 # Tweet
2d341029 1218 usage = '\n'
8bc30efd 1219 usage += s + grey(u'\u266A' + ' Tweets \n')
c075e6dc
O
1220 usage += s * 2 + light_green('t oops ') + \
1221 'will tweet "' + light_yellow('oops') + '" immediately.\n'
7e4ccbf3 1222 usage += s * 2 + \
c075e6dc
O
1223 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1224 light_yellow('[id=12]') + '.\n'
80b70d60
O
1225 usage += s * 2 + \
1226 light_green('quote 12 ') + ' will quote the tweet with ' + \
1227 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1228 'the quote will be canceled.\n'
1f24a05a 1229 usage += s * 2 + \
c075e6dc
O
1230 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1231 light_yellow('[id=12]') + '.\n'
1232 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
1233 light_yellow('oops') + '" to tweet with ' + \
1234 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1235 usage += s * 2 + \
c075e6dc
O
1236 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1237 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1238 usage += s * 2 + \
c075e6dc
O
1239 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1240 light_yellow('[id=12]') + '.\n'
8bc30efd 1241 usage += s * 2 + \
c075e6dc
O
1242 light_green('del 12 ') + ' will delete tweet with ' + \
1243 light_yellow('[id=12]') + '.\n'
1244 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1245 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
80b70d60
O
1246 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1247 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
2d341029 1248 printNicely(usage)
8bc30efd 1249
2d341029
O
1250
1251def help_messages():
1252 """
1253 Messages
1254 """
1255 s = ' ' * 2
5b2c4faf 1256 # Direct message
2d341029 1257 usage = '\n'
8bc30efd 1258 usage += s + grey(u'\u266A' + ' Direct messages \n')
c075e6dc
O
1259 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1260 light_green('inbox 7') + ' will show newest 7 messages.\n'
1261 usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \
1262 light_green('sent 7') + ' will show newest 7 messages.\n'
1263 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
8bc30efd 1264 magenta('@dtvd88') + '.\n'
c075e6dc
O
1265 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1266 light_yellow('[message_id=5]') + '.\n'
2d341029 1267 printNicely(usage)
8bc30efd 1268
2d341029
O
1269
1270def help_friends_and_followers():
1271 """
1272 Friends and Followers
1273 """
1274 s = ' ' * 2
8bc30efd 1275 # Follower and following
2d341029 1276 usage = '\n'
cdccb0d6 1277 usage += s + grey(u'\u266A' + ' Friends and followers \n')
8bc30efd 1278 usage += s * 2 + \
c075e6dc 1279 light_green('ls fl') + \
8bc30efd 1280 ' will list all followers (people who are following you).\n'
1281 usage += s * 2 + \
c075e6dc 1282 light_green('ls fr') + \
8bc30efd 1283 ' will list all friends (people who you are following).\n'
c075e6dc 1284 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
305ce127 1285 magenta('@dtvd88') + '.\n'
c075e6dc 1286 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 1287 magenta('@dtvd88') + '.\n'
c075e6dc 1288 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
5b2c4faf 1289 magenta('@dtvd88') + '.\n'
c075e6dc 1290 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
5b2c4faf 1291 magenta('@dtvd88') + '.\n'
c075e6dc
O
1292 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1293 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
305ce127 1294 magenta('@dtvd88') + '.\n'
c075e6dc 1295 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
305ce127 1296 magenta('@dtvd88') + '.\n'
c075e6dc 1297 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
305ce127 1298 magenta('@dtvd88') + ' as a spam account.\n'
2d341029
O
1299 printNicely(usage)
1300
1301
1302def help_list():
1303 """
1304 Lists
1305 """
1306 s = ' ' * 2
1307 # Twitter list
1308 usage = '\n'
1309 usage += s + grey(u'\u266A' + ' Twitter list\n')
1310 usage += s * 2 + light_green('list') + \
1311 ' will show all lists you are belong to.\n'
1312 usage += s * 2 + light_green('list home') + \
bef33491 1313 ' will show timeline of list. You will be asked for list\'s name.\n'
a65bd34c 1314 usage += s * 2 + light_green('list all_mem') + \
2d341029 1315 ' will show list\'s all members.\n'
a65bd34c 1316 usage += s * 2 + light_green('list all_sub') + \
2d341029 1317 ' will show list\'s all subscribers.\n'
422dd385
O
1318 usage += s * 2 + light_green('list add') + \
1319 ' will add specific person to a list owned by you.' + \
1320 ' You will be asked for list\'s name and person\'s name.\n'
2d341029
O
1321 usage += s * 2 + light_green('list rm') + \
1322 ' will remove specific person from a list owned by you.' + \
1323 ' You will be asked for list\'s name and person\'s name.\n'
422dd385
O
1324 usage += s * 2 + light_green('list sub') + \
1325 ' will subscribe you to a specific list.\n'
1326 usage += s * 2 + light_green('list unsub') + \
1327 ' will unsubscribe you from a specific list.\n'
1328 usage += s * 2 + light_green('list own') + \
1329 ' will show all list owned by you.\n'
1330 usage += s * 2 + light_green('list new') + \
1331 ' will create a new list.\n'
1332 usage += s * 2 + light_green('list update') + \
1333 ' will update a list owned by you.\n'
1334 usage += s * 2 + light_green('list del') + \
1335 ' will delete a list owned by you.\n'
2d341029 1336 printNicely(usage)
8bc30efd 1337
2d341029
O
1338
1339def help_stream():
1340 """
1341 Stream switch
1342 """
1343 s = ' ' * 2
8bc30efd 1344 # Switch
2d341029 1345 usage = '\n'
8bc30efd 1346 usage += s + grey(u'\u266A' + ' Switching streams \n')
c075e6dc 1347 usage += s * 2 + light_green('switch public #AKB') + \
48a25fe8 1348 ' will switch to public stream and follow "' + \
c075e6dc
O
1349 light_yellow('AKB') + '" keyword.\n'
1350 usage += s * 2 + light_green('switch mine') + \
48a25fe8 1351 ' will switch to your personal stream.\n'
c075e6dc 1352 usage += s * 2 + light_green('switch mine -f ') + \
48a25fe8 1353 ' will prompt to enter the filter.\n'
c075e6dc 1354 usage += s * 3 + light_yellow('Only nicks') + \
48a25fe8 1355 ' filter will decide nicks will be INCLUDE ONLY.\n'
c075e6dc 1356 usage += s * 3 + light_yellow('Ignore nicks') + \
48a25fe8 1357 ' filter will decide nicks will be EXCLUDE.\n'
c075e6dc 1358 usage += s * 2 + light_green('switch mine -d') + \
48a25fe8 1359 ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n'
2d341029
O
1360 printNicely(usage)
1361
1362
1363def help():
1364 """
1365 Help
1366 """
1367 s = ' ' * 2
1368 h, w = os.popen('stty size', 'r').read().split()
2d341029
O
1369 # Start
1370 usage = '\n'
1371 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1372 usage += s + '-' * (int(w) - 4) + '\n'
1373 usage += s + 'You are ' + \
1374 light_yellow('already') + ' on your personal stream.\n'
1375 usage += s + 'Any update from Twitter will show up ' + \
1376 light_yellow('immediately') + '.\n'
1377 usage += s + 'In addtion, following commands are available right now:\n'
2d341029
O
1378 # Twitter help section
1379 usage += '\n'
1380 usage += s + grey(u'\u266A' + ' Twitter help\n')
1381 usage += s * 2 + light_green('h discover') + \
1382 ' will show help for discover commands.\n'
1383 usage += s * 2 + light_green('h tweets') + \
1384 ' will show help for tweets commands.\n'
1385 usage += s * 2 + light_green('h messages') + \
1386 ' will show help for messages commands.\n'
1387 usage += s * 2 + light_green('h friends_and_followers') + \
1388 ' will show help for friends and followers commands.\n'
1389 usage += s * 2 + light_green('h list') + \
1390 ' will show help for list commands.\n'
1391 usage += s * 2 + light_green('h stream') + \
1392 ' will show help for stream commands.\n'
1f24a05a 1393 # Smart shell
1394 usage += '\n'
1395 usage += s + grey(u'\u266A' + ' Smart shell\n')
c075e6dc 1396 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1f24a05a 1397 'will be evaluate by Python interpreter.\n'
c075e6dc 1398 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1f24a05a 1399 ' for current month.\n'
29fd0be6 1400 # Config
1f24a05a 1401 usage += '\n'
29fd0be6
O
1402 usage += s + grey(u'\u266A' + ' Config \n')
1403 usage += s * 2 + light_green('theme') + ' will list available theme. ' + \
c075e6dc 1404 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
632c6fa5 1405 ' theme immediately.\n'
29fd0be6
O
1406 usage += s * 2 + light_green('config') + ' will list all config.\n'
1407 usage += s * 3 + \
1408 light_green('config ASCII_ART') + ' will output current value of ' +\
a8c5fce4 1409 light_yellow('ASCII_ART') + ' config key.\n'
29fd0be6 1410 usage += s * 3 + \
fe9bb33b 1411 light_green('config TREND_MAX default') + ' will output default value of ' + \
1412 light_yellow('TREND_MAX') + ' config key.\n'
1413 usage += s * 3 + \
1414 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1415 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
29fd0be6 1416 usage += s * 3 + \
fe9bb33b 1417 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1418 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1419 light_yellow('True') + '.\n'
29fd0be6
O
1420 # Screening
1421 usage += '\n'
1422 usage += s + grey(u'\u266A' + ' Screening \n')
c075e6dc 1423 usage += s * 2 + light_green('h') + ' will show this help again.\n'
d6cc4c67
O
1424 usage += s * 2 + light_green('p') + ' will pause the stream.\n'
1425 usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
c075e6dc
O
1426 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
1427 usage += s * 2 + light_green('q') + ' will quit.\n'
8bc30efd 1428 # End
1429 usage += '\n'
7e4ccbf3 1430 usage += s + '-' * (int(w) - 4) + '\n'
8bc30efd 1431 usage += s + 'Have fun and hang tight! \n'
2d341029
O
1432 # Show help
1433 d = {
422dd385
O
1434 'discover': help_discover,
1435 'tweets': help_tweets,
1436 'messages': help_messages,
1437 'friends_and_followers': help_friends_and_followers,
1438 'list': help_list,
1439 'stream': help_stream,
2d341029
O
1440 }
1441 if g['stuff']:
1442 d[g['stuff'].strip()]()
1443 else:
1444 printNicely(usage)
f405a7d0
O
1445
1446
d6cc4c67
O
1447def pause():
1448 """
1449 Pause stream display
1450 """
1451 db.semaphore_update_pause(True)
1452 printNicely(green('Stream is paused'))
1453
1454
1455def replay():
1456 """
1457 Replay stream
1458 """
1459 db.semaphore_update_pause(False)
1460 printNicely(green('Stream is running back now'))
1461
1462
843647ad 1463def clear():
f405a7d0 1464 """
7b674cef 1465 Clear screen
f405a7d0 1466 """
843647ad 1467 os.system('clear')
f405a7d0
O
1468
1469
843647ad 1470def quit():
b8dda704
O
1471 """
1472 Exit all
1473 """
f5677fb1 1474 save_history()
8e633322 1475 os.system('rm -rf rainbow.db')
843647ad 1476 os.kill(g['stream_pid'], signal.SIGKILL)
64156ac4 1477 printNicely(green('See you next time :)'))
843647ad 1478 sys.exit()
b8dda704
O
1479
1480
94a5f62e 1481def reset():
f405a7d0 1482 """
94a5f62e 1483 Reset prefix of line
f405a7d0 1484 """
c91f75f2 1485 if g['reset']:
e3885f55 1486 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 1487 g['reset'] = False
d0a726d6 1488 try:
2a0cabee
O
1489 printNicely(str(eval(g['cmd'])))
1490 except Exception:
d0a726d6 1491 pass
54277114
O
1492
1493
94a5f62e 1494def process(cmd):
54277114 1495 """
94a5f62e 1496 Process switch
54277114 1497 """
94a5f62e 1498 return dict(zip(
1499 cmdset,
b2b933a9 1500 [
42fde775 1501 switch,
4592d231 1502 trend,
b2b933a9 1503 home,
1504 view,
305ce127 1505 mentions,
b2b933a9 1506 tweet,
1507 retweet,
80b70d60 1508 quote,
1f24a05a 1509 allretweet,
7e4ccbf3 1510 favorite,
b2b933a9 1511 reply,
1512 delete,
7e4ccbf3 1513 unfavorite,
b2b933a9 1514 search,
305ce127 1515 message,
f5677fb1 1516 show,
80bb2040 1517 urlopen,
2d341029 1518 ls,
305ce127 1519 inbox,
1520 sent,
1521 trash,
e2b81717 1522 whois,
f5677fb1
O
1523 follow,
1524 unfollow,
5b2c4faf 1525 mute,
1526 unmute,
1527 muting,
305ce127 1528 block,
1529 unblock,
1530 report,
2d341029 1531 list,
813a5d80 1532 cal,
29fd0be6 1533 config,
632c6fa5 1534 theme,
b2b933a9 1535 help,
d6cc4c67
O
1536 pause,
1537 replay,
b2b933a9 1538 clear,
1539 quit
1540 ]
94a5f62e 1541 )).get(cmd, reset)
1542
1543
1544def listen():
42fde775 1545 """
1546 Listen to user's input
1547 """
d51b4107
O
1548 d = dict(zip(
1549 cmdset,
1550 [
affcb149 1551 ['public', 'mine'], # switch
4592d231 1552 [], # trend
7e4ccbf3 1553 [], # home
1554 ['@'], # view
305ce127 1555 [], # mentions
7e4ccbf3 1556 [], # tweet
1557 [], # retweet
80b70d60 1558 [], # quote
1f24a05a 1559 [], # allretweet
f5677fb1 1560 [], # favorite
7e4ccbf3 1561 [], # reply
1562 [], # delete
f5677fb1 1563 [], # unfavorite
7e4ccbf3 1564 ['#'], # search
305ce127 1565 ['@'], # message
f5677fb1 1566 ['image'], # show image
80b70d60 1567 [''], # open url
305ce127 1568 ['fl', 'fr'], # list
1569 [], # inbox
1570 [], # sent
1571 [], # trash
e2b81717 1572 ['@'], # whois
affcb149
O
1573 ['@'], # follow
1574 ['@'], # unfollow
5b2c4faf 1575 ['@'], # mute
1576 ['@'], # unmute
1577 ['@'], # muting
305ce127 1578 ['@'], # block
1579 ['@'], # unblock
1580 ['@'], # report
422dd385
O
1581 [
1582 'home',
1583 'all_mem',
1584 'all_sub',
1585 'add',
1586 'rm',
1587 'sub',
1588 'unsub',
1589 'own',
1590 'new',
1591 'update',
1592 'del'
1593 ], # list
813a5d80 1594 [], # cal
a8c5fce4 1595 [key for key in dict(get_all_config())], # config
ceec8593 1596 g['themes'], # theme
422dd385
O
1597 [
1598 'discover',
1599 'tweets',
1600 'messages',
1601 'friends_and_followers',
1602 'list',
1603 'stream'
1604 ], # help
d6cc4c67
O
1605 [], # pause
1606 [], # reconnect
7e4ccbf3 1607 [], # clear
1608 [], # quit
d51b4107 1609 ]
7e4ccbf3 1610 ))
d51b4107 1611 init_interactive_shell(d)
f5677fb1 1612 read_history()
819569e8 1613 reset()
b2b933a9 1614 while True:
1dd312f5 1615 if g['prefix']:
ceec8593 1616 line = raw_input(g['decorated_name'](c['PREFIX']))
1dd312f5
O
1617 else:
1618 line = raw_input()
843647ad
O
1619 try:
1620 cmd = line.split()[0]
1621 except:
1622 cmd = ''
d0a726d6 1623 g['cmd'] = cmd
b8c1f42a 1624 try:
9683e61d 1625 # Lock the semaphore
c37c04a9 1626 db.semaphore_update_lock(True)
9683e61d 1627 # Save cmd to global variable and call process
b8c1f42a 1628 g['stuff'] = ' '.join(line.split()[1:])
9683e61d 1629 # Process the command
b8c1f42a 1630 process(cmd)()
9683e61d
O
1631 # Not re-display
1632 if cmd in ['switch', 't', 'rt', 'rep']:
1633 g['prefix'] = False
1634 else:
1635 g['prefix'] = True
1636 # Release the semaphore lock
c37c04a9 1637 db.semaphore_update_lock(False)
eadd85a8 1638 except Exception:
b8c1f42a 1639 printNicely(red('OMG something is wrong with Twitter right now.'))
54277114
O
1640
1641
42fde775 1642def stream(domain, args, name='Rainbow Stream'):
54277114 1643 """
f405a7d0 1644 Track the stream
54277114 1645 """
54277114 1646 # The Logo
42fde775 1647 art_dict = {
632c6fa5
O
1648 c['USER_DOMAIN']: name,
1649 c['PUBLIC_DOMAIN']: args.track_keywords,
1f2f6159 1650 c['SITE_DOMAIN']: name,
42fde775 1651 }
687567eb 1652 if c['ASCII_ART']:
c075e6dc 1653 ascii_art(art_dict[domain])
91476ec3
O
1654 # These arguments are optional:
1655 stream_args = dict(
1656 timeout=args.timeout,
1657 block=not args.no_block,
1658 heartbeat_timeout=args.heartbeat_timeout)
91476ec3
O
1659 # Track keyword
1660 query_args = dict()
1661 if args.track_keywords:
1662 query_args['track'] = args.track_keywords
91476ec3 1663 # Get stream
2a6238f5 1664 stream = TwitterStream(
22be990e 1665 auth=authen(),
42fde775 1666 domain=domain,
2a6238f5 1667 **stream_args)
2a0cabee
O
1668 try:
1669 if domain == c['USER_DOMAIN']:
1670 tweet_iter = stream.user(**query_args)
1671 elif domain == c['SITE_DOMAIN']:
1672 tweet_iter = stream.site(**query_args)
42fde775 1673 else:
2a0cabee
O
1674 if args.track_keywords:
1675 tweet_iter = stream.statuses.filter(**query_args)
1676 else:
1677 tweet_iter = stream.statuses.sample()
72c02928
VNM
1678 for tweet in tweet_iter:
1679 if tweet is None:
1680 printNicely("-- None --")
1681 elif tweet is Timeout:
1682 printNicely("-- Timeout --")
1683 elif tweet is HeartbeatTimeout:
1684 printNicely("-- Heartbeat Timeout --")
1685 elif tweet is Hangup:
1686 printNicely("-- Hangup --")
1687 elif tweet.get('text'):
1688 draw(
1689 t=tweet,
72c02928 1690 keyword=args.track_keywords,
9683e61d 1691 check_semaphore=True,
72c02928
VNM
1692 fil=args.filter,
1693 ig=args.ignore,
1694 )
14db58c7 1695 elif tweet.get('direct_message'):
c37c04a9 1696 print_message(tweet['direct_message'],check_semaphore=True)
2a0cabee
O
1697 except TwitterHTTPError:
1698 printNicely('')
c075e6dc 1699 printNicely(
2a0cabee 1700 magenta("We have maximum connection problem with twitter'stream API right now :("))
54277114
O
1701
1702
1703def fly():
1704 """
1705 Main function
1706 """
531f5682 1707 # Initial
42fde775 1708 args = parse_arguments()
2a0cabee 1709 try:
fe9bb33b 1710 init(args)
2a0cabee
O
1711 except TwitterHTTPError:
1712 printNicely('')
1713 printNicely(
2e1241c7 1714 magenta("Something wrong with Twitter Oauth right now :("))
1715 printNicely(
1716 magenta("Please delete ~/.rainbow_oauth and try again."))
2a0cabee
O
1717 save_history()
1718 os.system('rm -rf rainbow.db')
1719 sys.exit()
531f5682 1720 # Spawn stream process
c075e6dc
O
1721 p = Process(
1722 target=stream,
1723 args=(
422dd385 1724 c['USER_DOMAIN'],
c075e6dc
O
1725 args,
1726 g['original_name']))
42fde775 1727 p.start()
42fde775 1728 # Start listen process
819569e8 1729 time.sleep(0.5)
c91f75f2 1730 g['reset'] = True
1dd312f5 1731 g['prefix'] = True
f405a7d0 1732 g['stream_pid'] = p.pid
0f6e4daf 1733 listen()