Skip to main content

media-sdk-m8

Shared, settings-agnostic media primitives for the m8 media stack. Consumed by:

  • media-service-m8 — the live API (job producer)
  • media-worker-m8 — the async ARQ worker (job consumer)

The SDK is framework-agnostic (no FastAPI, no auth-sdk, no pydantic-settings) and imgtools-free. It owns no business logic, no database, and no preset knowledge — callers pass an explicit config object; the SDK never reads settings or env.

Contents

Object storage — media_sdk_m8.storage

ObjectStorage is a thin, provider-neutral wrapper over the Amazon S3 API (SigV4), built on boto3/botocore — the reference client every S3-compatible server is tested against. It never depends on a particular implementation: the validated backends are SeaweedFS 4.x (default reference implementation), Garage 2.x (validated fallback), and any other S3-compatible provider, including MinIO. It is constructed from an explicit ObjectStorageConfig (also exported as S3StorageConfig; endpoint, credentials, region, TLS, and the default presigned-URL lifetime), so it has no dependency on any service's settings module.

from media_sdk_m8 import ObjectStorage, ObjectStorageConfig

config = ObjectStorageConfig(
    endpoint="storage:9000",
    access_key="...",
    secret_key="...",
    secure=False,
    region="us-east-1",
    presigned_expire_seconds=300,
)
storage = ObjectStorage(config)

data = storage.get_object(bucket="private-media", object_key="key")
storage.put_object(
    bucket="public-media",
    object_key="key/variants/thumb_webp/thumb.webp",
    data=variant_bytes,
    content_type="image/webp",
)

Methods: stat_object, remove_object, get_object_head, get_object, stream_object, list_object_keys, put_object, put_object_stream, set_object_content_type, copy_object, post_upload_url, presigned_post_object, presigned_get_object.

list_object_keys(*, bucket, prefix="") recursively yields stored keys — the read primitive an orphan reconciler uses to find bytes that have no DB row.

stream_object and put_object_stream are the unbuffered pair. The first yields an object's bytes in chunks; the second writes length bytes from an open file-like object, for a payload the caller has already assembled on disk (an archive export, say) that put_object's bytes argument would force resident in memory.

Presigned-URL expiry defaults to config.presigned_expire_seconds and can be overridden per call via expires_seconds.

Browser-direct presigned URLs (public endpoint)

When the browser cannot resolve the internal storage host (e.g. storage:9000 in a container stack), set the two optional endpoint fields:

config = ObjectStorageConfig(
    endpoint="storage:9000",  # internal — service and worker only
    access_key="...",
    secret_key="...",
    secure=False,
    region="us-east-1",
    public_endpoint="127.0.0.1:9005",  # host:port, no scheme — browser-reachable
    public_secure=False,  # scheme for public URLs; falls back to `secure` when None
)
  • public_endpoint — the host the browser hits, in host:port form (no scheme). post_upload_url returns a URL built from this host/scheme; presigned_get_object is signed by a client bound to this endpoint (SigV4 GET signatures bind the Host, so the signing client must match the endpoint the browser sends the request to).
  • public_secure — TLS flag for the public endpoint. Falls back to secure when omitted.

All internal ops (stat_object, get_object, copy_object, etc.) always use endpoint, not public_endpoint. When public_endpoint is None (default), post_upload_url and presigned_get_object behave identically to before — compatible with proxy-through deployments and media-worker-m8.

Reverse-proxy requirement: a proxy (e.g. Traefik) forwarding requests to the storage backend must preserve the Host header (passHostHeader: true in Traefik, which is its default) so the SigV4 signature validates on arrival.

Job contracts — media_sdk_m8.contracts

Self-contained Pydantic v2 models that form the producer↔consumer contract. The service builds and enqueues them; the worker deserializes and acts on them.

  • ScanJobPayload — { object_id, bucket, object_key, owner_user_id }
  • VariantSpec — { variant_name, output_options, target_bucket, target_key }; output_options is the imgtools-shaped dict (one format + name) built by the service, so the worker needs no preset or key knowledge.
  • VariantJobPayload — { job_id, media_object_id, source_bucket, source_object_key, specs }
  • ExportArchiveEntry — one validated, traversal-safe source-object → ZIP-entry mapping; ExportArchiveJobPayload carries the authorized manifest, entries, target, chunk size and presign lifetime for delegated archive assembly.
  • OutboxEventPayload — { event_id, event_type, object_id, payload, created_at }; the outbound webhook contract. media-service-m8 writes one per state change to its transactional outbox and POSTs this HMAC-signed body to subscriber URLs, so a subscriber needs only this shape to verify and consume an event.

Development

pip install -e ".[dev]"
ruff format . && ruff check .
mypy media_sdk_m8 --ignore-missing-imports
bandit -r media_sdk_m8 --severity-level medium
pytest --cov=media_sdk_m8 --cov-report=term-missing --cov-fail-under=100

Published to PyPI on tagged release.

Metadata

Release files for media-sdk-m8 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for media-sdk-m8 1.0.0
File Size Uploaded Provenance Actions
media_sdk_m8-1.0.0.tar.gz 105.9 kB With provenance Details for media_sdk_m8-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for media-sdk-m8 1.0.0
File Interpreter ABI Platform Actions
media_sdk_m8-1.0.0-py3-none-any.whl Python 3 none any Details for media_sdk_m8-1.0.0-py3-none-any.whl

Total release size: 129.0 kB

Release files / media_sdk_m8-1.0.0.tar.gz

Download URL media_sdk_m8-1.0.0.tar.gz
Size 105.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8f5cf98bfda102670087aeb96e9932ff38a7dc763c00572f920f3210f793de81
BLAKE2b-256 checksum
How to use checksums
3121cad78d58c82b207ebbc2fad6b49d9dc027e9ed6c727040e11e4c4fadc97e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / media_sdk_m8-1.0.0-py3-none-any.whl

Download URL media_sdk_m8-1.0.0-py3-none-any.whl
Size 23.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ed34182d36773e6ad9790ed7d2c9719414c0660dd6d109fae4c7c11838d7824b
BLAKE2b-256 checksum
How to use checksums
1dfc6bf4bf99df2901395328c43d9157df6eaa39f9ca1f760c4698824c4262a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Security for media-sdk-m8 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for media_sdk_m8-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page