# -*- 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, DownloadDB 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()) 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' and __settings__.getSetting('keep_files') == 'true' seeding_status=False seeding_run=False def __init__(self, userStorageDirectory, torrentUrl, params={}): self.userStorageDirectory = userStorageDirectory self.torrentUrl=torrentUrl 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, self.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) self.loop() else: break #print '************************************* GO NEXT?' if self.next_dl and self.next_dling and (self.next_contentId or self.next_contentId==0) 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: if self.seeding_status: showMessage(Localization.localize('Information'), Localization.localize('Torrent is seeding. To stop it use Download Status.'), forced=True) else: if self.seeding: self.db_delete() 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.continueSession(self.contentId, Offset=Offset) 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) self.basename=label self.seeding_run=False 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 not self.seeding_run and self.iterator == 100 and self.seeding: self.seeding_run=True xbmc.sleep(1000) self.seed(self.contentId) self.seeding_status=True if self.iterator == 100 and not self.next_dling and (self.next_contentId or self.next_contentId==0): showMessage(Localization.localize('Torrent Downloading'), Localization.localize('Starting download next episode!'), forced=True) self.torrent.stopSession() xbmc.sleep(1000) path = self.torrent.getFilePath(self.next_contentId) self.basename=self.display_name = os.path.basename(path) self.torrent.continueSession(self.next_contentId) 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) ] def db_delete(self): db=DownloadDB() get=db.get(self.basename) if get: db.delete(get[0]) def seed(self, contentId): self.db_delete() exec_str='XBMC.RunPlugin(%s)' % \ ('%s?action=%s&url=%s&storage=%s&ind=%s') % \ (sys.argv[0], 'downloadLibtorrent', urllib.quote_plus(self.torrentUrl), urllib.quote_plus(self.userStorageDirectory), str(contentId)) xbmc.executebuiltin(exec_str)