| name | medias-module-patterns |
| description | Use when creating or editing the medias module in src/korone/modules/medias. Follow PyKorone structure and patterns for handlers, filters, provider adapters, platform packages, URL parsing, caching, media downloads, soft failures, and structured error reporting. |
Medias Module Patterns for PyKorone
Use this guide for all changes under src/korone/modules/medias/.
Goals
- Keep new media integrations consistent with existing handler and provider architecture.
- Prefer composable platform adapters over monolithic handlers.
- Keep failures soft with
None returns and observable through structured logs and the runtime logging pipeline.
Directory and Layering
Follow this structure for new platforms:
handlers/<platform>.py: thin handler class, usually no custom logic.
utils/platforms/<platform>/constants.py: regex patterns and API endpoints.
utils/platforms/<platform>/parser.py: pure extraction and normalization helpers.
utils/platforms/<platform>/client.py: network calls and payload decoding.
utils/platforms/<platform>/provider.py: orchestration and MediaPost assembly.
utils/platforms/<platform>/types.py: optional typed platform data models.
utils/platforms/<platform>/anubis.py or similar helper modules: optional internal support code that stays inside the platform package.
Keep cross-platform logic in shared files only:
handlers/base.py
filters.py
utils/parsing.py
utils/provider_base.py
utils/settings.py
utils/types.py
utils/url.py
Module Wiring
When adding a new platform handler:
- Export provider in
utils/platforms/__init__.py.
- Create
handlers/<platform>.py as a minimal subclass of BaseMediaHandler.
- Import the handler in
medias/__init__.py.
- Add the handler to
manifest.handlers in medias/__init__.py.
- Update user-facing module info text if supported platforms are listed.
Handler Pattern
Platform handlers should be minimal:
- Subclass
BaseMediaHandler.
- Set
PROVIDER.
- Set
DEFAULT_AUTHOR_NAME.
- Set
DEFAULT_AUTHOR_HANDLE.
Do not duplicate send, caption, cache, or compression logic in per-platform handlers unless there is a clear platform-only requirement.
Filter and Auto-Download Contract
- URL extraction must flow through
MediaUrlFilter.
- Provider URL regex,
PROVIDER.pattern, is the source of truth for detection.
- Keep URL normalization via
normalize_media_url(...).
- Respect chat-level auto-download toggle via settings/disabling repository.
- Keep
/url command bypass behavior intact.
Provider Contract
All providers must extend MediaProvider and define:
name
website
pattern
fetch(url: str) -> MediaPost | None
Provider behavior expectations:
- Return
None for unsupported links, parse failures, and empty media results.
- Build
MediaPost with non-empty media list.
- Prefer
download_media(...) for media downloads and retry/caching behavior. Keep established platform-specific download paths when they are part of the existing implementation, such as Instagram's single-media client flow.
- Preserve cancellation semantics; do not swallow
asyncio.CancelledError.
Parser and Client Rules
Parser layer, parser.py:
- Keep functions deterministic and side-effect free.
- Prefer explicit coercion/type guards for weak external payloads, ideally via shared helpers in
utils/parsing.py.
- Avoid I/O and network calls.
Client layer, client.py:
- Use shared HTTP session from
HTTPClient.get_session().
- Use provider defaults for timeout and headers unless the platform requires overrides.
- Return
None on non-200 or invalid payloads.
- Use structured logs for platform-specific network failures.
Shared parsing helpers:
- Use
coerce_str(...), coerce_int(...), dict_or_empty(...), and dict_list(...) for weak external payloads.
- Use
ensure_url_scheme(...) for simple scheme normalization when a provider needs it.
- Keep these helpers side-effect free and reusable across platform parsers.
Shared Types
Use shared media dataclasses from utils/types.py:
MediaSource: pre-download source metadata.
MediaItem: downloadable or cached Telegram media.
MediaPost: final content package for handler delivery.
Use MediaKind to classify media and keep type-safe branching.
Caching and URL Normalization
- Keep source URL normalization consistent with
normalize_media_url(...).
- Keep source-level cache keys stable through provider/base helpers.
- Keep post-level cache payloads serializable and backward-tolerant.
- Avoid creating new cache namespaces unless there is a clear cross-platform need.
Error Reporting
Use structured logger calls such as adebug, awarning, aerror, and aexception for unexpected failures in provider/client/handler flow.
When logging failures:
- Include
provider.
- Include
source_url when available.
- Include
stage, source_index, or source_kind when they help reproduction.
- Keep the failure path soft and return
None instead of raising from provider/client helpers.
Do not add manual Sentry capture inside medias. The module should rely on structured logs and the shared runtime logging path.
Performance and Limits
- Respect Telegram media constraints already enforced in
BaseMediaHandler.
- Keep media group handling compatible with current group limit and caption constraints.
- Reuse existing compression/fallback paths for photo delivery.
- Avoid blocking operations in handlers; move CPU-heavy transforms to thread offload when needed.
Keep Existing Contracts Stable
Do not break these established contracts without explicit migration:
BaseMediaHandler.filters() uses GroupChatFilter and MediaUrlFilter(PROVIDER.pattern).
MediaProvider.safe_fetch(...) wraps provider fetch and standardizes failures.
- Module handler wiring through
medias/__init__.py ModuleManifest(..., handlers=(...)).
Implementation Checklist for New Platform
- Add platform regex and endpoint constants.
- Implement parser helpers with defensive extraction.
- Implement client calls with shared session and timeout rules.
- Implement provider
fetch(...) returning MediaPost | None.
- Build media list via
download_media(...) unless preserving an existing platform-specific path.
- Add thin handler class and module wiring.
- Validate URL matching, media send path, and cache hit behavior.
- Verify failure paths log context and do not crash handler pipeline.