基于trace.moe API的视频自动重命名代码故障排查
修复trace.moe API自动重命名动漫视频的代码问题
报错原因拆解
你遇到的两个核心问题:
- 索引越界/无匹配结果:直接取
data['result'][0]但API返回的result数组为空(错误码0对应trace.moe的"no result",也就是截图没匹配到任何动漫) - 字段不存在:trace.moe的基础API返回里根本没有
season字段,强行访问会直接报错
修复后的完整代码
import os import requests import subprocess import re def process_video(video_path): # 先检查视频时长是否够16分钟,避免截取无效时间点 try: duration_output = subprocess.run( ['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', video_path], capture_output=True, text=True, check=True ) video_duration = float(duration_output.stdout.strip()) if video_duration < 16 * 60: print(f"[跳过] {video_path} 时长不足16分钟") return except subprocess.CalledProcessError: print(f"[失败] 无法获取{video_path}的时长") return # 生成临时截图 temp_screenshot = "temp_shot.jpg" try: subprocess.run( ['ffmpeg', '-ss', '00:16:00', '-i', video_path, '-vframes', '1', '-q:v', '2', temp_screenshot], capture_output=True, check=True ) except subprocess.CalledProcessError: print(f"[失败] 无法截取{video_path}的截图") return # 调用trace.moe API api_endpoint = "https://api.trace.moe/search" try: with open(temp_screenshot, 'rb') as img_file: api_response = requests.post(api_endpoint, files={"image": img_file}) api_response.raise_for_status() response_data = api_response.json() except requests.exceptions.RequestException as e: print(f"[失败] API调用出错: {str(e)}") os.remove(temp_screenshot) return # 处理API返回结果 if response_data.get("error"): print(f"[失败] 处理{video_path}时出错: {response_data['error']}") os.remove(temp_screenshot) return if not response_data.get("result"): print(f"[跳过] {video_path} 未匹配到任何动漫") os.remove(temp_screenshot) return # 取置信度最高的匹配结果 best_match = response_data["result"][0] # 优先用英文标题,没有就用日文标题,最后 fallback 到未知标题 anime_title = best_match.get("title_english") or best_match.get("title") or "未知动漫" # 提取集数,没有就显示未知集 episode_num = best_match.get("episode", "未知集") # 从标题里提取季数(匹配S01、Season 1这类格式) season_num = "00" season_match = re.search(r'(?:S|Season)\s?(\d+)', anime_title, re.IGNORECASE) if not season_match: # 英文标题没找到就试试日文标题 season_match = re.search(r'(?:S|Season)\s?(\d+)', best_match.get("title_japanese", ""), re.IGNORECASE) if season_match: season_num = season_match.group(1).zfill(2) # 补零成两位,保持格式统一 # 生成新文件名 new_filename = f"{anime_title} - S{season_num}E{episode_num.zfill(2)}.mp4" new_file_path = os.path.join(os.path.dirname(video_path), new_filename) # 重命名前检查文件是否存在,避免覆盖 if not os.path.exists(new_file_path): os.rename(video_path, new_file_path) print(f"[成功] {video_path} → {new_filename}") else: print(f"[跳过] {new_filename} 已存在,不覆盖") # 清理临时截图 os.remove(temp_screenshot) # 遍历目标目录处理所有MP4文件 target_dir = r"D:/Projet Reno/Inco" for file_name in os.listdir(target_dir): if file_name.lower().endswith(".mp4"): full_path = os.path.join(target_dir, file_name) process_video(full_path)
关键修改说明
完善错误链路:
- 先检查视频时长,跳过短于16分钟的视频
- 捕获ffmpeg/ffprobe的执行错误,避免崩溃
- 先判断API的
error字段和result数组是否为空,再也不会出现索引越界的问题
解决season字段缺失问题:
- 用正则表达式从动漫标题里提取季数(支持S01、Season 1等常见格式)
- 如果标题里没找到季数,默认用"00"标记为未知季
提升鲁棒性:
- 标题有多层 fallback,避免无标题时报错
- 集数和季数自动补零,保持文件名格式统一
- 重命名前检查目标文件是否存在,防止覆盖已恢复的文件
- 自动清理临时截图,避免垃圾文件残留
内容的提问来源于stack exchange,提问作者iHAVOK
相关产品推荐
相关产品推荐

