start implementing new Image stuff, tie in RenderMachine into the new Image class, assoicated config stuff
import os, os.path
import settings, image, utils, helpers, log
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))
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()