This commit is contained in:
ct
2025-06-17 22:58:51 +08:00
parent ec22cacd6b
commit d36bd4b8bf
3 changed files with 118 additions and 21 deletions

View File

@@ -1,7 +1,9 @@
import { useMitt } from '@/plugins/MittContext';
import useMediaStore from '@/stores/MediaStore';
import useVideoEditorStore from '@/stores/VideoEditorStore';
import { useCallback, useEffect, useRef, useState } from 'react';
import sampleTimelineElements from './sample-timeline-data';
import SINGLE_CAPTION_TEMPLATE from '../../templates/single_caption_meme_background.json';
import { generateTimelineFromTemplate } from '../../utils/timeline-template-processor';
import useVideoExport from './video-export';
import VideoPreview from './video-preview';
@@ -32,6 +34,7 @@ const VideoEditor = ({ width, height }) => {
const pausedTimeRef = useRef(0);
const { setVideoIsPlaying } = useVideoEditorStore();
const { selectedMeme, selectedBackground, currentCaption } = useMediaStore();
const FPS_INTERVAL = 1000 / 30; // 30 FPS
@@ -40,11 +43,18 @@ const VideoEditor = ({ width, height }) => {
timelineElementsRef.current = timelineElements;
}, [timelineElements]);
// Initialize timeline
// Initialize timeline on mount
useEffect(() => {
initTimeline();
}, []);
// Watch MediaStore changes and regenerate timeline
useEffect(() => {
if (selectedMeme || selectedBackground) {
generateAndSetTimeline();
}
}, [selectedMeme, selectedBackground, currentCaption]);
const timelineUpdateResolverRef = useRef(null);
const setTimelineElementsAsync = useCallback((newElements) => {
@@ -61,13 +71,34 @@ const VideoEditor = ({ width, height }) => {
}
}, [timelineElements]);
const generateAndSetTimeline = () => {
const mediaStoreData = {
selectedMeme,
selectedBackground,
currentCaption: currentCaption || 'Default caption text',
};
const generatedTimeline = generateTimelineFromTemplate(SINGLE_CAPTION_TEMPLATE, mediaStoreData);
if (generatedTimeline.length > 0) {
cleanupVideos(videoElements);
setTimelineElementsAsync(generatedTimeline).then(() => {
showConsoleLogs && console.log('Generated timeline from template:', generatedTimeline);
setupVideos();
setupImages();
});
}
};
const initTimeline = () => {
cleanupVideos(videoElements);
setTimelineElementsAsync(sampleTimelineElements).then(() => {
showConsoleLogs && console.log('Loaded sample timeline');
setupVideos();
setupImages();
});
// Try to generate from current MediaStore state first
if (selectedMeme || selectedBackground) {
generateAndSetTimeline();
} else {
// Set empty timeline and wait for media selections
setTimelineElements([]);
setStatus('Select meme and background to start editing');
}
};
// Handle element transformations (position, scale, rotation) and text properties
@@ -134,8 +165,8 @@ const VideoEditor = ({ width, height }) => {
scaledHeight = imgHeight * scale;
}
const centeredX = element.x || (maxWidth - scaledWidth) / 2;
const centeredY = element.y || (maxHeight - scaledHeight) / 2;
const centeredX = element.x !== undefined ? element.x : (maxWidth - scaledWidth) / 2;
const centeredY = element.y !== undefined ? element.y : (maxHeight - scaledHeight) / 2;
setTimelineElements((prev) =>
prev.map((el) => {
@@ -247,8 +278,8 @@ const VideoEditor = ({ width, height }) => {
scaledHeight = posterHeight * scale;
}
const centeredX = (maxWidth - scaledWidth) / 2;
const centeredY = (maxHeight - scaledHeight) / 2;
const centeredX = element.x !== undefined ? element.x : (maxWidth - scaledWidth) / 2;
const centeredY = element.y !== undefined ? element.y : (maxHeight - scaledHeight) / 2;
setTimelineElements((prev) =>
prev.map((el) => {
@@ -331,10 +362,11 @@ const VideoEditor = ({ width, height }) => {
} else if (mediaCount > 0) {
setStatus(`Loading media... (${loadedVideos.size}/${mediaCount})`);
} else {
setStatus('Ready to play');
setStatus('Select meme and background to start editing');
}
};
// Rest of the component remains the same...
const handlePause = useCallback(() => {
if (isPlaying) {
setIsPlaying(false);