Show saved-video counts (not channel counts) in the Saved page sidebar

GET /api/feed/saved-counts aggregates, per category, how many videos have
a completed download (using each video's latest job only, same rule as
the existing ?downloaded=true feed filter). CategoryNav gains an optional
categoryCounts override so Feed/Channels keep showing channel_count while
Saved shows this instead.

Query key ['feed', 'saved-counts'] deliberately nests under 'feed' so
DownloadButton's existing invalidateQueries({queryKey: ['feed']}) on
download/delete refreshes these counts too, with no extra wiring.

1 new backend test (77 total).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
vrubelroman 2026-09-16 20:41:20 +00:00
parent 44f81f0f0d
commit 90eb012e0d
5 changed files with 85 additions and 18 deletions

View file

@ -139,6 +139,26 @@ def test_feed_filters_downloaded_uses_latest_job_per_video(client, db_session):
assert resp["items"] == []
def test_saved_counts(client, db_session):
channel_a, channel_b, category, videos = _seed(db_session)
# vid0 is on channel_a (in "Linux"), vid1 is on channel_b (uncategorized).
db_session.add_all(
[
DownloadJob(video_id=videos[0].id, status="completed", media_url="http://x/0.mp4"),
DownloadJob(video_id=videos[1].id, status="completed", media_url="http://x/1.mp4"),
DownloadJob(video_id=videos[2].id, status="failed"),
]
)
db_session.commit()
resp = client.get("/api/feed/saved-counts").json()
assert resp["all"] == 2
assert resp["uncategorized"] == 1
assert resp["categories"] == {str(category.id): 1}
def test_feed_item_shape(client, db_session):
channel_a, _, category, _ = _seed(db_session)