Compare commits

..

No commits in common. "master" and "sandbox1" have entirely different histories.

95 changed files with 3351 additions and 5719 deletions

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.12 (D:\Python27\python.exe)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.7 (D:/Python27/python.exe)" project-jdk-type="Python SDK" />
</project>

View File

@ -6,3 +6,4 @@
</modules>
</component>
</project>

View File

@ -2,7 +2,8 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 2.7.12 (D:\Python27\python.exe)" jdkType="Python SDK" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

File diff suppressed because it is too large Load Diff

View File

@ -25,10 +25,10 @@ import hashlib
import re
import base64
from StringIO import StringIO
import zlib
import gzip
from functions import file_decode, file_encode
from functions import magnet_alert, log, loadsw_onstop
from functions import magnet_alert, log, debug
import xbmcvfs
@ -81,7 +81,6 @@ class AceStream:
def __exit__(self):
self.TSplayer.end()
loadsw_onstop() # Reload Search Window
def play_url_ind(self, ind, label, icon):
self.TSplayer.play_url_ind(int(ind), label, str(icon), '')
@ -94,12 +93,19 @@ class AceStream:
torrentFile = self.storageDirectory + os.sep + self.torrentFilesDirectory + os.sep + self.md5(
torrentUrl) + '.torrent'
try:
if not re.match("^[htps]+?://.+$|^://.+$", torrentUrl):
log('xbmcvfs.File for %s' % torrentUrl)
content = xbmcvfs.File(torrentUrl, "rb").read()
if not re.match("^http\:.+$", torrentUrl):
content = xbmcvfs.File(file_decode(torrentUrl), "rb").read()
else:
log('request for %s' % torrentUrl)
content = self.makeRequest(torrentUrl)
request = urllib2.Request(torrentUrl)
request.add_header('Referer', torrentUrl)
request.add_header('Accept-encoding', 'gzip')
result = urllib2.urlopen(request)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
f = gzip.GzipFile(fileobj=buf)
content = f.read()
else:
content = result.read()
localFile = xbmcvfs.File(torrentFile, "w+b")
localFile.write(content)
@ -113,33 +119,10 @@ class AceStream:
self.torrentFileInfo = self.TSplayer.load_torrent(base64.b64encode(content), 'RAW')
return self.torrentFile
def makeRequest(self, torrentUrl):
torrentUrl = re.sub('^://', 'http://', torrentUrl)
x = re.search("://(.+?)/|://(.+?)$", torrentUrl)
if x:
baseurl = x.group(1) if x.group(1) else x.group(2)
else:
baseurl =''
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'),
('Referer', 'http://%s/' % baseurl), ('Accept-encoding', 'gzip'), ]
opener = urllib2.build_opener()
opener.addheaders = headers
result = opener.open(torrentUrl)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
return content
def magnetToTorrent(self, magnet):
try:
from SkorbaLoader import SkorbaLoader
torrent = SkorbaLoader(self.storageDirectory, magnet)
from Libtorrent import Libtorrent
torrent = Libtorrent(self.storageDirectory, magnet)
torrent.magnetToTorrent(magnet)
self.torrentFile = torrent.torrentFile
log('[AceStream][magnetToTorrent]: self.torrentFile '+str(self.torrentFile))

View File

@ -2,7 +2,6 @@
'''
Torrenter v2 plugin for XBMC/Kodi
Copyright (C) 2012-2015 Vadim Skorba v1 - DiMartino v2
https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html
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
@ -30,7 +29,7 @@ import xbmcgui
import xbmcvfs
import xbmcaddon
import Localization
from functions import localize_path, isSubtitle, loadsw_onstop, is_writable, file_url
from functions import localize_path, isSubtitle, is_writable, file_url
import os
@ -41,10 +40,16 @@ from contextlib import contextmanager, closing, nested
from functions import foldername, showMessage, clearStorage, WatchedHistoryDB, get_ids_video, log, debug, ensure_str
#if sys.modules["__main__"].__settings__.getSetting("torrent_player") == '2':
from torrent2http import State, Engine, MediaType
author = 'Anteo'
__settings__ = xbmcaddon.Addon(id='script.module.torrent2http')
__version__ = __settings__.getAddonInfo('version')
#elif sys.modules["__main__"].__settings__.getSetting("torrent_player") == '3':
# from pyrrent2http import State, Engine, MediaType
# author = 'Inpos'
# __settings__ = xbmcaddon.Addon(id='script.module.pyrrent2http')
# __version__ = __settings__.getAddonInfo('version')
ROOT = sys.modules["__main__"].__root__
RESOURCES_PATH = os.path.join(ROOT, 'resources')
@ -133,8 +138,8 @@ class AnteoLoader:
keep_incomplete = True
dht_routers = ["router.bittorrent.com:6881", "router.utorrent.com:6881"]
user_agent = ''
self.engine = Engine(uri=file_url(localize_path(self.torrentFile)), download_path=self.storageDirectory,
user_agent = 'uTorrent/2200(24683)'
self.engine = Engine(uri=file_url(self.torrentFile), download_path=self.storageDirectory,
connections_limit=connections_limit,
encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
@ -148,8 +153,8 @@ class AnteoLoader:
def getContentList(self):
try:
from SkorbaLoader import SkorbaLoader
torrent = SkorbaLoader(self.storageDirectory, self.torrentFile)
from Libtorrent import Libtorrent
torrent = Libtorrent(self.storageDirectory, self.torrentFile)
return torrent.getContentList()
except:
import traceback
@ -160,7 +165,7 @@ class AnteoLoader:
self.setup_engine()
files = []
filelist = []
with closing(self.engine):
try:
self.engine.start()
#media_types=[MediaType.VIDEO, MediaType.AUDIO, MediaType.SUBTITLES, MediaType.UNKNOWN]
@ -187,6 +192,11 @@ class AnteoLoader:
stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
'offset': fs.offset}
filelist.append(stringdata)
except:
import traceback
log(traceback.format_exc())
finally:
self.engine.close()
return filelist
def saveTorrent(self, torrentUrl):
@ -200,12 +210,19 @@ class AnteoLoader:
if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
try:
if not re.match("^[htps]+?://.+$|^://.+$", torrentUrl):
log('xbmcvfs.File for %s' % torrentUrl)
if not re.match("^http\:.+$", torrentUrl):
content = xbmcvfs.File(torrentUrl, "rb").read()
else:
log('request for %s' % torrentUrl)
content = self.makeRequest(torrentUrl)
request = urllib2.Request(torrentUrl)
request.add_header('Referer', torrentUrl)
request.add_header('Accept-encoding', 'gzip')
result = urllib2.urlopen(request)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
localFile = xbmcvfs.File(torrentFile, "w+b")
localFile.write(content)
@ -222,29 +239,6 @@ class AnteoLoader:
self.torrentFile = torrentFile
return self.torrentFile
def makeRequest(self, torrentUrl):
torrentUrl = re.sub('^://', 'http://', torrentUrl)
x = re.search("://(.+?)/|://(.+?)$", torrentUrl)
if x:
baseurl = x.group(1) if x.group(1) else x.group(2)
else:
baseurl =''
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'),
('Referer', 'http://%s/' % baseurl), ('Accept-encoding', 'gzip'), ]
opener = urllib2.build_opener()
opener.addheaders = headers
result = opener.open(torrentUrl)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
return content
def md5(self, string):
hasher = hashlib.md5()
try:
@ -255,13 +249,13 @@ class AnteoLoader:
def magnetToTorrent(self, magnet):
try:
from SkorbaLoader import SkorbaLoader
torrent = SkorbaLoader(self.storageDirectory, magnet)
from Libtorrent import Libtorrent
torrent = Libtorrent(self.storageDirectory, magnet)
torrent.magnetToTorrent(magnet)
self.torrentFile = torrent.torrentFile
except:
self.torrentFile = magnet
log('[AnteoLoader][magnetToTorrent]: self.torrentFile '+ensure_str(self.torrentFile))
log('['+author+'Loader][magnetToTorrent]: self.torrentFile '+str(self.torrentFile))
class AnteoPlayer(xbmc.Player):
__plugin__ = sys.modules["__main__"].__plugin__
@ -285,12 +279,6 @@ class AnteoPlayer(xbmc.Player):
def __init__(self, userStorageDirectory, torrentUrl, params={}):
self.userStorageDirectory = userStorageDirectory
self.torrentUrl = torrentUrl
if not is_writable(self.userStorageDirectory):
xbmcgui.Dialog().ok(Localization.localize('Torrenter v2'),
Localization.localize('Your storage path is not writable or not local! Please change it in settings!'),
self.storageDirectory)
sys.exit(1)
xbmc.Player.__init__(self)
log("["+author+"Player] Initalized v"+__version__)
self.params = params
@ -298,51 +286,52 @@ class AnteoPlayer(xbmc.Player):
self.contentId = int(self.get("url"))
if self.get("seek"):
self.seek = int(self.get("seek"))
#self.torrent = AnteoLoader(self.userStorageDirectory, self.torrentUrl, self.torrentFilesDirectory)
self.init()
self.setup_engine()
with closing(self.engine):
try:
self.engine.start(self.contentId)
self.setup_nextep()
while True:
if self.buffer():
log('[AnteoPlayer]: ************************************* GOING LOOP')
log('['+author+'Player]: ************************************* GOING LOOP')
if self.setup_play():
WatchedHistoryDB().add(self.basename, self.torrentUrl,
foldername(self.getContentList()[self.contentId]['title']),
self.watchedTime, self.totalTime, self.contentId, self.fullSize)
self.setup_subs()
self.loop()
WatchedHistoryDB().add(self.basename, self.torrentUrl, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
WatchedHistoryDB().add(self.basename, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
else:
log('[AnteoPlayer]: ************************************* break')
log('['+author+'Player]: ************************************* break')
break
log('[AnteoPlayer]: ************************************* GO NEXT?')
log('['+author+'Player]: ************************************* GO NEXT?')
if self.next_dl and self.next_contentId != False and isinstance(self.next_contentId, int) and self.iterator == 100:
if not self.next_play:
xbmc.sleep(3000)
if not xbmcgui.Dialog().yesno(
self.localize('[%sPlayer v%s] ' % (author, __version__)),
self.localize('Torrent2HTTP'),
self.localize('Would you like to play next episode?')):
break
self.contentId = self.next_contentId
continue
log('[AnteoPlayer]: ************************************* NO! break')
showMessage(self.localize('Information'),
self.localize('Stopping the torrent2http process...'))
log('['+author+'Player]: ************************************* NO! break')
break
except:
import traceback
log(traceback.format_exc())
finally:
self.engine.close()
xbmc.Player().stop()
if '1' != self.__settings__.getSetting("keep_files") and 'Saved Files' not in self.userStorageDirectory:
xbmc.sleep(1000)
clearStorage(self.userStorageDirectory)
showMessage(self.localize('Information'),
self.localize('torrent2http process stopped.'))
loadsw_onstop() # Reload Search Window
else:
#if self.seeding_status:
#showMessage(self.localize('Information'),
# self.localize('Torrent is seeding. To stop it use Download Status.'), forced=True)
#else:
#if self.seeding: self.db_delete()
showMessage(self.localize('Information'),
self.localize('Torrent downloading is stopped.'), forced=True)
def init(self):
self.next_contentId = False
@ -356,6 +345,16 @@ class AnteoPlayer(xbmc.Player):
self.torrentUrl = self.torrentUrl
def setup_engine(self):
#uri=None, binaries_path=None, platform=None, download_path=".",
#bind_host='127.0.0.1', bind_port=5001, connections_limit=None, download_kbps=None, upload_kbps=None,
#enable_dht=True, enable_lsd=True, enable_natpmp=True, enable_upnp=True, enable_scrape=False,
#log_stats=False, encryption=Encryption.ENABLED, keep_complete=False, keep_incomplete=False,
#keep_files=False, log_files_progress=False, log_overall_progress=False, log_pieces_progress=False,
#listen_port=6881, use_random_port=False, max_idle_timeout=None, no_sparse=False, resume_file=None,
#user_agent=None, startup_timeout=5, state_file=None, enable_utp=True, enable_tcp=True,
#debug_alerts=False, logger=None, torrent_connect_boost=50, connection_speed=50,
#peer_connect_timeout=15, request_timeout=20, min_reconnect_time=60, max_failcount=3,
#dht_routers=None, trackers=None)
encryption = Encryption.ENABLED if self.__settings__.getSetting('encryption') == 'true' else Encryption.DISABLED
upload_limit = int(self.__settings__.getSetting("upload_limit"))*1024/8 if self.__settings__.getSetting(
@ -384,22 +383,28 @@ class AnteoPlayer(xbmc.Player):
keep_files = True
resume_file=os.path.join(self.userStorageDirectory, 'torrents', os.path.basename(self.torrentUrl)+'.resume_data')
enable_dht = self.__settings__.getSetting("enable_dht") == 'true'
dht_routers = ["router.bittorrent.com:6881","router.utorrent.com:6881"]
user_agent = ''
user_agent = 'uTorrent/2200(24683)'
self.pre_buffer_bytes = int(self.__settings__.getSetting("pre_buffer_bytes"))*1024*1024
showMessage('[%sPlayer v%s] ' % (author, __version__), self.localize('Please Wait'))
self.engine = Engine(uri=file_url(self.torrentUrl), download_path=self.userStorageDirectory,
connections_limit=connections_limit, download_kbps=download_limit, upload_kbps=upload_limit,
encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
keep_files=keep_files, user_agent=user_agent, resume_file=resume_file, enable_dht=enable_dht)
keep_files=keep_files, user_agent=user_agent, resume_file=resume_file)
def buffer(self):
#self.pre_buffer_bytes = 30*1024*1024 #30 MB
ready = False
progressBar = xbmcgui.DialogProgress()
progressBar.create('[%sPlayer v%s] ' % (author, __version__) + self.localize('Please Wait'),
self.localize('Seeds searching.'))
#if self.subs_dl:
# subs = self.torrent.getSubsIds(os.path.basename(self.torrent.getFilePath(self.contentId)))
# if len(subs) > 0:
# for ind, title in subs:
# self.torrent.continueSession(ind)
while not xbmc.abortRequested and not ready:
xbmc.sleep(500)
@ -465,7 +470,7 @@ class AnteoPlayer(xbmc.Player):
else:
self.next_dl = False
self.next_play = self.__settings__.getSetting('next_play') == 'true'
log('[AnteoPlayer]: next_dl - %s, next_play - %s, ids_video - %s' % (str(self.next_dl), str(self.next_play), str(self.ids_video)))
log('['+author+'Player]: next_dl - %s, next_play - %s, ids_video - %s' % (str(self.next_dl), str(self.next_play), str(self.ids_video)))
def setup_play(self):
file_status = self.engine.file_status(self.contentId)
@ -484,7 +489,7 @@ class AnteoPlayer(xbmc.Player):
self.next_contentId = int(self.ids_video[next_contentId_index])
else:
self.next_contentId = False
log('[AnteoPlayer][setup_play]: next_contentId: '+str(self.next_contentId))
log('['+author+'Player][setup_play]: next_contentId: '+str(self.next_contentId))
try:
seasonId = self.get("seasonId")
self.episodeId = self.get("episodeId") if not self.episodeId else int(self.episodeId) + 1
@ -504,17 +509,13 @@ class AnteoPlayer(xbmc.Player):
'season': int(seasonId),
'tvshowtitle': title})
except:
log('[AnteoPlayer]: Operation INFO failed!')
log('['+author+'Player]: Operation INFO failed!')
thumbnail = self.get("thumbnail")
if thumbnail:
listitem.setThumbnailImage(urllib.unquote_plus(thumbnail))
self.display_name = label
if self.get('listitem'):
listitem = self.get('listitem')
listitem.setPath(url)
player = xbmc.Player()
player.play(url, listitem)
@ -524,12 +525,12 @@ class AnteoPlayer(xbmc.Player):
xbmc.sleep(200)
i += 1
log('[AnteoPlayer]: self.isPlaying() = %s, i = %d, xbmc.abortRequested - %s' % (str(self.isPlaying()), i, str(xbmc.abortRequested)))
log('['+author+'Player]: self.isPlaying() = %s, i = %d, xbmc.abortRequested - %s' % (str(self.isPlaying()), i, str(xbmc.abortRequested)))
if not self.isPlaying() or xbmc.abortRequested:
return False
if self.seek > 0:
log('[AnteoPlayer]: seekTime - '+str(self.seek))
log('['+author+'Player]: seekTime - '+str(self.seek))
self.seekTime(self.seek)
return True
@ -543,7 +544,7 @@ class AnteoPlayer(xbmc.Player):
if isSubtitle(filename, i.name):
subs.append(i)
if subs:
log("[AnteoPlayer][setup_subs]: Detected subtitles: %s" % str(subs))
log("["+author+"Player][setup_subs]: Detected subtitles: %s" % str(subs))
for sub in subs:
xbmc.Player().setSubtitles(sub.url)
@ -559,10 +560,10 @@ class AnteoPlayer(xbmc.Player):
status = self.engine.status()
file_status = self.engine.file_status(self.contentId)
self.watchedTime = xbmc.Player().getTime()
self.totalTime = xbmc.Player().getTotalTime()
if self.iterator == 100 and debug_counter < 100:
debug_counter += 1
else:
self.totalTime = xbmc.Player().getTotalTime()
self.print_debug(status)
debug_counter=0
@ -573,9 +574,14 @@ class AnteoPlayer(xbmc.Player):
if pause and self.__settings__.getSetting("pause_onplay") == 'true':
pause = False
xbmc.Player().pause()
log('[loop]: xbmc.Player().pause()')
xbmc.sleep(1000)
#if not self.seeding_run and self.iterator == 100 and self.seeding:
#self.seeding_run = True
#self.seed(self.contentId)
#self.seeding_status = True
# xbmc.sleep(7000)
def onPlayBackStarted(self):
for f in self.on_playback_started:
f()
@ -606,10 +612,10 @@ class AnteoPlayer(xbmc.Player):
def _get_status_lines(self, s, f):
return [
ensure_str(self.display_name),
"%.2f%% %s" % (f.progress * 100, self.localize(STATE_STRS[s.state])),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate, self.localize('kb/s'),
s.upload_rate, self.localize('kb/s'),
localize_path(self.display_name),
"%.2f%% %s" % (f.progress * 100, self.localize(STATE_STRS[s.state]).decode('utf-8')),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate, self.localize('kb/s').decode('utf-8'),
s.upload_rate, self.localize('kb/s').decode('utf-8'),
s.num_seeds, s.num_peers)
]
@ -631,7 +637,7 @@ class AnteoPlayer(xbmc.Player):
if not status:
status = self.engine.status()
self.engine.check_torrent_error(status)
log('[AnteoPlayer]: %.2f%% complete (down: %.1f kb/s up: %.1f kb/s peers: %d) %s' % \
log('['+author+'Player]: %.2f%% complete (down: %.1f kb/s up: %.1f kb/s peers: %d) %s' % \
(status.progress * 100, status.download_rate,
status.upload_rate, status.num_peers, status.state_str))
@ -668,8 +674,7 @@ class OverlayText(object):
self._shown = False
self._text = ""
self._label = xbmcgui.ControlLabel(x, y, w, h, self._text, *args, **kwargs)
filename = os.path.join(RESOURCES_PATH, "images", "black.png")
self._background = xbmcgui.ControlImage(x, y, w, h, filename)
self._background = xbmcgui.ControlImage(x, y, w, h, os.path.join(RESOURCES_PATH, "images", "black.png"))
self._background.setColorDiffuse("0xD0000000")
def show(self):
@ -703,10 +708,5 @@ class OverlayText(object):
skin_path = xbmc.translatePath("special://skin/")
tree = ET.parse(os.path.join(skin_path, "addon.xml"))
res = None
for element in tree.findall("./extension/res"):
if element.attrib["default"] == 'true':
res = element
break
if res is None: res = tree.findall("./extension/res")[0]
res = tree.findall("./extension/res")[0]
return int(res.attrib["width"]), int(res.attrib["height"])

View File

@ -19,15 +19,6 @@
'''
import abc
import sys
proxy = int(sys.modules["__main__"].__settings__.getSetting("cl_proxy"))
if proxy == 1:
socks_ip = sys.modules["__main__"].__settings__.getSetting("socks_ip")
import socket
from resources.proxy import socks
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, socks_ip,
int(sys.modules["__main__"].__settings__.getSetting("socks_port")))
socket.socket = socks.socksocket
import urllib
import urllib2
import cookielib
@ -35,8 +26,6 @@ import re
from StringIO import StringIO
import gzip
import HTMLParser
import ssl
from datetime import date
import Localization
from functions import log, debug
@ -97,11 +86,10 @@ class Content:
'horror': ('Horror',),
'romance': ('Romance',),
'thriller': ('Thriller',),
'sci_fi': ('Sci-Fi',),
}
}
for y in range(date.today().year, 1970, -1):
for y in range(2015, 1970, -1):
category_dict['year'][str(y)] = (str(y), '/top/y/%s/' % str(y))
def get_contentList(self, category, subcategory=None, apps_property=None):
@ -142,8 +130,7 @@ class Content:
else:
get = self.category_dict[category][subcategory]
if category == 'search' and subcategory != True:
get = (get[0], get[1] % urllib.quote_plus(subcategory.encode('utf-8')))
if category == 'search': get = (get[0], get[1] % urllib.quote_plus(subcategory.encode('utf-8')))
property = self.get_property(category, subcategory)
@ -184,20 +171,14 @@ class Content:
except:
pass
if has_property:
if category == 'search' and subcategory != True:
property['page'] = property['page'] % urllib.quote_plus(subcategory.encode('utf-8'))
if category == 'search': property['page'] = property['page'] % urllib.quote_plus(
subcategory.encode('utf-8'))
return property
def makeRequest(self, url, data={}, headers=[]):
self.cookieJar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
# python ssl Context support - PEP 0466
if hasattr(ssl, '_create_unverified_context'):
ssl_context = ssl._create_unverified_context()
opener.add_handler(urllib2.HTTPSHandler(context=ssl_context))
else:
opener.add_handler(urllib2.HTTPSHandler())
opener.addheaders = headers
if 0 < len(data):
encodedData = urllib.urlencode(data)
@ -229,7 +210,6 @@ class Content:
('>', '&gt;'),
('"', '&quot;'),
("'", '&#39;'),
("'", '&#039;'),
(' ', '&nbsp;',),
('"', '&laquo;', ),
('"', '&raquo;', ),
@ -237,7 +217,6 @@ class Content:
('e', '&#233;',),
('e', '&#232;',),
('&', '&#38;',),
('&', '&#038;',),
('u', '&#249;',),
('u', '&#250;',),
('o', '&#244;',),

479
Core.py
View File

