From 4be3701b611c83012e3e965dc32638b19e7ba19f Mon Sep 17 00:00:00 2001
From: Gareth Latty <gareth@lattyware.co.uk>
Date: Sat, 11 Feb 2012 02:31:21 +0000
Subject: [PATCH] Fixed extractor plugin to work with move on complete - also
 provides a general solution for working with move on
 complete torrents using the TorrentMoveEvent event.

---
 deluge/core/torrentmanager.py                      |    2 +
 deluge/event.py                                    |   11 ++
 deluge/plugins/extractor/extractor/core.py         |  123 ++++++++++++--------
 .../extractor/extractor/data/extractor_prefs.glade |   15 +++
 deluge/plugins/extractor/extractor/gtkui.py        |    4 +-
 5 files changed, 107 insertions(+), 48 deletions(-)

diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py
index 996f5c4..59b9de3 100644
--- a/deluge/core/torrentmanager.py
+++ b/deluge/core/torrentmanager.py
@@ -977,10 +977,12 @@ def on_alert_storage_moved(self, alert):
         log.debug("on_alert_storage_moved")
         try:
             torrent = self.torrents[str(alert.handle.info_hash())]
+            torrent_id = str(alert.handle.info_hash())
         except:
             return
         torrent.set_save_path(os.path.normpath(alert.handle.save_path()))
         torrent.set_move_completed(False)
+        component.get("EventManager").emit(TorrentMovedEvent(torrent_id))
 
     def on_alert_torrent_resumed(self, alert):
         log.debug("on_alert_torrent_resumed")
diff --git a/deluge/event.py b/deluge/event.py
index 4289990..e2c743e 100644
--- a/deluge/event.py
+++ b/deluge/event.py
@@ -154,6 +154,17 @@ def __init__(self, torrent_id):
         """
         self._args = [torrent_id]
 
+class TorrentMovedEvent(DelugeEvent):
+    """
+    Emitted when a torrent finished being moved.
+    """
+    def __init__(self, torrent_id):
+        """
+        :param torrent_id: the torrent_id
+        :type torrent_id: string
+        """
+        self._args = [torrent_id]
+
 class TorrentResumedEvent(DelugeEvent):
     """
     Emitted when a torrent resumes from a paused state.
diff --git a/deluge/plugins/extractor/extractor/core.py b/deluge/plugins/extractor/extractor/core.py
index f7c888e..dca9f3d 100644
--- a/deluge/plugins/extractor/extractor/core.py
+++ b/deluge/plugins/extractor/extractor/core.py
@@ -49,7 +49,8 @@
 
 DEFAULT_PREFS = {
     "extract_path": "",
-    "use_name_folder": True
+    "use_name_folder": True,
+    "use_extract_path_on_moved": False
 }
 
 # The first format is the source file, the second is the dest path
@@ -67,10 +68,15 @@ def enable(self):
         if not self.config["extract_path"]:
             self.config["extract_path"] = deluge.configmanager.ConfigManager("core.conf")["download_location"]
 
-        component.get("EventManager").register_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
+        self.waiting = {}
+        event_manager = component.get("EventManager")
+        event_manager.register_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
+        event_manager.register_event_handler("TorrentMovedEvent", self.extract)
 
     def disable(self):
-        component.get("EventManager").deregister_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
+        event_manager = component.get("EventManager")
+        event_manager.deregister_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
+        event_manager.deregister_event_handler("TorrentMovedEvent", self.extract)
 
     def update(self):
         pass
