2024-09-09 12:57:25 +01:00
|
|
|
import uuid
|
|
|
|
import os
|
2024-10-28 20:28:12 +00:00
|
|
|
import hashlib
|
2024-09-09 12:57:25 +01:00
|
|
|
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>
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2024-10-28 20:28:12 +00:00
|
|
|
def generate_filename_hash(title: str, pubdate: str):
|
|
|
|
"""Generate the filename for the title card based on post title and pub date"""
|
2024-09-09 12:57:25 +01:00
|
|
|
|
2024-10-28 20:28:12 +00:00
|
|
|
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()
|
2024-10-28 20:38:31 +00:00
|
|
|
@click.option("--subdir", "-i", required=True, type=click.Path(exists=True))
|
2024-10-28 20:28:12 +00:00
|
|
|
@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}")
|
2024-09-09 12:57:25 +01:00
|
|
|
front_matter = frontmatter.load(input_file)
|
|
|
|
|
2024-10-28 20:28:12 +00:00
|
|
|
title: str = str(front_matter.get("title"))
|
|
|
|
date: str = str(front_matter.get("date", datetime.now().isoformat()))
|
2024-09-09 12:57:25 +01:00
|
|
|
|
|
|
|
if title and date:
|
2024-10-28 20:28:12 +00:00
|
|
|
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"
|
2024-09-09 12:57:25 +01:00
|
|
|
|
|
|
|
hti = html2image.Html2Image()
|
2024-10-28 20:28:12 +00:00
|
|
|
output_path = Path(workspace_path) / "static" / "social" / file_name
|
|
|
|
|
|
|
|
if os.path.exists(output_path):
|
|
|
|
print(f"{output_path} Already exists, using cached image")
|
|
|
|
return
|
2024-09-09 12:57:25 +01:00
|
|
|
|
|
|
|
hti.temp_path = Path(workspace_path) / "tmp"
|
|
|
|
|
|
|
|
if not os.path.exists(hti.temp_path):
|
|
|
|
os.mkdir(hti.temp_path)
|
|
|
|
|
|
|
|
files = hti.screenshot(
|
2024-10-28 20:28:12 +00:00
|
|
|
html_str=[parsed_html], save_as=file_name, size=[(1128, 600)]
|
|
|
|
)
|
2024-09-09 12:57:25 +01:00
|
|
|
|
|
|
|
# move from tmp location to workspace folder
|
|
|
|
output_path = output_path.absolute().as_posix()
|
|
|
|
os.rename(files[0], output_path)
|
|
|
|
|
2024-10-28 20:28:12 +00:00
|
|
|
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):
|
|
|
|
print(f"Move {old_fill_path} into cleanup...")
|
|
|
|
os.rename(old_fill_path, old_fill_path + ".cleanup")
|
|
|
|
|
|
|
|
front_matter["preview"] = f"/social/{file_name}"
|
2024-09-09 12:57:25 +01:00
|
|
|
|
|
|
|
frontmatter.dump(front_matter, input_file)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2024-10-28 20:28:12 +00:00
|
|
|
cli()
|