import os import hashlib from datetime import datetime from pathlib import Path import html2image import click import frontmatter html = """ <html> <head> <style> body { margin: 0; padding: 0; width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center; } .content { width: 95%; } </style> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet"> </head> <body> <div class="content p-4" style="background-color: #fefefe;font-family: 'Nunito', sans-serif; font-size: 20px;"> <div class="d-flex flex-column justify-content-center align-items-center text-center" style="border: 10px solid #025a5f; padding: 20px; border-radius:50px;"> <span class="tweet-text mb-2" style="font-size: 2.6rem;"> {title} </span> <span class="text-muted mb-2"> {date} </span> <div class="flex justify-center my-4"> <div class="rounded-full inline-flex" style="background-color: #ffffff; height: 0.25rem; width: 4rem;"></div> </div> <div class="mb-2"> <img src="https://brainsteam.co.uk/images/avatar_small.png" class="rounded-circle" style="width: 150px;"> </div> <h4 class="mt-2" style="color: #025a5f" >James Ravenscroft</h4> <span class="text-muted">@jamesravey@fosstodon.org</span> </div> </div> </body> </html> """ def generate_filename_hash(title: str, pubdate: str): """Generate the filename for the title card based on post title and pub date""" fhash = hashlib.new("sha256") fhash.update(f"{title}:{pubdate}".encode("utf8")) return fhash.hexdigest() @click.group() def cli(): pass @cli.command() @click.option("--input-file", "-i", required=True, type=click.Path(exists=True)) @click.option("--workspace-path", "-w", required=True, type=click.Path(exists=True)) def single(workspace_path, input_file): """Generate a title card for a single post""" generate_card(input_file, workspace_path) @cli.command() @click.option("--subdir", "-i", required=True, type=click.Path(exists=True)) @click.option("--workspace-path", "-w", required=True, type=click.Path(exists=True)) def tree(workspace_path, subdir): """Retursively walk subdir and generate title cards for all posts""" for root, dirs, files in os.walk(subdir): for file in files: if file.endswith(".md"): generate_card(os.path.join(root, file), workspace_path) def generate_card(input_file, workspace_path): print(f"Loading {input_file}") front_matter = frontmatter.load(input_file) title: str = str(front_matter.get("title")) date: str = str(front_matter.get("date", datetime.now().isoformat())) if title and date: parsed_date = datetime.fromisoformat(date).strftime("%b %d, %Y") parsed_html = html.replace("{title}", title).replace("{date}", parsed_date) # file_name = f"{uuid.uuid4()}.png" file_name = f"{generate_filename_hash(title, date)}.png" hti = html2image.Html2Image() output_path = Path(workspace_path) / "static" / "social" / file_name if os.path.exists(output_path): print(f"{output_path} Already exists, using cached image") else: print(f"Generating card... {output_path}") hti.temp_path = Path(workspace_path) / "tmp" if not os.path.exists(hti.temp_path): os.mkdir(hti.temp_path) files = hti.screenshot( html_str=[parsed_html], save_as=file_name, size=[(1128, 600)] ) # move from tmp location to workspace folder output_path = output_path.absolute().as_posix() os.rename(files[0], output_path) if "preview" in front_matter: # strip '/social/' from the existing preview value old_fin = front_matter["preview"][:8] old_fill_path = Path(workspace_path) / "static" / "social" / old_fin if os.path.exists(old_fill_path) and (old_fill_path != output_path): print(f"Move {old_fill_path} into cleanup...") os.rename(old_fill_path, old_fill_path + ".cleanup") front_matter["preview"] = f"/social/{file_name}" frontmatter.dump(front_matter, input_file) if __name__ == "__main__": cli()