Process uploaded images and video
Turn an upload into image sizes, HLS video and audio in a background job, then serve a signed link to the result.
Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.
Stability The promise an interface ships with.
- Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
- Beta Usable in production; may change before it becomes stable.
- Experimental May change or go away; needs an explicit opt-in in main.yaml.
You will resize an uploaded photo in a background job and serve a signed link to a thumbnail. It takes about 15 minutes.
You need
- A MainSDK app with
filesset up (see file uploads). - A file that is
ready.
1. Choose a driver
media:
driver: getqrThe local driver keeps the job and file flow working offline but does not transcode, so use it in tests.
2. Start a job
import { media } from "mainsdk/media";
import type { FileRef } from "mainsdk/files";
export async function thumbnails(photo: FileRef) {
const job = await media.image(photo, { widths: [320, 640], formats: ["avif", "webp"] });
return job.id;
}The job is queued when the call returns, so the request never waits on the work. For video use media.video(file, { renditions: ["360p", "720p"], thumbnails: true }). Location data is stripped from every output.
3. Serve a result
import { auth } from "mainsdk";
import { media } from "mainsdk/media";
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
const session = await auth.require(req);
const { id } = await params;
const job = await media.get(id);
const thumb = job.outputs.find((o) => o.kind === "image" && o.width === 320);
if (!thumb) return new Response("not ready", { status: 404 });
return Response.json({ url: await media.url(thumb, { for: { id: session.user } }) });
}For an HLS video, media.playlist(job, output, { for }) returns a playlist whose paths are already signed, so a player makes no second request.
Check that it works
media.get(job.id)moves fromqueuedtoready.- A user who may not read the source gets
MAIN-MEDIA-0001.
Next
Was this page helpful?