Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

155 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""
图片存储方案迁移脚本
将图片从旧的层级目录结构迁移到新的扁平结构
旧结构: /{module}/{year}/{month}/{filename}
/{module}/{year}/{month}/thumbnails/thumb_{filename}.jpg
新结构: /{filename}
/thumbnails/{filename_stem}.jpg
"""
import os
import sys
import shutil
from pathlib import Path
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker, Session
# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from app.config import get_settings
settings = get_settings()
# 数据库路径
DB_PATH = "./cms.db"
UPLOAD_DIR = Path(settings.UPLOAD_DIR)
def migrate_images():
"""迁移图片路径"""
engine = create_engine(f"sqlite:///{DB_PATH}")
SessionLocal = sessionmaker(bind=engine)
db = SessionLocal()
try:
# 获取所有图片记录
result = db.execute(text("SELECT id, file_path, thumb_path, filename FROM images"))
images = result.fetchall()
print(f"找到 {len(images)} 条图片记录需要迁移")
migrated_count = 0
skipped_count = 0
error_count = 0
for img in images:
try:
img_id = img[0]
old_file_path = img[1] # e.g., /news/2026/04/20260420_121931_b91c5d3a.jpg
old_thumb_path = img[2] # e.g., /news/2026/04/thumbnails/thumb_20260420_121931_b91c5d3a.jpg.jpg
filename = img[3] # e.g., 20260420_121931_b91c5d3a.jpg
# 如果已经是新格式,跳过
if old_file_path.startswith("/") and "/" not in old_file_path.lstrip("/"):
print(f"跳过 (已是新格式): {old_file_path}")
skipped_count += 1
continue
# 新的路径格式
new_file_path = f"/{filename}"
new_thumb_path = f"/thumbnails/{Path(filename).stem}.jpg" if old_thumb_path else None
# 物理文件路径
old_file_full = UPLOAD_DIR / old_file_path.lstrip("/")
new_file_full = UPLOAD_DIR / filename
# 移动原图文件
if old_file_full.exists() and old_file_full != new_file_full:
try:
shutil.move(str(old_file_full), str(new_file_full))
print(f"移动文件: {old_file_full} -> {new_file_full}")
except Exception as e:
print(f"移动文件失败 {old_file_full}: {e}")
error_count += 1
continue
# 处理缩略图
if old_thumb_path:
old_thumb_full = UPLOAD_DIR / old_thumb_path.lstrip("/")
new_thumb_full = UPLOAD_DIR / "thumbnails" / f"{Path(filename).stem}.jpg"
if old_thumb_full.exists() and old_thumb_full != new_thumb_full:
try:
shutil.move(str(old_thumb_full), str(new_thumb_full))
print(f"移动缩略图: {old_thumb_full} -> {new_thumb_full}")
except Exception as e:
print(f"移动缩略图失败 {old_thumb_full}: {e}")
# 更新数据库
db.execute(
text("UPDATE images SET file_path = :new_path, thumb_path = :new_thumb WHERE id = :id"),
{"new_path": new_file_path, "new_thumb": new_thumb_path, "id": img_id}
)
migrated_count += 1
print(f"迁移成功 ID={img_id}: {old_file_path} -> {new_file_path}")
except Exception as e:
print(f"迁移失败 ID={img_id}: {e}")
error_count += 1
db.commit()
print("\n" + "="*60)
print(f"迁移完成!")
print(f"成功: {migrated_count}")
print(f"跳过 (已是新格式): {skipped_count}")
print(f"失败: {error_count}")
print("="*60)
# 清理空目录
cleanup_empty_dirs(UPLOAD_DIR)
except Exception as e:
print(f"迁移过程出错: {e}")
db.rollback()
finally:
db.close()
def cleanup_empty_dirs(root_dir: Path):
"""清理空目录"""
removed_count = 0
for dirpath, dirnames, filenames in os.walk(str(root_dir), topdown=False):
dir_path = Path(dirpath)
# 跳过根目录和 thumbnails 目录
if dir_path == root_dir or dir_path.name == "thumbnails":
continue
# 检查是否为空
try:
if dir_path.exists() and not any(dir_path.iterdir()):
dir_path.rmdir()
print(f"删除空目录: {dir_path}")
removed_count += 1
except Exception as e:
print(f"删除目录失败 {dir_path}: {e}")
print(f"清理完成,共删除 {removed_count} 个空目录")
if __name__ == "__main__":
print("图片存储方案迁移工具")
print("="*60)
print(f"数据库: {DB_PATH}")
print(f"上传目录: {UPLOAD_DIR}")
print("="*60)
confirm = input("\n确定要开始迁移吗? (yes/no): ")
if confirm.lower() == "yes":
migrate_images()
else:
print("已取消迁移")