Allow passing different arguments to different postprocessors

* Also deprecated --sponskrub-args

Closes: https://github.com/ytdl-org/youtube-dl/issues/27593
Eg: `--postprocessor-args "VideoConvertor:-c:v h264_nvenc -preset slow"`
Eg: `--postprocessor-args "SponsKrub:-include-selfpromo"`

For backward compatibility, `--postprocessor-args args` is equivalent to:
`--post-processor-args "sponskrub:" --post-processor-args "default:args"`
This commit is contained in:
pukkandan 2021-01-08 00:58:41 +05:30
parent 6c40e33c9e
commit 1b77b347d4
11 changed files with 96 additions and 58 deletions

View File

@ -550,7 +550,18 @@ ## Post-Processing Options:
--recode-video FORMAT Re-encode the video into another format if --recode-video FORMAT Re-encode the video into another format if
re-encoding is necessary (currently re-encoding is necessary (currently
supported: mp4|flv|ogg|webm|mkv|avi) supported: mp4|flv|ogg|webm|mkv|avi)
--postprocessor-args ARGS Give these arguments to the postprocessor --postprocessor-args NAME:ARGS Give these arguments to the postprocessors.
Specify the postprocessor name and the
arguments separated by a colon ':' to give
the argument to only the specified
postprocessor. Supported names are
ExtractAudio, VideoRemuxer, VideoConvertor,
EmbedSubtitle, Metadata, Merger,
FixupStretched, FixupM4a, FixupM3u8,
SubtitlesConvertor, SponSkrub and Default.
You can use this option multiple times to
give different arguments to different
postprocessors
-k, --keep-video Keep the intermediate video file on disk -k, --keep-video Keep the intermediate video file on disk
after post-processing after post-processing
--no-keep-video Delete the intermediate video file after --no-keep-video Delete the intermediate video file after

View File

@ -333,8 +333,9 @@ class YoutubeDL(object):
otherwise prefer ffmpeg. otherwise prefer ffmpeg.
ffmpeg_location: Location of the ffmpeg/avconv binary; either the path ffmpeg_location: Location of the ffmpeg/avconv binary; either the path
to the binary or its containing directory. to the binary or its containing directory.
postprocessor_args: A list of additional command-line arguments for the postprocessor_args: A dictionary of postprocessor names (in lower case) and a list
postprocessor. of additional command-line arguments for the postprocessor.
Use 'default' as the name for arguments to passed to all PP.
The following options are used by the Youtube extractor: The following options are used by the Youtube extractor:
youtube_include_dash_manifest: If True (default), DASH manifests and related youtube_include_dash_manifest: If True (default), DASH manifests and related

View File

@ -331,9 +331,23 @@ def parse_retries(retries):
external_downloader_args = None external_downloader_args = None
if opts.external_downloader_args: if opts.external_downloader_args:
external_downloader_args = compat_shlex_split(opts.external_downloader_args) external_downloader_args = compat_shlex_split(opts.external_downloader_args)
postprocessor_args = None
if opts.postprocessor_args: postprocessor_args = {}
postprocessor_args = compat_shlex_split(opts.postprocessor_args) if opts.postprocessor_args is not None:
for string in opts.postprocessor_args:
mobj = re.match(r'(?P<pp>\w+):(?P<args>.*)$', string)
if mobj is None:
if 'sponskrub' not in postprocessor_args: # for backward compatibility
postprocessor_args['sponskrub'] = []
if opts.verbose:
write_string('[debug] Adding postprocessor args from command line option sponskrub:\n')
pp_name, pp_args = 'default', string
else:
pp_name, pp_args = mobj.group('pp').lower(), mobj.group('args')
if opts.verbose:
write_string('[debug] Adding postprocessor args from command line option %s:%s\n' % (pp_name, pp_args))
postprocessor_args[pp_name] = compat_shlex_split(pp_args)
match_filter = ( match_filter = (
None if opts.match_filter is None None if opts.match_filter is None
else match_filter_func(opts.match_filter)) else match_filter_func(opts.match_filter))

