Communitygithub.com

영상 현지화: 링크 하나로 하드자막 완성본

Porter로 YouTube·X·Instagram·TikTok·Bilibili 링크를 현지화 완성본으로 만듭니다. 가져오기, 전사, 번역 후 FFmpeg로 이중 언어 또는 중국어 자막을 입히며 모든 단계를 디스크에 저장합니다.

영상 현지화: 링크 하나로 하드자막 완성본란 무엇인가요?

'영상 현지화' 레시피 1단계(엔드투엔드 파이프라인), RolinShmily/porter-workflow 제공. Porter는 가져오기 → 전사 → 번역 → 자막 입히기의 재개 가능한 4단계를 실행하고 각 결과를 디스크에 기록해 실패해도 완료된 작업을 잃지 않습니다. 에이전트는 먼저 `plan`을 실행해 플랫폼 기본 자막 트랙(ASR·키 불필요)이 있는지, Whisper 호환 전사가 필요한지 판단한 뒤 이중 언어/중국어 SRT와 libass 하드자막 MP4를 만듭니다. 하나의 엔진을 CLI, MCP 서버, 웹 워크벤치, 이 Agent Skill로 제공합니다.

지원 대상~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/RolinShmily/porter-workflow/tree/HEAD/skills/porter-skill

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Porter Skill(스트리밍 미디어 운반공)

비디오 링크를 중국어 하드 자막이 포함된 완성본으로 만듭니다. 네 단계를 순서대로 실행합니다: 획득 → 전사 → 번역 → 인코딩, 각 단계의 결과물을 디스크에 기록하므로 중간에 실패해도 완료된 부분이 손실되지 않습니다.


⚠️ 사전 조건: 전사를 위한 키 필요

이 부분을 먼저 확인해야 합니다. 그렇지 않으면 작업이 전사 단계에서 실패합니다.

기능키 필요 여부
다운로드, 번역, 인코딩필요 없음
음성 전사(ASR)OPENAI_API_KEY (또는 WHISPER_API_KEY) 필요, 또는 VideoCaptioner CLI 설치 필요
플랫폼 기본 자막 트랙 (YouTube / Bilibili 등)필요 없음 – 기본 트랙이 있으면 ASR을 실행하지 않음

v0.1에서 주장한 "순수 Python, 키 제로 폐쇄 루프"는 더 이상 유효하지 않습니다: 모든 키 없는 음성 인식 엔드포인트가 중단되었습니다 (2026-09-22 기준; 또는 [asr-local] extra를 사용하여 키 없는 로컬 인식 가능). 키가 없고 비디오에 플랫폼 자막 트랙도 없는 경우 작업은 transcribe 단계에서 every speech-to-text backend failed 오류로 종료됩니다.

따라서: 먼저 plan을 실행하세요. 이 명령은 이 비디오가 플랫폼 자막 트랙을 사용할지 ASR을 사용할지, 그리고 가능한지 여부를 직접 알려줍니다.


호출 진입점

CLI 진입점은 uvx를 통해 실행됩니다. Windows PowerShell은 기본 .ps1을 사용하고, Git Bash / WSL을 가정하지 마세요:

스크립트용도
scripts/porter.shBash 메인 진입점, porter CLI로 전달.
scripts/porter.ps1Windows PowerShell 메인 진입점, inspect / plan / run / jobs 등의 하위 명령을 지원합니다.
scripts/inspect.shBash 사전 검사, porter.sh inspect와 동일.
scripts/bootstrap.sh리포지토리 체크아웃에서 .venv를 생성하는 대체 진입점; 스킬과 함께 Python 소스 코드를 설치하지 않습니다.
# 사전 검사
<SKILL_DIR>/scripts/inspect.sh "https://youtu.be/dQw4w9WgXcQ"
# 계획
<SKILL_DIR>/scripts/porter.sh plan "https://youtu.be/dQw4w9WgXcQ"
# 실행
<SKILL_DIR>/scripts/porter.sh run "https://youtu.be/dQw4w9WgXcQ" -o ./porter_output

