diff options
| author | 2013-07-17 11:50:15 +0200 | |
|---|---|---|
| committer | 2013-07-17 11:50:15 +0200 | |
| commit | a3dfd09a8d560f6e6591de2e1de95e82ed2ddce3 (patch) | |
| tree | c3ebfd206a532a91300e69ac04c6229abf615ba5 /pyload | |
| parent | fixed last commit (diff) | |
| download | pyload-a3dfd09a8d560f6e6591de2e1de95e82ed2ddce3.tar.xz | |
improved inputTypes, config api
Diffstat (limited to 'pyload')
| -rw-r--r-- | pyload/PluginManager.py | 48 | ||||
| -rw-r--r-- | pyload/api/ConfigApi.py | 15 | ||||
| -rw-r--r-- | pyload/config/ConfigManager.py | 7 | ||||
| -rw-r--r-- | pyload/config/ConfigParser.py | 80 | ||||
| -rw-r--r-- | pyload/config/convert.py | 38 | ||||
| -rw-r--r-- | pyload/config/default.py | 150 | ||||
| -rw-r--r-- | pyload/interaction/InteractionManager.py | 10 | ||||
| -rw-r--r-- | pyload/plugins/Account.py | 6 | ||||
| -rw-r--r-- | pyload/plugins/Base.py | 14 | ||||
| -rw-r--r-- | pyload/plugins/hoster/BasePlugin.py | 4 | ||||
| -rw-r--r-- | pyload/remote/apitypes.py | 34 | ||||
| -rw-r--r-- | pyload/remote/apitypes_debug.py | 8 | ||||
| -rw-r--r-- | pyload/remote/pyload.thrift | 16 | ||||
| -rw-r--r-- | pyload/remote/wsbackend/AsyncHandler.py | 2 | ||||
| -rw-r--r-- | pyload/utils/__init__.py | 28 | ||||
| -rw-r--r-- | pyload/web/app/scripts/utils/apitypes.js | 2 | ||||
| -rw-r--r-- | pyload/web/app/scripts/views/input/inputLoader.js | 2 | ||||
| -rw-r--r-- | pyload/web/app/scripts/views/input/inputView.js | 4 | ||||
| -rw-r--r-- | pyload/web/app/scripts/views/queryModal.js | 2 | 
19 files changed, 259 insertions, 211 deletions
| diff --git a/pyload/PluginManager.py b/pyload/PluginManager.py index dab5be063..149d04fc2 100644 --- a/pyload/PluginManager.py +++ b/pyload/PluginManager.py @@ -22,6 +22,7 @@ from os import listdir, makedirs  from os.path import isfile, join, exists, abspath, basename  from sys import version_info  from time import time +from collections import defaultdict  from pyload.lib.SafeEval import const_eval as literal_eval  from pyload.plugins.Base import Base @@ -34,10 +35,20 @@ from new_collections import namedtuple  IGNORE = (      "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('addons', 'UnRar'),      'EasyShareCom', 'FlyshareCz' -    ) +)  PluginTuple = namedtuple("PluginTuple", "version re deps category user path") +class BaseAttributes(defaultdict): +    """ Dictionary that loads defaults values from Base object """ +    def __missing__(self, key): +        attr = "__%s__" % key +        if not hasattr(Base, attr): +            return defaultdict.__missing__(self, key) + +        return getattr(Base, attr) + +  class PluginManager:      ROOT = "pyload.plugins."      LOCALROOT = "localplugins." @@ -45,7 +56,7 @@ class PluginManager:      BUILTIN = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s?(True|False|None|[0-9x.]+)', re.I)      SINGLE = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s*(?:r|u|_)?((?:(?<!")"(?!")|\'|\().*(?:(?<!")"(?!")|\'|\)))', -        re.I) +                        re.I)      # note the nongreedy character: that means we can not embed list and dicts      MULTI = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s*((?:\{|\[|"{3}).*?(?:"""|\}|\]))', re.DOTALL | re.M | re.I) @@ -102,7 +113,7 @@ class PluginManager:          for f in listdir(pfolder):              if (isfile(join(pfolder, f)) and f.endswith(".py") or f.endswith("_25.pyc") or f.endswith( -                "_26.pyc") or f.endswith("_27.pyc")) and not f.startswith("_"): +                    "_26.pyc") or f.endswith("_27.pyc")) and not f.startswith("_"):                  if f.endswith("_25.pyc") and version_info[0:2] != (2, 5):                      continue                  elif f.endswith("_26.pyc") and version_info[0:2] != (2, 6): @@ -130,7 +141,7 @@ class PluginManager:          content = data.read()          data.close() -        attrs = {} +        attrs = BaseAttributes()          for m in self.BUILTIN.findall(content) + self.SINGLE.findall(content) + self.MULTI.findall(content):              #replace gettext function and eval result              try: @@ -179,10 +190,11 @@ class PluginManager:              except:                  self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"])                  plugin_re = self.NO_MATCH -        else: plugin_re = self.NO_MATCH +        else: +            plugin_re = self.NO_MATCH -        deps = attrs.get("dependencies", None) -        category = attrs.get("category", None) if folder == "addons" else None +        deps = attrs["dependencies"] +        category = attrs["category"] if folder == "addons" else ""          # create plugin tuple          plugin = PluginTuple(version, plugin_re, deps, category, bool(home), filename) @@ -191,29 +203,29 @@ class PluginManager:          if folder == "internal":              return plugin -        if folder == "addons" and "config" not in attrs and not attrs.get("internal", False): +        if folder == "addons" and "config" not in attrs and not attrs["internal"]:              attrs["config"] = (["activated", "bool", "Activated", False],)          if "config" in attrs and attrs["config"] is not None:              config = attrs["config"] -            desc = attrs.get("description", "") -            long_desc = attrs.get("long_description", "") +            desc = attrs["description"] +            expl = attrs["explanation"]              # Convert tuples to list              config = [list(x) for x in config] -            if folder == "addons" and not attrs.get("internal", False): +            if folder == "addons" and not attrs["internal"]:                  for item in config:                      if item[0] == "activated": break                  else: # activated flag missing                      config.insert(0, ("activated", "bool", "Activated", False))              # Everything that is no addon and user_context=True, is added to dict -            if folder != "addons" or attrs.get("user_context", False): +            if folder != "addons" or attrs["user_context"]:                  self.user_context[name] = True              try: -                self.core.config.addConfigSection(name, name, desc, long_desc, config) +                self.core.config.addConfigSection(name, name, desc, expl, config)              except:                  self.logDebug(folder, name, "Invalid config  %s" % config) @@ -312,8 +324,10 @@ class PluginManager:      def find_module(self, fullname, path=None):          #redirecting imports if necesarry          if fullname.startswith(self.ROOT) or fullname.startswith(self.LOCALROOT): #separate pyload plugins -            if fullname.startswith(self.LOCALROOT): user = 1 -            else: user = 0 #used as bool and int +            if fullname.startswith(self.LOCALROOT): +                user = 1 +            else: +                user = 0 #used as bool and int              split = fullname.split(".")              if len(split) != 4 - user: return @@ -347,13 +361,13 @@ class PluginManager:                  self.log.debug("Old import reference detected, use %s" % name)                  replace = False -              if replace:                  if self.ROOT in name:                      newname = name.replace(self.ROOT, self.LOCALROOT)                  else:                      newname = name.replace(self.LOCALROOT, self.ROOT) -            else: newname = name +            else: +                newname = name              base, plugin = newname.rsplit(".", 1) diff --git a/pyload/api/ConfigApi.py b/pyload/api/ConfigApi.py index 82cfdd418..2adc0c565 100644 --- a/pyload/api/ConfigApi.py +++ b/pyload/api/ConfigApi.py @@ -8,9 +8,9 @@ from ApiComponent import ApiComponent  # helper function to create a ConfigHolder  def toConfigHolder(section, config, values): -    holder = ConfigHolder(section, config.name, config.description, config.long_desc) -    holder.items = [ConfigItem(option, x.name, x.description, x.type, to_string(x.default), -                               to_string(values.get(option, x.default))) for option, x in +    holder = ConfigHolder(section, config.label, config.description, config.explanation) +    holder.items = [ConfigItem(option, x.label, x.description, x.input, +                               to_string(values.get(option, x.input.default_value))) for option, x in                      config.config.iteritems()]      return holder @@ -56,7 +56,7 @@ class ConfigApi(ApiComponent):          :rtype: list of PluginInfo          """ -        return [ConfigInfo(section, config.name, config.description, False, False) +        return [ConfigInfo(section, config.label, config.description, False, False)                  for section, config, values in self.core.config.iterCoreSections()]      @RequirePerm(Permission.Plugins) @@ -74,11 +74,12 @@ class ConfigApi(ApiComponent):              # skip unmodified and inactive addons              if not values and name not in active: continue -            item = ConfigInfo(name, config.name, config.description, +            item = ConfigInfo(name, config.label, config.description,                                self.core.pluginManager.getCategory(name),                                self.core.pluginManager.isUserPlugin(name), +                              # TODO: won't work probably                                values.get("activated", None if "activated" not in config.config else config.config[ -                                  "activated"].default)) +                                  "activated"].input.default_value))              data.append(item)          return data @@ -90,7 +91,7 @@ class ConfigApi(ApiComponent):          :rtype: list of PluginInfo          """          # TODO: filter user_context / addons when not allowed -        plugins = [ConfigInfo(name, config.name, config.description, +        plugins = [ConfigInfo(name, config.label, config.description,                                self.core.pluginManager.getCategory(name),                                self.core.pluginManager.isUserPlugin(name))                     for name, config, values in self.core.config.iterSections(self.primaryUID)] diff --git a/pyload/config/ConfigManager.py b/pyload/config/ConfigManager.py index f9dc3795b..33bd151c3 100644 --- a/pyload/config/ConfigManager.py +++ b/pyload/config/ConfigManager.py @@ -4,10 +4,11 @@  from new_collections import OrderedDict  from pyload.Api import InvalidConfigSection -from pyload.utils import from_string, json +from pyload.utils import json  from ConfigParser import ConfigParser +from convert import to_input, from_string  def convertKeyError(func):      """ converts KeyError into InvalidConfigSection """ @@ -64,7 +65,7 @@ class ConfigManager(ConfigParser):              except KeyError:                  pass # Returns default value later -        return self.config[section].config[option].default +        return self.config[section].config[option].input.default_value      def loadValues(self, user, section):          if (user, section) not in self.values: @@ -86,7 +87,7 @@ class ConfigManager(ConfigParser):              changed = self.parser.set(section, option, value, sync)          else:              data = self.config[section].config[option] -            value = from_string(value, data.type) +            value = from_string(value, data.input.type)              old_value = self.get(section, option)              # Values will always be saved to db, sync is ignored diff --git a/pyload/config/ConfigParser.py b/pyload/config/ConfigParser.py index fd22e93b9..bda3f7bd4 100644 --- a/pyload/config/ConfigParser.py +++ b/pyload/config/ConfigParser.py @@ -6,14 +6,16 @@ from os.path import exists  from gettext import gettext  from new_collections import namedtuple, OrderedDict -from pyload.utils import from_string + +from pyload.Api import Input, InputType  from pyload.utils.fs import chmod  from default import make_config +from convert import to_input, from_string  CONF_VERSION = 2 -SectionTuple = namedtuple("SectionTuple", "name description long_desc config") -ConfigData = namedtuple("ConfigData", "name type description default") +SectionTuple = namedtuple("SectionTuple", "label description explanation config") +ConfigData = namedtuple("ConfigData", "label description input")  class ConfigParser:      """ @@ -41,31 +43,21 @@ class ConfigParser:      def checkVersion(self):          """Determines if config needs to be deleted""" -        e = None -        # workaround conflict, with GUI (which also accesses the config) so try read in 3 times -        for i in range(0, 3): -            try: -                if exists(self.CONFIG): -                    f = open(self.CONFIG, "rb") -                    v = f.readline() -                    f.close() -                    v = v[v.find(":") + 1:].strip() - -                    if not v or int(v) < CONF_VERSION: -                        f = open(self.CONFIG, "wb") -                        f.write("version: " + str(CONF_VERSION)) -                        f.close() -                        print "Old version of %s deleted" % self.CONFIG -                else: -                    f = open(self.CONFIG, "wb") -                    f.write("version:" + str(CONF_VERSION)) -                    f.close() - -            except Exception, ex: -                e = ex -                sleep(0.3) -        if e: raise e - +        if exists(self.CONFIG): +            f = open(self.CONFIG, "rb") +            v = f.readline() +            f.close() +            v = v[v.find(":") + 1:].strip() + +            if not v or int(v) < CONF_VERSION: +                f = open(self.CONFIG, "wb") +                f.write("version: " + str(CONF_VERSION)) +                f.close() +                print "Old version of %s deleted" % self.CONFIG +        else: +            f = open(self.CONFIG, "wb") +            f.write("version:" + str(CONF_VERSION)) +            f.close()      def parseValues(self, filename):          """read config values from file""" @@ -139,13 +131,13 @@ class ConfigParser:          try:              return self.values[section][option]          except KeyError: -            return self.config[section].config[option].default +            return self.config[section].config[option].input.default_value      def set(self, section, option, value, sync=True):          """set value"""          data = self.config[section].config[option] -        value = from_string(value, data.type) +        value = from_string(value, data.input.type)          old_value = self.get(section, option)          # only save when different values @@ -172,22 +164,34 @@ class ConfigParser:          """ Retrieves single config as tuple (section, values) """          return self.config[section], self.values[section] if section in self.values else {} -    def addConfigSection(self, section, name, desc, long_desc, config): +    def addConfigSection(self, section, label, desc, expl, config):          """Adds a section to the config. `config` is a list of config tuples as used in plugin api defined as:          The order of the config elements is preserved with OrderedDict          """          d = OrderedDict()          for entry in config: -            if len(entry) == 5: -                conf_name, type, conf_desc, conf_verbose, default = entry -            else: # config options without description -                conf_name, type, conf_desc, default = entry -                conf_verbose = "" +            if len(entry) != 4: +                raise ValueError("Config entry must be of length 4") + +            # Values can have different roles depending on the two config formats +            conf_name, type_label, label_desc, default_input = entry + +            # name, label, desc, input +            if isinstance(default_input, Input): +                input = default_input +                conf_label = type_label +                conf_desc = label_desc +            # name, type, label, default +            else: +                input = Input(to_input(type_label)) +                input.default_value = from_string(default_input, input.type) +                conf_label = label_desc +                conf_desc = "" -            d[conf_name] = ConfigData(gettext(conf_desc), type, gettext(conf_verbose), from_string(default, type)) +            d[conf_name] = ConfigData(gettext(conf_label), gettext(conf_desc), input) -        data = SectionTuple(gettext(name), gettext(desc), gettext(long_desc), d) +        data = SectionTuple(gettext(label), gettext(desc), gettext(expl), d)          self.config[section] = data  class Section: diff --git a/pyload/config/convert.py b/pyload/config/convert.py new file mode 100644 index 000000000..f25f6a7ba --- /dev/null +++ b/pyload/config/convert.py @@ -0,0 +1,38 @@ + +from pyload.Api import Input, InputType +from pyload.utils import decode, to_bool + +# Maps old config formats to new values +input_dict = { +    "int": InputType.Int, +    "bool": InputType.Bool, +    "time": InputType.Time, +    "file": InputType.File, +    "folder": InputType.Folder +} + + +def to_input(typ): +    """ Converts old config format to input type""" +    return input_dict.get(typ, InputType.Text) + + +def from_string(value, typ=None): +    """ cast value to given type, unicode for strings """ + +    # value is no string +    if not isinstance(value, basestring): +        return value + +    value = decode(value) + +    if typ == InputType.Int: +        return int(value) +    elif typ == InputType.Bool: +        return to_bool(value) +    elif typ == InputType.Time: +        if not value: value = "0:00" +        if not ":" in value: value += ":00" +        return value +    else: +        return value
\ No newline at end of file diff --git a/pyload/config/default.py b/pyload/config/default.py index 8388d32df..9fad814d3 100644 --- a/pyload/config/default.py +++ b/pyload/config/default.py @@ -12,96 +12,96 @@ def make_config(config):      _ = lambda x: x      config.addConfigSection("remote", _("Remote"), _("Description"), _("Long description"), -        [ -            ("activated", "bool", _("Activated"), _("Tooltip"), True), -            ("port", "int", _("Port"), _("Tooltip"), 7227), -            ("listenaddr", "ip", _("Adress"), _("Tooltip"), "0.0.0.0"), -        ]) +                            [ +                                ("activated", "bool", _("Activated"), True), +                                ("port", "int", _("Port"), 7227), +                                ("listenaddr", "ip", _("Adress"), "0.0.0.0"), +                            ])      config.addConfigSection("log", _("Log"), _("Description"), _("Long description"), -        [ -            ("log_size", "int", _("Size in kb"), _("Tooltip"), 100), -            ("log_folder", "folder", _("Folder"), _("Tooltip"), "Logs"), -            ("file_log", "bool", _("File Log"), _("Tooltip"), True), -            ("log_count", "int", _("Count"), _("Tooltip"), 5), -            ("log_rotate", "bool", _("Log Rotate"), _("Tooltip"), True), -        ]) +                            [ +                                ("log_size", "int", _("Size in kb"), 100), +                                ("log_folder", "folder", _("Folder"), "Logs"), +                                ("file_log", "bool", _("File Log"), True), +                                ("log_count", "int", _("Count"), 5), +                                ("log_rotate", "bool", _("Log Rotate"), True), +                            ])      config.addConfigSection("permission", _("Permissions"), _("Description"), _("Long description"), -        [ -            ("group", "str", _("Groupname"), _("Tooltip"), "users"), -            ("change_dl", "bool", _("Change Group and User of Downloads"), _("Tooltip"), False), -            ("change_file", "bool", _("Change file mode of downloads"), _("Tooltip"), False), -            ("user", "str", _("Username"), _("Tooltip"), "user"), -            ("file", "str", _("Filemode for Downloads"), _("Tooltip"), "0644"), -            ("change_group", "bool", _("Change group of running process"), _("Tooltip"), False), -            ("folder", "str", _("Folder Permission mode"), _("Tooltip"), "0755"), -            ("change_user", "bool", _("Change user of running process"), _("Tooltip"), False), -        ]) +                            [ +                                ("group", "str", _("Groupname"), "users"), +                                ("change_dl", "bool", _("Change Group and User of Downloads"), False), +                                ("change_file", "bool", _("Change file mode of downloads"), False), +                                ("user", "str", _("Username"), "user"), +                                ("file", "str", _("Filemode for Downloads"), "0644"), +                                ("change_group", "bool", _("Change group of running process"), False), +                                ("folder", "str", _("Folder Permission mode"), "0755"), +                                ("change_user", "bool", _("Change user of running process"), False), +                            ])      config.addConfigSection("general", _("General"), _("Description"), _("Long description"), -        [ -            ("language", "en;de;fr;it;es;nl;sv;ru;pl;cs;sr;pt_BR", _("Language"), _("Tooltip"), "en"), -            ("download_folder", "folder", _("Download Folder"), _("Tooltip"), "Downloads"), -            ("checksum", "bool", _("Use Checksum"), _("Tooltip"), False), -            ("folder_per_package", "bool", _("Create folder for each package"), _("Tooltip"), True), -            ("debug_mode", "bool", _("Debug Mode"), _("Tooltip"), False), -            ("min_free_space", "int", _("Min Free Space (MB)"), _("Tooltip"), 200), -            ("renice", "int", _("CPU Priority"), _("Tooltip"), 0), -        ]) +                            [ +                                ("language", "en;de;fr;it;es;nl;sv;ru;pl;cs;sr;pt_BR", _("Language"), "en"), +                                ("download_folder", "folder", _("Download Folder"), "Downloads"), +                                ("checksum", "bool", _("Use Checksum"), False), +                                ("folder_per_package", "bool", _("Create folder for each package"), True), +                                ("debug_mode", "bool", _("Debug Mode"), False), +                                ("min_free_space", "int", _("Min Free Space (MB)"), 200), +                                ("renice", "int", _("CPU Priority"), 0), +                            ])      config.addConfigSection("ssl", _("SSL"), _("Description"), _("Long description"), -        [ -            ("cert", "file", _("SSL Certificate"), _("Tooltip"), "ssl.crt"), -            ("activated", "bool", _("Activated"), _("Tooltip"), False), -            ("key", "file", _("SSL Key"), _("Tooltip"), "ssl.key"), -        ]) +                            [ +                                ("cert", "file", _("SSL Certificate"), "ssl.crt"), +                                ("activated", "bool", _("Activated"), False), +                                ("key", "file", _("SSL Key"), "ssl.key"), +                            ])      config.addConfigSection("webinterface", _("Webinterface"), _("Description"), _("Long description"), -        [ -            ("template", "str", _("Template"), _("Tooltip"), "default"), -            ("activated", "bool", _("Activated"), _("Tooltip"), True), -            ("prefix", "str", _("Path Prefix"), _("Tooltip"), ""), -            ("server", "auto;threaded;fallback;fastcgi", _("Server"), _("Tooltip"), "auto"), -            ("force_server", "str", _("Favor specific server"), _("Tooltip"), ""), -            ("host", "ip", _("IP"), _("Tooltip"), "0.0.0.0"), -            ("https", "bool", _("Use HTTPS"), _("Tooltip"), False), -            ("port", "int", _("Port"), _("Tooltip"), 8001), -            ("develop", "str", _("Development mode"), _("Tooltip"), False), -        ]) +                            [ +                                ("template", "str", _("Template"), "default"), +                                ("activated", "bool", _("Activated"), True), +                                ("prefix", "str", _("Path Prefix"), ""), +                                ("server", "auto;threaded;fallback;fastcgi", _("Server"), "auto"), +                                ("force_server", "str", _("Favor specific server"), ""), +                                ("host", "ip", _("IP"), "0.0.0.0"), +                                ("https", "bool", _("Use HTTPS"), False), +                                ("port", "int", _("Port"), 8001), +                                ("develop", "str", _("Development mode"), False), +                            ])      config.addConfigSection("proxy", _("Proxy"), _("Description"), _("Long description"), -        [ -            ("username", "str", _("Username"), _("Tooltip"), ""), -            ("proxy", "bool", _("Use Proxy"), _("Tooltip"), False), -            ("address", "str", _("Address"), _("Tooltip"), "localhost"), -            ("password", "password", _("Password"), _("Tooltip"), ""), -            ("type", "http;socks4;socks5", _("Protocol"), _("Tooltip"), "http"), -            ("port", "int", _("Port"), _("Tooltip"), 7070), -        ]) +                            [ +                                ("username", "str", _("Username"), ""), +                                ("proxy", "bool", _("Use Proxy"), False), +                                ("address", "str", _("Address"), "localhost"), +                                ("password", "password", _("Password"), ""), +                                ("type", "http;socks4;socks5", _("Protocol"), "http"), +                                ("port", "int", _("Port"), 7070), +                            ])      config.addConfigSection("reconnect", _("Reconnect"), _("Description"), _("Long description"), -        [ -            ("endTime", "time", _("End"), _("Tooltip"), "0:00"), -            ("activated", "bool", _("Use Reconnect"), _("Tooltip"), False), -            ("method", "str", _("Method"), _("Tooltip"), "./reconnect.sh"), -            ("startTime", "time", _("Start"), _("Tooltip"), "0:00"), -        ]) +                            [ +                                ("endTime", "time", _("End"), "0:00"), +                                ("activated", "bool", _("Use Reconnect"), False), +                                ("method", "str", _("Method"), "./reconnect.sh"), +                                ("startTime", "time", _("Start"), "0:00"), +                            ])      config.addConfigSection("download", _("Download"), _("Description"), _("Long description"), -        [ -            ("max_downloads", "int", _("Max Parallel Downloads"), _("Tooltip"), 3), -            ("limit_speed", "bool", _("Limit Download Speed"), _("Tooltip"), False), -            ("interface", "str", _("Download interface to bind (ip or Name)"), _("Tooltip"), ""), -            ("skip_existing", "bool", _("Skip already existing files"), _("Tooltip"), False), -            ("max_speed", "int", _("Max Download Speed in kb/s"), _("Tooltip"), -1), -            ("ipv6", "bool", _("Allow IPv6"), _("Tooltip"), False), -            ("chunks", "int", _("Max connections for one download"), _("Tooltip"), 3), -            ("restart_failed", "bool", _("Restart failed downloads on startup"), _("Tooltip"), False), -        ]) +                            [ +                                ("max_downloads", "int", _("Max Parallel Downloads"), 3), +                                ("limit_speed", "bool", _("Limit Download Speed"), False), +                                ("interface", "str", _("Download interface to bind (ip or Name)"), ""), +                                ("skip_existing", "bool", _("Skip already existing files"), False), +                                ("max_speed", "int", _("Max Download Speed in kb/s"), -1), +                                ("ipv6", "bool", _("Allow IPv6"), False), +                                ("chunks", "int", _("Max connections for one download"), 3), +                                ("restart_failed", "bool", _("Restart failed downloads on startup"), False), +                            ])      config.addConfigSection("downloadTime", _("Download Time"), _("Description"), _("Long description"), -        [ -            ("start", "time", _("Start"), _("Tooltip"), "0:00"), -            ("end", "time", _("End"), _("Tooltip"), "0:00"), -        ]) +                            [ +                                ("start", "time", _("Start"), "0:00"), +                                ("end", "time", _("End"), "0:00"), +                            ]) diff --git a/pyload/interaction/InteractionManager.py b/pyload/interaction/InteractionManager.py index 9c5449b31..36d457323 100644 --- a/pyload/interaction/InteractionManager.py +++ b/pyload/interaction/InteractionManager.py @@ -71,21 +71,21 @@ class InteractionManager:          :param plugin: plugin name          :return: :class:`InteractionTask`          """ -        task = InteractionTask(self.ids, IA.Notification, Input(InputType.Text, content), "", title, desc, plugin, +        task = InteractionTask(self.ids, IA.Notification, Input(InputType.Text, None, content), title, desc, plugin,                                 owner=owner)          self.ids += 1          self.queueTask(task)          return task      @lock -    def createQueryTask(self, input, desc, default="", plugin="", owner=None): +    def createQueryTask(self, input, desc, plugin="", owner=None):          # input type was given, create a input widget          if type(input) == int:              input = Input(input)          if not isinstance(input, Input):              raise TypeError("'Input' class expected not '%s'" % type(input)) -        task = InteractionTask(self.ids, IA.Query, input, default, _("Query"), desc, plugin, owner=owner) +        task = InteractionTask(self.ids, IA.Query, input, _("Query"), desc, plugin, owner=owner)          self.ids += 1          self.queueTask(task)          return task @@ -104,11 +104,11 @@ class InteractionManager:          elif type == 'positional':              type = InputType.Click -        input = Input(type, [standard_b64encode(img), format, filename]) +        input = Input(type, data=[standard_b64encode(img), format, filename])          #todo: title desc plugin          task = InteractionTask(self.ids, IA.Captcha, input, -                               None, _("Captcha request"), _("Please solve the captcha."), plugin, owner=owner) +                            _("Captcha request"), _("Please solve the captcha."), plugin, owner=owner)          self.ids += 1          self.queueTask(task) diff --git a/pyload/plugins/Account.py b/pyload/plugins/Account.py index 2a85e2b44..0bf201c1a 100644 --- a/pyload/plugins/Account.py +++ b/pyload/plugins/Account.py @@ -4,7 +4,7 @@ from time import time  from traceback import print_exc  from threading import RLock -from pyload.utils import compare_time, format_size, parseFileSize, lock, from_string +from pyload.utils import compare_time, format_size, parseFileSize, lock, to_bool  from pyload.Api import AccountInfo  from pyload.network.CookieJar import CookieJar @@ -50,7 +50,7 @@ class Account(Base):          Base.__init__(self, manager.core)          if "activated" in options: -            self.activated = from_string(options["activated"], "bool") +            self.activated = to_bool(options["activated"])          else:              self.activated = Account.activated @@ -141,7 +141,7 @@ class Account(Base):          self.valid = True #set valid, so the login will be retried          if "activated" in options: -            self.activated = from_string(options["avtivated"], "bool") +            self.activated = True if options["activated"] == "True" else False          if password:              self.password = password diff --git a/pyload/plugins/Base.py b/pyload/plugins/Base.py index 47369e21f..308a38726 100644 --- a/pyload/plugins/Base.py +++ b/pyload/plugins/Base.py @@ -50,12 +50,12 @@ class Base(object):      #: When True this addon can be enabled by every user      __user_context__ = False      #: Config definition: list of  (name, type, label, default_value) or -    #: (name, type, label, short_description, default_value) -    __config__ = list() +    #: (name, label, desc, Input(...)) +    __config__ = tuple()      #: Short description, one liner -    __label__ = "" +    __description__ = ""      #: More detailed text -    __description__ = """""" +    __explanation__ = """"""      #: List of needed modules      __dependencies__ = tuple()      #: Used to assign a category for addon plugins @@ -66,6 +66,8 @@ class Base(object):      __icon__ = ""      #: Alternative, link to png icon      __icon_url__ = "" +    #: Domain name of the service +    __domain__ = ""      #: Url with general information/support/discussion      __url__ = ""      #: Url to term of content, user is accepting these when using the plugin @@ -106,6 +108,10 @@ class Base(object):          #: last interaction task          self.task = None +    def __getitem__(self, item): +        """ Retrieves meta data attribute """ +        return getattr(Base, "__%s__" % item) +      def logInfo(self, *args, **kwargs):          """ Print args to log at specific level diff --git a/pyload/plugins/hoster/BasePlugin.py b/pyload/plugins/hoster/BasePlugin.py index 7070fafde..552e7bc73 100644 --- a/pyload/plugins/hoster/BasePlugin.py +++ b/pyload/plugins/hoster/BasePlugin.py @@ -13,7 +13,7 @@ class BasePlugin(Hoster):      __type__ = "hoster"      __pattern__ = r"^unmatchable$"      __version__ = "0.17" -    __description__ = """Base Plugin when any other didnt fit""" +    __description__ = """Base Plugin when any other didn't match"""      __author_name__ = ("RaNaN")      __author_mail__ = ("RaNaN@pyload.org") @@ -31,7 +31,7 @@ class BasePlugin(Hoster):          #TODO: remove debug          if pyfile.url.lower().startswith("debug"): -            self.decryptCaptcha("http://download.pyload.org/pie.png", imgtype="png") +            self.decryptCaptcha("http://forum.pyload.org/lib/tpl/pyload/images/pyload-logo-edited3.5-new-font-small.png", imgtype="png")              self.download("http://download.pyload.org/random100.bin")              return  # diff --git a/pyload/remote/apitypes.py b/pyload/remote/apitypes.py index 196491083..d487599c3 100644 --- a/pyload/remote/apitypes.py +++ b/pyload/remote/apitypes.py @@ -51,12 +51,13 @@ class InputType:  	Folder = 4  	Textbox = 5  	Password = 6 -	Bool = 7 -	Click = 8 -	Select = 9 -	Multiple = 10 -	List = 11 -	Table = 12 +	Time = 7 +	Bool = 8 +	Click = 9 +	Select = 10 +	Multiple = 11 +	List = 12 +	Table = 13  class Interaction:  	All = 0 @@ -127,13 +128,13 @@ class AddonService(BaseObject):  		self.media = media  class ConfigHolder(BaseObject): -	__slots__ = ['name', 'label', 'description', 'long_description', 'items', 'info'] +	__slots__ = ['name', 'label', 'description', 'explanation', 'items', 'info'] -	def __init__(self, name=None, label=None, description=None, long_description=None, items=None, info=None): +	def __init__(self, name=None, label=None, description=None, explanation=None, items=None, info=None):  		self.name = name  		self.label = label  		self.description = description -		self.long_description = long_description +		self.explanation = explanation  		self.items = items  		self.info = info @@ -149,14 +150,13 @@ class ConfigInfo(BaseObject):  		self.activated = activated  class ConfigItem(BaseObject): -	__slots__ = ['name', 'label', 'description', 'input', 'default_value', 'value'] +	__slots__ = ['name', 'label', 'description', 'input', 'value'] -	def __init__(self, name=None, label=None, description=None, input=None, default_value=None, value=None): +	def __init__(self, name=None, label=None, description=None, input=None, value=None):  		self.name = name  		self.label = label  		self.description = description  		self.input = input -		self.default_value = default_value  		self.value = value  class DownloadInfo(BaseObject): @@ -211,20 +211,20 @@ class Forbidden(ExceptionObject):  	pass  class Input(BaseObject): -	__slots__ = ['type', 'data'] +	__slots__ = ['type', 'default_value', 'data'] -	def __init__(self, type=None, data=None): +	def __init__(self, type=None, default_value=None, data=None):  		self.type = type +		self.default_value = default_value  		self.data = data  class InteractionTask(BaseObject): -	__slots__ = ['iid', 'type', 'input', 'default_value', 'title', 'description', 'plugin'] +	__slots__ = ['iid', 'type', 'input', 'title', 'description', 'plugin'] -	def __init__(self, iid=None, type=None, input=None, default_value=None, title=None, description=None, plugin=None): +	def __init__(self, iid=None, type=None, input=None, title=None, description=None, plugin=None):  		self.iid = iid  		self.type = type  		self.input = input -		self.default_value = default_value  		self.title = title  		self.description = description  		self.plugin = plugin diff --git a/pyload/remote/apitypes_debug.py b/pyload/remote/apitypes_debug.py index 96673cc99..7c62a6277 100644 --- a/pyload/remote/apitypes_debug.py +++ b/pyload/remote/apitypes_debug.py @@ -23,17 +23,17 @@ classes = {  	'AddonService' : [basestring, basestring, (list, basestring), (None, int)],  	'ConfigHolder' : [basestring, basestring, basestring, basestring, (list, ConfigItem), (None, (list, AddonInfo))],  	'ConfigInfo' : [basestring, basestring, basestring, basestring, bool, (None, bool)], -	'ConfigItem' : [basestring, basestring, basestring, Input, basestring, basestring], +	'ConfigItem' : [basestring, basestring, basestring, Input, basestring],  	'DownloadInfo' : [basestring, basestring, basestring, int, basestring, basestring],  	'DownloadProgress' : [int, int, int, int],  	'EventInfo' : [basestring, (list, basestring)],  	'FileDoesNotExists' : [int],  	'FileInfo' : [int, basestring, int, int, int, int, int, int, int, (None, DownloadInfo)], -	'Input' : [int, (None, basestring)], -	'InteractionTask' : [int, int, Input, (None, basestring), basestring, basestring, basestring], +	'Input' : [int, (None, basestring), (None, basestring)], +	'InteractionTask' : [int, int, Input, basestring, basestring, basestring],  	'InvalidConfigSection' : [basestring],  	'LinkStatus' : [basestring, basestring, basestring, int, int, basestring], -	'OnlineCheck' : [int, (None, (dict, basestring, LinkStatus))], +	'OnlineCheck' : [int, (dict, basestring, LinkStatus)],  	'PackageDoesNotExists' : [int],  	'PackageInfo' : [int, basestring, basestring, int, int, basestring, basestring, basestring, int, (list, basestring), int, bool, int, PackageStats, (list, int), (list, int)],  	'PackageStats' : [int, int, int, int], diff --git a/pyload/remote/pyload.thrift b/pyload/remote/pyload.thrift index 57d7e0a0a..f218896ef 100644 --- a/pyload/remote/pyload.thrift +++ b/pyload/remote/pyload.thrift @@ -77,6 +77,7 @@ enum InputType {    Folder,    Textbox,    Password, +  Time,    Bool,   // confirm like, yes or no dialog    Click,  // for positional captchas    Select,  // select from list @@ -113,7 +114,8 @@ enum Role {  struct Input {      1: InputType type, -    2: optional JSONString data, +    2: optional JSONString default_value, +    3: optional JSONString data,  }  struct DownloadProgress { @@ -215,10 +217,9 @@ struct InteractionTask {    1: InteractionID iid,    2: Interaction type,    3: Input input, -  4: optional JSONString default_value, -  5: string title, -  6: string description, -  7: PluginName plugin, +  4: string title, +  5: string description, +  6: PluginName plugin,  }  struct AddonService { @@ -239,15 +240,14 @@ struct ConfigItem {    2: string label,    3: string description,    4: Input input, -  5: JSONString default_value, -  6: JSONString value, +  5: JSONString value,  }  struct ConfigHolder {    1: string name, // for plugin this is the PluginName    2: string label,    3: string description, -  4: string long_description, +  4: string explanation,    5: list<ConfigItem> items,    6: optional list<AddonInfo> info,  } diff --git a/pyload/remote/wsbackend/AsyncHandler.py b/pyload/remote/wsbackend/AsyncHandler.py index f1c584b7d..b936de898 100644 --- a/pyload/remote/wsbackend/AsyncHandler.py +++ b/pyload/remote/wsbackend/AsyncHandler.py @@ -43,7 +43,7 @@ class AsyncHandler(AbstractHandler):      PATH = "/async"      COMMAND = "start" -    PROGRESS_INTERVAL = 2 +    PROGRESS_INTERVAL = 1.5      EVENT_PATTERN = re.compile(r"^(package|file|interaction)", re.I)      INTERACTION = Interaction.All diff --git a/pyload/utils/__init__.py b/pyload/utils/__init__.py index da7b81af7..c9c24ac40 100644 --- a/pyload/utils/__init__.py +++ b/pyload/utils/__init__.py @@ -42,13 +42,13 @@ def remove_chars(string, repl):  def get_console_encoding(enc): -    if os.name == "nt":  +    if os.name == "nt":          if enc == "cp65001": # aka UTF-8              print "WARNING: Windows codepage 65001 is not supported."              enc = "cp850"      else:          enc = "utf8" -     +      return enc  def compare_time(start, end): @@ -199,6 +199,10 @@ def accumulate(it, inv_map=None):  def to_string(value):      return str(value) if not isinstance(value, basestring) else value +def to_bool(value): +    if not isinstance(value, basestring): return value +    return True if value.lower() in ("1", "true", "on", "an", "yes") else False +  def to_int(string, default=0):      """ return int from string or default """      try: @@ -206,26 +210,6 @@ def to_int(string, default=0):      except ValueError:          return default -def from_string(value, typ=None): -    """ cast value to given type, unicode for strings """ - -    # value is no string -    if not isinstance(value, basestring): -        return value - -    value = decode(value) - -    if typ == "int": -        return int(value) -    elif typ == "bool": -        return True if value.lower() in ("1", "true", "on", "an", "yes") else False -    elif typ == "time": -        if not value: value = "0:00" -        if not ":" in value: value += ":00" -        return value -    else: -        return value -  def get_index(l, value):      """ .index method that also works on tuple and python 2.5 """      for pos, t in enumerate(l): diff --git a/pyload/web/app/scripts/utils/apitypes.js b/pyload/web/app/scripts/utils/apitypes.js index cbbc9064f..d3b984923 100644 --- a/pyload/web/app/scripts/utils/apitypes.js +++ b/pyload/web/app/scripts/utils/apitypes.js @@ -6,7 +6,7 @@ define([], function() {  		DownloadState: {'Failed': 3, 'All': 0, 'Unmanaged': 4, 'Finished': 1, 'Unfinished': 2},  		DownloadStatus: {'Downloading': 10, 'NA': 0, 'Processing': 14, 'Waiting': 9, 'Decrypting': 13, 'Paused': 4, 'Failed': 7, 'Finished': 5, 'Skipped': 6, 'Unknown': 16, 'Aborted': 12, 'Online': 2, 'TempOffline': 11, 'Offline': 1, 'Custom': 15, 'Starting': 8, 'Queued': 3},  		FileStatus: {'Remote': 2, 'Ok': 0, 'Missing': 1}, -		InputType: {'Multiple': 10, 'Int': 2, 'NA': 0, 'List': 11, 'Bool': 7, 'File': 3, 'Text': 1, 'Table': 12, 'Folder': 4, 'Password': 6, 'Click': 8, 'Select': 9, 'Textbox': 5}, +		InputType: {'Multiple': 11, 'Int': 2, 'NA': 0, 'Time': 7, 'List': 12, 'Bool': 8, 'File': 3, 'Text': 1, 'Table': 13, 'Folder': 4, 'Password': 6, 'Click': 9, 'Select': 10, 'Textbox': 5},  		Interaction: {'Captcha': 2, 'All': 0, 'Query': 4, 'Notification': 1},  		MediaType: {'All': 0, 'Audio': 2, 'Image': 4, 'Other': 1, 'Video': 8, 'Document': 16, 'Archive': 32},  		PackageStatus: {'Paused': 1, 'Remote': 3, 'Folder': 2, 'Ok': 0}, diff --git a/pyload/web/app/scripts/views/input/inputLoader.js b/pyload/web/app/scripts/views/input/inputLoader.js index 11665abb4..04d591d30 100644 --- a/pyload/web/app/scripts/views/input/inputLoader.js +++ b/pyload/web/app/scripts/views/input/inputLoader.js @@ -2,7 +2,7 @@ define(['./textInput'], function(textInput) {      'use strict';      // selects appropriate input element -    return function(input, value, default_value, description) { +    return function(input) {          return textInput;      };  });
\ No newline at end of file diff --git a/pyload/web/app/scripts/views/input/inputView.js b/pyload/web/app/scripts/views/input/inputView.js index 1fbe5042d..1860fcaf1 100644 --- a/pyload/web/app/scripts/views/input/inputView.js +++ b/pyload/web/app/scripts/views/input/inputView.js @@ -8,16 +8,16 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) {          input: null,          value: null, -        default_value: null,          description: null, +        default_value: null,          // enables tooltips          tooltip: true,          initialize: function(options) {              this.input = options.input; +            this.default_value = this.input.default_value;              this.value = options.value; -            this.default_value = options.default_value;              this.description = options.description;          }, diff --git a/pyload/web/app/scripts/views/queryModal.js b/pyload/web/app/scripts/views/queryModal.js index c748e1657..ce624814a 100644 --- a/pyload/web/app/scripts/views/queryModal.js +++ b/pyload/web/app/scripts/views/queryModal.js @@ -39,7 +39,7 @@ define(['jquery', 'underscore', 'app', 'views/abstract/modalView', './input/inpu                  // instantiate the input                  var input = this.model.get('input');                  var InputView = load_input(input); -                this.input = new InputView(input); +                this.input = new InputView({input: input});                  // only renders after wards                  this.$('#inputField').append(this.input.render().el);              }, | 