View File

@ -970,9 +970,14 @@ def _comma_separated_values_options_callback(option, opt_str, value, parser):
metavar='FORMAT', dest='recodevideo', default=None, metavar='FORMAT', dest='recodevideo', default=None,
help='Re-encode the video into another format if re-encoding is necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)') help='Re-encode the video into another format if re-encoding is necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)')
postproc.add_option( postproc.add_option(
'--postprocessor-args', '--postprocessor-args', metavar='NAME:ARGS',
dest='postprocessor_args', metavar='ARGS', dest='postprocessor_args', action='append',
help='Give these arguments to the postprocessor') help=(
'Give these arguments to the postprocessors. '
"Specify the postprocessor name and the arguments separated by a colon ':' "
'to give the argument to only the specified postprocessor. Supported names are '
'ExtractAudio, VideoRemuxer, VideoConvertor, EmbedSubtitle, Metadata, Merger, FixupStretched, FixupM4a, FixupM3u8, SubtitlesConvertor, SponSkrub and Default'
'. You can use this option multiple times to give different arguments to different postprocessors'))
postproc.add_option( postproc.add_option(
'-k', '--keep-video', '-k', '--keep-video',
action='store_true', dest='keepvideo', default=False, action='store_true', dest='keepvideo', default=False,
@ -1089,7 +1094,7 @@ def _comma_separated_values_options_callback(option, opt_str, value, parser):
help='Location of the sponskrub binary; either the path to the binary or its containing directory.') help='Location of the sponskrub binary; either the path to the binary or its containing directory.')
sponskrub.add_option( sponskrub.add_option(
'--sponskrub-args', dest='sponskrub_args', metavar='ARGS', '--sponskrub-args', dest='sponskrub_args', metavar='ARGS',
help='Give these arguments to sponskrub') help=optparse.SUPPRESS_HELP)
extractor = optparse.OptionGroup(parser, 'Extractor Options') extractor = optparse.OptionGroup(parser, 'Extractor Options')
extractor.add_option( extractor.add_option(

View File

@ -33,6 +33,11 @@ class PostProcessor(object):
def __init__(self, downloader=None): def __init__(self, downloader=None):
self._downloader = downloader self._downloader = downloader
if not hasattr(self, 'PP_NAME'):
self.PP_NAME = self.__class__.__name__[:-2]
def to_screen(self, text, *args, **kwargs):
return self._downloader.to_screen('[%s] %s' % (self.PP_NAME, text), *args, **kwargs)
def set_downloader(self, downloader): def set_downloader(self, downloader):
"""Sets the downloader for this PP.""" """Sets the downloader for this PP."""
@ -62,7 +67,10 @@ def try_utime(self, path, atime, mtime, errnote='Cannot update utime of file'):
self._downloader.report_warning(errnote) self._downloader.report_warning(errnote)
def _configuration_args(self, default=[]): def _configuration_args(self, default=[]):
return cli_configuration_args(self._downloader.params, 'postprocessor_args', default) args = self._downloader.params.get('postprocessor_args', {})
if isinstance(args, list): # for backward compatibility
args = {'default': args, 'sponskrub': []}
return cli_configuration_args(args, self.PP_NAME.lower(), args.get('default', []))
class AudioConversionError(PostProcessingError): class AudioConversionError(PostProcessingError):

View File

@ -23,6 +23,8 @@ class EmbedThumbnailPPError(PostProcessingError):
class EmbedThumbnailPP(FFmpegPostProcessor): class EmbedThumbnailPP(FFmpegPostProcessor):
PP_NAME = 'EmbedThumbnail'
def __init__(self, downloader=None, already_have_thumbnail=False): def __init__(self, downloader=None, already_have_thumbnail=False):
super(EmbedThumbnailPP, self).__init__(downloader) super(EmbedThumbnailPP, self).__init__(downloader)
self._already_have_thumbnail = already_have_thumbnail self._already_have_thumbnail = already_have_thumbnail
@ -32,7 +34,7 @@ def run(self, info):
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
if not info.get('thumbnails'): if not info.get('thumbnails'):
self._downloader.to_screen('[embedthumbnail] There aren\'t any thumbnails to embed') self.to_screen('There aren\'t any thumbnails to embed')
return [], info return [], info
thumbnail_filename = info['thumbnails'][-1]['filename'] thumbnail_filename = info['thumbnails'][-1]['filename']
@ -52,8 +54,7 @@ def is_webp(path):
if thumbnail_ext: if thumbnail_ext:
thumbnail_ext = thumbnail_ext[1:].lower() thumbnail_ext = thumbnail_ext[1:].lower()
if thumbnail_ext != 'webp' and is_webp(thumbnail_filename): if thumbnail_ext != 'webp' and is_webp(thumbnail_filename):
self._downloader.to_screen( self.to_screen('Correcting extension to webp and escaping path for thumbnail "%s"' % thumbnail_filename)
'[ffmpeg] Correcting extension to webp and escaping path for thumbnail "%s"' % thumbnail_filename)
thumbnail_webp_filename = replace_extension(thumbnail_filename, 'webp') thumbnail_webp_filename = replace_extension(thumbnail_filename, 'webp')
os.rename(encodeFilename(thumbnail_filename), encodeFilename(thumbnail_webp_filename)) os.rename(encodeFilename(thumbnail_filename), encodeFilename(thumbnail_webp_filename))
thumbnail_filename = thumbnail_webp_filename thumbnail_filename = thumbnail_webp_filename
@ -66,7 +67,7 @@ def is_webp(path):
escaped_thumbnail_filename = thumbnail_filename.replace('%', '#') escaped_thumbnail_filename = thumbnail_filename.replace('%', '#')
os.rename(encodeFilename(thumbnail_filename), encodeFilename(escaped_thumbnail_filename)) os.rename(encodeFilename(thumbnail_filename), encodeFilename(escaped_thumbnail_filename))
escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg') escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg')
self._downloader.to_screen('[ffmpeg] Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename) self.to_screen('Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename)
self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg']) self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg'])
os.remove(encodeFilename(escaped_thumbnail_filename)) os.remove(encodeFilename(escaped_thumbnail_filename))
thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg') thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg')
@ -79,7 +80,7 @@ def is_webp(path):
'-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3', '-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3',
'-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"'] '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"']
self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options)
@ -99,7 +100,7 @@ def is_webp(path):
'-c', 'copy', '-map', '0', '-dn', '-c', 'copy', '-map', '0', '-dn',
'-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg'] '-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg']
self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
self.run_ffmpeg_multiple_files([filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename], temp_filename, options)
@ -121,7 +122,7 @@ def is_webp(path):
encodeArgument('-o'), encodeArgument('-o'),
encodeFilename(temp_filename, True)] encodeFilename(temp_filename, True)]
self._downloader.to_screen('[atomicparsley] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
if self._downloader.params.get('verbose', False): if self._downloader.params.get('verbose', False):
self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd)) self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd))

