diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..29440e1 --- /dev/null +++ b/__init__.py @@ -0,0 +1,5 @@ +#-*- coding: utf-8 -*- +''' + Torrenter v2 plugin for XBMC/Kodi + Copyright (C) 2015 DiMartino +''' \ No newline at end of file diff --git a/default.py b/default.py index 6bf8bb7..be0b316 100644 --- a/default.py +++ b/default.py @@ -1,40 +1,22 @@ # -*- coding: utf-8 -*- -import xbmcplugin, xbmcgui, os -from python_libtorrent.platform_pulsar import get_platform -from ctypes import * +from python_libtorrent import get_libtorrent, get_platform, log +import xbmcgui sucsess=False -dialog = xbmcgui.Dialog() +version='' p=get_platform() -ROOT_PATH=os.path.dirname(__file__) -dirname=os.path.join(ROOT_PATH, 'python_libtorrent', p['system']) -#dirname = os.path.join(xbmc.translatePath('special://home'), 'addons', 'script.module.libtorrent', -# 'python_libtorrent', platform['system']) -#sys.path.insert(0, dirname) +dialog = xbmcgui.Dialog() try: - import python_libtorrent as libtorrent + libtorrent=get_libtorrent() - print '[script.module.libtorrent]: Imported libtorrent v' + libtorrent.version + ' from python_libtorrent' + log('Imported libtorrent v' + libtorrent.version + ' from get_libtorrent()') + version=str(libtorrent.version) sucsess=True except Exception, e: - print '[script.module.libtorrent]: Error importing from system. Exception: ' + str(e) - -try: - cdll.LoadLibrary(dirname + '/libpython2.6.so') -except Exception, e: - print '[script.module.libtorrent]: Error importing from '+str(dirname)+'. Exception: ' + str(e) - -try: - cdll.LoadLibrary(dirname + '/libpython2.6.so') - cdll.LoadLibrary(dirname + '/libtorrent.so') - - print '[script.module.libtorrent]: Imported libtorrent v' + libtorrent.version + ' from cdll' - sucsess=True -except Exception, e: - print '[script.module.libtorrent]: Error importing from '+str(dirname)+'. Exception: ' + str(e) + log('Error importing from get_libtorrent(). Exception: ' + str(e)) -line2='WE DID IT! IMPORTED' if sucsess else 'Failed!' +line2='Python-libtorrent %s IMPORTED successfully' % version if sucsess else 'Failed to import python-libtorrent!' dialog.ok('Libtorrent','OS:'+p['os']+' arch:'+p['arch'], line2) \ No newline at end of file diff --git a/python_libtorrent/__init__.py b/python_libtorrent/__init__.py index b70e523..d094c20 100644 --- a/python_libtorrent/__init__.py +++ b/python_libtorrent/__init__.py @@ -20,7 +20,7 @@ dirname = os.path.join(xbmc.translatePath('special://temp'), 'xbmcup', 'script.m #dirname = os.path.join(xbmc.translatePath('special://home'), 'addons', 'script.module.libtorrent', # 'python_libtorrent') dest_path = os.path.join(dirname, platform['system']) -sys.path.insert(0, dirname) +sys.path.insert(0, dest_path) lm=LibraryManager(dest_path) if not lm.check_exist(): @@ -33,14 +33,8 @@ if __settings__.getSetting('plugin_name')!=__plugin__: log('platform ' + str(platform)) try: - if platform['system'] == 'darwin': - from darwin import libtorrent - elif platform['system'] == 'linux_x86': - from linux_x86 import libtorrent - elif platform['system'] == 'linux_x86_64': - from linux_x86_64 import libtorrent - elif platform['system'] == 'windows': - from windows import libtorrent + if platform['system'] in ['darwin', 'linux_x86', 'linux_x86_64', 'windows']: + import libtorrent elif platform['system'] == 'android' and platform['arch'] == 'arm': import imp from ctypes import * @@ -48,20 +42,19 @@ try: dll_path=os.path.join(dest_path, 'liblibtorrent.so') print "CDLL path = " + dll_path liblibtorrent=CDLL(dll_path) - print 'CDLL = ' + str(liblibtorrent) + log('CDLL = ' + str(liblibtorrent)) path_list = [dest_path] - print 'path_list = ' + str(path_list) + log('path_list = ' + str(path_list)) fp, pathname, description = imp.find_module('libtorrent', path_list) - print 'fp = ' + str(fp) - print 'pathname = ' + str(pathname) + log('fp = ' + str(fp)) + log('pathname = ' + str(pathname)) libtorrent = imp.load_module('libtorrent', fp, pathname, description) - print '[script.module.libtorrent]: Imported libtorrent v' + libtorrent.version + ' from python_libtorrent.' + platform[ - 'system'] + log('Imported libtorrent v' + libtorrent.version + ' from ' + dest_path) except Exception, e: - print '[script.module.libtorrent]: Error importing python_libtorrent.' + platform['system'] + '. Exception: ' + str(e) + log('Error importing libtorrent from' + dest_path + '. Exception: ' + str(e)) pass def get_libtorrent(): diff --git a/python_libtorrent/functions.py b/python_libtorrent/functions.py index 060c3da..641e376 100644 --- a/python_libtorrent/functions.py +++ b/python_libtorrent/functions.py @@ -1,8 +1,7 @@ import sys import os import xbmc, xbmcgui, xbmcvfs -import urllib - +from net import HTTP __libbaseurl__ = "https://github.com/DiMartinoXBMC/script.module.libtorrent/raw/master/python_libtorrent/" __scriptname__ = "script.module.libtorrent" @@ -15,30 +14,14 @@ class DownloaderClass(): self.platform = get_platform() tempdir(self.platform) - def download(self, url, dest): - self.dp = xbmcgui.DialogProgress() - self.dp.create("script.module.libtorrent","Downloading File", url) - urllib.urlretrieve(url, dest, lambda nb, bs, fs, url= url: self._pbhook(nb,bs,fs)) - - def _pbhook(self, numblocks, blocksize, filesize): - try: - percent = min((numblocks*blocksize*100)/filesize, 100) - self.dp.update(percent) - except: - percent = 100 - self.dp.update(percent) - log("libtorrent: DOWNLOAD FAILED") - if self.dp.iscanceled(): - log("libtorrent: DOWNLOAD CANCELLED") - self.dp.close() - def tools_download(self): - log("libtorrent: try to fetch libtorrent.so") for libname in get_libname(self.platform): - url = "%s/%s/%s.zip" % (__libbaseurl__, self.platform, libname) + log("try to fetch %s" % libname) + url = "%s/%s/%s.zip" % (__libbaseurl__, self.platform['system'], libname) dest = os.path.join(self.dest_path, libname) try: - self.download(url, dest + ".zip") + self.http = HTTP() + self.http.fetch(url, download=dest + ".zip", progress=True) log("%s -> %s" % (url, dest)) xbmc.executebuiltin('XBMC.Extract("%s.zip","%s")' % (dest, self.dest_path), True) xbmcvfs.delete(dest + ".zip") @@ -46,7 +29,6 @@ class DownloaderClass(): text = 'Failed!' xbmc.executebuiltin("XBMC.Notification(%s,%s,%s,%s)" % (__scriptname__,text,750,__icon__)) - def log(msg): xbmc.log("### [%s]: %s" % (__scriptname__,msg,), level=xbmc.LOGINFO ) #print "### [%s]: %s" % (__scriptname__,msg,) diff --git a/python_libtorrent/liblibtorrent.so.zip b/python_libtorrent/liblibtorrent.so.zip deleted file mode 100644 index 15cb0ec..0000000 Binary files a/python_libtorrent/liblibtorrent.so.zip and /dev/null differ diff --git a/python_libtorrent/libtorrent.so.zip b/python_libtorrent/libtorrent.so.zip deleted file mode 100644 index 15cb0ec..0000000 Binary files a/python_libtorrent/libtorrent.so.zip and /dev/null differ diff --git a/python_libtorrent/net.py b/python_libtorrent/net.py new file mode 100644 index 0000000..0836c4b --- /dev/null +++ b/python_libtorrent/net.py @@ -0,0 +1,297 @@ +# -*- coding: utf-8 -*- + +import os +import time +import re +import urllib +import urllib2 +import cookielib +import base64 +import mimetools +import itertools + +import xbmc +import xbmcgui +import xbmcvfs + +RE = { + 'content-disposition': re.compile('attachment;\sfilename="*([^"\s]+)"|\s') +} + +# ################################ +# +# HTTP +# +# ################################ + +class HTTP: + def __init__(self): + self._dirname = xbmc.translatePath('special://temp') + for subdir in ('xbmcup', 'script.module.libtorrent'): + self._dirname = os.path.join(self._dirname, subdir) + if not xbmcvfs.exists(self._dirname): + xbmcvfs.mkdir(self._dirname) + + def fetch(self, request, **kwargs): + self.con, self.fd, self.progress, self.cookies, self.request = None, None, None, None, request + + if not isinstance(self.request, HTTPRequest): + self.request = HTTPRequest(url=self.request, **kwargs) + + self.response = HTTPResponse(self.request) + + xbmc.log('XBMCup: HTTP: request: ' + str(self.request), xbmc.LOGDEBUG) + + try: + self._opener() + self._fetch() + except Exception, e: + xbmc.log('XBMCup: HTTP: ' + str(e), xbmc.LOGERROR) + if isinstance(e, urllib2.HTTPError): + self.response.code = e.code + self.response.error = e + else: + self.response.code = 200 + + if self.fd: + self.fd.close() + self.fd = None + + if self.con: + self.con.close() + self.con = None + + if self.progress: + self.progress.close() + self.progress = None + + self.response.time = time.time() - self.response.time + + xbmc.log('XBMCup: HTTP: response: ' + str(self.response), xbmc.LOGDEBUG) + + return self.response + + def _opener(self): + + build = [urllib2.HTTPHandler()] + + if self.request.redirect: + build.append(urllib2.HTTPRedirectHandler()) + + if self.request.proxy_host and self.request.proxy_port: + build.append(urllib2.ProxyHandler( + {self.request.proxy_protocol: self.request.proxy_host + ':' + str(self.request.proxy_port)})) + + if self.request.proxy_username: + proxy_auth_handler = urllib2.ProxyBasicAuthHandler() + proxy_auth_handler.add_password('realm', 'uri', self.request.proxy_username, + self.request.proxy_password) + build.append(proxy_auth_handler) + + if self.request.cookies: + self.request.cookies = os.path.join(self._dirname, self.request.cookies) + self.cookies = cookielib.MozillaCookieJar() + if os.path.isfile(self.request.cookies): + self.cookies.load(self.request.cookies) + build.append(urllib2.HTTPCookieProcessor(self.cookies)) + + urllib2.install_opener(urllib2.build_opener(*build)) + + def _fetch(self): + params = {} if self.request.params is None else self.request.params + + if self.request.upload: + boundary, upload = self._upload(self.request.upload, params) + req = urllib2.Request(self.request.url) + req.add_data(upload) + else: + + if self.request.method == 'POST': + if isinstance(params, dict) or isinstance(params, list): + params = urllib.urlencode(params) + req = urllib2.Request(self.request.url, params) + else: + req = urllib2.Request(self.request.url) + + for key, value in self.request.headers.iteritems(): + req.add_header(key, value) + + if self.request.upload: + req.add_header('Content-type', 'multipart/form-data; boundary=%s' % boundary) + req.add_header('Content-length', len(upload)) + + if self.request.auth_username and self.request.auth_password: + req.add_header('Authorization', 'Basic %s' % base64.encodestring( + ':'.join([self.request.auth_username, self.request.auth_password])).strip()) + + self.con = urllib2.urlopen(req, timeout=self.request.timeout) + # self.con = urllib2.urlopen(req) + self.response.headers = self._headers(self.con.info()) + + if self.request.download: + self._download() + else: + self.response.body = self.con.read() + + if self.request.cookies: + self.cookies.save(self.request.cookies) + + def _download(self): + fd = open(self.request.download, 'wb') + if self.request.progress: + self.progress = xbmcgui.DialogProgress() + self.progress.create(u'Download') + + bs = 1024 * 8 + size = -1 + read = 0 + name = None + + if self.request.progress: + if 'content-length' in self.response.headers: + size = int(self.response.headers['content-length']) + if 'content-disposition' in self.response.headers: + r = RE['content-disposition'].search(self.response.headers['content-disposition']) + if r: + name = urllib.unquote(r.group(1)) + + while 1: + buf = self.con.read(bs) + if buf == '': + break + read += len(buf) + fd.write(buf) + + if self.request.progress: + self.progress.update(*self._progress(read, size, name)) + + self.response.filename = self.request.download + + def _upload(self, upload, params): + res = [] + boundary = mimetools.choose_boundary() + part_boundary = '--' + boundary + + if params: + for name, value in params.iteritems(): + res.append([part_boundary, 'Content-Disposition: form-data; name="%s"' % name, '', value]) + + if isinstance(upload, dict): + upload = [upload] + + for obj in upload: + name = obj.get('name') + filename = obj.get('filename', 'default') + content_type = obj.get('content-type') + try: + body = obj['body'].read() + except AttributeError: + body = obj['body'] + + if content_type: + res.append([part_boundary, + 'Content-Disposition: file; name="%s"; filename="%s"' % (name, urllib.quote(filename)), + 'Content-Type: %s' % content_type, '', body]) + else: + res.append([part_boundary, + 'Content-Disposition: file; name="%s"; filename="%s"' % (name, urllib.quote(filename)), '', + body]) + + result = list(itertools.chain(*res)) + result.append('--' + boundary + '--') + result.append('') + return boundary, '\r\n'.join(result) + + def _headers(self, raw): + headers = {} + for line in raw.headers: + pair = line.split(':', 1) + if len(pair) == 2: + tag = pair[0].lower().strip() + value = pair[1].strip() + if tag and value: + headers[tag] = value + return headers + + def _progress(self, read, size, name): + res = [] + if size < 0: + res.append(1) + else: + res.append(int(float(read) / (float(size) / 100.0))) + if name: + res.append(u'File: ' + name) + if size != -1: + res.append(u'Size: ' + self._human(size)) + res.append(u'Load: ' + self._human(read)) + return res + + def _human(self, size): + human = None + for h, f in (('KB', 1024), ('MB', 1024 * 1024), ('GB', 1024 * 1024 * 1024), ('TB', 1024 * 1024 * 1024 * 1024)): + if size / f > 0: + human = h + factor = f + else: + break + if human is None: + return (u'%10.1f %s' % (size, u'byte')).replace(u'.0', u'') + else: + return u'%10.2f %s' % (float(size) / float(factor), human) + + +class HTTPRequest: + def __init__(self, url, method='GET', headers=None, cookies=None, params=None, upload=None, download=None, + progress=False, auth_username=None, auth_password=None, proxy_protocol='http', proxy_host=None, + proxy_port=None, proxy_username=None, proxy_password='', timeout=20.0, redirect=True, gzip=False): + if headers is None: + headers = {} + + self.url = url + self.method = method + self.headers = headers + + self.cookies = cookies + + self.params = params + + self.upload = upload + self.download = download + self.progress = progress + + self.auth_username = auth_username + self.auth_password = auth_password + + self.proxy_protocol = proxy_protocol + self.proxy_host = proxy_host + self.proxy_port = proxy_port + self.proxy_username = proxy_username + self.proxy_password = proxy_password + + self.timeout = timeout + + self.redirect = redirect + + self.gzip = gzip + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, ','.join('%s=%r' % i for i in self.__dict__.iteritems())) + + +class HTTPResponse: + def __init__(self, request): + self.request = request + self.code = None + self.headers = {} + self.error = None + self.body = None + self.filename = None + self.time = time.time() + + def __repr__(self): + args = ','.join('%s=%r' % i for i in self.__dict__.iteritems() if i[0] != 'body') + if self.body: + args += ',body=' + else: + args += ',body=None' + return '%s(%s)' % (self.__class__.__name__, args)