# -*- coding: utf-8 -*- import random import re import time from Crypto.Cipher import ARC4 from binascii import hexlify, unhexlify from pycurl import HTTPHEADER from urllib import quote from module.network.RequestFactory import getURL from module.plugins.internal.CaptchaService import ReCaptcha from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp class TurbobitNet(SimpleHoster): __name__ = "TurbobitNet" __type__ = "hoster" __version__ = "0.11" __pattern__ = r'http://(?:www\.)?(turbobit.net|unextfiles.com)/(?!download/folder/)(?:download/free/)?(?P<ID>\w+).*' __description__ = """Turbobit.net plugin""" __author_name__ = "zoidberg" __author_mail__ = "zoidberg@mujmail.cz" FILE_INFO_PATTERN = r"<span class='file-icon1[^>]*>(?P<N>[^<]+)</span>\s*\((?P<S>[^\)]+)\)\s*</h1>" #: long filenames are shortened FILE_NAME_PATTERN = r'<meta name="keywords" content="\s+(?P<N>[^,]+)' #: full name but missing on page2 OFFLINE_PATTERN = r'<h2>File Not Found</h2>|html\(\'File (?:was )?not found' FILE_URL_REPLACEMENTS = [(r"http://(?:www\.)?(turbobit.net|unextfiles.com)/(?:download/free/)?(?P<ID>\w+).*", "http://turbobit.net/\g<ID>.html")] SH_COOKIES = [(".turbobit.net", "user_lang", "en")] LINK_PATTERN = r'(?P<url>/download/redirect/[^"\']+)' LIMIT_WAIT_PATTERN = r'<div id="time-limit-text">\s*.*?<span id=\'timeout\'>(\d+)</span>' CAPTCHA_KEY_PATTERN = r'src="http://api\.recaptcha\.net/challenge\?k=([^"]+)"' CAPTCHA_SRC_PATTERN = r'<img alt="Captcha" src="(.*?)"' def handleFree(self): self.url = "http://turbobit.net/download/free/%s" % self.file_info['ID'] self.html = self.load(self.url) rtUpdate = self.getRtUpdate() self.solveCaptcha() self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) self.url = self.getDownloadUrl(rtUpdate) self.wait() self.html = self.load(self.url) self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) self.downloadFile() def solveCaptcha(self): for _ in xrange(5): m = re.search(self.LIMIT_WAIT_PATTERN, self.html) if m: wait_time = int(m.group(1)) self.wait(wait_time, wait_time > 60) self.retry() action, inputs = self.parseHtmlForm("action='#'") if not inputs: self.parseError("captcha form") self.logDebug(inputs) if inputs['captcha_type'] == 'recaptcha': recaptcha = ReCaptcha(self) m = re.search(self.CAPTCHA_KEY_PATTERN, self.html) captcha_key = m.group(1) if m else '6LcTGLoSAAAAAHCWY9TTIrQfjUlxu6kZlTYP50_c' inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge( captcha_key) else: m = re.search(self.CAPTCHA_SRC_PATTERN, self.html) if m is None: self.parseError('captcha') captcha_url = m.group(1) inputs['captcha_response'] = self.decryptCaptcha(captcha_url) self.logDebug(inputs) self.html = self.load(self.url, post=inputs) if not "<div class='download-timer-header'>" in self.html: self.invalidCaptcha() else: self.correctCaptcha() break else: self.fail("Invalid captcha") def getRtUpdate(self): rtUpdate = self.getStorage("rtUpdate") if not rtUpdate: if self.getStorage("version") != self.__version__ or int( self.getStorage("timestamp", 0)) + 86400000 < timestamp(): # that's right, we are even using jdownloader updates rtUpdate = getURL("http://update0.jdownloader.org/pluginstuff/tbupdate.js") rtUpdate = self.decrypt(rtUpdate.splitlines()[1]) # but we still need to fix the syntax to work with other engines than rhino rtUpdate = re.sub(r'for each\(var (\w+) in(\[[^\]]+\])\)\{', r'zza=\2;for(var zzi=0;zzi<zza.length;zzi++){\1=zza[zzi];', rtUpdate) rtUpdate = re.sub(r"for\((\w+)=", r"for(var \1=", rtUpdate) self.logDebug("rtUpdate") self.setStorage("rtUpdate", rtUpdate) self.setStorage("timestamp", timestamp()) self.setStorage("version", self.__version__) else: self.logError("Unable to download, wait for update...") self.tempOffline() return rtUpdate def getDownloadUrl(self, rtUpdate): self.req.http.lastURL = self.url m = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html) url = "http://turbobit.net%s%s" % (m.groups() if m else ( '/files/timeout.js?ver=', ''.join(random.choice('0123456789ABCDEF') for _ in xrange(32)))) fun = self.load(url) self.setWait(65, False) for b in [1, 3]: self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % ( self.file_info['ID'], b, quote(fun), rtUpdate) try: out = self.js.eval(self.jscode) self.logDebug("URL", self.js.engine, out) if out.startswith('/download/'): return "http://turbobit.net%s" % out.strip() except Exception, e: self.logError(e) else: if self.retries >= 2: # retry with updated js self.delStorage("rtUpdate") self.retry() def decrypt(self, data): cipher = ARC4.new(hexlify('E\x15\xa1\x9e\xa3M\xa0\xc6\xa0\x84\xb6H\x83\xa8o\xa0')) return unhexlify(cipher.encrypt(unhexlify(data))) def getLocalTimeString(self): lt = time.localtime() tz = time.altzone if lt.tm_isdst else time.timezone return "%s GMT%+03d%02d" % (time.strftime("%a %b %d %Y %H:%M:%S", lt), -tz // 3600, tz % 3600) def handlePremium(self): self.logDebug("Premium download as user %s" % self.user) self.html = self.load(self.pyfile.url) # Useless in 0.5 self.downloadFile() def downloadFile(self): m = re.search(self.LINK_PATTERN, self.html) if m is None: self.parseError("download link") self.url = "http://turbobit.net" + m.group('url') self.logDebug(self.url) self.download(self.url) getInfo = create_getInfo(TurbobitNet)