Two-step thumbnail picker (choose text + frame, then render) + title-select fix#28
Conversation
Replaces the one-shot "generate 3 variations" thumbnail UI with a
pick-then-render flow on the clip detail page:
- "Get options" fetches headline text candidates (one AI call) and face
frame candidates (no AI) for the clip.
- Pick a text option (fills Line 1/2) and a frame, or upload your own
frame; leaving the lines empty lets the AI write them.
- "Generate" renders one final thumbnail from the chosen frame + text and
bakes it into the clip; a rendering indicator shows progress.
- "Refresh options" re-rolls both lists for iteration.
Backend: new `thumbnail-options` and `thumbnail-render` CLI commands wrap
generate_headline_variations / extract_candidate_frames /
generate_thumbnail_with_template; new
GET/POST /api/clips/:id/thumbnail/{options,render} endpoints.
Also fix title-option selection feedback: clicking a generated title now
shows a selected state and a "Save to apply" hint (it set the title
silently before, off-screen, so it looked broken).
|
Warning Review limit reached
More reviews will be available in 41 minutes and 46 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughTwo new CLI subcommands ( ChangesThumbnail options/render pipeline
Path resolution and MCP/Config UI updates
Sequence Diagram(s)sequenceDiagram
participant Browser as ClipDetail (Browser)
participant WebServer as web-server.ts
participant CLI as backend/cli.py
rect rgba(70, 130, 180, 0.5)
note over Browser,CLI: Step 1 — Fetch options
Browser->>WebServer: GET /api/clips/:id/thumbnail/options
WebServer->>CLI: thumbnail-options --title ... --video ... --n-texts --n-frames
CLI-->>WebServer: JSON {texts: [...], frames: [...]}
WebServer-->>Browser: candidate texts + frame paths
end
rect rgba(100, 160, 100, 0.5)
note over Browser,CLI: Step 2 — Render thumbnail
Browser->>WebServer: POST /api/clips/:id/thumbnail/render (frame_path, line1, line2)
WebServer->>CLI: thumbnail-render --frame ... --output ... --line1 --line2
CLI-->>WebServer: JSON {output_path}
WebServer->>CLI: bake-thumbnail + clips edit thumbnail_config
WebServer-->>Browser: {ok: true, preview_path}
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/ui/web-server.ts (1)
1487-1489: Guardclip.output_pathbefore callingexistsSyncto avoid deprecation warnings.
fs.existsSync()does not throw when passedundefinedin current Node.js versions (it returnsfalse), but this behavior is deprecated and will likely throw in future major versions. While line 1487 works today, the same pattern appears unguarded at lines 1414 and 1435. Add a null-check guard to all three locations:Suggested fix for line 1487
- if (existsSync(clip.output_path)) { + if (clip.output_path && existsSync(clip.output_path)) { const bake = await bakeThumbnailCard(clip.output_path, outPath, tc.card_seconds || 0);Also apply the same guard at lines 1414 and 1435 for consistency. Note: The
String()wrapper is unnecessary sinceoutput_pathis already typed asstring(or defaults to empty string at initialization).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/web-server.ts` around lines 1487 - 1489, Add null-check guards before calling existsSync with clip.output_path at all three locations where this pattern appears in the code. Verify that clip.output_path is truthy before passing it to existsSync to prevent deprecated behavior of passing undefined to the function. Since output_path is already typed as string, avoid using String() wrapper and simply check the value directly before the existsSync call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/ui/client/McpSetupPage.tsx`:
- Around line 45-53: The desktopJson variable uses a template literal to
directly interpolate the serverPath into a JSON string, which causes invalid
JSON on Windows systems because backslashes in file paths are not escaped.
Instead of using a template literal, create a JavaScript object with the
appropriate structure (containing mcpServers with podcli configuration including
command "node" and args array with serverPath), then serialize it using
JSON.stringify() to automatically handle proper escaping of all special
characters including backslashes for cross-platform compatibility.
In `@src/ui/web-server.ts`:
- Around line 1491-1493: The runCli call for the clips edit command on line 1492
does not check whether the command succeeded or failed. If the metadata
persistence operation fails, the endpoint still returns ok: true, leaving the
clip state inconsistent. After the runCli call with the clips edit command,
check the result to verify success and only return the success response with ok:
true if the command executed successfully. If the command fails, throw an error
or return an appropriate error response instead of continuing to the success
response.
- Around line 1472-1477: The current validation of frame_path only checks
existence with existsSync, which does not prevent path traversal attacks.
Replace the existence check with a security validation that first resolves the
frame_path to its absolute form using the resolve function, then validates it is
within allowed directories (such as clip thumbnail or upload roots) before
allowing it to be used in the args array for the thumbnail-render command. This
ensures that crafted requests cannot point to arbitrary server paths.
---
Nitpick comments:
In `@src/ui/web-server.ts`:
- Around line 1487-1489: Add null-check guards before calling existsSync with
clip.output_path at all three locations where this pattern appears in the code.
Verify that clip.output_path is truthy before passing it to existsSync to
prevent deprecated behavior of passing undefined to the function. Since
output_path is already typed as string, avoid using String() wrapper and simply
check the value directly before the existsSync call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7cc12055-6145-47ad-9064-4ef02bb3a6d6
📒 Files selected for processing (8)
backend/cli.pysrc/config/paths.tssrc/handlers/integrations.routes.tssrc/ui/client/ClipDetail.tsxsrc/ui/client/ConfigPage.tsxsrc/ui/client/McpSetupPage.tsxsrc/ui/public/css/styles.csssrc/ui/web-server.ts
…ixes - Resolve conflicts: take main's improved ConfigPage secret preview and McpSetupPage JSON.stringify config; keep main's resolveBackendDir(). - Apply the podcli landing 3D "surface" treatment to secondary buttons (.btn-ghost, .btn-danger) to match the primary 3D buttons. - Remove a duplicate .copy-btn definition (kept the one with the copied state).
…, guard output_path - thumbnail/render: resolve frame_path and require it under the clip's thumbnail dir or the upload dir before passing to the renderer. - Fail the request if the clips-edit metadata write returns non-zero. - Guard clip.output_path before existsSync. (McpSetup Windows-path JSON was already resolved by taking JSON.stringify in the merge.)
What
Reworks the clip detail Thumbnail section from a one-shot "generate 3 variations" into a pick-then-render flow, per request: first text choices, then frame choices, select both, generate — with re-iteration and a progress indicator.
Flow
Backend
thumbnail-options(wrapsgenerate_headline_variations+extract_candidate_frames) andthumbnail-render(wrapsgenerate_thumbnail_with_templatewithline1/2overrides + frame face-info).GET /api/clips/:id/thumbnail/options,POST /api/clips/:id/thumbnail/render(route through the CLI, so they honorPODCLI_BACKENDand work in the bundled runtime).Also: title-select fix
Clicking a generated title in Titles & description set the title silently (the field is in a section above, so it looked dead). Now it shows a selected state + a "Save to apply" hint.
Verification
thumbnail-renderexercised end-to-end with the runtime Python/Node: renders the chosen text in the brand style (white headline + cyan highlight + frame + logo).cli.pycompiles; root + clienttscclean; studio bundle builds.Summary by CodeRabbit
New Features
UI/UX Improvements