[minicurses] Fix when printing to file

Closes #1215
This commit is contained in:
pukkandan 2021-10-10 07:08:22 +05:30
parent 2e01ba6218
commit d1d5c08f29
No known key found for this signature in database
GPG key ID: 0F00D95A001F4698
4 changed files with 29 additions and 24 deletions

View file

@ -514,6 +514,7 @@ class YoutubeDL(object):
self.cache = Cache(self) self.cache = Cache(self)
windows_enable_vt_mode() windows_enable_vt_mode()
# FIXME: This will break if we ever print color to stdout
self.params['no_color'] = self.params.get('no_color') or not supports_terminal_sequences(self._err_file) self.params['no_color'] = self.params.get('no_color') or not supports_terminal_sequences(self._err_file)
if sys.version_info < (3, 6): if sys.version_info < (3, 6):
@ -3298,6 +3299,9 @@ class YoutubeDL(object):
KEYRING_AVAILABLE and 'keyring', KEYRING_AVAILABLE and 'keyring',
)))) or 'none' )))) or 'none'
self._write_string('[debug] Optional libraries: %s\n' % lib_str) self._write_string('[debug] Optional libraries: %s\n' % lib_str)
self._write_string('[debug] ANSI escape support: stdout = %s, stderr = %s\n' % (
supports_terminal_sequences(self._screen_file),
supports_terminal_sequences(self._err_file)))
proxy_map = {} proxy_map = {}
for handler in self._opener.handlers: for handler in self._opener.handlers:

View file

@ -3,7 +3,6 @@ from __future__ import division, unicode_literals
import copy import copy
import os import os
import re import re
import sys
import time import time
import random import random
@ -247,9 +246,9 @@ class FileDownloader(object):
elif self.ydl.params.get('logger'): elif self.ydl.params.get('logger'):
self._multiline = MultilineLogger(self.ydl.params['logger'], lines) self._multiline = MultilineLogger(self.ydl.params['logger'], lines)
elif self.params.get('progress_with_newline'): elif self.params.get('progress_with_newline'):
self._multiline = BreaklineStatusPrinter(sys.stderr, lines) self._multiline = BreaklineStatusPrinter(self.ydl._screen_file, lines)
else: else:
self._multiline = MultilinePrinter(sys.stderr, lines, not self.params.get('quiet')) self._multiline = MultilinePrinter(self.ydl._screen_file, lines, not self.params.get('quiet'))
def _finish_multiline_status(self): def _finish_multiline_status(self):
self._multiline.end() self._multiline.end()

View file

@ -1,6 +1,6 @@
import functools import functools
from threading import Lock from threading import Lock
from .utils import supports_terminal_sequences, TERMINAL_SEQUENCES from .utils import supports_terminal_sequences, TERMINAL_SEQUENCES, write_string
class MultilinePrinterBase: class MultilinePrinterBase:
@ -25,20 +25,26 @@ class MultilinePrinterBase:
return f'{line + 1}: {text}' return f'{line + 1}: {text}'
return text return text
def write(self, *text):
write_string(''.join(text), self.stream)
class QuietMultilinePrinter(MultilinePrinterBase): class QuietMultilinePrinter(MultilinePrinterBase):
pass pass
class MultilineLogger(MultilinePrinterBase): class MultilineLogger(MultilinePrinterBase):
def write(self, *text):
self.stream.debug(''.join(text))
def print_at_line(self, text, pos): def print_at_line(self, text, pos):
# stream is the logger object, not an actual stream # stream is the logger object, not an actual stream
self.stream.debug(self._add_line_number(text, pos)) self.write(self._add_line_number(text, pos))
class BreaklineStatusPrinter(MultilinePrinterBase): class BreaklineStatusPrinter(MultilinePrinterBase):
def print_at_line(self, text, pos): def print_at_line(self, text, pos):
self.stream.write(self._add_line_number(text, pos) + '\n') self.write(self._add_line_number(text, pos), '\n')
class MultilinePrinter(MultilinePrinterBase): class MultilinePrinter(MultilinePrinterBase):
@ -58,50 +64,46 @@ class MultilinePrinter(MultilinePrinterBase):
def _move_cursor(self, dest): def _move_cursor(self, dest):
current = min(self._lastline, self.maximum) current = min(self._lastline, self.maximum)
self.stream.write('\r') yield '\r'
distance = dest - current distance = dest - current
if distance < 0: if distance < 0:
self.stream.write(TERMINAL_SEQUENCES['UP'] * -distance) yield TERMINAL_SEQUENCES['UP'] * -distance
elif distance > 0: elif distance > 0:
self.stream.write(TERMINAL_SEQUENCES['DOWN'] * distance) yield TERMINAL_SEQUENCES['DOWN'] * distance
self._lastline = dest self._lastline = dest
@lock @lock
def print_at_line(self, text, pos): def print_at_line(self, text, pos):
if self._HAVE_FULLCAP: if self._HAVE_FULLCAP:
self._move_cursor(pos) self.write(*self._move_cursor(pos), TERMINAL_SEQUENCES['ERASE_LINE'], text)
self.stream.write(TERMINAL_SEQUENCES['ERASE_LINE'])
self.stream.write(text)
return
text = self._add_line_number(text, pos) text = self._add_line_number(text, pos)
textlen = len(text) textlen = len(text)
if self._lastline == pos: if self._lastline == pos:
# move cursor at the start of progress when writing to same line # move cursor at the start of progress when writing to same line
self.stream.write('\r') prefix = '\r'
if self._lastlength > textlen: if self._lastlength > textlen:
text += ' ' * (self._lastlength - textlen) text += ' ' * (self._lastlength - textlen)
self._lastlength = textlen self._lastlength = textlen
else: else:
# otherwise, break the line # otherwise, break the line
self.stream.write('\n') prefix = '\n'
self._lastlength = textlen self._lastlength = textlen
self.stream.write(text) self.write(prefix, text)
self._lastline = pos self._lastline = pos
@lock @lock
def end(self): def end(self):
# move cursor to the end of the last line, and write line break # move cursor to the end of the last line, and write line break
# so that other to_screen calls can precede # so that other to_screen calls can precede
if self._HAVE_FULLCAP: text = self._move_cursor(self.maximum) if self._HAVE_FULLCAP else []
self._move_cursor(self.maximum)
if self.preserve_output: if self.preserve_output:
self.stream.write('\n') self.write(*text, '\n')
return return
if self._HAVE_FULLCAP: if self._HAVE_FULLCAP:
self.stream.write( self.write(
TERMINAL_SEQUENCES['ERASE_LINE'] *text, TERMINAL_SEQUENCES['ERASE_LINE'],
+ f'{TERMINAL_SEQUENCES["UP"]}{TERMINAL_SEQUENCES["ERASE_LINE"]}' * self.maximum) f'{TERMINAL_SEQUENCES["UP"]}{TERMINAL_SEQUENCES["ERASE_LINE"]}' * self.maximum)
else: else:
self.stream.write(' ' * self._lastlength) self.write(*text, ' ' * self._lastlength)

View file

@ -6458,7 +6458,7 @@ def jwt_encode_hs256(payload_data, key, headers={}):
def supports_terminal_sequences(stream): def supports_terminal_sequences(stream):
if compat_os_name == 'nt': if compat_os_name == 'nt':
if get_windows_version() < (10, ): if get_windows_version() < (10, 0, 10586):
return False return False
elif not os.getenv('TERM'): elif not os.getenv('TERM'):
return False return False