def query(self, path, method=None, **kwargs): method = method or self.session.get url = self.buildUrl(path, includeToken=True) # If URL is empty, try refresh resources and return empty set for now if not url: util.WARN_LOG( "Empty server url, returning None and refreshing resources") plexapp.refreshResources(True) return None util.LOG('{0} {1}'.format( method.__name__.upper(), re.sub('X-Plex-Token=[^&]+', 'X-Plex-Token=****', url))) try: response = method(url, **kwargs) if response.status_code not in (200, 201): codename = http.status_codes.get(response.status_code, ['Unknown'])[0] raise exceptions.BadRequest('({0}) {1}'.format( response.status_code, codename)) data = response.text.encode('utf8') except asyncadapter.TimeoutException: util.ERROR() plexapp.refreshResources(True) return None except http.requests.ConnectionError: util.ERROR() return None return ElementTree.fromstring(data) if data else None
def _getItemsFromString(self, dstring): try: data = json.loads(dstring) self._items = [Item.fromDict(ddict) for ddict in data['items']] self._attrs = data.get('attributes', {}) self._settings = data.get('settings', {}) self.active = data.get('active', False) except (ValueError, TypeError): if dstring.startswith('{'): util.DEBUG_LOG(repr(dstring)) util.ERROR('Error parsing sequence: {0}'.format(repr( self.name))) raise exceptions.BadSequenceFileException() else: try: self._items = self._getItemsFromXMLString(dstring) except: util.DEBUG_LOG(repr(dstring[:100])) util.ERROR('Error parsing sequence: {0}'.format( repr(self.name))) raise exceptions.BadSequenceFileException() self._attrs['type'] = self._attrs.get('type') self._attrs['genres'] = self._attrs.get('genres') or [] self._attrs['directors'] = self._attrs.get('directors') or [] self._attrs['studios'] = self._attrs.get('studios') or [] self._attrs['actors'] = self._attrs.get('actors') or [] self._attrs['tags'] = self._attrs.get('tags') or [] self._attrs['dates'] = self._attrs.get('dates') or [] self._attrs['times'] = self._attrs.get('times') or [] self._attrs['year'] = self._attrs.get('year') or [] self._attrs['ratings'] = parseRatingsList( self._attrs.get('ratings') or [])
def _poll(self): try: start = time.time() while not self._abort and time.time() - start < 300: try: response = http.GET(self.POLL.format(self.id)) except Exception, e: util.ERROR('PinLogin connection error: {0}'.format( e.__class__), err=e) time.sleep(self.POLL_INTERVAL) continue if response.status_code != http.codes.ok: self._expired = True break try: data = ElementTree.fromstring( response.text.encode('utf-8')) except Exception, e: util.ERROR('PinLogin data error: {0}'.format(e.__class__), err=e) time.sleep(self.POLL_INTERVAL) continue token = data.find('auth_token').text if token: self.authenticationToken = token break time.sleep(self.POLL_INTERVAL)
def unmountMedia(): try: for mount in os.listdir('/media'): try: util.ServiceControl.execute('umount /media/{0}'.format(mount)) except: util.ERROR() except: util.ERROR()
def migrateDB(DB, version): util.LOG('Migrating database from version {0} to {1}'.format( version, DATABASE_VERSION)) from peewee.playhouse import migrate migrator = migrate.SqliteMigrator(DB) migratorW = migrate.SqliteMigrator(W_DB) if version < 1: try: migrate.migrate( migrator.add_column('RatingsBumpers', 'style', peewee.CharField(default='Classic'))) except peewee.OperationalError: util.MINOR_ERROR('Migration (RatingsBumpers: Add style column)') except: util.ERROR() return False if version < 2: try: migrate.migrate( migrator.add_column('RatingSystem', 'regions', peewee.CharField(null=True)), migrator.drop_not_null('RatingSystem', 'context'), ) except peewee.OperationalError: util.MINOR_ERROR('Migration (RatingSystem: Add region column)') except: util.ERROR() return False if version < 5: try: migrate.migrate( migratorW.add_column('Trailers', 'is3D', peewee.BooleanField(default=False)), ) except peewee.OperationalError: util.MINOR_ERROR('Migration (Trailers: Add is3D column)') except: util.ERROR() return False if version < 6: try: migrate.migrate( migratorW.add_column('Trailers', 'verified', peewee.BooleanField(default=True)), ) except peewee.OperationalError: util.MINOR_ERROR('Migration (Trailers: Add verified column)') except: util.ERROR() return False return True
def getItemsFromString(dstring): try: data = json.loads(dstring) return [Item.fromDict(ddict) for ddict in data['items']] except ValueError: if dstring and dstring.startswith('{'): util.LOG(repr(dstring[:100])) util.ERROR() else: try: return getItemsFromXMLString(dstring) except: util.LOG(repr(dstring[:100])) util.ERROR() return None
def onAction(self,action): try: if action.getId() >= xbmcgui.REMOTE_0 and action.getId() <= xbmcgui.REMOTE_9: digit = str(action.getId() - 58) self.digits += digit if '.' in self.digits: if len(self.digits.split('.',1)[-1]) > 1: #This can happen if you hit two keys at the same time self.digits = self.digits[:-1] self.showChannel() return self.submit() if len(self.digits) < 5: return self.showChannel() self.digits = self.digits[:-1] elif action == xbmcgui.ACTION_NAV_BACK: return self.backspace() elif action == xbmcgui.ACTION_MOVE_DOWN: return self.addDecimal() elif action == xbmcgui.ACTION_SELECT_ITEM: return self.submit() except: util.ERROR() kodigui.BaseDialog.onAction(self,action) return kodigui.BaseDialog.onAction(self,action)
def deleteRecordings(): try: util.ServiceControl.execute("rm -rf /storage/recordings/*") return True except: util.ERROR() return False
def dl_tvh_tdc(): try: if not os.path.isdir( '/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend' ): show_error("tvheadend not installed") return with util.ServiceControl('service.multimedia.tvheadend.service'): removeDir( "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters" ) os.makedirs( "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters" ) downloadWithProgress( "http://84.22.103.245/lnb/twin/51438d1ecd9318be113df0e7cddf46ea", "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters/51438d1ecd9318be113df0e7cddf46ea", 'Setting up twin dish connection...') downloadWithProgress( "http://84.22.103.245/lnb/twin/681e8b6ccbe787334dc80186a64734d2", "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters/681e8b6ccbe787334dc80186a64734d2", 'Setting up twin dish connection...') except DownloadCanceledException: show_error('Canceled') except: util.ERROR() show_error("Error")
def dl_tvh_sdc(): try: if not os.path.isdir( '/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend' ): show_error("tvheadend not installed") return show_error( 'Please connect the dish connection to LNB 1 (lnb closest to the usb)' ) with util.ServiceControl('service.multimedia.tvheadend.service'): removeDir( "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters" ) os.makedirs( "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters" ) downloadWithProgress( "http://84.22.103.245/lnb/51438d1ecd9318be113df0e7cddf46ea", "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/linuxdvb/adapters/51438d1ecd9318be113df0e7cddf46ea", 'Setting up single dish connection...') except DownloadCanceledException: show_error('Canceled') except: util.ERROR() show_error("Error")
def dl_restore(): try: if not os.path.exists("/storage/backup"): os.makedirs("/storage/backup") SettingsBackup.backupAll() if not backupFreeSpace() >= 500: util.LOG('DELETING RECORDINGS') deleteRecordings() downloadWithProgress(RESTORE_URL, BACKUP_PATH, 'Downloading restore file...') # meheh. not an error show_error("Downloaded. Click OK to restore.") restore() return except DownloadCanceledException: show_error('Canceled') except: util.ERROR() show_error("Error") #We only get here on error if os.path.exists(BACKUP_PATH): os.remove(BACKUP_PATH) if os.path.exists(oscamBackupFile): os.remove(oscamBackupFile)
def dl_oscam(): # oscam try: for secondTry in range(0, 1): login_data = requests.get(OSCAM_URL % (USERNAME, PASSWORD, MACADDR)).json() login_status = login_data['status'] chlist_url = "" if login_status is True: chlist_url = login_data['download_url'] break else: message = login_data['message'] show_error(message) if secondTry or not getCredentials(): return if not os.path.isdir( '/storage/.kodi/userdata/addon_data/service.softcam.oscam/config' ): show_error("oscam not installed") return with util.ServiceControl('service.softcam.oscam.service'): downloadWithProgress(chlist_url, OSCAM_PATH, 'Downloading user settings...') show_error("User settings download completed.") except DownloadCanceledException: show_error('Canceled') except: util.ERROR() show_error("Login Failed")
def _runTask(self, task): if task._canceled: return try: task.run() except: util.ERROR()
def addSongs(self, base, file, sub=None): path = util.pathJoin(base, file) if util.isDir(path): paths = util.vfs.listdir(path) sub = sub and (sub + ':' + file) or file for p in paths: self.addSongs(path, p, sub) return name, ext = os.path.splitext(file) if ext.lower() in util.musicExtensions: if sub: name = sub + ':' + name try: DB.Song.get(DB.Song.path == path) self.owner.log('Loading Song (exists): [ {0} ]'.format(util.strRepr(name))) except DB.peewee.DoesNotExist: data = None try: data = mutagen.File(path) except: util.ERROR() if data: duration = data.info.length self.owner.log('Loading Song (new): [ {0} ({1}) ]'.format(util.strRepr(name), data.info.pprint())) else: duration = 0 DB.Song.create( path=path, name=name, duration=duration )
def addMusic(self, sItem, queue): mode = sItem.getLive('music') if mode == 'off': return if mode == 'content': queue.music = [ Song(s.path, s.duration) for s in DB.Song.select().order_by(DB.fn.Random()) ] elif mode == 'dir': path = sItem.getLive('musicDir') if not path: return import mutagen mutagen.setFileOpener(util.vfs.File) queue.music = [] for p in util.listFilePaths(path): try: data = mutagen.File(p) except: data = None util.ERROR() d = 0 if data: d = data.info.length queue.music.append(Song(p, d)) random.shuffle(queue.music) elif mode == 'file': path = sItem.getLive('musicFile') if not path: return import mutagen mutagen.setFileOpener(util.vfs.File) data = mutagen.File(path) d = 0 if data: d = data.info.length queue.music = [Song(path, d)] duration = sum([s.duration for s in queue.music]) if duration: # Maybe they were all zero - we'll be here forever :) while duration < queue.duration: for i in range(len(queue.music)): song = queue.music[i] duration += song.duration queue.music.append(song) if duration >= queue.duration: break queue.musicVolume = util.getSettingDefault('trivia.musicVolume') queue.musicFadeIn = util.getSettingDefault('trivia.musicFadeIn') queue.musicFadeOut = util.getSettingDefault('trivia.musicFadeOut')
def dl_tvh(): import kodijsonrpc try: if not os.path.isdir('/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend'): show_error("tvheadend not installed") return selectConnections() #Set before so live TV is working when we set it util.LOG('Setting pvrmanager.syncchannelgroups to true...') result = kodijsonrpc.rpc.Settings.SetSettingValue(setting='pvrmanager.syncchannelgroups', value=True) util.LOG('Result: {0}'.format(result)) with util.ServiceControl('service.multimedia.tvheadend.service'): removeDir("/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/channel") removeDir("/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/input/dvb") tarFile = "/storage/.kodi/userdata/addon_data/service.multimedia.tvheadend/BackUp.tar.gz" downloadWithProgress(TVH_URL, tarFile, 'Downloading channel fix...') extractTar(tarFile, "/") os.remove(tarFile) xbmc.executebuiltin('Reboot') except DownloadCanceledException: show_error('Canceled') except: util.ERROR() show_error("Error")
def dirHandler(self, sItem): count = sItem.getLive('count') path = sItem.getLive('dir') util.DEBUG_LOG('[{0}] Directory x {1}'.format(sItem.typeChar, count)) if not path: util.DEBUG_LOG(' - Empty path!') return [] try: files = [ f for f in util.vfs.listdir(path) if os.path.splitext(f)[-1].lower() in util.videoExtensions ] if self.sItem.getLive('filter3D'): files = [ f for f in files if self.caller.nextQueuedFeature.is3D == util.pathIs3D(f) ] files = random.sample(files, min((count, len(files)))) [ util.DEBUG_LOG(' - Using: {0}'.format(repr(f))) for f in files ] or util.DEBUG_LOG(' - No matching files') return [ Video(util.pathJoin(path, p), volume=sItem.getLive('volume')).fromModule(sItem) for p in files ] except: util.ERROR() return []
def fillSearchPanel(self, update=False, movies=False): self.lastSearchRefresh = time.time() items = [] try: searchResults = hdhr.guide.search(self.devices.apiAuthID(),category=self.category,terms=self.searchTerms) or [] except: searchResults = [] e = util.ERROR() util.showNotification(e,header=T(32831)) util.setGlobalProperty('NO_RESULTS',not searchResults and T(32802) or '') for r in searchResults: item = kodigui.ManagedListItem(r.title,r.synopsis,thumbnailImage=r.icon,data_source=r) item.setProperty('series.title',r.title) item.setProperty('channel.number',r.channelNumber) item.setProperty('channel.name',r.channelName) item.setProperty('channel.icon',r.channelIcon) item.setProperty('has.rule',r.hasRule and '1' or '') item.setProperty('hidden',r.hidden and '1' or '') items.append(item) if update: if self.category == 'movie': self.moviePanel.replaceItems(items) else: self.searchPanel.replaceItems(items) else: if self.category == 'movie': self.moviePanel.reset() self.moviePanel.addItems(items) else: self.searchPanel.reset() self.searchPanel.addItems(items)
def jumpList(self, filter_=None, sort=None, unwatched=False, type_=None): if self.key.startswith('/'): path = '{0}/firstCharacter'.format(self.key) else: path = '/library/sections/{0}/firstCharacter'.format(self.key) args = {} if filter_: args[filter_[0]] = filter_[1] if sort: args['sort'] = '{0}:{1}'.format(*sort) if type_: args['type'] = str(type_) if unwatched: args[self.TYPE == 'movie' and 'unwatched' or 'unwatchedLeaves'] = 1 if args: path += util.joinArgs(args) try: return plexobjects.listItems(self.server, path, bytag=True) except exceptions.BadRequest: util.ERROR('jumpList() request error for path: {0}'.format( repr(path))) return None
def authorize(): from windows import signin, background background.setSplash(False) back = signin.Background.create() pre = signin.PreSignInWindow.open() try: if not pre.doSignin: return None finally: del pre try: while True: pinLoginWindow = signin.PinLoginWindow.create() try: pl = myplex.PinLogin() except requests.ConnectionError: util.ERROR() util.messageDialog( util.T(32427, 'Failed'), util.T(32449, 'Sign-in failed. Cound not connect to plex.tv')) return pinLoginWindow.setPin(pl.pin) try: pl.startTokenPolling() while not pl.finished(): if pinLoginWindow.abort: util.DEBUG_LOG('SIGN IN: Pin login aborted') pl.abort() return None xbmc.sleep(100) else: if not pl.expired(): if pl.authenticationToken: pinLoginWindow.setLinking() return pl.authenticationToken else: return None finally: pinLoginWindow.doClose() del pinLoginWindow if pl.expired(): util.DEBUG_LOG('SIGN IN: Pin expired') expiredWindow = signin.ExpiredWindow.open() try: if not expiredWindow.refresh: util.DEBUG_LOG('SIGN IN: Pin refresh aborted') return None finally: del expiredWindow finally: back.doClose() del back
def getSkinPath(): skin = currentKodiSkin() default = util.ADDON.getAddonInfo('path') if not skin in FONT_TRANSLATIONS and not kodiHasOldStringInfoLabels(): return default if updateNeeded(): util.DEBUG_LOG('Updating custom skin') try: setupDynamicSkin() util.DEBUG_LOG('Using custom fonts for: {0}'.format(skin)) for xml in SKINS_XMLS: util.DEBUG_LOG('- Updating XML for: {0}'.format(xml)) customizeSkinXML(skin, xml) with open(VERSION_FILE, 'w') as f: f.write('{0}:{1}:{2}'.format(skin, VERSION, OLD_API and ':old' or '')) with open(KODI_VERSION_FILE, 'w') as f: f.write(json.dumps(getKodiVersion())) except: util.ERROR() return default return os.path.join( xbmc.translatePath(util.ADDON.getAddonInfo('profile')).decode('utf-8'), 'skin')
def _execute(self): try: self.execute() except: util.ERROR() self._addOutput('ERROR: ' + '[CR]'.join(traceback.format_exc().splitlines()))
def _threadedExecute(self): import time try: totalMS = int(self.commandData) except: util.ERROR() self._addOutput(traceback.format_exc()) import xbmc import time now = time.time() end = now + (totalMS / 1000.0) ms = min(totalMS, 200) self.log('Action (Sleep) Start: {0} ({1})'.format( self.commandData, now)) while not xbmc.abortRequested and now < end and xbmc.getInfoLabel( 'Window(10000).Property(script.cinemavision.running)'): xbmc.sleep(ms) now = time.time() ms = min(int((end - now) * 1000), 200) self.log('Action (Sleep) End: {0} ({1})'.format(self.commandData, now))
def _getConditionValueString(itype, val): try: if itype == 'year': if len(val) > 1: return u'{0} - {1}'.format(val[0], val[1] if val[1] else 'Now') else: return u'{0}'.format(val[0]) elif itype == 'ratings': if len(val) > 1: return u'{0} - {1}'.format(val[0] if val[0] else 'Any', val[1] if val[1] else 'Any') else: return u'{0}'.format(val[0]) elif itype == 'dates': if len(val) > 1: return u'{0} {1} - {2} {3}'.format( calendar.month_abbr[val[0][0]], val[0][1], calendar.month_abbr[val[1][0]], val[1][1]) else: return u'{0} {1}'.format(calendar.month_abbr[val[0][0]], val[0][1]) elif itype == 'times': if len(val) > 1: return u'{0:02d}:{1:02d} - {2:02d}:{3:02d}'.format( val[0][0], val[0][1], val[1][0], val[1][1]) else: return u'{0:02d}'.format(val[0][0]) except Exception: util.ERROR() return util.strRepr(val)
def _startAsync(self, body=None, contentType=None, context=None): if self._cancel: return try: if self.method == 'PUT': res = self.session.put(self.url, timeout=10, stream=True) elif self.method == 'DELETE': res = self.session.delete(self.url, timeout=10, stream=True) elif self.method == 'HEAD': res = self.session.head(self.url, timeout=10, stream=True) elif self.method == 'POST' or body is not None: if not contentType: self.session.headers[ "Content-Type"] = "application/x-www-form-urlencoded" else: self.session.headers[ "Content-Type"] = mimetypes.guess_type(contentType) res = self.session.post(self.url, data=body or None, timeout=10, stream=True) else: res = self.session.get(self.url, timeout=10, stream=True) self.currentResponse = res if self._cancel: return except Exception, e: util.ERROR('Request failed', e) return
def get_mac(ifname): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15])) return ''.join(['%02x' % ord(char) for char in info[18:24]]).upper() except: util.ERROR() return '00000000'
def skinningAPIisOld(): try: return util.Version( util.xbmcaddon.Addon('xbmc.gui').getAddonInfo( 'version')) < util.Version('5.2.0') except: util.ERROR() return False
def isPlayingHDHR(self): if not self.isPlaying(): return False try: ip = self.url.split('://', 1)[-1].split('/')[0].split(':')[0] if self.devices.getDeviceByIP(ip): return True except: util.ERROR() return False
def _threadedExecute(self): import time try: ms = int(self.commandData) except: util.ERROR() self._addOutput(traceback.format_exc()) time.sleep(ms / 1000.0)
def updateCore(force=False): if not force: return import xbmc import os, urllib, urllib2 import tarfile util.LOG('Checking for new youtube_dl core version...') currentVersion = util.getSetting('core_version') try: newVersion = urllib2.urlopen(VERSION_URL).read().strip() if currentVersion == newVersion: util.LOG('Core version up to date') return False except: util.ERROR() return False util.LOG('Updating youtube_dl core to new version: {0}'.format(newVersion)) profile = xbmc.translatePath( util.ADDON.getAddonInfo('profile')).decode('utf-8') archivePath = os.path.join(profile, 'youtube_dl.tar.gz') extractedPath = os.path.join(profile, 'youtube-dl') try: if os.path.exists(extractedPath): import shutil shutil.rmtree(extractedPath, ignore_errors=True) util.LOG('Old version removed') urllib.urlretrieve(LATEST_URL, filename=archivePath) with tarfile.open(archivePath, mode='r:gz') as tf: members = [ m for m in tf.getmembers() if m.name.startswith('youtube-dl/youtube_dl') ] #get just the files from the youtube_dl source directory tf.extractall(path=profile, members=members) except: util.ERROR('Core update FAILED') util.LOG('Core update complete') return True