diff --git a/automations/birthday-tracker/birthdays.json b/automations/birthday-tracker/birthdays.json index 7ced8da..49f69db 100644 --- a/automations/birthday-tracker/birthdays.json +++ b/automations/birthday-tracker/birthdays.json @@ -6,25 +6,43 @@ "birthday": "06-02", "birth_year": 1951, "notes": "Cancer treatment ongoing - be extra thoughtful. Loves gardening, cooking, family time.", - "gift_ideas": ["Flowers", "Gardening supplies", "Photo album", "Day spa voucher", "Home-cooked meal"], + "gift_ideas": [ + "Flowers", + "Gardening supplies", + "Photo album", + "Day spa voucher", + "Home-cooked meal" + ], "past_gifts": [] }, { - "name": "Harvey Martin", + "name": "Harvey Martin", "relationship": "Dad", "birthday": "12-08", "birth_year": 1949, "notes": "Full-time carer for Grace. Needs respite/support. Loves tech gadgets, wine, coffee.", - "gift_ideas": ["Ember mug", "Wine subscription", "Coffee beans", "Tech gadget", "Day out voucher"], + "gift_ideas": [ + "Ember mug", + "Wine subscription", + "Coffee beans", + "Tech gadget", + "Day out voucher" + ], "past_gifts": [] }, { "name": "Elizabeth Martin", - "relationship": "Sister", + "relationship": "Sister", "birthday": "09-11", "birth_year": 1990, "notes": "Vegan - avoid food gifts unless specifically vegan. Creative, environmentally conscious.", - "gift_ideas": ["Vegan cookbook", "Eco-friendly products", "Plants", "Art supplies", "Experience gift"], + "gift_ideas": [ + "Vegan cookbook", + "Eco-friendly products", + "Plants", + "Art supplies", + "Experience gift" + ], "past_gifts": [] }, { @@ -33,8 +51,314 @@ "birthday": "07-XX", "birth_year": 2016, "notes": "8 years old (born July 2016). Loves games, books, LEGO, sports.", - "gift_ideas": ["LEGO set", "Books", "Board games", "Sports equipment", "Science kit"], + "gift_ideas": [ + "LEGO set", + "Books", + "Board games", + "Sports equipment", + "Science kit" + ], "past_gifts": [] + }, + { + "name": "Jamie Greer", + "relationship": "Contact (from Google Calendar)", + "birthday": "03-30", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Jamie Greer's birthday", + "birth_year": 2019 + }, + { + "name": "Martin (Kristy’s)", + "relationship": "Contact (from Google Calendar)", + "birthday": "11-01", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Martin (Kristy’s) Birthday lunch ", + "birth_year": 2020 + }, + { + "name": "Josh O'keefe", + "relationship": "Contact (from Google Calendar)", + "birthday": "05-03", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Josh O'keefe's birthday dinner", + "birth_year": 2019 + }, + { + "name": "JK 40th", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-19", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: JK's 40th Birthday Zoom Champagne Sundowner!", + "birth_year": 2020 + }, + { + "name": "Pick up Elizabeth", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-20", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Pick up Elizabeth's birthday cake", + "birth_year": 2025 + }, + { + "name": "Jackie R’s", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-19", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Jackie R’s birthday", + "birth_year": 2021 + }, + { + "name": "Michael Somic", + "relationship": "Contact (from Google Calendar)", + "birthday": "10-15", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Michael Somic birthday ", + "birth_year": 2020 + }, + { + "name": "Anthony", + "relationship": "Contact (from Google Calendar)", + "birthday": "02-05", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Anthony birthday lunch", + "birth_year": 2023 + }, + { + "name": "Adrianna’s special", + "relationship": "Contact (from Google Calendar)", + "birthday": "02-25", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Adrianna’s special birthday 🥳", + "birth_year": 2023 + }, + { + "name": "Elizabeth", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-11", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Elizabeth's birthday", + "birth_year": 2020 + }, + { + "name": "By Justin a", + "relationship": "Contact (from Google Calendar)", + "birthday": "11-23", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: By Justin a birthday present", + "birth_year": 2019 + }, + { + "name": "Elizabeth", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-22", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Elizabeth's birthday party", + "birth_year": 2019 + }, + { + "name": "Kerry Milne", + "relationship": "Contact (from Google Calendar)", + "birthday": "11-04", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Kerry Milne birthday soirée ", + "birth_year": 2023 + }, + { + "name": "Simon te Brinke", + "relationship": "Contact (from Google Calendar)", + "birthday": "06-28", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Simon te Brinke's birthday celebrations", + "birth_year": 2024 + }, + { + "name": "Jackie 50th", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-22", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Jackie 50th Birthday Drinks 🥳", + "birth_year": 2024 + }, + { + "name": "Georga Stewart 30th", + "relationship": "Contact (from Google Calendar)", + "birthday": "10-12", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Georga Stewart's 30th birthday party", + "birth_year": 2019 + }, + { + "name": "Pineapples", + "relationship": "Contact (from Google Calendar)", + "birthday": "03-03", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Pineapples Birthday", + "birth_year": 2019 + }, + { + "name": "Terry’s 50th", + "relationship": "Contact (from Google Calendar)", + "birthday": "01-18", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Terry’s 50th birthday", + "birth_year": 2020 + }, + { + "name": "Kanya’s", + "relationship": "Contact (from Google Calendar)", + "birthday": "03-05", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Kanya’s birthday drinks", + "birth_year": 2021 + }, + { + "name": "Martin rages", + "relationship": "Contact (from Google Calendar)", + "birthday": "10-29", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Martin rages birthday", + "birth_year": 2022 + }, + { + "name": "Elly", + "relationship": "Contact (from Google Calendar)", + "birthday": "08-21", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Elly's birthday", + "birth_year": 2010 + }, + { + "name": "Jackie Cash", + "relationship": "Contact (from Google Calendar)", + "birthday": "09-25", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Jackie Cash Birthday Drinks 🥳", + "birth_year": 2022 + }, + { + "name": "Bianca’s", + "relationship": "Contact (from Google Calendar)", + "birthday": "02-21", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Bianca’s Birthday Brunch", + "birth_year": 2021 + }, + { + "name": "Daniel Surprise", + "relationship": "Contact (from Google Calendar)", + "birthday": "03-22", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Daniel's Surprise Birthday Lunch", + "birth_year": 2025 + }, + { + "name": "Pick up Alex", + "relationship": "Contact (from Google Calendar)", + "birthday": "07-06", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Pick up Alex's birthday cake", + "birth_year": 2025 + }, + { + "name": "Mums", + "relationship": "Contact (from Google Calendar)", + "birthday": "06-04", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Mums birthday ", + "birth_year": 2023 + }, + { + "name": "Joshua", + "relationship": "Contact (from Google Calendar)", + "birthday": "05-02", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Joshua's birthday drinks", + "birth_year": 2021 + }, + { + "name": "Lee’s", + "relationship": "Contact (from Google Calendar)", + "birthday": "02-18", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Lee’s birthday Drinks", + "birth_year": 2023 + }, + { + "name": "Jamie’s Good Friday", + "relationship": "Contact (from Google Calendar)", + "birthday": "03-29", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Jamie’s Good Friday Birthday Cruise", + "birth_year": 2024 + }, + { + "name": "Daniels", + "relationship": "Contact (from Google Calendar)", + "birthday": "05-28", + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": "Found in Google Calendar: Daniels birthday", + "birth_year": 2011 } ], "settings": { diff --git a/automations/birthday-tracker/sync-google-calendar.sh b/automations/birthday-tracker/sync-google-calendar.sh new file mode 100755 index 0000000..1786d4e --- /dev/null +++ b/automations/birthday-tracker/sync-google-calendar.sh @@ -0,0 +1,178 @@ +#!/bin/bash +# Google Calendar Birthday Sync +# Fetches iCal feed, extracts birthdays, syncs with birthdays.json +# Runs daily alongside birthday-tracker + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../../.env" 2>/dev/null || true + +# Config +ICAL_URL="${GOOGLE_CALENDAR_ICAL:-https://calendar.google.com/calendar/ical/anthonymau%40gmail.com/private-3636d9c51e7beda202676124684619ad/basic.ics}" +BIRTHDAY_DATA="$SCRIPT_DIR/../birthday-tracker/birthdays.json" +TELEGRAM_CHAT="${TELEGRAM_CHAT:-1793951355}" +GOTIFY_URL="${GOTIFY_URL:-http://runtipi.kangaroo-eel.ts.net:8129}" +GOTIFY_TOKEN="${GOTIFY_TOKEN:-AGKnHafW3FGzBlt}" +TEMP_ICS="/tmp/gcal-birthdays.ics" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# Fetch iCal feed +fetch_ical() { + log "Fetching Google Calendar iCal feed..." + curl -s "$ICAL_URL" -o "$TEMP_ICS" || { + log "ERROR: Failed to fetch iCal feed" + return 1 + } + log "Fetched $(wc -l < "$TEMP_ICS") lines" +} + +# Parse birthdays from iCal using Python +parse_birthdays() { + python3 << 'EOF' - "$TEMP_ICS" "$BIRTHDAY_DATA" +import sys +import json +import re +from datetime import datetime +from icalendar import Calendar + +ics_path = sys.argv[1] +data_path = sys.argv[2] + +# Load existing birthdays data +with open(data_path, 'r') as f: + data = json.load(f) + +existing_names = {p['name'].lower() for p in data['people']} +new_birthdays = [] + +# Parse iCal +with open(ics_path, 'rb') as f: + cal = Calendar.from_ical(f.read()) + +for event in cal.walk('VEVENT'): + summary = str(event.get('summary', '')) + + # Check if this looks like a birthday event + if not re.search(r'\bbirthday\b', summary, re.IGNORECASE): + continue + + # Extract name (remove "birthday" and common suffixes) + name = re.sub(r'\s*(?:\'s|\s)?\s*birthday.*$', '', summary, flags=re.IGNORECASE).strip() + name = re.sub(r'^(?:buy|get)\s+', '', name, flags=re.IGNORECASE).strip() + name = name.replace("'s", "").strip() + + # Skip if already tracked or empty + if not name or name.lower() in existing_names: + continue + + # Get date + dtstart = event.get('dtstart') + if dtstart: + dt = dtstart.dt + if hasattr(dt, 'month') and hasattr(dt, 'day'): + # Handle both date and datetime + month = dt.month + day = dt.day + birth_year = dt.year if hasattr(dt, 'year') and dt.year > 1900 else None + else: + continue + else: + continue + + # Format birthday as MM-DD + birthday = f"{month:02d}-{day:02d}" + + new_person = { + "name": name, + "relationship": "Contact (from Google Calendar)", + "birthday": birthday, + "source": "google-calendar", + "gift_ideas": [], + "past_gifts": [], + "notes": f"Found in Google Calendar: {summary}" + } + + if birth_year: + new_person["birth_year"] = birth_year + + new_birthdays.append(new_person) + print(f"Found: {name} - {birthday}", file=sys.stderr) + +# Output as JSON +print(json.dumps(new_birthdays, indent=2)) +EOF +} + +# Merge new birthdays into existing data +merge_birthdays() { + local new_birthdays="$1" + local count=$(echo "$new_birthdays" | jq 'length') + + if ((count == 0)); then + log "No new birthdays found" + return 0 + fi + + log "Merging $count new birthdays..." + + # Add to existing data + local temp_file=$(mktemp) + jq --argjson new "$new_birthdays" '.people += $new' "$BIRTHDAY_DATA" > "$temp_file" + mv "$temp_file" "$BIRTHDAY_DATA" + + log "Updated birthday database with $count new entries" + + # Send notification + local names=$(echo "$new_birthdays" | jq -r '.[].name' | tr '\n' ', ' | sed 's/, $//') + local message="📅 *Google Calendar Sync*\n\nFound and added *$count* new birthdays:\n$names\n\nThese will now be included in your birthday reminders!" + + # Telegram + curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ + -H "Content-Type: application/json" \ + -d "{\"chat_id\": \"$TELEGRAM_CHAT\", \"text\": \"$message\", \"parse_mode\": \"Markdown\"}" > /dev/null || true + + # Gotify + curl -s -X POST "${GOTIFY_URL}/message?token=${GOTIFY_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"title\": \"Birthday Sync\", \"message\": \"Added $count new birthdays from Google Calendar: $names\", \"priority\": 5}" > /dev/null || true +} + +# Show current stats +show_stats() { + local total=$(jq '.people | length' "$BIRTHDAY_DATA") + local gcal=$(jq '[.people[] | select(.source == "google-calendar")] | length' "$BIRTHDAY_DATA") + local manual=$((total - gcal)) + + log "Birthday database stats:" + log " Total: $total people" + log " Manual entries: $manual" + log " From Google Calendar: $gcal" +} + +# Cleanup +cleanup() { + rm -f "$TEMP_ICS" +} + +# Main +main() { + trap cleanup EXIT + + log "Starting Google Calendar birthday sync..." + + fetch_ical + + local new_birthdays + new_birthdays=$(parse_birthdays) + + merge_birthdays "$new_birthdays" + show_stats + + log "Sync complete!" +} + +main "$@"