parent
e5bd0ca668
commit
baf6d0c369
78
addon.py
78
addon.py
|
@ -1,13 +1,17 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
import xbmc
|
||||||
|
import xbmcgui
|
||||||
from codequick import Route, Script, Listitem, utils, run # @UnresolvedImport
|
from codequick import Route, Script, Listitem, utils, run # @UnresolvedImport
|
||||||
from codequick.storage import PersistentList # @UnresolvedImport
|
from codequick.storage import PersistentList # @UnresolvedImport
|
||||||
import os.path
|
|
||||||
import xbmcgui, xbmc
|
|
||||||
from resources.lib.searchers import rutor, kinozal, rutracker
|
|
||||||
from resources.lib.utils import localize, store_torrent_file, get_engine
|
|
||||||
from resources.lib.overrrides.session import torrent_file_fetch
|
from resources.lib.overrrides.session import torrent_file_fetch
|
||||||
from resources.lib.player import VideoLoop
|
from resources.lib.player import VideoLoop
|
||||||
|
from resources.lib.searchers import rutor, kinozal, rutracker
|
||||||
|
from resources.lib.utils import localize, store_torrent_file, get_engine
|
||||||
|
|
||||||
video_extensions = ('.mp4', '.avi', '.3gp', '.ogv', '.mkv', '.ts', '.mpg', '.mpeg', '.webm', '.flv', '.vob')
|
video_extensions = ('.mp4', '.avi', '.3gp', '.ogv', '.mkv', '.ts', '.mpg', '.mpeg', '.webm', '.flv', '.vob')
|
||||||
|
|
||||||
|
@ -15,31 +19,37 @@ search_engines = [
|
||||||
rutor.SearchEngine,
|
rutor.SearchEngine,
|
||||||
kinozal.SearchEngine,
|
kinozal.SearchEngine,
|
||||||
rutracker.SearchEngine
|
rutracker.SearchEngine
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT = os.path.abspath(os.path.dirname(__file__))
|
ROOT = os.path.abspath(os.path.dirname(__file__))
|
||||||
ICON_DIR = os.path.join(ROOT, 'resources', 'icons')
|
ICON_DIR = os.path.join(ROOT, 'resources', 'icons')
|
||||||
|
|
||||||
|
|
||||||
@Route.register
|
@Route.register
|
||||||
def root(plugin, content_type='video'):
|
def root(plugin, content_type='video'):
|
||||||
@Route.register_delayed
|
@Route.register_delayed
|
||||||
def set_view():
|
def set_view():
|
||||||
xbmc.executebuiltin('Container.SetViewMode("500")')
|
xbmc.executebuiltin('Container.SetViewMode("500")')
|
||||||
|
|
||||||
def build_item(a):
|
def build_item(a):
|
||||||
cb, name, image = a
|
cb, name, image = a
|
||||||
i = Listitem.from_dict(cb, name)
|
i = Listitem.from_dict(cb, name)
|
||||||
i.art.local_thumb(image)
|
i.art.local_thumb(image)
|
||||||
return i
|
return i
|
||||||
return map(build_item, (
|
|
||||||
|
for li in (
|
||||||
(search_history, localize(33052), 'history2.png'),
|
(search_history, localize(33052), 'history2.png'),
|
||||||
(new_search, localize(33053), 'search.png')
|
(new_search, localize(33053), 'search.png')):
|
||||||
))
|
yield build_item(li)
|
||||||
|
|
||||||
|
|
||||||
@Route.register
|
@Route.register
|
||||||
def search_history(plugin):
|
def search_history(plugin):
|
||||||
try:
|
try:
|
||||||
@Route.register_delayed
|
@Route.register_delayed
|
||||||
def set_view():
|
def set_view():
|
||||||
xbmc.executebuiltin('Container.SetViewMode("51")')
|
xbmc.executebuiltin('Container.SetViewMode("51")')
|
||||||
|
|
||||||
h_list = PersistentList('search_history')
|
h_list = PersistentList('search_history')
|
||||||
for i in h_list:
|
for i in h_list:
|
||||||
item = Listitem.from_dict(search, i, params={'search_query': i})
|
item = Listitem.from_dict(search, i, params={'search_query': i})
|
||||||
|
@ -49,18 +59,23 @@ def search_history(plugin):
|
||||||
yield None
|
yield None
|
||||||
except:
|
except:
|
||||||
yield False
|
yield False
|
||||||
|
|
||||||
|
|
||||||
@Route.register
|
@Route.register
|
||||||
def new_search(plugin):
|
def new_search(plugin):
|
||||||
q = utils.keyboard('Поиск')
|
q = utils.keyboard('Поиск')
|
||||||
if not q:
|
if not q:
|
||||||
return False
|
return False
|
||||||
return search(plugin, q)
|
return search(plugin, q)
|
||||||
|
|
||||||
|
|
||||||
@Route.register
|
@Route.register
|
||||||
def search(plugin, search_query, thumb=None):
|
def search(plugin, search_query, thumb=None):
|
||||||
try:
|
try:
|
||||||
@Route.register_delayed
|
@Route.register_delayed
|
||||||
def set_view():
|
def set_view():
|
||||||
xbmc.executebuiltin('Container.SetViewMode("51")')
|
xbmc.executebuiltin('Container.SetViewMode("51")')
|
||||||
|
|
||||||
with PersistentList('search_history') as h_list:
|
with PersistentList('search_history') as h_list:
|
||||||
if search_query in h_list:
|
if search_query in h_list:
|
||||||
del h_list[h_list.index(search_query)]
|
del h_list[h_list.index(search_query)]
|
||||||
|
@ -69,16 +84,20 @@ def search(plugin, search_query, thumb=None):
|
||||||
found_items = []
|
found_items = []
|
||||||
progress.create(localize(33054))
|
progress.create(localize(33054))
|
||||||
search_in = list(filter(lambda x: x.enabled, search_engines))
|
search_in = list(filter(lambda x: x.enabled, search_engines))
|
||||||
for p, se in zip(range(0, 100, 100 / len(search_in)), search_in):
|
for p, se in zip(range(0, 100, 100 // len(search_in)), search_in):
|
||||||
progress.update(p, line1=se.name)
|
progress.update(p, se.name)
|
||||||
found_items.extend(se().search(search_query))
|
found_items.extend(se().search(search_query))
|
||||||
#open('/tmp/t.t', 'w').write(repr(list(map(lambda x: x.url, found_items))))
|
# open('/tmp/t.t', 'w').write(repr(list(map(lambda x: x.url, found_items))))
|
||||||
res_items = []
|
res_items = []
|
||||||
for i in sorted(found_items, key=lambda x: x.seeders, reverse=True):
|
for i in sorted(found_items, key=lambda x: x.seeders, reverse=True):
|
||||||
if '2160p' in i.title: hd = '[2160p/{}] '.format(i.size)
|
if '2160p' in i.title:
|
||||||
elif '1080p' in i.title: hd = '[1080p/{}] '.format(i.size)
|
hd = '[2160p/{}] '.format(i.size)
|
||||||
elif '720p' in i.title: hd = '[720p/{}] '.format(i.size)
|
elif '1080p' in i.title:
|
||||||
else: hd = ''
|
hd = '[1080p/{}] '.format(i.size)
|
||||||
|
elif '720p' in i.title:
|
||||||
|
hd = '[720p/{}] '.format(i.size)
|
||||||
|
else:
|
||||||
|
hd = ''
|
||||||
item = Listitem.from_dict(
|
item = Listitem.from_dict(
|
||||||
open_torrent,
|
open_torrent,
|
||||||
'{}{} {} ({}/{})'.format(hd, i.title, i.size, i.seeders, i.leachers),
|
'{}{} {} ({}/{})'.format(hd, i.title, i.size, i.seeders, i.leachers),
|
||||||
|
@ -93,6 +112,8 @@ def search(plugin, search_query, thumb=None):
|
||||||
return res_items
|
return res_items
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@Route.register
|
@Route.register
|
||||||
def open_torrent(plugin, url='--back--', cookies={}, referer='', path=''):
|
def open_torrent(plugin, url='--back--', cookies={}, referer='', path=''):
|
||||||
try:
|
try:
|
||||||
|
@ -103,18 +124,23 @@ def open_torrent(plugin, url='--back--', cookies={}, referer='', path=''):
|
||||||
@Route.register_delayed
|
@Route.register_delayed
|
||||||
def set_view():
|
def set_view():
|
||||||
xbmc.executebuiltin('Container.SetViewMode("51")')
|
xbmc.executebuiltin('Container.SetViewMode("51")')
|
||||||
|
|
||||||
tf = torrent_file_fetch(url, referer, cookies)
|
tf = torrent_file_fetch(url, referer, cookies)
|
||||||
if not tf: yield False
|
if not tf:
|
||||||
|
yield False
|
||||||
t_full_path = store_torrent_file(tf)
|
t_full_path = store_torrent_file(tf)
|
||||||
e = get_engine(t_full_path)
|
e = get_engine(t_full_path)
|
||||||
files = sorted(list(filter(
|
files = sorted(list(filter(
|
||||||
lambda x: x.name.decode('utf-8').startswith(path) and x.name.decode('utf-8').lower().endswith(video_extensions), e.list_from_info(media_types=['video']))),
|
lambda x: x.name.startswith(path) and x.name.lower().endswith(
|
||||||
|
video_extensions), e.list_from_info(media_types=['video']))),
|
||||||
key=lambda x: x.name)
|
key=lambda x: x.name)
|
||||||
dirs = list(set(list(map( lambda x: x.name.decode('utf-8')[len(path):].lstrip('/').split('/')[0], filter( lambda x: len(x.name.decode('utf-8')[len(path):].lstrip('/').split('/')) > 1, files ) ))))
|
dirs = list(set(list(map(lambda x: x.name[len(path):].lstrip('/').split('/')[0], filter(
|
||||||
|
lambda x: len(x.name[len(path):].lstrip('/').split('/')) > 1, files)))))
|
||||||
for d in sorted(dirs):
|
for d in sorted(dirs):
|
||||||
item = Listitem.from_dict(open_torrent,
|
item = Listitem.from_dict(open_torrent,
|
||||||
d,
|
d,
|
||||||
params={'url': url, 'cookies': cookies, 'referer': referer, 'path': '{}/{}'.format(
|
params={'url': url, 'cookies': cookies, 'referer': referer,
|
||||||
|
'path': '{}/{}'.format(
|
||||||
path, d
|
path, d
|
||||||
) if path != '' else d}
|
) if path != '' else d}
|
||||||
)
|
)
|
||||||
|
@ -122,10 +148,10 @@ def open_torrent(plugin, url='--back--', cookies={}, referer='', path=''):
|
||||||
yield item
|
yield item
|
||||||
for i in range(len(files)):
|
for i in range(len(files)):
|
||||||
f = files[i]
|
f = files[i]
|
||||||
p = f.name.decode('utf-8')[len(path):].lstrip('/').split('/')
|
p = f.name[len(path):].lstrip('/').split('/')
|
||||||
if len(p) == 1:
|
if len(p) == 1:
|
||||||
item = Listitem.from_dict(play_file,
|
item = Listitem.from_dict(play_file,
|
||||||
'{} ({:.3f} GB)'.format(p[0], f.size / 1024.0 / 1024.0 /1024.0),
|
'{} ({:.3f} GB)'.format(p[0], f.size / 1024.0 / 1024.0 / 1024.0),
|
||||||
params={'t_full_path': t_full_path, 'f_index': f.index}
|
params={'t_full_path': t_full_path, 'f_index': f.index}
|
||||||
)
|
)
|
||||||
item.art.local_thumb('video.png')
|
item.art.local_thumb('video.png')
|
||||||
|
@ -134,6 +160,8 @@ def open_torrent(plugin, url='--back--', cookies={}, referer='', path=''):
|
||||||
yield None
|
yield None
|
||||||
except:
|
except:
|
||||||
yield False
|
yield False
|
||||||
|
|
||||||
|
|
||||||
@Script.register
|
@Script.register
|
||||||
def play_file(plugin, t_full_path, f_index):
|
def play_file(plugin, t_full_path, f_index):
|
||||||
try:
|
try:
|
||||||
|
@ -141,6 +169,14 @@ def play_file(plugin, t_full_path, f_index):
|
||||||
vl.start(f_index)
|
vl.start(f_index)
|
||||||
return False
|
return False
|
||||||
except:
|
except:
|
||||||
|
|
||||||
|
# todo
|
||||||
|
import traceback
|
||||||
|
xbmc.log(f'PLAY exception: {traceback.format_exc()}')
|
||||||
|
#
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run()
|
run()
|
||||||
|
|
13
addon.xml
13
addon.xml
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.torrenter3" name="Torrenter3" provider-name="inpos" version="3.2.1">
|
<addon id="plugin.video.torrenter3" name="Torrenter3" provider-name="inpos" version="3.3.0">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.25.0"/>
|
<import addon="xbmc.python" version="3.0.0"/>
|
||||||
<import addon="script.module.pyrrent2http" version="1.0.0"/>
|
<import addon="script.module.pyrrent2http" version="1.1.0"/>
|
||||||
<import addon="script.module.codequick" version="0.9.6"/>
|
<import addon="script.module.codequick" version="1.0.2"/>
|
||||||
<import addon="script.module.pysocks" version="1.0.0"/>
|
<import addon="script.module.htmlement" version="1.0.0"/>
|
||||||
<import addon="script.module.win_inet_pton" version="1.0.0"/>
|
<import addon="script.module.requests" version="2.22.0"/>
|
||||||
</requires>
|
</requires>
|
||||||
<extension point="xbmc.python.pluginsource" library="addon.py">
|
<extension point="xbmc.python.pluginsource" library="addon.py">
|
||||||
<provides>video</provides>
|
<provides>video</provides>
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
<email>roman@ukamnya.ru</email>
|
<email>roman@ukamnya.ru</email>
|
||||||
<platform>all</platform>
|
<platform>all</platform>
|
||||||
<language>en_GB ru_RU</language>
|
<language>en_GB ru_RU</language>
|
||||||
|
<news>- 3.3.0: Support for Kodi 19</news>
|
||||||
<news>- 3.2.1: Fix wrong torrent size for rutracker</news>
|
<news>- 3.2.1: Fix wrong torrent size for rutracker</news>
|
||||||
<news>- 3.2.0: Add searcher rutracker.org. Add socks-proxy for trackers</news>
|
<news>- 3.2.0: Add searcher rutracker.org. Add socks-proxy for trackers</news>
|
||||||
<news>- 3.1.0: Add searcher kinozal.tv</news>
|
<news>- 3.1.0: Add searcher kinozal.tv</news>
|
||||||
|
|
|
@ -1,85 +1,28 @@
|
||||||
import urlquick # @UnresolvedImport
|
from typing import Optional
|
||||||
|
|
||||||
from ..settings import option
|
from ..settings import option
|
||||||
import socks
|
import requests
|
||||||
|
|
||||||
class SocksiPyConnection(urlquick.HTTPConnection):
|
|
||||||
def __init__(self, proxytype, proxyaddr, proxyport=None, host='127.0.0.1', port=9050, rdns=True, username=None, password=None, **kwargs):
|
|
||||||
self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
|
|
||||||
urlquick.HTTPConnection.__init__(self, host, port=port, **kwargs)
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
self.sock = socks.socksocket()
|
|
||||||
self.sock.setproxy(*self.proxyargs)
|
|
||||||
if type(self.timeout) in (int, float):
|
|
||||||
self.sock.settimeout(self.timeout)
|
|
||||||
self.sock.connect((self.host, self.port))
|
|
||||||
|
|
||||||
class SocksiPyConnectionS(urlquick.HTTPSConnection):
|
|
||||||
def __init__(self, proxytype, proxyaddr, proxyport=None, host='127.0.0.1', port=9050, rdns=True, username=None, password=None, **kwargs):
|
|
||||||
self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
|
|
||||||
urlquick.HTTPSConnection.__init__(self, host, port=port, **kwargs)
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
sock = socks.socksocket()
|
|
||||||
sock.setproxy(*self.proxyargs)
|
|
||||||
if type(self.timeout) in (int, float):
|
|
||||||
sock.settimeout(self.timeout)
|
|
||||||
sock.connect((self.host, self.port))
|
|
||||||
self.sock = urlquick.ssl.wrap_socket(sock, self.key_file, self.cert_file)
|
|
||||||
|
|
||||||
class Session(urlquick.Session):
|
|
||||||
def connect(self, req, timeout, verify):
|
|
||||||
# Fetch connection from pool and attempt to reuse if available
|
|
||||||
pool = self.request_handler[req.type]
|
|
||||||
if req.host in pool:
|
|
||||||
try:
|
|
||||||
# noinspection PyTypeChecker
|
|
||||||
return self.send_request(pool[req.host], req)
|
|
||||||
except Exception as e:
|
|
||||||
# Remove the connection from the pool as it's unusable
|
|
||||||
pool[req.host].close()
|
|
||||||
del pool[req.host]
|
|
||||||
|
|
||||||
# Raise the exception if it's not a subclass of UrlError
|
|
||||||
if not isinstance(e, urlquick.UrlError):
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
host_port = req.host.split(':')
|
|
||||||
host = host_port[0]
|
|
||||||
port = int(host_port[2]) if len(host_port) > 1 else 443 if req.type == 'https' else 80
|
|
||||||
# Create a new connection
|
|
||||||
if not option.get_boolean('use_socks'): # @UndefinedVariable
|
|
||||||
if req.type == "https":
|
|
||||||
context = urlquick.ssl._create_unverified_context() if verify is False else None
|
|
||||||
conn = urlquick.HTTPSConnection(host, port, timeout=timeout, context=context)
|
|
||||||
else:
|
|
||||||
conn = urlquick.HTTPConnection(host, port, timeout=timeout)
|
|
||||||
else:
|
|
||||||
if req.type == "https":
|
|
||||||
context = urlquick.ssl._create_unverified_context() if verify is False else None
|
|
||||||
conn = SocksiPyConnectionS(socks.PROXY_TYPE_SOCKS5, option['socks_ip'], proxyport=int(option['socks_port']),
|
|
||||||
host=host, port=port, timeout=timeout, context=context)
|
|
||||||
else:
|
|
||||||
conn = SocksiPyConnection(socks.PROXY_TYPE_SOCKS5, option['socks_ip'], proxyport=int(option['socks_port']),
|
|
||||||
host=host, port=port, timeout=timeout)
|
|
||||||
|
|
||||||
# Make first connection to server
|
|
||||||
response = self.send_request(conn, req)
|
|
||||||
|
|
||||||
# Add connection to the pool if the response is not set to close
|
|
||||||
if not response.will_close:
|
|
||||||
pool[req.host] = conn
|
|
||||||
return response
|
|
||||||
def torrent_file_fetch(url, referer, cookies):
|
def torrent_file_fetch(url, referer, cookies):
|
||||||
sess = Session()
|
|
||||||
headers = {
|
headers = {
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 YaBrowser/14.10.2062.12061 Safari/537.36',
|
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||||
|
'Chrome/37.0.2062.124 YaBrowser/14.10.2062.12061 Safari/537.36',
|
||||||
'Referer': referer
|
'Referer': referer
|
||||||
}
|
}
|
||||||
resp = sess.get(url, cookies=cookies, headers=headers)
|
|
||||||
|
resp = requests.get(url, cookies=cookies, headers=headers, proxies=proxies())
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
return resp.content
|
return resp.content
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def proxies():
|
||||||
|
if option.get_boolean('use_socks'):
|
||||||
|
return {
|
||||||
|
'http': f'socks5://{option["socks_ip"]}:{option["socks_port"]}',
|
||||||
|
'https': f'socks5://{option["socks_ip"]}:{option["socks_port"]}'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
import xbmc, xbmcgui
|
import xbmc, xbmcgui
|
||||||
from .utils import get_engine, localize
|
from .utils import get_engine, localize
|
||||||
|
|
||||||
class TorrentPlayer(xbmc.Player) :
|
|
||||||
|
class TorrentPlayer(xbmc.Player):
|
||||||
pyrrent_engine = None
|
pyrrent_engine = None
|
||||||
loop = None
|
loop = None
|
||||||
paused = False
|
paused = False
|
||||||
|
|
||||||
def onPlayBackEnded(self):
|
def onPlayBackEnded(self):
|
||||||
self.pyrrent_engine.close()
|
self.pyrrent_engine.close()
|
||||||
self.loop.stopped = True
|
self.loop.stopped = True
|
||||||
xbmc.Player().stop()
|
xbmc.Player().stop()
|
||||||
|
|
||||||
def onPlayBackPaused(self):
|
def onPlayBackPaused(self):
|
||||||
self.pyrrent_engine.pause()
|
self.pyrrent_engine.pause()
|
||||||
self.paused = True
|
self.paused = True
|
||||||
|
|
||||||
def onPlayBackResumed(self):
|
def onPlayBackResumed(self):
|
||||||
self.paused = False
|
self.paused = False
|
||||||
self.pyrrent_engine.resume()
|
self.pyrrent_engine.resume()
|
||||||
|
@ -20,15 +24,16 @@ class TorrentPlayer(xbmc.Player) :
|
||||||
self.pyrrent_engine.close()
|
self.pyrrent_engine.close()
|
||||||
self.loop.stopped = True
|
self.loop.stopped = True
|
||||||
xbmc.Player().stop()
|
xbmc.Player().stop()
|
||||||
|
|
||||||
def play(self, engine, f_index):
|
def play(self, engine, f_index):
|
||||||
self.pyrrent_engine = engine
|
self.pyrrent_engine = engine
|
||||||
self.pyrrent_engine.start()
|
self.pyrrent_engine.start()
|
||||||
self.pyrrent_engine.activate_file(f_index)
|
self.pyrrent_engine.activate_file(f_index)
|
||||||
monitor = xbmc.Monitor()
|
monitor = xbmc.Monitor()
|
||||||
pw = xbmcgui.DialogProgress()
|
pw = xbmcgui.DialogProgress()
|
||||||
pw.create(localize(33055), line1='0 Kbit/s')
|
pw.create(localize(33055), '0 Kbit/s')
|
||||||
f_size = self.pyrrent_engine.file_status(f_index).size
|
f_size = self.pyrrent_engine.file_status(f_index).size
|
||||||
EXPECTED_KBYTES = f_size / 3 / 1024 / 1024
|
EXPECTED_KBYTES = f_size // 3 // 1024 // 1024
|
||||||
if EXPECTED_KBYTES > 768:
|
if EXPECTED_KBYTES > 768:
|
||||||
EXPECTED_KBYTES = 768
|
EXPECTED_KBYTES = 768
|
||||||
while True:
|
while True:
|
||||||
|
@ -42,9 +47,9 @@ class TorrentPlayer(xbmc.Player) :
|
||||||
status = self.pyrrent_engine.status()
|
status = self.pyrrent_engine.status()
|
||||||
d_rate = status.download_rate
|
d_rate = status.download_rate
|
||||||
# xbmc.log('*** DRATE: {}'.format(d_rate), level=xbmc.LOGNOTICE)
|
# xbmc.log('*** DRATE: {}'.format(d_rate), level=xbmc.LOGNOTICE)
|
||||||
perc = d_rate / EXPECTED_KBYTES * 100
|
perc = d_rate // EXPECTED_KBYTES * 100
|
||||||
if perc > 100: perc = 100
|
if perc > 100: perc = 100
|
||||||
pw.update(perc, line1=' {} / {} KB/s'.format(int(d_rate), int(EXPECTED_KBYTES)))
|
pw.update(perc, ' {} / {} KB/s'.format(int(d_rate), int(EXPECTED_KBYTES)))
|
||||||
if perc == 100:
|
if perc == 100:
|
||||||
pw.close()
|
pw.close()
|
||||||
break
|
break
|
||||||
|
@ -52,10 +57,13 @@ class TorrentPlayer(xbmc.Player) :
|
||||||
listitem = xbmcgui.ListItem('.'.join(fstat.name.split('/')[-1].split('.')[:-1])[:-1], path=fstat.url)
|
listitem = xbmcgui.ListItem('.'.join(fstat.name.split('/')[-1].split('.')[:-1])[:-1], path=fstat.url)
|
||||||
xbmc.Player.play(self, fstat.url, listitem)
|
xbmc.Player.play(self, fstat.url, listitem)
|
||||||
|
|
||||||
|
|
||||||
class VideoLoop(object):
|
class VideoLoop(object):
|
||||||
stopped = False
|
stopped = False
|
||||||
|
|
||||||
def __init__(self, torr_fp):
|
def __init__(self, torr_fp):
|
||||||
self.e = get_engine(torr_fp)
|
self.e = get_engine(torr_fp)
|
||||||
|
|
||||||
def start(self, f_index):
|
def start(self, f_index):
|
||||||
self.statinfo = xbmcgui.Dialog()
|
self.statinfo = xbmcgui.Dialog()
|
||||||
self.mediaPlayer = TorrentPlayer()
|
self.mediaPlayer = TorrentPlayer()
|
||||||
|
@ -68,11 +76,12 @@ class VideoLoop(object):
|
||||||
status = self.e.status()
|
status = self.e.status()
|
||||||
f_status = self.e.file_status(f_index)
|
f_status = self.e.file_status(f_index)
|
||||||
if self.mediaPlayer.paused:
|
if self.mediaPlayer.paused:
|
||||||
self.statinfo.notification('[{}]{}.'.format(('|' * (int(f_status.progress * 100) / 2)).ljust(50, '.'), ' ' * 100),
|
self.statinfo.notification(
|
||||||
|
# '[{}]{}.'.format(('|' * (int(f_status.progress * 100) // 2)).ljust(50, '.'), ' ' * 100),
|
||||||
|
'[{}]'.format(('|' * (int(f_status.progress * 100) // 2)).ljust(50, '.')),
|
||||||
'S: {} DL: {} KB/s UL: {} KB/s'.format(status.num_seeds,
|
'S: {} DL: {} KB/s UL: {} KB/s'.format(status.num_seeds,
|
||||||
status.download_rate,
|
status.download_rate,
|
||||||
status.upload_rate),
|
status.upload_rate),
|
||||||
time=2, sound=False
|
time=2, sound=False
|
||||||
)
|
)
|
||||||
xbmc.sleep(1000)
|
xbmc.sleep(1000)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from codequick.utils import urljoin_partial # @UnresolvedImport
|
import xbmc
|
||||||
import urlquick # @UnresolvedImport
|
from codequick.utils import urljoin_partial
|
||||||
from ..settings import option
|
from ..overrrides.session import proxies
|
||||||
from ..overrrides import session
|
from requests.sessions import Session
|
||||||
#import xbmc
|
from htmlement import HTMLement
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
|
||||||
class ResultItem(object):
|
class ResultItem(object):
|
||||||
def __init__(self, url, title, size, seeders, leachers, icon='video.png', cookies={}, referer=''):
|
def __init__(self, url, title, size, seeders, leachers, icon='video.png', cookies={}, referer=''):
|
||||||
|
@ -15,34 +17,46 @@ class ResultItem(object):
|
||||||
self.cookies = cookies
|
self.cookies = cookies
|
||||||
self.referer = referer
|
self.referer = referer
|
||||||
|
|
||||||
|
|
||||||
class Searcher(object):
|
class Searcher(object):
|
||||||
base_url = None
|
base_url = None
|
||||||
search_path = None
|
search_path = None
|
||||||
cookies = {}
|
cookies = {}
|
||||||
headers = {}
|
headers = {}
|
||||||
name = 'BaseClass'
|
name = 'BaseClass'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.session = session.Session()
|
self.session = Session()
|
||||||
|
self.session.proxies.update(proxies())
|
||||||
self.headers = {
|
self.headers = {
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 YaBrowser/14.10.2062.12061 Safari/537.36',
|
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||||
|
'Chrome/37.0.2062.124 YaBrowser/14.10.2062.12061 Safari/537.36',
|
||||||
'Referer': self.base_url
|
'Referer': self.base_url
|
||||||
}
|
}
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
'''Login or something else if needed'''
|
"""Login or something else if needed"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def search(self, query):
|
def search(self, query):
|
||||||
if self.prepare():
|
if self.prepare():
|
||||||
try:
|
try:
|
||||||
url_constructor = urljoin_partial(self.base_url)
|
url_constructor = urljoin_partial(self.base_url)
|
||||||
s_url = self.normalize_url(url_constructor(self.search_path.format(urlquick.quote(query))))
|
s_url = self.normalize_url(url_constructor(self.search_path.format(quote(query))))
|
||||||
resp = self.session.get(s_url, cookies=self.cookies, headers=self.headers)
|
resp = self.session.get(s_url, cookies=self.cookies, headers=self.headers)
|
||||||
body = resp.parse('body')
|
parser = HTMLement('body')
|
||||||
return self.process(body)
|
parser.feed(resp.text)
|
||||||
|
# todo отладка
|
||||||
|
xbmc.log(f'SEARCH BODY:\n{resp.text}')
|
||||||
|
#
|
||||||
|
return self.process(parser.close())
|
||||||
except:
|
except:
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def process(self, body):
|
def process(self, body):
|
||||||
'''Process element tree'''
|
"""Process element tree"""
|
||||||
|
|
||||||
def normalize_url(self, url):
|
def normalize_url(self, url):
|
||||||
return url
|
return url
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import xbmc
|
||||||
|
|
||||||
from . import Searcher, urljoin_partial, ResultItem
|
from . import Searcher, urljoin_partial, ResultItem
|
||||||
from ..settings import option
|
from ..settings import option
|
||||||
from ..utils import notify, localize
|
from ..utils import notify, localize
|
||||||
from codequick.listing import local_image # @UnresolvedImport
|
from codequick.listing import local_image
|
||||||
|
|
||||||
|
|
||||||
class SearchEngine(Searcher):
|
class SearchEngine(Searcher):
|
||||||
base_url = option['kinozal_url']
|
base_url = option['kinozal_url']
|
||||||
search_path = '/browse.php?s={}&t=1'
|
search_path = '/browse.php?s={}&t=1'
|
||||||
name = 'Kinozal.tv'
|
name = 'Kinozal.tv'
|
||||||
icon = 'searcher_kinozal.png'
|
icon = 'searcher_kinozal.png'
|
||||||
enabled = option.get_boolean('kinozal_enable') # @UndefinedVariable
|
enabled = option.get_boolean('kinozal_enable')
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
if self.cookies:
|
if self.cookies:
|
||||||
c_uid = self.cookies.get('uid', None)
|
c_uid = self.cookies.get('uid', None)
|
||||||
|
@ -17,6 +21,7 @@ class SearchEngine(Searcher):
|
||||||
if c_uid and c_pass:
|
if c_uid and c_pass:
|
||||||
return True
|
return True
|
||||||
return self.login()
|
return self.login()
|
||||||
|
|
||||||
def process(self, body):
|
def process(self, body):
|
||||||
url_constructor = urljoin_partial(self.base_url)
|
url_constructor = urljoin_partial(self.base_url)
|
||||||
rows = list(filter(lambda x: x.get('class') in ['first bg', 'bg'], body.findall('.//tr[@class]')))
|
rows = list(filter(lambda x: x.get('class') in ['first bg', 'bg'], body.findall('.//tr[@class]')))
|
||||||
|
@ -32,16 +37,27 @@ class SearchEngine(Searcher):
|
||||||
)
|
)
|
||||||
size = size_l[0].text.strip() if len(size_l) else '0'
|
size = size_l[0].text.strip() if len(size_l) else '0'
|
||||||
yield ResultItem(url, title, size, seeders, leachers, self.icon, self.cookies, self.base_url)
|
yield ResultItem(url, title, size, seeders, leachers, self.icon, self.cookies, self.base_url)
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
user = option['kinozal_login']
|
user = option['kinozal_login']
|
||||||
password = option['kinozal_password']
|
password = option['kinozal_password']
|
||||||
try:
|
try:
|
||||||
if not user or not password:
|
if not user or not password:
|
||||||
raise Exception
|
raise Exception
|
||||||
resp = self.session.post('{}/takelogin.php'.format(self.base_url), data={'username': user, 'password': password, 'returnto': ''},
|
resp = self.session.post('{}/takelogin.php'.format(self.base_url),
|
||||||
|
data={'username': user, 'password': password, 'returnto': ''},
|
||||||
cookies={}, headers=self.headers, allow_redirects=False)
|
cookies={}, headers=self.headers, allow_redirects=False)
|
||||||
|
# todo отладка
|
||||||
|
xbmc.log(f'Kinozal LOGIN BODY:\n{resp.text}')
|
||||||
|
#
|
||||||
|
|
||||||
if not resp.ok:
|
if not resp.ok:
|
||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
|
# todo отладка
|
||||||
|
xbmc.log(f'LOGIN COOKIE:\n{resp.cookies}')
|
||||||
|
#
|
||||||
|
|
||||||
cookies = resp.cookies
|
cookies = resp.cookies
|
||||||
c_uid = cookies.get('uid', None)
|
c_uid = cookies.get('uid', None)
|
||||||
c_pass = cookies.get('pass', None)
|
c_pass = cookies.get('pass', None)
|
||||||
|
@ -52,5 +68,6 @@ class SearchEngine(Searcher):
|
||||||
except:
|
except:
|
||||||
notify(self.name, localize(33056), local_image.format(self.icon))
|
notify(self.name, localize(33056), local_image.format(self.icon))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def normalize_url(self, url):
|
def normalize_url(self, url):
|
||||||
return url.encode('cp1251')
|
return url.encode('cp1251')
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import xbmc
|
||||||
|
|
||||||
from . import Searcher, urljoin_partial, ResultItem
|
from . import Searcher, urljoin_partial, ResultItem
|
||||||
from ..settings import option
|
from ..settings import option
|
||||||
from ..utils import notify, localize
|
from ..utils import notify, localize
|
||||||
|
@ -43,6 +45,11 @@ class SearchEngine(Searcher):
|
||||||
cookies={}, headers=self.headers, allow_redirects=False)
|
cookies={}, headers=self.headers, allow_redirects=False)
|
||||||
if not resp.ok:
|
if not resp.ok:
|
||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
|
# todo отладка
|
||||||
|
xbmc.log(f'RuTracker LOGIN BODY:\n{resp.text}')
|
||||||
|
#
|
||||||
|
|
||||||
cookies = resp.cookies
|
cookies = resp.cookies
|
||||||
bb_session = cookies.get('bb_session', None)
|
bb_session = cookies.get('bb_session', None)
|
||||||
if not bb_session:
|
if not bb_session:
|
||||||
|
|
|
@ -1,28 +1,26 @@
|
||||||
from codequick.support import addon_data # @UnresolvedImport
|
from codequick.support import addon_data # @UnresolvedImport
|
||||||
from codequick.listing import local_image # @UnresolvedImport
|
from codequick.utils import urljoin_partial # @UnresolvedImport
|
||||||
from urlquick import urljoin # @UnresolvedImport
|
|
||||||
from ..settings import option
|
from ..settings import option
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import os
|
import os
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from pyrrent2http import Engine # @UnresolvedImport
|
from pyrrent2http import Engine # @UnresolvedImport
|
||||||
import sys
|
from urllib.request import pathname2url
|
||||||
py3 = sys.version_info >= (3, 0)
|
|
||||||
if py3:
|
|
||||||
from urllib.request import pathname2url # @UnresolvedImport
|
|
||||||
else:
|
|
||||||
from urllib import pathname2url
|
|
||||||
|
|
||||||
def notify(heading, message, icon=xbmcgui.NOTIFICATION_INFO):
|
def notify(heading, message, icon=xbmcgui.NOTIFICATION_INFO):
|
||||||
n = xbmcgui.Dialog()
|
n = xbmcgui.Dialog()
|
||||||
n.notification(heading, message, icon, time=5, sound=True)
|
n.notification(heading, message, icon, time=5, sound=True)
|
||||||
|
|
||||||
|
|
||||||
def localize(sid):
|
def localize(sid):
|
||||||
return addon_data.getLocalizedString(sid)
|
return addon_data.getLocalizedString(sid)
|
||||||
|
|
||||||
|
|
||||||
def store_torrent_file(file_bytes):
|
def store_torrent_file(file_bytes):
|
||||||
h = sha1(file_bytes).hexdigest()
|
h = sha1(file_bytes).hexdigest()
|
||||||
t_fname = '{}.torrent'.format(h)
|
t_fname = '{}.torrent'.format(h)
|
||||||
full_path = os.path.join(storage_toorents_dir, t_fname)
|
full_path = os.path.join(storage_torrents_dir, t_fname)
|
||||||
if os.path.exists(full_path):
|
if os.path.exists(full_path):
|
||||||
with open(full_path, 'rb') as f:
|
with open(full_path, 'rb') as f:
|
||||||
if sha1(f.read()).hexdigest() == h:
|
if sha1(f.read()).hexdigest() == h:
|
||||||
|
@ -30,14 +28,18 @@ def store_torrent_file(file_bytes):
|
||||||
with open(full_path, 'wb') as f:
|
with open(full_path, 'wb') as f:
|
||||||
f.write(file_bytes)
|
f.write(file_bytes)
|
||||||
return full_path
|
return full_path
|
||||||
|
|
||||||
|
|
||||||
def torrent_full_path(t_fname):
|
def torrent_full_path(t_fname):
|
||||||
return os.path.join(storage_toorents_dir, t_fname)
|
return os.path.join(storage_torrents_dir, t_fname)
|
||||||
|
|
||||||
|
|
||||||
def file_url(path):
|
def file_url(path):
|
||||||
if not path.startswith('file:'):
|
if not path.startswith('file:'):
|
||||||
path = urljoin('file:', pathname2url(path))
|
path = urljoin_partial('file:')(pathname2url(path))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def get_engine(torrent_uri):
|
def get_engine(torrent_uri):
|
||||||
if option.get_boolean('use_socks_for_trackers'): # @UndefinedVariable
|
if option.get_boolean('use_socks_for_trackers'): # @UndefinedVariable
|
||||||
proxy = {
|
proxy = {
|
||||||
|
@ -48,14 +50,17 @@ def get_engine(torrent_uri):
|
||||||
proxy = None
|
proxy = None
|
||||||
return Engine(uri=file_url(torrent_uri), download_path=storage_download_dir,
|
return Engine(uri=file_url(torrent_uri), download_path=storage_download_dir,
|
||||||
encryption=1, keep_complete=False, keep_incomplete=False,
|
encryption=1, keep_complete=False, keep_incomplete=False,
|
||||||
dht_routers=["router.bittorrent.com:6881", "router.utorrent.com:6881"], use_random_port=False, listen_port=6881,
|
dht_routers=["router.bittorrent.com:6881", "router.utorrent.com:6881"], use_random_port=False,
|
||||||
|
listen_port=6881,
|
||||||
user_agent='', enable_dht=True, proxy=proxy)
|
user_agent='', enable_dht=True, proxy=proxy)
|
||||||
|
|
||||||
|
|
||||||
while not option['storage_dir']:
|
while not option['storage_dir']:
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
dialog.ok(localize(33000), localize(33051))
|
dialog.ok(localize(33000), localize(33051))
|
||||||
addon_data.openSettings()
|
addon_data.openSettings()
|
||||||
storage_root = os.path.abspath(os.path.join(option['storage_dir'], 'Torrenter3'))
|
storage_root = os.path.abspath(os.path.join(option['storage_dir'], 'Torrenter3'))
|
||||||
storage_toorents_dir = os.path.join(storage_root, 'torrents')
|
storage_torrents_dir = os.path.join(storage_root, 'torrents')
|
||||||
storage_download_dir = os.path.join(storage_root, 'download')
|
storage_download_dir = os.path.join(storage_root, 'download')
|
||||||
if not os.path.exists(storage_toorents_dir): os.makedirs(storage_toorents_dir)
|
if not os.path.exists(storage_torrents_dir): os.makedirs(storage_torrents_dir)
|
||||||
if not os.path.exists(storage_download_dir): os.makedirs(storage_download_dir)
|
if not os.path.exists(storage_download_dir): os.makedirs(storage_download_dir)
|
||||||
|
|
Loading…
Reference in New Issue