fix: dedupe suffixed video tasks
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import type { AssetPack, AssetTemplate, GenImage, GenSession, PackKind, ToyAsset } from '@/lib/types';
|
import type { AssetPack, AssetTemplate, GenImage, GenSession, PackKind, ToyAsset, VideoTask } from '@/lib/types';
|
||||||
import { PACK_LABELS, PACK_ORDER, PACK_TEMPLATES, TEXT_TEMPLATES, VIDEO_TEMPLATES } from '@/lib/templates';
|
import { PACK_LABELS, PACK_ORDER, PACK_TEMPLATES, TEXT_TEMPLATES, VIDEO_TEMPLATES } from '@/lib/templates';
|
||||||
import { HoverImagePreview, HoverVideoPreview } from './HoverImagePreview';
|
import { HoverImagePreview, HoverVideoPreview } from './HoverImagePreview';
|
||||||
|
|
||||||
@@ -35,6 +35,30 @@ function aspectCss(aspectRatio: AssetTemplate['aspectRatio'] | string | undefine
|
|||||||
return aspectRatio.replace(':', ' / ');
|
return aspectRatio.replace(':', ' / ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canonicalVideoTemplateId(templateId: string) {
|
||||||
|
return VIDEO_TEMPLATES.find(template => (
|
||||||
|
templateId === template.id || templateId.startsWith(`${template.id}_`)
|
||||||
|
))?.id ?? templateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function videoTaskScore(task: VideoTask) {
|
||||||
|
let score = 0;
|
||||||
|
if (task.videoUrl) score += 8;
|
||||||
|
if (task.status === 'succeeded') score += 4;
|
||||||
|
if (task.status === 'processing' || task.status === 'submitted') score += 2;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectVideoTaskForTemplate(tasks: VideoTask[], templateId: string) {
|
||||||
|
return tasks
|
||||||
|
.filter(task => canonicalVideoTemplateId(task.templateId) === templateId)
|
||||||
|
.sort((a, b) => {
|
||||||
|
const scoreDiff = videoTaskScore(b) - videoTaskScore(a);
|
||||||
|
if (scoreDiff) return scoreDiff;
|
||||||
|
return (b.updatedAt || b.submittedAt || 0) - (a.updatedAt || a.submittedAt || 0);
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
|
||||||
type AssetDetail = {
|
type AssetDetail = {
|
||||||
template: AssetTemplate;
|
template: AssetTemplate;
|
||||||
asset: ToyAsset | undefined;
|
asset: ToyAsset | undefined;
|
||||||
@@ -379,20 +403,23 @@ function VideoSection({ videoLoading, primaryImage, locked, session, onGenerateV
|
|||||||
onRefreshVideo: (taskId: string) => void;
|
onRefreshVideo: (taskId: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const [showPromptId, setShowPromptId] = useState<string | null>(null);
|
const [showPromptId, setShowPromptId] = useState<string | null>(null);
|
||||||
const videoTasks = session.videoTasks ?? [];
|
const videoTasks = (session.videoTasks ?? []).filter(task => !/_part[12]$/.test(task.templateId));
|
||||||
const byTemplate = new Map(videoTasks.map(task => [task.templateId, task]));
|
|
||||||
const builtInIds = new Set<string>(VIDEO_TEMPLATES.map(template => template.id));
|
const builtInIds = new Set<string>(VIDEO_TEMPLATES.map(template => template.id));
|
||||||
const extraTasks = videoTasks.filter(task => !builtInIds.has(task.templateId) && !/_part[12]$/.test(task.templateId));
|
const extraTasks = videoTasks.filter(task => !builtInIds.has(canonicalVideoTemplateId(task.templateId)));
|
||||||
const videoItems = [
|
const videoItems = [
|
||||||
...VIDEO_TEMPLATES.map(template => ({
|
...VIDEO_TEMPLATES.map(template => {
|
||||||
id: template.id,
|
const task = selectVideoTaskForTemplate(videoTasks, template.id);
|
||||||
title: template.title,
|
return {
|
||||||
description: template.description,
|
id: template.id,
|
||||||
duration: template.duration,
|
title: task?.title ?? template.title,
|
||||||
ratio: template.ratio,
|
description: task?.description ?? template.description,
|
||||||
promptTemplate: template.promptTemplate,
|
duration: task?.duration ?? template.duration,
|
||||||
template,
|
ratio: task?.ratio ?? template.ratio,
|
||||||
})),
|
promptTemplate: task?.prompt ?? template.promptTemplate,
|
||||||
|
template,
|
||||||
|
task,
|
||||||
|
};
|
||||||
|
}),
|
||||||
...extraTasks.map(task => ({
|
...extraTasks.map(task => ({
|
||||||
id: task.templateId,
|
id: task.templateId,
|
||||||
title: task.title,
|
title: task.title,
|
||||||
@@ -401,9 +428,10 @@ function VideoSection({ videoLoading, primaryImage, locked, session, onGenerateV
|
|||||||
ratio: task.ratio,
|
ratio: task.ratio,
|
||||||
promptTemplate: task.prompt,
|
promptTemplate: task.prompt,
|
||||||
template: null,
|
template: null,
|
||||||
|
task,
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
const submittedCount = videoItems.filter(item => byTemplate.has(item.id)).length;
|
const submittedCount = videoItems.filter(item => item.task).length;
|
||||||
const totalCount = Math.max(videoItems.length, 1);
|
const totalCount = Math.max(videoItems.length, 1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -430,8 +458,8 @@ function VideoSection({ videoLoading, primaryImage, locked, session, onGenerateV
|
|||||||
<div className="grid grid-cols-1 gap-2 border-t border-white/[0.05] p-3 2xl:grid-cols-2">
|
<div className="grid grid-cols-1 gap-2 border-t border-white/[0.05] p-3 2xl:grid-cols-2">
|
||||||
{videoItems.map(item => {
|
{videoItems.map(item => {
|
||||||
const isOpen = showPromptId === item.id;
|
const isOpen = showPromptId === item.id;
|
||||||
const task = byTemplate.get(item.id);
|
const task = item.task;
|
||||||
const loadingThis = videoLoading === item.id;
|
const loadingThis = videoLoading === item.id || videoLoading === task?.templateId;
|
||||||
return (
|
return (
|
||||||
<div key={item.id} className="grid min-w-0 grid-cols-[128px_minmax(0,1fr)] gap-3 rounded-[8px] bg-white/[0.025] p-2.5 ring-1 ring-white/[0.05] transition-all hover:ring-white/[0.12]">
|
<div key={item.id} className="grid min-w-0 grid-cols-[128px_minmax(0,1fr)] gap-3 rounded-[8px] bg-white/[0.025] p-2.5 ring-1 ring-white/[0.05] transition-all hover:ring-white/[0.12]">
|
||||||
<div className="relative h-24 overflow-hidden rounded-[8px] bg-black/70">
|
<div className="relative h-24 overflow-hidden rounded-[8px] bg-black/70">
|
||||||
|
|||||||
Reference in New Issue
Block a user