View File

@ -11,6 +11,8 @@
class ExecAfterDownloadPP(PostProcessor): class ExecAfterDownloadPP(PostProcessor):
PP_NAME = 'Exec'
def __init__(self, downloader, exec_cmd): def __init__(self, downloader, exec_cmd):
super(ExecAfterDownloadPP, self).__init__(downloader) super(ExecAfterDownloadPP, self).__init__(downloader)
self.exec_cmd = exec_cmd self.exec_cmd = exec_cmd
@ -22,7 +24,7 @@ def run(self, information):
cmd = cmd.replace('{}', compat_shlex_quote(information['filepath'])) cmd = cmd.replace('{}', compat_shlex_quote(information['filepath']))
self._downloader.to_screen('[exec] Executing command: %s' % cmd) self.to_screen('Executing command: %s' % cmd)
retCode = subprocess.call(encodeArgument(cmd), shell=True) retCode = subprocess.call(encodeArgument(cmd), shell=True)
if retCode != 0: if retCode != 0:
raise PostProcessingError( raise PostProcessingError(

View File

@ -53,6 +53,8 @@ class FFmpegPostProcessorError(PostProcessingError):
class FFmpegPostProcessor(PostProcessor): class FFmpegPostProcessor(PostProcessor):
def __init__(self, downloader=None): def __init__(self, downloader=None):
if not hasattr(self, 'PP_NAME'):
self.PP_NAME = self.__class__.__name__[6:-2] # Remove ffmpeg from the front
PostProcessor.__init__(self, downloader) PostProcessor.__init__(self, downloader)
self._determine_executables() self._determine_executables()
@ -328,11 +330,11 @@ def run(self, information):
# If we download foo.mp3 and convert it to... foo.mp3, then don't delete foo.mp3, silly. # If we download foo.mp3 and convert it to... foo.mp3, then don't delete foo.mp3, silly.
if (new_path == path if (new_path == path
or (self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))): or (self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))):
self._downloader.to_screen('[ffmpeg] Post-process file %s exists, skipping' % new_path) self.to_screen('Post-process file %s exists, skipping' % new_path)
return [], information return [], information
try: try:
self._downloader.to_screen('[ffmpeg] Destination: ' + new_path) self.to_screen('Destination: ' + new_path)
self.run_ffmpeg(path, new_path, acodec, more_opts) self.run_ffmpeg(path, new_path, acodec, more_opts)
except AudioConversionError as e: except AudioConversionError as e:
raise PostProcessingError( raise PostProcessingError(
@ -357,12 +359,12 @@ def __init__(self, downloader=None, preferedformat=None):
def run(self, information): def run(self, information):
path = information['filepath'] path = information['filepath']
if information['ext'] == self._preferedformat: if information['ext'] == self._preferedformat:
self._downloader.to_screen('[ffmpeg] Not remuxing video file %s - already is in target format %s' % (path, self._preferedformat)) self.to_screen('Not remuxing video file %s - already is in target format %s' % (path, self._preferedformat))
return [], information return [], information
options = ['-c', 'copy', '-map', '0', '-dn'] options = ['-c', 'copy', '-map', '0', '-dn']
prefix, sep, ext = path.rpartition('.') prefix, sep, ext = path.rpartition('.')
outpath = prefix + sep + self._preferedformat outpath = prefix + sep + self._preferedformat
self._downloader.to_screen('[' + 'ffmpeg' + '] Remuxing video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath) self.to_screen('Remuxing video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
self.run_ffmpeg(path, outpath, options) self.run_ffmpeg(path, outpath, options)
information['filepath'] = outpath information['filepath'] = outpath
information['format'] = self._preferedformat information['format'] = self._preferedformat
@ -378,14 +380,14 @@ def __init__(self, downloader=None, preferedformat=None):
def run(self, information): def run(self, information):
path = information['filepath'] path = information['filepath']
if information['ext'] == self._preferedformat: if information['ext'] == self._preferedformat:
self._downloader.to_screen('[ffmpeg] Not converting video file %s - already is in target format %s' % (path, self._preferedformat)) self.to_screen('Not converting video file %s - already is in target format %s' % (path, self._preferedformat))
return [], information return [], information
options = [] options = []
if self._preferedformat == 'avi': if self._preferedformat == 'avi':
options.extend(['-c:v', 'libxvid', '-vtag', 'XVID']) options.extend(['-c:v', 'libxvid', '-vtag', 'XVID'])
prefix, sep, ext = path.rpartition('.') prefix, sep, ext = path.rpartition('.')
outpath = prefix + sep + self._preferedformat outpath = prefix + sep + self._preferedformat
self._downloader.to_screen('[' + 'ffmpeg' + '] Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath) self.to_screen('Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
self.run_ffmpeg(path, outpath, options) self.run_ffmpeg(path, outpath, options)
information['filepath'] = outpath information['filepath'] = outpath
information['format'] = self._preferedformat information['format'] = self._preferedformat
@ -396,11 +398,11 @@ def run(self, information):
class FFmpegEmbedSubtitlePP(FFmpegPostProcessor): class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
def run(self, information): def run(self, information):
if information['ext'] not in ('mp4', 'webm', 'mkv'): if information['ext'] not in ('mp4', 'webm', 'mkv'):
self._downloader.to_screen('[ffmpeg] Subtitles can only be embedded in mp4, webm or mkv files') self.to_screen('Subtitles can only be embedded in mp4, webm or mkv files')
return [], information return [], information
subtitles = information.get('requested_subtitles') subtitles = information.get('requested_subtitles')
if not subtitles: if not subtitles:
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to embed') self.to_screen('There aren\'t any subtitles to embed')
return [], information return [], information
filename = information['filepath'] filename = information['filepath']
@ -413,14 +415,14 @@ def run(self, information):
for lang, sub_info in subtitles.items(): for lang, sub_info in subtitles.items():
sub_ext = sub_info['ext'] sub_ext = sub_info['ext']
if sub_ext == 'json': if sub_ext == 'json':
self._downloader.to_screen('[ffmpeg] JSON subtitles cannot be embedded') self.to_screen('JSON subtitles cannot be embedded')
elif ext != 'webm' or ext == 'webm' and sub_ext == 'vtt': elif ext != 'webm' or ext == 'webm' and sub_ext == 'vtt':
sub_langs.append(lang) sub_langs.append(lang)
sub_filenames.append(subtitles_filename(filename, lang, sub_ext, ext)) sub_filenames.append(subtitles_filename(filename, lang, sub_ext, ext))
else: else:
if not webm_vtt_warn and ext == 'webm' and sub_ext != 'vtt': if not webm_vtt_warn and ext == 'webm' and sub_ext != 'vtt':
webm_vtt_warn = True webm_vtt_warn = True
self._downloader.to_screen('[ffmpeg] Only WebVTT subtitles can be embedded in webm files') self.to_screen('Only WebVTT subtitles can be embedded in webm files')
if not sub_langs: if not sub_langs:
return [], information return [], information
@ -444,7 +446,7 @@ def run(self, information):
opts.extend(['-metadata:s:s:%d' % i, 'language=%s' % lang_code]) opts.extend(['-metadata:s:s:%d' % i, 'language=%s' % lang_code])
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
self._downloader.to_screen('[ffmpeg] Embedding subtitles in \'%s\'' % filename) self.to_screen('Embedding subtitles in \'%s\'' % filename)
self.run_ffmpeg_multiple_files(input_files, temp_filename, opts) self.run_ffmpeg_multiple_files(input_files, temp_filename, opts)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename)) os.rename(encodeFilename(temp_filename), encodeFilename(filename))
@ -492,7 +494,7 @@ def add(meta_list, info_list=None):
add('episode_sort', 'episode_number') add('episode_sort', 'episode_number')
if not metadata: if not metadata:
self._downloader.to_screen('[ffmpeg] There isn\'t any metadata to add') self.to_screen('There isn\'t any metadata to add')
return [], info return [], info
filename = info['filepath'] filename = info['filepath']
@ -527,7 +529,7 @@ def ffmpeg_escape(text):
in_filenames.append(metadata_filename) in_filenames.append(metadata_filename)
options.extend(['-map_metadata', '1']) options.extend(['-map_metadata', '1'])
self._downloader.to_screen('[ffmpeg] Adding metadata to \'%s\'' % filename) self.to_screen('Adding metadata to \'%s\'' % filename)
self.run_ffmpeg_multiple_files(in_filenames, temp_filename, options) self.run_ffmpeg_multiple_files(in_filenames, temp_filename, options)
if chapters: if chapters:
os.remove(metadata_filename) os.remove(metadata_filename)
@ -546,7 +548,7 @@ def run(self, info):
args.extend(['-map', '%u:a:0' % (i)]) args.extend(['-map', '%u:a:0' % (i)])
if fmt.get('vcodec') != 'none': if fmt.get('vcodec') != 'none':
args.extend(['-map', '%u:v:0' % (i)]) args.extend(['-map', '%u:v:0' % (i)])
self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename) self.to_screen('Merging formats into "%s"' % filename)
self.run_ffmpeg_multiple_files(info['__files_to_merge'], temp_filename, args) self.run_ffmpeg_multiple_files(info['__files_to_merge'], temp_filename, args)
os.rename(encodeFilename(temp_filename), encodeFilename(filename)) os.rename(encodeFilename(temp_filename), encodeFilename(filename))
return info['__files_to_merge'], info return info['__files_to_merge'], info
@ -579,7 +581,7 @@ def run(self, info):
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-dn', '-aspect', '%f' % stretched_ratio] options = ['-c', 'copy', '-map', '0', '-dn', '-aspect', '%f' % stretched_ratio]
self._downloader.to_screen('[ffmpeg] Fixing aspect ratio in "%s"' % filename) self.to_screen('Fixing aspect ratio in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@ -597,7 +599,7 @@ def run(self, info):
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4'] options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4']
self._downloader.to_screen('[ffmpeg] Correcting container in "%s"' % filename) self.to_screen('Correcting container in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@ -613,7 +615,7 @@ def run(self, info):
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc'] options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc']
self._downloader.to_screen('[ffmpeg] Fixing malformed AAC bitstream in "%s"' % filename) self.to_screen('Fixing malformed AAC bitstream in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@ -634,19 +636,18 @@ def run(self, info):
if new_format == 'vtt': if new_format == 'vtt':
new_format = 'webvtt' new_format = 'webvtt'
if subs is None: if subs is None:
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to convert') self.to_screen('There aren\'t any subtitles to convert')
return [], info return [], info
self._downloader.to_screen('[ffmpeg] Converting subtitles') self.to_screen('Converting subtitles')
sub_filenames = [] sub_filenames = []
for lang, sub in subs.items(): for lang, sub in subs.items():
ext = sub['ext'] ext = sub['ext']
if ext == new_ext: if ext == new_ext:
self._downloader.to_screen( self.to_screen('Subtitle file for %s is already in the requested format' % new_ext)
'[ffmpeg] Subtitle file for %s is already in the requested format' % new_ext)
continue continue
elif ext == 'json': elif ext == 'json':
self._downloader.to_screen( self.to_screen(
'[ffmpeg] You have requested to convert json subtitles into another format, ' 'You have requested to convert json subtitles into another format, '
'which is currently not possible') 'which is currently not possible')
continue continue
old_file = subtitles_filename(filename, lang, ext, info.get('ext')) old_file = subtitles_filename(filename, lang, ext, info.get('ext'))
@ -655,7 +656,7 @@ def run(self, info):
if ext in ('dfxp', 'ttml', 'tt'): if ext in ('dfxp', 'ttml', 'tt'):
self._downloader.report_warning( self._downloader.report_warning(
'[ffmpeg] You have requested to convert dfxp (TTML) subtitles into another format, ' 'You have requested to convert dfxp (TTML) subtitles into another format, '
'which results in style information loss') 'which results in style information loss')
dfxp_file = old_file dfxp_file = old_file

