plugin.video.torrenter/Player.py

378 lines
15 KiB
Python

# -*- coding: utf-8 -*-
import os
import urllib
import json
import tempfile
import sys
from contextlib import contextmanager, closing, nested
import xbmc
import xbmcgui
import Downloader
import xbmcgui
import xbmcvfs
import Localization
from functions import calculate, showMessage, clearStorage, tempdir
ROOT = sys.modules["__main__"].__root__
RESOURCES_PATH = os.path.join(ROOT, 'resources')
TORRENT2HTTP_TIMEOUT = 20
TORRENT2HTTP_POLL = 1000
PLAYING_EVENT_INTERVAL = 60
MIN_COMPLETED_PIECES = 0.5
WINDOW_FULLSCREEN_VIDEO = 12005
XBFONT_LEFT = 0x00000000
XBFONT_RIGHT = 0x00000001
XBFONT_CENTER_X = 0x00000002
XBFONT_CENTER_Y = 0x00000004
XBFONT_TRUNCATED = 0x00000008
XBFONT_JUSTIFY = 0x00000010
STATE_STRS = [
'Queued',
'Checking',
'Downloading metadata',
'Downloading',
'Finished',
'Seeding',
'Allocating',
'Allocating file & Checking resume'
]
VIEWPORT_WIDTH = 1920.0
VIEWPORT_HEIGHT = 1088.0
OVERLAY_WIDTH = int(VIEWPORT_WIDTH * 0.7) # 70% size
OVERLAY_HEIGHT = 150
ENCRYPTION_SETTINGS = {
"Forced": 0,
"Enabled": 1,
"Disabled": 2,
}
class OverlayText(object):
def __init__(self, w, h, *args, **kwargs):
self.window = xbmcgui.Window(WINDOW_FULLSCREEN_VIDEO)
viewport_w, viewport_h = self._get_skin_resolution()
# Adjust size based on viewport, we are using 1080p coordinates
w = int(w * viewport_w / VIEWPORT_WIDTH)
h = int(h * viewport_h / VIEWPORT_HEIGHT)
x = (viewport_w - w) / 2
y = (viewport_h - h) / 2
self._shown = False
self._text = ""
self._label = xbmcgui.ControlLabel(x, y, w, h, self._text, *args, **kwargs)
self._background = xbmcgui.ControlImage(x, y, w, h, os.path.join(RESOURCES_PATH, "images", "black.png"))
self._background.setColorDiffuse("0xD0000000")
def show(self):
if not self._shown:
self.window.addControls([self._background, self._label])
self._shown = True
self._background.setColorDiffuse("0xD0000000")
def hide(self):
if self._shown:
self._shown = False
self.window.removeControls([self._background, self._label])
self._background.setColorDiffuse("0xFF000000")
def close(self):
self.hide()
@property
def text(self):
return self._text
@text.setter
def text(self, text):
self._text = text
if self._shown:
self._label.setLabel(self._text)
# This is so hackish it hurts.
def _get_skin_resolution(self):
import xml.etree.ElementTree as ET
skin_path = xbmc.translatePath("special://skin/")
tree = ET.parse(os.path.join(skin_path, "addon.xml"))
res = tree.findall("./extension/res")[0]
return int(res.attrib["width"]), int(res.attrib["height"])
class TorrentPlayer(xbmc.Player):
__plugin__ = sys.modules["__main__"].__plugin__
__settings__ = sys.modules["__main__"].__settings__
ROOT = sys.modules["__main__"].__root__ #.decode('utf-8').encode(sys.getfilesystemencoding())
userStorageDirectory = __settings__.getSetting("storage")
USERAGENT = "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0"
torrentFilesDirectory = 'torrents'
debug = __settings__.getSetting('debug') == 'true'
subs_dl = __settings__.getSetting('subs_dl') == 'true'
seeding = __settings__.getSetting('keep_seeding') == 'true'
def __init__(self, torrentUrl, params={}):
if 0 == len(self.userStorageDirectory):
try:
temp_dir = tempfile.gettempdir()
except:
temp_dir = tempdir()
self.userStorageDirectory = temp_dir + os.path.sep + 'Torrenter'
else:
self.userStorageDirectory = self.userStorageDirectory + 'Torrenter'
xbmc.Player.__init__(self)
print ("[TorrentPlayer] Initalized")
self.params = params
self.get = self.params.get
self.contentId = int(self.get("url"))
try:
self.ids_video = urllib.unquote_plus(self.get("url2")).split(',')
#print str(self.ids_video)
except:
self.ids_video = None
self.torrent = Downloader.Torrent(self.userStorageDirectory, torrentUrl, self.torrentFilesDirectory).player
self.init()
self.setup_torrent()
if self.buffer():
while True:
if self.setup_play():
#print '************************************* GOING LOOP'
self.torrent.continueSession(self.contentId, seeding=self.seeding)
self.loop()
else:
break
#print '************************************* GO NEXT?'
if self.next_dl and self.next_dling and self.next_contentId and self.iterator == 100:
self.contentId = self.next_contentId
continue
#print '************************************* NO! break'
break
self.torrent.stopSession()
self.torrent.threadComplete = True
self.torrent.checkThread()
if 'false' == self.__settings__.getSetting("keep_files"):
clearStorage(self.userStorageDirectory)
else:
showMessage(Localization.localize('Information'),
Localization.localize('Torrent downloading is stopped.'), forced=True)
def init(self):
self.next_dl = True if self.__settings__.getSetting('next_dl') == 'true' else False
self.next_contentId = None
self.display_name = ''
self.downloadedSize = 0
self.dialog = xbmcgui.Dialog()
self.on_playback_started = []
self.on_playback_resumed = []
self.on_playback_paused = []
self.on_playback_stopped = []
def setup_torrent(self):
self.torrent.startSession()
if 0 < int(self.__settings__.getSetting("upload_limit")):
self.torrent.setUploadLimit(int(self.__settings__.getSetting("upload_limit")) * 1000000 / 8) #MBits/second
if 0 < int(self.__settings__.getSetting("download_limit")):
self.torrent.setDownloadLimit(
int(self.__settings__.getSetting("download_limit")) * 1000000 / 8) #MBits/second
self.torrent.status = False
self.fullSize = self.torrent.getFileSize(self.contentId)
Offset = calculate(self.fullSize)
#print 'Offset: '+str(Offset)
self.torrent.threadSeeding = self.seeding
self.torrent.continueSession(self.contentId, Offset=Offset, seeding=self.seeding)
def buffer(self):
iterator = 0
progressBar = xbmcgui.DialogProgress()
progressBar.create(Localization.localize('Please Wait') + str(' [%s]' % str(self.torrent.lt.version)),
Localization.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)
num_pieces=int(self.torrent.torrentFileInfo.num_pieces())
while iterator < 100:
xbmc.sleep(1000)
self.torrent.debug()
downloadedSize = self.torrent.torrentHandle.file_progress()[self.contentId]
status = self.torrent.torrentHandle.status()
iterator = int(status.progress * 100)
if status.state == 0 or (status.progress == 0 and status.num_pieces > 0):
iterator = int(status.num_pieces*100/num_pieces)
if iterator > 99: iterator = 99
progressBar.update(iterator, Localization.localize('Checking preloaded files...'), ' ', ' ')
elif status.state == 3:
dialogText = Localization.localize('Preloaded: ') + str(downloadedSize / 1024 / 1024) + ' MB / ' + str(
self.fullSize / 1024 / 1024) + ' MB'
peersText = ' [%s: %s; %s: %s]' % (
Localization.localize('Seeds'), str(self.torrent.getSeeds()), Localization.localize('Peers'),
str(self.torrent.getPeers()),)
speedsText = '%s: %s Mbit/s; %s: %s Mbit/s' % (
Localization.localize('Downloading'), str(self.torrent.getDownloadRate() * 8 / 1000000),
Localization.localize('Uploading'), str(self.torrent.getUploadRate() * 8 / 1000000))
progressBar.update(iterator, Localization.localize('Seeds searching.') + peersText, dialogText,
speedsText)
else:
progressBar.update(iterator, Localization.localize('UNKNOWN STATUS'), ' ', ' ')
if progressBar.iscanceled():
progressBar.update(0)
progressBar.close()
self.torrent.threadComplete = True
self.torrent.checkThread()
return
progressBar.update(0)
progressBar.close()
return True
def setup_subs(self, label, path):
iterator=0
subs=self.torrent.getSubsIds(label)
#print str(subs)
if len(subs)>0:
showMessage(Localization.localize('Information'),
Localization.localize('Downloading and copy subtitles. Please wait.'), forced=True)
for ind, title in subs:
self.torrent.continueSession(ind)
while iterator < 100:
xbmc.sleep(1000)
self.torrent.debug()
status = self.torrent.torrentHandle.status()
iterator = int(status.progress * 100)
xbmc.sleep(2000)
for ind, title in subs:
newFileName=os.path.join(self.userStorageDirectory,os.path.dirname(path),os.path.basename(title))
if xbmcvfs.exists(newFileName):
newFileName=None
for i in range(1,9):
temp=os.path.basename(title)
ext=temp.split('.')[-1]
temp = temp[:len(temp) - len(temp.split('.')[-1]) - 1]+'.'+str(i)+'.'+ext
if not xbmcvfs.exists(os.path.join(self.userStorageDirectory,os.path.dirname(path),temp)):
newFileName=os.path.join(self.userStorageDirectory,os.path.dirname(path),temp)
break
if newFileName:
#print str((os.path.join(self.userStorageDirectory,title),newFileName))
xbmcvfs.copy(os.path.join(self.userStorageDirectory,title),newFileName)
def setup_play(self):
self.next_dling = False
self.iterator=0
path = self.torrent.getFilePath(self.contentId)
label = os.path.basename(path)
listitem = xbmcgui.ListItem(label, path=path)
if self.subs_dl:
self.setup_subs(label, path)
if self.next_dl and self.ids_video:
next_contentId_index = self.ids_video.index(str(self.contentId)) + 1
if len(self.ids_video) > next_contentId_index:
self.next_contentId = int(self.ids_video[next_contentId_index])
else:
self.next_contentId = False
if not self.ids_video:
seasonId = self.get("seasonId")
episodeId = self.get("episodeId")
title = self.get("title")
try:
label = urllib.unquote_plus(self.get("label"))
print 'ok'
except:
print 'except'
if seasonId and episodeId and label and title:
listitem = xbmcgui.ListItem(label, path=path)
listitem.setInfo(type='video', infoLabels={'title': label,
'episode': int(episodeId),
'season': int(seasonId),
'tvshowtitle': urllib.unquote_plus(title)})
thumbnail = self.get("thumbnail")
if thumbnail:
listitem.setThumbnailImage(urllib.unquote_plus(thumbnail))
self.display_name = label
#мегакостыль!
rpc = ({'jsonrpc': '2.0', 'method': 'Files.GetDirectory', 'params': {
'media': 'video', 'directory': os.path.dirname(path)}, 'id': 0})
data = json.dumps(rpc)
request = xbmc.executeJSONRPC(data)
response = json.loads(request)
xbmc.sleep(300)
if response:
xbmc.Player().play(path, listitem)
xbmc.sleep(3000)#very important, do not edit this, podavan
return True
def onPlayBackStarted(self):
for f in self.on_playback_started:
f()
print(str(("video", "play", self.display_name)))
def onPlayBackResumed(self):
for f in self.on_playback_resumed:
f()
self.onPlayBackStarted()
def onPlayBackPaused(self):
for f in self.on_playback_paused:
f()
print(str(("video", "pause", self.display_name)))
def onPlayBackStopped(self):
for f in self.on_playback_stopped:
f()
print(str(("video", "stop", self.display_name)))
@contextmanager
def attach(self, callback, *events):
for event in events:
event.append(callback)
yield
for event in events:
event.remove(callback)
def loop(self):
with closing(
OverlayText(w=OVERLAY_WIDTH, h=OVERLAY_HEIGHT, alignment=XBFONT_CENTER_X | XBFONT_CENTER_Y)) as overlay:
with nested(self.attach(overlay.show, self.on_playback_paused),
self.attach(overlay.hide, self.on_playback_resumed, self.on_playback_stopped)):
while not xbmc.abortRequested and self.isPlaying():
self.torrent.checkThread()
self.torrent.debug()
status = self.torrent.torrentHandle.status()
overlay.text = "\n".join(self._get_status_lines(status))
#downloadedSize = torrent.torrentHandle.file_progress()[contentId]
self.iterator = int(status.progress * 100)
if self.iterator == 100 and not self.next_dling and self.next_contentId:
showMessage(Localization.localize('Torrent Downloading'),
Localization.localize('Starting download next episode!'), forced=True)
self.torrent.stopSession()
xbmc.sleep(1000)
self.torrent.threadSeeding = self.seeding
self.torrent.continueSession(self.next_contentId, seeding=self.seeding)
path = self.torrent.getFilePath(self.next_contentId)
self.display_name = os.path.basename(path)
self.next_dling = True
xbmc.sleep(1000)
def _get_status_lines(self, s):
return [
self.display_name.decode('utf-8'),
"%.2f%% %s" % (s.progress * 100, Localization.localize(STATE_STRS[s.state]).decode('utf-8')),
"D:%.2f%s U:%.2f%s S:%d P:%d" % (s.download_rate / 1000, Localization.localize('kb/s').decode('utf-8'),
s.upload_rate / 1000, Localization.localize('kb/s').decode('utf-8'),
s.num_seeds, s.num_peers)
]