Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first prototype of a stream plugin #304

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions sigal/gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

from copy import copy as shallowcopy
import fnmatch
import locale
import logging
Expand Down Expand Up @@ -527,6 +528,34 @@ def zip(self):
self.logger.debug('Created ZIP archive %s', archive_path)
return zip_gallery

def flatten(self):
'''flatten album hierarchy in a single album

this modifies the album: make sure to call `.copy()` if you need
the original album untouched.
'''
ret = shallowcopy(self)
for album in ret.albums:
ret.merge(album)
album.flatten()
return ret

def merge(self, album):
'''merge in another album into this album

..todo:: could be reimplemented as __add__()? but then you'd have
consumers expecting `all operators`_ to be supported?

.. _all operators: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
'''
for media in album.medias:
media = shallowcopy(media)
media.thumb_name = os.path.join(album.path, media.thumb_name)
media.filename = os.path.join(album.path, media.filename)
self.medias.append(media)
# XXX; should be factored out? copied from Album.__init__()
self.medias_count[media.type] += 1


class Gallery(object):

Expand Down Expand Up @@ -729,6 +758,13 @@ def process_dir(self, album, force=False):
yield (f.type, f.path, f.filename, f.src_path, album.dst_path,
self.settings)

def flatten(self, path='.'):
'''flatten all albums into a single one'''
flat_album = Album(path, self.settings, [], [], self)
for album in self.albums.values():
flat_album.merge(album)
return flat_album.flatten()


def process_file(args):
# args => ftype, path, filename, src_path, dst_path, settings
Expand Down
59 changes: 59 additions & 0 deletions sigal/plugins/stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-

"""Plugin which adds a "stream page" listing all images.

This plugin is similar to the feeds plugin in that it allows listing
images in (reverse) chronological order, to show the most recent
ones. This allows users to browse the gallery as a "flat" list of
images, a bit like you would on sites like Flickr or Instagram.

Settigns:

- ``stream_page``, see below

Example::

stream_page = { 'filename': 'stream.html', 'nb_items': 10, 'title': 'Stream' }

In the above example, a 10-item page will be created at
/stream.html. If any entry is missing, a default will be used as
defined above (except `nb_items` which defaults to no limit.

.. todo:: What happens if an album with the same name exists?

"""

import logging
import os.path

from sigal import signals
from sigal.writer import Writer

logger = logging.getLogger(__name__)


def generate_stream(gallery):
settings = gallery.settings.get('stream_page', {})
albums = gallery.albums.values()
if len(albums) < 1:
logging.debug('no albums, empty stream')
return
# fake meta-album to regroup the top-level ones
feed_album = gallery.flatten()
feed_album.output_file = settings.get('filename', 'stream.html')
nb_medias = len(feed_album.medias)
nb_items = settings.get('nb_items', 0)
nb_items = min(nb_items, nb_medias) if nb_items > 0 else nb_medias
del feed_album.medias[nb_items:]
# copy-pasted from feeds.py
feed_album.medias.sort(key=lambda m: m.date, reverse=True)
writer = Writer(gallery.settings,
index_title=settings.get('title', 'Stream'))
# copy-pasted from Writer.write()
path = os.path.join(feed_album.dst_path, feed_album.output_file)
logger.info('Generating streams page: %s', path)
writer.write(feed_album)


def register(settings):
signals.gallery_build.connect(generate_stream)
11 changes: 11 additions & 0 deletions tests/test_gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,17 @@ def test_medias_sort(settings):
'archlinux-kiss-1024x640.png', '21.jpg', '22.jpg']


def test_flatten_merge(settings):
gal = Gallery(settings, ncpu=1)
flat_album = gal.flatten()
# expected = sum([len(album['medias']) for album in REF.values()])
# XXX: not sure why, but the above Gallery does not skip .nomedia
# even if the plugin is present
expected = 25
assert expected == len(flat_album.medias), 'right number of items'
assert '/' not in ''.join(gal.albums['dir1'].medias), 'original paths preserved'


def test_gallery(settings, tmpdir):
"Test the Gallery class."

Expand Down
24 changes: 24 additions & 0 deletions tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,27 @@ def test_plugins(settings, tmpdir, disconnect_signals):

for file in files:
assert "ignore" not in file


def test_stream(settings, tmpdir):
settings['destination'] = str(tmpdir)
if "sigal.plugins.stream" not in settings["plugins"]:
settings['plugins'] += ["sigal.plugins.stream"]
title = 'Stream unit test'
nb_items = 3
filename = 'stream-test.html'
settings['stream_page'] = {'filename': filename,
'nb_items': nb_items,
'title': title}

init_plugins(settings)
gal = Gallery(settings)
gal.build()

out_html = os.path.join(settings['destination'], filename)
assert os.path.isfile(out_html)

with open(out_html) as stream_page:
content = stream_page.read()
assert title in content
assert content.count('data-big') == nb_items