feat: editor-v2 assemble lane — multi-clip/card timeline rendering in the worker
Per the adopted qwen38 plan §2 (+ glm53 amendments): video_processing_jobs kind 'assemble' (claim widened via 044), EdlPlan mirror validation (lenient-fail), the filter_complex builder (interleaved concat pairs, fit cover/contain chains, absolute-timeline PNG overlays with enable windows, VO adelay/sidechain duck, hard-breaking word wrap for card PNGs), and the runner's assemble path with pre-spawn trim gates, attempt backoff and 15-min cap. Sources open by magic (SPENC1 kek / SPENC2 direct key) so direct-to-R2 uploads assemble without the api ever seeing bytes. Tests: builder 18, edl-plan 12, overlay-png 3, runner fakes extended.
This commit is contained in:
parent
df62aa88d4
commit
10dfda3b7c
12 changed files with 1749 additions and 8 deletions
54
apps/api/migrations/044_assemble_claim.sql
Normal file
54
apps/api/migrations/044_assemble_claim.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
-- 044: the produce worker claims ASSEMBLE jobs (editor-v2 L1, the worker assemble lane).
|
||||
--
|
||||
-- An assemble row is an editor-v2 timeline render: input_json carries
|
||||
-- { edlProjectId, project: EdlProject } (the EDL shapes live in
|
||||
-- apps/api/src/media-control/edl.ts), video_asset_id points at the project's
|
||||
-- first source clip, and the produced output is a derived video_assets row
|
||||
-- exactly like a compose/mix produce. 043 owns the intake half of the feature
|
||||
-- (edl_projects + widening video_processing_jobs.kind's CHECK to admit
|
||||
-- 'assemble'); THIS migration is only the worker's half — the claim's kind
|
||||
-- filter widened so the lane can pick those rows up.
|
||||
--
|
||||
-- Same body as 042 with 'assemble' added to the kind list; 'transcoding'
|
||||
-- remains the lease state and the stale-lease sweep is unchanged, so a worker
|
||||
-- that dies mid-assembly still hands its row back through the same path a
|
||||
-- dead compose/mix encode does today.
|
||||
|
||||
CREATE OR REPLACE FUNCTION produce_job_claim(p_lane text, p_stale_after interval)
|
||||
RETURNS TABLE (
|
||||
id uuid,
|
||||
workspace_id uuid,
|
||||
kind text,
|
||||
input_json jsonb,
|
||||
video_asset_id uuid
|
||||
)
|
||||
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$
|
||||
BEGIN
|
||||
UPDATE video_processing_jobs stale
|
||||
SET state = 'queued', progress_percent = 0, error = NULL, updated_at = now()
|
||||
WHERE stale.state = 'transcoding'
|
||||
AND stale.updated_at < now() - p_stale_after;
|
||||
|
||||
RETURN QUERY
|
||||
UPDATE video_processing_jobs j
|
||||
SET state = 'transcoding', progress_percent = 5, error = NULL, updated_at = now()
|
||||
WHERE j.id IN (
|
||||
SELECT c.id
|
||||
FROM video_processing_jobs c
|
||||
WHERE c.kind IN ('probe', 'compose', 'mix', 'assemble')
|
||||
AND c.state = 'queued'
|
||||
AND (
|
||||
(p_lane = 'remote' AND c.input_json->>'lane' = 'remote')
|
||||
OR (p_lane <> 'remote' AND c.input_json->>'lane' IS DISTINCT FROM 'remote')
|
||||
)
|
||||
ORDER BY c.created_at, c.id
|
||||
FOR UPDATE SKIP LOCKED
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING j.id, j.workspace_id, j.kind, j.input_json, j.video_asset_id;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Ownership unchanged from 040/042.
|
||||
REVOKE ALL ON FUNCTION produce_job_claim(text, interval) FROM PUBLIC;
|
||||
GRANT EXECUTE ON FUNCTION produce_job_claim(text, interval) TO sp_app;
|
||||
Loading…
Add table
Add a link
Reference in a new issue