Merge branch 'develop'
[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).')
2a6238f5
O
48 parser.add_argument(
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(
102 magenta("Sorry, wrong proxy type specified! Aborting..."))
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
O
117 if not os.path.exists(twitter_credential):
118 oauth_dance("Rainbow Stream",
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:
dfbc7288 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
6e8fb961 173 latest = readme.split("version = \'")[1].split("\'")[0]
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
fd87ddac 504def favorite():
7b674cef 505 """
fd87ddac 506 Favorite
7b674cef 507 """
508 t = Twitter(auth=authen())
509 try:
99b52f5f 510 id = int(g['stuff'].split()[0])
7b674cef 511 except:
305ce127 512 printNicely(red('Sorry I can\'t understand.'))
b8c1f42a 513 return
99b52f5f 514 tid = c['tweet_dict'][id]
fd87ddac
O
515 t.favorites.create(_id=tid, include_entities=False)
516 printNicely(green('Favorited.'))
517 draw(t.statuses.show(id=tid))
518 printNicely('')
829cc2d8
O
519
520
7e4ccbf3 521def unfavorite():
522 """
523 Unfavorite
524 """
525 t = Twitter(auth=authen())
526 try:
527 id = int(g['stuff'].split()[0])
7e4ccbf3 528 except:
b8c1f42a
O
529 printNicely(red('Sorry I can\'t understand.'))
530 return
99b52f5f 531 tid = c['tweet_dict'][id]
b8c1f42a
O
532 t.favorites.destroy(_id=tid)
533 printNicely(green('Okay it\'s unfavorited.'))
fe9bb33b 534 draw(t.statuses.show(id=tid))
b8c1f42a 535 printNicely('')
7e4ccbf3 536
537
413857b5
O
538def share():
539 """
540 Copy url of a tweet to clipboard
541 """
542 t = Twitter(auth=authen())
543 try:
544 id = int(g['stuff'].split()[0])
66fe9f75 545 tid = c['tweet_dict'][id]
413857b5 546 except:
66fe9f75 547 printNicely(red('Tweet id is not valid.'))
413857b5 548 return
413857b5
O
549 tweet = t.statuses.show(id=tid)
550 url = 'https://twitter.com/' + \
551 tweet['user']['screen_name'] + '/status/' + str(tid)
eb9b6273 552 import platform
553 if platform.system().lower() == 'darwin':
554 os.system("echo '%s' | pbcopy" % url)
555 printNicely(green('Copied tweet\'s url to clipboard.'))
556 else:
557 printNicely('Direct link: ' + yellow(url))
413857b5
O
558
559
fd87ddac 560def delete():
305ce127 561 """
fd87ddac 562 Delete
305ce127 563 """
564 t = Twitter(auth=authen())
fd87ddac
O
565 try:
566 id = int(g['stuff'].split()[0])
567 except:
568 printNicely(red('Sorry I can\'t understand.'))
569 return
570 tid = c['tweet_dict'][id]
571 t.statuses.destroy(id=tid)
572 printNicely(green('Okay it\'s gone.'))
305ce127 573
574
f5677fb1 575def show():
843647ad 576 """
f5677fb1 577 Show image
843647ad
O
578 """
579 t = Twitter(auth=authen())
f5677fb1
O
580 try:
581 target = g['stuff'].split()[0]
582 if target != 'image':
583 return
584 id = int(g['stuff'].split()[1])
99b52f5f 585 tid = c['tweet_dict'][id]
f5677fb1
O
586 tweet = t.statuses.show(id=tid)
587 media = tweet['entities']['media']
588 for m in media:
589 res = requests.get(m['media_url'])
b3164e62 590 img = Image.open(BytesIO(res.content))
f5677fb1
O
591 img.show()
592 except:
7a8a52fc 593 debug_option()
f5677fb1 594 printNicely(red('Sorry I can\'t show this image.'))
843647ad
O
595
596
80bb2040 597def urlopen():
80b70d60
O
598 """
599 Open url
600 """
601 t = Twitter(auth=authen())
602 try:
603 if not g['stuff'].isdigit():
604 return
8101275e 605 tid = c['tweet_dict'][int(g['stuff'])]
80b70d60 606 tweet = t.statuses.show(id=tid)
571ea706
O
607 link_prefix = ('http://', 'https://')
608 link_ary = [u for u in tweet['text'].split()
609 if u.startswith(link_prefix)]
80b70d60
O
610 if not link_ary:
611 printNicely(light_magenta('No url here @.@!'))
612 return
613 for link in link_ary:
614 webbrowser.open(link)
615 except:
7a8a52fc 616 debug_option()
80b70d60
O
617 printNicely(red('Sorry I can\'t open url in this tweet.'))
618
619
305ce127 620def inbox():
621 """
67c663f8 622 Inbox threads
305ce127 623 """
624 t = Twitter(auth=authen())
632c6fa5 625 num = c['MESSAGES_DISPLAY']
305ce127 626 if g['stuff'].isdigit():
627 num = g['stuff']
67c663f8 628 # Get inbox messages
305ce127 629 cur_page = 1
67c663f8 630 inbox = []
305ce127 631 while num > 20:
67c663f8 632 inbox = inbox + t.direct_messages(
305ce127 633 count=20,
634 page=cur_page,
635 include_entities=False,
636 skip_status=False
48a25fe8 637 )
305ce127 638 num -= 20
639 cur_page += 1
67c663f8 640 inbox = inbox + t.direct_messages(
305ce127 641 count=num,
642 page=cur_page,
643 include_entities=False,
644 skip_status=False
48a25fe8 645 )
67c663f8 646 # Get sent messages
632c6fa5 647 num = c['MESSAGES_DISPLAY']
305ce127 648 if g['stuff'].isdigit():
67c663f8 649 num = g['stuff']
305ce127 650 cur_page = 1
67c663f8 651 sent = []
305ce127 652 while num > 20:
67c663f8 653 sent = sent + t.direct_messages.sent(
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 sent = sent + t.direct_messages.sent(
305ce127 662 count=num,
663 page=cur_page,
664 include_entities=False,
665 skip_status=False
48a25fe8 666 )
67c663f8
O
667
668 d = {}
669 uniq_inbox = list(set(
03c0d30b 670 [(m['sender_screen_name'], m['sender']['name']) for m in inbox]
67c663f8 671 ))
03c0d30b 672 uniq_sent = list(set(
673 [(m['recipient_screen_name'], m['recipient']['name']) for m in sent]
67c663f8
O
674 ))
675 for partner in uniq_inbox:
676 inbox_ary = [m for m in inbox if m['sender_screen_name'] == partner[0]]
03c0d30b 677 sent_ary = [
678 m for m in sent if m['recipient_screen_name'] == partner[0]]
67c663f8
O
679 d[partner] = inbox_ary + sent_ary
680 for partner in uniq_sent:
681 if partner not in d:
03c0d30b 682 d[partner] = [
683 m for m in sent if m['recipient_screen_name'] == partner[0]]
67c663f8
O
684 g['message_threads'] = print_threads(d)
685
686
687def thread():
688 """
689 View a thread of message
690 """
691 try:
692 thread_id = int(g['stuff'])
03c0d30b 693 print_thread(
694 g['message_threads'][thread_id],
695 g['original_name'],
696 g['full_name'])
697 except Exception:
7a8a52fc 698 debug_option()
67c663f8 699 printNicely(red('No such thread.'))
e2b81717 700
305ce127 701
fd87ddac
O
702def message():
703 """
704 Send a direct message
705 """
706 t = Twitter(auth=authen())
03c0d30b 707 try:
708 user = g['stuff'].split()[0]
709 if user[0].startswith('@'):
710 content = ' '.join(g['stuff'].split()[1:])
711 t.direct_messages.new(
712 screen_name=user[1:],
713 text=content
714 )
715 printNicely(green('Message sent.'))
716 else:
717 printNicely(red('A name should begin with a \'@\''))
718 except:
7a8a52fc 719 debug_option()
03c0d30b 720 printNicely(red('Sorry I can\'t understand.'))
fd87ddac
O
721
722
305ce127 723def trash():
724 """
725 Remove message
726 """
727 t = Twitter(auth=authen())
728 try:
99b52f5f 729 id = int(g['stuff'].split()[0])
305ce127 730 except:
731 printNicely(red('Sorry I can\'t understand.'))
99b52f5f 732 mid = c['message_dict'][id]
b8c1f42a
O
733 t.direct_messages.destroy(id=mid)
734 printNicely(green('Message deleted.'))
305ce127 735
736
fd87ddac 737def ls():
e2b81717 738 """
fd87ddac 739 List friends for followers
e2b81717
O
740 """
741 t = Twitter(auth=authen())
fd87ddac
O
742 # Get name
743 try:
744 name = g['stuff'].split()[1]
745 if name.startswith('@'):
746 name = name[1:]
747 else:
748 printNicely(red('A name should begin with a \'@\''))
749 raise Exception('Invalid name')
750 except:
751 name = g['original_name']
752 # Get list followers or friends
753 try:
754 target = g['stuff'].split()[0]
755 except:
756 printNicely(red('Omg some syntax is wrong.'))
757 # Init cursor
758 d = {'fl': 'followers', 'fr': 'friends'}
759 next_cursor = -1
760 rel = {}
761 # Cursor loop
762 while next_cursor != 0:
763 list = getattr(t, d[target]).list(
764 screen_name=name,
765 cursor=next_cursor,
766 skip_status=True,
767 include_entities=False,
768 )
769 for u in list['users']:
770 rel[u['name']] = '@' + u['screen_name']
771 next_cursor = list['next_cursor']
772 # Print out result
773 printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.')
774 for name in rel:
775 user = ' ' + cycle_color(name)
776 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
777 printNicely(user)
e2b81717
O
778
779
f5677fb1 780def follow():
843647ad 781 """
f5677fb1 782 Follow a user
843647ad
O
783 """
784 t = Twitter(auth=authen())
f5677fb1 785 screen_name = g['stuff'].split()[0]
b8c1f42a
O
786 if screen_name.startswith('@'):
787 t.friendships.create(screen_name=screen_name[1:], follow=True)
788 printNicely(green('You are following ' + screen_name + ' now!'))
f5677fb1 789 else:
b8c1f42a 790 printNicely(red('A name should begin with a \'@\''))
f5677fb1
O
791
792
793def unfollow():
794 """
795 Unfollow a user
796 """
797 t = Twitter(auth=authen())
798 screen_name = g['stuff'].split()[0]
b8c1f42a
O
799 if screen_name.startswith('@'):
800 t.friendships.destroy(
801 screen_name=screen_name[1:],
802 include_entities=False)
803 printNicely(green('Unfollow ' + screen_name + ' success!'))
f5677fb1 804 else:
b8c1f42a 805 printNicely(red('A name should begin with a \'@\''))
843647ad
O
806
807
5b2c4faf 808def mute():
809 """
810 Mute a user
811 """
812 t = Twitter(auth=authen())
813 try:
814 screen_name = g['stuff'].split()[0]
815 except:
816 printNicely(red('A name should be specified. '))
817 return
818 if screen_name.startswith('@'):
e3927852
O
819 try:
820 rel = t.mutes.users.create(screen_name=screen_name[1:])
821 if isinstance(rel, dict):
822 printNicely(green(screen_name + ' is muted.'))
612d6863 823 c['IGNORE_LIST'] += [unc(screen_name)]
e3927852
O
824 c['IGNORE_LIST'] = list(set(c['IGNORE_LIST']))
825 else:
826 printNicely(red(rel))
827 except:
7a8a52fc 828 debug_option()
e3927852 829 printNicely(red('Something is wrong, can not mute now :('))
5b2c4faf 830 else:
831 printNicely(red('A name should begin with a \'@\''))
832
833
834def unmute():
835 """
836 Unmute a user
837 """
838 t = Twitter(auth=authen())
839 try:
840 screen_name = g['stuff'].split()[0]
841 except:
842 printNicely(red('A name should be specified. '))
843 return
844 if screen_name.startswith('@'):
e3927852
O
845 try:
846 rel = t.mutes.users.destroy(screen_name=screen_name[1:])
847 if isinstance(rel, dict):
848 printNicely(green(screen_name + ' is unmuted.'))
849 c['IGNORE_LIST'].remove(screen_name)
850 else:
851 printNicely(red(rel))
852 except:
853 printNicely(red('Maybe you are not muting this person ?'))
5b2c4faf 854 else:
855 printNicely(red('A name should begin with a \'@\''))
856
857
858def muting():
859 """
860 List muting user
861 """
e3927852
O
862 # Get dict of muting users
863 md = build_mute_dict(dict_data=True)
864 printNicely('All: ' + str(len(md)) + ' people.')
865 for name in md:
866 user = ' ' + cycle_color(md[name])
867 user += color_func(c['TWEET']['nick'])(' ' + name + ' ')
5b2c4faf 868 printNicely(user)
e3927852
O
869 # Update from Twitter
870 c['IGNORE_LIST'] = [n for n in md]
5b2c4faf 871
872
305ce127 873def block():
874 """
875 Block a user
876 """
877 t = Twitter(auth=authen())
878 screen_name = g['stuff'].split()[0]
b8c1f42a
O
879 if screen_name.startswith('@'):
880 t.blocks.create(
5b2c4faf 881 screen_name=screen_name[1:],
882 include_entities=False,
883 skip_status=True)
b8c1f42a 884 printNicely(green('You blocked ' + screen_name + '.'))
305ce127 885 else:
b8c1f42a 886 printNicely(red('A name should begin with a \'@\''))
305ce127 887
888
889def unblock():
890 """
891 Unblock a user
892 """
893 t = Twitter(auth=authen())
894 screen_name = g['stuff'].split()[0]
b8c1f42a
O
895 if screen_name.startswith('@'):
896 t.blocks.destroy(
897 screen_name=screen_name[1:],
898 include_entities=False,
899 skip_status=True)
900 printNicely(green('Unblock ' + screen_name + ' success!'))
305ce127 901 else:
b8c1f42a 902 printNicely(red('A name should begin with a \'@\''))
305ce127 903
904
905def report():
906 """
907 Report a user as a spam account
908 """
909 t = Twitter(auth=authen())
910 screen_name = g['stuff'].split()[0]
b8c1f42a
O
911 if screen_name.startswith('@'):
912 t.users.report_spam(
913 screen_name=screen_name[1:])
914 printNicely(green('You reported ' + screen_name + '.'))
305ce127 915 else:
916 printNicely(red('Sorry I can\'t understand.'))
917
918
8b8566d1
O
919def get_slug():
920 """
ee4c94b1 921 Get slug
8b8566d1 922 """
a8c5fce4 923 # Get list name
be4dba0e 924 list_name = raw_input(
925 light_magenta('Give me the list\'s name ("@owner/list_name"): ', rl=True))
8b8566d1
O
926 # Get list name and owner
927 try:
928 owner, slug = list_name.split('/')
929 if slug.startswith('@'):
930 slug = slug[1:]
931 return owner, slug
932 except:
a8c5fce4
O
933 printNicely(
934 light_magenta('List name should follow "@owner/list_name" format.'))
8b8566d1
O
935 raise Exception('Wrong list name')
936
937
2d341029
O
938def show_lists(t):
939 """
422dd385 940 List list
2d341029
O
941 """
942 rel = t.lists.list(screen_name=g['original_name'])
943 if rel:
944 print_list(rel)
945 else:
946 printNicely(light_magenta('You belong to no lists :)'))
947
948
949def list_home(t):
950 """
951 List home
952 """
8b8566d1 953 owner, slug = get_slug()
2d341029 954 res = t.lists.statuses(
422dd385
O
955 slug=slug,
956 owner_screen_name=owner,
957 count=c['LIST_MAX'],
2d341029 958 include_entities=False)
7304256c 959 for tweet in reversed(res):
2d341029
O
960 draw(t=tweet)
961 printNicely('')
962
963
964def list_members(t):
965 """
966 List members
967 """
8b8566d1 968 owner, slug = get_slug()
422dd385 969 # Get members
2d341029
O
970 rel = {}
971 next_cursor = -1
422dd385 972 while next_cursor != 0:
2d341029 973 m = t.lists.members(
422dd385
O
974 slug=slug,
975 owner_screen_name=owner,
976 cursor=next_cursor,
2d341029
O
977 include_entities=False)
978 for u in m['users']:
979 rel[u['name']] = '@' + u['screen_name']
980 next_cursor = m['next_cursor']
981 printNicely('All: ' + str(len(rel)) + ' members.')
982 for name in rel:
983 user = ' ' + cycle_color(name)
422dd385 984 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
985 printNicely(user)
986
987
988def list_subscribers(t):
989 """
990 List subscribers
991 """
8b8566d1 992 owner, slug = get_slug()
422dd385 993 # Get subscribers
2d341029
O
994 rel = {}
995 next_cursor = -1
422dd385 996 while next_cursor != 0:
2d341029 997 m = t.lists.subscribers(
422dd385
O
998 slug=slug,
999 owner_screen_name=owner,
1000 cursor=next_cursor,
2d341029
O
1001 include_entities=False)
1002 for u in m['users']:
1003 rel[u['name']] = '@' + u['screen_name']
1004 next_cursor = m['next_cursor']
1005 printNicely('All: ' + str(len(rel)) + ' subscribers.')
1006 for name in rel:
1007 user = ' ' + cycle_color(name)
422dd385 1008 user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ')
2d341029
O
1009 printNicely(user)
1010
1011
422dd385
O
1012def list_add(t):
1013 """
1014 Add specific user to a list
1015 """
8b8566d1 1016 owner, slug = get_slug()
422dd385 1017 # Add
be4dba0e 1018 user_name = raw_input(
1019 light_magenta(
1020 'Give me name of the newbie: ',
1021 rl=True))
422dd385
O
1022 if user_name.startswith('@'):
1023 user_name = user_name[1:]
1024 try:
1025 t.lists.members.create(
1026 slug=slug,
1027 owner_screen_name=owner,
1028 screen_name=user_name)
d6cc4c67 1029 printNicely(green('Added.'))
422dd385 1030 except:
7a8a52fc 1031 debug_option()
422dd385
O
1032 printNicely(light_magenta('I\'m sorry we can not add him/her.'))
1033
1034
2d341029
O
1035def list_remove(t):
1036 """
1037 Remove specific user from a list
1038 """
8b8566d1 1039 owner, slug = get_slug()
2d341029 1040 # Remove
be4dba0e 1041 user_name = raw_input(
1042 light_magenta(
1043 'Give me name of the unlucky one: ',
1044 rl=True))
422dd385
O
1045 if user_name.startswith('@'):
1046 user_name = user_name[1:]
2d341029
O
1047 try:
1048 t.lists.members.destroy(
422dd385
O
1049 slug=slug,
1050 owner_screen_name=owner,
1051 screen_name=user_name)
d6cc4c67 1052 printNicely(green('Gone.'))
422dd385 1053 except:
7a8a52fc 1054 debug_option()
422dd385
O
1055 printNicely(light_magenta('I\'m sorry we can not remove him/her.'))
1056
1057
1058def list_subscribe(t):
1059 """
1060 Subscribe to a list
1061 """
8b8566d1 1062 owner, slug = get_slug()
422dd385
O
1063 # Subscribe
1064 try:
1065 t.lists.subscribers.create(
1066 slug=slug,
1067 owner_screen_name=owner)
d6cc4c67 1068 printNicely(green('Done.'))
422dd385 1069 except:
7a8a52fc 1070 debug_option()
422dd385
O
1071 printNicely(
1072 light_magenta('I\'m sorry you can not subscribe to this list.'))
1073
1074
1075def list_unsubscribe(t):
1076 """
1077 Unsubscribe a list
1078 """
8b8566d1 1079 owner, slug = get_slug()
422dd385
O
1080 # Subscribe
1081 try:
1082 t.lists.subscribers.destroy(
1083 slug=slug,
1084 owner_screen_name=owner)
d6cc4c67 1085 printNicely(green('Done.'))
422dd385 1086 except:
7a8a52fc 1087 debug_option()
422dd385
O
1088 printNicely(
1089 light_magenta('I\'m sorry you can not unsubscribe to this list.'))
1090
1091
1092def list_own(t):
1093 """
1094 List own
1095 """
1096 rel = []
1097 next_cursor = -1
1098 while next_cursor != 0:
1099 res = t.lists.ownerships(
1100 screen_name=g['original_name'],
1101 cursor=next_cursor)
1102 rel += res['lists']
1103 next_cursor = res['next_cursor']
1104 if rel:
1105 print_list(rel)
1106 else:
1107 printNicely(light_magenta('You own no lists :)'))
1108
1109
1110def list_new(t):
1111 """
1112 Create a new list
1113 """
be4dba0e 1114 name = raw_input(light_magenta('New list\'s name: ', rl=True))
1115 mode = raw_input(
1116 light_magenta(
1117 'New list\'s mode (public/private): ',
1118 rl=True))
1119 description = raw_input(
1120 light_magenta(
1121 'New list\'s description: ',
1122 rl=True))
422dd385
O
1123 try:
1124 t.lists.create(
1125 name=name,
1126 mode=mode,
1127 description=description)
d6cc4c67 1128 printNicely(green(name + ' list is created.'))
422dd385 1129 except:
7a8a52fc 1130 debug_option()
422dd385
O
1131 printNicely(red('Oops something is wrong with Twitter :('))
1132
1133
1134def list_update(t):
1135 """
1136 Update a list
1137 """
be4dba0e 1138 slug = raw_input(
1139 light_magenta(
1140 'Your list that you want to update: ',
1141 rl=True))
1142 name = raw_input(
1143 light_magenta(
1144 'Update name (leave blank to unchange): ',
1145 rl=True))
1146 mode = raw_input(light_magenta('Update mode (public/private): ', rl=True))
1147 description = raw_input(light_magenta('Update description: ', rl=True))
422dd385
O
1148 try:
1149 if name:
1150 t.lists.update(
1151 slug='-'.join(slug.split()),
1152 owner_screen_name=g['original_name'],
1153 name=name,
1154 mode=mode,
1155 description=description)
1156 else:
1157 t.lists.update(
1158 slug=slug,
1159 owner_screen_name=g['original_name'],
1160 mode=mode,
1161 description=description)
d6cc4c67 1162 printNicely(green(slug + ' list is updated.'))
3c85d8fc 1163 except:
7a8a52fc 1164 debug_option()
422dd385
O
1165 printNicely(red('Oops something is wrong with Twitter :('))
1166
1167
1168def list_delete(t):
1169 """
1170 Delete a list
1171 """
be4dba0e 1172 slug = raw_input(
1173 light_magenta(
1174 'Your list that you want to delete: ',
1175 rl=True))
422dd385
O
1176 try:
1177 t.lists.destroy(
1178 slug='-'.join(slug.split()),
1179 owner_screen_name=g['original_name'])
d6cc4c67 1180 printNicely(green(slug + ' list is deleted.'))
2d341029 1181 except:
7a8a52fc 1182 debug_option()
422dd385 1183 printNicely(red('Oops something is wrong with Twitter :('))
2d341029
O
1184
1185
e3927852 1186def twitterlist():
2d341029
O
1187 """
1188 Twitter's list
1189 """
1190 t = Twitter(auth=authen())
1191 # List all lists or base on action
1192 try:
1193 g['list_action'] = g['stuff'].split()[0]
1194 except:
1195 show_lists(t)
1196 return
422dd385 1197 # Sub-function
2d341029
O
1198 action_ary = {
1199 'home': list_home,
1200 'all_mem': list_members,
1201 'all_sub': list_subscribers,
422dd385 1202 'add': list_add,
2d341029 1203 'rm': list_remove,
422dd385
O
1204 'sub': list_subscribe,
1205 'unsub': list_unsubscribe,
1206 'own': list_own,
1207 'new': list_new,
1208 'update': list_update,
1209 'del': list_delete,
2d341029
O
1210 }
1211 try:
1212 return action_ary[g['list_action']](t)
3c85d8fc 1213 except:
8b8566d1 1214 printNicely(red('Please try again.'))
2d341029
O
1215
1216
fd87ddac
O
1217def switch():
1218 """
1219 Switch stream
1220 """
1221 try:
1222 target = g['stuff'].split()[0]
1223 # Filter and ignore
1224 args = parse_arguments()
1225 try:
1226 if g['stuff'].split()[-1] == '-f':
1227 guide = 'To ignore an option, just hit Enter key.'
1228 printNicely(light_magenta(guide))
1229 only = raw_input('Only nicks [Ex: @xxx,@yy]: ')
1230 ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ')
1231 args.filter = filter(None, only.split(','))
1232 args.ignore = filter(None, ignore.split(','))
fd87ddac
O
1233 except:
1234 printNicely(red('Sorry, wrong format.'))
1235 return
1236 # Public stream
1237 if target == 'public':
1238 keyword = g['stuff'].split()[1]
1239 if keyword[0] == '#':
1240 keyword = keyword[1:]
1241 # Kill old thread
1242 g['stream_stop'] = True
1243 args.track_keywords = keyword
1d01129e
LP
1244 # Set the variable to tracked keyword
1245 # and reset the listname
1246 g['keyword'] = keyword
1247 g['listname'] = ''
72f58edb 1248 # Reset prefix
063f6bb1 1249 g['PREFIX'] = u2str(emojize(format_prefix(keyword=g['keyword'])))
fd87ddac
O
1250 # Start new thread
1251 th = threading.Thread(
1252 target=stream,
1253 args=(
1254 c['PUBLIC_DOMAIN'],
1255 args))
1256 th.daemon = True
1257 th.start()
1258 # Personal stream
1259 elif target == 'mine':
1260 # Kill old thread
1261 g['stream_stop'] = True
1d01129e
LP
1262 # Reset the tracked keyword and listname
1263 g['keyword'] = g['listname'] = ''
72f58edb 1264 # Reset prefix
b85ec13a 1265 g['PREFIX'] = u2str(emojize(format_prefix()))
fd87ddac
O
1266 # Start new thread
1267 th = threading.Thread(
1268 target=stream,
1269 args=(
1270 c['USER_DOMAIN'],
1271 args,
1272 g['original_name']))
1273 th.daemon = True
1274 th.start()
ee4c94b1
O
1275 # Stream base on list
1276 elif target == 'list':
1277 owner, slug = get_slug()
1278 # Force python 2 not redraw readline buffer
b85ec13a 1279 listname = '/'.join([owner, slug])
063f6bb1 1280 # Set the listname variable
1d01129e
LP
1281 # and reset tracked keyword
1282 g['listname'] = listname
1283 g['keyword'] = ''
063f6bb1 1284 g['PREFIX'] = g['cmd'] = u2str(emojize(format_prefix(
1285 listname=g['listname']
1286 )))
ee4c94b1
O
1287 printNicely(light_yellow('getting list members ...'))
1288 # Get members
1289 t = Twitter(auth=authen())
1290 members = []
1291 next_cursor = -1
1292 while next_cursor != 0:
1293 m = t.lists.members(
1294 slug=slug,
1295 owner_screen_name=owner,
1296 cursor=next_cursor,
1297 include_entities=False)
1298 for u in m['users']:
1299 members.append('@' + u['screen_name'])
1300 next_cursor = m['next_cursor']
1301 printNicely(light_yellow('... done.'))
1302 # Build thread filter array
1303 args.filter = members
1304 # Kill old thread
1305 g['stream_stop'] = True
1306 # Start new thread
1307 th = threading.Thread(
1308 target=stream,
1309 args=(
1310 c['USER_DOMAIN'],
1311 args,
1312 slug))
1313 th.daemon = True
1314 th.start()
fd87ddac
O
1315 printNicely('')
1316 if args.filter:
ac03309c 1317 printNicely(cyan('Include: ' + str(len(args.filter)) + ' people.'))
fd87ddac 1318 if args.ignore:
ac03309c 1319 printNicely(red('Ignore: ' + str(len(args.ignore)) + ' people.'))
fd87ddac 1320 printNicely('')
050a294e 1321 except:
ee4c94b1 1322 debug_option()
fd87ddac
O
1323 printNicely(red('Sorry I can\'t understand.'))
1324
1325
813a5d80 1326def cal():
1327 """
1328 Unix's command `cal`
1329 """
1330 # Format
1331 rel = os.popen('cal').read().split('\n')
1332 month = rel.pop(0)
813a5d80 1333 date = rel.pop(0)
2a0cabee 1334 show_calendar(month, date, rel)
813a5d80 1335
1336
fd87ddac
O
1337def theme():
1338 """
1339 List and change theme
1340 """
1341 if not g['stuff']:
1342 # List themes
1343 for theme in g['themes']:
1344 line = light_magenta(theme)
1345 if c['THEME'] == theme:
1346 line = ' ' * 2 + light_yellow('* ') + line
1347 else:
1348 line = ' ' * 4 + line
1349 printNicely(line)
1350 else:
1351 # Change theme
1352 try:
1353 # Load new theme
1354 c['THEME'] = reload_theme(g['stuff'], c['THEME'])
1355 # Redefine decorated_name
1356 g['decorated_name'] = lambda x: color_func(
1357 c['DECORATED_NAME'])(
1358 '[' + x + ']: ')
1359 printNicely(green('Theme changed.'))
1360 except:
1361 printNicely(red('No such theme exists.'))
1362
1363
29fd0be6
O
1364def config():
1365 """
1366 Browse and change config
1367 """
1368 all_config = get_all_config()
1369 g['stuff'] = g['stuff'].strip()
1370 # List all config
1371 if not g['stuff']:
1372 for k in all_config:
a8c5fce4 1373 line = ' ' * 2 + \
d6cc4c67 1374 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1375 printNicely(line)
1376 guide = 'Detailed explanation can be found at ' + \
a8c5fce4
O
1377 color_func(c['TWEET']['link'])(
1378 'http://rainbowstream.readthedocs.org/en/latest/#config-explanation')
29fd0be6
O
1379 printNicely(guide)
1380 # Print specific config
1381 elif len(g['stuff'].split()) == 1:
1382 if g['stuff'] in all_config:
1383 k = g['stuff']
a8c5fce4 1384 line = ' ' * 2 + \
d6cc4c67 1385 green(k) + ': ' + light_yellow(str(all_config[k]))
29fd0be6
O
1386 printNicely(line)
1387 else:
fe9bb33b 1388 printNicely(red('No such config key.'))
29fd0be6
O
1389 # Print specific config's default value
1390 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'default':
1391 key = g['stuff'].split()[0]
fe9bb33b 1392 try:
1393 value = get_default_config(key)
d6cc4c67 1394 line = ' ' * 2 + green(key) + ': ' + light_magenta(value)
fe9bb33b 1395 printNicely(line)
050a294e
O
1396 except:
1397 debug_option()
1398 printNicely(red('Just can not get the default.'))
fe9bb33b 1399 # Delete specific config key in config file
1400 elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop':
1401 key = g['stuff'].split()[0]
1402 try:
1403 delete_config(key)
d6cc4c67 1404 printNicely(green('Config key is dropped.'))
050a294e
O
1405 except:
1406 debug_option()
1407 printNicely(red('Just can not drop the key.'))
29fd0be6 1408 # Set specific config
a8c5fce4 1409 elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=':
29fd0be6
O
1410 key = g['stuff'].split()[0]
1411 value = g['stuff'].split()[-1]
ceec8593 1412 if key == 'THEME' and not validate_theme(value):
1413 printNicely(red('Invalid theme\'s value.'))
1414 return
3c01ba57 1415 try:
a8c5fce4 1416 set_config(key, value)
050a294e 1417 # Keys that needs to be apply immediately
ceec8593 1418 if key == 'THEME':
baec5f50 1419 c['THEME'] = reload_theme(value, c['THEME'])
ceec8593 1420 g['decorated_name'] = lambda x: color_func(
a8e71259 1421 c['DECORATED_NAME'])('[' + x + ']: ')
050a294e 1422 elif key == 'PREFIX':
063f6bb1 1423 g['PREFIX'] = u2str(emojize(format_prefix(
1424 listname=g['listname'],
1425 keyword=g['keyword']
1426 )))
a8e71259 1427 reload_config()
d6cc4c67 1428 printNicely(green('Updated successfully.'))
050a294e
O
1429 except:
1430 debug_option()
1431 printNicely(red('Just can not set the key.'))
29fd0be6
O
1432 else:
1433 printNicely(light_magenta('Sorry I can\'s understand.'))
1434
1435
2d341029 1436def help_discover():
f405a7d0 1437 """
2d341029 1438 Discover the world
f405a7d0 1439 """
7e4ccbf3 1440 s = ' ' * 2
1f24a05a 1441 # Discover the world
2d341029 1442 usage = '\n'
8bc30efd 1443 usage += s + grey(u'\u266A' + ' Discover the world \n')
c075e6dc
O
1444 usage += s * 2 + light_green('trend') + ' will show global trending topics. ' + \
1445 'You can try ' + light_green('trend US') + ' or ' + \
1446 light_green('trend JP Tokyo') + '.\n'
1447 usage += s * 2 + light_green('home') + ' will show your timeline. ' + \
1448 light_green('home 7') + ' will show 7 tweets.\n'
99cd1fba
O
1449 usage += s * 2 + \
1450 light_green('notification') + ' will show your recent notification.\n'
c075e6dc
O
1451 usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \
1452 light_green('mentions 7') + ' will show 7 mention tweets.\n'
1453 usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \
8bc30efd 1454 magenta('@mdo') + '.\n'
c075e6dc 1455 usage += s * 2 + light_green('view @mdo') + \
8bc30efd 1456 ' will show ' + magenta('@mdo') + '\'s home.\n'
03e08f86
O
1457 usage += s * 2 + light_green('s AKB48') + ' will search for "' + \
1458 light_yellow('AKB48') + '" and return 5 newest tweet. ' + \
1459 'Search can be performed with or without hashtag.\n'
2d341029
O
1460 printNicely(usage)
1461
8bc30efd 1462
2d341029
O
1463def help_tweets():
1464 """
1465 Tweets
1466 """
1467 s = ' ' * 2
1f24a05a 1468 # Tweet
2d341029 1469 usage = '\n'
8bc30efd 1470 usage += s + grey(u'\u266A' + ' Tweets \n')
c075e6dc
O
1471 usage += s * 2 + light_green('t oops ') + \
1472 'will tweet "' + light_yellow('oops') + '" immediately.\n'
7e4ccbf3 1473 usage += s * 2 + \
c075e6dc
O
1474 light_green('rt 12 ') + ' will retweet to tweet with ' + \
1475 light_yellow('[id=12]') + '.\n'
80b70d60
O
1476 usage += s * 2 + \
1477 light_green('quote 12 ') + ' will quote the tweet with ' + \
1478 light_yellow('[id=12]') + '. If no extra text is added, ' + \
1479 'the quote will be canceled.\n'
1f24a05a 1480 usage += s * 2 + \
c075e6dc
O
1481 light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \
1482 light_yellow('[id=12]') + '.\n'
fd87ddac
O
1483 usage += s * 2 + light_green('conversation 12') + ' will show the chain of ' + \
1484 'replies prior to the tweet with ' + light_yellow('[id=12]') + '.\n'
c075e6dc
O
1485 usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \
1486 light_yellow('oops') + '" to tweet with ' + \
1487 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1488 usage += s * 2 + \
c075e6dc
O
1489 light_green('fav 12 ') + ' will favorite the tweet with ' + \
1490 light_yellow('[id=12]') + '.\n'
7e4ccbf3 1491 usage += s * 2 + \
c075e6dc
O
1492 light_green('ufav 12 ') + ' will unfavorite tweet with ' + \
1493 light_yellow('[id=12]') + '.\n'
413857b5 1494 usage += s * 2 + \
66fe9f75 1495 light_green('share 12 ') + ' will get the direct link of the tweet with ' + \
1496 light_yellow('[id=12]') + '.\n'
8bc30efd 1497 usage += s * 2 + \
c075e6dc
O
1498 light_green('del 12 ') + ' will delete tweet with ' + \
1499 light_yellow('[id=12]') + '.\n'
1500 usage += s * 2 + light_green('show image 12') + ' will show image in tweet with ' + \
1501 light_yellow('[id=12]') + ' in your OS\'s image viewer.\n'
80b70d60
O
1502 usage += s * 2 + light_green('open 12') + ' will open url in tweet with ' + \
1503 light_yellow('[id=12]') + ' in your OS\'s default browser.\n'
2d341029 1504 printNicely(usage)
8bc30efd 1505
2d341029
O
1506
1507def help_messages():
1508 """
1509 Messages
1510 """
1511 s = ' ' * 2
5b2c4faf 1512 # Direct message
2d341029 1513 usage = '\n'
8bc30efd 1514 usage += s + grey(u'\u266A' + ' Direct messages \n')
c075e6dc
O
1515 usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \
1516 light_green('inbox 7') + ' will show newest 7 messages.\n'
03c0d30b 1517 usage += s * 2 + light_green('thread 2') + ' will show full thread with ' + \
1518 light_yellow('[thread_id=2]') + '.\n'
c075e6dc 1519 usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \
8bc30efd 1520 magenta('@dtvd88') + '.\n'
c075e6dc
O
1521 usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \
1522 light_yellow('[message_id=5]') + '.\n'
2d341029 1523 printNicely(usage)
8bc30efd 1524
2d341029
O
1525
1526def help_friends_and_followers():
1527 """
1528 Friends and Followers
1529 """
1530 s = ' ' * 2
8bc30efd 1531 # Follower and following
2d341029 1532 usage = '\n'
cdccb0d6 1533 usage += s + grey(u'\u266A' + ' Friends and followers \n')
8bc30efd 1534 usage += s * 2 + \
c075e6dc 1535 light_green('ls fl') + \
8bc30efd 1536 ' will list all followers (people who are following you).\n'
1537 usage += s * 2 + \
c075e6dc 1538 light_green('ls fr') + \
8bc30efd 1539 ' will list all friends (people who you are following).\n'
c075e6dc 1540 usage += s * 2 + light_green('fl @dtvd88') + ' will follow ' + \
305ce127 1541 magenta('@dtvd88') + '.\n'
c075e6dc 1542 usage += s * 2 + light_green('ufl @dtvd88') + ' will unfollow ' + \
305ce127 1543 magenta('@dtvd88') + '.\n'
c075e6dc 1544 usage += s * 2 + light_green('mute @dtvd88') + ' will mute ' + \
5b2c4faf 1545 magenta('@dtvd88') + '.\n'
c075e6dc 1546 usage += s * 2 + light_green('unmute @dtvd88') + ' will unmute ' + \
5b2c4faf 1547 magenta('@dtvd88') + '.\n'
c075e6dc
O
1548 usage += s * 2 + light_green('muting') + ' will list muting users.\n'
1549 usage += s * 2 + light_green('block @dtvd88') + ' will block ' + \
305ce127 1550 magenta('@dtvd88') + '.\n'
c075e6dc 1551 usage += s * 2 + light_green('unblock @dtvd88') + ' will unblock ' + \
305ce127 1552 magenta('@dtvd88') + '.\n'
c075e6dc 1553 usage += s * 2 + light_green('report @dtvd88') + ' will report ' + \
305ce127 1554 magenta('@dtvd88') + ' as a spam account.\n'
2d341029
O
1555 printNicely(usage)
1556
1557
1558def help_list():
1559 """
1560 Lists
1561 """
1562 s = ' ' * 2
1563 # Twitter list
1564 usage = '\n'
1565 usage += s + grey(u'\u266A' + ' Twitter list\n')
1566 usage += s * 2 + light_green('list') + \
1567 ' will show all lists you are belong to.\n'
1568 usage += s * 2 + light_green('list home') + \
bef33491 1569 ' will show timeline of list. You will be asked for list\'s name.\n'
a65bd34c 1570 usage += s * 2 + light_green('list all_mem') + \
2d341029 1571 ' will show list\'s all members.\n'
a65bd34c 1572 usage += s * 2 + light_green('list all_sub') + \
2d341029 1573 ' will show list\'s all subscribers.\n'
422dd385
O
1574 usage += s * 2 + light_green('list add') + \
1575 ' will add specific person to a list owned by you.' + \
1576 ' You will be asked for list\'s name and person\'s name.\n'
2d341029
O
1577 usage += s * 2 + light_green('list rm') + \
1578 ' will remove specific person from a list owned by you.' + \
1579 ' You will be asked for list\'s name and person\'s name.\n'
422dd385
O
1580 usage += s * 2 + light_green('list sub') + \
1581 ' will subscribe you to a specific list.\n'
1582 usage += s * 2 + light_green('list unsub') + \
1583 ' will unsubscribe you from a specific list.\n'
1584 usage += s * 2 + light_green('list own') + \
1585 ' will show all list owned by you.\n'
1586 usage += s * 2 + light_green('list new') + \
1587 ' will create a new list.\n'
1588 usage += s * 2 + light_green('list update') + \
1589 ' will update a list owned by you.\n'
1590 usage += s * 2 + light_green('list del') + \
1591 ' will delete a list owned by you.\n'
2d341029 1592 printNicely(usage)
8bc30efd 1593
2d341029
O
1594
1595def help_stream():
1596 """
1597 Stream switch
1598 """
1599 s = ' ' * 2
8bc30efd 1600 # Switch
2d341029 1601 usage = '\n'
8bc30efd 1602 usage += s + grey(u'\u266A' + ' Switching streams \n')
c075e6dc 1603 usage += s * 2 + light_green('switch public #AKB') + \
48a25fe8 1604 ' will switch to public stream and follow "' + \
c075e6dc
O
1605 light_yellow('AKB') + '" keyword.\n'
1606 usage += s * 2 + light_green('switch mine') + \
48a25fe8 1607 ' will switch to your personal stream.\n'
c075e6dc 1608 usage += s * 2 + light_green('switch mine -f ') + \
48a25fe8 1609 ' will prompt to enter the filter.\n'
c075e6dc 1610 usage += s * 3 + light_yellow('Only nicks') + \
48a25fe8 1611 ' filter will decide nicks will be INCLUDE ONLY.\n'
c075e6dc 1612 usage += s * 3 + light_yellow('Ignore nicks') + \
48a25fe8 1613 ' filter will decide nicks will be EXCLUDE.\n'
ee4c94b1
O
1614 usage += s * 2 + light_green('switch list') + \
1615 ' will switch to a Twitter list\'s stream. You will be asked for list name\n'
2d341029
O
1616 printNicely(usage)
1617
1618
1619def help():
1620 """
1621 Help
1622 """
1623 s = ' ' * 2
1624 h, w = os.popen('stty size', 'r').read().split()
2d341029
O
1625 # Start
1626 usage = '\n'
1627 usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
1628 usage += s + '-' * (int(w) - 4) + '\n'
1629 usage += s + 'You are ' + \
1630 light_yellow('already') + ' on your personal stream.\n'
1631 usage += s + 'Any update from Twitter will show up ' + \
1632 light_yellow('immediately') + '.\n'
37d1047f 1633 usage += s + 'In addition, following commands are available right now:\n'
2d341029
O
1634 # Twitter help section
1635 usage += '\n'
1636 usage += s + grey(u'\u266A' + ' Twitter help\n')
1637 usage += s * 2 + light_green('h discover') + \
1638 ' will show help for discover commands.\n'
1639 usage += s * 2 + light_green('h tweets') + \
1640 ' will show help for tweets commands.\n'
1641 usage += s * 2 + light_green('h messages') + \
1642 ' will show help for messages commands.\n'
1643 usage += s * 2 + light_green('h friends_and_followers') + \
1644 ' will show help for friends and followers commands.\n'
1645 usage += s * 2 + light_green('h list') + \
1646 ' will show help for list commands.\n'
1647 usage += s * 2 + light_green('h stream') + \
1648 ' will show help for stream commands.\n'
1f24a05a 1649 # Smart shell
1650 usage += '\n'
1651 usage += s + grey(u'\u266A' + ' Smart shell\n')
c075e6dc 1652 usage += s * 2 + light_green('111111 * 9 / 7') + ' or any math expression ' + \
1f24a05a 1653 'will be evaluate by Python interpreter.\n'
c075e6dc 1654 usage += s * 2 + 'Even ' + light_green('cal') + ' will show the calendar' + \
1f24a05a 1655 ' for current month.\n'
29fd0be6 1656 # Config
1f24a05a 1657 usage += '\n'
29fd0be6
O
1658 usage += s + grey(u'\u266A' + ' Config \n')
1659 usage += s * 2 + light_green('theme') + ' will list available theme. ' + \
c075e6dc 1660 light_green('theme monokai') + ' will apply ' + light_yellow('monokai') + \
632c6fa5 1661 ' theme immediately.\n'
29fd0be6
O
1662 usage += s * 2 + light_green('config') + ' will list all config.\n'
1663 usage += s * 3 + \
1664 light_green('config ASCII_ART') + ' will output current value of ' +\
a8c5fce4 1665 light_yellow('ASCII_ART') + ' config key.\n'
29fd0be6 1666 usage += s * 3 + \
fe9bb33b 1667 light_green('config TREND_MAX default') + ' will output default value of ' + \
1668 light_yellow('TREND_MAX') + ' config key.\n'
1669 usage += s * 3 + \
1670 light_green('config CUSTOM_CONFIG drop') + ' will drop ' + \
1671 light_yellow('CUSTOM_CONFIG') + ' config key.\n'
29fd0be6 1672 usage += s * 3 + \
fe9bb33b 1673 light_green('config IMAGE_ON_TERM = true') + ' will set value of ' + \
1674 light_yellow('IMAGE_ON_TERM') + ' config key to ' + \
1675 light_yellow('True') + '.\n'
29fd0be6
O
1676 # Screening
1677 usage += '\n'
1678 usage += s + grey(u'\u266A' + ' Screening \n')
c075e6dc 1679 usage += s * 2 + light_green('h') + ' will show this help again.\n'
d6cc4c67
O
1680 usage += s * 2 + light_green('p') + ' will pause the stream.\n'
1681 usage += s * 2 + light_green('r') + ' will unpause the stream.\n'
c075e6dc 1682 usage += s * 2 + light_green('c') + ' will clear the screen.\n'
806f42df 1683 usage += s * 2 + light_green('v') + ' will show version info.\n'
c075e6dc 1684 usage += s * 2 + light_green('q') + ' will quit.\n'
8bc30efd 1685 # End
1686 usage += '\n'
7e4ccbf3 1687 usage += s + '-' * (int(w) - 4) + '\n'
8bc30efd 1688 usage += s + 'Have fun and hang tight! \n'
2d341029
O
1689 # Show help
1690 d = {
422dd385
O
1691 'discover': help_discover,
1692 'tweets': help_tweets,
1693 'messages': help_messages,
1694 'friends_and_followers': help_friends_and_followers,
1695 'list': help_list,
1696 'stream': help_stream,
2d341029
O
1697 }
1698 if g['stuff']:
baec5f50 1699 d.get(
1700 g['stuff'].strip(),
1701 lambda: printNicely(red('No such command.'))
3d48702f 1702 )()
2d341029
O
1703 else:
1704 printNicely(usage)
f405a7d0
O
1705
1706
d6cc4c67
O
1707def pause():
1708 """
1709 Pause stream display
1710 """
4dc385b5 1711 g['pause'] = True
d6cc4c67
O
1712 printNicely(green('Stream is paused'))
1713
1714
1715def replay():
1716 """
1717 Replay stream
1718 """
4dc385b5 1719 g['pause'] = False
d6cc4c67
O
1720 printNicely(green('Stream is running back now'))
1721
1722
843647ad 1723def clear():
f405a7d0 1724 """
7b674cef 1725 Clear screen
f405a7d0 1726 """
843647ad 1727 os.system('clear')
f405a7d0
O
1728
1729
843647ad 1730def quit():
b8dda704
O
1731 """
1732 Exit all
1733 """
4c025026 1734 try:
1735 save_history()
4c025026 1736 printNicely(green('See you next time :)'))
1737 except:
1738 pass
843647ad 1739 sys.exit()
b8dda704
O
1740
1741
94a5f62e 1742def reset():
f405a7d0 1743 """
94a5f62e 1744 Reset prefix of line
f405a7d0 1745 """
c91f75f2 1746 if g['reset']:
a8e71259 1747 if c.get('USER_JSON_ERROR'):
1748 printNicely(red('Your ~/.rainbow_config.json is messed up:'))
1749 printNicely(red('>>> ' + c['USER_JSON_ERROR']))
1750 printNicely('')
e3885f55 1751 printNicely(magenta('Need tips ? Type "h" and hit Enter key!'))
c91f75f2 1752 g['reset'] = False
d0a726d6 1753 try:
779b0640 1754 printNicely(str(eval(g['cmd'])))
2a0cabee 1755 except Exception:
d0a726d6 1756 pass
54277114
O
1757
1758
f1c1dfea
O
1759# Command set
1760cmdset = [
1761 'switch',
1762 'trend',
1763 'home',
99cd1fba 1764 'notification',
f1c1dfea
O
1765 'view',
1766 'mentions',
1767 't',
1768 'rt',
1769 'quote',
1770 'allrt',
fd87ddac 1771 'conversation',
f1c1dfea
O
1772 'fav',
1773 'rep',
1774 'del',
1775 'ufav',
413857b5 1776 'share',
f1c1dfea
O
1777 's',
1778 'mes',
1779 'show',
1780 'open',
1781 'ls',
1782 'inbox',
67c663f8 1783 'thread',
f1c1dfea
O
1784 'trash',
1785 'whois',
1786 'fl',
1787 'ufl',
1788 'mute',
1789 'unmute',
1790 'muting',
1791 'block',
1792 'unblock',
1793 'report',
1794 'list',
1795 'cal',
1796 'config',
1797 'theme',
1798 'h',
1799 'p',
1800 'r',
1801 'c',
806f42df 1802 'v',
bf766c7b 1803 'q',
f1c1dfea
O
1804]
1805
1806# Handle function set
1807funcset = [
1808 switch,
1809 trend,
1810 home,
99cd1fba 1811 notification,
f1c1dfea
O
1812 view,
1813 mentions,
1814 tweet,
1815 retweet,
1816 quote,
1817 allretweet,
fd87ddac 1818 conversation,
f1c1dfea
O
1819 favorite,
1820 reply,
1821 delete,
1822 unfavorite,
413857b5 1823 share,
f1c1dfea
O
1824 search,
1825 message,
1826 show,
1827 urlopen,
1828 ls,
1829 inbox,
67c663f8 1830 thread,
f1c1dfea
O
1831 trash,
1832 whois,
1833 follow,
1834 unfollow,
1835 mute,
1836 unmute,
1837 muting,
1838 block,
1839 unblock,
1840 report,
1841 twitterlist,
1842 cal,
1843 config,
1844 theme,
1845 help,
1846 pause,
1847 replay,
1848 clear,
bf766c7b 1849 upgrade_center,
806f42df 1850 quit,
f1c1dfea
O
1851]
1852
1853
94a5f62e 1854def process(cmd):
54277114 1855 """
94a5f62e 1856 Process switch
54277114 1857 """
f1c1dfea 1858 return dict(zip(cmdset, funcset)).get(cmd, reset)
94a5f62e 1859
1860
1861def listen():
42fde775 1862 """
1863 Listen to user's input
1864 """
d51b4107
O
1865 d = dict(zip(
1866 cmdset,
1867 [
ee4c94b1 1868 ['public', 'mine', 'list'], # switch
4592d231 1869 [], # trend
7e4ccbf3 1870 [], # home
99cd1fba 1871 [], # notification
7e4ccbf3 1872 ['@'], # view
305ce127 1873 [], # mentions
7e4ccbf3 1874 [], # tweet
1875 [], # retweet
80b70d60 1876 [], # quote
1f24a05a 1877 [], # allretweet
fd87ddac 1878 [], # conversation
f5677fb1 1879 [], # favorite
7e4ccbf3 1880 [], # reply
1881 [], # delete
f5677fb1 1882 [], # unfavorite
413857b5 1883 [], # url
7e4ccbf3 1884 ['#'], # search
305ce127 1885 ['@'], # message
f5677fb1 1886 ['image'], # show image
80b70d60 1887 [''], # open url
305ce127 1888 ['fl', 'fr'], # list
1889 [], # inbox
03c0d30b 1890 [i for i in g['message_threads']], # sent
305ce127 1891 [], # trash
e2b81717 1892 ['@'], # whois
affcb149
O
1893 ['@'], # follow
1894 ['@'], # unfollow
5b2c4faf 1895 ['@'], # mute
1896 ['@'], # unmute
1897 ['@'], # muting
305ce127 1898 ['@'], # block
1899 ['@'], # unblock
1900 ['@'], # report
422dd385
O
1901 [
1902 'home',
1903 'all_mem',
1904 'all_sub',
1905 'add',
1906 'rm',
1907 'sub',
1908 'unsub',
1909 'own',
1910 'new',
1911 'update',
1912 'del'
1913 ], # list
813a5d80 1914 [], # cal
a8c5fce4 1915 [key for key in dict(get_all_config())], # config
ceec8593 1916 g['themes'], # theme
422dd385
O
1917 [
1918 'discover',
1919 'tweets',
1920 'messages',
1921 'friends_and_followers',
1922 'list',
1923 'stream'
1924 ], # help
d6cc4c67
O
1925 [], # pause
1926 [], # reconnect
7e4ccbf3 1927 [], # clear
7cfb8af4 1928 [], # version
806f42df 1929 [], # quit
d51b4107 1930 ]
7e4ccbf3 1931 ))
d51b4107 1932 init_interactive_shell(d)
f5677fb1 1933 read_history()
819569e8 1934 reset()
b2b933a9 1935 while True:
b8c1f42a 1936 try:
39b8e6b3
O
1937 # raw_input
1938 if g['prefix']:
aa452ee9 1939 # Only use PREFIX as a string with raw_input
c285decf 1940 line = raw_input(g['decorated_name'](g['PREFIX']))
39b8e6b3
O
1941 else:
1942 line = raw_input()
1943 # Save cmd to compare with readline buffer
1944 g['cmd'] = line.strip()
1945 # Get short cmd to pass to handle function
1946 try:
1947 cmd = line.split()[0]
1948 except:
1949 cmd = ''
9683e61d 1950 # Lock the semaphore
99b52f5f 1951 c['lock'] = True
9683e61d 1952 # Save cmd to global variable and call process
b8c1f42a 1953 g['stuff'] = ' '.join(line.split()[1:])
9683e61d 1954 # Process the command
b8c1f42a 1955 process(cmd)()
9683e61d 1956 # Not re-display
99b52f5f 1957 if cmd in ['switch', 't', 'rt', 'rep']:
9683e61d
O
1958 g['prefix'] = False
1959 else:
1960 g['prefix'] = True
1961 # Release the semaphore lock
99b52f5f 1962 c['lock'] = False
39b8e6b3
O
1963 except EOFError:
1964 printNicely('')
eadd85a8 1965 except Exception:
7a8a52fc 1966 debug_option()
b8c1f42a 1967 printNicely(red('OMG something is wrong with Twitter right now.'))
ee444288 1968
54277114 1969
47cee703
O
1970def reconn_notice():
1971 """
1972 Notice when Hangup or Timeout
1973 """
1974 guide = light_magenta("You can use ") + \
1975 light_green("switch") + \
1976 light_magenta(" command to return to your stream.\n")
1977 guide += light_magenta("Type ") + \
1978 light_green("h stream") + \
1979 light_magenta(" for more details.")
1980 printNicely(guide)
211e8be1 1981 sys.stdout.write(g['decorated_name'](g['PREFIX']))
47cee703
O
1982 sys.stdout.flush()
1983
1984
42fde775 1985def stream(domain, args, name='Rainbow Stream'):
54277114 1986 """
f405a7d0 1987 Track the stream
54277114 1988 """
54277114 1989 # The Logo
42fde775 1990 art_dict = {
632c6fa5
O
1991 c['USER_DOMAIN']: name,
1992 c['PUBLIC_DOMAIN']: args.track_keywords,
1f2f6159 1993 c['SITE_DOMAIN']: name,
42fde775 1994 }
687567eb 1995 if c['ASCII_ART']:
c075e6dc 1996 ascii_art(art_dict[domain])
91476ec3
O
1997 # These arguments are optional:
1998 stream_args = dict(
e3927852 1999 timeout=0.5, # To check g['stream_stop'] after each 0.5 s
cb45dc23 2000 block=True,
2001 heartbeat_timeout=c['HEARTBEAT_TIMEOUT'] * 60)
91476ec3
O
2002 # Track keyword
2003 query_args = dict()
2004 if args.track_keywords:
2005 query_args['track'] = args.track_keywords
91476ec3 2006 # Get stream
2a6238f5 2007 stream = TwitterStream(
22be990e 2008 auth=authen(),
42fde775 2009 domain=domain,
2a6238f5 2010 **stream_args)
2a0cabee
O
2011 try:
2012 if domain == c['USER_DOMAIN']:
2013 tweet_iter = stream.user(**query_args)
2014 elif domain == c['SITE_DOMAIN']:
2015 tweet_iter = stream.site(**query_args)
42fde775 2016 else:
2a0cabee
O
2017 if args.track_keywords:
2018 tweet_iter = stream.statuses.filter(**query_args)
2019 else:
2020 tweet_iter = stream.statuses.sample()
92983945
BS
2021 # Block new stream until other one exits
2022 StreamLock.acquire()
2023 g['stream_stop'] = False
e53e2c70 2024 last_tweet_time = time.time()
72c02928
VNM
2025 for tweet in tweet_iter:
2026 if tweet is None:
a1222228 2027 printNicely("-- None --")
72c02928 2028 elif tweet is Timeout:
47cee703
O
2029 # Because the stream check for each 0.3s
2030 # so we shouldn't output anything here
335e7803
O
2031 if(g['stream_stop']):
2032 StreamLock.release()
2033 break
72c02928
VNM
2034 elif tweet is HeartbeatTimeout:
2035 printNicely("-- Heartbeat Timeout --")
47cee703 2036 reconn_notice()
8715dda0
O
2037 StreamLock.release()
2038 break
72c02928
VNM
2039 elif tweet is Hangup:
2040 printNicely("-- Hangup --")
47cee703
O
2041 reconn_notice()
2042 StreamLock.release()
2043 break
72c02928 2044 elif tweet.get('text'):
84b41f58
O
2045 # Slow down the stream by STREAM_DELAY config key
2046 if time.time() - last_tweet_time < c['STREAM_DELAY']:
2047 continue
2048 last_tweet_time = time.time()
2049 # Check the semaphore pause and lock (stream process only)
2050 if g['pause']:
2051 continue
2052 while c['lock']:
2053 time.sleep(0.5)
2054 # Draw the tweet
2055 draw(
2056 t=tweet,
2057 keyword=args.track_keywords,
2058 humanize=False,
2059 fil=args.filter,
2060 ig=args.ignore,
2061 )
2062 # Current readline buffer
2063 current_buffer = readline.get_line_buffer().strip()
2064 # There is an unexpected behaviour in MacOSX readline + Python 2:
2065 # after completely delete a word after typing it,
2066 # somehow readline buffer still contains
2067 # the 1st character of that word
2068 if current_buffer and g['cmd'] != current_buffer:
2069 sys.stdout.write(
211e8be1 2070 g['decorated_name'](g['PREFIX']) + current_buffer)
84b41f58
O
2071 sys.stdout.flush()
2072 elif not c['HIDE_PROMPT']:
211e8be1 2073 sys.stdout.write(g['decorated_name'](g['PREFIX']))
84b41f58 2074 sys.stdout.flush()
14db58c7 2075 elif tweet.get('direct_message'):
4dc385b5
O
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 print_message(tweet['direct_message'])
99cd1fba 2082 elif tweet.get('event'):
d7d9c67c 2083 c['events'].append(tweet)
99cd1fba 2084 print_event(tweet)
742266f8 2085 except TwitterHTTPError as e:
2a0cabee 2086 printNicely('')
c075e6dc 2087 printNicely(
9e38891f 2088 magenta("We have connection problem with twitter'stream API right now :("))
2089 detail_twitter_error(e)
211e8be1 2090 sys.stdout.write(g['decorated_name'](g['PREFIX']))
62058715 2091 sys.stdout.flush()
54277114
O
2092
2093
2094def fly():
2095 """
2096 Main function
2097 """
531f5682 2098 # Initial
42fde775 2099 args = parse_arguments()
2a0cabee 2100 try:
a65129d4 2101 proxy_connect(args)
fe9bb33b 2102 init(args)
a65129d4 2103 # Twitter API connection problem
742266f8 2104 except TwitterHTTPError as e:
2a0cabee
O
2105 printNicely('')
2106 printNicely(
9e38891f 2107 magenta("We have connection problem with twitter'REST API right now :("))
2108 detail_twitter_error(e)
2a0cabee 2109 save_history()
2a0cabee 2110 sys.exit()
a65129d4
O
2111 # Proxy connection problem
2112 except (socks.ProxyConnectionError, URLError):
c426a344 2113 printNicely(
2114 magenta("There seems to be a connection problem."))
2115 printNicely(
2116 magenta("You might want to check your proxy settings (host, port and type)!"))
2117 save_history()
2118 sys.exit()
2119
92983945 2120 # Spawn stream thread
baec5f50 2121 th = threading.Thread(
2122 target=stream,
2123 args=(
2124 c['USER_DOMAIN'],
2125 args,
2126 g['original_name']))
92983945
BS
2127 th.daemon = True
2128 th.start()
42fde775 2129 # Start listen process
819569e8 2130 time.sleep(0.5)
c91f75f2 2131 g['reset'] = True
1dd312f5 2132 g['prefix'] = True
0f6e4daf 2133 listen()