@ -18,6 +18,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
import tempfile
import Downloader
import xbmc
import xbmcaddon
@ -30,16 +32,14 @@ class Core:
__plugin__ = sys.modules["__main__"].__plugin__
__settings__ = sys.modules["__main__"].__settings__
ROOT = sys.modules["__main__"].__root__
userStorageDirectory = localize_path(xbmc.translatePath(__settings__.getSetting("storage")))#file_encode(__settings__.getSetting("storage"))
userStorageDirectory = localize_path(__settings__.getSetting("storage"))#file_encode(__settings__.getSetting("storage"))
torrentFilesDirectory = 'torrents'
debug = __settings__.getSetting('debug') == 'true'
torrent_player = __settings__.getSetting("torrent_player")
history_bool = __settings__.getSetting('history') == 'true'
open_option = int(__settings__.getSetting('open_option'))
language = {0: 'en', 1: 'ru', 2: 'uk', 3: 'he', 4: 'hu'}.get(int(__settings__.getSetting("language")))
language = {0: 'en', 1: 'ru', 2: 'uk', 3: 'he'}.get(int(__settings__.getSetting("language")))
scrapperDB_ver = {'en':'1.1', 'ru':'1.3', 'he':'1.3'}
torrent_info_style = int(__settings__.getSetting('torrent_info_style'))
searchwindowmode = int(__settings__.getSetting('searchwindowmode'))
log('SYS ARGV: ' + str(sys.argv))
@ -54,11 +54,7 @@ class Core:
def sectionMenu(self):
if self.__settings__.getSetting('plugin_name') != self.__plugin__:
#Every update run
first_run_260()
if self.version_check():
estuary()
self.__settings__.setSetting('first_run_260', 'True')
first_run_250()
self.__settings__.setSetting('plugin_name', self.__plugin__)
#check_network_advancedsettings()
check_download_dir()
@ -70,100 +66,49 @@ class Core:
contextMenu = [(self.localize('Search Control Window'),
'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))]
#Search Window
if self.searchwindowmode < 3:
self.drawItem('< %s >' % self.localize('Search Window'), 'searchWindow',
image=self.ROOT + '/icons/kodi.png', isFolder=False)
#History
if self.history_bool and self.searchwindowmode > 0:
HistorycontextMenu = []
if self.history_bool:
HistorycontextMenu=[]
HistorycontextMenu.extend(contextMenu)
HistorycontextMenu.append(
(self.localize('Clear %s') % self.localize('Search History'),
ListString % ('History', 'clear', 'addtime', '')))
if self.searchwindowmode == 1:
self.drawItem('< %s >' % self.localize('Search History'), 'swHistory',
image=self.ROOT + '/icons/history2.png', contextMenu=HistorycontextMenu, replaceMenu=False)
else:
self.drawItem('< %s >' % self.localize('Search History'), 'History',
image=self.ROOT + '/icons/history2.png', contextMenu=HistorycontextMenu, replaceMenu=False)
#Search
if self.searchwindowmode == 1:
self.drawItem('< %s >' % self.localize('Search'), 'swsearch', image=self.ROOT + '/icons/search.png',)
elif self.searchwindowmode > 1:
self.drawItem('< %s >' % self.localize('Search'), 'search', image=self.ROOT + '/icons/search.png', )
#Media
(self.localize('Clear %s') % self.localize('Search History'), ListString % ('History', 'clear', 'addtime', '')))
self.drawItem('< %s >' % self.localize('Search History'), 'History',
image=self.ROOT + '/icons/history2.png', contextMenu=HistorycontextMenu, replaceMenu=False)
self.drawItem('< %s >' % self.localize('Search'), 'search', image=self.ROOT + '/icons/search.png', )
CLcontextMenu=[]
CLcontextMenu.extend(contextMenu)
CLcontextMenu.append((self.localize('Reset All Cache DBs'),
ListString % ('full_download', '', 'url', json.dumps({'action': 'delete'}))))
self.drawItem('< %s >' % self.localize('Content Lists'), 'openContent', image=self.ROOT + '/icons/media.png',
contextMenu=CLcontextMenu, replaceMenu=False)
#DL Status
DLScontextMenu=[(self.localize('Start All'), ListString % ('DownloadStatus', 'startall', 'addtime', '')),
(self.localize('Stop All'), ListString % ('DownloadStatus', 'stopall', 'addtime', '')),]
DLScontextMenu.append(
(self.localize('Clear %s') % self.localize('Download Status'), ListString % ('DownloadStatus', 'clear', 'addtime', '')))
DLScontextMenu.extend(contextMenu)
if self.searchwindowmode == 1:
self.drawItem('< %s >' % self.localize('Download Status'), 'swDownloadStatus',
image=self.ROOT + '/icons/download.png',
contextMenu=DLScontextMenu, replaceMenu=False)
elif self.searchwindowmode > 1:
self.drawItem('< %s >' % self.localize('Download Status'), 'DownloadStatus',
image=self.ROOT + '/icons/download.png',
contextMenu=DLScontextMenu, replaceMenu=False)
#Torrent-client
if self.searchwindowmode == 1:
self.drawItem('< %s >' % self.localize('Torrent-client Browser'), 'swuTorrentBrowser',
image=self.ROOT + '/icons/' + getTorrentClientIcon())
elif self.searchwindowmode > 1:
self.drawItem('< %s >' % self.localize('Torrent-client Browser'), 'uTorrentBrowser',
image=self.ROOT + '/icons/' + getTorrentClientIcon())
#Watched
if self.history_bool and self.searchwindowmode > 0:
self.drawItem('< %s >' % self.localize('Download Status'), 'DownloadStatus', image=self.ROOT + '/icons/download.png',
contextMenu=DLScontextMenu, replaceMenu=False)
self.drawItem('< %s >' % self.localize('Torrent-client Browser'), 'uTorrentBrowser',
image=self.ROOT + '/icons/' + self.getTorrentClientIcon())
if self.history_bool:
WatchedHistorycontextMenu=[]
WatchedHistorycontextMenu.extend(contextMenu)
WatchedHistorycontextMenu.append(
(self.localize('Clear %s') % self.localize('Watched History'), ListString % ('WatchedHistory', 'clear', 'addtime', '')))
if self.searchwindowmode == 1:
self.drawItem('< %s >' % self.localize('Watched History'), 'swWatchedHistory',
image=self.ROOT + '/icons/watched.png', contextMenu=WatchedHistorycontextMenu,
replaceMenu=False)
else:
self.drawItem('< %s >' % self.localize('Watched History'), 'WatchedHistory',
image=self.ROOT + '/icons/watched.png', contextMenu=WatchedHistorycontextMenu,
replaceMenu=False)
#Torr player
self.drawItem('< %s >' % self.localize('Watched History'), 'WatchedHistory',
image=self.ROOT + '/icons/watched.png', contextMenu=WatchedHistorycontextMenu, replaceMenu=False)
self.drawItem('< %s >' % self.localize('.torrent Player'), 'torrentPlayer',
image=self.ROOT + '/icons/torrentPlayer.png', isFolder = False)
#Search Control Window
image=self.ROOT + '/icons/torrentPlayer.png')
self.drawItem('< %s >' % self.localize('Search Control Window'), 'controlCenter',
image=self.ROOT + '/icons/settings.png', isFolder=False)
#Magnet player
self.drawItem('< %s >' % self.localize('Magnet-link Player'), 'magentPlayer',
image=self.ROOT + '/icons/magnet.png', isFolder = False)
#Debug
image=self.ROOT + '/icons/magnet.png')
if self.debug:
self.drawItem('full_download', 'full_download', image=self.ROOT + '/icons/magnet.png')
self.drawItem('test', 'test', image=self.ROOT + '/icons/magnet.png', isFolder=False)
#Clear storage
if '0' != self.__settings__.getSetting("keep_files"):
self.drawItem('< %s >' % self.localize('Clear Storage'), 'clearStorage', isFolder=True,
image=self.ROOT + '/icons/clear.png')
view_style('sectionMenu')
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True)
@ -296,50 +241,54 @@ class Core:
lockView('wide')
def test(self, params={}):
pass
xbmc.Player().play('D:\\filmz\\The Missing (2014).mp4')
from Anteoloader import OverlayText, OVERLAY_WIDTH, OVERLAY_HEIGHT, XBFONT_CENTER_X,XBFONT_CENTER_Y
overlay = OverlayText(w=OVERLAY_WIDTH, h=OVERLAY_HEIGHT,
alignment=XBFONT_CENTER_X | XBFONT_CENTER_Y)
overlay.show()
overlay.text = 'XXXXXXXXXXXXXXXXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxXXXXXXXXXXXXXXXXXX\r\n' \
'YYyyyYyYYyYyY'
time.sleep(5)
overlay.hide()
time.sleep(1)
xbmc.Player().stop()
#from Anteoloader import AnteoPlayer
#from python_libtorrent import get_libtorrent
#self.lt=get_libtorrent()
#self.torrentFile='D:\\test.torrent'
#self.session = self.lt.session()
#e=self.lt.bdecode(xbmcvfs.File(self.torrentFile,'rb').read())
#self.torrentFileInfo = self.lt.torrent_info(e)
#torrent_info={'ti': self.torrentFileInfo,
# 'save_path': self.userStorageDirectory,
# 'flags': 0x300,
# #'storage_mode': self.lt.storage_mode_t(1),
# 'paused': False,
# #'auto_managed': False,
# #'duplicate_is_error': True
# }
#self.torrentHandle = self.session.add_torrent(torrent_info)
#log(self.torrentHandle.torrent_file())
#self.session.remove_torrent(self.torrentHandle)
def swHistory(self, params={}):
import searchwindow
params = {'mode': 'history'}
searchwindow.main(params)
#params['url']='0'
#if not xbmcvfs.exists(torrentUrl):
# action = xbmcgui.Dialog()
# torrentUrl = action.browse(1, self.localize('Choose .torrent in video library'), 'video', '.torrent')
#if torrentUrl and xbmcvfs.exists(torrentUrl):
# if 0 != len(torrentUrl):
# self.Downloader = Downloader.Torrent(self.userStorageDirectory, torrentUrl)
# else:
# log(self.__plugin__ + " Unexpected access to method Anteoloader() without torrent content")
#if self.Downloader:
# x=self.Downloader.getContentList()
# print str(x)
# xbmc.sleep(1000)
# self.Downloader.__exit__()
#self.Player = AnteoPlayer(userStorageDirectory=self.userStorageDirectory, torrentUrl=torrentUrl, params=params)
def swDownloadStatus(self, params={}):
import searchwindow
params = {'mode': 'downloadstatus'}
searchwindow.main(params)
def swuTorrentBrowser(self, params={}):
import searchwindow
params = {'mode': 'browser'}
searchwindow.main(params)
def swWatchedHistory(self, params={}):
import searchwindow
params = {'mode': 'watched'}
searchwindow.main(params)
def swsearch(self, params={}):
if len(Searchers().get_active())<1:
noActiveSerachers()
return
keyboard = xbmc.Keyboard('', self.localize('Search Phrase'))
keyboard.doModal()
params["query"] = keyboard.getText()
if keyboard.isConfirmed():
params["mode"] = 'search'
import searchwindow
searchwindow.main(params)
#xbmcgui.Dialog().ok('Dam Son!','Now send this shit to DiMartino')
from resources.proxy import antizapret
filename = os.path.join(tempdir(),"antizapret.pac_config")
import shelve
from contextlib import contextmanager, closing
with closing(shelve.open(filename, writeback=True)) as d:
import time
log(str(d))
log(str(time.time()))
log(str((time.time() - d["created_at"])))
ttl = 24*3600
if ttl > 0 and (time.time() - d["created_at"]) > ttl:
log('xxx')
def DownloadStatus(self, params={}):
db = DownloadDB()
@ -472,6 +421,8 @@ class Core:
self.drawItem(title, 'DownloadStatus', link, image=img, contextMenu=contextMenu, replaceMenu=False)
view_style('DownloadStatus')
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True)
#xbmc.sleep(30000)
#xbmc.executebuiltin('Container.Refresh')
return
def History(self, params={}):
@ -572,7 +523,7 @@ class Core:
self.__settings__.setSetting("lastTorrent", path)
xbmc.executebuiltin(
'XBMC.ActivateWindow(%s)' % 'Videos,plugin://plugin.video.torrenter/?action=%s&url=%s'
% ('torrentPlayer', path.encode('utf-8')))
% ('torrentPlayer', path))
if action2 == 'playnoseek' or action2 == 'playwithseek':
filename, path, url, seek, length, ind = db.get('filename, path, url, seek, length, ind', 'addtime', str(addtime))
@ -602,7 +553,7 @@ class Core:
#for favbool, bbstring in favlist:
for addtime, filename, foldername, path, url, seek, length, ind, size in items:
seek = int(seek) if int(seek) > 3*60 else 0
watchedPercent = int((float(seek) / float(length if length else 1)) * 100)
watchedPercent = int((float(seek) / float(length)) * 100)
duration = '%02d:%02d:%02d' % ((length / (60*60)), (length / 60) % 60, length % 60)
title = '[%d%%][%s] %s [%d MB]' %\
(watchedPercent, duration, filename.encode('utf-8'), int(size))
@ -776,19 +727,6 @@ class Core:
else:
if provider:
self.Content = self.contenterObject[provider]
if category == 'search' and provider and subcategory == True:
keyboard = xbmc.Keyboard('', self.localize('Search Phrase') + ':')
keyboard.doModal()
query = keyboard.getText()
if not query:
return
elif keyboard.isConfirmed():
subcategory = query
if subcategory:
apps['subcategory'] = subcategory.decode('utf-8')
else:
return
if not self.Content.isTracker():
self.draw(apps, mode='content')
else:
@ -804,7 +742,6 @@ class Core:
page = apps.get('page') if apps.get('page') else 1
sort = apps.get('sort') if apps.get('sort') else 0
apps_property={'page':page, 'sort':sort}
log('draw: '+str((category, subcategory)))
property = self.Content.get_property(category, subcategory)
contentList = self.Content.get_contentList(category, subcategory, apps_property)
if property and property.get('page'):
@ -960,7 +897,7 @@ class Core:
progressBar.update(iterator, dialogText, title, scrapers[scraper])
meta = self.Scraper.scraper(scraper, {'label': title, 'search': search, 'year': year}, self.language)
log('meta:'+str(meta))
#print 'meta:'+str(meta)
if self.language == 'ru':
if not meta.get('info').get('title') or \
not meta.get('properties').get('fanart_image') or not meta.get('icon'):
@ -974,7 +911,7 @@ class Core:
kinometa = self.Scraper.scraper(scraper, {'label': title, 'search': search,
'year': year}, self.language)
log('kinometa:'+str(kinometa))
#print 'kinometa:'+str(kinometa)
for section in kinometa.keys():
if isinstance(kinometa[section], dict):
@ -1000,13 +937,7 @@ class Core:
else:
title = meta.get('info').get('title')
listitem = xbmcgui.ListItem(title)
images = {'thumb': img, #'icon': img,
'poster': img,# 'banner': img,
#'fanart': img, 'landscape': img,
# 'clearart': image, 'clearlogo': image,
}
listitem.setArt(images)
listitem = xbmcgui.ListItem(title, iconImage=img, thumbnailImage=img)
listitem.setInfo(type='Video', infoLabels=info)
if meta:
listitem=itemScrap(listitem, meta)
@ -1056,7 +987,7 @@ class Core:
title = title.encode('utf-8', 'ignore')
except:
continue
log(str(info))
label = info.get('label').encode('utf-8', 'ignore')
if info.get('link'):
if isinstance(info.get('link'), tuple):
@ -1093,6 +1024,28 @@ class Core:
self.drawItem(title, 'downloadLibtorrent', link, image=img, info=info, contextMenu=contextMenu, replaceMenu=False)
#self.drawItem(title, 'openTorrent', link, img, info=info, contextMenu=contextMenu, replaceMenu=False)
def ActionInfo(self, params={}):
from resources.skins.DialogXml import DialogXml
get = params.get
contenter=get('provider')
infolink=get('url')
link=get('link')
if ROOT + os.sep + 'resources' + os.sep + 'contenters' not in sys.path:
sys.path.insert(0, ROOT + os.sep + 'resources' + os.sep + 'contenters')
try:
self.Content = getattr(__import__(contenter), contenter)()
except Exception, e:
log('Unable to use contenter: ' + contenter + ' at ' + ' ActionInfo(). Exception: ' + str(e))
movieInfo=self.Content.get_info(infolink)
if movieInfo:
w = DialogXml("movieinfo.xml", ROOT, "Default")
w.doModal(movieInfo, link)
del w
del movieInfo
else:
showMessage(self.localize('Information'),self.localize('Information not found!'))
def searchOption(self, params={}):
try:
apps = json.loads(urllib.unquote_plus(params.get("url")))
@ -1150,30 +1103,8 @@ class Core:
def drawItem(self, title, action, link='', image='', isFolder=True, contextMenu=None, replaceMenu=True, action2='', fileSize=0L,
info={}):
listitem = xbmcgui.ListItem(title, iconImage=image, thumbnailImage=image)
#log('[drawItem]:'+str((title, action, image, isFolder, contextMenu, replaceMenu, action2, info)))
listitem = xbmcgui.ListItem(title)
images = {'icon':image, 'thumb':image}
images = {'icon': image, 'thumb': image,
'poster': image, 'banner': image,
#'fanart': image, 'landscape': image,
#'clearart': image, 'clearlogo': image,
}
listitem.setArt(images)
"""
setArt(values) -- Sets the listitem's art
values : dictionary - pairs of { label: value }.
- Some default art values (any string possible):
- thumb : string - image filename
- poster : string - image filename
- banner : string - image filename
- fanart : string - image filename
- clearart : string - image filename
- clearlogo : string - image filename
- landscape : string - image filename
- icon : string - image filename
example:
- self.list.getSelectedItem().setArt({ 'poster': 'poster.png', 'banner' : 'banner.png' })
"""
if not info: info = {"Title": title, "plot": title}
if not isFolder and fileSize:
info['size'] = fileSize
@ -1186,19 +1117,19 @@ class Core:
else:
url = '%s?action=%s&url=%s' % (sys.argv[0], action, urllib.quote_plus(link))
if action2:
url = url + '&url2=%s' % urllib.quote_plus(ensure_str(action2))
url = url + '&url2=%s' % urllib.quote_plus(action2)
if not contextMenu:
contextMenu = [(self.localize('Search Control Window'),
'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))]
replaceMenu = False
if contextMenu:
listitem.addContextMenuItems(contextMenu, replaceItems=replaceMenu)
if isFolder:
listitem.setProperty("Folder", "true")
listitem.setInfo(type='Video', infoLabels=info)
else:
listitem.setInfo(type='Video', infoLabels=info)
listitem.setArt({'thumb': image})
if contextMenu:
listitem.addContextMenuItems(contextMenu, replaceItems=replaceMenu)
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=isFolder)
def getParameters(self, parameterString):
@ -1276,7 +1207,7 @@ class Core:
filename = os.path.join(folder, filename)
xbmc.executebuiltin('xbmc.PlayMedia("' + filename.encode('utf-8') + '")')
elif tdir and action == 'copy':
path = os.path.join(localize_path(folder), localize_path(tdir))
path=os.path.join(folder, tdir)
dirs, files=xbmcvfs.listdir(path)
if len(dirs) > 0:
dirs.insert(0, self.localize('./ (Root folder)'))
@ -1291,10 +1222,9 @@ class Core:
path=os.path.join(path, dirs[ret])
dirs, files=xbmcvfs.listdir(path)
for file in files:
file = localize_path(file)
if not xbmcvfs.exists(os.path.join(path, file)):
xbmcvfs.delete(os.path.join(path, file))
xbmcvfs.copy(os.path.join(path, file),os.path.join(folder, file))
if not xbmcvfs.exists(os.path.join(path,file)):
xbmcvfs.delete(os.path.join(path,file))
xbmcvfs.copy(os.path.join(path,file),os.path.join(folder,file))
i=i+1
showMessage(self.localize('Torrent-client Browser'), self.localize('Copied %d files!') % i, forced=True)
return
@ -1409,6 +1339,7 @@ class Core:
params["url"] = urllib.quote_plus(unescape(urllib.unquote_plus(query)))
else:
params["url"] = urllib.quote_plus(unescape(urllib.unquote_plus(defaultKeyword)))
#print str(params)
self.torrentPlayer(params)
def torrentPlayer(self, params={}):
@ -1419,23 +1350,13 @@ class Core:
if not url:
action = xbmcgui.Dialog()
url = action.browse(1, self.localize('Choose .torrent in video library'), 'video', '.torrent')
url = urllib.quote_plus(url)
torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
self.__settings__.setSetting("lastTorrent", torrent.saveTorrent(url))
self.__settings__.setSetting("lastTorrentUrl", url)
if url:
xbmc.executebuiltin("Dialog.Close(all,true)")
xbmc.executebuiltin(
'XBMC.ActivateWindow(%s)' % 'Videos,plugin://plugin.video.torrenter/?action=%s&url=%s'
% ('torrentPlayer', url))
return
if url:
if self.searchwindowmode > 1:
self.openTorrent(params)
else:
import searchwindow
params = {'mode': 'open_torrent', 'link': url}
searchwindow.main(params)
self.openTorrent(params)
def userStorage(self, params):
save=False
@ -1462,14 +1383,7 @@ class Core:
self.userStorageDirectory=dirname
def playTorrent(self, params={}):
if params.get('filename'):
torrentUrl = unquote(params.get('filename'))
else:
torrentUrl = self.__settings__.getSetting("lastTorrent")
#xbmc.executebuiltin('Action(Stop)')
if self.torrent_player != '1' and params.get('external') == '1' and not params.get('seek'):
params['seek'] = watched_seek(torrentUrl, params['url'])
torrentUrl = self.__settings__.getSetting("lastTorrent")
self.userStorage(params)
if self.torrent_player == '0':
from Player import TorrentPlayer
@ -1489,14 +1403,11 @@ class Core:
self.Player = InposPlayer(userStorageDirectory=self.userStorageDirectory, torrentUrl=torrentUrl, params=params)
else:
log(self.__plugin__ + " Unexpected access to method playTorrent() without torrent content")
elif self.torrent_player == '4':
xbmc.executebuiltin('XBMC.ActivateWindow(%s)' % 'Videos,plugin://plugin.video.yatp/?action=play&torrent=%s&file_index=%s' % (urllib.quote_plus(torrentUrl), params['url']))
#xbmc.executebuiltin('xbmc.RunPlugin("plugin://plugin.video.yatp/?action=play&torrent=%s&file_index=%s")' % (urllib.quote_plus(torrentUrl), params['url']))
elif self.torrent_player == '1':
__ASsettings__ = xbmcaddon.Addon(id='script.module.torrent.ts')
folder=__ASsettings__.getSetting("path")
folder=__ASsettings__.getSetting("folder")
save=__ASsettings__.getSetting("save")
__ASsettings__.setSetting("path", xbmc.translatePath(self.__settings__.getSetting("storage")))
__ASsettings__.setSetting("folder", self.__settings__.getSetting("storage"))
__ASsettings__.setSetting("save", self.__settings__.getSetting("keep_files"))
xbmc.sleep(1000)
torrent = Downloader.Torrent(self.userStorageDirectory, torrentUrl, self.torrentFilesDirectory)
@ -1507,7 +1418,7 @@ class Core:
label = unquote(get("label"), os.path.basename(path))
torrent.play_url_ind(int(ind), label, icon)
torrent.__exit__()
__ASsettings__.setSetting("path", folder)
__ASsettings__.setSetting("folder", folder)
__ASsettings__.setSetting("save", save)
def saveUrlTorrent(self, url):
@ -1518,11 +1429,9 @@ class Core:
request.add_header('Accept-encoding', 'gzip')
result = urllib2.urlopen(request)
if result.info().get('Content-Encoding') == 'gzip':
from StringIO import StringIO
import zlib
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
f = gzip.GzipFile(fileobj=buf)
content = f.read()
else:
content = result.read()
localFile = xbmcvfs.File(torrentFile, "wb+")
@ -1537,34 +1446,19 @@ class Core:
get = params.get
xbmc.executebuiltin('xbmc.Playlist.Clear')
url = unquote(get("url"), None)
url2 = unquote(get("url2"), None)
index = unquote(get("index"), None)
fileIndex = unquote(get("index"), None)
if url:
self.__settings__.setSetting("lastTorrentUrl", url)
classMatch = re.search('(\w+)::(.+)', url)
if classMatch:
searcher = classMatch.group(1)
url = Searchers().downloadWithSearcher(classMatch.group(2), searcher)
torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
filename = torrent.saveTorrent(url)
self.__settings__.setSetting("lastTorrent", filename)
if index == None: index = chooseFile(torrent.getContentList())
if index:
#params = {'url': index, 'filename': filename}
#if url2: params['url2'] = url2
#self.playTorrent(params)
url = 'plugin://plugin.video.torrenter/?action=playTorrent'
url += '&url=%s' % (str(index))
if url2: url += '&url2=%s' % (url2)
if filename: url += '&filename=%s' % (urllib.quote_plus(ensure_str(filename)))
xbmc.executebuiltin('xbmc.RunPlugin("%s")' % (url))
self.__settings__.setSetting("lastTorrent", torrent.saveTorrent(url))
if fileIndex==None: fileIndex = chooseFile(torrent.getContentList())
if fileIndex:
xbmc.executebuiltin('xbmc.RunPlugin("plugin://plugin.video.torrenter/?action=playTorrent&url='+fileIndex+'")')
def openTorrent(self, params={}):
get = params.get
tdir = unquote(get("url2"),None)
thumbnail = unquote(get("thumbnail"), False) or 'DefaultVideo.png'
thumbnail = unquote(get("thumbnail"), False) and True or 'DefaultVideo.png'
save_folder = unquote(get("save_folder"),'')
url = urllib.unquote_plus(get("url"))
@ -1575,12 +1469,10 @@ class Core:
url = Searchers().downloadWithSearcher(classMatch.group(2), searcher)
self.__settings__.setSetting("lastTorrent", url)
torrent = Downloader.Torrent(self.userStorageDirectory,
torrentFilesDirectory=self.torrentFilesDirectory)
torrent = Downloader.Torrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
if not torrent: torrent = Downloader.Torrent(self.userStorageDirectory,
torrentFilesDirectory=self.torrentFilesDirectory)
filename = torrent.saveTorrent(url)
self.__settings__.setSetting("lastTorrent", filename)
self.__settings__.setSetting("lastTorrent", torrent.saveTorrent(url))
append_filesize = self.__settings__.getSetting("append_filesize") == 'true'
hasSize = False
@ -1592,7 +1484,7 @@ class Core:
if append_filesize:
fileTitle += ' [%d MB]' % (size / 1024 / 1024)
hasSize = True
contentList.append([unescape(fileTitle), str(filedict.get('ind')), size])
contentList.append((unescape(fileTitle), str(filedict.get('ind')), size))
#contentList = sorted(contentList, key=lambda x: x[0])
dirList, contentListNew = cutFolder(contentList, tdir)
@ -1616,11 +1508,9 @@ class Core:
'XBMC.RunPlugin(%s)' % ('%s?action=%s&ind=%s') % (
sys.argv[0], 'downloadLibtorrent', str(identifier))),
]
link = {'url': identifier, 'thumbnail': thumbnail, 'save_folder':save_folder,
'filename':ensure_str(filename)}
link = {'url': identifier, 'thumbnail': thumbnail, 'save_folder':save_folder}
self.drawItem(title, 'playTorrent', link, image=thumbnail, isFolder=False,
action2=ids_video.rstrip(','), contextMenu=contextMenu,
replaceMenu=False, fileSize=filesize)
action2=ids_video.rstrip(','), contextMenu=contextMenu, replaceMenu=False, fileSize=filesize)
view_style('openTorrent')
p_handle = int(sys.argv[1])
try:
@ -1677,10 +1567,6 @@ class Core:
xbmc.executebuiltin(
'xbmc.RunScript(%s,)' % os.path.join(ROOT, 'controlcenter.py'))
def searchWindow(self, params={}):
import searchwindow
searchwindow.main(params)
def showFilesList(self, filesList, params={}):
get = params.get
thumbnail = unquote(get("thumbnail"),'')
@ -1698,8 +1584,8 @@ class Core:
(self.localize('Download via Libtorrent'),
'XBMC.RunPlugin(%s)' % ('%s?action=%s&url=%s') % (
sys.argv[0], 'downloadLibtorrent', urllib.quote_plus(link))),
(self.localize('Open'),
'XBMC.Container.Update(%s)' % ('%s?action=%s%s') % (
(self.localize('Open (no return)'),
'XBMC.ActivateWindow(Videos,%s)' % ('%s?action=%s%s') % (
sys.argv[0], 'openTorrent', link_url)),
]
title = self.titleMake(seeds, leechers, size, title)
@ -1759,8 +1645,8 @@ class Core:
(self.localize('Add to %s') % return_name,
'XBMC.RunPlugin(%s)' % (back_url+'&stringdata=' + urllib.quote_plus(
json.dumps(sdata)))),
(self.localize('Open'),
'XBMC.Container.Update(%s)' % ('%s?action=%s%s') % (
(self.localize('Open (no return)'),
'XBMC.ActivateWindow(Videos,%s)' % ('%s?action=%s%s') % (
sys.argv[0], 'openTorrent', link_url)),
(self.localize('Return to %s') % return_name,
'XBMC.ActivateWindow(%s)' % ('Videos,%s' % return_url)),
@ -1776,28 +1662,8 @@ class Core:
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True)
def context(self, params={}):
if not self.version_check():
xbmc.executebuiltin("Action(ContextMenu)")
sys.exit()
else:
fixed = xbmcgui.Dialog().contextmenu(list=[(self.localize('Open')),
(self.localize('Download via Libtorrent')),
(self.localize('Download via T-client'))])
if fixed == 0:
xbmc.executebuiltin('XBMC.Container.Update(%s)' %
('%s?action=%s&url=%s') %
(sys.argv[0], 'openTorrent', params['url']))
elif fixed == 1:
xbmc.executebuiltin('XBMC.RunPlugin(%s)' %
('%s?action=%s&url=%s') %
(sys.argv[0], 'downloadLibtorrent', params['url']))
elif fixed == 2:
xbmc.executebuiltin('XBMC.RunPlugin(%s)' %
('%s?action=%s&url=%s') %
(sys.argv[0], 'downloadFilesList', params['url']))
def version_check(self):
return False if int(xbmc.getInfoLabel( "System.BuildVersion" )[:2]) < 17 else True
xbmc.executebuiltin("Action(ContextMenu)")
return
def downloadFilesList(self, params={}):
from resources.utorrent.net import Download
@ -1868,23 +1734,15 @@ class Core:
f = open(url, 'rb')
torrent = f.read()
f.close()
try:
from python_libtorrent import get_libtorrent
libtorrent = get_libtorrent()
info = libtorrent.torrent_info(libtorrent.bdecode(torrent))
name = info.name()
except:
log('get_libtorrent import error, name = None')
name = None
success = Download().add(torrent, dirname)
if success:
showMessage(self.localize('Torrent-client Browser'), self.localize('Added!'), forced=True)
if ind:
id = self.chooseHASH(Download().list(), name)[0]
id = self.chooseHASH(Download().list())[0]
Download().setprio(id, ind)
def downloadLibtorrent(self, params={}):
import SkorbaLoader
import Libtorrent
get = params.get
storage=get('storage')
if not storage: self.userStorage(params)
@ -1900,7 +1758,7 @@ class Core:
if classMatch:
searcher = classMatch.group(1)
url = Searchers().downloadWithSearcher(classMatch.group(2), searcher)
torrent = SkorbaLoader.SkorbaLoader(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
torrent = Libtorrent.Libtorrent(self.userStorageDirectory, torrentFilesDirectory=self.torrentFilesDirectory)
torrent.initSession()
encryption = self.__settings__.getSetting('encryption') == 'true'
if encryption:
@ -1914,6 +1772,7 @@ class Core:
int(self.__settings__.getSetting("download_limit")) * 1000000 / 8) #MBits/second
torrent.downloadProcess(ind, encryption)
showMessage(self.localize('Download Status'), self.localize('Added!'))
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True)
def titleMake(self, seeds, leechers, size, title):
@ -1925,21 +1784,13 @@ class Core:
clAliceblue = '[COLOR FFF0F8FF]%s[/COLOR]'
clRed = '[COLOR FFFF0000]%s[/COLOR]'
title = title.replace('720p', '[B]720p[/B]').replace('1080p', '[B]1080p[/B]')
if self.torrent_info_style == 0:
title = clWhite % title
second = '[I](%s) [S/L: %d/%d] [/I]' % (size, seeds, leechers)
title += ' ' + second
elif self.torrent_info_style == 1:
title = clWhite % title
second = '[I](%s) [S/L: %d/%d] [/I]' % (size, seeds, leechers)
title = second + ' ' + title
elif self.torrent_info_style == 2:
title = clWhite % title
second = '[I](%s) [S/L: %d/%d] [/I]' % (size, seeds, leechers)
title += '\r\n' + clDimgray % second
title = title.replace('720p', '[B]720p[/B]')
title = clWhite % title + chr(10)
second = '[I](%s) [S/L: %d/%d] [/I]' % (size, seeds, leechers) + chr(10)
space = ''
for i in range(0, 180 - len(second)):
space += ' '
title += space + second
return title
def search(self, params={}):
@ -1970,7 +1821,7 @@ class Core:
else:
self.openSection(params)
def chooseHASH(self, list, name = None):
def chooseHASH(self, list):
dialog_items, dialog_items_clean = [], []
dialog_files = []
dat = list
@ -1980,29 +1831,14 @@ class Core:
for data in dat:
dialog_files.append((data['id'], data['dir'].encode('utf-8')))
dialog_items.append('[' + str(data['progress']) + '%] ' + data['name'])
dialog_items_clean.append(data['name'])
log('[chooseHASH]: name %s ' % str(name))
for data in dat:
# Debug('[chooseHASH]: '+str((data['name'], data['id'], data['dir'].encode('utf-8'))))
dialog_files.append((data['id'], data['dir'].encode('utf-8')))
dialog_items.append('[' + str(data['progress']) + '%] ' + data['name'])
dialog_items_clean.append(data['name'])
if name:
if decode_str(name) in dialog_items_clean:
return dialog_files[dialog_items_clean.index(decode_str(name))]
elif name in dialog_items_clean:
return dialog_files[dialog_items_clean.index(name)]
else:
if len(dialog_items) > 1:
ret = xbmcgui.Dialog().select(self.localize('Choose in torrent-client:'), dialog_items)
if ret > -1 and ret < len(dialog_files):
hash = dialog_files[ret]
return hash
elif len(dialog_items) == 1:
hash = dialog_files[0]
if len(dialog_items) > 1:
ret = xbmcgui.Dialog().select(self.localize('Choose in torrent-client:'), dialog_items)
if ret > -1 and ret < len(dialog_files):
hash = dialog_files[ret]
return hash
elif len(dialog_items) == 1:
hash = dialog_files[0]
return hash
def localize(self, string):
try:
@ -2014,9 +1850,23 @@ class Core:
i=delete_russian(ok=True, action='return')
showMessage(self.localize('Return Russian stuff'),self.localize('%d files have been returned')%i)
def getTorrentClientIcon(self):
client = self.__settings__.getSetting("torrent")
if client == '1':
return 'transmission.png'
elif client == '2':
return 'vuze.png'
elif client == '3':
return 'deluge.png'
elif client == '4':
return 'qbittorrent.png'
else:
return 'torrent-client.png'
def callback(self, params={}):
get = params.get
external = unquote(get("external"), None)
subaction = unquote(get("subaction"), None)
url = unquote(get("url"),'')
sdata = unquote(get("sdata"),'{}')
@ -2054,6 +1904,5 @@ class Core:
xbmc.executebuiltin('xbmc.RunPlugin("plugin://plugin.video.torrenter/?action=playTorrent&url=' + fileIndex + '")')
return
sdata['filename'] = ensure_str(url)
#log('[call]: '+sdata['filename']+json.loads(json.dumps(sdata))['filename'])
xbmc.executebuiltin('xbmc.RunPlugin(%s&stringdata=%s)' % (back_url, urllib.quote_plus(json.dumps(sdata))))
sdata['filename'] = url
xbmc.executebuiltin('xbmc.RunPlugin("' + back_url + '&stringdata=' + json.dumps(sdata) + '")')

View File

@ -21,6 +21,10 @@
import hashlib
import sys
import Libtorrent
import AceStream
import Anteoloader
import Inposloader
from functions import log
class Torrent():
@ -29,19 +33,15 @@ class Torrent():
def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
self.get_torrent_client()
if self.player == 'libtorrent':
import SkorbaLoader
self.player = SkorbaLoader.SkorbaLoader(storageDirectory, torrentFile, torrentFilesDirectory)
self.player = Libtorrent.Libtorrent(storageDirectory, torrentFile, torrentFilesDirectory)
elif self.player == 'acestream':
import AceStream
self.player = AceStream.AceStream(storageDirectory, torrentFile, torrentFilesDirectory)
elif self.player == 'anteo':
import Anteoloader
self.player = Anteoloader.AnteoLoader(storageDirectory, torrentFile, torrentFilesDirectory)
elif self.player == 'inpos':
import Inposloader
self.player = Inposloader.InposLoader(storageDirectory, torrentFile, torrentFilesDirectory)
def __exit__(self):
@ -49,7 +49,7 @@ class Torrent():
def get_torrent_client(self):
player = self.__settings__.getSetting("torrent_player")
if player == '0' or player == '4':
if player == '0':
self.player = 'libtorrent'
elif player == '1':
self.player = 'acestream'

View File

@ -28,9 +28,8 @@ import xbmc
import xbmcgui
import xbmcvfs
import xbmcaddon
import xbmcplugin
import Localization
from functions import loadsw_onstop, isSubtitle, is_writable, file_url, localize_path
from functions import localize_path, isSubtitle, is_writable, file_url
import os
@ -138,14 +137,13 @@ class InposLoader:
keep_complete = True
keep_incomplete = True
enable_dht = self.__settings__.getSetting("enable_dht") == 'true'
dht_routers = ["router.bittorrent.com:6881", "router.utorrent.com:6881"]
user_agent = ''
user_agent = 'uTorrent/2200(24683)'
self.engine = Engine(uri=file_url(self.torrentFile), download_path=self.storageDirectory,
connections_limit=connections_limit,
encryption=encryption, keep_complete=keep_complete, keep_incomplete=keep_incomplete,
dht_routers=dht_routers, use_random_port=use_random_port, listen_port=listen_port,
user_agent=user_agent, enable_dht=enable_dht)
user_agent=user_agent)
def localize(self, string):
try:
@ -154,10 +152,48 @@ class InposLoader:
return string
def getContentList(self):
from SkorbaLoader import SkorbaLoader
torrent = SkorbaLoader(self.storageDirectory, self.torrentFile)
from Libtorrent import Libtorrent
torrent = Libtorrent(self.storageDirectory, self.torrentFile)
return torrent.getContentList()
'''def getContentList_engine(self):
self.setup_engine()
files = []
filelist = []
try:
self.engine.start()
#media_types=[MediaType.VIDEO, MediaType.AUDIO, MediaType.SUBTITLES, MediaType.UNKNOWN]
iterator = 0
text = Localization.localize('Magnet-link is converting') if self.magnetLink\
else Localization.localize('Opening torrent file')
while not files and not xbmc.abortRequested and iterator < 100:
files = self.engine.list()
self.engine.check_torrent_error()
if iterator==4:
progressBar = xbmcgui.DialogProgress()
progressBar.create(Localization.localize('Please Wait'),
Localization.localize('Magnet-link is converting'))
elif iterator>4:
progressBar.update(iterator, Localization.localize('Please Wait'),text+'.' * (iterator % 4), ' ')
if progressBar.iscanceled():
progressBar.update(0)
progressBar.close()
return []
xbmc.sleep(500)
iterator += 1
for fs in files:
stringdata = {"title": ensure_str(fs.name), "size": fs.size, "ind": fs.index,
'offset': fs.offset}
filelist.append(stringdata)
except:
import traceback
log(traceback.format_exc())
finally:
self.engine.close()
return filelist'''
def saveTorrent(self, torrentUrl):
#if not xbmcvfs.exists(torrentUrl) or re.match("^http.+$", torrentUrl):
if re.match("^magnet\:.+$", torrentUrl):
@ -167,14 +203,22 @@ class InposLoader:
return self.torrentFile
else:
if not xbmcvfs.exists(self.torrentFilesPath): xbmcvfs.mkdirs(self.torrentFilesPath)
torrentFile = localize_path(os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent'))
torrentFile = os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent')
try:
if not re.match("^[htps]+?://.+$|^://.+$", torrentUrl):
log('xbmcvfs.File for %s' % torrentUrl)
if not re.match("^http\:.+$", torrentUrl):
content = xbmcvfs.File(torrentUrl, "rb").read()
else:
log('request for %s' % torrentUrl)
content = self.makeRequest(torrentUrl)
request = urllib2.Request(torrentUrl)
request.add_header('Referer', torrentUrl)
request.add_header('Accept-encoding', 'gzip')
result = urllib2.urlopen(request)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
localFile = xbmcvfs.File(torrentFile, "w+b")
localFile.write(content)
localFile.close()
@ -190,29 +234,6 @@ class InposLoader:
self.torrentFile = torrentFile
return self.torrentFile
def makeRequest(self, torrentUrl):
torrentUrl = re.sub('^://', 'http://', torrentUrl)
x = re.search("://(.+?)/|://(.+?)$", torrentUrl)
if x:
baseurl = x.group(1) if x.group(1) else x.group(2)
else:
baseurl =''
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'),
('Referer', 'http://%s/' % baseurl), ('Accept-encoding', 'gzip'), ]
opener = urllib2.build_opener()
opener.addheaders = headers
result = opener.open(torrentUrl)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
return content
def md5(self, string):
hasher = hashlib.md5()
try:
@ -223,13 +244,13 @@ class InposLoader:
def magnetToTorrent(self, magnet):
try:
from SkorbaLoader import SkorbaLoader
torrent = SkorbaLoader(self.storageDirectory, magnet)
from Libtorrent import Libtorrent
torrent = Libtorrent(self.storageDirectory, magnet)
torrent.magnetToTorrent(magnet)
self.torrentFile = torrent.torrentFile
except:
self.torrentFile = magnet
log('['+author+'Loader][magnetToTorrent]: self.torrentFile '+ensure_str((self.torrentFile)))
log('['+author+'Loader][magnetToTorrent]: self.torrentFile '+str(self.torrentFile))
class InposPlayer(xbmc.Player):
__plugin__ = sys.modules["__main__"].__plugin__
@ -253,12 +274,6 @@ class InposPlayer(xbmc.Player):
def __init__(self, userStorageDirectory, torrentUrl, params={}):
self.userStorageDirectory = userStorageDirectory
self.torrentUrl = torrentUrl
if not is_writable(self.userStorageDirectory):
xbmcgui.Dialog().ok(Localization.localize('Torrenter v2'),
Localization.localize('Your storage path is not writable or not local! Please change it in settings!'),
self.storageDirectory)
sys.exit(1)
xbmc.Player.__init__(self)
log("["+author+"Player] Initalized v"+__version__)
self.params = params
@ -268,23 +283,16 @@ class InposPlayer(xbmc.Player):
self.seek = int(self.get("seek"))
self.init()
self.setup_engine()
self.on_playback_resumed.append(self.engine.resume)
self.on_playback_paused.append(self.engine.pause)
showMessage('[%sPlayer v%s] ' % (author, __version__), self.localize('Please Wait'))
try:
self.engine.start()
self.engine.start(self.contentId)
self.setup_nextep()
self.engine.activate_file(self.contentId)
if self.buffer():
while True:
while True:
if self.buffer():
log('['+author+'Player]: ************************************* GOING LOOP')
if self.setup_play():
WatchedHistoryDB().add(self.basename, self.torrentUrl,
foldername(self.getContentList()[self.contentId]['title']),
self.watchedTime, self.totalTime, self.contentId, self.fullSize)
self.setup_subs()
self.loop()
WatchedHistoryDB().add(self.basename, self.torrentUrl, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
WatchedHistoryDB().add(self.basename, foldername(self.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize)
else:
log('['+author+'Player]: ************************************* break')
break
@ -293,15 +301,13 @@ class InposPlayer(xbmc.Player):
if not self.next_play:
xbmc.sleep(3000)
if not xbmcgui.Dialog().yesno(
self.localize('[%sPlayer v%s] ' % (author, __version__)),
self.localize('Torrent2HTTP'),
self.localize('Would you like to play next episode?')):
break
self.contentId = self.next_contentId
self.engine.activate_file(self.contentId)
showMessage('[%sPlayer v%s] ' % (author, __version__), self.localize('Please Wait'))
continue
log('['+author+'Player]: ************************************* NO! break')
break
break
except:
import traceback
log(traceback.format_exc())
@ -320,9 +326,7 @@ class InposPlayer(xbmc.Player):
#else:
#if self.seeding: self.db_delete()
showMessage(self.localize('Information'),
self.localize('Torrent downloading is stopped.'))
loadsw_onstop() # Reload Search Window
self.localize('Torrent downloading is stopped.'), forced=True)
def init(self):
self.next_contentId = False
@ -375,10 +379,9 @@ class InposPlayer(xbmc.Player):
resume_file=os.path.join(self.userStorageDirectory, 'torrents', os.path.basename(self.torrentUrl)+'.resume_data')
dht_routers = ["router.bittorrent.com:6881","router.utorrent.com:6881"]
user_agent = ''
user_agent = 'uTorrent/2200(24683)'
self.pre_buffer_bytes = int(self.__settings__.getSetting("pre_buffer_bytes"))*1024*1024
if self.__settings__.getSetting('debug') == 'true':
showMessage('[%sPlayer v%s] ' % (author, __version__), self.localize('Please Wait'))
showMessage('[%sPlayer v%s] ' % (author, __version__), self.localize('Please Wait'))
self.engine = Engine(uri=file_url(self.torrentUrl), download_path=self.userStorageDirectory,
connections_limit=connections_limit, download_kbps=download_limit, upload_kbps=upload_limit,
@ -473,7 +476,6 @@ class InposPlayer(xbmc.Player):
label = os.path.basename(file_status.name)
self.basename = label
self.seeding_run = False
self.next_dling = False
listitem = xbmcgui.ListItem(label, path=url)
if self.next_dl:
@ -508,11 +510,6 @@ class InposPlayer(xbmc.Player):
if thumbnail:
listitem.setThumbnailImage(urllib.unquote_plus(thumbnail))
self.display_name = label
log(self.display_name)
if self.get('listitem'):
listitem = self.get('listitem')
listitem.setPath(url)
player = xbmc.Player()
player.play(url, listitem)
@ -556,10 +553,7 @@ class InposPlayer(xbmc.Player):
while not xbmc.abortRequested and self.isPlaying():
#self.print_fulldebug()
status = self.engine.status()
if not self.next_dling:
file_status = self.engine.file_status(self.contentId)
else:
file_status = self.engine.file_status(self.next_contentId)
file_status = self.engine.file_status(self.contentId)
self.watchedTime = xbmc.Player().getTime()
self.totalTime = xbmc.Player().getTotalTime()
if self.iterator == 100 and debug_counter < 100:
@ -572,21 +566,16 @@ class InposPlayer(xbmc.Player):
self.iterator = int(file_status.progress * 100)
if pause and (self.__settings__.getSetting("pause_onplay") == 'true') and (self.getTime() > 0):
if pause and self.__settings__.getSetting("pause_onplay") == 'true':
pause = False
xbmc.Player().pause()
xbmc.sleep(1000)
if self.iterator == 100 and self.next_dl and not self.next_dling and isinstance(self.next_contentId,
int) and self.next_contentId != False:
self.engine.activate_file(self.next_contentId)
showMessage(self.localize('Torrent Downloading'),
self.localize('Starting download next episode!'))
log('[loop]: next_contentId '+str(self.next_contentId)+str(isinstance(self.next_contentId, int)))
file_status = self.engine.file_status(self.next_contentId)
self.basename = self.display_name = os.path.basename(file_status.name)
self.next_dling = True
#if not self.seeding_run and self.iterator == 100 and self.seeding:
#self.seeding_run = True
#self.seed(self.contentId)
#self.seeding_status = True
# xbmc.sleep(7000)
def onPlayBackStarted(self):
for f in self.on_playback_started:
@ -618,7 +607,7 @@ class InposPlayer(xbmc.Player):
def _get_status_lines(self, s, f):
return [
ensure_str(self.display_name),
localize_path(self.display_name),
"%.2f%% %s" % (f.progress * 100, self.localize(STATE_STRS[s.state])),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate, self.localize('kb/s'),
s.upload_rate, self.localize('kb/s'),

View File

@ -32,9 +32,9 @@ import xbmcgui
import xbmcvfs
import Localization
from functions import isSubtitle, DownloadDB, log, debug, is_writable,\
vista_check, windows_check, localize_path, decode_str
vista_check, windows_check, localize_path
class SkorbaLoader:
class Libtorrent:
magnetLink = None
startPart = 0
endPart = 0
@ -46,7 +46,6 @@ class SkorbaLoader:
lt = None
save_resume_data = None
__settings__ = sys.modules["__main__"].__settings__
enable_dht = __settings__.getSetting("enable_dht") == 'true'
def __init__(self, storageDirectory='', torrentFile='', torrentFilesDirectory='torrents'):
self.storageDirectory = storageDirectory
@ -54,7 +53,7 @@ class SkorbaLoader:
if not is_writable(self.storageDirectory):
xbmcgui.Dialog().ok(Localization.localize('Torrenter v2'),
Localization.localize('Your storage path is not writable or not local! Please change it in settings!'),
self.storageDirectory)
Localization.localize(self.storageDirectory))
sys.exit(1)
@ -93,14 +92,24 @@ class SkorbaLoader:
else:
if not xbmcvfs.exists(self.torrentFilesPath):
xbmcvfs.mkdirs(self.torrentFilesPath)
torrentFile = localize_path(os.path.join(self.torrentFilesPath, self.md5(torrentUrl) + '.torrent'))
torrentFile = self.torrentFilesPath + self.md5(
torrentUrl) + '.torrent'
try:
if not re.match("^[htps]+?://.+$|^://.+$", torrentUrl):
log('xbmcvfs.File for %s' % torrentUrl)
content = xbmcvfs.File(torrentUrl, "rb").read()
if not re.match("^http\:.+$", torrentUrl):
contentFile = xbmcvfs.File(torrentUrl, "rb")
content = contentFile.read()
contentFile.close()
else:
log('request for %s' % torrentUrl)
content = self.makeRequest(torrentUrl)
request = urllib2.Request(torrentUrl)
request.add_header('Referer', torrentUrl)
request.add_header('Accept-encoding', 'gzip')
result = urllib2.urlopen(request)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
localFile = xbmcvfs.File(torrentFile, "w+b")
localFile.write(content)
@ -118,7 +127,7 @@ class SkorbaLoader:
return
if not xbmcvfs.exists(self.torrentFilesPath):
xbmcvfs.mkdirs(self.torrentFilesPath)
newFile = localize_path(self.torrentFilesPath + self.md5(torrentUrl) + '.torrent')
newFile = self.torrentFilesPath + self.md5(torrentUrl) + '.torrent'
if newFile != torrentFile:
if xbmcvfs.exists(newFile):
xbmcvfs.delete(newFile)
@ -136,29 +145,6 @@ class SkorbaLoader:
self.torrentFile = torrentFile
return self.torrentFile
def makeRequest(self, torrentUrl):
torrentUrl = re.sub('^://', 'http://', torrentUrl)
x = re.search("://(.+?)/|://(.+?)$", torrentUrl)
if x:
baseurl = x.group(1) if x.group(1) else x.group(2)
else:
baseurl =''
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'),
('Referer', 'http://%s/' % baseurl), ('Accept-encoding', 'gzip'), ]
opener = urllib2.build_opener()
opener.addheaders = headers
result = opener.open(torrentUrl)
if result.info().get('Content-Encoding') == 'gzip':
buf = StringIO(result.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
content = decomp.decompress(buf.getvalue())
else:
content = result.read()
return content
def getMagnetInfo(self):
magnetSettings = {
'url': self.magnetLink,
@ -170,11 +156,14 @@ class SkorbaLoader:
}
progressBar = xbmcgui.DialogProgress()
progressBar.create(Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting'))
#try:
self.torrentHandle = self.session.add_torrent(magnetSettings)
#except:
# self.torrentHandle = self.lt.add_magnet_uri(self.session, self.magnetLink, magnetSettings)
iterator = 0
if self.enable_dht: self.torrentHandle.force_dht_announce()
while iterator < 100:
xbmc.sleep(500)
self.torrentHandle.force_dht_announce()
progressBar.update(iterator, Localization.localize('Please Wait'), Localization.localize('Magnet-link is converting')+'.' * (iterator % 4), ' ')
iterator += 1
if progressBar.iscanceled():
@ -199,9 +188,10 @@ class SkorbaLoader:
if torrentInfo:
try:
torrentFile = self.lt.create_torrent(torrentInfo)
baseName = os.path.basename(self.storageDirectory + os.sep + torrentInfo.files()[0].path)
if not xbmcvfs.exists(self.torrentFilesPath):
xbmcvfs.mkdirs(self.torrentFilesPath)
self.torrentFile = self.torrentFilesPath + self.md5(magnet) + '.torrent'
self.torrentFile = self.torrentFilesPath + self.md5(baseName) + '.torrent'
torentFileHandler = xbmcvfs.File(self.torrentFile, "w+b")
torentFileHandler.write(self.lt.bencode(torrentFile.generate()))
torentFileHandler.close()
@ -243,13 +233,12 @@ class SkorbaLoader:
return self.getContentList()[contentId]['size']
def getFilePath(self, contentId=0):
return os.path.join(self.storageDirectory, decode_str(self.getContentList()[contentId]['title']))
return os.path.join(self.storageDirectory, self.getContentList()[contentId]['title']) # .decode('utf8')
def getContentList(self):
filelist = []
#from functions import decode_str
for contentId, contentFile in enumerate(self.torrentFileInfo.files()):
stringdata = {"title": contentFile.path, "size": contentFile.size, "ind": int(contentId),
stringdata = {"title": localize_path(contentFile.path), "size": contentFile.size, "ind": int(contentId),
'offset': contentFile.offset}
filelist.append(stringdata)
return filelist
@ -318,13 +307,13 @@ class SkorbaLoader:
else:
for i in range(self.torrentFileInfo.num_pieces()):
self.torrentHandle.piece_priority(i, 6)
del db
thread.start_new_thread(self.downloadLoop, (title,))
def downloadLoop(self, title):
db = DownloadDB()
status = 'downloading'
while db.get(title) and status != 'stopped':
xbmc.sleep(3000)
status = db.get_status(title)
if not self.paused:
if status == 'pause':
@ -343,9 +332,7 @@ class SkorbaLoader:
iterator = int(s.progress * 100)
info['progress'] = iterator
db.update(title, info)
#self.debug()
xbmc.sleep(3000)
log('out of downloadLoop')
self.debug()
self.session.remove_torrent(self.torrentHandle)
return
@ -353,10 +340,9 @@ class SkorbaLoader:
self.session = self.lt.session()
self.session.set_alert_mask(self.lt.alert.category_t.error_notification | self.lt.alert.category_t.status_notification | self.lt.alert.category_t.storage_notification)
#self.session.set_alert_mask(self.lt.alert.category_t.all_categories)
if self.enable_dht:
self.session.add_dht_router("router.bittorrent.com", 6881)
self.session.add_dht_router("router.utorrent.com", 6881)
self.session.start_dht()
self.session.add_dht_router("router.bittorrent.com", 6881)
self.session.add_dht_router("router.utorrent.com", 6881)
self.session.start_dht()
self.session.start_lsd()
self.session.start_upnp()
self.session.start_natpmp()
@ -381,7 +367,7 @@ class SkorbaLoader:
session_settings['rate_limit_ip_overhead'] = True
session_settings['request_timeout'] = 1
session_settings['torrent_connect_boost'] = 50
session_settings['user_agent'] = ''
session_settings['user_agent'] = 'uTorrent/2200(24683)'
if pc_config == 0:
#good pc
session_settings['connections_limit'] = 200
@ -412,7 +398,7 @@ class SkorbaLoader:
session_settings.rate_limit_ip_overhead = True
session_settings.request_timeout = 1
session_settings.torrent_connect_boost = 100
session_settings.user_agent = ''
session_settings.user_agent = 'uTorrent/2200(24683)'
#
self.session.set_settings(session_settings)
@ -496,7 +482,7 @@ class SkorbaLoader:
self.session.stop_natpmp()
self.session.stop_upnp()
self.session.stop_lsd()
if self.enable_dht: self.session.stop_dht()
self.session.stop_dht()
def resume_data(self):
wasPaused=self.session.is_paused()

View File

@ -23,7 +23,7 @@ try:
__settings__ = xbmcaddon.Addon(id='plugin.video.torrenter')
language = ('en', 'ru', 'uk','he', 'es')[int(__settings__.getSetting("language"))]
language = ('en', 'ru', 'uk','he')[int(__settings__.getSetting("language"))]
except:
language = 'ru'
@ -31,266 +31,7 @@ except:
def localize(text):
dictionary = {
'es': {
'Seeds searching.': 'Búsqueda de fuentes',
'Please Wait': 'Espere',
'Information': 'Información',
'Torrent downloading is stopped.': 'Se detuvo la descarga del torrent',
'Search': 'Buscar',
'Seeds': 'Semillas',
'Peers': 'Pares',
'Materials are loading now.': 'Se están cargando los materiales',
'Search Phrase': 'Términos de búsqueda',
'Magnet-link is converting': 'Se está convirtiendo el enlace magnet',
'Error': 'Error',
'Your library out of date and can\'t save magnet-links.': 'Su colección está anticuada y no pueden guardarse enlaces magnet.',
'Bookmarks': 'Favoritos',
'Logout': 'Cerrar sesión',
'Login': 'Iniciar sesión',
'Recent Materials': 'Materiales recientes ',
'Register': 'Registrar',
'Bookmark': 'Favorito',
'Item successfully added to Bookmarks': 'El elemento se ha añadido a "Favoritos"',
'Item successfully removed from Bookmarks': 'El elemento se ha eliminado de "Favoritos"',
'Bookmark not added': 'No se ha añadido a "Favoritos"',
'Bookmark not removed': 'No se ha eliminado de "Favoritos"',
'Add To Bookmarks': 'Añadir a "Favoritos"',
'Remove From Bookmarks': 'Eliminar de "Favoritos"',
'Auth': 'Validación',
'Already logged in': 'Ya se había iniciado sesión',
'Input Email (for password recovery):': 'Introduzca correo electrónico (para recuperar contraseña):',
'Input Email:': 'Introduzca correo electrónico:',
'Input Password (6+ symbols):': 'Introduzca contraseña (más de 6 caracteres):',
'Input Password:': 'Introduzca contraseña',
'Login successfull': 'Se ha iniciado sesión',
'Login failed': 'Falló el inicio de sesión',
'User not logged in': 'El usuario no ha iniciado sesión',
'User successfully logged out': 'El usuario ha cerrado sesión',
'Preloaded: ': 'Carga previa: ',
'Do you want to STOP torrent downloading and seeding?': '¿Desea detener la descarga y dejar de compartir el torrent?',
'Torrent Downloading': 'Descarga de torrent',
'Auth expired, please relogin': 'Expiró la identificación. Vuelva a iniciar sesión',
'Storage': 'Almacén',
'Storage has been cleared': 'El almacén se ha vaciado',
'Clear Storage': 'Vaciar almacén',
'Popular': 'Popular',
'Views': 'Vistas',
'Uploading': 'Subiendo',
'Download': 'Descargar',
'Input symbols from CAPTCHA image:': 'Introduzca los caracteres que aparecen en la imagen:',
'Please, rate watched video:': 'Valore el vídeo que ha visto:',
'Bad': 'Malo',
'So-So': 'Regular',
'Good': 'Bueno',
'Ratings': 'Valoraciones',
'Rating': 'Valoración',
'Retry': 'Reintentar',
'%ds has left': 'Ha quedado %ds',
'File failed to play! Do you want to RETRY and buffer more?': 'Falló la reproducción del archivo. ¿Desea volver a intentarlo y aumentar el tamaño de búfer?',
'High Priority Files': 'Archivos de prioridad alta',
'Skip All Files': 'Omitir todos los archivos',
'Start': 'Iniciar',
'Stop': 'Detener',
'Play':'Reproducir',
'High Priority': 'Prioridad alta',
'Skip File': 'Omitir archivo',
'Remove': 'Eliminar',
'Remove with files': 'Eliminar con los archivos',
'Play File': 'Reproducir archivo',
'Start All Files': 'Iniciar todos los archivos',
'Stop All Files': 'Detener todos los archivos',
'Torrent-client Browser': 'Explorador de cliente de BitTorrent',
'Remote Torrent-client': 'Cliente de BitTorrent remoto',
'You didn\'t set up replacement path in setting.': 'No se ha establecido una ruta alternativa en "Ajustes".',
'For example /media/dl_torr/ to smb://SERVER/dl_torr/. Setup now?': 'Por ejemplo, /media/dl_torr/ a smb://SERVER/dl_torr/. ¿Desea establecerla ahora?',
'Manual Torrent-client Path Edit': 'Edición manual de la ruta del cliente de BitTorrent',
'Choose .torrent in video library': 'Seleccione archivo .torrent en la colección de vídeos',
'.torrent Player': 'Gestor de archivo .torrent',
'Choose directory:': 'Seleccionar directorio:',
'Starting download next episode!': 'Iniciando descarga de episodio siguiente',
'Choose in torrent-client:': 'Elija cliente torrent',
'Search Control Window': 'Control de búsquedas',
'Magnet-link (magnet:...)': 'Enlace magnet (magnet:...)',
'Not a magnet-link!': 'No es un enlace magnet',
'Magnet-link Player': 'Gestor de enlace magnet',
'UNKNOWN STATUS': 'ESTADO DESCONOCIDO',
'Checking preloaded files...': 'Comprobando archivos precargados...',
'Waiting for website response...': 'Esperando respuesta del sitio web...',
'Search and cache information for:': 'Buscar y almacenar datos para:',
'Open Torrent': 'Abrir torrent',
'Torrent list is empty.': 'La lista de torrents está en blanco',
'Content Lists': 'Listas de contenido',
'Canceled by User': 'Cancelado por el usuario',
'Do you want to search and cache full metadata + arts?': '¿Desea buscar y almacenar los metadatos y fan-arts completos?',
'This vastly decreases load speed, but you will be asked to download premade bases!': 'Esto reduce considerablemente la velocidad de carga. Pero se le solicitará descargar desde cero',
'Do you want to preload full metadata?': '¿Desea precargar los metadatos completos?',
'It is highly recommended!': 'Altamente recomendado',
'TV Shows': 'Series de televisión',
'Cartoons': 'Dibujos animados',
'Anime': 'Anime',
'Most Recent': 'Estrenos',
'Top 250 Movies': 'Las 250 mejores películas',
'Top All Time': 'Las mejores de todos los tiempos',
'by Genre': 'Por género',
'by Year': 'Por año',
'Action': 'Acción',
'Adventure': 'Aventuras',
'Animation': 'Animación',
'Biography': 'Biografías',
'Comedy': 'Comedia',
'Crime': 'Policiacas',
'Documentary': 'Documentales',
'Drama': 'Drama',
'Family': 'Todos los públicos',
'Fantasy': 'Fantásticas',
'Film-Noir': 'Cine negro',
'History': 'Historia',
'Horror': 'Terror',
'Music': 'Música',
'Musical': 'Musicales',
'Mystery': 'Misterio',
'Romance': 'Románticas',
'Sci-Fi': 'Ciencia ficción',
'Short': 'Cortos',
'Sport': 'Deportes',
'Thriller': 'Suspense',
'War': 'Bélicas',
'Western': 'Películas del Oeste',
'[B]by Site[/B]': '[B]Por sitio[/B]',
'Cartoons Series': 'Series de dibujos animados',
'Cartoons Short': 'Cortos de dibujos animados',
'Male': 'Hombre',
'Female': 'Mujer',
'Russia & USSR': 'Rusia & URSS',
'Next Page': 'Página siguiente',
'Previous Page': 'Página anterior',
'Russian Movies': 'Películas rusas',
'israeli Movies': 'Películas israelíes',
'hebdub movies': 'Películas dobladas al hebreo',
'Movies': 'Películas',
'High Resolution Movies': 'Películas en alta resolución',
'3D Movies': 'Películas en 3D',
'Movies [Bluray]': 'Películas en formato Blu-ray',
'Anime Film': 'Películas Anime',
'Anime Series': 'Series Anime',
'Can\'t download torrent, probably no seeds available.': 'No se puede descargar el torrent, probablemente no hay fuentes disponibles.',
'Personal List': 'Lista personal',
'Add to %s': 'Añadir a %s',
'Delete from %s': 'Eliminar de %s',
'Added!': 'Añadido',
'Deleted!': 'Eliminado',
'Search History': 'Historial de búsquedas',
' History ':' Historial ',
'Torrent History':'Historial de archivos torrent',
'Watched History':'Historial de vistos',
'Favourites': 'Favoritos',
'Favourites SH': 'Favoritos SH',
'Clear %s': 'Vaciar %s',
'Clear!': 'Vacío',
'kb/s': 'kbps',
'Queued': 'Situado en cola',
'Checking': 'Comprobando',
'Downloading metadata': 'Descargando metadatos',
'Downloading': 'Descargando',
'Finished': 'Finalizado',
'Seeding': 'Compartiendo',
'Allocating': 'Reservando espacio',
'Allocating file & Checking resume': 'Reservando espacio y comprobando reanudación',
'For Kids': 'Para niños',
'Adult': 'Adultos',
'Does not support magnet links!': 'No compatible con enlaces magnet',
'Reset All Cache DBs': 'Reiniciar todas las bases de datos de la caché',
'[B]Search[/B]': '[B]Buscar[/B]',
'You can always restart this by deleting DBs via Context Menu': 'Siempre se puede reiniciar esto eliminando las bases de datos a través del menú contextual',
'Your preloaded databases are outdated!': 'Las bases de datos precargadas son obsoletas',
'Do you want to download new ones right now?': '¿Desea descargar versiones actualizadas?',
'Individual Tracker Options':'Opciones individuales del rastreador',
'Downloading and copy subtitles. Please wait.':'Descargando y copiando subtítulos. Espere.',
'International Check - First Run':'Comprobación internacional - Primera ejecución.',
'Delete Russian stuff?':'¿Desea eliminar las cosas de Rusia?',
'Save to path':'Ruta para guardar',
'Return Russian stuff':'Devolver las cosas de Rusia',
'%d files have been returned':'Han vuelto %d archivos',
'Download via T-client':'Descargar a través de cliente BitTorrent',
'Download via Libtorrent':'Descargar a través de Libtorrent',
'Download Status':'Estado de la descarga',
'Download has not finished yet':'La descarga no ha finalizado todavía',
'Stopped and Deleted!':'Detenido y eliminado',
'Unpaused!':'Despausado',
'Paused!':'Pausado',
'Stopped!':'Detenido',
'Started!':'Iniciado',
'Delete and Stop':'Eliminar y detener',
'Unpause':'Despausar',
'Pause':'Pausar',
'Delete':'Eliminar',
'Open':'Abrir',
'Torrent is seeding. To stop it use Download Status.':'El torrent se está compartiendo. Para detenerlo utilice "Estado de la descarga".',
'Start All':'Iniciar todo',
'Started All!':'Se ha iniciado todo',
'Stopped All!':'Se ha detenido todo',
'Stop All':'Detener todo',
'Keyboard':'Teclado',
'Copy Files in Root':'Copiar archivos en directorio personal de root (/root)',
'Copied %d files!':'Se han copiado %d archivos',
'Add to MyShows.ru':'Añadir a MyShows.ru',
'Return to MyShows.ru':'Volver a MyShows.ru',
'Search results:':'Resultados de la búsqueda',
'by Seeders':'Por fuentes',
'by Date':'Por fecha',
'Sort':'Ordenar',
'Close':'Cerrar',
'Views:':'Vistas:',
'Rating:':'Valoración:',
'Information not found!':'No se han encontrado datos',
'Choose searcher':'Elegir buscador',
'python-libtorrent Not Found':'No se ha encontrado python-libtorrent',
'Windows has static compiled python-libtorrent included.':'Windows incluye una versión de python-libtorrent compilada estáticamente',
'You should install "script.module.libtorrent" from "MyShows.me Kodi Repo"':'Se debe instalar "script.module.libtorrrent" desde el repositorio "MyShows.me"',
'Linux x64 has not static compiled python-libtorrent included.':'Linux x64 no incluye una versión de python-libtorrent compilada estáticamente',
'You should install it by "sudo apt-get install python-libtorrent"':'Se debe instalar con "sudo apt-get install python-libtorrent"',
'Linux has static compiled python-libtorrent included but it didn\'t work.':'Linux incluye una version de python-libtorrent compilada estáticamente, pero no ha funcionado',
'As far as I know you can compile python-libtorrent for ARMv6-7.':'Por lo que yo sé, python-libtorrent se puede compilar para ARMv6-7.',
'You should search for "OneEvil\'s OpenELEC libtorrent" or use Ace Stream.':'Se debe buscar "OpenELEC libtorrent de OneEvil" o utilizar Ace Stream',
'Please use install Ace Stream APK and choose it in Settings.':'Instale APK de Ace Stream y selecciónelo en "Ajustes"',
'It is possible to compile python-libtorrent for Android, but I don\'t know how.':'Es posible compilar python-libtorrent para Android, pero no sé como hacerlo.',
'It is possible to compile python-libtorrent for OS X.':'Es posible compilar python-libtorrent para Mac OS X.',
'But you would have to do it by yourself, there is some info on github.com.':'Pero debe hacerlo por sí mismo. Hay alguna información en github.com.',
'It is NOT possible to compile python-libtorrent for iOS.':'No es posible compilar python-libtorrent para iOS',
'But you can use torrent-client control functions.':'Pero se pueden utilizar las funciones de control del cliente de BitTorrent',
'I added custom searchers to Torrenter v2!':'Se han añadido buscadores personalizados a Torrenter v2',
'Now you can use your login on trackers or write and install your own searcher!':'Ahora puede identificarse en rastreadores o crear e instalar su propio buscador',
'Would you like to install %s from "MyShows.me Kodi Repo" in Programs section?':'¿Le gustaría instalar %s desde el repositorio "MyShows.me", sección Programas?',
'Open installation window?':'¿Abrir ventana de instalación?',
'Android Support':'Soporte de Android',
'Android has no temprorary folder':'Android no tiene carpeta temporal',
'Please specify storage folder in Settings!':'Especifique la carpeta de almacenamiento en "Ajustes"',
'You have no installed or active searchers! More info in Search Control Window!':'No se han instalado o activado buscadores. Tiene más información en Control de búsquedas',
'Please contact DiMartino on kodi.tv forum. We compiled python-libtorrent for Android,':'Póngase en contacto con DiMartino en el foro de kodi.tv. Hemos compilado python-libtorren para Android,',
'but we need your help with some Torrent is seeding. To stop it use Download Status.s on different processors.':'pero necesitamos su ayuda con algún torrent que se comparte. Para detenerlo utilice Estado de la descarga. En diferentes procesadores.',
'We added Android ARM full support to Torrenter v2!':'Hemos añadido compatibilidad completa para Android ARM a Torrenter v2',
'I deleted pre-installed ones, install them in Search Control Window!':'Se eliminaron los que estaban preinstalados; instálelos desde Control de búsquedas',
'Torrenter didn\'t find %s searcher':'Torrenter no ha encontrado el buscador %s',
'Torrenter Tracker Install':'Instalación de rastreador de Torrenter',
'Ask to save':'Preguntar para guardar',
'Would you like to save this file?':'¿Le gustaría guardar este archivo?',
'Your storage path is not writable or not local! Please change it in settings!':'La ruta del almacén está protegida contra escritura o no es local. Cámbiela en "Ajustes"',
'Upgrade advancedsettings.xml':'Actualizar archivo advancedsettings.xml',
'We would like to set some advanced settings for you!':'Nos gustaría efectuar algunos ajustes avanzados por usted',
'Do it!':'Hazlo',
'Please, restart Kodi now!':'Reinicie Kodi',
'./ (Root folder)':'./ (Carpeta de root)',
'Opening torrent file':'Abriendo archivo torrent',
'New player to Torrenter v2 - Torrent2HTTP! It should be faster, stable and better with Android, also seeking works in it.':'Nuevo reproductor para Torrenter v2 - Torrent2HTTP. Debe ser más rápido, estable y mejor en Android; además, con él funcionan los intercambios.',
'Would you like to try it?':'¿Le gustaría probarlo?',
'Torrent2HTTP enabled! Can be changed in Settings.':'Se ha activado Torrent2HTTP. Puede cambiarse en "Ajustes".',
'Seeking':'Compartiendo',
'Would you like to resume from %s?':'¿Le gustaría reanudar desde %s?',
'Seeking is working only with player Torrent2HTTP.':'Compartir funciona solamente con el reproductor Torrent2HTTP.',
'Play (from %s)':'Reproducir desde %s',
'Play (from start)':'Reproducir desde el inicio',
},
'he': {
'he': {
'Seeds searching.': 'חיפוש זורעים',
'Please Wait': 'המתן',
'Information': 'מידע',
@ -330,7 +71,7 @@ def localize(text):
'Torrent Downloading': 'טורנט בהורדה',
'Auth expired, please relogin': 'Auth expired, please relogin',
'Storage': 'אחסון',
'Storage has been cleared': 'אחסון נוקה',
'Storage was cleared': 'אחסון נוקה',
'Clear Storage': 'נקה אחסון',
'Popular': 'פופולארי',
'Views': 'צפיות',
@ -483,7 +224,7 @@ def localize(text):
'Unpause':'אל תפסיק',
'Pause':'הפסק',
'Delete':'מחק',
'Open':'פתח',
'Open (no return)':'פתח',
'Torrent is seeding. To stop it use Download Status.':'Torrent is seeding. To stop it use Download Status.',
'Start All':'התחל הכל',
'Started All!':'מיין הכל',
@ -549,280 +290,7 @@ def localize(text):
'Play (from %s)':'%s נגן מ',
'Play (from start)':'נגן מהתחלה',
},
'hu': {
'Seeds searching.': 'Seederek keresése.',
'Please Wait': 'Kérlek várj',
'Information': 'Információ',
'Torrent downloading is stopped.': 'A torrent letöltése befejeződött.',
'Search': 'Keresés',
'Seeds': 'Seederek',
'Peers': 'Kapcsolatok',
'Materials are loading now.': 'A tartalmak most töltődnek.',
'Search Phrase': 'Keresés kifejezésre',
'Magnet-link is converting': 'Magnet-link konvertálása',
'Error': 'Hiba',
'Your library out of date and can\'t save magnet-links.': 'A könyvtár elavult, nem lehet lementeni a magnet-linket.',
'Bookmarks': 'Könyvjelzők',
'Logout': 'Kijelentkezés',
'Login': 'Bejelentkezés',
'Recent Materials': 'Jelenlegi tartalmak',
'Register': 'Regisztráció',
'Bookmark': 'Könyvjelző',
'Item successfully added to Bookmarks': 'Az elem sikeresen hozzáadva a Könyvjelzőkhöz',
'Item successfully removed from Bookmarks': 'Az elem sikeresen törölve a Könyvjelzőkből',
'Bookmark not added': 'A könyvjelző nem lett hozzáadva',
'Bookmark not removed': 'A könyvjelző nem lett törölve',
'Add To Bookmarks': 'Hozzáadás a Könyvjelzőkhöz',
'Remove From Bookmarks': 'Eltávolítás a Könyvjelzőkből',
'Auth': 'Hitelesítés',
'Already logged in': 'Már be vagy jelentkezve',
'Input Email (for password recovery):': 'E-mail bevitel (jelszó helyreállításához):',
'Input Email:': 'E-mail bevitel:',
'Input Password (6+ symbols):': 'Jelszó bevitel (6+ karakter):',
'Input Password:': 'Jelszó bevitel:',
'Login successfull': 'Bejelentkezés sikeres',
'Login failed': 'Bejelentkezés sikertelen',
'User not logged in': 'A felhasználó nincs bejelentkezve',
'User successfully logged out': 'A felhasználó sikeresen kijelentkezett',
'Preloaded: ': 'Előtöltés: ',
'Do you want to STOP torrent downloading and seeding?': 'Be akarod fejezni a torrent letöltését és seedelését?',
'Torrent Downloading': 'Torrent letöltése',
'Auth expired, please relogin': 'Hitelesítés lejárt, kérlek jelentkezz be újra',
'Storage': 'Tárolóhely',
'Storage has been cleared': 'A tárolóhely megtisztítva',
'Clear Storage': 'Tárolóhely Megtisztítása',
'Popular': 'Népszerű',
'Views': 'Nézetek',
'Uploading': 'Feltöltés',
'Download': 'Letöltés',
'Input symbols from CAPTCHA image:': 'Szimbólumok bevitele a CAPTCHA képről:',
'Please, rate watched video:': 'Kérlek, értékeld a megnézett videót:',
'Bad': 'Rossz',
'So-So': 'Elmegy',
'Good': '',
'Ratings': 'Értékelések',
'Rating': 'Értékelés',
'Retry': 'Újra',
'%ds has left': '%ds van hátra',
'File failed to play! Do you want to RETRY and buffer more?': 'A fájl lejátszása hibába ütközött. Újra akarod indítani és többet bufferelni?',
'High Priority Files': 'Magas prioritású fájlok',
'Skip All Files': 'Összes fájl kihagyása',
'Start': 'Indít',
'Stop': 'Megállít',
'Play':'Lejátszás',
'High Priority': 'Magas prioritás',
'Skip File': 'Fájl kihagyása',
'Remove': 'Eltávolítás',
'Remove with files': 'Eltávolítás a fájlokkal együtt',
'Play File': 'Fájl lejátszása',
'Start All Files': 'Összes fájl elindítása',
'Stop All Files': 'Összes fájl megállítása',
'Torrent-client Browser': 'Torrentkliens Böngésző',
'Remote Torrent-client': 'Távoli torrentkliens',
'You didn\'t set up replacement path in setting.': 'Nem állítottál be helyettesítő elérési utat a beállításokban.',
'For example /media/dl_torr/ to smb://SERVER/dl_torr/. Setup now?': 'Például /media/dl_torr/ a smb://SERVER/dl_torr/ - hez. Beállítod most?',
'Manual Torrent-client Path Edit': 'Kézi torrentkliens elérési út módosítás',
'Choose .torrent in video library': '.torrent kiválasztása a videó könyvtárban',
'.torrent Player': '.torrent Lejátszó',
'Choose directory:': 'Könyvtár kiválasztása:',
'Starting download next episode!': 'Elindul a következő epizód letöltése!',
'Choose in torrent-client:': 'Kiválasztás a torrentkliensben:',
'Search Control Window': 'Keresést Kezelő Ablak',
'Magnet-link (magnet:...)': 'Magnet-link (magnet:...)',
'Not a magnet-link!': 'Ez nem magnet-link!',
'Magnet-link Player': 'Magnet-link Lejátszó',
'UNKNOWN STATUS': 'ISMERETLEN STÁTUSZ',
'Checking preloaded files...': 'Előtöltött fájlok ellenőrzése...',
'Waiting for website response...': 'Várakozás a weboldal válaszára...',
'Search and cache information for:': 'Információ keresése és gyorsítótárazása:',
'Open Torrent': 'Torrent megnyitása',
'Torrent list is empty.': 'A torrent lista üres.',
'Content Lists': 'Tartalmak Listája',
'Canceled by User': 'Leállítva felhasználó által',
'Do you want to search and cache full metadata + arts?': 'Szeretnéd lekérni és gyorsítótárazni a metaadatokat és a képeket?',
'This vastly decreases load speed, but you will be asked to download premade bases!': 'Ez jelentősen csökkenti a betöltési sebességet, megkérünk, hogy töltsd le az előre elkészített adatbázisokat!',
'Do you want to preload full metadata?': 'Előtöltöd a metaadatokat?',
'It is highly recommended!': 'Ez erősen ajánlott!',
'TV Shows': 'Sorozatok',
'Cartoons': 'Rajzfilmek',
'Anime': 'Anime',
'Most Recent': 'Legújabb',
'Top 250 Movies': 'Top 250 Filmek',
'Top All Time': 'Top Mindenkori',
'by Genre': 'Műfaj alapján',
'by Year': 'Évszám alapján',
'Action': 'Akció',
'Adventure': 'Kaland',
'Animation': 'Animációs',
'Biography': 'Életrajzi',
'Comedy': 'Vígjáték',
'Crime': 'Bűnügyi',
'Documentary': 'Dokumentum',
'Drama': 'Dráma',
'Family': 'Családi',
'Fantasy': 'Fantasy',
'Film-Noir': 'Film-Noir',
'History': 'Történelmi',
'Horror': 'Horror',
'Music': 'Zenei',
'Musical': 'Musical',
'Mystery': 'Misztikus',
'Romance': 'Romantikus',
'Sci-Fi': 'Sci-Fi',
'Short': 'Rövidfilm',
'Sport': 'Sport',
'Thriller': 'Thriller',
'War': 'Háborús',
'Western': 'Western',
'[B]by Site[/B]': '[B]Weboldal alapján[/B]',
'Cartoons Series': 'Rajzfilmsorozatok',
'Cartoons Short': 'Rövid rajzfilmek',
'Male': 'Férfi',
'Female': 'Női',
'Russia & USSR': 'Oroszország & Szovjetunió',
'Next Page': 'Következő oldal',
'Previous Page': 'Előző oldal',
'Russian Movies': 'Orosz filmek',
'israeli Movies': 'Izraeli fimek',
'hebdub movies': 'hebdub filmek',
'Movies': 'Filmek',
'High Resolution Movies': 'HD filmek',
'3D Movies': '3D filmek',
'Movies [Bluray]': 'Filmek [Bluray]',
'Anime Film': 'Anime filmek',
'Anime Series': 'Anime sorozatok',
'Can\'t download torrent, probably no seeds available.': 'Nem lehet letölteni a torrentet, valószínűleg nincsenek elérhető seederek.',
'Personal List': 'Saját lista',
'Add to %s': 'Hozzáadás ehhez %s',
'Delete from %s': 'Eltávolítás innen %s',
'Added!': 'Hozzáadva!',
'Deleted!': 'Eltávolítva!',
'Search History': 'Keresési Előzmények',
' History ':' Előzmények ',
'Torrent History':'Torrent Előzmények',
'Watched History':'Megtekintett Előzmények',
'Favourites': 'Kedvencek',
'Favourites SH': 'Kedvencek SH',
'Clear %s': 'Tisztítás %s',
'Clear!': 'Tisztítás!',
'kb/s': 'kb/s',
'Queued': 'Sorba állítva',
'Checking': 'Ellenőrzés',
'Downloading metadata': 'Metaadatok letöltése',
'Downloading': 'Letöltés',
'Finished': 'Befejezve',
'Seeding': 'Seedelés',
'Allocating': 'Összeállítás',
'Allocating file & Checking resume': 'Fájl összeállítása és folytatás ellenőrzése',
'For Kids': 'Gyerekek számára',
'Adult': 'Felnőtt',
'Does not support magnet links!': 'Nem támogatja a magnet-linkeket!',
'Reset All Cache DBs': 'Összes gyorsítótár adatbázis visszaállítása',
'[B]Search[/B]': '[B]Keresés[/B]',
'You can always restart this by deleting DBs via Context Menu': 'Mindig visszaállíthatja az adatbázis törlésével a helyi menün keresztül',
'Your preloaded databases are outdated!': 'Az előtöltött adatbázisok elavultak!',
'Do you want to download new ones right now?': 'Szeretnéd letölteni az újakat most?',
'Individual Tracker Options':'Egyéni tracker beállítások',
'Downloading and copy subtitles. Please wait.':'Feliratok letöltése és másolása. Kérlek, várj.',
'International Check - First Run':'International ellenőrzés - első futtatás',
'Delete Russian stuff?':'Orosz tartalom törlése?',
'Save to path':'Mentés a mappába',
'Return Russian stuff':'Orosz tartalom visszaállítása',
'%d files have been returned':'%d fájlok visszaállítva',
'Download via T-client':'Letöltés T-kliensen keresztül',
'Download via Libtorrent':'Letöltés Libtorrenten keresztül',
'Download Status':'Letöltési Állapot',
'Download has not finished yet':'A letöltés még nem fejeződött be',
'Stopped and Deleted!':'Leállítva és eltávolítva!',
'Unpaused!':'Újra elindítva!',
'Paused!':'Szünetelve!',
'Stopped!':'Megállítva!',
'Started!':'Elindítva!',
'Delete and Stop':'Megállít és eltávolít',
'Unpause':'Újra elindít',
'Pause':'Szüneteltet',
'Delete':'Eltávolít',
'Open':'Megnyitás',
'Torrent is seeding. To stop it use Download Status.':'Torrent seedelés alatt. Ahhoz, hogy megállítsd használd a Letöltési Állapotot.',
'Start All':'Összes elindítása',
'Started All!':'Összes elindítva!',
'Stopped All!':'Összes megállítva!',
'Stop All':'Összes megállítása',
'Keyboard':'Billentyűzet',
'Copy Files in Root':'Fájlok másolása a Rendszerkönyvtárba',
'Copied %d files!':'%d fájl átmásolva!',
'Add to MyShows.ru':'Hozzáadás MyShows.ru-hoz',
'Return to MyShows.ru':'Visszatérés a MyShows.ru-hoz',
'Search results:':'Keresési eredmények:',
'by Seeders':'Seederek alapján',
'by Date':'Dátum alapján',
'Sort':'Rendezés',
'Close':'Bezár',
'Views:':'Nézetek:',
'Rating:':'Értékelés:',
'Information not found!':'Nem található információ!',
'Choose searcher':'Válassz keresőt',
'python-libtorrent Not Found':'python-libtorrent nem található',
'Windows has static compiled python-libtorrent included.':'A Windows statikusan fordított python-libtorrentet tartalmaz.',
'You should install "script.module.libtorrent" from "MyShows.me Kodi Repo"':'Telepítsd a "script.module.libtorrent"-et a "MyShows.me Kodi Repo"-ból',
'Linux x64 has not static compiled python-libtorrent included.':'A Linux x64 statikusan fordított python-libtorrentet nem tartalmaz.',
'You should install it by "sudo apt-get install python-libtorrent"':'Telepítsd ezzel a paranccsal "sudo apt-get install python-libtorrent"',
'Linux has static compiled python-libtorrent included but it didn\'t work.':'A Linux statikusan fordított python-libtorrentet tartalmaz de nem működik.',
'As far as I know you can compile python-libtorrent for ARMv6-7.':'Ahogy én tudom, le lehet fordítani a python-libtorrentet ARMv6-7-ra',
'You should search for "OneEvil\'s OpenELEC libtorrent" or use Ace Stream.':'Keress rá "OneEvil\'s OpenELEC libtorrent"-re vagy használj Ace Streamet',
'Please use install Ace Stream APK and choose it in Settings.':'Kérlek használj Ace Stream APK-t és válaszd ki a beállításokban.',
'It is possible to compile python-libtorrent for Android, but I don\'t know how.':'Lehetséges, hogy lefordítható a python-libtorrent Android-ra, de nem tudom hogyan.',
'It is possible to compile python-libtorrent for OS X.':'Lehetséges, hogy lefordítható a python-libtorrent OS X-re.',
'But you would have to do it by yourself, there is some info on github.com.':'De ezt magadnak kell megcsinálnod, van néhány infó erről a github.com-on.',
'It is NOT possible to compile python-libtorrent for iOS.':'iOS-re nem lehet lefordítani a python-libtorrentet.',
'But you can use torrent-client control functions.':'De a torrentkliens kezelőt funkciót tudod használni.',
'I added custom searchers to Torrenter v2!':'Hozzáadtam egyéni keresőket a Torrenter v2-höz!',
'Now you can use your login on trackers or write and install your own searcher!':'Most már be tudsz lépni a trackerekre, vagy megírhatod és feltelepítheted a saját keresődet!',
'Would you like to install %s from "MyShows.me Kodi Repo" in Programs section?':'Szeretnéd telepíteni %s a "MyShows.me Kodi Repo"-ból?',
'Open installation window?':'Telepítő ablak megnyitása?',
'Android Support':'Android támogatás',
'Android has no temprorary folder':'Az Android nem rendelkezik ideiglenes mappával',
'Please specify storage folder in Settings!':'Kérlek add meg a tárolóhely mappáját a beállításokban!',
'You have no installed or active searchers! More info in Search Control Window!':'Nincsenek telepített vagy aktív keresők! Több információ a Keresést Kezelő Abalakban.',
'Please contact DiMartino on kodi.tv forum. We compiled python-libtorrent for Android,':'Kérünk lépj kapcsolatba DiMartino-val a kodi.tv fórumon. Lefordítottuk a python-libtorrentet Androidhoz,',
'but we need your help with some tests on different processors.':'de szükségünk lesz még néhány tesztre különböző processzorokon.',
'We added Android ARM full support to Torrenter v2!':'A Torrenter v2 számara teljesen támogatottá tettük az Android ARM-t!',
'I deleted pre-installed ones, install them in Search Control Window!':'Töröltem az összes előre telepítettet, telepítsd őket a Keresést Kezelő Ablakban!',
'Torrenter didn\'t find %s searcher':'A Torrenter nem találja a %s keresőt',
'Torrenter Tracker Install':'Torrent tracker telepítés',
'Ask to save':'Mentés kérése',
'Would you like to save this file?':'El szeretnéd menteni ez a fájlt?',
'Your storage path is not writable or not local! Please change it in settings!':'A tárolóhely elérési útja nem írható vagy nem elérhető! Kérlek változtatsd meg a beállításokban!',
'Upgrade advancedsettings.xml':'advancedsettings.xml frissítése',
'We would like to set some advanced settings for you!':'Be szeretnénk állítani néhány haladó beállítást!',
'Do it!':'Csináld!',
'Please, restart Kodi now!':'Kérlek, indítsd újra a Kodit, most.',
'./ (Root folder)':'./ (Rendszerkönyvtár)',
'Opening torrent file':'Torrent fájl megnyitása',
'New player to Torrenter v2 - Torrent2HTTP! It should be faster, stable and better with Android, also seeking works in it.':'Új lejátszó a Torrenter v2-höz - Torrent2HTTP: Gyorsabb, stabilabb és jobb Androiddal, valamint a keresés is működik vele.',
'Would you like to try it?':'Ki szeretnéd próbálni?',
'Torrent2HTTP enabled! Can be changed in Settings.':'Torrent2HTTP engedélyezve! Ezen a beállításokban tudsz változtatni.',
'Seeking':'Keresés',
'Would you like to resume from %s?':'Szeretnéd folytatni innen: %s?',
'Seeking is working only with player Torrent2HTTP.':'A keresés csak a Torrent2HTTP lejátszóval működik.',
'Play (from %s)':'Lejátszás (innen %s)',
'Play (from start)':'Lejátszás (az elejétől)',
},
'ru': {
'Torrenter has a better view style for Kodi 17 default skin.':'У Torrenter есть оптимизированный вид под новый скин Kodi 17.',
'is recommended for Kodi 17 users and now out of beta.': 'рекомендовано пользователям Kodi 17 и вышло из беты.',
'You can disable it usage in Settings.':'Его можно отключить в настройках плагина.',
'Move Up': 'Вверх',
'Torrenter Search Window': 'Окно Поиска Torrenter',
'Cancel': 'Отмена',
'Clear History': 'Очистить Историю',
'Play (with seek)': 'Играть (перемотка)',
'Mass Control':'Массовое Управление',
'Info':'Инфо',
'Delete torrent with files?':'Вы уверены, что хотите удалить торрент с файлами?',
'Fav. / Unfav.':'Доб./удал. Избранное',
'Search Window': 'Окно поиска',
'Context menu': 'Контекстное меню',
'Seeds searching.': 'Идёт поиск сидов.',
'Please Wait': 'Подождите',
'Information': 'Информация',
@ -862,7 +330,7 @@ def localize(text):
'Torrent Downloading': 'Загрузка торрента',
'Auth expired, please relogin': 'Авторизация истекла, пожалуйста войдите снова',
'Storage': 'Хранилище',
'Storage has been cleared': 'Хранилище очищено',
'Storage was cleared': 'Хранилище очищено',
'Clear Storage': 'Очистить хранилище',
'Popular': 'Популярное',
'Views': 'Просмотров',
@ -908,7 +376,7 @@ def localize(text):
'Checking preloaded files...': 'Проверка файлов...',
'Waiting for website response...': 'Ожидание ответа сайта...',
'Search and cache information for:': 'Поиск и кэширование информации для:',
'Open Torrent': 'Открыть Торрент',
'Open Torrent': 'Открыть Список файлов',
'Torrent list is empty.': 'Список раздач пуст.',
'Content Lists': 'Списки Медиа',
'Canceled by User': 'Отменено пользователем',
@ -1015,7 +483,7 @@ def localize(text):
'Unpause':'Возобновить',
'Pause':'Пауза',
'Delete':'Удалить',
'Open':'Открыть',
'Open (no return)':'Открыть (без возврата)',
'Torrent is seeding. To stop it use Download Status.':'Сидирование. Для остановки используйте Статус Загрузки.',
'Start All':'Запустить Все',
'Started All!':'Все Запущены!',
@ -1023,7 +491,6 @@ def localize(text):
'Stop All':'Остановить Все',
'Keyboard':'Клавиатура',
'Copy Files in Root':'Скопировать файлы в Корень',
'Copy in Root': 'Скопировать в Корень',
'Copied %d files!':'Скопировано %d файлов!',
'Return to %s':'Вернуться в %s',
'Search results:':'Результаты поиска:',
@ -1274,7 +741,7 @@ def localize(text):
'Unpause':'Відновити',
'Pause':'Пауза',
'Delete':'Видалити',
'Open':'Відкрити',
'Open (no return)':'Відкрити (без повернення)',
'Torrent is seeding. To stop it use Download Status.':'Сідування. Для зупинки використовуйте Статус завантаження.',
'Start All':'Запустити все',
'Started All!':'Все запущене!',

View File

@ -30,7 +30,7 @@ import Downloader
import xbmcgui
import xbmcvfs
import Localization
from functions import calculate, showMessage, clearStorage, WatchedHistoryDB, DownloadDB, get_ids_video, log, debug, foldername, ensure_str, loadsw_onstop, decode_str
from functions import calculate, showMessage, clearStorage, WatchedHistoryDB, DownloadDB, get_ids_video, log, debug, foldername
ROOT = sys.modules["__main__"].__root__
RESOURCES_PATH = os.path.join(ROOT, 'resources')
@ -166,12 +166,8 @@ class TorrentPlayer(xbmc.Player):
debug('************************************* GOING LOOP')
self.torrent.startSession()
self.torrent.continueSession(self.contentId)
WatchedHistoryDB().add(self.basename, self.torrentUrl,
foldername(self.torrent.getContentList()[self.contentId]['title']),
self.watchedTime, self.totalTime, self.contentId,
self.fullSize / 1024 / 1024)
self.loop()
WatchedHistoryDB().add(self.basename, self.torrentUrl, foldername(self.torrent.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize / 1024 / 1024)
WatchedHistoryDB().add(self.basename, foldername(self.torrent.getContentList()[self.contentId]['title']), self.watchedTime, self.totalTime, self.contentId, self.fullSize / 1024 / 1024)
else:
break
debug('************************************* GO NEXT?')
@ -197,13 +193,11 @@ class TorrentPlayer(xbmc.Player):
else:
if self.seeding_status:
showMessage(self.localize('Information'),
self.localize('Torrent is seeding. To stop it use Download Status.'))
self.localize('Torrent is seeding. To stop it use Download Status.'), forced=True)
else:
if self.seeding: self.db_delete()
showMessage(self.localize('Information'),
self.localize('Torrent downloading is stopped.'))
loadsw_onstop() # Reload Search Window
self.localize('Torrent downloading is stopped.'), forced=True)
def init(self):
self.next_dl = True if self.__settings__.getSetting('next_dl') == 'true' and self.ids_video else False
@ -344,12 +338,12 @@ class TorrentPlayer(xbmc.Player):
response = json.loads(request)
xbmc.sleep(1000)
if self.get('listitem'):
listitem = self.get('listitem')
listitem.setPath(path)
if response:
xbmc.Player().play(path, listitem)
#playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
#playlist.clear()
#playlist.add(path, listitem)
#xbmc.Player().play(playlist)
xbmc.sleep(2000) # very important, do not edit this, podavan
i = 0
@ -373,7 +367,7 @@ class TorrentPlayer(xbmc.Player):
if len(subs) > 0:
self.torrent.startSession()
showMessage(self.localize('Information'),
self.localize('Downloading and copy subtitles. Please wait.'))
self.localize('Downloading and copy subtitles. Please wait.'), forced=True)
for ind, title in subs:
self.torrent.continueSession(ind)
while iterator < 100:
@ -388,11 +382,10 @@ class TorrentPlayer(xbmc.Player):
addition = os.path.dirname(title).lstrip(folder + os.sep).replace(os.sep, '.').replace(' ', '_').strip()
ext = temp.split('.')[-1]
temp = temp[:len(temp) - len(ext) - 1] + '.' + addition + '.' + ext
newFileName = os.path.join(ensure_str(os.path.dirname(decode_str(path))), ensure_str(temp))
debug('[setup_subs]: {} {}'.format(newFileName, title))
newFileName = os.path.join(os.path.dirname(path), temp)
debug('[setup_subs]: '+str((os.path.join(os.path.dirname(os.path.dirname(path)),title),newFileName)))
if not xbmcvfs.exists(newFileName):
fileName = os.path.join(ensure_str(os.path.dirname(os.path.dirname(decode_str(path)))), ensure_str(title))
xbmcvfs.copy(fileName, newFileName)
xbmcvfs.copy(os.path.join(os.path.dirname(os.path.dirname(path)), title), newFileName)
def onPlayBackStarted(self):
for f in self.on_playback_started:
@ -462,7 +455,7 @@ class TorrentPlayer(xbmc.Player):
if self.iterator == 100 and self.next_dl and not self.next_dling and isinstance(self.next_contentId,
int) and self.next_contentId != False:
showMessage(self.localize('Torrent Downloading'),
self.localize('Starting download next episode!'))
self.localize('Starting download next episode!'), forced=True)
self.torrent.stopSession()
# xbmc.sleep(1000)
path = self.torrent.getFilePath(self.next_contentId)
@ -472,10 +465,10 @@ class TorrentPlayer(xbmc.Player):
def _get_status_lines(self, s):
return [
ensure_str(self.display_name),
"%.2f%% %s" % (s.progress * 100, self.localize(STATE_STRS[s.state])),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate / 1024, self.localize('kb/s'),
s.upload_rate / 1024, self.localize('kb/s'),
self.display_name+'; '+self.torrent.get_debug_info('dht_state'),
"%.2f%% %s; %s" % (s.progress * 100, self.localize(STATE_STRS[s.state]).decode('utf-8'), self.torrent.get_debug_info('trackers_sum')),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate / 1024, self.localize('kb/s').decode('utf-8'),
s.upload_rate / 1024, self.localize('kb/s').decode('utf-8'),
s.num_seeds, s.num_peers)
]

View File

@ -18,38 +18,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
import urllib
import urllib2
import cookielib
import re
import tempfile
import hashlib
import os
from StringIO import StringIO
import zlib
import gzip
import socket
import sys
proxy = int(sys.modules["__main__"].__settings__.getSetting("proxy"))
if proxy == 2:
socks_ip = sys.modules["__main__"].__settings__.getSetting("socks_ip")
from resources.proxy import socks
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, socks_ip,
int(sys.modules["__main__"].__settings__.getSetting("socks_port")))
socket.socket = socks.socksocket
import urllib
import urllib2
import cookielib
import xbmcgui
import xbmc
import Localization
from functions import log, debug, showMessage
import ssl
#ssl._create_default_https_context = ssl._create_unverified_context
class SearcherABC:
searchIcon = '/icons/video.png'
sourceWeight = 1
cookieJar = None
timeout_multi=int(sys.modules["__main__"].__settings__.getSetting("timeout"))
proxy=int(sys.modules["__main__"].__settings__.getSetting("proxy"))
__plugin__='Empty v 0 0 0'
baseurl = 'site.com'
@ -111,25 +103,25 @@ class SearcherABC:
def makeRequest(self, url, data={}, headers={}):
self.load_cookie()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
if proxy == 1:
opener = None
if self.proxy == 1:
try:
from resources.proxy import antizapret
opener.add_handler(antizapret.AntizapretProxyHandler())
opener = urllib2.build_opener(antizapret.AntizapretProxyHandler(), urllib2.HTTPCookieProcessor(self.cookieJar))
config = antizapret.config()
self.debug('[antizapret]: '+str(config["domains"]))
self.debug('[antizapret]: '+str(config["server"]))
except:
showMessage('AntiZapret', Localization.localize('Error'))
self.debug('[antizapret]: OFF!')
# python ssl Context support - PEP 0466
if 'https:' in url:
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
log('urllib2.HTTPSHandler(context=ssl_context)')
opener.add_handler(urllib2.HTTPSHandler(context=ssl_context))
#elif self.proxy == 2:
# from resources.proxy import immunicity
# opener = urllib2.build_opener(immunicity.ImmunicityProxyHandler(), urllib2.HTTPCookieProcessor(self.cookieJar))
# config = immunicity.config()
# self.debug('[immunicity]: '+str(config["domains"]))
# self.debug('[immunicity]: '+str(config["server"]))
if not opener:
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
opener.addheaders = headers
if 0 < len(data):
encodedData = urllib.urlencode(data)
@ -148,14 +140,13 @@ class SearcherABC:
self.log('[makeRequest]: HTTP Error, e.code=' + str(e.code))
return
#self.cookieJar.extract_cookies(response, urllib2)
#self.log(response.info().get('Set-Cookie'))
if response.info().get('Content-Encoding') == 'gzip':
buf = StringIO(response.read())
decomp = zlib.decompressobj(16 + zlib.MAX_WBITS)
text = decomp.decompress(buf.getvalue())
f = gzip.GzipFile(fileobj=buf)
response = f.read()
else:
text = response.read()
return text
response = response.read()
return response
def askCaptcha(self, url):
temp_dir = self.tempdir()

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.torrenter" name="Torrenter" version="2.6.7" provider-name="inpos">
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.torrenter" name="Torrenter" version="2.5.2" provider-name="DiMartino">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.libtorrent"/>
@ -8,7 +8,6 @@
<import addon="script.module.torrent2http"/>
<import addon="script.module.pyrrent2http"/>
<import addon="script.module.chardet" />
<import addon="script.module.pyxbmct"/>
</requires>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py">
<provides>video</provides>
@ -24,13 +23,10 @@
</summary>
<description lang='ru'>Так же плагин может добавлять, проигрывать и управлять скачками в торрент клиентах (uTorrent, Transmisson, Deluge и Vuse, qBittorrent) или средставми python-libtorrent.
</description>
<disclaimer lang='ru'>GNU GPLv3 http://www.gnu.org/licenses/</disclaimer>
<summary lang='es'>Complemento que nos permite ver vídeos que se distribuyen en redes BitTorrent sin necesidad de descargarlos previamente por completo.
</summary>
<description lang='es'>También gestiona torrents y nos deja elegir entre su propio cliente interno y otros externos (μTorrent, Transmission, Deluge, Vuze, qBittorrent), el cliente BitTorrent con el que realizar las descargas.
</description>
<forum>https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html</forum>
<website>http://xbmc.ru/forum/showthread.php?t=6837</website>
<source>https://github.com/inpos/plugin.video.torrenter</source>
<disclaimer lang='ru'>GNU GPLv3 http://www.gnu.org/licenses/</disclaimer>
<forum>https://forums.tvaddons.ag/addon-releases/29224-torrenter-v2.html</forum>
<website>http://xbmc.ru/forum/showthread.php?t=6837</website>
<email>skype:kyonkodura</email>
<source>https://github.com/DiMartinoXBMC/plugin.video.torrenter</source>
</extension>
</addon>

View File

@ -1,58 +1,13 @@
[B]Version 2.6.7[/B]
[+] Теперь можно указать порт SOCKS-прокси, при использоании прокси Tor
[+] Списки медиа: исправлен RiperAM
[+] .torrent Player: Исправлена работа c длинными названиями
[-] Удален user-agent "uTorrent/2200(24683)" во избежании бана
[B]Version 2.6.6[/B]
[+] Добавлена поддержка прокси для windows
[+] Теперь можно указать адрес SOCKS-прокси, при использоании прокси Tor
[B]Version 2.6.5[/B]
[+] Восстановлена работа RiperAM в списках медиа.
[+] Разделена настройка прокси: для поиска и для списков медиа
[B]Version 2.6.4[/B]
[+] Проблемы с сетью: добавлена поддержка Tor для поиска торрентов и заказчки torrent-файлов
[B]Version 2.6.3[/B]
[+] Списки медиа: возобновлена работа получения метаданных
[B]Version 2.6.2[/B]
[+] История Просмотров: Перемотка при внешнем вызове
[B]Version 2.6.1[/B]
[+] Окно Поиска: Использование окна в сторонних плагинах
[B]Version 2.6.0[/B]
[+] Окно Поиска: Полноценный релиз
[+] Настройки: Добавлена возможность отключения уведомлений
[+] История Просмотров: При аварийном выходе данные остаются
[B]Version 2.5.6[/B]
[+] Списки Медиа: Добавлен RuTorOrg
[B]Version 2.5.5[/B]
[+] Control Center: Исправлена работа выбора трекеров для определенного запроса
[+] Торрент-клиент: При скачивании одного файла торрент-клиентом теперь автоматически выбирается раздача
[+] .torrent Player: Исправлена работа (спасибо kolosovski)
[+] Окно Поиска: Добавлено Окно Поиска в режиме тестирования
[B]Version 2.5.4[/B]
[+] Исправлено "открыть без возврата". Спасибо viorel-m.
[B]Version 2.5.3[/B]
[+] Венгерский язык
[+] Совместимость с Коди 17
English changelog at http://bit.ly/1MfSVUP
[B]Version 2.5.2[/B]
[+] Упорядочивание по размеру файла
[+] Упорядочивание по разверу файла.
[B]Version 2.5.1[/B]
[+] Исправлена работа с кодировками
[+] Исправлена работа с кодировками.
[B]Version 2.5.0[/B]
[+] НОВЫЙ проигрыватель pyrrent2http от inpos! Аналог torrent2http написаный на python, а не на GO
[+] НОВЫЙ проигрыватель pyrrent2http от inpos! Аналог torrent2http написаный на python, а не на GO.
[+] Проигрыватель: Ускорена повторная работа с торрентом - resume data (спасибо srg70 и RussakHH)
[B]Version 2.4.6[/B]

View File

@ -24,7 +24,7 @@ import xbmcaddon
import xbmc
import xbmcgui
from functions import getParameters, HistoryDB, Searchers, log
import pyxbmct
from resources.pyxbmct.addonwindow import *
__settings__ = xbmcaddon.Addon(id='plugin.video.torrenter')
__language__ = __settings__.getLocalizedString
@ -39,7 +39,7 @@ if len(sys.argv) > 1:
else:
params = {}
class ControlCenter(pyxbmct.AddonDialogWindow):
class ControlCenter(AddonDialogWindow):
def __init__(self, title, addtime=None):
super(ControlCenter, self).__init__(title)
@ -57,17 +57,18 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
if not providers:
self.db.set_providers(addtime, self.dic)
else:
for searcher in self.dic.keys():
for searcher in self.keys:
self.dic[searcher] = False
for searcher in providers:
try:
if searcher in self.dic.keys():
if searcher in self.keys:
self.dic[searcher] = True
except:
log('self.dic[searcher] except')
pass
self.keys = self.dic.keys()
self.placed, self.button_columns, self.last_column_row = self.place()
#print str((self.placed, self.button_columns, self.last_column_row))
else:
self.button_columns=0
@ -77,7 +78,7 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
self.set_active_controls()
self.set_navigation()
# Connect a key action (Backspace) to close the window.
self.connect(pyxbmct.ACTION_NAV_BACK, self.close)
self.connect(ACTION_NAV_BACK, self.close)
def place(self):
placed = {}
@ -89,6 +90,7 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
else:
i += 1
placed[item] = (j, i)
#print item+str((j, i))
return placed, j, i
def set_info_controls(self):
@ -101,7 +103,7 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
self.radiobutton_top, self.radiobutton_bottom = [None, None, None], [None, None, None]
for searcher in self.keys:
place = self.placed[searcher]
self.radiobutton[searcher] = pyxbmct.RadioButton(searcher)
self.radiobutton[searcher] = RadioButton(searcher)
self.placeControl(self.radiobutton[searcher], place[0], place[1])
self.radiobutton[searcher].setSelected(self.dic[searcher])
self.connect(self.radiobutton[searcher], self.radio_update)
@ -110,32 +112,32 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
self.radiobutton_bottom[place[1]] = self.radiobutton[searcher]
# Button
self.button_install = pyxbmct.Button(__language__(30415))
self.button_install = Button(__language__(30415))
self.placeControl(self.button_install, 2 + self.button_columns, 0)
self.connect(self.button_install, self.installSearcher)
# Button
self.button_openserchset = pyxbmct.Button(__language__(30416))
self.button_openserchset = Button(__language__(30416))
self.placeControl(self.button_openserchset, 2 + self.button_columns, 1)
self.connect(self.button_openserchset, self.openSearcherSettings)
# Button
self.button_clearstor = pyxbmct.Button(__language__(30417))
self.button_clearstor = Button(__language__(30417))
self.placeControl(self.button_clearstor, 2 + self.button_columns, 2)
self.connect(self.button_clearstor, self.clearStorage)
# Button
self.button_openset = pyxbmct.Button(__language__(30413))
self.button_openset = Button(__language__(30413))
self.placeControl(self.button_openset, 3 + self.button_columns, 0)
self.connect(self.button_openset, self.openSettings)
# Button
self.button_utorrent = pyxbmct.Button(__language__(30414))
self.button_utorrent = Button(__language__(30414))
self.placeControl(self.button_utorrent, 3 + self.button_columns, 1)
self.connect(self.button_utorrent, self.openUtorrent)
# Button
self.button_close = pyxbmct.Button(__language__(30412))
self.button_close = Button(__language__(30412))
self.placeControl(self.button_close, 3 + self.button_columns, 2)
self.connect(self.button_close, self.close)
@ -169,6 +171,8 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
ser = placed_keys[placed_values.index((place[0], place[1] - 1))]
self.radiobutton[searcher].controlLeft(self.radiobutton[ser])
#print str((self.button_columns, self.last_column_row))
#print searcher
if self.more_two_searcher:
if place == (self.button_columns, self.last_column_row) and self.last_column_row < 2:
ser = placed_keys[placed_values.index((place[0] - 1, place[1] + 1))]
@ -243,10 +247,7 @@ class ControlCenter(pyxbmct.AddonDialogWindow):
def openSearcherSettings(self):
slist=Searchers().activeExternal()
if len(slist)>0:
if len(slist) == 1:
ret = 0
else:
ret = xbmcgui.Dialog().select(__language__(30418), slist)
ret = xbmcgui.Dialog().select(__language__(30418), slist)
if ret > -1 and ret < len(slist):
sid = slist[ret]
Searcher=xbmcaddon.Addon(id='torrenter.searcher.'+sid)

View File

@ -43,8 +43,7 @@ except:
__settings__ = xbmcaddon.Addon(id='plugin.video.torrenter')
__language__ = __settings__.getLocalizedString
ROOT = __settings__.getAddonInfo('path') # .decode('utf-8').encode(sys.getfilesystemencoding())
userStorageDirectory = xbmc.translatePath(__settings__.getSetting("storage"))
torrentFilesDirectory = 'torrents'
userStorageDirectory = __settings__.getSetting("storage")
USERAGENT = "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0"
__addonpath__ = __settings__.getAddonInfo('path')
icon = os.path.join(__addonpath__, 'icon.png')
@ -56,7 +55,7 @@ def clearStorage(userStorageDirectory, force = False):
userStorageDirectory = decode(userStorageDirectory)
#log('[clearStorage]: storage '+str(userStorageDirectory) + os.sep)
min_storage_size = __settings__.getSetting("min_storage_size")
storage_size = getDirectorySizeInGB(userStorageDirectory.encode('utf-8'))
storage_size = getDirectorySizeInGB(userStorageDirectory)
if storage_size >= min_storage_size or force:
if xbmcvfs.exists(userStorageDirectory + os.sep) or os.path.exists(userStorageDirectory):
log('[clearStorage]: storage exists')
@ -84,8 +83,7 @@ def clearStorage(userStorageDirectory, force = False):
shutil.move(saved, saved_temp)
saved_bool = True
shutil.rmtree(userStorageDirectory, ignore_errors=True)
#log(str(xbmcvfs.listdir(userStorageDirectory)))
shutil.rmtree(userStorageDirectory.encode('utf-8'), ignore_errors=True)
xbmcvfs.mkdir(userStorageDirectory)
if torrents_bool:
@ -93,10 +91,10 @@ def clearStorage(userStorageDirectory, force = False):
if saved_bool:
shutil.move(saved_temp, saved)
showMessage(Localization.localize('Storage'), Localization.localize('Storage has been cleared'))
showMessage(Localization.localize('Storage'), Localization.localize('Storage has been cleared'), forced=True)
else:
showMessage(Localization.localize('Storage'), Localization.localize('Does not exists'))
showMessage(Localization.localize('Storage'), Localization.localize('Does not exists'), forced=True)
log('[clearStorage]: fail storage '+userStorageDirectory + os.sep)
try:
@ -104,6 +102,8 @@ def clearStorage(userStorageDirectory, force = False):
except Exception, e:
log('[clearStorage]: DownloadDB().clear() failed. '+str(e))
showMessage(Localization.localize('Storage'), Localization.localize('Storage was cleared'), forced=True)
def sortcomma(dict, json):
for x in dict:
@ -152,9 +152,8 @@ def debug(msg, forced=False):
def showMessage(heading, message, times=10000, forced=False):
if forced or not getSettingAsBool('disable_notifications'):
xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s, "%s")' % (
heading.replace('"', "'"), message.replace('"', "'"), times, icon))
xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s, "%s")' % (
heading.replace('"', "'"), message.replace('"', "'"), times, icon))
debug(str((heading.replace('"', "'"), message.replace('"', "'"), times, icon)))
@ -423,7 +422,6 @@ def cutFolder(contentList, tdir=None):
if len(contentList) > 1:
common_folder = contentList[0][0]
debug('[cutFolder]: common_folder '+common_folder)
if '\\' in common_folder:
common_folder = common_folder.split('\\')[0]
elif '/' in common_folder:
@ -431,36 +429,38 @@ def cutFolder(contentList, tdir=None):
common = True
for item in contentList:
if common_folder not in item[0]:
fileTitle = item[0]
if common_folder not in fileTitle:
common = False
break
# print common_folder
for item in contentList:
fileTitle = item[0]
contentId = item[1]
dir = None
if common:
item[0] = item[0][len(common_folder) + 1:]
fileTitle = fileTitle[len(common_folder) + 1:]
#debug('[cutFolder]: item[0] '+item[0])
# print fileTitle
if '\\' in item[0]:
dir = item[0].split('\\')[0]
elif '/' in item[0]:
dir = item[0].split('/')[0]
if '\\' in fileTitle:
dir = fileTitle.split('\\')[0]
elif '/' in fileTitle:
dir = fileTitle.split('/')[0]
elif not tdir:
contentListNew.append(item)
if tdir and ensure_str(dir) == ensure_str(tdir):
if tdir and dir == tdir:
tupleContent = list(item)
tupleContent[0] = item[0][len(dir) + 1:]
contentListNew.append(list(tupleContent))
tupleContent[0] = fileTitle[len(dir) + 1:]
contentListNew.append(tuple(tupleContent))
if not tdir and dir and dir not in dirList:
dirList.append(dir)
debug('[cutFolder]: dirList, contentListNew '+str(dirList)+str(contentListNew))
return dirList, contentListNew
else:
debug('[cutFolder]: dirList, contentList '+str(dirList)+str(contentList))
return dirList, contentList
@ -577,52 +577,32 @@ def view_style(func):
styles['sectionMenu'] = styles['Seasons'] = 'list'
styles['uTorrentBrowser'] = styles['torrentPlayer'] = styles['openTorrent'] = 'wide'
styles['showFilesList'] = styles['DownloadStatus'] = 'wide'
elif view_style in [1, 4, 5, 7]:
elif view_style in [1, 4, 5]:
styles['searchOption'] = 'info'
styles['drawContent'] = styles['torrentPlayer'] = styles['openTorrent'] = styles['drawtrackerList'] = 'info'
styles['uTorrentBrowser'] = styles['History'] = styles['DownloadStatus'] = 'wide'
styles['showFilesList'] = styles['sectionMenu'] = 'wide'
styles['List'] = styles['drawcontentList'] = 'info3'
if view_style in [1, 7]:
if view_style == 1:
styles['uTorrentBrowser'] = styles['torrentPlayer'] = 'wide'
styles['openTorrent'] = styles['History'] = styles['DownloadStatus'] = 'wide'
styles['sectionMenu'] = 'icons'
elif view_style == 5:
styles['uTorrentBrowser'] = styles['torrentPlayer'] = 'wide'
styles['openTorrent'] = styles['History'] = styles['DownloadStatus'] = 'wide'
styles['drawtrackerList'] = styles['drawContent'] = styles['List'] = styles['sectionMenu'] = 'list'
styles['drawtrackerList'] = styles['drawContent'] = styles['List'] = styles['sectionMenu'] = 'icons'
styles['searchOption'] = 'info'
if view_style == 8:
styles['sectionMenu'] = 'thumbnails' #меню
styles['List'] = 'biglist'
styles['Seasons'] = 'biglist'
styles['uTorrentBrowser'] = 'biglist'
styles['torrentPlayer'] = 'biglist'
styles['openTorrent'] = 'biglist'
styles['History'] = 'biglist' #история поиска
styles['DownloadStatus'] = 'biglist' #статус загрузки
styles['drawtrackerList'] = 'biglist'
styles['drawContent'] = 'list' #списки медиа
styles['drawcontentList'] = 'extrainfo' #списки медиа - лист
styles['searchOption'] = 'biglist'
styles['showFilesList'] = 'biglist'
if view_style in [1, 3, 4, 5]:
num_skin = 0
elif view_style == 2:
num_skin = 1
elif view_style == 6:
num_skin = 2
elif view_style == 7:
num_skin = 3
if view_style == 8:
num_skin = 4
style = styles.get(func)
log('[view_style]: lock '+str(style)+' for '+str(func))
# debug('[view_style]: lock '+str(style))
lockView(style, num_skin)
@ -632,38 +612,23 @@ def lockView(viewId='info', num_skin=0):
{'list': 50, 'info': 50, 'wide': 51, 'icons': 500, 'info3': 515, }, # Confluence
{'list': 50, 'info': 51, 'wide': 52, 'icons': 53, }, # Transperency!
{'list': 55, 'info': 55, 'wide': 55, 'icons': 55, 'info3': 55, }, # Aeon Nox
{'list': 50, 'info': 54, 'wide': 55, 'icons': 54, 'info3': 500, }, # Estuary
{'list': 50, 'bigwide': 51, 'biglist': 52, 'poster': 53, 'banner': 54, 'wall': 55, 'mediainfo': 56, 'extrainfo': 57, "cards":58, "bannerwall":59, 'thumbnails': 500, 'postersquare': 503, 'wallsquare': 505, }, # Arctic: Zephyr
)
try:
if viewId == 'wide' and num_skin == 3:
xbmcplugin.setContent(int(sys.argv[1]), 'files')
xbmc.executebuiltin("Container.SetViewMode(%s)" % str(skinOptimizations[num_skin][viewId]))
except:
return
''' Estuary
<include>View_50_List</include>
<include>View_51_Poster</include>
<include>View_52_IconWall</include>
<include>View_53_Shift</include>
<include>View_54_InfoWall</include>
<include>View_55_WideList</include>
<include>View_500_SmallThumb</include>
<include>View_501_Banner</include>
<include>View_502_FanArt</include>
'''
'''
<include>PosterWrapView2_Fanart</include> <!-- view id = 508 -->
<include>MediaListView3</include> <!-- view id = 503 -->
<include>MediaListView2</include> <!-- view id = 504 -->
<include>MediaListView4</include> <!-- view id = 515 -->
<include>WideIconView</include> <!-- view id = 505 -->
<include>MusicVideoInfoListView</include> <!-- view id = 511 -->
<include>AddonInfoListView1</include> <!-- view id = 550 -->
<include>AddonInfoThumbView1</include> <!-- view id = 551 -->
<include>LiveTVView1</include> <!-- view id = 560 -->
'''
<include>PosterWrapView2_Fanart</include> <!-- view id = 508 -->
<include>MediaListView3</include> <!-- view id = 503 -->
<include>MediaListView2</include> <!-- view id = 504 -->
<include>MediaListView4</include> <!-- view id = 515 -->
<include>WideIconView</include> <!-- view id = 505 -->
<include>MusicVideoInfoListView</include> <!-- view id = 511 -->
<include>AddonInfoListView1</include> <!-- view id = 550 -->
<include>AddonInfoThumbView1</include> <!-- view id = 551 -->
<include>LiveTVView1</include> <!-- view id = 560 -->
'''
def torrent_dir():
@ -936,6 +901,7 @@ class HistoryDB:
self.cur.execute('select providers from history where addtime="' + addtime + '"')
x = self.cur.fetchone()
self._close()
# print 'get_providers: '+str(x[0].split(',') if x and x[0]!='' else None)
return x[0].split(',') if x and x[0] != '' else None
def set_providers(self, addtime, providers):
@ -952,7 +918,7 @@ class HistoryDB:
self._close()
def change_providers(self, addtime, searcher):
#self._connect()
self._connect()
providers = self.get_providers(addtime)
keys = Searchers().dic().keys()
if providers and len(providers) > 0:
@ -964,8 +930,8 @@ class HistoryDB:
if i not in keys:
providers.remove(i)
self.set_providers(addtime, providers)
#self.db.commit()
#self._close()
self.db.commit()
self._close()
def add(self, url):
self._connect()
@ -1071,23 +1037,13 @@ class WatchedHistoryDB:
self._close()
return x if x else None
def getbypathind(self, path, ind):
self._connect()
self.cur.execute('select seek from history where path="' + path + '" AND ind=' + ind)
x = self.cur.fetchone()
self._close()
return x if x else None
def add(self, filename, path, foldername = None, seek = 0, length = 1, ind = 0, size = 0):
try:
watchedPercent = int((float(seek) / float(length if length else 1)) * 100)
except:
watchedPercent = 0
def add(self, filename, foldername = None, seek = 0, length = 1, ind = 0, size = 0):
watchedPercent = int((float(seek) / float(length)) * 100)
max_history_add = int(__settings__.getSetting('max_history_add'))
if self.history_bool and watchedPercent <= max_history_add:
self._connect()
url = __settings__.getSetting("lastTorrentUrl")
#path = __settings__.getSetting("lastTorrent")
path = __settings__.getSetting("lastTorrent")
if not foldername:
foldername = ''
self.cur.execute('delete from history where filename="' + decode(filename) + '"')
@ -1335,76 +1291,9 @@ def search(url, searchersList, isApi=None):
progressBar.close()
for k in result.keys():
if result.get(k):
filesList.extend(result[k])
filesList.extend(result[k])
return filesList
def get_filesList(query, searchersList, addtime = None):
if __settings__.getSetting('history')=='true':
HistoryDB().add(query)
filesList=search(query, searchersList)
if __settings__.getSetting('sort_search')=='true':
__settings__.setSetting('sort_search','1')
if int(__settings__.getSetting('sort_search'))==0:
filesList = sorted(filesList, key=lambda x: x[0], reverse=True)
elif int(__settings__.getSetting('sort_search'))==2:
filesList = sorted(filesList, key=lambda x: x[4], reverse=False)
debug('get_filesList filesList: '+str(filesList))
return filesList
def get_searchersList(addtime = None):
searchersList = []
if addtime:
providers=HistoryDB().get_providers(addtime)
if providers:
for searcher in providers:
searchersList.append(searcher)
if not addtime or not searchersList:
searchersList = Searchers().get_active()
debug('get_searchersList: '+str(searchersList))
return searchersList
def get_contentList(url):
import Downloader
url = urllib.unquote_plus(url)
debug('0' + __settings__.getSetting("lastTorrent"))
__settings__.setSetting("lastTorrentUrl", url)
classMatch = re.search('(\w+)::(.+)', url)
if classMatch:
searcher = classMatch.group(1)
url = Searchers().downloadWithSearcher(classMatch.group(2), searcher)
__settings__.setSetting("lastTorrent", url)
torrent = Downloader.Torrent(userStorageDirectory, url, torrentFilesDirectory=torrentFilesDirectory)
debug('1'+__settings__.getSetting("lastTorrent"))
filename = torrent.saveTorrent(url)
__settings__.setSetting("lastTorrent", filename)
debug('2'+__settings__.getSetting("lastTorrent"))
append_filesize = __settings__.getSetting("append_filesize") == 'true'
contentList = []
for filedict in torrent.getContentList():
fileTitle = filedict.get('title')
size = filedict.get('size')
if size:
if append_filesize:
fileTitle += ' [%d MB]' % (size / 1024 / 1024)
contentList.append([unescape(fileTitle), str(filedict.get('ind')), size])
# contentList = sorted(contentList, key=lambda x: x[0])
debug('get_contentList contentList: ' + str(contentList))
return contentList, filename
def join_list(l, char=', ', replace=''):
string=''
@ -1419,8 +1308,6 @@ class Contenters():
def first_time(self, scrapperDB_ver, language='ru'):
from resources.scrapers.scrapers import Scrapers
if language not in ['en','ru','he']:
language = 'ru'
searcher = 'metadata'
redl = False
scrapperDB_ver = scrapperDB_ver[language]
@ -1473,7 +1360,7 @@ class Contenters():
searchersList = []
dirList = os.listdir(ROOT + os.sep + 'resources' + os.sep + 'contenters')
for searcherFile in dirList:
if re.match('^(\w+)\.py$', searcherFile) and searcherFile != '__init__.py':
if re.match('^(\w+)\.py$', searcherFile):
searchersList.append(searcherFile.replace('.py', ''))
return searchersList
@ -1885,29 +1772,6 @@ def first_run_250():
#ok = xbmcgui.Dialog().ok('< %s >' % (Localization.localize('Torrenter Update ') + '2.4.2'),
# Localization.localize('Torrent2HTTP enabled! Can be changed in Settings.'))
def first_run_260():
if not __settings__.getSetting('first_run_260') == 'True':
yes=xbmcgui.Dialog().yesno('< %s >' % (Localization.localize('Torrenter Update ') + '2.6.0'),
Localization.localize('Torrenter Search Window')+' '
+Localization.localize('is recommended for Kodi 17 users and now out of beta.')
+Localization.localize('You can disable it usage in Settings.'),
Localization.localize('Would you like to try it?'),)
if yes:
import searchwindow
searchwindow.main()
def estuary():
if __settings__.getSetting('skin_optimization') not in ['7', '0'] and \
__settings__.getSetting('ask17_skin_optimization') != 'True':
yes = xbmcgui.Dialog().yesno('< %s >' % (Localization.localize('Torrenter Update ') + '2.6.0'),
Localization.localize('Torrenter has a better view style for Kodi 17 default skin.'),
Localization.localize('Would you like to try it?'), )
if yes:
__settings__.setSetting('skin_optimization', '7')
__settings__.setSetting('ask_skin_optimization', 'True')
def seeking_warning(seek):
if __settings__.getSetting('torrent_player')!='1':
seek_point = '%02d:%02d:%02d' % ((seek / (60*60)), (seek / 60) % 60, seek % 60)
@ -2048,7 +1912,7 @@ def check_network_advancedsettings():
file_cont='''<advancedsettings>
<network>
<buffermode>2</buffermode>
<curlclienttimeout>30</curlclienttimeout>
<curlclienttimeout>30</curlclienttimeout>
<cachemembuffersize>252420</cachemembuffersize>
<readbufferfactor>5</readbufferfactor>
</network>
@ -2065,7 +1929,7 @@ def check_network_advancedsettings():
'''<advancedsettings>
<network>
<buffermode>2</buffermode>
<curlclienttimeout>30</curlclienttimeout>
<curlclienttimeout>30</curlclienttimeout>
<cachemembuffersize>252420</cachemembuffersize>
<readbufferfactor>5</readbufferfactor>
</network>
@ -2190,30 +2054,20 @@ def uri2path(uri):
def localize_path(path):
import chardet
if not isinstance(path, unicode):
try:
path = path.decode(chardet.detect(path).get('encoding') or 'utf-8')
except:
pass
if not isinstance(path, unicode): path = path.decode(chardet.detect(path)['encoding'])
if not sys.platform.startswith('win'):
path = encode_msg(path)
return path
def encode_msg(msg):
try:
msg = isinstance(msg, unicode) and msg.encode(
(sys.getfilesystemencoding() not in ('ascii', 'ANSI_X3.4-1968')) and sys.getfilesystemencoding() or 'utf-8') or msg
msg = isinstance(msg, unicode) and msg.encode(True and sys.getfilesystemencoding() or 'utf-8') or msg
except:
import traceback
log(traceback.format_exc())
msg = ensure_str(msg)
msg = msg.encode('utf-8')
return msg
def decode_str(string, encoding='utf-8'):
if not isinstance(string, unicode):
string = string.decode(encoding)
return string
def get_platform():
ret = {
"arch": sys.maxsize > 2 ** 32 and "x64" or "x86",
@ -2246,83 +2100,3 @@ def get_platform():
ret["arch"] = "arm"
return ret
def getTorrentClientIcon():
client = __settings__.getSetting("torrent")
if client == '1':
return 'transmission.png'
elif client == '2':
return 'vuze.png'
elif client == '3':
return 'deluge.png'
elif client == '4':
return 'qbittorrent.png'
else:
return 'torrent-client.png'
def get_item():
#some plugin.video.quasar magic
item = xbmcgui.ListItem(
path='',
label=xbmc.getInfoLabel("ListItem.Label"),
label2=xbmc.getInfoLabel("ListItem.label2"),
thumbnailImage=xbmc.getInfoLabel("ListItem.Art(thumb)"))
_infoLabels = {
"Title": xbmc.getInfoLabel("ListItem.Title"),
"OriginalTitle": xbmc.getInfoLabel("ListItem.OriginalTitle"),
"TVShowTitle": xbmc.getInfoLabel("ListItem.TVShowTitle"),
"Season": xbmc.getInfoLabel("ListItem.Season"),
"Episode": xbmc.getInfoLabel("ListItem.Episode"),
"Premiered": xbmc.getInfoLabel("ListItem.Premiered"),
"Plot": xbmc.getInfoLabel("ListItem.Plot"),
# "Date": xbmc.getInfoLabel("ListItem.Date"),
"VideoCodec": xbmc.getInfoLabel("ListItem.VideoCodec"),
"VideoResolution": xbmc.getInfoLabel("ListItem.VideoResolution"),
"VideoAspect": xbmc.getInfoLabel("ListItem.VideoAspect"),
"DBID": xbmc.getInfoLabel("ListItem.DBID"),
"DBTYPE": xbmc.getInfoLabel("ListItem.DBTYPE"),
"Writer": xbmc.getInfoLabel("ListItem.Writer"),
"Director": xbmc.getInfoLabel("ListItem.Director"),
"Rating": xbmc.getInfoLabel("ListItem.Rating"),
"Votes": xbmc.getInfoLabel("ListItem.Votes"),
"IMDBNumber": xbmc.getInfoLabel("ListItem.IMDBNumber"),
}
infoLabels = {}
for key, value in _infoLabels.iteritems():
if value:
infoLabels[key] = value
poster = xbmc.getInfoLabel("ListItem.Art(poster)")
if not poster:
poster = xbmc.getInfoLabel("ListItem.Art(tvshow.poster)")
item.setArt({
"poster": poster,
"banner": xbmc.getInfoLabel("ListItem.Art(banner)"),
"fanart": xbmc.getInfoLabel("ListItem.Art(fanart)")
})
item.setInfo(type='Video', infoLabels=infoLabels)
return item
def loadsw_onstop():
if __settings__.getSetting('loadsw_onstop') == 'true':
import searchwindow
params = {'mode': 'load'}
searchwindow.main(params)
def watched_seek(filename, ind):
db = WatchedHistoryDB()
seek = db.getbypathind(filename, ind)
log('[watched_seek] seek - '+str(seek))
if seek:
seek = seek[0]
seek = int(seek) if int(seek) > 3 * 60 else 0
if seek > 0:
seek_text = '%02d:%02d:%02d' % ((seek / (60 * 60)), (seek / 60) % 60, seek % 60)
dialog_items = [Localization.localize('Play (from %s)') % seek_text,
Localization.localize('Play (from start)')]
ret = xbmcgui.Dialog().select(Localization.localize('Play (with seek)'), dialog_items)
if ret == 0:
return str(seek)
return '0'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -22,7 +22,7 @@ import re
import Content
from BeautifulSoup import BeautifulSoup
from datetime import date
def make_category_dict():
category_dict = {
@ -72,7 +72,7 @@ def make_category_dict():
x[0], x[1] + 'view=list', {'page': x[1] + 'view=list&page=%d', 'increase': 1, 'second_page': 1})
category_dict['year'] = {'year': 'by Year', }
for y in range(date.today().year, 1970, -1):
for y in range(2015, 1970, -1):
category_dict['year'][str(y)] = (str(y), '/films/year/%s/' % str(y),
{'page': '/films/year/%s/' % str(y) + '?view=list&page=%d', 'increase': 1,
'second_page': 1})

View File

@ -28,7 +28,7 @@ class EZTV(Content.Content):
'hot': ('Most Recent', '/', {'page': '/page_%d', 'increase': 1, 'second_page': 1}),
}
baseurl = "https://eztv.ag"
baseurl = "https://eztv.ch"
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'),

View File

@ -23,7 +23,6 @@ import HTMLParser
import Content
from BeautifulSoup import BeautifulSoup
from datetime import date
class IMDB(Content.Content):
@ -66,7 +65,7 @@ class IMDB(Content.Content):
}
}
for y in range(date.today().year, 1970, -1):
for y in range(2015, 1970, -1):
category_dict['year'][str(y)] = (str(y), '/year/%s/' % str(y))
regex_list = []
@ -99,28 +98,27 @@ class IMDB(Content.Content):
return True
def get_contentList(self, category, subcategory=None, apps_property=None):
self.debug = self.log
contentList = []
url = self.get_url(category, subcategory, apps_property)
response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response):
self.debug(response)
#print response
if category in ['top']:
contentList = self.topmode(response)
elif category == 'search':
contentList = self.searchmode(response)
else: #if category in ['genre']:
contentList = self.genremode(response)
self.debug(str(contentList))
#print str(contentList)
return contentList
def searchmode(self, response):
contentList = []
pars = HTMLParser.HTMLParser()
Soup = BeautifulSoup(response)
result = Soup.findAll('tr', {'class': 'lister-item mode-advanced'})
result = Soup.findAll('tr', {'class': ['findResult odd', 'findResult even']})
num = 250
for tr in result:
#main
@ -148,7 +146,7 @@ class IMDB(Content.Content):
int(int(self.sourceWeight) * (251 - int(num))),
originaltitle, title, int(year), img, info,
))
self.debug(str(result))
#print result
return contentList
def genremode(self, response):
@ -182,7 +180,7 @@ class IMDB(Content.Content):
int(int(self.sourceWeight) * (251 - int(num))),
originaltitle, title, int(year), img, info,
))
self.debug(str(result))
#print result
return contentList
def biggerImg(self, img):

View File

@ -48,7 +48,7 @@ class KickAssSo(Content.Content):
}
baseurl = "http://kat.am"
baseurl = "http://kat.cr"
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'),
@ -82,25 +82,25 @@ class KickAssSo(Content.Content):
return False
def get_contentList(self, category, subcategory=None, apps_property=None):
self.debug = self.log
contentList = []
url = self.get_url(category, subcategory, apps_property)
response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response):
self.debug(response)
# print response
if category:
contentList = self.mode(response)
self.debug(str(contentList))
# print str(contentList)
return contentList
def mode(self, response):
contentList = []
# print str(result)
num = 51
good_forums = ['TV', 'Anime', 'Movies']
regex = '''<tr class=".+?" id=.+?</tr>'''
regex_tr = r'''<a data-download .+? href="(.+?)" class=".+?"><i.+?<a.+?<a.+?<a href="(.+?html)" class=".+?">(.+?)</a>.+? in <span.+?"><strong>.+?">(.+?)</a>.+?<td class="nobr center">(.+?)</td>.+?<td class="center".+?>(\d+&nbsp;.+?)</td>.+?<td class="green center">(\d+?)</td>.+?<td class="red lasttd center">(\d+?)</td>'''
regex_tr = r'''title="Download torrent file" href="(.+?)" class=".+?"><i.+?<a.+?<a.+?<a href="(.+?html)" class=".+?">(.+?)</a>.+? in <span.+?"><strong>.+?">(.+?)</a>.+?<td class="nobr center">(.+?)</td>.+?<td class="center".+?>(\d+&nbsp;.+?)</td>.+?<td class="green center">(\d+?)</td>.+?<td class="red lasttd center">(\d+?)</td>'''
for tr in re.compile(regex, re.DOTALL).findall(response):
result=re.compile(regex_tr, re.DOTALL).findall(tr)
if result:
@ -129,7 +129,6 @@ class KickAssSo(Content.Content):
return contentList
def get_info(self, url):
self.debug = self.log
movieInfo = {}
color = '[COLOR blue]%s:[/COLOR] %s\r\n'
response = self.makeRequest(url, headers=self.headers)
@ -144,7 +143,7 @@ class KickAssSo(Content.Content):
'kinopoisk': ''}
try:
img = result.find('a', {'class': 'movieCover'}).find('img').get('src')
movieInfo['poster'] = img if img.startswith('http:') else 'http:' + img
movieInfo['poster'] = 'http:' + img
except:
pass
try:
@ -191,5 +190,7 @@ class KickAssSo(Content.Content):
if i == 'IMDb link':
movieInfo['kinopoisk'] = 'http://imdb.snick.ru/ratefor/02/tt%s.png' % info.get(i)
self.debug(str(movieInfo))
# print str(info)
return movieInfo

View File

@ -20,7 +20,6 @@
import re
import socket
from datetime import date
import Content
from BeautifulSoup import BeautifulSoup
@ -71,7 +70,7 @@ class KinoPoisk(Content.Content):
x[0], x[1] + 'perpage/25/', {'page': x[1] + 'perpage/25/page/%d/', 'increase': 1, 'second_page': 2})
category_dict['year'] = {'year': 'by Year', }
for y in range(date.today().year, 1970, -1):
for y in range(2015, 1970, -1):
category_dict['year'][str(y)] = (str(y), '/s/type/film/list/1/m_act[year]/%s/' % str(y) + 'perpage/25/',
{'page': '/s/type/film/list/1/m_act[year]/%s/' % str(y) + 'perpage/25/page/%d/',
'increase': 1, 'second_page': 2})
@ -104,23 +103,22 @@ class KinoPoisk(Content.Content):
return True
def get_contentList(self, category, subcategory=None, apps_property=None):
#self.debug=self.log
socket.setdefaulttimeout(15)
contentList = []
url = self.get_url(category, subcategory, apps_property)
self.debug('get_contentList: url = '+url)
#print url
response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response):
self.debug(str(response))
#print response
if category in ['hot']:
contentList = self.popmode(response)
elif url.startswith(self.baseurl + '/s/type/film/list/'):
contentList = self.infomode(response)
else:
contentList = self.topmode(response)
self.debug('get_contentList: contentList = '+str(contentList))
#print str(contentList)
return contentList
def stripTtl(self, title):
@ -133,12 +131,12 @@ class KinoPoisk(Content.Content):
contentList = []
Soup = BeautifulSoup(response)
result = Soup.find('div', 'stat').findAll('div', 'el')
self.debug('popmode: '+str(result))
#print str(result)
for tr in result:
#main
a = tr.findAll('a')
num = a[0].text
#print num
info = {}
year = 0
img = ''
@ -153,14 +151,12 @@ class KinoPoisk(Content.Content):
img = self.id2img(id[0])
try:
title, year = re.compile('(.+?) \((\d\d\d\d)\)', re.DOTALL).findall(a[1].text)[0]
#self.log('popmode 1'+str((title, year)))
except:
pass
if not year:
try:
title, year = re.compile('(.+?) \(.*(\d\d\d\d)').findall(a[1].text)[0]
info['tvshowtitle'] = title
#self.log('popmode 2' + str((title, year)))
except:
pass
title = self.stripHtml(self.stripTtl(title))
@ -179,7 +175,7 @@ class KinoPoisk(Content.Content):
contentList = []
Soup = BeautifulSoup(response)
result = Soup.find('table', {'cellpadding': '3'}).findAll('tr')[2:]
self.debug('topmode: ' + str(result))
#print str(result)
for tr in result:
#main
td = tr.findAll('td')
@ -201,12 +197,8 @@ class KinoPoisk(Content.Content):
year = re.compile('(.+) \((\d\d\d\d)\)').findall(a_all.text)
if not year:
try:
match = re.search(r"(.+) \((\d\d\d\d) &ndash;|(.+) \(.*(\d\d\d\d)", a_all.text,
re.IGNORECASE | re.MULTILINE)
if match:
title = match.group(1)
year = match.group(2)
info['tvshowtitle'] = title
title, year = re.compile('(.+) \(.*(\d\d\d\d)').findall(a_all.text)[0]
info['tvshowtitle'] = title
except:
title = a_all.text
else:

View File

@ -28,7 +28,7 @@ class RiperAM(Content.Content):
'hot': ('Most Recent', '/', {'page': '/portal.php?tp=%d', 'increase': 30, 'second_page': 30}),
}
baseurl = "http://riperam.org/"
baseurl = "http://riperam.org"
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'),

View File

@ -1,249 +0,0 @@
# -*- coding: utf-8 -*-
'''
Torrenter plugin for XBMC
Copyright (C) 2012 Vadim Skorba
vadim.skorba@gmail.com
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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
'''
import re, sys
import Content
from BeautifulSoup import BeautifulSoup
#http://anti-tor.org/browse/0/1/0/0 date movie
#http://anti-tor.org/browse/1/1/0/0 page 2
#http://anti-tor.org/browse/0/1/0/2 seed movie
# page/cat/?/sort
class RuTorOrg(Content.Content):
category_dict = {
'movies': ('Movies', '/browse/0/1/0',
{'page': '/browse/%d/1/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'rus_movies': ('Russian Movies', '/browse/0/5/0',
{'page': '/browse/%d/5/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'tvshows': ('TV Shows', '/browse/0/4/0',
{'page': '/browse/%d/4/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'science': ('Научно - популярные фильмы', '/browse/0/12/0',
{'page': '/browse/%d/12/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'cartoons': ('Cartoons', '/browse/0/7/0',
{'page': '/browse/%d/7/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'anime': ('Anime', '/browse/0/10/0',
{'page': '/browse/%d/10/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'sport': ('Спорт и Здоровье', '/browse/0/13/0',
{'page': '/browse/%d/13/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'tele': ('Телевизор', '/browse/0/6/0',
{'page': '/browse/%d/6/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
'humor': ('Юмор', '/browse/0/15/0',
{'page': '/browse/%d/15/0', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/2'},
{'name': 'by Date', 'url_after': '/0'}]}),
}
#'hot': ('Most Recent',),
baseurl = "anti-tor.org"
'''
Weight of source with this searcher provided.
Will be multiplied on default weight.
Default weight is seeds number
'''
sourceWeight = 1
def isTracker(self):
return True
def isSearcher(self):
return False
def isScrappable(self):
return False
def isInfoLink(self):
return True
def isPages(self):
return True
def isSort(self):
return True
def isSearchOption(self):
return False
def get_contentList(self, category, subcategory=None, apps_property=None):
#self.debug = self.log
contentList = []
url = 'http://%s' % self.get_url(category, subcategory, apps_property)
self.debug(url)
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'),
('Referer', 'http://%s' % self.baseurl), ('Accept-encoding', 'gzip'),
('Cookie', str(sys.modules["__main__"].__settings__.getSetting("rutor-auth")))]
response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response):
#self.debug(response)
cookie = re.compile("document.cookie='(.+?)';").findall(response)
if cookie and str(cookie[0]) != str(sys.modules["__main__"].__settings__.getSetting("rutor-auth")):
cookie = cookie[0]
self.log('ok found new cookie: ' + str(cookie))
sys.modules["__main__"].__settings__.setSetting("rutor-auth", cookie)
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'),
('Referer', 'http://%s' % self.baseurl), ('Accept-encoding', 'gzip'),
('Cookie', str(sys.modules["__main__"].__settings__.getSetting("rutor-auth")))]
response = self.makeRequest(url, headers=headers)
self.debug(response)
if category:
contentList = self.mode(response.decode('utf-8'))
self.debug(str(contentList))
return contentList
def mode(self, response):
contentList = []
num = 101
regex = '''<tr class="[tg].+?</tr>'''
regex_tr = '<td>(.+?)</td><td ><a.+?href="(.+?download/\d+)">.+?<a href=".+?">.+?<a href="(.+?)">(.+?)</a></td>.+?<td align="right">(\d*?\..+?&nbsp;.+?)</td>.+?<img .+?alt="S".+?>&nbsp;(\d+)</span>.+?alt="L".+?>&nbsp;(\d+)'
for tr in re.compile(regex, re.DOTALL).findall(response):
result=re.compile(regex_tr, re.DOTALL).findall(tr)
if result:
self.debug(tr + ' -> ' + str(result[0]))
(date, link, infolink, title, size, seeds, leechers)=result[0]
# main
info = {}
num = num - 1
original_title = None
year = 0
img = ''
# info
title = self.unescape(self.stripHtml(title.strip()))
info['label'] = info['title'] = title
if link[0] == '/': link = 'http://%s%s' % (self.baseurl, link)
info['link'] = link
#if infolink[0] == '/': infolink = 'http://%s%s' % (self.baseurl, infolink)
#info['infolink'] = infolink
size = size.replace('&nbsp;', ' ')
date = date.replace('&nbsp;', ' ')
info['plot'] = info['title'] + '\r\n[I](%s) [S/L: %s/%s] [/I]\r\n%s: %s' % (
size, seeds, leechers, self.localize('Date'), date)
#regex_title = '(.+?) / (.+?) \((\d\d\d\d)\)'
#regex_result = re.compile(regex_title, re.DOTALL).findall(title)
#if regex_result:
# title, original_title, year = regex_result[0]
# info['title'] = title
contentList.append((
int(int(self.sourceWeight) * (int(num))),
original_title, title, int(year), img, info,
))
return contentList
def get_info(self, url):
self.debug = self.log
movieInfo = {}
color = '[COLOR blue]%s:[/COLOR] %s\r\n'
response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response):
Soup = BeautifulSoup(response)
result = Soup.find('div', 'torrentMediaInfo')
if not result:
return None
li = result.findAll('li')
info, movieInfo = {'Cast': ''}, {'desc': '', 'poster': '', 'title': '', 'views': '0', 'rating': '50',
'kinopoisk': ''}
try:
img = result.find('a', {'class': 'movieCover'}).find('img').get('src')
movieInfo['poster'] = img if img.startswith('http:') else 'http:' + img
except:
pass
try:
movie = re.compile('View all <strong>(.+?)</strong> episodes</a>').match(str(result))
if movie:
info['Movie'] = movie.group(1)
except:
pass
for i in li:
name = i.find('strong').text
if name:
info[name.rstrip(':')] = i.text.replace(name, '', 1)
plot = result.find('div', {'id': 'summary'})
if plot:
cut = plot.find('strong').text
info['plot'] = plot.text.replace(cut, '', 1).replace('report summary', '')
# print str(result)
cast = re.compile('<a href="/movies/actor/.+?">(.+?)</a>').findall(str(result))
if cast:
for actor in cast:
info['Cast'] += actor + ", "
if 'Genres' in info:
info['Genres'] = info['Genres'].replace(', ', ',').replace(',', ', ')
for key in info.keys():
if not 'Movie' in info and info[key] == 'addto bookmarks':
movieInfo['title'] = self.unescape(key)
info['TV Show'] = self.unescape(key)
if not 'plot' in info and 'Summary' in key:
info['plot'] = info[key]
for i in ['Movie', 'TV Show', 'Release date', 'Original run', 'Episode', 'Air date', 'Genres', 'Language',
'Director', 'Writers', 'Cast', 'Original run', 'IMDb rating', 'AniDB rating']:
if info.get(i) and info.get(i) not in ['']:
movieInfo['desc'] += color % (i, info.get(i))
if i == 'Movie':
movieInfo['title'] = info.get(i)
for i in ['plot', 'IMDb link', 'RottenTomatoes']:
if info.get(i) and info.get(i) not in ['']:
if i == 'plot':
movieInfo['desc'] += '\r\n[COLOR blue]Plot:[/COLOR]\r\n' + self.unescape(info.get(i))
if i == 'RottenTomatoes':
movieInfo['rating'] = str(info.get(i).split('%')[0])
if i == 'IMDb link':
movieInfo['kinopoisk'] = 'http://imdb.snick.ru/ratefor/02/tt%s.png' % info.get(i)
self.debug(str(movieInfo))
return movieInfo

