Remove logo data from templates, add logo args

Removed the hard-coded data: URIs from the template files. Implemented a
--logo argument to provide a logo file, and a --no-logo argument to
prevent the default logo from being displayed. Data URIs are now created
on demand and passed as context to the templates.

Bumped version to 0.1.3
This commit is contained in:
Kumi 2024-02-14 20:57:17 +01:00
parent 4b523aa979
commit df3d17ba58
Signed by: kumi
GPG key ID: ECBCC9082395383F
9 changed files with 133 additions and 81 deletions

View file

@ -1,6 +1,6 @@
# Kalente # Kalente
<img src="img/kalente.png" alt="Kalente logo" width="200" height="200" align="right"> <img src="src/kalente/static/logo.png" alt="Kalente logo" width="200" height="200" align="right">
Kalente is a simple Python script for generating PDF calendars. Kalente is a simple Python script for generating PDF calendars.

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "kalente" name = "kalente"
version = "0.1.2" version = "0.1.3"
authors = [ authors = [
{ name="Kumi Mitterer", email="kalente@kumi.email" }, { name="Kumi Mitterer", email="kalente@kumi.email" },
] ]

2
requirements-dev.txt Normal file
View file

@ -0,0 +1,2 @@
djlint
black

View file

@ -6,12 +6,15 @@ from datetime import date, timedelta
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from locale import setlocale, LC_ALL from locale import setlocale, LC_ALL
from base64 import b64encode
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from dateutil.parser import parse from dateutil.parser import parse
import math import math
NO_LOGO = ""
def get_day( def get_day(
for_date: date = None, for_date: date = None,
@ -25,11 +28,14 @@ def get_day(
"date_obj": day, "date_obj": day,
"day": day.strftime("%A"), "day": day.strftime("%A"),
"date": day.strftime(date_format), "date": day.strftime(date_format),
"holiday": holidays.CountryHoliday(country_code, years=[for_date.year]).get(day), "holiday": holidays.CountryHoliday(country_code, years=[for_date.year]).get(
day
),
"is_weekend": (day.weekday() in [5, 6]), "is_weekend": (day.weekday() in [5, 6]),
} }
return day_info return day_info
def get_week( def get_week(
for_date: date = None, for_date: date = None,
country_code: Optional[str] = None, country_code: Optional[str] = None,
@ -60,6 +66,7 @@ def get_week(
week_days.append(day_info) week_days.append(day_info)
return week_days return week_days
def get_month( def get_month(
for_date: date = None, for_date: date = None,
country_code: Optional[str] = None, country_code: Optional[str] = None,
@ -87,6 +94,7 @@ def get_month(
return month_weeks return month_weeks
def get_year( def get_year(
for_date: date = None, for_date: date = None,
country_code: Optional[str] = None, country_code: Optional[str] = None,
@ -107,7 +115,10 @@ def get_year(
return year_months return year_months
def generate_html(content, content_type, template_path: str = None):
def generate_html(
content, content_type, template_path: str = None, logo_path: str = None
):
if not template_path: if not template_path:
template_name = "{}.html".format(content_type) template_name = "{}.html".format(content_type)
file_loader = FileSystemLoader(Path(__file__).parent.absolute() / "templates") file_loader = FileSystemLoader(Path(__file__).parent.absolute() / "templates")
@ -115,20 +126,35 @@ def generate_html(content, content_type, template_path: str = None):
template_name = template_path template_name = template_path
file_loader = FileSystemLoader() file_loader = FileSystemLoader()
if logo_path is None:
logo_path = Path(__file__).parent / "static" / "logo.png"
if logo_path:
# Let it throw, let it throw, let it throw...
with Path(logo_path).open("rb") as logo_file:
logo = b64encode(logo_file.read()).decode("utf-8")
mime_type = (
"image/png" if str(logo_path).endswith(".png") else "image/jpeg"
) # Doesn't matter much anyway.
data_uri = f"data:image/png;base64,{logo}"
env = Environment(loader=file_loader) env = Environment(loader=file_loader)
template = env.get_template(template_name) template = env.get_template(template_name)
context = {"logo": data_uri}
if content_type == "yearly": if content_type == "yearly":
return template.render(year=content) return template.render(year=content, **context)
elif content_type == "monthly": elif content_type == "monthly":
return template.render(month=content, month_obj=content[1][0]["date_obj"]) return template.render(month=content, **context)
elif content_type == "weekly": elif content_type == "weekly":
return template.render(week=content) return template.render(week=content, **context)
elif content_type == "daily": elif content_type == "daily":
return template.render(day=content) return template.render(day=content, **context)
else: else:
raise ValueError("Invalid content type: {}".format(content_type)) raise ValueError("Invalid content type: {}".format(content_type))
def convert_html_to_pdf(content, output_filename, options=None): def convert_html_to_pdf(content, output_filename, options=None):
options.setdefault("page-size", "A4") options.setdefault("page-size", "A4")
options.setdefault("orientation", "Landscape") options.setdefault("orientation", "Landscape")
@ -224,6 +250,20 @@ def main():
default=None, default=None,
) )
logo_group = parser.add_mutually_exclusive_group()
logo_group.add_argument(
"--logo",
help="Path to the logo to use",
required=False,
default=None,
)
logo_group.add_argument(
"--no-logo",
action="store_true",
help="Don't use a logo",
required=False,
)
args = parser.parse_args() args = parser.parse_args()
# Set locale to en_US.UTF-8 for now, only English is supported # Set locale to en_US.UTF-8 for now, only English is supported
@ -277,20 +317,27 @@ def main():
if not args.type in ["daily", "weekly", "monthly", "yearly"]: if not args.type in ["daily", "weekly", "monthly", "yearly"]:
raise ValueError(f"Invalid calendar type: {args.type}") raise ValueError(f"Invalid calendar type: {args.type}")
if args.no_logo:
logo_path = NO_LOGO
else:
logo_path = args.logo
for i in range(count): for i in range(count):
data = ({ data = (
{
"daily": get_day, "daily": get_day,
"weekly": get_week, "weekly": get_week,
"monthly": get_month, "monthly": get_month,
"yearly": get_year "yearly": get_year,
}[args.type])(for_date, country_code, args.date_format) }[args.type]
html_content = generate_html(data, args.type, args.template) )(for_date, country_code, args.date_format)
html_content = generate_html(data, args.type, args.template, logo_path)
pages.append(html_content) pages.append(html_content)
for_date = { for_date = {
"daily": lambda x: x["date_obj"] + timedelta(days=1), "daily": lambda x: x["date_obj"] + timedelta(days=1),
"weekly": lambda x: x[-1]["date_obj"] + timedelta(days=1), "weekly": lambda x: x[-1]["date_obj"] + timedelta(days=1),
"monthly": lambda x: x[1][0]["date_obj"] + timedelta(days=31), "monthly": lambda x: x[1][0]["date_obj"] + timedelta(days=31),
"yearly": lambda x: x[11][5][0]["date_obj"] + timedelta(days=365) "yearly": lambda x: x[11][5][0]["date_obj"] + timedelta(days=365),
}[args.type](data) }[args.type](data)
conversion_options = {"orientation": "Portrait"} if args.type == "daily" else {} conversion_options = {"orientation": "Portrait"} if args.type == "daily" else {}

View file

Before

Width:  |  Height:  |  Size: 3 MiB

After

Width:  |  Height:  |  Size: 3 MiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long