Мы не используем внешний бинарник

sandbox1
inpos 2016-03-04 16:30:29 +03:00
parent 91c0a67480
commit a18b31edf4
1 changed files with 75 additions and 75 deletions

View File

@ -22,12 +22,12 @@ from util import can_bind, find_free_port, ensure_fs_encoding
class Engine: class Engine:
""" """
This is python binding class to torrent2http client. This is python binding class to pyrrent2http client.
""" """
SUBTITLES_FORMATS = ['.aqt', '.gsub', '.jss', '.sub', '.ttxt', '.pjs', '.psb', '.rt', '.smi', '.stl', SUBTITLES_FORMATS = ['.aqt', '.gsub', '.jss', '.sub', '.ttxt', '.pjs', '.psb', '.rt', '.smi', '.stl',
'.ssf', '.srt', '.ssa', '.ass', '.usf', '.idx'] '.ssf', '.srt', '.ssa', '.ass', '.usf', '.idx']
def _ensure_binary_executable(self, path): __to_del = '''def _ensure_binary_executable(self, path):
st = os.stat(path) st = os.stat(path)
if not st.st_mode & stat.S_IEXEC: if not st.st_mode & stat.S_IEXEC:
try: try:
@ -44,19 +44,19 @@ class Engine:
self._log("Failed") self._log("Failed")
return False return False
return True return True
'''
def _log(self, message): def _log(self, message):
if self.logger: if self.logger:
self.logger(message) self.logger(message)
else: else:
xbmc.log("[torrent2http] %s" % message) xbmc.log("[pyrrent2http] %s" % message)
def _get_binary_path(self, binaries_path): __to_del = '''def _get_binary_path(self, binaries_path):
""" """
Detects platform and returns corresponding torrent2http binary path Detects platform and returns corresponding pyrrent2http binary path
:param binaries_path: :param binaries_path:
:return: torrent2http binary path :return: pyrrent2http binary path
""" """
binary = "torrent2http" + (".exe" if self.platform.system == 'windows' else "") binary = "torrent2http" + (".exe" if self.platform.system == 'windows' else "")
binary_dir = os.path.join(binaries_path, "%s_%s" % (self.platform.system, self.platform.arch)) binary_dir = os.path.join(binaries_path, "%s_%s" % (self.platform.system, self.platform.arch))
@ -94,8 +94,8 @@ class Engine:
"partition is in read/write mode" % binary_path, Error.NOEXEC_FILESYSTEM) "partition is in read/write mode" % binary_path, Error.NOEXEC_FILESYSTEM)
self._log("Selected %s as torrent2http binary" % binary_path) self._log("Selected %s as torrent2http binary" % binary_path)
return binary_path return binary_path
'''
def __init__(self, uri=None, binaries_path=None, platform=None, download_path=".", def __init__(self, uri=None, platform=None, download_path=".",
bind_host='127.0.0.1', bind_port=5001, connections_limit=None, download_kbps=None, upload_kbps=None, 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, 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, log_stats=False, encryption=Encryption.ENABLED, keep_complete=False, keep_incomplete=False,
@ -165,7 +165,7 @@ class Engine:
self.platform = platform self.platform = platform
self.bind_host = bind_host self.bind_host = bind_host
self.bind_port = bind_port self.bind_port = bind_port
self.binaries_path = binaries_path or os.path.join(dirname(dirname(dirname(os.path.abspath(__file__)))), 'bin') # self.binaries_path = binaries_path or os.path.join(dirname(dirname(dirname(os.path.abspath(__file__)))), 'bin')
self.download_path = download_path self.download_path = download_path
self.connections_limit = connections_limit self.connections_limit = connections_limit
self.download_kbps = download_kbps self.download_kbps = download_kbps
@ -222,7 +222,7 @@ class Engine:
def start(self, start_index=None): def start(self, start_index=None):
""" """
Starts torrent2http client with specified settings. If it can be started in startup_timeout seconds, exception Starts pyrrent2http client with specified settings. If it can be started in startup_timeout seconds, exception
will be raised. will be raised.
:param start_index: File index to start download instantly, if not specified, downloading will be paused, until :param start_index: File index to start download instantly, if not specified, downloading will be paused, until
@ -234,49 +234,49 @@ class Engine:
if not can_bind(self.bind_host, self.bind_port): if not can_bind(self.bind_host, self.bind_port):
port = find_free_port(self.bind_host) port = find_free_port(self.bind_host)
if port is False: if port is False:
raise Error("Can't find port to bind torrent2http", Error.BIND_ERROR) raise Error("Can't find port to bind pyrrent2http", Error.BIND_ERROR)
self._log("Can't bind to %s:%s, so we found another port: %d" % (self.bind_host, self.bind_port, port)) self._log("Can't bind to %s:%s, so we found another port: %d" % (self.bind_host, self.bind_port, port))
self.bind_port = port self.bind_port = port
kwargs = { kwargs = {
'--bind': "%s:%s" % (self.bind_host, self.bind_port), 'bind': "%s:%s" % (self.bind_host, self.bind_port),
'--uri': self.uri, 'uri': self.uri,
'--file-index': start_index, 'file-index': start_index,
'--dl-path': download_path, 'dl-path': download_path,
'--connections-limit': self.connections_limit, 'connections-limit': self.connections_limit,
'--dl-rate': self.download_kbps, 'dl-rate': self.download_kbps,
'--ul-rate': self.upload_kbps, 'ul-rate': self.upload_kbps,
'--enable-dht': self.enable_dht, 'enable-dht': self.enable_dht,
'--enable-lsd': self.enable_lsd, 'enable-lsd': self.enable_lsd,
'--enable-natpmp': self.enable_natpmp, 'enable-natpmp': self.enable_natpmp,
'--enable-upnp': self.enable_upnp, 'enable-upnp': self.enable_upnp,
'--enable-scrape': self.enable_scrape, 'enable-scrape': self.enable_scrape,
'--encryption': self.encryption, 'encryption': self.encryption,
'--show-stats': self.log_stats, 'show-stats': self.log_stats,
'--files-progress': self.log_files_progress, 'files-progress': self.log_files_progress,
'--overall-progress': self.log_overall_progress, 'overall-progress': self.log_overall_progress,
'--pieces-progress': self.log_pieces_progress, 'pieces-progress': self.log_pieces_progress,
'--listen-port': self.listen_port, 'listen-port': self.listen_port,
'--random-port': self.use_random_port, 'random-port': self.use_random_port,
'--keep-complete': self.keep_complete, 'keep-complete': self.keep_complete,
'--keep-incomplete': self.keep_incomplete, 'keep-incomplete': self.keep_incomplete,
'--keep-files': self.keep_files, 'keep-files': self.keep_files,
'--max-idle': self.max_idle_timeout, 'max-idle': self.max_idle_timeout,
'--no-sparse': self.no_sparse, 'no-sparse': self.no_sparse,
'--resume-file': self.resume_file, 'resume-file': self.resume_file,
'--user-agent': self.user_agent, 'user-agent': self.user_agent,
'--state-file': self.state_file, 'state-file': self.state_file,
'--enable-utp': self.enable_utp, 'enable-utp': self.enable_utp,
'--enable-tcp': self.enable_tcp, 'enable-tcp': self.enable_tcp,
'--debug-alerts': self.debug_alerts, 'debug-alerts': self.debug_alerts,
'--torrent-connect-boost': self.torrent_connect_boost, 'torrent-connect-boost': self.torrent_connect_boost,
'--connection-speed': self.connection_speed, 'connection-speed': self.connection_speed,
'--peer-connect-timeout': self.peer_connect_timeout, 'peer-connect-timeout': self.peer_connect_timeout,
'--request-timeout': self.request_timeout, 'request-timeout': self.request_timeout,
'--min-reconnect-time': self.min_reconnect_time, 'min-reconnect-time': self.min_reconnect_time,
'--max-failcount': self.max_failcount, 'max-failcount': self.max_failcount,
'--dht-routers': ",".join(self.dht_routers), 'dht-routers': ",".join(self.dht_routers),
'--trackers': ",".join(self.trackers), 'trackers': ",".join(self.trackers),
} }
args = [binary_path] args = [binary_path]
@ -306,7 +306,7 @@ class Engine:
try: try:
self.process = subprocess.Popen(args, stderr=self.logpipe, stdout=self.logpipe, startupinfo=startupinfo) self.process = subprocess.Popen(args, stderr=self.logpipe, stdout=self.logpipe, startupinfo=startupinfo)
except OSError, e: except OSError, e:
raise Error("Can't start torrent2http: %r" % e, Error.POPEN_ERROR) raise Error("Can't start pyrrent2http: %r" % e, Error.POPEN_ERROR)
start = time.time() start = time.time()
self.started = True self.started = True
@ -314,7 +314,7 @@ class Engine:
while (time.time() - start) < self.startup_timeout: while (time.time() - start) < self.startup_timeout:
time.sleep(0.1) time.sleep(0.1)
if not self.is_alive(): if not self.is_alive():
raise Error("Can't start torrent2http, see log for details", Error.PROCESS_ERROR) raise Error("Can't start pyrrent2http, see log for details", Error.PROCESS_ERROR)
try: try:
self.status(1) self.status(1)
initialized = True initialized = True
@ -324,14 +324,14 @@ class Engine:
if not initialized: if not initialized:
self.started = False self.started = False
raise Error("Can't start torrent2http, time is out", Error.TIMEOUT) raise Error("Can't start pyrrent2http, time is out", Error.TIMEOUT)
self._log("torrent2http successfully started.") self._log("pyrrent2http successfully started.")
def check_torrent_error(self, status=None): def check_torrent_error(self, status=None):
""" """
It is recommended to call this method periodically to check if any libtorrent errors occurred. It is recommended to call this method periodically to check if any libtorrent errors occurred.
Usually libtorrent sets error if it can't download or parse torrent file by specified URI. Usually libtorrent sets error if it can't download or parse torrent file by specified URI.
Note that torrent2http remains started after such error, so you need to shutdown it manually. Note that pyrrent2http remains started after such error, so you need to shutdown it manually.
:param status: Pass return of status() method if you don't want status() called twice :param status: Pass return of status() method if you don't want status() called twice
""" """
@ -345,7 +345,7 @@ class Engine:
Returns libtorrent session status. See SessionStatus named tuple. Returns libtorrent session status. See SessionStatus named tuple.
:rtype : SessionStatus :rtype : SessionStatus
:param timeout: torrent2http client request timeout :param timeout: pyrrent2http client request timeout
""" """
status = self._decode(self._request('status', timeout)) status = self._decode(self._request('status', timeout))
status = SessionStatus(**status) status = SessionStatus(**status)
@ -370,11 +370,11 @@ class Engine:
def list(self, media_types=None, timeout=10): def list(self, media_types=None, timeout=10):
""" """
Returns list of files in the torrent (see FileStatus named tuple). Returns list of files in the torrent (see FileStatus named tuple).
Note that it will return None if torrent file is not loaded yet by torrent2http client, so you may need to call Note that it will return None if torrent file is not loaded yet by pyrrent2http client, so you may need to call
this method periodically until results are returned. this method periodically until results are returned.
:param media_types: List of media types (see MediaType constants) :param media_types: List of media types (see MediaType constants)
:param timeout: torrent2http client request timeout :param timeout: pyrrent2http client request timeout
:rtype : list of FileStatus :rtype : list of FileStatus
:return: List of files of specified media types or None if torrent is not loaded yet :return: List of files of specified media types or None if torrent is not loaded yet
""" """
@ -389,11 +389,11 @@ class Engine:
def file_status(self, file_index, timeout=10): def file_status(self, file_index, timeout=10):
""" """
Returns file in the torrent with specified index (see FileStatus named tuple) Returns file in the torrent with specified index (see FileStatus named tuple)
Note that it will return None if torrent file is not loaded yet by torrent2http client, so you may need to call Note that it will return None if torrent file is not loaded yet by pyrrent2http client, so you may need to call
this method periodically until results are returned. this method periodically until results are returned.
:param file_index: Requested file's index :param file_index: Requested file's index
:param timeout: torrent2http client request timeout :param timeout: pyrrent2http client request timeout
:return: File with specified index :return: File with specified index
:rtype: FileStatus :rtype: FileStatus
""" """
@ -409,7 +409,7 @@ class Engine:
""" """
Returns list of peers connected (see PeerInfo named tuple). Returns list of peers connected (see PeerInfo named tuple).
:param timeout: torrent2http client request timeout :param timeout: pyrrent2http client request timeout
:return: List of peers :return: List of peers
:rtype: list of PeerInfo :rtype: list of PeerInfo
""" """
@ -425,11 +425,11 @@ class Engine:
try: try:
return json.loads(response) return json.loads(response)
except (KeyError, ValueError), e: except (KeyError, ValueError), e:
raise Error("Can't decode response from torrent2http: %r" % e, Error.REQUEST_ERROR) raise Error("Can't decode response from pyrrent2http: %r" % e, Error.REQUEST_ERROR)
def _request(self, cmd, timeout=None): def _request(self, cmd, timeout=None):
if not self.started: if not self.started:
raise Error("torrent2http is not started", Error.REQUEST_ERROR) raise Error("pyrrent2http is not started", Error.REQUEST_ERROR)
try: try:
url = "http://%s:%s/%s" % (self.bind_host, self.bind_port, cmd) url = "http://%s:%s/%s" % (self.bind_host, self.bind_port, cmd)
kwargs = {} kwargs = {}
@ -438,34 +438,34 @@ class Engine:
return urllib2.urlopen(url, **kwargs).read() return urllib2.urlopen(url, **kwargs).read()
except (urllib2.URLError, httplib.HTTPException) as e: except (urllib2.URLError, httplib.HTTPException) as e:
if isinstance(e, urllib2.URLError) and isinstance(e.reason, socket.timeout): if isinstance(e, urllib2.URLError) and isinstance(e.reason, socket.timeout):
raise Error("Timeout occurred while sending command '%s' to torrent2http" % cmd, Error.TIMEOUT) raise Error("Timeout occurred while sending command '%s' to pyrrent2http" % cmd, Error.TIMEOUT)
elif not self.is_alive() and self.started: elif not self.is_alive() and self.started:
raise Error("torrent2http has crashed.", Error.CRASHED) raise Error("pyrrent2http has crashed.", Error.CRASHED)
else: else:
raise Error("Can't send command '%s' to torrent2http: %r" % (cmd, e), Error.REQUEST_ERROR) raise Error("Can't send command '%s' to pyrrent2http: %r" % (cmd, e), Error.REQUEST_ERROR)
except socket.error as e: except socket.error as e:
reason = e[1] if isinstance(e, tuple) else e reason = e[1] if isinstance(e, tuple) else e
raise Error("Can't read from torrent2http: %s" % reason, Error.REQUEST_ERROR) raise Error("Can't read from pyrrent2http: %s" % reason, Error.REQUEST_ERROR)
def wait_on_close(self, wait_timeout=10): def wait_on_close(self, wait_timeout=10):
""" """
By default, close() method sends shutdown command to torrent2http, stops logging and returns immediately, not By default, close() method sends shutdown command to pyrrent2http, stops logging and returns immediately, not
waiting while torrent2http exits. It can be handy to wait torrent2http to view log messages during shutdown. waiting while pyrrent2http exits. It can be handy to wait pyrrent2http to view log messages during shutdown.
So call this method with reasonable timeout before calling close(). So call this method with reasonable timeout before calling close().
:param wait_timeout: Time in seconds to wait until torrent2http client shut down :param wait_timeout: Time in seconds to wait until pyrrent2http client shut down
""" """
self.wait_on_close_timeout = wait_timeout self.wait_on_close_timeout = wait_timeout
def close(self): def close(self):
""" """
Shuts down torrent2http and stops logging. If wait_on_close() was called earlier, it will wait until Shuts down pyrrent2http and stops logging. If wait_on_close() was called earlier, it will wait until
torrent2http successfully exits. pyrrent2http successfully exits.
""" """
if self.logpipe and self.wait_on_close_timeout is None: if self.logpipe and self.wait_on_close_timeout is None:
self.logpipe.close() self.logpipe.close()
if self.is_alive(): if self.is_alive():
self._log("Shutting down torrent2http...") self._log("Shutting down pyrrent2http...")
self._request('shutdown') self._request('shutdown')
finished = False finished = False
if self.wait_on_close_timeout is not None: if self.wait_on_close_timeout is not None:
@ -477,10 +477,10 @@ class Engine:
finished = True finished = True
break break
if not finished: if not finished:
self._log("Timeout occurred while shutting down torrent2http, killing it") self._log("Timeout occurred while shutting down pyrrent2http, killing it")
self.process.kill() self.process.kill()
else: else:
self._log("torrent2http successfully shut down.") self._log("pyrrent2http successfully shut down.")
self.wait_on_close_timeout = None self.wait_on_close_timeout = None
self.process.wait() self.process.wait()
self.started = False self.started = False