mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-22 16:31:41 +00:00
parent
f279aaee8e
commit
dac5df5a98
@ -431,7 +431,7 @@ class YoutubeDL(object):
|
||||
compat_opts: Compatibility options. See "Differences in default behavior".
|
||||
The following options do not work when used through the API:
|
||||
filename, abort-on-error, multistreams, no-live-chat, format-sort
|
||||
no-clean-infojson, no-playlist-metafiles, no-keep-subs.
|
||||
no-clean-infojson, no-playlist-metafiles, no-keep-subs, no-attach-info-json.
|
||||
Refer __init__.py for their implementation
|
||||
progress_template: Dictionary of templates for progress outputs.
|
||||
Allowed keys are 'download', 'postprocess',
|
||||
@ -2654,6 +2654,8 @@ def process_info(self, info_dict):
|
||||
infofn = self.prepare_filename(info_dict, 'infojson')
|
||||
_infojson_written = self._write_info_json('video', info_dict, infofn)
|
||||
if _infojson_written:
|
||||
info_dict['infojson_filename'] = infofn
|
||||
# For backward compatability, even though it was a private field
|
||||
info_dict['__infojson_filename'] = infofn
|
||||
elif _infojson_written is None:
|
||||
return
|
||||
@ -3012,8 +3014,8 @@ def sanitize_info(info_dict, remove_private_keys=False):
|
||||
keep_keys = ['_type'] # Always keep this to facilitate load-info-json
|
||||
if remove_private_keys:
|
||||
remove_keys |= {
|
||||
'requested_formats', 'requested_subtitles', 'requested_entries',
|
||||
'filepath', 'entries', 'original_url', 'playlist_autonumber',
|
||||
'requested_formats', 'requested_subtitles', 'requested_entries', 'entries',
|
||||
'filepath', 'infojson_filename', 'original_url', 'playlist_autonumber',
|
||||
}
|
||||
empty_values = (None, {}, [], set(), tuple())
|
||||
reject = lambda k, v: k not in keep_keys and (
|
||||
|
@ -290,6 +290,11 @@ def set_default_compat(compat_name, opt_name, default=True, remove_compat=True):
|
||||
set_default_compat('abort-on-error', 'ignoreerrors', 'only_download')
|
||||
set_default_compat('no-playlist-metafiles', 'allow_playlist_files')
|
||||
set_default_compat('no-clean-infojson', 'clean_infojson')
|
||||
if 'no-attach-info-json' in compat_opts:
|
||||
if opts.embed_infojson:
|
||||
_unused_compat_opt('no-attach-info-json')
|
||||
else:
|
||||
opts.embed_infojson = False
|
||||
if 'format-sort' in compat_opts:
|
||||
opts.format_sort.extend(InfoExtractor.FormatSort.ytdl_default)
|
||||
_video_multistreams_set = set_default_compat('multistreams', 'allow_multiple_video_streams', False, remove_compat=False)
|
||||
@ -526,11 +531,14 @@ def metadataparser_actions(f):
|
||||
# By default ffmpeg preserves metadata applicable for both
|
||||
# source and target containers. From this point the container won't change,
|
||||
# so metadata can be added here.
|
||||
if opts.addmetadata or opts.addchapters:
|
||||
if opts.addmetadata or opts.addchapters or opts.embed_infojson:
|
||||
if opts.embed_infojson is None:
|
||||
opts.embed_infojson = 'if_exists'
|
||||
postprocessors.append({
|
||||
'key': 'FFmpegMetadata',
|
||||
'add_chapters': opts.addchapters,
|
||||
'add_metadata': opts.addmetadata,
|
||||
'add_infojson': opts.embed_infojson,
|
||||
})
|
||||
# Note: Deprecated
|
||||
# This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment
|
||||
|
@ -1287,7 +1287,9 @@ def _dict_from_options_callback(
|
||||
postproc.add_option(
|
||||
'--embed-metadata', '--add-metadata',
|
||||
action='store_true', dest='addmetadata', default=False,
|
||||
help='Embed metadata to the video file. Also adds chapters to file unless --no-add-chapters is used (Alias: --add-metadata)')
|
||||
help=(
|
||||
'Embed metadata to the video file. Also embeds chapters/infojson if present '
|
||||
'unless --no-embed-chapters/--no-embed-info-json are used (Alias: --add-metadata)'))
|
||||
postproc.add_option(
|
||||
'--no-embed-metadata', '--no-add-metadata',
|
||||
action='store_false', dest='addmetadata',
|
||||
@ -1300,6 +1302,14 @@ def _dict_from_options_callback(
|
||||
'--no-embed-chapters', '--no-add-chapters',
|
||||
action='store_false', dest='addchapters',
|
||||
help='Do not add chapter markers (default) (Alias: --no-add-chapters)')
|
||||
postproc.add_option(
|
||||
'--embed-info-json',
|
||||
action='store_true', dest='embed_infojson', default=None,
|
||||
help='Embed the infojson as an attachment to mkv/mka video files')
|
||||
postproc.add_option(
|
||||
'--no-embed-info-json',
|
||||
action='store_false', dest='embed_infojson',
|
||||
help='Do not embed the infojson as an attachment to the video file')
|
||||
postproc.add_option(
|
||||
'--metadata-from-title',
|
||||
metavar='FORMAT', dest='metafromtitle',
|
||||
|
@ -28,6 +28,7 @@
|
||||
shell_quote,
|
||||
traverse_obj,
|
||||
variadic,
|
||||
write_json_file,
|
||||
)
|
||||
|
||||
|
||||
@ -636,10 +637,11 @@ def run(self, information):
|
||||
|
||||
class FFmpegMetadataPP(FFmpegPostProcessor):
|
||||
|
||||
def __init__(self, downloader, add_metadata=True, add_chapters=True):
|
||||
def __init__(self, downloader, add_metadata=True, add_chapters=True, add_infojson='if_exists'):
|
||||
FFmpegPostProcessor.__init__(self, downloader)
|
||||
self._add_metadata = add_metadata
|
||||
self._add_chapters = add_chapters
|
||||
self._add_infojson = add_infojson
|
||||
|
||||
@staticmethod
|
||||
def _options(target_ext):
|
||||
@ -652,13 +654,23 @@ def _options(target_ext):
|
||||
@PostProcessor._restrict_to(images=False)
|
||||
def run(self, info):
|
||||
filename, metadata_filename = info['filepath'], None
|
||||
options = []
|
||||
files_to_delete, options = [], []
|
||||
if self._add_chapters and info.get('chapters'):
|
||||
metadata_filename = replace_extension(filename, 'meta')
|
||||
options.extend(self._get_chapter_opts(info['chapters'], metadata_filename))
|
||||
files_to_delete.append(metadata_filename)
|
||||
if self._add_metadata:
|
||||
options.extend(self._get_metadata_opts(info))
|
||||
|
||||
if self._add_infojson:
|
||||
if info['ext'] in ('mkv', 'mka'):
|
||||
infojson_filename = info.get('infojson_filename')
|
||||
options.extend(self._get_infojson_opts(info, infojson_filename))
|
||||
if not infojson_filename:
|
||||
files_to_delete.append(info.get('infojson_filename'))
|
||||
elif self._add_infojson is True:
|
||||
self.to_screen('The info-json can only be attached to mkv/mka files')
|
||||
|
||||
if not options:
|
||||
self.to_screen('There isn\'t any metadata to add')
|
||||
return [], info
|
||||
@ -668,8 +680,8 @@ def run(self, info):
|
||||
self.run_ffmpeg_multiple_files(
|
||||
(filename, metadata_filename), temp_filename,
|
||||
itertools.chain(self._options(info['ext']), *options))
|
||||
if metadata_filename:
|
||||
os.remove(metadata_filename)
|
||||
for file in filter(None, files_to_delete):
|
||||
os.remove(file) # Don't obey --keep-files
|
||||
os.replace(temp_filename, filename)
|
||||
return [], info
|
||||
|
||||
@ -741,15 +753,26 @@ def add(meta_list, info_list=None):
|
||||
yield ('-metadata:s:%d' % (stream_idx + i), 'language=%s' % lang)
|
||||
stream_idx += stream_count
|
||||
|
||||
if ('no-attach-info-json' not in self.get_param('compat_opts', [])
|
||||
and '__infojson_filename' in info and info['ext'] in ('mkv', 'mka')):
|
||||
old_stream, new_stream = self.get_stream_number(info['filepath'], ('tags', 'mimetype'), 'application/json')
|
||||
if old_stream is not None:
|
||||
yield ('-map', '-0:%d' % old_stream)
|
||||
new_stream -= 1
|
||||
def _get_infojson_opts(self, info, infofn):
|
||||
if not infofn or not os.path.exists(infofn):
|
||||
if self._add_infojson is not True:
|
||||
return
|
||||
infofn = infofn or '%s.temp' % (
|
||||
self._downloader.prepare_filename(info, 'infojson')
|
||||
or replace_extension(self._downloader.prepare_filename(info), 'info.json', info['ext']))
|
||||
if not self._downloader._ensure_dir_exists(infofn):
|
||||
return
|
||||
self.write_debug(f'Writing info-json to: {infofn}')
|
||||
write_json_file(self._downloader.sanitize_info(info, self.get_param('clean_infojson', True)), infofn)
|
||||
info['infojson_filename'] = infofn
|
||||
|
||||
yield ('-attach', info['__infojson_filename'],
|
||||
'-metadata:s:%d' % new_stream, 'mimetype=application/json')
|
||||
old_stream, new_stream = self.get_stream_number(info['filepath'], ('tags', 'mimetype'), 'application/json')
|
||||
if old_stream is not None:
|
||||
yield ('-map', '-0:%d' % old_stream)
|
||||
new_stream -= 1
|
||||
|
||||
yield ('-attach', infofn,
|
||||
'-metadata:s:%d' % new_stream, 'mimetype=application/json')
|
||||
|
||||
|
||||
class FFmpegMergerPP(FFmpegPostProcessor):
|
||||
|
Loading…
Reference in New Issue
Block a user