refactor(main.py): simplify seek logic, update imports and print statements; update pyproject.toml to include ruff as a dependency

This commit is contained in:
2025-09-07 23:09:54 +02:00
parent 366de8e796
commit 8a266303a5
3 changed files with 42 additions and 63 deletions

View File

@@ -4,7 +4,7 @@ import cv2
import argparse import argparse
import numpy as np import numpy as np
from pathlib import Path from pathlib import Path
from typing import Optional, Tuple, List from typing import List
import time import time
import re import re
import json import json
@@ -402,7 +402,7 @@ class VideoEditor:
self.cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY) self.cap.set(cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY)
break break
self.cap.release() self.cap.release()
except: except Exception:
continue continue
if not self.cap or not self.cap.isOpened(): if not self.cap or not self.cap.isOpened():
@@ -427,11 +427,11 @@ class VideoEditor:
# Performance warning for known problematic cases # Performance warning for known problematic cases
if codec in ['H264', 'H.264', 'AVC1', 'avc1'] and self.total_frames > 10000: if codec in ['H264', 'H.264', 'AVC1', 'avc1'] and self.total_frames > 10000:
print(f" Warning: Large H.264 video detected - seeking may be slow") print(" Warning: Large H.264 video detected - seeking may be slow")
if self.frame_width * self.frame_height > 1920 * 1080: if self.frame_width * self.frame_height > 1920 * 1080:
print(f" Warning: High resolution video - decoding may be slow") print(" Warning: High resolution video - decoding may be slow")
if self.fps > 60: if self.fps > 60:
print(f" Warning: High framerate video - may impact playback smoothness") print(" Warning: High framerate video - may impact playback smoothness")
# Reset playback state for new media # Reset playback state for new media
self.current_frame = 0 self.current_frame = 0
@@ -500,55 +500,6 @@ class VideoEditor:
self.current_frame = target_frame self.current_frame = target_frame
self.load_current_frame() self.load_current_frame()
def seek_video_smart(self, frames_delta: int):
"""Seek using keyframe jumping for large jumps"""
target_frame = max(
0, min(self.current_frame + frames_delta, self.total_frames - 1)
)
# For small jumps, use regular seeking
if abs(frames_delta) <= 10:
self.current_frame = target_frame
self.load_current_frame()
return
# For larger jumps, use keyframe seeking
# Jump to nearest keyframe first, then seek forward
keyframe_interval = self._detect_keyframe_interval()
nearest_keyframe = (target_frame // keyframe_interval) * keyframe_interval
# Seek to keyframe first
self.cap.set(cv2.CAP_PROP_POS_FRAMES, nearest_keyframe)
self.current_frame = nearest_keyframe
# Then seek forward to target frame
frames_to_seek = target_frame - nearest_keyframe
for _ in range(frames_to_seek):
ret, frame = self.cap.read()
if not ret:
break
self.current_frame += 1
self.current_display_frame = frame if 'frame' in locals() else None
def _detect_keyframe_interval(self):
"""Detect the keyframe interval for the current video"""
# Try to get keyframe interval from video properties
try:
# Some backends support keyframe interval detection
keyframe_interval = self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.cap.get(cv2.CAP_PROP_FPS)
if keyframe_interval > 0:
return int(keyframe_interval)
except:
pass
# Fallback: estimate based on video characteristics
if self.fps >= 60:
return 60 # High FPS videos often have keyframes every 60 frames
elif self.fps >= 30:
return 30 # Standard videos have keyframes every 30 frames
else:
return 15 # Lower FPS videos have keyframes every 15 frames
def seek_video_with_modifier( def seek_video_with_modifier(
self, direction: int, shift_pressed: bool, ctrl_pressed: bool self, direction: int, shift_pressed: bool, ctrl_pressed: bool
@@ -556,13 +507,12 @@ class VideoEditor:
"""Seek video with different frame counts based on modifiers""" """Seek video with different frame counts based on modifiers"""
if ctrl_pressed: if ctrl_pressed:
frames = direction * 60 # Ctrl: 60 frames frames = direction * 60 # Ctrl: 60 frames
self.seek_video_smart(frames)
elif shift_pressed: elif shift_pressed:
frames = direction * 10 # Shift: 10 frames frames = direction * 10 # Shift: 10 frames
self.seek_video_smart(frames)
else: else:
frames = direction * 1 # Default: 1 frame frames = direction * 1 # Default: 1 frame
self.seek_video(frames)
self.seek_video(frames)
def start_auto_repeat_seek(self, key: int, direction: int, shift_pressed: bool, ctrl_pressed: bool): def start_auto_repeat_seek(self, key: int, direction: int, shift_pressed: bool, ctrl_pressed: bool):
"""Start auto-repeat seeking for a held key""" """Start auto-repeat seeking for a held key"""
@@ -1296,7 +1246,6 @@ class VideoEditor:
# Handle crop selection (Shift + click and drag) # Handle crop selection (Shift + click and drag)
if flags & cv2.EVENT_FLAG_SHIFTKEY: if flags & cv2.EVENT_FLAG_SHIFTKEY:
available_height = self.window_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT)
if event == cv2.EVENT_LBUTTONDOWN: if event == cv2.EVENT_LBUTTONDOWN:
self.crop_selecting = True self.crop_selecting = True
@@ -1888,7 +1837,6 @@ class VideoEditor:
# Get modifier key states # Get modifier key states
window_title = "Image Editor" if self.is_image_mode else "Video Editor" window_title = "Image Editor" if self.is_image_mode else "Video Editor"
modifiers = cv2.getWindowProperty(window_title, cv2.WND_PROP_AUTOSIZE)
# Note: OpenCV doesn't provide direct access to modifier keys in waitKey # Note: OpenCV doesn't provide direct access to modifier keys in waitKey
# We'll handle this through special key combinations # We'll handle this through special key combinations
@@ -2008,7 +1956,7 @@ class VideoEditor:
temp_fd, temp_path = tempfile.mkstemp(suffix=self.video_path.suffix, dir=temp_dir) temp_fd, temp_path = tempfile.mkstemp(suffix=self.video_path.suffix, dir=temp_dir)
os.close(temp_fd) # Close the file descriptor, we just need the path os.close(temp_fd) # Close the file descriptor, we just need the path
print(f"Rendering to temporary file first...") print("Rendering to temporary file first...")
success = self.render_video(temp_path) success = self.render_video(temp_path)
if success: if success:
@@ -2092,9 +2040,9 @@ def main():
try: try:
args = parser.parse_args() args = parser.parse_args()
except SystemExit as e: except SystemExit:
# If launched from context menu without arguments, this might fail # If launched from context menu without arguments, this might fail
input(f"Argument parsing failed. Press Enter to exit...") input("Argument parsing failed. Press Enter to exit...")
return return
if not os.path.exists(args.media): if not os.path.exists(args.media):

View File

@@ -5,6 +5,7 @@ description = "Media Grader - Grade media files by moving them to numbered folde
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"opencv-python>=4.12.0.88", "opencv-python>=4.12.0.88",
"ruff>=0.12.12",
] ]
[project.scripts] [project.scripts]

