feat: preview templates, thumbnail features, 2 new org templates

This commit is contained in:
Rotimi Best
2026-05-23 12:24:57 +01:00
parent 4fdd4115b9
commit 78ab13f54b
106 changed files with 8320 additions and 2040 deletions
+34
View File
@@ -118,6 +118,40 @@ export async function enqueueLessonVideoPipeline(
};
}
/**
* Enqueue only generate-thumbnail (new `media_job` row required). Used by the
* "regenerate thumbnails" action from the media manager. Skips probe — the
* asset already has a duration from the original pipeline.
*/
export async function enqueueGenerateThumbnailOnly(input: {
mediaJobId: string;
assetId: string;
storageKey: string;
actorContext: TActorContext;
}): Promise<EnqueueLessonVideoPipelineResult> {
const { mediaJobId, assetId, storageKey, actorContext } = input;
const sharedData = {
mediaJobId,
assetId,
storageKey,
actorContext,
markJobCompleteOnSuccess: true
};
const job = await getQueue(QUEUE_NAMES.media).add(
JOB_NAMES.media.generateThumbnail,
sharedData,
QUEUE_DEFAULTS[QUEUE_NAMES.media]
);
return {
rootJobId: job.id ?? '',
jobIds: {
[JOB_NAMES.media.generateThumbnail]: job.id ?? ''
}
};
}
/**
* Enqueue only extract-audio → transcribe-audio (new `media_job` row required).
* Used for manual “generate transcript” when the initial pipeline had no OpenAI key.
+7 -1
View File
@@ -29,7 +29,13 @@ export const ZGenerateThumbnailPayload = z.object({
storageKey: z.string().min(1),
actorContext: ZActorContext,
/** Seconds into the video to grab. Defaults to 1.0 in the worker. */
atSeconds: z.number().nonnegative().optional()
atSeconds: z.number().nonnegative().optional(),
/**
* When true, the processor marks the parent `media_job` as `completed`
* after a successful run. Set by `enqueueGenerateThumbnailOnly` because
* thumbnail is the only step and nothing else will flip status.
*/
markJobCompleteOnSuccess: z.boolean().optional()
});
export type TGenerateThumbnailPayload = z.infer<typeof ZGenerateThumbnailPayload>;