feat(patreon): native JSON-API client — ingester build step 1 (plan #697)
PatreonClient: cookie-auth requests session, /api/posts cursor pagination, JSON:API included flattening, per-post media extraction (images/image_large/ attachments/postfile/content) with filehash dedup, loud drift detection. Zero per-file HEADs — every media URL+file_name comes from the API. Not yet wired into download_service (later step). Pure-parsing unit tests + fixture. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "1001",
|
||||
"type": "post",
|
||||
"attributes": {
|
||||
"title": "Image gallery post",
|
||||
"published_at": "2026-05-01T12:00:00.000+00:00",
|
||||
"post_type": "image_file",
|
||||
"content": "<p>just a gallery</p>",
|
||||
"url": "https://www.patreon.com/posts/1001",
|
||||
"image": {
|
||||
"large_url": "https://c10.patreonusercontent.com/4/large/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/gallery-one.jpg",
|
||||
"url": "https://c10.patreonusercontent.com/4/orig/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/gallery-one.jpg"
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"images": {
|
||||
"data": [
|
||||
{"id": "9001", "type": "media"},
|
||||
{"id": "9002", "type": "media"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "1002",
|
||||
"type": "post",
|
||||
"attributes": {
|
||||
"title": "Attachment post",
|
||||
"published_at": "2026-04-15T09:30:00.000+00:00",
|
||||
"post_type": "text_only",
|
||||
"content": "<p>here is a zip</p>",
|
||||
"url": "https://www.patreon.com/posts/1002",
|
||||
"post_file": {
|
||||
"name": "bonus-pack.zip",
|
||||
"url": "https://www.patreon.com/file?h=cccccccccccccccccccccccccccccccc&i=1002"
|
||||
}
|
||||
},
|
||||
"relationships": {
|
||||
"attachments_media": {
|
||||
"data": [
|
||||
{"id": "9003", "type": "media"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "1003",
|
||||
"type": "post",
|
||||
"attributes": {
|
||||
"title": "Inline content post",
|
||||
"published_at": "2026-04-01T08:00:00.000+00:00",
|
||||
"post_type": "text_only",
|
||||
"content": "<p>look</p><figure><img src=\"https://c10.patreonusercontent.com/4/orig/dddddddddddddddddddddddddddddddd/inline.png?token=x&v=2\" alt=\"inline\"></figure>",
|
||||
"url": "https://www.patreon.com/posts/1003"
|
||||
},
|
||||
"relationships": {}
|
||||
},
|
||||
{
|
||||
"id": "1004",
|
||||
"type": "post",
|
||||
"attributes": {
|
||||
"title": "Video post",
|
||||
"published_at": "2026-03-20T18:45:00.000+00:00",
|
||||
"post_type": "video_external_file",
|
||||
"content": "<p>watch</p>",
|
||||
"url": "https://www.patreon.com/posts/1004",
|
||||
"post_file": {
|
||||
"name": "clip.m3u8",
|
||||
"url": "https://stream.mux.com/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.m3u8?token=jwt"
|
||||
}
|
||||
},
|
||||
"relationships": {}
|
||||
}
|
||||
],
|
||||
"included": [
|
||||
{
|
||||
"id": "9001",
|
||||
"type": "media",
|
||||
"attributes": {
|
||||
"file_name": "gallery-one.jpg",
|
||||
"download_url": "https://c10.patreonusercontent.com/4/orig/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/gallery-one.jpg",
|
||||
"image_urls": {
|
||||
"original": "https://c10.patreonusercontent.com/4/orig/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/gallery-one.jpg",
|
||||
"default": "https://c10.patreonusercontent.com/4/default/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/gallery-one.jpg"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "9002",
|
||||
"type": "media",
|
||||
"attributes": {
|
||||
"file_name": "gallery-two.jpg",
|
||||
"download_url": "https://c10.patreonusercontent.com/4/orig/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/gallery-two.jpg",
|
||||
"image_urls": {
|
||||
"original": "https://c10.patreonusercontent.com/4/orig/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/gallery-two.jpg"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "9003",
|
||||
"type": "media",
|
||||
"attributes": {
|
||||
"file_name": "bonus-pack.zip",
|
||||
"download_url": "https://www.patreon.com/file/download?h=cccccccccccccccccccccccccccccccc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5555",
|
||||
"type": "campaign",
|
||||
"attributes": {
|
||||
"name": "Example Creator",
|
||||
"url": "https://www.patreon.com/example"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"next": "https://www.patreon.com/api/posts?filter%5Bcampaign_id%5D=5555&page%5Bcursor%5D=NEXTCURSOR123&sort=-published_at"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user