diff --git a/requirements.txt b/requirements.txt index 83d7719..c02e578 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ flask gunicorn requests python-dotenv -pytz \ No newline at end of file +pytz +Pillow \ No newline at end of file diff --git a/server.py b/server.py index 635e9be..043fe75 100644 --- a/server.py +++ b/server.py @@ -9,6 +9,7 @@ from flask import ( render_template, send_from_directory, send_file, + Response ) import os import json @@ -18,6 +19,9 @@ import dotenv from pytz import timezone import pytz import re +from PIL import Image, ImageDraw, ImageFont +import io +import urllib.parse dotenv.load_dotenv() @@ -78,7 +82,20 @@ def wellknown(path): # region Main routes @app.route("/") def index(): - return render_template("index.html") + from_tz = request.args.get('from_tz', '') + time = request.args.get('time', '') + to_tzs = request.args.get('to_tzs', '') + + # Generate the OG image URL based on the parameters + # Make sure to encode the parameters + from_tz = urllib.parse.quote(from_tz) + time = urllib.parse.quote(time) + to_tzs = urllib.parse.quote(to_tzs) + + + og_image = f"og_image?from_tz={from_tz}&time={time}&to_tzs={to_tzs}" + + return render_template("index.html", og_image=og_image) # Mapping of short timezone names to full names SHORT_TZ_MAP = { @@ -193,6 +210,80 @@ def convert_multiple(): return jsonify(results) +@app.route("/og_image") +def og_image(): + from_tz = request.args.get('from_tz', 'Unknown') + time = request.args.get('time', 'Unknown') + to_tzs = request.args.get('to_tzs', 'Unknown') + + # Load the background image + img_path = "templates/assets/img/og_image.webp" + img = Image.open(img_path).convert("RGBA") + d = ImageDraw.Draw(img) + + # Convert time format to 12-hour format and add AM/PM + try: + input_time = datetime.strptime(time, "%Y-%m-%dT%H:%M:%S") + except ValueError: + input_time = datetime.strptime(time, "%Y-%m-%dT%H:%M") + time = input_time.strftime("%I:%M %p") + + + + # Prepare text + text = f"{time} {from_tz.replace("_","/")}" + + from_tz = get_full_timezone(from_tz.replace("_", "/")) + + # Check if multiple timezones are provided + if "," in to_tzs: + to_tzs = to_tzs.split(",") + to_tz_list = [(tz, get_full_timezone(tz.replace("_", "/"))) for tz in to_tzs if len(tz) > 0] + else: + to_tz_list = [(to_tzs, get_full_timezone(to_tzs.replace("_", "/")))] + + if from_tz is None or any(tz[1] is None for tz in to_tz_list): + return send_from_directory("templates/assets/img", "og_image.webp") + + + + for tz in to_tz_list: + to_tz = tz[1] + to_tz_time = from_tz.localize(input_time).astimezone(to_tz) + text += f"\n{to_tz_time.strftime('%I:%M %p')} {tz[0].replace('_','/')}" + + + + font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" + font_size = 200 + # Shrink font size if text is too long + if (max(len(line) for line in text.split("\n")) > 13): + font_size = 150 + + font_size -= (len(text.split("\n")) - 4) * 10 + + + + font = ImageFont.truetype(font_path, font_size) + + text_bbox = d.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + + # Calculate text position + x = (img.width - text_width) / 2 + y = (img.height - text_height) / 2 + + # Add text to the image + d.text((x, y), text, fill=(255, 255, 255), font=font, align="center") + + # Save the image to a BytesIO object in WebP format + img_io = io.BytesIO() + img.save(img_io, 'WEBP') + img_io.seek(0) + + return Response(img_io, mimetype='image/webp') + @app.route("/<path:path>") def catch_all(path: str): if os.path.isfile("templates/" + path): diff --git a/templates/assets/img/og_image.webp b/templates/assets/img/og_image.webp new file mode 100644 index 0000000..a6cc74e Binary files /dev/null and b/templates/assets/img/og_image.webp differ diff --git a/templates/index.html b/templates/index.html index a1610af..1993ddb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,6 +7,22 @@ <title>Time Converter</title> <link rel="icon" href="/assets/img/favicon.png" type="image/png"> <link rel="stylesheet" href="/assets/css/index.css"> + <!-- og meta --> + <meta property="og:type" value="website" /> + <meta property="og:title" value="Timezone Converter" /> + <meta property="og:description" value="Convert between timezone | Nathan.Woodburn/" /> + <meta property="og:url" value="https://time.c.woodburn.au" /> + <meta property="og:image" value="https://time.c.woodburn.au/{{ og_image }}" /> + <meta property="og:image:alt" value="Convert between timezone image" /> + + <!-- twitter meta --> + <meta name="twitter:card" value="summary" /> + <meta name="twitter:site" value="@woodburn_nathan" /> + <meta name="twitter:creator" value="@woodburn_nathan" /> + <meta name="twitter:title" value="Timezone Converter" /> + <meta name="twitter:description" value="Convert between timezone | Nathan.Woodburn/" /> + <meta name="twitter:image" value="/{{ og_image }}" /> + <meta name="twitter:image:alt" value="Convert between timezone image" /> </head> <body>