Windows PowerShell에서는 & '<SKILL_DIR>\scripts\porter.ps1' inspect '<URL>' --json을 사용하며, plan / run / jobs도 동일한 진입점을 호출합니다. inspect.sh와 아래의 nohup, grep 명령은 Bash 예시이므로 PowerShell에 그대로 붙여넣을 수 없습니다.

uvx를 처음 실행하면 네트워크를 통해 종속성을 확인합니다. 기본적으로 porter-workflow[llm]만 설치됩니다 (기본 패키지에는 yt-dlp가 포함됨). 로컬 ASR이 필요한 경우 사용자 동의 하에 PORTER_SKILL_SPEC=porter-workflow[llm,asr-local]을 설정합니다. 오프라인 설치 시 리포지토리 체크아웃에서 로컬 종속성을 준비하고, 스킬 디렉토리에 소스 코드가 포함되어 있다고 가정하지 마십시오.

작업 영역만 쓸 수 있는 호스트에서는 먼저 허용된 절대 디렉토리를 확인하고, PORTER_SKILL_STATE_DIR을 그 디렉토리의 .state로 설정한 다음, porter.sh --host-check 또는 porter.ps1 --host-check를 실행합니다. 그러면 uv, yt-dlp 및 작업 레지스트리 캐시가 해당 디렉토리로 리디렉션됩니다 (호스트에서 설정된 캐시 경로를 덮어씀). 출력 -o도 허용된 디렉토리에 있어야 합니다. 설정되지 않은 경우 호스트 기본 경로가 유지됩니다. 명령, 제한 사항 및 Windows 예제는 references/HOSTS.md를 참조하십시오.


워크플로우 폐쇄 루프

순서대로 실행합니다. 각 단계는 다음 단계보다 비용이 적게 들며, 오랜 시간이 걸리는 계산을 시작하기 전에 잘못된 입력을 거부하는 것을 목표로 합니다.

1. 사전 검사 – inspect

<SKILL_DIR>/scripts/inspect.sh "<URL>" --json

플랫폼, 제목, 길이, 해상도, 화면비, 자막 트랙 유무를 반환합니다. 미디어를 다운로드하기 전에 완료되며, 몇 초가 걸립니다.

해석: is_valid가 "링크 사용 가능"을 의미하며, ok는 "호출 성공"만 의미합니다. 링크가 유효하지 않으면 is_valid=false이며, 이 경우 재시도하지 마십시오 – 끊어진 링크를 다시 시도하는 것은 의미가 없습니다.

종료 코드 1은 링크를 사용할 수 없음을 나타냅니다.

2. 계획 – plan

<SKILL_DIR>/scripts/porter.sh plan "<URL>" --json

이 단계가 가장 시간을 절약해 줍니다. "이 비디오가 어떻게 처리되고, 가능한지"를 알려줍니다:

  • subtitles.route: platform (플랫폼 기본 자막 트랙 사용) 또는 asr (음성 인식 실행)
  • translation.needed: 이미 중국어 트랙이 있는 경우 false이며, 번역 단계를 건너뛸 수 있습니다.
  • feasible / blocking_issues: false이면 중단하고 작업을 시작하지 마십시오.
  • notes: 필독. 가장 중요한 두 가지:
    • 플랫폼 자막 트랙은 "요청되었으나 보장되지 않음" – 가져오기가 실패할 수 있음 (플랫폼 속도 제한, HTTP 429) 및 음성 인식으로 대체됨
    • 사용 가능한 인식 백엔드가 모두 테스트되지 않은 리버스 엔지니어링 엔드포인트인 경우 note에 명시됨

종료 코드 1은 불가능함을 나타냅니다.

3. 사용자 확인

