更新 main.py
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import pathlib
|
||||
import subprocess
|
||||
from io import BytesIO
|
||||
|
||||
current_mode = None
|
||||
|
||||
def force_close_handles(folder_path):
|
||||
try:
|
||||
import psutil
|
||||
closed_count = 0
|
||||
|
||||
for proc in psutil.process_iter(['pid', 'name']):
|
||||
try:
|
||||
for item in proc.open_files():
|
||||
if folder_path.lower() in item.path.lower():
|
||||
proc.kill()
|
||||
closed_count += 1
|
||||
print(f"[系统] 已关闭占用进程: {proc.info['name']} (PID: {proc.info['pid']})")
|
||||
break
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
if closed_count > 0:
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
|
||||
return closed_count > 0
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
def delete_system_files(folder_path):
|
||||
system_files = ['thumbs.db', 'desktop.ini', '.ds_store', 'thumbs.db:encryptable']
|
||||
deleted_count = 0
|
||||
|
||||
try:
|
||||
for root, dirs, files in os.walk(folder_path):
|
||||
for filename in files:
|
||||
if filename.lower() in system_files or filename.startswith('._'):
|
||||
file_path = os.path.join(root, filename)
|
||||
try:
|
||||
os.chmod(file_path, 0o777)
|
||||
os.remove(file_path)
|
||||
deleted_count += 1
|
||||
except:
|
||||
pass
|
||||
|
||||
if deleted_count > 0:
|
||||
print(f"[系统] 已清理 {deleted_count} 个系统隐藏文件")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def get_next_log_index():
|
||||
index = 1
|
||||
while pathlib.Path(f"path_list_{index}.log").exists():
|
||||
index += 1
|
||||
return index
|
||||
|
||||
|
||||
def open_folder(path: pathlib.Path):
|
||||
if sys.platform.startswith("win"):
|
||||
os.startfile(path)
|
||||
elif sys.platform.startswith("darwin"):
|
||||
subprocess.run(["open", path])
|
||||
else:
|
||||
subprocess.run(["xdg-open", path])
|
||||
|
||||
def mode_wb():
|
||||
print("\n" + "="*60)
|
||||
print("已进入 WB 模式 - 文件夹批处理工具")
|
||||
print("功能:复制文件夹 -> 重命名文件夹和内部文件 -> 标记原文件夹")
|
||||
print("="*60)
|
||||
|
||||
while True:
|
||||
print("\n================== 新的工作任务 ==================")
|
||||
work_dir = input("请输入主文件夹路径 (工作路径, 输入 :back 返回): ").strip()
|
||||
|
||||
if work_dir == ":back":
|
||||
return
|
||||
|
||||
if not os.path.exists(work_dir):
|
||||
print(f"[错误] 工作路径 '{work_dir}' 不存在,请先创建或检查路径。")
|
||||
continue
|
||||
|
||||
print(f"[系统] 已锁定工作路径: {work_dir}")
|
||||
|
||||
process_wb_folder(work_dir)
|
||||
|
||||
print("\n------------------------------------------------------")
|
||||
while True:
|
||||
choice = input("任务结束。输入 :back 返回主菜单,或输入 :y 开启下一个工作路径: ").strip().lower()
|
||||
if choice == ":back":
|
||||
return
|
||||
elif choice == ":y":
|
||||
break
|
||||
else:
|
||||
print("输入无效,请输入 :back 或 :y")
|
||||
|
||||
|
||||
def process_wb_folder(work_dir):
|
||||
while True:
|
||||
print("\n------------------------------------------------------")
|
||||
src_path_input = input("请输入待复制的文件夹路径 (输入 :end 结束当前阶段): ").strip()
|
||||
|
||||
if src_path_input == ":end":
|
||||
return
|
||||
|
||||
if not os.path.exists(src_path_input):
|
||||
print(f"[错误] 路径 '{src_path_input}' 不存在,请重新输入。")
|
||||
continue
|
||||
|
||||
target_name = input("请输入想要重命名的名称: ").strip()
|
||||
if not target_name:
|
||||
print("[错误] 名称不能为空。")
|
||||
continue
|
||||
|
||||
dest_path = os.path.join(work_dir, target_name)
|
||||
|
||||
try:
|
||||
if os.path.exists(dest_path):
|
||||
print(f"[错误] 目标文件夹 '{dest_path}' 已经在工作路径下存在,跳过此任务。")
|
||||
continue
|
||||
|
||||
shutil.copytree(src_path_input, dest_path)
|
||||
print(f"[成功] 文件夹已复制并重命名为: {target_name}")
|
||||
|
||||
all_items = os.listdir(dest_path)
|
||||
files = []
|
||||
for f in all_items:
|
||||
full_path = os.path.join(dest_path, f)
|
||||
if os.path.isfile(full_path) and not f.startswith('.') and f.lower() not in ['thumbs.db', 'desktop.ini']:
|
||||
files.append(f)
|
||||
|
||||
files.sort()
|
||||
|
||||
count = 1
|
||||
for filename in files:
|
||||
file_ext = os.path.splitext(filename)[1]
|
||||
new_filename = f"{target_name} {count}{file_ext}"
|
||||
|
||||
old_file_path = os.path.join(dest_path, filename)
|
||||
new_file_path = os.path.join(dest_path, new_filename)
|
||||
|
||||
os.rename(old_file_path, new_file_path)
|
||||
count += 1
|
||||
|
||||
print(f"[成功] 已重命名文件夹内的 {count-1} 个文件 (从 1 开始)。")
|
||||
|
||||
clean_src_path = os.path.normpath(src_path_input)
|
||||
parent_dir = os.path.dirname(clean_src_path)
|
||||
original_folder_name = os.path.basename(clean_src_path)
|
||||
new_src_folder_name = "used_" + original_folder_name
|
||||
used_src_path = os.path.join(parent_dir, new_src_folder_name)
|
||||
|
||||
try:
|
||||
delete_system_files(clean_src_path)
|
||||
|
||||
os.rename(clean_src_path, used_src_path)
|
||||
print(f"[成功] 原文件夹已重命名为: {new_src_folder_name}")
|
||||
except PermissionError:
|
||||
print(f"[警告] 文件夹被占用,尝试强制解锁...")
|
||||
if force_close_handles(clean_src_path):
|
||||
try:
|
||||
os.rename(clean_src_path, used_src_path)
|
||||
print(f"[成功] 原文件夹已重命名为: {new_src_folder_name}")
|
||||
except Exception as e:
|
||||
print(f"[警告] 解锁后仍无法重命名: {e}")
|
||||
print(f" 原文件夹路径: {clean_src_path}")
|
||||
else:
|
||||
print(f"[警告] 无法重命名原文件夹为 used_ 开头(需要安装psutil库)")
|
||||
print(f" 安装命令: python.exe -m pip install psutil --break-system-packages")
|
||||
print(f" 原文件夹路径: {clean_src_path}")
|
||||
except FileExistsError:
|
||||
print(f"[警告] 目标名称 '{new_src_folder_name}' 已存在,跳过重命名")
|
||||
except Exception as e:
|
||||
print(f"[警告] 重命名原文件夹时出错: {e}")
|
||||
|
||||
except PermissionError:
|
||||
print(f"[错误] 权限不足,无法访问或复制文件夹")
|
||||
except Exception as e:
|
||||
print(f"[异常] 发生未知错误: {e}")
|
||||
|
||||
|
||||
def mode_path():
|
||||
print("\n" + "="*60)
|
||||
print("已进入 PATH 模式 - 文件夹批量创建工具")
|
||||
print("操作指南:")
|
||||
print("1. 输入路径后按回车 -> 加入待创建队列")
|
||||
print("2. 输入 ':y' 并回车 -> 立即批量创建队列中所有文件夹")
|
||||
print("3. 输入 ':open x' -> 打开 path_list_x.log 中的所有文件夹")
|
||||
print("4. 输入 ':back' -> 返回主菜单")
|
||||
print("="*60 + "\n")
|
||||
|
||||
path_queue = []
|
||||
|
||||
while True:
|
||||
queue_count = len(path_queue)
|
||||
prompt = f"[{queue_count} 个待创建] >>> 请输入路径: "
|
||||
raw_path = input(prompt).strip()
|
||||
|
||||
if raw_path.lower().startswith(":open"):
|
||||
parts = raw_path.split()
|
||||
if len(parts) != 2 or not parts[1].isdigit():
|
||||
print("用法错误,应为 :open x")
|
||||
continue
|
||||
|
||||
log_index = parts[1]
|
||||
log_file = pathlib.Path(f"path_list_{log_index}.log")
|
||||
|
||||
if not log_file.exists():
|
||||
print(f"日志文件不存在: {log_file}")
|
||||
continue
|
||||
|
||||
print(f"正在打开 {log_file} 中的文件夹...")
|
||||
with log_file.open("r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
folder = pathlib.Path(line.strip())
|
||||
if folder.exists():
|
||||
open_folder(folder)
|
||||
else:
|
||||
print(f"路径不存在,已跳过: {folder}")
|
||||
continue
|
||||
|
||||
if raw_path.lower() == ':y':
|
||||
if not path_queue:
|
||||
print("警告:队列为空,没有什么可创建的。")
|
||||
print("-" * 30)
|
||||
continue
|
||||
|
||||
print(f"\n开始执行批量创建,共 {len(path_queue)} 个任务...")
|
||||
success_count = 0
|
||||
created_paths = []
|
||||
|
||||
for p_str in path_queue:
|
||||
target_path = pathlib.Path(p_str)
|
||||
try:
|
||||
target_path.mkdir(parents=True, exist_ok=True)
|
||||
print(f" [OK] Created: {target_path}")
|
||||
success_count += 1
|
||||
created_paths.append(str(target_path))
|
||||
except Exception as e:
|
||||
print(f" [ERR] Failed: {target_path} | 原因: {e}")
|
||||
|
||||
print(f"\n执行完毕。成功: {success_count} / 总计: {len(path_queue)}")
|
||||
|
||||
log_index = get_next_log_index()
|
||||
log_file = pathlib.Path(f"path_list_{log_index}.log")
|
||||
with log_file.open("w", encoding="utf-8") as f:
|
||||
for p in created_paths:
|
||||
f.write(p + "\n")
|
||||
print(f"已生成日志文件: {log_file}")
|
||||
|
||||
print("-" * 30)
|
||||
path_queue.clear()
|
||||
continue
|
||||
|
||||
if raw_path.lower() == ':back':
|
||||
if path_queue:
|
||||
confirm = input(f"队列中还有 {len(path_queue)} 个路径未创建,确定要返回吗?(y/n): ")
|
||||
if confirm.lower() != 'y':
|
||||
continue
|
||||
return
|
||||
|
||||
if not raw_path:
|
||||
continue
|
||||
|
||||
path_queue.append(raw_path)
|
||||
print(f"已加入队列: '{raw_path}'")
|
||||
print("-" * 20)
|
||||
|
||||
|
||||
def mode_photo():
|
||||
print("\n" + "="*60)
|
||||
print("已进入 PHOTO 模式 - 图片左右镜像工具")
|
||||
print("功能:批量将文件夹中的所有图片进行左右镜像翻转")
|
||||
print("支持格式:.jpg, .jpeg, .png, .bmp, .gif, .webp, .tif, .tiff")
|
||||
print("操作指南:")
|
||||
print("1. 输入文件夹路径后按回车 -> 加入待处理队列")
|
||||
print("2. 输入 ':y' 并回车 -> 批量处理队列中所有文件夹的图片")
|
||||
print("3. 输入 ':back' -> 返回主菜单")
|
||||
print("="*60 + "\n")
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print("[错误] 未检测到 Pillow 库!")
|
||||
print("请先安装 Pillow:")
|
||||
print(" python.exe -m pip install pillow")
|
||||
print("或者手动下载 pillow 的 .whl 文件后安装")
|
||||
input("\n按回车返回主菜单...")
|
||||
return
|
||||
|
||||
folder_queue = []
|
||||
supported_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp', '.tif', '.tiff'}
|
||||
|
||||
while True:
|
||||
queue_count = len(folder_queue)
|
||||
prompt = f"[{queue_count} 个文件夹待处理] >>> 请输入文件夹路径: "
|
||||
folder_path = input(prompt).strip()
|
||||
|
||||
if folder_path.lower() == ':y':
|
||||
if not folder_queue:
|
||||
print("警告:队列为空,没有什么可处理的。")
|
||||
print("-" * 30)
|
||||
continue
|
||||
|
||||
print(f"\n开始执行图片镜像处理,共 {len(folder_queue)} 个文件夹...")
|
||||
|
||||
for folder in folder_queue:
|
||||
print(f"\n处理文件夹: {folder}")
|
||||
if not os.path.exists(folder):
|
||||
print(f" [警告] 文件夹不存在,跳过")
|
||||
continue
|
||||
|
||||
if not os.path.isdir(folder):
|
||||
print(f" [警告] 路径不是文件夹,跳过")
|
||||
continue
|
||||
|
||||
image_count = 0
|
||||
error_count = 0
|
||||
|
||||
for filename in os.listdir(folder):
|
||||
file_path = os.path.join(folder, filename)
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
_, ext = os.path.splitext(filename)
|
||||
if ext.lower() not in supported_extensions:
|
||||
continue
|
||||
|
||||
try:
|
||||
if ext.lower() in ['.tif', '.tiff']:
|
||||
with open(file_path, 'rb') as f:
|
||||
img_data = f.read()
|
||||
|
||||
img = Image.open(BytesIO(img_data))
|
||||
|
||||
flipped_img = img.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
|
||||
output = BytesIO()
|
||||
flipped_img.save(output, format='TIFF')
|
||||
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(output.getvalue())
|
||||
else:
|
||||
img = Image.open(file_path)
|
||||
flipped_img = img.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
flipped_img.save(file_path)
|
||||
|
||||
print(f" [OK] {filename}")
|
||||
image_count += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f" [ERR] {filename} | 原因: {e}")
|
||||
error_count += 1
|
||||
|
||||
print(f" 文件夹处理完毕。成功: {image_count}, 失败: {error_count}")
|
||||
|
||||
print(f"\n全部执行完毕!共处理 {len(folder_queue)} 个文件夹。")
|
||||
print("-" * 30)
|
||||
folder_queue.clear()
|
||||
continue
|
||||
|
||||
if folder_path.lower() == ':back':
|
||||
if folder_queue:
|
||||
confirm = input(f"队列中还有 {len(folder_queue)} 个文件夹未处理,确定要返回吗?(y/n): ")
|
||||
if confirm.lower() != 'y':
|
||||
continue
|
||||
return
|
||||
|
||||
if not folder_path:
|
||||
continue
|
||||
|
||||
folder_queue.append(folder_path)
|
||||
print(f"已加入队列: '{folder_path}'")
|
||||
print("-" * 20)
|
||||
|
||||
|
||||
def print_main_menu():
|
||||
print("\n" + "="*60)
|
||||
print(" 集成工具箱 by FlandreScarle7")
|
||||
print("="*60)
|
||||
print("可用模式:")
|
||||
print(" :mode wb - 文件夹批处理工具 (复制、重命名、标记)")
|
||||
print(" :mode path - 文件夹批量创建工具")
|
||||
print(" :mode photo - 图片左右镜像工具")
|
||||
print(" :exit - 退出程序")
|
||||
print("="*60)
|
||||
|
||||
|
||||
def main():
|
||||
print_main_menu()
|
||||
|
||||
while True:
|
||||
command = input("\n>>> 请输入命令: ").strip().lower()
|
||||
|
||||
if command == ":exit":
|
||||
print("[系统] 程序已退出。")
|
||||
sys.exit(0)
|
||||
|
||||
elif command == ":mode wb":
|
||||
mode_wb()
|
||||
print_main_menu()
|
||||
|
||||
elif command == ":mode path":
|
||||
mode_path()
|
||||
print_main_menu()
|
||||
|
||||
elif command == ":mode photo":
|
||||
mode_photo()
|
||||
print_main_menu()
|
||||
|
||||
elif command == ":help":
|
||||
print_main_menu()
|
||||
|
||||
else:
|
||||
print("[错误] 未知命令。请输入 :mode wb / :mode path / :mode photo / :exit")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n[系统] 程序被强制中断。")
|
||||
sys.exit(0)
|
||||
Reference in New Issue
Block a user