From 8d31fa3cce47a7c9d932b872e277cf89eb3441a2 Mon Sep 17 00:00:00 2001 From: Philipp Hagemeister Date: Mon, 25 Aug 2014 10:18:01 +0200 Subject: [PATCH] [execafterdownload] Simplify (#3569) --- youtube_dl/YoutubeDL.py | 1 + youtube_dl/__init__.py | 12 +++-- youtube_dl/postprocessor/execafterdownload.py | 48 ++++++++----------- 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) -- 2.22.2