degal/folder.py
changeset 70 67dd32adf159
parent 64 4ebd563214d2
child 76 e22d9f699081
equal deleted inserted replaced
69:5b53fe294034 70:67dd32adf159
   112             return self.subfile("index.html")
   112             return self.subfile("index.html")
   113     
   113     
   114     def index (self) :
   114     def index (self) :
   115         """
   115         """
   116             Recursively index this Folder, yielding a series of all Folder objects inside.
   116             Recursively index this Folder, yielding a series of all Folder objects inside.
       
   117 
       
   118             XXX: not used
   117         """
   119         """
   118         
   120         
   119         # and subfolders
   121         # and subfolders
   120         for subfolder in self.subfolders :
   122         for subfolder in self.subfolders :
   121             yield subfolder
   123             yield subfolder
   122 
   124 
   123             for item in subfolder.index_subfolders() :
   125             for item in subfolder.index_subfolders() :
   124                 yield item
   126                 yield item
   125    
   127    
   126 class Folder (object) :
       
   127     def __init__ (self, name='.', parent=None) :
       
   128         # the directory name, no trailing /
       
   129         self.name = unicode(name.rstrip(os.sep))
       
   130 
       
   131         # our parent Folder, or None
       
   132         self.parent = parent
       
   133 
       
   134         # the path to this dir, as a relative path to the root of the image gallery, always starts with .
       
   135         if parent and name :
       
   136             self.path = parent.pathFor(self.name)
       
   137         else :
       
   138             self.path = self.name
       
   139 
       
   140         # the url-path to the index.html file
       
   141         self.html_path = self.path
       
   142         
       
   143         # dict of fname -> Folder
       
   144         self.subdirs = {}
       
   145 
       
   146         # dict of fname -> Image
       
   147         self.images = {}
       
   148         
       
   149         # our human-friendly title
       
   150         self.title = None
       
   151 
       
   152         # our long-winded description
       
   153         self.descr = ''
       
   154 
       
   155         # is this folder non-empty?
       
   156         self.alive = None
       
   157         
       
   158         # self.images.values(), but sorted by filename
       
   159         self.sorted_images = []
       
   160         
       
   161         # the ShortURL key to this dir
       
   162         self.shorturl_code = None
       
   163 
       
   164         # were we filtered out?
       
   165         self.filtered = False
       
   166    
       
   167     def pathFor (self, *fnames) :
       
   168         """
       
   169             Return a root-relative path to the given path inside this dir
       
   170         """
       
   171         return os.path.join(self.path, *fnames)
       
   172 
       
   173     def index (self, filters=None) :
       
   174         """
       
   175             Look for other dirs and images inside this dir. Filters must be either None,
       
   176             whereupon all files will be included, or a dict of {filename -> next_filter}.
       
   177             If given, only filenames that are present in the dict will be indexed, and in
       
   178             the case of dirs, the next_filter will be passed on to that Folder's index
       
   179             method.
       
   180         """
       
   181 
       
   182         if filters :
       
   183             self.filtered = True
       
   184         
       
   185         # iterate through listdir
       
   186         for fname in os.listdir(self.path) :
       
   187             # the full filesystem path to it
       
   188             fpath = self.pathFor(fname)
       
   189             
       
   190             # ignore dotfiles
       
   191             if fname.startswith('.') :
       
   192                 log.debug("Skipping dotfile %s", fname)
       
   193                 continue
       
   194             
       
   195             # apply filters
       
   196             if filters :
       
   197                 if fname in filters :
       
   198                     next_filter = filters[fname]
       
   199                 else :
       
   200                     log.debug("Skip `%s' as we have a filter", fname)
       
   201                     continue
       
   202             else :
       
   203                 next_filter = None
       
   204                 
       
   205             # recurse into subdirs, but not thumbs/previews
       
   206             if (os.path.isdir(fpath) 
       
   207                 and (fname not in (settings.THUMB_DIR, settings.PREVIEW_DIR))
       
   208                 and (self.parent or fname not in settings.ROOT_IGNORE)
       
   209             ) :
       
   210                 log.down(fname)
       
   211 
       
   212                 f = Folder(fname, self)
       
   213                 
       
   214                 try :
       
   215                     if f.index(next_filter) :   # recursion
       
   216                         # if a subdir is alive, we are alive as well
       
   217                         self.subdirs[fname] = f
       
   218                         self.alive = True
       
   219                 except Exception, e :
       
   220                     log.warning("skip - %s: %s" % (type(e), e))
       
   221 
       
   222                 log.up()
       
   223 
       
   224             # handle images
       
   225             elif os.path.isfile(fpath) and utils.isImage(fname) :
       
   226                 log.next(fname)
       
   227                 self.images[fname] = image.Image(self, fname)
       
   228 
       
   229             # ignore everything else
       
   230             else :
       
   231                 log.debug("Ignoring file %s", fname)
       
   232         
       
   233         # sort and link the images
       
   234         if self.images :
       
   235             self.alive = True
       
   236 
       
   237             # sort the images
       
   238             fnames = self.images.keys()
       
   239             fnames.sort()
       
   240 
       
   241             prev = None
       
   242 
       
   243             # link
       
   244             for fname in fnames :
       
   245                 img = self.images[fname]
       
   246 
       
   247                 img.prev = prev
       
   248 
       
   249                 if prev :
       
   250                     prev.next = img
       
   251 
       
   252                 prev = img
       
   253                 
       
   254                 # add to the sorted images list
       
   255                 self.sorted_images.append(img)
       
   256                 
       
   257         # figure out our title/ descr. Must be done before our parent dir is rendered (self.title)
       
   258         title_path = self.pathFor(settings.TITLE_FILE)
       
   259         
       
   260         self.title, self.descr = utils.readTitleDescr(title_path)
       
   261         
       
   262         # default title for the root dir
       
   263         if self.title or self.descr :
       
   264             self.alive = True
       
   265             pass # use what was in the title file
       
   266             
       
   267         elif not self.parent :
       
   268             self.title = 'Index'
       
   269 
       
   270         else :
       
   271             self.title = self.name
       
   272         
       
   273         if not self.alive :
       
   274             log.debug("Dir %s isn't alive" % self.path)
       
   275 
       
   276         return self.alive
       
   277 
       
   278     def getObjInfo (self) :
       
   279         """
       
   280             Metadata for shorturls2.db
       
   281         """
       
   282         return 'dir', self.path, ''
       
   283 
       
   284     def breadcrumb (self, forImg=None) :
       
   285         """
       
   286             Returns a [(fname, title)] list of this dir's parent dirs
       
   287         """
       
   288 
       
   289         f = self
       
   290         b = []
       
   291         d = 0
       
   292         
       
   293         while f :
       
   294             # functionality of the slightly-hacked-in variety
       
   295             if f is self and forImg is not None :
       
   296                 url = helpers.url_for_page(self.getPageNumber(forImg))
       
   297             else :
       
   298                 url = dirUp(d)
       
   299                 
       
   300             b.insert(0, (url, f.title))
       
   301 
       
   302             d += 1
       
   303             f = f.parent
       
   304         
       
   305         return b
       
   306         
       
   307     def getPageNumber (self, img) :
       
   308         """
       
   309             Get the page number that the given image is on
       
   310         """
       
   311         
       
   312         return self.sorted_images.index(img) // settings.IMAGE_COUNT
       
   313 
       
   314     def countParents (self, acc=0) :
       
   315         if self.parent :
       
   316             return self.parent.countParents(acc+1)
       
   317         else :
       
   318             return acc
       
   319     
       
   320     def inRoot (self, *fnames) :
       
   321         """
       
   322             Return a relative URL from this dir to the given path in the root dir
       
   323         """
       
   324 
       
   325         c = self.countParents()
       
   326 
       
   327         return utils.url_join(*((['..']*c) + list(fnames)))
       
   328 
       
   329     def render (self) :
       
   330         """
       
   331             Render the index.html, Images, and recurse into subdirs
       
   332         """
       
   333         
       
   334         # ded folders are skipped
       
   335         if not self.alive :
       
   336             # dead, skip, no output
       
   337             return
       
   338         
       
   339         index_mtime = utils.mtime(self.pathFor("index.html"))
       
   340         dir_mtime = utils.mtime(self.path)
       
   341 
       
   342         # 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
       
   343         if self.filtered :
       
   344             log.warning("Dir `%s' contents were filtered, so we won't render the gallery index again", self.path)
       
   345 
       
   346         elif index_mtime > dir_mtime :
       
   347             # no changes, pass, ignored
       
   348             pass
       
   349 
       
   350         else :  
       
   351             # create the thumb/preview dirs if needed
       
   352             for dir in (settings.THUMB_DIR, settings.PREVIEW_DIR) :
       
   353                 path = self.pathFor(dir)
       
   354 
       
   355                 if not os.path.isdir(path) :
       
   356                     log.info("mkdir %s", dir)
       
   357                     os.mkdir(path)
       
   358 
       
   359             # sort the subdirs
       
   360             subdirs = self.subdirs.values()
       
   361             subdirs.sort(key=lambda d: d.name)
       
   362             
       
   363             # paginate!
       
   364             images = self.sorted_images
       
   365             image_count = len(images)
       
   366             pages = []
       
   367             
       
   368             while images :
       
   369                 pages.append(images[:settings.IMAGE_COUNT])
       
   370                 images = images[settings.IMAGE_COUNT:]
       
   371 
       
   372             pagination_required = len(pages) > 1
       
   373 
       
   374             if pagination_required :
       
   375                 log.info("%d pages @ %d images", len(pages), settings.IMAGE_COUNT)
       
   376             elif not pages :
       
   377                 log.info("no images, render for subdirs")
       
   378                 pages = [[]]
       
   379 
       
   380             for cur_page, images in enumerate(pages) :
       
   381                 if pagination_required and cur_page > 0 :
       
   382                     shorturl = "%s/%s" % (self.shorturl_code, cur_page+1)
       
   383                 else :
       
   384                     shorturl = self.shorturl_code
       
   385                 
       
   386                 # render to index.html
       
   387                 gallery_tpl.render_to(self.pathFor(url_for_page(cur_page)), 
       
   388                     stylesheet_url               = self.inRoot('style.css'),
       
   389                     title                        = self.title,
       
   390                     breadcrumb                   = self.breadcrumb(),
       
   391                     
       
   392                     dirs                         = subdirs,
       
   393                     images                       = images,
       
   394                     
       
   395                     num_pages                    = len(pages),
       
   396                     cur_page                     = cur_page,
       
   397                     
       
   398                     description                  = self.descr,
       
   399                     
       
   400                     shorturl                     = self.inRoot('s', shorturl),
       
   401                     shorturl_code                = shorturl,
       
   402                 )
       
   403 
       
   404         # render images
       
   405         image_count = len(self.sorted_images)
       
   406         for i, img in enumerate(self.images.itervalues()) :
       
   407             log.next("[%-4d/%4d] %s", i + 1, image_count, img.name)
       
   408 
       
   409             img.render()
       
   410         
       
   411         # recurse into subdirs
       
   412         for dir in self.subdirs.itervalues() :
       
   413             log.down(dir.name)
       
   414 
       
   415             dir.render()
       
   416 
       
   417             log.up()
       
   418