feat: AI-generated shorts render pipeline

- Remotion composition (ShortsVideo) renders 1080x1920 9:16 shorts
  from script segments (hook/setup/conflict/insight/cta) with animated
  gradient background, word-by-word captions, progress bar
- render-worker.mjs: standalone poller (systemd hermyhq-render.service)
  TTS via edge-tts → Remotion render via Chrome headless → ffmpeg mux +
  thumbnail; ≤60s gate; marks YoutubeScript rendered
- API: POST /api/youtube/render (queue approved→render_queued),
  GET status, GET /render/file (stream video/thumb with Range support)
- Schema: YoutubeScript.videoUrl/thumbnailUrl + YoutubeRender model
- UI: youtube tab gains Renders view (preview/review/approve/reject/
  download), Render Shorts button on approved scripts
- Prisma db push applied to prod DB
This commit is contained in:
MythEclipse
2026-09-22 20:16:25 +07:00
parent 2a051875f3
commit 33e85ce8bf
11 changed files with 3272 additions and 89 deletions
+20
View File
@@ -165,6 +165,10 @@ model YoutubeScript {
seoChapters Json?
titleVariants Json?
thumbnailConcept String?
// Render output (shorts)
videoUrl String?
thumbnailUrl String?
render YoutubeRender?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -179,6 +183,22 @@ model YoutubeFeedback {
date DateTime @default(now())
}
model YoutubeRender {
id String @id @default(cuid())
scriptId String @unique
script YoutubeScript @relation(fields: [scriptId], references: [id], onDelete: Cascade)
status String @default("queued") // queued | rendering | rendered | failed
videoPath String?
thumbnailPath String?
durationMs Int?
error String?
metadata Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([status])
}
model LongformScript {
id String @id @default(cuid())
title String