wttr.in/lib/view/wttr.py
Sebastian Espei 856a67a474
Add not found header after postprocessing
The postprocessing method assumes that the sout data is always delivered in the same format. If the location is not found, the passed format deviates and this then leads to an incorrect behavior => incorrect return value.
Close #729
Close #728
2022-05-13 12:53:22 +02:00

187 lines
6 KiB
Python

# vim: set encoding=utf-8
# pylint: disable=wrong-import-position
"""
Main view (wttr.in) implementation.
The module is a wrapper for the modified Wego program.
"""
import sys
import re
from gevent.subprocess import Popen, PIPE
sys.path.insert(0, "..")
from translations import get_message, SUPPORTED_LANGS
from globals import WEGO, NOT_FOUND_LOCATION, DEFAULT_LOCATION, ANSI2HTML, \
error, remove_ansi
def get_wetter(parsed_query):
location = parsed_query['location']
html = parsed_query['html_output']
lang = parsed_query['lang']
location_not_found = False
if location == NOT_FOUND_LOCATION:
location_not_found = True
stderr = ""
returncode = 0
if not location_not_found:
stdout, stderr, returncode = _wego_wrapper(location, parsed_query)
first_line, stdout = _wego_postprocessing(location, parsed_query, stdout)
if location_not_found or \
(returncode != 0 \
and ('Unable to find any matching weather'
' location to the parsed_query submitted') in stderr):
stdout, stderr, returncode = _wego_wrapper(DEFAULT_LOCATION, parsed_query)
location_not_found = True
not_found_header = """
>>> _ _ ___ _ _
>>> | || | / _ \| || |
>>> | || |_| | | | || |_
>>> |__ _| |_| |__ _|
>>> |_| \___/ |_|
>>>
>>> 404 %s: %s
>>>
""" % (get_message("UNKNOWN_LOCATION", lang).upper(), parsed_query['override_location_name'])
not_found_header = "\n".join("\033[48;5;91m" + x + " \033[0m"
for x in not_found_header.splitlines()[1:])
not_found_footer = get_message('NOT_FOUND_MESSAGE', lang)
not_found_footer = "\n".join("\033[48;5;91m " + x + " \033[0m"
for x in not_found_footer.splitlines() if x) + "\n"
first_line, stdout = _wego_postprocessing(location, parsed_query, stdout)
stdout = not_found_header + "\n----\n" + stdout + not_found_footer
if html:
return _htmlize(stdout, first_line, parsed_query)
return stdout
def _wego_wrapper(location, parsed_query):
lang = parsed_query['lang']
if location == DEFAULT_LOCATION:
location_name = DEFAULT_LOCATION.capitalize()
else:
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']
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(
'<body class="">', '<body class="" style="background:white;color:#777777">')
title = "<title>%s</title>" % title
opengraph = _get_opengraph(parsed_query)
stdout = re.sub("<head>", "<head>" + 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 (
'<meta property="og:image" content="%(pic_url)s_0pq.png" />'
'<meta property="og:site_name" content="wttr.in" />'
'<meta property="og:type" content="profile" />'
'<meta property="og:url" content="%(url)s" />'
) % {
'pic_url': pic_url,
'url': url,
}