하나의 작업은 수백 MB를 다운로드하고 몇 분 동안 실행될 수 있습니다. plan의 결론을 사용자에게 보고하고 실행 전에 동의를 받으십시오 (어떤 트랙을 사용할지, 어떤 단계를 실행할지, 인코딩할지 여부). feasible=false인 경우 차단 문제를 보고하고 작업을 시작하지 마십시오.

4. 실행 – run

<SKILL_DIR>/scripts/porter.sh run "<URL>" -o ./porter_output

긴 비디오의 경우 포그라운드에서 호출하여 완료될 때까지 기다리지 마십시오. 백그라운드에서 시작한 다음 작업 레지스트리를 폴링하십시오:

nohup <SKILL_DIR>/scripts/porter.sh run "<URL>" -o ./porter_output > run.log 2>&1 &
# 폴링 (작업 기록은 공유 레지스트리 파일에 기록되며, 프로세스 간에 표시됨)
<SKILL_DIR>/scripts/porter.sh jobs list
<SKILL_DIR>/scripts/porter.sh jobs status <job_id>

PowerShell의 경우 호스트에서 제공하는 백그라운드 작업 도구를 사용하여 & '<SKILL_DIR>\scripts\porter.ps1' run ...을 비동기적으로 시작하고, 동일한 PORTER_SKILL_STATE_DIR을 사용하여 jobs status를 계속 폴링하십시오. 오래 걸리는 명령의 진행 상황을 끝날 때까지 모아서 출력하는 데 Out-String을 사용하지 마십시오.

하지 마십시오 – "도구 시간 제한을 1200초로 설정"하여 긴 작업을 억지로 처리하는 것 (v0.1의 방식). 그렇게 하면 비디오가 더 길어질 때 여전히 실패하고, 실패 시 진행 상황을 전혀 얻을 수 없습니다. 작업 레지스트리는 이를 위해 설계되었습니다.

5. 품질 검사 (필수)

종료 코드만 보고 완료되었다고 판단하지 마십시오. 최소한 다음을 확인하십시오:

# 1. 중국어 자막이 실제로 존재하고 CJK 문자를 포함하는지 확인 ("번역되지 않은 가짜 자막" 방지)
grep -qP '[\x{4e00}-\x{9fff}]' ./porter_output/<task>/cooked/subtitle_zh.srt \
  && echo "OK: 중국어 포함" || echo "FAIL: 중국어 없음"

# 2. 완성본이 디코딩 가능하고 moov atom이 손상되지 않았는지 확인 (게시 중단 파일 방지)
ffprobe -v error -show_entries format=duration -of csv=p=0 ./porter_output/<task>/cooked/video_zh.mp4

완성본 크기가 비정상적으로 작으면 일반적으로 인코딩 실패를 의미하며, 비디오가 짧은 것을 의미하지는 않습니다.

6. 오류 발생 시

<SKILL_DIR>/scripts/porter.sh doctor     # 이 머신에서 작업 가능 여부 확인: ffmpeg/libass, JS 런타임, 글꼴, 인코더
<SKILL_DIR>/scripts/porter.sh config list # 구문 분석된 구성 (키는 마스킹됨)

일반적인 매개변수

# 자막만, 인코딩하지 않음
run "<URL>" --burn skip

# 중국어 완성본만 (이중 언어 생성하지 않음)
run "<URL>" --burn zh_only

# 출력 디렉토리 / 대상 언어 지정
run "<URL>" -o /path/to/out --target-lang zh-Hans

# 특정 백엔드를 우선적으로 사용 (나머지는 여전히 대체 백엔드로 사용, "해당 백엔드만 사용"이 아님)
run "<URL>" --translator google
run "<URL>" --asr-engine whisper-api

# 이 작업에 다른 LLM 모델 사용 (구성 변경 없음)
run "<URL>" --llm-model deepseek-reasoner

# 기존 소스 자막이 있는 경우: 직접 사용, 인식 실행하지 않음 (.srt / .vtt)
run "<URL>" --subtitle-file ./my_subtitles.srt

# 로그인이 필요한 비디오
run "<URL>" --cookies-from-browser chrome
run "<URL>" --cookies ./cookies.txt

# 재실행 (캐시된 단계 결과 무시)
run "<URL>" --force

# 스크립트에서 사용하기 위한 JSON 출력
run "<URL>" --json

--only-phase의 의미는 "이 단계까지" 이며, "이 단계만 실행"이 아닙니다 – 각 단계는 이전 단계의 출력을 필요로 하므로 이전 단계도 계속 실행됩니다.


결과물 구조

<task_dir>/
├── raw/                       # 마스터 및 중간 결과물
│   ├── video.mp4              # 표준화된 마스터 (무손실 스트림 복사, 재인코딩 없음)
│   ├── audio.wav              # 기준 오디오 트랙
│   ├── audio_enhanced.wav     # ASR 전용 강화 오디오 트랙 (노이즈 감소 + 음성 이퀄라이제이션), 완성본에서는 사용되지 않음
│   ├── subtitle.srt           # 소스 언어 자막 (플랫폼 트랙 또는 ASR 결과)
│   ├── transcript.json/.txt   # 구조화된 대본
│   ├── cover.jpg
│   └── metadata.json
└── cooked/                    # 완성본
    ├── subtitle.srt / .ass    # 이중 언어
    ├── subtitle_zh.srt / .ass # 중국어 전용
    ├── video_bilingual.mp4    # 이중 언어 하드 자막 완성본
    └── video_zh.mp4           # 중국어 전용 하드 자막 완성본

완성본의 오디오는 직접 복사 (-c:a copy)되어 원본 마스터에서 가져오며, 강화 오디오 트랙은 인식 전용으로 사용됩니다 – 인식 정확도와 완성본 음질을 모두 얻습니다.


구성

구성 검색 순서 (나중에 오는 것이 이전 것을 덮어씀):

  1. 내장 기본값
  2. 환경 변수: OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL, WHISPER_API_KEY, PORTER_ASR_ENGINE
  3. 사용자 구성 (porter config list는 실제 경로를 출력함)
  4. 프로젝트 구성: 현재 디렉토리의 porter.json / porter.toml / config.json
  5. --config <path>

전체 키 목록은 references/CONFIG.md를, 템플릿은 assets/config.example.json를 참조하십시오.


MCP를 통한 사용 (선택 사항이지만 더 나은 방법)

호스트가 porter MCP 서버를 이미 구성한 경우 셸 대신 이를 우선적으로 사용하십시오:

  • 구조화된 결과 제공, stdout 구문 분석 불필요 (셸 이스케이프 및 인코딩 문제 회피)
  • porter_job_start가 즉시 반환되고 porter_job_status로 폴링하여 긴 작업이 도구 시간 제한에 걸리지 않음
  • 키 없이 LLM 수준 번역을 얻을 수 있는 유일한 방법: §8.3 sampling은 호스트 모델을 사용하여 번역하며, CLI 프로세스는 호스트 모델에 접근할 수 없음

도구 이름 대조 및 구성 방법은 references/MCP.md를 참조하십시오.

참고: npx skills add는 이 스킬 디렉토리만 설치하며, MCP 서버는 설치하지 않습니다. 새로 설치할 때는 CLI 경로를 기준으로 합니다.


참고 파일

파일내용
references/ARCHITECTURE.md4단계 파이프라인, 플랫폼 및 백엔드 대체 체인, 설계 제약 사항
references/CONFIG.md모든 구성 키, 환경 변수, 우선 순위
references/MCP.mdMCP 도구 대조표 및 구성 방법
references/HOSTS.mdWindows 기본 진입점 및 제한된 호스트 사전 검사
assets/config.example.json구성 템플릿

관련 스킬