Compare commits

..

No commits in common. "main" and "v0.0.2b" have entirely different histories.

9 changed files with 136 additions and 178 deletions

15
LICENSE
View file

@ -1,5 +1,3 @@
SOFTWARE
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2014 - Scott Boone Copyright (c) 2014 - Scott Boone
@ -20,16 +18,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE. IN THE SOFTWARE.
===
IMAGES
All example images copyright (c) 2014 - Scott Boone
They are licensed under Creative Commons Attribution 4.0 International:
http://creativecommons.org/licenses/by/4.0/legalcode
This license allows others to distribute, remix, tweak, and build upon this
work, even commercially, as long as they provide credit for the original
creation.

View file

@ -7,8 +7,7 @@ Colorbox/Galleria static site generator.
##How To ##How To
1. Add this package to your Pelican plugins directory. 1. Add this package to your Pelican plugins directory.
2. Add 'siglican' to PLUGINS in pelicanconf.py. Add SIGLICAN_ settings to 2. Add 'siglican' to PLUGINS in pelicanconf.py. Add SIGLICAN_ settings to
pelicanconf.py as desired (see "Pelican Configuration Settings" below for pelicanconf.py as desired.
a complete list).
3. Create a *siglican* directory in your base directory, at the same level as 3. Create a *siglican* directory in your base directory, at the same level as
*content*. *content*.
4. Drag gallery.md from examples to your pelican *pages* directory and edit it. 4. Drag gallery.md from examples to your pelican *pages* directory and edit it.
@ -22,9 +21,7 @@ Colorbox/Galleria static site generator.
That will give your siglican theme a way to inject gallery-specific css and That will give your siglican theme a way to inject gallery-specific css and
javascript into your gallery pages. javascript into your gallery pages.
8. Create an 'images' folder under 'siglican'. Add album folders along with 8. Create an 'images' folder under 'siglican'. Add album folders along with
images and metadata. See *examples/images* for simple examples or the images and metadata.
[Sigal documentation](http://sigal.readthedocs.org/en/latest/) for more
details.
###Example directory excerpt: ###Example directory excerpt:
``` ```

View file

@ -33,11 +33,9 @@ import os
import logging import logging
from collections import defaultdict from collections import defaultdict
from PIL import Image as PILImage
from .compat import strxfrm, UnicodeMixin, url_quote from .compat import strxfrm, UnicodeMixin, url_quote
from .utils import read_markdown, url_from_path from .utils import read_markdown, url_from_path
from .image import process_image, get_exif_tags
class Media(UnicodeMixin): class Media(UnicodeMixin):
"""Base Class for media files. """Base Class for media files.
@ -84,7 +82,22 @@ class Media(UnicodeMixin):
@property @property
def thumbnail(self): def thumbnail(self):
"""Path to the thumbnail image (relative to the album directory).""" """Path to the thumbnail image (relative to the album directory)."""
# cleanup: make this deal better with SIGLICAN_MAKE_THUMBS: False
if not os.path.isfile(self.thumb_path):
# if thumbnail is missing (if settings['make_thumbs'] is False)
if self.type == 'image':
generator = image.generate_thumbnail
elif self.type == 'video':
generator = video.generate_thumbnail
self.logger.debug('siglican: Generating thumbnail for %r', self)
try:
generator(self.src_path, self.thumb_path,
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
return url_from_path(self.thumb_name) return url_from_path(self.thumb_name)
def _get_metadata(self): def _get_metadata(self):
@ -397,3 +410,81 @@ def get_thumb(settings, filename):
ext = '.jpg' ext = '.jpg'
return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] + return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] +
name + settings['SIGLICAN_THUMB_SUFFIX'] + ext) name + settings['SIGLICAN_THUMB_SUFFIX'] + ext)
def get_exif_tags(source):
"""Read EXIF tags from file @source and return a tuple of two dictionaries,
the first one containing the raw EXIF data, the second one a simplified
version with common tags.
"""
logger = logging.getLogger(__name__)
if os.path.splitext(source)[1].lower() not in ('.jpg', '.jpeg'):
return (None, None)
try:
data = _get_exif_data(source)
except (IOError, IndexError, TypeError, AttributeError):
logger.warning(u'Could not read EXIF data from %s', source)
return (None, None)
simple = {}
# Provide more accessible tags in the 'simple' key
if 'FNumber' in data:
fnumber = data['FNumber']
simple['fstop'] = float(fnumber[0]) / fnumber[1]
if 'FocalLength' in data:
focal = data['FocalLength']
simple['focal'] = round(float(focal[0]) / focal[1])
if 'ExposureTime' in data:
if isinstance(data['ExposureTime'], tuple):
simple['exposure'] = '{0}/{1}'.format(*data['ExposureTime'])
elif isinstance(data['ExposureTime'], int):
simple['exposure'] = str(data['ExposureTime'])
else:
logger.warning('Unknown format for ExposureTime: %r (%s)',
data['ExposureTime'], source)
if 'ISOSpeedRatings' in data:
simple['iso'] = data['ISOSpeedRatings']
if 'DateTimeOriginal' in data:
try:
# Remove null bytes at the end if necessary
date = data['DateTimeOriginal'].rsplit('\x00')[0]
simple['dateobj'] = datetime.strptime(date, '%Y:%m:%d %H:%M:%S')
dt = simple['dateobj'].strftime('%A, %d. %B %Y')
if compat.PY2:
simple['datetime'] = dt.decode('utf8')
else:
simple['datetime'] = dt
except (ValueError, TypeError) as e:
logger.warning(u'Could not parse DateTimeOriginal of %s: %s',
source, e)
if 'GPSInfo' in data:
info = data['GPSInfo']
lat_info = info.get('GPSLatitude')
lon_info = info.get('GPSLongitude')
lat_ref_info = info.get('GPSLatitudeRef')
lon_ref_info = info.get('GPSLongitudeRef')
if lat_info and lon_info and lat_ref_info and lon_ref_info:
try:
lat = dms_to_degrees(lat_info)
lon = dms_to_degrees(lon_info)
except (ZeroDivisionError, ValueError):
logger.warning('Failed to read GPS info for %s', source)
lat = lon = None
if lat and lon:
simple['gps'] = {
'lat': - lat if lat_ref_info != 'N' else lat,
'lon': - lon if lon_ref_info != 'E' else lon,
}
return (data, simple)

