- Docs
- Data and storage
- Media processing
Media processing
Upload, probe, transform, and serve images and video with bounded size, pixel, and URL limits.
media.Media bundles the upload pipeline behind Upload, Download, DownloadRange, Stat, Probe, Transform, and Delete. It validates IDs, caps decode size, and probes format. For plain blobs, see Storage and media.
Quick start
Section titled “Quick start”local (default, adapters/media/local) writes under root and suits single instances and tests. s3 (adapters/media/s3) needs bucket, region, and credentials. Transforms call the configured ffmpeg and ffprobe binaries.
MEDIA_ADAPTER=localMEDIA_ROOT=/var/mediaMEDIA_MAX_DOWNLOAD_BYTES=67108864MEDIA_MAX_PIXELS=50000000MEDIA_PRESIGN_TTL=1hDefaults: root /tmp/media, base_url /media, ffmpeg and ffprobe on PATH, max_download_bytes 64 MiB, max_pixels 52428800, derived_ttl 10m, presign_ttl 1h (max 7 days), max_duration unlimited, region us-east-1. Durations are nanoseconds; env accepts "1h". Validate rejects negative bounds. See the media options.
Upload and probe an asset
Section titled “Upload and probe an asset”Upload generates the asset ID, so use asset.ID (not your path) for later calls. Register the adapter first; the container wires nothing. Media() resolves lazily, caches, and retries.
package main
import ( "context" "fmt" "os"
medialocal "github.com/zenta-dev/zever/adapters/media/local" "github.com/zenta-dev/zever/config" "github.com/zenta-dev/zever/container" "github.com/zenta-dev/zever/core/media")
func main() { medialocal.Register() ctx := context.Background() c := container.New(config.Default()) defer c.Close(ctx)
m, err := c.Media() if err != nil { panic(err) } raw, err := os.ReadFile("testdata/avatar.png") if err != nil { panic(err) } asset, err := m.Upload(ctx, "avatar.png", raw, media.UploadOptions{ContentType: "image/png"}) if err != nil { panic(err) } info, err := m.Stat(ctx, asset.ID) if err != nil { panic(err) } fmt.Println("size:", info.Size)}size: 48210Values vary with your file. Transform takes media.TransformOps (Width, Height, Format, Quality, Bitrate, CRF, Offset) and returns the derived asset URL plus an error.
Production checklist
Section titled “Production checklist”ValidIDaccepts only ASCII letters, digits, hyphens, and underscores; it rejects empty,.,.., and anything containing.., blocking path traversal. Never build a storage key from a raw caller ID.- Decoded images are capped at
max_pixelsand downloads atmax_download_bytes, so a crafted image cannot exhaust memory. - A
presign_ttlover 7 days failsValidate()withInvalidOptionsError. It is rejected, not clamped. - Pin
ffmpegandffprobepaths in config;access_key_idandsecret_access_keynever appear in logs.
Troubleshooting
Section titled “Troubleshooting”Stat or Download fails on an ID you just uploaded
Cause: the ID failed ValidID, usually your own path instead of asset.ID. Fix: use the ID Upload returned; sanitize caller input.
Transforms fail with “binary not found”
Cause: ffmpeg or ffprobe is missing. Fix: install them or set absolute paths in config. The storage adapter does not affect this.
Startup fails with InvalidOptionsError on presign_ttl
Cause: the TTL exceeds 7 days. Fix: lower it. The limit is enforced, not clamped.