Merge pull request 'Patreon: a missing media file_name is a fallback, not API drift' (#79) from dev into main
Build images / sign-extension (push) Successful in 2s
CI / lint (push) Successful in 2s
Build images / build-ml (push) Successful in 7s
Build images / build-web (push) Successful in 7s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 27s
CI / integration (push) Successful in 3m2s

This commit was merged in pull request #79.
This commit is contained in:
2026-06-06 23:14:25 -04:00
2 changed files with 15 additions and 18 deletions
+7 -13
View File
@@ -405,21 +405,19 @@ class PatreonClient:
return candidate
return None
def _media_item(
self, attrs: dict, kind: str, post_id: str, *, require_file_name: bool
) -> MediaItem:
def _media_item(self, attrs: dict, kind: str, post_id: str) -> MediaItem:
url = self._media_url(attrs)
if not url:
raise PatreonDriftError(
f"Patreon media (post {post_id}, kind={kind}) had no resolvable URL "
f"(no download_url / image_urls)"
)
# file_name is OPTIONAL: Patreon legitimately serves some gallery images
# without it (operator-flagged 2026-06-07, BlenderKnight post 73665615),
# and the URL basename is a fine fallback — the same thing gallery-dl
# uses. A genuine schema change shows up as no URL (above) or a media id
# absent from `included` (caller), not a missing name.
file_name = attrs.get("file_name")
if require_file_name and not (isinstance(file_name, str) and file_name):
raise PatreonDriftError(
f"Patreon media resource (post {post_id}, kind={kind}) missing "
f"'file_name'"
)
filename = file_name if isinstance(file_name, str) and file_name else _basename_from_url(url)
return MediaItem(
url=url,
@@ -452,11 +450,7 @@ class PatreonClient:
f"Patreon post {post_id} references media {mid} "
f"({rel_name}) not present in 'included'"
)
items.append(
self._media_item(
media_attrs, kind, post_id, require_file_name=True
)
)
items.append(self._media_item(media_attrs, kind, post_id))
# 1. gallery images
_resolve_rel("images", "images")
+8 -5
View File
@@ -159,9 +159,10 @@ def test_non_list_data_raises_drift(client):
client._validate_response({"data": {"id": "1"}})
def test_media_missing_file_name_raises_drift(client):
# A media resource referenced by a gallery relationship but lacking
# file_name is drift from the contract.
def test_media_missing_file_name_falls_back_to_url_basename(client):
# A gallery image with a valid URL but no file_name is NOT drift — Patreon
# serves these (operator-flagged 2026-06-07, BlenderKnight post 73665615);
# fall back to the URL basename like gallery-dl does.
post = {
"id": "2000",
"type": "post",
@@ -175,8 +176,10 @@ def test_media_missing_file_name_raises_drift(client):
+ "/x.jpg"
}
}
with pytest.raises(PatreonDriftError):
client.extract_media(post, index)
items = client.extract_media(post, index)
assert len(items) == 1
assert items[0].filename == "x.jpg"
assert items[0].kind == "images"
def test_media_referenced_but_absent_raises_drift(client):