summaryrefslogtreecommitdiff
path: root/build.py
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-04-03 23:12:04 +0200
committerJulian T <julian@jtle.dk>2021-04-03 23:15:25 +0200
commit4cbc2eae6335222b74129c9eaedab39250c3b7b9 (patch)
tree109eb8b854896aa5b8e8777dbebcd08c615f578b /build.py
parent556f61555c022946e80bd5815232867bfab77f6b (diff)
Moved to python based builder
Diffstat (limited to 'build.py')
-rwxr-xr-xbuild.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/build.py b/build.py
new file mode 100755
index 0000000..05b05bd
--- /dev/null
+++ b/build.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3
+import jinja2
+from PIL import Image
+import argparse
+from pathlib import Path
+import yaml
+import os
+import re
+import hashlib
+
+imagereg = re.compile("([a-z0-9]*)\\..*")
+resreg = re.compile("([0-9]*)x([0-9]*)")
+
+def hashfile(fname):
+ md5 = hashlib.md5()
+ print(fname)
+ with open(fname, "rb") as f:
+ for chunk in iter(lambda: f.read(4096), b""):
+ md5.update(chunk)
+
+ return md5
+
+def parse_res(res):
+ m = resreg.match(res)
+ return (int(m.group(1)), int(m.group(2)))
+
+class FileLoader(jinja2.BaseLoader):
+ def get_source(self, environment, template):
+ if not os.path.exists(template):
+ raise TemplateNotFound(template)
+ mtime = os.path.getmtime(template)
+ with open(template, "r") as f:
+ source = f.read()
+ return source, template, lambda: mtime == getmtime(template)
+
+class ImageLocation:
+ def __init__(self, folder):
+ self.folder = folder
+ self.stuff = {}
+
+ self.unused = set()
+ self.existing = {}
+
+ if not os.path.isdir(folder):
+ os.mkdir(folder)
+
+ self.look()
+
+ self.tmpname = os.path.join(folder, "tmp")
+
+ def look(self):
+ for name in os.listdir(self.folder):
+ m = imagereg.match(name)
+ if m is not None:
+ fhash = m.group(1)
+
+ self.unused.add(fhash)
+ self.existing[fhash] = name
+
+ def convert(self, imgname, settings):
+ # First determine the hash from settings
+ thash = hashlib.md5(bytes(
+ f"{settings['res']}+{settings['ext']}" + imgname
+ , encoding="utf8")).hexdigest()
+
+ # Now check if it exists
+ if thash in self.existing:
+ print(f"Skipping file {imgname}[{thash}]")
+ return self.existing[thash], thash
+
+ # Okay convert it
+ fname = f"{thash}.{settings['ext']}"
+ print(f"Converting file {imgname} to {fname}")
+
+ im = Image.open(imgname)
+ im = im.resize(settings["res"], Image.ANTIALIAS)
+ tmpname = f"{self.tmpname}.{settings['ext']}"
+ im.save(tmpname)
+
+ os.rename(tmpname, os.path.join(self.folder, fname))
+
+ self.existing[thash] = fname
+ self.unused.add(thash)
+
+ return fname, thash
+
+ def fetch(self, imgname, settings, relto=None):
+ # Check if we already have it
+ fname, hash = self.convert(imgname, settings)
+
+ # Mark the hash as used
+ self.unused.remove(hash)
+
+ if relto is not None:
+ full = os.path.join(self.folder, fname)
+ return os.path.relpath(full, start=relto)
+
+ return fname
+
+ def clean(self):
+ print("Running cleanup")
+ for uhash in self.unused:
+ fname = os.path.join(self.folder, self.existing[uhash])
+ print(f"Removing file {fname}")
+ os.remove(fname)
+
+class Renderer:
+ def __init__(self, config_file, loadpath, resolution, extension):
+ self.config = Renderer.__load_config(config_file)
+ self.loadpath = loadpath
+ self.scaled = None
+
+ self.settings = {
+ "res": parse_res(resolution),
+ "ext": extension,
+ }
+
+ def __load_config(config_file):
+ config = {}
+ with open(config_file, "r") as f:
+ config = yaml.safe_load(f)
+
+ print(f"Loaded config: {config}")
+ return config
+
+ def imgfetch_gen(self, loc, dest):
+ def fn(img):
+ return loc.fetch(img, self.settings, relto=dest)
+
+ return fn
+
+ def build_to(self, dest, template, context, loc=None, clean=False):
+ if loc is None:
+ loc = ImageLocation(os.path.join(dest, "imgs"))
+
+ jenv = jinja2.Environment(
+ loader = FileLoader(),
+ autoescape=jinja2.select_autoescape(['html', 'xml'])
+ )
+ jenv.globals.update(
+ imgfetch=self.imgfetch_gen(loc, dest)
+ )
+
+ tmpl = jenv.get_template(template)
+
+ with open(os.path.join(dest, "index.html"), "w") as f:
+ f.write(tmpl.render({**self.config, **context}))
+
+ if clean:
+ loc.clean()
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--dest", "-d", default="build", help="where to put resulting files")
+parser.add_argument("--size", "-s", default="1920x1080", help="size to scale web images to")
+parser.add_argument("--commit", "-g", help="git commit hash to announce")
+parser.add_argument("--clean", help="clean unused image files", action="store_true")
+parser.add_argument("--config", "-c", default="imginfo.yml", help="where to load image definitions from")
+parser.add_argument("--template", "-t", default="index.html.j2", help="html template to use")
+parser.add_argument("--cgit", "-w", help="cgit repo base url")
+parser.add_argument("--load", "-l", default=".", help="where to load full size images from")
+parser.add_argument("--ext", "-e", default="png", help="image extension to use")
+
+args = parser.parse_args()
+
+context = {
+ "cgit": args.cgit,
+ "git": args.commit
+ }
+
+rend = Renderer(args.config, args.load, args.size, args.ext)
+rend.build_to(args.dest, args.template, context, clean=args.clean)
+
+