feat(subscribestar): flip dispatch to the native ingester (#893, Step 5)
SubscribeStar now downloads + verifies through the native core ingester instead of gallery-dl — the go-live switch for milestone #71. - download_backends: subscribestar added to NATIVE_INGESTER_PLATFORMS; a _NATIVE_INGESTERS registry + _resolve_native_campaign_id make _run_native_ingester / preview_source / verify_source_credential platform-aware. SubscribeStar's campaign_id IS the creator URL (no resolver); Patreon still resolves the vanity. preview now catches the shared NativeIngestError (covers both platforms). - platform_lock: subscribestar serialized (one paced walk at a time). - gallery_dl: subscribestar entry removed from PLATFORM_DEFAULTS (rule 22 — no fallback once native works). - frontend SourceActions: isPatreon → isNative (patreon|subscribestar) so the recover/recapture actions show for subscribestar; download_service's cursor/mode/post_first + the preview endpoint already key on uses_native_ingester, so backfill/recovery/recapture/preview light up for free. - tests: download_backends (subscribestar native), platform_lock (serialized), and three gallery-dl-sample tests repointed to hentaifoundry (api_credentials verify, gallery_dl_service skip-value, api_sources arm-no-preflight). post_is_gated stays best-effort (can't cause junk downloads); not gating this. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -165,25 +165,26 @@ async def test_verify_runs_gallery_dl_and_stamps_on_success(client, db, monkeypa
|
||||
return (True, "Credentials valid — the feed authenticated.")
|
||||
monkeypatch.setattr(gdl_mod.GalleryDLService, "verify", _fake_verify)
|
||||
|
||||
# hentaifoundry is a gallery-dl platform (subscribestar migrated to native).
|
||||
await client.post("/api/credentials", json={
|
||||
"platform": "subscribestar", "credential_type": "cookies", "data": _NETSCAPE,
|
||||
"platform": "hentaifoundry", "credential_type": "cookies", "data": _NETSCAPE,
|
||||
})
|
||||
artist = Artist(name="Maewix", slug="maewix")
|
||||
db.add(artist)
|
||||
await db.flush()
|
||||
db.add(Source(
|
||||
artist_id=artist.id, platform="subscribestar",
|
||||
url="https://www.subscribestar.com/maewix", enabled=True, config_overrides={},
|
||||
artist_id=artist.id, platform="hentaifoundry",
|
||||
url="https://www.hentai-foundry.com/user/Maewix", enabled=True, config_overrides={},
|
||||
))
|
||||
await db.commit()
|
||||
|
||||
resp = await client.post("/api/credentials/subscribestar/verify")
|
||||
resp = await client.post("/api/credentials/hentaifoundry/verify")
|
||||
body = await resp.get_json()
|
||||
assert body["valid"] is True
|
||||
assert body["last_verified"] is not None
|
||||
|
||||
# The stamp is persisted on the credential record.
|
||||
rec = await (await client.get("/api/credentials/subscribestar")).get_json()
|
||||
rec = await (await client.get("/api/credentials/hentaifoundry")).get_json()
|
||||
assert rec["last_verified"] is not None
|
||||
|
||||
|
||||
|
||||
@@ -430,8 +430,8 @@ async def test_gallery_dl_platform_arm_skips_pre_flight(client, artist, db, monk
|
||||
monkeypatch.setattr(db_mod, "verify_source_credential", _boom)
|
||||
|
||||
src = Source(
|
||||
artist_id=artist.id, platform="subscribestar",
|
||||
url="https://www.subscribestar.com/x", enabled=True,
|
||||
artist_id=artist.id, platform="hentaifoundry",
|
||||
url="https://www.hentai-foundry.com/user/x", enabled=True,
|
||||
)
|
||||
db.add(src)
|
||||
await db.commit()
|
||||
|
||||
@@ -7,15 +7,16 @@ from backend.app.services.download_backends import (
|
||||
)
|
||||
|
||||
|
||||
def test_patreon_is_native():
|
||||
assert uses_native_ingester("patreon") is True
|
||||
assert "patreon" in NATIVE_INGESTER_PLATFORMS
|
||||
def test_native_platforms():
|
||||
for platform in ("patreon", "subscribestar"):
|
||||
assert uses_native_ingester(platform) is True
|
||||
assert platform in NATIVE_INGESTER_PLATFORMS
|
||||
|
||||
|
||||
def test_gallery_dl_platforms_are_not_native():
|
||||
# The five platforms still served by gallery-dl must NOT route to the
|
||||
# native ingester — guards an accidental over-broad migration.
|
||||
for platform in ("subscribestar", "hentaifoundry", "discord", "pixiv", "deviantart"):
|
||||
# The platforms still served by gallery-dl must NOT route to the native
|
||||
# ingester — guards an accidental over-broad migration.
|
||||
for platform in ("hentaifoundry", "discord", "pixiv", "deviantart"):
|
||||
assert uses_native_ingester(platform) is False
|
||||
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ def test_build_config_emits_tick_skip_value(gdl):
|
||||
scans once 20 contiguous archived items are seen."""
|
||||
from backend.app.services.gallery_dl import TICK_SKIP_VALUE
|
||||
cfg = gdl._build_config_for_source(
|
||||
platform="subscribestar",
|
||||
platform="hentaifoundry",
|
||||
source_config=SourceConfig(),
|
||||
artist_slug="alice",
|
||||
skip_value=TICK_SKIP_VALUE,
|
||||
@@ -272,7 +272,7 @@ def test_build_config_emits_backfill_skip_value(gdl):
|
||||
full post history."""
|
||||
from backend.app.services.gallery_dl import BACKFILL_SKIP_VALUE
|
||||
cfg = gdl._build_config_for_source(
|
||||
platform="subscribestar",
|
||||
platform="hentaifoundry",
|
||||
source_config=SourceConfig(),
|
||||
artist_slug="alice",
|
||||
skip_value=BACKFILL_SKIP_VALUE,
|
||||
|
||||
@@ -9,8 +9,14 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
def test_non_serialized_platform_has_no_lock():
|
||||
# gallery-dl platforms aren't capped — they get no lock at all.
|
||||
assert platform_lock("subscribestar", ttl_seconds=60) is None
|
||||
assert platform_lock("deviantart", ttl_seconds=60) is None
|
||||
assert platform_lock("hentaifoundry", ttl_seconds=60) is None
|
||||
|
||||
|
||||
def test_subscribestar_is_serialized():
|
||||
# subscribestar is a native-ingester platform now — one paced walk at a time.
|
||||
lock = platform_lock("subscribestar", ttl_seconds=60)
|
||||
assert lock is not None
|
||||
|
||||
|
||||
def test_patreon_serializes_to_one_holder():
|
||||
|
||||
Reference in New Issue
Block a user