diff --git a/lib/view/wttr.py b/lib/view/wttr.py index 4007776..7d3c682 100644 --- a/lib/view/wttr.py +++ b/lib/view/wttr.py @@ -1,225 +1,163 @@ # vim: set encoding=utf-8 +# pylint: disable=wrong-import-position -from __future__ import print_function -import gevent -from gevent.pywsgi import WSGIServer -from gevent.queue import Queue -from gevent.monkey import patch_all -from gevent.subprocess import Popen, PIPE, STDOUT -patch_all() +""" +Main view (wttr.in) implementation. +The module is a wrapper for the modified Wego program. +""" import sys -import os import re -import time -import hashlib + +from gevent.subprocess import Popen, PIPE sys.path.insert(0, "..") -from translations import get_message, FULL_TRANSLATION, PARTIAL_TRANSLATION, SUPPORTED_LANGS -from globals import WEGO, CACHEDIR, \ - NOT_FOUND_LOCATION, DEFAULT_LOCATION, TEST_FILE, ANSI2HTML, \ - log, error, remove_ansi +from translations import get_message, SUPPORTED_LANGS +from globals import WEGO, NOT_FOUND_LOCATION, DEFAULT_LOCATION, ANSI2HTML, \ + error, remove_ansi -def _is_invalid_location(location): - if '.png' in location: - return True def get_wetter(parsed_query): location = parsed_query['location'] - ip = parsed_query['ip_addr'] html = parsed_query['html_output'] lang = parsed_query['lang'] - location_name = parsed_query['override_location_name'] - full_address = parsed_query['full_address'] - url = parsed_query['request_url'] - - local_url = url - local_location = location - - def get_opengraph(): - - if local_url is None: - url = "" - else: - url = local_url - - if local_location is None: - location = "" - else: - location = local_location - - pic_url = url.replace('?', '_') - - return ( - '' - '' - '' - '' - ) % { - 'pic_url': pic_url, - 'url': url, - 'location': location, - } - - # '' - # '' - - def get_filename(location, lang=None, query=None, location_name=None): - location = location.replace('/', '_') - timestamp = time.strftime( "%Y%m%d%H", time.localtime() ) - - imperial_suffix = '' - if query.get('use_imperial', False): - imperial_suffix = '-imperial' - - lang_suffix = '' - if lang is not None: - lang_suffix = '-lang_%s' % lang - - if query != None: - query_line = "_" + "_".join("%s=%s" % (key, value) for (key, value) in query.items()) - else: - query_line = "" - - if location_name is None: - location_name = "" - - filename = "".join([timestamp, imperial_suffix, lang_suffix, query_line, location_name]) - digest = hashlib.sha1(filename.encode('utf-8')).hexdigest() - return "%s/%s/%s" % (CACHEDIR, location, digest) - - def save_weather_data(location, filename, lang=None, query=None, location_name=None, full_address=None): - - if _is_invalid_location( location ): - error("Invalid location: %s" % location) - - NOT_FOUND_MESSAGE_HEADER = "" - while True: - location_not_found = False - if location in [ "test-thunder" ]: - test_name = location[5:] - test_file = TEST_FILE.replace('NAME', test_name) - stdout = open(test_file, 'r').read() - stderr = "" - break - if location == NOT_FOUND_LOCATION: - location_not_found = True - location = DEFAULT_LOCATION - - cmd = [WEGO, '--city=%s' % location] - - if query.get('inverted_colors'): - cmd += ['-inverse'] - - if query.get('use_ms_for_wind'): - cmd += ['-wind_in_ms'] - - if query.get('narrow'): - cmd += ['-narrow'] - - if lang and lang in SUPPORTED_LANGS: - cmd += ['-lang=%s'%lang] - - if query.get('use_imperial', False): - cmd += ['-imperial'] - - if location_name: - cmd += ['-location_name', location_name] - - p = Popen(cmd, stdout=PIPE, stderr=PIPE) - stdout, stderr = p.communicate() - stdout = stdout.decode("utf-8") - stderr = stderr.decode("utf-8") - - if p.returncode != 0: - print("ERROR: location not found: %s" % location) - if u'Unable to find any matching weather location to the query submitted' in stderr: - if location != NOT_FOUND_LOCATION: - NOT_FOUND_MESSAGE_HEADER = u"ERROR: %s: %s\n---\n\n" % (get_message('UNKNOWN_LOCATION', lang), location) - location = NOT_FOUND_LOCATION - continue - error(stdout + stderr) - break - - dirname = os.path.dirname(filename) - if not os.path.exists(dirname): - os.makedirs(dirname) - - if location_not_found: + + location_not_found = False + if location == NOT_FOUND_LOCATION: + location_not_found = True + + if not location_not_found: + stdout, stderr, returncode = _wego_wrapper(location, parsed_query) + + if location_not_found or returncode != 0: + if ('Unable to find any matching weather' + ' location to the parsed_query submitted') in stderr: + stdout, stderr, returncode = _wego_wrapper(NOT_FOUND_LOCATION, parsed_query) + location_not_found = True stdout += get_message('NOT_FOUND_MESSAGE', lang) - stdout = NOT_FOUND_MESSAGE_HEADER + stdout - - if 'days' in query: - if query['days'] == '0': - stdout = "\n".join(stdout.splitlines()[:7]) + "\n" - if query['days'] == '1': - stdout = "\n".join(stdout.splitlines()[:17]) + "\n" - if query['days'] == '2': - stdout = "\n".join(stdout.splitlines()[:27]) + "\n" - - first = stdout.splitlines()[0] - rest = stdout.splitlines()[1:] - if query.get('no-caption', False): - - separator = None - if ':' in first: - separator = ':' - if u':' in first: - separator = u':' - - if separator: - first = first.split(separator, 1)[1] - stdout = "\n".join([first.strip()] + rest) + "\n" - - if query.get('no-terminal', False): - stdout = remove_ansi(stdout) - - if query.get('no-city', False): - stdout = "\n".join(stdout.splitlines()[2:]) + "\n" - - if full_address \ - and query.get('format', 'txt') != 'png' \ - and (not query.get('no-city') - and not query.get('no-caption') - and not query.get('days') == '0'): - line = "%s: %s [%s]\n" % ( - get_message('LOCATION', lang), - full_address, - location) - stdout += line - - if query.get('padding', False): - lines = [x.rstrip() for x in stdout.splitlines()] - max_l = max(len(remove_ansi(x)) for x in lines) - last_line = " "*max_l + " .\n" - stdout = " \n" + "\n".join(" %s " %x for x in lines) + "\n" + last_line - - open(filename, 'w').write(stdout) - - cmd = ["bash", ANSI2HTML, "--palette=solarized"] - if not query.get('inverted_colors'): - cmd += ["--bg=dark"] - - p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE ) - stdout, stderr = p.communicate(stdout.encode("utf-8")) - stdout = stdout.decode("utf-8") - stderr = stderr.decode("utf-8") - if p.returncode != 0: - error(stdout + stderr) - - if query.get('inverted_colors'): - stdout = stdout.replace('', '') - - title = "%s" % first - opengraph = get_opengraph() - stdout = re.sub("", "" + title + opengraph, stdout) - open(filename+'.html', 'w').write(stdout) - - filename = get_filename(location, lang=lang, query=parsed_query, location_name=location_name) - if not os.path.exists(filename): - save_weather_data(location, filename, lang=lang, query=parsed_query, location_name=location_name, full_address=full_address) + + first_line, stdout = _wego_postprocessing(location, parsed_query, stdout) + + if html: - filename += '.html' + return _htmlize(stdout, first_line, parsed_query) + return stdout + +def _wego_wrapper(location, parsed_query): + + lang = parsed_query['lang'] + location_name = parsed_query['override_location_name'] + + cmd = [WEGO, '--city=%s' % location] + + if parsed_query.get('inverted_colors'): + cmd += ['-inverse'] + + if parsed_query.get('use_ms_for_wind'): + cmd += ['-wind_in_ms'] + + if parsed_query.get('narrow'): + cmd += ['-narrow'] + + if lang and lang in SUPPORTED_LANGS: + cmd += ['-lang=%s'%lang] + + if parsed_query.get('use_imperial', False): + cmd += ['-imperial'] + + if location_name: + cmd += ['-location_name', location_name] + + proc = Popen(cmd, stdout=PIPE, stderr=PIPE) + stdout, stderr = proc.communicate() + stdout = stdout.decode("utf-8") + stderr = stderr.decode("utf-8") + + return stdout, stderr, proc.returncode + +def _wego_postprocessing(location, parsed_query, stdout): + full_address = parsed_query['full_address'] + lang = parsed_query['lang'] - return open(filename).read() + if 'days' in parsed_query: + if parsed_query['days'] == '0': + stdout = "\n".join(stdout.splitlines()[:7]) + "\n" + if parsed_query['days'] == '1': + stdout = "\n".join(stdout.splitlines()[:17]) + "\n" + if parsed_query['days'] == '2': + stdout = "\n".join(stdout.splitlines()[:27]) + "\n" + + + first = stdout.splitlines()[0] + rest = stdout.splitlines()[1:] + if parsed_query.get('no-caption', False): + if ':' in first: + first = first.split(":", 1)[1] + stdout = "\n".join([first.strip()] + rest) + "\n" + + if parsed_query.get('no-terminal', False): + stdout = remove_ansi(stdout) + + if parsed_query.get('no-city', False): + stdout = "\n".join(stdout.splitlines()[2:]) + "\n" + + if full_address \ + and parsed_query.get('format', 'txt') != 'png' \ + and (not parsed_query.get('no-city') + and not parsed_query.get('no-caption') + and not parsed_query.get('days') == '0'): + line = "%s: %s [%s]\n" % ( + get_message('LOCATION', lang), + full_address, + location) + stdout += line + + if parsed_query.get('padding', False): + lines = [x.rstrip() for x in stdout.splitlines()] + max_l = max(len(remove_ansi(x)) for x in lines) + last_line = " "*max_l + " .\n" + stdout = " \n" + "\n".join(" %s " %x for x in lines) + "\n" + last_line + + return first, stdout + +def _htmlize(ansi_output, title, parsed_query): + """Return HTML representation of `ansi_output`. + Use `title` as the title of the page. + Format page according to query parameters from `parsed_query`.""" + + cmd = ["bash", ANSI2HTML, "--palette=solarized"] + if not parsed_query.get('inverted_colors'): + cmd += ["--bg=dark"] + + proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = proc.communicate(ansi_output.encode("utf-8")) + stdout = stdout.decode("utf-8") + stderr = stderr.decode("utf-8") + if proc.returncode != 0: + error(stdout + stderr) + + if parsed_query.get('inverted_colors'): + stdout = stdout.replace( + '', '') + + title = "%s" % title + opengraph = _get_opengraph(parsed_query) + stdout = re.sub("", "" + title + opengraph, stdout) + return stdout + +def _get_opengraph(parsed_query): + """Return OpenGraph data for `parsed_query`""" + + url = parsed_query['request_url'] or "" + pic_url = url.replace('?', '_') + + return ( + '' + '' + '' + '' + ) % { + 'pic_url': pic_url, + 'url': url, + }