Принципиальные изменения движка
parent
d3f3f729f5
commit
bd646784cb
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="script.module.pyrrent2http" name="pyrrent2http" version="0.8.4" provider-name="inpos">
|
<addon id="script.module.pyrrent2http" name="pyrrent2http" version="0.9.0" provider-name="inpos">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.14.0"/>
|
<import addon="xbmc.python" version="2.14.0"/>
|
||||||
<import addon="script.module.libtorrent" />
|
<import addon="script.module.libtorrent" />
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
[B]Version 0.9.0[/B]
|
||||||
|
+ Изменён принцип работы с торрентом
|
||||||
|
|
||||||
[B]Version 0.8.3[/B]
|
[B]Version 0.8.3[/B]
|
||||||
+ Исправил быстрый запуск (fix fast resume)
|
+ Исправил быстрый запуск (fix fast resume)
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,10 @@ import pyrrent2http
|
||||||
import xbmc
|
import xbmc
|
||||||
from error import Error
|
from error import Error
|
||||||
from . import SessionStatus, FileStatus, PeerInfo, Encryption
|
from . import SessionStatus, FileStatus, PeerInfo, Encryption
|
||||||
from util import can_bind, find_free_port, localize_path, uri2path
|
from util import can_bind, find_free_port, localize_path, uri2path, detect_media_type
|
||||||
import threading
|
import threading
|
||||||
|
import urllib
|
||||||
|
import chardet
|
||||||
|
|
||||||
LOGGING = True
|
LOGGING = True
|
||||||
|
|
||||||
|
@ -286,7 +288,7 @@ class Engine:
|
||||||
if media_types is not None:
|
if media_types is not None:
|
||||||
res = filter(lambda fs: fs.media_type in media_types, res)
|
res = filter(lambda fs: fs.media_type in media_types, res)
|
||||||
return res
|
return res
|
||||||
def list_from_info(self):
|
def list_from_info(self, media_types=None):
|
||||||
try:
|
try:
|
||||||
info = pyrrent2http.lt.torrent_info(uri2path(self.uri))
|
info = pyrrent2http.lt.torrent_info(uri2path(self.uri))
|
||||||
except:
|
except:
|
||||||
|
@ -294,18 +296,21 @@ class Engine:
|
||||||
files = []
|
files = []
|
||||||
for i in range(info.num_files()):
|
for i in range(info.num_files()):
|
||||||
f = info.file_at(i)
|
f = info.file_at(i)
|
||||||
|
Url = 'http://' + "%s:%s" % (self.bind_host, self.bind_port) + '/files/' + urllib.quote(f.path)
|
||||||
files.append({
|
files.append({
|
||||||
'name': localize_path(f.path),
|
'name': localize_path(f.path),
|
||||||
'size': f.size,
|
'size': f.size,
|
||||||
'offset': f.offset,
|
'offset': f.offset,
|
||||||
'media_type': '',
|
'media_type': media_types and detect_media_type(f.path.decode(chardet.detect(f.path)['encoding'])) or '',
|
||||||
'download': 0,
|
'download': 0,
|
||||||
'progress': 0.0,
|
'progress': 0.0,
|
||||||
'save_path': '',
|
'save_path': '',
|
||||||
'url': ''
|
'url': Url
|
||||||
})
|
})
|
||||||
if files:
|
if files:
|
||||||
res = [FileStatus(index=index, **f) for index, f in enumerate(files)]
|
res = [FileStatus(index=index, **f) for index, f in enumerate(files)]
|
||||||
|
if media_types is not None:
|
||||||
|
res = filter(lambda fs: fs.media_type in media_types, res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def file_status(self, file_index, timeout=10):
|
def file_status(self, file_index, timeout=10):
|
||||||
|
@ -319,11 +324,11 @@ class Engine:
|
||||||
:return: File with specified index
|
:return: File with specified index
|
||||||
:rtype: FileStatus
|
:rtype: FileStatus
|
||||||
"""
|
"""
|
||||||
res = self.list(timeout=timeout)
|
files = self.pyrrent2http.Ls()['files']
|
||||||
if res:
|
if files:
|
||||||
try:
|
for f in files:
|
||||||
return res[file_index]
|
if f['index'] == file_index:
|
||||||
except IndexError:
|
return FileStatus(**f)
|
||||||
raise Error("Requested file index (%d) is invalid" % (file_index,), Error.INVALID_FILE_INDEX,
|
raise Error("Requested file index (%d) is invalid" % (file_index,), Error.INVALID_FILE_INDEX,
|
||||||
file_index=file_index)
|
file_index=file_index)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sys, os
|
import os
|
||||||
import json
|
|
||||||
import chardet
|
import chardet
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -19,7 +18,7 @@ except Exception, e:
|
||||||
|
|
||||||
from random import SystemRandom
|
from random import SystemRandom
|
||||||
import time
|
import time
|
||||||
import urlparse, urllib
|
import urllib
|
||||||
import BaseHTTPServer
|
import BaseHTTPServer
|
||||||
import SocketServer
|
import SocketServer
|
||||||
import threading
|
import threading
|
||||||
|
@ -90,7 +89,8 @@ if not hasattr(os, 'getppid'):
|
||||||
|
|
||||||
AVOID_HTTP_SERVER_EXCEPTION_OUTPUT = True
|
AVOID_HTTP_SERVER_EXCEPTION_OUTPUT = True
|
||||||
VERSION = "0.6.0"
|
VERSION = "0.6.0"
|
||||||
USER_AGENT = "pyrrent2http/" + VERSION + " libtorrent/" + lt.version
|
#USER_AGENT = "pyrrent2http/" + VERSION + " libtorrent/" + lt.version
|
||||||
|
USER_AGENT = 'libtorrent/1.0.9.0'
|
||||||
|
|
||||||
VIDEO_EXTS={'.avi':'video/x-msvideo','.mp4':'video/mp4','.mkv':'video/x-matroska',
|
VIDEO_EXTS={'.avi':'video/x-msvideo','.mp4':'video/mp4','.mkv':'video/x-matroska',
|
||||||
'.m4v':'video/mp4','.mov':'video/quicktime', '.mpg':'video/mpeg','.ogv':'video/ogg',
|
'.m4v':'video/mp4','.mov':'video/quicktime', '.mpg':'video/mpeg','.ogv':'video/ogg',
|
||||||
|
@ -168,7 +168,7 @@ class TorrentFile(object):
|
||||||
self.filePtr = io.open(self.save_path, 'rb')
|
self.filePtr = io.open(self.save_path, 'rb')
|
||||||
return self.filePtr
|
return self.filePtr
|
||||||
def log(self, message):
|
def log(self, message):
|
||||||
fnum = self.index
|
fnum = self.tfs.openedFiles.index(self)
|
||||||
logging.info("[%d] %s\n" % (fnum, message))
|
logging.info("[%d] %s\n" % (fnum, message))
|
||||||
def Pieces(self):
|
def Pieces(self):
|
||||||
startPiece, _ = self.pieceFromOffset(1)
|
startPiece, _ = self.pieceFromOffset(1)
|
||||||
|
@ -267,8 +267,9 @@ class TorrentFS(object):
|
||||||
self.waitForMetadata()
|
self.waitForMetadata()
|
||||||
self.save_path = localize_path(self.root.torrentParams['save_path'])
|
self.save_path = localize_path(self.root.torrentParams['save_path'])
|
||||||
self.priorities = list(self.handle.file_priorities())
|
self.priorities = list(self.handle.file_priorities())
|
||||||
self.files = self.__files_()
|
file_ = self.__file_at_(startIndex)
|
||||||
self.handle.set_piece_deadline(self.files[startIndex].startPiece, 50)
|
self.files = {file_.name: file_}
|
||||||
|
#self.handle.set_piece_deadline(self.files[startIndex].startPiece, 50)
|
||||||
if startIndex < 0:
|
if startIndex < 0:
|
||||||
logging.info('No -file-index specified, downloading will be paused until any file is requested')
|
logging.info('No -file-index specified, downloading will be paused until any file is requested')
|
||||||
|
|
||||||
|
@ -313,9 +314,9 @@ class TorrentFS(object):
|
||||||
return self.info is not None
|
return self.info is not None
|
||||||
def LoadFileProgress(self):
|
def LoadFileProgress(self):
|
||||||
self.progresses = self.handle.file_progress()
|
self.progresses = self.handle.file_progress()
|
||||||
for i, f in enumerate(self.files):
|
for k in self.files.keys():
|
||||||
f.downloaded = self.getFileDownloadedBytes(i)
|
self.files[k].downloaded = self.getFileDownloadedBytes(self.files[k].index)
|
||||||
if f.size > 0: f.progress = float(f.downloaded)/float(f.size)
|
if self.files[k].size > 0: self.files[k].progress = float(self.files[k].downloaded) / float(self.files[k].size)
|
||||||
def getFileDownloadedBytes(self, i):
|
def getFileDownloadedBytes(self, i):
|
||||||
try:
|
try:
|
||||||
bytes_ = self.progresses[i]
|
bytes_ = self.progresses[i]
|
||||||
|
@ -344,10 +345,9 @@ class TorrentFS(object):
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
def FileByName(self, name):
|
def FileByName(self, name):
|
||||||
savePath = os.path.abspath(os.path.join(self.save_path, localize_path(name)))
|
for i, f in enumerate(self.info.files()):
|
||||||
for file_ in self.files:
|
if f.path == name:
|
||||||
if file_.save_path == savePath:
|
return self.__file_at_(i)
|
||||||
return file_
|
|
||||||
raise IOError
|
raise IOError
|
||||||
def Open(self, name):
|
def Open(self, name):
|
||||||
if self.shuttingDown or not self.HasTorrentInfo():
|
if self.shuttingDown or not self.HasTorrentInfo():
|
||||||
|
@ -372,11 +372,12 @@ class TorrentFS(object):
|
||||||
tf.closed = False
|
tf.closed = False
|
||||||
self.fileCounter += 1
|
self.fileCounter += 1
|
||||||
tf.num = self.fileCounter
|
tf.num = self.fileCounter
|
||||||
tf.log('Opening %s...' % (tf.name,))
|
self.addOpenedFile(tf)
|
||||||
|
tf.log('Opened %s...' % (tf.name,))
|
||||||
tf.SetPriority(1)
|
tf.SetPriority(1)
|
||||||
self.handle.set_piece_deadline(tf.startPiece, 50)
|
self.handle.set_piece_deadline(tf.startPiece, 50)
|
||||||
self.lastOpenedFile = tf
|
self.lastOpenedFile = tf
|
||||||
self.addOpenedFile(tf)
|
self.files[tf.name] = tf
|
||||||
self.checkPriorities()
|
self.checkPriorities()
|
||||||
return tf
|
return tf
|
||||||
|
|
||||||
|
@ -393,23 +394,6 @@ def HttpHandlerFactory():
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
#print ('---Headers---\n%s\n' % (self.headers,))
|
#print ('---Headers---\n%s\n' % (self.headers,))
|
||||||
#print ('---Request---\n%s\n' % (self.path,))
|
#print ('---Request---\n%s\n' % (self.path,))
|
||||||
'''if self.path == '/status':
|
|
||||||
self.statusHandler()
|
|
||||||
elif self.path == '/ls':
|
|
||||||
self.lsHandler()
|
|
||||||
elif self.path == '/peers':
|
|
||||||
self.peersHandler()
|
|
||||||
elif self.path == '/trackers':
|
|
||||||
self.trackersHandler()
|
|
||||||
elif self.path.startswith('/get/'): # Неясно, зачем
|
|
||||||
return
|
|
||||||
# self.getHandler() # этот запрос?
|
|
||||||
elif self.path == '/shutdown':
|
|
||||||
self.server.root_obj.forceShutdown = True
|
|
||||||
self.server.server_close()
|
|
||||||
self.end_headers()
|
|
||||||
self.wfile.write('OK')
|
|
||||||
elif self.path.startswith('/files/'):'''
|
|
||||||
if self.path.startswith('/files/'):
|
if self.path.startswith('/files/'):
|
||||||
self.filesHandler()
|
self.filesHandler()
|
||||||
else:
|
else:
|
||||||
|
@ -471,56 +455,6 @@ def HttpHandlerFactory():
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
#print "Sending Bytes ",start_range, " to ", end_range, "...\n"
|
#print "Sending Bytes ",start_range, " to ", end_range, "...\n"
|
||||||
return (f, start_range, end_range)
|
return (f, start_range, end_range)
|
||||||
'''def statusHandler(self):
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header("Content-type", "application/json")
|
|
||||||
self.end_headers()
|
|
||||||
status = self.server.root_obj.Status()
|
|
||||||
output = json.dumps(status)
|
|
||||||
self.wfile.write(output)'''
|
|
||||||
'''def lsHandler(self):
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header("Content-type", "application/json")
|
|
||||||
self.end_headers()
|
|
||||||
retFiles = self.server.root_obj.Ls()
|
|
||||||
output = json.dumps(retFiles)
|
|
||||||
self.wfile.write(output)'''
|
|
||||||
'''def peersHandler(self):
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header("Content-type", "application/json")
|
|
||||||
self.end_headers()
|
|
||||||
peers = self.server.root_obj.Peers()
|
|
||||||
output = json.dumps(peers)
|
|
||||||
self.wfile.write(output)'''
|
|
||||||
'''def trackersHandler(self):
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header("Content-type", "application/json")
|
|
||||||
self.end_headers()
|
|
||||||
ret = list()
|
|
||||||
try:
|
|
||||||
info = self.server.root_obj.torrentHandler.torrent_file()
|
|
||||||
except:
|
|
||||||
info = self.server.root_obj.torrentHandler.get_torrent_info()
|
|
||||||
for tracker in info.trackers():
|
|
||||||
pi = {
|
|
||||||
'Url': tracker.url,
|
|
||||||
'NextAnnounceIn': self.server.root_obj.torrentHandler.status().next_announce.seconds,
|
|
||||||
'MinAnnounceIn': 10, # FIXME неясно, откуда брать
|
|
||||||
'ErrorCode': 0, #FIXME неясно, откуда брать
|
|
||||||
'ErrorMessage': u'', #FIXME неясно, откуда брать
|
|
||||||
'Message': u'', #FIXME неясно, откуда брать
|
|
||||||
'Tier': tracker.tier,
|
|
||||||
'FailLimit': tracker.fail_limit,
|
|
||||||
'Fails': tracker.fails,
|
|
||||||
'Source': tracker.source,
|
|
||||||
'Verified': tracker.verified,
|
|
||||||
'Updating': tracker.updating,
|
|
||||||
'StartSent': tracker.start_sent,
|
|
||||||
'CompleteSent': tracker.complete_sent,
|
|
||||||
}
|
|
||||||
ret.append(pi)
|
|
||||||
output = json.dumps(ret)
|
|
||||||
self.wfile.write(output)'''
|
|
||||||
# Вырубаем access-log
|
# Вырубаем access-log
|
||||||
def log_message(self, format, *args):
|
def log_message(self, format, *args):
|
||||||
return
|
return
|
||||||
|
@ -805,16 +739,17 @@ class Pyrrent2http(object):
|
||||||
retFiles = {'files': []}
|
retFiles = {'files': []}
|
||||||
if self.TorrentFS.HasTorrentInfo():
|
if self.TorrentFS.HasTorrentInfo():
|
||||||
files = self.TorrentFS.files
|
files = self.TorrentFS.files
|
||||||
for file_ in files:
|
for name in files.keys():
|
||||||
Url = 'http://' + self.config.bindAddress + '/files/' + urllib.quote(file_.name)
|
Url = 'http://' + self.config.bindAddress + '/files/' + urllib.quote(name)
|
||||||
fi = {
|
fi = {
|
||||||
'name': file_.unicode_name,
|
'index': files[name].index,
|
||||||
'media_type': file_.media_type,
|
'name': files[name].unicode_name,
|
||||||
'size': file_.size,
|
'media_type': files[name].media_type,
|
||||||
'offset': file_.offset,
|
'size': files[name].size,
|
||||||
'download': file_.downloaded,
|
'offset': files[name].offset,
|
||||||
'progress': file_.progress,
|
'download': files[name].downloaded,
|
||||||
'save_path': file_.save_path,
|
'progress': files[name].progress,
|
||||||
|
'save_path': files[name].save_path,
|
||||||
'url': Url
|
'url': Url
|
||||||
}
|
}
|
||||||
retFiles['files'].append(fi)
|
retFiles['files'].append(fi)
|
||||||
|
@ -837,7 +772,7 @@ class Pyrrent2http(object):
|
||||||
}
|
}
|
||||||
peers['peers'].append(pi)
|
peers['peers'].append(pi)
|
||||||
return peers
|
return peers
|
||||||
def stats(self):
|
'''def stats(self):
|
||||||
status = self.torrentHandle.status()
|
status = self.torrentHandle.status()
|
||||||
dhtStatusStr = ''
|
dhtStatusStr = ''
|
||||||
if not status.has_metadata:
|
if not status.has_metadata:
|
||||||
|
@ -865,7 +800,7 @@ class Pyrrent2http(object):
|
||||||
logging.info(str_)
|
logging.info(str_)
|
||||||
if (self.config.showPiecesProgress or self.config.showAllStats) and self.TorrentFS.lastOpenedFile != None:
|
if (self.config.showPiecesProgress or self.config.showAllStats) and self.TorrentFS.lastOpenedFile != None:
|
||||||
self.TorrentFS.lastOpenedFile.ShowPieces()
|
self.TorrentFS.lastOpenedFile.ShowPieces()
|
||||||
|
'''
|
||||||
def consumeAlerts(self):
|
def consumeAlerts(self):
|
||||||
alerts = self.session.pop_alerts()
|
alerts = self.session.pop_alerts()
|
||||||
for alert in alerts:
|
for alert in alerts:
|
||||||
|
@ -883,7 +818,7 @@ class Pyrrent2http(object):
|
||||||
if type(alert) == alert_type:
|
if type(alert) == alert_type:
|
||||||
return alert
|
return alert
|
||||||
def loop(self):
|
def loop(self):
|
||||||
self.statsTicker = Ticker(30)
|
#self.statsTicker = Ticker(30)
|
||||||
self.saveResumeDataTicker = Ticker(5)
|
self.saveResumeDataTicker = Ticker(5)
|
||||||
time_start = time.time()
|
time_start = time.time()
|
||||||
while True:
|
while True:
|
||||||
|
@ -898,8 +833,8 @@ class Pyrrent2http(object):
|
||||||
if os.getppid() == 1:
|
if os.getppid() == 1:
|
||||||
self.forceShutdown = True
|
self.forceShutdown = True
|
||||||
time_start = time.time()
|
time_start = time.time()
|
||||||
if self.statsTicker.true:
|
#if self.statsTicker.true:
|
||||||
self.stats()
|
# self.stats()
|
||||||
if self.saveResumeDataTicker.true:
|
if self.saveResumeDataTicker.true:
|
||||||
self.saveResumeData(True)
|
self.saveResumeData(True)
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
|
@ -954,10 +889,12 @@ class Pyrrent2http(object):
|
||||||
def filesToRemove(self):
|
def filesToRemove(self):
|
||||||
files = []
|
files = []
|
||||||
if self.TorrentFS.HasTorrentInfo():
|
if self.TorrentFS.HasTorrentInfo():
|
||||||
for file in self.TorrentFS.files:
|
for i, f in enumerate(self.torrentHandle.files()):
|
||||||
if (not self.config.keepComplete or not file.IsComplete()) and (not self.config.keepIncomplete or file.IsComplete()):
|
isComplete = self.TorrentFS.progresses[i] == f.size
|
||||||
if os.path.exists(file.save_path):
|
if (not self.config.keepComplete or not isComplete) and (not self.config.keepIncomplete or isComplete):
|
||||||
files.append(file.save_path)
|
path = os.path.abspath(os.path.join(self.TorrentFS.save_path, localize_path(f.path)))
|
||||||
|
if os.path.exists(path):
|
||||||
|
files.append(path)
|
||||||
return files
|
return files
|
||||||
def removeTorrent(self):
|
def removeTorrent(self):
|
||||||
files = []
|
files = []
|
||||||
|
@ -977,7 +914,7 @@ class Pyrrent2http(object):
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
logging.info('Stopping pyrrent2http...')
|
logging.info('Stopping pyrrent2http...')
|
||||||
self.forceShutdown = True
|
self.forceShutdown = True
|
||||||
self.statsTicker.stop()
|
#self.statsTicker.stop()
|
||||||
self.saveResumeDataTicker.stop()
|
self.saveResumeDataTicker.stop()
|
||||||
self.httpListener.shutdown()
|
self.httpListener.shutdown()
|
||||||
self.TorrentFS.Shutdown()
|
self.TorrentFS.Shutdown()
|
||||||
|
|
Loading…
Reference in New Issue