This commit is contained in:
ct
2025-06-16 13:37:57 +08:00
parent 70813b16ba
commit 8ab96e5d00

View File

@@ -1,9 +1,9 @@
// TODO: I moved the sample timeline data to a dedicated file, and delayed the loading to 1 sec with useEffect. as such, alot of the ogics are broken. I need to make sure the delayed timeline should work like normal
// Updated video-editor.jsx to use selected meme and background
import { useMitt } from '@/plugins/MittContext';
import useMediaStore from '@/stores/MediaStore'; // Add this import
import useVideoEditorStore from '@/stores/VideoEditorStore';
import { useCallback, useEffect, useRef, useState } from 'react';
import sampleTimelineElements from './sample-timeline-data';
import useVideoExport from './video-export';
import VideoPreview from './video-preview';
@@ -23,6 +23,9 @@ const VideoEditor = ({ width, height }) => {
const lastUpdateRef = useRef(0);
const emitter = useMitt();
// Add MediaStore to get selected items
const { selectedMeme, selectedBackground } = useMediaStore();
const [currentTime, setCurrentTime] = useState(0);
const [isPlaying, setIsPlaying] = useState(false);
const [videoElements, setVideoElements] = useState({});
@@ -44,10 +47,56 @@ const VideoEditor = ({ width, height }) => {
timelineElementsRef.current = timelineElements;
}, [timelineElements]);
// ✅ FIX 1: Use useEffect to automatically setup videos when timeline loads
useEffect(() => {
initTimeline();
}, []);
// ✅ NEW: Create timeline from selected items
const createTimelineFromSelections = useCallback(() => {
const elements = [];
// If we have a selected meme, use its duration, otherwise default to 5 seconds
const memeDuration = selectedMeme?.duration ? parseFloat(selectedMeme.duration) : 5;
// Add background video if selected (base layer)
if (selectedBackground) {
elements.push({
id: `bg_${selectedBackground.ids}`,
type: 'video',
source_webm: selectedBackground.media_url, // Assuming it's webm
source_mov: selectedBackground.media_url, // You might need different URLs
poster: selectedBackground.media_url,
name: 'Background',
startTime: 0,
layer: 0,
inPoint: 0,
duration: memeDuration, // Match meme duration
x: 0,
y: 0,
width: dimensions.width,
height: dimensions.height,
});
}
// Add meme video if selected (overlay layer)
if (selectedMeme) {
elements.push({
id: `meme_${selectedMeme.ids}`,
type: 'video',
source_webm: selectedMeme.webm_url,
source_mov: selectedMeme.mov_url,
poster: selectedMeme.webp_url,
name: selectedMeme.name,
startTime: 0,
layer: 1,
inPoint: 0,
duration: memeDuration,
x: 50, // Offset slightly for overlay effect
y: 50,
width: dimensions.width - 100,
height: dimensions.height - 100,
});
}
showConsoleLogs && console.log('Created timeline from selections:', elements);
return elements;
}, [selectedMeme, selectedBackground, dimensions]);
const timelineUpdateResolverRef = useRef(null);
@@ -60,20 +109,29 @@ const VideoEditor = ({ width, height }) => {
// Add this useEffect to resolve the promise when timeline updates
useEffect(() => {
if (timelineUpdateResolverRef.current && timelineElements.length > 0) {
if (timelineUpdateResolverRef.current && timelineElements.length >= 0) {
// Changed from > 0 to >= 0
timelineUpdateResolverRef.current();
timelineUpdateResolverRef.current = null;
}
}, [timelineElements]);
const initTimeline = () => {
// ✅ UPDATED: Use selections instead of sample data
const initTimeline = useCallback(() => {
cleanupVideos(videoElements);
setTimelineElementsAsync(sampleTimelineElements).then(() => {
showConsoleLogs && console.log('Loaded sample timeline');
const newElements = createTimelineFromSelections();
setTimelineElementsAsync(newElements).then(() => {
showConsoleLogs && console.log('Loaded timeline from selections');
setupVideos();
});
};
}, [createTimelineFromSelections, videoElements]);
// ✅ NEW: Watch for changes in selected items and update timeline
useEffect(() => {
initTimeline();
}, [selectedMeme, selectedBackground]); // Re-run when selections change
// ✅ FIX 3: Auto-update status when videos load
useEffect(() => {
setupVideoStatus();
@@ -83,7 +141,8 @@ const VideoEditor = ({ width, height }) => {
setVideoIsPlaying(isPlaying);
}, [isPlaying, setVideoIsPlaying]);
const totalDuration = Math.max(...timelineElements.map((el) => el.startTime + el.duration));
// ✅ UPDATED: Calculate duration from actual timeline
const totalDuration = timelineElements.length > 0 ? Math.max(...timelineElements.map((el) => el.startTime + el.duration)) : 5; // Default fallback
// Use the FFmpeg hook
const { isExporting, exportProgress, exportStatus, ffmpegCommand, copyFFmpegCommand, exportVideo } = useVideoExport({
@@ -155,8 +214,19 @@ const VideoEditor = ({ width, height }) => {
scaledHeight = posterHeight * scale;
}
const centeredX = (maxWidth - scaledWidth) / 2;
const centeredY = (maxHeight - scaledHeight) / 2;
// ✅ UPDATED: Different positioning for background vs meme
let centeredX, centeredY;
if (element.id.startsWith('bg_')) {
// Background should fill the canvas
centeredX = 0;
centeredY = 0;
scaledWidth = maxWidth;
scaledHeight = maxHeight;
} else {
// Meme should be centered
centeredX = (maxWidth - scaledWidth) / 2;
centeredY = (maxHeight - scaledHeight) / 2;
}
setTimelineElements((prev) =>
prev.map((el) => {
@@ -215,6 +285,7 @@ const VideoEditor = ({ width, height }) => {
setVideoElements(videoEls);
};
// Rest of the component remains the same...
const cleanupVideos = (videosToCleanup) => {
if (!videosToCleanup) return;