diff -r 27dac27d1a58 -r c2d8e9a754a1 lib/folder.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/folder.py Fri Dec 21 20:36:03 2007 +0000 @@ -0,0 +1,287 @@ +import os, os.path + +import settings, image, utils +from log import index, render +from template import gallery as gallery_tpl +from helpers import url_for_page + +def dirUp (count=1) : + """ + Returns a relative path to the directly count levels above the current one + """ + + if not count : + return '.' + + return os.path.join(*(['..']*count)) + +def isImage (fname) : + """ + Is the given filename likely to be an image file? + """ + + fname = fname.lower() + base, ext = os.path.splitext(fname) + ext = ext.lstrip('.') + + return ext in settings.IMAGE_EXTS + +class Folder (object) : + def __init__ (self, name='.', parent=None) : + # the directory name, no trailing / + self.name = name.rstrip(os.sep) + + # our parent Folder, or None + self.parent = parent + + # the path to this dir, as a relative path to the root of the image gallery, always starts with . + if parent and name : + self.path = parent.pathFor(self.name) + else : + self.path = self.name + + # the url-path to the index.html file + self.html_path = self.path + + # dict of fname -> Folder + self.subdirs = {} + + # dict of fname -> Image + self.images = {} + + # our human-friendly title + self.title = None + + # our long-winded description + self.descr = '' + + # is this folder non-empty? + self.alive = None + + # self.images.values(), but sorted by filename + self.sorted_images = [] + + # the ShortURL key to this dir + self.shorturl_code = None + + # were we filtered out? + self.filtered = False + + def pathFor (self, *fnames) : + """ + Return a root-relative path to the given path inside this dir + """ + return os.path.join(self.path, *fnames) + + def index (self, filters=None) : + """ + Look for other dirs and images inside this dir. Filters must be either None, + whereupon all files will be included, or a dict of {filename -> next_filter}. + If given, only filenames that are present in the dict will be indexed, and in + the case of dirs, the next_filter will be passed on to that Folder's index + method. + """ + + index.info("Indexing %s", self.path) + + if filters : + self.filtered = True + + # iterate through listdir + for fname in os.listdir(self.path) : + # the full filesystem path to it + fpath = self.pathFor(fname) + + # ignore dotfiles + if fname.startswith('.') : + index.debug("Skipping dotfile %s", fname) + continue + + # apply filters + if filters : + if fname in filters : + next_filter = filters[fname] + else : + index.debug("Skip `%s' as we have a filter", fname) + continue + else : + next_filter = None + + # recurse into subdirs, but not thumbs/previews + if (os.path.isdir(fpath) + and (fname not in (settings.THUMB_DIR, settings.PREVIEW_DIR)) + and (self.parent or fname not in settings.ROOT_IGNORE) + ) : + index.debug("Found subdir %s", fpath) + f = self.subdirs[fname] = Folder(fname, self) + if f.index(next_filter) : # recursion + # if a subdir is alive, we are alive as well + self.alive = True + + # handle images + elif os.path.isfile(fpath) and isImage(fname) : + index.debug("Found image %s", fname) + self.images[fname] = image.Image(self, fname) + + # ignore everything else + else : + index.debug("Ignoring file %s", fname) + + # sort and link the images + if self.images : + self.alive = True + + # sort the images + fnames = self.images.keys() + fnames.sort() + + prev = None + + # link + for fname in fnames : + img = self.images[fname] + + img.prev = prev + + if prev : + prev.next = img + + prev = img + + # add to the sorted images list + self.sorted_images.append(img) + + # figure out our title/ descr. Must be done before our parent dir is rendered (self.title) + title_path = self.pathFor(settings.TITLE_FILE) + + self.title, self.descr = utils.readTitleDescr(title_path) + + # default title for the root dir + if self.title : + self.alive = True + pass # use what was in the title file + + elif not self.parent : + self.title = 'Index' + + else : + self.title = self.name + + if self.descr : + self.alive = True + + return self.alive + + def getObjInfo (self) : + """ + Metadata for shorturls2.db + """ + return 'dir', self.path, '' + + def breadcrumb (self) : + """ + Returns a [(fname, title)] list of this dir's parent dirs + """ + + f = self + b = [] + d = 0 + + while f : + b.insert(0, (dirUp(d), f.title)) + + d += 1 + f = f.parent + + return b + + def countParents (self, acc=0) : + if self.parent : + return self.parent.countParents(acc+1) + else : + return acc + + def inRoot (self, *fnames) : + """ + Return a relative URL from this dir to the given path in the root dir + """ + + c = self.countParents() + + return utils.url_join(*((['..']*c) + list(fnames))) + + def render (self) : + """ + Render the index.html, Images, and recurse into subdirs + """ + + # ded folders are skipped + if not self.alive : + render.info("Skipping dir %s (no images)", self.path) + return + + # if this dir's contents were filtered out, then we can't render the index.html, as we aren't aware of all the images in here + if self.filtered : + render.warning("Dir `%s' contents were filtered, so we won't render the gallery index again", self.path) + + else : + # create the thumb/preview dirs if needed + for dir in (settings.THUMB_DIR, settings.PREVIEW_DIR) : + path = self.pathFor(dir) + + if not os.path.isdir(path) : + render.info("Creating dir %s", path) + os.mkdir(path) + + # sort the subdirs + subdirs = self.subdirs.values() + subdirs.sort(key=lambda d: d.name) + + render.info("Rendering %s", self.path) + + # paginate! + images = self.sorted_images + image_count = len(images) + pages = [] + + while images : + pages.append(images[:settings.IMAGE_COUNT]) + images = images[settings.IMAGE_COUNT:] + + pagination_required = len(pages) > 1 + + if pagination_required : + render.info("Index split into %d pages of %d images each", len(pages), settings.IMAGE_COUNT) + + for cur_page, images in enumerate(pages) : + if pagination_required and cur_page > 0 : + shorturl = "%s/%s" % (self.shorturl_code, cur_page+1) + else : + shorturl = self.shorturl_code + + # render to index.html + gallery_tpl.render_to(self.pathFor(url_for_page(cur_page)), + stylesheet_url = self.inRoot('style.css'), + title = self.title, + breadcrumb = self.breadcrumb(), + + dirs = subdirs, + images = images, + + num_pages = len(pages), + cur_page = cur_page, + + description = self.descr, + + shorturl = self.inRoot('s', shorturl), + shorturl_code = shorturl, + ) + + # render images + for img in self.images.itervalues() : + img.render() + + # recurse into subdirs + for dir in self.subdirs.itervalues() : + dir.render() + \ No newline at end of file