
FAGO – Ngày 07/09/2026 – 21h30-10h30 (qua đêm)
286.000 ₫
Còn hàng
from pathlib import Path from datetime import datetime import subprocess import platform import re from openpyxl import Workbook, load_workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side EXCEL_NAME = "0. DanhMucRename.xlsx" # DanhMuc DM_HEADER_ROW = 5 DM_DATA_START = 6 # Frozen columns (1-indexed) FR_STT = 1 # A FR_TEN_GOC = 2 # B tên file gốc FR_TEN_MOI = 3 # C tên file mới — người/Claude điền vào Frozen FR_OLD_PATH = 4 # D đường dẫn đầy đủ gốc FR_NEW_PATH = 5 # E đường dẫn đầy đủ mới (Python ghi sau rename) FR_STATUS = 6 # F DONE / ERROR / SKIP FR_GHI_CHU = 7 # G lỗi hoặc ghi chú FR_NGAY = 8 # H ngày xử lý # ===================================================== # BASIC # ===================================================== def clean_path(raw_path: str) -> str: return raw_path.strip().strip("'").strip('"').replace("\\ ", " ") def ask_folder() -> Path: while True: raw = input("Dán đường dẫn thư mục cần xử lý: ") folder = Path(clean_path(raw)).expanduser() if folder.exists() and folder.is_dir(): return folder print("Không tìm thấy thư mục. Nhập lại.") def open_file(path: Path): system = platform.system() if system == "Darwin": subprocess.run(["open", str(path)]) elif system == "Windows": subprocess.run(["start", str(path)], shell=True) else: subprocess.run(["xdg-open", str(path)]) def safe_filename(name: str) -> str: name = str(name or "").strip() name = re.sub(r'[\\/:*?"<>|]', "-", name) name = re.sub(r"\s+", " ", name) return name def scan_files(folder: Path) -> list[Path]: return sorted( [ item for item in folder.iterdir() if item.is_file() and item.name != EXCEL_NAME ], key=lambda x: x.name.lower() ) # ===================================================== # EXCEL STYLE — DanhMuc # ===================================================== def style_danhmuc(ws): header_fill = PatternFill("solid", fgColor="1F4E78") header_font = Font(color="FFFFFF", bold=True) thin = Side(style="thin", color="D9E2F3") border = Border(left=thin, right=thin, top=thin, bottom=thin) ws.freeze_panes = "A6" for cell in ws[DM_HEADER_ROW]: cell.fill = header_fill cell.font = header_font cell.alignment = Alignment(horizontal="center", vertical="center") cell.border = border for row in ws.iter_rows(min_row=DM_HEADER_ROW): for cell in row: cell.border = border cell.alignment = Alignment(vertical="center", wrap_text=True) ws.column_dimensions["A"].width = 8 ws.column_dimensions["B"].width = 40 for col in "CDEFGHIJKLMNOPQRSTUVW": ws.column_dimensions[col].width = 25 # ===================================================== # EXCEL STYLE — Frozen # ===================================================== def style_frozen(ws): header_fill = PatternFill("solid", fgColor="4A4A4A") header_font = Font(color="FFFFFF", bold=True) thin = Side(style="thin", color="AAAAAA") border = Border(left=thin, right=thin, top=thin, bottom=thin) ws.freeze_panes = "A2" for cell in ws[1]: cell.fill = header_fill cell.font = header_font cell.alignment = Alignment(horizontal="center", vertical="center") cell.border = border for row in ws.iter_rows(min_row=2): for cell in row: cell.border = border cell.alignment = Alignment(vertical="center", wrap_text=True) ws.column_dimensions["A"].width = 8 ws.column_dimensions["B"].width = 55 # ten_file_goc ws.column_dimensions["C"].width = 55 # ten_file_moi ws.column_dimensions["D"].width = 80 # old_path ws.column_dimensions["E"].width = 80 # new_path ws.column_dimensions["F"].width = 15 # trang_thai ws.column_dimensions["G"].width = 50 # ghi_chu ws.column_dimensions["H"].width = 22 # ngay_xu_ly # ===================================================== # CREATE EXCEL # ===================================================== def create_excel_catalog(folder: Path) -> Path: excel_path = folder / EXCEL_NAME files = scan_files(folder) wb = Workbook() # ── Sheet 1: DanhMuc ────────────────────────────── ws = wb.active ws.title = "DanhMuc" for _ in range(4): ws.append([""]) # Row 5: header — B = ID, C→W tự do theo nghiệp vụ headers = [""] * 23 headers[0] = "STT" # A headers[1] = "ID" # B — Claude điền tùy ngữ cảnh ws.append(headers) for idx, _ in enumerate(files, start=1): row = [""] * 23 row[0] = idx ws.append(row) style_danhmuc(ws) # ── Sheet 2: Frozen (hidden) ────────────────────── fr = wb.create_sheet("Frozen") fr.append([ "STT", # A "ten_file_goc", # B "ten_file_moi", # C ← người/Claude điền tên mới tại đây "old_path", # D "new_path", # E "trang_thai", # F "ghi_chu", # G "ngay_xu_ly", # H ]) for idx, file_path in enumerate(files, start=1): fr.append([ idx, file_path.name, "", # C: ten_file_moi — để trống, chờ điền str(file_path), # D: old_path đầy đủ "", "", "", "", ]) style_frozen(fr) fr.sheet_state = "hidden" wb.save(excel_path) return excel_path # ===================================================== # READ PLAN # ===================================================== def read_plan(excel_path: Path): wb = load_workbook(excel_path) fr = wb["Frozen"] plan = [] for fr_row in range(2, fr.max_row + 1): stt = fr.cell(row=fr_row, column=FR_STT).value ten_file_goc = fr.cell(row=fr_row, column=FR_TEN_GOC).value ten_file_moi = fr.cell(row=fr_row, column=FR_TEN_MOI).value old_path_str = fr.cell(row=fr_row, column=FR_OLD_PATH).value if not ten_file_goc or not old_path_str: continue old_path = Path(old_path_str) if not ten_file_moi: fr.cell(row=fr_row, column=FR_STATUS).value = "SKIP" fr.cell(row=fr_row, column=FR_GHI_CHU).value = "Chưa nhập tên file mới" continue ten_file_moi = safe_filename(str(ten_file_moi)) if "." not in Path(ten_file_moi).name: ten_file_moi += old_path.suffix new_path = old_path.parent / ten_file_moi plan.append({ "fr_row": fr_row, "stt": stt, "old_path": old_path, "new_path": new_path, }) return wb, fr, plan # ===================================================== # AUDIT # ===================================================== def audit_plan(plan: list[dict]) -> bool: print("\n===== PREVIEW RENAME =====") safe = True new_names = {} for item in plan: old_path = item["old_path"] new_path = item["new_path"] print(f"{old_path.name}") print(f" -> {new_path.name}") print("-" * 60) if not old_path.exists(): print(f"LỖI: Không tìm thấy file gốc: {old_path.name}") safe = False if new_path.exists() and new_path.name != old_path.name: print(f"LỖI: Tên mới đã tồn tại: {new_path.name}") safe = False if new_path.name in new_names: print(f"LỖI: Trùng tên mới: {new_path.name}") safe = False new_names[new_path.name] = True if not plan: print("Không có dòng nào đủ điều kiện rename.") safe = False return safe # ===================================================== # APPLY RENAME # ===================================================== def apply_rename(wb, fr, plan: list[dict], excel_path: Path): done_fill = PatternFill("solid", fgColor="C6EFCE") error_fill = PatternFill("solid", fgColor="FFC7CE") now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") for item in plan: fr_row = item["fr_row"] old_path = item["old_path"] new_path = item["new_path"] try: old_path.rename(new_path) fr.cell(row=fr_row, column=FR_NEW_PATH).value = str(new_path) fr.cell(row=fr_row, column=FR_STATUS).value = "DONE" fr.cell(row=fr_row, column=FR_GHI_CHU).value = "" fr.cell(row=fr_row, column=FR_NGAY).value = now fr.cell(row=fr_row, column=FR_STATUS).fill = done_fill print(f"Đã rename: {old_path.name} -> {new_path.name}") except Exception as e: fr.cell(row=fr_row, column=FR_STATUS).value = "ERROR" fr.cell(row=fr_row, column=FR_GHI_CHU).value = str(e) fr.cell(row=fr_row, column=FR_NGAY).value = now fr.cell(row=fr_row, column=FR_STATUS).fill = error_fill print(f"LỖI: {old_path.name}: {e}") style_frozen(fr) fr.sheet_state = "hidden" wb.save(excel_path) # ===================================================== # MAIN # ===================================================== def main(): folder = ask_folder() excel_path = folder / EXCEL_NAME if excel_path.exists(): print("\nĐã có file Excel.") print("1. Mở Excel hiện có") print("2. Tạo mới Excel (ghi đè)") choice = input("Chọn 1 hoặc 2: ").strip() if choice == "2": excel_path = create_excel_catalog(folder) else: excel_path = create_excel_catalog(folder) print(f"\nĐã tạo/mở: {excel_path}") open_file(excel_path) print("\nHướng dẫn:") print(" Sheet DanhMuc : Claude điền ID (cột B) + metadata (C→W)") print(" Sheet Frozen : điền tên file mới vào cột C (ten_file_moi)") print(" Sau khi điền xong: Cmd+S → Đóng Excel → Quay lại Terminal") input("\nBấm Enter để tiếp tục rename...") wb, fr, plan = read_plan(excel_path) if not audit_plan(plan): wb.save(excel_path) return confirm = input("\nĐồng ý rename thật không? y/n: ").strip().lower() if confirm not in ["y", "yes", "co", "có"]: print("Đã huỷ.") return apply_rename(wb, fr, plan, excel_path) print("\nDone.") if __name__ == "__main__": main()

286.000 ₫
Còn hàng