diff --git a/gallery_dl/output.py b/gallery_dl/output.py index cb0c988d..3f6b24ad 100644 --- a/gallery_dl/output.py +++ b/gallery_dl/output.py @@ -14,10 +14,7 @@ import platform def select(): """Automatically select a suitable printer class""" if hasattr(sys.stdout, "isatty") and sys.stdout.isatty(): - if _color_supported(): - return ColorPrinter - else: - return TerminalPrinter + return ColorPrinter if ANSI else TerminalPrinter else: return Printer @@ -32,7 +29,7 @@ class Printer(): @staticmethod def skip(path): """Print a message indicating that a download has been skipped""" - print("#", path, sep="", flush=True) + print(CHAR_SKIP, path, sep="", flush=True) @staticmethod def success(path, tries): @@ -50,26 +47,28 @@ class TerminalPrinter(): @staticmethod def start(path): """Print a message indicating the start of a download""" - print(_shorten(" "+path), end="", flush=True) + _safeprint(_shorten(" " + path), end="", flush=True) @staticmethod def skip(path): """Print a message indicating that a download has been skipped""" - print(_shorten("#"+path)) + _safeprint(_shorten(CHAR_SKIP + path)) @staticmethod def success(path, tries): """Print a message indicating the completion of a download""" - if tries == 0: - print("\r", end="") - print("\r", _shorten("✔" + path), sep="") + print("\r", end="") + _safeprint(_shorten(CHAR_SUCCESS + path)) @staticmethod def error(file, error, tries, max_tries): """Print a message indicating an error during download""" if tries <= 1 and hasattr(file, "name"): - print("\r", _shorten("❌" + file.name), sep="") - print("[Error] ", error, " (", tries, "/", max_tries, ")", sep="") + print("\r", end="") + _safeprint(_shorten(CHAR_ERROR + file.name)) + print("[Error] ", end="") + _safeprint(error, end="") + print(" (", tries, "/", max_tries, ")", sep="") class ColorPrinter(): @@ -101,14 +100,32 @@ class ColorPrinter(): def _shorten(txt): """Reduce the length of 'txt' to the width of the terminal""" - width = shutil.get_terminal_size().columns + width = shutil.get_terminal_size().columns - OFFSET if len(txt) > width: - hwidth = width // 2 - return "".join((txt[:hwidth-1], "…", txt[-hwidth-(width%2):])) + hwidth = width // 2 - OFFSET + return "".join((txt[:hwidth-1], CHAR_ELLIPSIES, txt[-hwidth-(width%2):])) return txt -def _color_supported(): - """Return True if a terminal supports colors""" - if platform.system() == "Windows": - return os.environ.get("TERM") == "ANSI" - return True +def _safeprint(txt, **kwargs): + """Handle unicode errors and replace invalid characters""" + try: + print(txt, **kwargs) + except UnicodeEncodeError: + enc = sys.stdout.encoding + txt = txt.encode(enc, errors="replace").decode(enc) + print(txt, **kwargs) + +if platform.system() == "Windows": + ANSI = os.environ.get("TERM") == "ANSI" + OFFSET = 1 + CHAR_SKIP = "#" + CHAR_ERROR = "!" + CHAR_SUCCESS = "*" + CHAR_ELLIPSIES = "..." +else: + ANSI = True + OFFSET = 0 + CHAR_SKIP = "#" + CHAR_ERROR = "❌" + CHAR_SUCCESS = "✔" + CHAR_ELLIPSIES = "…"