View File

@ -23,7 +23,6 @@ import Content
class ThePirateBaySe(Content.Content):
# debug = log
category_dict = {
'tvshows': ('TV Shows', '/browse/205', {'page': '/browse/208/%d', 'increase': 1, 'second_page': 1,
'sort': [{'name': 'by Seeders', 'url_after': '/0/7/0'},
@ -46,11 +45,11 @@ class ThePirateBaySe(Content.Content):
'heb_movies': ('סרטים מדובבים', '/search/Hebrew-dubbed/0/7/0'),
}
baseurl = "http://thepiratebay.ae"
baseurl = "thepiratebay.rs"
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'),
('Referer', 'http://thepiratebay.ae/'), ('Accept-Encoding', 'gzip')]
('Referer', 'http://kickass.so/'), ('Accept-Encoding', 'gzip')]
'''
Weight of source with this searcher provided.
Will be multiplied on default weight.
@ -83,8 +82,7 @@ class ThePirateBaySe(Content.Content):
contentList = []
url = self.get_url(category, subcategory, apps_property)
import requests
response = requests.get(url).text
response = self.open2(url)
if None != response and 0 < len(response):
# print response
@ -93,35 +91,40 @@ class ThePirateBaySe(Content.Content):
# print str(contentList)
return contentList
def open2(self, url=''):
import httplib
conn = httplib.HTTPConnection(self.baseurl)
conn.request("GET", url.replace(self.baseurl,''))
r1 = conn.getresponse()
status = str(r1.status) + " " + r1.reason
content = r1.read()
#print str(status)
#print str(content)
return content
def mode(self, response):
contentList = []
self.debug = self.log
# print str(result)
num = 31
self.debug(response)
regex = '''<tr>.+?</tr>'''
regex_tr = r'<div class="detName">.+?">(.+?)</a>.+?<a href="(.+?)".+?<font class="detDesc">Uploaded (.+?), Size (.+?), .+?</font>.+?<td align="right">(\d+?)</td>.+?<td align="right">(\d+?)</td>'
for tr in re.compile(regex, re.DOTALL).findall(response):
result = re.compile(regex_tr, re.DOTALL).findall(tr)
self.debug(tr + ' -> ' + str(result))
if result:
(title, link, date, size, seeds, leechers) = result[0]
result = re.compile(
r'''<div class="detName">.+?">(.+?)</a>.+?<a href="(.+?)".+?<font class="detDesc">Uploaded (.+?), Size (.+?), .+?</font>.+?<td align="right">(\d+?)</td>.+?<td align="right">(\d+?)</td>''',
re.DOTALL).findall(response)
for title, link, date, size, seeds, leechers in result:
info = {}
num = num - 1
original_title = None
year = 0
img = ''
size = size.replace('&nbsp;', ' ')
date = self.stripHtml(date.replace('&nbsp;', ' '))
info = {}
num = num - 1
original_title = None
year = 0
img = ''
size = size.replace('&nbsp;', ' ')
date = self.stripHtml(date.replace('&nbsp;', ' '))
# info
# info
info['label'] = info['title'] = self.unescape(title)
info['link'] = link
self.log(info['link'])
info['plot'] = info['title'] + '\r\n[I](%s) [S/L: %s/%s] [/I]\r\n%s' % (size, seeds, leechers, date)
contentList.append((
int(int(self.sourceWeight) * (int(num))),
original_title, title, int(year), img, info,
))
info['label'] = info['title'] = self.unescape(title)
info['link'] = link
info['plot'] = info['title'] + '\r\n[I](%s) [S/L: %s/%s] [/I]\r\n%s' % (size, seeds, leechers, date)
contentList.append((
int(int(self.sourceWeight) * (int(num))),
original_title, title, int(year), img, info,
))
return contentList

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 95 B

