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