"""FC-3b platforms registry — single source of truth for what FabledCurator supports + where each platform's quirks live. Adding a new platform: drop a new module `.py` next to this one, declare an `INFO = PlatformInfo(...)`, add the import + entry in PLATFORMS below. Sidecar parsing, cookie materialization, and `/api/platforms` pick it up automatically. Lifted from GallerySubscriber's ~/Nextcloud/Projects/GallerySubscriber/backend/app/api/platforms.py and ~/.../extension/lib/platforms.js. Six platforms; auth_type and URL patterns match GS exactly so the existing browser extension hits FC unmodified. """ from .base import ( DEFAULT_DESCRIPTION_KEYS, DEFAULT_EXTERNAL_POST_ID_KEYS, PlatformInfo, ) from .deviantart import INFO as _DEVIANTART from .discord import INFO as _DISCORD from .hentaifoundry import INFO as _HENTAIFOUNDRY from .patreon import INFO as _PATREON from .pixiv import INFO as _PIXIV from .subscribestar import INFO as _SUBSCRIBESTAR PLATFORMS: dict[str, PlatformInfo] = { info.key: info for info in ( _PATREON, _SUBSCRIBESTAR, _HENTAIFOUNDRY, _DISCORD, _PIXIV, _DEVIANTART, ) } def known_platform_keys() -> frozenset[str]: return frozenset(PLATFORMS.keys()) def auth_type_for(platform: str) -> str | None: info = PLATFORMS.get(platform) return info.auth_type if info else None def to_dict(info: PlatformInfo) -> dict: """Serialize a PlatformInfo to a JSON-safe dict for /api/platforms. Behavioral fields (callables, sidecar-chain overrides) are intentionally omitted — they aren't useful to API consumers. """ return { "key": info.key, "name": info.name, "description": info.description, "auth_type": info.auth_type, "requires_auth": info.requires_auth, "url_pattern": info.url_pattern, "url_examples": info.url_examples, "default_config": info.default_config, "notes": info.notes, } def external_post_id_keys_for(platform: str | None) -> tuple[str, ...]: """Resolve the external_post_id lookup chain for a given platform, falling back to the module default when the platform isn't registered or hasn't overridden the chain.""" info = PLATFORMS.get(platform) if platform else None if info is not None and info.external_post_id_keys is not None: return info.external_post_id_keys return DEFAULT_EXTERNAL_POST_ID_KEYS def description_keys_for(platform: str | None) -> tuple[str, ...]: """Resolve the description body lookup chain for a given platform.""" info = PLATFORMS.get(platform) if platform else None if info is not None and info.description_keys is not None: return info.description_keys return DEFAULT_DESCRIPTION_KEYS __all__ = [ "PLATFORMS", "PlatformInfo", "auth_type_for", "description_keys_for", "external_post_id_keys_for", "known_platform_keys", "to_dict", ]