Merge: auto-complete full history when stored >= video_count
This commit is contained in:
commit
fdb38a5863
2 changed files with 40 additions and 3 deletions
|
|
@ -20,6 +20,7 @@ from app.sync.videos import (
|
||||||
backfill_channel_recent,
|
backfill_channel_recent,
|
||||||
enrich_pending,
|
enrich_pending,
|
||||||
poll_rss_channel,
|
poll_rss_channel,
|
||||||
|
reconcile_full_history,
|
||||||
run_shorts_classification,
|
run_shorts_classification,
|
||||||
)
|
)
|
||||||
from app.youtube.client import YouTubeClient
|
from app.youtube.client import YouTubeClient
|
||||||
|
|
@ -118,7 +119,12 @@ def run_recent_backfill(
|
||||||
except Exception:
|
except Exception:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
log.exception("Recent backfill failed for channel %s", channel.id)
|
log.exception("Recent backfill failed for channel %s", channel.id)
|
||||||
return {"channels_processed": processed, "videos_added": videos_added}
|
reconciled = reconcile_full_history(db)
|
||||||
|
return {
|
||||||
|
"channels_processed": processed,
|
||||||
|
"videos_added": videos_added,
|
||||||
|
"reconciled_full": reconciled,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def run_deep_backfill(db: Session, max_channels: int = 10, max_pages: int = 5) -> dict:
|
def run_deep_backfill(db: Session, max_channels: int = 10, max_pages: int = 5) -> dict:
|
||||||
|
|
@ -158,7 +164,12 @@ def run_deep_backfill(db: Session, max_channels: int = 10, max_pages: int = 5) -
|
||||||
except Exception:
|
except Exception:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
log.exception("Deep backfill failed for channel %s", channel.id)
|
log.exception("Deep backfill failed for channel %s", channel.id)
|
||||||
return {"channels_processed": processed, "videos_added": videos_added}
|
reconciled = reconcile_full_history(db)
|
||||||
|
return {
|
||||||
|
"channels_processed": processed,
|
||||||
|
"videos_added": videos_added,
|
||||||
|
"reconciled_full": reconciled,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def estimate_deep_backfill(db: Session, channels: list[Channel]) -> dict:
|
def estimate_deep_backfill(db: Session, channels: list[Channel]) -> dict:
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import re
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
from sqlalchemy import or_, select, update
|
from sqlalchemy import func, or_, select, update
|
||||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
|
@ -173,6 +173,32 @@ def backfill_channel_deep(
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
def reconcile_full_history(db: Session) -> int:
|
||||||
|
"""Mark channels fully backfilled once their stored uploads meet or exceed YouTube's
|
||||||
|
advertised video_count. The uploads playlist length is normally <= the advertised
|
||||||
|
count, so 'stored >= video_count' means we already hold the whole history — even if
|
||||||
|
the deep cursor never reached the end (e.g. a small channel that was never
|
||||||
|
deep-requested, so the demand-driven deep job never ran). Without this such a channel
|
||||||
|
sits in 'needs full history' forever despite having every video. Idempotent, no API
|
||||||
|
quota; returns the number of channels flipped."""
|
||||||
|
stored = (
|
||||||
|
select(func.count(Video.id))
|
||||||
|
.where(Video.channel_id == Channel.id)
|
||||||
|
.scalar_subquery()
|
||||||
|
)
|
||||||
|
result = db.execute(
|
||||||
|
update(Channel)
|
||||||
|
.where(
|
||||||
|
Channel.backfill_done.is_(False),
|
||||||
|
Channel.video_count.is_not(None),
|
||||||
|
stored >= Channel.video_count,
|
||||||
|
)
|
||||||
|
.values(backfill_done=True, backfill_cursor=None)
|
||||||
|
)
|
||||||
|
db.commit()
|
||||||
|
return result.rowcount
|
||||||
|
|
||||||
|
|
||||||
# --- Enrichment (videos.list) ---
|
# --- Enrichment (videos.list) ---
|
||||||
def _live_status(snippet: dict, live_details: dict | None) -> str:
|
def _live_status(snippet: dict, live_details: dict | None) -> str:
|
||||||
broadcast = snippet.get("liveBroadcastContent")
|
broadcast = snippet.get("liveBroadcastContent")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue