diff options
| author | Sergey M․ <dstftw@gmail.com> | 2016-03-06 03:52:42 +0600 | 
|---|---|---|
| committer | Sergey M <dstftw@gmail.com> | 2017-02-23 22:57:53 +0800 | 
| commit | d0d9ade4860fd44a07f5513d13b66233fdca0e89 (patch) | |
| tree | cfff31416171320f6b1973ce3da05a9d2b778011 | |
| parent | 28572a1a0b27ba3ccedac5d8d093f925dfb7485f (diff) | |
[YoutubeDL] Add support for string formatting operations in output template
| -rw-r--r-- | test/test_YoutubeDL.py | 14 | ||||
| -rwxr-xr-x | youtube_dl/YoutubeDL.py | 36 | 
2 files changed, 49 insertions, 1 deletions
| diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index 2cfcf743a..8491a88bd 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -526,6 +526,7 @@ class TestYoutubeDL(unittest.TestCase):              'id': '1234',              'ext': 'mp4',              'width': None, +            'height': 1080,          }          def fname(templ): @@ -535,6 +536,19 @@ class TestYoutubeDL(unittest.TestCase):          self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')          # Replace missing fields with 'NA'          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):          ydl = YoutubeDL() diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py index 68000dea2..bdaf06e62 100755 --- a/youtube_dl/YoutubeDL.py +++ b/youtube_dl/YoutubeDL.py @@ -33,6 +33,7 @@ from .compat import (      compat_get_terminal_size,      compat_http_client,      compat_kwargs, +    compat_numeric_types,      compat_os_name,      compat_str,      compat_tokenize_tokenize, @@ -609,12 +610,45 @@ class YoutubeDL(object):                  compat_str(v),                  restricted=self.params.get('restrictfilenames'),                  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()                                   if v is not None and not isinstance(v, (list, tuple, dict)))              template_dict = collections.defaultdict(lambda: 'NA', template_dict)              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)              filename = tmpl % template_dict              # Temporary fix for #4787 | 
