Initial commit: skills library

- 70 skills with code and documentation
- Add .gitignore (ignore __pycache__, output/, temp/, venv/)
- Clean up test intermediates and caches
This commit is contained in:
hmo
2026-04-26 19:27:40 +08:00
commit 04db423416
861 changed files with 210414 additions and 0 deletions
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env python3
"""
Audio Merger - 音频合并工具
功能:
- 合并多个音频文件为一个完整版
- 自动按文件名排序
- 支持指定输出文件名
- 保持原有文件不变
依赖:
- ffmpeg(必须安装并添加到PATH)
使用方法:
python scripts/merge_audio.py <audio_dir> [options]
示例:
# 合并指定目录所有MP3
python scripts/merge_audio.py ./audio_chapters
# 指定输出文件名
python scripts/merge_audio.py ./audio_chapters --output 完整版.mp3
# 指定文件模式(默认*.mp3)
python scripts/merge_audio.py ./audio_chapters --pattern "*.mp3"
"""
import os
import argparse
import subprocess
import sys
from pathlib import Path
def get_audio_files(audio_dir: str, pattern: str = "*.mp3") -> list:
"""获取目录中的音频文件并按文件名排序"""
audio_path = Path(audio_dir)
if not audio_path.exists():
print(f"错误: 目录不存在 {audio_dir}")
return []
files = list(audio_path.glob(pattern))
files.sort()
# 过滤掉已经存在的完整版文件(避免重复合并)
files = [
f for f in files if "完整版" not in f.name and "complete" not in f.name.lower()
]
return [str(f) for f in files]
def merge_audio_files(audio_files: list, output_file: str, audio_dir: str) -> bool:
"""使用 ffmpeg 合并音频文件"""
if not audio_files:
print("错误: 没有找到音频文件")
return False
print(f"找到 {len(audio_files)} 个音频文件")
print("文件列表:")
for i, f in enumerate(audio_files[:5], 1):
print(f" {i}. {os.path.basename(f)}")
if len(audio_files) > 5:
print(f" ... 还有 {len(audio_files) - 5} 个文件")
print()
# 创建 ffmpeg concat 列表文件
concat_file = os.path.join(audio_dir, ".merge_list.txt")
try:
with open(concat_file, "w", encoding="utf-8") as f:
for audio_file in audio_files:
# 使用相对路径
rel_path = os.path.relpath(audio_file, audio_dir)
f.write(f"file '{rel_path}'\n")
print(f"开始合并到: {os.path.basename(output_file)}")
# 构建 ffmpeg 命令
cmd = [
"ffmpeg",
"-y", # 覆盖已存在的文件
"-f",
"concat",
"-safe",
"0",
"-i",
concat_file,
"-c",
"copy", # 直接复制,不重新编码
output_file,
]
# 执行合并
result = subprocess.run(cmd, capture_output=True, cwd=audio_dir)
if result.returncode == 0:
file_size = os.path.getsize(output_file) / (1024 * 1024)
print(f"✓ 合并成功!")
print(f" 输出文件: {os.path.basename(output_file)}")
print(f" 文件大小: {file_size:.1f} MB")
print(f" 包含文件: {len(audio_files)}")
return True
else:
print(f"✗ 合并失败")
error_msg = (
result.stderr.decode("utf-8", errors="ignore")
if result.stderr
else "未知错误"
)
if "ffmpeg" in error_msg.lower() and "not found" in error_msg.lower():
print(" 提示: 未找到 ffmpeg,请先安装 ffmpeg 并添加到 PATH")
else:
print(f" 错误: {error_msg[:200]}")
return False
finally:
# 清理临时文件
if os.path.exists(concat_file):
os.remove(concat_file)
def main():
parser = argparse.ArgumentParser(
description="音频文件合并工具",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
%(prog)s ./audio_chapters
%(prog)s ./audio_chapters --output 完整版.mp3
%(prog)s ./audio_chapters --pattern "chapter_*.mp3"
注意:
需要先安装 ffmpeg: https://ffmpeg.org/download.html
""",
)
parser.add_argument("audio_dir", help="音频文件所在目录")
parser.add_argument(
"--output", "-o", help="输出文件名(默认: 00_完整版_合并音频.mp3)"
)
parser.add_argument(
"--pattern", default="*.mp3", help="文件匹配模式(默认: *.mp3"
)
args = parser.parse_args()
# 检查目录
if not os.path.isdir(args.audio_dir):
print(f"错误: 目录不存在 {args.audio_dir}")
sys.exit(1)
# 获取音频文件
audio_files = get_audio_files(args.audio_dir, args.pattern)
if not audio_files:
print("没有找到音频文件,退出")
sys.exit(1)
# 确定输出文件名
if args.output:
output_file = os.path.join(args.audio_dir, args.output)
else:
output_file = os.path.join(args.audio_dir, "00_完整版_合并音频.mp3")
# 检查输出文件是否已存在
if os.path.exists(output_file):
print(f"警告: 输出文件已存在,将被覆盖: {os.path.basename(output_file)}")
response = input("是否继续? (y/n): ")
if response.lower() != "y":
print("已取消")
sys.exit(0)
print("=" * 60)
print("音频合并工具")
print("=" * 60)
print()
# 执行合并
success = merge_audio_files(audio_files, output_file, args.audio_dir)
print()
print("=" * 60)
if success:
print("合并完成!")
else:
print("合并失败!")
print("=" * 60)
if __name__ == "__main__":
main()