X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=blobdiff_plain;f=rainbowstream%2Frainbow.py;h=465299f0e41b96b28694e4645f58f32cffb0357e;hp=a5824a6382650984abeb11fc8baf0ed269b8bba3;hb=5edc9cd172a33b2fd0379f212b8b9780e3213396;hpb=ba6c09d1585318207fa3ddf47b374b5ebcc3a22c diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index a5824a6..465299f 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -41,6 +41,11 @@ 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', @@ -62,6 +67,11 @@ def parse_arguments(): '--image-on-term', action='store_true', help='Display all image on terminal.') + parser.add_argument( + '-24', + '--color-24bit', + action='store_true', + help='Display images using 24bit color codes.') parser.add_argument( '-ph', '--proxy-host', @@ -171,19 +181,20 @@ def upgrade_center(): 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: + g['using_latest'] = current == latest + if not g['using_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) + notice += '\n' + printNicely(notice) except: pass @@ -228,7 +239,8 @@ def init(args): c['message_dict'] = [] # Image on term c['IMAGE_ON_TERM'] = args.image_on_term - set_config('IMAGE_ON_TERM', str(c['IMAGE_ON_TERM'])) + # Use 24 bit color + c['24BIT'] = args.color_24bit # 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.')) @@ -319,7 +331,11 @@ def whois(): Show profile of a specific user """ t = Twitter(auth=authen()) - screen_name = g['stuff'].split()[0] + 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( @@ -338,7 +354,11 @@ 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]) @@ -352,6 +372,21 @@ def view(): printNicely(red('A name should begin with a \'@\'')) +def view_my_tweets(): + """ + Display user's recent tweets. + """ + t = Twitter(auth=authen()) + try: + num = int(g['stuff']) + except: + num = c['HOME_TWEET_NUM'] + for tweet in reversed( + t.statuses.user_timeline(count=num, screen_name=g['original_name'])): + draw(t=tweet) + printNicely('') + + def search(): """ Search @@ -359,6 +394,9 @@ def search(): t = Twitter(auth=authen()) # 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' @@ -514,11 +552,13 @@ def reply_all(): tid = c['tweet_dict'][id] original_tweet = t.statuses.show(id=tid) text = original_tweet['text'] - owner = '@' + original_tweet['user']['screen_name'] - nick_ary = ['@' + re.sub('[\W_]', '', w) - for w in text.split() if w.startswith('@')] + [owner] + 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_ary) + ' ' + str2u(status) + status = ' '.join(['@' + nick for nick in nick_ary]) + ' ' + str2u(status) t.statuses.update(status=status, in_reply_to_status_id=tid) @@ -625,14 +665,14 @@ def urlopen(): return tid = c['tweet_dict'][int(g['stuff'])] tweet = t.statuses.show(id=tid) - link_prefix = ('http://', 'https://') - link_ary = [u for u in tweet['text'].split() - if u.startswith(link_prefix)] - if not link_ary: + urls = tweet['entities']['urls'] + if not urls: printNicely(light_magenta('No url here @.@!')) return - for link in link_ary: - webbrowser.open(link) + else: + for url in urls: + expanded_url = url['expanded_url'] + webbrowser.open(expanded_url) except: debug_option() printNicely(red('Sorry I can\'t open url in this tweet.')) @@ -775,6 +815,7 @@ def ls(): target = g['stuff'].split()[0] except: printNicely(red('Omg some syntax is wrong.')) + return # Init cursor d = {'fl': 'followers', 'fr': 'friends'} next_cursor = -1 @@ -841,7 +882,7 @@ def mute(): 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'] += [screen_name] c['IGNORE_LIST'] = list(set(c['IGNORE_LIST'])) else: printNicely(red(rel)) @@ -956,6 +997,22 @@ def get_slug(): raise Exception('Wrong list name') +def check_slug(list_name): + """ + Check slug + """ + # 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 show_lists(t): """ List list @@ -1254,91 +1311,19 @@ def switch(): 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 - # Set the variable to tracked keyword - # and reset the listname - g['keyword'] = keyword - g['listname'] = '' - # Reset prefix - g['PREFIX'] = u2str(emojize(format_prefix(keyword=g['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 - # 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() - # Stream base on list - elif target == 'list': - 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 - # Kill old thread - g['stream_stop'] = True - # 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('') + # 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.')) @@ -1467,6 +1452,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('me') + ' will show your latest tweets. ' + \ + light_green('me 2') + ' will show your last 2 tweets.\n' usage += s * 2 + \ light_green('notification') + ' will show your recent notification.\n' usage += s * 2 + light_green('mentions') + ' will show mentions timeline. ' + \ @@ -1791,6 +1778,7 @@ cmdset = [ 't', 'rt', 'quote', + 'me', 'allrt', 'conversation', 'fav', @@ -1839,6 +1827,7 @@ funcset = [ tweet, retweet, quote, + view_my_tweets, allretweet, conversation, favorite, @@ -1900,6 +1889,7 @@ def listen(): [], # tweet [], # retweet [], # quote + [], # view_my_tweets [], # allretweet [], # conversation [], # favorite @@ -1978,6 +1968,7 @@ def listen(): c['lock'] = True # Save cmd to global variable and call process g['stuff'] = ' '.join(line.split()[1:]) + # Check tweet length # Process the command process(cmd)() # Not re-display @@ -1985,13 +1976,16 @@ def listen(): g['prefix'] = False else: g['prefix'] = True - # Release the semaphore lock - c['lock'] = False except EOFError: printNicely('') + except TwitterHTTPError as e: + detail_twitter_error(e) except Exception: debug_option() - printNicely(red('OMG something is wrong with Twitter right now.')) + printNicely(red('OMG something is wrong with Twitter API right now.')) + finally: + # Release the semaphore lock + c['lock'] = False def reconn_notice(): @@ -2016,11 +2010,11 @@ 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 @@ -2116,13 +2110,108 @@ def stream(domain, args, name='Rainbow Stream'): detail_twitter_error(e) sys.stdout.write(g['decorated_name'](g['PREFIX'])) sys.stdout.flush() - except (URLError, ConnectionResetError): + 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(): """ Main function @@ -2150,14 +2239,20 @@ def fly(): 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