| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import type {
- VideoDocument,
- AssetManifest,
- RenderProps,
- RenderScene,
- PlatformPreset,
- TemplateType,
- } from "@pipeline/shared";
- import { PLATFORM_PRESETS } from "@pipeline/shared";
- import { basename } from "node:path";
- import { segmentImageRefs, resolveGithubImages } from "./github-images.js";
- /**
- * Project a document into the render-time `RenderProps` for one platform:
- * resolve asset filenames for staticFile() and carry each segment's AUDIO
- * duration. No frame/size computation here — the TEMPLATE computes the visual
- * timeline (it may extend beyond audio for silent padding, holds, etc.), and
- * the Remotion Composition owns fps/width/height/durationInFrames.
- */
- export function composeRenderProps(
- doc: VideoDocument,
- assets: AssetManifest,
- platform: PlatformPreset,
- template: TemplateType,
- channelName = "Pipeline"
- ): RenderProps {
- const scenes: RenderScene[] = doc.data.map((seg, i) => {
- const backgroundAsset = assets.backgrounds[i]
- ? { id: assets.backgrounds[i].id, filename: basename(assets.backgrounds[i].localPath) }
- : undefined;
- const images = segmentImageRefs(seg)
- .map((img) => {
- const resolved = assets.images.find(
- (a) =>
- (img.path && a.path === img.path) ||
- (img.url && a.url === img.url) ||
- (img.query && a.query === img.query) ||
- (img.repoSocialPreview && a.repoSocialPreview === img.repoSocialPreview)
- );
- return resolved
- ? { filename: basename(resolved.localPath), url: img.url, query: img.query }
- : undefined;
- })
- .filter((x): x is NonNullable<typeof x> => !!x);
- // Resolve the per-template extension (github-trending images → filenames).
- const extension = seg.extension?.type === "github-trending"
- ? {
- type: "github-trending" as const,
- repo: seg.extension.repo,
- highlights: seg.extension.highlights,
- intro: seg.extension.intro,
- review: seg.extension.review,
- images: resolveGithubImages(seg.extension, assets),
- }
- : undefined;
- return {
- id: seg.id,
- kind: seg.kind,
- index: seg.index,
- title: seg.title,
- desc: seg.desc,
- captionOrigin: seg.captionOrigin,
- caption: seg.caption,
- cardList: seg.cardList,
- menu: seg.menu,
- images,
- layoutHint: seg.layoutHint,
- extension,
- duration: seg.duration, // audio seconds (template computes visual frames)
- audioFilename: seg.captionAudioFileUrl ? basename(seg.captionAudioFileUrl) : "",
- backgroundAsset,
- };
- });
- return {
- scenes,
- template,
- platform,
- title: doc.meta?.title || "",
- subtitle: doc.meta?.subtitle || "",
- channelName,
- trendSummary: doc.meta?.trendSummary,
- globalStyle: { tone: "formal", pace: "normal" },
- };
- }
- /** Composition id the Remotion root registers (Root.tsx uses `${template}-${landscape|portrait}`). */
- export function compositionIdFor(template: TemplateType, platform: string): string {
- const preset = PLATFORM_PRESETS[platform as PlatformPreset];
- const aspectKey = preset.aspect === "16:9" ? "landscape" : "portrait";
- return `${template}-${aspectKey}`;
- }
|