diff --git a/client/src/remotion/ImageComposition.tsx b/client/src/remotion/ImageComposition.tsx index 06caf3f..6a286e7 100644 --- a/client/src/remotion/ImageComposition.tsx +++ b/client/src/remotion/ImageComposition.tsx @@ -165,27 +165,13 @@ export const ImageComposition = ({ ? wordTimings.findIndex(w => frame >= w.startFrame && frame < w.endFrame) : -1; - // Determine which group is currently active - const currentGroupIdx = activeWordIdx >= 0 ? Math.floor(activeWordIdx / WORDS_PER_GROUP) : -1; + // Only show caption when a word is actively being spoken + const renderCaption = frame < endingStart && activeWordIdx >= 0; - // Determine the last group that was visible (for holding display between words) - const lastActiveWordIdx = wordTimings - ? [...wordTimings].reverse().findIndex(w => frame >= w.startFrame) - : -1; - const resolvedLastIdx = lastActiveWordIdx >= 0 && wordTimings - ? wordTimings.length - 1 - lastActiveWordIdx - : -1; - const displayGroupIdx = activeWordIdx >= 0 - ? currentGroupIdx - : resolvedLastIdx >= 0 - ? Math.floor(resolvedLastIdx / WORDS_PER_GROUP) - : -1; - - const renderCaption = frame < endingStart && wordTimings && wordTimings.length > 0 && displayGroupIdx >= 0; - - const groupStart = displayGroupIdx * WORDS_PER_GROUP; + const groupIdx = activeWordIdx >= 0 ? Math.floor(activeWordIdx / WORDS_PER_GROUP) : 0; + const groupStart = groupIdx * WORDS_PER_GROUP; const groupWords = wordTimings ? wordTimings.slice(groupStart, groupStart + WORDS_PER_GROUP) : []; - const activeIdxInGroup = activeWordIdx >= 0 ? activeWordIdx - groupStart : -1; + const activeIdxInGroup = activeWordIdx - groupStart; // First frame of the current group (for fade-in) const groupFirstFrame = groupWords.length > 0 ? groupWords[0].startFrame : 0; diff --git a/server/routes/remotion.ts b/server/routes/remotion.ts index d0ce9fc..eb0768d 100644 --- a/server/routes/remotion.ts +++ b/server/routes/remotion.ts @@ -378,8 +378,7 @@ remotionRouter.post("/publish", async (req, res) => { console.log(`🚀 Publishing to ${page.pageName} (direct binary upload)...`); // Upload video bytes directly — Facebook cannot access local URLs const videoBuffer = await fs.promises.readFile(localPath); - const arrayBuffer = videoBuffer.buffer.slice(videoBuffer.byteOffset, videoBuffer.byteOffset + videoBuffer.byteLength) as ArrayBuffer; - const reelId = await facebookService.publishVideoFromBuffer(page, arrayBuffer, description || ""); + const reelId = await facebookService.publishVideoFromBuffer(page, videoBuffer, description || ""); await dbStorage.updateScheduledPost(scheduledPost.id, { publishedAt: new Date(), externalPostId: reelId }); results.push({ pageId, success: true, reelId }); } else { diff --git a/server/services/facebook.ts b/server/services/facebook.ts index 781b67e..8b423e6 100644 --- a/server/services/facebook.ts +++ b/server/services/facebook.ts @@ -78,8 +78,7 @@ export class FacebookService { ? path.join(process.cwd(), videoMedia.originalUrl) : videoMedia.originalUrl; const nodeBuffer = await fs.promises.readFile(localPath); - const arrayBuffer = nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.byteLength) as ArrayBuffer; - return await this.publishVideoFromBuffer(page, arrayBuffer, post.content); + return await this.publishVideoFromBuffer(page, nodeBuffer, post.content); } else { // Default to feed const imageMedia = mediaList.filter(m => m.type === 'image'); @@ -568,7 +567,7 @@ export class FacebookService { */ async publishVideoFromBuffer( page: SocialPage, - videoBuffer: ArrayBuffer, + videoBuffer: Buffer | ArrayBuffer, description?: string ): Promise { if (!page.accessToken) throw new Error('No access token found for this page');