Fix syntax and indentation errors in tkinter_simple_player.py, improve stability of settings UI and video playback

This commit is contained in:
2025-08-22 11:12:42 +01:00
parent e9cb256529
commit b4956607d3
6 changed files with 124 additions and 106 deletions

View File

@@ -533,88 +533,34 @@ class SimpleMediaPlayerApp:
self.auto_advance_timer = self.root.after(5000, self.next_media)
def play_video(self, file_path):
"""Play video file"""
# Clear any status text and hide status label
"""Play video file using python-vlc-wrapper for robust hardware acceleration."""
self.status_label.place_forget()
# Check if PIL is available for video playback
if not PIL_AVAILABLE:
Logger.error("PIL not available - cannot play video")
self.status_label.config(text="PIL/Pillow not available\nCannot play video files")
self.status_label.place(relx=0.5, rely=0.5, anchor='center')
self.auto_advance_timer = self.root.after(5000, self.next_media)
return
# Use OpenCV to play video in a separate thread
def video_player():
def run_vlc():
try:
cap = cv2.VideoCapture(file_path)
if not cap.isOpened():
raise ValueError(f"Cannot open video file: {file_path}")
# Get video properties
fps = cap.get(cv2.CAP_PROP_FPS)
delay = int(1000 / fps) if fps > 0 else 30 # Default to 30 FPS if unknown
# Get video dimensions
video_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
video_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Get screen dimensions
screen_width = self.root.winfo_width()
screen_height = self.root.winfo_height()
# Ensure we have valid screen dimensions
if screen_width <= 1 or screen_height <= 1:
screen_width = 1920 # Default fallback
screen_height = 1080
Logger.info(f"Video dimensions: {video_width}x{video_height}, "
f"Screen dimensions: {screen_width}x{screen_height}")
while self.current_index < len(self.playlist) and not self.is_paused and self.running:
ret, frame = cap.read()
if not ret:
break # End of video
# Convert color from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Convert to PIL Image for better scaling
try:
img = Image.fromarray(frame)
# Scale video frame using the scaling helper
final_img, offset = self.scale_image_to_screen(img, screen_width, screen_height, self.scaling_mode)
# Convert to PhotoImage
photo = ImageTk.PhotoImage(final_img)
# Update UI from main thread
self.root.after_idle(lambda p=photo: self._update_video_frame(p))
except Exception as img_error:
Logger.error(f"Video frame processing error: {img_error}")
Logger.info(f"Starting VLC for video: {file_path}")
import vlc
instance = vlc.Instance('--no-osd', '--no-video-title-show', '--intf', 'dummy', '--no-video-deco', '--no-embedded-video', '--quiet')
player = instance.media_player_new()
media = instance.media_new(file_path)
player.set_media(media)
player.play()
time.sleep(0.5)
try:
player.set_fullscreen(True)
except Exception as e:
Logger.warning(f"Could not set VLC fullscreen: {e}")
while True:
state = player.get_state()
if state in [vlc.State.Ended, vlc.State.Error, vlc.State.Stopped]:
break
# Wait for the next frame
time.sleep(delay / 1000)
cap.release()
# Schedule next media from main thread
self.root.after_idle(lambda: setattr(self, 'auto_advance_timer',
self.root.after(1000, self.next_media)))
time.sleep(0.5)
player.stop()
Logger.info(f"VLC finished: {file_path}")
except Exception as e:
Logger.error(f"Error playing video {file_path}: {e}")
# Show error from main thread
self.root.after_idle(lambda: self._show_video_error(str(e)))
# Start video player thread
threading.Thread(target=video_player, daemon=True).start()
Logger.error(f"VLC error: {e}")
finally:
self.root.after_idle(lambda: setattr(self, 'auto_advance_timer', self.root.after(1000, self.next_media)))
threading.Thread(target=run_vlc, daemon=True).start()
def _update_video_frame(self, photo):
"""Update video frame from main thread"""
@@ -1095,41 +1041,36 @@ class SettingsWindow:
# Configure enhanced custom styles
style = ttk.Style()
style.theme_use('clam')
# Enhanced dark theme styles
style.configure('Dark.TNotebook',
background=self.colors['bg_secondary'],
borderwidth=0,
tabmargins=[2, 5, 2, 0])
background=self.colors['bg_secondary'],
borderwidth=0,
tabmargins=[2, 5, 2, 0])
style.configure('Dark.TNotebook.Tab',
padding=[20, 12],
font=('Segoe UI', 11, 'bold'),
background=self.colors['bg_tertiary'],
foreground=self.colors['text_secondary'],
borderwidth=1,
focuscolor='none')
padding=[20, 12],
font=('Segoe UI', 11, 'bold'),
background=self.colors['bg_tertiary'],
foreground=self.colors['text_secondary'],
borderwidth=1,
focuscolor='none')
style.map('Dark.TNotebook.Tab',
background=[('selected', self.colors['accent']),
('active', self.colors['accent_hover'])],
foreground=[('selected', self.colors['text_primary']),
('active', self.colors['text_primary'])])
background=[('selected', self.colors['accent']),
('active', self.colors['accent_hover'])],
foreground=[('selected', self.colors['text_primary']),
('active', self.colors['text_primary'])])
style.configure('Dark.TFrame', background=self.colors['bg_secondary'])
style.configure('Dark.TLabel',
background=self.colors['bg_secondary'],
foreground=self.colors['text_primary'],
font=('Segoe UI', 10))
background=self.colors['bg_secondary'],
foreground=self.colors['text_primary'],
font=('Segoe UI', 10))
style.configure('Dark.TEntry',
fieldbackground=self.colors['bg_tertiary'],
foreground=self.colors['text_primary'],
bordercolor=self.colors['border'],
lightcolor=self.colors['bg_tertiary'],
darkcolor=self.colors['bg_tertiary'],
font=('Segoe UI', 10),
insertcolor=self.colors['text_primary'])
fieldbackground=self.colors['bg_tertiary'],
foreground=self.colors['text_primary'],
bordercolor=self.colors['border'],
lightcolor=self.colors['bg_tertiary'],
darkcolor=self.colors['bg_tertiary'],
font=('Segoe UI', 10),
insertcolor=self.colors['text_primary'])
# Main container frame
main_frame = tk.Frame(self.window, bg=self.colors['bg_primary'])