View file

@ -4,7 +4,7 @@
{% block content %} {% block content %}
<h2>albums</h2> <h2>albums</h2>
<ul> <ul>
{% for aname,album in ALBUMS.items() %} {% for aname,album in ALBUMS.iteritems() %}
<li>{{ aname }}<a href="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.url }}"><img src="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.thumbnail }}"></a> <li>{{ aname }}<a href="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.url }}"><img src="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.thumbnail }}"></a>
{% endfor %} {% endfor %}
</ul> </ul>

View file

@ -1,3 +0,0 @@
To make this play nicely with limited modification, move siglican_gallery.html
to your Pelican template. This will provide an entry point to colorbox which is
driven by album.html here.

View file

@ -1,17 +0,0 @@
{% extends "base.html" %}
{% block content %}
<h2>albums</h2>
<hr>
<div class="row">
{% for aname,album in ROOT_ALBUMS.iteritems() %}
{% if loop.last %}
<div class="four columns end" style="text-align:right;">
{% else %}
<div class="four columns" style="text-align:right;">
{% endif %}
<a href="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.url }}"><img src="{{ SITEURL }}/{{ SIGLICAN_DESTINATION }}/{{ album.thu
mbnail }}"><br>{{ aname }}</a><p>
</div>
{% endfor %}
</div>
{% endblock %}

View file

