feat(channels): aggregate columns + smarter tag display
- Add Last upload, total Length and a Normal/Shorts/Live breakdown, computed on read in the existing grouped query (~35ms over the full catalog — measured, so no denormalization). - Subscribers shown compact (919K), since the YouTube API already rounds them. - Tag cell now shows only the tags actually attached to a channel; a '+' opens a per-channel picker to attach/detach, instead of listing every user tag on every row.
This commit is contained in:
parent
c000ea8bce
commit
cd28287968
6 changed files with 153 additions and 30 deletions
|
|
@ -27,16 +27,33 @@ def list_channels(
|
|||
.order_by(Subscription.priority.desc(), func.lower(Channel.title))
|
||||
).all()
|
||||
|
||||
# Per-channel stored video count (shared data) in one grouped query.
|
||||
# Per-channel aggregates over the shared catalog in ONE grouped pass: stored count, last
|
||||
# upload, total duration, and a Normal/Shorts/Live breakdown. Cheap — a single grouped scan
|
||||
# (~35 ms over the full 233k-row catalog on the dev DB), so computed on read rather than
|
||||
# denormalised (measure-first: reads aren't frequent/hot enough to warrant cached columns).
|
||||
channel_ids = [c.id for _, c in rows]
|
||||
stored: dict[str, int] = {}
|
||||
agg: dict[str, dict] = {}
|
||||
if channel_ids:
|
||||
for cid, count in db.execute(
|
||||
select(Video.channel_id, func.count(Video.id))
|
||||
for cid, n, last_up, total_dur, shorts, live in db.execute(
|
||||
select(
|
||||
Video.channel_id,
|
||||
func.count(Video.id),
|
||||
func.max(Video.published_at),
|
||||
func.coalesce(func.sum(Video.duration_seconds), 0),
|
||||
func.count(Video.id).filter(Video.is_short.is_(True)),
|
||||
func.count(Video.id).filter(Video.live_status.in_(("live", "upcoming"))),
|
||||
)
|
||||
.where(Video.channel_id.in_(channel_ids))
|
||||
.group_by(Video.channel_id)
|
||||
).all():
|
||||
stored[cid] = count
|
||||
agg[cid] = {
|
||||
"stored": n,
|
||||
"last_video_at": last_up.isoformat() if last_up else None,
|
||||
"total_duration_seconds": int(total_dur or 0),
|
||||
"count_short": int(shorts),
|
||||
"count_live": int(live),
|
||||
"count_normal": max(0, int(n) - int(shorts) - int(live)),
|
||||
}
|
||||
|
||||
# Channels already in the *global* deep-backfill queue — i.e. at least one user (any
|
||||
# user) has requested full history and it isn't done yet. Their whole back-catalogue is
|
||||
|
|
@ -71,7 +88,12 @@ def list_channels(
|
|||
"thumbnail_url": ch.thumbnail_url,
|
||||
"subscriber_count": ch.subscriber_count,
|
||||
"video_count": ch.video_count,
|
||||
"stored_videos": stored.get(ch.id, 0),
|
||||
"stored_videos": (agg.get(ch.id) or {}).get("stored", 0),
|
||||
"last_video_at": (agg.get(ch.id) or {}).get("last_video_at"),
|
||||
"total_duration_seconds": (agg.get(ch.id) or {}).get("total_duration_seconds", 0),
|
||||
"count_normal": (agg.get(ch.id) or {}).get("count_normal", 0),
|
||||
"count_short": (agg.get(ch.id) or {}).get("count_short", 0),
|
||||
"count_live": (agg.get(ch.id) or {}).get("count_live", 0),
|
||||
"priority": sub.priority,
|
||||
"hidden": sub.hidden,
|
||||
"deep_requested": sub.deep_requested,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue