mydocker/scripts/gcal_delete_by_pattern.py

88 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""
Delete Google Calendar events matching a regex pattern in summary or description.
Usage:
python gcal_delete_by_pattern.py --pattern "foo-bar.*" --credentials /path/to/sa.json [--year 2026] [--dry-run]
python gcal_delete_by_pattern.py --pattern "\\(custody-gen\\)" --credentials sa.json --field description
"""
import argparse
import re
import sys
from datetime import date
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
CALENDAR_ID = "ked0ao233h92ogj8l80b7e9a4g@group.calendar.google.com"
SCOPES = ["https://www.googleapis.com/auth/calendar"]
def main():
parser = argparse.ArgumentParser(
description="Delete Google Calendar events matching a regex pattern"
)
parser.add_argument("--pattern", required=True, help="Regex pattern to match")
parser.add_argument("--credentials", required=True, help="Path to GCP service account JSON")
parser.add_argument("--year", type=int, default=date.today().year, help="Year to scan (default: current)")
parser.add_argument("--field", choices=["summary", "description", "both"], default="both",
help="Which field to match against (default: both)")
parser.add_argument("--dry-run", action="store_true", help="List matches without deleting")
args = parser.parse_args()
try:
regex = re.compile(args.pattern)
except re.error as e:
print(f"Invalid regex: {e}")
sys.exit(1)
creds = Credentials.from_service_account_file(args.credentials, scopes=SCOPES)
service = build("calendar", "v3", credentials=creds)
time_min = f"{args.year}-01-01T00:00:00Z"
time_max = f"{args.year + 1}-01-31T23:59:59Z"
matched = 0
page_token = None
while True:
result = service.events().list(
calendarId=CALENDAR_ID,
timeMin=time_min,
timeMax=time_max,
maxResults=250,
pageToken=page_token,
).execute()
for event in result.get("items", []):
summary = event.get("summary", "") or ""
description = event.get("description", "") or ""
hit = False
if args.field in ("summary", "both") and regex.search(summary):
hit = True
if args.field in ("description", "both") and regex.search(description):
hit = True
if hit:
matched += 1
start = event.get("start", {}).get("dateTime", event.get("start", {}).get("date", "?"))
label = f"{start} | {summary[:50]} | {description[:50]}"
if args.dry_run:
print(f" [MATCH] {label}")
else:
service.events().delete(calendarId=CALENDAR_ID, eventId=event["id"]).execute()
print(f" [DELETED] {label}")
page_token = result.get("nextPageToken")
if not page_token:
break
action = "matched" if args.dry_run else "deleted"
print(f"\nDone. {matched} events {action} for pattern '{args.pattern}' in {args.year}.")
if __name__ == "__main__":
main()