자가호스팅 LibreTranslate(h-etc2.tolag.shop) 연동. 재가공 화면 '번역→재작성'
버튼으로 원본 전사 스크립트를 한국어로 번역해 재작성 칸 초안으로 채운다.
소스 언어는 전사 언어로 자동(없으면 auto), 타깃 기본 ko.
- TranslateService 신규: POST /translate {q,source,target} → translatedText
(요청 조립/응답 파싱 순수 메서드 + 단위테스트)
- POST /{id}/translate 엔드포인트, CurationService.translateScript
- rework.html: '번역→재작성' 버튼 + translateToEditor()
- 설정 translate.base-url(기본값 有)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
원본 다운로드/캐시 보유 시 왼쪽 플레이어를 YouTube 임베드 대신 받은 원본 mp4로
전환한다. 세그먼트(타임라인) 클릭 시 기존 seekTo/하이라이트가 그대로 동작해
해당 지점으로 이동·재생된다. (업로드본이 있으면 업로드본 우선)
- GET /{id}/download/file: 받은 원본 스트리밍(Resource 반환 → HTTP Range 206 자동 지원)
- CurationService.cachedDownloadFile(id)
- rework.html: showServerVideoInPlayer/showYoutubeInPlayer, updateCacheUI가 플레이어 전환,
다운로드 직후/진입 시 캐시 있으면 자동 적용, 삭제 시 YouTube로 복귀
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1) 재가공 화면에 '받은 원본 삭제' 버튼 추가(캐시 보유 시에만 노출).
GET/DELETE /{id}/download 로 캐시 상태 조회·삭제(자막/세그먼트는 유지).
진입 시 캐시 상태를 조회해 삭제버튼 노출 + 렌더 캐시 사용 여부를 갱신.
2) 수집함 영상 삭제 시 downloads/{id}.mp4 도 함께 삭제(고아 파일 방지).
- VideoDownloadService.deleteCache(id) + 단위테스트(@TempDir)
- CurationService: downloadStatus/deleteDownloadCache, delete() 캐시 정리
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
재가공 사용법 모달 상단에 실제 화면 캡쳐 3장으로 단계별 안내 추가:
1) 원본 다운로드 버튼 2) 자동 전사된 시간싱크 자막 3) 내보내기(업로드 불필요).
?help=1 딥링크로 사용법을 바로 펼칠 수 있게 함.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
재가공 화면 '원본 다운로드' 버튼으로 저장된 videoId를 yt-dlp(로컬 ProcessBuilder)로
받아 서버에 캐시하고, 그 파일을 기존 Python /transcribe·/render 에 그대로 투입한다.
수동 다운로드+업로드 단계를 전사·렌더 양쪽에서 제거.
- VideoDownloadService 신규: 인자 리스트 ProcessBuilder(셸 미사용), videoId 검증, 캐시 조회
- ChannelService: 전사·렌더를 Resource 기반 공통 메서드로 추출(업로드/캐시 공유)
- 컨트롤러: POST /{id}/download(다운로드+전사), /render 의 file 을 선택값으로(없으면 캐시)
- rework.html: '원본 다운로드' 버튼 + downloadOriginal(), 렌더가 서버 캐시 재사용
- 설정 ytdlp.*/download.dir(기본값 有), downloads/ gitignore
- buildCommand/videoId 검증 단위테스트(src/test 신규)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 3: remove "no-talk" gaps (Whisper-segment based, not audio silencedetect
which finds nothing under background music) and render a trimmed (+speed) video
via ffmpeg, with subtitles remapped to match.
- KeepIntervalPlanner + TimelineRemapper (pure, unit-tested): keep/remove plan
from segments (pad/minGap) and timestamp remap f(t)=t-removedBefore(t)
- GET /{id}/trim-plan (preview: keep/remove/remapped segments/kept duration)
- POST /{id}/render (multipart: file,pad,minGap,speed) -> proxy Python /render
(ffmpeg trim/atrim+concat+atempo) -> mp4 download; ffmpeg graph validated locally
- rework.html: export panel (speed + speech-gap trim preview + SRT/video export),
client-side SRT from working segments, language selector (auto/ko/en/zh/ja)
- transcribeFromFile forwards optional language (Whisper auto-detect misfired -> zh)
Spec updated with the audio-silence -> speech-gap design correction.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>