fix(sync): only a refusal about the channel spends its fallback window

A failed connection or token step answered nothing about the channel, yet stamped it: one proxy blip
during an RSS blackout delayed every due channel by a whole window. YouTubeError now names the
endpoint that answered; a failure no endpoint gave, or a spent quota, ends the round and stamps
nothing.
This commit is contained in:
2026-09-19 05:54:19 +02:00
parent 038da5374f
commit a7891d03c5
3 changed files with 27 additions and 12 deletions
+9 -3
View File
@@ -26,11 +26,15 @@ class YouTubeError(Exception):
`reason` is the API's own error reason code (`quotaExceeded`, `subscriptionDuplicate`,
`videoNotFound`, …) when the body carried one. Branch on THAT, never on the message: the
message is prose, it changes under us, and it is deliberately the poorer of the two here."""
message is prose, it changes under us, and it is deliberately the poorer of the two here.
def __init__(self, message: str, *, reason: str = ""):
`path` is the API endpoint that ANSWERED with the failure (`playlistItems`); empty when no
endpoint did — the request never got through (`transport`) or the token step refused first."""
def __init__(self, message: str, *, reason: str = "", path: str = ""):
super().__init__(message)
self.reason = reason
self.path = path
def _error_reason(resp: httpx.Response) -> str:
@@ -87,7 +91,9 @@ def _upstream_failure(
# log-pii-ok: only under this user's own Teljes consent, which is what it is for
extra=logs.event("youtube.api.body", body=resp.text[:500]),
)
return YouTubeError(f"{method} {path} -> {resp.status_code}: {reason}", reason=reason)
return YouTubeError(
f"{method} {path} -> {resp.status_code}: {reason}", reason=reason, path=path
)
# The `mine` reads' answer for a Google account that has no YouTube channel.