View File

@ -44,13 +44,9 @@
<string id="30044">Save files</string>
<string id="30045">Ask to save</string>
<string id="30046">Torrent2HTTP (libtorrent via http)</string>
<string id="30047">Proxy for Search</string>
<string id="31047">Proxy for Content Lists</string>
<string id="32047">SOCKS-proxy IP</string>
<string id="32048">SOCKS-proxy Port</string>
<string id="30047">Auto-unblocking proxy</string>
<string id="30048">None</string>
<string id="30049">Anti-zapret</string>
<string id="31050">Tor</string>
<string id="30050">Immunicity</string>
<string id="30051">Max. connections (0 - unlimited)</string>
<string id="30052">Use random ports</string>
@ -71,25 +67,11 @@
<string id="30067">Aeon Nox (by joyrider)</string>
<string id="30068">pyrrent2http (python-libtorrent via http)</string>
<string id="30069">Append size to file name</string>
<string id="30070">Enable DHT</string>
<string id="30071">Estuary (by DiMartino)</string>
<string id="30072">Стиль информации о раздаче</string>
<string id="30073">In the end</string>
<string id="30074">In the beginning</string>
<string id="30075">Second string</string>
<string id="30076">Arctic: Zephyr (by xbmc00)</string>
<string id="30101">Interface</string>
<string id="30102">P2P Network</string>
<string id="30103">Advanced</string>
<string id="30104">Torrent-client</string>
<string id="30105">Hentai (fine-tuning)</string>
<string id="30106">Search Window Mode</string>
<string id="30107">Enabled, hide old style</string>
<string id="30108">Enabled, replace old style</string>
<string id="30109">Enabled, optional</string>
<string id="30110">Disabled</string>
<string id="30111">Search Window Transparent Background</string>
<string id="30112">Disable Notifications</string>
<string id="50301">Save path</string>
<string id="50302">Call dialog</string>
<string id="50303">Default</string>

