X-Git-Url: https://jfr.im/git/yt-dlp.git/blobdiff_plain/87ea7dfc04a63a4ef80786ade1f0de93c6fe7fcd..b5c5d84f60addd49a010a1f485d28f1b41676631:/yt_dlp/YoutubeDL.py diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index df6306fd0..ad96cebcd 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -101,7 +101,7 @@ strftime_or_none, subtitles_filename, to_high_limit_path, - traverse_dict, + traverse_obj, UnavailableVideoError, url_basename, version_tuple, @@ -813,6 +813,19 @@ def parse_outtmpl(self): 'Put from __future__ import unicode_literals at the top of your code file or consider switching to Python 3.x.') return outtmpl_dict + @staticmethod + def validate_outtmpl(tmpl): + ''' @return None or Exception object ''' + try: + re.sub( + STR_FORMAT_RE.format(''), + lambda mobj: ('%' if not mobj.group('has_key') else '') + mobj.group(0), + tmpl + ) % collections.defaultdict(int) + return None + except ValueError as err: + return err + def prepare_outtmpl(self, outtmpl, info_dict, sanitize=None): """ Make the template and info_dict suitable for substitution (outtmpl % info_dict)""" info_dict = dict(info_dict) @@ -852,10 +865,12 @@ def prepare_outtmpl(self, outtmpl, info_dict, sanitize=None): } tmpl_dict = {} + get_key = lambda k: traverse_obj( + info_dict, k.split('.'), is_user_input=True, traverse_string=True) + def get_value(mdict): # Object traversal - fields = mdict['fields'].split('.') - value = traverse_dict(info_dict, fields) + value = get_key(mdict['fields']) # Negative if mdict['negate']: value = float_or_none(value) @@ -872,7 +887,7 @@ def get_value(mdict): item, multiplier = (item[1:], -1) if item[0] == '-' else (item, 1) offset = float_or_none(item) if offset is None: - offset = float_or_none(traverse_dict(info_dict, item.split('.'))) + offset = float_or_none(get_key(item)) try: value = operator(value, multiplier * offset) except (TypeError, ZeroDivisionError): @@ -906,7 +921,13 @@ def create_key(outer_mobj): value = default if value is None else value key += '\0%s' % fmt - if fmt[-1] not in 'crs': # numeric + if fmt == 'c': + value = compat_str(value) + if value is None: + value, fmt = default, 's' + else: + value = value[0] + elif fmt[-1] not in 'rs': # numeric value = float_or_none(value) if value is None: value, fmt = default, 's' @@ -1144,6 +1165,7 @@ def add_default_extra_info(self, ie_result, ie, url): self.add_extra_info(ie_result, { 'extractor': ie.IE_NAME, 'webpage_url': url, + 'original_url': url, 'webpage_url_basename': url_basename(url), 'extractor_key': ie.ie_key(), }) @@ -1163,7 +1185,11 @@ def process_ie_result(self, ie_result, download=True, extra_info={}): extract_flat = self.params.get('extract_flat', False) if ((extract_flat == 'in_playlist' and 'playlist' in extra_info) or extract_flat is True): - self.__forced_printings(ie_result, self.prepare_filename(ie_result), incomplete=True) + info_copy = ie_result.copy() + self.add_extra_info(info_copy, extra_info) + self.add_default_extra_info( + info_copy, self.get_info_extractor(ie_result.get('ie_key')), ie_result['url']) + self.__forced_printings(info_copy, self.prepare_filename(info_copy), incomplete=True) return ie_result if result_type == 'video': @@ -2759,7 +2785,7 @@ def filter_requested_info(info_dict, actually_filter=True): remove_keys = ['__original_infodict'] # Always remove this since this may contain a copy of the entire dict keep_keys = ['_type'], # Always keep this to facilitate load-info-json if actually_filter: - remove_keys += ('requested_formats', 'requested_subtitles', 'requested_entries', 'filepath', 'entries') + remove_keys += ('requested_formats', 'requested_subtitles', 'requested_entries', 'filepath', 'entries', 'original_url') empty_values = (None, {}, [], set(), tuple()) reject = lambda k, v: k not in keep_keys and ( k.startswith('_') or k in remove_keys or v in empty_values)