Add multi-provider event discovery and improve sync UI
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
from app.config import settings
|
||||
from app.models import RegionScope, WatchType
|
||||
|
||||
|
||||
class EventimProvider:
|
||||
base_url = "https://public-api.eventim.com/websearch/search/api/exploration/v1/products"
|
||||
source_name = "eventim"
|
||||
|
||||
def is_configured(self) -> bool:
|
||||
return settings.eventim_enabled
|
||||
|
||||
def search_events(
|
||||
self,
|
||||
term: str,
|
||||
watch_type: WatchType,
|
||||
region_scope: RegionScope,
|
||||
) -> list[dict]:
|
||||
if not self.is_configured():
|
||||
return []
|
||||
|
||||
params = {
|
||||
"webId": "web__eventim-de",
|
||||
"language": "de",
|
||||
"page": 1,
|
||||
"sort": "DateAsc",
|
||||
"top": 50,
|
||||
"search_term": term,
|
||||
}
|
||||
|
||||
if region_scope == RegionScope.hamburg:
|
||||
params["city_names"] = "Hamburg"
|
||||
|
||||
response = requests.get(
|
||||
self.base_url,
|
||||
params=params,
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
||||
),
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
response.raise_for_status()
|
||||
payload = response.json()
|
||||
products = payload.get("products") or []
|
||||
|
||||
results: list[dict] = []
|
||||
normalized_term = term.casefold()
|
||||
|
||||
for product in products:
|
||||
title = product.get("name") or ""
|
||||
attractions = product.get("attractions") or []
|
||||
attraction_names = [entry.get("name", "") for entry in attractions]
|
||||
|
||||
if watch_type == WatchType.artist:
|
||||
haystack = " ".join(attraction_names + [title]).casefold()
|
||||
if normalized_term not in haystack:
|
||||
continue
|
||||
elif normalized_term not in title.casefold():
|
||||
continue
|
||||
|
||||
live_data = product.get("typeAttributes", {}).get("liveEntertainment", {})
|
||||
location = live_data.get("location") or {}
|
||||
city = location.get("city")
|
||||
|
||||
if region_scope == RegionScope.hamburg and (city or "").casefold() != "hamburg":
|
||||
continue
|
||||
|
||||
event_date = None
|
||||
start_date = live_data.get("startDate")
|
||||
if start_date:
|
||||
try:
|
||||
event_date = datetime.fromisoformat(
|
||||
start_date.replace("Z", "+00:00")
|
||||
).replace(tzinfo=None)
|
||||
except ValueError:
|
||||
event_date = None
|
||||
|
||||
url = self._build_url(product)
|
||||
country_code = "DE" if region_scope == RegionScope.germany or city else None
|
||||
|
||||
results.append(
|
||||
{
|
||||
"external_id": str(product.get("productId") or url or title),
|
||||
"title": title,
|
||||
"matched_term": term,
|
||||
"venue_name": location.get("name"),
|
||||
"city": city,
|
||||
"country_code": country_code,
|
||||
"event_date": event_date,
|
||||
"ticket_url": url,
|
||||
"image_url": None,
|
||||
"raw_payload": product,
|
||||
}
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
def _build_url(self, product: dict) -> str | None:
|
||||
direct_link = product.get("link")
|
||||
if direct_link:
|
||||
return direct_link
|
||||
|
||||
url = product.get("url") or {}
|
||||
domain = url.get("domain")
|
||||
path = url.get("path")
|
||||
if domain and path:
|
||||
return f"{domain}{path}"
|
||||
return None
|
||||
Reference in New Issue
Block a user