#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys # 添加项目根目录到 Python 路径 current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(current_dir) sys.path.append(project_root) import yaml from PyQt6.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QScrollArea, QGridLayout, QFrame, QGroupBox, QFileDialog, QComboBox, QLineEdit, QFormLayout ) from PyQt6.QtCore import Qt, QSize, QTimer from PyQt6.QtGui import QFont from kodi_util.kodi_server import KodiServer from kodi_util.task_registry import get_registered_tasks, get_task_class from kodi_util.kodi_play.thread import KodiStateMonitorThread class TaskButton(QPushButton): """代表一个任务的按钮""" def __init__(self, task_name, parent=None): super().__init__(task_name, parent) self.task_name = task_name self.setMinimumWidth(200) self.setMinimumHeight(60) self.setFont(QFont("Arial", 12, QFont.Weight.Bold)) self.setStyleSheet(""" QPushButton { background-color: #3498db; color: white; border-radius: 5px; padding: 10px; } QPushButton:hover { background-color: #2980b9; } QPushButton:pressed { background-color: #1c6ea4; } """) class TaskConfigWidget(QWidget): """任务配置界面""" def __init__(self, task_name, parent=None): super().__init__(parent) self.task_name = task_name self.task_instance = None self.state_monitor = None self.init_ui() def init_ui(self): """初始化配置界面""" layout = QVBoxLayout(self) # 添加控制按钮 button_layout = QHBoxLayout() self.start_btn = QPushButton("开始任务") self.start_btn.clicked.connect(self.start_task) self.stop_btn = QPushButton("停止任务") self.stop_btn.clicked.connect(self.stop_task) self.stop_btn.setEnabled(False) button_layout.addWidget(self.start_btn) button_layout.addWidget(self.stop_btn) layout.addLayout(button_layout) def start_task(self): """开始任务""" try: # 获取任务类 task_class = get_task_class(self.task_name) # 创建任务实例 self.task_instance = task_class() # 创建状态监控线程 if hasattr(self.task_instance, 'kodi_server'): self.state_monitor = KodiStateMonitorThread( self.task_instance.kodi_server.clients, interval=1.0 ) self.state_monitor.start() # 设置任务实例的状态监控器 self.task_instance.state_monitor = self.state_monitor # 如果是联动任务,直接开始播放 if self.task_name == "联动": self.task_instance.play() # 启动任务 if hasattr(self.task_instance, 'start_monitoring'): self.task_instance.start_monitoring() # 更新按钮状态 self.start_btn.setEnabled(False) self.stop_btn.setEnabled(True) except Exception as e: print(f"启动任务失败: {str(e)}") def stop_task(self): """停止任务""" if self.task_instance: try: # 停止状态监控线程 if self.state_monitor: self.state_monitor.stop() self.state_monitor = None self.task_instance.interrupt() self.task_instance = None # 更新按钮状态 self.start_btn.setEnabled(True) self.stop_btn.setEnabled(False) except Exception as e: print(f"停止任务失败: {str(e)}") class PlayWindow(QWidget): """播放效果模块窗口""" def __init__(self): super().__init__() # 设置窗口标题和大小 self.setWindowTitle("任务控制面板") self.setMinimumSize(QSize(800, 600)) # 创建主布局 self.main_layout = QVBoxLayout(self) self.main_layout.setContentsMargins(20, 20, 20, 20) self.main_layout.setSpacing(15) # 初始化 KodiServer self.kodi_server = KodiServer() # 存储正在运行的任务 self.running_tasks = {} # 存储状态监控线程 self.state_monitors = {} # 创建状态更新定时器 self.status_update_timer = QTimer() self.status_update_timer.timeout.connect(self.update_ui) self.status_update_timer.start(1000) # 每秒更新一次UI # 初始化UI self.init_ui() # 自动启动按钮监听任务 self.execute_task("按钮监听串") def init_ui(self): """初始化用户界面""" # 创建标题 title_label = QLabel("任务控制面板") title_label.setFont(QFont("Arial", 18, QFont.Weight.Bold)) title_label.setAlignment(Qt.AlignmentFlag.AlignCenter) title_label.setStyleSheet("color: #2c3e50; margin-bottom: 10px;") self.main_layout.addWidget(title_label) # 创建正在执行的任务区域 running_tasks_group = QGroupBox("正在执行的任务") running_tasks_group.setStyleSheet(""" QGroupBox { background-color: #f8f9fa; border-radius: 5px; padding: 10px; } """) self.running_tasks_layout = QVBoxLayout(running_tasks_group) self.main_layout.addWidget(running_tasks_group) # 创建分隔线 line = QFrame() line.setFrameShape(QFrame.Shape.HLine) line.setStyleSheet("background-color: #bdc3c7;") self.main_layout.addWidget(line) # 创建可用任务区域 available_tasks_group = QGroupBox("可用任务") available_tasks_group.setStyleSheet(""" QGroupBox { background-color: #f8f9fa; border-radius: 5px; padding: 10px; } """) self.available_tasks_layout = QVBoxLayout(available_tasks_group) self.main_layout.addWidget(available_tasks_group) # 添加任务按钮 self.add_task_buttons() # 添加状态信息区域 self.status_frame = QFrame() self.status_frame.setFrameShape(QFrame.Shape.StyledPanel) self.status_frame.setStyleSheet("background-color: #f0f0f0; border-radius: 5px;") status_layout = QVBoxLayout(self.status_frame) self.status_label = QLabel("准备就绪") self.status_label.setFont(QFont("Arial", 12)) self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) status_layout.addWidget(self.status_label) self.main_layout.addWidget(self.status_frame) def add_task_buttons(self): """添加所有任务按钮""" # 获取所有注册的任务 registered_tasks = get_registered_tasks() if not registered_tasks: # 如果没有找到任务,添加提示信息 label = QLabel("未找到注册的任务") label.setFont(QFont("Arial", 14)) label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setStyleSheet("color: #e74c3c;") self.available_tasks_layout.addWidget(label) return # 为每个任务创建一个按钮和配置界面 for task_name in registered_tasks: # 创建任务容器 task_container = QWidget() task_layout = QHBoxLayout(task_container) task_layout.setContentsMargins(5, 5, 5, 5) # 创建任务标签 task_label = QLabel(task_name) task_label.setFont(QFont("Arial", 12)) task_label.setMinimumWidth(200) task_layout.addWidget(task_label) # 创建执行按钮 execute_btn = QPushButton("执行") execute_btn.setMinimumWidth(100) execute_btn.clicked.connect(lambda checked, name=task_name: self.execute_task(name)) # 如果任务正在运行,禁用按钮 if task_name in self.running_tasks: execute_btn.setEnabled(False) execute_btn.setText("运行中") execute_btn.setStyleSheet(""" QPushButton { background-color: #95a5a6; color: white; border-radius: 5px; } """) task_layout.addWidget(execute_btn) # 添加到布局 self.available_tasks_layout.addWidget(task_container) def execute_task(self, task_name): """执行任务""" try: # 如果任务已经在运行,直接返回 if task_name in self.running_tasks: self.update_status(f"任务 {task_name} 已经在运行中") return # 先停止所有正在运行的任务 self.stop_all_tasks() # 获取任务类 task_class = get_task_class(task_name) # 创建任务实例 task_instance = task_class() # 确保任务实例使用相同的KodiServer实例 if hasattr(task_instance, 'kodi_server'): task_instance.kodi_server = self.kodi_server # 创建状态监控线程 if hasattr(task_instance, 'kodi_server'): state_monitor = KodiStateMonitorThread( task_instance.kodi_server.clients, interval=1.0 ) state_monitor.start() # 设置任务实例的状态监控器 task_instance.state_monitor = state_monitor # 存储状态监控线程 self.state_monitors[task_name] = state_monitor # 添加到正在执行的任务列表 self.add_running_task(task_name, task_instance) # 如果是联动任务,直接开始播放 if task_name == "联动": try: # 使用QTimer延迟执行play方法,避免阻塞UI QTimer.singleShot(0, lambda: self._start_linkage_task(task_instance)) except Exception as e: self.update_status(f"联动任务播放失败: {str(e)}") return # 启动任务 if hasattr(task_instance, 'start_monitoring'): try: task_instance.start_monitoring() except Exception as e: self.update_status(f"启动任务监控失败: {str(e)}") return # 更新状态 self.update_status(f"任务 {task_name} 已开始执行") except Exception as e: self.update_status(f"启动任务失败: {str(e)}") # 确保清理资源 if task_name in self.state_monitors: self.state_monitors[task_name].stop() del self.state_monitors[task_name] if task_name in self.running_tasks: del self.running_tasks[task_name] def _start_linkage_task(self, task_instance): """启动联动任务""" try: print("开始执行联动任务...") print(f"任务实例类型: {type(task_instance)}") print(f"任务实例属性: {dir(task_instance)}") # 检查kodi_server if hasattr(task_instance, 'kodi_server'): print(f"KodiServer状态: {task_instance.kodi_server}") print(f"客户端数量: {len(task_instance.kodi_server.clients)}") for client in task_instance.kodi_server.clients: print(f"客户端信息: {client.host}:{client.port}") # 检查state_monitor if hasattr(task_instance, 'state_monitor'): print(f"状态监控器状态: {task_instance.state_monitor}") # 执行播放 print("调用play方法...") task_instance.play() print("play方法调用完成") except Exception as e: print(f"联动任务播放失败: {str(e)}") import traceback traceback.print_exc() self.update_status(f"联动任务播放失败: {str(e)}") def stop_all_tasks(self): """停止所有正在运行的任务""" for running_task_name, task_instance in list(self.running_tasks.items()): try: # 停止状态监控线程 if running_task_name in self.state_monitors: self.state_monitors[running_task_name].stop() del self.state_monitors[running_task_name] # 停止任务 if task_instance: task_instance.interrupt() del self.running_tasks[running_task_name] # 更新状态 self.update_status(f"已停止任务 {running_task_name}") except Exception as e: print(f"停止任务 {running_task_name} 失败: {str(e)}") # 清空正在执行的任务列表 while self.running_tasks_layout.count(): item = self.running_tasks_layout.takeAt(0) if item.widget(): item.widget().deleteLater() def update_ui(self): """更新UI状态""" # 更新所有任务按钮状态 self.update_task_buttons() # 更新状态信息 if self.running_tasks: self.update_status(f"当前运行任务: {', '.join(self.running_tasks.keys())}") else: self.update_status("准备就绪") def update_task_buttons(self): """更新所有任务按钮的状态""" for i in range(self.available_tasks_layout.count()): widget = self.available_tasks_layout.itemAt(i).widget() if isinstance(widget, QWidget): for child in widget.findChildren(QPushButton): task_name = child.parent().findChild(QLabel).text() if task_name in self.running_tasks: child.setEnabled(False) child.setText("运行中") child.setStyleSheet(""" QPushButton { background-color: #95a5a6; color: white; border-radius: 5px; } """) else: child.setEnabled(True) child.setText("执行") child.setStyleSheet("") def add_running_task(self, task_name, task_instance): """添加正在执行的任务到显示区域""" # 创建任务容器 task_container = QWidget() task_layout = QHBoxLayout(task_container) task_layout.setContentsMargins(5, 5, 5, 5) # 创建任务标签 task_label = QLabel(task_name) task_label.setFont(QFont("Arial", 12)) task_label.setMinimumWidth(200) task_layout.addWidget(task_label) # 创建停止按钮 stop_btn = QPushButton("停止") stop_btn.setMinimumWidth(100) stop_btn.clicked.connect(lambda: self.stop_task(task_name, task_container)) task_layout.addWidget(stop_btn) # 添加到布局 self.running_tasks_layout.addWidget(task_container) # 存储任务实例 self.running_tasks[task_name] = task_instance def stop_task(self, task_name, task_container): """停止任务""" if task_name in self.running_tasks: try: # 停止状态监控线程 if task_name in self.state_monitors: self.state_monitors[task_name].stop() del self.state_monitors[task_name] task_instance = self.running_tasks[task_name] task_instance.interrupt() del self.running_tasks[task_name] # 从界面中移除任务容器 self.running_tasks_layout.removeWidget(task_container) task_container.deleteLater() # 更新可用任务区域的按钮状态 for i in range(self.available_tasks_layout.count()): widget = self.available_tasks_layout.itemAt(i).widget() if isinstance(widget, QWidget): for child in widget.findChildren(QPushButton): if child.text() == "运行中": child.setEnabled(True) child.setText("执行") child.setStyleSheet("") break # 更新状态 self.update_status(f"任务 {task_name} 已停止") except Exception as e: self.update_status(f"停止任务失败: {str(e)}") def update_status(self, message): """更新状态信息""" self.status_label.setText(message) # 根据消息类型设置不同的样式 if "错误" in message or "失败" in message: color = "#e74c3c" # 红色 elif "成功" in message: color = "#27ae60" # 绿色 else: color = "#2980b9" # 蓝色 self.status_label.setStyleSheet(f"color: {color};") def closeEvent(self, event): """窗口关闭事件""" # 停止所有任务 self.stop_all_tasks() # 停止状态更新定时器 self.status_update_timer.stop() # 接受关闭事件 event.accept() if __name__ == "__main__": app = QApplication(sys.argv) window = PlayWindow() window.show() sys.exit(app.exec())