View File

@ -44,10 +44,9 @@
<string id="30044">שמור קבצים</string>
<string id="30045">שאל לשמירה</string>
<string id="30046">Torrent2HTTP (python-libtorrent via http)</string>
<string id="30047">Proxy</string>
<string id="30047">ביטול אוטומטי של חסימת proxy</string>
<string id="30048">ללא</string>
<string id="30049">Anti-zapret</string>
<string id="31050">Tor</string>
<string id="30050">Immunicity</string>
<string id="30101">ממשק</string>
<string id="30102">רשת P2P</string>

View File

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<string id="30001">Kezelőfelület nyelve</string>
<string id="30002">Mappák nézetének lezárása</string>
<string id="30003">Ki</string>
<string id="30004">Fájlok mentése mappába (nem FAT32)</string>
<string id="30007">Magnet-linkek használata</string>
<string id="30008">Letöltött fájlok megtartása</string>
<string id="30009">Letöltött fájlok seedben tartása</string>
<string id="30010">Feltöltési sebességkorlát MBits/sec (0 - korlátlan)</string>
<string id="30011">Letöltési sebességkorlát MBits/sec (0 - korlátlan)</string>
<string id="30012">Csak rendszerszintű libtorrent használata</string>
<string id="30013">A következő epizód előtöltése és lejátszása</string>
<string id="30014">Metaadatok letöltése a Tartalmak Listájába</string>
<string id="30015">Hibakeresés (Fejlesztői Mód)</string>
<string id="30016">Confluence (by slng)</string>
<string id="30017">Transperency (by slng)</string>
<string id="30018">Confluence (by DiMartino)</string>
<string id="30019">Confluence (by RussakHH)</string>
<string id="30020">Keresési Előzmények engedélyezése</string>
<string id="30021">python-libtorrent</string>
<string id="30022">Ace Stream</string>
<string id="30023">P2P Lejátszó</string>
<string id="30024">Egyéb beállítások a programban - AceStream Client</string>
<string id="30025">Keresés időkorlátja</string>
<string id="30026">Rövid (10s)</string>
<string id="30027">Normál (20s)</string>
<string id="30028">Hosszú (30s)</string>
<string id="30029">Feliratok előtöltése az összes mappából</string>
<string id="30030">Seedben tartás megtekintés után</string>
<string id="30031">Kérdezzen rá a tárolóhely váltására lejátszás előtt</string>
<string id="30032">Orosz tartalmak törlése</string>
<string id="30033">Orosz tartalmak visszaállítása</string>
<string id="30034">Torrentre kattintás művelete</string>
<string id="30035">Torrent fájl megnyitása</string>
<string id="30036">Helyi menü megnyitása</string>
<string id="30037">Letöltés torrentkliensen keresztül</string>
<string id="30038">Letöltés python-libtorrenten keresztül</string>
<string id="30039">Keresések rendezése seed alapján</string>
<string id="30040">Egyéni keresési lehetőség kifejezésre</string>
<string id="30041">Titkosítás</string>
<string id="30042">Keresési szálak száma</string>
<string id="30043">Törölje a fájlokat</string>
<string id="30044">Mentse a fájlokat</string>
<string id="30045">Kérdezzen rá</string>
<string id="30046">Torrent2HTTP (libtorrent via http)</string>
<string id="30047">Proxy</string>
<string id="30048">Ki</string>
<string id="30049">Anti-zapret</string>
<string id="31050">Tor</string>
<string id="30050">Immunicity</string>
<string id="30051">Max. kapcsolatok (0 - korlátlan)</string>
<string id="30052">Véletlen port használata</string>
<string id="30053">Port a bejövő kapcsolatokhoz</string>
<string id="30054">Előtöltendő adat lejátszás előtt (MB)</string>
<string id="30055">Következő epizód automatikus lejátszása (vagy kérdezzen)</string>
<string id="30056">Eszköz konfiguráció</string>
<string id="30057">Átlagos/Jó PC</string>
<string id="30058">Átlag alatti PC/router</string>
<string id="30059">Tárolóhely legkisebb mérete automatikus tisztítás miatt (GB)</string>
<string id="30060">Videó szüneteltetése elindítás után</string>
<string id="30061">Keresési eredmények rendezése</string>
<string id="30062">Seed alapján</string>
<string id="30063">Ne rendezze</string>
<string id="30064">Név alapján</string>
<string id="30065">Ne adja Megtek. Előzm.-hez ennél kevesebb lejátszásnál (%)</string>
<string id="30066">Confluence (by safonov_ivan)</string>
<string id="30067">Aeon Nox (by joyrider)</string>
<string id="30068">pyrrent2http (python-libtorrent via http)</string>
<string id="30069">Méret mellékelése a fájl nevéhez</string>
<string id="30070">DHT engedélyezése</string>
<string id="30101">Kezelőfelület</string>
<string id="30102">P2P Hálózat</string>
<string id="30103">Haladó</string>
<string id="30104">Torrentkliens</string>
<string id="30105">Hentai (finomhangolás)</string>
<string id="50301">Mentési útvonal</string>
<string id="50302">Párbeszédablak</string>
<string id="50303">Alapértelmezett</string>
<string id="50304">Elérési út</string>
<string id="50305">Alkönyvtár készítése a leolvasó számára</string>
<string id="50312">Gazdagép</string>
<string id="50313">Port</string>
<string id="50314">URL</string>
<string id="50315">Felhasználónév</string>
<string id="50316">Jelszó</string>
<string id="50311">Torrentkliens</string>
<string id="50317">URL (csak No SSL)</string>
<string id="30426">Elérési út helyettesítése (csak távoli)</string>
<string id="30412">Bezár</string>
<string id="30413">Beállítások megnyitása</string>
<string id="30414">Torrentkliens Böngésző</string>
<string id="30415">Trackerek telepítése</string>
<string id="30416">Tracker beállítások</string>
<string id="30417">Tárolóhely tisztítása</string>
<string id="30418">Kereső választása</string>
<string id="30419">Nem rendelkezel külső keresővel. Kérlek, telepíts egyet.</string>
</strings>

