# -*- coding: UTF-8 -*- #/* # * Copyright (C) 2013 Libor Zoubek # * # * # * This Program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by # * the Free Software Foundation; either version 2, or (at your option) # * any later version. # * # * This Program is distributed in the hope that it will be useful, # * but WITHOUT ANY WARRANTY; without even the implied warranty of # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # * GNU General Public License for more details. # * # * You should have received a copy of the GNU General Public License # * along with this program; see the file COPYING. If not, write to # * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # * http://www.gnu.org/copyleft/gpl.html # * # */ import sys import urllib import ulozto_search query = "your_query" file_type = "documents|videos|images|archives|audios" # optional kwargs = { "insecure": False, # disables SSL check, optional, default False "includeApproximate": False # also return approximate results } #Python 2 try: import cookielib import urllib2 #import sys reload(sys) # Reload does the trick! sys.setdefaultencoding('UTF8') #Python 3 except: import http.cookiejar cookielib = http.cookiejar urllib2 = urllib.request import re,random,util,os,traceback import json from base64 import b64decode from provider import ContentProvider from provider import ResolveException from provider import cached def loadurl(url, req, headers=None): print (url) req = urllib.parse.urlencode(req).encode('utf-8') if headers: req = urllib.request.Request(url, req, headers=headers) else: req = urllib.request.Request(url, req) with urllib.request.urlopen(req) as f: try: if f.getcode()==200: response = f.read() return response except: return False class UloztoContentProvider(ContentProvider): def __init__(self,username=None,password=None,filter=None): ContentProvider.__init__(self,'ulozto.cz','https://www.ulozto.cz/',username,password,filter) self.search_type='' self.cp = urllib2.HTTPCookieProcessor(cookielib.LWPCookieJar()) self.rh = UloztoHTTPRedirectHandler() self.rh.throw = False self.rh.location = None self.init_urllib() def init_urllib(self): opener = urllib2.build_opener(self.cp,self.rh) urllib2.install_opener(opener) def capabilities(self): return ['login','search','resolve','categories'] def categories(self): result = [] if not self.login(): return result data = util.request(self.base_url+'m/'+self.username) fav = re.search('
  • [^\"]+)[^>]*>(?P[^<]+)',data,re.IGNORECASE|re.DOTALL) if fav: item = self.dir_item() item['url'] = '#fm#'+fav.group('url') item['title'] = fav.group('title') result.append(item) myfiles = re.search('<a class=\"fmHomeFolder.+?href=\"(?P<url>[^\"]+)[^>]*>(?P<title>[^<]+)',data,re.IGNORECASE|re.DOTALL) if myfiles: item = self.dir_item() item['url'] = '#fm#' + myfiles.group('url') item['title'] = myfiles.group('title') result.append(item) return result def search(self, keyword): #https://ulozto.sk/hledej?type=videos&q=matrix # brb = self.base_url+'hledej?'+self.search_type+'q='+urllib.parse.quote(keyword) # self.info (brb) # return self.list('https://ulozto.cz/hledej?'+self.search_type+'q='+urllib.parse.quote(keyword)) query = keyword l = ulozto_search.search(query, 1, file_type, **kwargs) return self.list( l ) def login(self): return True # if self.username and self.password and len(self.username)>0 and len(self.password)>0: # self.info('Login user=%s, pass=*****' % self.username) # self.rh.throw = False # page = util.request(self.base_url+'login?key=logreg')#.decode('utf-8-sig') # # headers = util.headers # self.info(page) # self.info(type(page)) # if page.find('href="/?do=web-logout') > 0: # self.info('Already logged in') # return True # data = util.substr(page,'<li class=\"menu-username','</li') # m = re.search('key=(?P<key>[^\"]+)\"',data,re.IGNORECASE | re.DOTALL) # token = re.search('<input type=\"hidden\" name=\"_token_\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) # self.info (token) # #if m and token: # if True: # #login_url = self.base_url+'login?key='+m.group('key')+'&do=loginForm-submit' # #login_url = self.base_url+'login?key=logreg' # # urllib.parse.urljoin("https://ulozto.net/login", url), # # post=inputs) # inputs = {'username' : self.username, # 'password' : self.password, # 'fakeUsername':'', # 'fakePassword':'', # 'login': '', # '_do': 'loginComponent-loginForm-form-submit', # } # data = util.post(self.base_url+'login&do=loginForm-submit', inputs) # #data = util.post('https://uloz.to/login&do=loginForm-submit', inputs) # #data = loadurl(self._url('login'), inputs, headers=headers) # self.info (data) # if data.find('href="/?do=web-logout') > 0: # self.info('Login successfull') # return True # self.info('Login failed') # return False def list_folder(self,url): self.login() result = [] page = util.request(self._url(url)) page = util.substr(page,'<div id=\"fmItems','</ul') for m in re.finditer('<div class=\"fmFolder(.+?)</em',page,re.IGNORECASE | re.DOTALL): data = m.group(1) item = self.dir_item() item['url'] = '#fm#' + re.search('data-href=\"([^\"]+)',data).group(1) item['title'] = re.search('data-name=\"([^\"]+)',data).group(1) item['img'] = re.search('<img src=\"([^\"]+)',data).group(1) result.append(item) for m in re.finditer('<div class=\"fmFile(.+?)</em>',page,re.IGNORECASE | re.DOTALL): data = m.group(1) item = self.video_item() item['url'] = re.search('data-href=\"([^\"]+)',data).group(1) item['title'] = '%s.%s' % (re.search('data-name=\"([^\"]+)',data).group(1),re.search('data-ext=\"([^\"]+)',data).group(1)) item['img'] = re.search('<img src=\"([^\"]+)',data).group(1) result.append(item) return result @cached(1) def list(self, url): self.info(url) # if url.find('#fm#') == 0: # return self.list_folder(url[5:]) # url = self._url(url) # # page = util.request(url,headers={'X-Requested-With':'XMLHttpRequest','Referer':url,'Cookie':'uloz-to-id=1561277170;'})#.decode('string-escape') # self.info(page) # # script = util.substr(page,'var kn','</script>') # keymap = None # key = None # # self.info(script) # # k = re.search(r'({.+?})',script) # # if k: # # keymap = util.json.loads(k.group(1)) # # j = re.search(r'ad.push\(\[kn, kn\["([^"]+)', script) # # if j: # # key = j.group(1) # # if not (j and k): # # self.error('error parsing page - unable to locate keys') # # return [] # keymap = json.loads(page) # burl = b64decode('I2h0dHA6Ly9kZWNyLWNlY2gucmhjbG91ZC5jb20vZGVjcnlwdC8/a2V5PSVzJnZhbHVlPSVz') # murl = b64decode('aHR0cDovL2RlY3ItY2VjaC5yaGNsb3VkLmNvbS9kZWNyeXB0Lw==') # result = [] # req = {'seed':keymap[key], 'values':keymap} # decr = json.loads(util.post_json(murl, req)) page = url result = [] for p in page: item = self.video_item() item['title'] = p['name'] item['url'] = p['link'] item['length'] = p['length'] item['size'] = p['size'] # div_media = util.substr(body, 'div class="media"', '<div class="tools">') # img_match = re.search(r'img src="([^"]+)', div_media) # if img_match: # item['img'] = "http:" + img_match.group(1) # time_match = re.search(r'<span>Čas</span>(.+)', div_media) # if time_match: # item['length'] = time_match.group(1).strip() # size_match = re.search(r'<span>Velikost</span>([^<]+)', div_media) # if size_match: # item['size'] = size_match.group(1).strip() self._filter(result, item) # for li in re.finditer('<div data-icon=\"(?P<key>[^\"]+)',page, re.IGNORECASE | re.DOTALL): # body = urllib.unquote(b64decode(decr[li.group('key')])) # div_name = util.substr(body, '<div class="name"', '</div>') # title_url_match = re.search(r'<a href="(?P<url>[^"]+)" title="(?P<title>[^"]+)', div_name) # if not title_url_match: # continue # item = self.video_item() # item['title'] = title_url_match.group('title') # item['url'] = title_url_match.group('url') # div_media = util.substr(body, 'div class="media"', '<div class="tools">') # img_match = re.search(r'img src="([^"]+)', div_media) # if img_match: # item['img'] = "http:" + img_match.group(1) # time_match = re.search(r'<span>Čas</span>(.+)', div_media) # if time_match: # item['length'] = time_match.group(1).strip() # size_match = re.search(r'<span>Velikost</span>([^<]+)', div_media) # if size_match: # item['size'] = size_match.group(1).strip() # self._filter(result,item) # page navigation # data = util.substr(page,'<div class=\"paginator','</div') # mnext = re.search('<a href=\"(?P<url>[^\"]+)\" class="next',data) # ulozto_search.search(query, file_type, **kwargs) # if mnext: # item = self.dir_item() # item['type'] = 'next' # item['url'] = util.decode_html(mnext.group('url')) # result.append(item) # mnext = re.search('page=(?P<id>[\d]+)', url) # # idx = url.find('page=') # # if idx != -1: # # st = url[idx + len('page='):] # if mnext: # s = int(mnext.group('id')) # url = re.sub(mnext.group(), 'page={}'.format(s+1), url) # item = self.dir_item() # item['type'] = 'next' # item['url'] = util.decode_html(url) # result.append(item) # return result @cached(48) def decr_url(self,url): if url.startswith('#'): ret = json.loads(util.request(url[1:])) #if ret.has_key('result'): if 'result' in ret.keys(): url = b64decode(ret['result']) url = self._url(url) return url def resolve(self,item,captcha_cb=None): item = item.copy() url = item['url'] if url.startswith('http://www.ulozto.sk'): url = self.base_url + url[20:] url = self.decr_url(url) url = self._url(url) if url.startswith('#'): util.error('[uloz.to] - url was not correctly decoded') return self.init_urllib() self.login() self.info('Resolving %s'% url) # if not item.has_key('vip'): if not 'vip' in item.keys(): item['vip'] = False vip = item['vip'] if vip: page = util.request(url) else: try: request = urllib2.Request(url) response = urllib2.urlopen(request) page = response.read().decode('utf-8') response.close() except urllib2.HTTPError as e: traceback.print_exc() return self.info( page ) if page.find('Stránka nenalezena!') > 0: self.error('page with movie was not found on server') return if vip: url = self._url('quickDownload/' + 'e2ZbEck4nD1E') self.info( url ) # data = util.substr(page,'<h3>Neomezené stahování</h3>','</div') # m = re.search('<a(.+?)href=\"(?P<url>[^\"#]+)\"',data,re.IGNORECASE | re.DOTALL) if url: try: self.rh.throw = True resp = urllib2.urlopen(urllib2.Request(url)) except RedirectionException: # this is what we need, our redirect handler raises this pass except urllib2.HTTPError: # this is not OK, something went wrong traceback.print_exc() self.error('Cannot resolve stream url, server did not redirected us') self.info('POST url:'+post_url) return stream = self.rh.location item['url'] = self._fix_stream_url(stream) item['surl'] = url return item else: # m = re.search('<form action="(?P<action>[^"]+)[^>]+class="jsFreeDownloadForm"', page) m = re.search('data-href=\"(/download-dialog/free/download\?fileSlug=\S+)\"', page) self.info (m) if m: self.info (m.group(1)) self.rh.throw = True stream_url = self._get_file_url_anonymous(page,self._url(m.group(1)),response.headers,captcha_cb) #stream_url = self._get_file_url_anonymous(page,self._url(m.group('action')),response.headers,captcha_cb) if stream_url: item['url'] = stream_url # free ulozto allows seeking but doesn't allow multiple connections. # kodi does this when seeking is possible so playback doesn't work. # To prevent from use of multiple connections we set header special for kodi # which disables seeking -> only one connection -> playback works, though we lose # seeking possibility. # more info - http://forum.kodi.tv/showthread.php?tid=236411 item['headers'] = {'seekable':'0'} item['surl'] = url return item def _get_file_url_anonymous(self,page,post_url,headers,captcha_cb): data = util.request(self._url('reloadXapca.php')) capdata = json.loads(data) captcha = capdata['image'] if not captcha.startswith('http'): captcha = 'http:' + captcha sound = capdata['sound'] if not sound.startswith('http'): sound = 'http:' + sound # ask callback to provide captcha code self.info('Asking for captcha img %s' % captcha) code = captcha_cb({'id':captcha,'img': captcha,'snd':sound}) if not code: self.info('Captcha not provided, done') return self.info( page ) ts = re.search('<input type=\"hidden\" name=\"ts\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) cid = re.search('<input type=\"hidden\" name=\"cid\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) sign = re.search('<input type=\"hidden\" name=\"sign\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) sign_a = re.search('<input type=\"hidden\" name=\"sign_a\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) has = capdata['hash'] salt = capdata['salt'] timestamp = capdata['timestamp'] token = re.search('<input type=\"hidden\" name=\"_token_\".+?value=\"([^\"]+)"',page,re.IGNORECASE | re.DOTALL) if not (sign and ts and cid and has and token): util.error('[uloz.to] - unable to parse required params from page, plugin needs fix') return request = { 'captcha_type':'xapca', 'hash':has, 'salt':salt, 'timestamp':timestamp, 'ts':ts.group(1), 'cid':'', 'sign':sign.group(1), 'sign_a':sign_a.group(1), 'captcha_value':code, '_do':'download-freeDownloadTab-freeDownloadForm-submit', '_token_':token.group(1), 'adi':'f' } req = urllib2.Request(post_url, urllib.urlencode(request)) req.add_header('User-Agent',util.UA) req.add_header('Referer',post_url) req.add_header('Accept','application/json') req.add_header('X-Requested-With','XMLHttpRequest') sessid=[] for cookie in re.finditer('(ULOSESSID=[^\;]+)',headers.get('Set-Cookie'),re.IGNORECASE | re.DOTALL): sessid.append(cookie.group(1)) req.add_header('Cookie','nomobile=1; uloztoid='+cid.group(1)+'; uloztoid2='+cid.group(1)+'; '+sessid[-1]) util.info(req.headers) util.info(request) try: resp = urllib2.urlopen(req) page = resp.read() headers = resp.headers except urllib2.HTTPError: # this is not OK, something went wrong traceback.print_exc() util.error('[uloz.to] cannot resolve stream url, server did not redirected us') util.info('[uloz.to] POST url:'+post_url) return try: result = json.loads(page) except: raise ResolveException('Unexpected error, addon needs fix') if not 'status' in result.keys(): raise ResolveException('Unexpected error, addon needs fix') if result['status'] == 'ok': return self._fix_stream_url(result['url']) elif result['status'] == 'error': # the only known state is wrong captcha for now util.error('Captcha validation failed, please try playing/downloading again') util.error(result) raise ResolveException('Captcha failed, try again') def _fix_stream_url(self,stream): index = stream.rfind('/') if index > 0: fn = stream[index:] index2 = fn.find('?') if index2 > 0: fn = urllib.quote(fn[:index2])+fn[index2:] else: fn = urllib.quote(fn) stream = stream[:index]+fn return stream def _regex(url): return re.search('(#(.*)|ulozto\.cz|uloz\.to)',url,re.IGNORECASE | re.DOTALL) class UloztoHTTPRedirectHandler(urllib2.HTTPRedirectHandler): def http_error_302(self, req, fp, code, msg, headers): if self.throw: self.location = headers.getheader('Location') raise RedirectionException() else: return urllib2.HTTPRedirectHandler.http_error_302(self,req,fp,code,msg,headers) class RedirectionException(Exception): pass