diff options
Diffstat (limited to 'youtube_dl/utils.py')
| -rw-r--r-- | youtube_dl/utils.py | 88 | 
1 files changed, 75 insertions, 13 deletions
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 3ecd798d7..42ad520f9 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -24,6 +24,7 @@ import socket  import struct  import subprocess  import sys +import tempfile  import traceback  import xml.etree.ElementTree  import zlib @@ -228,22 +229,46 @@ else:          assert type(s) == type(u'')          print(s) -# In Python 2.x, json.dump expects a bytestream. -# In Python 3.x, it writes to a character stream -if sys.version_info < (3,0): -    def write_json_file(obj, fn): -        with open(fn, 'wb') as f: -            json.dump(obj, f) -else: -    def write_json_file(obj, fn): -        with open(fn, 'w', encoding='utf-8') as f: -            json.dump(obj, f) -if sys.version_info >= (2,7): +def write_json_file(obj, fn): +    """ Encode obj as JSON and write it to fn, atomically """ + +    args = { +        'suffix': '.tmp', +        'prefix': os.path.basename(fn) + '.', +        'dir': os.path.dirname(fn), +        'delete': False, +    } + +    # In Python 2.x, json.dump expects a bytestream. +    # In Python 3.x, it writes to a character stream +    if sys.version_info < (3, 0): +        args['mode'] = 'wb' +    else: +        args.update({ +            'mode': 'w', +            'encoding': 'utf-8', +        }) + +    tf = tempfile.NamedTemporaryFile(**args) + +    try: +        with tf: +            json.dump(obj, tf) +        os.rename(tf.name, fn) +    except: +        try: +            os.remove(tf.name) +        except OSError: +            pass +        raise + + +if sys.version_info >= (2, 7):      def find_xpath_attr(node, xpath, key, val):          """ Find the xpath xpath[@key=val] """ -        assert re.match(r'^[a-zA-Z]+$', key) -        assert re.match(r'^[a-zA-Z0-9@\s:._]*$', val) +        assert re.match(r'^[a-zA-Z-]+$', key) +        assert re.match(r'^[a-zA-Z0-9@\s:._-]*$', val)          expr = xpath + u"[@%s='%s']" % (key, val)          return node.find(expr)  else: @@ -827,6 +852,7 @@ def unified_strdate(date_str):          '%b %dnd %Y %I:%M%p',          '%b %dth %Y %I:%M%p',          '%Y-%m-%d', +        '%Y/%m/%d',          '%d.%m.%Y',          '%d/%m/%Y',          '%Y/%m/%d %H:%M:%S', @@ -852,6 +878,8 @@ def unified_strdate(date_str):      return upload_date  def determine_ext(url, default_ext=u'unknown_video'): +    if url is None: +        return default_ext      guess = url.partition(u'?')[0].rpartition(u'.')[2]      if re.match(r'^[A-Za-z0-9]+$', guess):          return guess @@ -1271,9 +1299,15 @@ def int_or_none(v, scale=1, default=None, get_attr=None, invscale=1):      if get_attr:          if v is not None:              v = getattr(v, get_attr, None) +    if v == '': +        v = None      return default if v is None else (int(v) * invscale // scale) +def str_or_none(v, default=None): +    return default if v is None else compat_str(v) + +  def str_to_int(int_str):      if int_str is None:          return None @@ -1440,6 +1474,34 @@ def strip_jsonp(code):      return re.sub(r'(?s)^[a-zA-Z0-9_]+\s*\(\s*(.*)\);?\s*?\s*$', r'\1', code) +def js_to_json(code): +    def fix_kv(m): +        key = m.group(2) +        if key.startswith("'"): +            assert key.endswith("'") +            assert '"' not in key +            key = '"%s"' % key[1:-1] +        elif not key.startswith('"'): +            key = '"%s"' % key + +        value = m.group(4) +        if value.startswith("'"): +            assert value.endswith("'") +            assert '"' not in value +            value = '"%s"' % value[1:-1] + +        return m.group(1) + key + m.group(3) + value + +    res = re.sub(r'''(?x) +            ([{,]\s*) +            ("[^"]*"|\'[^\']*\'|[a-z0-9A-Z]+) +            (:\s*) +            ([0-9.]+|true|false|"[^"]*"|\'[^\']*\'|\[|\{) +        ''', fix_kv, code) +    res = re.sub(r',(\s*\])', lambda m: m.group(1), res) +    return res + +  def qualities(quality_ids):      """ Get a numeric quality value out of a list of possible values """      def q(qid):  | 
