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