フォルダ名一括変更ツール『黎明ノ再構者』 ソースコード

以下は『黎明ノ再構者』のソースコード全文です:

 
        import tkinter as tk
        from tkinter import filedialog, messagebox, scrolledtext
        import os
        import csv
        import datetime
        import shutil
        
        class FolderRenamerGUI:
            def __init__(self, root):
                self.root = root
                self.root.title("フォルダ一括名称変更ツール - 黎明ノ再構者")
        
                self.base_folder = ""
                self.csv_file = ""
                self.rename_pairs = []
        
                self.build_gui()
        
            def build_gui(self):
                tk.Button(self.root, text="① 対象フォルダを選択", command=self.select_base_folder).pack(pady=5)
                self.base_label = tk.Label(self.root, text="未選択")
                self.base_label.pack()
        
                tk.Button(self.root, text="② CSVファイルを選択", command=self.select_csv_file).pack(pady=5)
                self.csv_label = tk.Label(self.root, text="未選択")
                self.csv_label.pack()
        
                tk.Button(self.root, text="③ 実行", command=self.confirm_and_rename).pack(pady=10)
        
                self.log = scrolledtext.ScrolledText(self.root, width=80, height=20)
                self.log.pack(padx=10, pady=10)
        
            def select_base_folder(self):
                self.base_folder = filedialog.askdirectory()
                self.base_label.config(text=self.base_folder if self.base_folder else "未選択")
        
            def select_csv_file(self):
                self.csv_file = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
                self.csv_label.config(text=self.csv_file if self.csv_file else "未選択")
        
            def confirm_and_rename(self):
                if not self.base_folder or not self.csv_file:
                    messagebox.showwarning("入力不足", "対象フォルダとCSVファイルの両方を選択してください。")
                    return
        
                self.rename_pairs = self.load_csv()
                if self.rename_pairs is None:
                    return  # エラーメッセージは load_csv 内で表示済み
        
                count = len(self.rename_pairs)
                if messagebox.askokcancel("確認", f"{count}個のフォルダに対して実行します。\nよろしいですか?"):
                    self.execute_rename()
        
            def load_csv(self):
                pairs = []
                seen_old = {}
                seen_new = {}
            
                duplicate_old = set()
                duplicate_new = set()
            
                try:
                    with open(self.csv_file, encoding="utf-8") as f:
                        reader = csv.reader(f)
                        for i, row in enumerate(reader, 1):
                            if len(row) >= 2:
                                old = row[0].strip()
                                new = row[1].strip()
            
                                if old and new:
                                    pairs.append((old, new))
            
                                    # 小文字に変換して重複チェック
                                    old_lower = old.lower()
                                    new_lower = new.lower()
            
                                    if old_lower in seen_old:
                                        duplicate_old.add(old)
                                    else:
                                        seen_old[old_lower] = i
            
                                    if new_lower in seen_new:
                                        duplicate_new.add(new)
                                    else:
                                        seen_new[new_lower] = i
            
                    if duplicate_old or duplicate_new:
                        messages = []
                        for name in sorted(duplicate_old):
                            messages.append(f"現在名:{name} が重複しています。")
                        for name in sorted(duplicate_new):
                            messages.append(f"変更名:{name} が重複しています。")
                        messagebox.showerror("重複検出", "\n".join(messages))
                        return None
            
                except Exception as e:
                    messagebox.showerror("CSV読み込みエラー", str(e))
                    return None
            
                return pairs
            
            def execute_rename(self):
                log_lines = []
                for old_name, new_name in self.rename_pairs:
                    old_path = os.path.join(self.base_folder, old_name)
                    new_path = os.path.join(self.base_folder, new_name)
        
                    if os.path.exists(old_path):
                        try:
                            shutil.move(old_path, new_path)
                            msg = f"{old_name} → {new_name} に変更しました"
                        except Exception as e:
                            msg = f"{old_name} の変更に失敗しました: {e}"
                    else:
                        msg = f"{old_name} は存在しません"
        
                    log_lines.append(msg)
                    self.log.insert(tk.END, msg + "\n")
                    self.log.see(tk.END)
        
                self.save_log(log_lines)
        
            def save_log(self, lines):
                now = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
                log_path = os.path.join(self.base_folder, f"{now}.txt")
                try:
                    with open(log_path, "w", encoding="utf-8") as f:
                        f.write("\n".join(lines))
                    self.log.insert(tk.END, f"\nログを保存しました: {log_path}\n")
                except Exception as e:
                    self.log.insert(tk.END, f"\nログ保存に失敗しました: {e}\n")
        
        if __name__ == "__main__":
            root = tk.Tk()
            app = FolderRenamerGUI(root)
            root.mainloop()      
       
    

📦 ダウンロード 🏠 ホームへ