--- a/degal/folder.py Fri Jun 05 23:03:35 2009 +0300
+++ b/degal/folder.py Fri Jun 05 23:05:11 2009 +0300
@@ -114,6 +114,8 @@
def index (self) :
"""
Recursively index this Folder, yielding a series of all Folder objects inside.
+
+ XXX: not used
"""
# and subfolders
@@ -123,296 +125,3 @@
for item in subfolder.index_subfolders() :
yield item
-class Folder (object) :
- def __init__ (self, name='.', parent=None) :
- # the directory name, no trailing /
- self.name = unicode(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.
- """
-
- 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('.') :
- log.debug("Skipping dotfile %s", fname)
- continue
-
- # apply filters
- if filters :
- if fname in filters :
- next_filter = filters[fname]
- else :
- log.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)
- ) :
- log.down(fname)
-
- f = Folder(fname, self)
-
- try :
- if f.index(next_filter) : # recursion
- # if a subdir is alive, we are alive as well
- self.subdirs[fname] = f
- self.alive = True
- except Exception, e :
- log.warning("skip - %s: %s" % (type(e), e))
-
- log.up()
-
- # handle images
- elif os.path.isfile(fpath) and utils.isImage(fname) :
- log.next(fname)
- self.images[fname] = image.Image(self, fname)
-
- # ignore everything else
- else :
- log.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 or self.descr :
- self.alive = True
- pass # use what was in the title file
-
- elif not self.parent :
- self.title = 'Index'
-
- else :
- self.title = self.name
-
- if not self.alive :
- log.debug("Dir %s isn't alive" % self.path)
-
- return self.alive
-
- def getObjInfo (self) :
- """
- Metadata for shorturls2.db
- """
- return 'dir', self.path, ''
-
- def breadcrumb (self, forImg=None) :
- """
- Returns a [(fname, title)] list of this dir's parent dirs
- """
-
- f = self
- b = []
- d = 0
-
- while f :
- # functionality of the slightly-hacked-in variety
- if f is self and forImg is not None :
- url = helpers.url_for_page(self.getPageNumber(forImg))
- else :
- url = dirUp(d)
-
- b.insert(0, (url, f.title))
-
- d += 1
- f = f.parent
-
- return b
-
- def getPageNumber (self, img) :
- """
- Get the page number that the given image is on
- """
-
- return self.sorted_images.index(img) // settings.IMAGE_COUNT
-
- 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 :
- # dead, skip, no output
- return
-
- index_mtime = utils.mtime(self.pathFor("index.html"))
- dir_mtime = utils.mtime(self.path)
-
- # 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 :
- log.warning("Dir `%s' contents were filtered, so we won't render the gallery index again", self.path)
-
- elif index_mtime > dir_mtime :
- # no changes, pass, ignored
- pass
-
- 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) :
- log.info("mkdir %s", dir)
- os.mkdir(path)
-
- # sort the subdirs
- subdirs = self.subdirs.values()
- subdirs.sort(key=lambda d: d.name)
-
- # 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 :
- log.info("%d pages @ %d images", len(pages), settings.IMAGE_COUNT)
- elif not pages :
- log.info("no images, render for subdirs")
- pages = [[]]
-
- 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
- image_count = len(self.sorted_images)
- for i, img in enumerate(self.images.itervalues()) :
- log.next("[%-4d/%4d] %s", i + 1, image_count, img.name)
-
- img.render()
-
- # recurse into subdirs
- for dir in self.subdirs.itervalues() :
- log.down(dir.name)
-
- dir.render()
-
- log.up()
-
--- a/degal/image.py Fri Jun 05 23:03:35 2009 +0300
+++ b/degal/image.py Fri Jun 05 23:05:11 2009 +0300
@@ -104,163 +104,32 @@
return self.metadata
- def render_image (self) :
+ @lazy_load
+ def thumb (self) :
"""
- Renders new thumbnails/previews for this image.
-
- Note: this does not check for the existance of the thumbs/previews subdirs!
+ Load and update the thumbnail if needed
"""
- # load origional image
- img = self.load_image()
-
# renderer to use
# XXX: get from elsewhere
render_machine = self.config.get_renderer()
- # lazy-render both thumb and preview
- self.thumb = render_machine.render_lazy(self
+ # render if needed
+ return render_machine.render_lazy(self
self.config.thumb_size, self.parent.load_thumb_dir.subnode(self.name)
)
+
+ @lazy_load
+ def preview (self) :
+ """
+ Load and update the preview if needed
+ """
- self.preview = render_machine.render_lazy(self,
+ # renderer to use
+ # XXX: get from elsewhere
+ render_machine = self.config.get_renderer()
+
+ return render_machine.render_lazy(self,
self.config.preview_size, self.parent.load_preview_dir.subnode(self.name)
)
-class Image (object) :
- def __init__ (self, dir, name) :
- # the image filename, e.g. DSC3948.JPG
- self.name = unicode(name)
-
- # the Folder object that we are in
- self.dir = dir
-
- # the relative path from the root to us
- self.path = dir.pathFor(self.name)
-
- # the basename+ext, e.g. DSCR3948, .JPG
- self.base_name, self.ext = os.path.splitext(self.name)
-
- # our user-friendly title
- self.title = self.name
-
- # our long-winded description
- self.descr = ''
-
- # the image before and after us, both may be None
- self.prev = self.next = None
-
- # the image-relative names for the html page, thumb and preview images
- self.html_name = self.name + ".html"
- self.thumb_name = utils.url_join(settings.THUMB_DIR, self.name)
- self.preview_name = utils.url_join(settings.PREVIEW_DIR, self.name)
-
- # the root-relative paths to the html page, thumb and preview images
- self.html_path = self.dir.pathFor(self.html_name)
- self.thumb_path = self.dir.pathFor(settings.THUMB_DIR, self.name)
- self.preview_path = self.dir.pathFor(settings.PREVIEW_DIR, self.name)
-
- #
- # Figured out after prepare
- #
-
- # (w, h) tuple
- self.img_size = None
-
- # the ShortURL code for this image
- self.shorturl_code = None
-
- # EXIF data
- self.exif_data = {}
-
- # what to use in the rendered templates, intended to be overridden by subclasses
- self.series_act = "add"
- self.series_verb = "Add to"
-
- def getObjInfo (self) :
- """
- Metadata for shorturl2.db
- """
- return 'img', self.dir.path, self.name
-
- def breadcrumb (self) :
- """
- Returns a [(fname, title)] list of this image's parents
- """
-
- return self.dir.breadcrumb(forImg=self) + [(self.html_name, self.title)]
-
- def render (self) :
- """
- Write out the .html file
- """
-
- # stat the image file to get the filesize and mtime
- st = os.stat(self.path)
-
- self.filesize = st.st_size
- self.timestamp = st.st_mtime
-
- # open the image in PIL to get image attributes + generate thumbnails
- img = PIL.Image.open(self.path)
-
- self.img_size = img.size
-
- for out_path, geom in ((self.thumb_path, settings.THUMB_GEOM), (self.preview_path, settings.PREVIEW_GEOM)) :
- # if it doesn't exist, or it's older than the image itself, generate
- if utils.mtime(out_path) < self.timestamp :
- log.info("render [%sx%s]", geom[0], geom[1], wait=True)
-
- # XXX: is this the most efficient way to do this? It seems slow
- out_img = img.copy()
- out_img.thumbnail(geom, resample=True)
- out_img.save(out_path)
-
- log.done()
-
- # look for the metadata file
- title_path = self.dir.pathFor(self.base_name + '.txt')
-
- self.title, self.descr = utils.readTitleDescr(title_path)
-
- if not self.title :
- self.title = self.name
-
- if utils.mtime(self.html_path) < self.timestamp :
- log.info("render %s.html", self.name)
-
- # parse the exif data from the file
- try :
- self.exif_data = dexif.parse_exif(self.path)
- except dexif.ExifError, message:
- log.warning("Reading EXIF data for %s failed: %s" % (self.filename, message))
- self.exif_data = {}
-
-
- image_tpl.render_to(self.html_path,
- stylesheet_url = self.dir.inRoot('style.css'),
- title = self.title,
- breadcrumb = self.breadcrumb(),
-
- prev = self.prev,
- next = self.next,
- img = self,
-
- description = self.descr,
-
- filename = self.name,
- img_size = self.img_size,
- file_size = self.filesize,
- timestamp = self.timestamp,
- exif_data = self.exif_data,
-
- shorturl = self.dir.inRoot('s', self.shorturl_code),
- shorturl_code = self.shorturl_code,
-
- series_url = self.dir.inRoot('series/%s/%s' % (self.series_act, self.shorturl_code)),
- series_verb = self.series_verb,
- )
-
- def __str__ (self) :
- return "Image `%s' in `%s'" % (self.name, self.dir.path)
-