mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-26 02:55:17 +00:00
Refactor (See desc)
* Create `FFmpegPostProcessor.real_run_ffmpeg` that can accept multiple input/output files along with switches for each * Rewrite `cli_configuration_args` and related functions * Create `YoutubeDL._ensure_dir_exists` - this was previously defined in multiple places
This commit is contained in:
parent
ea3a012d2a
commit
e92caff5d5
7 changed files with 56 additions and 49 deletions
|
@ -1171,6 +1171,9 @@ def _fixup(r):
|
||||||
else:
|
else:
|
||||||
raise Exception('Invalid result type: %s' % result_type)
|
raise Exception('Invalid result type: %s' % result_type)
|
||||||
|
|
||||||
|
def _ensure_dir_exists(self, path):
|
||||||
|
return make_dir(path, self.report_error)
|
||||||
|
|
||||||
def __process_playlist(self, ie_result, download):
|
def __process_playlist(self, ie_result, download):
|
||||||
# We process each entry in the playlist
|
# We process each entry in the playlist
|
||||||
playlist = ie_result.get('title') or ie_result.get('id')
|
playlist = ie_result.get('title') or ie_result.get('id')
|
||||||
|
@ -1187,12 +1190,9 @@ def __process_playlist(self, ie_result, download):
|
||||||
}
|
}
|
||||||
ie_copy.update(dict(ie_result))
|
ie_copy.update(dict(ie_result))
|
||||||
|
|
||||||
def ensure_dir_exists(path):
|
|
||||||
return make_dir(path, self.report_error)
|
|
||||||
|
|
||||||
if self.params.get('writeinfojson', False):
|
if self.params.get('writeinfojson', False):
|
||||||
infofn = self.prepare_filename(ie_copy, 'pl_infojson')
|
infofn = self.prepare_filename(ie_copy, 'pl_infojson')
|
||||||
if not ensure_dir_exists(encodeFilename(infofn)):
|
if not self._ensure_dir_exists(encodeFilename(infofn)):
|
||||||
return
|
return
|
||||||
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
|
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
|
||||||
self.to_screen('[info] Playlist metadata is already present')
|
self.to_screen('[info] Playlist metadata is already present')
|
||||||
|
@ -1208,7 +1208,7 @@ def ensure_dir_exists(path):
|
||||||
|
|
||||||
if self.params.get('writedescription', False):
|
if self.params.get('writedescription', False):
|
||||||
descfn = self.prepare_filename(ie_copy, 'pl_description')
|
descfn = self.prepare_filename(ie_copy, 'pl_description')
|
||||||
if not ensure_dir_exists(encodeFilename(descfn)):
|
if not self._ensure_dir_exists(encodeFilename(descfn)):
|
||||||
return
|
return
|
||||||
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
|
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
|
||||||
self.to_screen('[info] Playlist description is already present')
|
self.to_screen('[info] Playlist description is already present')
|
||||||
|
@ -2089,17 +2089,14 @@ def process_info(self, info_dict):
|
||||||
if full_filename is None:
|
if full_filename is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
def ensure_dir_exists(path):
|
if not self._ensure_dir_exists(encodeFilename(full_filename)):
|
||||||
return make_dir(path, self.report_error)
|
|
||||||
|
|
||||||
if not ensure_dir_exists(encodeFilename(full_filename)):
|
|
||||||
return
|
return
|
||||||
if not ensure_dir_exists(encodeFilename(temp_filename)):
|
if not self._ensure_dir_exists(encodeFilename(temp_filename)):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.params.get('writedescription', False):
|
if self.params.get('writedescription', False):
|
||||||
descfn = self.prepare_filename(info_dict, 'description')
|
descfn = self.prepare_filename(info_dict, 'description')
|
||||||
if not ensure_dir_exists(encodeFilename(descfn)):
|
if not self._ensure_dir_exists(encodeFilename(descfn)):
|
||||||
return
|
return
|
||||||
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
|
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
|
||||||
self.to_screen('[info] Video description is already present')
|
self.to_screen('[info] Video description is already present')
|
||||||
|
@ -2116,7 +2113,7 @@ def ensure_dir_exists(path):
|
||||||
|
|
||||||
if self.params.get('writeannotations', False):
|
if self.params.get('writeannotations', False):
|
||||||
annofn = self.prepare_filename(info_dict, 'annotation')
|
annofn = self.prepare_filename(info_dict, 'annotation')
|
||||||
if not ensure_dir_exists(encodeFilename(annofn)):
|
if not self._ensure_dir_exists(encodeFilename(annofn)):
|
||||||
return
|
return
|
||||||
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(annofn)):
|
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(annofn)):
|
||||||
self.to_screen('[info] Video annotations are already present')
|
self.to_screen('[info] Video annotations are already present')
|
||||||
|
@ -2204,7 +2201,7 @@ def dl(name, info, subtitle=False):
|
||||||
|
|
||||||
if self.params.get('writeinfojson', False):
|
if self.params.get('writeinfojson', False):
|
||||||
infofn = self.prepare_filename(info_dict, 'infojson')
|
infofn = self.prepare_filename(info_dict, 'infojson')
|
||||||
if not ensure_dir_exists(encodeFilename(infofn)):
|
if not self._ensure_dir_exists(encodeFilename(infofn)):
|
||||||
return
|
return
|
||||||
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
|
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
|
||||||
self.to_screen('[info] Video metadata is already present')
|
self.to_screen('[info] Video metadata is already present')
|
||||||
|
@ -2360,7 +2357,7 @@ def correct_ext(filename):
|
||||||
fname = prepend_extension(
|
fname = prepend_extension(
|
||||||
self.prepare_filename(new_info, 'temp'),
|
self.prepare_filename(new_info, 'temp'),
|
||||||
'f%s' % f['format_id'], new_info['ext'])
|
'f%s' % f['format_id'], new_info['ext'])
|
||||||
if not ensure_dir_exists(fname):
|
if not self._ensure_dir_exists(fname):
|
||||||
return
|
return
|
||||||
downloaded.append(fname)
|
downloaded.append(fname)
|
||||||
partial_success, real_download = dl(fname, new_info)
|
partial_success, real_download = dl(fname, new_info)
|
||||||
|
|
|
@ -108,7 +108,8 @@ def _valueless_option(self, command_option, param, expected_value=True):
|
||||||
def _configuration_args(self, *args, **kwargs):
|
def _configuration_args(self, *args, **kwargs):
|
||||||
return cli_configuration_args(
|
return cli_configuration_args(
|
||||||
self.params.get('external_downloader_args'),
|
self.params.get('external_downloader_args'),
|
||||||
self.get_basename(), *args, **kwargs)
|
[self.get_basename(), 'default'],
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
def _call_downloader(self, tmpfilename, info_dict):
|
def _call_downloader(self, tmpfilename, info_dict):
|
||||||
""" Either overwrite this or implement _make_cmd """
|
""" Either overwrite this or implement _make_cmd """
|
||||||
|
|
|
@ -91,10 +91,18 @@ def try_utime(self, path, atime, mtime, errnote='Cannot update utime of file'):
|
||||||
except Exception:
|
except Exception:
|
||||||
self.report_warning(errnote)
|
self.report_warning(errnote)
|
||||||
|
|
||||||
def _configuration_args(self, *args, **kwargs):
|
def _configuration_args(self, exe, keys=None, default=[], use_compat=True):
|
||||||
|
pp_key = self.pp_key().lower()
|
||||||
|
exe = exe.lower()
|
||||||
|
root_key = exe if pp_key == exe else '%s+%s' % (pp_key, exe)
|
||||||
|
keys = ['%s%s' % (root_key, k) for k in (keys or [''])]
|
||||||
|
if root_key in keys:
|
||||||
|
keys += [root_key] + ([] if pp_key == exe else [(self.pp_key(), exe)]) + ['default']
|
||||||
|
else:
|
||||||
|
use_compat = False
|
||||||
return cli_configuration_args(
|
return cli_configuration_args(
|
||||||
self._downloader.params.get('postprocessor_args'),
|
self._downloader.params.get('postprocessor_args'),
|
||||||
self.pp_key().lower(), *args, **kwargs)
|
keys, default, use_compat)
|
||||||
|
|
||||||
|
|
||||||
class AudioConversionError(PostProcessingError):
|
class AudioConversionError(PostProcessingError):
|
||||||
|
|
|
@ -139,7 +139,7 @@ def is_webp(path):
|
||||||
encodeFilename(thumbnail_filename, True),
|
encodeFilename(thumbnail_filename, True),
|
||||||
encodeArgument('-o'),
|
encodeArgument('-o'),
|
||||||
encodeFilename(temp_filename, True)]
|
encodeFilename(temp_filename, True)]
|
||||||
cmd += [encodeArgument(o) for o in self._configuration_args(exe='AtomicParsley')]
|
cmd += [encodeArgument(o) for o in self._configuration_args('AtomicParsley')]
|
||||||
|
|
||||||
self.to_screen('Adding thumbnail to "%s"' % filename)
|
self.to_screen('Adding thumbnail to "%s"' % filename)
|
||||||
self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd))
|
self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd))
|
||||||
|
|
|
@ -234,25 +234,35 @@ def get_stream_number(self, path, keys, value):
|
||||||
return num, len(streams)
|
return num, len(streams)
|
||||||
|
|
||||||
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts):
|
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts):
|
||||||
|
return self.real_run_ffmpeg(
|
||||||
|
[(path, []) for path in input_paths],
|
||||||
|
[(out_path, opts)])
|
||||||
|
|
||||||
|
def real_run_ffmpeg(self, input_path_opts, output_path_opts):
|
||||||
self.check_version()
|
self.check_version()
|
||||||
|
|
||||||
oldest_mtime = min(
|
oldest_mtime = min(
|
||||||
os.stat(encodeFilename(path)).st_mtime for path in input_paths)
|
os.stat(encodeFilename(path)).st_mtime for path, _ in input_path_opts)
|
||||||
|
|
||||||
cmd = [encodeFilename(self.executable, True), encodeArgument('-y')]
|
cmd = [encodeFilename(self.executable, True), encodeArgument('-y')]
|
||||||
# avconv does not have repeat option
|
# avconv does not have repeat option
|
||||||
if self.basename == 'ffmpeg':
|
if self.basename == 'ffmpeg':
|
||||||
cmd += [encodeArgument('-loglevel'), encodeArgument('repeat+info')]
|
cmd += [encodeArgument('-loglevel'), encodeArgument('repeat+info')]
|
||||||
|
|
||||||
def make_args(file, pre=[], post=[], *args, **kwargs):
|
def make_args(file, args, name, number):
|
||||||
args = pre + self._configuration_args(*args, **kwargs) + post
|
keys = ['_%s%d' % (name, number), '_%s' % name]
|
||||||
|
if name == 'o' and number == 1:
|
||||||
|
keys.append('')
|
||||||
|
args += self._configuration_args(self.basename, keys)
|
||||||
|
if name == 'i':
|
||||||
|
args.append('-i')
|
||||||
return (
|
return (
|
||||||
[encodeArgument(o) for o in args]
|
[encodeArgument(arg) for arg in args]
|
||||||
+ [encodeFilename(self._ffmpeg_filename_argument(file), True)])
|
+ [encodeFilename(self._ffmpeg_filename_argument(file), True)])
|
||||||
|
|
||||||
for i, path in enumerate(input_paths):
|
for arg_type, path_opts in (('i', input_path_opts), ('o', output_path_opts)):
|
||||||
cmd += make_args(path, post=['-i'], exe='%s_i%d' % (self.basename, i + 1), use_default_arg=False)
|
cmd += [arg for i, o in enumerate(path_opts)
|
||||||
cmd += make_args(out_path, pre=opts, exe=self.basename)
|
for arg in make_args(o[0], o[1], arg_type, i + 1)]
|
||||||
|
|
||||||
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 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
@ -262,7 +272,8 @@ def make_args(file, pre=[], post=[], *args, **kwargs):
|
||||||
if self.get_param('verbose', False):
|
if self.get_param('verbose', False):
|
||||||
self.report_error(stderr)
|
self.report_error(stderr)
|
||||||
raise FFmpegPostProcessorError(stderr.split('\n')[-1])
|
raise FFmpegPostProcessorError(stderr.split('\n')[-1])
|
||||||
self.try_utime(out_path, oldest_mtime, oldest_mtime)
|
for out_path, _ in output_path_opts:
|
||||||
|
self.try_utime(out_path, oldest_mtime, oldest_mtime)
|
||||||
return stderr.decode('utf-8', 'replace')
|
return stderr.decode('utf-8', 'replace')
|
||||||
|
|
||||||
def run_ffmpeg(self, path, out_path, opts):
|
def run_ffmpeg(self, path, out_path, opts):
|
||||||
|
|
|
@ -71,7 +71,7 @@ def run(self, information):
|
||||||
if not self.cutout:
|
if not self.cutout:
|
||||||
cmd += ['-chapter']
|
cmd += ['-chapter']
|
||||||
cmd += compat_shlex_split(self.args) # For backward compatibility
|
cmd += compat_shlex_split(self.args) # For backward compatibility
|
||||||
cmd += self._configuration_args(exe=self._exe_name, use_default_arg='no_compat')
|
cmd += self._configuration_args(self._exe_name, use_compat=False)
|
||||||
cmd += ['--', information['id'], filename, temp_filename]
|
cmd += ['--', information['id'], filename, temp_filename]
|
||||||
cmd = [encodeArgument(i) for i in cmd]
|
cmd = [encodeArgument(i) for i in cmd]
|
||||||
|
|
||||||
|
|
|
@ -4692,36 +4692,26 @@ def cli_valueless_option(params, command_option, param, expected_value=True):
|
||||||
return [command_option] if param == expected_value else []
|
return [command_option] if param == expected_value else []
|
||||||
|
|
||||||
|
|
||||||
def cli_configuration_args(argdict, key, default=[], exe=None, use_default_arg=True):
|
def cli_configuration_args(argdict, keys, default=[], use_compat=True):
|
||||||
# use_default_arg can be True, False, or 'no_compat'
|
|
||||||
if isinstance(argdict, (list, tuple)): # for backward compatibility
|
if isinstance(argdict, (list, tuple)): # for backward compatibility
|
||||||
if use_default_arg is True:
|
if use_compat:
|
||||||
return argdict
|
return argdict
|
||||||
else:
|
else:
|
||||||
argdict = None
|
argdict = None
|
||||||
|
|
||||||
if argdict is None:
|
if argdict is None:
|
||||||
return default
|
return default
|
||||||
assert isinstance(argdict, dict)
|
assert isinstance(argdict, dict)
|
||||||
|
|
||||||
key = key.lower()
|
assert isinstance(keys, (list, tuple))
|
||||||
args = exe_args = None
|
for key_list in keys:
|
||||||
if exe is not None:
|
if isinstance(key_list, compat_str):
|
||||||
assert isinstance(exe, compat_str)
|
key_list = (key_list,)
|
||||||
exe = exe.lower()
|
arg_list = list(filter(
|
||||||
args = argdict.get('%s+%s' % (key, exe))
|
lambda x: x is not None,
|
||||||
if args is None:
|
[argdict.get(key.lower()) for key in key_list]))
|
||||||
exe_args = argdict.get(exe)
|
if arg_list:
|
||||||
|
return [arg for args in arg_list for arg in args]
|
||||||
if args is None:
|
return default
|
||||||
args = argdict.get(key) if key != exe else None
|
|
||||||
if args is None and exe_args is None:
|
|
||||||
args = argdict.get('default', default) if use_default_arg else default
|
|
||||||
|
|
||||||
args, exe_args = args or [], exe_args or []
|
|
||||||
assert isinstance(args, (list, tuple))
|
|
||||||
assert isinstance(exe_args, (list, tuple))
|
|
||||||
return args + exe_args
|
|
||||||
|
|
||||||
|
|
||||||
class ISO639Utils(object):
|
class ISO639Utils(object):
|
||||||
|
|
Loading…
Reference in a new issue