diff options
| -rw-r--r-- | docs/conf.py | 2 | ||||
| -rw-r--r-- | module/Api.py | 34 | ||||
| -rw-r--r-- | module/PyPackage.py | 9 | ||||
| -rw-r--r-- | module/database/FileDatabase.py | 3 | ||||
| -rw-r--r-- | module/plugins/Account.py | 30 | ||||
| -rw-r--r-- | module/plugins/Crypter.py | 92 | ||||
| -rw-r--r-- | module/plugins/crypter/LinkList.py (renamed from module/plugins/container/LinkList.py) | 32 | ||||
| -rw-r--r-- | module/plugins/hoster/YoutubeCom.py | 6 | ||||
| -rw-r--r-- | module/remote/thriftbackend/pyload.thrift | 2 | ||||
| -rw-r--r-- | module/threads/BaseThread.py | 30 | ||||
| -rw-r--r-- | module/threads/DecrypterThread.py | 65 | ||||
| -rw-r--r-- | module/threads/DownloadThread.py | 4 | ||||
| -rw-r--r-- | module/threads/InfoThread.py | 51 | ||||
| -rw-r--r-- | module/threads/ThreadManager.py | 11 | ||||
| -rw-r--r-- | module/utils/__init__.py | 4 | ||||
| -rw-r--r-- | module/utils/fs.py | 5 | ||||
| -rw-r--r-- | module/web/templates/default/base.html | 2 | ||||
| -rwxr-xr-x | pyLoadCli.py | 4 | ||||
| -rwxr-xr-x | pyLoadCore.py | 2 | 
19 files changed, 227 insertions, 161 deletions
| diff --git a/docs/conf.py b/docs/conf.py index 9d2cf98f9..09e4d0c1c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -52,7 +52,7 @@ master_doc = 'index'  # General information about the project.  project = u'pyLoad' -copyright = u'2011, pyLoad Team' +copyright = u'2012, pyLoad Team'  # The version info for the project you're documenting, acts as replacement for  # |version| and |release|, also used in various other places throughout the diff --git a/module/Api.py b/module/Api.py index deac1a19f..810613b66 100644 --- a/module/Api.py +++ b/module/Api.py @@ -17,10 +17,12 @@      @author: RaNaN  """ +import re  from base64 import standard_b64encode  from os.path import join  from time import time -import re +from itertools import chain +  from PyFile import PyFile  from utils import freeSpace, compare_time @@ -321,7 +323,7 @@ class Api(Iface):          self.core.threadManager.createInfoThread(hoster, pid)          self.core.threadManager.createDecryptThread(crypter, pid) -        self.core.log.info(_("Added %(count)d links to package #%(package)d ") % {"count": len(links), "package": pid}) +        self.core.log.debug("Added %d links to package #%d " % (len(hoster), pid))          self.core.files.save()      @permission(PERMS.ADD) @@ -354,7 +356,7 @@ class Api(Iface):          data, crypter = self.core.pluginManager.parseUrls(urls)          plugins = {} -        for url, plugin in data: +        for url, plugin in chain(data, crypter):              if plugin in plugins:                  plugins[plugin].append(url)              else: @@ -364,15 +366,14 @@ class Api(Iface):      @permission(PERMS.ADD)      def checkOnlineStatus(self, urls): -        """ initiates online status check +        """ initiates online status check, will also decrypt files.          :param urls:          :return: initial set of data as `OnlineCheck` instance containing the result id          """          data, crypter = self.core.pluginManager.parseUrls(urls) -        rid = self.core.threadManager.createResultThread(data, False) - +        # initial result does not contain the crypter links          tmp = [(url, (url, OnlineStatus(url, pluginname, "unknown", 3, 0))) for url, pluginname in data]          data = parseNames(tmp)          result = {} @@ -382,6 +383,9 @@ class Api(Iface):                  status.packagename = k                  result[url] = status +        data.update(crypter) # hoster and crypter will be processed +        rid = self.core.threadManager.createResultThread(data, False) +          return OnlineCheck(rid, result)      @permission(PERMS.ADD) @@ -396,8 +400,8 @@ class Api(Iface):          th = open(join(self.core.config["general"]["download_folder"], "tmp_" + container), "wb")          th.write(str(data))          th.close() - -        return self.checkOnlineStatus(urls + [th.name]) +        urls.append(th.name) +        return self.checkOnlineStatus(urls)      @permission(PERMS.ADD)      def pollResults(self, rid): @@ -436,18 +440,6 @@ class Api(Iface):          return [self.addPackage(name, urls, dest) for name, urls                  in self.generatePackages(links).iteritems()] -    @permission(PERMS.ADD) -    def checkAndAddPackages(self, links, dest=Destination.Queue): -        """Checks online status, retrieves names, and will add packages.\ -        Because of this packages are not added immediatly, only for internal use. - -        :param links: list of urls -        :param dest: `Destination` -        :return: None -        """ -        data, crypter = self.core.pluginManager.parseUrls(links) -        self.core.threadManager.createResultThread(data, True) -      @permission(PERMS.LIST)      def getPackageData(self, pid): @@ -677,7 +669,7 @@ class Api(Iface):          th.write(str(data))          th.close() -        self.addPackage(th.name, [th.name], Destination.Queue) +        self.addPackage(th.name, [th.name])      @permission(PERMS.MODIFY)      def orderPackage(self, pid, position): diff --git a/module/PyPackage.py b/module/PyPackage.py index dce501d93..d4b468f9c 100644 --- a/module/PyPackage.py +++ b/module/PyPackage.py @@ -69,6 +69,13 @@ class PyPackage():      def delete(self):          self.m.deletePackage(self.id) -                 + +    def deleteIfEmpty(self): +        """  True if deleted  """ +        if not len(self.getChildren()): +            self.delete() +            return True +        return False +      def notifyChange(self):          self.m.core.eventManager.dispatchEvent("packageUpdated", self.id) diff --git a/module/database/FileDatabase.py b/module/database/FileDatabase.py index abe7c8fc9..116f2b02b 100644 --- a/module/database/FileDatabase.py +++ b/module/database/FileDatabase.py @@ -190,8 +190,7 @@ class FileHandler:          self.ev.dispatchEvent("linkDeleted", id, pid)          p = self.getPackage(pid) -        if not len(p.getChildren()): -            p.delete() +        p.deleteIfEmpty()          pyfiles = self.cache.values()          for pyfile in pyfiles: diff --git a/module/plugins/Account.py b/module/plugins/Account.py index 6b65051db..dcf36f8a0 100644 --- a/module/plugins/Account.py +++ b/module/plugins/Account.py @@ -48,10 +48,6 @@ class Account(Base, AccountInfo):          else:              activated = Account.activated -        for opt in self.known_opt: -            if opt not in options: -                options[opt] = "" -          for opt in options.keys():              if opt not in self.known_opt:                  del options[opt] @@ -74,12 +70,9 @@ class Account(Base, AccountInfo):      def init(self):          pass -    #TODO: remove user, data -    def login(self, user, data, req): +    def login(self, req):          """login into account, the cookies will be saved so user can be recognized -        :param user: Deprecated -        :param data: Deprecated          :param req: `Request` instance          """          raise NotImplemented @@ -98,7 +91,13 @@ class Account(Base, AccountInfo):          self.login_ts = time()          try: -            self.login(self.loginname, {"password": self.password}, req) +            try: +                self.login(req) +            except TypeError: #TODO: temporary +                self.logDebug("Deprecated .login(...) signature ommit user, data") +                self.login(self.loginname, {"password": self.password}, req) + +                              self.valid = True          except WrongPassword:              self.logWarning( @@ -117,24 +116,23 @@ class Account(Base, AccountInfo):          return self.valid      def restoreDefaults(self): -        self.valid = Account.valid          self.validuntil = Account.validuntil          self.trafficleft = Account.trafficleft          self.maxtraffic = Account.maxtraffic          self.premium = Account.premium -        self.activated = Account.activated -    def update(self, password=None, options={}): +    def update(self, password=None, options=None):          """ updates account and return true if anything changed """          self.login_ts = 0 +        self.valid = True #set valid so it will be retried to login          if "activated" in options:              self.activated = from_string(options["avtivated"], "bool")          if password:              self.password = password -            self._login() +            self.relogin()              return True          if options:              # remove unknown options @@ -172,7 +170,11 @@ class Account(Base, AccountInfo):              self.checkLogin(req)              self.logDebug("Get Account Info for %s" % self.loginname)              try: -                infos = self.loadAccountInfo(self.loginname, req) +                try: +                    infos = self.loadAccountInfo(req) +                except TypeError: #TODO: temporary +                    self.logDebug("Deprecated .loadAccountInfo(...) signature, ommit user argument.") +                    infos = self.loadAccountInfo(self.loginname, req)              except Exception, e:                  infos = {"error": str(e)}              finally: diff --git a/module/plugins/Crypter.py b/module/plugins/Crypter.py index fc54b32d7..7c76afee7 100644 --- a/module/plugins/Crypter.py +++ b/module/plugins/Crypter.py @@ -1,9 +1,11 @@  # -*- coding: utf-8 -*- +from traceback import print_exc +  from module.Api import Destination  from module.common.packagetools import parseNames -from module.utils import to_list -from module.utils.fs import exists +from module.utils import to_list, has_method +from module.utils.fs import exists, remove, fs_encode  from Base import Base, Retry @@ -17,6 +19,12 @@ class Package:      def addUrl(self, url):          self.urls.append(url) +    def __eq__(self, other): +        return self.name == other.name and self.urls == other.urls + +    def __repr__(self): +        return "<CrypterPackage name=%s, links=%s, dest=%s" % (self.name, self.urls, self.dest) +  class PyFileMockup:      """ Legacy class needed by old crypter plugins """      def __init__(self, url): @@ -49,8 +57,8 @@ class Crypter(Base):          """Static method to decrypt, something. Can be used by other plugins.          :param core: pyLoad `Core`, needed in decrypt context -        :param url_or_urls: List of urls or urls -        :return: List of decrypted urls, all packages info removed +        :param url_or_urls: List of urls or single url/ file content +        :return: List of decrypted urls, all package info removed          """          urls = to_list(url_or_urls)          p = cls(core) @@ -66,18 +74,19 @@ class Crypter(Base):                  ret.extend(url_or_pack.urls)              else: # single url                  ret.append(url_or_pack) +        # eliminate duplicates +        return set(ret) -        return ret - -    def __init__(self, core, pid=-1, password=None): +    def __init__(self, core, package=None, password=None):          Base.__init__(self, core)          self.req = core.requestFactory.getRequest(self.__name__) -        # Package id plugin was initilized for, dont use this, its not guaranteed to be set -        self.pid = pid - +        # Package the plugin was initialized for, dont use this, its not guaranteed to be set +        self.package = package          #: Password supplied by user          self.password = password +        #: Propose a renaming of the owner package +        self.rename = None          # For old style decrypter, do not use these !          self.packages = [] @@ -125,7 +134,7 @@ class Crypter(Base):          """          return [Package(name, purls) for name, purls in parseNames([(url,url) for url in urls]).iteritems()] -    def processDecrypt(self, urls): +    def _decrypt(self, urls):          """ Internal  method to select decrypting method          :param urls: List of urls/content @@ -136,28 +145,47 @@ class Crypter(Base):          # seperate local and remote files          content, urls = self.getLocalContent(urls) -        if hasattr(cls, "decryptURLs"): +        if has_method(cls, "decryptURLs"):              self.setup()              result = to_list(self.decryptURLs(urls)) -        elif hasattr(cls, "decryptURL"): +        elif has_method(cls, "decryptURL"):              result = []              for url in urls:                  self.setup()                  result.extend(to_list(self.decryptURL(url))) -        elif hasattr(cls, "decrypt"): +        elif has_method(cls, "decrypt"):              self.logDebug("Deprecated .decrypt() method in Crypter plugin") -            result = [] # TODO +            self.setup() +            self.decrypt() +            result = self.convertPackages()          else: -            self.logError("No Decrypting method was overwritten") +            if not has_method(cls, "decryptFile"): +                self.logDebug("No Decrypting method was overwritten in plugin %s" % self.__name__)              result = [] -        if hasattr(cls, "decryptFile"): -            for c in content: +        if has_method(cls, "decryptFile"): +            for f, c in content:                  self.setup()                  result.extend(to_list(self.decryptFile(c))) +                try: +                    if f.startswith("tmp_"): remove(f) +                except : +                    pass          return result +    def processDecrypt(self, urls): +        """ Catches all exceptions in decrypt methods and return results + +        :return: Decrypting results +        """ +        try: +            return self._decrypt(urls) +        except Exception: +            if self.core.debug: +                print_exc() +            return [] +      def getLocalContent(self, urls):          """Load files from disk @@ -178,9 +206,13 @@ class Crypter(Base):                      path = self.core.path(url)                  if path: -                    f = open(path, "wb") -                    content.append(f.read()) -                    f.close() +                    try: +                        f = open(fs_encode(path), "rb") +                        content.append((f.name, f.read())) +                        f.close() +                    except IOError, e: +                        self.logError("IOError", e) +                        remote.append(url)                  else:                      remote.append(url) @@ -193,20 +225,12 @@ class Crypter(Base):          """ Retry decrypting, will only work once. Somewhat deprecated method, should be avoided. """          raise Retry() -    def createPackages(self): +    def convertPackages(self):          """ Deprecated """ -        self.logDebug("Deprecated method .createPackages()") -        for pack in self.packages: - -            self.log.debug("Parsed package %(name)s with %(len)d links" % { "name" : pack[0], "len" : len(pack[1]) } ) -             -            links = [x.decode("utf-8") for x in pack[1]] -             -            pid = self.core.api.files.addLinks(self.pid, links) - - -        if self.urls: -            self.core.api.generateAndAddPackages(self.urls) +        self.logDebug("Deprecated method .convertPackages()") +        res = [Package(name, urls) for name, urls in self.packages] +        res.extend(self.urls) +        return res      def clean(self):          if hasattr(self, "req"): diff --git a/module/plugins/container/LinkList.py b/module/plugins/crypter/LinkList.py index 614c76c90..8e46f88a9 100644 --- a/module/plugins/container/LinkList.py +++ b/module/plugins/crypter/LinkList.py @@ -1,25 +1,21 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- - -from module.plugins.Crypter import Crypter +from module.plugins.Crypter import Crypter, Package  class LinkList(Crypter):      __name__ = "LinkList"      __version__ = "0.11"      __pattern__ = r".+\.txt$"      __description__ = """Read Link Lists in txt format""" -    __config__ = [("clear", "bool", "Clear Linklist after adding", False)]      __author_name__ = ("spoob", "jeix")      __author_mail__ = ("spoob@pyload.org", "jeix@hasnomail.com") +    def decryptFile(self, content): +        links = content.splitlines() -    def decrypt(self, pyfile): -        txt = open(pyfile.url, 'r') -        links = txt.readlines() -        curPack = "Parsed links from %s" % pyfile.name -         -        packages = {curPack:[],} +        curPack = "default" +        packages = {curPack:[]}          for link in links:              link = link.strip() @@ -33,10 +29,8 @@ class LinkList(Crypter):                  packages[curPack] = []                  continue              packages[curPack].append(link) -        txt.close()          # empty packages fix -          delete = []          for key,value in packages.iteritems(): @@ -46,12 +40,12 @@ class LinkList(Crypter):          for key in delete:              del packages[key] -        if self.getConfig("clear"): -            try: -                txt = open(pyfile.url, 'wb') -                txt.close() -            except: -                self.log.warning(_("LinkList could not be cleared.")) -         +        urls = [] +          for name, links in packages.iteritems(): -            self.packages.append((name, links, name)) +            if name == "default": +                urls.extend(links) +            else: +                urls.append(Package(name, links)) + +        return urls
\ No newline at end of file diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py index 2b3ea7ed7..b6ea36a3c 100644 --- a/module/plugins/hoster/YoutubeCom.py +++ b/module/plugins/hoster/YoutubeCom.py @@ -75,10 +75,10 @@ class YoutubeCom(Hoster):              fmt_dict[fmt] = unquote(url)          self.logDebug("Found links: %s" % fmt_dict) -	for fmt in fmt_dict.keys(): +        for fmt in fmt_dict.keys():              if fmt not in self.formats: -	        self.logDebug("FMT not supported: %s" % fmt) -		del fmt_dict[fmt] +                self.logDebug("FMT not supported: %s" % fmt) +                del fmt_dict[fmt]          allowed = lambda x: self.getConfig(self.formats[x][0])          sel = lambda x: self.formats[x][3] #select quality index diff --git a/module/remote/thriftbackend/pyload.thrift b/module/remote/thriftbackend/pyload.thrift index a6c0a259c..d33b468c3 100644 --- a/module/remote/thriftbackend/pyload.thrift +++ b/module/remote/thriftbackend/pyload.thrift @@ -177,7 +177,7 @@ struct AccountInfo {    6: i64 maxtraffic,    7: bool premium,    8: bool activated, -  9: map<string, list<string>> options, +  9: map<string, string> options,  }  struct ServiceCall { diff --git a/module/threads/BaseThread.py b/module/threads/BaseThread.py index b5856c856..1ba3f7a9f 100644 --- a/module/threads/BaseThread.py +++ b/module/threads/BaseThread.py @@ -1,6 +1,10 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- +import os +import sys +import locale +  from threading import Thread  from time import strftime, gmtime  from sys import exc_info @@ -14,32 +18,33 @@ class BaseThread(Thread):      """abstract base class for thread types"""      def __init__(self, manager): -        """Constructor"""          Thread.__init__(self)          self.setDaemon(True)          self.m = manager #thread manager          self.log = manager.core.log - -    def writeDebugReport(self, pyfile): +    def writeDebugReport(self, name, pyfile=None, plugin=None):          """ writes a debug report to disk  """ -        dump_name = "debug_%s_%s.zip" % (pyfile.pluginname, strftime("%d-%m-%Y_%H-%M-%S")) -        dump = self.getDebugDump(pyfile) +        dump_name = "debug_%s_%s.zip" % (name, strftime("%d-%m-%Y_%H-%M-%S")) +        if pyfile: +            dump = self.getFileDump(pyfile) +        else: +            dump = self.getPluginDump(plugin)          try:              import zipfile              zip = zipfile.ZipFile(dump_name, "w") -            for f in listdir(join("tmp", pyfile.pluginname)): +            for f in listdir(join("tmp", name)):                  try:                      # avoid encoding errors -                    zip.write(join("tmp", pyfile.pluginname, f), save_join(pyfile.pluginname, f)) +                    zip.write(join("tmp", name, f), save_join(name, f))                  except:                      pass -            info = zipfile.ZipInfo(save_join(pyfile.pluginname, "debug_Report.txt"), gmtime()) +            info = zipfile.ZipInfo(save_join(name, "debug_Report.txt"), gmtime())              info.external_attr = 0644 << 16L # change permissions              zip.writestr(info, dump) @@ -58,7 +63,7 @@ class BaseThread(Thread):          self.log.info("Debug Report written to %s" % dump_name) -    def getDebugDump(self, pyfile): +    def getFileDump(self, pyfile):          dump = "pyLoad %s Debug Report of %s %s \n\nTRACEBACK:\n %s \n\nFRAMESTACK:\n" % (              self.m.core.api.getServerVersion(), pyfile.pluginname, pyfile.plugin.__version__, format_exc()) @@ -111,6 +116,13 @@ class BaseThread(Thread):          return dump +        #TODO +    def getPluginDump(self, plugin): +        return "" + +    def getSystemDump(self): +        return "" +      def clean(self, pyfile):          """ set thread unactive and release pyfile """          self.active = False diff --git a/module/threads/DecrypterThread.py b/module/threads/DecrypterThread.py index 5ce59a65e..a1b7e4f38 100644 --- a/module/threads/DecrypterThread.py +++ b/module/threads/DecrypterThread.py @@ -1,35 +1,78 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- +from time import sleep +from traceback import print_exc + +from module.plugins.Base import Retry +from module.plugins.Crypter import Package +  from BaseThread import BaseThread  class DecrypterThread(BaseThread):      """thread for decrypting""" -    def __init__(self, manager, data, package): +    def __init__(self, manager, data, pid):          """constructor"""          BaseThread.__init__(self, manager) -        self.queue = data -        self.package = package - -        self.m.log.debug("Starting Decrypt thread") +        self.data = data +        self.pid = pid          self.start() -    def add(self, data): -        self.queue.extend(data) -      def run(self):          plugin_map = {} -        for plugin, url in self.queue: +        for url, plugin in self.data:              if plugin in plugin_map:                  plugin_map[plugin].append(url)              else:                  plugin_map[plugin] = [url] -          self.decrypt(plugin_map)      def decrypt(self, plugin_map): +        pack = self.m.core.files.getPackage(self.pid) +        result = [] +          for name, urls in plugin_map.iteritems(): -            p = self.m.core.pluginManager.loadClass("crypter", name) +            klass = self.m.core.pluginManager.loadClass("crypter", name) +            plugin = klass(self.m.core, pack, pack.password) +            plugin_result = [] + +            try: +                try: +                    plugin_result = plugin._decrypt(urls) +                except Retry: +                    sleep(1) +                    plugin_result = plugin._decrypt(urls) +            except Exception, e: +                plugin.logError(_("Decrypting failed"), e) +                if self.m.core.debug: +                    print_exc() +                    self.writeDebugReport(plugin.__name__, plugin=plugin) + +            plugin.logDebug("Decrypted", plugin_result) +            result.extend(plugin_result) + +        pack_names = {} +        urls = [] + +        for p in result: +            if isinstance(p, Package): +                if p.name in pack_names: +                    pack_names[p.name].urls.extend(p.urls) +                else: +                    pack_names[p.name] = p +            else: +                urls.append(p) + +        if urls: +            self.log.info(_("Decrypted %(count)d links into package %(name)s") % {"count": len(urls), "name": pack.name}) +            self.m.core.api.addFiles(self.pid, urls) + +        for p in pack_names: +            self.m.core.api.addPackage(p.name, p.urls, p.dest, pack.password) + +        if not result: +            self.log.info(_("No links decrypted")) + diff --git a/module/threads/DownloadThread.py b/module/threads/DownloadThread.py index 3d444686b..638861338 100644 --- a/module/threads/DownloadThread.py +++ b/module/threads/DownloadThread.py @@ -156,7 +156,7 @@ class DownloadThread(BaseThread):                      self.m.log.error("pycurl error %s: %s" % (code, msg))                      if self.m.core.debug:                          print_exc() -                        self.writeDebugReport(pyfile) +                        self.writeDebugReport(pyfile.pluginname, pyfile)                      self.m.core.hookManager.downloadFailed(pyfile) @@ -186,7 +186,7 @@ class DownloadThread(BaseThread):                  if self.m.core.debug:                      print_exc() -                    self.writeDebugReport(pyfile) +                    self.writeDebugReport(pyfile.pluginname, pyfile)                  self.m.core.hookManager.downloadFailed(pyfile)                  self.clean(pyfile) diff --git a/module/threads/InfoThread.py b/module/threads/InfoThread.py index 4cba7da38..596153c4b 100644 --- a/module/threads/InfoThread.py +++ b/module/threads/InfoThread.py @@ -7,11 +7,12 @@ from traceback import print_exc  from module.Api import OnlineStatus  from module.PyFile import PyFile  from module.common.packagetools import parseNames +from module.utils import has_method  from BaseThread import BaseThread  class InfoThread(BaseThread): -    def __init__(self, manager, data, pid=-1, rid=-1, add=False): +    def __init__(self, manager, data, pid=-1, rid=-1):          """Constructor"""          BaseThread.__init__(self, manager) @@ -20,7 +21,6 @@ class InfoThread(BaseThread):          # [ .. (name, plugin) .. ]          self.rid = rid #result id -        self.add = add #add packages instead of return result          self.cache = [] #accumulated data @@ -39,8 +39,8 @@ class InfoThread(BaseThread):                  plugins[plugin] = [url] -        # filter out container plugins -        for name in self.m.core.pluginManager.getPlugins("container"): +        # filter out crypter plugins +        for name in self.m.core.pluginManager.getPlugins("crypter"):              if name in plugins:                  container.extend([(name, url) for url in plugins[name]]) @@ -50,35 +50,17 @@ class InfoThread(BaseThread):          if self.pid > -1:              for pluginname, urls in plugins.iteritems():                  plugin = self.m.core.pluginManager.getPlugin(pluginname, True) -                if hasattr(plugin, "getInfo"): +                klass = getattr(plugin, pluginname) +                if has_method(klass, "getInfo"): +                    self.fetchForPlugin(pluginname, klass, urls, self.updateDB) +                    self.m.core.files.save() +                elif has_method(plugin, "getInfo"): +                    self.log.debug("Deprecated .getInfo() method on module level, use classmethod instead")                      self.fetchForPlugin(pluginname, plugin, urls, self.updateDB)                      self.m.core.files.save() -        elif self.add: -            for pluginname, urls in plugins.iteritems(): -                plugin = self.m.core.pluginManager.getPlugin(pluginname, True) -                if hasattr(plugin, "getInfo"): -                    self.fetchForPlugin(pluginname, plugin, urls, self.updateCache, True) - -                else: -                    #generate default result -                    result = [(url, 0, 3, url) for url in urls] - -                    self.updateCache(pluginname, result) - -            packs = parseNames([(name, url) for name, x, y, url in self.cache]) - -            self.m.log.debug("Fetched and generated %d packages" % len(packs)) - -            for k, v in packs: -                self.m.core.api.addPackage(k, v) - -            #empty cache -            del self.cache[:] -          else: #post the results - - +            #TODO: finer crypter control              for name, url in container:                  #attach container content                  try: @@ -98,13 +80,18 @@ class InfoThread(BaseThread):              for pluginname, urls in plugins.iteritems():                  plugin = self.m.core.pluginManager.getPlugin(pluginname, True) -                if hasattr(plugin, "getInfo"): +                klass = getattr(plugin, pluginname) +                if has_method(klass, "getInfo"): +                    self.fetchForPlugin(pluginname, plugin, urls, self.updateResult, True) +                    #force to process cache +                    if self.cache: +                        self.updateResult(pluginname, [], True) +                elif has_method(plugin, "getInfo"): +                    self.log.debug("Deprecated .getInfo() method on module level, use staticmethod instead")                      self.fetchForPlugin(pluginname, plugin, urls, self.updateResult, True) -                      #force to process cache                      if self.cache:                          self.updateResult(pluginname, [], True) -                  else:                      #generate default result                      result = [(url, 0, 3, url) for url in urls] diff --git a/module/threads/ThreadManager.py b/module/threads/ThreadManager.py index c32286eb9..612da2536 100644 --- a/module/threads/ThreadManager.py +++ b/module/threads/ThreadManager.py @@ -71,7 +71,7 @@ class ThreadManager:          pycurl.global_init(pycurl.GLOBAL_DEFAULT) -        for i in range(0, self.core.config.get("download", "max_downloads")): +        for i in range(self.core.config.get("download", "max_downloads")):              self.createThread() @@ -84,25 +84,24 @@ class ThreadManager:      def createInfoThread(self, data, pid):          """ start a thread whichs fetches online status and other infos """          self.timestamp = time() + 5 * 60 - -        InfoThread(self, data, pid) +        if data: InfoThread(self, data, pid)      @lock -    def createResultThread(self, data, add=False): +    def createResultThread(self, data):          """ creates a thread to fetch online status, returns result id """          self.timestamp = time() + 5 * 60          rid = self.resultIDs          self.resultIDs += 1 -        InfoThread(self, data, rid=rid, add=add) +        InfoThread(self, data, rid=rid)          return rid      @lock      def createDecryptThread(self, data, pid):          """ Start decrypting of entered data, all links in one package are accumulated to one thread.""" -        DecrypterThread(self, data, pid) +        if data: DecrypterThread(self, data, pid)      @lock diff --git a/module/utils/__init__.py b/module/utils/__init__.py index 0d68448cb..a237fde9b 100644 --- a/module/utils/__init__.py +++ b/module/utils/__init__.py @@ -157,6 +157,10 @@ def fixup(m):      return text # leave as is +def has_method(obj, name): +    """ checks if 'name' was defined in obj, (false if it was inhereted) """ +    return name in obj.__dict__ +  def html_unescape(text):      """Removes HTML or XML character references and entities from a text string"""      return re.sub("&#?\w+;", fixup, text) diff --git a/module/utils/fs.py b/module/utils/fs.py index 23f87a326..037165b6b 100644 --- a/module/utils/fs.py +++ b/module/utils/fs.py @@ -20,7 +20,10 @@ else:  # FS utilities  def chmod(path, mode): -    return os.chmod(fs_encode(path), mode) +    try: +        return os.chmod(fs_encode(path), mode) +    except : +        pass  def chown(path, uid, gid):      return os.chown(fs_encode(path), uid, gid) diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html index 0b20ecdb0..1f77c04ba 100644 --- a/module/web/templates/default/base.html +++ b/module/web/templates/default/base.html @@ -162,7 +162,7 @@  	<hr style="clear: both;" />
 -<div id="foot">© 2008-2011 pyLoad Team
 +<div id="foot">© 2008-2012 pyLoad Team
  <a href="#top" class="action top" accesskey="x"><span>{{_("Back to top")}}</span></a><br />
  <!--<div class="breadcrumbs"></div>-->
 diff --git a/pyLoadCli.py b/pyLoadCli.py index 079cee19c..97e64dfee 100755 --- a/pyLoadCli.py +++ b/pyLoadCli.py @@ -1,7 +1,7 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*-  # -#Copyright (C) 2011 RaNaN +#Copyright (C) 2012 RaNaN  #  #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 @@ -392,7 +392,7 @@ class RefreshThread(Thread):  def print_help(config):      print -    print "pyLoadCli Copyright (c) 2008-2011 the pyLoad Team" +    print "pyLoadCli Copyright (c) 2008-2012 the pyLoad Team"      print      print "Usage: [python] pyLoadCli.py [options] [command]"      print diff --git a/pyLoadCore.py b/pyLoadCore.py index b5b4add9e..d1a557c43 100755 --- a/pyLoadCore.py +++ b/pyLoadCore.py @@ -151,7 +151,7 @@ class Core(object):      def print_help(self):          print "" -        print "pyLoad v%s     2008-2011 the pyLoad Team" % CURRENT_VERSION +        print "pyLoad v%s     2008-2012 the pyLoad Team" % CURRENT_VERSION          print ""          if sys.argv[0].endswith(".py"):              print "Usage: python pyLoadCore.py [options]" | 