View File

@ -44,13 +44,9 @@
<string id="30044">Сохранять файлы</string>
<string id="30045">Спросить о сохранении</string>
<string id="30046">Torrent2HTTP (libtorrent по http)</string>
<string id="30047">Прокси для поиска</string>
<string id="31047">Прокси для списков медиа</string>
<string id="32047">IP SOCKS-прокси</string>
<string id="32048">Порт SOCKS-прокси</string>
<string id="30047">Антизапрет (прокси)</string>
<string id="30048">Не использовать</string>
<string id="30049">Anti-zapret</string>
<string id="31050">Tor</string>
<string id="30050">Immunicity</string>
<string id="30051">Макс. соединений (0 - безлимит)</string>
<string id="30052">Использовать случайные порты</string>
@ -71,25 +67,11 @@
<string id="30067">Aeon Nox (от joyrider)</string>
<string id="30068">pyrrent2http (python-libtorrent по http)</string>
<string id="30069">Добавлять размер к имени файла</string>
<string id="30070">Включить DHT</string>
<string id="30071">Estuary (от DiMartino)</string>
<string id="30072">Стиль информации о раздаче</string>
<string id="30073">В конце</string>
<string id="30074">В начале</string>
<string id="30075">Второй строкой</string>
<string id="30076">Arctic: Zephyr (от xbmc00)</string>
<string id="30101">Интерфейс</string>
<string id="30102">P2P Сеть</string>
<string id="30103">Дополнительные</string>
<string id="30104">Торрент-клиент</string>
<string id="30105">Hentai (тонкая настр.)</string>
<string id="30106">Режим работы Окна Поиска</string>
<string id="30107">Включен, убрать старый вид</string>
<string id="30108">Включен, заменить старый вид</string>
<string id="30109">Включен, как опция</string>
<string id="30110">Отключен</string>
<string id="30111">Прозрачность Окна Поиска</string>
<string id="30112">Отключить Уведомления</string>
<string id="50301">Директория для сохранения файлов</string>
<string id="50302">Вызывать диалог</string>
<string id="50303">Задать по умолчанию</string>

View File

@ -44,10 +44,9 @@
<string id="30044">Uložiť súbory</string>
<string id="30045">Ponúknuť uloženie</string>
<string id="30046">Torrent2HTTP (libtorrent cez http)</string>
<string id="30047">Proxy</string>
<string id="30047">Auto-odblokovanie proxy</string>
<string id="30048"Žiadny</string>
<string id="30049">Anti-zapret</string>
<string id="31050">Tor</string>
<string id="30050">Immunicity</string>
<string id="30051">Max. pripojenia (0 - neobmedzene)</string>
<string id="30052">Požit náhodný port</string>

View File

@ -1,111 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<string id="30001">Idioma de la interfaz</string>
<string id="30002">Modo vista de carpetas</string>
<string id="30003">No fijar</string>
<string id="30004">Carpeta en la que guardar archivos (no FAT32)</string>
<string id="30007">Utilizar enlaces magnet</string>
<string id="30008">Almacenaje de archivos descargados</string>
<string id="30009">Seguir compartiendo archivos descargados</string>
<string id="30010">Máx. vel. de subida en Mbit/s (0 = ilimitada)</string>
<string id="30011">Máx. vel. de descarga en Mbit/s (0 = ilimitada)</string>
<string id="30012">Utilizar solo libtorrent</string>
<string id="30013">Lanzar descarga de episodio siguiente</string>
<string id="30014">Descargar metadatos para listas de contenido</string>
<string id="30015">Depuración (Modo desarrollador)</string>
<string id="30016">Confluence (de slng)</string>
<string id="30017">Transperency (de slng)</string>
<string id="30018">Confluence (de DiMartino)</string>
<string id="30019">Confluence (de RussakHH)</string>
<string id="30020">Habilitar el historial de búsquedas</string>
<string id="30021">python-libtorrent</string>
<string id="30022">Ace Stream</string>
<string id="30023">Reproductor P2P</string>
<string id="30024">Restablecer ajustes en Add-ons de programas -- AceStream client</string>
<string id="30025">Duración de las búsquedas</string>
<string id="30026">Breve (10 s)</string>
<string id="30027">Normal (20 s)</string>
<string id="30028">Larga (30 s)</string>
<string id="30029">Predescargar los subtítulos de todas las carpetas</string>
<string id="30030">Seguir compartiendo después de ver el vídeo</string>
<string id="30031">Preguntar para cambiar de almacén antes de la descarga</string>
<string id="30032">Eliminar material ruso</string>
<string id="30033">Restituir material ruso</string>
<string id="30034">Efecto de clic sobre torrent</string>
<string id="30035">Abrir archivo torrent</string>
<string id="30036">Abrir menú contextual</string>
<string id="30037">Descargar vía cliente BitTorrent</string>
<string id="30038">Descargar vía python-libtorrent</string>
<string id="30039">Ordenar resultados por fuentes</string>
<string id="30040">Términos para búsqueda personalizada</string>
<string id="30041">Cifrado</string>
<string id="30042">Número de hilos de búsqueda</string>
<string id="30043">Eliminar archivos</string>
<string id="30044">Guardar archivos</string>
<string id="30045">Preguntar para guardar</string>
<string id="30046">Torrent2HTTP (libtorrent vía HTTP)</string>
<string id="30047">Proxy</string>
<string id="30048">Ninguno</string>
<string id="30049">Anti-zapret (antirestricción)</string>
<string id="31050">Tor</string>
<string id="30050">Inmunidad</string>
<string id="30051">Núm. máx. de conexiones (0 = ilimitadas)</string>
<string id="30052">Utilizar puertos aleatorios</string>
<string id="30053">Puerto para conexiones entrantes</string>
<string id="30054">Tamaño de precarga para empezar a reproducir (MB)</string>
<string id="30055">Autorreproducir episodio siguiente (o preguntar)</string>
<string id="30056">Configuración de dispositivo</string>
<string id="30057">Promedio/Buen PC</string>
<string id="30058">Por debajo de la media, PC/router</string>
<string id="30059">Tamaño mínimo de almacenaje para autoborrado (GB)</string>
<string id="30060">Diferir inicio del reproductor</string>
<string id="30061">Ordenar resultados de la búsqueda</string>
<string id="30062">Por fuentes</string>
<string id="30063">No ordenar</string>
<string id="30064">Por nombre</string>
<string id="30065">Añadir al historial de vistos después del (%)</string>
<string id="30066">Confluence (de safonov_ivan)</string>
<string id="30067">Aeon Nox (de joyrider)</string>
<string id="30068">pyrrent2http (python-libtorrent vía HTTP)</string>
<string id="30069">Añadir tamaño a nombre de archivo</string>
<string id="30070">Activar protocolo DHT</string>
<string id="30071">Estuary (de DiMartino)</string>
<string id="30072">Modo presentación de datos</string>
<string id="30073">Al final</string>
<string id="30074">Al principio</string>
<string id="30075">En segunda línea</string>
<string id="30076">Arctic: Zephyr (de xbmc00)</string>
<string id="30101">Interfaz</string>
<string id="30102">Red P2P</string>
<string id="30103">Avanzado</string>
<string id="30104">Cliente de BitTorrent</string>
<string id="30105">Hentai (reajustes)</string>
<string id="30106">Modo ventana de búsquedas</string>
<string id="30107">Activado ocultar estilo anterior</string>
<string id="30108">Activado remplazar estilo anterior</string>
<string id="30109">Activado opcional</string>
<string id="30110">Desactivado</string>
<string id="30111">Fondo transparente de ventana de búsquedas</string>
<string id="30112">Desactivar notificaciones</string>
<string id="50301">Ruta para guardar</string>
<string id="50302">Preguntar</string>
<string id="50303">Por defecto</string>
<string id="50304">Ruta</string>
<string id="50305">Crear subdirectorio para scrapper</string>
<string id="50312">Host</string>
<string id="50313">Puerto</string>
<string id="50314">URL</string>
<string id="50315">Usuario</string>
<string id="50316">Contraseña</string>
<string id="50311">Cliente de BitTorrent</string>
<string id="50317">URL (no SSL)</string>
<string id="30426">Sustitución de ruta (Solo remoto)</string>
<string id="30412">Cerrar</string>
<string id="30413">Abrir "Ajustes"</string>
<string id="30414">Navegador de cliente BitTorrent</string>
<string id="30415">Instalar rastreadores</string>
<string id="30416">Ajustes de rastreadores</string>
<string id="30417">Vaciar almacén</string>
<string id="30418">Seleccionar buscador</string>
<string id="30419">No hay buscador externo. Instale uno primero.</string>
</strings>

View File

@ -1,72 +1,66 @@
# -*- coding: utf-8 -*-
import os, re, fnmatch, threading, urllib2, time, shelve, anydbm
import os, re, fnmatch, threading, urllib2
from contextlib import contextmanager, closing
from functions import log, debug, tempdir
LOCKS = {}
PAC_URL = "http://antizapret.prostovpn.org/proxy.pac"
CACHE_DIR = tempdir()
USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"
CONFIG_LOCK = threading.Lock()
if not os.path.exists(CACHE_DIR):
os.makedirs(CACHE_DIR)
CACHE_LIFETIME = 24 * 3600 # 24 hour caching
CACHE = 24 * 3600 # 24 hour caching
#@contextmanager
def shelf(filename, ttl=0):
import shelve
filename = os.path.join(CACHE_DIR, filename)
with LOCKS.get(filename, threading.RLock()):
# with closing(shelve.open(filename, writeback=True)) as d:
d = shelve.open(filename, writeback=True)
try:
import time
if not dict(d):
d.update({
"created_at": time.time(),
"data": {},
})
elif ttl > 0 and (time.time() - d["created_at"]) > ttl:
d["created_at"] = time.time()
d["data"] = {}
return d
except:
d.close()
raise
_config = {}
def config():
shelf = None
try:
CONFIG_LOCK.acquire()
filename = os.path.join(CACHE_DIR, "antizapret.pac_config2")
try:
shelf = shelve.open(filename)
except anydbm.error:
os.remove(filename)
shelf = shelve.open(filename)
global _config
if not _config:
# with shelf("antizapret.pac_config", ttl=CACHE) as pac_config:
d = shelf("antizapret.pac_config2", ttl=CACHE)
pac_config = d['data']
if not pac_config:
log("[antizapret]: Fetching Antizapret PAC file on %s" %PAC_URL)
try:
pac_data = urllib2.urlopen(PAC_URL).read()
except:
pac_data = ""
created_at = 0
data = {}
if 'created_at' in shelf:
created_at = shelf['created_at']
if 'data' in shelf:
data = shelf['data']
if((time.time() - created_at) <= CACHE_LIFETIME
and 'domains' in data
and len(data['domains']) > 0):
return data
log("[antizapret]: Fetching Antizapret PAC file on %s" %PAC_URL)
try:
pac_data = urllib2.urlopen(PAC_URL).read()
except:
pac_data = ""
r = re.search(r"\"PROXY (.*); DIRECT", pac_data)
if r:
data["server"] = r.group(1)
data["domains"] = map(lambda x: x.replace(r"\Z(?ms)", "").replace("\\", ""), map(fnmatch.translate, re.findall(r"\"(.*?)\",", pac_data)))
else:
data["server"] = None
data["domains"] = []
shelf.clear()
shelf.update({
"created_at": time.time(),
"data": data,
})
return data
except Exception as ex:
debug("[antizapret]: " + str(ex))
raise
finally:
if shelf:
shelf.close()
if CONFIG_LOCK.locked():
CONFIG_LOCK.release()
r = re.search(r"\"PROXY (.*); DIRECT", pac_data)
if r:
pac_config["server"] = r.group(1)
pac_config["domains"] = map(lambda x: x.replace(r"\Z(?ms)", "").replace("\\", ""), map(fnmatch.translate, re.findall(r"\"(.*?)\",", pac_data)))
else:
pac_config["server"] = None
pac_config["domains"] = []
d.close()
_config = pac_config
return _config
class AntizapretProxyHandler(urllib2.ProxyHandler, object):
def __init__(self):
@ -79,8 +73,7 @@ class AntizapretProxyHandler(urllib2.ProxyHandler, object):
def proxy_open(self, req, proxy, type):
import socket
hostname = req.get_host().split(":")[0]
if socket.gethostbyname(hostname) in self.config["domains"] or hostname in self.config["domains"]:
if socket.gethostbyname(req.get_host().split(":")[0]) in self.config["domains"]:
debug("[antizapret]: Pass request through proxy " + self.config["server"])
return urllib2.ProxyHandler.proxy_open(self, req, self.config["server"], type)
@ -112,3 +105,4 @@ def url_get(url, params={}, headers={}, post = None):
except urllib2.HTTPError as e:
log("[antizapret]: HTTP Error(%s): %s" % (e.errno, e.strerror))
return None

View File

