以下は『黎明ノ再構者』のソースコード全文です:
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()