diff --git a/sigal/gallery.py b/sigal/gallery.py index bedebc3..00c6f45 100644 --- a/sigal/gallery.py +++ b/sigal/gallery.py @@ -237,6 +237,11 @@ class Image(Media): """The dimensions of the resized image.""" return get_size(self.dst_path) + @cached_property + def input_size(self): + """The dimensions of the input image.""" + return get_size(self.src_path) + @cached_property def thumb_size(self): """The dimensions of the thumbnail image.""" @@ -479,7 +484,7 @@ class Album: # Use f.size if available as it is quicker (in cache), but # fallback to the size of src_path if dst_path is missing - size = f.size + size = f.input_size if size is None: size = f.file_metadata['size'] diff --git a/sigal/plugins/encrypt/encrypt.py b/sigal/plugins/encrypt/encrypt.py index 27ca094..e484843 100644 --- a/sigal/plugins/encrypt/encrypt.py +++ b/sigal/plugins/encrypt/encrypt.py @@ -30,20 +30,25 @@ from click import progressbar from sigal import signals from sigal.settings import get_thumb -from sigal.utils import copy, url_from_path +from sigal.utils import copy from .endec import encrypt, kdf_gen_key logger = logging.getLogger(__name__) -ASSETS_PATH = os.path.normpath(os.path.join( - os.path.abspath(os.path.dirname(__file__)), 'static')) +ASSETS_PATH = os.path.normpath( + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'static')) + class Abort(Exception): pass + def gen_rand_string(length=16): - return "".join(random.SystemRandom().choices(string.ascii_letters + string.digits, k=length)) + return "".join(random.SystemRandom().choices(string.ascii_letters + + string.digits, + k=length)) + def get_options(settings, cache): if "encrypt_options" not in settings: @@ -58,7 +63,7 @@ def get_options(settings, cache): table = str.maketrans({'"': r'\"', '\\': r'\\'}) if "password" not in settings["encrypt_options"] \ - or len(settings["encrypt_options"]["password"]) == 0: + or len(settings["encrypt_options"]["password"]) == 0: logger.error("Encrypt: no password provided") raise ValueError("no password provided") else: @@ -66,8 +71,10 @@ def get_options(settings, cache): options["escaped_password"] = options["password"].translate(table) if "ask_password" not in options: - options["ask_password"] = settings["encrypt_options"].get("ask_password", False) - options["filtered_password"] = "" if options["ask_password"] else options["escaped_password"] + options["ask_password"] = settings["encrypt_options"].get( + "ask_password", False) + options["filtered_password"] = "" if options["ask_password"] else options[ + "escaped_password"] if "gcm_tag" not in options: options["gcm_tag"] = gen_rand_string() @@ -83,7 +90,8 @@ def get_options(settings, cache): if "kdf_iters" not in options: options["kdf_iters"] = 10000 - # in case any of the credentials are newly generated, write them back to cache + # in case any of the credentials are newly generated, write them back + # to cache cache["credentials"] = { "gcm_tag": options["gcm_tag"], "kdf_salt": options["kdf_salt"], @@ -93,9 +101,11 @@ def get_options(settings, cache): return options + def cache_key(media): return os.path.join(media.path, media.filename) + def save_property(cache, media): key = cache_key(media) if key not in cache: @@ -104,16 +114,20 @@ def save_property(cache, media): cache[key]["thumb_size"] = media.thumb_size cache[key]["encrypted"] = set() + def get_encrypt_list(settings, media): to_encrypt = [] - to_encrypt.append(media.filename) #resized image or in case of "use_orig", the original + # resized image or in case of "use_orig", the original + to_encrypt.append(media.filename) if settings["make_thumbs"]: - to_encrypt.append(get_thumb(settings, media.filename)) #thumbnail + to_encrypt.append(get_thumb(settings, media.filename)) # thumbnail if media.big is not None and not settings["use_orig"]: - to_encrypt.append(media.big) #original image - to_encrypt = list(map(lambda path: os.path.join(media.path, path), to_encrypt)) + to_encrypt.append(media.big) # original image + to_encrypt = list( + map(lambda path: os.path.join(media.path, path), to_encrypt)) return to_encrypt + def load_property(album): gallery = album.gallery cache = load_cache(gallery.settings) @@ -125,21 +139,25 @@ def load_property(album): media.size = cache[key]["size"] media.thumb_size = cache[key]["thumb_size"] + def load_cache(settings): cachePath = os.path.join(settings["destination"], ".encryptCache") try: with open(cachePath, "rb") as cacheFile: encryptCache = pickle.load(cacheFile) - logger.debug("Loaded encryption cache with %d entries", len(encryptCache)) + logger.debug("Loaded encryption cache with %d entries", + len(encryptCache)) return encryptCache except FileNotFoundError: encryptCache = {} return encryptCache except Exception as e: logger.error("Could not load encryption cache: %s", e) - logger.error("Giving up encryption. You may have to delete and rebuild the entire gallery.") + logger.error("Giving up encryption. You may have to delete and " + "rebuild the entire gallery.") raise Abort + def save_cache(settings, cache): cachePath = os.path.join(settings["destination"], ".encryptCache") try: @@ -150,6 +168,7 @@ def save_cache(settings, cache): logger.warning("Could not store encryption cache: %s", e) logger.warning("Next build of the gallery is likely to fail!") + def encrypt_gallery(gallery): albums = gallery.albums settings = gallery.settings @@ -163,19 +182,26 @@ def encrypt_gallery(gallery): encrypt_files(settings, config, cache, albums, gallery.progressbar_target) save_cache(settings, cache) + def encrypt_files(settings, config, cache, albums, progressbar_target): if settings["keep_orig"] and settings["orig_link"]: - logger.warning("Original images are symlinked! Encryption is aborted. Please set \"orig_link\" to False and restart gallery build.") + logger.warning( + "Original images are symlinked! Encryption is aborted. " + "Please set 'orig_link' to False and restart gallery build.") raise Abort - key = kdf_gen_key(config["password"], config["kdf_salt"], config["kdf_iters"]) + key = kdf_gen_key(config["password"], config["kdf_salt"], + config["kdf_iters"]) gcm_tag = config["gcm_tag"].encode("utf-8") medias = list(chain.from_iterable(albums.values())) - with progressbar(medias, label="%16s" % "Encrypting files", file=progressbar_target, show_eta=True) as medias: + with progressbar(medias, + label="%16s" % "Encrypting files", + file=progressbar_target, + show_eta=True) as medias: for media in medias: if media.type != "image": - logger.info("Skipping non-image file %s", media.filename) + logger.info("Skipping non-image file %s", media.src_filename) continue save_property(cache, media) @@ -196,9 +222,11 @@ def encrypt_files(settings, config, cache, albums, progressbar_target): save_cache(settings, cache) raise Abort - key_check_path = os.path.join(settings["destination"], 'static', 'keycheck.txt') + key_check_path = os.path.join(settings["destination"], 'static', + 'keycheck.txt') encrypt_file("keycheck.txt", key_check_path, key, gcm_tag) + def encrypt_file(filename, full_path, key, gcm_tag): with BytesIO() as outBuffer: try: @@ -217,16 +245,28 @@ def encrypt_file(filename, full_path, key, gcm_tag): return False return True + def copy_assets(settings): theme_path = os.path.join(settings["destination"], 'static') - copy(os.path.join(ASSETS_PATH, "decrypt.js"), theme_path, symlink=False, rellink=False) - copy(os.path.join(ASSETS_PATH, "keycheck.txt"), theme_path, symlink=False, rellink=False) - copy(os.path.join(ASSETS_PATH, "sw.js"), settings["destination"], symlink=False, rellink=False) + copy(os.path.join(ASSETS_PATH, "decrypt.js"), + theme_path, + symlink=False, + rellink=False) + copy(os.path.join(ASSETS_PATH, "keycheck.txt"), + theme_path, + symlink=False, + rellink=False) + copy(os.path.join(ASSETS_PATH, "sw.js"), + settings["destination"], + symlink=False, + rellink=False) + def inject_scripts(context): cache = load_cache(context['settings']) context["encrypt_options"] = get_options(context['settings'], cache) + def register(settings): signals.gallery_build.connect(encrypt_gallery) signals.album_initialized.connect(load_property) diff --git a/tests/sample/sigal.conf.py b/tests/sample/sigal.conf.py index 8cdafcd..e30b0c2 100644 --- a/tests/sample/sigal.conf.py +++ b/tests/sample/sigal.conf.py @@ -4,7 +4,7 @@ source = 'pictures' thumb_suffix = '.tn' keep_orig = True thumb_video_delay = 5 -img_format = 'jpeg' +# img_format = 'jpeg' links = [('Example link', 'http://example.org'), ('Another link', 'http://example.org')] diff --git a/tests/test_gallery.py b/tests/test_gallery.py index 785dcdc..e96262f 100644 --- a/tests/test_gallery.py +++ b/tests/test_gallery.py @@ -141,8 +141,11 @@ def test_image(settings, tmpdir): def test_video(settings, tmpdir): settings['destination'] = str(tmpdir) m = Video('example video.ogv', 'video', settings) + + src_path = join('video', 'example video.ogv') + assert str(m) == src_path + file_path = join('video', 'example video.webm') - assert str(m) == file_path assert m.dst_path == join(settings['destination'], file_path) os.makedirs(join(settings['destination'], 'video', 'thumbnails'))