commit 91355cf05bd18ca861803d36d6565e9f3dbf1103 Author: Ville Rantanen Date: Tue Jun 1 10:56:20 2021 +0300 first version diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..905cf02 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016 Ville Rantanen + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e8b529 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Mirva + +A tool to create a web gallery from a single folder of images. + +## Installation + +Usage requires ImageMagick binaries! Make sure you have `convert` in PATH. + +Use pip or similar to install from source. + +ex. + +`pip3 install --user --upgrade https://bitbucket.org/MoonQ/mirva/get/tip.tar.gz` + +## Usage + +Use the command line tool `mirva` to render web sites. + diff --git a/mirva/__init__.py b/mirva/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mirva/mirva.py b/mirva/mirva.py new file mode 100755 index 0000000..57232b7 --- /dev/null +++ b/mirva/mirva.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python3 + +import configparser +import os +import re +import shutil +import subprocess +from argparse import ArgumentParser + + +class Mirva: + def __init__(self): + + self.resource_src = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "resources" + ) + self.resource_dir = ".template" + self.config_file = os.path.join(self.resource_dir, "config") + self.get_options() + os.chdir(self.options.folder) + self.write_resources() + self.file_list = self.get_files() + if self.options.config or not os.path.exists(self.config_file): + self.create_config() + print("Exiting. Check config.") + return + self.get_config() + self.create_posts() + self.write_index() + self.write_mediums() + + def create_config(self): + print("Creating config: {}".format(os.path.join(self.options.folder,self.config_file))) + + config = configparser.ConfigParser() + config.read(self.config_file) + if not "SITE" in config: + config["SITE"] = { + "title": "", + "sub_title": "", + "intro": "", + } + + for f in self.file_list: + if not f in config: + config[f] = {"title": f, "description": ""} + + with open(self.config_file, "wt") as fp: + config.write(fp) + + def create_posts(self): + + self.posts = [] + for f in self.file_list: + if not f in self.config: + post = self.get_post(f, f, "") + else: + post = self.get_post( + f, self.config[f]["title"], self.config[f]["description"] + ) + self.posts.append(post) + + def get_config(self): + self.config = configparser.ConfigParser() + self.config.read(self.config_file) + + def get_files(self): + image_match = re.compile(".*\.jpg$|.*\.jpeg$|.*\.png$|.*\.gif$|.*\.tif$", re.I) + files = [] + for f in sorted(os.listdir(".")): + if f.startswith("."): + continue + if not image_match.match(f): + continue + files.append(f) + return files + + def get_options(self): + parser = ArgumentParser() + #parser.add_argument("-v", default=False, action="store_true") + parser.add_argument( + "--config", default=False, action="store_true", help="Write config and exit" + ) + + parser.add_argument( + "folder", + type=str, + default=".", + nargs="?", + help="Folder for gallery", + ) + self.options = parser.parse_args() + + def get_index(self, page_title, sub_title, intro, posts): + + return """ + + + + + + + +{page_title} + + + + +
+ + +
+
+
+
+
+
+ {intro} +
+
+ {posts} + +
 
+
+ +
 
+
+
+ +
+ +""".format( + page_title=page_title, + sub_title=sub_title, + intro=intro, + posts="\n".join(posts), + resource=self.resource_dir, + ) + + def get_post(self, image, title, content): + + return """ +
+ +
+

{title}

+
 
