feat(feed): filter by year — per-year count facet + year control (E8·S2)
Add a Year filter to the feed rail: quick chips for recent years plus a 'More…' popover listing all years with per-year video counts, sortable by year or count. Selecting a year narrows the feed to that whole calendar year (a published_after/before range applied in the api layer) and is mutually exclusive with the Upload-date control. Backend: new /api/feed/years endpoint + feed_years() — one grouped query that honours every filter EXCEPT the publish-date narrowing (dropped), so the year list stays a live drill-down and switching years never zeroes the others. FE keys the list on the date-stripped filters, so picking a year re-queries the feed but not the list. Wires year through FeedFilters, the filterParams/URL (?year) round-trip, the active-filter chip row, and the panel layout. i18n HU+EN. Tests: feed_years count query (date narrowing ignored, other filters honoured); dateFilter year-clearing; urlState year round-trip.
This commit is contained in:
@@ -437,6 +437,26 @@ def feed_summary(db: Session, user: User, **params) -> dict:
|
||||
return {"count": count, "facets": facets}
|
||||
|
||||
|
||||
def feed_years(db: Session, user: User, **params) -> list[dict]:
|
||||
"""Per-year video counts for the current filter context (item 8 / E8·S2): powers the year control's
|
||||
quick chips + the "more…" per-year-counts dialog. Every OTHER filter (tags, channels, content type,
|
||||
search, watch state, scope) still applies, but the publish-date narrowing itself is DROPPED —
|
||||
published_after/before and max_age_days — so the year list is the full set of years available and
|
||||
switching years stays a live drill-down (the same principle as the tag facets dropping their own
|
||||
category). One grouped query, newest year first."""
|
||||
base, _rank = filtered_query(
|
||||
db,
|
||||
user,
|
||||
**{**params, "published_after": None, "published_before": None, "max_age_days": None},
|
||||
)
|
||||
pub = base.with_only_columns(Video.published_at.label("pub")).subquery()
|
||||
year = func.extract("year", pub.c.pub)
|
||||
rows = db.execute(
|
||||
select(year.label("y"), func.count()).group_by(year).order_by(year.desc())
|
||||
).all()
|
||||
return [{"year": int(y), "count": n} for y, n in rows if y is not None]
|
||||
|
||||
|
||||
# --- Keyset (cursor) pagination ---------------------------------------------
|
||||
#
|
||||
# Each sort is described as an ordered list of key columns (expression + direction
|
||||
|
||||
Reference in New Issue
Block a user