Update
This commit is contained in:
@@ -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 { useMitt } from '@/plugins/MittContext';
|
||||||
|
import useMediaStore from '@/stores/MediaStore'; // Add this import
|
||||||
import useVideoEditorStore from '@/stores/VideoEditorStore';
|
import useVideoEditorStore from '@/stores/VideoEditorStore';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import sampleTimelineElements from './sample-timeline-data';
|
|
||||||
import useVideoExport from './video-export';
|
import useVideoExport from './video-export';
|
||||||
import VideoPreview from './video-preview';
|
import VideoPreview from './video-preview';
|
||||||
|
|
||||||
@@ -23,6 +23,9 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
const lastUpdateRef = useRef(0);
|
const lastUpdateRef = useRef(0);
|
||||||
const emitter = useMitt();
|
const emitter = useMitt();
|
||||||
|
|
||||||
|
// Add MediaStore to get selected items
|
||||||
|
const { selectedMeme, selectedBackground } = useMediaStore();
|
||||||
|
|
||||||
const [currentTime, setCurrentTime] = useState(0);
|
const [currentTime, setCurrentTime] = useState(0);
|
||||||
const [isPlaying, setIsPlaying] = useState(false);
|
const [isPlaying, setIsPlaying] = useState(false);
|
||||||
const [videoElements, setVideoElements] = useState({});
|
const [videoElements, setVideoElements] = useState({});
|
||||||
@@ -44,10 +47,56 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
timelineElementsRef.current = timelineElements;
|
timelineElementsRef.current = timelineElements;
|
||||||
}, [timelineElements]);
|
}, [timelineElements]);
|
||||||
|
|
||||||
// ✅ FIX 1: Use useEffect to automatically setup videos when timeline loads
|
// ✅ NEW: Create timeline from selected items
|
||||||
useEffect(() => {
|
const createTimelineFromSelections = useCallback(() => {
|
||||||
initTimeline();
|
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);
|
const timelineUpdateResolverRef = useRef(null);
|
||||||
|
|
||||||
@@ -60,20 +109,29 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
|
|
||||||
// Add this useEffect to resolve the promise when timeline updates
|
// Add this useEffect to resolve the promise when timeline updates
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (timelineUpdateResolverRef.current && timelineElements.length > 0) {
|
if (timelineUpdateResolverRef.current && timelineElements.length >= 0) {
|
||||||
|
// Changed from > 0 to >= 0
|
||||||
timelineUpdateResolverRef.current();
|
timelineUpdateResolverRef.current();
|
||||||
timelineUpdateResolverRef.current = null;
|
timelineUpdateResolverRef.current = null;
|
||||||
}
|
}
|
||||||
}, [timelineElements]);
|
}, [timelineElements]);
|
||||||
|
|
||||||
const initTimeline = () => {
|
// ✅ UPDATED: Use selections instead of sample data
|
||||||
|
const initTimeline = useCallback(() => {
|
||||||
cleanupVideos(videoElements);
|
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();
|
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
|
// ✅ FIX 3: Auto-update status when videos load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setupVideoStatus();
|
setupVideoStatus();
|
||||||
@@ -83,7 +141,8 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
setVideoIsPlaying(isPlaying);
|
setVideoIsPlaying(isPlaying);
|
||||||
}, [isPlaying, setVideoIsPlaying]);
|
}, [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
|
// Use the FFmpeg hook
|
||||||
const { isExporting, exportProgress, exportStatus, ffmpegCommand, copyFFmpegCommand, exportVideo } = useVideoExport({
|
const { isExporting, exportProgress, exportStatus, ffmpegCommand, copyFFmpegCommand, exportVideo } = useVideoExport({
|
||||||
@@ -155,8 +214,19 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
scaledHeight = posterHeight * scale;
|
scaledHeight = posterHeight * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const centeredX = (maxWidth - scaledWidth) / 2;
|
// ✅ UPDATED: Different positioning for background vs meme
|
||||||
const centeredY = (maxHeight - scaledHeight) / 2;
|
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) =>
|
setTimelineElements((prev) =>
|
||||||
prev.map((el) => {
|
prev.map((el) => {
|
||||||
@@ -215,6 +285,7 @@ const VideoEditor = ({ width, height }) => {
|
|||||||
setVideoElements(videoEls);
|
setVideoElements(videoEls);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Rest of the component remains the same...
|
||||||
const cleanupVideos = (videosToCleanup) => {
|
const cleanupVideos = (videosToCleanup) => {
|
||||||
if (!videosToCleanup) return;
|
if (!videosToCleanup) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user