#!/usr/bin/env python # -*- coding: utf-8 -*- import re import string from module.plugins.Hoster import Hoster from module.plugins.ReCaptcha import ReCaptcha from module.plugins.Plugin import chunks from module.network.RequestFactory import getURL from module.common.json_layer import json_loads def getInfo(urls): for chunk in chunks(urls, 20): result = [] ids = dict() for url in chunk: id = getId(url) if id: ids[id] = url else: result.append((None, 0, 1, url)) if len(ids) > 0: check_url = "http://api.filesonic.com/link?method=getInfo&format=json&ids=" + ",".join(ids.keys()) response = json_loads(getURL(check_url, decode=True)) for item in response["FSApi_Link"]["getInfo"]["response"]["links"]: if item["status"] != "AVAILABLE": result.append((None, 0, 1, ids[str(item["id"])])) else: result.append((item["filename"], item["size"], 2, ids[str(item["id"])])) yield result def getId(url): match = re.search(FilesonicCom.FILE_ID_PATTERN, url) if match: return string.replace(match.group("id"), "/", "-") else: return None class FilesonicCom(Hoster): __name__ = "FilesonicCom" __type__ = "hoster" __pattern__ = r"http://[\w\.]*?(sharingmatrix|filesonic)\..*?/file/(([a-z][0-9]+/)?[0-9]+)(/.*)?" __version__ = "0.33" __description__ = """FilesonicCom und Sharingmatrix Download Hoster""" __author_name__ = ("jeix", "paulking") __author_mail__ = ("jeix@hasnomail.de", "") API_ADDRESS = "http://api.filesonic.com" URL_DOMAIN_PATTERN = r'(?P<prefix>.*?)(?P<domain>.(filesonic|sharingmatrix)\..+?)(?P<suffix>/.*)' FILE_ID_PATTERN = r'/file/(?P<id>([a-z][0-9]+/)?[0-9]+)(/.*)?' #change may break wupload - be careful FILE_LINK_PATTERN = r'<p><a href="(http://.+?\.(filesonic|sharingmatrix)\..+?)"><span>Start download' WAIT_TIME_PATTERN = r'countDownDelay = (?P<wait>\d+)' WAIT_TM_PATTERN = r"name='tm' value='(.*?)' />" WAIT_TM_HASH_PATTERN = r"name='tm_hash' value='(.*?)' />" CAPTCHA_TYPE1_PATTERN = r'Recaptcha.create\("(.*?)",' CAPTCHA_TYPE2_PATTERN = r'id="recaptcha_image"><img style="display: block;" src="(.+)image?c=(.+?)"' def init(self): if self.account: self.premium = self.account.getAccountInfo(self.user)["premium"] if not self.premium: self.chunkLimit = 1 self.multiDL = False def process(self, pyfile): self.pyfile = pyfile self.pyfile.url = self.checkFile(self.pyfile.url) if self.premium: self.downloadPremium() else: self.downloadFree() def checkFile(self, url): id = getId(url) self.logDebug("file id is %s" % id) if id: # Use the api to check the current status of the file and fixup data check_url = self.API_ADDRESS + "/link?method=getInfo&format=json&ids=%s" % id result = json_loads(self.load(check_url, decode=True)) item = result["FSApi_Link"]["getInfo"]["response"]["links"][0] self.logDebug("api check returns %s" % item) if item["status"] != "AVAILABLE": self.offline() if item["is_password_protected"] != 0: self.fail("This file is password protected") # ignored this check due to false api information #if item["is_premium_only"] != 0 and not self.premium: # self.fail("need premium account for file") self.pyfile.name = item["filename"] # Fix the url and resolve the domain to the correct regional variation url = item["url"] urlparts = re.search(self.URL_DOMAIN_PATTERN, url) if urlparts: url = urlparts.group("prefix") + self.getDomain() + urlparts.group("suffix") self.logDebug("localised url is %s" % url) return url else: self.fail("Invalid URL") def getDomain(self): result = json_loads( self.load(self.API_ADDRESS + "/utility?method=getFilesonicDomainForCurrentIp&format=json", decode=True)) self.logDebug("response to get domain %s" % result) return result["FSApi_Utility"]["getFilesonicDomainForCurrentIp"]["response"] def downloadPremium(self): self.logDebug("Premium download") api = self.API_ADDRESS + "/link?method=getDownloadLink&u=%%s&p=%%s&ids=%s" % getId(self.pyfile.url) result = json_loads(self.load(api % (self.user, self.account.getAccountData(self.user)["password"]))) links = result["FSApi_Link"]["getDownloadLink"]["response"]["links"] #wupload seems to return list and no dicts if type(links) == dict: info = links.values()[0] else: info = links[0] if "status" in info and info["status"] == "NOT_AVAILABLE": self.tempOffline() self.download(info["url"]) def downloadFree(self): self.logDebug("Free download") # Get initial page self.html = self.load(self.pyfile.url) url = self.pyfile.url + "?start=1" self.html = self.load(url) self.handleErrors() finalUrl = re.search(self.FILE_LINK_PATTERN, self.html) if not finalUrl: self.doWait(url) chall = re.search(self.CAPTCHA_TYPE1_PATTERN, self.html) chall2 = re.search(self.CAPTCHA_TYPE2_PATTERN, self.html) if chall or chall2: for i in range(5): re_captcha = ReCaptcha(self) if chall: self.logDebug("Captcha type1") challenge, result = re_captcha.challenge(chall.group(1)) else: self.logDebug("Captcha type2") server = chall2.group(1) challenge = chall2.group(2) result = re_captcha.result(server, challenge) postData = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": result} self.html = self.load(url, post=postData) self.handleErrors() chall = re.search(self.CAPTCHA_TYPE1_PATTERN, self.html) chall2 = re.search(self.CAPTCHA_TYPE2_PATTERN, self.html) if chall or chall2: self.invalidCaptcha() else: self.correctCaptcha() break finalUrl = re.search(self.FILE_LINK_PATTERN, self.html) if not finalUrl: self.fail("Couldn't find free download link") self.logDebug("got download url %s" % finalUrl.group(1)) self.download(finalUrl.group(1)) def doWait(self, url): # If the current page requires us to wait then wait and move to the next page as required # There maybe more than one wait period. The extended wait if download limits have been exceeded (in which case we try reconnect) # and the short wait before every download. Visually these are the same, the difference is that one includes a code to allow # progress to the next page waitSearch = re.search(self.WAIT_TIME_PATTERN, self.html) while waitSearch: wait = int(waitSearch.group("wait")) if wait > 300: self.wantReconnect = True self.setWait(wait) self.logDebug("Waiting %d seconds." % wait) self.wait() tm = re.search(self.WAIT_TM_PATTERN, self.html) tm_hash = re.search(self.WAIT_TM_HASH_PATTERN, self.html) if tm and tm_hash: tm = tm.group(1) tm_hash = tm_hash.group(1) self.html = self.load(url, post={"tm": tm, "tm_hash": tm_hash}) self.handleErrors() break else: self.html = self.load(url) self.handleErrors() waitSearch = re.search(self.WAIT_TIME_PATTERN, self.html) def handleErrors(self): if "This file is available for premium users only." in self.html: self.fail("need premium account for file") if "The file that you're trying to download is larger than" in self.html: self.fail("need premium account for file") if "Free users may only download 1 file at a time" in self.html: self.fail("only 1 file at a time for free users") if "Free user can not download files" in self.html: self.fail("need premium account for file") if "Download session in progress" in self.html: self.fail("already downloading") if "This file is password protected" in self.html: self.fail("This file is password protected") if "An Error Occurred" in self.html: self.fail("A server error occured.") if "This file was deleted" in self.html: self.offline()