added sorting and artist dates

This commit is contained in:
Ebbe Baß
2026-09-09 14:10:15 +02:00
parent b2468cc083
commit 5d56df1af8
11 changed files with 96 additions and 11 deletions
+24 -8
View File
@@ -9,17 +9,23 @@ Run with:
import datetime
import os
from typing import List, Optional
from collections import defaultdict
from typing import List, Literal, Optional
from fastapi import FastAPI, HTTPException, Query
from fastapi.responses import PlainTextResponse
from calendar_feed import build_ics
from datasource import EventStore, iter_artist_names, parse_event_date
from models import Event, EventList
from datasource import EventStore, iter_artist_names, parse_event_date, sort_date_strings, sort_events
from models import ArtistSchedule, Event, EventList
from rate_limit import Cooldown
from scrape_schedule import discover_cron_expr, get_schedule_info
SortOrder = Literal["asc", "desc", "az", "za"]
_SORT_DESCRIPTION = (
"Sort order: asc/desc by event date, az/za alphabetically by event name"
)
app = FastAPI(
title="Fundi Scraper API",
description="REST API over the scraped upcoming/past events at the Fundbureau Hamburg.",
@@ -118,6 +124,7 @@ def list_events(
artist: Optional[str] = Query(None, description="Case-insensitive substring match on any artist name"),
date: Optional[str] = Query(None, description="Exact match on the raw event date (dd.mm.yy)"),
upcoming: Optional[bool] = Query(None, description="true = today or later, false = past events"),
sort: Optional[SortOrder] = Query(None, description=_SORT_DESCRIPTION),
):
today = datetime.date.today()
events = [
@@ -125,16 +132,23 @@ def list_events(
for e in store.all()
if _matches(e, free, name, artist, date, upcoming, today)
]
events = sort_events(events, sort)
return EventList(count=len(events), events=events)
@app.get("/artists", response_model=List[str])
@app.get("/artists", response_model=List[ArtistSchedule])
def list_artists():
"""Deduplicated, sorted list of all artist names across all events."""
names = set()
"""Deduplicated, sorted list of all artists, each with every date
(past or upcoming) they appear in the line-up.
"""
appearances: dict = defaultdict(set)
for event in store.all():
names.update(iter_artist_names(event))
return sorted(names, key=str.lower)
for artist_name in iter_artist_names(event):
appearances[artist_name].add(event.event_date)
return [
ArtistSchedule(artist_name=artist_name, dates=sort_date_strings(dates))
for artist_name, dates in sorted(appearances.items(), key=lambda kv: kv[0].lower())
]
@app.get("/events/archive", response_model=EventList)
@@ -143,6 +157,7 @@ def list_archive_events(
name: Optional[str] = Query(None, description="Case-insensitive substring match on event name"),
artist: Optional[str] = Query(None, description="Case-insensitive substring match on any artist name"),
date: Optional[str] = Query(None, description="Exact match on the raw event date (dd.mm.yy)"),
sort: Optional[SortOrder] = Query(None, description=_SORT_DESCRIPTION),
):
"""Past events only - shorthand for ``/events?upcoming=false``."""
today = datetime.date.today()
@@ -151,6 +166,7 @@ def list_archive_events(
for e in store.all()
if _matches(e, free, name, artist, date, upcoming=False, today=today)
]
events = sort_events(events, sort)
return EventList(count=len(events), events=events)