100 lines
3.9 KiB
Python
100 lines
3.9 KiB
Python
import os
|
|
import re
|
|
from datetime import datetime
|
|
|
|
# ====================== 【配置区,请修改】 ======================
|
|
MEDIA_FOLDER = "/Volumes/JoyDisk/myMedia/olstrms/电影/未分类/2025" # Mac挂载NAS路径
|
|
# MEDIA_FOLDER = "/media/movies" # 飞牛容器内运行用这个
|
|
|
|
DRY_RUN = True # True=预览,不修改;确认无误改为False执行改名
|
|
SKIP_PROCESSED = False # True=跳过已处理(文件名含(20xx)年份)
|
|
LOG_FILE = "./rename_log.txt"
|
|
# =================================================================
|
|
|
|
# 清洗正则规则(文件夹、文件共用一套)
|
|
RULES = [
|
|
(r"^[A-Za-z] ", ""), # 【新增】移除开头单个英文字母+空格:A 流浪地球 → 流浪地球
|
|
(r"(?<=[a-zA-Z0-9])\.(?=[a-zA-Z0-9])", " "), # Dune.Part → Dune Part
|
|
(r"\[.*?\]", ""), # 删除全部 [xxx] 方括号内容
|
|
(r"\s*(2160p|1080p|720p|HDR|DV|DoVi|HEVC|x265|x264|DDP|AAC|Atmos|TrueHD)\b", ""),
|
|
(r"\.+", " "), # 剩下连续多个点替换成空格
|
|
]
|
|
|
|
# 支持的文件后缀
|
|
ALLOW_EXT = {".mkv", ".mp4", ".mov", ".srt", ".ass", ".sub"}
|
|
|
|
def clean_name(name: str) -> str:
|
|
"""统一清洗函数,文件夹名、文件名共用"""
|
|
name_no_ext, ext = os.path.splitext(name)
|
|
|
|
# 处理 A . B . C 这种「字母 空格 . 空格 字母」
|
|
while re.search(r"(\w) \. (\w)", name_no_ext):
|
|
name_no_ext = re.sub(r"(\w) \. (\w)", r"\1\2", name_no_ext)
|
|
|
|
# 执行所有正则替换规则
|
|
for pattern, repl in RULES:
|
|
name_no_ext = re.sub(pattern, repl, name_no_ext)
|
|
|
|
# 合并连续空格,去除首尾空格
|
|
name_no_ext = re.sub(r"\s+", " ", name_no_ext).strip()
|
|
return name_no_ext + ext
|
|
|
|
def write_log(msg: str):
|
|
time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
line = f"[{time_str}] {msg}"
|
|
print(line)
|
|
with open(LOG_FILE, "a", encoding="utf-8") as f:
|
|
f.write(line + "\n")
|
|
|
|
if __name__ == "__main__":
|
|
write_log("===== 文件名+文件夹清洗(移除开头A 中文片名前缀) =====")
|
|
write_log(f"根目录:{MEDIA_FOLDER}")
|
|
write_log(f"预览模式 DRY_RUN = {DRY_RUN}")
|
|
|
|
dir_rename_list = []
|
|
file_rename_list = []
|
|
|
|
# 遍历收集(自底向上,防止目录路径错乱)
|
|
for root, dirs, files in os.walk(MEDIA_FOLDER, topdown=False):
|
|
# 文件
|
|
for fname in files:
|
|
ext = os.path.splitext(fname)[1].lower()
|
|
if ext not in ALLOW_EXT:
|
|
continue
|
|
new_name = clean_name(fname)
|
|
if new_name != fname:
|
|
if SKIP_PROCESSED and re.search(r"\(\d{4}\)", new_name):
|
|
write_log(f"跳过文件(疑似已处理): {fname}")
|
|
continue
|
|
old_path = os.path.join(root, fname)
|
|
new_path = os.path.join(root, new_name)
|
|
file_rename_list.append((old_path, new_path))
|
|
|
|
# 文件夹
|
|
for dname in dirs:
|
|
new_name = clean_name(dname)
|
|
if new_name != dname:
|
|
if SKIP_PROCESSED and re.search(r"\(\d{4}\)", new_name):
|
|
write_log(f"跳过文件夹(疑似已处理): {dname}")
|
|
continue
|
|
old_path = os.path.join(root, dname)
|
|
new_path = os.path.join(root, new_name)
|
|
dir_rename_list.append((old_path, new_name))
|
|
|
|
# 先改文件夹,再改文件
|
|
dir_count = 0
|
|
for old, new in dir_rename_list:
|
|
write_log(f"【文件夹】{os.path.basename(old)} → {os.path.basename(new)}")
|
|
dir_count +=1
|
|
if not DRY_RUN:
|
|
os.rename(old, new)
|
|
|
|
file_count =0
|
|
for old, new in file_rename_list:
|
|
write_log(f"【文件】{os.path.basename(old)} → {os.path.basename(new)}")
|
|
file_count +=1
|
|
if not DRY_RUN:
|
|
os.rename(old, new)
|
|
|
|
write_log(f"任务完成,待修改文件夹:{dir_count},待修改文件:{file_count}")
|
|
write_log("="*60 + "\n") |