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