664 lines
26 KiB
Python
664 lines
26 KiB
Python
# debug_console.py - Enhanced with Folder Reset button
|
|
import tkinter as tk
|
|
from tkinter import ttk, scrolledtext, messagebox
|
|
import threading
|
|
import time
|
|
import logging
|
|
from datetime import datetime
|
|
from collections import deque
|
|
import sys
|
|
|
|
class EnhancedDebugConsole:
|
|
def __init__(self):
|
|
self.root = tk.Tk()
|
|
self.text_widget = None
|
|
self.running = False
|
|
self.logger = logging.getLogger(__name__)
|
|
self.video_player = None
|
|
self.message_queue = deque(maxlen=1000)
|
|
self.lock = threading.Lock()
|
|
self.nfc_buffer = ""
|
|
self.nfc_timeout = 0.3
|
|
self.last_nfc_input = 0
|
|
|
|
# Global input capture
|
|
self.global_listener = None
|
|
self.global_input_method = None
|
|
self.global_input_active = False
|
|
|
|
# Track mute state
|
|
self.is_muted = False
|
|
|
|
self.stats = {
|
|
'videos_played': 0,
|
|
'key_presses': 0,
|
|
'errors': 0,
|
|
'start_time': datetime.now(),
|
|
'queue_depth': 0,
|
|
'current_video': 'None',
|
|
'fullscreen': True,
|
|
'folder_videos_played': 0 # New stat for folder videos
|
|
}
|
|
|
|
self.setup_gui()
|
|
self.setup_global_input_capture()
|
|
self.log("Enhanced debug console initialized with folder support")
|
|
|
|
def setup_global_input_capture(self):
|
|
"""Setup global keyboard capture"""
|
|
if self.try_pynput_global_capture():
|
|
return
|
|
if sys.platform == "win32" and self.try_windows_global_capture():
|
|
return
|
|
if sys.platform.startswith('linux') and self.try_linux_global_capture():
|
|
return
|
|
|
|
self.log("Warning: Global input capture not available")
|
|
|
|
def try_pynput_global_capture(self):
|
|
"""Try pynput global keyboard listener"""
|
|
try:
|
|
from pynput import keyboard
|
|
|
|
def on_key_press(key):
|
|
try:
|
|
current_time = time.time()
|
|
|
|
if key == keyboard.Key.enter:
|
|
if self.nfc_buffer:
|
|
self.log(f"Global NFC input: {self.nfc_buffer}")
|
|
self.process_global_nfc_input(self.nfc_buffer.strip())
|
|
self.nfc_buffer = ""
|
|
return
|
|
|
|
if hasattr(key, 'char') and key.char and key.char.isdigit():
|
|
if current_time - self.last_nfc_input > self.nfc_timeout:
|
|
self.nfc_buffer = ""
|
|
|
|
self.nfc_buffer += key.char
|
|
self.last_nfc_input = current_time
|
|
|
|
except Exception as e:
|
|
self.logger.debug(f"Global key press error: {e}")
|
|
|
|
self.global_listener = keyboard.Listener(on_press=on_key_press)
|
|
self.global_listener.start()
|
|
|
|
self.global_input_method = "pynput"
|
|
self.global_input_active = True
|
|
self.log("Global input capture active (pynput)")
|
|
return True
|
|
|
|
except ImportError:
|
|
return False
|
|
except Exception as e:
|
|
self.logger.debug(f"pynput setup failed: {e}")
|
|
return False
|
|
|
|
def try_windows_global_capture(self):
|
|
"""Windows-specific global keyboard hook"""
|
|
try:
|
|
import win32api
|
|
import win32con
|
|
import win32gui
|
|
|
|
def low_level_keyboard_proc(nCode, wParam, lParam):
|
|
try:
|
|
if nCode >= 0 and wParam == win32con.WM_KEYDOWN:
|
|
vk_code = lParam[0]
|
|
current_time = time.time()
|
|
|
|
if vk_code == 13: # Enter
|
|
if self.nfc_buffer:
|
|
self.log(f"Global NFC input: {self.nfc_buffer}")
|
|
self.process_global_nfc_input(self.nfc_buffer.strip())
|
|
self.nfc_buffer = ""
|
|
|
|
elif 48 <= vk_code <= 57: # 0-9
|
|
if current_time - self.last_nfc_input > self.nfc_timeout:
|
|
self.nfc_buffer = ""
|
|
|
|
digit = chr(vk_code)
|
|
self.nfc_buffer += digit
|
|
self.last_nfc_input = current_time
|
|
|
|
except Exception as e:
|
|
self.logger.debug(f"Windows hook error: {e}")
|
|
|
|
return win32gui.CallNextHookEx(None, nCode, wParam, lParam)
|
|
|
|
hook = win32gui.SetWindowsHookEx(
|
|
win32con.WH_KEYBOARD_LL,
|
|
low_level_keyboard_proc,
|
|
win32api.GetModuleHandle(None),
|
|
0
|
|
)
|
|
|
|
if hook:
|
|
self.global_listener = hook
|
|
self.global_input_method = "windows"
|
|
self.global_input_active = True
|
|
self.log("Global input capture active (Windows)")
|
|
return True
|
|
|
|
except ImportError:
|
|
return False
|
|
except Exception as e:
|
|
self.logger.debug(f"Windows hook setup failed: {e}")
|
|
return False
|
|
|
|
return False
|
|
|
|
def try_linux_global_capture(self):
|
|
"""Linux-specific global keyboard listener"""
|
|
# Implementation same as original
|
|
return False
|
|
|
|
def process_global_nfc_input(self, nfc_id):
|
|
"""Process NFC input captured globally"""
|
|
if not nfc_id:
|
|
return
|
|
|
|
try:
|
|
if hasattr(self, 'nfc_entry'):
|
|
self.nfc_entry.delete(0, tk.END)
|
|
self.nfc_entry.insert(0, nfc_id)
|
|
except:
|
|
pass
|
|
|
|
self.process_nfc_input(nfc_id)
|
|
|
|
def setup_gui(self):
|
|
"""Setup GUI with folder reset button"""
|
|
self.root.title("Video Player Controller (Enhanced with Folder Support)")
|
|
self.root.geometry("900x700")
|
|
|
|
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
|
|
|
try:
|
|
self.root.state('zoomed')
|
|
except:
|
|
self.root.geometry("{0}x{1}+0+0".format(
|
|
self.root.winfo_screenwidth()//2,
|
|
self.root.winfo_screenheight()
|
|
))
|
|
|
|
main_frame = ttk.Frame(self.root, padding="10")
|
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# Enhanced controls
|
|
control_frame = ttk.LabelFrame(main_frame, text="Controls", padding="10")
|
|
control_frame.pack(fill=tk.X)
|
|
|
|
# Primary controls row
|
|
controls_row1 = ttk.Frame(control_frame)
|
|
controls_row1.pack(fill=tk.X, pady=(0, 5))
|
|
|
|
ttk.Button(controls_row1, text="Skip Video", command=self.skip_video).pack(side=tk.LEFT, padx=5)
|
|
ttk.Button(controls_row1, text="Toggle Fullscreen", command=self.toggle_fullscreen).pack(side=tk.LEFT, padx=5)
|
|
|
|
# Mute/Unmute button
|
|
self.mute_button = ttk.Button(controls_row1, text="Mute", command=self.toggle_mute)
|
|
self.mute_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
# NEW: Folder Reset Button
|
|
reset_button = ttk.Button(
|
|
controls_row1,
|
|
text="🔄 Reset Folder Sequences",
|
|
command=self.reset_folder_sequences
|
|
)
|
|
reset_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
# Global input status
|
|
self.global_input_label = ttk.Label(controls_row1, text="Global Input: Checking...", foreground="orange")
|
|
self.global_input_label.pack(side=tk.LEFT, padx=20)
|
|
|
|
# Exit button
|
|
exit_button = ttk.Button(controls_row1, text="Exit Application", command=self.exit_application)
|
|
exit_button.pack(side=tk.RIGHT, padx=5)
|
|
|
|
# Secondary controls row
|
|
controls_row2 = ttk.Frame(control_frame)
|
|
controls_row2.pack(fill=tk.X, pady=(5, 0))
|
|
|
|
ttk.Button(controls_row2, text="Clear Log", command=self.clear_log).pack(side=tk.LEFT, padx=5)
|
|
|
|
# Manual NFC input
|
|
ttk.Label(controls_row2, text="NFC Test:").pack(side=tk.LEFT, padx=(20, 5))
|
|
self.nfc_entry = ttk.Entry(controls_row2, width=15)
|
|
self.nfc_entry.pack(side=tk.LEFT, padx=5)
|
|
self.nfc_entry.bind('<Return>', self.manual_nfc_input)
|
|
ttk.Button(controls_row2, text="Send", command=self.manual_nfc_input).pack(side=tk.LEFT, padx=2)
|
|
|
|
# Status indicator
|
|
self.status_label = ttk.Label(controls_row2, text="Status: Starting...", foreground="orange")
|
|
self.status_label.pack(side=tk.RIGHT, padx=5)
|
|
|
|
# Logging display
|
|
log_frame = ttk.LabelFrame(main_frame, text="System Log", padding="5")
|
|
log_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
self.text_widget = scrolledtext.ScrolledText(
|
|
log_frame,
|
|
wrap=tk.WORD,
|
|
font=('Consolas', 9),
|
|
height=20
|
|
)
|
|
self.text_widget.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# Enhanced statistics
|
|
stats_frame = ttk.LabelFrame(main_frame, text="Statistics", padding="5")
|
|
stats_frame.pack(fill=tk.X)
|
|
|
|
self.stats_labels = {}
|
|
stats_grid = ttk.Frame(stats_frame)
|
|
stats_grid.pack(fill=tk.X)
|
|
|
|
stats_keys = [
|
|
('videos_played', 'Videos Played'),
|
|
('folder_videos_played', 'Folder Videos'),
|
|
('key_presses', 'NFC Scans'),
|
|
('errors', 'Errors'),
|
|
('uptime', 'Uptime'),
|
|
('queue_depth', 'Queue Depth'),
|
|
('trailers_pool', 'Trailers Available'),
|
|
('current_video', 'Current Video')
|
|
]
|
|
|
|
for i, (key, label) in enumerate(stats_keys):
|
|
row = i // 2
|
|
col = (i % 2) * 2
|
|
|
|
ttk.Label(stats_grid, text=f"{label}:").grid(row=row, column=col, sticky=tk.W, padx=5)
|
|
self.stats_labels[key] = ttk.Label(stats_grid, text="0", font=('Consolas', 9))
|
|
self.stats_labels[key].grid(row=row, column=col+1, sticky=tk.W, padx=5)
|
|
|
|
# Bind local keys as fallback
|
|
self.root.bind('<Key>', self.on_key_press)
|
|
self.root.focus_set()
|
|
|
|
def reset_folder_sequences(self):
|
|
"""Reset all folder video sequences to the beginning"""
|
|
if messagebox.askyesno(
|
|
"Reset Folder Sequences",
|
|
"This will reset all folder video sequences back to the first video.\n\nAre you sure?"
|
|
):
|
|
if self.video_player:
|
|
try:
|
|
self.log("Resetting all folder sequences...")
|
|
self.status_label.config(text="Status: Resetting folders...", foreground="orange")
|
|
|
|
if self.video_player.reset_all_folder_positions():
|
|
self.log("✓ All folder sequences reset successfully")
|
|
messagebox.showinfo(
|
|
"Reset Complete",
|
|
"All folder video sequences have been reset to the beginning."
|
|
)
|
|
self.status_label.config(text="Status: Folders reset", foreground="green")
|
|
else:
|
|
self.log_error("Failed to reset folder sequences")
|
|
messagebox.showerror("Reset Failed", "Could not reset folder sequences.")
|
|
self.status_label.config(text="Status: Reset failed", foreground="red")
|
|
|
|
# Reset status after delay
|
|
self.root.after(3000, lambda: self.status_label.config(text="Status: Ready", foreground="green"))
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Folder reset error: {e}")
|
|
messagebox.showerror("Error", f"Reset failed: {e}")
|
|
self.status_label.config(text="Status: Error", foreground="red")
|
|
else:
|
|
self.log_error("Video player not connected")
|
|
messagebox.showerror("Error", "Video player not connected")
|
|
|
|
def update_global_input_status(self):
|
|
"""Update global input status indicator"""
|
|
if self.global_input_active:
|
|
self.global_input_label.config(
|
|
text=f"Global Input: Active ({self.global_input_method})",
|
|
foreground="green"
|
|
)
|
|
else:
|
|
self.global_input_label.config(
|
|
text="Global Input: Inactive (Focus Required)",
|
|
foreground="red"
|
|
)
|
|
|
|
def on_closing(self):
|
|
"""Handle window close event"""
|
|
if messagebox.askokcancel("Exit", "Do you want to exit the video player?"):
|
|
self.exit_application()
|
|
|
|
def exit_application(self):
|
|
"""Exit the application cleanly"""
|
|
try:
|
|
self.log("Exit requested - shutting down")
|
|
self.status_label.config(text="Status: Shutting down...", foreground="red")
|
|
|
|
# Stop global input capture
|
|
if self.global_listener:
|
|
try:
|
|
if self.global_input_method == "pynput":
|
|
self.global_listener.stop()
|
|
elif self.global_input_method == "windows":
|
|
import win32gui
|
|
win32gui.UnhookWindowsHookEx(self.global_listener)
|
|
self.log("Global input capture stopped")
|
|
except Exception as e:
|
|
self.log_error(f"Error stopping global input: {e}")
|
|
|
|
# Stop video player
|
|
if self.video_player:
|
|
self.video_player.stop()
|
|
self.log("Video player stopped")
|
|
|
|
self.running = False
|
|
self.root.quit()
|
|
self.root.destroy()
|
|
|
|
import sys
|
|
sys.exit(0)
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Error during exit: {e}")
|
|
import sys
|
|
sys.exit(1)
|
|
|
|
def clear_log(self):
|
|
"""Clear the log display"""
|
|
if self.text_widget:
|
|
self.text_widget.delete(1.0, tk.END)
|
|
self.log("Log cleared")
|
|
|
|
def manual_nfc_input(self, event=None):
|
|
"""Handle manual NFC input"""
|
|
nfc_id = self.nfc_entry.get().strip()
|
|
if nfc_id:
|
|
self.log(f"Manual NFC input: {nfc_id}")
|
|
self.process_nfc_input(nfc_id)
|
|
self.nfc_entry.delete(0, tk.END)
|
|
|
|
def on_key_press(self, event):
|
|
"""Fallback NFC input handling"""
|
|
if self.global_input_active:
|
|
return
|
|
|
|
current_time = time.time()
|
|
|
|
try:
|
|
if event.keysym == 'Return':
|
|
if self.nfc_buffer:
|
|
self.log(f"Local NFC input: {self.nfc_buffer}")
|
|
self.process_nfc_input(self.nfc_buffer)
|
|
self.nfc_buffer = ""
|
|
return
|
|
|
|
if event.char and event.char.isdigit():
|
|
if current_time - self.last_nfc_input > self.nfc_timeout:
|
|
self.nfc_buffer = ""
|
|
|
|
self.nfc_buffer += event.char
|
|
self.last_nfc_input = current_time
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Local key press error: {e}")
|
|
|
|
def log(self, message, level="INFO"):
|
|
"""Enhanced logging"""
|
|
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|
thread_name = threading.current_thread().name[:10]
|
|
formatted = f"[{timestamp}][{thread_name}] {level}: {message}"
|
|
|
|
with self.lock:
|
|
self.message_queue.append(formatted)
|
|
|
|
if level == "ERROR":
|
|
self.stats['errors'] += 1
|
|
|
|
def log_error(self, message):
|
|
"""Log error message"""
|
|
self.log(message, "ERROR")
|
|
|
|
def log_video_played(self, video_name):
|
|
"""Log video playback - thread-safe version"""
|
|
self.log(f"Video played: {video_name}")
|
|
self.stats['videos_played'] += 1
|
|
self.stats['current_video'] = video_name
|
|
|
|
# Update status label using thread-safe after() method
|
|
if self.status_label:
|
|
try:
|
|
self.root.after(0, lambda: self._update_status_safe("Status: Playing video", "green"))
|
|
except:
|
|
pass # Ignore if GUI isn't ready
|
|
|
|
def _update_status_safe(self, text, color):
|
|
"""Safely update status label from any thread"""
|
|
try:
|
|
if self.status_label:
|
|
self.status_label.config(text=text, foreground=color)
|
|
except:
|
|
pass
|
|
|
|
def log_key_press(self, key):
|
|
"""Log key press"""
|
|
self.log(f"Key pressed: {key}")
|
|
self.stats['key_presses'] += 1
|
|
|
|
def process_nfc_input(self, nfc_id=None):
|
|
"""Process NFC input"""
|
|
if nfc_id is None:
|
|
nfc_id = self.nfc_buffer.strip()
|
|
|
|
if not nfc_id:
|
|
return
|
|
|
|
self.log(f"Processing NFC ID: {nfc_id}")
|
|
self.log_key_press(nfc_id)
|
|
|
|
if self.status_label:
|
|
self.status_label.config(text=f"Status: Processing NFC {nfc_id}", foreground="orange")
|
|
|
|
if self.video_player:
|
|
try:
|
|
self.video_player.play_specific_video(nfc_id)
|
|
self.log(f"Sent NFC {nfc_id} to video player")
|
|
self.root.after(2000, lambda: self.status_label.config(text="Status: Ready", foreground="green"))
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Failed to send NFC: {e}")
|
|
self.status_label.config(text="Status: Error", foreground="red")
|
|
else:
|
|
self.log_error("Video player not connected")
|
|
self.status_label.config(text="Status: No video player", foreground="red")
|
|
|
|
def set_video_player(self, video_player):
|
|
"""Set reference to video player"""
|
|
self.video_player = video_player
|
|
self.log("Video player connected to debug console")
|
|
if self.status_label:
|
|
self.status_label.config(text="Status: Connected", foreground="green")
|
|
|
|
def skip_video(self):
|
|
"""Skip current video"""
|
|
if self.video_player:
|
|
try:
|
|
self.log("Skipping video...")
|
|
self.status_label.config(text="Status: Skipping...", foreground="orange")
|
|
|
|
self.video_player.skip_current_video()
|
|
self.video_player.force_next_video()
|
|
self.log("Video skip requested")
|
|
|
|
self.root.after(1000, lambda: self.status_label.config(text="Status: Ready", foreground="green"))
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Skip video failed: {e}")
|
|
self.status_label.config(text="Status: Error", foreground="red")
|
|
else:
|
|
self.log_error("Video player not connected")
|
|
self.status_label.config(text="Status: No video player", foreground="red")
|
|
|
|
def toggle_mute(self):
|
|
"""Toggle mute/unmute"""
|
|
if self.video_player:
|
|
try:
|
|
if self.is_muted:
|
|
self.video_player.set_volume(0.7)
|
|
self.mute_button.config(text="Mute")
|
|
self.is_muted = False
|
|
self.log("Audio unmuted")
|
|
self.status_label.config(text="Status: Audio unmuted", foreground="green")
|
|
else:
|
|
self.video_player.set_volume(0.0)
|
|
self.mute_button.config(text="Unmute")
|
|
self.is_muted = True
|
|
self.log("Audio muted")
|
|
self.status_label.config(text="Status: Audio muted", foreground="orange")
|
|
|
|
self.root.after(2000, lambda: self.status_label.config(text="Status: Ready", foreground="green"))
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Mute toggle failed: {e}")
|
|
self.status_label.config(text="Status: Error", foreground="red")
|
|
else:
|
|
self.log_error("Video player not connected")
|
|
|
|
def toggle_fullscreen(self):
|
|
"""Toggle fullscreen mode"""
|
|
if self.video_player:
|
|
try:
|
|
self.status_label.config(text="Status: Toggling fullscreen...", foreground="orange")
|
|
self.video_player.toggle_fullscreen()
|
|
self.log("Fullscreen toggled")
|
|
|
|
self.root.after(1000, lambda: self.status_label.config(text="Status: Ready", foreground="green"))
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Fullscreen toggle failed: {e}")
|
|
self.status_label.config(text="Status: Error", foreground="red")
|
|
else:
|
|
self.log_error("Video player not connected")
|
|
|
|
def update_queue_depth(self, depth):
|
|
"""Update video queue depth"""
|
|
self.stats['queue_depth'] = depth
|
|
|
|
def update_display(self):
|
|
"""Update the console display"""
|
|
messages = []
|
|
with self.lock:
|
|
while self.message_queue:
|
|
messages.append(self.message_queue.popleft())
|
|
|
|
for msg in messages:
|
|
self.text_widget.insert(tk.END, msg + "\n")
|
|
|
|
# Color coding
|
|
if "ERROR" in msg:
|
|
self.text_widget.tag_add("error", f"end-2l linestart", f"end-1l lineend")
|
|
self.text_widget.tag_config("error", foreground="red", background="#ffe6e6")
|
|
elif "WARNING" in msg:
|
|
self.text_widget.tag_add("warning", f"end-2l linestart", f"end-1l lineend")
|
|
self.text_widget.tag_config("warning", foreground="orange", background="#fff3cd")
|
|
elif "Global NFC input" in msg or "NFC" in msg:
|
|
self.text_widget.tag_add("nfc", f"end-2l linestart", f"end-1l lineend")
|
|
self.text_widget.tag_config("nfc", foreground="blue", background="#e6f3ff")
|
|
elif "Video played:" in msg or "SPECIFIC VIDEO" in msg or "Folder" in msg:
|
|
self.text_widget.tag_add("video", f"end-2l linestart", f"end-1l lineend")
|
|
self.text_widget.tag_config("video", foreground="green", background="#e6ffe6")
|
|
elif "Reset" in msg or "reset" in msg:
|
|
self.text_widget.tag_add("reset", f"end-2l linestart", f"end-1l lineend")
|
|
self.text_widget.tag_config("reset", foreground="purple", background="#f0e6ff")
|
|
|
|
self.text_widget.see(tk.END)
|
|
|
|
# Limit text size
|
|
lines = self.text_widget.get("1.0", tk.END).count('\n')
|
|
if lines > 1000:
|
|
self.text_widget.delete("1.0", "200.0")
|
|
|
|
# Update statistics
|
|
uptime = str(datetime.now() - self.stats['start_time']).split('.')[0]
|
|
self.stats_labels['uptime'].config(text=uptime)
|
|
|
|
for key in self.stats_labels:
|
|
if key in self.stats and key != 'uptime':
|
|
value = str(self.stats[key])
|
|
if key == 'current_video' and len(value) > 30:
|
|
value = value[:27] + "..."
|
|
self.stats_labels[key].config(text=value)
|
|
|
|
# Update folder videos stat from video player
|
|
if self.video_player and hasattr(self.video_player, 'stats'):
|
|
folder_count = self.video_player.stats.get('folder_videos_played', 0)
|
|
self.stats_labels['folder_videos_played'].config(text=str(folder_count))
|
|
|
|
# Update trailers pool stat
|
|
if self.video_player:
|
|
try:
|
|
total_trailers = len(self.video_player.trailer_videos) if hasattr(self.video_player, 'trailer_videos') else 0
|
|
recent_count = len(self.video_player.recently_played_trailers[-25:]) if hasattr(self.video_player, 'recently_played_trailers') else 0
|
|
available = total_trailers - recent_count
|
|
if available < 0:
|
|
available = 0
|
|
self.stats_labels['trailers_pool'].config(text=f"{available}/{total_trailers}")
|
|
except:
|
|
pass
|
|
|
|
# Update global input status
|
|
self.update_global_input_status()
|
|
|
|
def run(self):
|
|
"""Run the debug console"""
|
|
self.running = True
|
|
self.log("Enhanced debug console started with folder support")
|
|
|
|
if self.status_label:
|
|
self.status_label.config(text="Status: Starting...", foreground="orange")
|
|
|
|
def update_loop():
|
|
if self.running:
|
|
try:
|
|
self.update_display()
|
|
|
|
if (self.status_label and
|
|
"Starting" in self.status_label.cget("text") and
|
|
self.video_player):
|
|
self.status_label.config(text="Status: Ready", foreground="green")
|
|
|
|
self.root.after(100, update_loop)
|
|
except Exception as e:
|
|
self.log_error(f"Display update error: {e}")
|
|
if self.running:
|
|
self.root.after(1000, update_loop)
|
|
|
|
update_loop()
|
|
|
|
try:
|
|
self.root.mainloop()
|
|
except Exception as e:
|
|
self.logger.error(f"Debug console error: {e}")
|
|
finally:
|
|
self.running = False
|
|
|
|
def stop(self):
|
|
"""Stop the debug console"""
|
|
self.running = False
|
|
|
|
if self.global_listener:
|
|
try:
|
|
if self.global_input_method == "pynput":
|
|
self.global_listener.stop()
|
|
elif self.global_input_method == "windows":
|
|
import win32gui
|
|
win32gui.UnhookWindowsHookEx(self.global_listener)
|
|
except Exception as e:
|
|
self.logger.debug(f"Error stopping global input: {e}")
|
|
|
|
if self.root:
|
|
try:
|
|
self.root.quit()
|
|
self.root.destroy()
|
|
except:
|
|
pass |