lib/folder.py
changeset 12 c2d8e9a754a1
child 13 c229bcb1de41
equal deleted inserted replaced
11:27dac27d1a58 12:c2d8e9a754a1
       
     1 import os, os.path
       
     2 
       
     3 import settings, image, utils
       
     4 from log import index, render
       
     5 from template import gallery as gallery_tpl
       
     6 from helpers import url_for_page
       
     7 
       
     8 def dirUp (count=1) :
       
     9     """
       
    10         Returns a relative path to the directly count levels above the current one
       
    11     """
       
    12 
       
    13     if not count :
       
    14         return '.'
       
    15 
       
    16     return os.path.join(*(['..']*count))
       
    17     
       
    18 def isImage (fname) :
       
    19     """
       
    20         Is the given filename likely to be an image file?
       
    21     """
       
    22 
       
    23     fname = fname.lower()
       
    24     base, ext = os.path.splitext(fname)
       
    25     ext = ext.lstrip('.')
       
    26 
       
    27     return ext in settings.IMAGE_EXTS
       
    28 
       
    29 class Folder (object) :
       
    30     def __init__ (self, name='.', parent=None) :
       
    31         # the directory name, no trailing /
       
    32         self.name = name.rstrip(os.sep)
       
    33 
       
    34         # our parent Folder, or None
       
    35         self.parent = parent
       
    36 
       
    37         # the path to this dir, as a relative path to the root of the image gallery, always starts with .
       
    38         if parent and name :
       
    39             self.path = parent.pathFor(self.name)
       
    40         else :
       
    41             self.path = self.name
       
    42 
       
    43         # the url-path to the index.html file
       
    44         self.html_path = self.path
       
    45         
       
    46         # dict of fname -> Folder
       
    47         self.subdirs = {}
       
    48 
       
    49         # dict of fname -> Image
       
    50         self.images = {}
       
    51         
       
    52         # our human-friendly title
       
    53         self.title = None
       
    54 
       
    55         # our long-winded description
       
    56         self.descr = ''
       
    57 
       
    58         # is this folder non-empty?
       
    59         self.alive = None
       
    60         
       
    61         # self.images.values(), but sorted by filename
       
    62         self.sorted_images = []
       
    63         
       
    64         # the ShortURL key to this dir
       
    65         self.shorturl_code = None
       
    66 
       
    67         # were we filtered out?
       
    68         self.filtered = False
       
    69    
       
    70     def pathFor (self, *fnames) :
       
    71         """
       
    72             Return a root-relative path to the given path inside this dir
       
    73         """
       
    74         return os.path.join(self.path, *fnames)
       
    75 
       
    76     def index (self, filters=None) :
       
    77         """
       
    78             Look for other dirs and images inside this dir. Filters must be either None,
       
    79             whereupon all files will be included, or a dict of {filename -> next_filter}.
       
    80             If given, only filenames that are present in the dict will be indexed, and in
       
    81             the case of dirs, the next_filter will be passed on to that Folder's index
       
    82             method.
       
    83         """
       
    84 
       
    85         index.info("Indexing %s", self.path)
       
    86 
       
    87         if filters :
       
    88             self.filtered = True
       
    89         
       
    90         # iterate through listdir
       
    91         for fname in os.listdir(self.path) :
       
    92             # the full filesystem path to it
       
    93             fpath = self.pathFor(fname)
       
    94             
       
    95             # ignore dotfiles
       
    96             if fname.startswith('.') :
       
    97                 index.debug("Skipping dotfile %s", fname)
       
    98                 continue
       
    99             
       
   100             # apply filters
       
   101             if filters :
       
   102                 if fname in filters :
       
   103                     next_filter = filters[fname]
       
   104                 else :
       
   105                     index.debug("Skip `%s' as we have a filter", fname)
       
   106                     continue
       
   107             else :
       
   108                 next_filter = None
       
   109                 
       
   110             # recurse into subdirs, but not thumbs/previews
       
   111             if (os.path.isdir(fpath) 
       
   112                 and (fname not in (settings.THUMB_DIR, settings.PREVIEW_DIR))
       
   113                 and (self.parent or fname not in settings.ROOT_IGNORE)
       
   114             ) :
       
   115                 index.debug("Found subdir %s", fpath)
       
   116                 f = self.subdirs[fname] = Folder(fname, self)
       
   117                 if f.index(next_filter) :   # recursion
       
   118                     # if a subdir is alive, we are alive as well
       
   119                     self.alive = True
       
   120 
       
   121             # handle images
       
   122             elif os.path.isfile(fpath) and isImage(fname) :
       
   123                 index.debug("Found image %s", fname)
       
   124                 self.images[fname] = image.Image(self, fname)
       
   125 
       
   126             # ignore everything else
       
   127             else :
       
   128                 index.debug("Ignoring file %s", fname)
       
   129         
       
   130         # sort and link the images
       
   131         if self.images :
       
   132             self.alive = True
       
   133 
       
   134             # sort the images
       
   135             fnames = self.images.keys()
       
   136             fnames.sort()
       
   137 
       
   138             prev = None
       
   139 
       
   140             # link
       
   141             for fname in fnames :
       
   142                 img = self.images[fname]
       
   143 
       
   144                 img.prev = prev
       
   145 
       
   146                 if prev :
       
   147                     prev.next = img
       
   148 
       
   149                 prev = img
       
   150                 
       
   151                 # add to the sorted images list
       
   152                 self.sorted_images.append(img)
       
   153                 
       
   154             # figure out our title/ descr. Must be done before our parent dir is rendered (self.title)
       
   155             title_path = self.pathFor(settings.TITLE_FILE)
       
   156             
       
   157             self.title, self.descr = utils.readTitleDescr(title_path)
       
   158             
       
   159             # default title for the root dir
       
   160             if self.title :
       
   161                 self.alive = True
       
   162                 pass # use what was in the title file
       
   163                 
       
   164             elif not self.parent :
       
   165                 self.title = 'Index'
       
   166 
       
   167             else :
       
   168                 self.title = self.name
       
   169             
       
   170             if self.descr :
       
   171                 self.alive = True
       
   172 
       
   173         return self.alive
       
   174 
       
   175     def getObjInfo (self) :
       
   176         """
       
   177             Metadata for shorturls2.db
       
   178         """
       
   179         return 'dir', self.path, ''
       
   180 
       
   181     def breadcrumb (self) :
       
   182         """
       
   183             Returns a [(fname, title)] list of this dir's parent dirs
       
   184         """
       
   185 
       
   186         f = self
       
   187         b = []
       
   188         d = 0
       
   189         
       
   190         while f :
       
   191             b.insert(0, (dirUp(d), f.title))
       
   192 
       
   193             d += 1
       
   194             f = f.parent
       
   195         
       
   196         return b
       
   197 
       
   198     def countParents (self, acc=0) :
       
   199         if self.parent :
       
   200             return self.parent.countParents(acc+1)
       
   201         else :
       
   202             return acc
       
   203     
       
   204     def inRoot (self, *fnames) :
       
   205         """
       
   206             Return a relative URL from this dir to the given path in the root dir
       
   207         """
       
   208 
       
   209         c = self.countParents()
       
   210 
       
   211         return utils.url_join(*((['..']*c) + list(fnames)))
       
   212 
       
   213     def render (self) :
       
   214         """
       
   215             Render the index.html, Images, and recurse into subdirs
       
   216         """
       
   217         
       
   218         # ded folders are skipped
       
   219         if not self.alive :
       
   220             render.info("Skipping dir %s (no images)", self.path)
       
   221             return
       
   222         
       
   223         # 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
       
   224         if self.filtered :
       
   225             render.warning("Dir `%s' contents were filtered, so we won't render the gallery index again", self.path)
       
   226 
       
   227         else :  
       
   228             # create the thumb/preview dirs if needed
       
   229             for dir in (settings.THUMB_DIR, settings.PREVIEW_DIR) :
       
   230                 path = self.pathFor(dir)
       
   231 
       
   232                 if not os.path.isdir(path) :
       
   233                     render.info("Creating dir %s", path)
       
   234                     os.mkdir(path)
       
   235 
       
   236             # sort the subdirs
       
   237             subdirs = self.subdirs.values()
       
   238             subdirs.sort(key=lambda d: d.name)
       
   239             
       
   240             render.info("Rendering %s", self.path)
       
   241 
       
   242             # paginate!
       
   243             images = self.sorted_images
       
   244             image_count = len(images)
       
   245             pages = []
       
   246             
       
   247             while images :
       
   248                 pages.append(images[:settings.IMAGE_COUNT])
       
   249                 images = images[settings.IMAGE_COUNT:]
       
   250 
       
   251             pagination_required = len(pages) > 1
       
   252 
       
   253             if pagination_required :
       
   254                 render.info("Index split into %d pages of %d images each", len(pages), settings.IMAGE_COUNT)
       
   255             
       
   256             for cur_page, images in enumerate(pages) :
       
   257                 if pagination_required and cur_page > 0 :
       
   258                     shorturl = "%s/%s" % (self.shorturl_code, cur_page+1)
       
   259                 else :
       
   260                     shorturl = self.shorturl_code
       
   261 
       
   262                 # render to index.html
       
   263                 gallery_tpl.render_to(self.pathFor(url_for_page(cur_page)), 
       
   264                     stylesheet_url               = self.inRoot('style.css'),
       
   265                     title                        = self.title,
       
   266                     breadcrumb                   = self.breadcrumb(),
       
   267                     
       
   268                     dirs                         = subdirs,
       
   269                     images                       = images,
       
   270                     
       
   271                     num_pages                    = len(pages),
       
   272                     cur_page                     = cur_page,
       
   273                     
       
   274                     description                  = self.descr,
       
   275                     
       
   276                     shorturl                     = self.inRoot('s', shorturl),
       
   277                     shorturl_code                = shorturl,
       
   278                 )
       
   279         
       
   280         # render images
       
   281         for img in self.images.itervalues() :
       
   282             img.render()
       
   283         
       
   284         # recurse into subdirs
       
   285         for dir in self.subdirs.itervalues() :
       
   286             dir.render()
       
   287