Media Upload
The "Add content" upload sheet in PlayoutAdmin โ file select โ transcoding profile pick โ TUS upload โ processing status.
- Component:
PlayoutAdmin/src/components/media/sections/AddContentSheet.jsx - Backend reference: domain/media โ full API schema, pipeline behavior, and category/passthrough rules live there, not here
API calls used
| Call | Used for | Notes / limitation |
|---|---|---|
GET /media/transcoding-profiles?category=<video\|image\|document> |
Populate the profile picker once a file is selected | Category is derived client-side from the file extension (detectMediaType โ categoryFor), not from the backend. audio/other never call this โ no category exists for them. See domain/media ยง Passthrough for what the returned profiles mean. |
POST /media/prepare |
Issue the upload token; also where tenant, folder, transcodingProfileId are sent |
tenant/folder are hardcoded constants in this component today, not derived from the logged-in user โ see Limitations. transcodingProfileId is only sent if a real numeric profile id was picked; "Custom..." sends none. |
TUS upload to /tusd/ |
The actual file bytes | Suite-wide shared path, not app-namespaced โ must match nginx's /tusd/ block and tusd's -base-path. Not a CoreAPI route. |
GET /media/?sortBy=created_at&sortDir=desc&limit=5 |
Find the Media row created for this upload (TUS itself doesn't return one) |
Matches by fileName/originalName, most-recent-first, retried for ~30s. Racy if two uploads with a colliding name finish at the same moment. |
GET /media/:id (polled every 2s) |
Track transcodingStage until done/failed |
Only meaningful when a real transcodingProfileId was sent โ otherwise stays at whatever default the backend leaves it. Full pipeline stages/stage semantics: domain/media. |
For request/response shapes, error codes, and everything about what a profile actually does (renditions vs. settings, passthrough, category rules) see domain/media and its OpenAPI spec.
Limitations
- Tenant and folder are hardcoded (
HARDCODED_TENANT = "jastv",HARDCODED_FOLDER = "marketing") โ every upload lands in the same place regardless of who's logged in. Should come from the authenticated user's org instead โ AuthAPI's access token already carries anorgs[]claim (org_id,org_slug,role,permissions) that's the natural source fortenant, it's just not decoded/used anywhere in this flow yet. Folder likely still needs a real picker. - "Custom..." in the profile picker isn't a real custom-config path
โ it just means "send no
transcodingProfileId." There's no way to submit ad-hoc, unsaved transcode settings from this form; a real profile has to be created first via Media Transcoding Presets. - Frontend media-type detection is extension-based and independent of
the backend's own MIME-based classifier (
media.InferMediaType) โ the two can disagree on an edge case; the backend's classification is the one that's actually persisted and drives behavior. - Media-record lookup after upload is a match-by-recency race, not an id returned directly from the upload response.
- One file per trip through the wizard โ no batch upload.
Full upload flow
sequenceDiagram
participant User
participant Sheet as AddContentSheet
participant API as CoreAPI
participant tusd
User->>Sheet: pick file
Sheet->>Sheet: detectMediaType(filename) โ categoryFor()
Sheet->>API: GET /media/transcoding-profiles?category=<detected>
API-->>Sheet: profiles (+ "Custom..." appended client-side)
User->>Sheet: name + pick profile โ Start upload
Sheet->>API: POST /media/prepare {tenant: HARDCODED, folder: HARDCODED, transcodingProfileId?}
API-->>Sheet: {token}
Sheet->>tusd: TUS upload to /tusd/ (metadata.uploadToken = token)
tusd->>API: POST /hooks/tusd (server-side, not seen by Sheet)
Sheet->>API: GET /media/?sortBy=created_at (find the new record)
loop every 2s until done/failed
Sheet->>API: GET /media/:id
API-->>Sheet: transcodingStage
end
- Type โ user drops/selects a file. No network call.
- Configure โ
detectMediaType+categoryForresolve a category;GET /media/transcoding-profilespopulates the picker; user names the asset and picks a profile. - Upload โ
POST /media/prepareissues a token, then a TUS upload streams the file directly to storage via/tusd/. - Processing โ the sheet locates the resulting
Mediarow and polls itstranscodingStageevery 2s untildone/failed. The pipeline itself (normalize/transcode/optimize/rasterize) runs entirely server-side โ see domain/media for what actually happens at each stage. - Done โ local summary only, no further calls.