# -*- coding: utf-8 -*- """ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . @author: mkaay """ 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 module.plugins.Hook import Hook from module.lib.pyunrar import Unrar, WrongPasswordError, CommandError, UnknownError, LowRamError from module.utils import save_join if os.name != "nt": from pwd import getpwnam from os import chown import re class UnRar(Hook): __name__ = "UnRar" __version__ = "0.11" __description__ = """unrar""" __config__ = [("activated", "bool", "Activated", False), ("fullpath", "bool", "extract full path", True), ("overwrite", "bool", "overwrite files", True), ("passwordfile", "str", "unrar password file", "unrar_passwords.txt"), ("deletearchive", "bool", "delete archives when done", False), ("ramwarning", "bool", "warn about low ram", True), ("renice", "int", "Cpu Priority", 10), ("unrar_destination", "str", "Unpack files to", "")] __threaded__ = ["packageFinished"] __author_name__ = ("mkaay") __author_mail__ = ("mkaay@mkaay.de") def setup(self): self.comments = ["# one password each line"] self.passwords = [] if exists(self.getConfig("passwordfile")): with open(self.getConfig("passwordfile"), "r") as f: for l in f.readlines(): l = l.strip("\n\r") if l and not l.startswith("#"): self.passwords.append(l) else: with open(self.getConfig("passwordfile"), "w") as f: f.writelines(self.comments) self.re_splitfile = re.compile("(.*)\.part(\d+)\.rar$") self.ram = 0 #ram in kb for unix osses try: f = open("/proc/meminfo") line = True while line: line = f.readline() if line.startswith("MemTotal:"): self.ram = int(re.search(r"([0-9]+)", line).group(1)) except: self.ram = 0 self.ram /= 1024 def setOwner(self, d, uid, gid, mode): if not exists(d): self.core.log.debug(_("Directory %s does not exist!") % d) return for fileEntry in listdir(d): fullEntryName = join(d, fileEntry) if isdir(fullEntryName): self.setOwner(fullEntryName, uid, gid, mode) try: chown(fullEntryName, uid, gid) chmod(fullEntryName, mode) except: self.core.log.debug(_("Chown/Chmod for %s failed") % fullEntryName) self.core.log.debug(_("Exception: %s") % sys.exc_info()[0]) continue try: chown(d, uid, gid) chmod(d, mode) except: self.core.log.debug(_("Chown/Chmod for %s failed") % d) self.core.log.debug(_("Exception: %s") % sys.exc_info()[0]) return def addPassword(self, pws): if not type(pws) == list: pws = [pws] pws.reverse() for pw in pws: pw = pw.strip() if not pw or pw == "None" or pw in self.passwords: continue self.passwords.insert(0, pw) with open(self.getConfig("passwordfile"), "w") as f: f.writelines([c + "\n" for c in self.comments]) f.writelines([p + "\n" for p in self.passwords]) def removeFiles(self, pack, fname): if not self.getConfig("deletearchive"): return m = self.re_splitfile.search(fname) 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 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()