X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=blobdiff_plain;f=rainbowstream%2Frainbow.py;h=53fcd639f4ef2b83929f899fa74a53a8d8c3b879;hp=598d367b70dafdea73be36b1eae16555f3080c08;hb=bb68c6872988e8bcb1f125dc86dba67ceb8a1415;hpb=a8e71259e8f1b8bee68a3f85211517de336008a1 diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index 598d367..53fcd63 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -1,6 +1,3 @@ -""" -Colorful user's timeline stream -""" import os import os.path import sys @@ -10,7 +7,12 @@ import time import threading import requests import webbrowser +import traceback +import pkg_resources +import socks +import socket +from io import BytesIO from twitter.stream import TwitterStream, Timeout, HeartbeatTimeout, Hangup from twitter.api import * from twitter.oauth import OAuth, read_token_file @@ -24,6 +26,8 @@ from .consumer import * from .interactive import * from .c_image import * from .py3patch import * +from .emoji import * +from .util import * # Global values g = {} @@ -31,69 +35,21 @@ g = {} # Lock for streams StreamLock = threading.Lock() -# Commands -cmdset = [ - 'switch', - 'trend', - 'home', - 'view', - 'mentions', - 't', - 'rt', - 'quote', - 'allrt', - 'fav', - 'rep', - 'del', - 'ufav', - 's', - 'mes', - 'show', - 'open', - 'ls', - 'inbox', - 'sent', - 'trash', - 'whois', - 'fl', - 'ufl', - 'mute', - 'unmute', - 'muting', - 'block', - 'unblock', - 'report', - 'list', - 'cal', - 'config', - 'theme', - 'h', - 'p', - 'r', - 'c', - 'q' -] - def parse_arguments(): """ Parse the arguments """ parser = argparse.ArgumentParser(description=__doc__ or "") + parser.add_argument( + '-s', + '--stream', + default="mine", + help='Default stream after program start. (Default: mine)') parser.add_argument( '-to', '--timeout', help='Timeout for the stream (seconds).') - parser.add_argument( - '-ht', - '--heartbeat-timeout', - help='Set heartbeat timeout.', - default=90) - parser.add_argument( - '-nb', - '--no-block', - action='store_true', - help='Set stream to non-blocking.') parser.add_argument( '-tt', '--track-keywords', @@ -111,9 +67,48 @@ def parse_arguments(): '--image-on-term', action='store_true', help='Display all image on terminal.') + parser.add_argument( + '-ph', + '--proxy-host', + help='Use HTTP/SOCKS proxy for network connections.') + parser.add_argument( + '-pp', + '--proxy-port', + default=8080, + help='HTTP/SOCKS proxy port (Default: 8080).') + parser.add_argument( + '-pt', + '--proxy-type', + default='SOCKS5', + help='Proxy type (HTTP, SOCKS4, SOCKS5; Default: SOCKS5).') return parser.parse_args() +def proxy_connect(args): + """ + Connect to specified proxy + """ + if args.proxy_host: + # Setup proxy by monkeypatching the standard lib + if args.proxy_type.lower() == "socks5" or not args.proxy_type: + socks.set_default_proxy( + socks.SOCKS5, args.proxy_host, + int(args.proxy_port)) + elif args.proxy_type.lower() == "http": + socks.set_default_proxy( + socks.HTTP, args.proxy_host, + int(args.proxy_port)) + elif args.proxy_type.lower() == "socks4": + socks.set_default_proxy( + socks.SOCKS4, args.proxy_host, + int(args.proxy_port)) + else: + printNicely( + magenta('Sorry, wrong proxy type specified! Aborting...')) + sys.exit() + socket.socket = socks.socksocket + + def authen(): """ Authenticate with Twitter OAuth @@ -125,7 +120,7 @@ def authen(): 'USERPROFILE', '')) + os.sep + '.rainbow_oauth' if not os.path.exists(twitter_credential): - oauth_dance("Rainbow Stream", + oauth_dance('Rainbow Stream', CONSUMER_KEY, CONSUMER_SECRET, twitter_credential) @@ -137,6 +132,67 @@ def authen(): CONSUMER_SECRET) +def build_mute_dict(dict_data=False): + """ + Build muting list + """ + t = Twitter(auth=authen()) + # Init cursor + next_cursor = -1 + screen_name_list = [] + name_list = [] + # Cursor loop + while next_cursor != 0: + list = t.mutes.users.list( + screen_name=g['original_name'], + cursor=next_cursor, + skip_status=True, + include_entities=False, + ) + screen_name_list += ['@' + u['screen_name'] for u in list['users']] + name_list += [u['name'] for u in list['users']] + next_cursor = list['next_cursor'] + # Return dict or list + if dict_data: + return dict(zip(screen_name_list, name_list)) + else: + return screen_name_list + + +def debug_option(): + """ + Save traceback when run in debug mode + """ + if g['debug']: + g['traceback'].append(traceback.format_exc()) + + +def upgrade_center(): + """ + Check latest and notify to upgrade + """ + try: + current = pkg_resources.get_distribution('rainbowstream').version + url = 'https://raw.githubusercontent.com/DTVD/rainbowstream/master/setup.py' + readme = requests.get(url).text + latest = readme.split('version = \'')[1].split('\'')[0] + if current != latest: + notice = light_magenta('RainbowStream latest version is ') + notice += light_green(latest) + notice += light_magenta(' while your current version is ') + notice += light_yellow(current) + '\n' + notice += light_magenta('You should upgrade with ') + notice += light_green('pip install -U rainbowstream') + printNicely(notice) + else: + notice = light_yellow('You are running latest version (') + notice += light_green(current) + notice += light_yellow(')') + printNicely(notice) + except: + pass + + def init(args): """ Init function @@ -144,90 +200,49 @@ def init(args): # Handle Ctrl C ctrl_c_handler = lambda signum, frame: quit() signal.signal(signal.SIGINT, ctrl_c_handler) + # Upgrade notify + upgrade_center() # Get name t = Twitter(auth=authen()) - name = '@' + t.account.verify_credentials()['screen_name'] - if not get_config('PREFIX'): - set_config('PREFIX', name) - g['original_name'] = name[1:] + credential = t.account.verify_credentials() + screen_name = '@' + credential['screen_name'] + name = credential['name'] + c['original_name'] = g['original_name'] = screen_name[1:] + g['listname'] = g['keyword'] = '' + g['PREFIX'] = u2str(emojize(format_prefix())) + g['full_name'] = name g['decorated_name'] = lambda x: color_func( - c['DECORATED_NAME'])('[' + x + ']: ') + c['DECORATED_NAME'])('[' + x + ']: ', rl=True) # Theme init files = os.listdir(os.path.dirname(__file__) + '/colorset') themes = [f.split('.')[0] for f in files if f.split('.')[-1] == 'json'] g['themes'] = themes + g['pause'] = False + g['message_threads'] = {} # Startup cmd - g['previous_cmd'] = '' + g['cmd'] = '' + # Debug option default = True + g['debug'] = True + g['traceback'] = [] + # Events + c['events'] = [] # Semaphore init c['lock'] = False - c['pause'] = False # Init tweet dict and message dict c['tweet_dict'] = [] c['message_dict'] = [] # Image on term c['IMAGE_ON_TERM'] = args.image_on_term - set_config('IMAGE_ON_TERM',str(c['IMAGE_ON_TERM'])) - - -def switch(): - """ - Switch stream - """ - try: - target = g['stuff'].split()[0] - # Filter and ignore - args = parse_arguments() - try: - if g['stuff'].split()[-1] == '-f': - guide = 'To ignore an option, just hit Enter key.' - printNicely(light_magenta(guide)) - only = raw_input('Only nicks [Ex: @xxx,@yy]: ') - ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ') - args.filter = filter(None, only.split(',')) - args.ignore = filter(None, ignore.split(',')) - elif g['stuff'].split()[-1] == '-d': - args.filter = c['ONLY_LIST'] - args.ignore = c['IGNORE_LIST'] - except: - printNicely(red('Sorry, wrong format.')) - return - # Public stream - if target == 'public': - keyword = g['stuff'].split()[1] - if keyword[0] == '#': - keyword = keyword[1:] - # Kill old thread - g['stream_stop'] = True - args.track_keywords = keyword - # Start new thread - th = threading.Thread( - target=stream, - args=( - c['PUBLIC_DOMAIN'], - args)) - th.daemon = True - th.start() - # Personal stream - elif target == 'mine': - # Kill old thread - g['stream_stop'] = True - # Start new thread - th = threading.Thread( - target=stream, - args=( - c['USER_DOMAIN'], - args, - g['original_name'])) - th.daemon = True - th.start() - printNicely('') - if args.filter: - printNicely(cyan('Only: ' + str(args.filter))) - if args.ignore: - printNicely(red('Ignore: ' + str(args.ignore))) - printNicely('') - except: - printNicely(red('Sorry I can\'t understand.')) + set_config('IMAGE_ON_TERM', str(c['IMAGE_ON_TERM'])) + # Check type of ONLY_LIST and IGNORE_LIST + if not isinstance(c['ONLY_LIST'], list): + printNicely(red('ONLY_LIST is not a valid list value.')) + c['ONLY_LIST'] = [] + if not isinstance(c['IGNORE_LIST'], list): + printNicely(red('IGNORE_LIST is not a valid list value.')) + c['IGNORE_LIST'] = [] + # Mute dict + c['IGNORE_LIST'] += build_mute_dict() def trend(): @@ -279,35 +294,106 @@ def home(): printNicely('') +def notification(): + """ + Show notifications + """ + if c['events']: + for e in c['events']: + print_event(e) + printNicely('') + else: + printNicely(magenta('Nothing at this time.')) + + +def mentions(): + """ + Mentions timeline + """ + t = Twitter(auth=authen()) + num = c['HOME_TWEET_NUM'] + if g['stuff'].isdigit(): + num = int(g['stuff']) + for tweet in reversed(t.statuses.mentions_timeline(count=num)): + draw(t=tweet) + printNicely('') + + +def whois(): + """ + Show profile of a specific user + """ + t = Twitter(auth=authen()) + try: + screen_name = g['stuff'].split()[0] + except: + printNicely(red('Sorry I can\'t understand.')) + return + if screen_name.startswith('@'): + try: + user = t.users.show( + screen_name=screen_name[1:], + include_entities=False) + show_profile(user) + except: + debug_option() + printNicely(red('No user.')) + else: + printNicely(red('A name should begin with a \'@\'')) + + def view(): """ Friend view """ t = Twitter(auth=authen()) - user = g['stuff'].split()[0] + try: + user = g['stuff'].split()[0] + except: + printNicely(red('Sorry I can\'t understand.')) + return if user[0] == '@': try: num = int(g['stuff'].split()[1]) except: num = c['HOME_TWEET_NUM'] - for tweet in reversed(t.statuses.user_timeline(count=num, screen_name=user[1:])): + for tweet in reversed( + t.statuses.user_timeline(count=num, screen_name=user[1:])): draw(t=tweet) printNicely('') else: printNicely(red('A name should begin with a \'@\'')) -def mentions(): +def search(): """ - Mentions timeline + Search """ t = Twitter(auth=authen()) - num = c['HOME_TWEET_NUM'] - if g['stuff'].isdigit(): - num = int(g['stuff']) - for tweet in reversed(t.statuses.mentions_timeline(count=num)): - draw(t=tweet) - printNicely('') + # Setup query + query = g['stuff'].strip() + if not query: + printNicely(red('Sorry I can\'t understand.')) + return + type = c['SEARCH_TYPE'] + if type not in ['mixed', 'recent', 'popular']: + type = 'mixed' + max_record = c['SEARCH_MAX_RECORD'] + count = min(max_record, 100) + # Perform search + rel = t.search.tweets( + q=query, + type=type, + count=count + )['statuses'] + # Return results + if rel: + printNicely('Newest tweets:') + for i in reversed(xrange(count)): + draw(t=rel[i], keyword=query) + printNicely('') + else: + printNicely(magenta('I\'m afraid there is no result')) def tweet(): @@ -336,6 +422,7 @@ def quote(): """ Quote a tweet """ + # Get tweet t = Twitter(auth=authen()) try: id = int(g['stuff'].split()[0]) @@ -344,17 +431,17 @@ def quote(): return tid = c['tweet_dict'][id] tweet = t.statuses.show(id=tid) - screen_name = tweet['user']['screen_name'] - text = tweet['text'] - quote = '\"@' + screen_name + ': ' + text + '\"' - quote = quote.encode('utf8') - notice = light_magenta('Compose mode ') - notice += light_yellow('(Enter nothing will cancel the quote)') - notice += light_magenta(':') - printNicely(notice) - extra = raw_input(quote) - if extra: - t.statuses.update(status=quote + extra) + # Get formater + formater = format_quote(tweet) + if not formater: + return + # Get comment + prefix = light_magenta('Compose your ', rl=True) + \ + light_green('#comment: ', rl=True) + comment = raw_input(prefix) + if comment: + quote = comment.join(formater.split('#comment')) + t.statuses.update(status=quote) else: printNicely(light_magenta('No text added.')) @@ -386,9 +473,9 @@ def allretweet(): printNicely('') -def favorite(): +def conversation(): """ - Favorite + Conversation view """ t = Twitter(auth=authen()) try: @@ -397,9 +484,19 @@ def favorite(): printNicely(red('Sorry I can\'t understand.')) return tid = c['tweet_dict'][id] - t.favorites.create(_id=tid, include_entities=False) - printNicely(green('Favorited.')) - draw(t.statuses.show(id=tid)) + tweet = t.statuses.show(id=tid) + limit = c['CONVERSATION_MAX'] + thread_ref = [] + thread_ref.append(tweet) + prev_tid = tweet['in_reply_to_status_id'] + while prev_tid and limit: + limit -= 1 + tweet = t.statuses.show(id=prev_tid) + prev_tid = tweet['in_reply_to_status_id'] + thread_ref.append(tweet) + + for tweet in reversed(thread_ref): + draw(t=tweet) printNicely('') @@ -416,13 +513,13 @@ def reply(): tid = c['tweet_dict'][id] user = t.statuses.show(id=tid)['user']['screen_name'] status = ' '.join(g['stuff'].split()[1:]) - status = '@' + user + ' ' + status.decode('utf-8') + status = '@' + user + ' ' + str2u(status) t.statuses.update(status=status, in_reply_to_status_id=tid) -def delete(): +def reply_all(): """ - Delete + Reply to all """ t = Twitter(auth=authen()) try: @@ -431,8 +528,33 @@ def delete(): printNicely(red('Sorry I can\'t understand.')) return tid = c['tweet_dict'][id] - t.statuses.destroy(id=tid) - printNicely(green('Okay it\'s gone.')) + original_tweet = t.statuses.show(id=tid) + text = original_tweet['text'] + nick_ary = [original_tweet['user']['screen_name']] + for user in list(original_tweet['entities']['user_mentions']): + if user['screen_name'] not in nick_ary \ + and user['screen_name'] != g['original_name']: + nick_ary.append(user['screen_name']) + status = ' '.join(g['stuff'].split()[1:]) + status = ' '.join(['@' + nick for nick in nick_ary]) + ' ' + str2u(status) + t.statuses.update(status=status, in_reply_to_status_id=tid) + + +def favorite(): + """ + Favorite + """ + t = Twitter(auth=authen()) + try: + id = int(g['stuff'].split()[0]) + except: + printNicely(red('Sorry I can\'t understand.')) + return + tid = c['tweet_dict'][id] + t.favorites.create(_id=tid, include_entities=False) + printNicely(green('Favorited.')) + draw(t.statuses.show(id=tid)) + printNicely('') def unfavorite(): @@ -452,41 +574,41 @@ def unfavorite(): printNicely('') -def search(): +def share(): """ - Search + Copy url of a tweet to clipboard """ t = Twitter(auth=authen()) - g['stuff'] = g['stuff'].strip() - rel = t.search.tweets(q=g['stuff'])['statuses'] - if rel: - printNicely('Newest tweets:') - for i in reversed(xrange(c['SEARCH_MAX_RECORD'])): - draw(t=rel[i], - keyword=g['stuff']) - printNicely('') + try: + id = int(g['stuff'].split()[0]) + tid = c['tweet_dict'][id] + except: + printNicely(red('Tweet id is not valid.')) + return + tweet = t.statuses.show(id=tid) + url = 'https://twitter.com/' + \ + tweet['user']['screen_name'] + '/status/' + str(tid) + import platform + if platform.system().lower() == 'darwin': + os.system("echo '%s' | pbcopy" % url) + printNicely(green('Copied tweet\'s url to clipboard.')) else: - printNicely(magenta('I\'m afraid there is no result')) + printNicely('Direct link: ' + yellow(url)) -def message(): +def delete(): """ - Send a direct message + Delete """ t = Twitter(auth=authen()) - user = g['stuff'].split()[0] - if user[0].startswith('@'): - try: - content = g['stuff'].split()[1] - except: - printNicely(red('Sorry I can\'t understand.')) - t.direct_messages.new( - screen_name=user[1:], - text=content - ) - printNicely(green('Message sent.')) - else: - printNicely(red('A name should begin with a \'@\'')) + try: + id = int(g['stuff'].split()[0]) + except: + printNicely(red('Sorry I can\'t understand.')) + return + tid = c['tweet_dict'][id] + t.statuses.destroy(id=tid) + printNicely(green('Okay it\'s gone.')) def show(): @@ -507,6 +629,7 @@ def show(): img = Image.open(BytesIO(res.content)) img.show() except: + debug_option() printNicely(red('Sorry I can\'t show this image.')) @@ -520,73 +643,32 @@ def urlopen(): return tid = c['tweet_dict'][int(g['stuff'])] tweet = t.statuses.show(id=tid) - link_ary = [ - u for u in tweet['text'].split() if u.startswith('http://')] + link_prefix = ('http://', 'https://') + link_ary = [u for u in tweet['text'].split() + if u.startswith(link_prefix)] if not link_ary: printNicely(light_magenta('No url here @.@!')) return for link in link_ary: webbrowser.open(link) except: + debug_option() printNicely(red('Sorry I can\'t open url in this tweet.')) -def ls(): - """ - List friends for followers - """ - t = Twitter(auth=authen()) - # Get name - try: - name = g['stuff'].split()[1] - if name.startswith('@'): - name = name[1:] - else: - printNicely(red('A name should begin with a \'@\'')) - raise Exception('Invalid name') - except: - name = g['original_name'] - # Get list followers or friends - try: - target = g['stuff'].split()[0] - except: - printNicely(red('Omg some syntax is wrong.')) - # Init cursor - d = {'fl': 'followers', 'fr': 'friends'} - next_cursor = -1 - rel = {} - # Cursor loop - while next_cursor != 0: - list = getattr(t, d[target]).list( - screen_name=name, - cursor=next_cursor, - skip_status=True, - include_entities=False, - ) - for u in list['users']: - rel[u['name']] = '@' + u['screen_name'] - next_cursor = list['next_cursor'] - # Print out result - printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.') - for name in rel: - user = ' ' + cycle_color(name) - user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') - printNicely(user) - - def inbox(): """ - Inbox direct messages + Inbox threads """ t = Twitter(auth=authen()) num = c['MESSAGES_DISPLAY'] - rel = [] if g['stuff'].isdigit(): num = g['stuff'] + # Get inbox messages cur_page = 1 - # Max message per page is 20 so we have to loop + inbox = [] while num > 20: - rel = rel + t.direct_messages( + inbox = inbox + t.direct_messages( count=20, page=cur_page, include_entities=False, @@ -594,32 +676,20 @@ def inbox(): ) num -= 20 cur_page += 1 - rel = rel + t.direct_messages( + inbox = inbox + t.direct_messages( count=num, page=cur_page, include_entities=False, skip_status=False ) - # Display - printNicely('Inbox: newest ' + str(len(rel)) + ' messages.') - for m in reversed(rel): - print_message(m) - printNicely('') - - -def sent(): - """ - Sent direct messages - """ - t = Twitter(auth=authen()) + # Get sent messages num = c['MESSAGES_DISPLAY'] - rel = [] if g['stuff'].isdigit(): - num = int(g['stuff']) + num = g['stuff'] cur_page = 1 - # Max message per page is 20 so we have to loop + sent = [] while num > 20: - rel = rel + t.direct_messages.sent( + sent = sent + t.direct_messages.sent( count=20, page=cur_page, include_entities=False, @@ -627,17 +697,66 @@ def sent(): ) num -= 20 cur_page += 1 - rel = rel + t.direct_messages.sent( + sent = sent + t.direct_messages.sent( count=num, page=cur_page, include_entities=False, skip_status=False ) - # Display - printNicely('Sent: newest ' + str(len(rel)) + ' messages.') - for m in reversed(rel): - print_message(m) - printNicely('') + + d = {} + uniq_inbox = list(set( + [(m['sender_screen_name'], m['sender']['name']) for m in inbox] + )) + uniq_sent = list(set( + [(m['recipient_screen_name'], m['recipient']['name']) for m in sent] + )) + for partner in uniq_inbox: + inbox_ary = [m for m in inbox if m['sender_screen_name'] == partner[0]] + sent_ary = [ + m for m in sent if m['recipient_screen_name'] == partner[0]] + d[partner] = inbox_ary + sent_ary + for partner in uniq_sent: + if partner not in d: + d[partner] = [ + m for m in sent if m['recipient_screen_name'] == partner[0]] + g['message_threads'] = print_threads(d) + + +def thread(): + """ + View a thread of message + """ + try: + thread_id = int(g['stuff']) + print_thread( + g['message_threads'][thread_id], + g['original_name'], + g['full_name']) + except Exception: + debug_option() + printNicely(red('No such thread.')) + + +def message(): + """ + Send a direct message + """ + t = Twitter(auth=authen()) + try: + user = g['stuff'].split()[0] + if user[0].startswith('@'): + content = ' '.join(g['stuff'].split()[1:]) + t.direct_messages.new( + screen_name=user[1:], + text=content + ) + printNicely(green('Message sent.')) + else: + printNicely(red('A name should begin with a \'@\'')) + except: + debug_option() + printNicely(red('Sorry I can\'t understand.')) def trash(): @@ -654,22 +773,48 @@ def trash(): printNicely(green('Message deleted.')) -def whois(): +def ls(): """ - Show profile of a specific user + List friends for followers """ t = Twitter(auth=authen()) - screen_name = g['stuff'].split()[0] - if screen_name.startswith('@'): - try: - user = t.users.show( - screen_name=screen_name[1:], - include_entities=False) - show_profile(user) - except: - printNicely(red('Omg no user.')) - else: - printNicely(red('A name should begin with a \'@\'')) + # Get name + try: + name = g['stuff'].split()[1] + if name.startswith('@'): + name = name[1:] + else: + printNicely(red('A name should begin with a \'@\'')) + raise Exception('Invalid name') + except: + name = g['original_name'] + # Get list followers or friends + try: + target = g['stuff'].split()[0] + except: + printNicely(red('Omg some syntax is wrong.')) + return + # Init cursor + d = {'fl': 'followers', 'fr': 'friends'} + next_cursor = -1 + rel = {} + # Cursor loop + while next_cursor != 0: + list = getattr(t, d[target]).list( + screen_name=name, + cursor=next_cursor, + skip_status=True, + include_entities=False, + ) + for u in list['users']: + rel[u['name']] = '@' + u['screen_name'] + next_cursor = list['next_cursor'] + # Print out result + printNicely('All: ' + str(len(rel)) + ' ' + d[target] + '.') + for name in rel: + user = ' ' + cycle_color(name) + user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') + printNicely(user) def follow(): @@ -711,11 +856,17 @@ def mute(): printNicely(red('A name should be specified. ')) return if screen_name.startswith('@'): - rel = t.mutes.users.create(screen_name=screen_name[1:]) - if isinstance(rel, dict): - printNicely(green(screen_name + ' is muted.')) - else: - printNicely(red(rel)) + try: + rel = t.mutes.users.create(screen_name=screen_name[1:]) + if isinstance(rel, dict): + printNicely(green(screen_name + ' is muted.')) + c['IGNORE_LIST'] += [unc(screen_name)] + c['IGNORE_LIST'] = list(set(c['IGNORE_LIST'])) + else: + printNicely(red(rel)) + except: + debug_option() + printNicely(red('Something is wrong, can not mute now :(')) else: printNicely(red('A name should begin with a \'@\'')) @@ -731,11 +882,15 @@ def unmute(): printNicely(red('A name should be specified. ')) return if screen_name.startswith('@'): - rel = t.mutes.users.destroy(screen_name=screen_name[1:]) - if isinstance(rel, dict): - printNicely(green(screen_name + ' is unmuted.')) - else: - printNicely(red(rel)) + try: + rel = t.mutes.users.destroy(screen_name=screen_name[1:]) + if isinstance(rel, dict): + printNicely(green(screen_name + ' is unmuted.')) + c['IGNORE_LIST'].remove(screen_name) + else: + printNicely(red(rel)) + except: + printNicely(red('Maybe you are not muting this person ?')) else: printNicely(red('A name should begin with a \'@\'')) @@ -744,27 +899,15 @@ def muting(): """ List muting user """ - t = Twitter(auth=authen()) - # Init cursor - next_cursor = -1 - rel = {} - # Cursor loop - while next_cursor != 0: - list = t.mutes.users.list( - screen_name=g['original_name'], - cursor=next_cursor, - skip_status=True, - include_entities=False, - ) - for u in list['users']: - rel[u['name']] = '@' + u['screen_name'] - next_cursor = list['next_cursor'] - # Print out result - printNicely('All: ' + str(len(rel)) + ' people.') - for name in rel: - user = ' ' + cycle_color(name) - user += color_func(c['TWEET']['nick'])(' ' + rel[name] + ' ') + # Get dict of muting users + md = build_mute_dict(dict_data=True) + printNicely('All: ' + str(len(md)) + ' people.') + for name in md: + user = ' ' + cycle_color(md[name]) + user += color_func(c['TWEET']['nick'])(' ' + name + ' ') printNicely(user) + # Update from Twitter + c['IGNORE_LIST'] = [n for n in md] def block(): @@ -815,10 +958,27 @@ def report(): def get_slug(): """ - Get Slug Decorator + Get slug """ # Get list name - list_name = raw_input(light_magenta('Give me the list\'s name: ')) + list_name = raw_input( + light_magenta('Give me the list\'s name ("@owner/list_name"): ', rl=True)) + # Get list name and owner + try: + owner, slug = list_name.split('/') + if slug.startswith('@'): + slug = slug[1:] + return owner, slug + except: + printNicely( + light_magenta('List name should follow "@owner/list_name" format.')) + raise Exception('Wrong list name') + + +def check_slug(list_name): + """ + Check slug + """ # Get list name and owner try: owner, slug = list_name.split('/') @@ -852,7 +1012,7 @@ def list_home(t): owner_screen_name=owner, count=c['LIST_MAX'], include_entities=False) - for tweet in res: + for tweet in reversed(res): draw(t=tweet) printNicely('') @@ -911,7 +1071,10 @@ def list_add(t): """ owner, slug = get_slug() # Add - user_name = raw_input(light_magenta('Give me name of the newbie: ')) + user_name = raw_input( + light_magenta( + 'Give me name of the newbie: ', + rl=True)) if user_name.startswith('@'): user_name = user_name[1:] try: @@ -921,6 +1084,7 @@ def list_add(t): screen_name=user_name) printNicely(green('Added.')) except: + debug_option() printNicely(light_magenta('I\'m sorry we can not add him/her.')) @@ -930,7 +1094,10 @@ def list_remove(t): """ owner, slug = get_slug() # Remove - user_name = raw_input(light_magenta('Give me name of the unlucky one: ')) + user_name = raw_input( + light_magenta( + 'Give me name of the unlucky one: ', + rl=True)) if user_name.startswith('@'): user_name = user_name[1:] try: @@ -940,6 +1107,7 @@ def list_remove(t): screen_name=user_name) printNicely(green('Gone.')) except: + debug_option() printNicely(light_magenta('I\'m sorry we can not remove him/her.')) @@ -955,6 +1123,7 @@ def list_subscribe(t): owner_screen_name=owner) printNicely(green('Done.')) except: + debug_option() printNicely( light_magenta('I\'m sorry you can not subscribe to this list.')) @@ -971,6 +1140,7 @@ def list_unsubscribe(t): owner_screen_name=owner) printNicely(green('Done.')) except: + debug_option() printNicely( light_magenta('I\'m sorry you can not unsubscribe to this list.')) @@ -997,9 +1167,15 @@ def list_new(t): """ Create a new list """ - name = raw_input(light_magenta('New list\'s name: ')) - mode = raw_input(light_magenta('New list\'s mode (public/private): ')) - description = raw_input(light_magenta('New list\'s description: ')) + name = raw_input(light_magenta('New list\'s name: ', rl=True)) + mode = raw_input( + light_magenta( + 'New list\'s mode (public/private): ', + rl=True)) + description = raw_input( + light_magenta( + 'New list\'s description: ', + rl=True)) try: t.lists.create( name=name, @@ -1007,6 +1183,7 @@ def list_new(t): description=description) printNicely(green(name + ' list is created.')) except: + debug_option() printNicely(red('Oops something is wrong with Twitter :(')) @@ -1014,10 +1191,16 @@ def list_update(t): """ Update a list """ - slug = raw_input(light_magenta('Your list that you want to update: ')) - name = raw_input(light_magenta('Update name (leave blank to unchange): ')) - mode = raw_input(light_magenta('Update mode (public/private): ')) - description = raw_input(light_magenta('Update description: ')) + slug = raw_input( + light_magenta( + 'Your list that you want to update: ', + rl=True)) + name = raw_input( + light_magenta( + 'Update name (leave blank to unchange): ', + rl=True)) + mode = raw_input(light_magenta('Update mode (public/private): ', rl=True)) + description = raw_input(light_magenta('Update description: ', rl=True)) try: if name: t.lists.update( @@ -1034,6 +1217,7 @@ def list_update(t): description=description) printNicely(green(slug + ' list is updated.')) except: + debug_option() printNicely(red('Oops something is wrong with Twitter :(')) @@ -1041,17 +1225,21 @@ def list_delete(t): """ Delete a list """ - slug = raw_input(light_magenta('Your list that you want to update: ')) + slug = raw_input( + light_magenta( + 'Your list that you want to delete: ', + rl=True)) try: t.lists.destroy( slug='-'.join(slug.split()), owner_screen_name=g['original_name']) printNicely(green(slug + ' list is deleted.')) except: + debug_option() printNicely(red('Oops something is wrong with Twitter :(')) -def list(): +def twitterlist(): """ Twitter's list """ @@ -1082,6 +1270,43 @@ def list(): printNicely(red('Please try again.')) +def switch(): + """ + Switch stream + """ + try: + target = g['stuff'].split()[0] + # Filter and ignore + args = parse_arguments() + try: + if g['stuff'].split()[-1] == '-f': + guide = 'To ignore an option, just hit Enter key.' + printNicely(light_magenta(guide)) + only = raw_input('Only nicks [Ex: @xxx,@yy]: ') + ignore = raw_input('Ignore nicks [Ex: @xxx,@yy]: ') + args.filter = filter(None, only.split(',')) + args.ignore = filter(None, ignore.split(',')) + except: + printNicely(red('Sorry, wrong format.')) + return + # Kill old thread + g['stream_stop'] = True + try: + stuff = g['stuff'].split()[1] + except: + stuff = None + # Spawn new thread + spawn_dict = { + 'public': spawn_public_stream, + 'list': spawn_list_stream, + 'mine': spawn_personal_stream, + } + spawn_dict.get(target)(args, stuff) + except: + debug_option() + printNicely(red('Sorry I can\'t understand.')) + + def cal(): """ Unix's command `cal` @@ -1093,6 +1318,33 @@ def cal(): show_calendar(month, date, rel) +def theme(): + """ + List and change theme + """ + if not g['stuff']: + # List themes + for theme in g['themes']: + line = light_magenta(theme) + if c['THEME'] == theme: + line = ' ' * 2 + light_yellow('* ') + line + else: + line = ' ' * 4 + line + printNicely(line) + else: + # Change theme + try: + # Load new theme + c['THEME'] = reload_theme(g['stuff'], c['THEME']) + # Redefine decorated_name + g['decorated_name'] = lambda x: color_func( + c['DECORATED_NAME'])( + '[' + x + ']: ') + printNicely(green('Theme changed.')) + except: + printNicely(red('No such theme exists.')) + + def config(): """ Browse and change config @@ -1125,16 +1377,18 @@ def config(): value = get_default_config(key) line = ' ' * 2 + green(key) + ': ' + light_magenta(value) printNicely(line) - except Exception as e: - printNicely(red(e)) + except: + debug_option() + printNicely(red('Just can not get the default.')) # Delete specific config key in config file elif len(g['stuff'].split()) == 2 and g['stuff'].split()[-1] == 'drop': key = g['stuff'].split()[0] try: delete_config(key) printNicely(green('Config key is dropped.')) - except Exception as e: - printNicely(red(e)) + except: + debug_option() + printNicely(red('Just can not drop the key.')) # Set specific config elif len(g['stuff'].split()) == 3 and g['stuff'].split()[1] == '=': key = g['stuff'].split()[0] @@ -1144,46 +1398,25 @@ def config(): return try: set_config(key, value) - # Apply theme immediately + # Keys that needs to be apply immediately if key == 'THEME': c['THEME'] = reload_theme(value, c['THEME']) g['decorated_name'] = lambda x: color_func( c['DECORATED_NAME'])('[' + x + ']: ') + elif key == 'PREFIX': + g['PREFIX'] = u2str(emojize(format_prefix( + listname=g['listname'], + keyword=g['keyword'] + ))) reload_config() printNicely(green('Updated successfully.')) - except Exception as e: - printNicely(red(e)) + except: + debug_option() + printNicely(red('Just can not set the key.')) else: printNicely(light_magenta('Sorry I can\'s understand.')) -def theme(): - """ - List and change theme - """ - if not g['stuff']: - # List themes - for theme in g['themes']: - line = light_magenta(theme) - if c['THEME'] == theme: - line = ' ' * 2 + light_yellow('* ') + line - else: - line = ' ' * 4 + line - printNicely(line) - else: - # Change theme - try: - # Load new theme - c['THEME'] = reload_theme(g['stuff'], c['THEME']) - # Redefine decorated_name - g['decorated_name'] = lambda x: color_func( - c['DECORATED_NAME'])( - '[' + x + ']: ') - printNicely(green('Theme changed.')) - except: - printNicely(red('No such theme exists.')) - - def help_discover(): """ Discover the world @@ -1197,6 +1430,8 @@ def help_discover(): light_green('trend JP Tokyo') + '.\n' usage += s * 2 + light_green('home') + ' will show your timeline. ' + \ light_green('home 7') + ' will show 7 tweets.\n' + usage += s * 2 + \ + light_green('notification') + ' will show your recent notification.\n' usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \ light_green('mentions 7') + ' will show 7 mention tweets.\n' usage += s * 2 + light_green('whois @mdo') + ' will show profile of ' + \ @@ -1229,8 +1464,13 @@ def help_tweets(): usage += s * 2 + \ light_green('allrt 12 20 ') + ' will list 20 newest retweet of the tweet with ' + \ light_yellow('[id=12]') + '.\n' + usage += s * 2 + light_green('conversation 12') + ' will show the chain of ' + \ + 'replies prior to the tweet with ' + light_yellow('[id=12]') + '.\n' usage += s * 2 + light_green('rep 12 oops') + ' will reply "' + \ - light_yellow('oops') + '" to tweet with ' + \ + light_yellow('oops') + '" to the owner of the tweet with ' + \ + light_yellow('[id=12]') + '.\n' + usage += s * 2 + light_green('repall 12 oops') + ' will reply "' + \ + light_yellow('oops') + '" to all people in the tweet with ' + \ light_yellow('[id=12]') + '.\n' usage += s * 2 + \ light_green('fav 12 ') + ' will favorite the tweet with ' + \ @@ -1238,6 +1478,9 @@ def help_tweets(): usage += s * 2 + \ light_green('ufav 12 ') + ' will unfavorite tweet with ' + \ light_yellow('[id=12]') + '.\n' + usage += s * 2 + \ + light_green('share 12 ') + ' will get the direct link of the tweet with ' + \ + light_yellow('[id=12]') + '.\n' usage += s * 2 + \ light_green('del 12 ') + ' will delete tweet with ' + \ light_yellow('[id=12]') + '.\n' @@ -1258,8 +1501,8 @@ def help_messages(): usage += s + grey(u'\u266A' + ' Direct messages \n') usage += s * 2 + light_green('inbox') + ' will show inbox messages. ' + \ light_green('inbox 7') + ' will show newest 7 messages.\n' - usage += s * 2 + light_green('sent') + ' will show sent messages. ' + \ - light_green('sent 7') + ' will show newest 7 messages.\n' + usage += s * 2 + light_green('thread 2') + ' will show full thread with ' + \ + light_yellow('[thread_id=2]') + '.\n' usage += s * 2 + light_green('mes @dtvd88 hi') + ' will send a "hi" messege to ' + \ magenta('@dtvd88') + '.\n' usage += s * 2 + light_green('trash 5') + ' will remove message with ' + \ @@ -1355,8 +1598,8 @@ def help_stream(): ' filter will decide nicks will be INCLUDE ONLY.\n' usage += s * 3 + light_yellow('Ignore nicks') + \ ' filter will decide nicks will be EXCLUDE.\n' - usage += s * 2 + light_green('switch mine -d') + \ - ' will use the config\'s ONLY_LIST and IGNORE_LIST.\n' + usage += s * 2 + light_green('switch list') + \ + ' will switch to a Twitter list\'s stream. You will be asked for list name\n' printNicely(usage) @@ -1374,7 +1617,7 @@ def help(): light_yellow('already') + ' on your personal stream.\n' usage += s + 'Any update from Twitter will show up ' + \ light_yellow('immediately') + '.\n' - usage += s + 'In addtion, following commands are available right now:\n' + usage += s + 'In addition, following commands are available right now:\n' # Twitter help section usage += '\n' usage += s + grey(u'\u266A' + ' Twitter help\n') @@ -1424,6 +1667,7 @@ def help(): usage += s * 2 + light_green('p') + ' will pause the stream.\n' usage += s * 2 + light_green('r') + ' will unpause the stream.\n' usage += s * 2 + light_green('c') + ' will clear the screen.\n' + usage += s * 2 + light_green('v') + ' will show version info.\n' usage += s * 2 + light_green('q') + ' will quit.\n' # End usage += '\n' @@ -1451,7 +1695,7 @@ def pause(): """ Pause stream display """ - c['pause'] = True + g['pause'] = True printNicely(green('Stream is paused')) @@ -1459,7 +1703,7 @@ def replay(): """ Replay stream """ - c['pause'] = False + g['pause'] = False printNicely(green('Stream is running back now')) @@ -1499,54 +1743,108 @@ def reset(): pass +# Command set +cmdset = [ + 'switch', + 'trend', + 'home', + 'notification', + 'view', + 'mentions', + 't', + 'rt', + 'quote', + 'allrt', + 'conversation', + 'fav', + 'rep', + 'repall', + 'del', + 'ufav', + 'share', + 's', + 'mes', + 'show', + 'open', + 'ls', + 'inbox', + 'thread', + 'trash', + 'whois', + 'fl', + 'ufl', + 'mute', + 'unmute', + 'muting', + 'block', + 'unblock', + 'report', + 'list', + 'cal', + 'config', + 'theme', + 'h', + 'p', + 'r', + 'c', + 'v', + 'q', +] + +# Handle function set +funcset = [ + switch, + trend, + home, + notification, + view, + mentions, + tweet, + retweet, + quote, + allretweet, + conversation, + favorite, + reply, + reply_all, + delete, + unfavorite, + share, + search, + message, + show, + urlopen, + ls, + inbox, + thread, + trash, + whois, + follow, + unfollow, + mute, + unmute, + muting, + block, + unblock, + report, + twitterlist, + cal, + config, + theme, + help, + pause, + replay, + clear, + upgrade_center, + quit, +] + + def process(cmd): """ Process switch """ - return dict(zip( - cmdset, - [ - switch, - trend, - home, - view, - mentions, - tweet, - retweet, - quote, - allretweet, - favorite, - reply, - delete, - unfavorite, - search, - message, - show, - urlopen, - ls, - inbox, - sent, - trash, - whois, - follow, - unfollow, - mute, - unmute, - muting, - block, - unblock, - report, - list, - cal, - config, - theme, - help, - pause, - replay, - clear, - quit - ] - )).get(cmd, reset) + return dict(zip(cmdset, funcset)).get(cmd, reset) def listen(): @@ -1556,26 +1854,30 @@ def listen(): d = dict(zip( cmdset, [ - ['public', 'mine'], # switch + ['public', 'mine', 'list'], # switch [], # trend [], # home + [], # notification ['@'], # view [], # mentions [], # tweet [], # retweet [], # quote [], # allretweet + [], # conversation [], # favorite [], # reply + [], # reply_all [], # delete [], # unfavorite + [], # url ['#'], # search ['@'], # message ['image'], # show image [''], # open url ['fl', 'fr'], # list [], # inbox - [], # sent + [i for i in g['message_threads']], # sent [], # trash ['@'], # whois ['@'], # follow @@ -1613,6 +1915,7 @@ def listen(): [], # pause [], # reconnect [], # clear + [], # version [], # quit ] )) @@ -1620,19 +1923,20 @@ def listen(): read_history() reset() while True: - # raw_input - if g['prefix']: - line = raw_input(g['decorated_name'](c['PREFIX'])) - else: - line = raw_input() - # Save previous cmd in order to compare with readline buffer - g['previous_cmd'] = line.strip() - try: - cmd = line.split()[0] - except: - cmd = '' - g['cmd'] = cmd try: + # raw_input + if g['prefix']: + # Only use PREFIX as a string with raw_input + line = raw_input(g['decorated_name'](g['PREFIX'])) + else: + line = raw_input() + # Save cmd to compare with readline buffer + g['cmd'] = line.strip() + # Get short cmd to pass to handle function + try: + cmd = line.split()[0] + except: + cmd = '' # Lock the semaphore c['lock'] = True # Save cmd to global variable and call process @@ -1646,10 +1950,28 @@ def listen(): g['prefix'] = True # Release the semaphore lock c['lock'] = False + except EOFError: + printNicely('') except Exception: + debug_option() printNicely(red('OMG something is wrong with Twitter right now.')) +def reconn_notice(): + """ + Notice when Hangup or Timeout + """ + guide = light_magenta('You can use ') + \ + light_green('switch') + \ + light_magenta(' command to return to your stream.\n') + guide += light_magenta('Type ') + \ + light_green('h stream') + \ + light_magenta(' for more details.') + printNicely(guide) + sys.stdout.write(g['decorated_name'](g['PREFIX'])) + sys.stdout.flush() + + def stream(domain, args, name='Rainbow Stream'): """ Track the stream @@ -1657,16 +1979,16 @@ def stream(domain, args, name='Rainbow Stream'): # The Logo art_dict = { c['USER_DOMAIN']: name, - c['PUBLIC_DOMAIN']: args.track_keywords, + c['PUBLIC_DOMAIN']: args.track_keywords or 'Global', c['SITE_DOMAIN']: name, } if c['ASCII_ART']: - ascii_art(art_dict[domain]) + ascii_art(art_dict.get(domain, name)) # These arguments are optional: stream_args = dict( - timeout=0.5, # To check g['stream_stop'] after each 0.5 s - block=not args.no_block, - heartbeat_timeout=args.heartbeat_timeout) + timeout=0.5, # To check g['stream_stop'] after each 0.5 s + block=True, + heartbeat_timeout=c['HEARTBEAT_TIMEOUT'] * 60) # Track keyword query_args = dict() if args.track_keywords: @@ -1689,22 +2011,41 @@ def stream(domain, args, name='Rainbow Stream'): # Block new stream until other one exits StreamLock.acquire() g['stream_stop'] = False + last_tweet_time = time.time() for tweet in tweet_iter: if tweet is None: - printNicely("-- None --") + printNicely('-- None --') elif tweet is Timeout: + # Because the stream check for each 0.3s + # so we shouldn't output anything here if(g['stream_stop']): StreamLock.release() break elif tweet is HeartbeatTimeout: - printNicely("-- Heartbeat Timeout --") + printNicely('-- Heartbeat Timeout --') + reconn_notice() + StreamLock.release() + break elif tweet is Hangup: - printNicely("-- Hangup --") + printNicely('-- Hangup --') + reconn_notice() + StreamLock.release() + break elif tweet.get('text'): + # Slow down the stream by STREAM_DELAY config key + if time.time() - last_tweet_time < c['STREAM_DELAY']: + continue + last_tweet_time = time.time() + # Check the semaphore pause and lock (stream process only) + if g['pause']: + continue + while c['lock']: + time.sleep(0.5) + # Draw the tweet draw( t=tweet, keyword=args.track_keywords, - check_semaphore=True, + humanize=False, fil=args.filter, ig=args.ignore, ) @@ -1714,19 +2055,130 @@ def stream(domain, args, name='Rainbow Stream'): # after completely delete a word after typing it, # somehow readline buffer still contains # the 1st character of that word - if current_buffer and g['previous_cmd'] != current_buffer: + if current_buffer and g['cmd'] != current_buffer: sys.stdout.write( - g['decorated_name'](c['PREFIX']) + current_buffer) + g['decorated_name'](g['PREFIX']) + current_buffer) sys.stdout.flush() elif not c['HIDE_PROMPT']: - sys.stdout.write(g['decorated_name'](c['PREFIX'])) + sys.stdout.write(g['decorated_name'](g['PREFIX'])) sys.stdout.flush() elif tweet.get('direct_message'): - print_message(tweet['direct_message'], check_semaphore=True) - except TwitterHTTPError: + # Check the semaphore pause and lock (stream process only) + if g['pause']: + continue + while c['lock']: + time.sleep(0.5) + print_message(tweet['direct_message']) + elif tweet.get('event'): + c['events'].append(tweet) + print_event(tweet) + except TwitterHTTPError as e: printNicely('') printNicely( - magenta("We have maximum connection problem with twitter'stream API right now :(")) + magenta('We have connection problem with twitter stream API right now :(')) + detail_twitter_error(e) + sys.stdout.write(g['decorated_name'](g['PREFIX'])) + sys.stdout.flush() + except (URLError): + printNicely( + magenta('There seems to be a connection problem.')) + save_history() + sys.exit() + + +def spawn_public_stream(args, keyword=None): + """ + Spawn a new public stream + """ + # Only set keyword if specified + if keyword: + if keyword[0] == '#': + keyword = keyword[1:] + args.track_keywords = keyword + g['keyword'] = keyword + else: + g['keyword'] = 'Global' + g['PREFIX'] = u2str(emojize(format_prefix(keyword=g['keyword']))) + g['listname'] = '' + # Start new thread + th = threading.Thread( + target=stream, + args=( + c['PUBLIC_DOMAIN'], + args)) + th.daemon = True + th.start() + + +def spawn_list_stream(args, stuff=None): + """ + Spawn a new list stream + """ + try: + owner, slug = check_slug(stuff) + except: + owner, slug = get_slug() + + # Force python 2 not redraw readline buffer + listname = '/'.join([owner, slug]) + # Set the listname variable + # and reset tracked keyword + g['listname'] = listname + g['keyword'] = '' + g['PREFIX'] = g['cmd'] = u2str(emojize(format_prefix( + listname=g['listname'] + ))) + printNicely(light_yellow('getting list members ...')) + # Get members + t = Twitter(auth=authen()) + members = [] + next_cursor = -1 + while next_cursor != 0: + m = t.lists.members( + slug=slug, + owner_screen_name=owner, + cursor=next_cursor, + include_entities=False) + for u in m['users']: + members.append('@' + u['screen_name']) + next_cursor = m['next_cursor'] + printNicely(light_yellow('... done.')) + # Build thread filter array + args.filter = members + # Start new thread + th = threading.Thread( + target=stream, + args=( + c['USER_DOMAIN'], + args, + slug)) + th.daemon = True + th.start() + printNicely('') + if args.filter: + printNicely(cyan('Include: ' + str(len(args.filter)) + ' people.')) + if args.ignore: + printNicely(red('Ignore: ' + str(len(args.ignore)) + ' people.')) + printNicely('') + + +def spawn_personal_stream(args, stuff=None): + """ + Spawn a new personal stream + """ + # Reset the tracked keyword and listname + g['keyword'] = g['listname'] = '' + # Reset prefix + g['PREFIX'] = u2str(emojize(format_prefix())) + # Start new thread + th = threading.Thread( + target=stream, + args=( + c['USER_DOMAIN'], + args, + g['original_name'])) + th.daemon = True + th.start() def fly(): @@ -1736,23 +2188,40 @@ def fly(): # Initial args = parse_arguments() try: + proxy_connect(args) init(args) - except TwitterHTTPError: + # Twitter API connection problem + except TwitterHTTPError as e: printNicely('') printNicely( - magenta("We have maximum connection problem with twitter'stream API right now :(")) - printNicely(magenta("Let's try again later.")) + magenta('We have connection problem with twitter REST API right now :(')) + detail_twitter_error(e) + save_history() + sys.exit() + # Proxy connection problem + except (socks.ProxyConnectionError, URLError): + printNicely( + magenta('There seems to be a connection problem.')) + printNicely( + magenta('You might want to check your proxy settings (host, port and type)!')) save_history() sys.exit() + # Spawn stream thread - th = threading.Thread( - target=stream, - args=( - c['USER_DOMAIN'], - args, - g['original_name'])) - th.daemon = True - th.start() + target = args.stream.split()[0] + if target == 'mine' : + spawn_personal_stream(args) + else: + try: + stuff = args.stream.split()[1] + except: + stuff = None + spawn_dict = { + 'public': spawn_public_stream, + 'list': spawn_list_stream, + } + spawn_dict.get(target)(args, stuff) + # Start listen process time.sleep(0.5) g['reset'] = True