test
This commit is contained in:
469
resources/lib/ulozto.py
Normal file
469
resources/lib/ulozto.py
Normal file
@@ -0,0 +1,469 @@
|
||||
# -*- 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('<li id=\"fmFavoritesFolder.+?href=\"(?P<url>[^\"]+)[^>]*>(?P<title>[^<]+)',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
|
||||
|
||||
Reference in New Issue
Block a user