Fix syntax and indentation errors in tkinter_simple_player.py, improve stability of settings UI and video playback
This commit is contained in:
@@ -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'])
|
||||
|
||||
Reference in New Issue
Block a user