Also don't load videos that have an edited variant

This commit is contained in:
2025-09-04 16:11:10 +02:00
parent 10eed9efcd
commit ad4130906b

View File

@@ -103,7 +103,7 @@ class VideoEditor:
# Display offset for panning when zoomed # Display offset for panning when zoomed
self.display_offset = [0, 0] self.display_offset = [0, 0]
# Progress bar state # Progress bar state
self.progress_bar_visible = False self.progress_bar_visible = False
self.progress_bar_progress = 0.0 # 0.0 to 1.0 self.progress_bar_progress = 0.0 # 0.0 to 1.0
@@ -114,16 +114,31 @@ class VideoEditor:
def _get_video_files_from_directory(self, directory: Path) -> List[Path]: def _get_video_files_from_directory(self, directory: Path) -> List[Path]:
"""Get all video files from a directory, sorted by name""" """Get all video files from a directory, sorted by name"""
video_files = [] video_files = set()
for file_path in directory.iterdir(): for file_path in directory.iterdir():
if ( if (
file_path.is_file() file_path.is_file()
and file_path.suffix.lower() in self.VIDEO_EXTENSIONS and file_path.suffix.lower() in self.VIDEO_EXTENSIONS
and not "_edited" in file_path.name
): ):
video_files.append(file_path) video_files.add(file_path)
return sorted(video_files)
edited_videos = set()
for file_path in video_files:
if "_edited" in file_path.stem:
edited_videos.add(file_path)
non_edited_videos = set()
for file_path in video_files:
if "_edited" in file_path.stem:
continue
edited_equivalent = file_path.with_name(
f"{file_path.stem}_edited{file_path.suffix}"
)
if edited_equivalent in edited_videos:
continue
non_edited_videos.add(file_path)
return sorted(non_edited_videos)
def _load_video(self, video_path: Path): def _load_video(self, video_path: Path):
"""Load a video file and initialize video properties""" """Load a video file and initialize video properties"""
if hasattr(self, "cap") and self.cap: if hasattr(self, "cap") and self.cap:
@@ -322,7 +337,7 @@ class VideoEditor:
self.progress_bar_complete = False self.progress_bar_complete = False
self.progress_bar_complete_time = None self.progress_bar_complete_time = None
self.progress_bar_text = text self.progress_bar_text = text
def update_progress_bar(self, progress: float, text: str = None, fps: float = None): def update_progress_bar(self, progress: float, text: str = None, fps: float = None):
"""Update progress bar progress (0.0 to 1.0) and optionally text and FPS""" """Update progress bar progress (0.0 to 1.0) and optionally text and FPS"""
if self.progress_bar_visible: if self.progress_bar_visible:
@@ -331,87 +346,163 @@ class VideoEditor:
self.progress_bar_text = text self.progress_bar_text = text
if fps is not None: if fps is not None:
self.progress_bar_fps = fps self.progress_bar_fps = fps
# Mark as complete when reaching 100% # Mark as complete when reaching 100%
if self.progress_bar_progress >= 1.0 and not self.progress_bar_complete: if self.progress_bar_progress >= 1.0 and not self.progress_bar_complete:
self.progress_bar_complete = True self.progress_bar_complete = True
self.progress_bar_complete_time = time.time() self.progress_bar_complete_time = time.time()
def hide_progress_bar(self): def hide_progress_bar(self):
"""Hide progress bar""" """Hide progress bar"""
self.progress_bar_visible = False self.progress_bar_visible = False
self.progress_bar_complete = False self.progress_bar_complete = False
self.progress_bar_complete_time = None self.progress_bar_complete_time = None
self.progress_bar_fps = 0.0 self.progress_bar_fps = 0.0
def draw_progress_bar(self, frame): def draw_progress_bar(self, frame):
"""Draw progress bar on frame if visible - positioned at top with full width""" """Draw progress bar on frame if visible - positioned at top with full width"""
if not self.progress_bar_visible: if not self.progress_bar_visible:
return return
# Check if we should fade out # Check if we should fade out
if self.progress_bar_complete and self.progress_bar_complete_time: if self.progress_bar_complete and self.progress_bar_complete_time:
elapsed = time.time() - self.progress_bar_complete_time elapsed = time.time() - self.progress_bar_complete_time
if elapsed > self.PROGRESS_BAR_FADE_DURATION: if elapsed > self.PROGRESS_BAR_FADE_DURATION:
self.hide_progress_bar() self.hide_progress_bar()
return return
# Calculate fade alpha (1.0 at start, 0.0 at end) # Calculate fade alpha (1.0 at start, 0.0 at end)
fade_alpha = max(0.0, 1.0 - (elapsed / self.PROGRESS_BAR_FADE_DURATION)) fade_alpha = max(0.0, 1.0 - (elapsed / self.PROGRESS_BAR_FADE_DURATION))
else: else:
fade_alpha = 1.0 fade_alpha = 1.0
height, width = frame.shape[:2] height, width = frame.shape[:2]
# Calculate progress bar position (top of frame with 5% margins) # Calculate progress bar position (top of frame with 5% margins)
margin_width = int(width * self.PROGRESS_BAR_MARGIN_PERCENT / 100) margin_width = int(width * self.PROGRESS_BAR_MARGIN_PERCENT / 100)
bar_width = width - (2 * margin_width) bar_width = width - (2 * margin_width)
bar_x = margin_width bar_x = margin_width
bar_y = self.PROGRESS_BAR_TOP_MARGIN bar_y = self.PROGRESS_BAR_TOP_MARGIN
# Apply fade alpha to colors # Apply fade alpha to colors
bg_color = tuple(int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_BG) bg_color = tuple(int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_BG)
border_color = tuple(int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_BORDER) border_color = tuple(
int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_BORDER
)
if self.progress_bar_complete: if self.progress_bar_complete:
fill_color = tuple(int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_FILL) fill_color = tuple(
int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_FILL
)
else: else:
fill_color = tuple(int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_PROGRESS) fill_color = tuple(
int(c * fade_alpha) for c in self.PROGRESS_BAR_COLOR_PROGRESS
)
# Draw background # Draw background
cv2.rectangle(frame, (bar_x, bar_y), (bar_x + bar_width, bar_y + self.PROGRESS_BAR_HEIGHT), bg_color, -1) cv2.rectangle(
frame,
(bar_x, bar_y),
(bar_x + bar_width, bar_y + self.PROGRESS_BAR_HEIGHT),
bg_color,
-1,
)
# Draw progress fill # Draw progress fill
fill_width = int(bar_width * self.progress_bar_progress) fill_width = int(bar_width * self.progress_bar_progress)
if fill_width > 0: if fill_width > 0:
cv2.rectangle(frame, (bar_x, bar_y), (bar_x + fill_width, bar_y + self.PROGRESS_BAR_HEIGHT), fill_color, -1) cv2.rectangle(
frame,
(bar_x, bar_y),
(bar_x + fill_width, bar_y + self.PROGRESS_BAR_HEIGHT),
fill_color,
-1,
)
# Draw border # Draw border
cv2.rectangle(frame, (bar_x, bar_y), (bar_x + bar_width, bar_y + self.PROGRESS_BAR_HEIGHT), border_color, 2) cv2.rectangle(
frame,
(bar_x, bar_y),
(bar_x + bar_width, bar_y + self.PROGRESS_BAR_HEIGHT),
border_color,
2,
)
# Draw progress percentage on the left # Draw progress percentage on the left
percentage_text = f"{self.progress_bar_progress * 100:.1f}%" percentage_text = f"{self.progress_bar_progress * 100:.1f}%"
text_color = tuple(int(255 * fade_alpha) for _ in range(3)) text_color = tuple(int(255 * fade_alpha) for _ in range(3))
cv2.putText(frame, percentage_text, (bar_x + 12, bar_y + 22), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 4) cv2.putText(
cv2.putText(frame, percentage_text, (bar_x + 10, bar_y + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 2) frame,
percentage_text,
(bar_x + 12, bar_y + 22),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0, 0),
4,
)
cv2.putText(
frame,
percentage_text,
(bar_x + 10, bar_y + 20),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
text_color,
2,
)
# Draw FPS on the right if available # Draw FPS on the right if available
if self.progress_bar_fps > 0: if self.progress_bar_fps > 0:
fps_text = f"{self.progress_bar_fps:.1f} FPS" fps_text = f"{self.progress_bar_fps:.1f} FPS"
fps_text_size = cv2.getTextSize(fps_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[0] fps_text_size = cv2.getTextSize(fps_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[
0
]
fps_x = bar_x + bar_width - fps_text_size[0] - 10 fps_x = bar_x + bar_width - fps_text_size[0] - 10
cv2.putText(frame, fps_text, (fps_x + 2, bar_y + 22), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 4) cv2.putText(
cv2.putText(frame, fps_text, (fps_x, bar_y + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 2) frame,
fps_text,
(fps_x + 2, bar_y + 22),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0, 0),
4,
)
cv2.putText(
frame,
fps_text,
(fps_x, bar_y + 20),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
text_color,
2,
)
# Draw main text in center # Draw main text in center
if self.progress_bar_text: if self.progress_bar_text:
text_size = cv2.getTextSize(self.progress_bar_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[0] text_size = cv2.getTextSize(
self.progress_bar_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1
)[0]
text_x = bar_x + (bar_width - text_size[0]) // 2 text_x = bar_x + (bar_width - text_size[0]) // 2
text_y = bar_y + 20 text_y = bar_y + 20
# Draw text shadow for better visibility # Draw text shadow for better visibility
cv2.putText(frame, self.progress_bar_text, (text_x + 2, text_y + 2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 4) cv2.putText(
cv2.putText(frame, self.progress_bar_text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 2) frame,
self.progress_bar_text,
(text_x + 2, text_y + 2),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0, 0),
4,
)
cv2.putText(
frame,
self.progress_bar_text,
(text_x, text_y),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
text_color,
2,
)
def draw_timeline(self, frame): def draw_timeline(self, frame):
"""Draw timeline at the bottom of the frame""" """Draw timeline at the bottom of the frame"""
@@ -941,7 +1032,7 @@ class VideoEditor:
# Update progress bar (10% to 95% of progress reserved for frame processing) # Update progress bar (10% to 95% of progress reserved for frame processing)
progress = 0.1 + (0.85 * (frames_written / total_output_frames)) progress = 0.1 + (0.85 * (frames_written / total_output_frames))
# Throttled progress update # Throttled progress update
if current_time - last_progress_update > 0.5: if current_time - last_progress_update > 0.5:
elapsed = current_time - start_time elapsed = current_time - start_time
@@ -949,10 +1040,10 @@ class VideoEditor:
eta = (elapsed / frames_written) * ( eta = (elapsed / frames_written) * (
total_output_frames - frames_written total_output_frames - frames_written
) )
progress_text = f"Rendering {frames_written}/{total_output_frames} frames (ETA: {eta:.1f}s)" progress_text = f"Rendering {frames_written}/{total_output_frames} frames (ETA: {eta:.1f}s)"
self.update_progress_bar(progress, progress_text, fps_rate) self.update_progress_bar(progress, progress_text, fps_rate)
print( print(
f"Progress: {progress*100:.1f}% | {frames_written}/{total_output_frames} | " f"Progress: {progress*100:.1f}% | {frames_written}/{total_output_frames} | "
f"FPS: {fps_rate:.1f} | ETA: {eta:.1f}s\r", f"FPS: {fps_rate:.1f} | ETA: {eta:.1f}s\r",
@@ -961,7 +1052,9 @@ class VideoEditor:
last_progress_update = current_time last_progress_update = current_time
# Update display more frequently to show progress bar # Update display more frequently to show progress bar
if current_time - last_display_update > 0.1: # Update display every 100ms if (
current_time - last_display_update > 0.1
): # Update display every 100ms
self.display_current_frame() self.display_current_frame()
cv2.waitKey(1) # Allow OpenCV to process events cv2.waitKey(1) # Allow OpenCV to process events
last_display_update = current_time last_display_update = current_time
@@ -973,7 +1066,11 @@ class VideoEditor:
avg_fps = total_frames_written / total_time if total_time > 0 else 0 avg_fps = total_frames_written / total_time if total_time > 0 else 0
# Complete the progress bar # Complete the progress bar
self.update_progress_bar(1.0, f"Complete! Rendered {total_frames_written} frames in {total_time:.1f}s", avg_fps) self.update_progress_bar(
1.0,
f"Complete! Rendered {total_frames_written} frames in {total_time:.1f}s",
avg_fps,
)
print(f"\nVideo rendered successfully to {output_path}") print(f"\nVideo rendered successfully to {output_path}")
print( print(