summaryrefslogtreecommitdiffstats
path: root/module/plugins/internal/UnRar.py
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-10-14 18:10:40 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-10-14 18:10:40 +0200
commite4077960822e24f3041e16e7e818c105e372152d (patch)
tree12580f141668f4eb0edf4b90fbf3417e8dcc3a3a /module/plugins/internal/UnRar.py
parentfixes syntax error on old python versions (diff)
downloadpyload-e4077960822e24f3041e16e7e818c105e372152d.tar.xz
first version of new extract plugin
Diffstat (limited to 'module/plugins/internal/UnRar.py')
-rw-r--r--module/plugins/internal/UnRar.py279
1 files changed, 152 insertions, 127 deletions
diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py
index d22e54b61..67f95b018 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -14,145 +14,170 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
- @author: mkaay
+ @author: RaNaN
"""
-from __future__ import with_statement
-import sys
import os
-from os.path import exists, join, isabs, isdir
-from os import remove, makedirs, rmdir, listdir, chmod
-from traceback import print_exc
+from os.path import join
-from module.plugins.hooks.ExtractArchive import AbtractExtractor
-from module.lib.pyunrar import Unrar, WrongPasswordError, CommandError, UnknownError, LowRamError
+from subprocess import Popen, PIPE
+from module.plugins.hooks.ExtractArchive import AbtractExtractor
from module.utils import save_join
-
+try:
+ import pexpect #used for progress
+ PEXPECT = True
+except ImportError:
+ PEXPECT = False
import re
class UnRar(AbtractExtractor):
+ __name__ = "UnRar"
+ __version__ = "0.1"
- def removeFiles(self, pack, fname):
- if not self.getConfig("deletearchive"):
- return
- m = self.re_splitfile.search(fname)
+ re_splitfile = re.compile("(.*)\.part(\d+)\.rar$")
- download_folder = self.core.config['general']['download_folder']
- if self.core.config['general']['folder_per_package']:
- folder = join(download_folder, pack.folder.decode(sys.getfilesystemencoding()))
- else:
- folder = download_folder
- if m:
- nre = re.compile("%s\.part\d+\.rar" % m.group(1))
- for fid, data in pack.getChildren().iteritems():
- if nre.match(data["name"]):
- remove(join(folder, data["name"]))
- elif not m and fname.endswith(".rar"):
- nre = re.compile("^%s\.r..$" % fname.replace(".rar", ""))
- for fid, data in pack.getChildren().iteritems():
- if nre.match(data["name"]):
- remove(join(folder, data["name"]))
-
- def packageFinished(self, pack):
- if pack.password and pack.password.strip() and pack.password.strip() != "None":
- self.addPassword(pack.password.splitlines())
- files = []
-
- for fid, data in pack.getChildren().iteritems():
- m = self.re_splitfile.search(data["name"])
- if m and int(m.group(2)) == 1:
- files.append((fid, m.group(0)))
- elif not m and data["name"].endswith(".rar"):
- files.append((fid, data["name"]))
-
- for fid, fname in files:
- self.core.log.info(_("starting Unrar of %s") % fname)
- pyfile = self.core.files.getFile(fid)
- pyfile.setStatus("processing")
-
- def s(p):
- pyfile.setProgress(p)
-
- download_folder = self.core.config['general']['download_folder']
- self.core.log.debug(_("download folder %s") % download_folder)
-
- folder = save_join(download_folder, pack.folder, "")
-
-
- destination = folder
- if self.getConfig("unrar_destination") and not self.getConfig("unrar_destination").lower() == "none":
- destination = self.getConfig("unrar_destination")
- sub = "."
- if self.core.config['general']['folder_per_package']:
- sub = pack.folder.decode(sys.getfilesystemencoding())
- if isabs(destination):
- destination = join(destination, sub, "")
- else:
- destination = join(folder, destination, sub, "")
-
- self.core.log.debug(_("Destination folder %s") % destination)
- if not exists(destination):
- self.core.log.info(_("Creating destination folder %s") % destination)
- makedirs(destination)
-
- u = Unrar(join(folder, fname), tmpdir=join(folder, "tmp"),
- ramSize=(self.ram if self.getConfig("ramwarning") else 0), cpu=self.getConfig("renice"))
- try:
- success = u.crackPassword(passwords=self.passwords, statusFunction=s, overwrite=True,
- destination=destination, fullPath=self.getConfig("fullpath"))
- except WrongPasswordError:
- self.core.log.info(_("Unrar of %s failed (wrong password)") % fname)
- continue
- except CommandError, e:
- if self.core.debug:
- print_exc()
- if re.search("Cannot find volume", e.stderr):
- self.core.log.info(_("Unrar of %s failed (missing volume)") % fname)
- continue
- try:
- if e.getExitCode() == 1 and len(u.listContent(u.getPassword())) == 1:
- self.core.log.info(_("Unrar of %s ok") % fname)
- self.removeFiles(pack, fname)
- except:
- if self.core.debug:
- print_exc()
- self.core.log.info(_("Unrar of %s failed") % fname)
- continue
- except LowRamError:
- self.log.warning(_(
- "Your ram amount of %s MB seems not sufficient to unrar this file. You can deactivate this warning and risk instability") % self.ram)
- continue
- except UnknownError:
- if self.core.debug:
- print_exc()
- self.core.log.info(_("Unrar of %s failed") % fname)
- continue
+ @staticmethod
+ def checkDeps():
+ return True #TODO
+
+ @staticmethod
+ def getTargets(files_ids):
+ result = []
+
+ for file, id in files_ids:
+ if not file.endswith(".rar"): continue
+
+ match = UnRar.re_splitfile.findall(file)
+ if match:
+ #only add first parts
+ if int(match[0][1]) == 1:
+ result.append((file, id))
else:
- if success:
- self.core.log.info(_("Unrar of %s ok") % fname)
- self.removeFiles(pack, fname)
-
- if os.name != "nt" and self.core.config['permission']['change_dl'] and\
- self.core.config['permission']['change_file']:
- ownerUser = self.core.config['permission']['user']
- fileMode = int(self.core.config['permission']['file'], 8)
-
- self.core.log.debug("Setting destination file/directory owner / mode to %s / %s"
- % (ownerUser, fileMode))
-
- uinfo = getpwnam(ownerUser)
- self.core.log.debug("Uid/Gid is %s/%s." % (uinfo.pw_uid, uinfo.pw_gid))
- self.setOwner(destination, uinfo.pw_uid, uinfo.pw_gid, fileMode)
- self.core.log.debug("The owner/rights have been successfully changed.")
-
- self.core.hookManager.unrarFinished(folder, fname)
- else:
- self.core.log.info(_("Unrar of %s failed (wrong password or bad parts)") % fname)
- finally:
- pyfile.setProgress(100)
- pyfile.setStatus("finished")
- pyfile.release()
+ result.append((file, id))
+
+ return result
+
+
+ def init(self):
+ self.passwordProtected = False
+ self.headerProtected = False #list files will not work without password
+ self.smallestFile = None #small file to test passwords
+ self.password = "" #save the correct password
+
+ def checkArchive(self):
+ p = self.call_unrar("l", "-v", self.file)
+ out, err = p.communicate()
+ if "Corrupt file or wrong password." in err:
+ self.passwordProtected = True
+ self.headerProtected = True
+ return True
+
+ self.listContent()
+ if not self.files:
+ self.m.archiveError("Empty Archive")
+
+ return False
+
+ def checkPassword(self, password):
+ if not self.passwordProtected: return True
+
+ if self.headerProtected:
+ p = self.call_unrar("l", "-v", self.file, password=password)
+ out, err = p.communicate()
+ if "Corrupt file or wrong password." in err:
+ return False
+
+ return True
+
+
+ def extract(self, progress, password=None):
+ command = "x" if self.fullpath else "e"
+
+ if PEXPECT:
+ p = self.call_unrar(command, self.file, self.out, password=password, pexpect=True)
+ #renice(p.pid, self.renice)
+
+ cpl = p.compile_pattern_list([pexpect.EOF, "(\d+)\s?%"])
+ while True:
+ i = p.expect_list(cpl, timeout=None)
+ if i == 0: # EOF
+ break #exited
+ elif i == 1:
+ perc = p.match.group(1)
+ progress(int(perc))
+ # pexpect thinks process is still alive (just like popen) - very strange behavior
+ p.terminated = True
+
+ else:
+ #subprocess - no progress
+ p = self.call_unrar(command, self.file, self.out, password=password)
+ renice(p.pid, self.renice)
+
+ progress(0)
+ out, err = p.communicate() #wait for process
+ progress(100)
+
+ #TODO, check for errors
+
+
+ def getDeleteFiles(self):
+ #TODO
+ return []
+
+ def listContent(self):
+ command = "vb" if self.fullpath else "lb"
+ p = self.call_unrar(command, "-v", self.file, password=self.password)
+ out, err = p.communicate()
+
+ result = set()
+
+ for f in out.splitlines():
+ f = f.strip()
+ result.add(save_join(self.out, f))
+
+ self.files = result
+
+
+ def call_unrar(self, command, *xargs, **kwargs):
+ if os.name == "nt":
+ cmd = join(pypath, "UnRAR.exe")
+ else:
+ cmd = "unrar"
+
+ args = []
+
+ #overwrite flag
+ args.append("-o+") if self.overwrite else args.append("-o-")
+
+ # assume yes on all queries
+ args.append("-y")
+
+ #set a password
+ if "password" in kwargs and kwargs["password"]:
+ args.append("-p%s" % kwargs["password"])
+ else:
+ args.append("-p-")
+
+
+ #NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue
+ call = [cmd, command] + args + list(xargs)
+ self.m.logDebug(" ".join(call))
+
+ if PEXPECT and "pexpect" in kwargs:
+ #use pexpect if available
+ p = pexpect.spawn(" ".join(call))
+ else:
+ p = Popen(call, stdout=PIPE, stderr=PIPE)
+
+ return p
+
+def renice(pid, value):
+ if os.name != "nt" and value:
+ try:
+ Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1)
+ except:
+ print "Renice failed" \ No newline at end of file