|
@@ -1,31 +1,58 @@
|
|
# -*- coding: utf-8 -*-
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import unicode_literals
|
|
from __future__ import unicode_literals
|
|
|
|
+
|
|
|
|
+import itertools
|
|
|
|
+import logging
|
|
import os
|
|
import os
|
|
|
|
+import pprint
|
|
import re
|
|
import re
|
|
-import logging
|
|
|
|
|
|
+
|
|
|
|
+from pelican.generators import ArticlesGenerator
|
|
|
|
+from pelican.generators import PagesGenerator
|
|
|
|
+from pelican.settings import DEFAULT_CONFIG
|
|
from pelican import signals
|
|
from pelican import signals
|
|
from pelican.utils import pelican_open
|
|
from pelican.utils import pelican_open
|
|
-from PIL import Image, ExifTags
|
|
|
|
-from itertools import chain
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger = logging.getLogger(__name__)
|
|
-queue_resize = dict()
|
|
|
|
-hrefs = None
|
|
|
|
|
|
|
|
-created_galleries = {}
|
|
|
|
|
|
+
|
|
|
|
+try:
|
|
|
|
+ from PIL import ExifTags
|
|
|
|
+ from PIL import Image
|
|
|
|
+ from PIL import ImageDraw
|
|
|
|
+ from PIL import ImageEnhance
|
|
|
|
+ from PIL import ImageFont
|
|
|
|
+except ImportError:
|
|
|
|
+ raise Exception('PIL/Pillow not found')
|
|
|
|
+
|
|
|
|
|
|
def initialized(pelican):
|
|
def initialized(pelican):
|
|
|
|
+
|
|
p = os.path.expanduser('~/Pictures')
|
|
p = os.path.expanduser('~/Pictures')
|
|
- from pelican.settings import DEFAULT_CONFIG
|
|
|
|
|
|
+
|
|
DEFAULT_CONFIG.setdefault('PHOTO_LIBRARY', p)
|
|
DEFAULT_CONFIG.setdefault('PHOTO_LIBRARY', p)
|
|
DEFAULT_CONFIG.setdefault('PHOTO_GALLERY', (1024, 768, 80))
|
|
DEFAULT_CONFIG.setdefault('PHOTO_GALLERY', (1024, 768, 80))
|
|
- DEFAULT_CONFIG.setdefault('PHOTO_ARTICLE', ( 760, 506, 80))
|
|
|
|
- DEFAULT_CONFIG.setdefault('PHOTO_THUMB', ( 192, 144, 60))
|
|
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_ARTICLE', (760, 506, 80))
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_THUMB', (192, 144, 60))
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_GALLERY_TITLE', '')
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_WATERMARK', 'False')
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_WATERMARK_TEXT', DEFAULT_CONFIG['SITENAME'])
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_WATERMARK_IMG', '')
|
|
|
|
+ DEFAULT_CONFIG.setdefault('PHOTO_WATERMARK_IMG_SIZE', (64, 64))
|
|
|
|
+
|
|
|
|
+ DEFAULT_CONFIG['queue_resize'] = {}
|
|
|
|
+ DEFAULT_CONFIG['created_galleries'] = {}
|
|
|
|
+
|
|
if pelican:
|
|
if pelican:
|
|
pelican.settings.setdefault('PHOTO_LIBRARY', p)
|
|
pelican.settings.setdefault('PHOTO_LIBRARY', p)
|
|
pelican.settings.setdefault('PHOTO_GALLERY', (1024, 768, 80))
|
|
pelican.settings.setdefault('PHOTO_GALLERY', (1024, 768, 80))
|
|
- pelican.settings.setdefault('PHOTO_ARTICLE', ( 760, 506, 80))
|
|
|
|
- pelican.settings.setdefault('PHOTO_THUMB', ( 192, 144, 60))
|
|
|
|
|
|
+ pelican.settings.setdefault('PHOTO_ARTICLE', (760, 506, 80))
|
|
|
|
+ pelican.settings.setdefault('PHOTO_THUMB', (192, 144, 60))
|
|
|
|
+ pelican.settings.setdefault('PHOTO_GALLERY_TITLE', '')
|
|
|
|
+ pelican.settings.setdefault('PHOTO_WATERMARK', 'False')
|
|
|
|
+ pelican.settings.setdefault('PHOTO_WATERMARK_TEXT', pelican.settings['SITENAME'])
|
|
|
|
+ pelican.settings.setdefault('PHOTO_WATERMARK_IMG', '')
|
|
|
|
+ pelican.settings.setdefault('PHOTO_WATERMARK_IMG_SIZE', (64, 64))
|
|
|
|
|
|
|
|
|
|
def read_notes(filename, msg=None):
|
|
def read_notes(filename, msg=None):
|
|
@@ -33,38 +60,105 @@ def read_notes(filename, msg=None):
|
|
try:
|
|
try:
|
|
with pelican_open(filename) as text:
|
|
with pelican_open(filename) as text:
|
|
for line in text.splitlines():
|
|
for line in text.splitlines():
|
|
|
|
+ if line.startswith('#'):
|
|
|
|
+ continue
|
|
|
|
+
|
|
m = line.split(':', 1)
|
|
m = line.split(':', 1)
|
|
if len(m) > 1:
|
|
if len(m) > 1:
|
|
pic = m[0].strip()
|
|
pic = m[0].strip()
|
|
note = m[1].strip()
|
|
note = m[1].strip()
|
|
if pic and note:
|
|
if pic and note:
|
|
notes[pic] = note
|
|
notes[pic] = note
|
|
- except:
|
|
|
|
|
|
+ else:
|
|
|
|
+ notes[line] = ''
|
|
|
|
+ except Exception as e:
|
|
if msg:
|
|
if msg:
|
|
- logger.warning(msg, filename)
|
|
|
|
|
|
+ logger.warning('{} at file {}'.format(msg, filename))
|
|
|
|
+ logger.debug('read_notes issue: {} at file {}. Debug message:{}'.format(msg, filename, e))
|
|
return notes
|
|
return notes
|
|
|
|
|
|
|
|
|
|
def enqueue_resize(orig, resized, spec=(640, 480, 80)):
|
|
def enqueue_resize(orig, resized, spec=(640, 480, 80)):
|
|
- global queue_resize
|
|
|
|
- if resized not in queue_resize:
|
|
|
|
- queue_resize[resized] = (orig, spec)
|
|
|
|
- elif queue_resize[resized] != (orig, spec):
|
|
|
|
- logger.error('photos: resize conflict for {}, {}-{} is not {}-{}',
|
|
|
|
- resized,
|
|
|
|
- queue_resize[resized][0], queue_resize[resized][1],
|
|
|
|
- orig, spec)
|
|
|
|
|
|
+
|
|
|
|
+ if resized not in DEFAULT_CONFIG['queue_resize']:
|
|
|
|
+ DEFAULT_CONFIG['queue_resize'][resized] = (orig, spec)
|
|
|
|
+ elif DEFAULT_CONFIG['queue_resize'][resized] != (orig, spec):
|
|
|
|
+ logger.error('photos: resize conflict for {}, {}-{} is not {}-{}'.format(resized, DEFAULT_CONFIG['queue_resize'][resized][0], DEFAULT_CONFIG['queue_resize'][resized][1], orig, spec))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def isalpha(img):
|
|
|
|
+ return True if img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info) else False
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def ReduceOpacity(im, opacity):
|
|
|
|
+ """Reduces Opacity
|
|
|
|
+
|
|
|
|
+ Returns an image with reduced opacity.
|
|
|
|
+ Taken from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/362879
|
|
|
|
+ """
|
|
|
|
+
|
|
|
|
+ assert opacity >= 0 and opacity <= 1
|
|
|
|
+ if isalpha(im):
|
|
|
|
+ im = im.copy()
|
|
|
|
+ else:
|
|
|
|
+ im = im.convert('RGBA')
|
|
|
|
+
|
|
|
|
+ alpha = im.split()[3]
|
|
|
|
+ alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
|
|
|
|
+ im.putalpha(alpha)
|
|
|
|
+ return im
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def watermark_photo(image, watermark_text, watermark_image, watermark_image_size):
|
|
|
|
+
|
|
|
|
+ margin = [10, 10]
|
|
|
|
+ opacity = 0.6
|
|
|
|
+
|
|
|
|
+ watermark_layer = Image.new("RGBA", image.size, (0, 0, 0, 0))
|
|
|
|
+ draw_watermark = ImageDraw.Draw(watermark_layer)
|
|
|
|
+ text_reducer = 32
|
|
|
|
+ image_reducer = 8
|
|
|
|
+ text_size = [0, 0]
|
|
|
|
+ mark_size = [0, 0]
|
|
|
|
+ font_height = 0
|
|
|
|
+ text_position = [0, 0]
|
|
|
|
+
|
|
|
|
+ if watermark_text:
|
|
|
|
+ font_name = 'SourceCodePro-Bold.otf'
|
|
|
|
+
|
|
|
|
+ plugin_dir = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
+ default_font = os.path.join(plugin_dir, font_name)
|
|
|
|
+ font = ImageFont.FreeTypeFont(default_font, watermark_layer.size[0] // text_reducer)
|
|
|
|
+ text_size = draw_watermark.textsize(watermark_text, font)
|
|
|
|
+ text_position = [image.size[i] - text_size[i] - margin[i] for i in [0, 1]]
|
|
|
|
+ draw_watermark.text(text_position, watermark_text, (255, 255, 255), font=font)
|
|
|
|
+
|
|
|
|
+ if watermark_image:
|
|
|
|
+ mark_image = Image.open(watermark_image)
|
|
|
|
+ mark_image_size = [ watermark_layer.size[0] // image_reducer for size in mark_size]
|
|
|
|
+ mark_image.thumbnail(mark_image_size, Image.ANTIALIAS)
|
|
|
|
+ mark_position = [watermark_layer.size[i] - mark_image.size[i] - margin[i] for i in [0, 1]]
|
|
|
|
+ mark_position = tuple([mark_position[0] - (text_size[0] // 2) + (mark_image_size[0] // 2), mark_position[1] - text_size[1]])
|
|
|
|
+
|
|
|
|
+ if not isalpha(mark_image):
|
|
|
|
+ mark_image = mark_image.convert('RGBA')
|
|
|
|
+
|
|
|
|
+ watermark_layer.paste(mark_image, mark_position, mark_image)
|
|
|
|
+
|
|
|
|
+ watermark_layer = ReduceOpacity(watermark_layer, opacity)
|
|
|
|
+ image.paste(watermark_layer, (0, 0), watermark_layer)
|
|
|
|
+
|
|
|
|
+ return image
|
|
|
|
|
|
|
|
|
|
def resize_photos(generator, writer):
|
|
def resize_photos(generator, writer):
|
|
- print('photos: {} photo resizes to consider.'
|
|
|
|
- .format(len(queue_resize.items())))
|
|
|
|
- for resized, what in queue_resize.items():
|
|
|
|
|
|
+ logger.info('photos: {} photo resizes to consider.'.format(len(DEFAULT_CONFIG['queue_resize'].items())))
|
|
|
|
+ for resized, what in DEFAULT_CONFIG['queue_resize'].items():
|
|
resized = os.path.join(generator.output_path, resized)
|
|
resized = os.path.join(generator.output_path, resized)
|
|
orig, spec = what
|
|
orig, spec = what
|
|
if (not os.path.isfile(resized) or
|
|
if (not os.path.isfile(resized) or
|
|
os.path.getmtime(orig) > os.path.getmtime(resized)):
|
|
os.path.getmtime(orig) > os.path.getmtime(resized)):
|
|
- logger.info('photos: make photo %s -> %s', orig, resized)
|
|
|
|
|
|
+ logger.info('photos: make photo {} -> {}'.format(orig, resized))
|
|
im = Image.open(orig)
|
|
im = Image.open(orig)
|
|
try:
|
|
try:
|
|
exif = im._getexif()
|
|
exif = im._getexif()
|
|
@@ -78,19 +172,28 @@ def resize_photos(generator, writer):
|
|
for tag, value in exif.items():
|
|
for tag, value in exif.items():
|
|
decoded = ExifTags.TAGS.get(tag, tag)
|
|
decoded = ExifTags.TAGS.get(tag, tag)
|
|
if decoded == 'Orientation':
|
|
if decoded == 'Orientation':
|
|
- if value == 3: im = im.rotate(180)
|
|
|
|
- elif value == 6: im = im.rotate(270)
|
|
|
|
- elif value == 8: im = im.rotate(90)
|
|
|
|
|
|
+ if value == 3:
|
|
|
|
+ im = im.rotate(180)
|
|
|
|
+ elif value == 6:
|
|
|
|
+ im = im.rotate(270)
|
|
|
|
+ elif value == 8:
|
|
|
|
+ im = im.rotate(90)
|
|
break
|
|
break
|
|
im.thumbnail((spec[0], spec[1]), Image.ANTIALIAS)
|
|
im.thumbnail((spec[0], spec[1]), Image.ANTIALIAS)
|
|
try:
|
|
try:
|
|
os.makedirs(os.path.split(resized)[0])
|
|
os.makedirs(os.path.split(resized)[0])
|
|
- except:
|
|
|
|
|
|
+ except Exception:
|
|
pass
|
|
pass
|
|
|
|
+
|
|
|
|
+ if generator.settings['PHOTO_WATERMARK']:
|
|
|
|
+ im = watermark_photo(im, generator.settings['PHOTO_WATERMARK_TEXT'], generator.settings['PHOTO_WATERMARK_IMG'], generator.settings['PHOTO_WATERMARK_IMG_SIZE'])
|
|
im.save(resized, 'JPEG', quality=spec[2], icc_profile=icc_profile)
|
|
im.save(resized, 'JPEG', quality=spec[2], icc_profile=icc_profile)
|
|
|
|
|
|
|
|
+
|
|
def detect_content(content):
|
|
def detect_content(content):
|
|
|
|
|
|
|
|
+ hrefs = None
|
|
|
|
+
|
|
def replacer(m):
|
|
def replacer(m):
|
|
what = m.group('what')
|
|
what = m.group('what')
|
|
value = m.group('value')
|
|
value = m.group('value')
|
|
@@ -100,8 +203,8 @@ def detect_content(content):
|
|
if value.startswith('/'):
|
|
if value.startswith('/'):
|
|
value = value[1:]
|
|
value = value[1:]
|
|
path = os.path.join(
|
|
path = os.path.join(
|
|
- os.path.expanduser(settings['PHOTO_LIBRARY']),
|
|
|
|
- value)
|
|
|
|
|
|
+ os.path.expanduser(settings['PHOTO_LIBRARY']),
|
|
|
|
+ value)
|
|
if not os.path.isfile(path):
|
|
if not os.path.isfile(path):
|
|
logger.error('photos: No photo %s', path)
|
|
logger.error('photos: No photo %s', path)
|
|
else:
|
|
else:
|
|
@@ -114,7 +217,6 @@ def detect_content(content):
|
|
return ''.join((m.group('markup'), m.group('quote'), origin,
|
|
return ''.join((m.group('markup'), m.group('quote'), origin,
|
|
m.group('quote')))
|
|
m.group('quote')))
|
|
|
|
|
|
- global hrefs
|
|
|
|
if hrefs is None:
|
|
if hrefs is None:
|
|
regex = r"""
|
|
regex = r"""
|
|
(?P<markup><\s*[^\>]* # match tag with src and href attr
|
|
(?P<markup><\s*[^\>]* # match tag with src and href attr
|
|
@@ -130,40 +232,68 @@ def detect_content(content):
|
|
content._content = hrefs.sub(replacer, content._content)
|
|
content._content = hrefs.sub(replacer, content._content)
|
|
|
|
|
|
|
|
|
|
-def process_gallery_photo(generator, article, gallery):
|
|
|
|
- if gallery.startswith('/'):
|
|
|
|
- gallery = gallery[1:]
|
|
|
|
|
|
+def galleries_string_decompose(gallery_string):
|
|
|
|
+ splitter_regex = re.compile(r'[\s,]*?({photo}|{filename})')
|
|
|
|
+ title_regex = re.compile(r'{(.+)}')
|
|
|
|
+ galleries = map(unicode.strip, filter(None, splitter_regex.split(gallery_string)))
|
|
|
|
+ galleries = [gallery[1:] if gallery.startswith('/') else gallery for gallery in galleries]
|
|
|
|
+ if len(galleries) % 2 == 0 and u' ' not in galleries:
|
|
|
|
+ galleries = zip(zip(['type'] * len(galleries[0::2]), galleries[0::2]), zip(['location'] * len(galleries[0::2]), galleries[1::2]))
|
|
|
|
+ galleries = [dict(gallery) for gallery in galleries]
|
|
|
|
+ for gallery in galleries:
|
|
|
|
+ title = re.search(title_regex, gallery['location'])
|
|
|
|
+ if title:
|
|
|
|
+ gallery['title'] = title.group(1)
|
|
|
|
+ gallery['location'] = re.sub(title_regex, '', gallery['location']).strip()
|
|
|
|
+ else:
|
|
|
|
+ gallery['title'] = DEFAULT_CONFIG['PHOTO_GALLERY_TITLE']
|
|
|
|
+ return galleries
|
|
|
|
+ else:
|
|
|
|
+ logger.critical('Unexpected gallery location format! \n{}'.format(pprint.pformat(galleries)))
|
|
|
|
+ raise Exception
|
|
|
|
|
|
- galleries = gallery.split('{photo}')
|
|
|
|
- article.photo_gallery = []
|
|
|
|
|
|
+
|
|
|
|
+def process_gallery(generator, content, location):
|
|
|
|
+
|
|
|
|
+ content.photo_gallery = []
|
|
|
|
+
|
|
|
|
+ galleries = galleries_string_decompose(location)
|
|
|
|
|
|
for gallery in galleries:
|
|
for gallery in galleries:
|
|
- # strip whitespaces
|
|
|
|
- gallery = gallery.strip()
|
|
|
|
|
|
|
|
- if gallery in created_galleries:
|
|
|
|
- article.photo_gallery.append((gallery, created_galleries[gallery]))
|
|
|
|
|
|
+ if gallery['location'] in DEFAULT_CONFIG['created_galleries']:
|
|
|
|
+ content.photo_gallery.append((gallery['location'], DEFAULT_CONFIG['created_galleries'][gallery]))
|
|
continue
|
|
continue
|
|
|
|
|
|
- dir_gallery = os.path.join(
|
|
|
|
- os.path.expanduser(generator.settings['PHOTO_LIBRARY']),
|
|
|
|
- gallery)
|
|
|
|
|
|
+ if gallery['type'] == '{photo}':
|
|
|
|
+ dir_gallery = os.path.join(os.path.expanduser(generator.settings['PHOTO_LIBRARY']), gallery['location'])
|
|
|
|
+ rel_gallery = gallery['location']
|
|
|
|
+ elif gallery['type'] == '{filename}':
|
|
|
|
+ base_path = os.path.join(generator.path, content.relative_dir)
|
|
|
|
+ dir_gallery = os.path.join(base_path, gallery['location'])
|
|
|
|
+ rel_gallery = os.path.join(content.relative_dir, gallery['location'])
|
|
|
|
|
|
if os.path.isdir(dir_gallery):
|
|
if os.path.isdir(dir_gallery):
|
|
- logger.info('photos: Gallery detected: %s', gallery)
|
|
|
|
- dir_photo = os.path.join('photos', gallery.lower())
|
|
|
|
- dir_thumb = os.path.join('photos', gallery.lower())
|
|
|
|
|
|
+ logger.info('photos: Gallery detected: {}'.format(rel_gallery))
|
|
|
|
+ dir_photo = os.path.join('photos', rel_gallery.lower())
|
|
|
|
+ dir_thumb = os.path.join('photos', rel_gallery.lower())
|
|
exifs = read_notes(os.path.join(dir_gallery, 'exif.txt'),
|
|
exifs = read_notes(os.path.join(dir_gallery, 'exif.txt'),
|
|
- msg='photos: No EXIF for gallery %s')
|
|
|
|
- captions = read_notes(os.path.join(dir_gallery, 'captions.txt'))
|
|
|
|
- articleGallery = []
|
|
|
|
|
|
+ msg='photos: No EXIF for gallery')
|
|
|
|
+ captions = read_notes(os.path.join(dir_gallery, 'captions.txt'), msg='photos: No captions for gallery')
|
|
|
|
+ blacklist = read_notes(os.path.join(dir_gallery, 'blacklist.txt'), msg='photos: No blacklist for gallery')
|
|
|
|
+ content_gallery = []
|
|
|
|
|
|
|
|
+ title = gallery['title']
|
|
for pic in sorted(os.listdir(dir_gallery)):
|
|
for pic in sorted(os.listdir(dir_gallery)):
|
|
- if pic.startswith('.'): continue
|
|
|
|
- if pic.endswith('.txt'): continue
|
|
|
|
|
|
+ if pic.startswith('.'):
|
|
|
|
+ continue
|
|
|
|
+ if pic.endswith('.txt'):
|
|
|
|
+ continue
|
|
|
|
+ if pic in blacklist:
|
|
|
|
+ continue
|
|
photo = os.path.splitext(pic)[0].lower() + '.jpg'
|
|
photo = os.path.splitext(pic)[0].lower() + '.jpg'
|
|
thumb = os.path.splitext(pic)[0].lower() + 't.jpg'
|
|
thumb = os.path.splitext(pic)[0].lower() + 't.jpg'
|
|
- articleGallery.append((
|
|
|
|
|
|
+ content_gallery.append((
|
|
pic,
|
|
pic,
|
|
os.path.join(dir_photo, photo),
|
|
os.path.join(dir_photo, photo),
|
|
os.path.join(dir_thumb, thumb),
|
|
os.path.join(dir_thumb, thumb),
|
|
@@ -179,67 +309,39 @@ def process_gallery_photo(generator, article, gallery):
|
|
os.path.join(dir_thumb, thumb),
|
|
os.path.join(dir_thumb, thumb),
|
|
generator.settings['PHOTO_THUMB'])
|
|
generator.settings['PHOTO_THUMB'])
|
|
|
|
|
|
- article.photo_gallery.append((gallery, articleGallery))
|
|
|
|
- created_galleries[gallery] = articleGallery
|
|
|
|
|
|
+ content.photo_gallery.append((title, content_gallery))
|
|
|
|
+ logger.debug('Gallery Data: '.format(pprint.pformat(content.photo_gallery)))
|
|
|
|
+ DEFAULT_CONFIG['created_galleries']['gallery'] = content_gallery
|
|
else:
|
|
else:
|
|
- logger.error('photos: Gallery does not exist: %s at %s', gallery, dir_gallery)
|
|
|
|
|
|
+ logger.critical('photos: Gallery does not exist: {} at {}'.format(gallery['location'], dir_gallery))
|
|
|
|
+ raise Exception
|
|
|
|
|
|
|
|
|
|
-def process_gallery_filename(generator, article, gallery):
|
|
|
|
- if gallery.startswith('/'):
|
|
|
|
- gallery = gallery[1:]
|
|
|
|
- else:
|
|
|
|
- gallery = os.path.join(article.relative_dir, gallery)
|
|
|
|
- dir_gallery = os.path.join(generator.path, gallery)
|
|
|
|
- if os.path.isdir(dir_gallery):
|
|
|
|
- logger.info('photos: Gallery detected: %s', gallery)
|
|
|
|
- dir_photo = gallery.lower()
|
|
|
|
- dir_thumb = os.path.join('photos', gallery.lower())
|
|
|
|
- exifs = read_notes(os.path.join(dir_gallery, 'exif.txt'),
|
|
|
|
- msg='photos: No EXIF for gallery %s')
|
|
|
|
- captions = read_notes(os.path.join(dir_gallery, 'captions.txt'))
|
|
|
|
- article.photo_gallery = []
|
|
|
|
- for pic in sorted(os.listdir(dir_gallery)):
|
|
|
|
- if pic.startswith('.'): continue
|
|
|
|
- if pic.endswith('.txt'): continue
|
|
|
|
- photo = pic.lower()
|
|
|
|
- thumb = os.path.splitext(pic)[0].lower() + 't.jpg'
|
|
|
|
- article.photo_gallery.append((
|
|
|
|
- pic,
|
|
|
|
- os.path.join(dir_photo, photo),
|
|
|
|
- os.path.join(dir_thumb, thumb),
|
|
|
|
- exifs.get(pic, ''),
|
|
|
|
- captions.get(pic, '')))
|
|
|
|
- enqueue_resize(
|
|
|
|
- os.path.join(dir_gallery, pic),
|
|
|
|
- os.path.join(dir_thumb, thumb),
|
|
|
|
- generator.settings['PHOTO_THUMB'])
|
|
|
|
- else:
|
|
|
|
- logger.error('photos: Gallery does not exist: %s at %s', gallery, dir_gallery)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def detect_gallery(generator):
|
|
|
|
- for article in chain(generator.articles, generator.drafts):
|
|
|
|
- if 'gallery' in article.metadata:
|
|
|
|
- gallery = article.metadata.get('gallery')
|
|
|
|
- if gallery.startswith('{photo}'):
|
|
|
|
- process_gallery_photo(generator, article, gallery[7:])
|
|
|
|
- elif gallery.startswith('{filename}'):
|
|
|
|
- process_gallery_filename(generator, article, gallery[10:])
|
|
|
|
- elif gallery:
|
|
|
|
- logger.error('photos: Gallery tag not recognized: %s', gallery)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def process_image_photo(generator, article, image):
|
|
|
|
- if image.startswith('/'):
|
|
|
|
- image = image[1:]
|
|
|
|
- path = os.path.join(
|
|
|
|
- os.path.expanduser(generator.settings['PHOTO_LIBRARY']),
|
|
|
|
- image)
|
|
|
|
|
|
+def detect_gallery(generator, content):
|
|
|
|
+ if 'gallery' in content.metadata:
|
|
|
|
+ gallery = content.metadata.get('gallery')
|
|
|
|
+ if gallery.startswith('{photo}') or gallery.startswith('{filename}'):
|
|
|
|
+ process_gallery(generator, content, gallery)
|
|
|
|
+ elif gallery:
|
|
|
|
+ logger.error('photos: Gallery tag not recognized: {}'.format(gallery))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def process_image(generator, content, image):
|
|
|
|
+
|
|
|
|
+ image_clipper = lambda x: x[8:] if x[8] == '/' else x[7:]
|
|
|
|
+ file_clipper = lambda x: x[11:] if x[10] == '/' else x[10:]
|
|
|
|
+
|
|
|
|
+ if image.startswith('{photo}'):
|
|
|
|
+ path = os.path.join(os.path.expanduser(generator.settings['PHOTO_LIBRARY']), image_clipper(image))
|
|
|
|
+ image = image_clipper(image)
|
|
|
|
+ elif image.startswith('{filename}'):
|
|
|
|
+ path = os.path.join(content.relative_dir, file_clipper(image))
|
|
|
|
+ image = file_clipper(image)
|
|
|
|
+
|
|
if os.path.isfile(path):
|
|
if os.path.isfile(path):
|
|
photo = os.path.splitext(image)[0].lower() + 'a.jpg'
|
|
photo = os.path.splitext(image)[0].lower() + 'a.jpg'
|
|
thumb = os.path.splitext(image)[0].lower() + 't.jpg'
|
|
thumb = os.path.splitext(image)[0].lower() + 't.jpg'
|
|
- article.photo_image = (
|
|
|
|
|
|
+ content.photo_image = (
|
|
os.path.basename(image).lower(),
|
|
os.path.basename(image).lower(),
|
|
os.path.join('photos', photo),
|
|
os.path.join('photos', photo),
|
|
os.path.join('photos', thumb))
|
|
os.path.join('photos', thumb))
|
|
@@ -252,44 +354,37 @@ def process_image_photo(generator, article, image):
|
|
os.path.join('photos', thumb),
|
|
os.path.join('photos', thumb),
|
|
generator.settings['PHOTO_THUMB'])
|
|
generator.settings['PHOTO_THUMB'])
|
|
else:
|
|
else:
|
|
- logger.error('photo: No photo for %s at %s', article.source_path, path)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def process_image_filename(generator, article, image):
|
|
|
|
- if image.startswith('/'):
|
|
|
|
- image = image[1:]
|
|
|
|
- else:
|
|
|
|
- image = os.path.join(article.relative_dir, image)
|
|
|
|
- path = os.path.join(generator.path, image)
|
|
|
|
- if os.path.isfile(path):
|
|
|
|
- small = os.path.splitext(image)[0].lower() + 't.jpg'
|
|
|
|
- article.photo_image = (
|
|
|
|
- os.path.basename(image),
|
|
|
|
- image.lower(),
|
|
|
|
- os.path.join('photos', small))
|
|
|
|
- enqueue_resize(
|
|
|
|
- path,
|
|
|
|
- os.path.join('photos', small),
|
|
|
|
- generator.settings['PHOTO_THUMB'])
|
|
|
|
- else:
|
|
|
|
- logger.error('photos: No photo at %s', path)
|
|
|
|
|
|
+ logger.error('photo: No photo for {} at {}'.format(content.source_path, path))
|
|
|
|
|
|
|
|
|
|
-def detect_image(generator):
|
|
|
|
- for article in chain(generator.articles, generator.drafts):
|
|
|
|
- image = article.metadata.get('image', None)
|
|
|
|
|
|
+def detect_image(generator, content):
|
|
|
|
+ image = content.metadata.get('image', None)
|
|
if image:
|
|
if image:
|
|
- if image.startswith('{photo}'):
|
|
|
|
- process_image_photo(generator, article, image[7:])
|
|
|
|
- elif image.startswith('{filename}'):
|
|
|
|
- process_image_filename(generator, article, image[10:])
|
|
|
|
|
|
+ if image.startswith('{photo}') or image.startswith('{filename}'):
|
|
|
|
+ process_image(generator, content, image)
|
|
else:
|
|
else:
|
|
- logger.error('photos: Image tag not recognized: %s', image)
|
|
|
|
|
|
+ logger.error('photos: Image tag not recognized: {}'.format(image))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def detect_images_and_galleries(generators):
|
|
|
|
+ """Runs generator on both pages and articles. """
|
|
|
|
+ for generator in generators:
|
|
|
|
+ if isinstance(generator, ArticlesGenerator):
|
|
|
|
+ for article in itertools.chain(generator.articles, generator.drafts):
|
|
|
|
+ detect_image(generator, article)
|
|
|
|
+ detect_gallery(generator, article)
|
|
|
|
+ elif isinstance(generator, PagesGenerator):
|
|
|
|
+ for page in itertools.chain(generator.pages, generator.hidden_pages):
|
|
|
|
+ detect_image(generator, page)
|
|
|
|
+ detect_gallery(generator, page)
|
|
|
|
|
|
|
|
|
|
def register():
|
|
def register():
|
|
|
|
+ """Uses the new style of registration based on GitHub Pelican issue #314. """
|
|
signals.initialized.connect(initialized)
|
|
signals.initialized.connect(initialized)
|
|
- signals.content_object_init.connect(detect_content)
|
|
|
|
- signals.article_generator_finalized.connect(detect_gallery)
|
|
|
|
- signals.article_generator_finalized.connect(detect_image)
|
|
|
|
- signals.article_writer_finalized.connect(resize_photos)
|
|
|
|
|
|
+ try:
|
|
|
|
+ signals.content_object_init.connect(detect_content)
|
|
|
|
+ signals.all_generators_finalized.connect(detect_images_and_galleries)
|
|
|
|
+ signals.article_writer_finalized.connect(resize_photos)
|
|
|
|
+ except Exception as e:
|
|
|
|
+ logger.exception('Plugin failed to execute: {}'.format(pprint.pformat(e)))
|