Принципиальные изменения движка

sandbox1
inpos 2016-03-19 17:25:09 +03:00
parent d3f3f729f5
commit bd646784cb
4 changed files with 58 additions and 113 deletions

View File

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

View File

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

View File

@ -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,12 +324,12 @@ 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)
def peers(self, timeout=10): def peers(self, timeout=10):

View File

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