X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=blobdiff_plain;f=rainbowstream%2Frainbow.py;h=a5824a6382650984abeb11fc8baf0ed269b8bba3;hp=c05183e74c6af1ee2529514bae48e27f85b9571d;hb=144f62cd2a07b0353eda1c029f7b37b65452d353;hpb=c426a344303087c8c13391752473c6a22fda8e14 diff --git a/rainbowstream/rainbow.py b/rainbowstream/rainbow.py index c05183e..a5824a6 100644 --- a/rainbowstream/rainbow.py +++ b/rainbowstream/rainbow.py @@ -12,14 +12,13 @@ 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 from twitter.oauth_dance import oauth_dance from twitter.util import printNicely -from urllib import error - from .draw import * from .colors import * from .config import * @@ -28,6 +27,7 @@ from .interactive import * from .c_image import * from .py3patch import * from .emoji import * +from .util import * # Global values g = {} @@ -74,11 +74,36 @@ def parse_arguments(): parser.add_argument( '-pt', '--proxy-type', - default='SOCKS4', + 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 @@ -90,7 +115,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) @@ -142,10 +167,10 @@ def upgrade_center(): Check latest and notify to upgrade """ try: - current = pkg_resources.get_distribution("rainbowstream").version + 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] + latest = readme.split('version = \'')[1].split('\'')[0] if current != latest: notice = light_magenta('RainbowStream latest version is ') notice += light_green(latest) @@ -154,6 +179,11 @@ def upgrade_center(): 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 @@ -172,11 +202,9 @@ def init(args): credential = t.account.verify_credentials() screen_name = '@' + credential['screen_name'] name = credential['name'] - if not get_config('PREFIX'): - set_config('PREFIX', screen_name) - c['PREFIX'] = emojize(c['PREFIX']) - g['PREFIX'] = u2str(c['PREFIX']) 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 + ']: ', rl=True) @@ -473,6 +501,27 @@ def reply(): t.statuses.update(status=status, in_reply_to_status_id=tid) +def reply_all(): + """ + Reply to all + """ + 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] + 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] + status = ' '.join(g['stuff'].split()[1:]) + status = ' '.join(nick_ary) + ' ' + str2u(status) + t.statuses.update(status=status, in_reply_to_status_id=tid) + + def favorite(): """ Favorite @@ -1213,8 +1262,12 @@ def switch(): # 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(c['PREFIX'])) + g['PREFIX'] = u2str(emojize(format_prefix(keyword=g['keyword']))) # Start new thread th = threading.Thread( target=stream, @@ -1227,8 +1280,10 @@ def switch(): 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(c['PREFIX'])) + g['PREFIX'] = u2str(emojize(format_prefix())) # Start new thread th = threading.Thread( target=stream, @@ -1242,7 +1297,14 @@ def switch(): elif target == 'list': owner, slug = get_slug() # Force python 2 not redraw readline buffer - g['PREFIX'] = g['cmd'] = '/'.join([owner, slug]) + 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()) @@ -1379,7 +1441,10 @@ def config(): g['decorated_name'] = lambda x: color_func( c['DECORATED_NAME'])('[' + x + ']: ') elif key == 'PREFIX': - g['PREFIX'] = u2str(emojize(c['PREFIX'])) + g['PREFIX'] = u2str(emojize(format_prefix( + listname=g['listname'], + keyword=g['keyword'] + ))) reload_config() printNicely(green('Updated successfully.')) except: @@ -1439,7 +1504,10 @@ def help_tweets(): 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 ' + \ @@ -1636,6 +1704,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' @@ -1726,6 +1795,7 @@ cmdset = [ 'conversation', 'fav', 'rep', + 'repall', 'del', 'ufav', 'share', @@ -1754,7 +1824,8 @@ cmdset = [ 'p', 'r', 'c', - 'q' + 'v', + 'q', ] # Handle function set @@ -1772,6 +1843,7 @@ funcset = [ conversation, favorite, reply, + reply_all, delete, unfavorite, share, @@ -1800,7 +1872,8 @@ funcset = [ pause, replay, clear, - quit + upgrade_center, + quit, ] @@ -1831,6 +1904,7 @@ def listen(): [], # conversation [], # favorite [], # reply + [], # reply_all [], # delete [], # unfavorite [], # url @@ -1878,6 +1952,7 @@ def listen(): [], # pause [], # reconnect [], # clear + [], # version [], # quit ] )) @@ -1923,14 +1998,14 @@ 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.") + 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'](c['PREFIX'])) + sys.stdout.write(g['decorated_name'](g['PREFIX'])) sys.stdout.flush() @@ -1973,9 +2048,10 @@ 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 @@ -1983,16 +2059,20 @@ def stream(domain, args, name='Rainbow Stream'): 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 @@ -2014,10 +2094,10 @@ def stream(domain, args, name='Rainbow Stream'): # the 1st character of that word if current_buffer and g['cmd'] != current_buffer: sys.stdout.write( - g['decorated_name'](c['PREFIX']) + str2u(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'): # Check the semaphore pause and lock (stream process only) @@ -2029,10 +2109,18 @@ def stream(domain, args, name='Rainbow Stream'): elif tweet.get('event'): c['events'].append(tweet) print_event(tweet) - except TwitterHTTPError: + 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, ConnectionResetError): + printNicely( + magenta('There seems to be a connection problem.')) + save_history() + sys.exit() def fly(): @@ -2042,33 +2130,22 @@ def fly(): # Initial args = parse_arguments() try: - if args.proxy_host: - # Setup proxy by monkeypatching the standard lib - # You might want to check https://github.com/Anorov/PySocks for further - # further info. - 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 + proxy_connect(args) init(args) - except TwitterHTTPError: + # Twitter API connection problem + except TwitterHTTPError as e: printNicely('') printNicely( - magenta("We have 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() - except (ConnectionRefusedError, socks.ProxyConnectionError, error.URLError): + # Proxy connection problem + except (socks.ProxyConnectionError, URLError): printNicely( - magenta("There seems to be a connection problem.")) + magenta('There seems to be a connection problem.')) printNicely( - magenta("You might want to check your proxy settings (host, port and type)!")) + magenta('You might want to check your proxy settings (host, port and type)!')) save_history() sys.exit()