def _media_cache_path(cls): _path = os.path.join(Addon.cache_path, cls.mediaType) if not os.path.exists(_path): os.makedirs(_path) if not os.path.exists(_path): raise Error("Unable to create cache directory %s" % _path, 30322) cls.media_cache_path = _path
def player(self, subtitle=None, quality=None, **params): log("(Main) Creating player options") if settings.addon.handle > -1: xbmcplugin.endOfDirectory(settings.addon.handle, True, False, False) item = self.getSelectedItem() free_space = self._calculate_free_space() if not quality: waring = [] for _q in self.mediaSettings.qualities: if params.get(_q): if params['%ssize' %_q] > free_space: if _q == '3D' and self.mediaSettings.play3d == 1 and not Dialog().yesno(line2=30011, lineStr1=' ', headingStr=item['info']['title']): continue quality = _q break waring = waring+[_q] if waring: if not quality: raise Notify('There is not enough free space in %s' %self.mediaSettings.download_path, 30323, level=NOTIFYLEVEL.ERROR) if len(waring) > 1: notify(message=__addon__.getLocalizedString(30325) %(", ".join(waring), waring.pop()), level=NOTIFYLEVEL.WARNING) else: notify(message=__addon__.getLocalizedString(30326) %waring[0], level=NOTIFYLEVEL.WARNING) log('(Main) There must be a minimum of %s to play. %s available in %s' %(shortenBytes(params['%ssize' %quality]), shortenBytes(free_space), self.mediaSettings.download_path), LOGLEVEL.NOTICE) elif not params.get(quality): raise Error('%s quality was not found' %quality, 30023) elif params['%ssize' %quality] < free_space: raise Notify('There is not enough free space in %s' %self.mediaSettings.download_path, 30323, level=NOTIFYLEVEL.ERROR) TorrentPlayer().playTorrentFile(self.mediaSettings, build_magnetFromMeta(params[quality], "quality %s" %quality), item, subtitle)
def _download_path(cls): _path = xbmc.translatePath( __addon__.getSetting("%s_download_path" % cls.__name__)) if _path: if _path.lower().startswith("smb://"): if not platform.system == "windows": raise Notify( "Downloading to an unmounted network share is not supported (%s)" % _path, 30319, 0) _path.replace("smb:", "").replace("/", "\\") if not os.path.isdir(_path): raise Notify('Download path does not exist (%s)' % _path, 30310, 1) cls.download_path = _path.encode(addon.fsencoding) else: _path = os.path.join(addon.cache_path, cls.mediaType) if not os.path.exists(_path): os.makedirs(_path) if not os.path.exists(_path): raise Error("Unable to create cache directory %s" % _path, 30322) cls.download_path = _path
def _cache_path(cls): _path = xbmc.translatePath("special://profile/addon_data/%s/cache" % cls.id) if not os.path.exists(_path): os.makedirs(_path) if not os.path.exists(_path): raise Error("Unable to create cache directory %s" % _path, 30322) cls.cache_path = _path.encode(cls.fsencoding)
def ensure_exec(binary, binary_path): st = os.stat(binary_path) if not st.st_mode & stat.S_IEXEC: os.chmod(binary_path, st.st_mode | stat.S_IEXEC) st = os.stat(binary_path) if not st.st_mode & stat.S_IEXEC: raise Error( "Cannot make %s executable (%s)" % (binary, binary_path), 30321)
def run(): try: log("(Main) Starting - Platform: %s %s" %(Platform.system, Platform.arch), LOGLEVEL.INFO) log("(Main) Platform: %s" %sys.platform) if hasattr(os, 'uname'): log("(Main) Uname: %s" %str(os.uname())) log("(Main) Environ: %s" %str(os.environ)) if not Platform.system: raise Error("Unsupported OS", 30302) def _empty_dir(path): if os.path.isdir(path): for x in os.listdir(path): if x in ['.', '..', 'movies', 'tvshows']: continue _path = os.path.join(path, x) if os.path.isfile(_path): os.remove(_path) elif os.path.isdir(_path): _empty_dir(_path) os.rmdir(_path) params = dict(urlparse.parse_qsl(settings.addon.cur_uri)) if not params.pop('cmd', None): if not settings.addon.version+"~1" == settings.addon.last_update_id: # Clear cache after update _empty_dir(settings.addon.cache_path) __addon__.setSetting("last_update_id", settings.addon.version+"~1") else: # Clean debris from the cache dir try: for mediaType in ['movies', 'tvshows']: if getattr(settings, mediaType).delete_files: _empty_dir(os.path.join(settings.addon.cache_path, mediaType)) except: log_error() sys.exc_clear() PopcornTime(**params) else: Cmd(**params) except (Error, HTTPError, ProxyError, TorrentError) as e: notify(e.messageID, level=NOTIFYLEVEL.ERROR) log_error() except Notify as e: notify(e.messageID, e.message, level=e.level) log("(Main) Notify: %s" %str(e), LOGLEVEL.NOTICE) sys.exc_clear() except Abort: log("(Main) Abort", LOGLEVEL.INFO) sys.exc_clear() except: notify(30308, level=NOTIFYLEVEL.ERROR) log_error()
def __call__(self, mediaType=None, endpoint=None, **params): self.mediaSettings = None if mediaType: self.mediaSettings = getattr(settings, mediaType) if not endpoint: endpoint = 'index' log("(Main) Calling %s. Params: %s" %(endpoint, str(params))) if not hasattr(self, endpoint): raise Error("'PopcornTime' class has no method '%s'" %endpoint) getattr(self, endpoint)(**params)
def playTorrentFile(self, mediaSettings, magnet, item, subtitleURL=None): with TorrentEngine(mediaSettings, magnet) as _TorrentEngine: # Loading log('(Torrent Player) Loading', LOGLEVEL.INFO) with closing(SafeDialogProgress()) as dialog: dialog.create(item['info']['title']) dialog.update(0, __addon__.getLocalizedString(30031), ' ', ' ') # Update progress dialog dialog.set_mentions((101+bool(subtitleURL))) def on_update(state, progressValue): if state == Loader.PRELOADING: dialog.update(progressValue, *self._get_status_lines(_TorrentEngine.status())) elif state == Loader.CHECKING_DATA: dialog.update(progressValue, __addon__.getLocalizedString(30037), ' ', ' ') elif state == Loader.WAITING_FOR_PLAY_FILE: dialog.update(progressValue, __addon__.getLocalizedString(30016), ' ', ' ') elif state == Loader.DOWNLOADING_SUBTITLE: dialog.update(progressValue, __addon__.getLocalizedString(30019), ' ', ' ') elif state == Loader.FINISHED: dialog.update(progressValue, __addon__.getLocalizedString(30020), ' ', ' ') with Loader(mediaSettings, _TorrentEngine, item, subtitleURL, on_update) as _loader: while not _loader.is_done(0.100): if xbmc.abortRequested or dialog.iscanceled(): raise Abort() # Starts the playback log('(Torrent Player) Start the playback', LOGLEVEL.INFO) self.play(Loader.url, xbmcItem(**item)) # Waiting for playback to start log('(Torrent Player) Waiting for playback to start') for _ in xrange(300): if self.isPlaying(): break time.sleep(0.100) else: raise Error('Playback is terminated due to timeout', 30318) if Loader.subtitle: log('(Torrent Player) Add subtitle to the playback') self.setSubtitles(Loader.subtitle) with OverlayText() as self._overlay: while not xbmc.abortRequested and self.isPlaying(): if self._overlay.isShowing(): self._overlay.setText("\n".join(self._get_status_lines(_TorrentEngine.status()))) time.sleep(0.100) continue time.sleep(0.250) log('(Torrent Player) The playback has stop')
def get_free_port(port=5001): """ Check we can bind to localhost with a specified port On failer find a new TCP port that can be used for binding """ try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', port)) s.close() except socket.error: try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 0)) port = s.getsockname()[1] s.close() except socket.error: raise Error("Can not find a TCP port to bind torrent2http", 30300) return port
try: reload(sys) sys.setdefaultencoding("utf-8") log( "(Main) Starting %s version %s build %s - Platform: %s %s" % (settings.addon.name, settings.addon.version, settings.BUILD, Platform.system, Platform.arch), LOGLEVEL.INFO) log("(Main) Platform: %s" % sys.platform) if hasattr(os, 'uname'): log("(Main) Uname: %s" % str(os.uname())) log("(Main) Environ: %s" % str(os.environ)) if not Platform.system: raise Error("Unsupported OS", 30302) params = dict(urlparse.parse_qsl(settings.addon.cur_uri)) if not params.get('cmd'): params = _fix(params) getattr(gui, params.pop('endpoint', 'index'))(params.pop('mediaType', '')).show(**params) else: getattr(gui.cmd, params.get('cmd'))() except (Error, HTTPError, ProxyError, TorrentError) as e: notify(e.messageID, level=NOTIFYLEVEL.ERROR) log_error() except Notify as e: notify(e.messageID, e.message, level=e.level)
def __init__(self, endpoint, **params): log("(Main) Calling %s. Params: %s" %(endpoint, str(params)), LOGLEVEL.INFO) if not hasattr(self, endpoint): raise Error("'Cmd' class has no method '%s'" %endpoint) getattr(self, endpoint)(**params)
def search(self, **params): log("(Main) Creating search view", LOGLEVEL.INFO) searchString = self.getSearchString() curPageNum = self.getCurPageNum() with closing(Cache("%s.search.query" %self.mediaSettings.mediaType, ttl=24 * 3600, last_changed=self.mediaSettings.lastchanged)) as cache: # Reset cache when we have different search string if cache and not searchString == cache['searchString']: log("(Main) Resetting view cache") cache.trunctate() # Reset page number if the user have cleaned the cache # or we have a different search string if not cache: curPageNum = 1 if not cache or curPageNum > cache['curNumOfPages']: log("(Main) Reading item cache") items = {} pages = 0 with closing(SafeDialogProgress()) as dialog: dialog.create(__addon__.getLocalizedString(30028)) dialog.update(0, __addon__.getLocalizedString(30007), ' ', ' ') _time = time.time() # Getting item list log("(Main) Getting item list") with closing(media.List(self.mediaSettings, 'search', *(searchString, curPageNum,), **params)) as medialist: while not medialist.is_done(0.100): if xbmc.abortRequested or dialog.iscanceled(): raise Abort() res = medialist.get_data() if not res: raise Notify("No search result", 30327, NOTIFYLEVEL.INFO) items = res['items'] pages = res['pages'] # Update progress dialog dialog.set_mentions(len(items)+2) dialog.update(1, __addon__.getLocalizedString(30018), ' ', ' ') def on_data(progressValue, oldItem, newItem): label = ["%s %s" %(__addon__.getLocalizedString(30034), oldItem["label"])] if newItem.get("label") and not oldItem["label"] == newItem["label"]: label = label+["%s %s" %(__addon__.getLocalizedString(30035), newItem["label"])] if newItem.get("stream_info", {}).get("subtitle", {}).get("language"): label = label+["%s %s" %(__addon__.getLocalizedString(30012), isoToLang(newItem["stream_info"]["subtitle"]["language"]))] while len(label) < 3: label = label+[' '] dialog.update(progressValue, *label) # Getting media cache log("(Main) Getting media info") with closing(media.MediaCache(self.mediaSettings, on_data)) as mediadata: [mediadata.submit(item) for item in items] mediadata.start() while not mediadata.is_done(0.100): if xbmc.abortRequested or dialog.iscanceled(): raise Abort() items = mediadata.get_data() if not items: raise Error("Did not receive any data", 30304) log("(Main) Reading time: %s" %(time.time()-_time)) # Done dialog.update(1, __addon__.getLocalizedString(30017), ' ', ' ') log("(Main) Updating view cache") cache.extendKey("items", items) cache.update({"curNumOfPages": curPageNum, "totalPages": pages, "searchString": searchString}) pageCache = cache.copy() log("(Main) Adding items") self.addItems(self.mediaSettings.mediaType, pageCache["items"], 'player', False) # NOTE: # Add show more, but we stop at page 20... yes 20 pages sounds all right... # ... each page cache file can be between 2 and 3 mByt with 20 pages and will have an average of 1 mByt... # This can become substantial problem with movies and tv-shows pages if pageCache['curNumOfPages'] < pageCache['totalPages'] and pageCache['curNumOfPages'] < 21: self.addNextButton(**{'pageNum': pageCache['curNumOfPages']+1, 'searchString': searchString}) update_listing = False if curPageNum > 1: update_listing = True self.finish(self.mediaSettings.mediaType, update_listing)
def ensure_exec(binary_path): st = os.stat(binary_path) os.chmod(binary_path, st.st_mode | stat.S_IEXEC) st = os.stat(binary_path) if not st.st_mode & stat.S_IEXEC: raise Error("Cannot make torrent2http executable (%s)" % binary_path, 30321)
def existBinary(binary_path): if not os.path.isfile(binary_path): raise Error("torrent2http binary was not found at path %s" % os.path.dirname(binary_path), 30320)
def _torrent_options(cls): binary = "torrent2http" if Platform.system == 'windows': binary = "torrent2http.exe" binary_path = os.path.join(__addon__.getAddonInfo('path'), 'resources', 'bin', "%s_%s" % (Platform.system, Platform.arch), binary).encode(addon.fsencoding) if not os.path.isfile(binary_path): raise Error( "torrent2http binary (%s) was not found at path %s" % (os.path.dirname(binary_path), binary), 30320) if Platform.system == "android": log( "Trying to copy torrent2http to ext4, since the sdcard is noexec", LOGLEVEL.INFO) android_path = os.path.join( os.path.dirname( os.path.dirname( os.path.dirname( xbmc.translatePath('special://xbmc')))), "files", __addon__.getAddonInfo('id'), binary).encode(addon.fsencoding) if not os.path.exists(os.path.dirname(android_path)): os.makedirs(os.path.dirname(android_path)) if not os.path.exists(android_path) or int( os.path.getmtime(android_path)) < int( os.path.getmtime(binary_path)): shutil.copy2(binary_path, android_path) binary_path = android_path if not os.path.isfile(binary_path): raise Error( "torrent2http binary was not found at path %s" % os.path.dirname(binary_path), 30320) st = os.stat(binary_path) os.chmod(binary_path, st.st_mode | stat.S_IEXEC) if not st.st_mode & stat.S_IEXEC: raise Error( "Cannot make %s executable, ensure partition is in exec mode\n%s" % (binary, os.path.dirname(binary_path)), 30321) download_kbps = int(__addon__.getSetting("download_kbps")) if download_kbps <= 0: download_kbps = -1 upload_kbps = int(__addon__.getSetting("upload_kbps")) if upload_kbps <= 0: upload_kbps = -1 elif upload_kbps < 15: raise Notify( 'Max Upload Rate must be above 15 Kilobytes per second.', 30324, 1) __addon__.setSetting('upload_kbps', '15') upload_kbps = 15 trackers = __addon__.getSetting('trackers') if trackers: trackers = ",".join(trackers.split(',') + PUBLIC_TRACKERS) else: trackers = ",".join(PUBLIC_TRACKERS) debug = __addon__.getSetting("debug") kwargs = { '--file-index': 0, '--dl-path': cls.download_path, '--connections-limit': int(__addon__.getSetting('connections_limit')), '--dl-rate': download_kbps, '--ul-rate': upload_kbps, '--enable-dht': __addon__.getSetting('enable_dht'), '--enable-lsd': __addon__.getSetting('enable_lsd'), '--enable-natpmp': __addon__.getSetting('enable_natpmp'), '--enable-upnp': __addon__.getSetting('enable_upnp'), '--enable-scrape': __addon__.getSetting('enable_scrape'), '--encryption': int(__addon__.getSetting('encryption')), '--show-stats': debug, '--files-progress': debug, '--overall-progress': debug, '--pieces-progress': debug, '--listen-port': int(__addon__.getSetting('listen_port')), '--random-port': __addon__.getSetting('use_random_port'), '--keep-complete': str(cls.keep_complete).lower(), '--keep-incomplete': str(cls.keep_incomplete).lower(), '--keep-files': str(cls.keep_files).lower(), '--max-idle': 300, '--no-sparse': 'false', #'--resume-file': None, '--user-agent': 'torrent2http/1.0.1 libtorrent/1.0.3.0 kodipopcorntime/%s' % addon.version, #'--state-file': None, '--enable-utp': __addon__.getSetting('enable_utp'), '--enable-tcp': __addon__.getSetting('enable_tcp'), '--debug-alerts': debug, '--torrent-connect-boost': int(__addon__.getSetting('torrent_connect_boost')), '--connection-speed': int(__addon__.getSetting('connection_speed')), '--peer-connect-timeout': int(__addon__.getSetting('peer_connect_timeout')), '--request-timeout': 20, '--min-reconnect-time': int(__addon__.getSetting('min_reconnect_time')), '--max-failcount': int(__addon__.getSetting('max_failcount')), '--dht-routers': __addon__.getSetting('dht_routers') or None, '--trackers': trackers } args = [binary_path] for k, v in kwargs.iteritems(): if v == 'true': args.append(k) elif v == 'false': args.append("%s=false" % k) elif v is not None: args.append(k) if isinstance(v, str): args.append(v.decode('utf-8').encode(addon.fsencoding)) else: args.append(str(v)) cls.torrent_options = args