Версия для Kodi 19

master v3.3.0
Роман Бородин 2022-03-14 09:16:22 +03:00
parent e5bd0ca668
commit baf6d0c369
8 changed files with 235 additions and 203 deletions

View File

@ -1,13 +1,17 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from codequick import Route, Script, Listitem, utils, run # @UnresolvedImport
from codequick.storage import PersistentList # @UnresolvedImport
import os.path import os.path
import xbmcgui, xbmc
from resources.lib.searchers import rutor, kinozal, rutracker import xbmc
from resources.lib.utils import localize, store_torrent_file, get_engine import xbmcgui
from codequick import Route, Script, Listitem, utils, run # @UnresolvedImport
from codequick.storage import PersistentList # @UnresolvedImport
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, (
(search_history, localize(33052), 'history2.png'), for li in (
(new_search, localize(33053), 'search.png') (search_history, localize(33052), 'history2.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,21 +84,25 @@ 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),
params={'url': i.url, 'cookies': i.cookies, 'referer': i.referer} params={'url': i.url, 'cookies': i.cookies, 'referer': i.referer}
) )
if thumb: if thumb:
item.art['thumb'] = thumb item.art['thumb'] = thumb
else: else:
@ -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,37 +124,44 @@ 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(
key=lambda x: x.name) video_extensions), e.list_from_info(media_types=['video']))),
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 ) )))) key=lambda x: x.name)
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, d 'path': '{}/{}'.format(
path, d
) if path != '' else d} ) if path != '' else d}
) )
item.art.local_thumb('folder.png') item.art.local_thumb('folder.png')
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')
yield item yield item
else: else:
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()

View File

@ -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>

View File

@ -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

View File

@ -1,61 +1,69 @@
import xbmc, xbmcgui import xbmc, xbmcgui
from .utils import get_engine, localize from .utils import get_engine, localize
class TorrentPlayer(xbmc.Player) :
pyrrent_engine = None
loop = None
paused = False
def onPlayBackEnded(self):
self.pyrrent_engine.close()
self.loop.stopped = True
xbmc.Player().stop()
def onPlayBackPaused(self):
self.pyrrent_engine.pause()
self.paused = True
def onPlayBackResumed(self):
self.paused = False
self.pyrrent_engine.resume()
def onPlayBackStopped(self): class TorrentPlayer(xbmc.Player):
self.pyrrent_engine.close() pyrrent_engine = None
self.loop.stopped = True loop = None
xbmc.Player().stop() paused = False
def play(self, engine, f_index):
self.pyrrent_engine = engine def onPlayBackEnded(self):
self.pyrrent_engine.start() self.pyrrent_engine.close()
self.pyrrent_engine.activate_file(f_index) self.loop.stopped = True
monitor = xbmc.Monitor() xbmc.Player().stop()
pw = xbmcgui.DialogProgress()
pw.create(localize(33055), line1='0 Kbit/s') def onPlayBackPaused(self):
f_size = self.pyrrent_engine.file_status(f_index).size self.pyrrent_engine.pause()
EXPECTED_KBYTES = f_size / 3 / 1024 / 1024 self.paused = True
if EXPECTED_KBYTES > 768:
EXPECTED_KBYTES = 768 def onPlayBackResumed(self):
while True: self.paused = False
xbmc.sleep(500) self.pyrrent_engine.resume()
if monitor.abortRequested() or pw.iscanceled():
pw.close() def onPlayBackStopped(self):
self.pyrrent_engine.close() self.pyrrent_engine.close()
xbmc.Player().stop() self.loop.stopped = True
self.loop.stopped = True xbmc.Player().stop()
return False
status = self.pyrrent_engine.status() def play(self, engine, f_index):
d_rate = status.download_rate self.pyrrent_engine = engine
# xbmc.log('*** DRATE: {}'.format(d_rate), level=xbmc.LOGNOTICE) self.pyrrent_engine.start()
perc = d_rate / EXPECTED_KBYTES * 100 self.pyrrent_engine.activate_file(f_index)
if perc > 100: perc = 100 monitor = xbmc.Monitor()
pw.update(perc, line1=' {} / {} KB/s'.format(int(d_rate), int(EXPECTED_KBYTES))) pw = xbmcgui.DialogProgress()
if perc == 100: pw.create(localize(33055), '0 Kbit/s')
pw.close() f_size = self.pyrrent_engine.file_status(f_index).size
break EXPECTED_KBYTES = f_size // 3 // 1024 // 1024
fstat = self.pyrrent_engine.file_status(f_index) if EXPECTED_KBYTES > 768:
listitem = xbmcgui.ListItem('.'.join(fstat.name.split('/')[-1].split('.')[:-1])[:-1], path=fstat.url) EXPECTED_KBYTES = 768
xbmc.Player.play(self, fstat.url, listitem) while True:
xbmc.sleep(500)
if monitor.abortRequested() or pw.iscanceled():
pw.close()
self.pyrrent_engine.close()
xbmc.Player().stop()
self.loop.stopped = True
return False
status = self.pyrrent_engine.status()
d_rate = status.download_rate
# xbmc.log('*** DRATE: {}'.format(d_rate), level=xbmc.LOGNOTICE)
perc = d_rate // EXPECTED_KBYTES * 100
if perc > 100: perc = 100
pw.update(perc, ' {} / {} KB/s'.format(int(d_rate), int(EXPECTED_KBYTES)))
if perc == 100:
pw.close()
break
fstat = self.pyrrent_engine.file_status(f_index)
listitem = xbmcgui.ListItem('.'.join(fstat.name.split('/')[-1].split('.')[:-1])[:-1], path=fstat.url)
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(
'S: {} DL: {} KB/s UL: {} KB/s'.format(status.num_seeds, # '[{}]{}.'.format(('|' * (int(f_status.progress * 100) // 2)).ljust(50, '.'), ' ' * 100),
status.download_rate, '[{}]'.format(('|' * (int(f_status.progress * 100) // 2)).ljust(50, '.')),
status.upload_rate), 'S: {} DL: {} KB/s UL: {} KB/s'.format(status.num_seeds,
time=2, sound=False status.download_rate,
) status.upload_rate),
time=2, sound=False
)
xbmc.sleep(1000) xbmc.sleep(1000)

View File

@ -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

View File

@ -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]')))
@ -28,20 +33,31 @@ class SearchEngine(Searcher):
seeders = int(r.find('.//td[@class="sl_s"]').text.strip()) seeders = int(r.find('.//td[@class="sl_s"]').text.strip())
leachers = int(r.find('.//td[@class="sl_p"]').text.strip()) leachers = int(r.find('.//td[@class="sl_p"]').text.strip())
size_l = list(filter(lambda x: x.text.strip().endswith((u'ГБ', u'МБ')), size_l = list(filter(lambda x: x.text.strip().endswith((u'ГБ', u'МБ')),
r.findall('.//td[@class="s"]')) r.findall('.//td[@class="s"]'))
) )
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')

View File

@ -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:

View File

@ -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,32 +28,39 @@ 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 = {
'host': option['socks_ip'], 'host': option['socks_ip'],
'port': int(option['socks_port']) 'port': int(option['socks_port'])
} }
else: else:
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,
user_agent='', enable_dht=True, proxy=proxy) listen_port=6881,
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)