diff options
| author | Yen Chi Hsuan <yan12125@gmail.com> | 2016-09-30 00:28:32 +0800 | 
|---|---|---|
| committer | Yen Chi Hsuan <yan12125@gmail.com> | 2016-09-30 00:28:32 +0800 | 
| commit | efa97bdcf1f1e90d1b51a09324d7869dcd70729b (patch) | |
| tree | a108ff2efe8c5182887266b8f36972b97e847647 | |
| parent | 475f8a458099c64d367356471069bd0ff2bd1b0d (diff) | |
Move write_xattr to utils.py
There are some other places that use xattr functions. It's better to
move it to a common place so that others can use it.
| -rw-r--r-- | youtube_dl/postprocessor/xattrpp.py | 114 | ||||
| -rw-r--r-- | youtube_dl/utils.py | 99 | 
2 files changed, 106 insertions, 107 deletions
| diff --git a/youtube_dl/postprocessor/xattrpp.py b/youtube_dl/postprocessor/xattrpp.py index e39ca60aa..fbdfa02ac 100644 --- a/youtube_dl/postprocessor/xattrpp.py +++ b/youtube_dl/postprocessor/xattrpp.py @@ -1,37 +1,15 @@  from __future__ import unicode_literals -import os -import subprocess -import sys -import errno -  from .common import PostProcessor  from ..compat import compat_os_name  from ..utils import ( -    check_executable,      hyphenate_date, -    version_tuple, -    PostProcessingError, -    encodeArgument, -    encodeFilename, +    write_xattr, +    XAttrMetadataError, +    XAttrUnavailableError,  ) -class XAttrMetadataError(PostProcessingError): -    def __init__(self, code=None, msg='Unknown error'): -        super(XAttrMetadataError, self).__init__(msg) -        self.code = code - -        # Parsing code and msg -        if (self.code in (errno.ENOSPC, errno.EDQUOT) or -                'No space left' in self.msg or 'Disk quota excedded' in self.msg): -            self.reason = 'NO_SPACE' -        elif self.code == errno.E2BIG or 'Argument list too long' in self.msg: -            self.reason = 'VALUE_TOO_LONG' -        else: -            self.reason = 'NOT_SUPPORTED' - -  class XAttrMetadataPP(PostProcessor):      # @@ -48,88 +26,6 @@ class XAttrMetadataPP(PostProcessor):      def run(self, info):          """ Set extended attributes on downloaded file (if xattr support is found). """ -        # This mess below finds the best xattr tool for the job and creates a -        # "write_xattr" function. -        try: -            # try the pyxattr module... -            import xattr - -            # Unicode arguments are not supported in python-pyxattr until -            # version 0.5.0 -            # See https://github.com/rg3/youtube-dl/issues/5498 -            pyxattr_required_version = '0.5.0' -            if version_tuple(xattr.__version__) < version_tuple(pyxattr_required_version): -                self._downloader.report_warning( -                    'python-pyxattr is detected but is too old. ' -                    'youtube-dl requires %s or above while your version is %s. ' -                    'Falling back to other xattr implementations' % ( -                        pyxattr_required_version, xattr.__version__)) - -                raise ImportError - -            def write_xattr(path, key, value): -                try: -                    xattr.set(path, key, value) -                except EnvironmentError as e: -                    raise XAttrMetadataError(e.errno, e.strerror) - -        except ImportError: -            if compat_os_name == 'nt': -                # Write xattrs to NTFS Alternate Data Streams: -                # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29 -                def write_xattr(path, key, value): -                    assert ':' not in key -                    assert os.path.exists(path) - -                    ads_fn = path + ':' + key -                    try: -                        with open(ads_fn, 'wb') as f: -                            f.write(value) -                    except EnvironmentError as e: -                        raise XAttrMetadataError(e.errno, e.strerror) -            else: -                user_has_setfattr = check_executable('setfattr', ['--version']) -                user_has_xattr = check_executable('xattr', ['-h']) - -                if user_has_setfattr or user_has_xattr: - -                    def write_xattr(path, key, value): -                        value = value.decode('utf-8') -                        if user_has_setfattr: -                            executable = 'setfattr' -                            opts = ['-n', key, '-v', value] -                        elif user_has_xattr: -                            executable = 'xattr' -                            opts = ['-w', key, value] - -                        cmd = ([encodeFilename(executable, True)] + -                               [encodeArgument(o) for o in opts] + -                               [encodeFilename(path, True)]) - -                        try: -                            p = subprocess.Popen( -                                cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) -                        except EnvironmentError as e: -                            raise XAttrMetadataError(e.errno, e.strerror) -                        stdout, stderr = p.communicate() -                        stderr = stderr.decode('utf-8', 'replace') -                        if p.returncode != 0: -                            raise XAttrMetadataError(p.returncode, stderr) - -                else: -                    # On Unix, and can't find pyxattr, setfattr, or xattr. -                    if sys.platform.startswith('linux'): -                        self._downloader.report_error( -                            "Couldn't find a tool to set the xattrs. " -                            "Install either the python 'pyxattr' or 'xattr' " -                            "modules, or the GNU 'attr' package " -                            "(which contains the 'setfattr' tool).") -                    else: -                        self._downloader.report_error( -                            "Couldn't find a tool to set the xattrs. " -                            "Install either the python 'xattr' module, " -                            "or the 'xattr' binary.") -          # Write the metadata to the file's xattrs          self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs') @@ -159,6 +55,10 @@ class XAttrMetadataPP(PostProcessor):              return [], info +        except XAttrUnavailableError as e: +            self._downloader.report_error(str(e)) +            return [], info +          except XAttrMetadataError as e:              if e.reason == 'NO_SPACE':                  self._downloader.report_warning( diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 69ca88c85..fcbfa0d76 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -42,6 +42,7 @@ from .compat import (      compat_html_entities_html5,      compat_http_client,      compat_kwargs, +    compat_os_name,      compat_parse_qs,      compat_shlex_quote,      compat_socket_create_connection, @@ -775,6 +776,25 @@ class ContentTooShortError(Exception):          self.expected = expected +class XAttrMetadataError(Exception): +    def __init__(self, code=None, msg='Unknown error'): +        super(XAttrMetadataError, self).__init__(msg) +        self.code = code + +        # Parsing code and msg +        if (self.code in (errno.ENOSPC, errno.EDQUOT) or +                'No space left' in self.msg or 'Disk quota excedded' in self.msg): +            self.reason = 'NO_SPACE' +        elif self.code == errno.E2BIG or 'Argument list too long' in self.msg: +            self.reason = 'VALUE_TOO_LONG' +        else: +            self.reason = 'NOT_SUPPORTED' + + +class XAttrUnavailableError(Exception): +    pass + +  def _create_http_connection(ydl_handler, http_class, is_https, *args, **kwargs):      # Working around python 2 bug (see http://bugs.python.org/issue17849) by limiting      # expected HTTP responses to meet HTTP/1.0 or later (see also @@ -3131,3 +3151,82 @@ def decode_png(png_data):              current_row.append(color)      return width, height, pixels + + +def write_xattr(path, key, value): +    # This mess below finds the best xattr tool for the job +    try: +        # try the pyxattr module... +        import xattr + +        # Unicode arguments are not supported in python-pyxattr until +        # version 0.5.0 +        # See https://github.com/rg3/youtube-dl/issues/5498 +        pyxattr_required_version = '0.5.0' +        if version_tuple(xattr.__version__) < version_tuple(pyxattr_required_version): +            # TODO: fallback to CLI tools +            raise XAttrUnavailableError( +                'python-pyxattr is detected but is too old. ' +                'youtube-dl requires %s or above while your version is %s. ' +                'Falling back to other xattr implementations' % ( +                    pyxattr_required_version, xattr.__version__)) + +        try: +            xattr.set(path, key, value) +        except EnvironmentError as e: +            raise XAttrMetadataError(e.errno, e.strerror) + +    except ImportError: +        if compat_os_name == 'nt': +            # Write xattrs to NTFS Alternate Data Streams: +            # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29 +            assert ':' not in key +            assert os.path.exists(path) + +            ads_fn = path + ':' + key +            try: +                with open(ads_fn, 'wb') as f: +                    f.write(value) +            except EnvironmentError as e: +                raise XAttrMetadataError(e.errno, e.strerror) +        else: +            user_has_setfattr = check_executable('setfattr', ['--version']) +            user_has_xattr = check_executable('xattr', ['-h']) + +            if user_has_setfattr or user_has_xattr: + +                value = value.decode('utf-8') +                if user_has_setfattr: +                    executable = 'setfattr' +                    opts = ['-n', key, '-v', value] +                elif user_has_xattr: +                    executable = 'xattr' +                    opts = ['-w', key, value] + +                cmd = ([encodeFilename(executable, True)] + +                       [encodeArgument(o) for o in opts] + +                       [encodeFilename(path, True)]) + +                try: +                    p = subprocess.Popen( +                        cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) +                except EnvironmentError as e: +                    raise XAttrMetadataError(e.errno, e.strerror) +                stdout, stderr = p.communicate() +                stderr = stderr.decode('utf-8', 'replace') +                if p.returncode != 0: +                    raise XAttrMetadataError(p.returncode, stderr) + +            else: +                # On Unix, and can't find pyxattr, setfattr, or xattr. +                if sys.platform.startswith('linux'): +                    raise XAttrUnavailableError( +                        "Couldn't find a tool to set the xattrs. " +                        "Install either the python 'pyxattr' or 'xattr' " +                        "modules, or the GNU 'attr' package " +                        "(which contains the 'setfattr' tool).") +                else: +                    raise XAttrUnavailableError( +                        "Couldn't find a tool to set the xattrs. " +                        "Install either the python 'xattr' module, " +                        "or the 'xattr' binary.") | 
