Small grammar correction
[rainbowstream.git] / rainbowstream / rainbow.py
CommitLineData
b2b933a9 1import os
2import os.path
3import sys
4import signal
5import argparse
6import time
92983945 7import threading
991c30af 8import requests
80b70d60 9import webbrowser
7a8a52fc 10import traceback
6e8fb961 11import pkg_resources
c426a344 12import socks
13import socket
91476ec3 14
a65129d4 15from io import BytesIO
91476ec3 16from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup
54277114 17from twitter.api import *
91476ec3 18from twitter.oauth import OAuth, read_token_file
8c840a83 19from twitter.oauth_dance import oauth_dance
91476ec3 20from twitter.util import printNicely
91476ec3 21
7500d90b 22from .draw import *
2a6238f5
O
23from .colors import *
24from .config import *
777c52d4 25from .consumer import *
94a5f62e 26from .interactive import *
991c30af 27from .c_image import *
c3bab4ef 28from .py3patch import *
841260fe 29from .emoji import *
9e38891f 30from .util import *
c3bab4ef 31
531f5682 32# Global values
f405a7d0 33g = {}
531f5682 34
92983945 35# Lock for streams
92983945
BS
36StreamLock = threading.Lock()
37
c075e6dc 38
91476ec3
O
39def parse_arguments():
40 """
41 Parse the arguments
42 """
91476ec3 43 parser = argparse.ArgumentParser(description=__doc__ or "")
2a6238f5
O
44 parser.add_argument(
45 '-to',
46 '--timeout',
47 help='Timeout for the stream (seconds).')
48 parser.add_argument(
2a6238f5
O
49 '-tt',
50 '--track-keywords',
51 help='Search the stream for specific text.')
d51b4107
O
52 parser.add_argument(
53 '-fil',
54 '--filter',
55 help='Filter specific screen_name.')
56 parser.add_argument(
57 '-ig',
58 '--ignore',
59 help='Ignore specific screen_name.')
88af38d8 60 parser.add_argument(
c1fa7c94
O
61 '-iot',
62 '--image-on-term',
63 action='store_true',
64 help='Display all image on terminal.')
c426a344 65 parser.add_argument(
66 '-ph',
67 '--proxy-host',
68 help='Use HTTP/SOCKS proxy for network connections.')
69 parser.add_argument(
70 '-pp',
71 '--proxy-port',
72 default=8080,
73 help='HTTP/SOCKS proxy port (Default: 8080).')
74 parser.add_argument(
75 '-pt',
76 '--proxy-type',
89e6bf4b 77 default='SOCKS5',
c426a344 78 help='Proxy type (HTTP, SOCKS4, SOCKS5; Default: SOCKS5).')
91476ec3
O
79 return parser.parse_args()
80
81
a65129d4
O
82def proxy_connect(args):
83 """
84 Connect to specified proxy
85 """
86 if args.proxy_host:
87 # Setup proxy by monkeypatching the standard lib
88 if args.proxy_type.lower() == "socks5" or not args.proxy_type:
89 socks.set_default_proxy(
90 socks.SOCKS5, args.proxy_host,
91 int(args.proxy_port))
92 elif args.proxy_type.lower() == "http":
93 socks.set_default_proxy(
94 socks.HTTP, args.proxy_host,
95 int(args.proxy_port))
96 elif args.proxy_type.lower() == "socks4":
97 socks.set_default_proxy(
98 socks.SOCKS4, args.proxy_host,
99 int(args.proxy_port))
100 else:
101 printNicely(
f07cfb6b 102 magenta('Sorry, wrong proxy type specified! Aborting...'))
a65129d4
O
103 sys.exit()
104 socket.socket = socks.socksocket
105
106
54277114
O
107def authen():
108 """
7b674cef 109 Authenticate with Twitter OAuth
54277114 110 """
8c840a83 111 # When using rainbow stream you must authorize.
2a6238f5
O
112 twitter_credential = os.environ.get(
113 'HOME',
114 os.environ.get(
115 'USERPROFILE',
116 '')) + os.sep + '.rainbow_oauth'
8c840a83 117 if not os.path.exists(twitter_credential):
f07cfb6b 118 oauth_dance('Rainbow Stream',
8c840a83
O
119 CONSUMER_KEY,
120 CONSUMER_SECRET,
121 twitter_credential)
122 oauth_token, oauth_token_secret = read_token_file(twitter_credential)
54277114 123 return OAuth(
2a6238f5
O
124 oauth_token,
125 oauth_token_secret,
126 CONSUMER_KEY,
127 CONSUMER_SECRET)
91476ec3 128
54277114 129
e3927852
O
130def build_mute_dict(dict_data=False):
131 """
132 Build muting list
133 """
134 t = Twitter(auth=authen())
135 # Init cursor
136 next_cursor = -1
137 screen_name_list = []
138 name_list = []
139 # Cursor loop
140 while next_cursor != 0:
141 list = t.mutes.users.list(
142 screen_name=g['original_name'],
143 cursor=next_cursor,
144 skip_status=True,
145 include_entities=False,
146 )
147 screen_name_list += ['@' + u['screen_name'] for u in list['users']]
148 name_list += [u['name'] for u in list['users']]
149 next_cursor = list['next_cursor']
150 # Return dict or list
151 if dict_data:
152 return dict(zip(screen_name_list, name_list))
153 else:
154 return screen_name_list
155
156
7a8a52fc
O
157def debug_option():
158 """
159 Save traceback when run in debug mode
160 """
161 if g['debug']:
162 g['traceback'].append(traceback.format_exc())
163
164
6e8fb961 165def upgrade_center():
166 """
167 Check latest and notify to upgrade
168 """
169 try:
f07cfb6b 170 current = pkg_resources.get_distribution('rainbowstream').version
6e8fb961 171 url = 'https://raw.githubusercontent.com/DTVD/rainbowstream/master/setup.py'
9ee4a3cc 172 readme = requests.get(url).text
f07cfb6b 173 latest = readme.split('version = \'')[1].split('\'')[0]
6e8fb961 174 if current != latest:
dfbc7288 175 notice = light_magenta('RainbowStream latest version is ')
6e8fb961 176 notice += light_green(latest)
177 notice += light_magenta(' while your current version is ')
178 notice += light_yellow(current) + '\n'
dfbc7288 179 notice += light_magenta('You should upgrade with ')
180 notice += light_green('pip install -U rainbowstream')
6e8fb961 181 printNicely(notice)
bf766c7b 182 else:
806f42df 183 notice = light_yellow('You are running latest version (')
184 notice += light_green(current)
185 notice += light_yellow(')')
186 printNicely(notice)
6e8fb961 187 except:
188 pass
189
190
fe9bb33b 191def init(args):
54277114 192 """
9683e61d 193 Init function
54277114 194 """
64156ac4
O
195 # Handle Ctrl C
196 ctrl_c_handler = lambda signum, frame: quit()
197 signal.signal(signal.SIGINT, ctrl_c_handler)
6e8fb961 198 # Upgrade notify
199 upgrade_center()
9683e61d 200 # Get name
54277114 201 t = Twitter(auth=authen())
67c663f8
O
202 credential = t.account.verify_credentials()
203 screen_name = '@' + credential['screen_name']
204 name = credential['name']
37cf396a 205 c['original_name'] = g['original_name'] = screen_name[1:]
1d01129e 206 g['listname'] = g['keyword'] = ''
b85ec13a 207 g['PREFIX'] = u2str(emojize(format_prefix()))
67c663f8 208 g['full_name'] = name
ceec8593 209 g['decorated_name'] = lambda x: color_func(
be4dba0e 210 c['DECORATED_NAME'])('[' + x + ']: ', rl=True)
9683e61d 211 # Theme init
422dd385 212 files = os.listdir(os.path.dirname(__file__) + '/colorset')
c075e6dc 213 themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json']
632c6fa5 214 g['themes'] = themes
4dc385b5 215 g['pause'] = False
67c663f8 216 g['message_threads'] = {}
4824b181 217 # Startup cmd
f1c1dfea 218 g['cmd'] = ''
6e8fb961 219 # Debug option default = True
220 g['debug'] = True
7a8a52fc 221 g['traceback'] = []
d7d9c67c 222 # Events
38a6dc30 223 c['events'] = []
9683e61d 224 # Semaphore init
99b52f5f 225 c['lock'] = False
99b52f5f
O
226 # Init tweet dict and message dict
227 c['tweet_dict'] = []
228 c['message_dict'] = []
fe9bb33b 229 # Image on term
230 c['IMAGE_ON_TERM'] = args.image_on_term
62686013 231 set_config('IMAGE_ON_TERM', str(c['IMAGE_ON_TERM']))
d4b36355
O
232 # Check type of ONLY_LIST and IGNORE_LIST
233 if not isinstance(c['ONLY_LIST'], list):
234 printNicely(red('ONLY_LIST is not a valid list value.'))
235 c['ONLY_LIST'] = []
236 if not isinstance(c['IGNORE_LIST'], list):
237 printNicely(red('IGNORE_LIST is not a valid list value.'))
238 c['IGNORE_LIST'] = []
e3927852
O
239 # Mute dict
240 c['IGNORE_LIST'] += build_mute_dict()
f405a7d0 241
ceec8593 242
4592d231 243def trend():
244 """
245 Trend
246 """
247 t = Twitter(auth=authen())
48a25fe8 248 # Get country and town
4592d231 249 try:
250 country = g['stuff'].split()[0]
251 except:
252 country = ''
48a25fe8 253 try:
254 town = g['stuff'].split()[1]
255 except:
256 town = ''
48a25fe8 257 avail = t.trends.available()
258 # World wide
259 if not country:
260 trends = t.trends.place(_id=1)[0]['trends']
261 print_trends(trends)
262 else:
263 for location in avail:
264 # Search for country and Town
265 if town:
266 if location['countryCode'] == country \
267 and location['placeType']['name'] == 'Town' \
268 and location['name'] == town:
269 trends = t.trends.place(_id=location['woeid'])[0]['trends']
270 print_trends(trends)
271 # Search for country only
272 else:
273 if location['countryCode'] == country \
274 and location['placeType']['name'] == 'Country':
275 trends = t.trends.place(_id=location['woeid'])[0]['trends']
276 print_trends(trends)
4592d231 277
278
7b674cef 279def home():
280 """
281 Home
282 """
283 t = Twitter(auth=authen())
632c6fa5 284 num = c['HOME_TWEET_NUM']
7b674cef 285 if g['stuff'].isdigit():
305ce127 286 num = int(g['stuff'])
94a5f62e 287 for tweet in reversed(t.statuses.home_timeline(count=num)):
fe9bb33b 288 draw(t=tweet)
94a5f62e 289 printNicely('')
7b674cef 290
291
99cd1fba
O
292def notification():
293 """
294 Show notifications
295 """
d7d9c67c 296 if c['events']:
297 for e in c['events']:
99cd1fba
O
298 print_event(e)
299 printNicely('')
300 else:
301 printNicely(magenta('Nothing at this time.'))
302
303
fd87ddac
O
304def mentions():
305 """
306 Mentions timeline
307 """
308 t = Twitter(auth=authen())
309 num = c['HOME_TWEET_NUM']
310 if g['stuff'].isdigit():
311 num = int(g['stuff'])
312 for tweet in reversed(t.statuses.mentions_timeline(count=num)):
313 draw(t=tweet)
314 printNicely('')
315
316
317def whois():
318 """
319 Show profile of a specific user
320 """
321 t = Twitter(auth=authen())
322 screen_name = g['stuff'].split()[0]
323 if screen_name.startswith('@'):
324 try:
325 user = t.users.show(
326 screen_name=screen_name[1:],
327 include_entities=False)
328 show_profile(user)
329 except:
7a8a52fc
O
330 debug_option()
331 printNicely(red('No user.'))
fd87ddac
O
332 else:
333 printNicely(red('A name should begin with a \'@\''))
334
335
7b674cef 336def view():
337 """
338 Friend view
339 """
340 t = Twitter(auth=authen())
341 user = g['stuff'].split()[0]
b8fbcb70 342 if user[0] == '@':
343 try:
94a5f62e 344 num = int(g['stuff'].split()[1])
b8fbcb70 345 except:
632c6fa5 346 num = c['HOME_TWEET_NUM']
9ee4a3cc
O
347 for tweet in reversed(
348 t.statuses.user_timeline(count=num, screen_name=user[1:])):
fe9bb33b 349 draw(t=tweet)
94a5f62e 350 printNicely('')
b8fbcb70 351 else:
c91f75f2 352 printNicely(red('A name should begin with a \'@\''))
7b674cef 353
354
fd87ddac 355def search():
2d0ad040 356 """
fd87ddac 357 Search
2d0ad040
J
358 """
359 t = Twitter(auth=authen())
954b3101 360 # Setup query
361 query = g['stuff'].strip()
362 type = c['SEARCH_TYPE']
363 if type not in ['mixed', 'recent', 'popular']:
364 type = 'mixed'
365 max_record = c['SEARCH_MAX_RECORD']
366 count = min(max_record, 100)
367 # Perform search
368 rel = t.search.tweets(
369 q=query,
370 type=type,
371 count=count
372 )['statuses']
373 # Return results
fd87ddac
O
374 if rel:
375 printNicely('Newest tweets:')
954b3101 376 for i in reversed(xrange(count)):
377 draw(t=rel[i], keyword=query)
fd87ddac
O
378 printNicely('')
379 else:
380 printNicely(magenta('I\'m afraid there is no result'))
2d0ad040
J
381
382
f405a7d0 383def tweet():
54277114 384 """
7b674cef 385 Tweet
54277114
O
386 """
387 t = Twitter(auth=authen())
f405a7d0 388 t.statuses.update(status=g['stuff'])
f405a7d0 389
b2b933a9 390
1ba4abfd
O
391def retweet():
392 """
393 ReTweet
394 """
395 t = Twitter(auth=authen())
396 try:
397 id = int(g['stuff'].split()[0])
1ba4abfd 398 except:
b8c1f42a
O
399 printNicely(red('Sorry I can\'t understand.'))
400 return
99b52f5f 401 tid = c['tweet_dict'][id]
b8c1f42a 402 t.statuses.retweet(id=tid, include_entities=False, trim_user=True)
1ba4abfd
O
403
404
80b70d60
O
405def quote():
406 """
407 Quote a tweet
408 """
b7c9c570 409 # Get tweet
80b70d60
O
410 t = Twitter(auth=authen())
411 try:
412 id = int(g['stuff'].split()[0])
413 except:
414 printNicely(red('Sorry I can\'t understand.'))
415 return
99b52f5f 416 tid = c['tweet_dict'][id]
80b70d60 417 tweet = t.statuses.show(id=tid)
b7c9c570 418 # Get formater
419 formater = format_quote(tweet)
420 if not formater:
7c437a0f 421 return
7c437a0f 422 # Get comment
be4dba0e 423 prefix = light_magenta('Compose your ', rl=True) + \
424 light_green('#comment: ', rl=True)
7c437a0f
O
425 comment = raw_input(prefix)
426 if comment:
427 quote = comment.join(formater.split('#comment'))
b7c9c570 428 t.statuses.update(status=quote)
80b70d60
O
429 else:
430 printNicely(light_magenta('No text added.'))
431
432
1f24a05a 433def allretweet():
434 """
435 List all retweet
436 """
437 t = Twitter(auth=authen())
438 # Get rainbow id
439 try:
440 id = int(g['stuff'].split()[0])
441 except:
442 printNicely(red('Sorry I can\'t understand.'))
443 return
99b52f5f 444 tid = c['tweet_dict'][id]
1f24a05a 445 # Get display num if exist
446 try:
447 num = int(g['stuff'].split()[1])
448 except:
632c6fa5 449 num = c['RETWEETS_SHOW_NUM']
1f24a05a 450 # Get result and display
d8e901a4 451 rt_ary = t.statuses.retweets(id=tid, count=num)
1f24a05a 452 if not rt_ary:
453 printNicely(magenta('This tweet has no retweet.'))
454 return
455 for tweet in reversed(rt_ary):
fe9bb33b 456 draw(t=tweet)
1f24a05a 457 printNicely('')
458
459
fd87ddac 460def conversation():
7e4ccbf3 461 """
fd87ddac 462 Conversation view
7e4ccbf3 463 """
464 t = Twitter(auth=authen())
465 try:
466 id = int(g['stuff'].split()[0])
7e4ccbf3 467 except:
b8c1f42a
O
468 printNicely(red('Sorry I can\'t understand.'))
469 return
99b52f5f 470 tid = c['tweet_dict'][id]
fd87ddac
O
471 tweet = t.statuses.show(id=tid)
472 limit = c['CONVERSATION_MAX']
473 thread_ref = []
474 thread_ref.append(tweet)
475 prev_tid = tweet['in_reply_to_status_id']
476 while prev_tid and limit:
477 limit -= 1
478 tweet = t.statuses.show(id=prev_tid)
479 prev_tid = tweet['in_reply_to_status_id']
480 thread_ref.append(tweet)
481
482 for tweet in reversed(thread_ref):
483 draw(t=tweet)
b8c1f42a 484 printNicely('')
7e4ccbf3 485
486
7b674cef 487def reply():
829cc2d8 488 """
7b674cef 489 Reply
829cc2d8
O
490 """
491 t = Twitter(auth=authen())
7b674cef 492 try:
493 id = int(g['stuff'].split()[0])
7b674cef 494 except:
c91f75f2 495 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a 496 return
99b52f5f 497 tid = c['tweet_dict'][id]
b8c1f42a
O
498 user = t.statuses.show(id=tid)['user']['screen_name']
499 status = ' '.join(g['stuff'].split()[1:])
7c437a0f 500 status = '@' + user + ' ' + str2u(status)
b8c1f42a 501 t.statuses.update(status=status, in_reply_to_status_id=tid)
7b674cef 502
503
ba6c09d1
O
504def reply_all():
505 """
506 Reply to all
507 """
508 t = Twitter(auth=authen())
509 try:
510 id = int(g['stuff'].split()[0])
511 except:
512 printNicely(red('Sorry I can\'t understand.'))
513 return
514 tid = c['tweet_dict'][id]
515 original_tweet = t.statuses.show(id=tid)
516 text = original_tweet['text']
517 owner = '@' + original_tweet['user']['screen_name']
518 nick_ary = ['@' + re.sub('[\W_]', '', w)
519 for w in text.split() if w.startswith('@')] + [owner]
520 status = ' '.join(g['stuff'].split()[1:])
521 status = ' '.join(nick_ary) + ' ' + str2u(status)
522 t.statuses.update(status=status, in_reply_to_status_id=tid)
523
524
fd87ddac 525def favorite():
7b674cef 526 """
fd87ddac 527 Favorite
7b674cef 528 """
529 t = Twitter(auth=authen())
530 try:
99b52f5f 531 id = int(g['stuff'].split()[0])
7b674cef 532 except:
305ce127 533 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a 534 return
99b52f5f 535 tid = c['tweet_dict'][id]
fd87ddac
O
536 t.favorites.create(_id=tid, include_entities=False)
537 printNicely(green('Favorited.'))
538 draw(t.statuses.show(id=tid))
539 printNicely('')
829cc2d8
O
540
541
7e4ccbf3 542def unfavorite():
543 """
544 Unfavorite
545 """
546 t = Twitter(auth=authen())
547 try:
548 id = int(g['stuff'].split()[0])
7e4ccbf3 549 except:
b8c1f42a
O
550 printNicely(red('Sorry I can\'t understand.'))
551 return
99b52f5f 552 tid = c['tweet_dict'][id]
b8c1f42a
O
553 t.favorites.destroy(_id=tid)
554 printNicely(green('Okay it\'s unfavorited.'))
fe9bb33b 555 draw(t.statuses.show(id=tid))
b8c1f42a 556 printNicely('')
7e4ccbf3 557
558
413857b5
O
559def share():
560 """
561 Copy url of a tweet to clipboard
562 """
563 t = Twitter(auth=authen())
564 try:
565 id = int(g['stuff'].split()[0])
66fe9f75 566 tid = c['tweet_dict'][id]
413857b5 567 except:
66fe9f75 568 printNicely(red('Tweet id is not valid.'))
413857b5 569 return
413857b5
O
570 tweet = t.statuses.show(id=tid)
571 url = 'https://twitter.com/' + \
572 tweet['user']['screen_name'] + '/status/' + str(tid)
eb9b6273 573 import platform
574 if platform.system().lower() == 'darwin':
575 os.system("echo '%s' | pbcopy" % url)
576 printNicely(green('Copied tweet\'s url to clipboard.'))
577 else:
578 printNicely('Direct link: ' + yellow(url))
413857b5
O
579
580
fd87ddac 581def delete():
305ce127 582 """
fd87ddac 583 Delete
305ce127 584 """
585 t = Twitter(auth=authen())
fd87ddac
O
586 try:
587 id = int(g['stuff'].split()[0])
588 except:
589 printNicely(red('Sorry I can\'t understand.'))
590 return
591 tid = c['tweet_dict'][id]
592 t.statuses.destroy(id=tid)
593 printNicely(green('Okay it\'s gone.'))
305ce127 594
595
f5677fb1 596def show():
843647ad 597 """
f5677fb1 598 Show image
843647ad
O
599 """
600 t = Twitter(auth=authen())
f5677fb1
O
601 try:
602 target = g['stuff'].split()[0]
603 if target != 'image':
604 return
605 id = int(g['stuff'].split()[1])
99b52f5f 606 tid = c['tweet_dict'][id]
f5677fb1
O
607 tweet = t.statuses.show(id=tid)
608 media = tweet['entities']['media']
609 for m in media:
610 res = requests.get(m['media_url'])
b3164e62 611 img = Image.open(BytesIO(res.content))
f5677fb1
O
612 img.show()
613 except:
7a8a52fc 614 debug_option()
f5677fb1 615 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
616
617
80bb2040 618def urlopen():
80b70d60
O
619 """
620 Open url
621 """
622 t = Twitter(auth=authen())
623 try:
624 if not g['stuff'].isdigit():
625 return
8101275e 626 tid = c['tweet_dict'][int(g['stuff'])]
80b70d60 627 tweet = t.statuses.show(id=tid)
571ea706
O
628 link_prefix = ('http://', 'https://')
629 link_ary = [u for u in tweet['text'].split()
630 if u.startswith(link_prefix)]
80b70d60
O
631 if not link_ary:
632 printNicely(light_magenta('No url here @.@!'))
633 return
634 for link in link_ary:
635 webbrowser.open(link)
636 except:
7a8a52fc 637 debug_option()
80b70d60
O
638 printNicely(red('Sorry I can\'t open url in this tweet.'))
639
640
305ce127 641def inbox():
642 """
67c663f8 643 Inbox threads
305ce127 644 """
645 t = Twitter(auth=authen())
632c6fa5 646 num = c['MESSAGES_DISPLAY']
305ce127 647 if g['stuff'].isdigit():
648 num = g['stuff']
67c663f8 649 # Get inbox messages
305ce127 650 cur_page = 1
67c663f8 651 inbox = []
305ce127 652 while num > 20:
67c663f8 653 inbox = inbox + t.direct_messages(
305ce127 654 count=20,
655 page=cur_page,
656 include_entities=False,
657 skip_status=False
48a25fe8 658 )
305ce127 659 num -= 20
660 cur_page += 1
67c663f8 661 inbox = inbox + t.direct_messages(
305ce127 662 count=num,
663 page=cur_page,
664 include_entities=False,
665 skip_status=False
48a25fe8 666 )
67c663f8 667 # Get sent messages
632c6fa5 668 num = c['MESSAGES_DISPLAY']
305ce127 669 if g['stuff'].isdigit():
67c663f8 670 num = g['stuff']
305ce127 671 cur_page = 1
67c663f8 672 sent = []
305ce127 673 while num > 20:
67c663f8 674 sent = sent + t.direct_messages.sent(
305ce127 675 count=20,
676 page=cur_page,
677 include_entities=False,
678 skip_status=False
48a25fe8 679 )
305ce127 680 num -= 20
681 cur_page += 1
67c663f8 682 sent = sent + t.direct_messages.sent(
305ce127 683 count=num,
684 page=cur_page,
685 include_entities=False,
686 skip_status=False
48a25fe8 687 )
67c663f8
O
688
689 d = {}
690 uniq_inbox = list(set(
03c0d30b 691 [(m['sender_screen_name'], m['sender']['name']) for m in inbox]
67c663f8 692 ))
03c0d30b 693 uniq_sent = list(set(
694 [(m['recipient_screen_name'], m['recipient']['name']) for m in sent]
67c663f8
O
695 ))
696 for partner in uniq_inbox:
697 inbox_ary = [m for m in inbox if m['sender_screen_name'] == partner[0]]
03c0d30b 698 sent_ary = [
699 m for m in sent if m['recipient_screen_name'] == partner[0]]
67c663f8
O
700 d[partner] = inbox_ary + sent_ary
701 for partner in uniq_sent:
702 if partner not in d:
03c0d30b 703 d[partner] = [
704 m for m in sent if m['recipient_screen_name'] == partner[0]]
67c663f8
O
705 g['message_threads'] = print_threads(d)
706
707
708def thread():
709 """
710 View a thread of message
711 """
712 try:
713 thread_id = int(g['stuff'])
03c0d30b 714 print_thread(
715 g['message_threads'][thread_id],
716 g['original_name'],
717 g['full_name'])
718 except Exception:
7a8a52fc 719 debug_option()
67c663f8 720 printNicely(red('No such thread.'))
e2b81717 721
305ce127 722
fd87ddac
O
723def message():
724 """
725 Send a direct message
726 """
727 t = Twitter(auth=authen())
03c0d30b 728 try:
729 user = g['stuff'].split()[0]
730 if user[0].startswith('@'):
731 content = ' '.join(g['stuff'].split()[1:])
732 t.direct_messages.new(
733 screen_name=user[1:],
734 text=content
735 )
736 printNicely(green('Message sent.'))
737 else:
738 printNicely(red('A name should begin with a \'@\''))
739 except:
7a8a52fc 740 debug_option()
03c0d30b 741 printNicely(red('Sorry I can\'t understand.'))
fd87ddac
O
742
743
305ce127 744def trash():
745 """
746 Remove message
747 """
748 t = Twitter(auth=authen())
749 try:
99b52f5f 750 id = int(g['stuff'].split()[0])
305ce127 751 except:
752 printNicely(red('Sorry I can\'t understand.'))
99b52f5f 753 mid = c['message_dict'][id]
b8c1f42a
O
754 t.direct_messages.destroy(id=mid)
755 printNicely(green('Message deleted.'))
305ce127 756
757
fd87ddac 758def ls():
e2b81717 759 """
fd87ddac 760 List friends for followers
e2b81717
O
761 """
762 t = Twitter(auth=authen())
fd87ddac
O
763 # Get name
764 try:
765 name = g['stuff'].split()[1]
766 if name.startswith('@'):
767 name = name[1:]
768 else:
769 printNicely(red('A name should begin with a \'@\''))
770 raise Exception('Invalid name')
771 except:
772 name = g['original_name']
773 # Get list followers or friends
774 try:
775 target = g['stuff'].split()[0]
776 except:
777 printNicely(red('Omg some syntax is wrong.'))
778 # Init cursor
779 d = {'fl': 'followers', 'fr': 'friends'}
780 next_cursor = -1
781 rel = {}
782 # Cursor loop
783 while next_cursor != 0:
784 list = getattr(t, d[target]).list(
785 screen_name=name,
786 cursor=next_cursor,
787 skip_status=True,
788 include_entities=False,
789 )
790 for u in list['users']:
791 rel[u['name']] = '@' + u['screen_name']
792 next_cursor = list['next_cursor']
793 # Print out result
794 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
795 for name in rel:
796 user = ' ' + cycle_color(name)
797 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
798 printNicely(user)
e2b81717
O
799
800
f5677fb1 801def follow():
843647ad 802 """
f5677fb1 803 Follow a user
843647ad
O
804 """
805 t = Twitter(auth=authen())
f5677fb1 806 screen_name = g['stuff'].split()[0]
b8c1f42a
O
807 if screen_name.startswith('@'):
808 t.friendships.create(screen_name=screen_name[1:], follow=True)
809 printNicely(green('You are following ' + screen_name + ' now!'))
f5677fb1 810 else:
b8c1f42a 811 printNicely(red('A name should begin with a \'@\''))
f5677fb1
O
812
813
814def unfollow():
815 """
816 Unfollow a user
817 """
818 t = Twitter(auth=authen())
819 screen_name = g['stuff'].split()[0]
b8c1f42a
O
820 if screen_name.startswith('@'):
821 t.friendships.destroy(
822 screen_name=screen_name[1:],
823 include_entities=False)
824 printNicely(green('Unfollow ' + screen_name + ' success!'))
f5677fb1 825 else:
b8c1f42a 826 printNicely(red('A name should begin with a \'@\''))
843647ad
O
827
828
5b2c4faf 829def mute():
830 """
831 Mute a user
832 """
833 t = Twitter(auth=authen())
834 try:
835 screen_name = g['stuff'].split()[0]
836 except:
837 printNicely(red('A name should be specified. '))
838 return
839 if screen_name.startswith('@'):
e3927852
O
840 try:
841 rel = t.mutes.users.create(screen_name=screen_name[1:])
842 if isinstance(rel, dict):
843 printNicely(green(screen_name + ' is muted.'))
612d6863 844 c['IGNORE_LIST'] += [unc(screen_name)]
e3927852
O
845 c['IGNORE_LIST'] = list(set(c['IGNORE_LIST']))
846 else:
847 printNicely(red(rel))
848 except:
7a8a52fc 849 debug_option()
e3927852 850 printNicely(red('Something is wrong, can not mute now :('))
5b2c4faf 851 else:
852 printNicely(red('A name should begin with a \'@\''))
853
854
855def unmute():
856 """
857 Unmute a user
858 """
859 t = Twitter(auth=authen())
860 try:
861 screen_name = g['stuff'].split()[0]
862 except:
863 printNicely(red('A name should be specified. '))
864 return
865 if screen_name.startswith('@'):
e3927852
O
866 try:
867 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
868 if isinstance(rel, dict):
869 printNicely(green(screen_name + ' is unmuted.'))
870 c['IGNORE_LIST'].remove(screen_name)
871 else:
872 printNicely(red(rel))
873 except:
874 printNicely(red('Maybe you are not muting this person ?'))
5b2c4faf 875 else:
876 printNicely(red('A name should begin with a \'@\''))
877
878
879def muting():
880 """
881 List muting user
882 """
e3927852
O
883 # Get dict of muting users
884 md = build_mute_dict(dict_data=True)
885 printNicely('All: ' + str(len(md)) + ' people.')
886 for name in md:
887 user = ' ' + cycle_color(md[name])
888 user += color_func(c['TWEET']['nick'])(' ' + name + ' ')
5b2c4faf 889 printNicely(user)
e3927852
O
890 # Update from Twitter
891 c['IGNORE_LIST'] = [n for n in md]
5b2c4faf 892
893
305ce127 894def block():
895 """
896 Block a user
897 """
898 t = Twitter(auth=authen())
899 screen_name = g['stuff'].split()[0]
b8c1f42a
O
900 if screen_name.startswith('@'):
901 t.blocks.create(
5b2c4faf 902 screen_name=screen_name[1:],
903 include_entities=False,
904 skip_status=True)
b8c1f42a 905 printNicely(green('You blocked ' + screen_name + '.'))
305ce127 906 else:
b8c1f42a 907 printNicely(red('A name should begin with a \'@\''))
305ce127 908
909
910def unblock():
911 """
912 Unblock a user
913 """
914 t = Twitter(auth=authen())
915 screen_name = g['stuff'].split()[0]
b8c1f42a
O
916 if screen_name.startswith('@'):
917 t.blocks.destroy(
918 screen_name=screen_name[1:],
919 include_entities=False,
920 skip_status=True)
921 printNicely(green('Unblock ' + screen_name + ' success!'))
305ce127 922 else:
b8c1f42a 923 printNicely(red('A name should begin with a \'@\''))
305ce127 924
925
926def report():
927 """
928 Report a user as a spam account
929 """
930 t = Twitter(auth=authen())
931 screen_name = g['stuff'].split()[0]
b8c1f42a
O
932 if screen_name.startswith('@'):
933 t.users.report_spam(
934 screen_name=screen_name[1:])
935 printNicely(green('You reported ' + screen_name + '.'))
305ce127 936 else:
937 printNicely(red('Sorry I can\'t understand.'))
938
939
8b8566d1
O
940def get_slug():
941 """
ee4c94b1 942 Get slug
8b8566d1 943 """
a8c5fce4 944 # Get list name
be4dba0e 945 list_name = raw_input(
946 light_magenta('Give me the list\'s name ("@owner/list_name"): ', rl=True))
8b8566d1
O
947 # Get list name and owner
948 try:
949 owner, slug = list_name.split('/')
950 if slug.startswith('@'):
951 slug = slug[1:]
952 return owner, slug
953 except:
a8c5fce4
O
954 printNicely(
955 light_magenta('List name should follow "@owner/list_name" format.'))
8b8566d1
O
956 raise Exception('Wrong list name')
957
958
2d341029
O
959def show_lists(t):
960 """
422dd385 961 List list
2d341029
O
962 """
963 rel = t.lists.list(screen_name=g['original_name'])
964 if rel:
965 print_list(rel)
966 else:
967 printNicely(light_magenta('You belong to no lists :)'))
968
969
970def list_home(t):
971 """
972 List home
973 """
8b8566d1 974 owner, slug = get_slug()
2d341029 975 res = t.lists.statuses(
422dd385
O
976 slug=slug,
977 owner_screen_name=owner,
978 count=c['LIST_MAX'],
2d341029 979 include_entities=False)
7304256c 980 for tweet in reversed(res):
2d341029
O
981 draw(t=tweet)
982 printNicely('')
983
984
985def list_members(t):
986 """
987 List members
988 """
8b8566d1 989 owner, slug = get_slug()
422dd385 990 # Get members
2d341029
O
991 rel = {}
992 next_cursor = -1
422dd385 993 while next_cursor != 0:
2d341029 994 m = t.lists.members(
422dd385
O
995 slug=slug,
996 owner_screen_name=owner,
997 cursor=next_cursor,
2d341029
O
998 include_entities=False)
999 for u in m['users']:
1000 rel[u['name']] = '@' + u['screen_name']
1001 next_cursor = m['next_cursor']
1002 printNicely('All: ' + str(len(rel)) + ' members.')
1003 for name in rel:
1004 user = ' ' + cycle_color(name)
422dd385 1005 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
1006 printNicely(user)
1007
1008
1009def list_subscribers(t):
1010 """
1011 List subscribers
1012 """
8b8566d1 1013 owner, slug = get_slug()
422dd385 1014 # Get subscribers
2d341029
O
1015 rel = {}
1016 next_cursor = -1
422dd385 1017 while next_cursor != 0:
2d341029 1018 m = t.lists.subscribers(
422dd385
O
1019 slug=slug,
1020 owner_screen_name=owner,
1021 cursor=next_cursor,
2d341029
O
1022 include_entities=False)
1023 for u in m['users']:
1024 rel[u['name']] = '@' + u['screen_name']
1025 next_cursor = m['next_cursor']
1026 printNicely('All: ' + str(len(rel)) + ' subscribers.')
1027 for name in rel:
1028 user = ' ' + cycle_color(name)
422dd385 1029 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
1030 printNicely(user)
1031
1032
422dd385
O
1033def list_add(t):
1034 """
1035 Add specific user to a list
1036 """
8b8566d1 1037 owner, slug = get_slug()
422dd385 1038 # Add
be4dba0e 1039 user_name = raw_input(
1040 light_magenta(
1041 'Give me name of the newbie: ',
1042 rl=True))
422dd385
O
1043 if user_name.startswith('@'):
1044 user_name = user_name[1:]
1045 try:
1046 t.lists.members.create(
1047 slug=slug,
1048 owner_screen_name=owner,
1049 screen_name=user_name)
d6cc4c67 1050 printNicely(green('Added.'))
422dd385 1051 except:
7a8a52fc 1052 debug_option()
422dd385
O
1053 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
1054
1055
2d341029
O
1056def list_remove(t):
1057 """
1058 Remove specific user from a list
1059 """
8b8566d1 1060 owner, slug = get_slug()
2d341029 1061 # Remove
be4dba0e 1062 user_name = raw_input(
1063 light_magenta(
1064 'Give me name of the unlucky one: ',
1065 rl=True))
422dd385
O
1066 if user_name.startswith('@'):
1067 user_name = user_name[1:]
2d341029
O
1068 try:
1069 t.lists.members.destroy(
422dd385
O
1070 slug=slug,
1071 owner_screen_name=owner,
1072 screen_name=user_name)
d6cc4c67 1073 printNicely(green('Gone.'))
422dd385 1074 except:
7a8a52fc 1075 debug_option()
422dd385
O
1076 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
1077
1078
1079def list_subscribe(t):
1080 """
1081 Subscribe to a list
1082 """
8b8566d1 1083 owner, slug = get_slug()
422dd385
O
1084 # Subscribe
1085 try:
1086 t.lists.subscribers.create(
1087 slug=slug,
1088 owner_screen_name=owner)
d6cc4c67 1089 printNicely(green('Done.'))
422dd385 1090 except:
7a8a52fc 1091 debug_option()
422dd385
O
1092 printNicely(
1093 light_magenta('I\'m sorry you can not subscribe to this list.'))
1094
1095
1096def list_unsubscribe(t):
1097 """
1098 Unsubscribe a list
1099 """
8b8566d1 1100 owner, slug = get_slug()
422dd385
O
1101 # Subscribe
1102 try:
1103 t.lists.subscribers.destroy(
1104 slug=slug,
1105 owner_screen_name=owner)
d6cc4c67 1106 printNicely(green('Done.'))
422dd385 1107 except:
7a8a52fc 1108 debug_option()
422dd385
O
1109 printNicely(
1110 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
1111
1112
1113def list_own(t):
1114 """
1115 List own
1116 """
1117 rel = []
1118 next_cursor = -1
1119 while next_cursor != 0:
1120 res = t.lists.ownerships(
1121 screen_name=g['original_name'],
1122 cursor=next_cursor)
1123 rel += res['lists']
1124 next_cursor = res['next_cursor']
1125 if rel:
1126 print_list(rel)
1127 else:
1128 printNicely(light_magenta('You own no lists :)'))
1129
1130
1131def list_new(t):
1132 """
1133 Create a new list
1134 """
be4dba0e 1135 name = raw_input(light_magenta('New list\'s name: ', rl=True))
1136 mode = raw_input(
1137 light_magenta(
1138 'New list\'s mode (public/private): ',
1139 rl=True))
1140 description = raw_input(
1141 light_magenta(
1142 'New list\'s description: ',
1143 rl=True))
422dd385
O
1144 try:
1145 t.lists.create(
1146 name=name,
1147 mode=mode,
1148 description=description)
d6cc4c67 1149 printNicely(green(name + ' list is created.'))
422dd385 1150 except:
7a8a52fc 1151 debug_option()
422dd385
O
1152 printNicely(red('Oops something is wrong with Twitter :('))
1153
1154
1155def list_update(t):
1156 """
1157 Update a list
1158 """
be4dba0e 1159 slug = raw_input(
1160 light_magenta(
1161 'Your list that you want to update: ',
1162 rl=True))
1163 name = raw_input(
1164 light_magenta(
1165 'Update name (leave blank to unchange): ',
1166 rl=True))
1167 mode = raw_input(light_magenta('Update mode (public/private): ', rl=True))
1168 description = raw_input(light_magenta('Update description: ', rl=True))
422dd385
O
1169 try:
1170 if name:
1171 t.lists.update(
1172 slug='-'.join(slug.split()),
1173 owner_screen_name=g['original_name'],
1174 name=name,
1175 mode=mode,
1176 description=description)
1177 else:
1178 t.lists.update(
1179 slug=slug,
1180 owner_screen_name=g['original_name'],
1181 mode=mode,
1182 description=description)
d6cc4c67 1183 printNicely(green(slug + ' list is updated.'))
3c85d8fc 1184 except:
7a8a52fc 1185 debug_option()
422dd385
O
1186 printNicely(red('Oops something is wrong with Twitter :('))
1187
1188
1189def list_delete(t):
1190 """
1191 Delete a list
1192 """
be4dba0e 1193 slug = raw_input(
1194 light_magenta(
1195 'Your list that you want to delete: ',
1196 rl=True))
422dd385
O
1197 try:
1198 t.lists.destroy(
1199 slug='-'.join(slug.split()),
1200 owner_screen_name=g['original_name'])
d6cc4c67 1201 printNicely(green(slug + ' list is deleted.'))
2d341029 1202 except:
7a8a52fc 1203 debug_option()
422dd385 1204 printNicely(red('Oops something is wrong with Twitter :('))
2d341029
O
1205
1206
e3927852 1207def twitterlist():
2d341029
O
1208 """
1209 Twitter's list
1210 """
1211 t = Twitter(auth=authen())
1212 # List all lists or base on action
1213 try:
1214 g['list_action'] = g['stuff'].split()[0]
1215 except:
1216 show_lists(t)
1217 return
422dd385 1218 # Sub-function
2d341029
O
1219 action_ary = {
1220 'home': list_home,
1221 'all_mem': list_members,
1222 'all_sub': list_subscribers,
422dd385 1223 'add': list_add,
2d341029 1224 'rm': list_remove,
422dd385
O
1225 'sub': list_subscribe,
1226 'unsub': list_unsubscribe,
1227 'own': list_own,
1228 'new': list_new,
1229 'update': list_update,
1230 'del': list_delete,
2d341029
O
1231 }
1232 try:
1233 return action_ary[g['list_action']](t)
3c85d8fc 1234 except:
8b8566d1 1235 printNicely(red('Please try again.'))
2d341029
O
1236
1237
fd87ddac
O
1238def switch():
1239 """
1240 Switch stream
1241 """
1242 try:
1243 target = g['stuff'].split()[0]
1244 # Filter and ignore
1245 args = parse_arguments()
1246 try:
1247 if g['stuff'].split()[-1] == '-f':
1248 guide = 'To ignore an option, just hit Enter key.'
1249 printNicely(light_magenta(guide))
1250 only = raw_input('Only nicks [Ex: @xxx,@yy]: ')
1251 ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
1252 args.filter = filter(None, only.split(','))
1253 args.ignore = filter(None, ignore.split(','))
fd87ddac
O
1254 except:
1255 printNicely(red('Sorry, wrong format.'))
1256 return
1257 # Public stream
1258 if target == 'public':
1259 keyword = g['stuff'].split()[1]
1260 if keyword[0] == '#':
1261 keyword = keyword[1:]
1262 # Kill old thread
1263 g['stream_stop'] = True
1264 args.track_keywords = keyword
1d01129e
LP
1265 # Set the variable to tracked keyword
1266 # and reset the listname
1267 g['keyword'] = keyword
1268 g['listname'] = ''
72f58edb 1269 # Reset prefix
063f6bb1 1270 g['PREFIX'] = u2str(emojize(format_prefix(keyword=g['keyword'])))
fd87ddac
O
1271 # Start new thread
1272 th = threading.Thread(
1273 target=stream,
1274 args=(
1275 c['PUBLIC_DOMAIN'],
1276 args))
1277 th.daemon = True
1278 th.start()
1279 # Personal stream
1280 elif target == 'mine':
1281 # Kill old thread
1282 g['stream_stop'] = True
1d01129e
LP
1283 # Reset the tracked keyword and listname
1284 g['keyword'] = g['listname'] = ''
72f58edb 1285 # Reset prefix
b85ec13a 1286 g['PREFIX'] = u2str(emojize(format_prefix()))
fd87ddac
O
1287 # Start new thread
1288 th = threading.Thread(
1289 target=stream,
1290 args=(
1291 c['USER_DOMAIN'],
1292 args,
1293 g['original_name']))
1294 th.daemon = True
1295 th.start()
ee4c94b1
O
1296 # Stream base on list
1297 elif target == 'list':
1298 owner, slug = get_slug()
1299 # Force python 2 not redraw readline buffer
b85ec13a 1300 listname = '/'.join([owner, slug])
063f6bb1 1301 # Set the listname variable
1d01129e
LP
1302 # and reset tracked keyword
1303 g['listname'] = listname
1304 g['keyword'] = ''
063f6bb1 1305 g['PREFIX'] = g['cmd'] = u2str(emojize(format_prefix(
1306 listname=g['listname']
1307 )))
ee4c94b1
O
1308 printNicely(light_yellow('getting list members ...'))
1309 # Get members
1310 t = Twitter(auth=authen())
1311 members = []
1312 next_cursor = -1
1313 while next_cursor != 0:
1314 m = t.lists.members(
1315 slug=slug,
1316 owner_screen_name=owner,
1317 cursor=next_cursor,
1318 include_entities=False)
1319 for u in m['users']:
1320 members.append('@' + u['screen_name'])
1321 next_cursor = m['next_cursor']
1322 printNicely(light_yellow('... done.'))
1323 # Build thread filter array
1324 args.filter = members
1325 # Kill old thread
1326 g['stream_stop'] = True
1327 # Start new thread
1328 th = threading.Thread(
1329 target=stream,
1330 args=(
1331 c['USER_DOMAIN'],
1332 args,
1333 slug))
1334 th.daemon = True
1335 th.start()
fd87ddac
O
1336 printNicely('')
1337 if args.filter:
ac03309c 1338 printNicely(cyan('Include: ' + str(len(args.filter)) + ' people.'))
fd87ddac 1339 if args.ignore:
ac03309c 1340 printNicely(red('Ignore: ' + str(len(args.ignore)) + ' people.'))
fd87ddac 1341 printNicely('')
050a294e 1342 except:
ee4c94b1 1343 debug_option()
fd87ddac
O
1344 printNicely(red('Sorry I can\'t understand.'))
1345
1346
813a5d80 1347def cal():
1348 """
1349 Unix's command `cal`
1350 """
1351 # Format
1352 rel = os.popen('cal').read().split('\n')
1353 month = rel.pop(0)
813a5d80 1354 date = rel.pop(0)
2a0cabee 1355 show_calendar(month, date, rel)
813a5d80 1356
1357
fd87ddac
O
1358def theme():
1359 """
1360 List and change theme
1361 """
1362 if not g['stuff']:
1363 # List themes
1364 for theme in g['themes']:
1365 line = light_magenta(theme)
1366 if c['THEME'] == theme:
1367 line = ' ' * 2 + light_yellow('* ') + line
1368 else:
1369 line = ' ' * 4 + line
1370 printNicely(line)
1371 else:
1372 # Change theme
1373 try:
1374 # Load new theme
1375 c['THEME'] = reload_theme(g['stuff'], c['THEME'])
1376 # Redefine decorated_name
1377 g['decorated_name'] = lambda x: color_func(
1378 c['DECORATED_NAME'])(
1379 '[' + x + ']: ')
1380 printNicely(green('Theme changed.'))
1381 except:
1382 printNicely(red('No such theme exists.'))
1383
1384
29fd0be6
O
1385def config():
1386 """
1387 Browse and change config
1388 """
1389 all_config = get_all_config()
1390 g['stuff'] = g['stuff'].strip()
1391 # List all config
1392 if not g['stuff']:
1393 for k in all_config:
a8c5fce4 1394 line = ' ' * 2 + \
d6cc4c67 1395 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1396 printNicely(line)
1397 guide = 'Detailed explanation can be found at ' + \
a8c5fce4
O
1398 color_func(c['TWEET']['link'])(
1399 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
29fd0be6
O
1400 printNicely(guide)
1401 # Print specific config
1402 elif len(g['stuff'].split()) == 1:
1403 if g['stuff'] in all_config:
1404 k = g['stuff']
a8c5fce4 1405 line = ' ' * 2 + \
d6cc4c67 1406 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1407 printNicely(line)
1408 else:
fe9bb33b 1409 printNicely(red('No such config key.'))
29fd0be6
O
1410 # Print specific config's default value
1411 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'default':
1412 key = g['stuff'].split()[0]
fe9bb33b 1413 try:
1414 value = get_default_config(key)
d6cc4c67 1415 line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
fe9bb33b 1416 printNicely(line)
050a294e
O
1417 except:
1418 debug_option()
1419 printNicely(red('Just can not get the default.'))
fe9bb33b 1420 # Delete specific config key in config file
1421 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop':
1422 key = g['stuff'].split()[0]
1423 try:
1424 delete_config(key)
d6cc4c67 1425 printNicely(green('Config key is dropped.'))
050a294e
O
1426 except:
1427 debug_option()
1428 printNicely(red('Just can not drop the key.'))
29fd0be6 1429 # Set specific config
a8c5fce4 1430 elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=':
29fd0be6
O
1431 key = g['stuff'].split()[0]
1432 value = g['stuff'].split()[-1]
ceec8593 1433 if key == 'THEME' and not validate_theme(value):
1434 printNicely(red('Invalid theme\'s value.'))
1435 return
3c01ba57 1436 try:
a8c5fce4 1437 set_config(key, value)
050a294e 1438 # Keys that needs to be apply immediately
ceec8593 1439 if key == 'THEME':
baec5f50 1440 c['THEME'] = reload_theme(value, c['THEME'])
ceec8593 1441 g['decorated_name'] = lambda x: color_func(
a8e71259 1442 c['DECORATED_NAME'])('[' + x + ']: ')
050a294e 1443 elif key == 'PREFIX':
063f6bb1 1444 g['PREFIX'] = u2str(emojize(format_prefix(
1445 listname=g['listname'],
1446 keyword=g['keyword']
1447 )))
a8e71259 1448 reload_config()
d6cc4c67 1449 printNicely(green('Updated successfully.'))
050a294e
O
1450 except:
1451 debug_option()
1452 printNicely(red('Just can not set the key.'))
29fd0be6
O
1453 else:
1454 printNicely(light_magenta('Sorry I can\'s understand.'))
1455
1456
2d341029 1457def help_discover():
f405a7d0 1458 """
2d341029 1459 Discover the world
f405a7d0 1460 """
7e4ccbf3 1461 s = ' ' * 2
1f24a05a 1462 # Discover the world
2d341029 1463 usage = '\n'
8bc30efd 1464 usage += s + grey(u'\u266A' + ' Discover the world \n')
c075e6dc
O
1465 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1466 'You can try ' + light_green('trend US') + ' or ' + \
1467 light_green('trend JP Tokyo') + '.\n'
1468 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1469 light_green('home 7') + ' will show 7 tweets.\n'
99cd1fba
O
1470 usage += s * 2 + \
1471 light_green('notification') + ' will show your recent notification.\n'
c075e6dc
O
1472 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1473 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1474 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
8bc30efd 1475 magenta('@mdo') + '.\n'
c075e6dc 1476 usage += s * 2 + light_green('view @mdo') + \
8bc30efd 1477 ' will show ' + magenta('@mdo') + '\'s home.\n'
03e08f86
O
1478 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1479 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1480 'Search can be performed with or without hashtag.\n'
2d341029
O
1481 printNicely(usage)
1482
8bc30efd 1483
2d341029
O
1484def help_tweets():
1485 """
1486 Tweets
1487 """
1488 s = ' ' * 2
1f24a05a 1489 # Tweet
2d341029 1490 usage = '\n'
8bc30efd 1491 usage += s + grey(u'\u266A' + ' Tweets \n')
c075e6dc
O
1492 usage += s * 2 + light_green('t oops ') + \
1493 'will tweet "' + light_yellow('oops') + '" immediately.\n'
7e4ccbf3 1494 usage += s * 2 + \
c075e6dc
O
1495 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1496 light_yellow('[id=12]') + '.\n'
1f24a05a 1497 usage += s * 2 + \
80b70d60
O
1498 light_green('quote 12 ') + ' will quote the tweet with ' + \
1499 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1500 'the quote will be canceled.\n'
1501 usage += s * 2 + \
c075e6dc
O
1502 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1503 light_yellow('[id=12]') + '.\n'
fd87ddac
O
1504 usage += s * 2 + light_green('conversation 12') + ' will show the chain of ' + \
1505 'replies prior to the tweet with ' + light_yellow('[id=12]') + '.\n'
c075e6dc 1506 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
ba6c09d1
O
1507 light_yellow('oops') + '" to the owner of the tweet with ' + \
1508 light_yellow('[id=12]') + '.\n'
1509 usage += s * 2 + light_green('repall 12 oops') + ' will reply "' + \
1510 light_yellow('oops') + '" to all people in the tweet with ' + \
c075e6dc 1511 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1512 usage += s * 2 + \
c075e6dc
O
1513 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1514 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1515 usage += s * 2 + \
c075e6dc
O
1516 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1517 light_yellow('[id=12]') + '.\n'
8bc30efd 1518 usage += s * 2 + \
66fe9f75 1519 light_green('share 12 ') + ' will get the direct link of the tweet with ' + \
1520 light_yellow('[id=12]') + '.\n'
413857b5 1521 usage += s * 2 + \
c075e6dc
O
1522 light_green('del 12 ') + ' will delete tweet with ' + \
1523 light_yellow('[id=12]') + '.\n'
1524 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1525 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
80b70d60
O
1526 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1527 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
2d341029 1528 printNicely(usage)
8bc30efd 1529
2d341029
O
1530
1531def help_messages():
1532 """
1533 Messages
1534 """
1535 s = ' ' * 2
5b2c4faf 1536 # Direct message
2d341029 1537 usage = '\n'
8bc30efd 1538 usage += s + grey(u'\u266A' + ' Direct messages \n')
c075e6dc
O
1539 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1540 light_green('inbox 7') + ' will show newest 7 messages.\n'
03c0d30b 1541 usage += s * 2 + light_green('thread 2') + ' will show full thread with ' + \
1542 light_yellow('[thread_id=2]') + '.\n'
c075e6dc 1543 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
8bc30efd 1544 magenta('@dtvd88') + '.\n'
c075e6dc
O
1545 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1546 light_yellow('[message_id=5]') + '.\n'
2d341029 1547 printNicely(usage)
8bc30efd 1548
2d341029
O
1549
1550def help_friends_and_followers():
1551 """
1552 Friends and Followers
1553 """
1554 s = ' ' * 2
8bc30efd 1555 # Follower and following
2d341029 1556 usage = '\n'
cdccb0d6 1557 usage += s + grey(u'\u266A' + ' Friends and followers \n')
8bc30efd 1558 usage += s * 2 + \
c075e6dc 1559 light_green('ls fl') + \
8bc30efd 1560 ' will list all followers (people who are following you).\n'
1561 usage += s * 2 + \
c075e6dc 1562 light_green('ls fr') + \
8bc30efd 1563 ' will list all friends (people who you are following).\n'
c075e6dc 1564 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
305ce127 1565 magenta('@dtvd88') + '.\n'
c075e6dc 1566 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 1567 magenta('@dtvd88') + '.\n'
c075e6dc 1568 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
5b2c4faf 1569 magenta('@dtvd88') + '.\n'
c075e6dc 1570 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
5b2c4faf 1571 magenta('@dtvd88') + '.\n'
c075e6dc
O
1572 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1573 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
305ce127 1574 magenta('@dtvd88') + '.\n'
c075e6dc 1575 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
305ce127 1576 magenta('@dtvd88') + '.\n'
c075e6dc 1577 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
305ce127 1578 magenta('@dtvd88') + ' as a spam account.\n'
2d341029
O
1579 printNicely(usage)
1580
1581
1582def help_list():
1583 """
1584 Lists
1585 """
1586 s = ' ' * 2
1587 # Twitter list
1588 usage = '\n'
1589 usage += s + grey(u'\u266A' + ' Twitter list\n')
1590 usage += s * 2 + light_green('list') + \
1591 ' will show all lists you are belong to.\n'
1592 usage += s * 2 + light_green('list home') + \
bef33491 1593 ' will show timeline of list. You will be asked for list\'s name.\n'
a65bd34c 1594 usage += s * 2 + light_green('list all_mem') + \
2d341029 1595 ' will show list\'s all members.\n'
a65bd34c 1596 usage += s * 2 + light_green('list all_sub') + \
2d341029 1597 ' will show list\'s all subscribers.\n'
422dd385
O
1598 usage += s * 2 + light_green('list add') + \
1599 ' will add specific person to a list owned by you.' + \
1600 ' You will be asked for list\'s name and person\'s name.\n'
2d341029
O
1601 usage += s * 2 + light_green('list rm') + \
1602 ' will remove specific person from a list owned by you.' + \
1603 ' You will be asked for list\'s name and person\'s name.\n'
422dd385
O
1604 usage += s * 2 + light_green('list sub') + \
1605 ' will subscribe you to a specific list.\n'
1606 usage += s * 2 + light_green('list unsub') + \
1607 ' will unsubscribe you from a specific list.\n'
1608 usage += s * 2 + light_green('list own') + \
1609 ' will show all list owned by you.\n'
1610 usage += s * 2 + light_green('list new') + \
1611 ' will create a new list.\n'
1612 usage += s * 2 + light_green('list update') + \
1613 ' will update a list owned by you.\n'
1614 usage += s * 2 + light_green('list del') + \
1615 ' will delete a list owned by you.\n'
2d341029 1616 printNicely(usage)
8bc30efd 1617
2d341029
O
1618
1619def help_stream():
1620 """
1621 Stream switch
1622 """
1623 s = ' ' * 2
8bc30efd 1624 # Switch
2d341029 1625 usage = '\n'
8bc30efd 1626 usage += s + grey(u'\u266A' + ' Switching streams \n')
c075e6dc 1627 usage += s * 2 + light_green('switch public #AKB') + \
48a25fe8 1628 ' will switch to public stream and follow "' + \
c075e6dc
O
1629 light_yellow('AKB') + '" keyword.\n'
1630 usage += s * 2 + light_green('switch mine') + \
48a25fe8 1631 ' will switch to your personal stream.\n'
c075e6dc 1632 usage += s * 2 + light_green('switch mine -f ') + \
48a25fe8 1633 ' will prompt to enter the filter.\n'
c075e6dc 1634 usage += s * 3 + light_yellow('Only nicks') + \
48a25fe8 1635 ' filter will decide nicks will be INCLUDE ONLY.\n'
c075e6dc 1636 usage += s * 3 + light_yellow('Ignore nicks') + \
48a25fe8 1637 ' filter will decide nicks will be EXCLUDE.\n'
ee4c94b1
O
1638 usage += s * 2 + light_green('switch list') + \
1639 ' will switch to a Twitter list\'s stream. You will be asked for list name\n'
2d341029
O
1640 printNicely(usage)
1641
1642
1643def help():
1644 """
1645 Help
1646 """
1647 s = ' ' * 2
1648 h, w = os.popen('stty size', 'r').read().split()
2d341029
O
1649 # Start
1650 usage = '\n'
1651 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1652 usage += s + '-' * (int(w) - 4) + '\n'
1653 usage += s + 'You are ' + \
1654 light_yellow('already') + ' on your personal stream.\n'
1655 usage += s + 'Any update from Twitter will show up ' + \
1656 light_yellow('immediately') + '.\n'
37d1047f 1657 usage += s + 'In addition, following commands are available right now:\n'
2d341029
O
1658 # Twitter help section
1659 usage += '\n'
1660 usage += s + grey(u'\u266A' + ' Twitter help\n')
1661 usage += s * 2 + light_green('h discover') + \
1662 ' will show help for discover commands.\n'
1663 usage += s * 2 + light_green('h tweets') + \
1664 ' will show help for tweets commands.\n'
1665 usage += s * 2 + light_green('h messages') + \
1666 ' will show help for messages commands.\n'
1667 usage += s * 2 + light_green('h friends_and_followers') + \
1668 ' will show help for friends and followers commands.\n'
1669 usage += s * 2 + light_green('h list') + \
1670 ' will show help for list commands.\n'
1671 usage += s * 2 + light_green('h stream') + \
1672 ' will show help for stream commands.\n'
1f24a05a 1673 # Smart shell
1674 usage += '\n'
1675 usage += s + grey(u'\u266A' + ' Smart shell\n')
c075e6dc 1676 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1f24a05a 1677 'will be evaluate by Python interpreter.\n'
c075e6dc 1678 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1f24a05a 1679 ' for current month.\n'
29fd0be6 1680 # Config
1f24a05a 1681 usage += '\n'
29fd0be6
O
1682 usage += s + grey(u'\u266A' + ' Config \n')
1683 usage += s * 2 + light_green('theme') + ' will list available theme. ' + \
c075e6dc 1684 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
632c6fa5 1685 ' theme immediately.\n'
29fd0be6
O
1686 usage += s * 2 + light_green('config') + ' will list all config.\n'
1687 usage += s * 3 + \
1688 light_green('config ASCII_ART') + ' will output current value of ' +\
a8c5fce4 1689 light_yellow('ASCII_ART') + ' config key.\n'
29fd0be6 1690 usage += s * 3 + \
fe9bb33b 1691 light_green('config TREND_MAX default') + ' will output default value of ' + \
1692 light_yellow('TREND_MAX') + ' config key.\n'
1693 usage += s * 3 + \
1694 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1695 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
29fd0be6 1696 usage += s * 3 + \
fe9bb33b 1697 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1698 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1699 light_yellow('True') + '.\n'
29fd0be6
O
1700 # Screening
1701 usage += '\n'
1702 usage += s + grey(u'\u266A' + ' Screening \n')
c075e6dc 1703 usage += s * 2 + light_green('h') + ' will show this help again.\n'
d6cc4c67
O
1704 usage += s * 2 + light_green('p') + ' will pause the stream.\n'
1705 usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
c075e6dc 1706 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
806f42df 1707 usage += s * 2 + light_green('v') + ' will show version info.\n'
c075e6dc 1708 usage += s * 2 + light_green('q') + ' will quit.\n'
8bc30efd 1709 # End
1710 usage += '\n'
7e4ccbf3 1711 usage += s + '-' * (int(w) - 4) + '\n'
8bc30efd 1712 usage += s + 'Have fun and hang tight! \n'
2d341029
O
1713 # Show help
1714 d = {
422dd385
O
1715 'discover': help_discover,
1716 'tweets': help_tweets,
1717 'messages': help_messages,
1718 'friends_and_followers': help_friends_and_followers,
1719 'list': help_list,
1720 'stream': help_stream,
2d341029
O
1721 }
1722 if g['stuff']:
baec5f50 1723 d.get(
1724 g['stuff'].strip(),
1725 lambda: printNicely(red('No such command.'))
3d48702f 1726 )()
2d341029
O
1727 else:
1728 printNicely(usage)
f405a7d0
O
1729
1730
d6cc4c67
O
1731def pause():
1732 """
1733 Pause stream display
1734 """
4dc385b5 1735 g['pause'] = True
d6cc4c67
O
1736 printNicely(green('Stream is paused'))
1737
1738
1739def replay():
1740 """
1741 Replay stream
1742 """
4dc385b5 1743 g['pause'] = False
d6cc4c67
O
1744 printNicely(green('Stream is running back now'))
1745
1746
843647ad 1747def clear():
f405a7d0 1748 """
7b674cef 1749 Clear screen
f405a7d0 1750 """
843647ad 1751 os.system('clear')
f405a7d0
O
1752
1753
843647ad 1754def quit():
b8dda704
O
1755 """
1756 Exit all
1757 """
4c025026 1758 try:
1759 save_history()
4c025026 1760 printNicely(green('See you next time :)'))
1761 except:
1762 pass
843647ad 1763 sys.exit()
b8dda704
O
1764
1765
94a5f62e 1766def reset():
f405a7d0 1767 """
94a5f62e 1768 Reset prefix of line
f405a7d0 1769 """
c91f75f2 1770 if g['reset']:
a8e71259 1771 if c.get('USER_JSON_ERROR'):
1772 printNicely(red('Your ~/.rainbow_config.json is messed up:'))
1773 printNicely(red('>>> ' + c['USER_JSON_ERROR']))
1774 printNicely('')
e3885f55 1775 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 1776 g['reset'] = False
d0a726d6 1777 try:
779b0640 1778 printNicely(str(eval(g['cmd'])))
2a0cabee 1779 except Exception:
d0a726d6 1780 pass
54277114
O
1781
1782
f1c1dfea
O
1783# Command set
1784cmdset = [
1785 'switch',
1786 'trend',
1787 'home',
99cd1fba 1788 'notification',
f1c1dfea
O
1789 'view',
1790 'mentions',
1791 't',
1792 'rt',
1793 'quote',
1794 'allrt',
fd87ddac 1795 'conversation',
f1c1dfea
O
1796 'fav',
1797 'rep',
ba6c09d1 1798 'repall',
f1c1dfea
O
1799 'del',
1800 'ufav',
413857b5 1801 'share',
f1c1dfea
O
1802 's',
1803 'mes',
1804 'show',
1805 'open',
1806 'ls',
1807 'inbox',
67c663f8 1808 'thread',
f1c1dfea
O
1809 'trash',
1810 'whois',
1811 'fl',
1812 'ufl',
1813 'mute',
1814 'unmute',
1815 'muting',
1816 'block',
1817 'unblock',
1818 'report',
1819 'list',
1820 'cal',
1821 'config',
1822 'theme',
1823 'h',
1824 'p',
1825 'r',
1826 'c',
806f42df 1827 'v',
bf766c7b 1828 'q',
f1c1dfea
O
1829]
1830
1831# Handle function set
1832funcset = [
1833 switch,
1834 trend,
1835 home,
99cd1fba 1836 notification,
f1c1dfea
O
1837 view,
1838 mentions,
1839 tweet,
1840 retweet,
1841 quote,
1842 allretweet,
fd87ddac 1843 conversation,
f1c1dfea
O
1844 favorite,
1845 reply,
ba6c09d1 1846 reply_all,
f1c1dfea
O
1847 delete,
1848 unfavorite,
413857b5 1849 share,
f1c1dfea
O
1850 search,
1851 message,
1852 show,
1853 urlopen,
1854 ls,
1855 inbox,
67c663f8 1856 thread,
f1c1dfea
O
1857 trash,
1858 whois,
1859 follow,
1860 unfollow,
1861 mute,
1862 unmute,
1863 muting,
1864 block,
1865 unblock,
1866 report,
1867 twitterlist,
1868 cal,
1869 config,
1870 theme,
1871 help,
1872 pause,
1873 replay,
1874 clear,
bf766c7b 1875 upgrade_center,
806f42df 1876 quit,
f1c1dfea
O
1877]
1878
1879
94a5f62e 1880def process(cmd):
54277114 1881 """
94a5f62e 1882 Process switch
54277114 1883 """
f1c1dfea 1884 return dict(zip(cmdset, funcset)).get(cmd, reset)
94a5f62e 1885
1886
1887def listen():
42fde775 1888 """
1889 Listen to user's input
1890 """
d51b4107
O
1891 d = dict(zip(
1892 cmdset,
1893 [
ee4c94b1 1894 ['public', 'mine', 'list'], # switch
4592d231 1895 [], # trend
7e4ccbf3 1896 [], # home
99cd1fba 1897 [], # notification
7e4ccbf3 1898 ['@'], # view
305ce127 1899 [], # mentions
7e4ccbf3 1900 [], # tweet
1901 [], # retweet
80b70d60 1902 [], # quote
1f24a05a 1903 [], # allretweet
fd87ddac 1904 [], # conversation
f5677fb1 1905 [], # favorite
7e4ccbf3 1906 [], # reply
ba6c09d1 1907 [], # reply_all
7e4ccbf3 1908 [], # delete
f5677fb1 1909 [], # unfavorite
413857b5 1910 [], # url
7e4ccbf3 1911 ['#'], # search
305ce127 1912 ['@'], # message
f5677fb1 1913 ['image'], # show image
80b70d60 1914 [''], # open url
305ce127 1915 ['fl', 'fr'], # list
1916 [], # inbox
03c0d30b 1917 [i for i in g['message_threads']], # sent
305ce127 1918 [], # trash
e2b81717 1919 ['@'], # whois
affcb149
O
1920 ['@'], # follow
1921 ['@'], # unfollow
5b2c4faf 1922 ['@'], # mute
1923 ['@'], # unmute
1924 ['@'], # muting
305ce127 1925 ['@'], # block
1926 ['@'], # unblock
1927 ['@'], # report
422dd385
O
1928 [
1929 'home',
1930 'all_mem',
1931 'all_sub',
1932 'add',
1933 'rm',
1934 'sub',
1935 'unsub',
1936 'own',
1937 'new',
1938 'update',
1939 'del'
1940 ], # list
813a5d80 1941 [], # cal
a8c5fce4 1942 [key for key in dict(get_all_config())], # config
ceec8593 1943 g['themes'], # theme
422dd385
O
1944 [
1945 'discover',
1946 'tweets',
1947 'messages',
1948 'friends_and_followers',
1949 'list',
1950 'stream'
1951 ], # help
d6cc4c67
O
1952 [], # pause
1953 [], # reconnect
7e4ccbf3 1954 [], # clear
7cfb8af4 1955 [], # version
806f42df 1956 [], # quit
d51b4107 1957 ]
7e4ccbf3 1958 ))
d51b4107 1959 init_interactive_shell(d)
f5677fb1 1960 read_history()
819569e8 1961 reset()
b2b933a9 1962 while True:
b8c1f42a 1963 try:
39b8e6b3
O
1964 # raw_input
1965 if g['prefix']:
aa452ee9 1966 # Only use PREFIX as a string with raw_input
c285decf 1967 line = raw_input(g['decorated_name'](g['PREFIX']))
39b8e6b3
O
1968 else:
1969 line = raw_input()
1970 # Save cmd to compare with readline buffer
1971 g['cmd'] = line.strip()
1972 # Get short cmd to pass to handle function
1973 try:
1974 cmd = line.split()[0]
1975 except:
1976 cmd = ''
9683e61d 1977 # Lock the semaphore
99b52f5f 1978 c['lock'] = True
9683e61d 1979 # Save cmd to global variable and call process
b8c1f42a 1980 g['stuff'] = ' '.join(line.split()[1:])
9683e61d 1981 # Process the command
b8c1f42a 1982 process(cmd)()
9683e61d 1983 # Not re-display
99b52f5f 1984 if cmd in ['switch', 't', 'rt', 'rep']:
9683e61d
O
1985 g['prefix'] = False
1986 else:
1987 g['prefix'] = True
1988 # Release the semaphore lock
99b52f5f 1989 c['lock'] = False
39b8e6b3
O
1990 except EOFError:
1991 printNicely('')
eadd85a8 1992 except Exception:
7a8a52fc 1993 debug_option()
b8c1f42a 1994 printNicely(red('OMG something is wrong with Twitter right now.'))
ee444288 1995
54277114 1996
47cee703
O
1997def reconn_notice():
1998 """
1999 Notice when Hangup or Timeout
2000 """
f07cfb6b 2001 guide = light_magenta('You can use ') + \
2002 light_green('switch') + \
2003 light_magenta(' command to return to your stream.\n')
2004 guide += light_magenta('Type ') + \
2005 light_green('h stream') + \
2006 light_magenta(' for more details.')
47cee703 2007 printNicely(guide)
211e8be1 2008 sys.stdout.write(g['decorated_name'](g['PREFIX']))
47cee703
O
2009 sys.stdout.flush()
2010
2011
42fde775 2012def stream(domain, args, name='Rainbow Stream'):
54277114 2013 """
f405a7d0 2014 Track the stream
54277114 2015 """
54277114 2016 # The Logo
42fde775 2017 art_dict = {
632c6fa5
O
2018 c['USER_DOMAIN']: name,
2019 c['PUBLIC_DOMAIN']: args.track_keywords,
1f2f6159 2020 c['SITE_DOMAIN']: name,
42fde775 2021 }
687567eb 2022 if c['ASCII_ART']:
c075e6dc 2023 ascii_art(art_dict[domain])
91476ec3
O
2024 # These arguments are optional:
2025 stream_args = dict(
e3927852 2026 timeout=0.5, # To check g['stream_stop'] after each 0.5 s
cb45dc23 2027 block=True,
2028 heartbeat_timeout=c['HEARTBEAT_TIMEOUT'] * 60)
91476ec3
O
2029 # Track keyword
2030 query_args = dict()
2031 if args.track_keywords:
2032 query_args['track'] = args.track_keywords
91476ec3 2033 # Get stream
2a6238f5 2034 stream = TwitterStream(
22be990e 2035 auth=authen(),
42fde775 2036 domain=domain,
2a6238f5 2037 **stream_args)
2a0cabee
O
2038 try:
2039 if domain == c['USER_DOMAIN']:
2040 tweet_iter = stream.user(**query_args)
2041 elif domain == c['SITE_DOMAIN']:
2042 tweet_iter = stream.site(**query_args)
42fde775 2043 else:
2a0cabee
O
2044 if args.track_keywords:
2045 tweet_iter = stream.statuses.filter(**query_args)
2046 else:
2047 tweet_iter = stream.statuses.sample()
92983945
BS
2048 # Block new stream until other one exits
2049 StreamLock.acquire()
2050 g['stream_stop'] = False
e53e2c70 2051 last_tweet_time = time.time()
72c02928
VNM
2052 for tweet in tweet_iter:
2053 if tweet is None:
f07cfb6b 2054 printNicely('-- None --')
72c02928 2055 elif tweet is Timeout:
47cee703
O
2056 # Because the stream check for each 0.3s
2057 # so we shouldn't output anything here
335e7803
O
2058 if(g['stream_stop']):
2059 StreamLock.release()
2060 break
72c02928 2061 elif tweet is HeartbeatTimeout:
f07cfb6b 2062 printNicely('-- Heartbeat Timeout --')
47cee703 2063 reconn_notice()
8715dda0
O
2064 StreamLock.release()
2065 break
72c02928 2066 elif tweet is Hangup:
f07cfb6b 2067 printNicely('-- Hangup --')
47cee703
O
2068 reconn_notice()
2069 StreamLock.release()
2070 break
72c02928 2071 elif tweet.get('text'):
84b41f58
O
2072 # Slow down the stream by STREAM_DELAY config key
2073 if time.time() - last_tweet_time < c['STREAM_DELAY']:
2074 continue
2075 last_tweet_time = time.time()
2076 # Check the semaphore pause and lock (stream process only)
2077 if g['pause']:
2078 continue
2079 while c['lock']:
2080 time.sleep(0.5)
2081 # Draw the tweet
2082 draw(
2083 t=tweet,
2084 keyword=args.track_keywords,
2085 humanize=False,
2086 fil=args.filter,
2087 ig=args.ignore,
2088 )
2089 # Current readline buffer
2090 current_buffer = readline.get_line_buffer().strip()
2091 # There is an unexpected behaviour in MacOSX readline + Python 2:
2092 # after completely delete a word after typing it,
2093 # somehow readline buffer still contains
2094 # the 1st character of that word
2095 if current_buffer and g['cmd'] != current_buffer:
2096 sys.stdout.write(
211e8be1 2097 g['decorated_name'](g['PREFIX']) + current_buffer)
84b41f58
O
2098 sys.stdout.flush()
2099 elif not c['HIDE_PROMPT']:
211e8be1 2100 sys.stdout.write(g['decorated_name'](g['PREFIX']))
84b41f58 2101 sys.stdout.flush()
14db58c7 2102 elif tweet.get('direct_message'):
4dc385b5
O
2103 # Check the semaphore pause and lock (stream process only)
2104 if g['pause']:
2105 continue
2106 while c['lock']:
2107 time.sleep(0.5)
2108 print_message(tweet['direct_message'])
99cd1fba 2109 elif tweet.get('event'):
d7d9c67c 2110 c['events'].append(tweet)
99cd1fba 2111 print_event(tweet)
742266f8 2112 except TwitterHTTPError as e:
2a0cabee 2113 printNicely('')
c075e6dc 2114 printNicely(
f07cfb6b 2115 magenta('We have connection problem with twitter stream API right now :('))
9e38891f 2116 detail_twitter_error(e)
211e8be1 2117 sys.stdout.write(g['decorated_name'](g['PREFIX']))
62058715 2118 sys.stdout.flush()
ba6c09d1
O
2119 except (URLError, ConnectionResetError):
2120 printNicely(
2121 magenta('There seems to be a connection problem.'))
2122 save_history()
2123 sys.exit()
54277114
O
2124
2125
2126def fly():
2127 """
2128 Main function
2129 """
531f5682 2130 # Initial
42fde775 2131 args = parse_arguments()
2a0cabee 2132 try:
a65129d4 2133 proxy_connect(args)
fe9bb33b 2134 init(args)
a65129d4 2135 # Twitter API connection problem
742266f8 2136 except TwitterHTTPError as e:
2a0cabee
O
2137 printNicely('')
2138 printNicely(
f07cfb6b 2139 magenta('We have connection problem with twitter REST API right now :('))
9e38891f 2140 detail_twitter_error(e)
2a0cabee 2141 save_history()
2a0cabee 2142 sys.exit()
a65129d4
O
2143 # Proxy connection problem
2144 except (socks.ProxyConnectionError, URLError):
c426a344 2145 printNicely(
f07cfb6b 2146 magenta('There seems to be a connection problem.'))
c426a344 2147 printNicely(
f07cfb6b 2148 magenta('You might want to check your proxy settings (host, port and type)!'))
c426a344 2149 save_history()
2150 sys.exit()
2151
92983945 2152 # Spawn stream thread
baec5f50 2153 th = threading.Thread(
2154 target=stream,
2155 args=(
2156 c['USER_DOMAIN'],
2157 args,
2158 g['original_name']))
92983945
BS
2159 th.daemon = True
2160 th.start()
42fde775 2161 # Start listen process
819569e8 2162 time.sleep(0.5)
c91f75f2 2163 g['reset'] = True
1dd312f5 2164 g['prefix'] = True
0f6e4daf 2165 listen()