Don't create console for subprocesses on Windows (#1261)

Closes #1251
This commit is contained in:
pukkandan 2021-10-20 21:49:40 +05:30 committed by GitHub
parent b4b855ebc7
commit d3c93ec2b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 63 additions and 58 deletions

View File

@ -87,10 +87,10 @@ from .utils import (
parse_filesize, parse_filesize,
PerRequestProxyHandler, PerRequestProxyHandler,
platform_name, platform_name,
Popen,
PostProcessingError, PostProcessingError,
preferredencoding, preferredencoding,
prepend_extension, prepend_extension,
process_communicate_or_kill,
register_socks_protocols, register_socks_protocols,
RejectedVideoReached, RejectedVideoReached,
render_table, render_table,
@ -578,12 +578,9 @@ class YoutubeDL(object):
stdout=slave, stdout=slave,
stderr=self._err_file) stderr=self._err_file)
try: try:
self._output_process = subprocess.Popen( self._output_process = Popen(['bidiv'] + width_args, **sp_kwargs)
['bidiv'] + width_args, **sp_kwargs
)
except OSError: except OSError:
self._output_process = subprocess.Popen( self._output_process = Popen(['fribidi', '-c', 'UTF-8'] + width_args, **sp_kwargs)
['fribidi', '-c', 'UTF-8'] + width_args, **sp_kwargs)
self._output_channel = os.fdopen(master, 'rb') self._output_channel = os.fdopen(master, 'rb')
except OSError as ose: except OSError as ose:
if ose.errno == errno.ENOENT: if ose.errno == errno.ENOENT:
@ -3280,11 +3277,11 @@ class YoutubeDL(object):
if self.params.get('compat_opts'): if self.params.get('compat_opts'):
write_debug('Compatibility options: %s\n' % ', '.join(self.params.get('compat_opts'))) write_debug('Compatibility options: %s\n' % ', '.join(self.params.get('compat_opts')))
try: try:
sp = subprocess.Popen( sp = Popen(
['git', 'rev-parse', '--short', 'HEAD'], ['git', 'rev-parse', '--short', 'HEAD'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
cwd=os.path.dirname(os.path.abspath(__file__))) cwd=os.path.dirname(os.path.abspath(__file__)))
out, err = process_communicate_or_kill(sp) out, err = sp.communicate_or_kill()
out = out.decode().strip() out = out.decode().strip()
if re.match('[0-9a-f]+', out): if re.match('[0-9a-f]+', out):
write_debug('Git HEAD: %s\n' % out) write_debug('Git HEAD: %s\n' % out)

View File

@ -17,7 +17,7 @@ from .compat import (
from .utils import ( from .utils import (
bug_reports_message, bug_reports_message,
expand_path, expand_path,
process_communicate_or_kill, Popen,
YoutubeDLCookieJar, YoutubeDLCookieJar,
) )
@ -599,14 +599,14 @@ def _get_mac_keyring_password(browser_keyring_name, logger):
return password.encode('utf-8') return password.encode('utf-8')
else: else:
logger.debug('using find-generic-password to obtain password') logger.debug('using find-generic-password to obtain password')
proc = subprocess.Popen(['security', 'find-generic-password', proc = Popen(
'-w', # write password to stdout ['security', 'find-generic-password',
'-a', browser_keyring_name, # match 'account' '-w', # write password to stdout
'-s', '{} Safe Storage'.format(browser_keyring_name)], # match 'service' '-a', browser_keyring_name, # match 'account'
stdout=subprocess.PIPE, '-s', '{} Safe Storage'.format(browser_keyring_name)], # match 'service'
stderr=subprocess.DEVNULL) stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
try: try:
stdout, stderr = process_communicate_or_kill(proc) stdout, stderr = proc.communicate_or_kill()
if stdout[-1:] == b'\n': if stdout[-1:] == b'\n':
stdout = stdout[:-1] stdout = stdout[:-1]
return stdout return stdout

View File

@ -22,7 +22,7 @@ from ..utils import (
handle_youtubedl_headers, handle_youtubedl_headers,
check_executable, check_executable,
is_outdated_version, is_outdated_version,
process_communicate_or_kill, Popen,
sanitize_open, sanitize_open,
) )
@ -116,9 +116,8 @@ class ExternalFD(FragmentFD):
self._debug_cmd(cmd) self._debug_cmd(cmd)
if 'fragments' not in info_dict: if 'fragments' not in info_dict:
p = subprocess.Popen( p = Popen(cmd, stderr=subprocess.PIPE)
cmd, stderr=subprocess.PIPE) _, stderr = p.communicate_or_kill()
_, stderr = process_communicate_or_kill(p)
if p.returncode != 0: if p.returncode != 0:
self.to_stderr(stderr.decode('utf-8', 'replace')) self.to_stderr(stderr.decode('utf-8', 'replace'))
return p.returncode return p.returncode
@ -128,9 +127,8 @@ class ExternalFD(FragmentFD):
count = 0 count = 0
while count <= fragment_retries: while count <= fragment_retries:
p = subprocess.Popen( p = Popen(cmd, stderr=subprocess.PIPE)
cmd, stderr=subprocess.PIPE) _, stderr = p.communicate_or_kill()
_, stderr = process_communicate_or_kill(p)
if p.returncode == 0: if p.returncode == 0:
break break
# TODO: Decide whether to retry based on error code # TODO: Decide whether to retry based on error code
@ -199,8 +197,8 @@ class CurlFD(ExternalFD):
self._debug_cmd(cmd) self._debug_cmd(cmd)
# curl writes the progress to stderr so don't capture it. # curl writes the progress to stderr so don't capture it.
p = subprocess.Popen(cmd) p = Popen(cmd)
process_communicate_or_kill(p) p.communicate_or_kill()
return p.returncode return p.returncode
@ -476,7 +474,7 @@ class FFmpegFD(ExternalFD):
args.append(encodeFilename(ffpp._ffmpeg_filename_argument(tmpfilename), True)) args.append(encodeFilename(ffpp._ffmpeg_filename_argument(tmpfilename), True))
self._debug_cmd(args) self._debug_cmd(args)
proc = subprocess.Popen(args, stdin=subprocess.PIPE, env=env) proc = Popen(args, stdin=subprocess.PIPE, env=env)
if url in ('-', 'pipe:'): if url in ('-', 'pipe:'):
self.on_process_started(proc, proc.stdin) self.on_process_started(proc, proc.stdin)
try: try:
@ -488,7 +486,7 @@ class FFmpegFD(ExternalFD):
# streams). Note that Windows is not affected and produces playable # streams). Note that Windows is not affected and produces playable
# files (see https://github.com/ytdl-org/youtube-dl/issues/8300). # files (see https://github.com/ytdl-org/youtube-dl/issues/8300).
if isinstance(e, KeyboardInterrupt) and sys.platform != 'win32' and url not in ('-', 'pipe:'): if isinstance(e, KeyboardInterrupt) and sys.platform != 'win32' and url not in ('-', 'pipe:'):
process_communicate_or_kill(proc, b'q') proc.communicate_or_kill(b'q')
else: else:
proc.kill() proc.kill()
proc.wait() proc.wait()

View File

@ -12,6 +12,7 @@ from ..utils import (
encodeFilename, encodeFilename,
encodeArgument, encodeArgument,
get_exe_version, get_exe_version,
Popen,
) )
@ -26,7 +27,7 @@ class RtmpFD(FileDownloader):
start = time.time() start = time.time()
resume_percent = None resume_percent = None
resume_downloaded_data_len = None resume_downloaded_data_len = None
proc = subprocess.Popen(args, stderr=subprocess.PIPE) proc = Popen(args, stderr=subprocess.PIPE)
cursor_in_new_line = True cursor_in_new_line = True
proc_stderr_closed = False proc_stderr_closed = False
try: try:

