diff --git a/script.logviewer/addon.xml b/script.logviewer/addon.xml index aa3120ad34..4eae12f458 100644 --- a/script.logviewer/addon.xml +++ b/script.logviewer/addon.xml @@ -1,5 +1,5 @@ - + @@ -19,8 +19,8 @@ Ferramenta para verificar e ler facilmente o log do Kodi. all -- Update log level regular expressions for v20. -- Small code improvements on webtail. +- Make text window skin independent +- Improve HTTP server icon.png diff --git a/script.logviewer/resources/lib/httpserver.py b/script.logviewer/resources/lib/httpserver.py index 3a4735420a..05ce2bda6c 100644 --- a/script.logviewer/resources/lib/httpserver.py +++ b/script.logviewer/resources/lib/httpserver.py @@ -3,7 +3,6 @@ import logging import os import shutil -import threading from resources.lib.logreader import LogReader from resources.lib.logviewer import log_location @@ -20,46 +19,47 @@ def base_handler(ctx): - with open(os.path.join(ADDON_PATH, "resources", "templates", "webtail.html"), "rb") as f: - html = f.read() - + html_path = os.path.join(ADDON_PATH, "resources", "templates", "webtail.html") ctx.send_response(200) ctx.send_header("Content-Type", "text/html") - ctx.send_header('Content-Length', len(html)) - ctx.send_header('Connection', 'keep-alive') + ctx.send_header("Content-Length", str(os.path.getsize(html_path))) + ctx.send_header("Connection", "keep-alive") ctx.end_headers() - ctx.wfile.write(html) + with open(html_path, "rb") as f: + shutil.copyfileobj(f, ctx.wfile) def tail_handler(ctx): if ctx.log_path is None: logging.error("Unable to find log path") - ctx.send_response(500) - ctx.end_headers() + ctx.send_response_and_end(500) return - offset = int(ctx.request.get('offset', 0)) + offset = int(ctx.request.get("offset", 0)) reader = LogReader(ctx.log_path) reader.set_offset(offset) content = encode(reader.tail()) ctx.send_response(200) ctx.send_header("Content-Type", "text/plain") - ctx.send_header('Content-Length', len(content)) - ctx.send_header('X-Seek-Offset', str(reader.get_offset())) + ctx.send_header("Content-Length", len(content)) + ctx.send_header("X-Seek-Offset", str(reader.get_offset())) ctx.end_headers() ctx.wfile.write(content) def favicon_handler(ctx): + favicon_path = os.path.join(ADDON_PATH, "resources", "images", "favicon.ico") ctx.send_response(200) ctx.send_header("Content-Type", "image/x-icon") + ctx.send_header("Content-length", str(os.path.getsize(favicon_path))) ctx.end_headers() - with open(os.path.join(ADDON_PATH, "resources", "images", "favicon.ico"), "rb") as f: + with open(favicon_path, "rb") as f: shutil.copyfileobj(f, ctx.wfile) class ServerHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" log_path = log_location(False) get_routes = { @@ -79,40 +79,22 @@ def do_GET(self): else: self.send_response(404) self.end_headers() + except BrokenPipeError as e: + raise e except Exception as e: logging.error(e) self.send_response(500) self.end_headers() + def send_response_and_end(self, code, message=None): + self.send_response(code, message=message) + self.send_header("Content-Length", "0") + self.end_headers() + def log_message(self, fmt, *args): - logging.debug(fmt % args) + logging.debug(fmt, *args) class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" - - def __init__(self, *args, **kwargs): - self.__shutdown_request = threading.Event() - self.__is_shut_down = threading.Event() - self.__is_shut_down.set() - HTTPServer.__init__(self, *args, **kwargs) - - def shutdown_server(self): - self.__shutdown_request.set() - self.__is_shut_down.wait() - - def serve_until_shutdown(self, should_stop=None, timeout=1): - if should_stop is None: - def should_stop(): - return False - - if timeout is not None: - self.timeout = timeout - - self.__is_shut_down.clear() - self.__shutdown_request.clear() - - while not self.__shutdown_request.is_set() and not should_stop(): - self.handle_request() - - self.__is_shut_down.set() + pass diff --git a/script.logviewer/resources/lib/service.py b/script.logviewer/resources/lib/service.py index 8d9dd868c0..7a88f8226b 100644 --- a/script.logviewer/resources/lib/service.py +++ b/script.logviewer/resources/lib/service.py @@ -14,18 +14,18 @@ class Monitor(xbmc.Monitor): def __init__(self): super(Monitor, self).__init__() - self._running = False + self._port = utils.get_int_setting("port") self._error_popup_runner = None self._http_server_runner = None + self._lock = threading.Lock() def start(self): - self._running = True self.onSettingsChanged() def stop(self): - self._running = False - self._stop_error_popup_runner() - self._stop_http_server_runner() + with self._lock: + self._stop_error_popup_runner() + self._stop_http_server_runner() def _start_error_popup_runner(self): if self._error_popup_runner is None: @@ -37,49 +37,61 @@ def _stop_error_popup_runner(self): if self._error_popup_runner is not None: logging.debug("Stopping error popup runner") self._error_popup_runner.stop() + self._error_popup_runner.join() self._error_popup_runner = None def _start_http_server_runner(self): if self._http_server_runner is None: logging.debug("Starting http server runner") - self._http_server_runner = HTTPServerRunner(self, utils.get_int_setting("port")) + self._http_server_runner = HTTPServerRunner(self._port) self._http_server_runner.start() def _stop_http_server_runner(self): if self._http_server_runner is not None: logging.debug("Stopping http server runner") self._http_server_runner.stop() + self._http_server_runner.join() self._http_server_runner = None def onSettingsChanged(self): - if self._running: - self._start_error_popup_runner() if utils.get_boolean_setting( - "error_popup") else self._stop_error_popup_runner() + with self._lock: + http_port = utils.get_int_setting("port") + run_http_server = utils.get_boolean_setting("http_server") + run_error_popup = utils.get_boolean_setting("error_popup") + + if run_http_server: + if http_port != self._port: + self._port = http_port + self._stop_http_server_runner() + self._start_http_server_runner() + else: + self._stop_http_server_runner() - self._start_http_server_runner() if utils.get_boolean_setting( - "http_server") else self._stop_http_server_runner() + if run_error_popup: + self._start_error_popup_runner() + else: + self._stop_error_popup_runner() class HTTPServerRunner(threading.Thread): - def __init__(self, monitor, port): - self._monitor = monitor + def __init__(self, port): self._port = port self._server = None super(HTTPServerRunner, self).__init__() def run(self): - self._server = ThreadedHTTPServer(("", self._port), ServerHandler) - self._server.daemon_threads = True - - logging.debug("Server started at port {}".format(self._port)) - logging.debug("Local IP: {}".format(xbmc.getIPAddress())) - - self._server.serve_until_shutdown(self._monitor.abortRequested) - self._server.server_close() + self._server = server = ThreadedHTTPServer(("", self._port), ServerHandler) + logging.debug("Server started at port %d", self._port) + logging.debug("Local IP is %s", xbmc.getIPAddress()) + server.serve_forever() + logging.debug("Closing server") + server.server_close() + logging.debug("Server terminated") def stop(self): if self._server is not None: - self._server.shutdown_server() + self._server.shutdown() + self._server = None class ErrorPopupRunner(threading.Thread): @@ -106,17 +118,14 @@ def run(self): # Ignore initial errors reader.tail() - while not self._monitor.abortRequested() and self._running: + while not self._monitor.waitForAbort(1) and self._running: content = reader.tail() parsed_errors = logviewer.parse_errors(content, set_style=True, exceptions_only=exceptions) if parsed_errors: logviewer.window(utils.ADDON_NAME, parsed_errors, default=utils.is_default_window()) - self._monitor.waitForAbort(1) def stop(self): self._running = False - # Wait for thread to stop - self.join() def run(start_delay=20): diff --git a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen-legacy.xml b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen-legacy.xml deleted file mode 100644 index 125d5718dd..0000000000 --- a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen-legacy.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - dialogeffect - DepthDialog+ - 32500 - - - - - 0 - 0 - 1280 - 720 - AddonWindow/black.png - - - - - 1210 - 30 - 32 - 32 - Button/close.png - Button/close.png - 32502 - - - - - 140 - 30 - 1000 - 30 - font14 - center - center - true - white - AA000000 - - - - - 1223 - 100 - 10 - 580 - 32500 - Scrollbar/scrollbar.png - Scrollbar/scrollbarv_bar.png - Scrollbar/scrollbarv_bar_focus.png - false - vertical - - - - - 45 - 100 - 1150 - 580 - true - FFFFFFFF - font13 - FFFFFFFF - 32502 - left - - - - diff --git a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen.xml b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen.xml index b2ed98d12e..b4fc2c9789 100644 --- a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen.xml +++ b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-fullscreen.xml @@ -1,8 +1,15 @@ - Animation_DialogPopupOpenClose - DepthOSD + + + + + + + + + 0.40 32500 @@ -21,7 +28,7 @@ 30 32 32 - Button/close.png + Button/close.png Button/close.png 32502 @@ -46,6 +53,11 @@ 100 10 580 + AddonWindow/white.png + AddonWindow/white.png + AddonWindow/white.png + + 32500 false vertical diff --git a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-legacy.xml b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-legacy.xml deleted file mode 100644 index cd05430b9e..0000000000 --- a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow-legacy.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - dialogeffect - DepthDialog+ - 32500 - - - - - 190 - 50 - 900 - 620 - AddonWindow/black.png - - - - - 1035 - 68 - 32 - 32 - Button/close.png - Button/close.png - 32502 - - - - - 290 - 75 - 700 - 30 - font14 - center - center - true - white - AA000000 - - - - - 1055 - 140 - 10 - 510 - 32500 - Scrollbar/scrollbar.png - Scrollbar/scrollbarv_bar.png - Scrollbar/scrollbarv_bar_focus.png - false - vertical - - - - - 215 - 140 - 815 - 510 - true - FFFFFFFF - font13 - FFFFFFFF - 32502 - left - - - - diff --git a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow.xml b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow.xml index 54de454fbd..259ccfa8f2 100644 --- a/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow.xml +++ b/script.logviewer/resources/skins/Default/720p/script.logviewer-textwindow.xml @@ -1,8 +1,15 @@ - Animation_DialogPopupOpenClose - DepthOSD + + + + + + + + + 0.40 32500 @@ -21,7 +28,7 @@ 68 32 32 - Button/close.png + Button/close.png Button/close.png 32502 @@ -46,6 +53,11 @@ 140 10 510 + AddonWindow/white.png + AddonWindow/white.png + AddonWindow/white.png + + 32500 false vertical diff --git a/script.logviewer/resources/skins/Default/media/AddonWindow/white.png b/script.logviewer/resources/skins/Default/media/AddonWindow/white.png new file mode 100644 index 0000000000..528c66f6e8 Binary files /dev/null and b/script.logviewer/resources/skins/Default/media/AddonWindow/white.png differ