@@ -81,51 +87,74 @@ def _on_torrent_finished(self, torrent_id):
         are any files to extract.
         """
         # Get the save path
-        save_path = component.get("TorrentManager")[torrent_id].get_status(["save_path"])["save_path"]
-        files = component.get("TorrentManager")[torrent_id].get_files()
-        for f in files:
-            ext = os.path.splitext(f["path"])
-            if ext[1] in (".gz", ".bz2", ".lzma"):
-                # We need to check if this is a tar
-                if os.path.splitext(ext[0]) == ".tar":
-                    cmd = EXTRACT_COMMANDS[".tar" + ext[1]]
-            else:
-                if ext[1] in EXTRACT_COMMANDS:
-                    cmd = EXTRACT_COMMANDS[ext[1]]
+        torrent = component.get("TorrentManager").torrents[torrent_id]
+        info = torrent.get_status(["name", "move_completed", "move_completed_path"])
+
+        log.debug("Beginning extraction of "+info["name"])
+
+        if not info["move_completed"]:
+            self.extract(torrent_id, True)
+        else:
+            self.waiting[torrent_id] = info["move_completed_path"]
+            log.debug("Waiting for move before extracting.")
+
+    def extract(self, torrent_id, skipcheck=False):
+        if (torrent_id in self.waiting) or skipcheck:
+            save_path = component.get("TorrentManager")[torrent_id].get_status(["save_path"])["save_path"]
+            files = component.get("TorrentManager")[torrent_id].get_files()
+            for f in files:
+                ext = os.path.splitext(f["path"])
+                if ext[1] in (".gz", ".bz2", ".lzma"):
+                    # We need to check if this is a tar
+                    if os.path.splitext(ext[0]) == ".tar":
+                        cmd = EXTRACT_COMMANDS[".tar" + ext[1]]
                 else:
-                    log.debug("Can't extract unknown file type: %s", ext[1])
-                    continue
-
-            # Now that we have the cmd, lets run it to extract the files
-            fp = os.path.join(save_path, f["path"])
-            
-            # Get the destination path
-            dest = self.config["extract_path"]
-            if self.config["use_name_folder"]:
-                name = component.get("TorrentManager")[torrent_id].get_status(["name"])["name"]
-                dest = os.path.join(dest, name)
-
-            # Create the destination folder if it doesn't exist                
-            if not os.path.exists(dest):
-                try:
-                    os.makedirs(dest)
-                except Exception, e:
-                    log.error("Error creating destination folder: %s", e)
-                    return
-            
-            log.debug("Extracting to %s", dest)        
-            def on_extract_success(result, torrent_id):
-                # XXX: Emit an event
-                log.debug("Extract was successful for %s", torrent_id)
-
-            def on_extract_failed(result, torrent_id):
-                # XXX: Emit an event
-                log.debug("Extract failed for %s", torrent_id)
-
-            # Run the command and add some callbacks
-            d = getProcessValue(cmd[0], cmd[1].split() + [str(fp)], {}, str(dest))
-            d.addCallback(on_extract_success, torrent_id)
-            d.addErrback(on_extract_failed, torrent_id)
+                    if ext[1] in EXTRACT_COMMANDS:
+                        cmd = EXTRACT_COMMANDS[ext[1]]
+                    else:
+                        log.debug("Can't extract unknown file type: %s", ext[1])
+                        continue
+
+                # Now that we have the cmd, lets run it to extract the files
+                fp = os.path.join(save_path, f["path"])
+
+                # Get the destination path
+                if torrent_id in self.waiting:
+                    if self.config["use_extract_path_on_moved"]:
+                        dest = os.path.join(self.waiting[torrent_id], self.config["extract_path"])
+                    else:
+                        dest = self.waiting[torrent_id]
+                else:
+                    if os.path.isabs(self.config["extract_path"]):
+                        dest = self.config["extract_path"]
+                    else:
+                        dest = os.path.join(deluge.configmanager.ConfigManager("core.conf")["download_location"])
+                if self.config["use_name_folder"]:
+                    name = component.get("TorrentManager")[torrent_id].get_status(["name"])["name"]
+                    dest = os.path.join(dest, name)
+
+                # Create the destination folder if it doesn't exist
+                if not os.path.exists(dest):
+                    try:
+                        os.makedirs(dest)
+                    except Exception, e:
+                        log.error("Error creating destination folder: %s", e)
+                        return
+
+                log.debug("Extracting to %s", dest)
+                def on_extract_success(result, torrent_id):
+                    # XXX: Emit an event
+                    log.debug("Extract was successful for %s", torrent_id)
+
+                def on_extract_failed(result, torrent_id):
+                    # XXX: Emit an event
+                    log.debug("Extract failed for %s", torrent_id)
+
+                # Run the command and add some callbacks
+                d = getProcessValue(cmd[0], cmd[1].split() + [str(fp)], {}, str(dest))
+                d.addCallback(on_extract_success, torrent_id)
+                d.addErrback(on_extract_failed, torrent_id)
+            self.waiting.remove(torrent_id)
 
     @export
     def set_config(self, config):
diff --git a/deluge/plugins/extractor/extractor/data/extractor_prefs.glade b/deluge/plugins/extractor/extractor/data/extractor_prefs.glade
index c6827e4..84d2ce4 100644
--- a/deluge/plugins/extractor/extractor/data/extractor_prefs.glade
+++ b/deluge/plugins/extractor/extractor/data/extractor_prefs.glade
@@ -79,6 +79,21 @@
                     <property name="position">1</property>
                   </packing>
                 </child>
+                <child>
+                  <widget class="GtkCheckButton" id="chk_use_extract_path_on_moved">
+                    <property name="label" translatable="yes">Use extract folder on torrents using 'move completed'.</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="tooltip" translatable="yes">When enabled, this will use the given path when moving completed torrents. Given as a relative path will create subdirectories in the moved-to folder, given as an absolute path will extract all files to the one directory given.</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
               </widget>
             </child>
             <child>
diff --git a/deluge/plugins/extractor/extractor/gtkui.py b/deluge/plugins/extractor/extractor/gtkui.py
index 9e3bf61..c478265 100644
--- a/deluge/plugins/extractor/extractor/gtkui.py
+++ b/deluge/plugins/extractor/extractor/gtkui.py
@@ -71,6 +71,7 @@ def on_apply_prefs(self):
 
         config = {
             "extract_path": path,
+            "use_extract_path_on_moved": self.glade.get_widget("chk_use_extract_path_on_moved").get_active(),
             "use_name_folder": self.glade.get_widget("chk_use_name").get_active()
         }
 
@@ -89,7 +90,8 @@ def on_get_config(config):
                 self.glade.get_widget("folderchooser_path").set_current_folder(config["extract_path"])
             else:
                 self.glade.get_widget("entry_path").set_text(config["extract_path"])
-            
+
+            self.glade.get_widget("chk_use_extract_path_on_moved").set_active(config["use_extract_path_on_moved"])
             self.glade.get_widget("chk_use_name").set_active(config["use_name_folder"])
 
         client.extractor.get_config().addCallback(on_get_config)
-- 
1.7.9

