Merge fix/live-reenrich: re-enrich transient live videos until they settle
This commit is contained in:
commit
e81a494436
2 changed files with 52 additions and 1 deletions
|
|
@ -21,6 +21,7 @@ from app.sync.videos import (
|
|||
enrich_pending,
|
||||
poll_rss_channel,
|
||||
reconcile_full_history,
|
||||
refresh_live,
|
||||
run_shorts_classification,
|
||||
)
|
||||
from app.youtube.client import YouTubeClient
|
||||
|
|
@ -65,6 +66,10 @@ def run_enrich(db: Session, max_batches: int = 200, floor: int = 200) -> int:
|
|||
total += n
|
||||
if n == 0:
|
||||
break
|
||||
# Revisit transient live/upcoming videos (enrich_pending is one-shot) so an ended
|
||||
# stream gains its final duration + was_live status instead of staying "live" forever.
|
||||
if quota.remaining_today(db) > floor:
|
||||
total += refresh_live(db, yt)
|
||||
return total
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import re
|
|||
from concurrent.futures import ThreadPoolExecutor
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import func, or_, select, update
|
||||
from sqlalchemy import and_, func, or_, select, update
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
|
@ -260,6 +260,52 @@ def enrich_pending(db: Session, yt: YouTubeClient, limit: int | None = None) ->
|
|||
return enriched
|
||||
|
||||
|
||||
def refresh_live(db: Session, yt: YouTubeClient, limit: int | None = None) -> int:
|
||||
"""Re-fetch videos in a transient live state so they pick up their final shape.
|
||||
|
||||
`enrich_pending` is one-shot (it only touches enriched_at IS NULL), but a live broadcast
|
||||
is not a final state: a stream ends and becomes a normal VOD — gaining a real duration
|
||||
and flipping live_status to was_live — and an upcoming premiere eventually goes live then
|
||||
ends. So we revisit anything still live/upcoming, plus a just-ended stream that hasn't got
|
||||
its duration yet (YouTube can lag a bit after the broadcast), until it settles. Cheap:
|
||||
videos.list is 1 unit per 50 ids, and the live/upcoming set is normally tiny."""
|
||||
limit = limit or settings.enrich_batch_size
|
||||
videos = (
|
||||
db.execute(
|
||||
select(Video)
|
||||
.where(
|
||||
or_(
|
||||
Video.live_status.in_(("live", "upcoming")),
|
||||
and_(
|
||||
Video.live_status == "was_live",
|
||||
Video.duration_seconds.is_(None),
|
||||
),
|
||||
)
|
||||
)
|
||||
.limit(limit)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
if not videos:
|
||||
return 0
|
||||
items = {it["id"]: it for it in yt.get_videos([v.id for v in videos])}
|
||||
now = _now()
|
||||
updated = 0
|
||||
for video in videos:
|
||||
item = items.get(video.id)
|
||||
if item is None:
|
||||
# The broadcast vanished (deleted/private). Stop treating it as live so it
|
||||
# doesn't get refreshed forever; it just becomes an ordinary (dead) row.
|
||||
video.live_status = "none"
|
||||
continue
|
||||
apply_video_details(video, item)
|
||||
video.enriched_at = now
|
||||
updated += 1
|
||||
db.commit()
|
||||
return updated
|
||||
|
||||
|
||||
def run_shorts_classification(db: Session, limit: int | None = None) -> dict:
|
||||
"""Finalize Shorts classification: cheaply mark non-candidates, then probe the
|
||||
youtube.com/shorts URL for short-enough, non-live, enriched videos."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue