강의 동영상 완전 자동 편집 (CapCut 불필요 방식)
해결하는 문제
사용자가 강의 동영상을 녹화한 후, "전사 → 오류 수정 → 군더더기 제거 → 더듬기/반복 삭제 → 잘못 설명한 부분 수정 → 완성본 생성" 전체 과정을 완전 자동화합니다. CapCut을 전혀 열 필요 없으며, 결과물은 바로 배포 가능한 완성본입니다(하드 자막 이미 입혀져 있고, 상단에 노란색 수정 바가 포함됨). 매개변수(글꼴 크기/삭제 구간/문구)를 변경한 후 스크립트를 다시 실행하기만 하면 되며, 반복 비용은 1분입니다.
jianying-subtitle-fixer와의 경계: 해당 스킬은 CapCut 초안을 수정합니다(사용자가 수동으로 내보내야 함). 반면, 이 스킬은 ffmpeg로 직접 완성본을 생성합니다. 사용자가 CapCut을 언급하지 않으면 이 스킬을 사용합니다.
환경 의존성 (로컬에 이미 준비됨)
- Python:
C:\Users\44162\AppData\Local\Programs\Python\Python312\python.exe(faster-whisper 1.2.1 + torch 이미 설치됨; 모델 캐시는 ~/.cache/huggingface에 있으며, small 모델 보유) - ffmpeg:
D:\소프트웨어\ffmpeg\bin\ffmpeg.exe(스크립트가 자동 탐지)
표준 워크플로우 (AI는 이 순서를 따름)
Step 0 ffprobe로 비디오 길이/해상도 확인 (이후 글꼴 크기 자동 조정에 사용)
Step 1 전사: transcribe.py -> raw.json (문장+단어 수준 타임스탬프)
Step 2 AI 분석 (이 스킬의 핵심 가치, 아래 참조) -> cut_plan.json 작성
Step 3 내용 삭제 항목을 AskUserQuestion으로 사용자에게 결정 요청 (한 번에 모두 질문, 나눠서 하지 않음)
Step 4 렌더링: render.py --plan cut_plan.json -> 완성본
Step 5 프레임 샘플링 검사 (수정 바 시간 지점마다 한 프레임씩 추출, Read + 시각적 확인으로 텍스트 완전성 및 너비 초과 여부 검사)
Step 6 인도: 무엇을 잘랐는지/무엇을 수정했는지/파일 위치 보고
Step 1 전사 명령
& "C:\Users\44162\AppData\Local\Programs\Python\Python312\python.exe" "<스킬경로>/scripts/transcribe.py" --video "<비디오경로>" --outdir "<작업디렉토리>" --prompt "XXX, YYY 등의 주제에 관한 중국어 기술 튜토리얼"
--prompt는 비디오 주제 + 자주 사용되는 용어를 사용합니다 (용어 사전 ~/.claude/skills/jianying-subtitle-fixer/config/terms.json에서 가져옴).
고유 명사 인식률이 크게 향상됩니다. 작업 디렉토리 권장: D:\콘텐츠생산시스템\편집\workspace\<날짜-job>\.
Step 2 AI 분석 (인간이 대체 불가능한 단계, 방법론은 references/cut-heuristics.md 참조)
raw.json 전체를 읽은 후 다음 네 가지를 생성합니다:
- 자막 오류 수정 fixed: 동음이의어 오류/전문 용어 오인식을 하나씩 수정합니다. 구어체 원문을 유지하며, 오류만 수정하고 윤문하지 않습니다 (자막은 음성에 붙어 있어야 하며, 다시 쓰면 음성-영상 불일치가 발생합니다). whisper 오인식 패턴은 references 참조.
- 내용 삭제 content_cuts: 통째로 삭제할 구간 (시간 코드 + 이유), 유형 및 판단 기준은 references 참조. 단어 수준 반복(문장 내 "~에 대해... ~에 대해")은 words 타임스탬프로 정밀하게 위치 파악.
- deleted_ids: content_cuts가 포함하는 자막 항목 id (이 항목들은 자막에 포함되지 않음).
- 수정 바 corrections: 사실을 잘못 설명한 부분, 영상 상단 노란색 바. cut_plan.json에 작성.
Step 3 사용자 결정 (원칙)
- 명확히 잘라야 할 부분 (더듬으며 다시 말하기/말실수 시작/반쯤 말하다 포기): 직접 계획에 포함시키고, 보고 시 설명만 하면 됨
- 내용을 잘못 설명한 부분: 사용자에게 질문 "삭제 / 유지+수정 바", 의견 성향의 내용은 유지+수정 바 선호
- 수정 바 문구, 사실 확인 결과 (인터넷 확인이 필요한 경우 WebSearch로 원문 찾기) 모두 사용자에게 보여줌
- AskUserQuestion을 사용해 모든 결정 항목을 한 번에 질문
Step 4 렌더링 명령
& "C:\Users\44162\AppData\Local\Programs\Python\Python312\python.exe" "<스킬경로>/scripts/render.py" --plan "<작업디렉토리>/cut_plan.json"
cut_plan.json 형식 (render.py 헤더 주석에 전체 설명 있음):
{
"video": "C:/원본영상.mp4",
"out": "C:/완성본.mp4",
"raw": "raw.json",
"content_cuts": [[213.45, 230.98, "실험 설명 중 실수"]],
"deleted_ids": [48, 49, 50],
"fixed": {"1": "수정 후 텍스트"},
"corrections": [[12.95, 20.14, "수정: 올바른 명칭은 XX임"]],
"silence": {"min_dur": 1.0, "keep": 0.25},
"style": {"sub_size": 64, "cor_size": 48}
}
모든 시간 코드는 원본 영상 타임라인을 사용합니다 (스크립트가 자동으로 편집 후 타임라인으로 재매핑). silence/style은 생략 가능합니다. 자막 스타일은 기본적으로 모바일 대형 글꼴(2560 너비 기준 64/48, 해상도에 따라 자동 비례 조정). 사용자가 "글꼴이 작다"고 하면 style 값을 조정하여 재실행합니다.
Step 5 프레임 샘플링 검사
final.ass에서 수정 바 실제 시간(Cor 행)을 읽고, 새 타임라인에 따라 프레임 추출:
& "D:\소프트웨어\ffmpeg\bin\ffmpeg.exe" -y -i "<완성본>" -vf "select='eq(n\,<프레임번호>)',scale=1100:-1" -vsync vfr "<qc디렉토리>/qc_%d.jpg"
프레임 번호 = 초 × 20fps. 프레임별 Read + 시각적 검사: 텍스트 완전성, 너비 초과 여부, 하단 자막과 겹치지 않는지 확인.
함정 기록 (피와 눈물, 밟지 마시오)
- aselect 무음 제거 실패: 일부 AAC 스트림에서 aselect가 한 프레임도 자르지 않고 오류도 발생하지 않음 → 오디오 제거는
반드시
asplit+atrim+concat을 사용해야 함 (render.py에 이미 내장되어 있음, aselect로 되돌리지 말 것) - concat은 단일 스트림 select 뒤에 연결기로 사용 불가 (패드 수 불일치 오류 발생); select+setpts는 자체적으로 연속 출력을 생성함
- 완성본 검증은 반드시 ffprobe로 비디오/오디오 두 스트림을 각각 검사해야 함: format duration은 더 긴 스트림에 의해 원본 길이로 늘어나 "전혀 잘리지 않은" 상태를 은폐할 수 있음 (실제 겪은 사례: 렌더링 "성공"했으나 오디오가 전부 보존됨)
- subtitles 필터 경로: ass 파일과 렌더링 cwd를 일치시켜 상대 경로를 사용하면 중국어 경로 이스케이프 문제를 피할 수 있음
- 무음 제거는 반드시 단어 보호 구역을 통과해야 함 (render.py에 내장된 strip_guard): whisper의 단어 타임스탬프와 silencedetect 간에 차이가 있어, 작은 소리 단어(예: 문장 시작의 영어 용어)가 "무음"에 포함될 수 있으며, 무음 기준으로 바로 자르면 단어 절반이 잘릴 수 있음
- 전사 스크립트는 ffmpeg stderr에 대해 GBK 오류 허용 처리를 함 (Windows 인코딩의 오래된 함정, 해당 스레드의 오류는 무시하면 됨)
반복 비용
글꼴 크기/수정 문구/삭제 구간 추가 또는 제거 → cut_plan.json의 해당 필드를 수정하고 render.py를 재실행, 한 번에 1~2분 소요. 완성본은 덮어쓰기되며, 원본 영상은 절대 수정되지 않습니다.