#!/usr/bin/python3 """!@brief:generates static html imagelibrary @author: Luzia Christiane Tesar @date Mo 13. Jul 20:52:54 CEST 2026 """ import os import sys import glob # import exif from PIL import Image import argparse import configparser from pathlib import Path import datetime BUILD_DIR = Path("./build") CONF_DIR = Path("./conf") THUMBSIZE = (300, 300) GLOBALNAME = "Chrissys random Imagelibrary" AUTHOR = "Luzia Christiane Tesar" LANGUAGE = "en" DESCRIPTION = "" TODAY = datetime.datetime.today().strftime("%Y-%m-%d") CANONICALURL = "https://dm2lct.radio" exclude = set(['.thumbnails']) class HTML: def __init__(self, **kwargs): self.header = Path(CONF_DIR / "header.html").read_text() self.footer = Path(CONF_DIR / "footer.html").read_text() for key, value in kwargs.items(): setattr(self, key, value) def title(self, title): return f"""

{title}

\n""" def par(self, text): return f"""

{text}

\n""" def ul(self): return f"""\n""" def li(self, text): return f"""
  • {text}\n""" def div(self, divclass): return f"""
    \n""" def endDiv(self): return f"""
    \n""" def img(self, src, alt=None, width=None, title=None): return f"""{alt}\n""" def aimg(self, src, dest, alt=None, width=None, title=None): return f"""{alt}\n""" def link(self, dest, data): return f"""{data}""" def headermeta(self, title): header = self.header.replace("{{title}}", title) header = header.replace("{{cannonical_url}}", CANONICALURL) header = header.replace("{{global_name}}", GLOBALNAME) header = header.replace("{{global_name}}", GLOBALNAME) header = header.replace("{{author}}", AUTHOR) header = header.replace("{{language}}", LANGUAGE) header = header.replace("{{description}}", DESCRIPTION) header = header.replace("{{published_date}}", TODAY) header = header.replace("{{modified_date}}", TODAY) header = header.replace("{{canonical_URL}}", CANONICALURL) return header def writeIndex(self, indir, odir, title, info=None) -> None: try: with open(f"{odir}/index.html", "w", encoding="utf-8") as file: file.write(self.headermeta(title)) file.write(self.title(title)) if info is not None: file.write(self.ul()) for line in info: file.write(self.li(line)) file.write(self.endUl()) file.write(self.div("row")) imglist = glob.glob(str(odir) + "/.thumbnails/*") for n in range(0,3): file.write(self.div("column")) for i in range(n, len(imglist),3): file.write( self.aimg( imglist[i].removeprefix(str(odir) + "/"), imglist[i].removeprefix(str(odir) + "/.thumbnails/"), ) ) file.write(self.endDiv()) file.write(self.endDiv()) file.write(self.footer) except: pass def writeDetail(self, img, previmg, nextimg): buf+= self.headermeta(title) buf+= self.title(title) buf+= self.img(image) buf+= self.footer with open(f"build/{self.outfolder}/index.html", "w", encoding="utf-8") as file: file.write(buf) def writeMain(self): with open(f"{str(BUILD_DIR)}/index.html", "w", encoding="utf-8") as file: title="Chrissys random Imagelibrary" file.write(self.headermeta(title)) file.write(self.title(title)) file.write(self.div("row")) dirs = list(filter(lambda x: x.is_dir(),os.scandir(BUILD_DIR))) #dirs[:] = list(filter(lambda x: not x in exclude, dirs)) for n in range(0,3): file.write(self.div("column")) for i in range(n, len(dirs),3): thumbs = os.listdir(str(BUILD_DIR)+"/"+dirs[i].name+"/.thumbnails") file.write(self.div("desc")) file.write("EH23") file.write(self.endDiv()) file.write( self.aimg( str(dirs[i].name)+"/.thumbnails/"+thumbs[0], str(dirs[i].name)+"/"), ) file.write(self.endDiv()) file.write(self.endDiv()) file.write(self.footer) class EXIF: def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) class IMG: def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) def createThumb(img, thumbdir): file = Path(img).stem with Image.open(img) as im: im.thumbnail(THUMBSIZE) im.convert("RGB").save(str(thumbdir) + "/" + file + ".jpg", "JPEG") def processImage(img, odir): file = Path(img).stem with Image.open(img) as im: im.convert("RGB").save(str(odir) + "/" + file + ".jpg", "JPEG") def generateDir(path): Path(BUILD_DIR / path.name).mkdir(parents=True, exist_ok=True) Path(BUILD_DIR / path.name / ".thumbnails").mkdir(parents=True, exist_ok=True) return Path(BUILD_DIR / path.name), Path(BUILD_DIR / path.name / ".thumbnails") def parseIni(file): title = "" desc=[] files = [] try: with open(file, 'r') as f: for line in f: if line.startswith("desc = "): desc.append(line.removeprefix("desc = ").strip()) elif line.endswith(".jpg\n" or ".png\n" or ".jpeg\n"): files.append(line.strip()) elif line.startswith("title = "): title=line.removeprefix("title = ").strip() else: next except: pass return files, desc, title def processDir(path): try: if Path(path/".purrpic.ini").is_file(): files, desc, title = parseIni(Path(args.inpath/".purrpic.ini")) odir, thumbdir = generateDir(args.inpath) for img in files: createThumb(Path(args.inpath/img), thumbdir) processImage(Path(args.inpath/img), odir) html = HTML() html.writeIndex(thumbdir, odir, title, desc) except: pass if __name__ == "__main__": parser = argparse.ArgumentParser( prog="PurrPic", description="Creates a static image gallery from a given Filelist", epilog="Meow! =^.^=", ) parser.add_argument( "--inpath", type=lambda p: Path(p), help="", ) parser.add_argument( "--outpath", type=lambda p: Path(p), help="", ) parser.add_argument( "--start", "-s", type=str, help="", ) args = parser.parse_args() processDir(args.inpath) html=HTML() html.writeMain()