fix(shop): key YouTube dead-cache by (release_id, uri) — mirrored video table has no id col

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-06-23 23:47:42 +10:00
parent 988e6437cb
commit 4c152954b5

View File

@ -209,7 +209,7 @@ async def shop_audio(release_id: int, db=Depends(get_db)):
async def _live_youtube(db, release_id):
"""Pick a NON-dead YouTube clip — validates unchecked ones via YouTube oembed (200=live) and caches `dead`."""
rows = [dict(r) for r in (await db.execute(text(
"SELECT id, uri, dead FROM disc_release_video WHERE release_id=:r AND uri<>'' ORDER BY id LIMIT 8"
"SELECT DISTINCT uri, dead FROM disc_release_video WHERE release_id=:r AND uri<>'' ORDER BY uri LIMIT 8"
), {"r": release_id})).mappings()]
unchecked = [v for v in rows if v["dead"] is None][:4]
if unchecked:
@ -217,21 +217,21 @@ async def _live_youtube(db, release_id):
async def chk(v):
yid = _ytid(v["uri"])
if not yid:
return v["id"], True
return v["uri"], True
try:
rr = await c.get("https://www.youtube.com/oembed",
params={"url": "https://youtu.be/" + yid, "format": "json"})
return v["id"], rr.status_code != 200
return v["uri"], rr.status_code != 200
except Exception:
return v["id"], None # network blip — leave unchecked for next time
return v["uri"], None # network blip — leave unchecked for next time
checked = await asyncio.gather(*[chk(v) for v in unchecked])
wrote = False
for vid, dead in checked:
for uri, dead in checked:
if dead is not None:
await db.execute(text("UPDATE disc_release_video SET dead=:d, checked_at=now() WHERE id=:i"),
{"d": dead, "i": vid})
await db.execute(text("UPDATE disc_release_video SET dead=:d, checked_at=now() "
"WHERE release_id=:r AND uri=:u"), {"d": dead, "r": release_id, "u": uri})
for v in rows:
if v["id"] == vid:
if v["uri"] == uri:
v["dead"] = dead
wrote = True
if wrote: