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