View File

@ -35,14 +35,10 @@ def run(self, info):
title = info['title'] title = info['title']
match = re.match(self._titleregex, title) match = re.match(self._titleregex, title)
if match is None: if match is None:
self._downloader.to_screen( self.to_screen('Could not interpret title of video as "%s"' % self._titleformat)
'[fromtitle] Could not interpret title of video as "%s"'
% self._titleformat)
return [], info return [], info
for attribute, value in match.groupdict().items(): for attribute, value in match.groupdict().items():
info[attribute] = value info[attribute] = value
self._downloader.to_screen( self.to_screen('parsed %s: %s' % (attribute, value if value is not None else 'NA'))
'[fromtitle] parsed %s: %s'
% (attribute, value if value is not None else 'NA'))
return [], info return [], info

View File

@ -22,7 +22,7 @@ def __init__(self, downloader, path='', args=None, ignoreerror=False, cut=False,
self.force = force self.force = force
self.cutout = cut self.cutout = cut
self.args = ['-chapter'] if not cut else [] self.args = ['-chapter'] if not cut else []
self.args += self._def_args if args is None else compat_shlex_split(args) self.args += self._configuration_args(self._def_args) if args is None else compat_shlex_split(args)
self.path = self.get_exe(path) self.path = self.get_exe(path)
if not ignoreerror and self.path is None: if not ignoreerror and self.path is None:
@ -43,7 +43,7 @@ def run(self, information):
return [], information return [], information
if information['extractor_key'].lower() != 'youtube': if information['extractor_key'].lower() != 'youtube':
self._downloader.to_screen('[sponskrub] Skipping sponskrub since it is not a YouTube video') self.to_screen('Skipping sponskrub since it is not a YouTube video')
return [], information return [], information
if self.cutout and not self.force and not information.get('__real_download', False): if self.cutout and not self.force and not information.get('__real_download', False):
self._downloader.to_screen( self._downloader.to_screen(
@ -51,7 +51,7 @@ def run(self, information):
'Use --sponskrub-force to run sponskrub anyway') 'Use --sponskrub-force to run sponskrub anyway')
return [], information return [], information
self._downloader.to_screen('[sponskrub] Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark')) self.to_screen('Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark'))
if self.cutout: if self.cutout:
self._downloader.to_screen('WARNING: Cutting out sponsor segments will cause the subtitles to go out of sync.') self._downloader.to_screen('WARNING: Cutting out sponsor segments will cause the subtitles to go out of sync.')
if not information.get('__real_download', False): if not information.get('__real_download', False):
@ -76,11 +76,11 @@ def run(self, information):
if p.returncode == 0: if p.returncode == 0:
os.remove(filename) os.remove(filename)
os.rename(temp_filename, filename) os.rename(temp_filename, filename)
self._downloader.to_screen('[sponskrub] Sponsor sections have been %s' % ('removed' if self.cutout else 'marked')) self.to_screen('Sponsor sections have been %s' % ('removed' if self.cutout else 'marked'))
elif p.returncode != 3: # error code 3 means there was no info about the video elif p.returncode == 3:
self.to_screen('No segments in the SponsorBlock database')
else:
stderr = stderr.decode('utf-8', 'replace') stderr = stderr.decode('utf-8', 'replace')
msg = stderr.strip().split('\n')[-1] msg = stderr.strip().split('\n')[-1]
raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s!' % p.returncode) raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s!' % p.returncode)
else:
self._downloader.to_screen('[sponskrub] No segments in the SponsorBlock database')
return [], information return [], information

View File

@ -11,7 +11,6 @@
class XAttrMetadataPP(PostProcessor): class XAttrMetadataPP(PostProcessor):
# #
# More info about extended attributes for media: # More info about extended attributes for media:
# http://freedesktop.org/wiki/CommonExtendedAttributes/ # http://freedesktop.org/wiki/CommonExtendedAttributes/
@ -27,7 +26,7 @@ def run(self, info):
""" Set extended attributes on downloaded file (if xattr support is found). """ """ Set extended attributes on downloaded file (if xattr support is found). """
# Write the metadata to the file's xattrs # Write the metadata to the file's xattrs
self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs') self.to_screen('Writing metadata to file\'s xattrs')
filename = info['filepath'] filename = info['filepath']