feat: feedback round 3 — content-type toggles, channel filter, card polish
- Content type is now three independent toggles (Normal / Shorts / Live·Upcoming); the feed is the union of enabled types (backend show_normal + include_shorts + include_live) - Per-channel filter: a button on each card scopes the feed to that channel, shown as a removable chip in the sidebar - Hide now refetches the feed once the change is persisted, so a hidden video shows up in the Hidden view immediately (no refresh needed); optimistic updates respect the current view - Grid cards are now distinct panels (card background, border, shadow) that lift on hover; clickable channel name in list view too
This commit is contained in:
parent
e07a37622d
commit
ecbecbb9f4
6 changed files with 115 additions and 30 deletions
|
|
@ -1,7 +1,7 @@
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy import and_, func, or_, select
|
||||
from sqlalchemy import and_, false, func, or_, select
|
||||
from sqlalchemy.orm import Session, aliased
|
||||
|
||||
from app.auth import current_user
|
||||
|
|
@ -50,6 +50,7 @@ def get_feed(
|
|||
min_duration: int | None = None,
|
||||
max_duration: int | None = None,
|
||||
max_age_days: int | None = None,
|
||||
show_normal: bool = True,
|
||||
include_shorts: bool = False,
|
||||
include_live: bool = False,
|
||||
show: str = "unwatched", # all | unwatched | watched | saved | hidden
|
||||
|
|
@ -92,13 +93,21 @@ def get_feed(
|
|||
)
|
||||
)
|
||||
|
||||
# In the explicit Watched/Saved/Hidden views, show the complete set regardless of
|
||||
# the Shorts / live default-hiding (so e.g. a hidden Short still shows up there).
|
||||
# Content-type filter: Normal (regular videos incl. past-stream VODs), Shorts and
|
||||
# Live/Upcoming are independent toggles; the feed is the union of the enabled types.
|
||||
# The explicit Watched/Saved/Hidden views show every type so nothing goes missing.
|
||||
explicit_view = show in ("watched", "saved", "hidden")
|
||||
if not include_shorts and not explicit_view:
|
||||
query = query.where(Video.is_short.is_(False))
|
||||
if not include_live and not explicit_view:
|
||||
query = query.where(Video.live_status.notin_(HIDDEN_LIVE))
|
||||
if not explicit_view:
|
||||
type_clauses = []
|
||||
if show_normal:
|
||||
type_clauses.append(
|
||||
and_(Video.is_short.is_(False), Video.live_status.notin_(HIDDEN_LIVE))
|
||||
)
|
||||
if include_shorts:
|
||||
type_clauses.append(Video.is_short.is_(True))
|
||||
if include_live:
|
||||
type_clauses.append(Video.live_status.in_(HIDDEN_LIVE))
|
||||
query = query.where(or_(*type_clauses) if type_clauses else false())
|
||||
if channel_id:
|
||||
query = query.where(Video.channel_id == channel_id)
|
||||
if min_duration is not None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue