#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
North Leeds monthly events → narrative → save as HTML file.
Usage:
export LEEDS_INSPIRED_KEY=xxxxxxxx
export MONTH=2025-08 # optional; defaults to current month
export AREAS="Chapel Allerton,Headingley,Meanwood,Moortown,Roundhay"
python3 north_leeds_events_html.py
"""
import os, sys, html, re, requests
from datetime import date
from urllib.parse import urlencode
LEEDS_API_BASE = "https://www.leedsinspired.co.uk/1.0"
ATTRIBUTION_HTML = (
'
'
'Listings via Leeds Inspired. '
'Please check with venues for the latest details. '
'
'
)
def env(name, default=None):
v = os.getenv(name)
return v if v and str(v).strip() else default
def month_bounds(iso_month: str | None):
if not iso_month:
today = date.today()
year, month = today.year, today.month
else:
year, month = map(int, iso_month.split("-"))
first = date(year, month, 1)
if month == 12:
nxt = date(year + 1, 1, 1)
else:
nxt = date(year, month + 1, 1)
return first, nxt
def ddmmyyyy(d: date) -> str:
return d.strftime("%d-%m-%Y")
def fetch_events(key: str, start: date, end: date):
params = {
"key": key,
"start_date": ddmmyyyy(start),
"end_date": ddmmyyyy(end.replace(day=28)) # crude end-of-month bound
}
url = f"{LEEDS_API_BASE}/events.json?{urlencode(params)}"
r = requests.get(url, timeout=30)
r.raise_for_status()
data = r.json()
return data.get("items", [])
def filter_north(items, areas_csv):
areas = [a.strip().lower() for a in areas_csv.split(",") if a.strip()]
return [
it for it in items
if any(a in (it.get("place_title") or "").lower() or a in (it.get("event_title") or "").lower() for a in areas)
]
def pick_highlights(items, limit=12):
seen, uniq = set(), []
for it in items:
t = (it.get("event_title") or "").strip().lower()
if t and t not in seen:
seen.add(t)
uniq.append(it)
return uniq[:limit]
def make_story_html(month_label, areas_csv, highlights, total_count):
bullets = []
for it in highlights:
title = html.escape(it.get("event_title","")).strip()
place = html.escape(it.get("place_title","") or "Leeds").strip()
url = it.get("li_url") or "#"
bullets.append(f'
{title} '
f'({place})')
areas_html = ", ".join([f"
{html.escape(a.strip())}" for a in areas_csv.split(",")])
intro = (
f"
Here’s a quick look at what’s happening around {areas_html} this {month_label}. "
f"We sifted {total_count} listings and picked a handful that feel distinctly North Leeds.
"
)
return (
f"
North Leeds: What’s Happening – {month_label}
"
+ intro
+ "
" + "\n".join(bullets) + "
"
+ ATTRIBUTION_HTML
+ "
Got a community event to share? Let us know and we’ll include it next time.
"
)
def main():
key = env("LEEDS_INSPIRED_KEY")
if not key:
print("ERROR: Set LEEDS_INSPIRED_KEY", file=sys.stderr)
sys.exit(1)
iso_month = env("MONTH")
start, end = month_bounds(iso_month)
month_label = start.strftime("%B %Y")
areas_csv = env("AREAS", "Chapel Allerton,Headingley,Meanwood,Moortown,Roundhay")
items = fetch_events(key, start, end)
north = filter_north(items, areas_csv)
highlights = pick_highlights(north)
html_body = make_story_html(month_label, areas_csv, highlights, len(north) or len(items))
out = f"north_leeds_whats_on_{start.strftime('%Y_%m')}.html"
with open(out, "w", encoding="utf-8") as f:
f.write(html_body)
print(f"Generated: {out}")
if __name__ == "__main__":
main()
Add comment
Comments
Test