diff options
| -rwxr-xr-x | youtube_dl/YoutubeDL.py | 1 | ||||
| -rw-r--r-- | youtube_dl/__init__.py | 12 | ||||
| -rw-r--r-- | youtube_dl/postprocessor/execafterdownload.py | 48 | ||||
| -rw-r--r-- | youtube_dl/utils.py | 7 | 
4 files changed, 35 insertions, 33 deletions
| diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py index a671d6450..e0cb1ef75 100755 --- a/youtube_dl/YoutubeDL.py +++ b/youtube_dl/YoutubeDL.py @@ -172,6 +172,7 @@ class YoutubeDL(object):      The following options are used by the post processors:      prefer_ffmpeg:     If True, use ffmpeg instead of avconv if both are available,                         otherwise prefer avconv. +    exec_cmd:          Arbitrary command to run after downloading      """      params = None diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py index 7cf5de43f..b15695053 100644 --- a/youtube_dl/__init__.py +++ b/youtube_dl/__init__.py @@ -552,8 +552,9 @@ def parseOpts(overrideArguments=None):          help='Prefer avconv over ffmpeg for running the postprocessors (default)')      postproc.add_option('--prefer-ffmpeg', action='store_true', dest='prefer_ffmpeg',          help='Prefer ffmpeg over avconv for running the postprocessors') -    postproc.add_option('--exec', metavar='', action='store', dest='execstring', -        help='Execute a command on the file after downloading, similar to find\'s -exec syntax. Must be enclosed in quotes. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'' ) +    postproc.add_option( +        '--exec', metavar='CMD', dest='exec_cmd', +        help='Execute a command on the file after downloading, similar to find\'s -exec syntax. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'' )      parser.add_option_group(general)      parser.add_option_group(selection) @@ -834,7 +835,7 @@ def _real_main(argv=None):          'default_search': opts.default_search,          'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,          'encoding': opts.encoding, -        'execstring': opts.execstring, +        'exec_cmd': opts.exec_cmd,      }      with YoutubeDL(ydl_opts) as ydl: @@ -861,8 +862,9 @@ def _real_main(argv=None):          # Please keep ExecAfterDownload towards the bottom as it allows the user to modify the final file in any way.          # So if the user is able to remove the file before your postprocessor runs it might cause a few problems. -        if opts.execstring: -            ydl.add_post_processor(ExecAfterDownloadPP(verboseOutput=opts.verbose,commandString=opts.execstring)) +        if opts.exec_cmd: +            ydl.add_post_processor(ExecAfterDownloadPP( +                verboseOutput=opts.verbose, exec_cmd=opts.exec_cmd))          # Update version          if opts.update_self: diff --git a/youtube_dl/postprocessor/execafterdownload.py b/youtube_dl/postprocessor/execafterdownload.py index e6f3cdfd2..08419a3d4 100644 --- a/youtube_dl/postprocessor/execafterdownload.py +++ b/youtube_dl/postprocessor/execafterdownload.py @@ -1,39 +1,31 @@  from __future__ import unicode_literals -from .common import PostProcessor -from ..utils import PostProcessingError +  import subprocess -import shlex + +from .common import PostProcessor +from ..utils import ( +    shlex_quote, +    PostProcessingError, +)  class ExecAfterDownloadPP(PostProcessor): -    def __init__(self, downloader=None, verboseOutput=None, commandString=None): +    def __init__(self, downloader=None, verboseOutput=None, exec_cmd=None):          self.verboseOutput = verboseOutput -        self.commandString = commandString +        self.exec_cmd = exec_cmd      def run(self, information): -        self.targetFile = information['filepath'].replace('\'', '\'\\\'\'')  # Replace single quotes with '\'' -        self.commandList = shlex.split(self.commandString) -        self.commandString = '' - -        # Replace all instances of '{}' with the file name and convert argument list to single string. -        for index, arg in enumerate(self.commandList): -            if(arg == '{}'): -                self.commandString += '\'' + self.targetFile + '\' ' -            else: -                self.commandString += arg + ' ' - -        if self.targetFile not in self.commandString:  # Assume user wants the file appended to the end of the command if no {}'s were given. -            self.commandString += '\'' + self.targetFile + '\'' - -        print("[exec] Executing command: " + self.commandString) -        self.retCode = subprocess.call(self.commandString, shell=True) -        if(self.retCode < 0): -            print("[exec] WARNING: Command exited with a negative return code, the process was killed externally. Your command may not of completed succesfully!") -        elif(self.verboseOutput): -            print("[exec] Command exited with return code: " + str(self.retCode)) +        cmd = self.exec_cmd +        if not '{}' in cmd: +            cmd += ' {}' -        return None, information  # by default, keep file and do nothing +        cmd = cmd.replace('{}', shlex_quote(information['filepath'])) + +        self._downloader.to_screen("[exec] Executing command: %s" % cmd) +        retCode = subprocess.call(cmd, shell=True) +        if retCode != 0: +            raise PostProcessingError( +                'Command returned error code %d' % retCode) +        return None, information  # by default, keep file and do nothing -class PostProcessingExecError(PostProcessingError): -    pass diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py index 8095400d0..2b05fd7b7 100644 --- a/youtube_dl/utils.py +++ b/youtube_dl/utils.py @@ -192,6 +192,13 @@ try:  except ImportError:  # Python 2.6      from xml.parsers.expat import ExpatError as compat_xml_parse_error +try: +    from shlex import quote as shlex_quote +except ImportError:  # Python < 3.3 +    def shlex_quote(s): +        return "'" + s.replace("'", "'\"'\"'") + "'" + +  def compat_ord(c):      if type(c) is int: return c      else: return ord(c) | 
