diff options
-rwxr-xr-x | build.py | 173 | ||||
-rwxr-xr-x | build.rb | 145 | ||||
-rw-r--r-- | imginfo.yml | 39 | ||||
-rw-r--r-- | index.html.j2 | 42 | ||||
-rw-r--r-- | index.tmpl | 22 | ||||
-rw-r--r-- | shell.nix | 7 |
6 files changed, 246 insertions, 182 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) + + diff --git a/build.rb b/build.rb deleted file mode 100755 index 9f4ef88..0000000 --- a/build.rb +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env ruby - -require 'yaml' -require 'optparse' -require 'digest' -require 'mini_magick' -require 'fileutils' -require 'erb' - -def copyimage(path, file, target, extension) - hash = Digest::MD5.file(file).hexdigest - hash = Digest::MD5.hexdigest(hash.to_s + target) - filename = "#{hash}.#{extension}" - dest = File.join(path, filename) - - if File.exist?(dest) - puts "Skipping" - return filename - end - - puts "Writing #{dest}" - # Resize image and write it to destination - image = MiniMagick::Image.open(file) - image.resize(target) - image.format(extension) - image.write(dest) - - return filename -end - -def forImgs(imgs, &block) - if imgs.respond_to?("each") - imgs.each &block - else - block.call(imgs) - end -end - -def placeImage(file, src, href = nil) - if href - file.puts "<a href=\"#{href}\">" - end - file.puts "<img src=\"#{src}\">" - if href - file.puts "</a>" - end -end - -options = {} -OptionParser.new do |opts| - opts.banner = "Usage: build.rb dest" - - opts.on("-d", "--dest PATH", "PATH to put build files") do |path| - options[:path] = path - end - opts.on("-s", "--size SIZE", "Size to resize images to") do |size| - options[:size] = size - end - opts.on("-g", "--commit HASH", "Commit to display on website") do |hash| - options[:commit] = hash - end - opts.on("-c", "--clean", "Cleanup unused images") do |v| - options[:clean] = true - end - opts.on("-b", "--linkbase URL", "Add links to images, with URL as base") do |url| - options[:base] = url - end - opts.on("-e", "--extension EXT", "Image extension to use with imagemagick") do |ext| - options[:extension] = ext - end -end.parse! - -options[:path] = "build" unless options[:path] -options[:size] = "1920x1080" unless options[:size] -options[:clean] = false unless options[:clean] -options[:extension] = "jpg" unless options[:extension] -puts options - -# Create build dir -FileUtils.mkdir_p(options[:path]) - -defs = YAML.load(File.read("imginfo.yml")) -files = {} - -puts defs - -defs["groups"].each do |value| - - # For each image inside group - forImgs(value["imgs"]) do |img| - puts "Converting file #{img}" - dest = copyimage(options[:path], img, options[:size], options[:extension]) - files[img] = dest - end - -end - -puts files - -template = File.read("index.tmpl") -template = template.split("%BODY%") - -# Cleanup old files -if options[:clean] - Dir.glob(File.join(options[:path], "*")) do |file| - hash = File.basename(file) - if !files.values.include? hash - puts "Cleaning #{hash}" - File.delete(file) - end - end -end - -File.open(File.join(options[:path], "index.html"), "w") do |file| - # Print preample - file.write(template[0]) - - defs["groups"].each do |value| - file.puts "<div class=\"group\">" - if value[:title] - file.puts "<h2>#{value[:title]}</h2>" - end - forImgs(value["imgs"]) do |img| - href = options[:base] - # If href is given add a filename at the end - if href - href = File.join(href, img) - end - - placeImage(file, files[img], href) - end - - if value["what"] - file.puts "<p>#{value["what"]}" - end - file.puts "</div>" - end - - if options[:commit] - file.puts "<p>Bygget fra commit #{options[:commit]}</p>" - end - - # Print postampleee? - file.write(template[1]) -end diff --git a/imginfo.yml b/imginfo.yml index 9a2419e..fbcc628 100644 --- a/imginfo.yml +++ b/imginfo.yml @@ -1,21 +1,30 @@ -groups: - - imgs: kirke.jpg - what: Kirke i Århus - - imgs: bi.jpg - - imgs: olie.jpg - what: Boreplatform i Grenå - - imgs: bakker.jpg - - imgs: vindmøller.jpg +posts: + - imgs: + - kirke.jpg + text: Kirke i Århus + - imgs: + - bi.jpg + - imgs: + - olie.jpg + text: Boreplatform i Grenå - imgs: + - bakker.jpg + - imgs: + - vindmøller.jpg + - imgs: - vinge.jpg - imgs: - blomster2.jpg - blomster.jpg - blomster3.jpg - - imgs: maskiner.jpg - what: Taget ved Tangeværket. - - imgs: Struktur.jpg - what: Taget ved Dwingeloo Radiotelescoop. - - imgs: bænk.jpg - what: Taget ved fyrtårn på Helgenæs. - - imgs: saks.jpg + - imgs: + - maskiner.jpg + text: Taget ved Tangeværket. + - imgs: + - Struktur.jpg + text: Taget ved Dwingeloo Radiotelescoop. + - imgs: + - bænk.jpg + text: Taget ved fyrtårn på Helgenæs. + - imgs: + - saks.jpg diff --git a/index.html.j2 b/index.html.j2 new file mode 100644 index 0000000..d25e242 --- /dev/null +++ b/index.html.j2 @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Jtle images</title> + <link rel="icon" href="/favicon.png"> + <meta name="robots" content="noindex,nofollow"> + <style> + img { + width: 50%; + } + .post { + background-color: lightgray; + margin-bottom: 20px; + padding: 10px; + } + </style> + </head> + <body> + <p>Billeder taget på forskellige ferier etc, som jeg bruger til baggrund. Filer kan også findes <a href="https://git.jtle.dk/wallpapers">her</a>.</p> + {% for post in posts %} + <div class="post"> + <p>{{ post.text }}</p> + {% for img in post.imgs %} + {% if cgit is not none %} + <a href="{{cgit}}/plain/{{img}}"> + <img src="{{ imgfetch(img) }}" /> + </a> + {% else %} + <img src="{{ imgfetch(img) }}" /> + {% endif %} + + {% endfor %} + </div> + {% endfor %} + + + {% if git is not none %} + <p>Bygget fra commit {{ git }}</p> + {% endif %} + </body> +</html> diff --git a/index.tmpl b/index.tmpl deleted file mode 100644 index a9dfadb..0000000 --- a/index.tmpl +++ /dev/null @@ -1,22 +0,0 @@ -<html> - <head> - <meta charset="utf-8"> - <title>Jtle images</title> - <link rel="icon" href="/favicon.png"> - <meta name="robots" content="noindex,nofollow"> - <style> -img { - width: 90%; -} -.group { - background-color: lightgray; - margin-bottom: 20px; - padding: 10px; -} - </style> - </head> - <body> - <p>Billeder taget på forskellige ferier etc, som jeg bruger til baggrund. Filer kan også findes <a href="https://git.jtle.dk/wallpapers">her</a>.</p> - %BODY% - </body> -</html> diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..d452969 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +{ pkgs ? import <nixpkgs> {}, pythonPackages ? pkgs.python38Packages }: + +pkgs.mkShell { + buildInputs = with pythonPackages; [ + jinja2 schema pillow pyyaml + ]; +} |