diff options
Diffstat (limited to 'module/plugins')
130 files changed, 464 insertions, 17 deletions
| diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py index 4b8063002..b039b5827 100644 --- a/module/plugins/AccountManager.py +++ b/module/plugins/AccountManager.py @@ -14,6 +14,7 @@ ACC_VERSION = 1  class AccountManager():      """manages all accounts""" +      #----------------------------------------------------------------------      def __init__(self, core):          """Constructor""" @@ -24,6 +25,7 @@ class AccountManager():          self.initPlugins()          self.saveAccounts() # save to add categories to conf +      def initPlugins(self):          self.accounts = {} # key = ( plugin )          self.plugins = {} @@ -31,6 +33,7 @@ class AccountManager():          self.initAccountPlugins()          self.loadAccounts() +      def getAccountPlugin(self, plugin):          """get account instance for plugin or None if anonymous"""          if plugin in self.accounts: @@ -41,6 +44,7 @@ class AccountManager():          else:              return None +      def getAccountPlugins(self):          """ get all account instances""" @@ -50,6 +54,7 @@ class AccountManager():          return plugins +      #----------------------------------------------------------------------      def loadAccounts(self):          """loads all accounts available""" @@ -97,6 +102,7 @@ class AccountManager():                  name, sep, pw = line.partition(":")                  self.accounts[plugin][name] = {"password": pw, "options": {}, "valid": True} +      #----------------------------------------------------------------------      def saveAccounts(self):          """save all account information""" @@ -117,12 +123,14 @@ class AccountManager():          f.close()          chmod(f.name, 0600) +      #----------------------------------------------------------------------      def initAccountPlugins(self):          """init names"""          for name in self.core.pluginManager.getAccountPlugins():              self.accounts[name] = {} +      @lock      def updateAccount(self, plugin , user, password=None, options={}):          """add or update account""" @@ -134,6 +142,7 @@ class AccountManager():              self.saveAccounts()              if updated: p.scheduleRefresh(user, force=False) +      @lock      def removeAccount(self, plugin, user):          """remove account""" @@ -144,6 +153,7 @@ class AccountManager():              self.saveAccounts() +      @lock      def getAccountInfos(self, force=True, refresh=False):          data = {} @@ -162,6 +172,7 @@ class AccountManager():          self.core.pullManager.addEvent(e)          return data +      def sendChange(self):          e = AccountUpdateEvent()          self.core.pullManager.addEvent(e) diff --git a/module/plugins/Hook.py b/module/plugins/Hook.py index 1e4749cd5..4d43b70f7 100644 --- a/module/plugins/Hook.py +++ b/module/plugins/Hook.py @@ -81,10 +81,12 @@ class Hook(Base):          self.initPeriodical()          self.setup() +      def initPeriodical(self):          if self.interval >=1:              self.cb = self.core.scheduler.addJob(0, self._periodical, threaded=False) +      def _periodical(self):          try:              if self.isActivated(): self.periodical() @@ -99,14 +101,17 @@ class Hook(Base):      def __repr__(self):          return "<Hook %s>" % self.__name__ +      def setup(self):          """ more init stuff if needed """          pass +      def unload(self):          """ called when hook was deactivated """          pass +      def isActivated(self):          """ checks if hook is activated"""          return self.config.getPlugin(self.__name__, "activated") @@ -116,36 +121,47 @@ class Hook(Base):      def coreReady(self):          pass +      def coreExiting(self):          pass +      def downloadPreparing(self, pyfile):          pass +      def downloadFinished(self, pyfile):          pass +      def downloadFailed(self, pyfile):          pass +      def packageFinished(self, pypack):          pass +      def beforeReconnecting(self, ip):          pass +      def afterReconnecting(self, ip):          pass +      def periodical(self):          pass +      def newCaptchaTask(self, task):          """ new captcha task for the plugin, it MUST set the handler and timeout or will be ignored """          pass +      def captchaCorrect(self, task):          pass +      def captchaInvalid(self, task):          pass diff --git a/module/plugins/Plugin.py b/module/plugins/Plugin.py index 0a4b6d44d..be26a8960 100644 --- a/module/plugins/Plugin.py +++ b/module/plugins/Plugin.py @@ -51,6 +51,7 @@ class Base(object):      A Base class with log/config/db methods *all* plugin types can use      """ +      def __init__(self, core):          #: Core instance          self.core = core @@ -59,19 +60,24 @@ class Base(object):          #: core config          self.config = core.config +      #log functions      def logDebug(self, *args):          self.log.debug("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args if a]))) +      def logInfo(self, *args):          self.log.info("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args if a]))) +      def logWarning(self, *args):          self.log.warning("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args if a]))) +      def logError(self, *args):          self.log.error("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args if a]))) +      def logCritical(self, *args):          self.log.critical("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args if a]))) @@ -80,6 +86,7 @@ class Base(object):          """ see `setConfig` """          self.core.config.setPlugin(self.__name__, option, value) +      def setConfig(self, option, value):          """ Set config value for current plugin @@ -89,10 +96,12 @@ class Base(object):          """          self.setConf(option, value) +      def getConf(self, option):          """ see `getConfig` """          return self.core.config.getPlugin(self.__name__, option) +      def getConfig(self, option):          """ Returns config value for current plugin @@ -101,24 +110,29 @@ class Base(object):          """          return self.getConf(option) +      def setStorage(self, key, value):          """ Saves a value persistently to the database """          self.core.db.setStorage(self.__name__, key, value) +      def store(self, key, value):          """ same as `setStorage` """          self.core.db.setStorage(self.__name__, key, value) +      def getStorage(self, key=None, default=None):          """ Retrieves saved value or dict of all saved entries if key is None """          if key is not None:              return self.core.db.getStorage(self.__name__, key) or default          return self.core.db.getStorage(self.__name__, key) +      def retrieve(self, *args, **kwargs):          """ same as `getStorage` """          return self.getStorage(*args, **kwargs) +      def delStorage(self, key):          """ Delete entry in db """          self.core.db.delStorage(self.__name__, key) @@ -198,22 +212,27 @@ class Plugin(Base):          self.init() +      def getChunkCount(self):          if self.chunkLimit <= 0:              return self.config['download']['chunks']          return min(self.config['download']['chunks'], self.chunkLimit) +      def __call__(self):          return self.__name__ +      def init(self):          """initialize the plugin (in addition to `__init__`)"""          pass +      def setup(self):          """ setup for enviroment and other things, called before downloading (possibly more than one time)"""          pass +      def preprocessing(self, thread):          """ handles important things to do before starting """          self.thread = thread @@ -234,12 +253,14 @@ class Plugin(Base):          """the 'main' method of every plugin, you **have to** overwrite it"""          raise NotImplementedError +      def resetAccount(self):          """ dont use account and retry download """          self.account = None          self.req = self.core.requestFactory.getRequest(self.__name__)          self.retry() +      def checksum(self, local_file=None):          """          return codes: @@ -264,6 +285,7 @@ class Plugin(Base):              self.wantReconnect = True          self.pyfile.waitUntil = time() + int(seconds) +      def wait(self):          """ waits the time previously set """          self.waiting = True @@ -281,23 +303,28 @@ class Plugin(Base):          self.waiting = False          self.pyfile.setStatus("starting") +      def fail(self, reason):          """ fail and give reason """          raise Fail(reason) +      def error(self, reason=None, type="parse"):          raise Fail("%s error%s | Plugin out of date" % (type.capitalize(), ': ' + str(reason) if reason else ""))          if self.core.debug:              print_exc() +      def offline(self):          """ fail and indicate file is offline """          raise Fail("offline") +      def tempOffline(self):          """ fail and indicates file ist temporary offline, the core may take consequences """          raise Fail("temp. offline") +      def retry(self, max_tries=3, wait_time=1, reason=""):          """Retries and begin again from the beginning @@ -316,14 +343,17 @@ class Plugin(Base):          self.retries += 1          raise Retry(reason) +      def invalidCaptcha(self):          if self.cTask:              self.cTask.invalid() +      def correctCaptcha(self):          if self.cTask:              self.cTask.correct() +      def decryptCaptcha(self, url, get={}, post={}, cookies=False, forceUser=False, imgtype='jpg',                         result_type='textual'):          """ Loads a captcha and decrypts it with ocr, plugin, user input @@ -455,6 +485,7 @@ class Plugin(Base):          return res +      def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=False):          """Downloads the content at url to download folder @@ -525,6 +556,7 @@ class Plugin(Base):          self.lastDownload = filename          return self.lastDownload +      def checkDownload(self, rules, api_size=0, max_size=50000, delete=True, read_size=0):          """ checks the content of the last downloaded file, re match is saved to `lastCheck` @@ -603,6 +635,7 @@ class Plugin(Base):              self.log.debug("File %s not skipped, because it does not exists." % self.pyfile.name) +      def clean(self):          """ clean everything and remove references """          if hasattr(self, "pyfile"): diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py index e263f8e04..034e40d4a 100644 --- a/module/plugins/PluginManager.py +++ b/module/plugins/PluginManager.py @@ -60,6 +60,7 @@ class PluginManager:          self.log.debug("created index of plugins") +      def parse(self, folder, pattern=False, home={}):          """          returns dict with information @@ -211,12 +212,14 @@ class PluginManager:          return res +      def findPlugin(self, name, pluginlist=("hoster", "crypter", "container")):          for ptype in pluginlist:              if name in self.plugins[ptype]:                  return self.plugins[ptype][name], ptype          return None, None +      def getPlugin(self, name, original=False):          """return plugin module from hoster|decrypter|container"""          plugin, type = self.findPlugin(name) @@ -230,6 +233,7 @@ class PluginManager:          return self.loadModule(type, name) +      def getPluginName(self, name):          """ used to obtain new name if other plugin was injected"""          plugin, type = self.findPlugin(name) @@ -239,6 +243,7 @@ class PluginManager:          return name +      def loadModule(self, type, name):          """ Returns loaded module for plugin @@ -258,15 +263,18 @@ class PluginManager:                  if self.core.debug:                      print_exc() +      def loadClass(self, type, name):          """Returns the class of a plugin with the same name"""          module = self.loadModule(type, name)          if module: return getattr(module, name) +      def getAccountPlugins(self):          """return list of account plugin names"""          return self.accountPlugins.keys() +      def find_module(self, fullname, path=None):          #redirecting imports if necesarry          if fullname.startswith(self.ROOT) or fullname.startswith(self.USERROOT): #seperate pyload plugins diff --git a/module/plugins/accounts/EuroshareEu.py b/module/plugins/accounts/EuroshareEu.py index bb2f0c8e2..e08cc7e45 100644 --- a/module/plugins/accounts/EuroshareEu.py +++ b/module/plugins/accounts/EuroshareEu.py @@ -31,7 +31,6 @@ class EuroshareEu(Account):      def login(self, user, data, req): -          html = req.load('http://euroshare.eu/customer-zone/login/', post={              "trvale": "1",              "login": user, diff --git a/module/plugins/accounts/FreeWayMe.py b/module/plugins/accounts/FreeWayMe.py index 12c24329c..797748c93 100644 --- a/module/plugins/accounts/FreeWayMe.py +++ b/module/plugins/accounts/FreeWayMe.py @@ -32,6 +32,7 @@ class FreeWayMe(Account):          return account_info +      def getpw(self, user):          return self.accounts[user]['password'] @@ -43,6 +44,7 @@ class FreeWayMe(Account):          if not status:              self.wrongPassword() +      def getAccountStatus(self, user, req):          answer = req.load("https://www.free-way.me/ajax/jd.php",                            get={"id": 4, "user": user, "pass": self.accounts[user]['password']}) diff --git a/module/plugins/accounts/FshareVn.py b/module/plugins/accounts/FshareVn.py index 45ee5a749..9e513d6f6 100644 --- a/module/plugins/accounts/FshareVn.py +++ b/module/plugins/accounts/FshareVn.py @@ -57,6 +57,7 @@ class FshareVn(Account):          if not re.search(r'<img\s+alt="VIP"', html):              self.wrongPassword() +      def getTrafficLeft(self):          m = re.search(self.TRAFFIC_LEFT_PATTERN, html)          return float(m.group(1)) * 1024 ** {'k': 0, 'K': 0, 'M': 1, 'G': 2}[m.group(2)] if m else 0 diff --git a/module/plugins/accounts/OneFichierCom.py b/module/plugins/accounts/OneFichierCom.py index 8e8430f61..71fa550b6 100644 --- a/module/plugins/accounts/OneFichierCom.py +++ b/module/plugins/accounts/OneFichierCom.py @@ -21,7 +21,6 @@ class OneFichierCom(Account):      def loadAccountInfo(self, user, req): -          html = req.load("http://1fichier.com/console/abo.pl")          m = re.search(self.VALID_UNTIL_PATTERN, html) @@ -38,7 +37,6 @@ class OneFichierCom(Account):      def login(self, user, data, req): -          req.http.c.setopt(REFERER, "http://1fichier.com/login.pl?lg=en")          html = req.load("http://1fichier.com/login.pl?lg=en", post={ diff --git a/module/plugins/accounts/PremiumizeMe.py b/module/plugins/accounts/PremiumizeMe.py index e65b9ec4b..4a789bfdf 100644 --- a/module/plugins/accounts/PremiumizeMe.py +++ b/module/plugins/accounts/PremiumizeMe.py @@ -38,6 +38,7 @@ class PremiumizeMe(Account):          if status['status'] != 200:              self.wrongPassword() +      def getAccountStatus(self, user, req):          # Use premiumize.me API v1 (see https://secure.premiumize.me/?show=api)          # to retrieve account info and return the parsed json answer diff --git a/module/plugins/accounts/RPNetBiz.py b/module/plugins/accounts/RPNetBiz.py index e4b873824..59349bd7a 100644 --- a/module/plugins/accounts/RPNetBiz.py +++ b/module/plugins/accounts/RPNetBiz.py @@ -40,6 +40,7 @@ class RPNetBiz(Account):          if 'error' in response:              self.wrongPassword() +      def getAccountStatus(self, user, req):          # Using the rpnet API, check if valid premium account          response = req.load("https://premium.rpnet.biz/client_api.php", diff --git a/module/plugins/accounts/ShareonlineBiz.py b/module/plugins/accounts/ShareonlineBiz.py index 76c564032..c00e4769d 100644 --- a/module/plugins/accounts/ShareonlineBiz.py +++ b/module/plugins/accounts/ShareonlineBiz.py @@ -18,6 +18,7 @@ class ShareonlineBiz(Account):          return req.load("http://api.share-online.biz/account.php",                          {"username": user, "password": self.accounts[user]['password'], "act": "userDetails"}) +      def loadAccountInfo(self, user, req):          src = self.getUserAPI(user, req) diff --git a/module/plugins/accounts/UploadedTo.py b/module/plugins/accounts/UploadedTo.py index 437730a3f..147962838 100644 --- a/module/plugins/accounts/UploadedTo.py +++ b/module/plugins/accounts/UploadedTo.py @@ -17,7 +17,6 @@ class UploadedTo(Account):      def loadAccountInfo(self, user, req): -          req.load("http://uploaded.net/language/en")          html = req.load("http://uploaded.net/me") @@ -44,7 +43,6 @@ class UploadedTo(Account):      def login(self, user, data, req): -          req.load("http://uploaded.net/language/en")          req.cj.setCookie("uploaded.net", "lang", "en") diff --git a/module/plugins/accounts/ZeveraCom.py b/module/plugins/accounts/ZeveraCom.py index 7e4fb0ab8..8ee8610ba 100644 --- a/module/plugins/accounts/ZeveraCom.py +++ b/module/plugins/accounts/ZeveraCom.py @@ -34,6 +34,7 @@ class ZeveraCom(Account):          if self.getAPIData(req) == "No traffic":              self.wrongPassword() +      def getAPIData(self, req, just_header=False, **kwargs):          get_data = {              'cmd': 'accountinfo', diff --git a/module/plugins/captcha/GigasizeCom.py b/module/plugins/captcha/GigasizeCom.py index 8fe67c0d0..d7fe25ab7 100644 --- a/module/plugins/captcha/GigasizeCom.py +++ b/module/plugins/captcha/GigasizeCom.py @@ -16,6 +16,7 @@ class GigasizeCom(OCR):      def __init__(self):          OCR.__init__(self) +      def get_captcha(self, image):          self.load_image(image)          self.threshold(2.8) diff --git a/module/plugins/captcha/LinksaveIn.py b/module/plugins/captcha/LinksaveIn.py index e8487c387..6535dd11f 100644 --- a/module/plugins/captcha/LinksaveIn.py +++ b/module/plugins/captcha/LinksaveIn.py @@ -26,6 +26,7 @@ class LinksaveIn(OCR):          OCR.__init__(self)          self.data_dir = dirname(abspath(__file__)) + sep + "LinksaveIn" + sep +      def load_image(self, image):          im = Image.open(image)          frame_nr = 0 @@ -53,6 +54,7 @@ class LinksaveIn(OCR):          self.pixels = self.image.load()          self.result_captcha = '' +      def get_bg(self):          stat = {}          cstat = {} @@ -89,6 +91,7 @@ class LinksaveIn(OCR):                  max_p = value          return bg +      def substract_bg(self, bgpath):          bg = Image.open(bgpath)          img = self.image.convert("P") @@ -111,6 +114,7 @@ class LinksaveIn(OCR):                  if rgb_c == rgb_bg:                      orgpix[x, y] = (255,255,255) +      def eval_black_white(self):          new = Image.new("RGB", (140, 75))          pix = new.load() @@ -132,6 +136,7 @@ class LinksaveIn(OCR):          self.image = new          self.pixels = self.image.load() +      def get_captcha(self, image):          self.load_image(image)          bg = self.get_bg() diff --git a/module/plugins/captcha/NetloadIn.py b/module/plugins/captcha/NetloadIn.py index 514cb259f..a8a05b210 100644 --- a/module/plugins/captcha/NetloadIn.py +++ b/module/plugins/captcha/NetloadIn.py @@ -16,6 +16,7 @@ class NetloadIn(OCR):      def __init__(self):          OCR.__init__(self) +      def get_captcha(self, image):          self.load_image(image)          self.to_greyscale() diff --git a/module/plugins/captcha/ShareonlineBiz.py b/module/plugins/captcha/ShareonlineBiz.py index 7435710d5..41caa3697 100644 --- a/module/plugins/captcha/ShareonlineBiz.py +++ b/module/plugins/captcha/ShareonlineBiz.py @@ -16,6 +16,7 @@ class ShareonlineBiz(OCR):      def __init__(self):          OCR.__init__(self) +      def get_captcha(self, image):          self.load_image(image)          self.to_greyscale() diff --git a/module/plugins/captcha/captcha.py b/module/plugins/captcha/captcha.py index fb85d8996..dda6fed02 100644 --- a/module/plugins/captcha/captcha.py +++ b/module/plugins/captcha/captcha.py @@ -28,18 +28,22 @@ class OCR(object):      def __init__(self):          self.logger = logging.getLogger("log") +      def load_image(self, image):          self.image = Image.open(image)          self.pixels = self.image.load()          self.result_captcha = '' +      def unload(self):          """delete all tmp images"""          pass +      def threshold(self, value):          self.image = self.image.point(lambda a: a * value + 10) +      def run(self, command):          """Run a command""" @@ -50,6 +54,7 @@ class OCR(object):          popen.stderr.close()          self.logger.debug("Tesseract ReturnCode %s Output: %s" % (popen.returncode, output)) +      def run_tesser(self, subset=False, digits=True, lowercase=True, uppercase=True):          #tmpTif = tempfile.NamedTemporaryFile(suffix=".tif")          tmpTif = open(join("tmp", "tmpTif_%s.tif" % self.__name__), "wb") @@ -103,15 +108,18 @@ class OCR(object):          except:              pass +      def get_captcha(self, name):          raise NotImplementedError +      def to_greyscale(self):          if self.image.mode != 'L':              self.image = self.image.convert('L')          self.pixels = self.image.load() +      def eval_black_white(self, limit):          self.pixels = self.image.load()          w, h = self.image.size @@ -122,6 +130,7 @@ class OCR(object):                  else:                      self.pixels[x, y] = 0 +      def clean(self, allowed):          pixels = self.pixels @@ -167,6 +176,7 @@ class OCR(object):          self.pixels = pixels +      def derotate_by_average(self):          """rotate by checking each angle and guess most suitable""" @@ -241,6 +251,7 @@ class OCR(object):          self.pixels = pixels +      def split_captcha_letters(self):          captcha = self.image          started = False @@ -280,6 +291,7 @@ class OCR(object):          return letters +      def correct(self, values, var=None):          if var:              result = var diff --git a/module/plugins/container/CCF.py b/module/plugins/container/CCF.py index 7a90ddf1c..4d62be553 100644 --- a/module/plugins/container/CCF.py +++ b/module/plugins/container/CCF.py @@ -24,7 +24,6 @@ class CCF(Container):      def decrypt(self, pyfile): -          infile = pyfile.url.replace("\n", "")          opener = build_opener(MultipartPostHandler) diff --git a/module/plugins/crypter/DDLMusicOrg.py b/module/plugins/crypter/DDLMusicOrg.py index a78794b6d..bd5560ed1 100644 --- a/module/plugins/crypter/DDLMusicOrg.py +++ b/module/plugins/crypter/DDLMusicOrg.py @@ -22,6 +22,7 @@ class DDLMusicOrg(Crypter):      def setup(self):          self.multiDL = False +      def decrypt(self, pyfile):          html = self.load(pyfile.url, cookies=True) diff --git a/module/plugins/crypter/DailymotionBatch.py b/module/plugins/crypter/DailymotionBatch.py index a0ed0e80f..5d2f53b38 100644 --- a/module/plugins/crypter/DailymotionBatch.py +++ b/module/plugins/crypter/DailymotionBatch.py @@ -26,6 +26,7 @@ class DailymotionBatch(Crypter):          page = self.load(url, get=req)          return json_loads(page) +      def getPlaylistInfo(self, id):          ref = "playlist/" + id          req = {"fields": "name,owner.screenname"} @@ -38,6 +39,7 @@ class DailymotionBatch(Crypter):          owner = playlist['owner.screenname']          return name, owner +      def _getPlaylists(self, user_id, page=1):          ref = "user/%s/playlists" % user_id          req = {"fields": "id", "page": page, "limit": 100} @@ -53,9 +55,11 @@ class DailymotionBatch(Crypter):              for item in self._getPlaylists(user_id, page + 1):                  yield item +      def getPlaylists(self, user_id):          return [(id,) + self.getPlaylistInfo(id) for id in self._getPlaylists(user_id)] +      def _getVideos(self, id, page=1):          ref = "playlist/%s/videos" % id          req = {"fields": "url", "page": page, "limit": 100} @@ -71,9 +75,11 @@ class DailymotionBatch(Crypter):              for item in self._getVideos(id, page + 1):                  yield item +      def getVideos(self, playlist_id):          return list(self._getVideos(playlist_id))[::-1] +      def decrypt(self, pyfile):          m = re.match(self.__pattern__, pyfile.url)          m_id = m.group("ID") diff --git a/module/plugins/crypter/DuckCryptInfo.py b/module/plugins/crypter/DuckCryptInfo.py index 29eeb4453..737ed59ec 100644 --- a/module/plugins/crypter/DuckCryptInfo.py +++ b/module/plugins/crypter/DuckCryptInfo.py @@ -33,6 +33,7 @@ class DuckCryptInfo(Crypter):          else:              self.handleFolder(m) +      def handleFolder(self, m):          src = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(m.group(2)))          m = re.match(self.__pattern__, src) @@ -47,6 +48,7 @@ class DuckCryptInfo(Crypter):              if clink.find("a"):                  self.handleLink(clink.find("a")['href']) +      def handleLink(self, url):          src = self.load(url)          soup = BeautifulSoup(src) diff --git a/module/plugins/crypter/EmbeduploadCom.py b/module/plugins/crypter/EmbeduploadCom.py index 71c4d5778..8e4f5da07 100644 --- a/module/plugins/crypter/EmbeduploadCom.py +++ b/module/plugins/crypter/EmbeduploadCom.py @@ -44,6 +44,7 @@ class EmbeduploadCom(Crypter):          if not self.urls:              self.fail('Could not extract any links') +      def getLocation(self, tmp_links):          new_links = []          for link in tmp_links: diff --git a/module/plugins/crypter/HoerbuchIn.py b/module/plugins/crypter/HoerbuchIn.py index 34e124d82..773e0bf8b 100644 --- a/module/plugins/crypter/HoerbuchIn.py +++ b/module/plugins/crypter/HoerbuchIn.py @@ -40,6 +40,7 @@ class HoerbuchIn(Crypter):          else:              self.urls = self.decryptFolder(pyfile.url) +      def decryptFolder(self, url):          m = self.protection.search(url)          if m is None: diff --git a/module/plugins/crypter/LinkdecrypterCom.py b/module/plugins/crypter/LinkdecrypterCom.py index c72092a5f..0358d1308 100644 --- a/module/plugins/crypter/LinkdecrypterCom.py +++ b/module/plugins/crypter/LinkdecrypterCom.py @@ -24,7 +24,6 @@ class LinkdecrypterCom(Crypter):      def decrypt(self, pyfile): -          self.passwords = self.getPassword().splitlines()          # API not working anymore @@ -32,8 +31,8 @@ class LinkdecrypterCom(Crypter):          if not self.urls:              self.fail('Could not extract any links') -    def decryptAPI(self): +    def decryptAPI(self):          get_dict = {"t": "link", "url": self.pyfile.url, "lcache": "1"}          self.html = self.load('http://linkdecrypter.com/api', get=get_dict)          if self.html.startswith('http://'): @@ -51,8 +50,8 @@ class LinkdecrypterCom(Crypter):          return None -    def decryptHTML(self): +    def decryptHTML(self):          retries = 5          post_dict = {"link_cache": "on", "pro_links": self.pyfile.url, "modo_links": "text"} diff --git a/module/plugins/crypter/NCryptIn.py b/module/plugins/crypter/NCryptIn.py index 28a0735a5..ef696dbd8 100644 --- a/module/plugins/crypter/NCryptIn.py +++ b/module/plugins/crypter/NCryptIn.py @@ -131,7 +131,6 @@ class NCryptIn(Crypter):      def unlockProtection(self): -          postData = {}          form = re.search(r'<form name="protected"(.*?)</form>', self.cleanedHtml, re.DOTALL).group(1) @@ -210,7 +209,6 @@ class NCryptIn(Crypter):      def handleSingleLink(self): -          self.logDebug("Handling Single link")          package_links = [] @@ -223,7 +221,6 @@ class NCryptIn(Crypter):      def handleCNL2(self): -          self.logDebug("Handling CNL2 links")          package_links = [] @@ -239,7 +236,6 @@ class NCryptIn(Crypter):      def handleContainers(self): -          self.logDebug("Handling Container links")          package_links = [] @@ -254,7 +250,6 @@ class NCryptIn(Crypter):      def handleWebLinks(self): -          self.logDebug("Handling Web links")          pattern = r'(http://ncrypt\.in/link-.*?=)'          links = re.findall(pattern, self.html) @@ -280,7 +275,6 @@ class NCryptIn(Crypter):      def _getCipherParams(self): -          pattern = r'<input.*?name="%s".*?value="(.*?)"'          # Get jk diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py index 027503bd2..03c62ba14 100644 --- a/module/plugins/crypter/NetfolderIn.py +++ b/module/plugins/crypter/NetfolderIn.py @@ -40,12 +40,14 @@ class NetfolderIn(SimpleCrypter):          # Set package          self.packages = [(package_name, package_links, folder_name)] +      def isPasswordProtected(self):          if '<input type="password" name="password"' in self.html:              self.logDebug("Links are password protected")              return True          return False +      def submitPassword(self):          # Gather data          try: @@ -69,6 +71,7 @@ class NetfolderIn(SimpleCrypter):          return html +      def getLinks(self):          links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",")          self.logDebug("Package has %d links" % len(links)) diff --git a/module/plugins/crypter/OneKhDe.py b/module/plugins/crypter/OneKhDe.py index 7a2aefe83..188a0a0ef 100644 --- a/module/plugins/crypter/OneKhDe.py +++ b/module/plugins/crypter/OneKhDe.py @@ -22,11 +22,13 @@ class OneKhDe(Crypter):          Crypter.__init__(self, parent)          self.parent = parent +      def file_exists(self):          """ returns True or False          """          return True +      def proceed(self, url, location):          url = self.parent.url          self.html = self.load(url) diff --git a/module/plugins/crypter/TurbobitNetFolder.py b/module/plugins/crypter/TurbobitNetFolder.py index 390520d88..1158c5cc1 100644 --- a/module/plugins/crypter/TurbobitNetFolder.py +++ b/module/plugins/crypter/TurbobitNetFolder.py @@ -35,6 +35,7 @@ class TurbobitNetFolder(SimpleCrypter):          else:              return +      def getLinks(self):          id = re.match(self.__pattern__, self.pyfile.url).group("ID")          fixurl = lambda id: "http://turbobit.net/%s.html" % id diff --git a/module/plugins/crypter/YoutubeBatch.py b/module/plugins/crypter/YoutubeBatch.py index e5fd83c4f..e70003ab1 100644 --- a/module/plugins/crypter/YoutubeBatch.py +++ b/module/plugins/crypter/YoutubeBatch.py @@ -33,6 +33,7 @@ class YoutubeBatch(Crypter):          page = self.load(url, get=req)          return json_loads(page) +      def getChannel(self, user):          channels = self.api_response("channels", {"part": "id,snippet,contentDetails", "forUsername": user, "maxResults": "50"})          if channels['items']: @@ -42,6 +43,7 @@ class YoutubeBatch(Crypter):                      "relatedPlaylists": channel['contentDetails']['relatedPlaylists'],                      "user": user}  # One lone channel for user? +      def getPlaylist(self, p_id):          playlists = self.api_response("playlists", {"part": "snippet", "id": p_id})          if playlists['items']: @@ -51,6 +53,7 @@ class YoutubeBatch(Crypter):                      "channelId": playlist['snippet']['channelId'],                      "channelTitle": playlist['snippet']['channelTitle']} +      def _getPlaylists(self, id, token=None):          req = {"part": "id", "maxResults": "50", "channelId": id}          if token: @@ -65,9 +68,11 @@ class YoutubeBatch(Crypter):              for item in self._getPlaylists(id, playlists['nextPageToken']):                  yield item +      def getPlaylists(self, ch_id):          return map(self.getPlaylist, self._getPlaylists(ch_id)) +      def _getVideosId(self, id, token=None):          req = {"part": "contentDetails", "maxResults": "50", "playlistId": id}          if token: @@ -82,9 +87,11 @@ class YoutubeBatch(Crypter):              for item in self._getVideosId(id, playlist['nextPageToken']):                  yield item +      def getVideosId(self, p_id):          return list(self._getVideosId(p_id)) +      def decrypt(self, pyfile):          m = re.match(self.__pattern__, pyfile.url)          m_id = m.group("ID") diff --git a/module/plugins/hooks/BypassCaptcha.py b/module/plugins/hooks/BypassCaptcha.py index 984aac919..a07b2fc66 100644 --- a/module/plugins/hooks/BypassCaptcha.py +++ b/module/plugins/hooks/BypassCaptcha.py @@ -13,12 +13,15 @@ class BypassCaptchaException(Exception):      def __init__(self, err):          self.err = err +      def getCode(self):          return self.err +      def __str__(self):          return "<BypassCaptchaException %s>" % self.err +      def __repr__(self):          return "<BypassCaptchaException %s>" % self.err @@ -49,12 +52,14 @@ class BypassCaptcha(Hook):      def setup(self):          self.info = {} +      def getCredits(self):          response = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")})          data = dict([x.split(' ', 1) for x in response.splitlines()])          return int(data['Left']) +      def submit(self, captcha, captchaType="file", match=None):          req = getRequest() @@ -81,6 +86,7 @@ class BypassCaptcha(Hook):          return ticket, result +      def respond(self, ticket, success):          try:              response = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig("passkey"), @@ -88,6 +94,7 @@ class BypassCaptcha(Hook):          except BadHeader, e:              self.logError(_("Could not send response."), e +      def newCaptchaTask(self, task):          if "service" in task.data:              return False @@ -110,14 +117,17 @@ class BypassCaptcha(Hook):          else:              self.logInfo(_("Your %s account has not enough credits") % self.__name__) +      def captchaCorrect(self, task):          if task.data['service'] == self.__name__ and "ticket" in task.data:              self.respond(task.data['ticket'], True) +      def captchaInvalid(self, task):          if task.data['service'] == self.__name__ and "ticket" in task.data:              self.respond(task.data['ticket'], False) +      def processCaptcha(self, task):          c = task.captchaFile          try: diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9kw.py index 6485db22b..947aff121 100755 --- a/module/plugins/hooks/Captcha9kw.py +++ b/module/plugins/hooks/Captcha9kw.py @@ -41,6 +41,7 @@ class Captcha9kw(Hook):          self.API_URL = "https" + self.API_URL if self.getConfig("https") else "http" + self.API_URL          self.info = {} +      def getCredits(self):          response = getURL(self.API_URL, get={"apikey": self.getConfig("passkey"), "pyload": "1", "source": "pyload",                                               "action": "usercaptchaguthaben"}) @@ -53,6 +54,7 @@ class Captcha9kw(Hook):              self.logError(response)              return 0 +      def processCaptcha(self, task):          result = None @@ -100,6 +102,7 @@ class Captcha9kw(Hook):              self.logError(_("Bad upload"), response)              return False +      def newCaptchaTask(self, task):          if not task.isTextual() and not task.isPositional():              return False @@ -118,6 +121,7 @@ class Captcha9kw(Hook):          else:              self.logError(_("Your Captcha 9kw.eu Account has not enough credits")) +      def captchaCorrect(self, task):          if "ticket" in task.data: @@ -137,6 +141,7 @@ class Captcha9kw(Hook):          else:              self.logError(_("No CaptchaID for correct request (task %s) found.") % task) +      def captchaInvalid(self, task):          if "ticket" in task.data: diff --git a/module/plugins/hooks/CaptchaBrotherhood.py b/module/plugins/hooks/CaptchaBrotherhood.py index 3157fead8..da8fcbafe 100644 --- a/module/plugins/hooks/CaptchaBrotherhood.py +++ b/module/plugins/hooks/CaptchaBrotherhood.py @@ -23,12 +23,15 @@ class CaptchaBrotherhoodException(Exception):      def __init__(self, err):          self.err = err +      def getCode(self):          return self.err +      def __str__(self):          return "<CaptchaBrotherhoodException %s>" % self.err +      def __repr__(self):          return "<CaptchaBrotherhoodException %s>" % self.err @@ -55,6 +58,7 @@ class CaptchaBrotherhood(Hook):      def setup(self):          self.info = {} +      def getCredits(self):          response = getURL(self.API_URL + "askCredits.aspx",                            get={"username": self.getConfig("username"), "password": self.getConfig("passkey")}) @@ -66,6 +70,7 @@ class CaptchaBrotherhood(Hook):              self.info['credits'] = credits              return credits +      def submit(self, captcha, captchaType="file", match=None):          try:              img = Image.open(captcha) @@ -116,6 +121,7 @@ class CaptchaBrotherhood(Hook):          raise CaptchaBrotherhoodException("No solution received in time") +      def get_api(self, api, ticket):          response = getURL("%s%s.aspx" % (self.API_URL, api),                            get={"username": self.getConfig("username"), @@ -126,6 +132,7 @@ class CaptchaBrotherhood(Hook):          return response +      def newCaptchaTask(self, task):          if "service" in task.data:              return False @@ -147,10 +154,12 @@ class CaptchaBrotherhood(Hook):          else:              self.logInfo(_("Your CaptchaBrotherhood Account has not enough credits")) +      def captchaInvalid(self, task):          if task.data['service'] == self.__name__ and "ticket" in task.data:              response = self.get_api("complainCaptcha", task.data['ticket']) +      def processCaptcha(self, task):          c = task.captchaFile          try: diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py index 32597beeb..4a7cfd661 100644 --- a/module/plugins/hooks/Checksum.py +++ b/module/plugins/hooks/Checksum.py @@ -67,12 +67,14 @@ class Checksum(Hook):          if not self.getConfig("check_checksum"):              self.logInfo(_("Checksum validation is disabled in plugin configuration")) +      def setup(self):          self.algorithms = sorted(              getattr(hashlib, "algorithms", ("md5", "sha1", "sha224", "sha256", "sha384", "sha512")), reverse=True)          self.algorithms.extend(["crc32", "adler32"])          self.formats = self.algorithms + ["sfv", "crc", "hash"] +      def downloadFinished(self, pyfile):          """          Compute checksum for the downloaded file and compare it with the hash provided by the hoster. @@ -130,6 +132,7 @@ class Checksum(Hook):              else:                  self.logWarning(_("Unable to validate checksum for file"), pyfile.name) +      def checkFailed(self, pyfile, local_file, msg):          check_action = self.getConfig("check_action")          if check_action == "retry": @@ -145,6 +148,7 @@ class Checksum(Hook):              return          pyfile.plugin.fail(reason=msg) +      def packageFinished(self, pypack):          download_folder = save_join(self.config['general']['download_folder'], pypack.folder, "") diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py index 2548506cb..99d7f7401 100644 --- a/module/plugins/hooks/DeathByCaptcha.py +++ b/module/plugins/hooks/DeathByCaptcha.py @@ -25,21 +25,26 @@ class DeathByCaptchaException(Exception):                    'invalid-request': 'Invalid request',                    'timed-out': 'No CAPTCHA solution received in time'} +      def __init__(self, err):          self.err = err +      def getCode(self):          return self.err +      def getDesc(self):          if self.err in self.DBC_ERRORS.keys():              return self.DBC_ERRORS[self.err]          else:              return self.err +      def __str__(self):          return "<DeathByCaptchaException %s>" % self.err +      def __repr__(self):          return "<DeathByCaptchaException %s>" % self.err @@ -66,6 +71,7 @@ class DeathByCaptcha(Hook):      def setup(self):          self.info = {} +      def call_api(self, api="captcha", post=False, multipart=False):          req = getRequest()          req.c.setopt(HTTPHEADER, ["Accept: application/json", "User-Agent: pyLoad %s" % self.core.version]) @@ -106,6 +112,7 @@ class DeathByCaptcha(Hook):          return response +      def getCredits(self):          response = self.call_api("user", True) @@ -116,12 +123,14 @@ class DeathByCaptcha(Hook):          else:              raise DeathByCaptchaException(response) +      def getStatus(self):          response = self.call_api("status", False)          if 'is_service_overloaded' in response and response['is_service_overloaded']:              raise DeathByCaptchaException('service-overload') +      def submit(self, captcha, captchaType="file", match=None):          #workaround multipart-post bug in HTTPRequest.py          if re.match("^\w*$", self.getConfig("passkey")): @@ -152,6 +161,7 @@ class DeathByCaptcha(Hook):          return ticket, result +      def newCaptchaTask(self, task):          if "service" in task.data:              return False @@ -183,6 +193,7 @@ class DeathByCaptcha(Hook):              task.setWaiting(180)              start_new_thread(self.processCaptcha, (task,)) +      def captchaInvalid(self, task):          if task.data['service'] == self.__name__ and "ticket" in task.data:              try: @@ -192,6 +203,7 @@ class DeathByCaptcha(Hook):              except Exception, e:                  self.logError(e) +      def processCaptcha(self, task):          c = task.captchaFile          try: diff --git a/module/plugins/hooks/DownloadScheduler.py b/module/plugins/hooks/DownloadScheduler.py index c7a0155dd..70930ab67 100644 --- a/module/plugins/hooks/DownloadScheduler.py +++ b/module/plugins/hooks/DownloadScheduler.py @@ -26,9 +26,11 @@ class DownloadScheduler(Hook):      def setup(self):          self.cb = None  # callback to scheduler job; will be by removed hookmanager when hook unloaded +      def coreReady(self):          self.updateSchedule() +      def updateSchedule(self, schedule=None):          if schedule is None:              schedule = self.getConfig("timetable") @@ -56,6 +58,7 @@ class DownloadScheduler(Hook):                  self.core.scheduler.removeJob(self.cb)                  self.cb = self.core.scheduler.addJob(next_time, self.updateSchedule, threaded=False) +      def setDownloadSpeed(self, speed):          if speed == 0:              abort = self.getConfig("abort") diff --git a/module/plugins/hooks/ExpertDecoders.py b/module/plugins/hooks/ExpertDecoders.py index 712b19677..e786cc35a 100644 --- a/module/plugins/hooks/ExpertDecoders.py +++ b/module/plugins/hooks/ExpertDecoders.py @@ -33,6 +33,7 @@ class ExpertDecoders(Hook):      def setup(self):          self.info = {} +      def getCredits(self):          response = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"}) @@ -44,6 +45,7 @@ class ExpertDecoders(Hook):              self.logError(response)              return 0 +      def processCaptcha(self, task):          task.data['ticket'] = ticket = uuid4()          result = None @@ -65,6 +67,7 @@ class ExpertDecoders(Hook):          self.logDebug("Result %s : %s" % (ticket, result))          task.setResult(result) +      def newCaptchaTask(self, task):          if not task.isTextual():              return False @@ -83,6 +86,7 @@ class ExpertDecoders(Hook):          else:              self.logInfo(_("Your ExpertDecoders Account has not enough credits")) +      def captchaInvalid(self, task):          if "ticket" in task.data: diff --git a/module/plugins/hooks/ExtractArchive.py b/module/plugins/hooks/ExtractArchive.py index f6958941e..649689f6e 100644 --- a/module/plugins/hooks/ExtractArchive.py +++ b/module/plugins/hooks/ExtractArchive.py @@ -14,6 +14,7 @@ if sys.version_info < (2, 7) and os.name != "nt":      import errno      from subprocess import Popen +      def _eintr_retry_call(func, *args):          while True:              try: @@ -23,6 +24,7 @@ if sys.version_info < (2, 7) and os.name != "nt":                      continue                  raise +      # unsued timeout option for older python version      def wait(self, timeout=0):          """Wait for child process to terminate.  Returns returncode diff --git a/module/plugins/hooks/HotFolder.py b/module/plugins/hooks/HotFolder.py index 34a9ff49b..688dcbf48 100644 --- a/module/plugins/hooks/HotFolder.py +++ b/module/plugins/hooks/HotFolder.py @@ -28,6 +28,7 @@ class HotFolder(Hook):      def setup(self):          self.interval = 10 +      def periodical(self):          if not exists(join(self.getConfig("folder"), "finished")):              makedirs(join(self.getConfig("folder"), "finished")) diff --git a/module/plugins/hooks/IRCInterface.py b/module/plugins/hooks/IRCInterface.py index d648db7cf..59977b8af 100644 --- a/module/plugins/hooks/IRCInterface.py +++ b/module/plugins/hooks/IRCInterface.py @@ -44,6 +44,7 @@ class IRCInterface(Thread, Hook):          #   self.sm = core.server_methods          self.api = core.api  # todo, only use api +      def coreReady(self):          self.abort = False          self.more = [] @@ -51,6 +52,7 @@ class IRCInterface(Thread, Hook):          self.start() +      def packageFinished(self, pypack):          try:              if self.getConfig("info_pack"): @@ -58,6 +60,7 @@ class IRCInterface(Thread, Hook):          except:              pass +      def downloadFinished(self, pyfile):          try:              if self.getConfig("info_file"): @@ -66,6 +69,7 @@ class IRCInterface(Thread, Hook):          except:              pass +      def newCaptchaTask(self, task):          if self.getConfig("captcha") and task.isTextual():              task.handler.append(self) @@ -78,6 +82,7 @@ class IRCInterface(Thread, Hook):              self.response(_("New Captcha Request: %s") % url)              self.response(_("Answer with 'c %s text on the captcha'") % task.id) +      def run(self):          # connect to IRC etc.          self.sock = socket.socket() @@ -99,6 +104,7 @@ class IRCInterface(Thread, Hook):              print_exc()              self.sock.close() +      def main_loop(self):          readbuffer = ""          while True: @@ -137,6 +143,7 @@ class IRCInterface(Thread, Hook):                  self.handle_events(msg) +      def handle_events(self, msg):          if not msg['origin'].split("!", 1)[0] in self.getConfig("owner").split():              return @@ -179,6 +186,7 @@ class IRCInterface(Thread, Hook):          except Exception, e:              self.logError(repr(e)) +      def response(self, msg, origin=""):          if origin == "":              for t in self.getConfig("owner").split(): @@ -186,11 +194,13 @@ class IRCInterface(Thread, Hook):          else:              self.sock.send("PRIVMSG %s :%s\r\n" % (origin.split("!", 1)[0], msg)) +          #### Events      def event_pass(self, args):          return [] +      def event_status(self, args):          downloads = self.api.statusDownloads()          if not downloads: @@ -216,6 +226,7 @@ class IRCInterface(Thread, Hook):                           ))          return lines +      def event_queue(self, args):          ps = self.api.getQueueData() @@ -228,6 +239,7 @@ class IRCInterface(Thread, Hook):          return lines +      def event_collector(self, args):          ps = self.api.getCollectorData()          if not ps: @@ -239,6 +251,7 @@ class IRCInterface(Thread, Hook):          return lines +      def event_info(self, args):          if not args:              return ["ERROR: Use info like this: info <id>"] @@ -252,6 +265,7 @@ class IRCInterface(Thread, Hook):          return ['LINK #%s: %s (%s) [%s][%s]' % (info.fid, info.name, info.format_size, info.statusmsg, info.plugin)] +      def event_packinfo(self, args):          if not args:              return ["ERROR: Use packinfo like this: packinfo <id>"] @@ -283,6 +297,7 @@ class IRCInterface(Thread, Hook):          return lines +      def event_more(self, args):          if not self.more:              return ["No more information to display."] @@ -293,14 +308,17 @@ class IRCInterface(Thread, Hook):          return lines +      def event_start(self, args):          self.api.unpauseServer()          return ["INFO: Starting downloads."] +      def event_stop(self, args):          self.api.pauseServer()          return ["INFO: No new downloads will be started."] +      def event_add(self, args):          if len(args) < 2:              return ['ERROR: Add links like this: "add <packagename|id> links". ', @@ -326,6 +344,7 @@ class IRCInterface(Thread, Hook):              id = self.api.addPackage(pack, links, 1)              return ["INFO: Created new Package %s [#%d] with %d links." % (pack, id, len(links))] +      def event_del(self, args):          if len(args) < 2:              return ["ERROR: Use del command like this: del -p|-l <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"] @@ -341,6 +360,7 @@ class IRCInterface(Thread, Hook):          else:              return ["ERROR: Use del command like this: del <-p|-l> <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"] +      def event_push(self, args):          if not args:              return ["ERROR: Push package to queue like this: push <package id>"] @@ -354,6 +374,7 @@ class IRCInterface(Thread, Hook):          self.api.pushToQueue(id)          return ["INFO: Pushed package #%d to queue." % id] +      def event_pull(self, args):          if not args:              return ["ERROR: Pull package from queue like this: pull <package id>."] @@ -365,6 +386,7 @@ class IRCInterface(Thread, Hook):          self.api.pullFromQueue(id)          return ["INFO: Pulled package #%d from queue to collector." % id] +      def event_c(self, args):          """ captcha answer """          if not args: @@ -377,6 +399,7 @@ class IRCInterface(Thread, Hook):          task.setResult(" ".join(args[1:]))          return ["INFO: Result %s saved." % " ".join(args[1:])] +      def event_help(self, args):          lines = ["The following commands are available:",                   "add <package|packid> <links> [...] Adds link to package. (creates new package if it does not exist)", @@ -400,5 +423,6 @@ class IRCError(Exception):      def __init__(self, value):          self.value = value +      def __str__(self):          return repr(self.value) diff --git a/module/plugins/hooks/ImageTyperz.py b/module/plugins/hooks/ImageTyperz.py index b7ee6b105..3eb0acd64 100644 --- a/module/plugins/hooks/ImageTyperz.py +++ b/module/plugins/hooks/ImageTyperz.py @@ -17,12 +17,15 @@ class ImageTyperzException(Exception):      def __init__(self, err):          self.err = err +      def getCode(self):          return self.err +      def __str__(self):          return "<ImageTyperzException %s>" % self.err +      def __repr__(self):          return "<ImageTyperzException %s>" % self.err @@ -51,6 +54,7 @@ class ImageTyperz(Hook):      def setup(self):          self.info = {} +      def getCredits(self):          response = getURL(self.GETCREDITS_URL, post={"action": "REQUESTBALANCE", "username": self.getConfig("username"),                                                       "password": self.getConfig("passkey")}) @@ -66,6 +70,7 @@ class ImageTyperz(Hook):          self.logInfo(_("Account balance: $%s left") % response)          return balance +      def submit(self, captcha, captchaType="file", match=None):          req = getRequest()          #raise timeout threshold @@ -100,6 +105,7 @@ class ImageTyperz(Hook):          return ticket, result +      def newCaptchaTask(self, task):          if "service" in task.data:              return False @@ -122,6 +128,7 @@ class ImageTyperz(Hook):          else:              self.logInfo(_("Your %s account has not enough credits") % self.__name__) +      def captchaInvalid(self, task):          if task.data['service'] == self.__name__ and "ticket" in task.data:              response = getURL(self.RESPOND_URL, post={"action": "SETBADIMAGE", "username": self.getConfig("username"), @@ -133,6 +140,7 @@ class ImageTyperz(Hook):              else:                  self.logError(_("Bad captcha solution received, refund request failed"), response) +      def processCaptcha(self, task):          c = task.captchaFile          try: diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py index de08e406a..463a5af96 100644 --- a/module/plugins/hooks/LinkdecrypterCom.py +++ b/module/plugins/hooks/LinkdecrypterCom.py @@ -25,6 +25,7 @@ class LinkdecrypterCom(Hook):          except Exception, e:              self.logError(e) +      def loadPatterns(self):          page = getURL("http://linkdecrypter.com/")          m = re.search(r'<b>Supported\(\d+\)</b>: <i>([^+<]*)', page) diff --git a/module/plugins/hooks/MergeFiles.py b/module/plugins/hooks/MergeFiles.py index 5a23ff862..0eab0037c 100644 --- a/module/plugins/hooks/MergeFiles.py +++ b/module/plugins/hooks/MergeFiles.py @@ -27,6 +27,7 @@ class MergeFiles(Hook):          # nothing to do          pass +      @threaded      def packageFinished(self, pack):          files = {} diff --git a/module/plugins/hooks/MultiHome.py b/module/plugins/hooks/MultiHome.py index 5cda53bd7..378c493e9 100644 --- a/module/plugins/hooks/MultiHome.py +++ b/module/plugins/hooks/MultiHome.py @@ -26,19 +26,23 @@ class MultiHome(Hook):              self.parseInterfaces([self.config['download']['interface']])              self.setConfig("interfaces", self.toConfig()) +      def toConfig(self):          return ";".join([i.adress for i in self.interfaces]) +      def parseInterfaces(self, interfaces):          for interface in interfaces:              if not interface or str(interface).lower() == "none":                  continue              self.interfaces.append(Interface(interface)) +      def coreReady(self):          requestFactory = self.core.requestFactory          oldGetRequest = requestFactory.getRequest +          def getRequest(pluginName, account=None):              iface = self.bestInterface(pluginName, account)              if iface: @@ -49,6 +53,7 @@ class MultiHome(Hook):          requestFactory.getRequest = getRequest +      def bestInterface(self, pluginName, account):          best = None          for interface in self.interfaces: @@ -63,13 +68,16 @@ class Interface(object):          self.adress = adress          self.history = {} +      def lastPluginAccess(self, pluginName, account):          if (pluginName, account) in self.history:              return self.history[(pluginName, account)]          return 0 +      def useFor(self, pluginName, account):          self.history[(pluginName, account)] = time() +      def __repr__(self):          return "<Interface - %s>" % self.adress diff --git a/module/plugins/hooks/PremiumTo.py b/module/plugins/hooks/PremiumTo.py index e783bac8f..15a357ce3 100644 --- a/module/plugins/hooks/PremiumTo.py +++ b/module/plugins/hooks/PremiumTo.py @@ -25,6 +25,7 @@ class PremiumTo(MultiHoster):                        get={'username': self.account.username, 'password': self.account.password})          return [x.strip() for x in page.replace("\"", "").split(";")] +      def coreReady(self):          self.account = self.core.accountManager.getAccountPlugin("PremiumTo") diff --git a/module/plugins/hooks/PremiumizeMe.py b/module/plugins/hooks/PremiumizeMe.py index c1a7866c4..1ef82612e 100644 --- a/module/plugins/hooks/PremiumizeMe.py +++ b/module/plugins/hooks/PremiumizeMe.py @@ -42,6 +42,7 @@ class PremiumizeMe(MultiHoster):          # Extract hosters from json file          return data['result']['hosterlist'] +      def coreReady(self):          # Get account plugin and check if there is a valid account available          self.account = self.core.accountManager.getAccountPlugin("PremiumizeMe") diff --git a/module/plugins/hooks/RPNetBiz.py b/module/plugins/hooks/RPNetBiz.py index f0231d0e7..feba36204 100644 --- a/module/plugins/hooks/RPNetBiz.py +++ b/module/plugins/hooks/RPNetBiz.py @@ -40,6 +40,7 @@ class RPNetBiz(MultiHoster):          # Extract hosters from json file          return hoster_list['hosters'] +      def coreReady(self):          # Get account plugin and check if there is a valid account available          self.account = self.core.accountManager.getAccountPlugin("RPNetBiz") diff --git a/module/plugins/hooks/RehostTo.py b/module/plugins/hooks/RehostTo.py index f3e1465ee..ea4521a28 100644 --- a/module/plugins/hooks/RehostTo.py +++ b/module/plugins/hooks/RehostTo.py @@ -24,6 +24,7 @@ class RehostTo(MultiHoster):          page = getURL("http://rehost.to/api.php?cmd=get_supported_och_dl&long_ses=%s" % self.long_ses)          return [x.strip() for x in page.replace("\"", "").split(",")] +      def coreReady(self):          self.account = self.core.accountManager.getAccountPlugin("RehostTo") diff --git a/module/plugins/hooks/RestartFailed.py b/module/plugins/hooks/RestartFailed.py index 6724ceaa8..ebce60b3f 100644 --- a/module/plugins/hooks/RestartFailed.py +++ b/module/plugins/hooks/RestartFailed.py @@ -31,13 +31,16 @@ class RestartFailed(Hook):              else:                  self.logDebug("Invalid interval value, kept current") +      def periodical(self):          self.logInfo(_("Restart failed downloads"))          self.api.restartFailed() +      def setup(self):          self.api = self.core.api          self.interval = self.MIN_INTERVAL +      def coreReady(self):          self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) diff --git a/module/plugins/hooks/UnSkipOnFail.py b/module/plugins/hooks/UnSkipOnFail.py index f29383b32..e3c0f6af9 100644 --- a/module/plugins/hooks/UnSkipOnFail.py +++ b/module/plugins/hooks/UnSkipOnFail.py @@ -32,6 +32,7 @@ class UnSkipOnFail(Hook):                  self.logInfo(_('restart "%s" (pid:%s)') % (pyfile_name, lpid))                  self.setLinkStatus(link, "queued") +      def findDuplicates(self, pyfile):          """ Search all packages for duplicate links to "pyfile".              Duplicates are links that would overwrite "pyfile". @@ -61,6 +62,7 @@ class UnSkipOnFail(Hook):                                  dups.append(link)          return dups +      def setLinkStatus(self, link, new_status):          """ Change status of "link" to "new_status".              "link" has to be a valid FileData object, diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py index cc086af5c..be1d6e5fc 100644 --- a/module/plugins/hooks/UpdateManager.py +++ b/module/plugins/hooks/UpdateManager.py @@ -48,14 +48,17 @@ class UpdateManager(Hook):              if value is True and self.core.debug:                  self.periodical2() +      def coreReady(self):          self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval"))          x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins"))          self.core.scheduler.addJob(10, x, threaded=False) +      def unload(self):          self.pluginConfigChanged(self.__name__, "reloadplugins", False) +      def setup(self):          self.cb2 = None          self.interval = self.MIN_INTERVAL @@ -63,11 +66,13 @@ class UpdateManager(Hook):          self.info = {'pyload': False, 'version': None, 'plugins': False}          self.mtimes = {}  #: store modification time for each plugin +      def periodical2(self):          if not self.updating:              self.autoreloadPlugins()          self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) +      @Expose      def autoreloadPlugins(self):          """ reload and reindex all modified plugins """ @@ -97,16 +102,19 @@ class UpdateManager(Hook):          return True if self.core.pluginManager.reloadPlugins(reloads) else False +      def periodical(self):          if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug):              self.updateThread() +      def server_request(self):          try:              return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines()          except:              self.logWarning(_("Unable to contact server to get updates")) +      @threaded      def updateThread(self):          self.updating = True @@ -116,11 +124,13 @@ class UpdateManager(Hook):          else:              self.updating = False +      @Expose      def updatePlugins(self):          """ simple wrapper for calling plugin update quickly """          return self.update(onlyplugin=True) +      @Expose      def update(self, onlyplugin=False):          """ check for updates """ @@ -142,6 +152,7 @@ class UpdateManager(Hook):              self.info['version'] = newversion          return exitcode  #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available +      def _updatePlugins(self, updates):          """ check for plugin updates """ @@ -240,6 +251,7 @@ class UpdateManager(Hook):          return exitcode  #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required +      @Expose      def removePlugins(self, type_plugins):          """ delete plugins from disk """ diff --git a/module/plugins/hooks/WindowsPhoneToastNotify.py b/module/plugins/hooks/WindowsPhoneToastNotify.py index eed61adbd..cf7920b74 100644 --- a/module/plugins/hooks/WindowsPhoneToastNotify.py +++ b/module/plugins/hooks/WindowsPhoneToastNotify.py @@ -25,12 +25,14 @@ class WindowsPhoneToastNotify(Hook):      def setup(self):          self.info = {} +      def getXmlData(self):          myxml = ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> "                   "<wp:Toast> <wp:Text1>Pyload Mobile</wp:Text1> <wp:Text2>Captcha waiting!</wp:Text2> "                   "</wp:Toast> </wp:Notification>")          return myxml +      def doRequest(self):          URL = self.getConfig("pushUrl")          request = self.getXmlData() @@ -46,6 +48,7 @@ class WindowsPhoneToastNotify(Hook):          webservice.close()          self.setStorage("LAST_NOTIFY", time.time()) +      def newCaptchaTask(self, task):          if not self.getConfig("pushId") or not self.getConfig("pushUrl"):              return False diff --git a/module/plugins/hooks/XMPPInterface.py b/module/plugins/hooks/XMPPInterface.py index b32eeb40b..c4d6e1b66 100644 --- a/module/plugins/hooks/XMPPInterface.py +++ b/module/plugins/hooks/XMPPInterface.py @@ -30,6 +30,7 @@ class XMPPInterface(IRCInterface, JabberClient):      implements(IMessageHandlersProvider) +      def __init__(self, core, manager):          IRCInterface.__init__(self, core, manager) @@ -58,11 +59,13 @@ class XMPPInterface(IRCInterface, JabberClient):              self,          ] +      def coreReady(self):          self.new_package = {}          self.start() +      def packageFinished(self, pypack):          try:              if self.getConfig("info_pack"): @@ -70,6 +73,7 @@ class XMPPInterface(IRCInterface, JabberClient):          except:              pass +      def downloadFinished(self, pyfile):          try:              if self.getConfig("info_file"): @@ -78,6 +82,7 @@ class XMPPInterface(IRCInterface, JabberClient):          except:              pass +      def run(self):          # connect to IRC etc.          self.connect() @@ -86,21 +91,26 @@ class XMPPInterface(IRCInterface, JabberClient):          except Exception, ex:              self.logError(ex) +      def stream_state_changed(self, state, arg):          """This one is called when the state of stream connecting the component          to a server changes. This will usually be used to let the user          know what is going on."""          self.logDebug("*** State changed: %s %r ***" % (state, arg)) +      def disconnected(self):          self.logDebug("Client was disconnected") +      def stream_closed(self, stream):          self.logDebug("Stream was closed", stream) +      def stream_error(self, err):          self.logDebug("Stream Error", err) +      def get_message_handlers(self):          """Return list of (message_type, message_handler) tuples. @@ -108,6 +118,7 @@ class XMPPInterface(IRCInterface, JabberClient):          in a client session."""          return [("normal", self.message)] +      def message(self, stanza):          """Message handler for the component."""          subject = stanza.get_subject() @@ -165,9 +176,11 @@ class XMPPInterface(IRCInterface, JabberClient):          else:              return True +      def response(self, msg, origin=""):          return self.announce(msg) +      def announce(self, message):          """ send message to all owners"""          for user in self.getConfig("owners").split(";"): @@ -187,9 +200,11 @@ class XMPPInterface(IRCInterface, JabberClient):              stream.send(m) +      def beforeReconnecting(self, ip):          self.disconnect() +      def afterReconnecting(self, ip):          self.connect() @@ -202,24 +217,29 @@ class VersionHandler(object):      implements(IIqHandlersProvider, IFeaturesProvider) +      def __init__(self, client):          """Just remember who created this."""          self.client = client +      def get_features(self):          """Return namespace which should the client include in its reply to a          disco#info query."""          return ["jabber:iq:version"] +      def get_iq_get_handlers(self):          """Return list of tuples (element_name, namespace, handler) describing          handlers of <iq type='get'/> stanzas"""          return [("query", "jabber:iq:version", self.get_version)] +      def get_iq_set_handlers(self):          """Return empty list, as this class provides no <iq type='set'/> stanza handler."""          return [] +      def get_version(self, iq):          """Handler for jabber:iq:version queries. diff --git a/module/plugins/hoster/AlldebridCom.py b/module/plugins/hoster/AlldebridCom.py index 74509110c..1b65237a0 100644 --- a/module/plugins/hoster/AlldebridCom.py +++ b/module/plugins/hoster/AlldebridCom.py @@ -31,10 +31,12 @@ class AlldebridCom(Hoster):              name += "%s.tmp" % randrange(100, 999)          return name +      def setup(self):          self.chunkLimit = 16          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/BayfilesCom.py b/module/plugins/hoster/BayfilesCom.py index b78af6286..8622f4dca 100644 --- a/module/plugins/hoster/BayfilesCom.py +++ b/module/plugins/hoster/BayfilesCom.py @@ -63,12 +63,14 @@ class BayfilesCom(SimpleHoster):              self.error("Free link")          self.startDownload(m.group(1)) +      def handlePremium(self):          m = re.search(self.PREMIUM_LINK_PATTERN, self.html)          if m is None:              self.error("Premium link")          self.startDownload(m.group(1)) +      def startDownload(self, url):          self.logDebug("%s URL: %s" % ("Premium" if self.premium else "Free", url))          self.download(url) diff --git a/module/plugins/hoster/BezvadataCz.py b/module/plugins/hoster/BezvadataCz.py index ffd586f74..9da1861ce 100644 --- a/module/plugins/hoster/BezvadataCz.py +++ b/module/plugins/hoster/BezvadataCz.py @@ -25,6 +25,7 @@ class BezvadataCz(SimpleHoster):      def setup(self):          self.multiDL = self.resumeDownload = True +      def handleFree(self):          #download button          m = re.search(r'<a class="stahnoutSoubor".*?href="(.*?)"', self.html) @@ -75,12 +76,14 @@ class BezvadataCz(SimpleHoster):          self.download(url) +      def checkErrors(self):          if 'images/button-download-disable.png' in self.html:              self.longWait(5 * 60, 24)  #: parallel dl limit          elif '<div class="infobox' in self.html:              self.tempOffline() +      def loadcaptcha(self, data, *args, **kwargs):          return data.decode("base64") diff --git a/module/plugins/hoster/CzshareCom.py b/module/plugins/hoster/CzshareCom.py index 9f2f23d9e..2b8278a7e 100644 --- a/module/plugins/hoster/CzshareCom.py +++ b/module/plugins/hoster/CzshareCom.py @@ -62,6 +62,7 @@ class CzshareCom(SimpleHoster):          return True +      def handlePremium(self):      # parse download link          try: @@ -75,6 +76,7 @@ class CzshareCom(SimpleHoster):          self.download("http://sdilej.cz/profi_down.php", post=inputs, disposition=True)          self.checkDownloadedFile() +      def handleFree(self):          # get free url          m = re.search(self.FREE_URL_PATTERN, self.html) @@ -126,6 +128,7 @@ class CzshareCom(SimpleHoster):          self.download(url)          self.checkDownloadedFile() +      def checkDownloadedFile(self):          # check download          check = self.checkDownload({ diff --git a/module/plugins/hoster/DailymotionCom.py b/module/plugins/hoster/DailymotionCom.py index 726663ca6..b4ef6fa92 100644 --- a/module/plugins/hoster/DailymotionCom.py +++ b/module/plugins/hoster/DailymotionCom.py @@ -54,6 +54,7 @@ class DailymotionCom(Hoster):      def setup(self):          self.resumeDownload = self.multiDL = True +      def getStreams(self):          streams = []          for result in re.finditer(r"\"(?P<URL>http:\\/\\/www.dailymotion.com\\/cdn\\/H264-(?P<QF>.*?)\\.*?)\"", @@ -65,6 +66,7 @@ class DailymotionCom(Hoster):              streams.append((quality, link))          return sorted(streams, key=lambda x: x[0][::-1]) +      def getQuality(self):          q = self.getConfig("quality")          if q == "Lowest": @@ -75,6 +77,7 @@ class DailymotionCom(Hoster):              quality = int(q.rsplit(" ")[1][:-1])          return quality +      def getLink(self, streams, quality):          if quality > 0:              for x, s in reversed([item for item in enumerate(streams)]): @@ -91,6 +94,7 @@ class DailymotionCom(Hoster):          self.logInfo("Download video quality %sx%s" % s[0])          return s[1] +      def checkInfo(self, pyfile):          pyfile.name, pyfile.size, pyfile.status, pyfile.url = getInfo([pyfile.url])[0]          if pyfile.status == 1: @@ -98,6 +102,7 @@ class DailymotionCom(Hoster):          elif pyfile.status == 6:              self.tempOffline() +      def process(self, pyfile):          self.checkInfo(pyfile) diff --git a/module/plugins/hoster/DateiTo.py b/module/plugins/hoster/DateiTo.py index 06a485eae..93840b108 100644 --- a/module/plugins/hoster/DateiTo.py +++ b/module/plugins/hoster/DateiTo.py @@ -65,6 +65,7 @@ class DateiTo(SimpleHoster):          self.logDebug("Download URL", download_url)          self.download(download_url) +      def checkErrors(self):          m = re.search(self.PARALELL_PATTERN, self.html)          if m: @@ -73,6 +74,7 @@ class DateiTo(SimpleHoster):              self.wait(wait_time + 1, False)              self.retry() +      def doWait(self):          m = re.search(self.WAIT_PATTERN, self.html)          wait_time = int(m.group(1)) if m else 30 diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py index 4e961fa9f..b1a2a4c77 100644 --- a/module/plugins/hoster/DebridItaliaCom.py +++ b/module/plugins/hoster/DebridItaliaCom.py @@ -21,6 +21,7 @@ class DebridItaliaCom(Hoster):          self.chunkLimit = -1          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/DepositfilesCom.py b/module/plugins/hoster/DepositfilesCom.py index ade91e7d4..16340036f 100644 --- a/module/plugins/hoster/DepositfilesCom.py +++ b/module/plugins/hoster/DepositfilesCom.py @@ -101,6 +101,7 @@ class DepositfilesCom(SimpleHoster):          except:              self.retry(wait_time=60) +      def handlePremium(self):          if '<span class="html_download_api-gold_traffic_limit">' in self.html:              self.logWarning("Download limit reached") diff --git a/module/plugins/hoster/DlFreeFr.py b/module/plugins/hoster/DlFreeFr.py index b653e2a8f..8932e749c 100644 --- a/module/plugins/hoster/DlFreeFr.py +++ b/module/plugins/hoster/DlFreeFr.py @@ -14,6 +14,7 @@ class CustomBrowser(Browser):      def __init__(self, bucket=None, options={}):          Browser.__init__(self, bucket, options) +      def load(self, *args, **kwargs):          post = kwargs.get("post") diff --git a/module/plugins/hoster/EdiskCz.py b/module/plugins/hoster/EdiskCz.py index 5112c55ab..a2e1937fb 100644 --- a/module/plugins/hoster/EdiskCz.py +++ b/module/plugins/hoster/EdiskCz.py @@ -27,6 +27,7 @@ class EdiskCz(SimpleHoster):      def setup(self):          self.multiDL = False +      def process(self, pyfile):          url = re.sub("/(stahni|sk/stahni)/", "/en/download/", pyfile.url) diff --git a/module/plugins/hoster/EuroshareEu.py b/module/plugins/hoster/EuroshareEu.py index a4a4e6881..d7c4b2eeb 100644 --- a/module/plugins/hoster/EuroshareEu.py +++ b/module/plugins/hoster/EuroshareEu.py @@ -31,6 +31,7 @@ class EuroshareEu(SimpleHoster):          self.multiDL = self.resumeDownload = self.premium          self.req.setOption("timeout", 120) +      def handlePremium(self):          if self.ERR_NOT_LOGGED_IN_PATTERN in self.html:              self.account.relogin(self.user) @@ -46,6 +47,7 @@ class EuroshareEu(SimpleHoster):          elif check == "json":              self.fail(self.lastCheck.group(1)) +      def handleFree(self):          if re.search(self.ERR_PARDL_PATTERN, self.html) is not None:              self.longWait(5 * 60, 12) diff --git a/module/plugins/hoster/FastixRu.py b/module/plugins/hoster/FastixRu.py index 7f61f7d7c..b1e834c61 100644 --- a/module/plugins/hoster/FastixRu.py +++ b/module/plugins/hoster/FastixRu.py @@ -30,10 +30,12 @@ class FastixRu(Hoster):              name += "%s.tmp" % randrange(100, 999)          return name +      def setup(self):          self.chunkLimit = 3          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py index 2a8d3af7d..0019a5708 100644 --- a/module/plugins/hoster/FastshareCz.py +++ b/module/plugins/hoster/FastshareCz.py @@ -60,6 +60,7 @@ class FastshareCz(SimpleHoster):          elif check == "wrong_captcha":              self.retry(max_tries=5, reason="Wrong captcha") +      def handlePremium(self):          header = self.load(self.pyfile.url, just_header=True)          if "location" in header: diff --git a/module/plugins/hoster/FileStoreTo.py b/module/plugins/hoster/FileStoreTo.py index 549335a04..b8e56271b 100644 --- a/module/plugins/hoster/FileStoreTo.py +++ b/module/plugins/hoster/FileStoreTo.py @@ -25,6 +25,7 @@ class FileStoreTo(SimpleHoster):      def setup(self):          self.resumeDownload = self.multiDL = True +      def handleFree(self):          self.wait(10)          ldc = re.search(r'wert="(\w+)"', self.html).group(1) diff --git a/module/plugins/hoster/FilecloudIo.py b/module/plugins/hoster/FilecloudIo.py index 5672e780d..659a2cc0f 100644 --- a/module/plugins/hoster/FilecloudIo.py +++ b/module/plugins/hoster/FilecloudIo.py @@ -37,6 +37,7 @@ class FilecloudIo(SimpleHoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = 1 +      def handleFree(self):          data = {"ukey": self.file_info['ID']} @@ -104,6 +105,7 @@ class FilecloudIo(SimpleHoster):          else:              self.fail("Unexpected server response") +      def handlePremium(self):          akey = self.account.getAccountData(self.user)['akey']          ukey = self.file_info['ID'] diff --git a/module/plugins/hoster/FilefactoryCom.py b/module/plugins/hoster/FilefactoryCom.py index a5942e261..0801ca9a1 100644 --- a/module/plugins/hoster/FilefactoryCom.py +++ b/module/plugins/hoster/FilefactoryCom.py @@ -85,6 +85,7 @@ class FilefactoryCom(SimpleHoster):          elif check == "error":              self.fail("Unknown error") +      def handlePremium(self):          header = self.load(self.pyfile.url, just_header=True)          if 'location' in header: diff --git a/module/plugins/hoster/FilepostCom.py b/module/plugins/hoster/FilepostCom.py index 0748b64f2..45fb2e644 100644 --- a/module/plugins/hoster/FilepostCom.py +++ b/module/plugins/hoster/FilepostCom.py @@ -93,6 +93,7 @@ class FilepostCom(SimpleHoster):          # Download          self.download(download_url) +      def getJsonResponse(self, get_dict, post_dict, field):          json_response = json_loads(self.load('https://filepost.com/files/get/', get=get_dict, post=post_dict))          self.logDebug(json_response) diff --git a/module/plugins/hoster/FilesMailRu.py b/module/plugins/hoster/FilesMailRu.py index 2889e0565..cd8069efc 100644 --- a/module/plugins/hoster/FilesMailRu.py +++ b/module/plugins/hoster/FilesMailRu.py @@ -45,6 +45,7 @@ class FilesMailRu(Hoster):          if not self.account:              self.multiDL = False +      def process(self, pyfile):          self.html = self.load(pyfile.url)          self.url_pattern = '<a href="(.+?)" onclick="return Act\(this\, \'dlink\'\, event\)">(.+?)</a>' @@ -68,20 +69,24 @@ class FilesMailRu(Hoster):              self.download(self.getFileUrl())              self.myPostProcess() +      def prepare(self):          """You have to wait some seconds. Otherwise you will get a 40Byte HTML Page instead of the file you expected"""          self.setWait(10)          self.wait()          return True +      def getFileUrl(self):          """gives you the URL to the file. Extracted from the Files.mail.ru HTML-page stored in self.html"""          return re.search(self.url_pattern, self.html).group(0).split('<a href="')[1].split('" onclick="return Act')[0] +      def getFileName(self):          """gives you the Name for each file. Also extracted from the HTML-Page"""          return re.search(self.url_pattern, self.html).group(0).split(', event)">')[1].split('</a>')[0] +      def myPostProcess(self):          # searches the file for HTMl-Code. Sometimes the Redirect          # doesn't work (maybe a curl Problem) and you get only a small diff --git a/module/plugins/hoster/FileserveCom.py b/module/plugins/hoster/FileserveCom.py index 4e722eb9f..7a06472d3 100644 --- a/module/plugins/hoster/FileserveCom.py +++ b/module/plugins/hoster/FileserveCom.py @@ -64,6 +64,7 @@ class FileserveCom(Hoster):          self.url = "%s%s" % (self.URLS[0], self.file_id)          self.logDebug("File ID: %s URL: %s" % (self.file_id, self.url)) +      def process(self, pyfile):          pyfile.name, pyfile.size, status, self.url = checkFile(self, [self.url])[0]          if status != 2: @@ -75,6 +76,7 @@ class FileserveCom(Hoster):          else:              self.handleFree() +      def handleFree(self):          self.html = self.load(self.url)          action = self.load(self.url, post={"checkDownload": "check"}, decode=True) @@ -132,6 +134,7 @@ class FileserveCom(Hoster):          self.thread.m.reconnecting.wait(3)  # Ease issue with later downloads appearing to be in parallel +      def doTimmer(self):          response = self.load(self.url, post={"downloadLink": "wait"}, decode=True)          self.logDebug("Wait response : %s" % response[:80]) @@ -150,6 +153,7 @@ class FileserveCom(Hoster):          self.setWait(wait_time)          self.wait() +      def doCaptcha(self):          captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group("key")          recaptcha = ReCaptcha(self) @@ -170,12 +174,14 @@ class FileserveCom(Hoster):          else:              self.fail("Invalid captcha") +      def doLongWait(self, m):          wait_time = (int(m.group(1)) * {'seconds': 1, 'minutes': 60, 'hours': 3600}[m.group(2)]) if m else 12 * 60          self.setWait(wait_time, True)          self.wait()          self.retry() +      def handlePremium(self):          premium_url = None          if self.__name__ == "FileserveCom": diff --git a/module/plugins/hoster/FreakshareCom.py b/module/plugins/hoster/FreakshareCom.py index df06f2e74..6287545cb 100644 --- a/module/plugins/hoster/FreakshareCom.py +++ b/module/plugins/hoster/FreakshareCom.py @@ -26,6 +26,7 @@ class FreakshareCom(Hoster):          self.multiDL = False          self.req_opts = [] +      def process(self, pyfile):          self.pyfile = pyfile @@ -62,6 +63,7 @@ class FreakshareCom(Hoster):              elif check == "downloadserver":                  self.retry(5, 15 * 60, "No Download server") +      def prepare(self):          pyfile = self.pyfile @@ -81,10 +83,12 @@ class FreakshareCom(Hoster):          return True +      def download_html(self):          self.load("http://freakshare.com/index.php", {"language": "EN"})  # Set english language in server session          self.html = self.load(self.pyfile.url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -97,6 +101,7 @@ class FreakshareCom(Hoster):          else:              self.offline() +      def get_file_name(self):          if not self.html:              self.download_html() @@ -110,6 +115,7 @@ class FreakshareCom(Hoster):          else:              return self.pyfile.url +      def get_file_size(self):          size = 0          if not self.html: @@ -124,6 +130,7 @@ class FreakshareCom(Hoster):          return size +      def get_waiting_time(self):          if not self.html:              self.download_html() @@ -138,6 +145,7 @@ class FreakshareCom(Hoster):          else:              return 60 +      def file_exists(self):          """ returns True or False          """ @@ -148,6 +156,7 @@ class FreakshareCom(Hoster):          else:              return True +      def get_download_options(self):          re_envelope = re.search(r".*?value=\"Free\sDownload\".*?\n*?(.*?<.*?>\n*)*?\n*\s*?</form>",                                  self.html).group(0)  # get the whole request diff --git a/module/plugins/hoster/FreeWayMe.py b/module/plugins/hoster/FreeWayMe.py index 996c8b6aa..88ba982f6 100644 --- a/module/plugins/hoster/FreeWayMe.py +++ b/module/plugins/hoster/FreeWayMe.py @@ -20,6 +20,7 @@ class FreeWayMe(Hoster):          self.chunkLimit = 1          self.multiDL = self.premium +      def process(self, pyfile):          if not self.account:              self.logError(_("Please enter your %s account or deactivate this plugin") % "FreeWayMe") diff --git a/module/plugins/hoster/FshareVn.py b/module/plugins/hoster/FshareVn.py index 1a995ce28..7ce7cd3e6 100644 --- a/module/plugins/hoster/FshareVn.py +++ b/module/plugins/hoster/FshareVn.py @@ -58,6 +58,7 @@ class FshareVn(SimpleHoster):              self.handleFree()          self.checkDownloadedFile() +      def handleFree(self):          self.html = self.load(self.pyfile.url, decode=True) @@ -94,9 +95,11 @@ class FshareVn(SimpleHoster):          self.wait()          self.download(self.url) +      def handlePremium(self):          self.download(self.pyfile.url) +      def checkErrors(self):          if '/error.php?' in self.req.lastEffectiveURL or u"Liên kết bạn chá»n khÃŽng tá»n" in self.html:              self.offline() @@ -111,6 +114,7 @@ class FshareVn(SimpleHoster):              self.logError("Unknown error occured or wait time not parsed")              self.retry(30, 2 * 60, "Unknown error") +      def checkDownloadedFile(self):          # check download          check = self.checkDownload({ diff --git a/module/plugins/hoster/GamefrontCom.py b/module/plugins/hoster/GamefrontCom.py index b7e7f0bc8..2009d06ab 100644 --- a/module/plugins/hoster/GamefrontCom.py +++ b/module/plugins/hoster/GamefrontCom.py @@ -28,6 +28,7 @@ class GamefrontCom(Hoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = -1 +      def process(self, pyfile):          self.pyfile = pyfile          self.html = self.load(pyfile.url, decode=True) @@ -44,12 +45,14 @@ class GamefrontCom(Hoster):          self.download(link) +      def _checkOnline(self):          if re.search(self.PATTERN_OFFLINE, self.html):              return False          else:              return True +      def _getName(self):          name = re.search(self.PATTERN_FILENAME, self.html)          if name is None: @@ -57,6 +60,7 @@ class GamefrontCom(Hoster):          return name.group(1) +      def _getLink(self):          self.html2 = self.load("http://www.gamefront.com/" + re.search("(files/service/thankyou\\?id=\w+)",                                                                         self.html).group(1)) diff --git a/module/plugins/hoster/GigapetaCom.py b/module/plugins/hoster/GigapetaCom.py index efec11079..65d940c5a 100644 --- a/module/plugins/hoster/GigapetaCom.py +++ b/module/plugins/hoster/GigapetaCom.py @@ -55,6 +55,7 @@ class GigapetaCom(SimpleHoster):          self.logDebug("Download URL: %s" % download_url)          self.download(download_url) +      def checkErrors(self):          if "All threads for IP" in self.html:              self.logDebug("Your IP is already downloading a file - wait and retry") diff --git a/module/plugins/hoster/GooIm.py b/module/plugins/hoster/GooIm.py index d27b38f1f..d8f4c6190 100644 --- a/module/plugins/hoster/GooIm.py +++ b/module/plugins/hoster/GooIm.py @@ -27,6 +27,7 @@ class GooIm(SimpleHoster):      def setup(self):          self.multiDL = self.resumeDownload = True +      def handleFree(self):          url = self.pyfile.url          self.html = self.load(url, cookies=True) diff --git a/module/plugins/hoster/HellshareCz.py b/module/plugins/hoster/HellshareCz.py index 10975829c..7a8579e78 100644 --- a/module/plugins/hoster/HellshareCz.py +++ b/module/plugins/hoster/HellshareCz.py @@ -27,6 +27,7 @@ class HellshareCz(SimpleHoster):          self.resumeDownload = self.multiDL = True if self.account else False          self.chunkLimit = 1 +      def process(self, pyfile):          if not self.account:              self.fail("User not logged in") diff --git a/module/plugins/hoster/IfolderRu.py b/module/plugins/hoster/IfolderRu.py index 774761049..176225e30 100644 --- a/module/plugins/hoster/IfolderRu.py +++ b/module/plugins/hoster/IfolderRu.py @@ -33,6 +33,7 @@ class IfolderRu(SimpleHoster):          self.resumeDownload = self.multiDL = True if self.account else False          self.chunkLimit = 1 +      def process(self, pyfile):          file_id = re.match(self.__pattern__, pyfile.url).group('ID')          self.html = self.load("http://rusfolder.com/%s" % file_id, cookies=True, decode=True) diff --git a/module/plugins/hoster/JumbofilesCom.py b/module/plugins/hoster/JumbofilesCom.py index fe0b72804..f43ee7697 100644 --- a/module/plugins/hoster/JumbofilesCom.py +++ b/module/plugins/hoster/JumbofilesCom.py @@ -25,6 +25,7 @@ class JumbofilesCom(SimpleHoster):      def setup(self):          self.resumeDownload = self.multiDL = True +      def handleFree(self):          ukey = re.match(self.__pattern__, self.pyfile.url).group(1)          post_data = {"id": ukey, "op": "download3", "rand": ""} diff --git a/module/plugins/hoster/LetitbitNet.py b/module/plugins/hoster/LetitbitNet.py index 8443c2206..002c986e2 100644 --- a/module/plugins/hoster/LetitbitNet.py +++ b/module/plugins/hoster/LetitbitNet.py @@ -56,7 +56,7 @@ class LetitbitNet(SimpleHoster):      def setup(self):          self.resumeDownload = True -        #TODO confirm that resume works +      def getFileInfo(self):          api_rep = api_download_info(self.pyfile.url) @@ -67,6 +67,7 @@ class LetitbitNet(SimpleHoster):          else:              self.offline() +      def handleFree(self):          action, inputs = self.parseHtmlForm('id="ifree_form"')          if not action: @@ -149,6 +150,7 @@ class LetitbitNet(SimpleHoster):          else:              self.fail("Download did not finish correctly") +      def handlePremium(self):          api_key = self.user          premium_key = self.account.getAccountData(self.user)['password'] diff --git a/module/plugins/hoster/LinksnappyCom.py b/module/plugins/hoster/LinksnappyCom.py index 3372a505d..b96c9492c 100644 --- a/module/plugins/hoster/LinksnappyCom.py +++ b/module/plugins/hoster/LinksnappyCom.py @@ -27,6 +27,7 @@ class LinksnappyCom(Hoster):          self.chunkLimit = -1          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url @@ -67,6 +68,7 @@ class LinksnappyCom(Hoster):          if check == "html302":              self.retry(wait_time=5, reason="Linksnappy returns only HTML data.") +      @staticmethod      def _get_host(url):          host = urlsplit(url).netloc diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py index fe5a80679..4a4d4a047 100644 --- a/module/plugins/hoster/LuckyShareNet.py +++ b/module/plugins/hoster/LuckyShareNet.py @@ -38,6 +38,7 @@ class LuckyShareNet(SimpleHoster):              self.retry(reason="Hash expired")          return json_loads(rep) +      # TODO: There should be a filesize limit for free downloads      # TODO: Some files could not be downloaded in free mode      def handleFree(self): diff --git a/module/plugins/hoster/MediafireCom.py b/module/plugins/hoster/MediafireCom.py index c2581aa9f..31b85b433 100644 --- a/module/plugins/hoster/MediafireCom.py +++ b/module/plugins/hoster/MediafireCom.py @@ -71,6 +71,7 @@ class MediafireCom(SimpleHoster):      def setup(self):          self.multiDL = False +      def process(self, pyfile):          pyfile.url = re.sub(r'/view/?\?', '/?', pyfile.url) @@ -93,6 +94,7 @@ class MediafireCom(SimpleHoster):              self.multiDL = True              self.download(self.url, disposition=True) +      def handleFree(self):          passwords = self.getPassword().splitlines()          while self.PASSWORD_PATTERN in self.html: @@ -111,6 +113,7 @@ class MediafireCom(SimpleHoster):          self.download(download_url) +      def checkCaptcha(self):          solvemedia = SolveMedia(self) diff --git a/module/plugins/hoster/MegaDebridEu.py b/module/plugins/hoster/MegaDebridEu.py index ca0569c6b..68b7e0c1e 100644 --- a/module/plugins/hoster/MegaDebridEu.py +++ b/module/plugins/hoster/MegaDebridEu.py @@ -29,6 +29,7 @@ class MegaDebridEu(Hoster):          except IndexError:              return "" +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url @@ -47,6 +48,7 @@ class MegaDebridEu(Hoster):              pyfile.name = filename          self.download(new_url, disposition=True) +      def connectToApi(self):          """          Connexion to the mega-debrid API @@ -63,6 +65,7 @@ class MegaDebridEu(Hoster):          else:              return False +      def debridLink(self, linkToDebrid):          """          Debrid a link @@ -78,6 +81,7 @@ class MegaDebridEu(Hoster):          else:              self.exitOnFail("Unable to debrid %s" % linkToDebrid) +      def exitOnFail(self, msg):          """          exit the plugin on fail case diff --git a/module/plugins/hoster/MegaRapidCz.py b/module/plugins/hoster/MegaRapidCz.py index 153f6ea8b..01b2aaf70 100644 --- a/module/plugins/hoster/MegaRapidCz.py +++ b/module/plugins/hoster/MegaRapidCz.py @@ -48,6 +48,7 @@ class MegaRapidCz(SimpleHoster):      def setup(self):          self.chunkLimit = 1 +      def handlePremium(self):          try:              self.html = self.load(self.pyfile.url, decode=True) diff --git a/module/plugins/hoster/MegacrypterCom.py b/module/plugins/hoster/MegacrypterCom.py index 67dec2a0b..5464dedce 100644 --- a/module/plugins/hoster/MegacrypterCom.py +++ b/module/plugins/hoster/MegacrypterCom.py @@ -29,6 +29,7 @@ class MegacrypterCom(MegaNz):          self.logDebug("API Response: " + resp)          return json_loads(resp) +      def process(self, pyfile):          # match is guaranteed because plugin was chosen to handle url          node = re.match(self.__pattern__, pyfile.url).group(1) diff --git a/module/plugins/hoster/MultishareCz.py b/module/plugins/hoster/MultishareCz.py index 1ce16f30c..f7c8b47fd 100644 --- a/module/plugins/hoster/MultishareCz.py +++ b/module/plugins/hoster/MultishareCz.py @@ -38,9 +38,11 @@ class MultishareCz(SimpleHoster):          else:              self.handleOverriden() +      def handleFree(self):          self.download("http://www.multishare.cz/html/download_free.php?ID=%s" % self.fileID) +      def handlePremium(self):          if not self.checkCredit():              self.logWarning("Not enough credit left to download file") @@ -48,6 +50,7 @@ class MultishareCz(SimpleHoster):          self.download("http://www.multishare.cz/html/download_premium.php?ID=%s" % self.fileID) +      def handleOverriden(self):          if not self.premium:              self.fail("Only premium users can download from other hosters") @@ -63,6 +66,7 @@ class MultishareCz(SimpleHoster):          self.logDebug(url, params)          self.download(url, get=params) +      def checkCredit(self):          self.acc_info = self.account.getAccountInfo(self.user, True)          self.logInfo("User %s has %i MB left" % (self.user, self.acc_info['trafficleft'] / 1024)) diff --git a/module/plugins/hoster/MyfastfileCom.py b/module/plugins/hoster/MyfastfileCom.py index 8fbae3e0a..d3a699e98 100644 --- a/module/plugins/hoster/MyfastfileCom.py +++ b/module/plugins/hoster/MyfastfileCom.py @@ -22,6 +22,7 @@ class MyfastfileCom(Hoster):          self.chunkLimit = -1          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/MyvideoDe.py b/module/plugins/hoster/MyvideoDe.py index 1f02b5b69..1f8c785a7 100644 --- a/module/plugins/hoster/MyvideoDe.py +++ b/module/plugins/hoster/MyvideoDe.py @@ -24,19 +24,23 @@ class MyvideoDe(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      def download_html(self):          self.html = self.load(self.pyfile.url) +      def get_file_url(self):          videoId = re.search(r"addVariable\('_videoid','(.*)'\);p.addParam\('quality'", self.html).group(1)          videoServer = re.search("rel='image_src' href='(.*)thumbs/.*' />", self.html).group(1)          file_url = videoServer + videoId + ".flv"          return file_url +      def get_file_name(self):          file_name_pattern = r'<h1 class=\'globalHd\'>(.*)</h1>'          return unescape(re.search(file_name_pattern, self.html).group(1).replace("/", "") + '.flv') +      def file_exists(self):          self.download_html()          self.load(str(self.pyfile.url), cookies=False, just_header=True) diff --git a/module/plugins/hoster/NetloadIn.py b/module/plugins/hoster/NetloadIn.py index 0c255afbe..800de3068 100644 --- a/module/plugins/hoster/NetloadIn.py +++ b/module/plugins/hoster/NetloadIn.py @@ -66,12 +66,14 @@ class NetloadIn(Hoster):      def setup(self):          self.multiDL = self.resumeDownload = self.premium +      def process(self, pyfile):          self.url = pyfile.url          self.prepare()          pyfile.setStatus("downloading")          self.proceed(self.url) +      def prepare(self):          self.download_api_data() @@ -93,6 +95,7 @@ class NetloadIn(Hoster):              self.fail("Failed")              return False +      def download_api_data(self, n=0):          url = self.url          id_regex = re.compile(self.__pattern__) @@ -134,6 +137,7 @@ class NetloadIn(Hoster):          else:              self.api_data = False +      def final_wait(self, page):          wait_time = self.get_wait_time(page)          self.setWait(wait_time) @@ -141,6 +145,7 @@ class NetloadIn(Hoster):          self.wait()          self.url = self.get_file_url(page) +      def download_html(self):          self.logDebug("Netload: Entering download_html")          page = self.load(self.url, decode=True) @@ -227,6 +232,7 @@ class NetloadIn(Hoster):          return False +      def get_file_url(self, page):          try:              file_url_pattern = r'<a class="Orange_Link" href="(http://.+)".?>Or click here' @@ -242,10 +248,12 @@ class NetloadIn(Hoster):              self.logDebug("Netload: Getting final link failed")              return None +      def get_wait_time(self, page):          wait_seconds = int(re.search(r"countdown\((.+),'change\(\)'\)", page).group(1)) / 100          return wait_seconds +      def proceed(self, url):          self.logDebug("Netload: Downloading..") diff --git a/module/plugins/hoster/NowDownloadEu.py b/module/plugins/hoster/NowDownloadEu.py index 57d31acd5..256b2c801 100644 --- a/module/plugins/hoster/NowDownloadEu.py +++ b/module/plugins/hoster/NowDownloadEu.py @@ -34,6 +34,7 @@ class NowDownloadEu(SimpleHoster):          self.multiDL = self.resumeDownload = True          self.chunkLimit = -1 +      def handleFree(self):          tokenlink = re.search(self.TOKEN_PATTERN, self.html)          continuelink = re.search(self.CONTINUE_PATTERN, self.html) diff --git a/module/plugins/hoster/OverLoadMe.py b/module/plugins/hoster/OverLoadMe.py index 5c3a36318..1b50ae8a2 100644 --- a/module/plugins/hoster/OverLoadMe.py +++ b/module/plugins/hoster/OverLoadMe.py @@ -31,10 +31,12 @@ class OverLoadMe(Hoster):              name += "%s.tmp" % randrange(100, 999)          return name +      def setup(self):          self.chunkLimit = 5          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/PornhostCom.py b/module/plugins/hoster/PornhostCom.py index 51426de71..6fb0fad83 100644 --- a/module/plugins/hoster/PornhostCom.py +++ b/module/plugins/hoster/PornhostCom.py @@ -25,11 +25,13 @@ class PornhostCom(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      # Old interface      def download_html(self):          url = self.pyfile.url          self.html = self.load(url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -47,6 +49,7 @@ class PornhostCom(Hoster):          return url.group(1).strip() +      def get_file_name(self):          if not self.html:              self.download_html() @@ -63,6 +66,7 @@ class PornhostCom(Hoster):          return name +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/PornhubCom.py b/module/plugins/hoster/PornhubCom.py index 60b57d2c8..01204010d 100644 --- a/module/plugins/hoster/PornhubCom.py +++ b/module/plugins/hoster/PornhubCom.py @@ -25,10 +25,12 @@ class PornhubCom(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      def download_html(self):          url = self.pyfile.url          self.html = self.load(url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -57,6 +59,7 @@ class PornhubCom(Hoster):          return re.search(r'flv_url.*(http.*?)##post_roll', content).group(1) +      def get_file_name(self):          if not self.html:              self.download_html() @@ -73,6 +76,7 @@ class PornhubCom(Hoster):          return name + '.flv' +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/PremiumTo.py b/module/plugins/hoster/PremiumTo.py index ed96f315b..8595304c4 100644 --- a/module/plugins/hoster/PremiumTo.py +++ b/module/plugins/hoster/PremiumTo.py @@ -26,6 +26,7 @@ class PremiumTo(Hoster):          self.resumeDownload = True          self.chunkLimit = 1 +      def process(self, pyfile):          if not self.account:              self.logError(_("Please enter your %s account or deactivate this plugin") % "premium.to") @@ -66,6 +67,7 @@ class PremiumTo(Hoster):          if err:              self.fail(err) +      def getTraffic(self):          try:              api_r = self.load("http://premium.to/api/straffic.php", diff --git a/module/plugins/hoster/QuickshareCz.py b/module/plugins/hoster/QuickshareCz.py index 5946565c6..12de0fa5b 100644 --- a/module/plugins/hoster/QuickshareCz.py +++ b/module/plugins/hoster/QuickshareCz.py @@ -53,6 +53,7 @@ class QuickshareCz(SimpleHoster):          if check == "err":              self.fail("File not m or plugin defect") +      def handleFree(self):          # get download url          download_url = '%s/download.php' % self.jsvars['server'] @@ -83,6 +84,7 @@ class QuickshareCz(SimpleHoster):          # download file          self.download(download_url) +      def handlePremium(self):          download_url = '%s/download_premium.php' % self.jsvars['server']          data = dict((x, self.jsvars[x]) for x in self.jsvars if x in ("ID1", "ID2", "ID4", "ID5")) diff --git a/module/plugins/hoster/RPNetBiz.py b/module/plugins/hoster/RPNetBiz.py index 3132001ed..0d032ef2f 100644 --- a/module/plugins/hoster/RPNetBiz.py +++ b/module/plugins/hoster/RPNetBiz.py @@ -22,6 +22,7 @@ class RPNetBiz(Hoster):          self.chunkLimit = -1          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              link_status = {'generated': pyfile.url} diff --git a/module/plugins/hoster/RapidshareCom.py b/module/plugins/hoster/RapidshareCom.py index befbbb123..2dd36b84e 100644 --- a/module/plugins/hoster/RapidshareCom.py +++ b/module/plugins/hoster/RapidshareCom.py @@ -70,10 +70,12 @@ class RapidshareCom(Hoster):          self.chunkLimit = -1 if self.premium else 1          self.multiDL = self.resumeDownload = self.premium +      def process(self, pyfile):          self.url = pyfile.url          self.prepare() +      def prepare(self):          m = re.match(self.__pattern__, self.url) @@ -106,6 +108,7 @@ class RapidshareCom(Hoster):          else:              self.fail("Unknown response code.") +      def handleFree(self):          while self.no_download:              self.dl_dict = self.freeWait() @@ -128,12 +131,14 @@ class RapidshareCom(Hoster):              self.offset += 5              self.handleFree() +      def handlePremium(self):          info = self.account.getAccountInfo(self.user, True)          self.logDebug("%s: Use Premium Account" % self.__name__)          url = self.api_data['mirror']          self.download(url, get={"directstart": 1}) +      def download_api_data(self, force=False):          """          http://images.rapidshare.com/apidoc.txt @@ -168,6 +173,7 @@ class RapidshareCom(Hoster):          self.api_data['mirror'] = "http://rs%(serverid)s%(shorthost)s.rapidshare.com/files/%(fileid)s/%(filename)s" % self.api_data +      def freeWait(self):          """downloads html with the important information          """ @@ -219,6 +225,7 @@ class RapidshareCom(Hoster):              return dl_dict +      def get_file_name(self):          if self.api_data['filename']:              return self.api_data['filename'] diff --git a/module/plugins/hoster/RealdebridCom.py b/module/plugins/hoster/RealdebridCom.py index fe6db98cb..cf1f825ef 100644 --- a/module/plugins/hoster/RealdebridCom.py +++ b/module/plugins/hoster/RealdebridCom.py @@ -32,10 +32,12 @@ class RealdebridCom(Hoster):              name += "%s.tmp" % randrange(100, 999)          return name +      def setup(self):          self.chunkLimit = 3          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/RedtubeCom.py b/module/plugins/hoster/RedtubeCom.py index f8ac81693..d136d145b 100644 --- a/module/plugins/hoster/RedtubeCom.py +++ b/module/plugins/hoster/RedtubeCom.py @@ -26,10 +26,12 @@ class RedtubeCom(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      def download_html(self):          url = self.pyfile.url          self.html = self.load(url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -40,12 +42,14 @@ class RedtubeCom(Hoster):          return file_url +      def get_file_name(self):          if not self.html:              self.download_html()          return re.search('<title>(.*?)- RedTube - Free Porn Videos</title>', self.html).group(1).strip() + ".flv" +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/RehostTo.py b/module/plugins/hoster/RehostTo.py index e1f719c19..80465724d 100644 --- a/module/plugins/hoster/RehostTo.py +++ b/module/plugins/hoster/RehostTo.py @@ -20,10 +20,12 @@ class RehostTo(Hoster):      def getFilename(self, url):          return unquote(url.rsplit("/", 1)[1]) +      def setup(self):          self.chunkLimit = 1          self.resumeDownload = True +      def process(self, pyfile):          if not self.account:              self.logError(_("Please enter your %s account or deactivate this plugin") % "rehost.to") diff --git a/module/plugins/hoster/RemixshareCom.py b/module/plugins/hoster/RemixshareCom.py index 4e812b20d..94be78b4f 100644 --- a/module/plugins/hoster/RemixshareCom.py +++ b/module/plugins/hoster/RemixshareCom.py @@ -38,6 +38,7 @@ class RemixshareCom(SimpleHoster):          self.multiDL = True          self.chunkLimit = 1 +      def handleFree(self):          b = re.search(self.LINK_PATTERN, self.html)          if not b: diff --git a/module/plugins/hoster/ShareplaceCom.py b/module/plugins/hoster/ShareplaceCom.py index 84be2706f..bef14de0f 100644 --- a/module/plugins/hoster/ShareplaceCom.py +++ b/module/plugins/hoster/ShareplaceCom.py @@ -24,6 +24,7 @@ class ShareplaceCom(Hoster):          self.prepare()          self.download(self.get_file_url()) +      def prepare(self):          if not self.file_exists():              self.offline() @@ -35,6 +36,7 @@ class ShareplaceCom(Hoster):          self.logDebug("%s: Waiting %d seconds." % (self.__name__, wait_time))          self.wait() +      def get_waiting_time(self):          if not self.html:              self.download_html() @@ -48,10 +50,12 @@ class ShareplaceCom(Hoster):          return sec +      def download_html(self):          url = re.sub("shareplace.com\/\?", "shareplace.com//index1.php/?a=", self.pyfile.url)          self.html = self.load(url, decode=True) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -66,12 +70,14 @@ class ShareplaceCom(Hoster):          else:              self.fail("absolute filepath could not be found. offline? ") +      def get_file_name(self):          if not self.html:              self.download_html()          return re.search("<title>\s*(.*?)\s*</title>", self.html).group(1) +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/SimplyPremiumCom.py b/module/plugins/hoster/SimplyPremiumCom.py index e78a1f469..965c1421a 100644 --- a/module/plugins/hoster/SimplyPremiumCom.py +++ b/module/plugins/hoster/SimplyPremiumCom.py @@ -24,6 +24,7 @@ class SimplyPremiumCom(Hoster):          self.chunkLimit = 16          self.resumeDownload = False +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url diff --git a/module/plugins/hoster/SimplydebridCom.py b/module/plugins/hoster/SimplydebridCom.py index c7df990e3..dea82591d 100644 --- a/module/plugins/hoster/SimplydebridCom.py +++ b/module/plugins/hoster/SimplydebridCom.py @@ -21,6 +21,7 @@ class SimplydebridCom(Hoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = 1 +      def process(self, pyfile):          if not self.account:              self.logError(_("Please enter your %s account or deactivate this plugin") % "simply-debrid.com") diff --git a/module/plugins/hoster/StreamCz.py b/module/plugins/hoster/StreamCz.py index 1459ca5f1..d4ebd7701 100644 --- a/module/plugins/hoster/StreamCz.py +++ b/module/plugins/hoster/StreamCz.py @@ -42,8 +42,8 @@ class StreamCz(Hoster):          self.multiDL = True          self.resumeDownload = True -    def process(self, pyfile): +    def process(self, pyfile):          self.html = self.load(pyfile.url, decode=True)          if re.search(self.OFFLINE_PATTERN, self.html): diff --git a/module/plugins/hoster/TwoSharedCom.py b/module/plugins/hoster/TwoSharedCom.py index 6b755219a..e1cdead9b 100644 --- a/module/plugins/hoster/TwoSharedCom.py +++ b/module/plugins/hoster/TwoSharedCom.py @@ -27,6 +27,7 @@ class TwoSharedCom(SimpleHoster):      def setup(self):          self.resumeDownload = self.multiDL = True +      def handleFree(self):          m = re.search(self.LINK_PATTERN, self.html)          if m is None: diff --git a/module/plugins/hoster/UlozTo.py b/module/plugins/hoster/UlozTo.py index 2d4762ba6..9b70c8efa 100644 --- a/module/plugins/hoster/UlozTo.py +++ b/module/plugins/hoster/UlozTo.py @@ -44,6 +44,7 @@ class UlozTo(SimpleHoster):          self.multiDL = self.premium          self.resumeDownload = True +      def process(self, pyfile):          pyfile.url = re.sub(r"(?<=http://)([^/]+)", "www.ulozto.net", pyfile.url)          self.html = self.load(pyfile.url, decode=True, cookies=True) @@ -81,6 +82,7 @@ class UlozTo(SimpleHoster):          self.doCheckDownload() +      def handleFree(self):          action, inputs = self.parseHtmlForm('id="frm-downloadDialog-freeDownloadForm"')          if not action or not inputs: @@ -115,11 +117,13 @@ class UlozTo(SimpleHoster):          self.multiDL = True          self.download("http://www.ulozto.net" + action, post=inputs, cookies=True, disposition=True) +      def handlePremium(self):          self.download(self.pyfile.url + "?do=directDownload", disposition=True)          #parsed_url = self.findDownloadURL(premium=True)          #self.download(parsed_url, post={"download": "Download"}) +      def findDownloadURL(self, premium=False):          msg = "%s link" % ("Premium" if premium else "Free")          m = re.search(self.PREMIUM_URL_PATTERN if premium else self.FREE_URL_PATTERN, self.html) @@ -129,6 +133,7 @@ class UlozTo(SimpleHoster):          self.logDebug("%s: %s" % (msg, parsed_url))          return parsed_url +      def doCheckDownload(self):          check = self.checkDownload({              "wrong_captcha": re.compile(r'<ul class="error">\s*<li>Error rewriting the text.</li>'), diff --git a/module/plugins/hoster/UloziskoSk.py b/module/plugins/hoster/UloziskoSk.py index 4323a71e5..2db2ce65e 100644 --- a/module/plugins/hoster/UloziskoSk.py +++ b/module/plugins/hoster/UloziskoSk.py @@ -38,6 +38,7 @@ class UloziskoSk(SimpleHoster):          else:              self.handleFree() +      def handleFree(self):          m = re.search(self.LINK_PATTERN, self.html)          if m is None: diff --git a/module/plugins/hoster/UnrestrictLi.py b/module/plugins/hoster/UnrestrictLi.py index 2acb7816d..a2ee2a020 100644 --- a/module/plugins/hoster/UnrestrictLi.py +++ b/module/plugins/hoster/UnrestrictLi.py @@ -34,6 +34,7 @@ class UnrestrictLi(Hoster):          self.chunkLimit = 16          self.resumeDownload = True +      def process(self, pyfile):          if re.match(self.__pattern__, pyfile.url):              new_url = pyfile.url @@ -82,6 +83,7 @@ class UnrestrictLi(Hoster):              self.load("https://unrestrict.li/history/&delete=all")              self.logInfo("Download history deleted") +      def setNameSize(self):          if 'name' in self.api_data:              self.pyfile.name = self.api_data['name'] diff --git a/module/plugins/hoster/UploadedTo.py b/module/plugins/hoster/UploadedTo.py index 73a903902..764bb75de 100644 --- a/module/plugins/hoster/UploadedTo.py +++ b/module/plugins/hoster/UploadedTo.py @@ -119,6 +119,7 @@ class UploadedTo(Hoster):          self.fileID = getID(self.pyfile.url)          self.pyfile.url = "http://uploaded.net/file/%s" % self.fileID +      def process(self, pyfile):          self.load("http://uploaded.net/language/en", just_header=True) @@ -158,6 +159,7 @@ class UploadedTo(Hoster):          else:              self.handleFree() +      def handlePremium(self):          info = self.account.getAccountInfo(self.user, True)          self.logDebug("%(name)s: Use Premium Account (%(left)sGB left)" % {"name": self.__name__, @@ -183,6 +185,7 @@ class UploadedTo(Hoster):              print "Premium URL: " + url              self.download(url, post={}) +      def handleFree(self):          self.html = self.load(self.pyfile.url, decode=True) diff --git a/module/plugins/hoster/UploadheroCom.py b/module/plugins/hoster/UploadheroCom.py index 753ad6807..f2bcaea6a 100644 --- a/module/plugins/hoster/UploadheroCom.py +++ b/module/plugins/hoster/UploadheroCom.py @@ -58,12 +58,14 @@ class UploadheroCom(SimpleHoster):          self.download(download_url) +      def handlePremium(self):          self.logDebug("%s: Use Premium Account" % self.__name__)          link = re.search(self.PREMIUM_URL_PATTERN, self.html).group(1)          self.logDebug("Downloading link : '%s'" % link)          self.download(link) +      def checkErrors(self):          m = re.search(self.IP_BLOCKED_PATTERN, self.html)          if m: diff --git a/module/plugins/hoster/VeehdCom.py b/module/plugins/hoster/VeehdCom.py index f82d429d1..47f95ed41 100644 --- a/module/plugins/hoster/VeehdCom.py +++ b/module/plugins/hoster/VeehdCom.py @@ -22,10 +22,12 @@ class VeehdCom(Hoster):      def _debug(self, msg):          self.logDebug("[%s] %s" % (self.__name__, msg)) +      def setup(self):          self.multiDL = True          self.req.canContinue = True +      def process(self, pyfile):          self.download_html()          if not self.file_exists(): @@ -34,11 +36,13 @@ class VeehdCom(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      def download_html(self):          url = self.pyfile.url          self._debug("Requesting page: %s" % (repr(url),))          self.html = self.load(url) +      def file_exists(self):          if not self.html:              self.download_html() @@ -47,6 +51,7 @@ class VeehdCom(Hoster):              return False          return True +      def get_file_name(self):          if not self.html:              self.download_html() @@ -65,6 +70,7 @@ class VeehdCom(Hoster):          return re.sub(pattern, self.getConfig('replacement_char'), name) + '.avi' +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ diff --git a/module/plugins/hoster/VeohCom.py b/module/plugins/hoster/VeohCom.py index a4b94f40f..f35ed2510 100644 --- a/module/plugins/hoster/VeohCom.py +++ b/module/plugins/hoster/VeohCom.py @@ -30,6 +30,7 @@ class VeohCom(SimpleHoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = -1 +      def handleFree(self):          quality = self.getConfig("quality")          if quality == "Auto": diff --git a/module/plugins/hoster/VimeoCom.py b/module/plugins/hoster/VimeoCom.py index 2f554ee1b..8de7fad88 100644 --- a/module/plugins/hoster/VimeoCom.py +++ b/module/plugins/hoster/VimeoCom.py @@ -32,6 +32,7 @@ class VimeoCom(SimpleHoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = -1 +      def handleFree(self):          password = self.getPassword() diff --git a/module/plugins/hoster/WebshareCz.py b/module/plugins/hoster/WebshareCz.py index 6e0354d12..42f1e9a14 100644 --- a/module/plugins/hoster/WebshareCz.py +++ b/module/plugins/hoster/WebshareCz.py @@ -43,6 +43,7 @@ class WebshareCz(SimpleHoster):          self.logDebug("Direct link: " + direct)          self.download(direct, disposition=True) +      def getFileInfo(self):          self.logDebug("URL: %s" % self.pyfile.url) diff --git a/module/plugins/hoster/WrzucTo.py b/module/plugins/hoster/WrzucTo.py index 47731642d..896da1c1b 100644 --- a/module/plugins/hoster/WrzucTo.py +++ b/module/plugins/hoster/WrzucTo.py @@ -28,6 +28,7 @@ class WrzucTo(SimpleHoster):      def setup(self):          self.multiDL = True +      def handleFree(self):          data = dict(re.findall(r'(md5|file): "(.*?)"', self.html))          if len(data) != 2: diff --git a/module/plugins/hoster/XHamsterCom.py b/module/plugins/hoster/XHamsterCom.py index dae9a8eae..7257b2988 100644 --- a/module/plugins/hoster/XHamsterCom.py +++ b/module/plugins/hoster/XHamsterCom.py @@ -41,10 +41,12 @@ class XHamsterCom(Hoster):          pyfile.name = self.get_file_name() + self.desired_fmt          self.download(self.get_file_url()) +      def download_html(self):          url = self.pyfile.url          self.html = self.load(url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -94,6 +96,7 @@ class XHamsterCom(Hoster):          return long_url +      def get_file_name(self):          if not self.html:              self.download_html() @@ -114,6 +117,7 @@ class XHamsterCom(Hoster):          return name.group(1) +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/Xdcc.py b/module/plugins/hoster/Xdcc.py index db9c5edf9..244c3d7e2 100644 --- a/module/plugins/hoster/Xdcc.py +++ b/module/plugins/hoster/Xdcc.py @@ -33,6 +33,7 @@ class Xdcc(Hoster):          self.timeout = 30          self.multiDL = False +      def process(self, pyfile):          # change request type          self.req = pyfile.m.core.requestFactory.getRequest(self.__name__, type="XDCC") @@ -59,6 +60,7 @@ class Xdcc(Hoster):          self.fail("Server blocked our ip, retry again later manually") +      def doDownload(self, url):          self.pyfile.setStatus("waiting")  # real link diff --git a/module/plugins/hoster/YoupornCom.py b/module/plugins/hoster/YoupornCom.py index 37788b9f7..821a7a8d6 100644 --- a/module/plugins/hoster/YoupornCom.py +++ b/module/plugins/hoster/YoupornCom.py @@ -26,10 +26,12 @@ class YoupornCom(Hoster):          pyfile.name = self.get_file_name()          self.download(self.get_file_url()) +      def download_html(self):          url = self.pyfile.url          self.html = self.load(url, post={"user_choice": "Enter"}, cookies=False) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -38,6 +40,7 @@ class YoupornCom(Hoster):          return re.search(r'(http://download\.youporn\.com/download/\d+\?save=1)">', self.html).group(1) +      def get_file_name(self):          if not self.html:              self.download_html() @@ -45,6 +48,7 @@ class YoupornCom(Hoster):          file_name_pattern = r'<title>(.+) - '          return re.search(file_name_pattern, self.html).group(1).replace("&", "&").replace("/", "") + '.flv' +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/YourfilesTo.py b/module/plugins/hoster/YourfilesTo.py index 4487a728a..9de5929ff 100644 --- a/module/plugins/hoster/YourfilesTo.py +++ b/module/plugins/hoster/YourfilesTo.py @@ -25,6 +25,7 @@ class YourfilesTo(Hoster):          self.prepare()          self.download(self.get_file_url()) +      def prepare(self):          if not self.file_exists():              self.offline() @@ -36,6 +37,7 @@ class YourfilesTo(Hoster):          self.logDebug("%s: Waiting %d seconds." % (self.__name__, wait_time))          self.wait() +      def get_waiting_time(self):          if not self.html:              self.download_html() @@ -49,10 +51,12 @@ class YourfilesTo(Hoster):          return sec +      def download_html(self):          url = self.pyfile.url          self.html = self.load(url) +      def get_file_url(self):          """ returns the absolute downloadable filepath          """ @@ -64,12 +68,14 @@ class YourfilesTo(Hoster):          else:              self.fail("absolute filepath could not be found. offline? ") +      def get_file_name(self):          if not self.html:              self.download_html()          return re.search("<title>(.*)</title>", self.html).group(1) +      def file_exists(self):          """ returns True or False          """ diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py index 5eacdc738..f16e9ae43 100644 --- a/module/plugins/hoster/YoutubeCom.py +++ b/module/plugins/hoster/YoutubeCom.py @@ -16,6 +16,7 @@ def which(program):      Courtesy of http://stackoverflow.com/a/377028/675646""" +      def is_exe(fpath):          return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -85,6 +86,7 @@ class YoutubeCom(Hoster):      def setup(self):          self.resumeDownload = self.multiDL = True +      def process(self, pyfile):          pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)          html = self.load(pyfile.url, decode=True) diff --git a/module/plugins/hoster/ZDF.py b/module/plugins/hoster/ZDF.py index 83a3bd95c..274dd474a 100644 --- a/module/plugins/hoster/ZDF.py +++ b/module/plugins/hoster/ZDF.py @@ -29,15 +29,18 @@ class ZDF(Hoster):              any(f.text == "progressive" for f in video.iter("facet")),          ) +      @staticmethod      def video_valid(video):          return video.findtext("url").startswith("http") and video.findtext("url").endswith(".mp4") and \                 video.findtext("facets/facet").startswith("progressive") +      @staticmethod      def get_id(url):          return int(re.search(r"\D*(\d{4,})\D*", url).group(1)) +      def process(self, pyfile):          xml = fromstring(self.load(self.XML_API % self.get_id(pyfile.url))) diff --git a/module/plugins/hoster/ZeveraCom.py b/module/plugins/hoster/ZeveraCom.py index 5720579bb..9394a5c93 100644 --- a/module/plugins/hoster/ZeveraCom.py +++ b/module/plugins/hoster/ZeveraCom.py @@ -19,6 +19,7 @@ class ZeveraCom(Hoster):          self.resumeDownload = self.multiDL = True          self.chunkLimit = 1 +      def process(self, pyfile):          if not self.account:              self.logError(_("Please enter your %s account or deactivate this plugin") % "zevera.com") diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/AbstractExtractor.py index 2b21ee357..8282e6ff5 100644 --- a/module/plugins/internal/AbstractExtractor.py +++ b/module/plugins/internal/AbstractExtractor.py @@ -28,6 +28,7 @@ class AbtractExtractor:          """          return True +      @staticmethod      def getTargets(files_ids):          """ Filter suited targets from list of filename id tuple list @@ -36,6 +37,7 @@ class AbtractExtractor:          """          raise NotImplementedError +      def __init__(self, m, file, out, fullpath, overwrite, excludefiles, renice):          """Initialize extractor for specific file @@ -55,10 +57,12 @@ class AbtractExtractor:          self.renice = renice          self.files = []  #: Store extracted files here +      def init(self):          """ Initialize additional data structures """          pass +      def checkArchive(self):          """Check if password if needed. Raise ArchiveError if integrity is          questionable. @@ -68,6 +72,7 @@ class AbtractExtractor:          """          return False +      def checkPassword(self, password):          """ Check if the given password is/might be correct.          If it can not be decided at this point return true. @@ -77,6 +82,7 @@ class AbtractExtractor:          """          return True +      def extract(self, progress, password=None):          """Extract the archive. Raise specific errors in case of failure. @@ -89,6 +95,7 @@ class AbtractExtractor:          """          raise NotImplementedError +      def getDeleteFiles(self):          """Return list of files to delete, do *not* delete them here. @@ -96,6 +103,7 @@ class AbtractExtractor:          """          raise NotImplementedError +      def getExtractedFiles(self):          """Populate self.files at some point while extracting"""          return self.files diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py index 4ef43bc31..5aadf6f2e 100644 --- a/module/plugins/internal/MultiHoster.py +++ b/module/plugins/internal/MultiHoster.py @@ -28,6 +28,7 @@ class MultiHoster(Hook):          self.supported = []          self.new_supported = [] +      def getConfig(self, option, default=''):          """getConfig with default value - sublass may not implements all config options"""          try: @@ -35,6 +36,7 @@ class MultiHoster(Hook):          except KeyError:              return default +      def getHosterCached(self):          if not self.hosters: @@ -61,6 +63,7 @@ class MultiHoster(Hook):          return self.hosters +      def toHosterSet(self, hosters):          hosters = set((str(x).strip().lower() for x in hosters)) @@ -72,6 +75,7 @@ class MultiHoster(Hook):          hosters.discard('')          return hosters +      def getHoster(self):          """Load list of supported hoster @@ -79,6 +83,7 @@ class MultiHoster(Hook):          """          raise NotImplementedError +      def coreReady(self):          if self.cb:              self.core.scheduler.removeJob(self.cb) @@ -94,9 +99,11 @@ class MultiHoster(Hook):          else:              self.periodical() +      def initPeriodical(self):          pass +      def periodical(self):          """reload hoster list periodically"""          self.logInfo(_("Reloading supported hoster list")) @@ -112,6 +119,7 @@ class MultiHoster(Hook):              for hoster in old_supported:                  self.unloadHoster(hoster) +      def overridePlugins(self):          pluginMap = {}          for name in self.core.pluginManager.hosterPlugins.keys(): @@ -162,6 +170,7 @@ class MultiHoster(Hook):              dict['pattern'] = regexp              dict['re'] = re.compile(regexp) +      def unloadHoster(self, hoster):          dict = self.core.pluginManager.hosterPlugins[hoster]          if "module" in dict: @@ -171,6 +180,7 @@ class MultiHoster(Hook):              del dict['new_module']              del dict['new_name'] +      def unload(self):          """Remove override for all hosters. Scheduler job is removed by hookmanager"""          for hoster in self.supported: @@ -182,6 +192,7 @@ class MultiHoster(Hook):          dict['pattern'] = getattr(klass, "__pattern__", r'^unmatchable$')          dict['re'] = re.compile(dict['pattern']) +      def downloadFailed(self, pyfile):          """remove plugin override if download fails but not if file is offline/temp.offline"""          if pyfile.hasStatus("failed") and self.getConfig("unloadFailing", True): diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index 613ffce1f..6c00a2267 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -51,6 +51,7 @@ class SimpleCrypter(Crypter):      and its loadPage method: +        def loadPage(self, page_n):            return the html of the page number page_n      """ diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py index 52b4bca27..ec493bcd8 100644 --- a/module/plugins/internal/UnZip.py +++ b/module/plugins/internal/UnZip.py @@ -19,6 +19,7 @@ class UnZip(AbtractExtractor):      def checkDeps():          return sys.version_info[:2] >= (2, 6) +      @staticmethod      def getTargets(files_ids):          result = [] @@ -29,10 +30,12 @@ class UnZip(AbtractExtractor):          return result +      def extract(self, progress, password=None):          z = zipfile.ZipFile(self.file)          self.files = z.namelist()          z.extractall(self.out) +      def getDeleteFiles(self):          return [self.file] | 
