Browse Source

first draft of plugin to handle nonmedia files

pull/434/head
David Schultz 5 years ago
parent
commit
0b972fddf2
  1. 10
      sigal/__init__.py
  2. 36
      sigal/gallery.py
  3. 139
      sigal/plugins/nonmedia_files.py
  4. 2
      sigal/signals.py
  5. 7
      sigal/templates/sigal.conf.py
  6. BIN
      tests/sample/pictures/nonmedia_files/dummy.pdf
  7. 19
      tests/test_plugins.py

10
sigal/__init__.py

@ -173,9 +173,13 @@ def build(source, destination, debug, verbose, quiet, force, config, theme,
return '{} {}s{}'.format(stats[_type], _type, opt)
if not quiet:
print('Done, processed {} and {} in {:.2f} seconds.'
.format(format_stats('image'), format_stats('video'),
time.time() - start_time))
stats_str = ''
types = sorted(set(t.rsplit('_',1)[0] for t in stats))
for t in types[:-1]:
stats_str += '{} and '.format(format_stats(t))
stats_str += '{}'.format(format_stats(types[-1]))
print('Done, processed {} in {:.2f} seconds.'
.format(stats_str, time.time() - start_time))
def init_plugins(settings):

36
sigal/gallery.py

@ -42,7 +42,7 @@ from PIL import Image as PILImage
from . import image, signals, video
from .image import get_exif_tags, get_image_metadata, get_size, process_image
from .settings import get_thumb
from .settings import Status, get_thumb
from .utils import (Devnull, cached_property, check_or_create_dir, copy,
get_mime, is_valid_html5_video, read_markdown,
url_from_path)
@ -340,15 +340,22 @@ class Album:
for f in filenames:
ext = splitext(f)[1]
media = None
if ext.lower() in settings['img_extensions']:
media = Image(f, self.path, settings)
elif ext.lower() in settings['video_extensions']:
media = Video(f, self.path, settings)
else:
continue
self.medias_count[media.type] += 1
medias.append(media)
# Allow modification of the media, including overriding the class
# type for the media.
result = signals.album_file.send(self, filename=f, media=media)
for recv, ret in result:
if ret is not None:
media = ret
if media:
self.medias_count[media.type] += 1
medias.append(media)
signals.album_initialized.send(self)
@ -835,8 +842,23 @@ class Gallery:
def process_file(media):
processor = process_image if media.type == 'image' else process_video
return processor(media)
processor = None
if media.type == 'image':
processor = process_image
elif media.type == 'video':
processor = process_video
# Allow overriding of the processor
result = signals.process_file.send(media, processor=processor)
for recv, ret in result:
if ret is not None:
processor = ret
if processor:
return processor(media)
else:
logging.warning('Processor not found for media %s', media.path)
return Status.FAILURE
def worker(args):

139
sigal/plugins/nonmedia_files.py

@ -0,0 +1,139 @@
"""Plugin to index non-media files.
This plugin will copy the files into the build tree and generate generic
thumbnails for the files. In-browser previews will likely fail, and
it is up to the theme to provide correct support for downloads.
Settings available as dictionary in ``nonmedia_files_options``:
- ``ext_as_thumb``: Enable simple thumbnail showing ext.
Default to ``True``
- ``ignore_ext``: List of file extensions to ignore.
Default to ``[".md"]``
"""
import logging
import os
from PIL import Image as PILImage
from PIL import ImageDraw, ImageFont
from pilkit.utils import save_image
from sigal import signals
from sigal import utils
from sigal.gallery import Media
from sigal.settings import Status
logger = logging.getLogger(__name__)
DEFAULT_CONFIG = {
'ext_as_thumb': True,
'ignore_ext': ['.md'],
}
COMMON_MIME_TYPES = {
'.azw': 'application/vnd.amazon.ebook',
'.csv': 'text/csv',
'.epub': 'application/epub+zip',
'.pdf': 'application/pdf',
'.svg': 'image/svg+xml',
'.txt': 'text/plain',
'.zip': 'application/zip',
}
def get_mime(ext):
if ext in COMMON_MIME_TYPES:
return COMMON_MIME_TYPES[ext]
return 'application/octet-stream'
class NonMedia(Media):
"""Gather all informations on a non-media file."""
type = 'nonmedia'
def __init__(self, filename, path, settings):
super().__init__(filename, path, settings)
self.thumb_name = os.path.splitext(self.thumb_name)[0] + '.jpg'
self.date = self._get_file_date()
self.mime = get_mime(self.src_ext)
logger.debug('mime type %s', self.mime)
@property
def thumbnail(self):
"""Path to the thumbnail image (relative to the album directory)."""
if not os.path.isfile(self.thumb_path):
generate_thumbnail(self.src_ext[1:].upper(), self.thumb_path,
self.settings['thumb_size'])
return super().thumbnail
def generate_thumbnail(text, outname, box, options=None):
"""Create a thumbnail image."""
img = PILImage.new("RGB", box, (255, 255, 255))
fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40)
anchor = (box[0] // 2, box[1] // 2)
d = ImageDraw.Draw(img)
d.text(anchor, text, font=fnt, fill=(0, 0, 0), anchor='mm')
outformat = 'JPEG'
logger.info('Save thumnail image: %s (%s)', outname, outformat)
save_image(img, outname, outformat, options=options, autoconvert=True)
def process_nonmedia(media):
"""Process a non-media file: copy and create thumbnail."""
logger.info('Processing non-media file: %s', media.dst_filename)
settings = media.settings
plugin_settings = settings.get('nonmedia_files_settings', {})
try:
utils.copy(media.src_path, media.dst_path,
symlink=settings['orig_link'])
except Exception:
if logger.getEffectiveLevel() == logging.DEBUG:
raise
else:
return Status.FAILURE
if plugin_settings.get('ext_as_thumb', DEFAULT_CONFIG['ext_as_thumb']):
try:
generate_thumbnail(
media.src_ext[1:].upper(),
media.thumb_path,
settings['thumb_size'],
options=settings['jpg_options'],
)
except Exception:
if logger.getEffectiveLevel() == logging.DEBUG:
raise
else:
return Status.FAILURE
def album_file(album, filename, media=None):
if not media:
ext = os.path.splitext(filename)[1]
ext_ignore = album.settings.get('nonmedia_files_settings', {}).get(
'ignore_ext', DEFAULT_CONFIG['ignore_ext'])
if ext in ext_ignore:
logger.info('Ignoring non-media file: %s', filename)
else:
logger.info('Registering non-media file: %s', filename)
return NonMedia(filename, album.path, album.settings)
def process_file(media, processor=None):
if media.type == 'nonmedia':
return process_nonmedia
def register(settings):
signals.album_file.connect(album_file)
signals.process_file.connect(process_file)

2
sigal/signals.py

@ -9,3 +9,5 @@ media_initialized = signal('media_initialized')
albums_sorted = signal('albums_sorted')
medias_sorted = signal('medias_sorted')
before_render = signal('before_render')
album_file = signal('album_file')
process_file = signal('process_file')

7
sigal/templates/sigal.conf.py

@ -273,6 +273,7 @@ ignore_files = []
# 'sigal.plugins.feeds',
# 'sigal.plugins.media_page',
# 'sigal.plugins.nomedia',
# 'sigal.plugins.nonmedia_files',
# 'sigal.plugins.upload_s3',
# 'sigal.plugins.watermark',
# 'sigal.plugins.zip_gallery',
@ -299,6 +300,12 @@ ignore_files = []
# 'ask_password': False
# }
# Settings for nonmedia_files plugin
# nonmedia_files_options = {
# 'ext_as_thumb': True,
# 'ignore_ext': ['.md'],
# }
# Settings for upload to s3 plugin
# upload_s3_options = {
# 'bucket': 'my-bucket',

BIN
tests/sample/pictures/nonmedia_files/dummy.pdf

Binary file not shown.

19
tests/test_plugins.py

@ -27,3 +27,22 @@ def test_plugins(settings, tmpdir, disconnect_signals):
for file in files:
assert "ignore" not in file
def test_nonmedia_files(settings, tmpdir, disconnect_signals):
settings['destination'] = str(tmpdir)
settings['plugins'] += ['sigal.plugins.nonmedia_files']
init_plugins(settings)
gal = Gallery(settings)
gal.build()
outfile = os.path.join(settings['destination'],
'nonmedia_files', 'dummy.pdf')
assert os.path.isfile(outfile)
outthumb = os.path.join(settings['destination'],
'nonmedia_files', 'thumbnails', 'dummy.tn.jpg')
assert os.path.isfile(outthumb)

Loading…
Cancel
Save