def _addDirectory(self, current, tree): if not util.vfs.exists(current): util.DEBUG_LOG('Creating: {0}'.format(repr(current))) util.vfs.mkdirs(current) for branch in tree: if isinstance(branch, tuple): new = util.pathJoin(current, branch[0]) self._addDirectory(new, branch[1]) else: sub = util.pathJoin(current, branch) if util.vfs.exists(sub): continue util.DEBUG_LOG('Creating: {0}'.format(util.strRepr(sub))) util.vfs.mkdirs(sub)
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 getSlide(self, path, c, pack=''): name, ext = os.path.splitext(c) duration = 0 path = util.pathJoin(path, c) try: DB.Trivia.get(DB.Trivia.answerPath == path) self._callback('Loading Trivia (exists): [ {0} ]'.format(util.strRepr(name))) except DB.peewee.DoesNotExist: if ext.lower() in util.videoExtensions: ttype = 'video' parser = hachoir.hachoir_parser.createParser(path) metadata = hachoir.hachoir_metadata.extractMetadata(parser) durationDT = None if metadata: durationDT = metadata.get('duration') duration = durationDT and util.datetimeTotalSeconds(durationDT) or 0 self._callback('Loading Trivia (video): [ {0} ({1}) ]'.format(util.strRepr(name), durationDT)) elif ext.lower() in util.imageExtensions: ttype = 'fact' self._callback('Loading Trivia (single): [ {0} ]'.format(util.strRepr(name))) else: return DB.Trivia.get_or_create( answerPath=path, defaults={ 'type': ttype, 'TID': u'{0}:{1}'.format(pack, name), 'name': name, 'duration': duration } )
def _fixTriviaSlidesDir(self): ts = util.pathJoin(self._contentDirectory, 'Trivia Slides' + util.getSep(self._contentDirectory)) util.DEBUG_LOG('Checking for the existence of {0}'.format(util.strRepr(ts))) if not util.vfs.exists(ts): util.DEBUG_LOG("No 'Trivia Slides' directory exists") return t = util.pathJoin(self._contentDirectory, 'Trivia') success = True if util.vfs.exists(t): success = util.vfs.rmdir(t) if success: success = util.vfs.rename(ts, t) else: util.DEBUG_LOG("Failed to remove existing 'Trivia' directory") if success: util.DEBUG_LOG("Renamed 'Trivia Slides' to 'Trivia'") else: util.DEBUG_LOG('Failed to rename {0} to {1}'.format(util.strRepr(ts), util.strRepr(t)))
def createBumpers(self, basePath, model, type_name, sub_name, pct_start, sub_default=''): paths = util.vfs.listdir(basePath) total = float(len(paths)) for ct, sub in enumerate(paths): pct = pct_start + int((ct/total)*20) if not self._callback(pct=pct): break path = util.pathJoin(basePath, sub) if not util.isDir(path): continue if sub.startswith('_Exclude'): util.DEBUG_LOG('SKIPPING EXCLUDED DIR: {0}'.format(util.strRepr(sub))) continue if util.vfs.exists(util.pathJoin(path, 'system.xml')): # For ratings self.loadRatingSystem(util.pathJoin(path, 'system.xml')) type_ = sub.replace(' Bumpers', '') self.addBumper(model, sub, path, type_name, sub_name, type_, sub_default)
def dir(self, sItem): if not sItem.dir: return [] try: files = util.vfs.listdir(sItem.dir) if sItem.random: files = random.sample(files, min((sItem.count, len(files)))) else: files = files[:sItem.count] return [Video(util.pathJoin(sItem.dir, p), volume=sItem.getLive('volume')).fromModule(sItem) for p in files] except: util.ERROR() return []
def addBumper(self, model, sub, path, type_name, sub_name, type_, sub_default, sub_val=None, prefix=None): for v in util.vfs.listdir(path): vpath = util.pathJoin(path, v) if util.isDir(vpath): if sub_name: if not sub_val: self.addBumper(model, sub, vpath, type_name, sub_name, type_, sub_default, v) else: self.addBumper(model, sub, vpath, type_name, sub_name, type_, sub_default, prefix=v) continue name, ext = os.path.splitext(v) is3D = '3D' in name if is3D and type_name == 'system': # Remove tags from rating bumpers name = re.sub(CONTENT_3D_RE, '', name).strip() isImage = False if ext in util.videoExtensions: isImage = False elif ext in util.imageExtensions: isImage = True else: continue name = prefix and (prefix + ':' + name) or name defaults = { type_name: TYPE_IDS.get(type_, type_), 'name': name, 'is3D': is3D, 'isImage': isImage } if sub_name: sub_val = sub_val or sub_default defaults[sub_name] = sub_val self.log('Loading {0} ({1} - {2}): [ {3}{4} ]'.format(model.__name__, util.strRepr(sub), sub_val, util.strRepr(name), is3D and ': 3D' or '')) else: self.log('Loading {0} ({1}): [ {2}{3} ]'.format(model.__name__, util.strRepr(sub), util.strRepr(name), is3D and ': 3D' or '')) model.get_or_create( path=vpath, defaults=defaults )
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 loadTrivia(self): self.logHeading('LOADING TRIVIA') basePath = util.pathJoin(self._contentDirectory, 'Trivia') paths = util.vfs.listdir(basePath) total = float(len(paths)) for ct, sub in enumerate(paths): pct = 20 + int((ct/total)*20) if not self._callback(pct=pct): break path = os.path.join(basePath, sub) if util.isDir(path): if sub.startswith('_Exclude'): util.DEBUG_LOG('SKIPPING EXCLUDED DIR: {0}'.format(util.strRepr(sub))) continue else: continue self.log('Processing trivia: {0}'.format(util.strRepr(os.path.basename(path)))) self.triviaDirectoryHandler(path, prefix=sub)
def __call__(self, basePath, prefix=None): hasSlidesXML = False slideXML = util.pathJoin(basePath, self._formatXML) if util.vfs.exists(slideXML): hasSlidesXML = True # pack = os.path.basename(basePath.rstrip('\\/')) xml = None slide = None if hasSlidesXML: try: f = util.vfs.File(slideXML, 'r') xml = f.read() finally: f.close() try: slides = ET.fromstring(xml) slide = slides.find('slide') except ET.ParseError: util.DEBUG_LOG('Bad slides.xml') except: util.ERROR() slide = None if slide: rating = self.getNodeAttribute(slide, self._ratingNA[0], self._ratingNA[1]) or '' questionRE = (self.getNodeAttribute(slide, self._questionNA[0], self._questionNA[1]) or '').replace('N/A', '') clueRE = self.getNodeAttribute(slide, self._clueNA[0], self._clueNA[1]) or ''.replace('N/A', '') answerRE = self.getNodeAttribute(slide, self._answerNA[0], self._answerNA[1]) or ''.replace('N/A', '') else: rating = '' questionRE = self._defaultQRegEx clueRE = self._defaultCRegEx answerRE = self._defaultARegEx contents = util.vfs.listdir(basePath) trivia = {} for c in contents: path = util.pathJoin(basePath, c) if util.isDir(path): self(path, prefix=prefix and (prefix + ':' + c) or c) continue base, ext = os.path.splitext(c) if not ext.lower() in util.imageExtensions: if ext.lower() in util.videoExtensions: self.getSlide(basePath, c, prefix) continue ttype = '' clueCount = 0 if re.search(questionRE, c): name = re.split(questionRE, c)[0] ttype = 'q' elif re.search(answerRE, c): name = re.split(answerRE, c)[0] ttype = 'a' elif re.search(clueRE, c): name = re.split(clueRE, c)[0] try: clueCount = re.search(clueRE, c).group(1) except: pass ttype = 'c' else: # A still name, ext = os.path.splitext(c) # name = re.split(clueRE, c)[0] ttype = 'a' if name not in trivia: trivia[name] = {'q': None, 'c': {}, 'a': None} if ttype == 'q' or ttype == 'a': trivia[name][ttype] = path elif ttype == 'c': trivia[name]['c'][clueCount] = path for name, data in trivia.items(): questionPath = data['q'] answerPath = data['a'] if not answerPath: continue if questionPath: ttype = 'QA' self._callback('Loading Trivia(QA): [ {0} ]'.format(util.strRepr(name))) else: ttype = 'fact' self._callback('Loading Trivia(single): [ {0} ]'.format(util.strRepr(name))) defaults = { 'type': ttype, 'TID': u'{0}:{1}'.format(prefix, name), 'name': name, 'rating': rating, 'questionPath': questionPath } for ct, key in enumerate(sorted(data['c'].keys())): defaults['cluePath{0}'.format(ct)] = data['c'][key] try: DB.Trivia.get_or_create( answerPath=answerPath, defaults=defaults ) except: print repr(data) util.ERROR()
def loadRatingsBumpers(self): self.logHeading('LOADING RATINGS BUMPERS') basePath = util.pathJoin(self._contentDirectory, 'Ratings Bumpers') self.createBumpers(basePath, DB.RatingsBumpers, 'system', 'style', 80, sub_default='Classic')
def loadVideoBumpers(self): self.logHeading('LOADING VIDEO BUMPERS') basePath = util.pathJoin(self._contentDirectory, 'Video Bumpers') self.createBumpers(basePath, DB.VideoBumpers, 'type', None, 60)
def loadMusic(self): self.logHeading('LOADING MUSIC') self.musicHandler(util.pathJoin(self._contentDirectory, 'Music'))
def initialize(path=None, callback=None): callback = callback or dummyCallback callback(None, 'Creating/updating database...') global DB global W_DB global DBVersion global Song global Trivia global AudioFormatBumpers global RatingsBumpers global VideoBumpers global RatingSystem global Rating global Trailers global WatchedTrivia ########################################################################################### # Version ########################################################################################### dbDir = path or util.STORAGE_PATH if not util.vfs.exists(dbDir): util.vfs.mkdirs(dbDir) dbPath = util.pathJoin(dbDir, 'content.db') dbExists = util.vfs.exists(dbPath) DB = peewee.SqliteDatabase(dbPath) W_DB = peewee.SqliteDatabase(util.pathJoin(path or util.STORAGE_PATH, 'watched.db')) DB.connect() class DBVersion(peewee.Model): version = peewee.IntegerField(default=0) class Meta: database = DB DBVersion.create_table(fail_silently=True) if dbExists: # Only check version if we had a DB, otherwise we're creating it fresh checkDBVersion(DB) ########################################################################################### # Content ########################################################################################### class ContentBase(peewee.Model): name = peewee.CharField() accessed = peewee.DateTimeField(null=True) pack = peewee.TextField(null=True) class Meta: database = DB callback(' - Music') class Song(ContentBase): rating = peewee.CharField(null=True) genre = peewee.CharField(null=True) year = peewee.CharField(null=True) path = peewee.CharField(unique=True) duration = peewee.FloatField(default=0) Song.create_table(fail_silently=True) callback(' - Tivia') class Trivia(ContentBase): type = peewee.CharField() TID = peewee.CharField(unique=True) rating = peewee.CharField(null=True) genre = peewee.CharField(null=True) year = peewee.CharField(null=True) duration = peewee.FloatField(default=0) questionPath = peewee.CharField(unique=True, null=True) cluePath0 = peewee.CharField(unique=True, null=True) cluePath1 = peewee.CharField(unique=True, null=True) cluePath2 = peewee.CharField(unique=True, null=True) cluePath3 = peewee.CharField(unique=True, null=True) cluePath4 = peewee.CharField(unique=True, null=True) cluePath5 = peewee.CharField(unique=True, null=True) cluePath6 = peewee.CharField(unique=True, null=True) cluePath7 = peewee.CharField(unique=True, null=True) cluePath8 = peewee.CharField(unique=True, null=True) cluePath9 = peewee.CharField(unique=True, null=True) answerPath = peewee.CharField(unique=True, null=True) Trivia.create_table(fail_silently=True) callback(' - AudioFormatBumpers') class BumperBase(ContentBase): is3D = peewee.BooleanField(default=False) isImage = peewee.BooleanField(default=False) path = peewee.CharField(unique=True) class AudioFormatBumpers(BumperBase): format = peewee.CharField() AudioFormatBumpers.create_table(fail_silently=True) callback(' - RatingsBumpers') class RatingsBumpers(BumperBase): system = peewee.CharField(default='MPAA') style = peewee.CharField(default='Classic') RatingsBumpers.create_table(fail_silently=True) callback(' - VideoBumpers') class VideoBumpers(BumperBase): type = peewee.CharField() rating = peewee.CharField(null=True) genre = peewee.CharField(null=True) year = peewee.CharField(null=True) VideoBumpers.create_table(fail_silently=True) ########################################################################################### # Ratings ########################################################################################### class RatingSystem(peewee.Model): name = peewee.CharField() context = peewee.CharField(null=True) regEx = peewee.CharField() regions = peewee.CharField(null=True) class Meta: database = DB RatingSystem.create_table(fail_silently=True) class Rating(peewee.Model): name = peewee.CharField(unique=True) internal = peewee.CharField() value = peewee.IntegerField(default=0) system = peewee.CharField() class Meta: database = DB Rating.create_table(fail_silently=True) ########################################################################################### # Watched Database ########################################################################################### class WatchedBase(peewee.Model): WID = peewee.CharField(unique=True) watched = peewee.BooleanField(default=False) date = peewee.DateTimeField(default=datetime.date(1900, 1, 1)) class Meta: database = W_DB class Trailers(WatchedBase): source = peewee.CharField() rating = peewee.CharField(null=True) genres = peewee.CharField(null=True) title = peewee.CharField() release = peewee.DateTimeField(default=datetime.date(1900, 1, 1)) url = peewee.CharField(null=True) userAgent = peewee.CharField(null=True) thumb = peewee.CharField(null=True) broken = peewee.BooleanField(default=False) is3D = peewee.BooleanField(default=False) verified = peewee.BooleanField(default=True) Trailers.create_table(fail_silently=True) callback(' - Trailers') class WatchedTrivia(WatchedBase): pass WatchedTrivia.create_table(fail_silently=True) callback(' - Trivia (watched status)') callback(None, 'Database created') DB.close()
def __call__(self, basePath, prefix=None): hasSlidesXML = False slideXML = util.pathJoin(basePath, self._formatXML) if util.vfs.exists(slideXML): hasSlidesXML = True # pack = os.path.basename(basePath.rstrip('\\/')) xml = None slide = None if hasSlidesXML: try: f = util.vfs.File(slideXML, 'r') xml = f.read() finally: f.close() try: slides = ET.fromstring(xml) slide = slides.find('slide') except ET.ParseError: util.DEBUG_LOG('Bad slides.xml') except: util.ERROR() slide = None if slide: rating = self.getNodeAttribute(slide, self._ratingNA[0], self._ratingNA[1]) or '' questionRE = (self.getNodeAttribute(slide, self._questionNA[0], self._questionNA[1]) or '').replace('N/A', '') clueRE = self.getNodeAttribute(slide, self._clueNA[0], self._clueNA[1]) or ''.replace( 'N/A', '') answerRE = self.getNodeAttribute(slide, self._answerNA[0], self._answerNA[1]) or ''.replace( 'N/A', '') else: rating = '' questionRE = self._defaultQRegEx clueRE = self._defaultCRegEx answerRE = self._defaultARegEx contents = util.vfs.listdir(basePath) trivia = {} for c in contents: path = util.pathJoin(basePath, c) if util.isDir(path): self(path, prefix=prefix and (prefix + ':' + c) or c) continue base, ext = os.path.splitext(c) if not ext.lower() in util.imageExtensions: if ext.lower() in util.videoExtensions: self.getSlide(basePath, c, prefix) continue ttype = '' clueCount = 0 if re.search(questionRE, c): name = re.split(questionRE, c)[0] ttype = 'q' elif re.search(answerRE, c): name = re.split(answerRE, c)[0] ttype = 'a' elif re.search(clueRE, c): name = re.split(clueRE, c)[0] try: clueCount = re.search(clueRE, c).group(1) except: pass ttype = 'c' else: # A still name, ext = os.path.splitext(c) # name = re.split(clueRE, c)[0] ttype = 'a' if name not in trivia: trivia[name] = {'q': None, 'c': {}, 'a': None} if ttype == 'q' or ttype == 'a': trivia[name][ttype] = path elif ttype == 'c': trivia[name]['c'][clueCount] = path for name, data in trivia.items(): questionPath = data['q'] answerPath = data['a'] if not answerPath: continue if questionPath: ttype = 'QA' self._callback('Loading Trivia(QA): [ {0} ]'.format( util.strRepr(name))) else: ttype = 'fact' self._callback('Loading Trivia(single): [ {0} ]'.format( util.strRepr(name))) defaults = { 'type': ttype, 'TID': u'{0}:{1}'.format(prefix, name), 'name': name, 'rating': rating, 'questionPath': questionPath } for ct, key in enumerate(sorted(data['c'].keys())): defaults['cluePath{0}'.format(ct)] = data['c'][key] try: DB.Trivia.get_or_create(answerPath=answerPath, defaults=defaults) except: print repr(data) util.ERROR()
def addBumper(self, model, sub, path, type_name, sub_name, type_, sub_default, sub_val=None, prefix=None): for v in util.vfs.listdir(path): vpath = util.pathJoin(path, v) if util.isDir(vpath): if sub_name: if not sub_val: self.addBumper(model, sub, vpath, type_name, sub_name, type_, sub_default, v) else: self.addBumper(model, sub, vpath, type_name, sub_name, type_, sub_default, prefix=v) continue name, ext = os.path.splitext(v) is3D = '3D' in name if is3D and type_name == 'system': # Remove tags from rating bumpers name = re.sub(CONTENT_3D_RE, '', name).strip() isImage = False if ext in util.videoExtensions: isImage = False elif ext in util.imageExtensions: isImage = True else: continue name = prefix and (prefix + ':' + name) or name defaults = { type_name: TYPE_IDS.get(type_, type_), 'name': name, 'is3D': is3D, 'isImage': isImage } if sub_name: sub_val = sub_val or sub_default defaults[sub_name] = sub_val self.log('Loading {0} ({1} - {2}): [ {3}{4} ]'.format( model.__name__, util.strRepr(sub), sub_val, util.strRepr(name), is3D and ': 3D' or '')) else: self.log('Loading {0} ({1}): [ {2}{3} ]'.format( model.__name__, util.strRepr(sub), util.strRepr(name), is3D and ': 3D' or '')) model.get_or_create(path=vpath, defaults=defaults)
def loadAudioFormatBumpers(self): self.logHeading('LOADING AUDIO FORMAT BUMPERS') basePath = util.pathJoin(self._contentDirectory, 'Audio Format Bumpers') self.createBumpers(basePath, DB.AudioFormatBumpers, 'format', None, 40)