from datetime import datetime import requests from app.config import settings from app.models import RegionScope, WatchType from app.providers.utils import normalize_search_text class TicketmasterProvider: base_url = "https://app.ticketmaster.com/discovery/v2/events.json" source_name = "ticketmaster" def is_configured(self) -> bool: return bool(settings.ticketmaster_api_key) def search_events( self, term: str, watch_type: WatchType, region_scope: RegionScope, ) -> list[dict]: if not self.is_configured(): return [] params = { "apikey": settings.ticketmaster_api_key, "keyword": term, "locale": "*", "size": 50, "sort": "date,asc", "countryCode": "DE", } if region_scope == RegionScope.hamburg: params["city"] = "Hamburg" response = requests.get(self.base_url, params=params, timeout=30) response.raise_for_status() payload = response.json() items = payload.get("_embedded", {}).get("events", []) setattr(self, "last_status", "ok") setattr( self, "last_message", f"Ticketmaster returned {len(items)} raw events for term '{term}'.", ) results: list[dict] = [] normalized_term = normalize_search_text(term) for item in items: title = item.get("name", "") attractions = item.get("_embedded", {}).get("attractions", []) attraction_names = [entry.get("name", "") for entry in attractions] if watch_type == WatchType.artist: haystack = normalize_search_text(" ".join(attraction_names + [title])) if normalized_term not in haystack: continue elif normalized_term not in normalize_search_text(title): continue dates = item.get("dates", {}).get("start", {}) local_date = dates.get("localDate") local_time = dates.get("localTime", "20:00:00") event_date = None if local_date: try: event_date = datetime.fromisoformat(f"{local_date}T{local_time}") except ValueError: event_date = datetime.fromisoformat(f"{local_date}T20:00:00") venue = ( item.get("_embedded", {}) .get("venues", [{}])[0] ) results.append( { "external_id": item.get("id"), "title": title, "matched_term": term, "venue_name": venue.get("name"), "city": venue.get("city", {}).get("name"), "country_code": venue.get("country", {}).get("countryCode"), "event_date": event_date, "ticket_url": item.get("url"), "image_url": next( (image.get("url") for image in item.get("images", []) if image.get("url")), None, ), "raw_payload": item, } ) return results