@ -1,802 +0,0 @@
"""
SocksiPy - Python SOCKS module.
Version 1.6.5
Copyright 2006 Dan-Haim. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of Dan Haim nor the names of his contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
This module provides a standard socket-like interface for Python
for tunneling connections through SOCKS proxies.
===============================================================================
Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
for use in PyLoris (http://pyloris.sourceforge.net/)
Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
mainly to merge bug fixes found in Sourceforge
Modifications made by Anorov (https://github.com/Anorov)
-Forked and renamed to PySocks
-Fixed issue with HTTP proxy failure checking (same bug that was in the old ___recvall() method)
-Included SocksiPyHandler (sockshandler.py), to be used as a urllib2 handler,
courtesy of e000 (https://github.com/e000): https://gist.github.com/869791#file_socksipyhandler.py
-Re-styled code to make it readable
-Aliased PROXY_TYPE_SOCKS5 -> SOCKS5 etc.
-Improved exception handling and output
-Removed irritating use of sequence indexes, replaced with tuple unpacked variables
-Fixed up Python 3 bytestring handling - chr(0x03).encode() -> b"\x03"
-Other general fixes
-Added clarification that the HTTP proxy connection method only supports CONNECT-style tunneling HTTP proxies
-Various small bug fixes
"""
__version__ = "1.6.5"
import socket
import struct
from errno import EOPNOTSUPP, EINVAL, EAGAIN
from io import BytesIO
from os import SEEK_CUR
import os
import sys
from collections import Callable
from base64 import b64encode
if os.name == "nt" and sys.version_info < (3, 0):
try:
from resources.proxy import win_inet_pton
except ImportError:
raise ImportError("To run PySocks on Windows you must install win_inet_pton")
PROXY_TYPE_SOCKS4 = SOCKS4 = 1
PROXY_TYPE_SOCKS5 = SOCKS5 = 2
PROXY_TYPE_HTTP = HTTP = 3
PROXY_TYPES = {"SOCKS4": SOCKS4, "SOCKS5": SOCKS5, "HTTP": HTTP}
PRINTABLE_PROXY_TYPES = dict(zip(PROXY_TYPES.values(), PROXY_TYPES.keys()))
_orgsocket = _orig_socket = socket.socket
class ProxyError(IOError):
"""
socket_err contains original socket.error exception.
"""
def __init__(self, msg, socket_err=None):
self.msg = msg
self.socket_err = socket_err
if socket_err:
self.msg += ": {0}".format(socket_err)
def __str__(self):
return self.msg
class GeneralProxyError(ProxyError): pass
class ProxyConnectionError(ProxyError): pass
class SOCKS5AuthError(ProxyError): pass
class SOCKS5Error(ProxyError): pass
class SOCKS4Error(ProxyError): pass
class HTTPError(ProxyError): pass
SOCKS4_ERRORS = { 0x5B: "Request rejected or failed",
0x5C: "Request rejected because SOCKS server cannot connect to identd on the client",
0x5D: "Request rejected because the client program and identd report different user-ids"
}
SOCKS5_ERRORS = { 0x01: "General SOCKS server failure",
0x02: "Connection not allowed by ruleset",
0x03: "Network unreachable",
0x04: "Host unreachable",
0x05: "Connection refused",
0x06: "TTL expired",
0x07: "Command not supported, or protocol error",
0x08: "Address type not supported"
}
DEFAULT_PORTS = { SOCKS4: 1080,
SOCKS5: 1080,
HTTP: 8080
}
def set_default_proxy(proxy_type=None, addr=None, port=None, rdns=True, username=None, password=None):
"""
set_default_proxy(proxy_type, addr[, port[, rdns[, username, password]]])
Sets a default proxy which all further socksocket objects will use,
unless explicitly changed. All parameters are as for socket.set_proxy().
"""
socksocket.default_proxy = (proxy_type, addr, port, rdns,
username.encode() if username else None,
password.encode() if password else None)
setdefaultproxy = set_default_proxy
def get_default_proxy():
"""
Returns the default proxy, set by set_default_proxy.
"""
return socksocket.default_proxy
getdefaultproxy = get_default_proxy
def wrap_module(module):
"""
Attempts to replace a module's socket library with a SOCKS socket. Must set
a default proxy using set_default_proxy(...) first.
This will only work on modules that import socket directly into the namespace;
most of the Python Standard Library falls into this category.
"""
if socksocket.default_proxy:
module.socket.socket = socksocket
else:
raise GeneralProxyError("No default proxy specified")
wrapmodule = wrap_module
def create_connection(dest_pair, proxy_type=None, proxy_addr=None,
proxy_port=None, proxy_rdns=True,
proxy_username=None, proxy_password=None,
timeout=None, source_address=None,
socket_options=None):
"""create_connection(dest_pair, *[, timeout], **proxy_args) -> socket object
Like socket.create_connection(), but connects to proxy
before returning the socket object.
dest_pair - 2-tuple of (IP/hostname, port).
**proxy_args - Same args passed to socksocket.set_proxy() if present.
timeout - Optional socket timeout value, in seconds.
source_address - tuple (host, port) for the socket to bind to as its source
address before connecting (only for compatibility)
"""
# Remove IPv6 brackets on the remote address and proxy address.
remote_host, remote_port = dest_pair
if remote_host.startswith('['):
remote_host = remote_host.strip('[]')
if proxy_addr and proxy_addr.startswith('['):
proxy_addr = proxy_addr.strip('[]')
err = None
# Allow the SOCKS proxy to be on IPv4 or IPv6 addresses.
for r in socket.getaddrinfo(proxy_addr, proxy_port, 0, socket.SOCK_STREAM):
family, socket_type, proto, canonname, sa = r
sock = None
try:
sock = socksocket(family, socket_type, proto)
if socket_options:
for opt in socket_options:
sock.setsockopt(*opt)
if isinstance(timeout, (int, float)):
sock.settimeout(timeout)
if proxy_type:
sock.set_proxy(proxy_type, proxy_addr, proxy_port, proxy_rdns,
proxy_username, proxy_password)
if source_address:
sock.bind(source_address)
sock.connect((remote_host, remote_port))
return sock
except (socket.error, ProxyConnectionError) as e:
err = e
if sock:
sock.close()
sock = None
if err:
raise err
raise socket.error("gai returned empty list.")
class _BaseSocket(socket.socket):
"""Allows Python 2's "delegated" methods such as send() to be overridden
"""
def __init__(self, *pos, **kw):
_orig_socket.__init__(self, *pos, **kw)
self._savedmethods = dict()
for name in self._savenames:
self._savedmethods[name] = getattr(self, name)
delattr(self, name) # Allows normal overriding mechanism to work
_savenames = list()
def _makemethod(name):
return lambda self, *pos, **kw: self._savedmethods[name](*pos, **kw)
for name in ("sendto", "send", "recvfrom", "recv"):
method = getattr(_BaseSocket, name, None)
# Determine if the method is not defined the usual way
# as a function in the class.
# Python 2 uses __slots__, so there are descriptors for each method,
# but they are not functions.
if not isinstance(method, Callable):
_BaseSocket._savenames.append(name)
setattr(_BaseSocket, name, _makemethod(name))
class socksocket(_BaseSocket):
"""socksocket([family[, type[, proto]]]) -> socket object
Open a SOCKS enabled socket. The parameters are the same as
those of the standard socket init. In order for SOCKS to work,
you must specify family=AF_INET and proto=0.
The "type" argument must be either SOCK_STREAM or SOCK_DGRAM.
"""
default_proxy = None
def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, *args, **kwargs):
if type not in (socket.SOCK_STREAM, socket.SOCK_DGRAM):
msg = "Socket type must be stream or datagram, not {!r}"
raise ValueError(msg.format(type))
_BaseSocket.__init__(self, family, type, proto, *args, **kwargs)
self._proxyconn = None # TCP connection to keep UDP relay alive
if self.default_proxy:
self.proxy = self.default_proxy
else:
self.proxy = (None, None, None, None, None, None)
self.proxy_sockname = None
self.proxy_peername = None
self._timeout = None
def _readall(self, file, count):
"""
Receive EXACTLY the number of bytes requested from the file object.
Blocks until the required number of bytes have been received.
"""
data = b""
while len(data) < count:
d = file.read(count - len(data))
if not d:
raise GeneralProxyError("Connection closed unexpectedly")
data += d
return data
def settimeout(self, timeout):
self._timeout = timeout
try:
# test if we're connected, if so apply timeout
peer = self.get_proxy_peername()
_BaseSocket.settimeout(self, self._timeout)
except socket.error:
pass
def gettimeout(self):
return self._timeout
def setblocking(self, v):
if v:
self.settimeout(None)
else:
self.settimeout(0.0)
def set_proxy(self, proxy_type=None, addr=None, port=None, rdns=True, username=None, password=None):
"""set_proxy(proxy_type, addr[, port[, rdns[, username[, password]]]])
Sets the proxy to be used.
proxy_type - The type of the proxy to be used. Three types
are supported: PROXY_TYPE_SOCKS4 (including socks4a),
PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
addr - The address of the server (IP or DNS).
port - The port of the server. Defaults to 1080 for SOCKS
servers and 8080 for HTTP proxy servers.
rdns - Should DNS queries be performed on the remote side
(rather than the local side). The default is True.
Note: This has no effect with SOCKS4 servers.
username - Username to authenticate with to the server.
The default is no authentication.
password - Password to authenticate with to the server.
Only relevant when username is also provided.
"""
self.proxy = (proxy_type, addr, port, rdns,
username.encode() if username else None,
password.encode() if password else None)
setproxy = set_proxy
def bind(self, *pos, **kw):
"""
Implements proxy connection for UDP sockets,
which happens during the bind() phase.
"""
proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy
if not proxy_type or self.type != socket.SOCK_DGRAM:
return _orig_socket.bind(self, *pos, **kw)
if self._proxyconn:
raise socket.error(EINVAL, "Socket already bound to an address")
if proxy_type != SOCKS5:
msg = "UDP only supported by SOCKS5 proxy type"
raise socket.error(EOPNOTSUPP, msg)
_BaseSocket.bind(self, *pos, **kw)
# Need to specify actual local port because
# some relays drop packets if a port of zero is specified.
# Avoid specifying host address in case of NAT though.
_, port = self.getsockname()
dst = ("0", port)
self._proxyconn = _orig_socket()
proxy = self._proxy_addr()
self._proxyconn.connect(proxy)
UDP_ASSOCIATE = b"\x03"
_, relay = self._SOCKS5_request(self._proxyconn, UDP_ASSOCIATE, dst)
# The relay is most likely on the same host as the SOCKS proxy,
# but some proxies return a private IP address (10.x.y.z)
host, _ = proxy
_, port = relay
_BaseSocket.connect(self, (host, port))
_BaseSocket.settimeout(self, self._timeout)
self.proxy_sockname = ("0.0.0.0", 0) # Unknown
def sendto(self, bytes, *args, **kwargs):
if self.type != socket.SOCK_DGRAM:
return _BaseSocket.sendto(self, bytes, *args, **kwargs)
if not self._proxyconn:
self.bind(("", 0))
address = args[-1]
flags = args[:-1]
header = BytesIO()
RSV = b"\x00\x00"
header.write(RSV)
STANDALONE = b"\x00"
header.write(STANDALONE)
self._write_SOCKS5_address(address, header)
sent = _BaseSocket.send(self, header.getvalue() + bytes, *flags, **kwargs)
return sent - header.tell()
def send(self, bytes, flags=0, **kwargs):
if self.type == socket.SOCK_DGRAM:
return self.sendto(bytes, flags, self.proxy_peername, **kwargs)
else:
return _BaseSocket.send(self, bytes, flags, **kwargs)
def recvfrom(self, bufsize, flags=0):
if self.type != socket.SOCK_DGRAM:
return _BaseSocket.recvfrom(self, bufsize, flags)
if not self._proxyconn:
self.bind(("", 0))
buf = BytesIO(_BaseSocket.recv(self, bufsize + 1024, flags))
buf.seek(2, SEEK_CUR)
frag = buf.read(1)
if ord(frag):
raise NotImplementedError("Received UDP packet fragment")
fromhost, fromport = self._read_SOCKS5_address(buf)
if self.proxy_peername:
peerhost, peerport = self.proxy_peername
if fromhost != peerhost or peerport not in (0, fromport):
raise socket.error(EAGAIN, "Packet filtered")
return (buf.read(bufsize), (fromhost, fromport))
def recv(self, *pos, **kw):
bytes, _ = self.recvfrom(*pos, **kw)
return bytes
def close(self):
if self._proxyconn:
self._proxyconn.close()
return _BaseSocket.close(self)
def get_proxy_sockname(self):
"""
Returns the bound IP address and port number at the proxy.
"""
return self.proxy_sockname
getproxysockname = get_proxy_sockname
def get_proxy_peername(self):
"""
Returns the IP and port number of the proxy.
"""
return _BaseSocket.getpeername(self)
getproxypeername = get_proxy_peername
def get_peername(self):
"""
Returns the IP address and port number of the destination
machine (note: get_proxy_peername returns the proxy)
"""
return self.proxy_peername
getpeername = get_peername
def _negotiate_SOCKS5(self, *dest_addr):
"""
Negotiates a stream connection through a SOCKS5 server.
"""
CONNECT = b"\x01"
self.proxy_peername, self.proxy_sockname = self._SOCKS5_request(self,
CONNECT, dest_addr)
def _SOCKS5_request(self, conn, cmd, dst):
"""
Send SOCKS5 request with given command (CMD field) and
address (DST field). Returns resolved DST address that was used.
"""
proxy_type, addr, port, rdns, username, password = self.proxy
writer = conn.makefile("wb")
reader = conn.makefile("rb", 0) # buffering=0 renamed in Python 3
try:
# First we'll send the authentication packages we support.
if username and password:
# The username/password details were supplied to the
# set_proxy method so we support the USERNAME/PASSWORD
# authentication (in addition to the standard none).
writer.write(b"\x05\x02\x00\x02")
else:
# No username/password were entered, therefore we
# only support connections with no authentication.
writer.write(b"\x05\x01\x00")
# We'll receive the server's response to determine which
# method was selected
writer.flush()
chosen_auth = self._readall(reader, 2)
if chosen_auth[0:1] != b"\x05":
# Note: string[i:i+1] is used because indexing of a bytestring
# via bytestring[i] yields an integer in Python 3
raise GeneralProxyError("SOCKS5 proxy server sent invalid data")
# Check the chosen authentication method
if chosen_auth[1:2] == b"\x02":
# Okay, we need to perform a basic username/password
# authentication.
writer.write(b"\x01" + chr(len(username)).encode()
+ username
+ chr(len(password)).encode()
+ password)
writer.flush()
auth_status = self._readall(reader, 2)
if auth_status[0:1] != b"\x01":
# Bad response
raise GeneralProxyError("SOCKS5 proxy server sent invalid data")
if auth_status[1:2] != b"\x00":
# Authentication failed
raise SOCKS5AuthError("SOCKS5 authentication failed")
# Otherwise, authentication succeeded
# No authentication is required if 0x00
elif chosen_auth[1:2] != b"\x00":
# Reaching here is always bad
if chosen_auth[1:2] == b"\xFF":
raise SOCKS5AuthError("All offered SOCKS5 authentication methods were rejected")
else:
raise GeneralProxyError("SOCKS5 proxy server sent invalid data")
# Now we can request the actual connection
writer.write(b"\x05" + cmd + b"\x00")
resolved = self._write_SOCKS5_address(dst, writer)
writer.flush()
# Get the response
resp = self._readall(reader, 3)
if resp[0:1] != b"\x05":
raise GeneralProxyError("SOCKS5 proxy server sent invalid data")
status = ord(resp[1:2])
if status != 0x00:
# Connection failed: server returned an error
error = SOCKS5_ERRORS.get(status, "Unknown error")
raise SOCKS5Error("{0:#04x}: {1}".format(status, error))
# Get the bound address/port
bnd = self._read_SOCKS5_address(reader)
_BaseSocket.settimeout(self, self._timeout)
return (resolved, bnd)
finally:
reader.close()
writer.close()
def _write_SOCKS5_address(self, addr, file):
"""
Return the host and port packed for the SOCKS5 protocol,
and the resolved address as a tuple object.
"""
host, port = addr
proxy_type, _, _, rdns, username, password = self.proxy
family_to_byte = {socket.AF_INET: b"\x01", socket.AF_INET6: b"\x04"}
# If the given destination address is an IP address, we'll
# use the IP address request even if remote resolving was specified.
# Detect whether the address is IPv4/6 directly.
for family in (socket.AF_INET, socket.AF_INET6):
try:
addr_bytes = socket.inet_pton(family, host)
file.write(family_to_byte[family] + addr_bytes)
host = socket.inet_ntop(family, addr_bytes)
file.write(struct.pack(">H", port))
return host, port
except socket.error:
continue
# Well it's not an IP number, so it's probably a DNS name.
if rdns:
# Resolve remotely
host_bytes = host.encode('idna')
file.write(b"\x03" + chr(len(host_bytes)).encode() + host_bytes)
else:
# Resolve locally
addresses = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_ADDRCONFIG)
# We can't really work out what IP is reachable, so just pick the
# first.
target_addr = addresses[0]
family = target_addr[0]
host = target_addr[4][0]
addr_bytes = socket.inet_pton(family, host)
file.write(family_to_byte[family] + addr_bytes)
host = socket.inet_ntop(family, addr_bytes)
file.write(struct.pack(">H", port))
return host, port
def _read_SOCKS5_address(self, file):
atyp = self._readall(file, 1)
if atyp == b"\x01":
addr = socket.inet_ntoa(self._readall(file, 4))
elif atyp == b"\x03":
length = self._readall(file, 1)
addr = self._readall(file, ord(length))
elif atyp == b"\x04":
addr = socket.inet_ntop(socket.AF_INET6, self._readall(file, 16))
else:
raise GeneralProxyError("SOCKS5 proxy server sent invalid data")
port = struct.unpack(">H", self._readall(file, 2))[0]
return addr, port
def _negotiate_SOCKS4(self, dest_addr, dest_port):
"""
Negotiates a connection through a SOCKS4 server.
"""
proxy_type, addr, port, rdns, username, password = self.proxy
writer = self.makefile("wb")
reader = self.makefile("rb", 0) # buffering=0 renamed in Python 3
try:
# Check if the destination address provided is an IP address
remote_resolve = False
try:
addr_bytes = socket.inet_aton(dest_addr)
except socket.error:
# It's a DNS name. Check where it should be resolved.
if rdns:
addr_bytes = b"\x00\x00\x00\x01"
remote_resolve = True
else:
addr_bytes = socket.inet_aton(socket.gethostbyname(dest_addr))
# Construct the request packet
writer.write(struct.pack(">BBH", 0x04, 0x01, dest_port))
writer.write(addr_bytes)
# The username parameter is considered userid for SOCKS4
if username:
writer.write(username)
writer.write(b"\x00")
# DNS name if remote resolving is required
# NOTE: This is actually an extension to the SOCKS4 protocol
# called SOCKS4A and may not be supported in all cases.
if remote_resolve:
writer.write(dest_addr.encode('idna') + b"\x00")
writer.flush()
# Get the response from the server
resp = self._readall(reader, 8)
if resp[0:1] != b"\x00":
# Bad data
raise GeneralProxyError("SOCKS4 proxy server sent invalid data")
status = ord(resp[1:2])
if status != 0x5A:
# Connection failed: server returned an error
error = SOCKS4_ERRORS.get(status, "Unknown error")
raise SOCKS4Error("{0:#04x}: {1}".format(status, error))
# Get the bound address/port
self.proxy_sockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
if remote_resolve:
self.proxy_peername = socket.inet_ntoa(addr_bytes), dest_port
else:
self.proxy_peername = dest_addr, dest_port
finally:
reader.close()
writer.close()
def _negotiate_HTTP(self, dest_addr, dest_port):
"""
Negotiates a connection through an HTTP server.
NOTE: This currently only supports HTTP CONNECT-style proxies.
"""
proxy_type, addr, port, rdns, username, password = self.proxy
# If we need to resolve locally, we do this now
addr = dest_addr if rdns else socket.gethostbyname(dest_addr)
http_headers = [
b"CONNECT " + addr.encode('idna') + b":" + str(dest_port).encode() + b" HTTP/1.1",
b"Host: " + dest_addr.encode('idna')
]
if username and password:
http_headers.append(b"Proxy-Authorization: basic " + b64encode(username + b":" + password))
http_headers.append(b"\r\n")
self.sendall(b"\r\n".join(http_headers))
# We just need the first line to check if the connection was successful
fobj = self.makefile()
status_line = fobj.readline()
fobj.close()
if not status_line:
raise GeneralProxyError("Connection closed unexpectedly")
try:
proto, status_code, status_msg = status_line.split(" ", 2)
except ValueError:
raise GeneralProxyError("HTTP proxy server sent invalid response")
if not proto.startswith("HTTP/"):
raise GeneralProxyError("Proxy server does not appear to be an HTTP proxy")
try:
status_code = int(status_code)
except ValueError:
raise HTTPError("HTTP proxy server did not return a valid HTTP status")
if status_code != 200:
error = "{0}: {1}".format(status_code, status_msg)
if status_code in (400, 403, 405):
# It's likely that the HTTP proxy server does not support the CONNECT tunneling method
error += ("\n[*] Note: The HTTP proxy server may not be supported by PySocks"
" (must be a CONNECT tunnel proxy)")
raise HTTPError(error)
self.proxy_sockname = (b"0.0.0.0", 0)
self.proxy_peername = addr, dest_port
_proxy_negotiators = {
SOCKS4: _negotiate_SOCKS4,
SOCKS5: _negotiate_SOCKS5,
HTTP: _negotiate_HTTP
}
def connect(self, dest_pair):
"""
Connects to the specified destination through a proxy.
Uses the same API as socket's connect().
To select the proxy server, use set_proxy().
dest_pair - 2-tuple of (IP/hostname, port).
"""
if len(dest_pair) != 2 or dest_pair[0].startswith("["):
# Probably IPv6, not supported -- raise an error, and hope
# Happy Eyeballs (RFC6555) makes sure at least the IPv4
# connection works...
raise socket.error("PySocks doesn't support IPv6")
dest_addr, dest_port = dest_pair
if self.type == socket.SOCK_DGRAM:
if not self._proxyconn:
self.bind(("", 0))
dest_addr = socket.gethostbyname(dest_addr)
# If the host address is INADDR_ANY or similar, reset the peer
# address so that packets are received from any peer
if dest_addr == "0.0.0.0" and not dest_port:
self.proxy_peername = None
else:
self.proxy_peername = (dest_addr, dest_port)
return
proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy
# Do a minimal input check first
if (not isinstance(dest_pair, (list, tuple))
or len(dest_pair) != 2
or not dest_addr
or not isinstance(dest_port, int)):
raise GeneralProxyError("Invalid destination-connection (host, port) pair")
# We set the timeout here so that we don't hang in connection or during
# negotiation.
_BaseSocket.settimeout(self, self._timeout)
if proxy_type is None:
# Treat like regular socket object
self.proxy_peername = dest_pair
_BaseSocket.settimeout(self, self._timeout)
_BaseSocket.connect(self, (dest_addr, dest_port))
return
proxy_addr = self._proxy_addr()
try:
# Initial connection to proxy server.
_BaseSocket.connect(self, proxy_addr)
except socket.error as error:
# Error while connecting to proxy
self.close()
proxy_addr, proxy_port = proxy_addr
proxy_server = "{0}:{1}".format(proxy_addr, proxy_port)
printable_type = PRINTABLE_PROXY_TYPES[proxy_type]
msg = "Error connecting to {0} proxy {1}".format(printable_type,
proxy_server)
raise ProxyConnectionError(msg, error)
else:
# Connected to proxy server, now negotiate
try:
# Calls negotiate_{SOCKS4, SOCKS5, HTTP}
negotiate = self._proxy_negotiators[proxy_type]
negotiate(self, dest_addr, dest_port)
except socket.error as error:
# Wrap socket errors
self.close()
raise GeneralProxyError("Socket error", error)
except ProxyError:
# Protocol error while negotiating with proxy
self.close()
raise
def _proxy_addr(self):
"""
Return proxy address to connect to as tuple object
"""
proxy_type, proxy_addr, proxy_port, rdns, username, password = self.proxy
proxy_port = proxy_port or DEFAULT_PORTS.get(proxy_type)
if not proxy_port:
raise GeneralProxyError("Invalid proxy type")
return proxy_addr, proxy_port

View File

@ -1,84 +0,0 @@
# This software released into the public domain. Anyone is free to copy,
# modify, publish, use, compile, sell, or distribute this software,
# either in source code form or as a compiled binary, for any purpose,
# commercial or non-commercial, and by any means.
import socket
import ctypes
import os
class sockaddr(ctypes.Structure):
_fields_ = [("sa_family", ctypes.c_short),
("__pad1", ctypes.c_ushort),
("ipv4_addr", ctypes.c_byte * 4),
("ipv6_addr", ctypes.c_byte * 16),
("__pad2", ctypes.c_ulong)]
if hasattr(ctypes, 'windll'):
WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA
WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA
else:
def not_windows():
raise SystemError(
"Invalid platform. ctypes.windll must be available."
)
WSAStringToAddressA = not_windows
WSAAddressToStringA = not_windows
def inet_pton(address_family, ip_string):
addr = sockaddr()
addr.sa_family = address_family
addr_size = ctypes.c_int(ctypes.sizeof(addr))
if WSAStringToAddressA(
ip_string,
address_family,
None,
ctypes.byref(addr),
ctypes.byref(addr_size)
) != 0:
raise socket.error(ctypes.FormatError())
if address_family == socket.AF_INET:
return ctypes.string_at(addr.ipv4_addr, 4)
if address_family == socket.AF_INET6:
return ctypes.string_at(addr.ipv6_addr, 16)
raise socket.error('unknown address family')
def inet_ntop(address_family, packed_ip):
addr = sockaddr()
addr.sa_family = address_family
addr_size = ctypes.c_int(ctypes.sizeof(addr))
ip_string = ctypes.create_string_buffer(128)
ip_string_size = ctypes.c_int(ctypes.sizeof(ip_string))
if address_family == socket.AF_INET:
if len(packed_ip) != ctypes.sizeof(addr.ipv4_addr):
raise socket.error('packed IP wrong length for inet_ntoa')
ctypes.memmove(addr.ipv4_addr, packed_ip, 4)
elif address_family == socket.AF_INET6:
if len(packed_ip) != ctypes.sizeof(addr.ipv6_addr):
raise socket.error('packed IP wrong length for inet_ntoa')
ctypes.memmove(addr.ipv6_addr, packed_ip, 16)
else:
raise socket.error('unknown address family')
if WSAAddressToStringA(
ctypes.byref(addr),
addr_size,
None,
ip_string,
ctypes.byref(ip_string_size)
) != 0:
raise socket.error(ctypes.FormatError())
return ip_string[:ip_string_size.value - 1]
# Adding our two functions to the socket library
if os.name == 'nt':
socket.inet_pton = inet_pton
socket.inet_ntop = inet_ntop

View File

