manus-skills/.kortix/opencode/skills/media/youtube-clipper/scripts/clip_video.py
zhukang 1c7abd81d1 All 310 Manus skill-hub community skills as a Kortix marketplace registry
- 310 registry:skill items, 1528 files, 7 categories (hub tags)
- registry.json generated by @kortix/registry buildRegistry
- nested SKILL.md in sn-da-* renamed SUBSKILL.md (no phantom skills)
- provenance + licenses: SOURCES.md
2026-09-15 13:37:20 +08:00

237 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
剪辑视频片段
使用 FFmpeg 精确剪辑视频,保持原始质量
"""
import sys
import shutil
import subprocess
from pathlib import Path
from typing import Union
from utils import (
time_to_seconds,
seconds_to_time,
format_file_size,
get_video_duration_display
)
def clip_video(
video_path: str,
start_time: Union[str, float],
end_time: Union[str, float],
output_path: str,
ffmpeg_path: str = None
) -> str:
"""
剪辑视频片段
Args:
video_path: 输入视频路径
start_time: 起始时间(秒数或时间字符串,如 "00:01:30")
end_time: 结束时间(秒数或时间字符串)
output_path: 输出视频路径
ffmpeg_path: FFmpeg 可执行文件路径(可选)
Returns:
str: 输出视频路径
Raises:
FileNotFoundError: 输入文件不存在
RuntimeError: FFmpeg 执行失败
"""
video_path = Path(video_path)
output_path = Path(output_path)
# 验证输入文件
if not video_path.exists():
raise FileNotFoundError(f"Video file not found: {video_path}")
# 转换时间为秒数
if isinstance(start_time, str):
start_seconds = time_to_seconds(start_time)
else:
start_seconds = float(start_time)
if isinstance(end_time, str):
end_seconds = time_to_seconds(end_time)
else:
end_seconds = float(end_time)
# 验证时间范围
if start_seconds >= end_seconds:
raise ValueError(f"Start time ({start_seconds}s) must be before end time ({end_seconds}s)")
duration = end_seconds - start_seconds
# 检测 FFmpeg
if ffmpeg_path is None:
ffmpeg_path = shutil.which('ffmpeg')
if not ffmpeg_path:
raise RuntimeError("FFmpeg not found. Please install FFmpeg.")
print(f"\n✂️ 剪辑视频片段...")
print(f" 输入: {video_path.name}")
print(f" 起始时间: {seconds_to_time(start_seconds)} ({start_seconds}s)")
print(f" 结束时间: {seconds_to_time(end_seconds)} ({end_seconds}s)")
print(f" 片段时长: {get_video_duration_display(duration)}")
print(f" 输出: {output_path.name}")
# 创建输出目录
output_path.parent.mkdir(parents=True, exist_ok=True)
# 构建 FFmpeg 命令
# 使用 -ss 和 -t 进行精确剪辑
# -c copy: 直接复制流,不重新编码(快速且无损)
cmd = [
ffmpeg_path,
'-ss', str(start_seconds), # 起始时间
'-i', str(video_path), # 输入文件
'-t', str(duration), # 持续时间
'-c', 'copy', # 直接复制,不重新编码
'-y', # 覆盖输出文件
str(output_path)
]
print(f" 执行 FFmpeg...")
# 执行 FFmpeg
result = subprocess.run(
cmd,
capture_output=True,
text=True
)
if result.returncode != 0:
print(f"\n❌ FFmpeg 执行失败:")
print(result.stderr)
raise RuntimeError(f"FFmpeg failed with return code {result.returncode}")
# 验证输出文件
if not output_path.exists():
raise RuntimeError("Output file not created")
# 获取文件大小
output_size = output_path.stat().st_size
print(f"✅ 剪辑完成")
print(f" 输出文件: {output_path}")
print(f" 文件大小: {format_file_size(output_size)}")
return str(output_path)
def extract_subtitle_segment(
subtitles: list,
start_time: float,
end_time: float,
adjust_timestamps: bool = True
) -> list:
"""
从完整字幕中提取指定时间段的字幕
Args:
subtitles: 完整字幕列表(每项包含 {start, end, text})
start_time: 起始时间(秒)
end_time: 结束时间(秒)
adjust_timestamps: 是否调整时间戳(减去起始时间)
Returns:
list: 提取的字幕列表
"""
segment_subtitles = []
for sub in subtitles:
# 字幕在时间范围内
if sub['start'] >= start_time and sub['end'] <= end_time:
if adjust_timestamps:
# 调整时间戳(相对于片段起始时间)
adjusted_sub = {
'start': sub['start'] - start_time,
'end': sub['end'] - start_time,
'text': sub['text']
}
segment_subtitles.append(adjusted_sub)
else:
segment_subtitles.append(sub.copy())
# 字幕跨越时间范围边界(部分重叠)
elif sub['start'] < end_time and sub['end'] > start_time:
if adjust_timestamps:
adjusted_sub = {
'start': max(0, sub['start'] - start_time),
'end': min(end_time - start_time, sub['end'] - start_time),
'text': sub['text']
}
segment_subtitles.append(adjusted_sub)
else:
segment_subtitles.append(sub.copy())
return segment_subtitles
def save_subtitles_as_srt(subtitles: list, output_path: str):
"""
保存字幕为 SRT 格式
Args:
subtitles: 字幕列表
output_path: 输出文件路径
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
for i, sub in enumerate(subtitles, 1):
# SRT 序号
f.write(f"{i}\n")
# SRT 时间戳(使用逗号分隔毫秒)
start_time = seconds_to_time(sub['start'], include_hours=True, use_comma=True)
end_time = seconds_to_time(sub['end'], include_hours=True, use_comma=True)
f.write(f"{start_time} --> {end_time}\n")
# 字幕文本
f.write(f"{sub['text']}\n")
# 空行分隔
f.write("\n")
print(f"✅ 字幕已保存: {output_path}")
def main():
"""命令行入口"""
if len(sys.argv) < 5:
print("Usage: python clip_video.py <video> <start_time> <end_time> <output>")
print("\nArguments:")
print(" video - 输入视频文件路径")
print(" start_time - 起始时间(秒数或时间字符串,如 00:01:30)")
print(" end_time - 结束时间(秒数或时间字符串)")
print(" output - 输出视频文件路径")
print("\nExample:")
print(" python clip_video.py input.mp4 0 195 output.mp4")
print(" python clip_video.py input.mp4 00:00:00 00:03:15 output.mp4")
print(" python clip_video.py input.mp4 01:30:00 01:33:15 output.mp4")
sys.exit(1)
video_path = sys.argv[1]
start_time = sys.argv[2]
end_time = sys.argv[3]
output_path = sys.argv[4]
try:
result_path = clip_video(video_path, start_time, end_time, output_path)
print(f"\n✨ 完成!输出文件: {result_path}")
except Exception as e:
print(f"\n❌ 错误: {str(e)}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()