218bfebb92
The credential Verify button still ran gallery-dl --simulate for Patreon after the cutover — testing the wrong path (and prone to the vanity "Failed to extract campaign ID" the native resolver fixes). Wire it to the native ingester, behind a DRY dispatch so callers never branch on platform. - services/download_backends.py (new): the ONE place that knows which platforms are native vs gallery-dl. `uses_native_ingester(platform)` is the shared predicate; `verify_source_credential(...)` is the uniform probe (same (ok|None, message) contract for both backends). As a platform migrates, it moves into NATIVE_INGESTER_PLATFORMS here and BOTH download routing and verify switch together. - PatreonClient.verify_auth(campaign_id): one authenticated /api/posts fetch → True (valid) / False (401/403/HTML-login) / None (drift or network — inconclusive, not a credential verdict). - patreon_ingester.verify_patreon_credential(): resolve campaign id, then verify_auth — the verify counterpart to the download path. - patreon_resolver.resolve_campaign_id_for_source(): extracted the override / id:-URL / vanity resolution into ONE helper now shared by the download ingester and verify (download_service no longer carries its own copy + regex; −`import re`). - download_service: routes on uses_native_ingester() instead of inline `== "patreon"` (3 sites); uses the shared resolver. - api/credentials: calls verify_source_credential — no platform branch. Tests: verify_auth mapping, resolve_campaign_id_for_source (override/id:/ vanity/none), the dispatch predicate, verify_patreon_credential glue, credentials endpoint proves Patreon uses the native path (gallery-dl verify asserted not-called); repointed the gallery-dl verify test to subscribestar. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
"""Platform → download-backend dispatch (one place that knows which platforms
|
|
are served by the native FC ingester vs. the gallery-dl subprocess).
|
|
|
|
gallery-dl wasn't built to be driven by an automated scheduler — no native
|
|
checkpoint/resume, no structured logs, per-file HEADs that dominate wall-clock.
|
|
The native ingester (services/patreon_ingester.py, plan #697) replaces it for
|
|
Patreon and is the path we grow as more platforms migrate. To keep that
|
|
migration DRY, every caller that has to behave differently per backend —
|
|
download routing, the credential-verify probe, cursor handling — asks THIS
|
|
module instead of testing ``platform == "patreon"`` inline. When a platform gets
|
|
a native ingester, it moves into ``NATIVE_INGESTER_PLATFORMS`` here and both the
|
|
download path and verify switch over together.
|
|
|
|
The backend surfaces share a UNIFORM signature so a caller invokes the same
|
|
function regardless of platform:
|
|
- verify_credential(...) → (ok: bool|None, message: str)
|
|
- (download stays in download_service for now; uses_native_ingester() is the
|
|
shared predicate it routes on, so the decision lives here too.)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
# Platforms whose download + verify go through the native ingester rather than
|
|
# gallery-dl. gallery-dl still serves every other platform (subscribestar,
|
|
# hentaifoundry, discord, pixiv, deviantart) unchanged.
|
|
NATIVE_INGESTER_PLATFORMS = frozenset({"patreon"})
|
|
|
|
|
|
def uses_native_ingester(platform: str) -> bool:
|
|
"""True when `platform` is served by the native ingester (not gallery-dl).
|
|
The single predicate the download path and verify both route on."""
|
|
return platform in NATIVE_INGESTER_PLATFORMS
|
|
|
|
|
|
async def verify_source_credential(
|
|
*,
|
|
platform: str,
|
|
url: str,
|
|
artist_slug: str,
|
|
config_overrides: dict | None,
|
|
cookies_path: str | None,
|
|
auth_token: str | None,
|
|
images_root: Path,
|
|
) -> tuple[bool | None, str]:
|
|
"""Uniform credential probe across backends. Returns `(ok, message)`:
|
|
True = authenticated, False = rejected, None = inconclusive (drift /
|
|
network / nothing to test). Callers don't branch on platform — they call
|
|
this and render the result.
|
|
"""
|
|
if uses_native_ingester(platform):
|
|
# Native ingester platforms verify via their own lightweight auth probe
|
|
# (resolve campaign id + one authenticated API page). Patreon today.
|
|
from .patreon_ingester import verify_patreon_credential
|
|
|
|
return await verify_patreon_credential(url, cookies_path, config_overrides)
|
|
|
|
# gallery-dl platforms: --simulate one item; the extractor errors before it
|
|
# can list if auth is bad.
|
|
from .gallery_dl import GalleryDLService, SourceConfig
|
|
|
|
gdl = GalleryDLService(images_root=images_root)
|
|
return await gdl.verify(
|
|
url=url,
|
|
artist_slug=artist_slug,
|
|
platform=platform,
|
|
source_config=SourceConfig.from_dict(config_overrides or {}),
|
|
cookies_path=cookies_path,
|
|
auth_token=auth_token,
|
|
)
|