diff options
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] |