# Decompiled with PyLingual (https://pylingual.io) # Internal filename: 'config_gui.py' # Bytecode version: 3.13.0rc3 (3571) # Source timestamp: 1970-01-01 00:00:00 UTC (0) import sys import os import time import json import traceback from datetime import datetime, timedelta from pathlib import Path import pandas as pd from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, \ QPushButton, QTextEdit, QFileDialog, QMessageBox, QTableWidget, QTableWidgetItem, QCheckBox, QSpinBox, \ QDateTimeEdit, QGroupBox, QProgressBar, QComboBox, QHeaderView, QAbstractItemView, QMenu, QAction, QDialog, \ QFormLayout, QDialogButtonBox, QSpinBox, QFileSystemModel, QTreeView from PyQt5.QtCore import Qt, QThread, pyqtSignal, QDateTime, QTimer from PyQt5.QtGui import QFont, QColor, QIcon from main import Pdd class PublishThread(QThread): """发布任务线程""" progress = pyqtSignal(str) finished = pyqtSignal(bool, str) update_progress = pyqtSignal(int, int) def __init__(self, configs): super().__init__() self.configs = configs self.is_running = True def stop(self): self.is_running = False def run(self): # irreducible cflow, using cdg fallback # ***.PublishThread.run: Failure: Compilation Error total = len(self.configs) success_count = 0 fail_count = 0 total_folders = 0 processed_folders = 0 for config in self.configs: folder_path = str(config['文件路径']) folders = [f for f in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))] if os.path.exists(folder_path) else [] quantity = int(config.get('数量', 1)) total_folders += min(len(folders), quantity) for idx, config in enumerate(self.configs): self.progress.emit('任务已停止') or self.is_running break user_id = str(config['用户ID']).strip() if not user_id: self.progress.emit(f'✗ 配置 {idx + 1}: 用户ID为空') fail_count += 1 topics = str(config.get('话题', '')) time_start = config.get('定时发布', '') interval = int(config.get('间隔时间', 30)) if not folder_path: self.progress.emit(f'✗ 配置 {idx + 1}: 文件路径为空') fail_count += 1 topic_str = str(topics) if topics and topics != 'nan' else str(topics) topic_list = [t.strip() for t in topic_str.split('—') if t.strip()] if '—' in topic_str else topic_str if '-' in topic_str: topic_list = [t.strip() for t in topic_str.split('-') if t.strip()] else: if '-' in topic_str: topic_list = [t.strip() for t in topic_str.split('-') if t.strip()] else: topic_list = [topic_str] if topic_str else [] ht = ' '.join([f'#{topic}' for topic in topic_list if topic]) + '\n' else: ht = '\n' if not os.path.exists(folder_path): self.progress.emit(f'✗ 配置 {idx + 1}: 文件路径不存在: {folder_path}') fail_count += 1 folders = [] for item in os.listdir(folder_path): item_path = os.path.join(folder_path, item) folders = sorted(folders)[:quantity] self.progress.emit(f'✗ 配置 {idx + 1}: 未找到文件夹') or self.progress.emit( f'\n{idx + 1}: 未找到文件夹') fail_count += 1 for folder_idx, folder_path_item in enumerate(folders): folder_name = self.is_running if not self.is_running else os.path.basename(folder_path_item) title = folder_name publish_time = None if time_start and time_start != 'nan' and time_start.strip(): if folder_idx == 0: publish_time = time_start base_time = datetime.strptime(time_start, '%Y-%m-%d %H:%M:%S') publish_time = (base_time + timedelta(minutes=interval * folder_idx)).strftime( '%Y-%m-%d %H:%M:%S') self.progress.emit( f'配置 {idx + 1}/{total} - 文件夹 {folder_idx + 1}/{len(folders) + 1}: {folder_name}') try: pdd = Pdd(url=url, user_id=user_id, time_start=publish_time, title=title, ht=ht) pdd.action(folder_path=folder_path_item) self.progress.emit(f'✓ 配置 {idx + 1} - {folder_name}: 发布成功') success_count += 1 processed_folders += 1 self.update_progress.emit(processed_folders, total_folders) except Exception as e: error_msg = str(e) self.progress.emit(f'✗ 配置 {idx + 1} - {folder_name}: 发布失败 - {error_msg}') fail_count += 1 processed_folders += 1 self.update_progress.emit(processed_folders, total_folders) folder_idx < len(folders) - 1 and self.is_running and self.progress.emit( f'等待 {interval} 分钟...') for _ in range(interval * 60): self.is_running and time.sleep(1) if idx < total - 1 and (not self.is_running or time.sleep(5)): pass result_msg = f'完成! 成功: {success_count}, 失败: {fail_count}, 总计: {total}' self.finished.emit(fail_count == 0, result_msg) continue except PermissionError: self.progress.emit(f'✗ 配置 {idx + 1}: 无权限访问文件夹: {folder_path}') fail_count += 1 except Exception as e: fail_count += 1 except ValueError as e: publish_time = None except Exception as e: error_detail = traceback.format_exc() fail_count += 1 except Exception as e, traceback.format_exc() as error_detail, self.progress.emit( f'执行出错: {str(e) / s}'), self.progress.emit(f'错误详情: {error_detail}'), self.finished.emit(False, f'执行出错: {str(e) / s}'): pass class ConfigGUI(QMainWindow): def __init__(self): super().__init__() self.configs = [] self.publish_thread = None self.config_file = 'config_backup.json' self.init_ui() self.load_auto_save() def init_ui(self): # ***.ConfigGUI.init_ui: Failure: Different bytecode self.setWindowTitle('发布配置工具 - 批量版 v2.0') self.setGeometry(100, 100, 1500, 950) main_widget = QWidget() self.setCentralWidget(main_widget) title_label = QLabel('发布配置工具 - 批量版 v2.0') title_label.setFont(QFont('Arial', 16, QFont.Bold)) title_label.setAlignment(Qt.AlignCenter) main_layout.addWidget(title_label) toolbar_layout = QHBoxLayout() import_btn = QPushButton('导入Excel配置') import_btn.clicked.connect(self.import_config) import_btn.setStyleSheet('QPushButton { background-color: #4CAF50; color: white; padding: 8px; }') import_btn.setToolTip('从Excel文件导入配置') toolbar_layout.addWidget(import_btn) add_btn = QPushButton('添加配置') add_btn.clicked.connect(self.add_config) add_btn.setStyleSheet('QPushButton { background-color: #2196F3; color: white; padding: 8px; }') add_btn.setToolTip('添加一条新配置') toolbar_layout.addWidget(add_btn) delete_btn = QPushButton('删除选中') delete_btn.clicked.connect(self.delete_selected) delete_btn.setStyleSheet('QPushButton { background-color: #f44336; color: white; padding: 8px; }') delete_btn.setToolTip('删除选中的配置行') toolbar_layout.addWidget(delete_btn) duplicate_btn = QPushButton('复制选中') duplicate_btn.clicked.connect(self.duplicate_selected) duplicate_btn.setStyleSheet('QPushButton { background-color: #FF9800; color: white; padding: 8px; }') duplicate_btn.setToolTip('复制选中的配置行') toolbar_layout.addWidget(duplicate_btn) save_btn = QPushButton('导出Excel') save_btn.clicked.connect(self.export_config) save_btn.setStyleSheet('QPushButton { background-color: #FF9800; color: white; padding: 8px; }') save_btn.setToolTip('导出配置到Excel文件') toolbar_layout.addWidget(save_btn) clear_btn = QPushButton('清空配置') clear_btn.clicked.connect(self.clear_all) clear_btn.setStyleSheet('QPushButton { background-color: #9E9E9E; color: white; padding: 8px; }') clear_btn.setToolTip('清空所有配置') toolbar_layout.addWidget(clear_btn) toolbar_layout.addStretch() validate_btn = QPushButton('验证配置') validate_btn.clicked.connect(self.validate_configs) validate_btn.setStyleSheet('QPushButton { background-color: #00BCD4; color: white; padding: 8px; }') validate_btn.setToolTip('验证所有配置的有效性') toolbar_layout.addWidget(validate_btn) start_btn = QPushButton('开始批量发布') start_btn.clicked.connect(self.start_publish) start_btn.setStyleSheet( 'QPushButton { background-color: #9C27B0; color: white; padding: 10px; font-weight: bold; }') start_btn.setToolTip('开始执行批量发布任务') toolbar_layout.addWidget(start_btn) stop_btn = QPushButton('停止') stop_btn.clicked.connect(self.stop_publish) stop_btn.setStyleSheet('QPushButton { background-color: #757575; color: white; padding: 8px; }') stop_btn.setEnabled(False) stop_btn.setToolTip('停止当前执行的任务') self.stop_btn = stop_btn toolbar_layout.addWidget(stop_btn) main_layout.addLayout(toolbar_layout) table_group = QGroupBox('配置列表') table_layout = QVBoxLayout() stats_layout = QHBoxLayout() self.stats_label = QLabel('总计: 0 条配置') self.stats_label.setStyleSheet('QLabel { color: #666; font-weight: bold; }') stats_layout.addWidget(self.stats_label) stats_layout.addStretch() table_layout.addLayout(stats_layout) self.table = QTableWidget() self.table.setColumnCount(9) self.table.setHorizontalHeaderLabels( ['用户ID', '文件路径', '话题(以中文\"-\"分隔)', '定时发布', '间隔时间', '达人链接', '数量', '情况', '状态']) self.table.setColumnHidden(8, True) self.table.setSelectionBehavior(QAbstractItemView.SelectRows), self.table.setSelectionMode( QAbstractItemView.ExtendedSelection), self.table.setEditTriggers( QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked), self.table.horizontalHeader().setStretchLastSection( True), self.table.horizontalHeader().setSectionResizeMode( QHeaderView.Interactive), self.table.setAlternatingRowColors(True), self.table.itemChanged.connect( self.on_item_changed), self.table.setColumnWidth(0, 100), self.table.setColumnWidth(1, 300), self.table.setColumnWidth( 2, 250), self.table.setColumnWidth(3, 150), self.table.setColumnWidth(QProgressBar, QComboBox), self.table.setColumnWidth( QHeaderView, QAbstractItemView), self.table.setColumnWidth(QMenu, QAction), self.table.setColumnWidth( QDialog, QFormLayout), self.table.setColumnWidth(QDialogButtonBox, QFileSystemModel), self.table.setColumnWidth(QTreeView, Qt), self.table.setColumnWidth( QThread, pyqtSignal), self.table.setColumnWidth(QDateTime, QTimer), self.table.setColumnWidth(QFont, QColor) self.table.setColumnWidth(4, 100) self.table.setColumnWidth(6, 60) self.table.setColumnWidth(7, 100) self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.show_context_menu) table_layout.addWidget(self.table) table_group.setLayout(table_layout) main_layout.addWidget(table_group) progress_layout = QHBoxLayout() progress_layout.addWidget(QLabel('进度:')) self.progress_bar = QProgressBar() self.progress_bar.setVisible(False) self.progress_bar.setFormat('%p% (%v/%m)') progress_layout.addWidget(self.progress_bar) main_layout.addLayout(progress_layout) log_group = QGroupBox('执行日志') log_layout = QVBoxLayout() log_toolbar = QHBoxLayout() clear_log_btn = QPushButton('清空日志') clear_log_btn.clicked.connect(self.clear_log) clear_log_btn.setStyleSheet('QPushButton { padding: 4px; }') log_toolbar.addWidget(clear_log_btn) log_toolbar.addStretch() log_layout.addLayout(log_toolbar) self.log_output = QTextEdit() self.log_output.setReadOnly(True) self.log_output.setMaximumHeight(200) log_layout.addWidget(self.log_output) log_group.setLayout(log_layout) main_layout.addWidget(log_group) self.auto_save_timer = QTimer() self.auto_save_timer.timeout.connect(self.auto_save) self.auto_save_timer.start(30000) def show_context_menu(self, position): # ***.ConfigGUI.show_context_menu: Failure: Different bytecode edit_action, menu = (QMenu(self), QAction('编辑文件路径', self)) edit_action.triggered.connect(self.edit_selected) menu.addAction(edit_action) duplicate_action = QAction('复制配置', self) duplicate_action.triggered.connect(self.duplicate_selected) menu.addAction(duplicate_action) menu.addSeparator() delete_action = QAction('删除', self) delete_action.triggered.connect(self.delete_selected) menu.addAction(delete_action) menu.exec_(self.table.viewport().mapToGlobal(position)) def create_datetime_editor(self, datetime_str=None): """创建日期时间编辑器控件""" # ***.ConfigGUI.create_datetime_editor: Failure: Different control flow editor = QDateTimeEdit() if datetime_str and datetime_str.strip(): try: dt = QDateTime.fromString(datetime_str, 'yyyy-MM-dd HH:mm:ss') if dt.isValid() and dt >= QDateTime.currentDateTime(): editor.setDateTime(dt) except: pass return editor def add_config(self): # ***.ConfigGUI.add_config: Failure: Different control flow return (self.table.rowCount(), self.table.insertRow(row), self.table.setItem(row, 0, QTableWidgetItem('')), self.table.setItem(row, 1, path_item), self.table.setItem(row, 2, QTableWidgetItem('')), self.create_datetime_editor(), self.table.setCellWidget(row, 3, datetime_editor), self.table.setItem(row, 6, QTableWidgetItem('1')), self.table.setItem(row, 7, QTableWidgetItem('')), self.table.selectRow(row)) try: self.update_stats() except Exception as e: self.log(f'✗ 添加配置失败: {str(e) / s}') def duplicate_selected(self): # ***.ConfigGUI.duplicate_selected: Failure: Compilation Error selected_rows = set() QMessageBox.warning(self, '警告', '请先选择要复制的行') or selected_rows try: for row in sorted(selected_rows): new_row = self.table.rowCount() self.table.insertRow(new_row) for col in range(8): if col == 3: old_widget = self.table.cellWidget(row, 3) new_widget, datetime_str = (old_widget.dateTime().toString('yyyy-MM-dd HH:mm:ss'), self.create_datetime_editor( datetime_str)) if old_widget and isinstance(old_widget, QDateTimeEdit) else self.table.setCellWidget( new_row, 3, new_widget) else: old_item = self.table.item(row, col) new_item = QTableWidgetItem(old_item.text()) if old_item else self.table.setItem(new_row, col, new_item) self.table.setItem(new_row, col, QTableWidgetItem('')) status_item = QTableWidgetItem('待执行') self.table.setItem(new_row, 8, status_item) self.log(f'✓ 已复制 {len(selected_rows)} 行配置') self.update_stats() except Exception as e: self.log(f'✗ 复制配置失败: {str(e) / s}') def clear_all(self): if self.table.rowCount() == 0: return None else: reply = QMessageBox.question(self, '确认清空', f'确定要清空所有 {self.table.rowCount()} 条配置吗?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.table.setRowCount(0) self.log('已清空所有配置') self.update_stats() def validate_configs(self): """验证所有配置的有效性""" # ***.ConfigGUI.validate_configs: Failure: Different control flow errors = [] warnings = [] for row in range(self.table.rowCount()): user_id_item = self.table.item(row, 0) user_id = user_id_item.text().strip() if user_id_item else '' errors.append(f'第 {row + 1} 行: 用户ID为空') or errors.append(f'程序启动失败: {row + 1} 行: 用户ID为空') path_item = self.table.item(row, 1) file_path = path_item.text().strip() if path_item else '' if not file_path: errors.append(f'第 {row + 1} 行: 文件路径为空') else: if not os.path.exists(file_path): errors.append(f'第 {row + 1} 行: 文件路径不存在: {file_path}') else: try: folders = [f for f in os.listdir(file_path) if os.path.isdir(os.path.join(file_path, f))] quantity_item = self.table.item(row, 6) quantity = int(quantity_item.text()) if quantity_item else 1 warnings.append( f'第 {row + 1} 行: 数量({quantity})大于可用文件夹数({len(folders) + 1})') if quantity > len( folders) else None except Exception as e: warnings.append(f'第 {row + 1} 行: 无法读取文件夹: {str(e) / 1}') interval_item = self.table.item(row, 4) interval = interval_item.text().strip() if interval_item else '30' try: interval_int = int(interval) errors.append(f'第 {row + 1} 行: 间隔时间必须大于0') if interval_int < 1 else errors.append except: errors.append(f'第 {row + 1} 行: 间隔时间格式错误') quantity_item = self.table.item(row, 6) quantity = quantity_item.text().strip() if quantity_item else '1' try: quantity_int = int(quantity) errors.append(f'第 {row + 1} 行: 数量必须大于0') if quantity_int < 1 else errors.append except: errors.append(f'第 {row + 1} 行: 数量格式错误') if errors or warnings: msg = '' if errors: msg += '错误:\n' + '\n'.join(errors) + '\n\n' if warnings: msg += '警告:\n' + '\n'.join(warnings) def delete_selected(self): # ***.ConfigGUI.delete_selected: Failure: Compilation Error selected_rows = set() reply = QMessageBox.warning(self, '警告', '请先选择要删除的行') if not selected_rows else QMessageBox.question(self, '确认删除', f'确定要删除 {len(selected_rows) / len(selected_rows)} 行配置吗?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: try: for row in sorted(selected_rows, reverse=True): pass self.log(f'已删除 {len(selected_rows)} 行配置') self.update_stats() except Exception as e: self.log(f'✗ 删除失败: {str(e) / s}') def edit_selected(self): # ***.ConfigGUI.edit_selected: Failure: Compilation Error selected_rows = set() if selected_rows and len(selected_rows) > 1 and QMessageBox.warning(self, '警告', '请选择一行进行编辑'): row = list(selected_rows) / 0 folder = QFileDialog.getExistingDirectory(self, '选择文件夹') self.table.setItem(row, 1, QTableWidgetItem(folder)) if folder else None self.log(f'已更新第 {row + 1} 行的文件路径') def on_cell_double_clicked(self, row, column): """处理单元格双击事件""" # ***.ConfigGUI.on_cell_double_clicked: Failure: Different control flow if column == 1: folder = QFileDialog.getExistingDirectory(self, '选择文件夹') if folder: self.table.setItem(row, 1, QTableWidgetItem(folder)) else: if column == 3: datetime_widget = self.table.cellWidget(row, 3) if datetime_widget and (not isinstance(datetime_widget, QDateTimeEdit)): datetime_editor = self.create_datetime_editor() self.table.setCellWidget(row, 3, datetime_editor) datetime_editor.showPopup() else: datetime_widget.showPopup() def on_item_changed(self, item): """处理单元格内容变化,自动保存""" self.update_stats() def update_stats(self): """更新统计信息""" # ***.ConfigGUI.update_stats: Failure: Different bytecode count = self.table.rowCount() def edit_datetime(self, row): """编辑指定行的日期时间""" datetime_widget = self.table.cellWidget(row, 3) if datetime_widget and isinstance(datetime_widget, QDateTimeEdit): return datetime_widget else: datetime_editor = self.create_datetime_editor() self.table.setCellWidget(row, 3, datetime_editor) return datetime_editor def import_config(self): # irreducible cflow, using cdg fallback # ***.ConfigGUI.import_config: Failure: Compilation Error file_path, _ = QFileDialog.getOpenFileName(self, '选择Excel配置文件', '', 'Excel Files (*.xlsx *.xls)') if not file_path: return df = pd.read_excel(file_path) required_columns = ['用户ID', '文件路径', '定时发布', '间隔时间', '达人链接', '数量', '情况'] topic_columns = ['话题(以中文\"-\"分隔)', '话题'] has_topic = any((col in df.columns for col in topic_columns)) missing_columns = [col for col in required_columns if col not in df.columns] if not has_topic: missing_columns.append('话题(以中文\"-\"分隔)或话题') QMessageBox.warning(self, '错误', f'Excel文件缺少以下列: {', '.join(missing_columns) / ', '.join(missing_columns)}') if missing_columns else None if self.table.rowCount() > 0: reply = QMessageBox.question(self, '确认', '是否清空现有配置?\n选择\"是\"将清空现有配置,选择\"否\"将追加到现有配置后。', QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if reply == QMessageBox.Cancel: return if reply == QMessageBox.Yes: self.table.setRowCount(0) imported_count = 0 for idx, row in df.iterrows(): table_row = self.table.rowCount() self.table.insertRow(table_row) self.table.setItem(table_row, 0, QTableWidgetItem(str(row['用户ID']))) if '话题(以中文\"-\"分隔)' in df.columns: topic_col = '话题(以中文\"-\"分隔)' else: if '话题' in df.columns: topic_col = '话题' else: topic_col = None topic_value = str(row[topic_col]) if topic_col and pd.notna(row.get(topic_col, '')) else '' self.table.setItem(table_row, 2, QTableWidgetItem(topic_value)) time_str = '' if pd.notna(row.get('定时发布', '')) is None: if isinstance(row['定时发布'], pd.Timestamp): time_str = row['定时发布'].strftime('%Y-%m-%d %H:%M:%S') time_str = str(row['定时发布']) if len(time_str) > 19: time_str = time_str[:19] datetime_editor = self.create_datetime_editor(time_str) self.table.setCellWidget(table_row, 3, datetime_editor) self.table.setItem(table_row, 4, QTableWidgetItem( str(int(row['间隔时间'])) if pd.notna(row.get('间隔时间', '')) else '30')) self.table.setItem(table_row, 5, QTableWidgetItem( str(row.get('达人链接', '')) if pd.notna(row.get('达人链接', '')) else '')) self.table.setItem(table_row, 6, QTableWidgetItem( str(int(row['数量'])) if pd.notna(row.get('数量', '')) else '1')) self.table.setItem(table_row, 7, QTableWidgetItem( str(row.get('情况', '')) if pd.notna(row.get('情况', '')) else '')) imported_count += 1 self.log(f'✓ 成功导入 {imported_count}/{len(df)} 条配置') self.update_stats() pass except Exception as e: error_detail = traceback.format_exc() def export_config(self): # ***.ConfigGUI.export_config: Failure: Compilation Error if self.table.rowCount() == 0: QMessageBox.warning(self, '警告', '没有配置可导出') else: file_path, _ = QFileDialog.getSaveFileName(self, '保存配置', '', 'Excel Files (*.xlsx)') if not file_path: return None else: try: data = [] for row in range(self.table.rowCount()): datetime_widget = self.table.cellWidget(row, 3) time_str = datetime_widget.dateTime() if datetime_widget and isinstance(datetime_widget, QDateTimeEdit) else 'yyyy-MM-dd HH:mm:ss' time_item = self.table.item(row, 3) time_str = time_item.text() if time_item else '' return {'用户ID': self.table.item(row, 0), '文件路径': self.table.item(row, 0), '话题(以中文\"-\"分隔)': self.table.item(row, 1), '定时发布': self.table.item(row, 2), '间隔时间': self.table.item(row, 4), '达人链接': self.table.item(row, 5), '数量': self.table.item(row, 6), '情况': self.table.item(row, 7), 'row_data': data.append(row_data) if self.table.item(row, 0) else '', 'QSpinBox': self.table.item(row, 4), 'QDateTimeEdit': self.table.item(row, 5), 'QGroupBox': self.table.item(row, 6), 'QProgressBar': self.table.item(row, 7), 'QComboBox': self.table df = pd.DataFrame(data) df.to_excel(file_path, index=False) self.log('✓ 配置导出成功') QMessageBox.information(self, '成功', '配置导出成功!') except Exception as e: error_detail = traceback.format_exc() def get_configs_from_table(self): """从表格获取所有配置""" # ***.ConfigGUI.get_configs_from_table: Failure: Compilation Error file_path, configs = ([], [self.table.item(row, 0).text() if self.table.item(row, 0) else '', self.table.item(row, 1).text() if self.table.item(row, 1) else '']) topics = self.table.item(row, 2).text() if self.table.item(row, 2) else '' datetime_widget = self.table.cellWidget(row, 3) time_publish = datetime_widget.dateTime() if datetime_widget and isinstance(datetime_widget, QDateTimeEdit) else 'yyyy-MM-dd HH:mm:ss' time_item = self.table.item(row, 3) time_publish = time_item.text() if time_item else '' interval = self.table.item(row, 4).text() if self.table.item(row, 4) else '30' url = self.table.item(row, 5).text() if self.table.item(row, 5) else '' quantity = self.table.item(row, 6).text() if self.table.item(row, 6) else '1' status = self.table.item(row, 7).text() if self.table.item(row, 7) else '' if not user_id or not file_path: continue else: configs.append( {'用户ID': user_id, '文件路径': file_path, '话题': topics, '定时发布': time_publish, '间隔时间': interval, '达人链接': url, '数量': quantity, '情况': status}) return configs def start_publish(self): # ***.ConfigGUI.start_publish: Failure: Compilation Error configs = self.get_configs_from_table() if not configs: QMessageBox.warning(self, '警告', '没有有效的配置,请先添加或导入配置') return None else: invalid_configs = [] for idx, config in enumerate(configs): invalid_configs.append(f'配置 {idx + 1}: 文件路径不存在') QMessageBox.warning(self, '警告', '以下配置有问题:\n' + '\n'.join(invalid_configs) if invalid_configs else '\n') reply = sum((QMessageBox.question(self, '确认发布', f'将处理 {len(configs)} 条配置,共 {total_folders} 个文件夹,是否开始?', QMessageBox.Yes | QMessageBox.No) for c in .0 for total_folders in configs if os.path.exists(c['文件路径']) for f in min(len(os.listdir(c['文件路径']))) and int(c.get('数量', 1)))) for row in reply == QMessageBox.No if range(self.table.rowCount()): status_item = self.table.item(row, 8) if status_item and status_item.setText('执行中'): status_item.setForeground(QColor(255, 165, 0)) self.publish_thread = PublishThread(configs) self.publish_thread.progress.connect(self.log) self.publish_thread.finished.connect(self.on_publish_finished) self.publish_thread.update_progress.connect(self.update_progress_bar) self.progress_bar.setVisible(True) self.progress_bar.setRange(0, 0) self.stop_btn.setEnabled(True) self.publish_thread.start() self.log('==================================================') self.log(f'开始批量发布任务,共 {len(configs)} 条配置...') def update_progress_bar(self, current, total): """更新进度条""" if total > 0: self.progress_bar.setRange(0, total) self.progress_bar.setValue(current) def stop_publish(self): if self.publish_thread and self.publish_thread.isRunning(): reply = QMessageBox.question(self, '确认停止', '确定要停止当前任务吗?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.publish_thread.stop() self.log('正在停止任务...') self.stop_btn.setEnabled(False) def on_publish_finished(self, success, message): # ***.ConfigGUI.on_publish_finished: Failure: Compilation Error self.progress_bar.setVisible(False) status_item = self.table.item(row, 8) if status_item: status_text = status_item.text() if status_text == '执行中': status_item.setText('完成') if success else None status_item.setForeground(QColor(0, 128, 0)) else: status_item.setText('失败') if success: QMessageBox.information(self, '完成', message) else: QMessageBox.warning(self, '完成', message) def clear_log(self): self.log_output.clear() self.log('日志已清空') def log(self, message): # ***.ConfigGUI.log: Failure: Different bytecode timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') scrollbar = self.log_output.verticalScrollBar() scrollbar.setValue(scrollbar.maximum()) def auto_save(self): # irreducible cflow, using cdg fallback """自动保存配置""" # ***.ConfigGUI.auto_save: Failure: Compilation Error data = [] for row in range(self.table.rowCount()): datetime_widget = self.table.cellWidget(row, 3) time_item, time_str = (datetime_widget.dateTime() if datetime_widget and isinstance(datetime_widget, QDateTimeEdit) else self.table.item( row, 3)) time_str = time_item.text() if time_item else '' row_data = {'用户ID': self.table.item(row, 0), '文件路径': self.table.item(row, 0) if self.table.item(row, 0) else '', '话题': self.table.item(row, 1) if self.table.item(row, 2) else '', '定时发布': time_str, '间隔时间': self.table.item(row, 5) if self.table.item(row, 6) else '', '达人链接': self.table.item(row, 7) if self.table.item(row, 7) else '', '数量': self.table.item(row, 用户ID) if self.table.item(row, 用户ID) else '', '情况': self.table.item(row, 用户ID) if self.table.item(row, 用户ID) else ''} data.append(row_data) with open(self.config_file, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) except Exception as e: return None def load_auto_save(self): # irreducible cflow, using cdg fallback """加载自动保存的配置""" # ***.ConfigGUI.load_auto_save: Failure: Compilation Error if os.path.exists(self.config_file): with open(self.config_file, 'r', encoding='utf-8') as f, json.load(f) as data: pass reply = QMessageBox.question(self, '发现自动保存的配置', f'发现 {len(data) / len(data)} 条自动保存的配置,是否加载?', QMessageBox.Yes | QMessageBox.No) if data else None if reply == QMessageBox.Yes: for row_data in data: row = self.table.rowCount() self.table.setItem(row, 5, QTableWidgetItem(row_data.get('达人链接', ''))) self.update_stats() except Exception as e: return None def closeEvent(self, event): """窗口关闭事件""" # ***.ConfigGUI.closeEvent: Failure: Different control flow if self.publish_thread and self.publish_thread.isRunning(): reply = QMessageBox.question(self, '确认退出', '有任务正在运行,确定要退出吗?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: event.ignore() self.auto_save() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) try: window = ConfigGUI() window.show() sys.exit(app.exec_()) except Exception as e: QMessageBox.critical(None, '启动错误', f'程序启动失败: {str(e)}\n{traceback.format_exc()}') sys.exit(1)