fix(sync): R5 S2 — sync guards
- never prune subscriptions on an empty fetch: one anomalous empty-but-200 response wiped every subscription (and its deep_requested flag) in one run - push_playlist: stop after 5 consecutive write failures — a quota-dead or scope-revoked account otherwise burns 50 units per remaining item - RSS: raise RssError instead of returning [] on a transport/HTTP failure, so a failed poll no longer stamps last_rss_at and a 404 feed stops looking healthy - worker: exit when the schema never appears instead of "continuing" into a crash one call later
This commit is contained in:
@@ -8,14 +8,24 @@ import httpx
|
||||
RSS_URL = "https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}"
|
||||
|
||||
|
||||
class RssError(Exception):
|
||||
"""The feed could not be read (transport failure or a non-200 answer).
|
||||
|
||||
Deliberately NOT the same as an empty feed: a failed poll used to return `[]`, which the
|
||||
caller stamped as a successful `last_rss_at` — so a channel whose feed 404s permanently
|
||||
(deleted, renamed id) looked like it was being polled fine forever, and nothing surfaced it."""
|
||||
|
||||
|
||||
def fetch_channel_feed(channel_id: str) -> list[dict]:
|
||||
"""The channel's recent uploads as stubs. `[]` means the feed really is empty; a failure
|
||||
raises RssError so the caller can leave the channel un-stamped and log it."""
|
||||
url = RSS_URL.format(channel_id=channel_id)
|
||||
try:
|
||||
resp = httpx.get(url, timeout=20.0, headers={"User-Agent": "Siftlode/1.0"})
|
||||
except httpx.HTTPError:
|
||||
return []
|
||||
except httpx.HTTPError as exc:
|
||||
raise RssError(f"RSS fetch failed for {channel_id}: {exc}") from exc
|
||||
if resp.status_code != 200:
|
||||
return []
|
||||
raise RssError(f"RSS fetch for {channel_id} returned HTTP {resp.status_code}")
|
||||
|
||||
parsed = feedparser.parse(resp.content)
|
||||
out: list[dict] = []
|
||||
|
||||
Reference in New Issue
Block a user