View File

@ -17,7 +17,7 @@ from ..utils import (
get_exe_version, get_exe_version,
is_outdated_version, is_outdated_version,
std_headers, std_headers,
process_communicate_or_kill, Popen,
) )
@ -223,11 +223,10 @@ class PhantomJSwrapper(object):
else: else:
self.extractor.to_screen('%s: %s' % (video_id, note2)) self.extractor.to_screen('%s: %s' % (video_id, note2))
p = subprocess.Popen([ p = Popen(
self.exe, '--ssl-protocol=any', [self.exe, '--ssl-protocol=any', self._TMP_FILES['script'].name],
self._TMP_FILES['script'].name stdout=subprocess.PIPE, stderr=subprocess.PIPE)
], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate_or_kill()
out, err = process_communicate_or_kill(p)
if p.returncode != 0: if p.returncode != 0:
raise ExtractorError( raise ExtractorError(
'Executing JS failed\n:' + encodeArgument(err)) 'Executing JS failed\n:' + encodeArgument(err))

View File

@ -26,9 +26,9 @@ from ..utils import (
encodeArgument, encodeArgument,
encodeFilename, encodeFilename,
error_to_compat_str, error_to_compat_str,
Popen,
PostProcessingError, PostProcessingError,
prepend_extension, prepend_extension,
process_communicate_or_kill,
shell_quote, shell_quote,
) )
@ -183,8 +183,8 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
self._report_run('atomicparsley', filename) self._report_run('atomicparsley', filename)
self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd)) self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process_communicate_or_kill(p) stdout, stderr = p.communicate_or_kill()
if p.returncode != 0: if p.returncode != 0:
msg = stderr.decode('utf-8', 'replace').strip() msg = stderr.decode('utf-8', 'replace').strip()
raise EmbedThumbnailPPError(msg) raise EmbedThumbnailPPError(msg)

View File

@ -20,9 +20,9 @@ from ..utils import (
is_outdated_version, is_outdated_version,
ISO639Utils, ISO639Utils,
orderedSet, orderedSet,
Popen,
PostProcessingError, PostProcessingError,
prepend_extension, prepend_extension,
process_communicate_or_kill,
replace_extension, replace_extension,
shell_quote, shell_quote,
traverse_obj, traverse_obj,
@ -178,10 +178,8 @@ class FFmpegPostProcessor(PostProcessor):
encodeArgument('-i')] encodeArgument('-i')]
cmd.append(encodeFilename(self._ffmpeg_filename_argument(path), True)) cmd.append(encodeFilename(self._ffmpeg_filename_argument(path), True))
self.write_debug('%s command line: %s' % (self.basename, shell_quote(cmd))) self.write_debug('%s command line: %s' % (self.basename, shell_quote(cmd)))
handle = subprocess.Popen( handle = Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
cmd, stderr=subprocess.PIPE, stdout_data, stderr_data = handle.communicate_or_kill()
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
stdout_data, stderr_data = process_communicate_or_kill(handle)
expected_ret = 0 if self.probe_available else 1 expected_ret = 0 if self.probe_available else 1
if handle.wait() != expected_ret: if handle.wait() != expected_ret:
return None return None
@ -223,7 +221,7 @@ class FFmpegPostProcessor(PostProcessor):
cmd += opts cmd += opts
cmd.append(encodeFilename(self._ffmpeg_filename_argument(path), True)) cmd.append(encodeFilename(self._ffmpeg_filename_argument(path), True))
self.write_debug('ffprobe command line: %s' % shell_quote(cmd)) self.write_debug('ffprobe command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
return json.loads(stdout.decode('utf-8', 'replace')) return json.loads(stdout.decode('utf-8', 'replace'))
@ -284,8 +282,8 @@ class FFmpegPostProcessor(PostProcessor):
for i, (path, opts) in enumerate(path_opts) if path) for i, (path, opts) in enumerate(path_opts) if path)
self.write_debug('ffmpeg command line: %s' % shell_quote(cmd)) self.write_debug('ffmpeg command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
stdout, stderr = process_communicate_or_kill(p) stdout, stderr = p.communicate_or_kill()
if p.returncode not in variadic(expected_retcodes): if p.returncode not in variadic(expected_retcodes):
stderr = stderr.decode('utf-8', 'replace').strip() stderr = stderr.decode('utf-8', 'replace').strip()
self.write_debug(stderr) self.write_debug(stderr)

View File

@ -11,9 +11,9 @@ from ..utils import (
encodeFilename, encodeFilename,
shell_quote, shell_quote,
str_or_none, str_or_none,
Popen,
PostProcessingError, PostProcessingError,
prepend_extension, prepend_extension,
process_communicate_or_kill,
) )
@ -81,8 +81,8 @@ class SponSkrubPP(PostProcessor):
self.write_debug('sponskrub command line: %s' % shell_quote(cmd)) self.write_debug('sponskrub command line: %s' % shell_quote(cmd))
pipe = None if self.get_param('verbose') else subprocess.PIPE pipe = None if self.get_param('verbose') else subprocess.PIPE
p = subprocess.Popen(cmd, stdout=pipe) p = Popen(cmd, stdout=pipe)
stdout = process_communicate_or_kill(p)[0] stdout = p.communicate_or_kill()[0]
if p.returncode == 0: if p.returncode == 0:
os.replace(temp_filename, filename) os.replace(temp_filename, filename)

