Files
eventlens/backend/app/providers/fabrik.py
T
2026-04-17 16:39:13 +02:00

89 lines
2.8 KiB
Python

from datetime import datetime
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
from app.models import RegionScope, WatchType
from app.providers.utils import normalize_search_text
class FabrikProvider:
source_name = "fabrik"
events_url = "https://fabrik.de/programm"
def search_events(
self,
term: str,
watch_type: WatchType,
region_scope: RegionScope,
) -> list[dict]:
response = requests.get(
self.events_url,
headers={"User-Agent": "Mozilla/5.0"},
timeout=30,
)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
normalized_term = normalize_search_text(term)
results: list[dict] = []
for event_block in soup.select(".programm_termin"):
detail_link = event_block.select_one('a[href*="/veranstaltungsdetail/"][title]')
if detail_link is None:
continue
title = detail_link.get("title") or detail_link.get_text(" ", strip=True)
if not title:
continue
block_text = event_block.get_text(" ", strip=True)
haystack = normalize_search_text(f"{title} {block_text}")
if normalized_term not in haystack:
continue
date_el = event_block.select_one(".programm_termin_lh_datum a")
date_text = date_el.get_text(" ", strip=True) if date_el else ""
event_date = self._parse_fabrik_date(date_text)
href = detail_link["href"]
results.append(
{
"external_id": href,
"title": title,
"matched_term": term,
"venue_name": "Fabrik",
"city": "Hamburg",
"country_code": "DE",
"event_date": event_date,
"ticket_url": urljoin(self.events_url, href),
"image_url": None,
"raw_payload": {
"title": title,
"date_text": date_text,
"href": href,
},
}
)
unique_results: dict[str, dict] = {}
for result in results:
unique_results[result["external_id"]] = result
self.last_status = "ok"
self.last_message = (
f"Fabrik returned {len(unique_results)} matched events for term '{term}'."
)
return list(unique_results.values())
def _parse_fabrik_date(self, value: str) -> datetime | None:
cleaned = value.replace(" ", "")
if len(cleaned) < 10:
return None
date_value = cleaned[-10:]
try:
return datetime.strptime(date_value, "%d.%m.%Y")
except ValueError:
return None