diff --git a/sigal/plugins/nomedia.py b/sigal/plugins/nomedia.py new file mode 100644 index 0000000..72bdb84 --- /dev/null +++ b/sigal/plugins/nomedia.py @@ -0,0 +1,112 @@ +# encoding: utf-8 + +# Copyright 2017 - Tilman 't.animal' Adler + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# 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 +# IN THE SOFTWARE. + +""" This plugin offers more fine-grained control over exluded images and folders, similarly to how + it's handled on Android. + + To ignore a folder or image put a .nomedia file next to it in its parent folder and put its name + into the file. + E.g.: + content of folder: + IMG_3425.JPG, IMG_2426.JPG, IMG_2427.JPG, subfolder, .nomedia + content of .nomedia: + IMG_2426.JPG + IMG_2427.JPG + subfolder + will ignore all images but IMG_3425.JPG and the subfolder + + Alternatively, if you put a .nomedia file into a folder and leave it blank (i.e. an empty file + called .nomedia in a folder containing images), this ignores the whole folder it's located in + (like on Android). + + WARNING: When you have a pre-existing gallery from a previous run of sigal adding a new .nomedia + file will not remove the newly ignored images/albums from the existing gallery (only the entries + in the parent gallery pointing to it). They might still be reachable thereafter. Either remove + the whole gallery to be sure or remove the ignored files/folders inside the gallery to remove + them for good. +""" + +import io +import logging +import os +from sigal import signals + +logger = logging.getLogger(__name__) + +def _remove_albums_with_subdirs(albums, keysToRemove, prefix=""): + for keyToRemove in keysToRemove: + for key in list(albums.keys()): + if key.startswith(prefix + keyToRemove): + # subdirs' target directories have already been created, remove them first + try: + album = albums[key] + if album.medias: + os.rmdir(os.path.join(album.dst_path, album.settings['thumb_dir'])) + + if album.medias and album.settings['keep_orig']: + os.rmdir(os.path.join(album.dst_path, album.settings['orig_dir'])) + + os.rmdir(album.dst_path) + except OSError: + # directory was created and populated with images in a previous run => keep it + pass + + # now remove the album from the surrounding album/gallery + del albums[key] + + +def filter_nomedia(album, settings=None): + """Removes all filtered Media and subdirs from an Album""" + nomediaPath = os.path.join(album.src_path, ".nomedia") + + if os.path.isfile(nomediaPath): + if os.path.getsize(nomediaPath) == 0: + logger.info("Ignoring album '%s' because of present 0-byte .nomedia file", album.name) + + # subdirs have been added to the gallery already, remove them there, too + _remove_albums_with_subdirs(album.gallery.albums, [album.path]) + try: + os.rmdir(album.dst_path) + except OSError as e: + # directory was created and populated with images in a previous run => keep it + pass + + # cannot set albums => empty subdirs so that no albums are generated + album.subdirs = [] + album.medias = [] + + else: + with io.open(nomediaPath, "r") as nomediaFile: + logger.info("Found a .nomedia file in %s, ignoring its entries", album.name) + ignoredEntries = nomediaFile.read().split("\n") + + album.medias = list(filter(lambda media: media.filename not in ignoredEntries, + album.medias)) + album.subdirs = list(filter(lambda dirName: dirName not in ignoredEntries, + album.subdirs)) + + #subdirs have been added to the gallery already, remove them there, too + _remove_albums_with_subdirs(album.gallery.albums, ignoredEntries, album.path + os.path.sep) + + +def register(settings): + signals.album_initialized.connect(filter_nomedia) \ No newline at end of file diff --git a/tests/sample/pictures/nomedia/created/.nomedia b/tests/sample/pictures/nomedia/created/.nomedia new file mode 100644 index 0000000..d40f1d0 --- /dev/null +++ b/tests/sample/pictures/nomedia/created/.nomedia @@ -0,0 +1,2 @@ +should_be_ignored3.jpg +ignored \ No newline at end of file diff --git a/tests/sample/pictures/nomedia/created/ignored/should_be_ignored2.jpg b/tests/sample/pictures/nomedia/created/ignored/should_be_ignored2.jpg new file mode 100644 index 0000000..bbb9eb9 Binary files /dev/null and b/tests/sample/pictures/nomedia/created/ignored/should_be_ignored2.jpg differ diff --git a/tests/sample/pictures/nomedia/created/should_be_created.jpg b/tests/sample/pictures/nomedia/created/should_be_created.jpg new file mode 100644 index 0000000..07c8953 Binary files /dev/null and b/tests/sample/pictures/nomedia/created/should_be_created.jpg differ diff --git a/tests/sample/pictures/nomedia/created/should_be_ignored3.jpg b/tests/sample/pictures/nomedia/created/should_be_ignored3.jpg new file mode 100644 index 0000000..da3b7c7 Binary files /dev/null and b/tests/sample/pictures/nomedia/created/should_be_ignored3.jpg differ diff --git a/tests/sample/pictures/nomedia/ignored/.nomedia b/tests/sample/pictures/nomedia/ignored/.nomedia new file mode 100644 index 0000000..e69de29 diff --git a/tests/sample/pictures/nomedia/ignored/recursively_ignored/should_be_ignored.jpg b/tests/sample/pictures/nomedia/ignored/recursively_ignored/should_be_ignored.jpg new file mode 100644 index 0000000..97e3e0a Binary files /dev/null and b/tests/sample/pictures/nomedia/ignored/recursively_ignored/should_be_ignored.jpg differ diff --git a/tests/sample/pictures/nomedia/ignored/should_be_ignored_1.jpg b/tests/sample/pictures/nomedia/ignored/should_be_ignored_1.jpg new file mode 100644 index 0000000..3ccf322 Binary files /dev/null and b/tests/sample/pictures/nomedia/ignored/should_be_ignored_1.jpg differ diff --git a/tests/sample/sigal.conf.py b/tests/sample/sigal.conf.py index 8a6a1bd..5745e73 100644 --- a/tests/sample/sigal.conf.py +++ b/tests/sample/sigal.conf.py @@ -10,7 +10,8 @@ links = [('Example link', 'http://example.org'), ('Another link', 'http://example.org')] plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright', - 'sigal.plugins.watermark', 'sigal.plugins.feeds', ] + 'sigal.plugins.watermark', 'sigal.plugins.feeds', + 'sigal.plugins.nomedia'] copyright = u"© An example copyright message" adjust_options = {'color': 0.0, 'brightness': 1.0, 'contrast': 1.0, 'sharpness': 0.0} diff --git a/tests/test_nomedia_plugin.py b/tests/test_nomedia_plugin.py new file mode 100644 index 0000000..0a76116 --- /dev/null +++ b/tests/test_nomedia_plugin.py @@ -0,0 +1,27 @@ +# -*- coding:utf-8 -*- + +import os + +from sigal.gallery import Gallery +from sigal import init_plugins + +CURRENT_DIR = os.path.dirname(__file__) + +def test_nomedia_plugin(settings, tmpdir): + + settings['destination'] = str(tmpdir) + if "plugins"in settings: + if not "sigal.plugins.nomedia" in settings["plugins"]: + settings['plugins'] += ["sigal.plugins.nomedia"] + else: + settings["plugins"] = ["sigal.plugins.nomedia"] + + init_plugins(settings) + gal = Gallery(settings) + gal.build() + + for path, dirs, files in os.walk(os.path.join(str(tmpdir), "nomedia")): + assert "ignore" not in path + + for file in files: + assert "ignore" not in file \ No newline at end of file