def build(self): """ Build the playlist. Create a list of items and filenames. This function will load the playlist file or expand directories """ if self.suffixlist: # we called this function before return playlist = self.playlist self.playlist = [] for p in plugin.mimetype(self.display_type): #if self.display_type in p.display_type: # XXX self.display_type seems to be set to None # XXX Which prevents the str->Item from occuring # XXX This is a short-term fix I guess self.suffixlist += p.suffix() self.get_plugins.append(p) if isstring(playlist): # it's a filename with a playlist try: f=open(playlist, "r") line = f.readline() f.close if line.find("[playlist]") > -1: self.read_pls(playlist) elif line.find("[Slides]") > -1: self.read_ssr(playlist) else: self.read_m3u(playlist) except (OSError, IOError), e: print 'playlist error: %s' % e self.set_url(playlist)
def __init__(self, item, rescan=False): self.artist = '' self.album = '' self.year = '' self.length = 0 item.build() songs = [] for i in item.playlist: if not callable(i): for p in plugin.mimetype('audio'): songs += p.get(None, [ i ]) else: songs.append(i) for song in songs: if not hasattr(song, 'filename'): continue try: data = mediainfo.get(song.filename) for type in ('artist', 'album'): setattr(self, type, self.strcmp(getattr(self, type), data[type])) self.year = self.strcmp(self.year, data['userdate']) if data['length']: self.length += int(data['length']) except OSError: pass if not self.length: return for type in ('artist', 'album', 'year', 'length'): if getattr(self, type): mediainfo.set(item.filename, type, getattr(self, type))
def create_metainfo(self): """ create some metainfo for the directory """ display_type = self.display_type if self.display_type == 'tv': display_type = 'video' name = display_type or 'all' # check autovars for var, val in self.autovars: if var == 'num_%s_timestamp' % name: break else: self.autovars += [('num_%s_timestamp' % name, 0), ('num_%s_items' % name, 0)] try: timestamp = os.stat(self.dir)[stat.ST_MTIME] except OSError: return num_timestamp = self.info['num_%s_timestamp' % name] if not num_timestamp or num_timestamp < timestamp: _debug_('create metainfo for %s', self.dir) need_umount = False if self.media: need_umount = not self.media.is_mounted() self.media.mount() num_dir_items = 0 num_play_items = 0 files = vfs.listdir(self.dir, include_overlay=True) # play items and playlists for p in plugin.mimetype(display_type): num_play_items += p.count(self, files) # normal DirItems for filename in files: if os.path.isdir(filename): num_dir_items += 1 # store info if num_play_items != self['num_%s_items' % name]: self['num_%s_items' % name] = num_play_items if self['num_dir_items'] != num_dir_items: self['num_dir_items'] = num_dir_items self['num_%s_timestamp' % name] = timestamp if need_umount: self.media.umount()
def create_metainfo(self): """ create some metainfo for the archive """ logger.log(9, 'create_metainfo()') display_type = self.display_type name = display_type or 'all' # check autovars for var, val in self.autovars: if var == 'num_%s_timestamp' % name: break else: self.autovars += [ ('num_%s_timestamp' % name, 0), ('num_%s_items' % name, 0), ('num_%s_total_items' % name, 0) ] try: timestamp = os.stat(self.dir)[stat.ST_MTIME] except OSError: return num_timestamp = self.info['num_%s_timestamp' % name] if not num_timestamp or num_timestamp < timestamp: logger.debug('Create metainfo for %s, display_type=%s', self.archive, self.display_type) if self.media: self.media.mount() num_dir_items = 0 num_play_items = 0 files = [] try: if zipfile.is_zipfile(self.archive): archive = zipfile.ZipFile(self.archive, 'r') files = archive.infolist() names = archive.namelist() elif tarfile.is_tarfile(self.archive): archive = tarfile.open(self.archive, 'r') files = archive.getmembers() names = archive.getnames() elif ARCHIVE_RAR_AVAILABLE and rarfile.is_rarfile(self.archive): archive = rarfile.RarFile(self.archive, 'r') files = archive.infolist() names = archive.namelist() except (ZipError, RarError, TarError) as exc: logger.warning('Archive %s error: %s', self.archive, exc) self.valid = False # play items and playlists for p in plugin.mimetype(display_type): num_play_items += p.count(self, names) # normal DirItems for file in files: if is_dir(file): num_dir_items += 1 # store info self['num_dir_items'] = num_dir_items self['num_%s_items' % name] = num_play_items self['num_%s_timestamp' % name] = timestamp total_play_items = DirItem.get_play_items_recursive(self, name) # some items such as archives are not walkable, hence no way to # calculate total number of playable items in the directory tree. logger.debug('self.name=%r, display_type=%r, total_play_items=%r, num_play_items=%r, num_dir_items=%r', self.name, name, total_play_items, num_play_items, num_dir_items) if total_play_items < num_play_items + num_dir_items: total_play_items = num_play_items + num_dir_items self['num_%s_total_items' % name] = total_play_items if self.media: self.media.umount()
def set_cover_image(self, dir): """ we search for images within the archive, sort the result and get the first that matches and extract it to the tmp directory """ logger.log(9, 'set_cover_image(dir=%r)', dir) cover = util.getimage(os.path.join(dir, 'cover')) if cover: # nothing to do, image already exist logger.debug('Nothing to do, archive cover already exist, skipping...') return cover files = [] images = [] try: if zipfile.is_zipfile(self.archive): archive = zipfile.ZipFile(self.archive, 'r') files = archive.namelist() elif tarfile.is_tarfile(self.archive): archive = tarfile.open(self.archive, 'r') files = archive.getnames() elif ARCHIVE_RAR_AVAILABLE and rarfile.is_rarfile(self.archive): archive = rarfile.RarFile(self.archive, 'r') files = archive.namelist() except (ZipError, RarError, TarError) as exc: logger.warning('Archive %s error: %s', self.archive, exc) self.valid = False return None if len(files): # get the image plugin matches on image files stored in the archive logger.debug('Found %d items in the archive %s', len(files), self.archive) for p in plugin.mimetype('image'): logger.debug('Found mime plugin for type \'image\', querying now...') images.extend(util.find_matches(files, p.suffix())) logger.debug('Plugin reports %d images matches the suffix rule', len(images)) if len(images): logger.debug('Found %d images in the archive %s', len(images), self.archive) excl = re.compile('cover') for image in images: if re.search(excl, image): # there is a cover image in the archive already logger.debug('Found cover image %s in the archive', images[0]) try: archive.extract(image, dir) logger.debug('Cover image %s extracted to %s', image, dir) return os.path.join(dir, image) except (ZipError, RarError, TarError) as exc: # we tried to extract the cover but there is an error, # we will try another approach later on logger.warning('Archive extract %s error: %s', self.archive, exc) # no cover image in the archive, let's try to guess which one we could use as such # extract first image on the list, most likely it'll represet # a useful cover. This is definitely the case with cbz/cbr comics covers # first, we need sort all files to make sure that we have them in sequence images.sort(lambda l, o: cmp(l.upper(), o.upper())) # just for cleaner code image = images[0] logger.debug('Found suitable cover image %s in the archive', image) try: archive.extract(image, dir) ext = os.path.splitext(image)[1].lower().replace('jpeg', 'jpg') except (ZipError, RarError, TarError) as exc: # we tried to extract the image but there was an error, we give up logger.warning('Archive %s extract error: %s', self.archive, exc) return None try: os.symlink(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext))) #shutil.copy(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext))) logger.debug('Cover image %s, copied to %s', normalize(image), dir) except (OSError, ShutilError) as exc: logger.warning('Error while getting cover image for archive %s, %s', self.archive, exc) return None return os.path.join(dir, ('cover.' + ext)) logger.debug('Unable to find a suitable cover image for archive %s', self.archive) return None
def create_metainfo(self): """ create some metainfo for the archive """ logger.log(9, 'create_metainfo()') display_type = self.display_type name = display_type or 'all' # check autovars for var, val in self.autovars: if var == 'num_%s_timestamp' % name: break else: self.autovars += [('num_%s_timestamp' % name, 0), ('num_%s_items' % name, 0)] try: timestamp = os.stat(self.dir)[stat.ST_MTIME] except OSError: return num_timestamp = self.info['num_%s_timestamp' % name] if not num_timestamp or num_timestamp < timestamp: logger.debug('Create metainfo for %s, display_type=%s', self.archive, self.display_type) if self.media: self.media.mount() num_dir_items = 0 num_play_items = 0 files = [] try: if zipfile.is_zipfile(self.archive): archive = zipfile.ZipFile(self.archive, 'r') files = archive.infolist() names = archive.namelist() elif tarfile.is_tarfile(self.archive): archive = tarfile.open(self.archive, 'r') files = archive.getmembers() names = archive.getnames() elif ARCHIVE_RAR_AVAILABLE and rarfile.is_rarfile( self.archive): archive = rarfile.RarFile(self.archive, 'r') files = archive.infolist() names = archive.namelist() except (ZipError, RarError, TarError) as exc: logger.warning('Archive %s error: %s', self.archive, exc) self.valid = False # play items and playlists for p in plugin.mimetype(display_type): num_play_items += p.count(self, names) # normal DirItems for file in files: if is_dir(file): num_dir_items += 1 # store info self['num_dir_items'] = num_dir_items self['num_%s_items' % name] = num_play_items self['num_%s_timestamp' % name] = timestamp if self.media: self.media.umount()
def set_cover_image(self, dir): """ we search for images within the archive, sort the result and get the first that matches and extract it to the tmp directory """ logger.log(9, 'set_cover_image(dir=%r)', dir) cover = util.getimage(os.path.join(dir, 'cover')) if cover: # nothing to do, image already exist logger.debug( 'Nothing to do, archive cover already exist, skipping...') return cover files = [] images = [] try: if zipfile.is_zipfile(self.archive): archive = zipfile.ZipFile(self.archive, 'r') files = archive.namelist() elif tarfile.is_tarfile(self.archive): archive = tarfile.open(self.archive, 'r') files = archive.getnames() elif ARCHIVE_RAR_AVAILABLE and rarfile.is_rarfile(self.archive): archive = rarfile.RarFile(self.archive, 'r') files = archive.namelist() except (ZipError, RarError, TarError) as exc: logger.warning('Archive %s error: %s', self.archive, exc) self.valid = False return None if len(files): # get the image plugin matches on image files stored in the archive logger.debug('Found %d items in the archive %s', len(files), self.archive) for p in plugin.mimetype('image'): logger.debug( 'Found mime plugin for type \'image\', querying now...') images.extend(util.find_matches(files, p.suffix())) logger.debug( 'Plugin reports %d images matches the suffix rule', len(images)) if len(images): logger.debug('Found %d images in the archive %s', len(images), self.archive) excl = re.compile('cover') for image in images: if re.search(excl, image): # there is a cover image in the archive already logger.debug('Found cover image %s in the archive', images[0]) try: archive.extract(image, dir) logger.debug('Cover image %s extracted to %s', image, dir) return os.path.join(dir, image) except (ZipError, RarError, TarError) as exc: # we tried to extract the cover but there is an error, # we will try another approach later on logger.warning('Archive extract %s error: %s', self.archive, exc) # no cover image in the archive, let's try to guess which one we could use as such # extract first image on the list, most likely it'll represet # a useful cover. This is definitely the case with cbz/cbr comics covers # first, we need sort all files to make sure that we have them in sequence images.sort(lambda l, o: cmp(l.upper(), o.upper())) # just for cleaner code image = images[0] logger.debug('Found suitable cover image %s in the archive', image) try: archive.extract(image, dir) ext = os.path.splitext(image)[1].lower().replace( 'jpeg', 'jpg') except (ZipError, RarError, TarError) as exc: # we tried to extract the image but there was an error, we give up logger.warning('Archive %s extract error: %s', self.archive, exc) return None try: os.symlink(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext))) #shutil.copy(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext))) logger.debug('Cover image %s, copied to %s', normalize(image), dir) except (OSError, ShutilError) as exc: logger.warning( 'Error while getting cover image for archive %s, %s', self.archive, exc) return None return os.path.join(dir, ('cover.' + ext)) logger.debug('Unable to find a suitable cover image for archive %s', self.archive) return None
def __init__(self, directory, parent, name='', display_type=None, add_args=None, create_metainfo=True): self.autovars = [('num_dir_items', 0), ('show_all_items', False)] Playlist.__init__(self, parent=parent, display_type=display_type) self.type = 'dir' self.menu = None # store FileInformation for moving/copying self.files = FileInformation() if self.media: self.files.read_only = True self.files.append(directory) self.dir = os.path.abspath(directory) self.info = mediainfo.get_dir(directory) #FIXME This should be done in the cache create if not self.image: mminfo = mmpython.parse(directory) if mminfo: if mminfo['image']: self.image = mminfo['image'] if mminfo['title']: self.title = mminfo['title'] if mminfo['comment']: self.comment = mminfo['comment'] if name: self.name = Unicode(name) elif self.info['title:filename']: self.name = self.info['title:filename'] elif self.info['title']: self.name = self.info['title'] else: self.name = util.getname(directory, skip_ext=False) if add_args == None and hasattr(parent, 'add_args'): add_args = parent.add_args self.add_args = add_args if self.parent and hasattr(parent, 'skin_display_type'): self.skin_display_type = parent.skin_display_type elif parent: self.skin_display_type = parent.display_type else: self.skin_display_type = display_type if self['show_all_items']: self.display_type = None # set tv to video now if self.display_type == 'tv': display_type = 'video' # set directory variables to default global all_variables self.all_variables = copy.copy(all_variables) # Check mimetype plugins if they want to add something for p in plugin.mimetype(display_type): self.all_variables += p.dirconfig(self) # set the variables to the default values for var in self.all_variables: if hasattr(parent, var[0]): setattr(self, var[0], getattr(parent, var[0])) elif hasattr(config, var[0]): setattr(self, var[0], getattr(config, var[0])) else: setattr(self, var[0], False) self.modified_vars = [] # Check for a cover in current dir if self.info['image']: image = self.info['image'] else: image = util.getimage(os.path.join(directory, 'cover')) # if we have an image then use it if image: self.image = image self.files.image = image # Check for a folder.fxd in current dir self.folder_fxd = directory + '/folder.fxd' if vfs.isfile(self.folder_fxd): self.set_fxd_file(self.folder_fxd) # Check mimetype plugins if they want to add something for p in plugin.mimetype(display_type): p.dirinfo(self) if self.DIRECTORY_SORT_BY_DATE == 2 and self.display_type != 'tv': self.DIRECTORY_SORT_BY_DATE = 0 # create some extra info if create_metainfo: self.create_metainfo()
def build(self, arg=None, menuw=None): """ build the items for the directory """ self.menuw = menuw self.playlist = [] self.play_items = [] self.dir_items = [] self.pl_items = [] if self.media: self.media.mount() if hasattr(self, '__dirwatcher_last_time__'): del self.__dirwatcher_last_time__ if arg == 'update': if not self.menu.choices: selected_pos = -1 else: # store the current selected item selected_id = self.menu.selected.id() selected_pos = self.menu.choices.index(self.menu.selected) if hasattr(self.menu, 'skin_default_has_description'): del self.menu.skin_default_has_description if hasattr(self.menu, 'skin_default_no_images'): del self.menu.skin_default_no_images if hasattr(self.menu, 'skin_force_text_view'): del self.menu.skin_force_text_view elif not os.path.exists(self.dir): AlertBox(text=_('Directory does not exist')).show() return display_type = self.display_type if self.display_type == 'tv': display_type = 'video' if arg and arg.startswith('playlist:'): if arg.endswith(':random'): Playlist(playlist=[(self.dir, 0)], parent=self, display_type=display_type, random=True).play(menuw=menuw) elif arg.endswith(':recursive'): Playlist(playlist=[(self.dir, 1)], parent=self, display_type=display_type, random=False).play(menuw=menuw) elif arg.endswith(':random_recursive'): Playlist(playlist=[(self.dir, 1)], parent=self, display_type=display_type, random=True).play(menuw=menuw) return if config.OSD_BUSYICON_TIMER: osd.get_singleton().busyicon.wait(config.OSD_BUSYICON_TIMER[0]) files = vfs.listdir(self.dir, include_overlay=True) num_changes = mediainfo.check_cache(self.dir) pop = None callback = None if skin.active(): if (num_changes > 10) or (num_changes and self.media): if self.media: pop = ProgressBox(text=_('Scanning disc, be patient...'), full=num_changes) else: pop = ProgressBox( text=_('Scanning directory, be patient...'), full=num_changes) pop.show() callback = pop.tick elif config.OSD_BUSYICON_TIMER and len( files) > config.OSD_BUSYICON_TIMER[1]: # many files, just show the busy icon now osd.get_singleton().busyicon.wait(0) if num_changes > 0: mediainfo.cache_dir(self.dir, callback=callback) # # build items # # build play_items, pl_items and dir_items for p in plugin.mimetype(display_type): for i in p.get(self, files): if i.type == 'playlist': self.pl_items.append(i) elif i.type == 'dir': self.dir_items.append(i) else: self.play_items.append(i) # normal DirItems for filename in files: if os.path.isdir(filename): d = DirItem(filename, self, display_type=self.display_type) self.dir_items.append(d) # remove same beginning from all play_items if self.DIRECTORY_SMART_NAMES: substr = '' if len(self.play_items) > 4 and len(self.play_items[0].name) > 5: substr = self.play_items[0].name[:-5].lower() for i in self.play_items[1:]: if len(i.name) > 5: substr = util.find_start_string(i.name.lower(), substr) if not substr or len(substr) < 10: break else: break else: for i in self.play_items: i.name = util.remove_start_string(i.name, substr) # # sort all items # # sort directories if self.DIRECTORY_SMART_SORT: self.dir_items.sort(lambda l, o: util.smartsort(l.dir, o.dir)) else: self.dir_items.sort(lambda l, o: cmp(l.dir.upper(), o.dir.upper())) # sort playlist self.pl_items.sort(lambda l, o: cmp(l.name.upper(), o.name.upper())) # sort normal items if self.DIRECTORY_SORT_BY_DATE: self.play_items.sort(lambda l, o: cmp( l.sort('date').upper(), o.sort('date').upper())) elif self['%s_advanced_sort' % display_type]: self.play_items.sort(lambda l, o: cmp( l.sort('advanced').upper(), o.sort('advanced').upper())) else: self.play_items.sort(lambda l, o: cmp(l.sort().upper(), o.sort().upper())) if self['num_dir_items'] != len(self.dir_items): self['num_dir_items'] = len(self.dir_items) if self['num_%s_items' % display_type] != len(self.play_items) + len(self.pl_items): self['num_%s_items' % display_type] = len(self.play_items) + len(self.pl_items) if self.DIRECTORY_REVERSE_SORT: self.dir_items.reverse() self.play_items.reverse() self.pl_items.reverse() # delete pl_items if they should not be displayed if self.display_type and not self.display_type in self.DIRECTORY_ADD_PLAYLIST_FILES: self.pl_items = [] # add all playable items to the playlist of the directory # to play one files after the other if not self.display_type or self.display_type in self.DIRECTORY_CREATE_PLAYLIST: self.playlist = self.play_items # build a list of all items items = self.dir_items + self.pl_items + self.play_items # random playlist (only active for audio) if self.display_type and self.display_type in self.DIRECTORY_ADD_RANDOM_PLAYLIST \ and len(self.play_items) > 1: pl = Playlist(_('Random playlist'), self.play_items, self, random=True) pl.autoplay = True items = [pl] + items if pop: pop.destroy() # closing the poup will rebuild the menu which may umount # the drive if self.media: self.media.mount() if config.OSD_BUSYICON_TIMER: # stop the timer. If the icons is drawn, it will stay there # until the osd is redrawn, if not, we don't need it to pop # up the next milliseconds osd.get_singleton().busyicon.stop() # # action # if arg == 'update': # update because of dirwatcher changes self.menu.choices = items if selected_pos != -1: for i in items: if Unicode(i.id()) == Unicode(selected_id): self.menu.selected = i break else: # item is gone now, try to the selection close # to the old item pos = max(0, min(selected_pos - 1, len(items) - 1)) if items: self.menu.selected = items[pos] else: self.menu.selected = None if self.menuw: if self.menu.selected and selected_pos != -1: self.menuw.rebuild_page() else: self.menuw.init_page() self.menuw.refresh() elif len(items) == 1 and items[0].actions() and \ self.DIRECTORY_AUTOPLAY_SINGLE_ITEM: # autoplay items[0].actions()[0][0](menuw=menuw) elif arg == 'play' and self.play_items: # called by play function self.playlist = self.play_items Playlist.play(self, menuw=menuw) else: # normal menu build item_menu = menu.Menu( self.name, items, reload_func=self.reload, item_types=self.skin_display_type, force_skin_layout=self.DIRECTORY_FORCE_SKIN_LAYOUT) if self.skin_fxd: item_menu.skin_settings = skin.load(self.skin_fxd) menuw.pushmenu(item_menu) dirwatcher.cwd(menuw, self, item_menu, self.dir) self.menu = item_menu self.menuw = menuw
def main_menu(self, arg=None, menuw=None): """ display the (IMAGE|VIDEO|AUDIO|GAMES) main menu """ self.display_type, force_text_view = arg title = _('Media') self.menuw = menuw if self.display_type == 'video': title = _('Movie') if self.display_type == 'audio': title = _('Audio') if self.display_type == 'image': title = _('Image') if self.display_type == 'games': title = _('Games') menutitle = _('%s Main Menu') % title if self.display_type: items = getattr(config, '%s_ITEMS' % self.display_type.upper()) else: items = [] self.normal_items = [] # add default items for item in items: try: add_args = None if isstring(item): title, filename = u'', item else: (title, filename) = item[:2] if len(item) > 2: add_args = item[2:] reachable = 1 pos = filename.find(':/') if pos > 0: if filename.find(':/') < filename.find('/'): hostname = filename[0:pos] filename = filename[pos+1:] try: if os.system( config.HOST_ALIVE_CHECK % hostname ) != 0: reachable = 0 except: traceback.print_exc() # May need to change this filename.find('.fxd') elif not os.path.exists(filename): print '\"%s\" doesn\'t exist' % (filename) reachable = 0 if reachable: if vfs.isdir(filename): item = directory.DirItem(String(filename), self, display_type=self.display_type, add_args=add_args) if title: item.name = title self.normal_items.append(item) else: if not vfs.isfile(filename): filename = filename[len(os.getcwd()):] if filename[0] == '/': filename = filename[1:] filename = vfs.join(config.SHARE_DIR, filename) # normal file # webradio is both a playlist and an fxditem dups = [] for p in plugin.mimetype(self.display_type): items = p.get(self, [ String(filename) ]) if filename in dups: continue else: dups.append(filename) if title: for i in items: i.name = title self.normal_items += items except: traceback.print_exc() items = self.main_menu_generate() # autoselect one item if len(items) == 1: items[0](menuw=menuw) return item_menu = menu.Menu(menutitle, items, item_types='%s main menu' % self.display_type, umount_all=1, reload_func=self.reload) item_menu.skin_force_text_view = force_text_view self.menuw = menuw menuw.pushmenu(item_menu)
class PluginInterface(plugin.MimetypePlugin): """ Plugin to handle all kinds of image items """ def __init__(self): plugin.MimetypePlugin.__init__(self) self.display_type = ['image'] # register the callbacks plugin.register_callback('fxditem', ['image'], 'slideshow', self.fxdhandler) # activate the mediamenu for image plugin.activate('mediamenu', level=plugin.is_active('image')[2], args='image') def suffix(self): """ return the list of suffixes this class handles """ return config.IMAGE_SUFFIX def get(self, parent, files): """ return a list of items based on the files """ items = [] if config.IMAGE_EXCLUDE: exclude_string = re.compile('|'.join(config.IMAGE_EXCLUDE)) for file in util.find_matches(files, config.IMAGE_SUFFIX): if config.IMAGE_EXCLUDE: if not re.search(exclude_string, file): items.append(ImageItem(file, parent)) files.remove(file) else: items.append(ImageItem(file, parent)) files.remove(file) return items def dirinfo(self, diritem): """ set information for a diritem based on album.xml """ #dirinfo = bins.DirInfo(diritem.dir) #if dirinfo.has_key('desc'): # info = dirinfo['desc'] #if dirinfo.has_key('sampleimage') and dirinfo['sampleimage']: # image = vfs.join(diritem.dir, dirinfo['sampleimage']) # if vfs.isfile(image): # diritem.image = image #if dirinfo.has_key('title') and dirinfo['title']: # diritem.name = dirinfo['title'] def fxdhandler(self, fxd, node): """ parse image specific stuff from fxd files:: <?xml version="1.0" ?> <freevo> <slideshow title="foo" random="1|0" repeat="1|0"> <cover-img>foo.jpg</cover-img> <background-music random="1|0"> <directory recursive="1|0">path</directory> <file>filename</file> </background-music> <files> <directory recursive="1|0" duration="10">path</directory> <file duration="0">filename</file> </files> <info> <description>A nice description</description> </info> </slideshow> </freevo> """ items = [] dirname = os.path.dirname(fxd.getattr(None, 'filename', '')) children = fxd.get_children(node, 'files') if children: children = children[0].children for child in children: try: citems = [] fname = os.path.join(dirname, String(fxd.gettext(child))) if child.name == 'directory': if fxd.getattr(child, 'recursive', 0): f = util.match_files_recursively(fname, self.suffix(), skip_password=True) else: f = util.match_files(fname, self.suffix()) citems = self.get(None, f) elif child.name == 'file': citems = self.get(None, [fname]) duration = fxd.getattr(child, 'duration', 0) if duration: for i in citems: i.duration = duration items += citems except OSError, e: print 'slideshow error:', e pl = Playlist('', items, fxd.getattr(None, 'parent', None), random=fxd.getattr(node, 'random', 0), repeat=fxd.getattr(node, 'repeat', 0)) pl.autoplay = True pl.name = fxd.getattr(node, 'title') pl.image = fxd.childcontent(node, 'cover-img') if pl.image: pl.image = vfs.join(vfs.dirname(fxd.filename), pl.image) # background music children = fxd.get_children(node, 'background-music') if children: random = fxd.getattr(children[0], 'random', 0) children = children[0].children files = [] suffix = [] for p in plugin.mimetype('audio'): suffix += p.suffix() for child in children: try: fname = os.path.join(dirname, fxd.gettext(child)) if child.name == 'directory': if fxd.getattr(child, 'recursive', 0): files += util.match_files_recursively( fname, suffix, skip_password=True) else: files += util.match_files(fname, suffix) elif child.name == 'file': files.append(fname) except OSError, e: print 'playlist error:', e