32
uv.lock generated
View File

@@ -29,10 +29,14 @@ version = "0.1.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "opencv-python" }, { name = "opencv-python" },
{ name = "ruff" },
] ]
[package.metadata] [package.metadata]
requires-dist = [{ name = "opencv-python", specifier = ">=4.12.0.88" }] requires-dist = [
{ name = "opencv-python", specifier = ">=4.12.0.88" },
{ name = "ruff", specifier = ">=0.12.12" },
]
[[package]] [[package]]
name = "numpy" name = "numpy"
@@ -78,3 +82,29 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" }, { url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" },
{ url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" }, { url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" },
] ]
[[package]]
name = "ruff"
version = "0.12.12"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a8/f0/e0965dd709b8cabe6356811c0ee8c096806bb57d20b5019eb4e48a117410/ruff-0.12.12.tar.gz", hash = "sha256:b86cd3415dbe31b3b46a71c598f4c4b2f550346d1ccf6326b347cc0c8fd063d6", size = 5359915, upload-time = "2025-09-04T16:50:18.273Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/09/79/8d3d687224d88367b51c7974cec1040c4b015772bfbeffac95face14c04a/ruff-0.12.12-py3-none-linux_armv6l.whl", hash = "sha256:de1c4b916d98ab289818e55ce481e2cacfaad7710b01d1f990c497edf217dafc", size = 12116602, upload-time = "2025-09-04T16:49:18.892Z" },
{ url = "https://files.pythonhosted.org/packages/c3/c3/6e599657fe192462f94861a09aae935b869aea8a1da07f47d6eae471397c/ruff-0.12.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7acd6045e87fac75a0b0cdedacf9ab3e1ad9d929d149785903cff9bb69ad9727", size = 12868393, upload-time = "2025-09-04T16:49:23.043Z" },
{ url = "https://files.pythonhosted.org/packages/e8/d2/9e3e40d399abc95336b1843f52fc0daaceb672d0e3c9290a28ff1a96f79d/ruff-0.12.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:abf4073688d7d6da16611f2f126be86523a8ec4343d15d276c614bda8ec44edb", size = 12036967, upload-time = "2025-09-04T16:49:26.04Z" },
{ url = "https://files.pythonhosted.org/packages/e9/03/6816b2ed08836be272e87107d905f0908be5b4a40c14bfc91043e76631b8/ruff-0.12.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:968e77094b1d7a576992ac078557d1439df678a34c6fe02fd979f973af167577", size = 12276038, upload-time = "2025-09-04T16:49:29.056Z" },
{ url = "https://files.pythonhosted.org/packages/9f/d5/707b92a61310edf358a389477eabd8af68f375c0ef858194be97ca5b6069/ruff-0.12.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42a67d16e5b1ffc6d21c5f67851e0e769517fb57a8ebad1d0781b30888aa704e", size = 11901110, upload-time = "2025-09-04T16:49:32.07Z" },
{ url = "https://files.pythonhosted.org/packages/9d/3d/f8b1038f4b9822e26ec3d5b49cf2bc313e3c1564cceb4c1a42820bf74853/ruff-0.12.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b216ec0a0674e4b1214dcc998a5088e54eaf39417327b19ffefba1c4a1e4971e", size = 13668352, upload-time = "2025-09-04T16:49:35.148Z" },
{ url = "https://files.pythonhosted.org/packages/98/0e/91421368ae6c4f3765dd41a150f760c5f725516028a6be30e58255e3c668/ruff-0.12.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:59f909c0fdd8f1dcdbfed0b9569b8bf428cf144bec87d9de298dcd4723f5bee8", size = 14638365, upload-time = "2025-09-04T16:49:38.892Z" },
{ url = "https://files.pythonhosted.org/packages/74/5d/88f3f06a142f58ecc8ecb0c2fe0b82343e2a2b04dcd098809f717cf74b6c/ruff-0.12.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ac93d87047e765336f0c18eacad51dad0c1c33c9df7484c40f98e1d773876f5", size = 14060812, upload-time = "2025-09-04T16:49:42.732Z" },
{ url = "https://files.pythonhosted.org/packages/13/fc/8962e7ddd2e81863d5c92400820f650b86f97ff919c59836fbc4c1a6d84c/ruff-0.12.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01543c137fd3650d322922e8b14cc133b8ea734617c4891c5a9fccf4bfc9aa92", size = 13050208, upload-time = "2025-09-04T16:49:46.434Z" },
{ url = "https://files.pythonhosted.org/packages/53/06/8deb52d48a9a624fd37390555d9589e719eac568c020b27e96eed671f25f/ruff-0.12.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afc2fa864197634e549d87fb1e7b6feb01df0a80fd510d6489e1ce8c0b1cc45", size = 13311444, upload-time = "2025-09-04T16:49:49.931Z" },
{ url = "https://files.pythonhosted.org/packages/2a/81/de5a29af7eb8f341f8140867ffb93f82e4fde7256dadee79016ac87c2716/ruff-0.12.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0c0945246f5ad776cb8925e36af2438e66188d2b57d9cf2eed2c382c58b371e5", size = 13279474, upload-time = "2025-09-04T16:49:53.465Z" },
{ url = "https://files.pythonhosted.org/packages/7f/14/d9577fdeaf791737ada1b4f5c6b59c21c3326f3f683229096cccd7674e0c/ruff-0.12.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0fbafe8c58e37aae28b84a80ba1817f2ea552e9450156018a478bf1fa80f4e4", size = 12070204, upload-time = "2025-09-04T16:49:56.882Z" },
{ url = "https://files.pythonhosted.org/packages/77/04/a910078284b47fad54506dc0af13839c418ff704e341c176f64e1127e461/ruff-0.12.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b9c456fb2fc8e1282affa932c9e40f5ec31ec9cbb66751a316bd131273b57c23", size = 11880347, upload-time = "2025-09-04T16:49:59.729Z" },
{ url = "https://files.pythonhosted.org/packages/df/58/30185fcb0e89f05e7ea82e5817b47798f7fa7179863f9d9ba6fd4fe1b098/ruff-0.12.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f12856123b0ad0147d90b3961f5c90e7427f9acd4b40050705499c98983f489", size = 12891844, upload-time = "2025-09-04T16:50:02.591Z" },
{ url = "https://files.pythonhosted.org/packages/21/9c/28a8dacce4855e6703dcb8cdf6c1705d0b23dd01d60150786cd55aa93b16/ruff-0.12.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:26a1b5a2bf7dd2c47e3b46d077cd9c0fc3b93e6c6cc9ed750bd312ae9dc302ee", size = 13360687, upload-time = "2025-09-04T16:50:05.8Z" },
{ url = "https://files.pythonhosted.org/packages/c8/fa/05b6428a008e60f79546c943e54068316f32ec8ab5c4f73e4563934fbdc7/ruff-0.12.12-py3-none-win32.whl", hash = "sha256:173be2bfc142af07a01e3a759aba6f7791aa47acf3604f610b1c36db888df7b1", size = 12052870, upload-time = "2025-09-04T16:50:09.121Z" },
{ url = "https://files.pythonhosted.org/packages/85/60/d1e335417804df452589271818749d061b22772b87efda88354cf35cdb7a/ruff-0.12.12-py3-none-win_amd64.whl", hash = "sha256:e99620bf01884e5f38611934c09dd194eb665b0109104acae3ba6102b600fd0d", size = 13178016, upload-time = "2025-09-04T16:50:12.559Z" },
{ url = "https://files.pythonhosted.org/packages/28/7e/61c42657f6e4614a4258f1c3b0c5b93adc4d1f8575f5229d1906b483099b/ruff-0.12.12-py3-none-win_arm64.whl", hash = "sha256:2a8199cab4ce4d72d158319b63370abf60991495fb733db96cd923a34c52d093", size = 12256762, upload-time = "2025-09-04T16:50:15.737Z" },
]