Add stats peak hours, RSS feed, channel health view, bulk video download

Stats:
- Peak watching hours chart (24-bar) from last_watched_at timestamps

RSS:
- GET /api/channels/rss — last 100 videos from followed channels as RSS 2.0
- RSS link in Following > Health tab

Channel health:
- New Health tab in Following groups channels into Active / Slow / Dormant / Dead
  based on days since last upload

Bulk video download:
- Select mode on Channel page (Videos tab) with checkboxes
- Sticky bottom bar shows count + Download button
- Queues a download for each selected video

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 23:50:55 +02:00
parent 3652038cf5
commit ff601d3585
6 changed files with 231 additions and 3 deletions

View File

@@ -119,6 +119,18 @@ def get_stats(
{"uid": uid},
).mappings().all()
peak_hours = db.execute(
text("""
SELECT CAST(strftime('%H', uv.last_watched_at) AS INTEGER) AS hour,
COUNT(*) AS count
FROM user_videos uv
WHERE uv.user_id = :uid AND uv.watched = 1 AND uv.last_watched_at IS NOT NULL
GROUP BY hour
ORDER BY hour ASC
"""),
{"uid": uid},
).mappings().all()
liked_count = db.execute(
text("SELECT COUNT(*) AS n FROM user_videos WHERE user_id = :uid AND liked = 1"),
{"uid": uid},
@@ -153,6 +165,7 @@ def get_stats(
"rewatched_videos": avg_completion["rewatched_videos"] or 0,
"total_liked": liked_count["n"] or 0,
"top_categories": [dict(r) for r in top_categories],
"peak_hours": [dict(r) for r in peak_hours],
"taste_profile": [dict(r) for r in taste_profile],
"disk": {
"total_bytes": disk.total if disk else None,