From a7cacbca2b140f668785d57264914de5585ed699 Mon Sep 17 00:00:00 2001
From: mcd1992 <theanonbutinf@gmail.com>
Date: Fri, 22 Aug 2014 16:40:43 -0500
Subject: [PATCH] Implemented --exec option.

---
 README.md                                     |   2 +
 youtube_dl/.__init__.py.swp                   | Bin 0 -> 16384 bytes
 youtube_dl/__init__.py                        |  15 +++++++-
 youtube_dl/postprocessor/__init__.py          |   2 +
 youtube_dl/postprocessor/execafterdownload.py |  36 ++++++++++++++++++
 5 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 youtube_dl/.__init__.py.swp
 create mode 100644 youtube_dl/postprocessor/execafterdownload.py

diff --git a/README.md b/README.md
index ba9fec8a7..30bdac189 100644
--- a/README.md
+++ b/README.md
@@ -288,6 +288,8 @@ which means you can modify it, redistribute it or use it however you like.
                                      postprocessors (default)
     --prefer-ffmpeg                  Prefer ffmpeg over avconv for running the
                                      postprocessors
+    --exec                           Execute a command after the file is finished downloading, similar to find's -exec format
+                                     Example: --exec 'adb push {} /sdcard/Music/ && rm {}'
 
 # CONFIGURATION
 
diff --git a/youtube_dl/.__init__.py.swp b/youtube_dl/.__init__.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..0586277fd44037e92b86628697b8bfb898bfe32a
GIT binary patch
literal 16384
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
U9!o#iS|P^?(d%2P>}A~fCv((wo&W#<

literal 0
HcmV?d00001

diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py
index a96bf9b5c..189a8ff35 100644
--- a/youtube_dl/__init__.py
+++ b/youtube_dl/__init__.py
@@ -71,8 +71,12 @@ __authors__  = (
     'Sebastian Haas',
     'Alexander Kirk',
     'Erik Johnson',
+<<<<<<< HEAD
     'Keith Beckman',
     'Ole Ernst',
+=======
+    'Aaron McDaniel (mcd1992)',
+>>>>>>> Implemented --exec option.
 )
 
 __license__ = 'Public Domain'
@@ -119,6 +123,7 @@ from .postprocessor import (
     FFmpegExtractAudioPP,
     FFmpegEmbedSubtitlePP,
     XAttrMetadataPP,
+    ExecAfterDownload,
 )
 
 
@@ -550,7 +555,8 @@ 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 {}\'' )
 
     parser.add_option_group(general)
     parser.add_option_group(selection)
@@ -831,6 +837,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,
     }
 
     with YoutubeDL(ydl_opts) as ydl:
@@ -854,6 +861,12 @@ def _real_main(argv=None):
                 ydl.add_post_processor(FFmpegAudioFixPP())
             ydl.add_post_processor(AtomicParsleyPP())
 
+
+        # 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(ExecAfterDownload(commandString=opts.execstring))
+
         # Update version
         if opts.update_self:
             update_self(ydl.to_screen, opts.verbose)
diff --git a/youtube_dl/postprocessor/__init__.py b/youtube_dl/postprocessor/__init__.py
index 08e6ddd00..59ab49e6d 100644
--- a/youtube_dl/postprocessor/__init__.py
+++ b/youtube_dl/postprocessor/__init__.py
@@ -9,6 +9,7 @@ from .ffmpeg import (
     FFmpegEmbedSubtitlePP,
 )
 from .xattrpp import XAttrMetadataPP
+from .execafterdownload import ExecAfterDownload
 
 __all__ = [
     'AtomicParsleyPP',
@@ -19,4 +20,5 @@ __all__ = [
     'FFmpegExtractAudioPP',
     'FFmpegEmbedSubtitlePP',
     'XAttrMetadataPP',
+    'ExecAfterDownload',
 ]
diff --git a/youtube_dl/postprocessor/execafterdownload.py b/youtube_dl/postprocessor/execafterdownload.py
new file mode 100644
index 000000000..431ab7f08
--- /dev/null
+++ b/youtube_dl/postprocessor/execafterdownload.py
@@ -0,0 +1,36 @@
+# ExecAfterDownload written by AaronM / mcd1992.
+# If there are any issues with this postprocessor please contact me via github or admin@fgthou.se
+
+import os, re, shlex
+from ..utils import PostProcessingError
+
+class ExecAfterDownload( object ):
+    _downloader = None
+
+    def __init__( self, downloader = None, commandString = None ):
+        self._downloader = downloader
+        self.commandString = commandString
+
+    def set_downloader( self, downloader ):
+        """Sets the downloader for this PP."""
+        self._downloader = downloader
+
+    def run( self, information ):
+        self.targetFile = information["filepath"]
+        self.finalCommand = None;
+
+        if( re.search( '{}', self.commandString ) ): # Find and replace all occurrences of {} with the file name.
+            self.finalCommand = re.sub( "{}", '\'' + self.targetFile + '\'', self.commandString )
+        else:
+            self.finalCommand = self.commandString + ' \'' + self.targetFile + '\''
+
+        if( self.finalCommand ):
+            print( "[exec] Executing command: " + self.finalCommand )
+            os.system( self.finalCommand )
+        else:
+            raise PostProcessingExecError( "Invalid syntax for --exec post processor" )
+
+        return None, information  # by default, keep file and do nothing
+
+class PostProcessingExecError( PostProcessingError ):
+    pass