diff --git a/README.md b/README.md index 0465f1a..38e98dd 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ A static gallery generator plugin for Pelican, based on the Sigal Colorbox/Galleria static site generator. ##How To -1. Put the contents of this folder into your Pelican plugins directory. Add - 'siglican' to PLUGINS in pelicanconf.py. +1. Put this folder into your Pelican plugins directory. Add 'siglican' to + PLUGINS in pelicanconf.py. 2. Create a 'siglican' directory in your base directory, at the same level as 'content'. Drag 'colorbox' or 'galleria' from the 'themes' directory into this folder. Also create an 'images' subdirectory under 'siglican'. @@ -30,9 +30,11 @@ Example directory tree: /templates/album.html ``` +##Pelican settings + ## To Do 1. Update galleria theme to work. -2. Change settings names to something other than SIGAL_* +2. Change settings names to something other than SIGLICAN_* 3. Unit tests. 4. Logging cleanup. 5. Update colorbox/galleria example themes to deal better with nested albums. diff --git a/album.py b/album.py index b5e8fd6..aaeb9ff 100644 --- a/album.py +++ b/album.py @@ -62,11 +62,11 @@ class Media(UnicodeMixin): self.path = path self.settings = settings - self.src_path = os.path.join(settings['SIGAL_SOURCE'], path, filename) - self.dst_path = os.path.join(settings['SIGAL_DESTINATION'], path, filename) + self.src_path = os.path.join(settings['SIGLICAN_SOURCE'], path, filename) + self.dst_path = os.path.join(settings['SIGLICAN_DESTINATION'], path, filename) self.thumb_name = get_thumb(self.settings, self.filename) - self.thumb_path = os.path.join(settings['SIGAL_DESTINATION'], path, self.thumb_name) + self.thumb_path = os.path.join(settings['SIGLICAN_DESTINATION'], path, self.thumb_name) self.logger = logging.getLogger(__name__) self.raw_exif = None @@ -95,8 +95,8 @@ class Media(UnicodeMixin): self.logger.debug('siglican: Generating thumbnail for %r', self) try: generator(self.src_path, self.thumb_path, - self.settings['SIGAL_THUMB_SIZE'], - fit=self.settings['SIGAL_THUMB_FIT']) + self.settings['SIGLICAN_THUMB_SIZE'], + fit=self.settings['SIGLICAN_THUMB_FIT']) except Exception as e: self.logger.error('siglican: Failed to generate thumbnail: %s', e) return @@ -139,7 +139,7 @@ class Video(Media): base = os.path.splitext(filename)[0] self.src_filename = filename self.filename = self.url = base + '.webm' - self.dst_path = os.path.join(settings['SIGAL_DESTINATION'], path, base + '.webm') + self.dst_path = os.path.join(settings['SIGLICAN_DESTINATION'], path, base + '.webm') # minimally modified from Sigal's gallery.Album class @@ -157,25 +157,25 @@ class Album(object): # set up source and destination paths if path == '.': - self.src_path = settings['SIGAL_SOURCE'] - self.dst_path = settings['SIGAL_DESTINATION'] + self.src_path = settings['SIGLICAN_SOURCE'] + self.dst_path = settings['SIGLICAN_DESTINATION'] else: - self.src_path = os.path.join(settings['SIGAL_SOURCE'], path) - self.dst_path = os.path.join(settings['SIGAL_DESTINATION'], path) + self.src_path = os.path.join(settings['SIGLICAN_SOURCE'], path) + self.dst_path = os.path.join(settings['SIGLICAN_DESTINATION'], path) self.logger = logging.getLogger(__name__) self._get_metadata() # this reads the index.md file # optionally add index.html to the URLs # ** don't understand purpose of this; default is False - self.url_ext = self.output_file if settings['SIGAL_INDEX_IN_URL'] else '' + self.url_ext = self.output_file if settings['SIGLICAN_INDEX_IN_URL'] else '' # creates appropriate subdirectory for the album self.index_url = url_from_path(os.path.relpath( - settings['SIGAL_DESTINATION'], self.dst_path)) + '/' + self.url_ext + settings['SIGLICAN_DESTINATION'], self.dst_path)) + '/' + self.url_ext # sort sub-albums - dirnames.sort(key=strxfrm, reverse=settings['SIGAL_ALBUMS_SORT_REVERSE']) + dirnames.sort(key=strxfrm, reverse=settings['SIGLICAN_ALBUMS_SORT_REVERSE']) self.subdirs = dirnames #: List of all medias in the album (:class:`~sigal.gallery.Image` and @@ -198,13 +198,13 @@ class Album(object): # sort images if medias: - medias_sort_attr = settings['SIGAL_MEDIAS_SORT_ATTR'] + medias_sort_attr = settings['SIGLICAN_MEDIAS_SORT_ATTR'] if medias_sort_attr == 'date': key = lambda s: s.date or datetime.now() else: key = lambda s: strxfrm(getattr(s, medias_sort_attr)) - medias.sort(key=key, reverse=settings['SIGAL_MEDIAS_SORT_REVERSE']) + medias.sort(key=key, reverse=settings['SIGLICAN_MEDIAS_SORT_REVERSE']) #signals.album_initialized.send(self) @@ -253,10 +253,10 @@ class Album(object): if self.medias: check_or_create_dir(os.path.join(self.dst_path, - self.settings['SIGAL_THUMB_DIR'])) + self.settings['SIGLICAN_THUMB_DIR'])) - #if self.medias and self.settings['SIGAL_KEEP_ORIG']: - # self.orig_path = os.path.join(self.dst_path, self.settings['SIGAL_ORIG_DIR']) + #if self.medias and self.settings['SIGLICAN_KEEP_ORIG']: + # self.orig_path = os.path.join(self.dst_path, self.settings['SIGLICAN_ORIG_DIR']) # check_or_create_dir(self.orig_path) @property @@ -368,13 +368,13 @@ class Album(object): archive with all original images of the corresponding directory. """ - zip_gallery = self.settings['SIGAL_ZIP_GALLERY'] + zip_gallery = self.settings['SIGLICAN_ZIP_GALLERY'] if zip_gallery and len(self) > 0: archive_path = os.path.join(self.dst_path, zip_gallery) archive = zipfile.ZipFile(archive_path, 'w') - if self.settings['SIGAL_ZIP_MEDIA_FORMAT'] == 'orig': + if self.settings['SIGLICAN_ZIP_MEDIA_FORMAT'] == 'orig': for p in self: archive.write(p.src_path, os.path.split(p.src_path)[1]) else: @@ -408,8 +408,8 @@ def get_thumb(settings, filename): if ext.lower() in Video.extensions: ext = '.jpg' - return os.path.join(path, settings['SIGAL_THUMB_DIR'], settings['SIGAL_THUMB_PREFIX'] + - name + settings['SIGAL_THUMB_SUFFIX'] + ext) + return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] + + name + settings['SIGLICAN_THUMB_SUFFIX'] + ext) def get_exif_tags(source): """Read EXIF tags from file @source and return a tuple of two dictionaries, diff --git a/compat.py b/compat.py index 5bef063..01d6697 100644 --- a/compat.py +++ b/compat.py @@ -20,8 +20,8 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -## ** TODO: use pelican's compatibility features in utils.py (which uses -## Django calls) +## ** TODO: consider switching to use pelican's compat features in utils.py +## (which uses Django calls) import locale import sys diff --git a/image.py b/image.py index 6f0d341..66d6a9f 100644 --- a/image.py +++ b/image.py @@ -68,13 +68,13 @@ def generate_image(source, outname, settings, options=None): img = PILImage.open(source) original_format = img.format - if settings['SIGAL_COPY_EXIF_DATA'] and settings['SIGAL_AUTOROTATE_IMAGES']: + if settings['SIGLICAN_COPY_EXIF_DATA'] and settings['SIGLICAN_AUTOROTATE_IMAGES']: logger.warning("The 'autorotate_images' and 'copy_exif_data' settings " "are not compatible because Sigal can't save the " "modified Orientation tag.") # Preserve EXIF data - if settings['SIGAL_COPY_EXIF_DATA'] and _has_exif_tags(img): + if settings['SIGLICAN_COPY_EXIF_DATA'] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: @@ -82,23 +82,23 @@ def generate_image(source, outname, settings, options=None): options['exif'] = img.info['exif'] # Rotate the img, and catch IOError when PIL fails to read EXIF - if settings['SIGAL_AUTOROTATE_IMAGES']: + if settings['SIGLICAN_AUTOROTATE_IMAGES']: try: img = Transpose().process(img) except (IOError, IndexError): pass # Resize the image - if settings['SIGAL_IMG_PROCESSOR']: + if settings['SIGLICAN_IMG_PROCESSOR']: try: - logger.debug('Processor: %s', settings['SIGAL_IMG_PROCESSOR']) + logger.debug('Processor: %s', settings['SIGLICAN_IMG_PROCESSOR']) processor_cls = getattr(pilkit.processors, - settings['SIGAL_IMG_PROCESSOR']) + settings['SIGLICAN_IMG_PROCESSOR']) except AttributeError: - logger.error('Wrong processor name: %s', settings['SIGAL_IMG_PROCESSOR']) + logger.error('Wrong processor name: %s', settings['SIGLICAN_IMG_PROCESSOR']) sys.exit() - processor = processor_cls(*settings['SIGAL_IMG_SIZE'], upscale=False) + processor = processor_cls(*settings['SIGLICAN_IMG_SIZE'], upscale=False) img = processor.process(img) # TODO ** delete (maintained from Sigal for reference) @@ -138,7 +138,7 @@ def process_image(filepath, outpath, settings): ext = os.path.splitext(filename)[1] if ext in ('.jpg', '.jpeg', '.JPG', '.JPEG'): - options = settings['SIGAL_JPG_OPTIONS'] + options = settings['SIGLICAN_JPG_OPTIONS'] elif ext == '.png': options = {'optimize': True} else: @@ -150,10 +150,10 @@ def process_image(filepath, outpath, settings): logger.error('Failed to process image: %s', e) return - if settings['SIGAL_MAKE_THUMBS']: + if settings['SIGLICAN_MAKE_THUMBS']: thumb_name = os.path.join(outpath, get_thumb(settings, filename)) - generate_thumbnail(outname, thumb_name, settings['SIGAL_THUMB_SIZE'], - fit=settings['SIGAL_THUMB_FIT'], options=options) + generate_thumbnail(outname, thumb_name, settings['SIGLICAN_THUMB_SIZE'], + fit=settings['SIGLICAN_THUMB_FIT'], options=options) def _get_exif_data(filename): @@ -197,6 +197,6 @@ def get_thumb(settings, filename): if ext.lower() in Video.extensions: ext = '.jpg' - return os.path.join(path, settings['SIGAL_THUMB_DIR'], settings['SIGAL_THUMB_PREFIX'] + - name + settings['SIGAL_THUMB_SUFFIX'] + ext) + return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] + + name + settings['SIGLICAN_THUMB_SUFFIX'] + ext) diff --git a/siglican.py b/siglican.py index dbcc023..9d75b72 100644 --- a/siglican.py +++ b/siglican.py @@ -37,43 +37,41 @@ logger = logging.getLogger(__name__) # Default config from Sigal's settings module. These have been changed to # upper case because Pelican does not recognize lower case configuration names. -_DEFAULT_SIGAL_SETTINGS = { - 'SIGAL_ALBUMS_SORT_REVERSE': False, - 'SIGAL_AUTOROTATE_IMAGES': True, - 'SIGAL_COLORBOX_COLUMN_SIZE': 4, - 'SIGAL_COPY_EXIF_DATA': False, - 'SIGAL_DESTINATION': 'gallery', - 'SIGAL_FILES_TO_COPY': (), -# 'GOOGLE_ANALYTICS': '', - 'SIGAL_IGNORE_DIRECTORIES': ['.'], # using a pelican theme template as base - 'SIGAL_IGNORE_FILES': [], - 'SIGAL_IMG_PROCESSOR': 'ResizeToFit', - 'SIGAL_IMG_SIZE': (640, 480), - 'SIGAL_INDEX_IN_URL': False, - 'SIGAL_JPG_OPTIONS': {'quality': 85, 'optimize': True, 'progressive': True}, -# 'SIGAL_KEEP_ORIG': False, - 'SIGAL_LINKS': '', - 'SIGAL_LOCALE': '', - 'SIGAL_MEDIAS_SORT_ATTR': 'filename', - 'SIGAL_MEDIAS_SORT_REVERSE': False, - 'SIGAL_MAKE_THUMBS': True, - 'SIGAL_ORIG_DIR': 'original', - 'SIGAL_ORIG_LINK': False, +_DEFAULT_SIGLICAN_SETTINGS = { + 'SIGLICAN_ALBUMS_SORT_REVERSE': False, + 'SIGLICAN_AUTOROTATE_IMAGES': True, + 'SIGLICAN_COLORBOX_COLUMN_SIZE': 4, + 'SIGLICAN_COPY_EXIF_DATA': False, + 'SIGLICAN_DESTINATION': 'gallery', + 'SIGLICAN_FILES_TO_COPY': (), + 'SIGLICAN_IGNORE_DIRECTORIES': ['.'], + 'SIGLICAN_IGNORE_FILES': [], + 'SIGLICAN_IMG_PROCESSOR': 'ResizeToFit', + 'SIGLICAN_IMG_SIZE': (640, 480), + 'SIGLICAN_INDEX_IN_URL': False, + 'SIGLICAN_JPG_OPTIONS': {'quality': 85, 'optimize': True, 'progressive': True}, + 'SIGLICAN_LINKS': '', + 'SIGLICAN_LOCALE': '', + 'SIGLICAN_MEDIAS_SORT_ATTR': 'filename', + 'SIGLICAN_MEDIAS_SORT_REVERSE': False, + 'SIGLICAN_MAKE_THUMBS': True, + 'SIGLICAN_ORIG_DIR': 'original', + 'SIGLICAN_ORIG_LINK': False, # 'PLUGINS': [], # 'PLUGIN_PATHS': [], - 'SIGAL_SOURCE': 'siglican', - 'SIGAL_THEME': 'colorbox', - 'SIGAL_THUMB_DIR': 'thumbs', - 'SIGAL_THUMB_FIT': True, - 'SIGAL_THUMB_PREFIX': '', - 'SIGAL_THUMB_SIZE': (200, 150), - 'SIGAL_THUMB_SUFFIX': '', - 'SIGAL_VIDEO_SIZE': (480, 360), - 'SIGAL_WEBM_OPTIONS': ['-crf', '10', '-b:v', '1.6M', - '-qmin', '4', '-qmax', '63'], - 'SIGAL_WRITE_HTML': True, - 'SIGAL_ZIP_GALLERY': False, - 'SIGAL_ZIP_MEDIA_FORMAT': 'resized', + 'SIGLICAN_SOURCE': 'siglican', + 'SIGLICAN_THEME': 'colorbox', + 'SIGLICAN_THUMB_DIR': 'thumbs', + 'SIGLICAN_THUMB_FIT': True, + 'SIGLICAN_THUMB_PREFIX': '', + 'SIGLICAN_THUMB_SIZE': (200, 150), + 'SIGLICAN_THUMB_SUFFIX': '', + 'SIGLICAN_VIDEO_SIZE': (480, 360), + 'SIGLICAN_WEBM_OPTIONS': ['-crf', '10', '-b:v', '1.6M', + '-qmin', '4', '-qmax', '63'], + 'SIGLICAN_WRITE_HTML': True, + 'SIGLICAN_ZIP_GALLERY': False, + 'SIGLICAN_ZIP_MEDIA_FORMAT': 'resized', } # Generator class used to generate plugin context and write. @@ -93,8 +91,8 @@ class SigalGalleryGenerator(Generator): # this needs to be first to establish pelican settings: super(SigalGalleryGenerator, self).__init__(*args, **kwargs) # add default sigal settings to generator settings: - for k in _DEFAULT_SIGAL_SETTINGS.keys()[:]: - self.settings[k] = self.settings.get(k, _DEFAULT_SIGAL_SETTINGS[k]) + for k in _DEFAULT_SIGLICAN_SETTINGS.keys()[:]: + self.settings[k] = self.settings.get(k, _DEFAULT_SIGLICAN_SETTINGS[k]) logger.debug("sigal.pelican: setting %s: %s",k,self.settings[k]) self._clean_settings() # this is where we could create a signal if we wanted to, e.g.: @@ -104,38 +102,38 @@ class SigalGalleryGenerator(Generator): """Checks existence of directories and normalizes image size settings.""" # create absolute paths to source, theme and destination directories: - init_source = self.settings['SIGAL_SOURCE'] - self.settings['SIGAL_SOURCE'] = os.path.normpath(self.settings['PATH'] + - "/../" + self.settings['SIGAL_SOURCE'] + '/images') - self.settings['SIGAL_THEME'] = os.path.normpath(self.settings['PATH'] + - "/../" + init_source + "/" + self.settings['SIGAL_THEME']) - self.settings['SIGAL_DESTINATION'] = os.path.normpath( - self.settings['OUTPUT_PATH'] + "/" + self.settings['SIGAL_DESTINATION']) + init_source = self.settings['SIGLICAN_SOURCE'] + self.settings['SIGLICAN_SOURCE'] = os.path.normpath(self.settings['PATH'] + + "/../" + self.settings['SIGLICAN_SOURCE'] + '/images') + self.settings['SIGLICAN_THEME'] = os.path.normpath(self.settings['PATH'] + + "/../" + init_source + "/" + self.settings['SIGLICAN_THEME']) + self.settings['SIGLICAN_DESTINATION'] = os.path.normpath( + self.settings['OUTPUT_PATH'] + "/" + self.settings['SIGLICAN_DESTINATION']) enc = locale.getpreferredencoding() if PY2 else None # test for existence of source directories - pathkeys = ['SIGAL_SOURCE', 'SIGAL_THEME'] + pathkeys = ['SIGLICAN_SOURCE', 'SIGLICAN_THEME'] for k in pathkeys: if os.path.isdir(self.settings[k]): # convert to unicode for os.walk dirname/filename if PY2 and isinstance(self.settings[k], str): self.settings[k] = self.settings[k].decode(enc) - logger.debug("siglican: %s = %s",k,self.settings[k]) + logger.info("%s = %s",k,self.settings[k]) else: logger.error("siglican: missing source directory %s: %s", k,self.settings[k]) sys.exit(1) # normalize sizes as e landscape - for key in ('SIGAL_IMG_SIZE', 'SIGAL_THUMB_SIZE', 'SIGAL_VIDEO_SIZE'): + for key in ('SIGLICAN_IMG_SIZE', 'SIGLICAN_THUMB_SIZE', 'SIGLICAN_VIDEO_SIZE'): w, h = self.settings[key] if h > w: self.settings[key] = (h, w) logger.warning("siglican: The %s setting should be specified " "with the largest value first.", key) - if not self.settings['SIGAL_IMG_PROCESSOR']: + if not self.settings['SIGLICAN_IMG_PROCESSOR']: logger.info('No Processor, images will not be resized') # based on Sigal's Gallery.__init__() method: @@ -143,14 +141,14 @@ class SigalGalleryGenerator(Generator): """"Update the global Pelican context that's shared between generators.""" logger.debug("siglican: in generate_context()") - locale.setlocale(locale.LC_ALL, self.settings['SIGAL_LOCALE']) + locale.setlocale(locale.LC_ALL, self.settings['SIGLICAN_LOCALE']) self.stats = {'image': 0, 'image_skipped': 0, 'video': 0, 'video_skipped': 0} # build the list of directories with images # ** TODO: add error checking, consider use of get(), etc. - src_path = self.settings['SIGAL_SOURCE'] - ignore_dirs = self.settings['SIGAL_IGNORE_DIRECTORIES'] - ignore_files = self.settings['SIGAL_IGNORE_FILES'] + src_path = self.settings['SIGLICAN_SOURCE'] + ignore_dirs = self.settings['SIGLICAN_IGNORE_DIRECTORIES'] + ignore_files = self.settings['SIGLICAN_IGNORE_FILES'] for path, dirs, files in os.walk(src_path, followlinks=True, topdown=False): relpath = os.path.relpath(path, src_path) @@ -191,7 +189,7 @@ class SigalGalleryGenerator(Generator): self.context['ALBUMS'] = self.albums # update the jinja context with the default sigal settings: - for k,v in _DEFAULT_SIGAL_SETTINGS.iteritems(): + for k,v in _DEFAULT_SIGLICAN_SETTINGS.iteritems(): if not k in self.context: self.context[k] = v @@ -209,8 +207,8 @@ class SigalGalleryGenerator(Generator): # page.gallery=gallery # create destination directory - if not os.path.isdir(self.settings['SIGAL_DESTINATION']): - os.makedirs(self.settings['SIGAL_DESTINATION']) + if not os.path.isdir(self.settings['SIGLICAN_DESTINATION']): + os.makedirs(self.settings['SIGLICAN_DESTINATION']) # TODO ** add lots of error/exception catching # TODO ** re-integrate multiprocessing logic from Sigal @@ -238,10 +236,10 @@ class SigalGalleryGenerator(Generator): media.dst_path),self.settings) # generate the index.html files for the albums - if self.settings['SIGAL_WRITE_HTML']: # defaults to True + if self.settings['SIGLICAN_WRITE_HTML']: # defaults to True # locate the theme; check for a custom theme in ./sigal/themes, if not # found, look for a default in siglican/themes - self.theme = self.settings['SIGAL_THEME'] + self.theme = self.settings['SIGLICAN_THEME'] default_themes = os.path.normpath(os.path.join( os.path.abspath(os.path.dirname(__file__)), 'themes')) #logger.debug("siglican: custom theme: %s", self.theme) diff --git a/themes/colorbox/templates/album.html b/themes/colorbox/templates/album.html index 9dd5c04..dcfbec4 100644 --- a/themes/colorbox/templates/album.html +++ b/themes/colorbox/templates/album.html @@ -10,15 +10,15 @@ {% block head %} {{ super() }} - + {% endblock %} {% block content %}