Files
tkinter_player/tkinter_app/src/media_playback_controller.py
2025-08-23 23:55:20 +03:00

147 lines
6.1 KiB
Python

import threading
import os
from logging_config import Logger
from PIL import Image, ImageTk
class MediaPlaybackController:
def __init__(self, app, ui):
self.app = app # Reference to SimpleMediaPlayerApp
self.ui = ui # Reference to PlayerUI
self.auto_advance_timer = None
self.current_index = 0
self.playlist = []
self.scaling_mode = 'fit'
def set_playlist(self, playlist):
self.playlist = playlist
self.current_index = 0
def play_current_media(self):
if not self.playlist or self.current_index >= len(self.playlist):
self.show_no_content_message()
return
media = self.playlist[self.current_index]
file_path = media.get('url', '')
file_name = media.get('file_name', '')
duration = media.get('duration', 10)
if file_path.startswith('static/resurse/'):
absolute_path = os.path.join(os.path.dirname(__file__), file_path)
file_path = absolute_path
Logger.info(f"Playing media: {file_name} from {file_path}")
self.log_event(file_name, "STARTED")
self.cancel_timers()
if file_path.startswith('text://'):
self.show_text_content(file_path[7:], duration)
elif file_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv')):
self.play_video(file_path)
elif os.path.exists(file_path) and file_path.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp')):
self.show_image(file_path, duration)
else:
Logger.error(f"Unsupported or missing media: {file_path}")
self.ui.status_label.config(text=f"Missing or unsupported media:\n{file_name}")
self.auto_advance_timer = self.ui.root.after(5000, self.next_media)
def play_video(self, file_path):
self.ui.status_label.place_forget()
def run_vlc_subprocess():
import subprocess
try:
Logger.info(f"Starting system VLC subprocess for video: {file_path}")
vlc_cmd = [
'cvlc',
'--fullscreen',
'--no-osd',
'--no-video-title-show',
'--play-and-exit',
'--quiet',
file_path
]
proc = subprocess.Popen(vlc_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
proc.wait()
Logger.info(f"VLC subprocess finished: {file_path}")
except Exception as e:
Logger.error(f"VLC subprocess error: {e}")
finally:
self.ui.root.after_idle(lambda: setattr(self, 'auto_advance_timer', self.ui.root.after(1000, self.next_media)))
threading.Thread(target=run_vlc_subprocess, daemon=True).start()
def show_image(self, file_path, duration):
try:
self.ui.status_label.place_forget()
self.ui.status_label.config(text="")
img = Image.open(file_path)
original_size = img.size
screen_width = self.ui.root.winfo_width()
screen_height = self.ui.root.winfo_height()
if screen_width <= 1 or screen_height <= 1:
screen_width = 1920
screen_height = 1080
final_img, offset = self.ui.scale_image_to_screen(img, screen_width, screen_height, self.scaling_mode)
photo = ImageTk.PhotoImage(final_img)
self.ui.image_label.config(image=photo)
self.ui.image_label.image = photo
Logger.info(f"Successfully displayed image: {os.path.basename(file_path)} "
f"(Original: {original_size}, Screen: {screen_width}x{screen_height}, "
f"Mode: {self.scaling_mode}, Offset: {offset})")
self.auto_advance_timer = self.ui.root.after(
int(duration * 1000),
self.next_media
)
except Exception as e:
Logger.error(f"Failed to show image {file_path}: {e}")
self.ui.image_label.config(image='')
self.ui.status_label.config(text=f"Image Error:\n{os.path.basename(file_path)}\n{str(e)}")
self.ui.status_label.place(relx=0.5, rely=0.5, anchor='center')
self.auto_advance_timer = self.ui.root.after(5000, self.next_media)
def show_text_content(self, text, duration):
self.ui.image_label.config(image='')
self.ui.status_label.config(text=text)
self.auto_advance_timer = self.ui.root.after(
int(duration * 1000),
self.next_media
)
def next_media(self):
self.cancel_timers()
if not self.playlist:
return
self.current_index = (self.current_index + 1) % len(self.playlist)
self.play_current_media()
def previous_media(self):
self.cancel_timers()
if not self.playlist:
return
self.current_index = (self.current_index - 1) % len(self.playlist)
self.play_current_media()
def toggle_play_pause(self):
self.app.is_paused = not self.app.is_paused
if self.app.is_paused:
self.ui.play_pause_btn.config(text="▶ Play")
self.cancel_timers()
else:
self.ui.play_pause_btn.config(text="⏸ Pause")
self.play_current_media()
Logger.info(f"Media {'paused' if self.app.is_paused else 'resumed'}")
def cancel_timers(self):
if self.auto_advance_timer:
self.ui.root.after_cancel(self.auto_advance_timer)
self.auto_advance_timer = None
def show_no_content_message(self):
self.ui.status_label.config(text="No content available.")
def log_event(self, file_name, event):
import datetime
try:
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_message = f"{timestamp} - {event}: {file_name}\n"
log_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'log.txt')
with open(log_file, 'a') as f:
f.write(log_message)
except Exception as e:
Logger.error(f"Failed to log event: {e}")