Refactor: remove AGPL imgly dependency and migrate background removal to python backend
This commit is contained in:
@@ -14,8 +14,8 @@ interface ExportModalProps {
|
||||
durationInFrames: number;
|
||||
brandVisibility?: { logo: boolean; frame: boolean; background: boolean };
|
||||
outputFormat?: 'video' | 'image';
|
||||
/** Template aspect ratio — used to filter resolution presets */
|
||||
aspectRatio?: '9:16' | '16:9' | '1:1' | '4:5' | '4:3';
|
||||
aspectRatio?: string;
|
||||
onAssetSaved?: (url: string) => void;
|
||||
}
|
||||
|
||||
const FORMAT_OPTIONS: { value: RenderFormat; label: string; icon: typeof Film; desc: string }[] = [
|
||||
@@ -53,6 +53,7 @@ export const ExportModal: React.FC<ExportModalProps> = ({
|
||||
brandVisibility,
|
||||
outputFormat,
|
||||
aspectRatio,
|
||||
onAssetSaved,
|
||||
}) => {
|
||||
const { jobs, activeJobs, hasActiveJobs, isConnected, startExport, cancelJob, downloadJob } = useExportQueue();
|
||||
|
||||
@@ -68,7 +69,24 @@ export const ExportModal: React.FC<ExportModalProps> = ({
|
||||
const filteredPresets = useMemo(() => {
|
||||
if (!aspectRatio) return RESOLUTION_PRESETS;
|
||||
const matching = RESOLUTION_PRESETS.filter(p => p.ratio === aspectRatio);
|
||||
return matching.length > 0 ? matching : RESOLUTION_PRESETS;
|
||||
if (matching.length > 0) return matching;
|
||||
|
||||
// Parse custom W:H
|
||||
const parts = aspectRatio.split(':');
|
||||
if (parts.length === 2) {
|
||||
const w = parseInt(parts[0], 10);
|
||||
const h = parseInt(parts[1], 10);
|
||||
if (!isNaN(w) && !isNaN(h)) {
|
||||
return [{
|
||||
label: `${w}x${h}`,
|
||||
w: w,
|
||||
h: h,
|
||||
desc: 'Resolución Original',
|
||||
ratio: aspectRatio
|
||||
}];
|
||||
}
|
||||
}
|
||||
return RESOLUTION_PRESETS;
|
||||
}, [aspectRatio]);
|
||||
|
||||
const [resIdx, setResIdx] = useState(0);
|
||||
@@ -94,6 +112,22 @@ export const ExportModal: React.FC<ExportModalProps> = ({
|
||||
return FORMAT_OPTIONS;
|
||||
}, [outputFormat]);
|
||||
|
||||
// Ensure selected format is valid for the current mode
|
||||
React.useEffect(() => {
|
||||
if (!filteredFormats.find(f => f.value === format)) {
|
||||
setFormat(filteredFormats[0].value);
|
||||
}
|
||||
}, [filteredFormats, format]);
|
||||
|
||||
// Track finished jobs to call onAssetSaved automatically
|
||||
React.useEffect(() => {
|
||||
if (!onAssetSaved) return;
|
||||
const completedJob = jobs.find(j => j.status === 'completed' && j.resultUrl);
|
||||
if (completedJob && completedJob.resultUrl) {
|
||||
onAssetSaved(completedJob.resultUrl);
|
||||
}
|
||||
}, [jobs, onAssetSaved]);
|
||||
|
||||
const handleExport = async () => {
|
||||
setIsExporting(true);
|
||||
try {
|
||||
@@ -128,8 +162,8 @@ export const ExportModal: React.FC<ExportModalProps> = ({
|
||||
<Download size={18} className="text-violet-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-sm font-bold text-white">Exportar</h2>
|
||||
<p className="text-[10px] text-neutral-500">Renderizar y descargar</p>
|
||||
<h2 className="text-sm font-bold text-white">{onAssetSaved ? 'Guardar Activo de Marca' : 'Exportar'}</h2>
|
||||
<p className="text-[10px] text-neutral-500">{onAssetSaved ? 'Renderizar y aplicar cambios' : 'Renderizar y descargar'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -284,7 +318,7 @@ export const ExportModal: React.FC<ExportModalProps> = ({
|
||||
}`}
|
||||
>
|
||||
<Zap size={16} />
|
||||
{isExporting ? 'Iniciando...' : `Exportar ${isStill ? 'Imagen' : 'Video'}`}
|
||||
{isExporting ? 'Iniciando...' : (onAssetSaved ? 'Renderizar y Guardar' : `Exportar ${isStill ? 'Imagen' : 'Video'}`)}
|
||||
<span className="text-[9px] opacity-60 font-mono">({estimatedSize})</span>
|
||||
</button>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user