@ -0,0 +1,786 @@
# -*- coding: utf-8 -*-
# This is a "local" version of PyXBMCt to be used in standalone addons.
#
# PyXBMCt is a mini-framework for creating XBMC Python addons with arbitrary UI
# made of controls - decendants of xbmcgui.Control class.
# The framework uses image textures from XBMC Confluence skin.
#
# Licence: GPL v.3 http://www.gnu.org/licenses/gpl.html
#
## @package addonwindow
# PyXBMCt framework module
import os
import xbmc
import xbmcgui
# _addon = xbmcaddon.Addon()
_images = os.path.join(os.path.dirname(__file__), 'textures', 'default')
# Text alighnment constants. Mixed variants are obtained by bit OR (|)
ALIGN_LEFT = 0
ALIGN_RIGHT = 1
ALIGN_CENTER_X = 2
ALIGN_CENTER_Y = 4
ALIGN_CENTER = 6
ALIGN_TRUNCATED = 8
ALIGN_JUSTIFY = 10
# XBMC key action codes.
# More codes at https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
## ESC action
ACTION_PREVIOUS_MENU = 10
## Backspace action
ACTION_NAV_BACK = 92
## Left arrow key
ACTION_MOVE_LEFT = 1
## Right arrow key
ACTION_MOVE_RIGHT = 2
## Up arrow key
ACTION_MOVE_UP = 3
## Down arrow key
ACTION_MOVE_DOWN = 4
## Mouse wheel up
ACTION_MOUSE_WHEEL_UP = 104
## Mouse wheel down
ACTION_MOUSE_WHEEL_DOWN = 105
## Mouse drag
ACTION_MOUSE_DRAG = 106
## Mouse move
ACTION_MOUSE_MOVE = 107
def _set_textures(textures={}, kwargs={}):
"""Set texture arguments for controls."""
for texture in textures.keys():
try:
kwargs[texture]
except KeyError:
kwargs[texture] = textures[texture]
class AddonWindowError(Exception):
"""Custom exception."""
pass
class Label(xbmcgui.ControlLabel):
"""ControlLabel class.
Parameters:
label: string or unicode - text string.
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
alignment: integer - alignment of label - *Note, see xbfont.h
hasPath: bool - True=stores a path / False=no path.
angle: integer - angle of control. (+ rotates CCW, - rotates CW)"
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.label = Label('Status', angle=45)
"""
def __new__(cls, *args, **kwargs):
return super(Label, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class FadeLabel(xbmcgui.ControlFadeLabel):
"""Control that scrolls label text.
Parameters:
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of fadelabel's labels. (e.g. '0xFFFFFFFF')
_alignment: integer - alignment of label - *Note, see xbfont.h
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.fadelabel = FadeLabel(textColor='0xFFFFFFFF')
"""
def __new__(cls, *args, **kwargs):
return super(FadeLabel, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class TextBox(xbmcgui.ControlTextBox):
"""ControlTextBox class.
Parameters:
font: string - font used for text. (e.g. 'font13')
textColor: hexstring - color of textbox's text. (e.g. '0xFFFFFFFF')
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.textbox = TextBox(textColor='0xFFFFFFFF')
"""
def __new__(cls, *args, **kwargs):
return super(TextBox, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Image(xbmcgui.ControlImage):
"""ControlImage class.
Parameters:
filename: string - image filename.
colorKey: hexString - (example, '0xFFFF3300')
aspectRatio: integer - (values 0 = stretch (default), 1 = scale up (crops), 2 = scale down (black bars)
colorDiffuse: hexString - (example, '0xC0FF0000' (red tint)).
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.image = Image('d:\images\picture.jpg', aspectRatio=2)
"""
def __new__(cls, *args, **kwargs):
return super(Image, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Button(xbmcgui.ControlButton):
"""ControlButton class.
Parameters:
label: string or unicode - text string.
focusTexture: string - filename for focus texture.
noFocusTexture: string - filename for no focus texture.
textOffsetX: integer - x offset of label.
textOffsetY: integer - y offset of label.
alignment: integer - alignment of label - *Note, see xbfont.h
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled button's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled button's label. (e.g. '0xFFFF3300')
angle: integer - angle of control. (+ rotates CCW, - rotates CW)
shadowColor: hexstring - color of button's label's shadow. (e.g. '0xFF000000')
focusedColor: hexstring - color of focused button's label. (e.g. '0xFF00FFFF')
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.button = Button('Status', font='font14')
"""
def __new__(cls, *args, **kwargs):
textures = {'focusTexture': os.path.join(_images, 'Button', 'KeyboardKey.png'),
'noFocusTexture': os.path.join(_images, 'Button', 'KeyboardKeyNF.png')}
_set_textures(textures, kwargs)
try:
kwargs['alignment']
except KeyError:
kwargs['alignment'] = ALIGN_CENTER
return super(Button, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class RadioButton(xbmcgui.ControlRadioButton):
"""ControlRadioButton class.
Parameters:
label: string or unicode - text string.
focusTexture: string - filename for focus texture.
noFocusTexture: string - filename for no focus texture.
textOffsetX: integer - x offset of label.
textOffsetY: integer - y offset of label.
_alignment: integer - alignment of label - *Note, see xbfont.h
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled radio button's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled radio button's label. (e.g. '0xFFFF3300')
angle: integer - angle of control. (+ rotates CCW, - rotates CW)
shadowColor: hexstring - color of radio button's label's shadow. (e.g. '0xFF000000')
focusedColor: hexstring - color of focused radio button's label. (e.g. '0xFF00FFFF')
focusOnTexture: string - filename for radio focused/checked texture.
noFocusOnTexture: string - filename for radio not focused/checked texture.
focusOffTexture: string - filename for radio focused/unchecked texture.
noFocusOffTexture: string - filename for radio not focused/unchecked texture.
Note: To customize RadioButton all 4 abovementioned textures need to be provided.
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.radiobutton = RadioButton('Status', font='font14')
"""
def __new__(cls, *args, **kwargs):
if int(xbmc.getInfoLabel('System.BuildVersion')[:2]) >= 13:
textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
'focusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'noFocusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'focusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png'),
'noFocusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
else: # This is for compatibility with Frodo and earlier versions.
textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
'TextureRadioFocus': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'TextureRadioNoFocus': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
_set_textures(textures, kwargs)
return super(RadioButton, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Edit(xbmcgui.ControlEdit):
"""
ControlEdit class.
Edit(label[, font, textColor, disabledColor, alignment, focusTexture, noFocusTexture])
Parameters:
label : string or unicode - text string.
font : [opt] string - font used for label text. (e.g. 'font13')
textColor : [opt] hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
disabledColor : [opt] hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
_alignment : [opt] integer - alignment of label - *Note, see xbfont.h
focusTexture : [opt] string - filename for focus texture.
noFocusTexture : [opt] string - filename for no focus texture.
isPassword : [opt] bool - if true, mask text value.
*Note, You can use the above as keywords for arguments and skip certain optional arguments.
Once you use a keyword, all following arguments require the keyword.
After you create the control, you need to add it to the window with palceControl().
example:
- self.edit = Edit('Status')
"""
def __new__(cls, *args, **kwargs):
textures = {'focusTexture': os.path.join(_images, 'Edit', 'button-focus.png'),
'noFocusTexture': os.path.join(_images, 'Edit', 'black-back2.png')}
_set_textures(textures, kwargs)
return super(Edit, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class List(xbmcgui.ControlList):
"""ControlList class.
Parameters:
font: string - font used for items label. (e.g. 'font13')
textColor: hexstring - color of items label. (e.g. '0xFFFFFFFF')
buttonTexture: string - filename for no focus texture.
buttonFocusTexture: string - filename for focus texture.
selectedColor: integer - x offset of label.
_imageWidth: integer - width of items icon or thumbnail.
_imageHeight: integer - height of items icon or thumbnail.
_itemTextXOffset: integer - x offset of items label.
_itemTextYOffset: integer - y offset of items label.
_itemHeight: integer - height of items.
_space: integer - space between items.
_alignmentY: integer - Y-axis alignment of items label - *Note, see xbfont.h
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.cList = List('font14', space=5)
"""
def __new__(cls, *args, **kwargs):
textures = {'buttonTexture': os.path.join(_images, 'List', 'MenuItemNF.png'),
'buttonFocusTexture': os.path.join(_images, 'List', 'MenuItemFO.png')}
_set_textures(textures, kwargs)
return super(List, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Slider(xbmcgui.ControlSlider):
"""ControlSlider class.
Parameters:
textureback: string - image filename.
texture: string - image filename.
texturefocus: string - image filename.
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.slider = Slider()
"""
def __new__(cls, *args, **kwargs):
textures = {'textureback': os.path.join(_images, 'Slider', 'osd_slider_bg.png'),
'texture': os.path.join(_images, 'Slider', 'osd_slider_nibNF.png'),
'texturefocus': os.path.join(_images, 'Slider', 'osd_slider_nib.png')}
_set_textures(textures, kwargs)
return super(Slider, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class _AbstractWindow(object):
"""
Top-level control window.
The control windows serves as a parent widget for other XBMC UI controls
much like Tkinter.Tk or PyQt QWidget class.
This is an abstract class which is not supposed to be instantiated directly
and will raise exeptions.
This class is a basic "skeleton" for a control window.
"""
def __init__(self):
"""Constructor method."""
self.actions_connected = []
self.controls_connected = []
def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1):
"""
Set width, height, Grid layout, and coordinates (optional) for a new control window.
Parameters:
width_, height_: widgh and height of the created window.
rows_, columns_: rows and colums of the Grid layout to place controls on.
pos_x, pos_y (optional): coordinates of the top left corner of the window.
If pos_x and pos_y are not privided, the window will be placed
at the center of the screen.
Example:
self.setGeometry(400, 500, 5, 4)
"""
self.width = width_
self.height = height_
self.rows = rows_
self.columns = columns_
if pos_x > 0 and pos_y > 0:
self.x = pos_x
self.y = pos_y
else:
self.x = 640 - self.width / 2
self.y = 360 - self.height / 2
self.setGrid()
def setGrid(self):
"""
Set window grid layout of rows * columns.
This is a helper method not to be called directly.
"""
self.grid_x = self.x
self.grid_y = self.y
self.tile_width = self.width / self.columns
self.tile_height = self.height / self.rows
def placeControl(self, control, row, column, rowspan=1, columnspan=1, pad_x=5, pad_y=5):
"""
Place a control within the window grid layout.
pad_x, pad_y: horisontal and vertical padding for control's
size and aspect adjustments. Negative values can be used
to make a control overlap with grid cells next to it, if necessary.
Raises AddonWindowError if a grid has not yet been set.
Example:
self.placeControl(self.label, 0, 1)
"""
try:
control_x = (self.grid_x + self.tile_width * column) + pad_x
control_y = (self.grid_y + self.tile_height * row) + pad_y
control_width = self.tile_width * columnspan - 2 * pad_x
control_height = self.tile_height * rowspan - 2 * pad_y
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
control.setPosition(control_x, control_y)
control.setWidth(control_width)
control.setHeight(control_height)
self.addControl(control)
self.setAnimation(control)
def getX(self):
"""Get X coordinate of the top-left corner of the window."""
try:
return self.x
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getY(self):
"""Get Y coordinate of the top-left corner of the window."""
try:
return self.y
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getWindowWidth(self):
"""Get window width."""
try:
return self.width
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getWindowHeight(self):
"""Get window height."""
try:
return self.height
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getRows(self):
"""
Get grid rows count.
Raises AddonWindowError if a grid has not yet been set.
"""
try:
return self.rows
except AttributeError:
raise AddonWindowError('Grid layot is not set! Call setGeometry first.')
def getColumns(self):
"""
Get grid columns count.
Raises AddonWindowError if a grid has not yet been set.
"""
try:
return self.columns
except AttributeError:
raise AddonWindowError('Grid layout is not set! Call setGeometry first.')
def connect(self, event, function):
"""
Connect an event to a function.
An event can be an inctance of a Control object or an integer key action code.
Several basic key action codes are provided by PyXBMCT. More action codes can be found at
https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
You can connect the following Controls: Button, RadioButton and List. Other Controls do not
generate any control events when activated so their connections won't work.
To catch Slider events you need to connect the following key actions:
ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT and ACTION_MOUSE_DRAG, and do a check
whether the Slider is focused.
"function" parameter is a function or a method to be executed. Note that you must provide
a function object [without brackets ()], not a function call!
lambda can be used as a function to call another function or method with parameters.
Examples:
self.connect(self.exit_button, self.close)
or
self.connect(ACTION_NAV_BACK, self.close)
"""
try:
self.disconnect(event)
except AddonWindowError:
if type(event) == int:
self.actions_connected.append([event, function])
else:
self.controls_connected.append([event, function])
def connectEventList(self, events, function):
"""
Connect a list of controls/action codes to a function.
See connect docstring for more info.
"""
[self.connect(event, function) for event in events]
def disconnect(self, event):
"""
Disconnect an event from a function.
An event can be an inctance of a Control object or an integer key action code
which has previously been connected to a function or a method.
Raises AddonWindowError if an event is not connected to any function.
Examples:
self.disconnect(self.exit_button)
or
self.disconnect(ACTION_NAV_BACK)
"""
if type(event) == int:
event_list = self.actions_connected
else:
event_list = self.controls_connected
for index in range(len(event_list)):
if event == event_list[index][0]:
event_list.pop(index)
break
else:
raise AddonWindowError('The action or control %s is not connected!' % event)
def disconnectEventList(self, events):
"""
Disconnect a list of controls/action codes from functions.
See disconnect docstring for more info.
Raises AddonWindowError if at least one event in the list
is not connected to any function.
"""
[self.disconnect(event) for event in events]
def executeConnected(self, event, connected_list):
"""
Execute a connected event (an action or a control).
This is a helper method not to be called directly.
"""
for item in connected_list:
if event == item[0]:
item[1]()
break
def setAnimation(self, control):
"""
This method is called to set animation properties for all controls
added to the current addon window instance - both built-in controls
(window background, title bar etc.) and controls added with placeControl().
It receives a control instance as the 2nd positional argument (besides self).
By default the method does nothing, i.e. no animation is set for controls.
To add animation you need to re-implement this menthod in your child class.
E.g:
def setAnimation(self, control):
control.setAnimations([('WindowOpen', 'effect=fade start=0 end=100 time=1000',),
('WindowClose', 'effect=fade start=100 end=0 time=1000',)])
"""
pass
class _AddonWindow(_AbstractWindow):
"""
Top-level control window.
The control windows serves as a parent widget for other XBMC UI controls
much like Tkinter.Tk or PyQt QWidget class.
This is an abstract class which is not supposed to be instantiated directly
and will raise exeptions. It is designed to be implemented in a grand-child class
with the second inheritance from xbmcgui.Window or xbmcgui.WindowDialog
in a direct child class.
This class provides a control window with a background and a header
similar to top-level widgets of desktop UI frameworks.
"""
def __init__(self, title=''):
"""Constructor method."""
super(_AddonWindow, self).__init__()
self.setFrame(title)
def setFrame(self, title):
"""
Define paths to images for window background and title background textures,
and set control position adjustment constants used in setGrid.
This is a helper method not to be called directly.
"""
# Window background image
self.background_img = os.path.join(_images, 'AddonWindow', 'ContentPanel.png')
# Background for a window header
self.title_background_img = os.path.join(_images, 'AddonWindow', 'dialogheader.png')
# Horisontal adjustment for a header background if the main background has transparent edges.
self.X_MARGIN = 5
# Vertical adjustment for a header background if the main background has transparent edges
self.Y_MARGIN = 5
# Header position adjustment if the main backround has visible borders.
self.Y_SHIFT = 4
# The height of a window header (for the title background and the title label).
self.HEADER_HEIGHT = 35
self.background = xbmcgui.ControlImage(-10, -10, 1, 1, self.background_img)
self.addControl(self.background)
self.setAnimation(self.background)
self.title_background = xbmcgui.ControlImage(-10, -10, 1, 1, self.title_background_img)
self.addControl(self.title_background)
self.setAnimation(self.title_background)
self.title_bar = xbmcgui.ControlLabel(-10, -10, 1, 1, title, alignment=ALIGN_CENTER, textColor='0xFFFFA500',
font='font13_title')
self.addControl(self.title_bar)
self.setAnimation(self.title_bar)
self.window_close_button = xbmcgui.ControlButton(-100, -100, 60, 30, '',
focusTexture=os.path.join(_images, 'AddonWindow',
'DialogCloseButton-focus.png'),
noFocusTexture=os.path.join(_images, 'AddonWindow',
'DialogCloseButton.png'))
self.addControl(self.window_close_button)
self.setAnimation(self.window_close_button)
def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1, padding=5):
"""
Set width, height, Grid layout, and coordinates (optional) for a new control window.
Parameters:
width_, height_: widgh and height of the created window.
rows_, columns_: rows and colums of the Grid layout to place controls on.
pos_x, pos_y (optional): coordinates of the top left corner of the window.
If pos_x and pos_y are not privided, the window will be placed
at the center of the screen.
padding (optional): padding between outer edges of the window and
controls placed on it.
Example:
self.setGeometry(400, 500, 5, 4)
"""
self.win_padding = padding
super(_AddonWindow, self).setGeometry(width_, height_, rows_, columns_, pos_x, pos_y)
self.background.setPosition(self.x, self.y)
self.background.setWidth(self.width)
self.background.setHeight(self.height)
self.title_background.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
self.title_background.setWidth(self.width - 2 * self.X_MARGIN)
self.title_background.setHeight(self.HEADER_HEIGHT)
self.title_bar.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
self.title_bar.setWidth(self.width - 2 * self.X_MARGIN)
self.title_bar.setHeight(self.HEADER_HEIGHT)
self.window_close_button.setPosition(self.x + self.width - 70, self.y + self.Y_MARGIN + self.Y_SHIFT)
def setGrid(self):
"""
Set window grid layout of rows * columns.
This is a helper method not to be called directly.
"""
self.grid_x = self.x + self.X_MARGIN + self.win_padding
self.grid_y = self.y + self.Y_MARGIN + self.Y_SHIFT + self.HEADER_HEIGHT + self.win_padding
self.tile_width = (self.width - 2 * (self.X_MARGIN + self.win_padding)) / self.columns
self.tile_height = (
self.height - self.HEADER_HEIGHT - self.Y_SHIFT - 2 * (
self.Y_MARGIN + self.win_padding)) / self.rows
def setWindowTitle(self, title=''):
"""
Set window title.
This method must be called AFTER (!!!) setGeometry(),
otherwise there is some werid bug with all skin text labels set to the 'title' text.
Example:
self.setWindowTitle('My Cool Addon')
"""
self.title_bar.setLabel(title)
def getWindowTitle(self):
"""Get window title."""
return self.title_bar.getLabel()
class _FullWindow(xbmcgui.Window):
"""An abstract class to define window event processing."""
def onAction(self, action):
"""
Catch button actions.
Note that, despite being compared to an integer,
action is an instance of xbmcgui.Action class.
"""
if action == ACTION_PREVIOUS_MENU:
self.close()
else:
self.executeConnected(action, self.actions_connected)
def onControl(self, control):
"""
Catch activated controls.
Control is an instance of xbmcgui.Control class.
"""
if control == self.window_close_button:
self.close()
else:
self.executeConnected(control, self.controls_connected)
class _DialogWindow(xbmcgui.WindowDialog):
"""An abstract class to define window event processing."""
def onAction(self, action):
"""
Catch button actions.
Note that, despite being compared to an integer,
action is an instance of xbmcgui.Action class.
"""
if action == ACTION_PREVIOUS_MENU:
self.close()
else:
self.executeConnected(action, self.actions_connected)
def onControl(self, control):
"""
Catch activated controls.
Control is an instance of xbmcgui.Control class.
"""
if control == self.window_close_button:
self.close()
else:
self.executeConnected(control, self.controls_connected)
class BlankFullWindow(_FullWindow, _AbstractWindow):
"""
Addon UI container with a solid background.
This is a blank window with a black background and without any elements whatsoever.
The decoration and layout are completely up to an addon developer.
The window controls can hide under video or music visualization.
Window ID can be passed on class instantiation an agrument
but __init__ must have the 2nd fake argument, e.g:
def __init__(self, *args)
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass
class BlankDialogWindow(_DialogWindow, _AbstractWindow):
"""
Addon UI container with a transparent background.
This is a blank window with a transparent background and without any elements whatsoever.
The decoration and layout are completely up to an addon developer.
The window controls are always displayed over video or music visualization.
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass
class AddonFullWindow(_FullWindow, _AddonWindow):
"""
Addon UI container with a solid background.
Control window is displayed on top of the main background image - self.main_bg.
Video and music visualization are displayed unhindered.
Window ID can be passed on class instantiation as the 2nd positional agrument
but __init__ must have the 3rd fake argument, e.g:
def __init__(self, title='', *args)
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
def __new__(cls, title='', *args, **kwargs):
return super(AddonFullWindow, cls).__new__(cls, *args, **kwargs)
def setFrame(self, title):
"""
Set the image for for the fullscreen background.
"""
# Image for the fullscreen background.
self.main_bg_img = os.path.join(_images, 'AddonWindow', 'SKINDEFAULT.jpg')
# Fullscreen background image control.
self.main_bg = xbmcgui.ControlImage(1, 1, 1280, 720, self.main_bg_img)
self.addControl(self.main_bg)
super(AddonFullWindow, self).setFrame(title)
def setBackground(self, image=''):
"""
Set the main bacground to an image file.
image: path to an image file as str.
Example:
self.setBackground('d:\images\bacground.png')
"""
self.main_bg.setImage(image)
class AddonDialogWindow(_DialogWindow, _AddonWindow):
"""
Addon UI container with a transparent background.
Control window is displayed on top of XBMC UI,
including video an music visualization!
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -19,7 +19,7 @@ class TmDb:
"""
def __init__(self, language='en'):
tmdb.configure("33dd11cb87f2b5fd9ecaff4a81d47edb", language=language)
tmdb.configure("f7f51775877e0bb6703520952b3c7840", language=language)
dbname='tmdb.%s.db' % language
self.cache = Cache(dbname, 1.0)

View File

@ -1,21 +1,17 @@
<settings>
<category label="30101">
<setting id="language" type="enum" label="30001" default="1" values="English|Russian|Ukrainian|Hebrew|Spanish|Hungarian" />
<setting id="language" type="enum" label="30001" default="1" values="English|Russian|Ukrainian|Hebrew" />
<setting id="metadata" type="bool" label="30014" default="false"/>
<setting id="history" type="bool" label="30020" default="true"/>
<setting id="sort_search" type="enum" label="30061" default="0" lvalues="30062|30063|30064"/>
<setting id="skin_optimization" type="enum" label="30002" default="1" lvalues="30003|30018|30017|30016|30019|30066|30067|30071|30076"/>
<setting id="skin_optimization" type="enum" label="30002" default="1" lvalues="30003|30018|30017|30016|30019|30066|30067"/>
<setting id="open_option" type="enum" label="30034" default="0" lvalues="30035|30036|30037|30038"/>
<setting id="searchwindowmode" type="enum" label="30106" default="1" lvalues="30107|30108|30109|30110"/>
</category>
<category label="30103">
<setting id="timeout" type="enum" lvalues="30026|30027|30028" label="30025" default="1"/>
<setting id="search_phrase" type="text" label="30040"/>
<setting id="num_threads" type="slider" label="30042" default="3" range="1,1,9" option="int"/>
<setting id="proxy" type="enum" lvalues="30048|30049|31050" label="30047" default="0"/>
<setting id="cl_proxy" type="enum" lvalues="30048|31050" label="31047" default="0"/>
<setting id="socks_ip" type="ipaddress" label="32047" default="127.0.0.1" visible="eq(-2,2)|eq(-1,1)"/>
<setting id="socks_port" type="number" label="32048" default="9050" visible="eq(-3,2)|eq(-2,1)"/>
<setting id="proxy" type="enum" lvalues="30048|30049|" label="30047" default="0"/>
<setting id="debug" type="bool" label="30015" default="false"/>
</category>
<category label="30102">
@ -65,18 +61,14 @@
<setting id="torrent_qbittorrent_password" type="text" label="50316" visible="eq(-21,4)" default="admin" option="hidden"/>
</category>
<category label="30105">
<setting id="torrent_player" type="enum" label="30023" default="2" lvalues="30021|30022|30046|30068" />
<setting id="ask_dir" type="bool" label="30031" default="false"/>
<setting id="connections_limit" type="number" label="30051" default="200" visible=" eq(-2,2)"/>
<setting id="use_random_port" type="bool" label="30052" default="false" visible=" eq(-3,2)"/>
<setting id="listen_port" type="number" label="30053" default="6881" visible="!eq(-4,1)"/>
<setting id="min_storage_size" type="slider" label="30059" default="0" visible="!eq(-5,1)" range="0,2,100" option="int"/>
<setting id="pause_onplay" type="bool" label="30060" default="false" visible="!eq(-6,1)"/>
<setting id="max_history_add" type="slider" label="30065" default="100" visible="!eq(-7,1)" range="0,2,100" option="int"/>
<setting id="enable_dht" type="bool" label="30070" default="true" visible="!eq(-8,1)"/>
<setting id="append_filesize" type="bool" label="30069" default="true"/>
<setting id="torrent_info_style" type="enum" label="30072" default="0" lvalues="30073|30074|30075"/>
<setting id="disable_notifications" type="bool" label="30112" default="false"/>
<setting id="sw_transparent_back" type="bool" label="30111" default="false"/>
<setting id="torrent_player" type="enum" label="30023" default="2" lvalues="30021|30022|30046|30068" />
<setting id="ask_dir" type="bool" label="30031" default="false"/>
<setting id="connections_limit" type="number" label="30051" default="200" visible=" eq(-2,2)"/>
<setting id="use_random_port" type="bool" label="30052" default="false" visible=" eq(-3,2)"/>
<setting id="listen_port" type="number" label="30053" default="6881" visible="!eq(-4,1)"/>
<setting id="min_storage_size" type="slider" label="30059" default="0" visible="!eq(-5,1)" range="0,2,100" option="int"/>
<setting id="pause_onplay" type="bool" label="30060" default="false" visible="!eq(-6,1)"/>
<setting id="max_history_add" type="slider" label="30065" default="100" visible="!eq(-7,1)" range="0,2,100" option="int"/>
<setting id="append_filesize" type="bool" label="30069" default="true"/>
</category>
</settings>

View File

@ -0,0 +1,218 @@
<window>
<coordinates>
<system>1</system>
<posx>240</posx>
<posy>20</posy>
</coordinates>
<include>dialogeffect</include>
<controls>
<control type="group">
<animation effect="fade" time="250">WindowOpen</animation>
<animation effect="fade" time="250">WindowClose</animation>
<control type="image">
<description>background image</description>
<posx>0</posx>
<posy>0</posy>
<width>800</width>
<height>680</height>
<texture border="40">ConfluenceDialogBack.png</texture>
</control>
<control type="image">
<description>Dialog Header image</description>
<posx>40</posx>
<posy>16</posy>
<width>720</width>
<height>40</height>
<texture>Confluencedialogheader.png</texture>
</control>
<control type="label" id="1">
<description>header label</description>
<posx>40</posx>
<posy>20</posy>
<width>720</width>
<height>30</height>
<font>font13_title</font>
<label>Информация о фильме</label>
<align>center</align>
<aligny>center</aligny>
<textcolor>selected</textcolor>
<shadowcolor>black</shadowcolor>
</control>
<control type="button" id="2">
<description>Close Window button</description>
<posx>710</posx>
<posy>15</posy>
<width>64</width>
<height>32</height>
<label>-</label>
<font>-</font>
<onclick>PreviousMenu</onclick>
<texturefocus>ConfluenceDialogCloseButton-focus.png</texturefocus>
<texturenofocus>ConfluenceDialogCloseButton.png</texturenofocus>
<onleft>10</onleft>
<onright>10</onright>
<onup>10</onup>
<ondown>10</ondown>
<visible>system.getbool(input.enablemouse)</visible>
</control>
<control type="scrollbar" id="60">
<posx>760</posx>
<posy>100</posy>
<width>25</width>
<height>495</height>
<texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground>
<texturesliderbar border="0,14,0,14">ScrollBarV_bar.png</texturesliderbar>
<texturesliderbarfocus border="0,14,0,14">ScrollBarV_bar_focus.png</texturesliderbarfocus>
<textureslidernib>ScrollBarNib.png</textureslidernib>
<textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus>
<onleft>30</onleft>
<onright>131</onright>
<showonepage>true</showonepage>
<visible>IntegerGreaterThan(Container(32).NumPages,1)</visible>
<orientation>vertical</orientation>
</control>
<control type="image" id="31">
<description>Dialog Header image</description>
<posx>33</posx>
<posy>85</posy>
<width>104</width>
<height>149</height>
<texture></texture>
</control>
<control type="label" id="34">
<description>rating</description>
<posx>34</posx>
<posy>240</posy>
<width>102</width>
<height>20</height>
<visible>true</visible>
<align>left</align>
<aligny>center</aligny>
<scroll>false</scroll>
<label></label>
<haspath>false</haspath>
<font>font10</font>
<textcolor>white</textcolor>
<shadowcolor>black</shadowcolor>
<wrapmultiline>false</wrapmultiline>
</control>
<control type="label" id="35">
<description>rating</description>
<posx>34</posx>
<posy>260</posy>
<width>102</width>
<height>20</height>
<visible>true</visible>
<align>left</align>
<aligny>center</aligny>
<scroll>false</scroll>
<label>[COLOR blue]Рейтинг:[/COLOR] [COLOR red]-200[/COLOR]</label>
<haspath>false</haspath>
<font>font10</font>
<textcolor>white</textcolor>
<shadowcolor>black</shadowcolor>
<wrapmultiline>false</wrapmultiline>
</control>
<control type="image" id="36">
<description>kinopoisk</description>
<posx>34</posx>
<posy>292</posy>
<width>102</width>
<height>38</height>
<texture></texture>
</control>
<control type="textbox" id="32">
<description>filepath</description>
<posx>180</posx>
<posy>70</posy>
<width>550</width>
<pagecontrol>60</pagecontrol>
<height max="470">470</height>
<align>left</align>
<aligny>top</aligny>
<font>font18</font>
<text>Нет описания</text>
<align>center</align>
<aligny>center</aligny>
<textcolor>white</textcolor>
<shadowcolor>black</shadowcolor>
<wrapmultiline>true</wrapmultiline>
</control>
<control type="group" id="9001">
<posy>615</posy>
<posx>50</posx>
<control type="button" id="22">
<description>close</description>
<posx>350</posx>
<posy>0</posy>
<width>320</width>
<height>40</height>
<align>center</align>
<aligny>center</aligny>
<font>font12_title</font>
<label></label>
<onleft>33</onleft>
<onright>60</onright>
<onup>30</onup>
<ondown>30</ondown>
</control>
<control type="button" id="131">
<description>play</description>
<posx>20</posx>
<posy>-50</posy>
<width>320</width>
<height>40</height>
<align>center</align>
<aligny>center</aligny>
<font>font12_title</font>
<label></label>
<onleft>60</onleft>
<onright>30</onright>
<onup>33</onup>
<ondown>33</ondown>
</control>
<control type="button" id="30">
<description>libtorrent</description>
<posx>350</posx>
<posy>-50</posy>
<width>320</width>
<height>40</height>
<align>center</align>
<aligny>center</aligny>
<font>font12_title</font>
<label></label>
<onleft>131</onleft>
<onright>60</onright>
<onup>22</onup>
<ondown>22</ondown>
</control>
<control type="button" id="33">
<description>tclient</description>
<posx>20</posx>
<posy>0</posy>
<width>320</width>
<height>40</height>
<align>center</align>
<aligny>center</aligny>
<font>font12_title</font>
<label>T-client</label>
<onleft>22</onleft>
<onright>22</onright>
<onup>131</onup>
<ondown>131</ondown>
</control>
</control>
</control>
</controls>
</window>

View File

@ -0,0 +1,127 @@
<window>
<coordinates>
<system>1</system>
<posx>240</posx>
<posy>20</posy>
</coordinates>
<include>dialogeffect</include>
<controls>
<control type="group">
<animation effect="fade" time="250">WindowOpen</animation>
<animation effect="fade" time="250">WindowClose</animation>
<control type="image">
<description>background image</description>
<posx>0</posx>
<posy>0</posy>
<width>800</width>
<height>680</height>
<texture border="40">DialogBack.png</texture>
</control>
<control type="image">
<description>Dialog Header image</description>
<posx>40</posx>
<posy>16</posy>
<width>720</width>
<height>40</height>
<texture>dialogheader.png</texture>
</control>
<control type="label" id="1">
<description>header label</description>
<posx>40</posx>
<posy>20</posy>
<width>720</width>
<height>30</height>
<font>font13_title</font>
<label>Отзывы о фильме</label>
<align>center</align>
<aligny>center</aligny>
<textcolor>selected</textcolor>
<shadowcolor>black</shadowcolor>
</control>
<control type="button" id="2">
<description>Close Window button</description>
<posx>710</posx>
<posy>15</posy>
<width>64</width>
<height>32</height>
<label>-</label>
<font>-</font>
<onclick>PreviousMenu</onclick>
<texturefocus>DialogCloseButton-focus.png</texturefocus>
<texturenofocus>DialogCloseButton.png</texturenofocus>
<onleft>10</onleft>
<onright>10</onright>
<onup>10</onup>
<ondown>10</ondown>
<visible>system.getbool(input.enablemouse)</visible>
</control>
<control type="scrollbar" id="60">
<posx>760</posx>
<posy>100</posy>
<width>25</width>
<height>495</height>
<texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground>
<texturesliderbar border="0,14,0,14">ScrollBarV_bar.png</texturesliderbar>
<texturesliderbarfocus border="0,14,0,14">ScrollBarV_bar_focus.png</texturesliderbarfocus>
<textureslidernib>ScrollBarNib.png</textureslidernib>
<textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus>
<onleft>22</onleft>
<onright>22</onright>
<showonepage>true</showonepage>
<visible>IntegerGreaterThan(Container(32).NumPages,1)</visible>
<orientation>vertical</orientation>
</control>
<control type="image" id="31">
<description>Dialog Header image</description>
<posx>33</posx>
<posy>85</posy>
<width>104</width>
<height>149</height>
<texture></texture>
</control>
<control type="textbox" id="32">
<description>filepath</description>
<posx>60</posx>
<posy>70</posy>
<width>690</width>
<pagecontrol>60</pagecontrol>
<height max="530">530</height>
<align>left</align>
<aligny>top</aligny>
<font>font12</font>
<text>Нет отзывов</text>
<align>center</align>
<aligny>center</aligny>
<textcolor>white</textcolor>
<shadowcolor>black</shadowcolor>
<wrapmultiline>true</wrapmultiline>
</control>
<control type="group" id="9001">
<posy>615</posy>
<posx>50</posx>
<control type="button" id="22">
<description>close</description>
<posx>20</posx>
<posy>0</posy>
<width>650</width>
<height>40</height>
<align>center</align>
<aligny>center</aligny>
<font>font12_title</font>
<label>Закрыть окно</label>
<onleft>60</onleft>
<onright>60</onright>
<onup>60</onup>
<ondown>60</ondown>
</control>
</control>
</control>
</controls>
</window>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
import re
import htmlentitydefs
import xbmcgui
pattern = re.compile("&(\w+?);")
def html_entity_decode_char(m, defs=htmlentitydefs.entitydefs):
try:
return defs[m.group(1)]
except KeyError:
return m.group(0)
def html_entity_decode(string):
return pattern.sub(html_entity_decode_char, string)
KEY_BUTTON_BACK = 275
KEY_KEYBOARD_ESC = 61467
ACTION_PREVIOUS_MENU = 10
ACTION_NAV_BACK = 92
class DialogReviews(xbmcgui.WindowXMLDialog):
def onInit(self):
print "DialogReviews(): Window Initialized"
self.reviews_box = self.getControl(32)
self.reviews_box.setText(self.get_reviews())
self.setFocus(self.getControl(22))
def onAction(self, action):
buttonCode = action.getButtonCode()
if (action == ACTION_NAV_BACK or action == ACTION_PREVIOUS_MENU):
self.close()
if (buttonCode == KEY_BUTTON_BACK or buttonCode == KEY_KEYBOARD_ESC):
self.close()
def onClick(self, controlID):
if (controlID == 2 or controlID == 22):
self.close()
def onFocus(self, controlID):
#print "onFocus(): control %i" % controlID
pass
def doModal(self, movieHtml):
self.movieHtml = movieHtml
xbmcgui.WindowXMLDialog.doModal(self)
def get_reviews(self):
reviews_texts = re.compile('<div class="comment" id="[^"]+">([^<]+)</div>',re.S).findall(self.movieHtml)
reviews_autors = re.compile('<div class="member"><a href="[^"]+"><strong>([^<]+)</strong></a></div>',re.S).findall(self.movieHtml)
reviews_dates = re.compile('<div class="date">([^<]+)</div>',re.S).findall(self.movieHtml)
texts = ''
i = 0
for text in reviews_texts:
texts = texts+"\n[B][COLOR purple]"+reviews_autors[i]+"[/COLOR][/B] [I]"+reviews_dates[i]+"[/I]\n"
texts = texts+html_entity_decode(text)+"\n"
i = i + 1
return texts

View File

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
import sys
import xbmcgui
import Localization
import xbmc
KEY_BUTTON_BACK = 275
KEY_KEYBOARD_ESC = 61467
ACTION_PREVIOUS_MENU = 10
ACTION_NAV_BACK = 92
class DialogXml(xbmcgui.WindowXMLDialog):
def onInit(self):
print "onInit(): Window Initialized"
localize = Localization.localize
color = '[COLOR %s]%s[/COLOR]'
self.movie_label = self.getControl(32)
self.movie_label.setText(self.movieInfo['desc'])
if self.movieInfo.get('views'):
self.view_label = self.getControl(34)
self.view_label.setLabel(color % ('blue', localize('Views:')) + self.movieInfo['views'])
self.view_label = self.getControl(35)
self.ratingcolor = 'green'
self.ratingint = int(self.movieInfo['rating'])
if (self.ratingint < 70):
self.ratingcolor = 'red'
self.view_label.setLabel(
color % ('blue', localize('Rating:')) + color % (self.ratingcolor, self.movieInfo['rating']))
self.movie_label = self.getControl(1)
self.movie_label.setLabel(self.movieInfo['title'])
self.movie_label = self.getControl(32)
self.movie_label.setText(self.movieInfo['desc'])
self.poster = self.getControl(31)
self.poster.setImage(self.movieInfo['poster'])
self.poster = self.getControl(36)
self.poster.setImage(self.movieInfo['kinopoisk'])
self.getControl(22).setLabel(localize('Close'))
self.getControl(33).setLabel(localize('Download via T-client'))
self.getControl(30).setLabel(localize('Download via Libtorrent'))
self.getControl(131).setLabel(localize('Play'))
self.setFocus(self.getControl(22))
def onAction(self, action):
buttonCode = action.getButtonCode()
if (action == ACTION_NAV_BACK or action == ACTION_PREVIOUS_MENU):
self.close()
if (buttonCode == KEY_BUTTON_BACK or buttonCode == KEY_KEYBOARD_ESC):
self.close()
def onClick(self, controlID):
if (controlID == 2 or controlID == 22):
self.close()
if (controlID == 30):
self.RunPlugin('downloadLibtorrent')
if (controlID == 33):
self.RunPlugin('downloadFilesList')
if (controlID == 131):
self.RunPlugin('openTorrent&external=1')
def RunPlugin(self, action):
if self.link:
exec_str = 'XBMC.RunPlugin(%s)' % \
('%s?action=%s&url=%s') % \
(sys.argv[0], action, self.link)
xbmc.executebuiltin(exec_str)
def onFocus(self, controlID):
# print "onFocus(): control %i" % controlID
pass
def doModal(self, movieInfo, url):
self.movieInfo = movieInfo
self.link = url
xbmcgui.WindowXMLDialog.doModal(self)

View File

@ -1064,10 +1064,7 @@ class qBittorrent:
'uploading': 'seeding',
'stalledUP': 'seeding',
}
if code in mapping:
return mapping[code]
else:
return 'unknown'
return mapping[code]
class Deluge:

File diff suppressed because it is too large Load Diff