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