lunch-notifier/scraper.py

101 lines
2.9 KiB
Python

import os
import sys
import logging
import smtplib
from datetime import datetime
from email.message import EmailMessage
import requests
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)
SCHOOL_SLUG = "kyrene-de-la-mariposa"
MENU_TYPE = "lunch"
API_BASE = "https://kyrene.api.nutrislice.com/menu/api/weeks/school"
def get_lunch_menu(date_str: str | None = None) -> tuple[list[str], str]:
if date_str is None:
date_str = datetime.now().strftime("%Y-%m-%d")
dt = datetime.strptime(date_str, "%Y-%m-%d")
url = f"{API_BASE}/{SCHOOL_SLUG}/menu-type/{MENU_TYPE}/{dt.year}/{dt.month:02d}/{dt.day:02d}/"
log.info(f"Fetching {url}")
resp = requests.get(
url,
headers={"Accept": "application/json", "User-Agent": "Mozilla/5.0"},
timeout=20,
)
resp.raise_for_status()
data = resp.json()
items = []
for day in data.get("days", []):
if day.get("date") != date_str:
continue
for entry in day.get("menu_items", []):
if entry.get("is_section_title") or entry.get("is_station_header"):
continue
food = entry.get("food")
if food and food.get("name"):
items.append(food["name"].strip())
return items, date_str
def send_sms(message: str, phone: str) -> None:
gmail_user = os.environ["GMAIL_USER"]
gmail_pass = os.environ["GMAIL_APP_PASSWORD"]
gateway = os.environ.get("CARRIER_GATEWAY", "vtext.com")
to_addr = f"{phone}@{gateway}"
msg = EmailMessage()
msg["From"] = gmail_user
msg["To"] = to_addr
msg.set_content(message)
log.info(f"Sending email-to-SMS → {to_addr}")
with smtplib.SMTP("smtp.gmail.com", 587) as smtp:
smtp.starttls()
smtp.login(gmail_user, gmail_pass)
smtp.send_message(msg)
log.info("Sent.")
def main():
phone = os.environ.get("PHONE_NUMBER", "").strip()
if not phone:
log.error("PHONE_NUMBER environment variable is not set.")
sys.exit(1)
try:
items, date_str = get_lunch_menu()
if items:
body = "\n".join(f"{i}" for i in items)
message = f"Mariposa Lunch {date_str}:\n{body}"
else:
message = (
f"No lunch menu posted for {date_str} "
f"(Kyrene de la Mariposa — may be a break or holiday)."
)
except Exception as e:
log.exception("Failed to fetch menu")
message = f"Error fetching Mariposa lunch menu: {e}"
# SMS via email has a ~160 char limit per message segment; keep it short
if len(message) > 1400:
message = message[:1397] + "..."
log.info(f"Message:\n{message}")
try:
send_sms(message, phone)
except Exception as e:
log.error(f"Failed to send SMS: {e}")
sys.exit(1)
if __name__ == "__main__":
main()