@ -48,6 +48,7 @@ from pilkit.processors import Transpose
from pilkit.utils import save_image from pilkit.utils import save_image
from . import compat #, signals from . import compat #, signals
from .album import Video
def _has_exif_tags(img): def _has_exif_tags(img):
return hasattr(img, 'info') and 'exif' in img.info return hasattr(img, 'info') and 'exif' in img.info
@ -176,84 +177,6 @@ def dms_to_degrees(v):
s = float(v[2][0]) / float(v[2][1]) s = float(v[2][0]) / float(v[2][1])
return d + (m / 60.0) + (s / 3600.0) return d + (m / 60.0) + (s / 3600.0)
def get_exif_tags(source):
"""Read EXIF tags from file @source and return a tuple of two dictionaries,
the first one containing the raw EXIF data, the second one a simplified
version with common tags.
"""
logger = logging.getLogger(__name__)
if os.path.splitext(source)[1].lower() not in ('.jpg', '.jpeg'):
return (None, None)
try:
data = _get_exif_data(source)
except (IOError, IndexError, TypeError, AttributeError):
logger.warning(u'Could not read EXIF data from %s', source)
return (None, None)
simple = {}
# Provide more accessible tags in the 'simple' key
if 'FNumber' in data:
fnumber = data['FNumber']
simple['fstop'] = float(fnumber[0]) / fnumber[1]
if 'FocalLength' in data:
focal = data['FocalLength']
simple['focal'] = round(float(focal[0]) / focal[1])
if 'ExposureTime' in data:
if isinstance(data['ExposureTime'], tuple):
simple['exposure'] = '{0}/{1}'.format(*data['ExposureTime'])
elif isinstance(data['ExposureTime'], int):
simple['exposure'] = str(data['ExposureTime'])
else:
logger.warning('Unknown format for ExposureTime: %r (%s)',
data['ExposureTime'], source)
if 'ISOSpeedRatings' in data:
simple['iso'] = data['ISOSpeedRatings']
if 'DateTimeOriginal' in data:
try:
# Remove null bytes at the end if necessary
date = data['DateTimeOriginal'].rsplit('\x00')[0]
simple['dateobj'] = datetime.strptime(date, '%Y:%m:%d %H:%M:%S')
dt = simple['dateobj'].strftime('%A, %d. %B %Y')
if compat.PY2:
simple['datetime'] = dt.decode('utf8')
else:
simple['datetime'] = dt
except (ValueError, TypeError) as e:
logger.warning(u'Could not parse DateTimeOriginal of %s: %s',
source, e)
if 'GPSInfo' in data:
info = data['GPSInfo']
lat_info = info.get('GPSLatitude')
lon_info = info.get('GPSLongitude')
lat_ref_info = info.get('GPSLatitudeRef')
lon_ref_info = info.get('GPSLongitudeRef')
if lat_info and lon_info and lat_ref_info and lon_ref_info:
try:
lat = dms_to_degrees(lat_info)
lon = dms_to_degrees(lon_info)
except (ZeroDivisionError, ValueError):
logger.warning('Failed to read GPS info for %s', source)
lat = lon = None
if lat and lon:
simple['gps'] = {
'lat': - lat if lat_ref_info != 'N' else lat,
'lon': - lon if lon_ref_info != 'E' else lon,
}
return (data, simple)
def get_thumb(settings, filename): def get_thumb(settings, filename):
"""Return the path to the thumb. """Return the path to the thumb.
@ -272,8 +195,7 @@ def get_thumb(settings, filename):
path, filen = os.path.split(filename) path, filen = os.path.split(filename)
name, ext = os.path.splitext(filen) name, ext = os.path.splitext(filen)
# TODO: replace this list with Video.extensions github #16 if ext.lower() in Video.extensions:
if ext.lower() in ('.mov', '.avi', '.mp4', '.webm', '.ogv'):
ext = '.jpg' ext = '.jpg'
return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] + return os.path.join(path, settings['SIGLICAN_THUMB_DIR'], settings['SIGLICAN_THUMB_PREFIX'] +
name + settings['SIGLICAN_THUMB_SUFFIX'] + ext) name + settings['SIGLICAN_THUMB_SUFFIX'] + ext)

View file

