Tag-casing acronym fix, Patreon resolver hardening, archive diagnostics, post-card strip #74
Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Operator-feedback batch. All CI-green on dev (run 624).
Tags
df2310b):normalize_tag_nameonly capitalizes the first letter of each word and preserves the rest —DC/NSFWsurvive (was lowercasing the tail →Dc/Nsfw). Matchesml/tag_name._title_word, so a Camie-suggested tag keeps the exact casing the suggestion UI showed when it round-trips throughPOST /api/tagson Accept. Lives only in the create endpoint, not the ML/allowlist path. Trade-off: all-caps input no longer folds to Title Case (protecting acronyms wins).Patreon resolution
3556a54): the three resolution surfaces (download event, dry-run preview, verify probe) now reportsource_url, the extractedvanity, and the exact campaigns-API lookup URL.a559fab): when Patreon's/api/campaigns?filter[vanity]=returns empty (its known failure mode), fall back to scraping the campaign id from the creator page's bootstrap JSON — gallery-dl's actual method.Imports / archives
19eb4e9): when_import_archivecaptures an archive without extracting any image (probe rejected / corrupt / missing extractor backend / non-media-only), it now records{file, reason}under the event'smetadata.unextracted_archivesand logs a warning, instead of failing silently.UI
9374f63): the hero-collage rail spans the full hero width (CSS grid, up to 5 cells + a "+N" overflow tile) instead of capping at 3 left-aligned cells.🤖 Generated with Claude Code
Patreon's /api/campaigns?filter[vanity]= lookup returns empty data for creators that plainly exist (operator-flagged 2026-06-06 — Atole etc. erroring at the resolve step). gallery-dl never used that endpoint; it pulls the campaign id out of the creator page's bootstrap JSON. Add the same as a fallback: when the API misses, GET the creator page (bare + /c/ vanity paths) and scrape the first campaign id from any known embedding ("id":"…","type":"campaign" / "campaign":{"data":{"id" / /api/campaigns/<id> / "campaign_id"). API is still tried first (cheap, structured); the page scrape only runs on a miss. Tests: API-empty → page-scrape fallback resolves; _scrape_campaign_id pattern coverage. Existing API-path tests unchanged (happy paths short-circuit before the fallback; failure paths hit the guarded scrape and still return None). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The recurring "post shows a zip but no images" report had no diagnostic: when _import_archive captured an archive as a bare PostAttachment — because the bomb-guard probe rejected it, or extraction yielded zero members (corrupt / unsupported / missing extractor backend), or it held only non-media files — it returned status="attached" silently. Now those paths set ImportResult.error with the specific reason and log a warning, and download_service records each as {file, reason} under the event's metadata.unextracted_archives (None when every archive extracted cleanly). So the next run names exactly which archives failed and why, instead of leaving the operator to guess. No behaviour change to the happy path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>