View File

@ -10,7 +10,7 @@ import traceback
from zipimport import zipimporter from zipimport import zipimporter
from .compat import compat_realpath from .compat import compat_realpath
from .utils import encode_compat_str from .utils import encode_compat_str, Popen
from .version import __version__ from .version import __version__
@ -191,7 +191,7 @@ def run_update(ydl):
return return
try: try:
# Continues to run in the background # Continues to run in the background
subprocess.Popen( Popen(
'ping 127.0.0.1 -n 5 -w 1000 & del /F "%s.old"' % exe, 'ping 127.0.0.1 -n 5 -w 1000 & del /F "%s.old"' % exe,
shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
ydl.to_screen('Updated yt-dlp to version %s' % version_id) ydl.to_screen('Updated yt-dlp to version %s' % version_id)

View File

@ -2272,6 +2272,20 @@ def process_communicate_or_kill(p, *args, **kwargs):
raise raise
class Popen(subprocess.Popen):
if sys.platform == 'win32':
_startupinfo = subprocess.STARTUPINFO()
_startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
_startupinfo = None
def __init__(self, *args, **kwargs):
super(Popen, self).__init__(*args, **kwargs, startupinfo=self._startupinfo)
def communicate_or_kill(self, *args, **kwargs):
return process_communicate_or_kill(self, *args, **kwargs)
def get_subprocess_encoding(): def get_subprocess_encoding():
if sys.platform == 'win32' and sys.getwindowsversion()[0] >= 5: if sys.platform == 'win32' and sys.getwindowsversion()[0] >= 5:
# For subprocess calls, encode with locale encoding # For subprocess calls, encode with locale encoding
@ -3977,8 +3991,7 @@ def check_executable(exe, args=[]):
""" Checks if the given binary is installed somewhere in PATH, and returns its name. """ Checks if the given binary is installed somewhere in PATH, and returns its name.
args can be a list of arguments for a short output (like -version) """ args can be a list of arguments for a short output (like -version) """
try: try:
process_communicate_or_kill(subprocess.Popen( Popen([exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate_or_kill()
[exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE))
except OSError: except OSError:
return False return False
return exe return exe
@ -3992,10 +4005,9 @@ def get_exe_version(exe, args=['--version'],
# STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers # STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers
# SIGTTOU if yt-dlp is run in the background. # SIGTTOU if yt-dlp is run in the background.
# See https://github.com/ytdl-org/youtube-dl/issues/955#issuecomment-209789656 # See https://github.com/ytdl-org/youtube-dl/issues/955#issuecomment-209789656
out, _ = process_communicate_or_kill(subprocess.Popen( out, _ = Popen(
[encodeArgument(exe)] + args, [encodeArgument(exe)] + args, stdin=subprocess.PIPE,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate_or_kill()
stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
except OSError: except OSError:
return False return False
if isinstance(out, bytes): # Python 2.x if isinstance(out, bytes): # Python 2.x
@ -6155,11 +6167,11 @@ def write_xattr(path, key, value):
+ [encodeFilename(path, True)]) + [encodeFilename(path, True)])
try: try:
p = subprocess.Popen( p = Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
except EnvironmentError as e: except EnvironmentError as e:
raise XAttrMetadataError(e.errno, e.strerror) raise XAttrMetadataError(e.errno, e.strerror)
stdout, stderr = process_communicate_or_kill(p) stdout, stderr = p.communicate_or_kill()
stderr = stderr.decode('utf-8', 'replace') stderr = stderr.decode('utf-8', 'replace')
if p.returncode != 0: if p.returncode != 0:
raise XAttrMetadataError(p.returncode, stderr) raise XAttrMetadataError(p.returncode, stderr)