xlambda-media
Image, video, and 360°-tour upload and transforms, plus live streaming (RTMP/SRT/WHIP ingest, WHEP/HLS playback).
pip install xlambda-media
Python port of @xlambda-tech/media.
Uploading
The platform's upload is a three-call dance — presign, PUT the bytes to storage, confirm. This collapses it into one call:
from xlambda.media import MediaClient
client = MediaClient(api_key=os.environ["XLAMBDA_API_KEY"])
result = client.media.upload(
file=Path("photo.jpg"), # bytes, a path, or any binary file object
filename="photo.jpg",
content_type="image/jpeg",
project_id="proj_123",
)
print(result["mediaId"])
A path is streamed rather than read into memory, which matters for video. The size is computed for you.
If the transfer to storage fails, you get an UploadTransferError carrying
the media_id:
from xlambda.media import UploadTransferError
try:
client.media.upload(file=data, filename="a.mp4", content_type="video/mp4")
except UploadTransferError as err:
log.warning("orphaned pending media %s: %s", err.media_id, err)
That id matters — the presign already created a row server-side, and there's no automatic cleanup, so losing the id loses the record.
Batches presign in one round trip and report per-file outcomes, index-aligned with the input, so one bad file doesn't sink the rest:
results = client.media.upload_batch(files=[
{"file": a, "filename": "a.jpg", "contentType": "image/jpeg"},
{"file": b, "filename": "b.jpg", "contentType": "image/jpeg"},
])
# [{"success": True, "mediaId": ...}, {"success": False, "error": ...}]
The sync version transfers sequentially; AsyncMediaClient.media.upload_batch
runs them concurrently via asyncio.gather, matching the npm SDK.
upload_stream() is the one-step alternative — bytes go through the platform
as multipart instead of direct-to-storage, with no confirm step. Prefer
upload() for anything client-originated; use this for server-to-server
piping where you already hold the bytes.
Image transforms
A pure URL builder — no network call, no auth header, because there's nowhere
to put one on an <img> tag:
from xlambda.media import transform_url
client.image.transform_url("med_123", width=800, format="webp", quality=90)
# https://api.xlambda.tech/v1/image/med_123?width=800&format=webp&quality=90
crop="fill" requires both width and height, and raises ValueError if
you omit one rather than sending a request that would fail server-side.
Live streaming
stream = client.livestreams.create(project_id="proj_123", title="Launch", record_enabled=True)
stream["rtmpServerUrl"], stream["rtmpStreamKey"] # paste into OBS
stream["hlsPlaybackUrl"] # for players
stream["webRtcIngestUrl"], stream["webRtcPlaybackUrl"] # WHIP / WHEP
The ingest secrets come back only from create() and regenerate_key() —
the plaintext stream key is never retrievable again. regenerate_key() kicks
the current publisher immediately and needs the admin scope.
Simulcast and clips hang off a stream id:
client.livestreams.simulcast_targets(stream["id"]).create(
label="YouTube", destination_url="rtmp://a.rtmp.youtube.com/live2/KEY"
)
client.livestreams.clips(stream["id"]).create(duration_seconds=30)
WHIP/WHEP are URLs for a browser or player to use directly; this SDK doesn't wrap the SDP exchange.
Webhooks
from xlambda.media import create_media_events_handler
from xlambda.core.webhooks.adapters.flask import create_flask_blueprint
handler = create_media_events_handler(
secret=os.environ["XLAMBDA_WEBHOOK_SECRET"],
on_ready=lambda data: Media.objects.filter(pk=data["mediaId"]).update(status="ready"),
on_failed=lambda data: log.error("processing failed: %s", data["error"]),
on_livestream_recorded=lambda data: attach_recording(data["liveStreamId"], data["mediaId"]),
)
app.register_blueprint(create_flask_blueprint(handler), url_prefix="/webhooks/media")
Every callback is optional, and anything that isn't a media.*/livestream.*
event is acknowledged with a 200 and ignored — so pointing a shared webhook
URL here is safe. create_async_media_events_handler is the FastAPI-side
twin. See xlambda-core for the adapters and the
raw-body rule.
Async
Everything above has an awaitable twin:
from xlambda.media import AsyncMediaClient
async with AsyncMediaClient(api_key=...) as client:
await client.media.upload(file=data, filename="a.jpg", content_type="image/jpeg")
client.image.transform_url() stays synchronous on both — it builds a string.
Conventions
Arguments are snake_case; responses are the API's own camelCase, returned as
plain dicts typed by TypedDict. See xlambda-core.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xlambda_media-0.2.0.tar.gz.
File metadata
- Download URL: xlambda_media-0.2.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ff1fa31306d8312ee39d28103d78623b1cfcf9a23ca9bc8ec721f8b0099618b
|
|
| MD5 |
5567830ab9fe5fdf17a32817ca53741f
|
|
| BLAKE2b-256 |
4e67658d4a3e20b138e93a1ee35e8589ffe9bbc8bdf55b7c2977f8d785c995ec
|
Provenance
The following attestation bundles were made for xlambda_media-0.2.0.tar.gz:
Publisher:
sdk-release-python.yml on randyryan177-cloud/media-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
xlambda_media-0.2.0.tar.gz -
Subject digest:
8ff1fa31306d8312ee39d28103d78623b1cfcf9a23ca9bc8ec721f8b0099618b - Sigstore transparency entry: 2743353875
- Sigstore integration time:
-
Permalink:
randyryan177-cloud/media-server@52f9f31ba1bd54d30231faecd72325166d087444 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/randyryan177-cloud
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-release-python.yml@52f9f31ba1bd54d30231faecd72325166d087444 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file xlambda_media-0.2.0-py3-none-any.whl.
File metadata
- Download URL: xlambda_media-0.2.0-py3-none-any.whl
- Upload date:
- Size: 17.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
313ba4d3b4a333ff72ce1da9f8e761223806760557aa212be7401685beea3ab1
|
|
| MD5 |
68bee6737831742f9fd6eed0f7f1174a
|
|
| BLAKE2b-256 |
2df9f67e8bc964c33c2b6c4783f37d34a31e1ae4984b2ded19d3629191ca1dfe
|
Provenance
The following attestation bundles were made for xlambda_media-0.2.0-py3-none-any.whl:
Publisher:
sdk-release-python.yml on randyryan177-cloud/media-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
xlambda_media-0.2.0-py3-none-any.whl -
Subject digest:
313ba4d3b4a333ff72ce1da9f8e761223806760557aa212be7401685beea3ab1 - Sigstore transparency entry: 2743353896
- Sigstore integration time:
-
Permalink:
randyryan177-cloud/media-server@52f9f31ba1bd54d30231faecd72325166d087444 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/randyryan177-cloud
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-release-python.yml@52f9f31ba1bd54d30231faecd72325166d087444 -
Trigger Event:
workflow_dispatch
-
Statement type: