diff --git a/croppa/main.py b/croppa/main.py index 3eb4954..010b798 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -145,6 +145,7 @@ class VideoEditor: """Save current editor state to JSON file""" state_file = self._get_state_file_path() if not state_file: + print("No state file path available") return False try: @@ -167,6 +168,7 @@ class VideoEditor: with open(state_file, 'w') as f: json.dump(state, f, indent=2) + print(f"State saved to {state_file}") return True except Exception as e: print(f"Error saving state: {e}") @@ -486,7 +488,6 @@ class VideoEditor: ) self.current_frame = target_frame self.load_current_frame() - self.save_state() def seek_video_with_modifier( @@ -544,7 +545,6 @@ class VideoEditor: """Seek to specific frame""" self.current_frame = max(0, min(frame_number, self.total_frames - 1)) self.load_current_frame() - self.save_state() def advance_frame(self) -> bool: """Advance to next frame - optimized to avoid seeking, handles playback speed""" @@ -564,13 +564,11 @@ class VideoEditor: new_frame = self.cut_start_frame self.current_frame = new_frame self.load_current_frame() - self.save_state() return True elif new_frame >= self.total_frames: new_frame = 0 # Loop - this will require a seek self.current_frame = new_frame self.load_current_frame() - self.save_state() return True # For sequential playback at normal speed, just read the next frame without seeking @@ -579,7 +577,6 @@ class VideoEditor: if ret: self.current_frame = new_frame self.current_display_frame = frame - self.save_state() return True else: @@ -589,7 +586,6 @@ class VideoEditor: self.total_frames = self.current_frame self.current_frame = 0 # Loop back to start self.load_current_frame() - self.save_state() return True else: # For speed > 1.0, we need to seek to skip frames @@ -604,7 +600,6 @@ class VideoEditor: else: self.current_frame = 0 # Loop back to start self.load_current_frame() - self.save_state() return True # Handle marker looping after successful frame load @@ -612,10 +607,8 @@ class VideoEditor: if self.current_frame >= self.cut_end_frame: self.current_frame = self.cut_start_frame self.load_current_frame() - self.save_state() return True - self.save_state() return success def apply_crop_zoom_and_rotation(self, frame): @@ -680,7 +673,6 @@ class VideoEditor: def rotate_clockwise(self): """Rotate video 90 degrees clockwise""" self.rotation_angle = (self.rotation_angle + 90) % 360 - self.save_state() def apply_brightness_contrast(self, frame): """Apply brightness and contrast adjustments to frame""" @@ -699,12 +691,10 @@ class VideoEditor: def adjust_brightness(self, delta: int): """Adjust brightness by delta (-100 to 100)""" self.brightness = max(-100, min(100, self.brightness + delta)) - self.save_state() def adjust_contrast(self, delta: float): """Adjust contrast by delta (0.1 to 3.0)""" self.contrast = max(0.1, min(3.0, self.contrast + delta)) - self.save_state() def show_progress_bar(self, text: str = "Processing..."): """Show progress bar with given text""" @@ -1234,7 +1224,6 @@ class VideoEditor: # Handle zoom center (Ctrl + click) if flags & cv2.EVENT_FLAG_CTRLKEY and event == cv2.EVENT_LBUTTONDOWN: self.zoom_center = (x, y) - self.save_state() # Handle scroll wheel for zoom (Ctrl + scroll) if flags & cv2.EVENT_FLAG_CTRLKEY: @@ -1247,7 +1236,6 @@ class VideoEditor: self.zoom_factor = max( self.MIN_ZOOM, self.zoom_factor - self.ZOOM_INCREMENT ) - self.save_state() def set_crop_from_screen_coords(self, screen_rect): """Convert screen coordinates to video frame coordinates and set crop""" @@ -1367,7 +1355,6 @@ class VideoEditor: if self.crop_rect: self.crop_history.append(self.crop_rect) self.crop_rect = (original_x, original_y, original_w, original_h) - self.save_state() def seek_to_timeline_position(self, mouse_x, bar_x_start, bar_width): """Seek to position based on mouse click on timeline""" @@ -1382,7 +1369,6 @@ class VideoEditor: self.crop_rect = self.crop_history.pop() else: self.crop_rect = None - self.save_state() def toggle_marker_looping(self): """Toggle looping between cut markers""" @@ -1438,26 +1424,22 @@ class VideoEditor: new_y = max(0, y - amount) new_h = h + (y - new_y) self.crop_rect = (x, new_y, w, new_h) - self.save_state() else: # Contract from bottom - decrease height new_h = max(10, h - amount) # Minimum size of 10 pixels self.crop_rect = (x, y, w, new_h) - self.save_state() elif direction == 'down': if expand: # Expand downward - increase height new_h = min(self.frame_height - y, h + amount) self.crop_rect = (x, y, w, new_h) - self.save_state() else: # Contract from top - increase y, decrease height amount = min(amount, h - 10) # Don't make it smaller than 10 pixels new_y = y + amount new_h = h - amount self.crop_rect = (x, new_y, w, new_h) - self.save_state() elif direction == 'left': if expand: @@ -1465,26 +1447,22 @@ class VideoEditor: new_x = max(0, x - amount) new_w = w + (x - new_x) self.crop_rect = (new_x, y, new_w, h) - self.save_state() else: # Contract from right - decrease width new_w = max(10, w - amount) # Minimum size of 10 pixels self.crop_rect = (x, y, new_w, h) - self.save_state() elif direction == 'right': if expand: # Expand rightward - increase width new_w = min(self.frame_width - x, w + amount) self.crop_rect = (x, y, new_w, h) - self.save_state() else: # Contract from left - increase x, decrease width amount = min(amount, w - 10) # Don't make it smaller than 10 pixels new_x = x + amount new_w = w - amount self.crop_rect = (new_x, y, new_w, h) - self.save_state() def render_video(self, output_path: str): """Render video or save image with current edits applied""" @@ -1797,13 +1775,13 @@ class VideoEditor: if key == ord("q") or key == 27: # ESC self.stop_auto_repeat_seek() + self.save_state() break elif key == ord(" "): # Don't allow play/pause for images if not self.is_image_mode: self.stop_auto_repeat_seek() # Stop seeking when toggling play/pause self.is_playing = not self.is_playing - self.save_state() elif key == ord("a") or key == ord("A"): # Seeking only for videos if not self.is_image_mode: @@ -1845,14 +1823,12 @@ class VideoEditor: self.playback_speed = min( self.MAX_PLAYBACK_SPEED, self.playback_speed + self.SPEED_INCREMENT ) - self.save_state() elif key == ord("S"): # Speed control only for videos if not self.is_image_mode: self.playback_speed = max( self.MIN_PLAYBACK_SPEED, self.playback_speed - self.SPEED_INCREMENT ) - self.save_state() elif key == ord("e") or key == ord("E"): # Brightness adjustment: E (increase), Shift+E (decrease) if key == ord("E"): @@ -1875,19 +1851,16 @@ class VideoEditor: if self.crop_rect: self.crop_history.append(self.crop_rect) self.crop_rect = None - self.save_state() elif key == ord("1"): # Cut markers only for videos if not self.is_image_mode: self.cut_start_frame = self.current_frame print(f"Set cut start at frame {self.current_frame}") - self.save_state() elif key == ord("2"): # Cut markers only for videos if not self.is_image_mode: self.cut_end_frame = self.current_frame print(f"Set cut end at frame {self.current_frame}") - self.save_state() elif key == ord("N"): if len(self.video_files) > 1: self.previous_video() @@ -1939,7 +1912,6 @@ class VideoEditor: # Marker looping only for videos if not self.is_image_mode: self.toggle_marker_looping() - self.save_state() # Individual direction controls using shift combinations we can detect elif key == ord("J"): # Shift+i - expand up @@ -1974,6 +1946,7 @@ class VideoEditor: if self.is_playing and not self.is_image_mode: self.advance_frame() + self.save_state() if hasattr(self, 'cap') and self.cap: self.cap.release() cv2.destroyAllWindows()