mirror of
				https://github.com/ytdl-org/youtube-dl.git
				synced 2025-10-29 09:26:20 -07:00 
			
		
		
		
	[YoutubeDL] Add support for string formatting operations in output template
This commit is contained in:
		| @@ -526,6 +526,7 @@ class TestYoutubeDL(unittest.TestCase): | |||||||
|             'id': '1234', |             'id': '1234', | ||||||
|             'ext': 'mp4', |             'ext': 'mp4', | ||||||
|             'width': None, |             'width': None, | ||||||
|  |             'height': 1080, | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         def fname(templ): |         def fname(templ): | ||||||
| @@ -535,6 +536,19 @@ class TestYoutubeDL(unittest.TestCase): | |||||||
|         self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4') |         self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4') | ||||||
|         # Replace missing fields with 'NA' |         # Replace missing fields with 'NA' | ||||||
|         self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4') |         self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)6d.%(ext)s'), '  1080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080  .mp4') | ||||||
|  |         self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)   06d.%(ext)s'), ' 01080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)0   6d.%(ext)s'), ' 01080.mp4') | ||||||
|  |         self.assertEqual(fname('%(height)   0   6d.%(ext)s'), ' 01080.mp4') | ||||||
|  |         self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4') | ||||||
|  |         self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4') | ||||||
|  |         self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s') | ||||||
|  |         self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4') | ||||||
|  |  | ||||||
|     def test_format_note(self): |     def test_format_note(self): | ||||||
|         ydl = YoutubeDL() |         ydl = YoutubeDL() | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ from .compat import ( | |||||||
|     compat_get_terminal_size, |     compat_get_terminal_size, | ||||||
|     compat_http_client, |     compat_http_client, | ||||||
|     compat_kwargs, |     compat_kwargs, | ||||||
|  |     compat_numeric_types, | ||||||
|     compat_os_name, |     compat_os_name, | ||||||
|     compat_str, |     compat_str, | ||||||
|     compat_tokenize_tokenize, |     compat_tokenize_tokenize, | ||||||
| @@ -609,12 +610,45 @@ class YoutubeDL(object): | |||||||
|                 compat_str(v), |                 compat_str(v), | ||||||
|                 restricted=self.params.get('restrictfilenames'), |                 restricted=self.params.get('restrictfilenames'), | ||||||
|                 is_id=(k == 'id')) |                 is_id=(k == 'id')) | ||||||
|             template_dict = dict((k, sanitize(k, v)) |             template_dict = dict((k, v if isinstance(v, compat_numeric_types) else sanitize(k, v)) | ||||||
|                                  for k, v in template_dict.items() |                                  for k, v in template_dict.items() | ||||||
|                                  if v is not None and not isinstance(v, (list, tuple, dict))) |                                  if v is not None and not isinstance(v, (list, tuple, dict))) | ||||||
|             template_dict = collections.defaultdict(lambda: 'NA', template_dict) |             template_dict = collections.defaultdict(lambda: 'NA', template_dict) | ||||||
|  |  | ||||||
|             outtmpl = self.params.get('outtmpl', DEFAULT_OUTTMPL) |             outtmpl = self.params.get('outtmpl', DEFAULT_OUTTMPL) | ||||||
|  |  | ||||||
|  |             NUMERIC_FIELDS = set(( | ||||||
|  |                 'width', 'height', 'tbr', 'abr', 'asr', 'vbr', 'fps', 'filesize', 'filesize_approx', | ||||||
|  |                 'upload_year', 'upload_month', 'upload_day', | ||||||
|  |                 'duration', 'view_count', 'like_count', 'dislike_count', 'repost_count', | ||||||
|  |                 'average_rating', 'comment_count', 'age_limit', | ||||||
|  |                 'start_time', 'end_time', | ||||||
|  |                 'chapter_number', 'season_number', 'episode_number', | ||||||
|  |             )) | ||||||
|  |  | ||||||
|  |             # Missing numeric fields used together with integer presentation types | ||||||
|  |             # in format specification will break the argument substitution since | ||||||
|  |             # string 'NA' is returned for missing fields. We will patch output | ||||||
|  |             # template for missing fields to meet string presentation type. | ||||||
|  |             for numeric_field in NUMERIC_FIELDS: | ||||||
|  |                 if numeric_field not in template_dict: | ||||||
|  |                     # As of [1] format syntax is: | ||||||
|  |                     #  %[mapping_key][conversion_flags][minimum_width][.precision][length_modifier]type | ||||||
|  |                     # 1. https://docs.python.org/2/library/stdtypes.html#string-formatting | ||||||
|  |                     FORMAT_RE = r'''(?x) | ||||||
|  |                         (?<!%) | ||||||
|  |                         % | ||||||
|  |                         \({0}\)  # mapping key | ||||||
|  |                         (?:[#0\-+ ]+)?  # conversion flags (optional) | ||||||
|  |                         (?:\d+)?  # minimum field width (optional) | ||||||
|  |                         (?:\.\d+)?  # precision (optional) | ||||||
|  |                         [hlL]?  # length modifier (optional) | ||||||
|  |                         [diouxXeEfFgGcrs%]  # conversion type | ||||||
|  |                     ''' | ||||||
|  |                     outtmpl = re.sub( | ||||||
|  |                         FORMAT_RE.format(numeric_field), | ||||||
|  |                         r'%({0})s'.format(numeric_field), outtmpl) | ||||||
|  |  | ||||||
|             tmpl = compat_expanduser(outtmpl) |             tmpl = compat_expanduser(outtmpl) | ||||||
|             filename = tmpl % template_dict |             filename = tmpl % template_dict | ||||||
|             # Temporary fix for #4787 |             # Temporary fix for #4787 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user