diff --git a/.gitignore b/.gitignore index 36b13f1..1fc4307 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,5 @@ cython_debug/ # PyPI configuration file .pypirc + +category_names.json diff --git a/main.py b/main.py new file mode 100644 index 0000000..617d76a --- /dev/null +++ b/main.py @@ -0,0 +1,156 @@ +import sys +import os +import json +from pathlib import Path +from PySide6.QtWidgets import ( + QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, + QPushButton, QFileDialog, QLineEdit, QListWidget, QMessageBox, QHBoxLayout, QInputDialog +) +from PySide6.QtCore import Qt, QMimeData +from PySide6.QtGui import QDragEnterEvent, QDropEvent + +CONFIG_FILE = "category_names.json" + +class FileRenamer(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("批量文件重命名工具") + self.setMinimumSize(600, 400) + self.setAcceptDrops(True) + + self.files = [] + self.initial_path = "" + self.prefix = "" + self.categories = self.load_categories() + + central_widget = QWidget() + self.setCentralWidget(central_widget) + + layout = QVBoxLayout(central_widget) + + self.info_label = QLabel("拖拽文件到此区域") + self.info_label.setAlignment(Qt.AlignCenter) + self.info_label.setStyleSheet("border: 2px dashed #aaa; padding: 20px; font-size: 16px;") + layout.addWidget(self.info_label) + + path_layout = QHBoxLayout() + self.path_btn = QPushButton("设置初始路径") + self.path_btn.clicked.connect(self.set_initial_path) + self.path_label = QLabel("未设置") + path_layout.addWidget(self.path_btn) + path_layout.addWidget(self.path_label) + layout.addLayout(path_layout) + + prefix_layout = QHBoxLayout() + self.prefix_btn = QPushButton("设置前缀") + self.prefix_btn.clicked.connect(self.set_prefix) + self.prefix_label = QLabel("当前前缀: (无)") + prefix_layout.addWidget(self.prefix_btn) + prefix_layout.addWidget(self.prefix_label) + layout.addLayout(prefix_layout) + + self.name_input = QLineEdit() + self.name_input.setPlaceholderText("输入新文件名(不含前缀和序号)") + layout.addWidget(self.name_input) + + self.suggestion_list = QListWidget() + self.suggestion_list.itemClicked.connect(self.select_suggestion) + layout.addWidget(self.suggestion_list) + + btn_layout = QHBoxLayout() + self.rename_btn = QPushButton("重命名") + self.rename_btn.clicked.connect(self.rename_files) + btn_layout.addWidget(self.rename_btn) + layout.addLayout(btn_layout) + + def dragEnterEvent(self, event: QDragEnterEvent): + if event.mimeData().hasUrls(): + event.acceptProposedAction() + + def dropEvent(self, event: QDropEvent): + for url in event.mimeData().urls(): + file_path = url.toLocalFile() + if os.path.isfile(file_path): + self.files.append(file_path) + self.info_label.setText(f"已添加 {len(self.files)} 个文件") + + if self.initial_path: + categories_found = set() + for f in self.files: + rel_path = os.path.relpath(f, self.initial_path) + category = os.path.dirname(rel_path).replace("\\", "/") + if category: + categories_found.add(category) + if categories_found: + self.show_suggestions(categories_found) + + def set_initial_path(self): + folder = QFileDialog.getExistingDirectory(self, "选择初始路径") + if folder: + self.initial_path = folder + self.path_label.setText(folder) + + def set_prefix(self): + prefix, ok = QInputDialog.getText(self, "设置前缀", "输入前缀:", text=self.prefix if self.prefix else "") + if ok: + self.prefix = prefix + self.prefix_label.setText(f"当前前缀: {self.prefix if self.prefix else '(无)'}") + + def rename_files(self): + if not self.files: + QMessageBox.warning(self, "警告", "请先拖拽文件") + return + + new_name = self.name_input.text().strip() + if not new_name: + QMessageBox.warning(self, "警告", "请输入新文件名") + return + + for idx, file_path in enumerate(self.files, start=1): + folder = os.path.dirname(file_path) + ext = os.path.splitext(file_path)[1] + new_filename = f"{self.prefix}{new_name}{idx:02}{ext}" + new_path = os.path.join(folder, new_filename) + os.rename(file_path, new_path) + + if self.initial_path: + for f in self.files: + rel_path = os.path.relpath(f, self.initial_path) + category = os.path.dirname(rel_path).replace("\\", "/") + if category: + self.categories.setdefault(category, set()).add(new_name) + + self.save_categories() + + QMessageBox.information(self, "完成", "重命名完成") + self.files.clear() + self.info_label.setText("拖拽文件到此区域") + + def load_categories(self): + if os.path.exists(CONFIG_FILE): + with open(CONFIG_FILE, "r", encoding="utf-8") as f: + data = json.load(f) + return {k: set(v) for k, v in data.items()} + return {} + + def save_categories(self): + data = {k: list(v) for k, v in self.categories.items()} + with open(CONFIG_FILE, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + + def show_suggestions(self, categories_found): + self.suggestion_list.clear() + suggestions = set() + for cat in categories_found: + if cat in self.categories: + suggestions.update(self.categories[cat]) + self.suggestion_list.addItems(sorted(suggestions)) + + def select_suggestion(self, item): + self.name_input.setText(item.text()) + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = FileRenamer() + window.show() + sys.exit(app.exec())