+
{content}
+
""".format( + image=image, title=title, content=content + ) + + def write_index(self): + + with open("index.html", "wt") as fp: + fp.write( + self.get_index( + self.config["SITE"]["title"], + self.config["SITE"]["sub_title"], + self.config["SITE"]["intro"], + self.posts, + ) + ) + + def write_resources(self): + + try: + os.makedirs(self.resource_dir) + except Exception: + pass + + for f in ("style.css", "arrow_up.png", "arrow_down.png", "banner.jpg"): + shutil.copy( + os.path.join(self.resource_src, f), os.path.join(self.resource_dir, f) + ) + + def write_mediums(self): + + try: + os.makedirs(".med") + except Exception: + pass + + # TODO: config image res + # TODO opts: force recreation + r = 850 + force = False + for f in self.file_list: + res = "{:d}x{:d}>".format(r, r) + outfile = os.path.join(".med", "{}.jpg".format(f)) + if not os.path.exists(outfile) or force: + convargs = [ + "convert", + "-define", + "jpeg:size={}x{}".format(r, r), + "{}[0]".format(f), + "-background", + "white", + "-flatten", + "-resize", + res, + "-quality", + "85", + outfile, + ] + subprocess.call(convargs) + + diff --git a/mirva/resources/arrow_down.png b/mirva/resources/arrow_down.png new file mode 100644 index 0000000..162483c Binary files /dev/null and b/mirva/resources/arrow_down.png differ diff --git a/mirva/resources/arrow_up.png b/mirva/resources/arrow_up.png new file mode 100644 index 0000000..d00f450 Binary files /dev/null and b/mirva/resources/arrow_up.png differ diff --git a/mirva/resources/banner.jpg b/mirva/resources/banner.jpg new file mode 100644 index 0000000..8fde91b Binary files /dev/null and b/mirva/resources/banner.jpg differ diff --git a/mirva/resources/style.css b/mirva/resources/style.css new file mode 100644 index 0000000..b46c145 --- /dev/null +++ b/mirva/resources/style.css @@ -0,0 +1,247 @@ + +/* +Design by TEMPLATED +http://templated.co +Released for free under the Creative Commons Attribution License +*/ + +body { + margin: 0; + padding: 0; + background-color: #eeeeee; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + color: #383838; +} + +h1, h2, h3 { + margin: 0; + padding: 0; + font-weight: normal; + color: #000000; +} + +h1 { + font-size: 2em; +} + +h2 { + font-size: 2.4em; +} + +h3 { + font-size: 1.6em; +} + +p, ul, ol { + margin-top: 0; + line-height: 180%; +} + +ul, ol { +} + +a { + text-decoration: none; + color: #7EAD01; +} + +a:hover { +} + +#wrapper { + width: 100vw; + margin: 0 auto; + padding: 0; +} + +/* Header */ + +#header { + clear: both; + width: 100vw; + height: 330px; + margin: 0 auto; + padding: 0px; + background: url(banner.jpg) no-repeat left top; + background-size: cover; +} + +/* Logo */ + +#logo { + margin: 0; + padding: 0px 0px 0px 60px; + color: #000000; +} + +#logo h1, #logo p { + margin: 0; + padding: 0; + color: #ffffff; +} + +#logo h1 { + padding-top: 160px; + letter-spacing: -1px; + font-size: 3.8em; +} + +#logo p { + margin: 0; + padding: 0px 0 0 10px; + font: normal 14px Georgia, "Times New Roman", Times, serif; + font-style: italic; + color: #FFFFFF; +} + +#logo a { + border: none; + background: none; + text-decoration: none; + color: #FFFFFF; +} + + +/* Page */ + +#page { + width: 90vw; + margin: 0 auto; + padding: 0px 0px 0px 0px; +} + +#page-bgtop { + padding: 20px 0px; +} + +#page-bgbtm { +} + +/* Content */ + +#content { + width: 90vw; + padding: 30px 0px 0px 0px; +} + +.post { + margin-bottom: 15px; + border-top: lightgray dashed; + padding-top: 5px; +} + +.post-bgtop { +} + +.post-bgbtm { +} + +.post .title { + height: 38px; + margin-bottom: 10px; + padding: 12px 0 0 0px; + letter-spacing: -.5px; + color: #000000; +} + +.post .title a { + color: #000000; + border: none; +} + +.post .meta { +/* margin-bottom: 30px;*/ + padding: 5px 0px 15px 0px; + text-align: left; + font-family: Arial, Helvetica, sans-serif; + font-size: 13px; + font-weight: bold; +} + +.post .meta .date { + float: left; +} + +.post .meta .posted { + float: right; +} + +.post .meta a { +} + +.post .entry { + padding: 0px 0px 20px 0px; + padding-bottom: 20px; + text-align: justify; +} + +.links { + padding-top: 20px; + font-size: 12px; + font-weight: bold; +} + +.center { + display: block; + text-align: center; +} + +.post_image { + max-height: 95vh; + max-width: 90vw; +} + +/* Footer */ + +#footer { + height: 50px; + margin: 0 auto; + padding: 0px 0 15px 0; + background: #ECECEC; + border-top: 1px solid #DEDEDE; + font-family: Arial, Helvetica, sans-serif; +} + +#footer p { + margin: 0; + padding-top: 20px; + line-height: normal; + font-size: 9px; + text-transform: uppercase; + text-align: center; + color: #A0A0A0; +} + +#footer a { + color: #8A8A8A; +} + +/* navi */ + +.navigation { + height: 20px; + margin-bottom: 5px; +} + +.navigation_button { + cursor: pointer; + box-shadow: 4px 4px 5px #888888; +} +.navigation_button:hover { + cursor: pointer; + box-shadow: 2px 2px 2px #888888; +} +@media only screen and (max-width: 800px) { + .navigation_button { + margin-top: 20px; + margin-bottom: 20px; + } +} +.float_up { + float: left; +} + +.float_down { + float: right; +} diff --git a/scripts/mirva b/scripts/mirva new file mode 100755 index 0000000..5965fdc --- /dev/null +++ b/scripts/mirva @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from mirva.mirva import Mirva + +if __name__ == '__main__': + Mirva() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..bfe2dc9 --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +from distutils.core import setup +setup( + name = 'mirva', + packages = ['mirva'], + scripts = ['scripts/mirva', + ], + package_data={'':['resources/*']}, + include_package_data=True, + version = '20210601', + description = 'A tool to create a web gallery from a folder of images.', + author = 'Ville Rantanen', + author_email = 'ville.q.rantanen@gmail.com', + url = 'https://bitbucket.org/MoonQ/mirva', + download_url = 'https://bitbucket.org/MoonQ/mirva/get/tip.tar.gz', + keywords = ['album', 'generator', 'javascript'], + classifiers = [], + license = 'MIT', +)