Skip to content

Commit 0060316

Browse files
committed
Refactor video animation functions and enhance lightbox automation for better video extension handling
1 parent 92c281a commit 0060316

5 files changed

Lines changed: 126 additions & 66 deletions

File tree

cli.ts

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ export async function imageCreateCommand(
176176
{
177177
animationPrompt,
178178
conversationId: createResult.conversationId,
179-
branchPath: createResult.branchPath,
180179
extendCount,
181180
outputVideo: outputVideo!,
182181
},
@@ -654,7 +653,6 @@ async function createImageAnimations(
654653
options: {
655654
animationPrompt: string;
656655
conversationId: string;
657-
branchPath: string;
658656
extendCount: number;
659657
outputVideo: string;
660658
},
@@ -709,7 +707,6 @@ async function createImageAnimation(
709707
imageIndex: number;
710708
animationPrompt: string;
711709
conversationId: string;
712-
branchPath: string;
713710
extendCount: number;
714711
videoPath: string;
715712
},
@@ -719,7 +716,6 @@ async function createImageAnimation(
719716
image,
720717
options.animationPrompt,
721718
);
722-
let currentBranchPath = options.branchPath;
723719
let currentVideo = await pickFirstCompletedVideo(
724720
client,
725721
animatedDraft.videos,
@@ -729,12 +725,10 @@ async function createImageAnimation(
729725

730726
for (let i = 0; i < options.extendCount; i += 1) {
731727
await pauseBetweenMutationJobs();
732-
const extendedDraft = await client.extendVideo(
733-
options.conversationId,
734-
currentBranchPath,
728+
const extendedDraft = await extendVideoWithLightbox(
729+
sessionName,
735730
currentVideo,
736731
);
737-
currentBranchPath = extendedDraft.branchPath;
738732
currentVideo = await pickFirstCompletedVideo(
739733
client,
740734
extendedDraft.videos,
@@ -769,7 +763,7 @@ async function createImageAnimation(
769763
};
770764
}
771765

772-
type LightboxAnimateResult = {
766+
type LightboxMediaResult = {
773767
ok: boolean;
774768
before?: string;
775769
after?: string;
@@ -789,9 +783,12 @@ async function animateImageWithLightbox(
789783
`https://www.meta.ai/create/${image.id}`,
790784
);
791785

792-
const result = await runPlaywrightCliCodeJson<LightboxAnimateResult>(
786+
const result = await runPlaywrightCliCodeJson<LightboxMediaResult>(
793787
sessionName,
794-
await buildCustomAnimateCode(animationPrompt, image.id),
788+
await buildLightboxAutomationCode("metaAiCustomAnimate", {
789+
prompt: animationPrompt,
790+
sourceMediaId: image.id,
791+
}),
795792
);
796793

797794
if (!result.ok || !result.videoId) {
@@ -802,35 +799,70 @@ async function animateImageWithLightbox(
802799
}
803800

804801
return {
805-
videos: [{
806-
id: result.videoId,
807-
url: null,
808-
thumbnail: null,
809-
prompt: animationPrompt,
810-
sourceMedia: {
811-
id: image.id,
812-
url: image.url,
813-
thumbnail: image.thumbnail ?? null,
814-
},
815-
}],
802+
videos: [buildGeneratedVideoDraft(result.videoId, animationPrompt, image)],
816803
};
817804
}
818805

819-
async function buildCustomAnimateCode(
820-
prompt: string,
821-
sourceMediaId: string,
806+
async function extendVideoWithLightbox(
807+
sessionName: string,
808+
video: CompletedVideo,
809+
): Promise<{ videos: GeneratedVideo[] }> {
810+
await gotoPlaywrightCliSession(
811+
sessionName,
812+
`https://www.meta.ai/create/${video.id}`,
813+
);
814+
815+
const result = await runPlaywrightCliCodeJson<LightboxMediaResult>(
816+
sessionName,
817+
await buildLightboxAutomationCode("metaAiExtendAnimation", {
818+
sourceMediaId: video.id,
819+
}),
820+
);
821+
822+
if (!result.ok || !result.videoId) {
823+
const detail = result.reason ? ` ${result.reason}` : "";
824+
throw new Error(
825+
`Meta video extend did not return a video media id.${detail}`,
826+
);
827+
}
828+
829+
return {
830+
videos: [buildGeneratedVideoDraft(result.videoId, "Extend", video)],
831+
};
832+
}
833+
834+
async function buildLightboxAutomationCode(
835+
functionName: "metaAiCustomAnimate" | "metaAiExtendAnimation",
836+
input: Record<string, unknown>,
822837
): Promise<string> {
823838
const scriptPath = await getCustomAnimateScriptPath();
824-
const input = { prompt, sourceMediaId };
825839

826840
return `async (page) => {
827841
await page.addScriptTag({ path: ${JSON.stringify(scriptPath)} });
828842
return await page.evaluate(async (input) => {
829-
return await window.metaAiCustomAnimate(input);
843+
return await window[${JSON.stringify(functionName)}](input);
830844
}, ${JSON.stringify(input)});
831845
}`;
832846
}
833847

848+
function buildGeneratedVideoDraft(
849+
id: string,
850+
prompt: string,
851+
sourceMedia: GeneratedImage | CompletedVideo,
852+
): GeneratedVideo {
853+
return {
854+
id,
855+
url: null,
856+
thumbnail: null,
857+
prompt,
858+
sourceMedia: {
859+
id: sourceMedia.id,
860+
url: sourceMedia.url,
861+
thumbnail: sourceMedia.thumbnail ?? null,
862+
},
863+
};
864+
}
865+
834866
async function getCustomAnimateScriptPath(): Promise<string> {
835867
const scriptUrl = new URL("./lib/meta_lightbox_animate.js", import.meta.url);
836868
if (scriptUrl.protocol === "file:") {

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cliat/meta-ai",
3-
"version": "0.3.4",
3+
"version": "0.3.5",
44
"license": "MIT",
55
"exports": {
66
".": "./mod.ts",

lib/history.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,7 @@ async function fetchMediaLibraryPage(
266266
}> {
267267
const response = await fetch(META_GRAPHQL_URL, {
268268
method: "POST",
269-
headers: {
270-
"Accept": "multipart/mixed, application/json",
271-
"Content-Type": "application/json",
272-
"Cookie": auth.cookieHeader,
273-
"Origin": "https://meta.ai",
274-
"Referer": META_CREATE_URL,
275-
"User-Agent": auth.userAgent,
276-
},
269+
headers: buildHistoryGraphqlHeaders(auth),
277270
body: JSON.stringify({
278271
doc_id: DOC_MEDIA_LIBRARY_FEED,
279272
variables: {
@@ -489,14 +482,7 @@ async function deleteHistoryPrompt(
489482
): Promise<void> {
490483
const response = await fetch(META_GRAPHQL_URL, {
491484
method: "POST",
492-
headers: {
493-
"Accept": "multipart/mixed, application/json",
494-
"Content-Type": "application/json",
495-
"Cookie": auth.cookieHeader,
496-
"Origin": "https://meta.ai",
497-
"Referer": META_CREATE_URL,
498-
"User-Agent": auth.userAgent,
499-
},
485+
headers: buildHistoryGraphqlHeaders(auth),
500486
body: JSON.stringify({
501487
doc_id: DOC_DELETE_CONVERSATION,
502488
variables: {
@@ -541,6 +527,17 @@ async function deleteHistoryPrompt(
541527
}
542528
}
543529

530+
function buildHistoryGraphqlHeaders(auth: HistoryFetchAuth): HeadersInit {
531+
return {
532+
"Accept": "multipart/mixed, application/json",
533+
"Content-Type": "application/json",
534+
"Cookie": auth.cookieHeader,
535+
"Origin": "https://meta.ai",
536+
"Referer": META_CREATE_URL,
537+
"User-Agent": auth.userAgent,
538+
};
539+
}
540+
544541
function getMediaLibraryFeedPayload(
545542
value: unknown,
546543
): Record<string, unknown> | null {

lib/meta_api.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -363,23 +363,7 @@ export class MetaAiClient {
363363

364364
for (const statusRecord of collectStatusRecords(payload)) {
365365
const previous = latestById.get(statusRecord.mediaId);
366-
if (!previous) {
367-
latestById.set(statusRecord.mediaId, statusRecord);
368-
continue;
369-
}
370-
371-
const previousHasUrl = asOptionalString(previous.generatedVideo?.url);
372-
const currentHasUrl = asOptionalString(
373-
statusRecord.generatedVideo?.url,
374-
);
375-
if (!previousHasUrl && currentHasUrl) {
376-
latestById.set(statusRecord.mediaId, statusRecord);
377-
continue;
378-
}
379-
380-
if (
381-
previous.status !== "COMPLETE" && statusRecord.status === "COMPLETE"
382-
) {
366+
if (shouldReplaceStatusRecord(previous, statusRecord)) {
383367
latestById.set(statusRecord.mediaId, statusRecord);
384368
}
385369
}
@@ -444,6 +428,23 @@ export class MetaAiClient {
444428
}
445429
}
446430

431+
function shouldReplaceStatusRecord(
432+
previous: StatusRecord | undefined,
433+
current: StatusRecord,
434+
): boolean {
435+
if (!previous) {
436+
return true;
437+
}
438+
439+
const previousHasUrl = asOptionalString(previous.generatedVideo?.url);
440+
const currentHasUrl = asOptionalString(current.generatedVideo?.url);
441+
if (!previousHasUrl && currentHasUrl) {
442+
return true;
443+
}
444+
445+
return previous.status !== "COMPLETE" && current.status === "COMPLETE";
446+
}
447+
447448
function coerceGeneratedVideo(
448449
value: Record<string, unknown>,
449450
): Partial<GeneratedVideo> {

lib/meta_lightbox_animate.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,40 @@
2121
};
2222
}
2323

24+
return await submitAndReadNewVideoId(
25+
animateButton,
26+
sourceMediaId,
27+
"Custom animate stayed on the source media page.",
28+
);
29+
};
30+
31+
globalThis.metaAiExtendAnimation = async function (input) {
32+
const { sourceMediaId } = input;
33+
let extendButton = await waitForButton("Extend", 20);
34+
if (!extendButton) {
35+
const extendPanelButton = await waitForButton("Extend animation", 100);
36+
extendPanelButton?.click();
37+
extendButton = await waitForButton("Extend", 100);
38+
}
39+
40+
if (!extendButton) {
41+
return {
42+
ok: false,
43+
reason: "Extend submit button was not enabled.",
44+
buttons: listButtons(),
45+
};
46+
}
47+
48+
return await submitAndReadNewVideoId(
49+
extendButton,
50+
sourceMediaId,
51+
"Video extend stayed on the source media page.",
52+
);
53+
};
54+
55+
async function submitAndReadNewVideoId(button, sourceMediaId, staleReason) {
2456
const before = location.href;
25-
animateButton.click();
57+
button.click();
2658
for (let i = 0; i < 1200 && location.href === before; i += 1) {
2759
await sleep(100);
2860
}
@@ -34,11 +66,9 @@
3466
before,
3567
after,
3668
videoId,
37-
reason: videoId === sourceMediaId
38-
? "Custom animate stayed on the source media page."
39-
: undefined,
69+
reason: videoId === sourceMediaId ? staleReason : undefined,
4070
};
41-
};
71+
}
4272

4373
async function waitForButton(text, attempts) {
4474
for (let i = 0; i < attempts; i += 1) {

0 commit comments

Comments
 (0)