Generating pretty images for each talks.
This commit is contained in:
parent
561239bfa5
commit
0df5876fbd
|
@ -4,15 +4,39 @@ import argparse
|
|||
import logging
|
||||
import re
|
||||
import sqlite3
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from time import sleep
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfo
|
||||
from contextlib import suppress
|
||||
|
||||
from mastodon import Mastodon
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from html2image import Html2Image
|
||||
|
||||
|
||||
def generate_file(output_path, title, author, type, date, salle):
|
||||
environment = Environment(loader=FileSystemLoader("template/"))
|
||||
template = environment.get_template("template.html")
|
||||
|
||||
rend = template.render(
|
||||
title=title, author=author, type=type, date=date, salle=salle
|
||||
)
|
||||
|
||||
hti = Html2Image()
|
||||
hti.load_file("template/illustration_1.png")
|
||||
hti.load_file("template/logo_pyconfr_1.png")
|
||||
hti.screenshot(
|
||||
html_str=rend,
|
||||
css_file="template/styles.css",
|
||||
save_as=output_path,
|
||||
size=(1200, 675),
|
||||
)
|
||||
|
||||
|
||||
def convert_datetime(val):
|
||||
"""Convert ISO 8601 datetime to datetime.datetime object."""
|
||||
return datetime.fromisoformat(val.decode())
|
||||
return datetime.fromisoformat(val.decode() + "+00:00")
|
||||
|
||||
|
||||
sqlite3.register_converter("datetime", convert_datetime)
|
||||
|
@ -64,7 +88,8 @@ def get_talks(django_site_id=4):
|
|||
with con:
|
||||
res = con.execute(
|
||||
f"""
|
||||
SELECT cfp_talk.start_date,
|
||||
SELECT cfp_talk.id,
|
||||
cfp_talk.start_date,
|
||||
cfp_room.name room,
|
||||
GROUP_CONCAT(cfp_participant.name, x'00') participant,
|
||||
GROUP_CONCAT(cfp_participant.mastodon, x'00') mastodon,
|
||||
|
@ -116,12 +141,28 @@ def live_toot(talks, mastodon: Mastodon, ahead_days=0):
|
|||
for talk in talks:
|
||||
if talk.category == "Sprint":
|
||||
continue # We don't toot sprints.
|
||||
delta = talk.start_date - datetime.now() - timedelta(days=ahead_days)
|
||||
delta = (
|
||||
talk.start_date - datetime.now(timezone.utc) - timedelta(days=ahead_days)
|
||||
)
|
||||
if delta.total_seconds() > 10:
|
||||
logging.info("Waiting %s for %s to start.", delta, talk.title)
|
||||
sleep(delta.total_seconds() - 2) # Wait for the talk to start.
|
||||
sleep(2) # This is just a fool guard so we can Ctrl-C easily anytime.
|
||||
mastodon.toot(toot_for(talk, ahead_days))
|
||||
png_name = f"talk-{talk.id}.png"
|
||||
with suppress(FileNotFoundError):
|
||||
Path(png_name).unlink()
|
||||
generate_file(
|
||||
output_path=png_name,
|
||||
title=talk.title,
|
||||
author=", ".join(talk.participants),
|
||||
type=talk.category.split()[0],
|
||||
date=talk.start_date.astimezone(ZoneInfo("Europe/Paris")).strftime(
|
||||
"%A %d %B %HH%M"
|
||||
),
|
||||
salle="Salle " + talk.room.split("/")[0],
|
||||
)
|
||||
media = mastodon.media_post("rend.png")
|
||||
mastodon.status_post(toot_for(talk, ahead_days), media_ids=[media])
|
||||
|
||||
|
||||
class DryRunMastodon:
|
||||
|
@ -136,6 +177,12 @@ class DryRunMastodon:
|
|||
def toot(self, message):
|
||||
print(message)
|
||||
|
||||
def media_post(self, *args, **kwargs):
|
||||
print("Would upload media to Mastodon.")
|
||||
|
||||
def status_post(self, *args, **kwargs):
|
||||
print("Would tooting", args, kwargs)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
Mastodon.py
|
||||
Jinja2==3.1.2
|
||||
html2image==2.0.1
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 644 KiB |
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
|
@ -0,0 +1,133 @@
|
|||
.1_3 {
|
||||
overflow:hidden;
|
||||
}
|
||||
.e1_3 {
|
||||
background-color:rgba(255, 255, 255, 1);
|
||||
width:1200px;
|
||||
height:675px;
|
||||
}
|
||||
.e1_4 {
|
||||
width:1200px;
|
||||
height:675px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
}
|
||||
.e4_34 {
|
||||
width:1200px;
|
||||
height:675px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
background-image:url(illustration_1.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:cover;
|
||||
}
|
||||
.e1_8 {
|
||||
background-color:rgba(22.4910007417202, 61.18752770125866, 69.30900290608406, 1);
|
||||
width:975px;
|
||||
height:309px;
|
||||
position:absolute;
|
||||
left:127px;
|
||||
top:138px;
|
||||
border-top-left-radius:16px;
|
||||
border-top-right-radius:16px;
|
||||
border-bottom-left-radius:16px;
|
||||
border-bottom-right-radius:16px;
|
||||
}
|
||||
.e1_9 {
|
||||
color:rgba(183.60000729560852, 242.1246188879013, 255, 1);
|
||||
width:943px;
|
||||
height:79px;
|
||||
position:absolute;
|
||||
left:16px;
|
||||
top:8px;
|
||||
font-family:Fira Sans;
|
||||
text-align:center;
|
||||
font-size:64px;
|
||||
letter-spacing:5;
|
||||
}
|
||||
.e1_10 {
|
||||
width:943px;
|
||||
height:198px;
|
||||
position:absolute;
|
||||
left:16px;
|
||||
top:95px;
|
||||
}
|
||||
.e1_11 {
|
||||
color:rgba(255, 255, 255, 1);
|
||||
width:943px;
|
||||
height:154px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
font-family:Fira Sans;
|
||||
text-align:center;
|
||||
font-size:42px;
|
||||
letter-spacing:0;
|
||||
}
|
||||
.e1_12 {
|
||||
color:rgba(255, 255, 255, 1);
|
||||
width:943px;
|
||||
height:44px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:154px;
|
||||
font-family:Fira Sans;
|
||||
text-align:center;
|
||||
font-size:30px;
|
||||
letter-spacing:0;
|
||||
}
|
||||
.e1_13 {
|
||||
background-color:rgba(250.00000029802322, 249.00000035762787, 247.00000047683716, 1);
|
||||
width:739px;
|
||||
height:115px;
|
||||
position:absolute;
|
||||
left:231px;
|
||||
top:493px;
|
||||
border-top-left-radius:16px;
|
||||
border-top-right-radius:16px;
|
||||
border-bottom-left-radius:16px;
|
||||
border-bottom-right-radius:16px;
|
||||
}
|
||||
.e1_15 {
|
||||
width:515px;
|
||||
height:83px;
|
||||
position:absolute;
|
||||
left:208px;
|
||||
top:16px;
|
||||
}
|
||||
.e1_16 {
|
||||
color:rgba(22.000000588595867, 61.00000016391277, 69.00000348687172, 1);
|
||||
width:515px;
|
||||
height:38px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
font-family:Fira Sans;
|
||||
text-align:center;
|
||||
font-size:44px;
|
||||
letter-spacing:-2;
|
||||
}
|
||||
.e1_17 {
|
||||
color:rgba(22.000000588595867, 61.00000016391277, 69.00000348687172, 1);
|
||||
width:512px;
|
||||
height:27px;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:56px;
|
||||
font-family:Fira Sans;
|
||||
text-align:center;
|
||||
font-size:26px;
|
||||
letter-spacing:-1.5;
|
||||
}
|
||||
.e4_35 {
|
||||
width:176px;
|
||||
height:83px;
|
||||
position:absolute;
|
||||
left:16px;
|
||||
top:16px;
|
||||
background-image:url(logo_pyconfr_1.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:cover;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Html Generated</title>
|
||||
<meta name="description" content="Figma htmlGenerator">
|
||||
<meta name="author" content="htmlGenerator">
|
||||
<link href="https://fonts.googleapis.com/css?family=Fira+Sans&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<style>
|
||||
/*
|
||||
Figma Background for illustrative/preview purposes only.
|
||||
You can remove this style tag with no consequence
|
||||
*/
|
||||
body {background: #E5E5E5; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class=e1_3><div class=e1_4><div class="e4_34"></div></div><div class=e1_8><span class="e1_9">{{type}}</span><div class=e1_10><span class="e1_11">{{title}}</span><span class="e1_12">{{type}} de {{author}}</span></div></div><div class=e1_13><div class=e1_15><span class="e1_16">{{date}}</span><span class="e1_17">Université de Bordeaux · {{salle}}</span></div><div class="e4_35"></div></div></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
$fira sans-font : "Fira Sans"
|
Loading…
Reference in New Issue