
- Removed YuMi/Library/ (138 MB, not tracked) - Removed YuMi/Resources/ (23 MB, not tracked) - Removed old version assets (566 files, not tracked) - Excluded Pods/, xcuserdata/ and other build artifacts - Clean repository optimized for company server deployment
337 lines
12 KiB
Python
Executable File
337 lines
12 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
图片资源批量处理脚本
|
||
用法: python3 2_rename_assets.py
|
||
"""
|
||
|
||
import os
|
||
import json
|
||
import hashlib
|
||
import shutil
|
||
from pathlib import Path
|
||
from typing import Dict, List, Set
|
||
import re
|
||
|
||
# 颜色输出
|
||
class Colors:
|
||
GREEN = '\033[92m'
|
||
YELLOW = '\033[93m'
|
||
RED = '\033[91m'
|
||
BLUE = '\033[94m'
|
||
END = '\033[0m'
|
||
|
||
# 配置
|
||
PROJECT_ROOT = "/Users/edwinqqq/Local/Company Projects/peko-ios"
|
||
ASSETS_DIR = os.path.join(PROJECT_ROOT, "YuMi/Assets.xcassets")
|
||
SOURCE_DIR = os.path.join(PROJECT_ROOT, "YuMi")
|
||
BACKUP_DIR = os.path.join(PROJECT_ROOT, "issues/temp_rename/assets_backup")
|
||
MAPPING_FILE = os.path.join(PROJECT_ROOT, "issues/temp_rename/asset_name_mapping.json")
|
||
|
||
# 存储映射关系
|
||
asset_mapping: Dict[str, str] = {}
|
||
|
||
def print_header(text):
|
||
"""打印标题"""
|
||
print(f"\n{Colors.GREEN}{'='*50}{Colors.END}")
|
||
print(f"{Colors.GREEN}{text}{Colors.END}")
|
||
print(f"{Colors.GREEN}{'='*50}{Colors.END}\n")
|
||
|
||
def print_info(text):
|
||
"""打印信息"""
|
||
print(f"{Colors.BLUE}ℹ️ {text}{Colors.END}")
|
||
|
||
def print_warning(text):
|
||
"""打印警告"""
|
||
print(f"{Colors.YELLOW}⚠️ {text}{Colors.END}")
|
||
|
||
def print_error(text):
|
||
"""打印错误"""
|
||
print(f"{Colors.RED}❌ {text}{Colors.END}")
|
||
|
||
def print_success(text):
|
||
"""打印成功"""
|
||
print(f"{Colors.GREEN}✓ {text}{Colors.END}")
|
||
|
||
def generate_new_name(old_name: str, index: int) -> str:
|
||
"""
|
||
生成新的资源名称
|
||
策略:使用语义化的随机名称,而不是完全随机
|
||
"""
|
||
# 提取原名称中的关键信息
|
||
parts = old_name.lower().split('_')
|
||
|
||
# 常见的UI元素映射
|
||
element_map = {
|
||
'icon': ['symbol', 'mark', 'sign', 'emblem'],
|
||
'button': ['btn', 'action', 'control', 'press'],
|
||
'background': ['bg', 'backdrop', 'layer', 'base'],
|
||
'avatar': ['profile', 'face', 'user', 'photo'],
|
||
'banner': ['header', 'top', 'promo', 'ad'],
|
||
'gift': ['present', 'reward', 'prize', 'bonus'],
|
||
'room': ['space', 'zone', 'area', 'hall'],
|
||
'home': ['main', 'index', 'start', 'feed'],
|
||
'message': ['msg', 'chat', 'talk', 'dialog'],
|
||
'mine': ['profile', 'me', 'personal', 'user'],
|
||
'login': ['signin', 'auth', 'entry', 'access'],
|
||
'arrow': ['pointer', 'indicator', 'direction', 'nav'],
|
||
'close': ['dismiss', 'exit', 'cancel', 'remove'],
|
||
'back': ['return', 'previous', 'prev', 'retreat'],
|
||
'next': ['forward', 'proceed', 'continue', 'advance'],
|
||
'play': ['start', 'run', 'launch', 'begin'],
|
||
'pause': ['stop', 'halt', 'freeze', 'wait'],
|
||
'more': ['additional', 'extra', 'plus', 'expand'],
|
||
}
|
||
|
||
# 尝试替换关键词
|
||
new_parts = []
|
||
for part in parts:
|
||
replaced = False
|
||
for key, alternatives in element_map.items():
|
||
if key in part:
|
||
# 使用 index 作为种子选择一个替代词
|
||
alt_index = (index + hash(part)) % len(alternatives)
|
||
new_part = part.replace(key, alternatives[alt_index])
|
||
new_parts.append(new_part)
|
||
replaced = True
|
||
break
|
||
if not replaced:
|
||
# 保留数字和常见后缀
|
||
if part.isdigit() or part in ['selected', 'normal', 'disabled', 'active', 'inactive']:
|
||
new_parts.append(part)
|
||
else:
|
||
# 使用简单的字符替换
|
||
new_part = ''.join([chr((ord(c) - 97 + 13) % 26 + 97) if c.isalpha() else c for c in part])
|
||
new_parts.append(new_part)
|
||
|
||
new_name = '_'.join(new_parts)
|
||
|
||
# 如果生成的名称和原名称一样,添加一个后缀
|
||
if new_name == old_name:
|
||
new_name = f"asset_{hashlib.md5(old_name.encode()).hexdigest()[:8]}"
|
||
|
||
return new_name
|
||
|
||
def backup_assets():
|
||
"""备份原始资源"""
|
||
print_header("第1步:备份原始资源")
|
||
|
||
if os.path.exists(BACKUP_DIR):
|
||
print_warning("备份目录已存在,将覆盖...")
|
||
shutil.rmtree(BACKUP_DIR)
|
||
|
||
print_info(f"正在备份 {ASSETS_DIR} 到 {BACKUP_DIR} ...")
|
||
shutil.copytree(ASSETS_DIR, BACKUP_DIR)
|
||
print_success(f"备份完成!")
|
||
|
||
def scan_imagesets() -> List[str]:
|
||
"""扫描所有 .imageset 目录"""
|
||
print_header("第2步:扫描图片资源")
|
||
|
||
imagesets = []
|
||
for root, dirs, files in os.walk(ASSETS_DIR):
|
||
for dir_name in dirs:
|
||
if dir_name.endswith('.imageset'):
|
||
full_path = os.path.join(root, dir_name)
|
||
imagesets.append(full_path)
|
||
|
||
print_success(f"找到 {len(imagesets)} 个图片资源")
|
||
return imagesets
|
||
|
||
def rename_imageset(imageset_path: str, index: int) -> tuple:
|
||
"""
|
||
重命名单个 imageset
|
||
返回 (old_name, new_name)
|
||
"""
|
||
dir_name = os.path.basename(imageset_path)
|
||
old_name = dir_name.replace('.imageset', '')
|
||
|
||
# 跳过 AppIcon
|
||
if 'AppIcon' in old_name:
|
||
print_info(f"跳过 AppIcon: {old_name}")
|
||
return (old_name, old_name)
|
||
|
||
# 生成新名称
|
||
new_name = generate_new_name(old_name, index)
|
||
new_dir_name = f"{new_name}.imageset"
|
||
new_path = os.path.join(os.path.dirname(imageset_path), new_dir_name)
|
||
|
||
# 重命名目录
|
||
try:
|
||
os.rename(imageset_path, new_path)
|
||
|
||
# 更新 Contents.json
|
||
contents_json = os.path.join(new_path, 'Contents.json')
|
||
if os.path.exists(contents_json):
|
||
with open(contents_json, 'r', encoding='utf-8') as f:
|
||
data = json.load(f)
|
||
|
||
# 更新图片文件名引用
|
||
for image in data.get('images', []):
|
||
if 'filename' in image:
|
||
old_filename = image['filename']
|
||
if old_name in old_filename:
|
||
new_filename = old_filename.replace(old_name, new_name)
|
||
# 重命名实际的图片文件
|
||
old_file_path = os.path.join(new_path, old_filename)
|
||
new_file_path = os.path.join(new_path, new_filename)
|
||
if os.path.exists(old_file_path):
|
||
os.rename(old_file_path, new_file_path)
|
||
image['filename'] = new_filename
|
||
|
||
# 写回 Contents.json
|
||
with open(contents_json, 'w', encoding='utf-8') as f:
|
||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||
|
||
return (old_name, new_name)
|
||
|
||
except Exception as e:
|
||
print_error(f"重命名失败 {old_name}: {str(e)}")
|
||
return (old_name, old_name)
|
||
|
||
def rename_all_imagesets():
|
||
"""批量重命名所有图片资源"""
|
||
print_header("第3步:批量重命名图片资源")
|
||
|
||
imagesets = scan_imagesets()
|
||
total = len(imagesets)
|
||
success_count = 0
|
||
|
||
for index, imageset_path in enumerate(imagesets, 1):
|
||
old_name, new_name = rename_imageset(imageset_path, index)
|
||
|
||
if old_name != new_name:
|
||
asset_mapping[old_name] = new_name
|
||
success_count += 1
|
||
|
||
# 显示进度
|
||
if index % 100 == 0:
|
||
print_info(f"进度: {index}/{total} ({index*100//total}%)")
|
||
|
||
print_success(f"完成!成功重命名 {success_count} 个资源")
|
||
|
||
# 保存映射关系
|
||
os.makedirs(os.path.dirname(MAPPING_FILE), exist_ok=True)
|
||
with open(MAPPING_FILE, 'w', encoding='utf-8') as f:
|
||
json.dump(asset_mapping, f, indent=2, ensure_ascii=False)
|
||
|
||
print_success(f"映射关系已保存到: {MAPPING_FILE}")
|
||
|
||
def update_code_references():
|
||
"""更新代码中的图片资源引用"""
|
||
print_header("第4步:更新代码引用")
|
||
|
||
print_warning("这一步需要手动处理,因为图片引用方式多样")
|
||
print_info("常见的引用方式:")
|
||
print(" 1. [UIImage imageNamed:@\"old_name\"]")
|
||
print(" 2. UIImage(named: \"old_name\")")
|
||
print(" 3. @\"old_name\"")
|
||
print("")
|
||
|
||
# 生成替换脚本
|
||
replace_script = os.path.join(PROJECT_ROOT, "issues/temp_rename/replace_image_refs.sh")
|
||
|
||
with open(replace_script, 'w') as f:
|
||
f.write("#!/bin/bash\n")
|
||
f.write("# 自动生成的图片引用替换脚本\n\n")
|
||
f.write(f"SOURCE_DIR=\"{SOURCE_DIR}\"\n\n")
|
||
|
||
for old_name, new_name in asset_mapping.items():
|
||
# 转义特殊字符
|
||
old_escaped = old_name.replace('"', '\\"')
|
||
new_escaped = new_name.replace('"', '\\"')
|
||
|
||
f.write(f"# {old_name} → {new_name}\n")
|
||
f.write(f"find \"$SOURCE_DIR\" -type f \\( -name \"*.m\" -o -name \"*.h\" -o -name \"*.swift\" \\) -exec sed -i '' 's/@\"{old_escaped}\"/@\"{new_escaped}\"/g' {{}} +\n")
|
||
f.write(f"find \"$SOURCE_DIR\" -type f \\( -name \"*.m\" -o -name \"*.h\" -o -name \"*.swift\" \\) -exec sed -i '' 's/\"{old_escaped}\"/\"{new_escaped}\"/g' {{}} +\n\n")
|
||
|
||
os.chmod(replace_script, 0o755)
|
||
print_success(f"替换脚本已生成: {replace_script}")
|
||
print_warning("请手动执行该脚本进行代码替换")
|
||
|
||
def generate_report():
|
||
"""生成替换报告"""
|
||
print_header("第5步:生成报告")
|
||
|
||
report_file = os.path.join(PROJECT_ROOT, "issues/temp_rename/assets_rename_report.txt")
|
||
|
||
with open(report_file, 'w', encoding='utf-8') as f:
|
||
f.write("=" * 60 + "\n")
|
||
f.write("图片资源批量重命名报告\n")
|
||
f.write("=" * 60 + "\n\n")
|
||
f.write(f"执行时间: {os.popen('date').read()}\n")
|
||
f.write(f"总共处理: {len(asset_mapping)} 个资源\n\n")
|
||
f.write("=" * 60 + "\n")
|
||
f.write("重命名映射(前50个):\n")
|
||
f.write("=" * 60 + "\n\n")
|
||
|
||
count = 0
|
||
for old_name, new_name in asset_mapping.items():
|
||
f.write(f"{old_name:40} → {new_name}\n")
|
||
count += 1
|
||
if count >= 50:
|
||
f.write(f"\n... 还有 {len(asset_mapping) - 50} 个资源\n")
|
||
break
|
||
|
||
f.write("\n" + "=" * 60 + "\n")
|
||
f.write("下一步操作:\n")
|
||
f.write("=" * 60 + "\n\n")
|
||
f.write("1. 执行生成的替换脚本更新代码引用\n")
|
||
f.write("2. 在 Xcode 中清理并重新构建项目\n")
|
||
f.write("3. 运行应用,检查所有图片是否正常显示\n")
|
||
f.write("4. 使用 UI 测试验证关键页面\n\n")
|
||
f.write("备份位置:\n")
|
||
f.write(f" {BACKUP_DIR}\n\n")
|
||
f.write("映射文件:\n")
|
||
f.write(f" {MAPPING_FILE}\n\n")
|
||
f.write("替换脚本:\n")
|
||
f.write(f" {os.path.join(PROJECT_ROOT, 'issues/temp_rename/replace_image_refs.sh')}\n\n")
|
||
|
||
print_success(f"报告已生成: {report_file}")
|
||
|
||
# 打印简要统计
|
||
print("")
|
||
print(f" 📊 总共重命名: {len(asset_mapping)} 个资源")
|
||
print(f" 📁 备份位置: {BACKUP_DIR}")
|
||
print(f" 📄 映射文件: {MAPPING_FILE}")
|
||
print("")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print_header("白牌项目 - 图片资源批量重命名工具")
|
||
|
||
# 确认操作
|
||
print_warning("此脚本将重命名所有图片资源!")
|
||
print_warning("请确保:")
|
||
print(" 1. 已经运行了类名替换脚本")
|
||
print(" 2. 已经提交了所有更改")
|
||
print(" 3. 已经创建了新的 Git 分支")
|
||
print("")
|
||
|
||
confirm = input("确认继续?(y/N): ")
|
||
if confirm.lower() != 'y':
|
||
print("已取消操作")
|
||
return
|
||
|
||
try:
|
||
# 执行步骤
|
||
backup_assets()
|
||
rename_all_imagesets()
|
||
update_code_references()
|
||
generate_report()
|
||
|
||
print_header("✅ 图片资源批量重命名完成!")
|
||
print_warning("记得执行生成的替换脚本更新代码引用!")
|
||
|
||
except Exception as e:
|
||
print_error(f"执行过程中出错: {str(e)}")
|
||
print_warning("你可以从备份恢复:")
|
||
print(f" rm -rf {ASSETS_DIR}")
|
||
print(f" cp -r {BACKUP_DIR} {ASSETS_DIR}")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|
||
|
||
|