@ -1,7 +1,7 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
# Copyright (c) 2014 - Scott Boone # Copyright (c) 2014 - Scott Boone
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights # in the Software without restriction, including without limitation the rights
@ -11,7 +11,7 @@
# #
# The above copyright notice and this permission notice shall be included in # The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. # all copies or substantial portions of the Software.
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -20,8 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
from __future__ import print_function
import os import os
import sys import sys
import locale import locale
@ -37,7 +35,7 @@ from .writer import Writer
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Default config from Sigal's settings module. These have been changed to # Default config from Sigal's settings module. These have been changed to
# upper case because Pelican does not recognize lower case configuration names. # upper case because Pelican does not recognize lower case configuration names.
# note: if a default is changed, please also update README.md # note: if a default is changed, please also update README.md
_DEFAULT_SIGLICAN_SETTINGS = { _DEFAULT_SIGLICAN_SETTINGS = {
@ -83,9 +81,9 @@ class SigalGalleryGenerator(Generator):
# reference: methods provided by Pelican Generator: # reference: methods provided by Pelican Generator:
# def _update_context(self, items): adds more items to the context dict # def _update_context(self, items): adds more items to the context dict
# def get_template(self, name): returns templates from theme based on theme # def get_template(self, name): returns templates from theme based on theme
# def get_files(self, paths, exclude=[], extensions=None): paths to search, # def get_files(self, paths, exclude=[], extensions=None): paths to search,
# exclude, allowed extensions # exclude, allowed extensions
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Initialize gallery dict and load in custom Sigal settings.""" """Initialize gallery dict and load in custom Sigal settings."""
@ -94,27 +92,27 @@ class SigalGalleryGenerator(Generator):
# this needs to be first to establish pelican settings: # this needs to be first to establish pelican settings:
super(SigalGalleryGenerator, self).__init__(*args, **kwargs) super(SigalGalleryGenerator, self).__init__(*args, **kwargs)
# add default sigal settings to generator settings: # add default sigal settings to generator settings:
for k in list(_DEFAULT_SIGLICAN_SETTINGS.keys()): for k in _DEFAULT_SIGLICAN_SETTINGS.keys()[:]:
self.settings[k] = self.settings.get(k, _DEFAULT_SIGLICAN_SETTINGS[k]) self.settings[k] = self.settings.get(k, _DEFAULT_SIGLICAN_SETTINGS[k])
#logger.debug("sigal.pelican: setting %s: %s",k,self.settings[k]) logger.debug("sigal.pelican: setting %s: %s",k,self.settings[k])
self._clean_settings() self._clean_settings()
# this is where we could create a signal if we wanted to, e.g.: # this is where we could create a signal if we wanted to, e.g.:
# signals.gallery_generator_init.send(self) # signals.gallery_generator_init.send(self)
def _clean_settings(self): def _clean_settings(self):
"""Checks existence of directories and normalizes image size settings.""" """Checks existence of directories and normalizes image size settings."""
# create absolute paths to source, theme and destination directories: # create absolute paths to source, theme and destination directories:
init_source = self.settings['SIGLICAN_SOURCE'] init_source = self.settings['SIGLICAN_SOURCE']
self.settings['SIGLICAN_SOURCE'] = os.path.normpath(self.settings['PATH'] + self.settings['SIGLICAN_SOURCE'] = os.path.normpath(self.settings['PATH'] +
"/../" + self.settings['SIGLICAN_SOURCE'] + '/images') "/../" + self.settings['SIGLICAN_SOURCE'] + '/images')
self.settings['SIGLICAN_THEME'] = os.path.normpath(self.settings['PATH'] + self.settings['SIGLICAN_THEME'] = os.path.normpath(self.settings['PATH'] +
"/../" + init_source + "/" + self.settings['SIGLICAN_THEME']) "/../" + init_source + "/" + self.settings['SIGLICAN_THEME'])
self.settings['SIGLICAN_DESTINATION'] = os.path.normpath( self.settings['SIGLICAN_DESTINATION'] = os.path.normpath(
self.settings['OUTPUT_PATH'] + "/" + self.settings['SIGLICAN_DESTINATION']) self.settings['OUTPUT_PATH'] + "/" + self.settings['SIGLICAN_DESTINATION'])
enc = locale.getpreferredencoding() if PY2 else None enc = locale.getpreferredencoding() if PY2 else None
# test for existence of source directories # test for existence of source directories
pathkeys = ['SIGLICAN_SOURCE', 'SIGLICAN_THEME'] pathkeys = ['SIGLICAN_SOURCE', 'SIGLICAN_THEME']
for k in pathkeys: for k in pathkeys:
@ -127,7 +125,7 @@ class SigalGalleryGenerator(Generator):
logger.error("siglican: missing source directory %s: %s", logger.error("siglican: missing source directory %s: %s",
k,self.settings[k]) k,self.settings[k])
sys.exit(1) sys.exit(1)
# normalize sizes as e landscape # normalize sizes as e landscape
for key in ('SIGLICAN_IMG_SIZE', 'SIGLICAN_THUMB_SIZE', 'SIGLICAN_VIDEO_SIZE'): for key in ('SIGLICAN_IMG_SIZE', 'SIGLICAN_THUMB_SIZE', 'SIGLICAN_VIDEO_SIZE'):
w, h = self.settings[key] w, h = self.settings[key]
@ -135,11 +133,11 @@ class SigalGalleryGenerator(Generator):
self.settings[key] = (h, w) self.settings[key] = (h, w)
logger.warning("siglican: The %s setting should be specified " logger.warning("siglican: The %s setting should be specified "
"with the largest value first.", key) "with the largest value first.", key)
if not self.settings['SIGLICAN_IMG_PROCESSOR']: if not self.settings['SIGLICAN_IMG_PROCESSOR']:
logger.info('No Processor, images will not be resized') logger.info('No Processor, images will not be resized')
# based on Sigal's Gallery.__init__() method: # based on Sigal's Gallery.__init__() method:
def generate_context(self): def generate_context(self):
""""Update the global Pelican context that's shared between generators.""" """"Update the global Pelican context that's shared between generators."""
@ -174,66 +172,55 @@ class SigalGalleryGenerator(Generator):
for d in dirs[:]: for d in dirs[:]:
path = os.path.join(relpath, d) if relpath != '.' else d path = os.path.join(relpath, d) if relpath != '.' else d
if path not in self.albums.keys(): if path not in self.albums.keys():
dirs.remove(d) dirs.remove(d)
album = Album(relpath, self.settings, dirs, files, self) album = Album(relpath, self.settings, dirs, files, self)
if not album.medias and not album.albums: if not album.medias and not album.albums:
logger.info('siglican: Skip empty album: %r', album) logger.info('siglican: Skip empty album: %r', album)
else: else:
self.albums[relpath] = album self.albums[relpath] = album
# done generating context (self.albums) now # done generating context (self.albums) now
logger.debug('siglican: albums:\n%r', self.albums.values()) logger.debug('siglican: albums:\n%r', self.albums.values())
# update the jinja context so that templates can access it: # update the jinja context so that templates can access it:
#self._update_context(('albums', )) # unnecessary? ** #self._update_context(('albums', )) # unnecessary? **
self.context['ALBUMS'] = self.albums # ** change to SIGLICAN_ALBUMS? self.context['ALBUMS'] = self.albums # ** change to SIGLICAN_ALBUMS?
root_albums = {}
for k,v in self.albums.items():
if os.sep not in v.path:
root_albums[k] = v
self.context['ROOT_ALBUMS'] = root_albums
# update the jinja context with the default sigal settings: # update the jinja context with the default sigal settings:
for k,v in _DEFAULT_SIGLICAN_SETTINGS.items(): for k,v in _DEFAULT_SIGLICAN_SETTINGS.iteritems():
if not k in self.context: if not k in self.context:
self.context[k] = v self.context[k] = v
def generate_output(self, writer): def generate_output(self, writer):
""" Creates gallery destination directories, thumbnails, resized """ Creates gallery destination directories, thumbnails, resized
images, and moves everything into the destination.""" images, and moves everything into the destination."""
# note: ignore the writer sent by Pelican because it's not certain # note: ignore the writer sent by Pelican because it's not certain
# which Writer it will send. if another active plugin also implements # which Writer it will send. if another active plugin also implements
# Writer, Pelican may send that instead of one of its core Writers. # Writer, Pelican may send that instead of one of its core Writers.
# I logged a feature request here: # I logged a feature request here:
# https://github.com/getpelican/pelican/issues/1459 # https://github.com/getpelican/pelican/issues/1459
# create destination directory # create destination directory
if not os.path.isdir(self.settings['SIGLICAN_DESTINATION']): if not os.path.isdir(self.settings['SIGLICAN_DESTINATION']):
os.makedirs(self.settings['SIGLICAN_DESTINATION']) os.makedirs(self.settings['SIGLICAN_DESTINATION'])
# github7 ** improve exception catching # github7 ** improve exception catching
# github8 ** re-integrate multiprocessing logic from Sigal # github8 ** re-integrate multiprocessing logic from Sigal
# generate thumbnails, process images, and move them to the destination # generate thumbnails, process images, and move them to the destination
if logger.getEffectiveLevel() > logging.INFO:
print('siglican is processing media: ', end='')
sys.stdout.flush()
albums = self.albums albums = self.albums
for a in albums: for a in albums:
logger.info("siglican: processing album: %s",a) logger.debug("siglican: creating directory for %s",a)
albums[a].create_output_directories() albums[a].create_output_directories()
for media in albums[a].medias: for media in albums[a].medias:
if logger.getEffectiveLevel() > logging.INFO: logger.debug("siglican: processing %r , source: %s, dst: %s",
print('.', end='') media,media.src_path,media.dst_path)
sys.stdout.flush()
if os.path.isfile(media.dst_path): if os.path.isfile(media.dst_path):
logger.info("siglican: %s exists - skipping", media.filename) logger.info("siglican: %s exists - skipping", media.filename)
self.stats[media.type + '_skipped'] += 1 self.stats[media.type + '_skipped'] += 1
else: else:
logger.info("siglican: processing %r , source: %s, dst: %s",
media,media.src_path,media.dst_path)
self.stats[media.type] += 1 self.stats[media.type] += 1
logger.debug("MEDIA TYPE: %s",media.type) logger.debug("MEDIA TYPE: %s",media.type)
# create/move resized images and thumbnails to output dirs: # create/move resized images and thumbnails to output dirs:
@ -243,9 +230,7 @@ class SigalGalleryGenerator(Generator):
elif media.type == 'video': elif media.type == 'video':
process_video(media.src_path,os.path.dirname( process_video(media.src_path,os.path.dirname(
media.dst_path),self.settings) media.dst_path),self.settings)
if logger.getEffectiveLevel() > logging.INFO:
print('')
# generate the index.html files for the albums # generate the index.html files for the albums
if self.settings['SIGLICAN_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 # locate the theme; check for a custom theme in ./sigal/themes, if not
@ -260,21 +245,19 @@ class SigalGalleryGenerator(Generator):
if not os.path.exists(self.theme): if not os.path.exists(self.theme):
raise Exception("siglican: unable to find theme: %s" % raise Exception("siglican: unable to find theme: %s" %
os.path.basename(self.theme)) os.path.basename(self.theme))
logger.info("siglican theme: %s", self.theme) logger.info("siglican theme: %s", self.theme)
self.writer = Writer(self.context, self.theme, 'album') self.writer = Writer(self.context, self.theme, 'album')
for album in self.albums.values(): for album in self.albums.values():
self.writer.write(album) self.writer.write(album)
## possible cleanup: ## possible cleanup:
## - bring back Writer options that Sigal had? ## - bring back Writer options that Sigal had?
## - make sure thumbnails don't break in some cases [fixed?] ## - make sure thumbnails don't break in some cases [fixed?]
def get_generators(generators): def get_generators(generators):
return SigalGalleryGenerator return SigalGalleryGenerator
def register(): def register():
signals.get_generators.connect(get_generators) signals.get_generators.connect(get_generators)

View file

@ -30,6 +30,7 @@ import shutil
from os.path import splitext from os.path import splitext
from . import image from . import image
from .album import Video
from .utils import call_subprocess from .utils import call_subprocess
# TODO: merge with image.py # TODO: merge with image.py
@ -169,8 +170,7 @@ def get_thumb(settings, filename):
path, filen = os.path.split(filename) path, filen = os.path.split(filename)
name, ext = os.path.splitext(filen) name, ext = os.path.splitext(filen)
# TODO: replace this list with Video.extensions github #16 if ext.lower() in Video.extensions:
if ext.lower() in ('.mov', '.avi', '.mp4', '.webm', '.ogv'):
ext = '.jpg' ext = '.jpg'
return os.path.join(path, settings['thumb_dir'], settings['thumb_prefix'] + return os.path.join(path, settings['thumb_dir'], settings['thumb_prefix'] +
name + settings['thumb_suffix'] + ext) name + settings['thumb_suffix'] + ext)