feat(learning): 업로드 동영상 카드 썸네일(ffmpeg 프레임 추출)

- 동영상 업로드 후 PPT와 동일한 썸네일 큐로 PNG 생성
- ENABLE_VIDEO_THUMBNAIL, VIDEO_THUMB_SEEK_SEC 환경 변수 지원
- 관리자: 동영상도 썸네일 재생성·삭제 시 썸네일 파일 정리
- 카드/스타일: 썸네일 이미지 표시 시 불투명도 1

Made-with: Cursor
This commit is contained in:
2026-04-21 17:02:21 +09:00
parent 8f441e8ef2
commit 7bee72f287
7 changed files with 173 additions and 38 deletions

View File

@@ -61,6 +61,7 @@
- PPT/PDF(`.pdf`) 상세: **1단·2단·3단** 보기 전환(그리드), 선택값은 브라우저 `localStorage`에 저장
- 목록 카드에 PPT 프리뷰(첫 슬라이드 제목 + 장수) 표시
- macOS 환경에서는 `qlmanage` 기반 실제 썸네일(첫 장 이미지) 자동 생성
- **업로드 동영상**(mp4/webm/mov 등): 목록 카드에 **ffmpeg**로 뽑은 대표 프레임 썸네일 표시(기본 약 0.5초 지점). 서버에 `ffmpeg`가 있어야 하며, PPT 썸네일과 동일한 백그라운드 큐·재시도 정책을 사용합니다.
- 썸네일 백그라운드 큐
- 썸네일 생성은 비동기 큐에서 처리
- 상태값: `pending` / `processing` / `ready` / `failed`
@@ -432,6 +433,13 @@ ENABLE_PPT_THUMBNAIL=1 npm start
- **PDF**: `pdftoppm`만 있으면 동작 (poppler 패키지)
- **한글 깨짐(이미지 안만 □)**: 서버에 PPT가 쓰는 글꼴·한글 폰트가 없을 때 발생. Linux: `fonts-nanum`, `fonts-noto-cjk` 등 설치 후 `fc-cache -fv`, 슬라이드 이미지 재생성.
### 업로드 동영상 카드 썸네일(선택)
- 기본값: `ENABLE_VIDEO_THUMBNAIL`이 `0`이 아니면 활성(미설정 시 켜짐).
- 서버 **PATH**에 `ffmpeg`가 있어야 합니다. macOS: `brew install ffmpeg`, Ubuntu: `sudo apt install -y ffmpeg`.
- 추출 시각은 `VIDEO_THUMB_SEEK_SEC`(초, 기본 `0.5`)로 조정할 수 있습니다. 영상 앞부분이 검은 화면이면 값을 키워 보세요.
- `ENABLE_VIDEO_THUMBNAIL=0`이면 업로드 직후 썸네일은 생성하지 않으며, 카드는 기존처럼 텍스트 폴백만 표시합니다.
### `.env` 예시
```env
@@ -446,6 +454,8 @@ DB_DATABASE=your_database
DB_USERNAME=your_user
DB_PASSWORD=your_password
ENABLE_PPT_THUMBNAIL=1
ENABLE_VIDEO_THUMBNAIL=1
# VIDEO_THUMB_SEEK_SEC=0.5
THUMBNAIL_WIDTH=1000
THUMBNAIL_MAX_RETRY=2
THUMBNAIL_RETRY_DELAY_MS=5000
@@ -465,6 +475,7 @@ OPENAI_API_KEY=
1. 메인 페이지에서 강의 등록
- **유튜브 강의 등록**: 제목 + 유튜브 링크 (+설명)
- **PowerPoint 강의 등록**: 제목 + `.pptx` 파일 (+설명)
- **동영상 파일 등록**: 제목 + 영상 파일 (`ffmpeg`로 카드 썸네일 생성)
- 두 등록 폼 모두 **태그(쉼표 구분)** 입력 가능
2. 하단 **등록된 강의** 카드에서 항목 클릭
3. 강의 상세 화면에서 시청
@@ -484,7 +495,7 @@ OPENAI_API_KEY=
### 썸네일 재생성(관리자)
- 관리자 모드에서 PPT 카드의 `썸네일 재생성` 버튼으로 수동 재생성 가능
- 관리자 모드에서 PPT·업로드 동영상 카드의 `썸네일 재생성` 버튼으로 수동 재생성 가능
- `실패 썸네일 일괄 재시도` 버튼으로 실패 건을 큐에 일괄 재등록 가능
- `이벤트 로그 페이지`에서 기간/유형/강의ID/사유 필터 조회 가능
- 이벤트 로그는 CSV 다운로드 지원
@@ -531,7 +542,7 @@ OPENAI_API_KEY=
관리자 토큰 기반 강의 삭제
- `POST /lectures/:id/thumbnail/regenerate`
관리자 토큰 기반 PPT 썸네일 재생성
관리자 토큰 기반 PDF/PPT·업로드 동영상 썸네일 재생성
- `POST /thumbnails/retry-failed`
관리자 토큰 기반 실패 썸네일 일괄 재시도 큐 등록
@@ -574,7 +585,7 @@ OPENAI_API_KEY=
## 구현 참고/제약
- PPT 뷰어는 **원본 슬라이드 디자인 렌더링**이 아닌, `.pptx` 내부 텍스트를 추출해 보여주는 방식입니다.
- PPT 썸네일은 시스템 도구 상태에 따라 생성 실패할 수 있으며, 이 경우 이미지 없이 텍스트 프리뷰만 표시됩니다.
- PPT·동영상 썸네일은 시스템 도구(`qlmanage`/LibreOffice/`ffmpeg` 등) 상태에 따라 생성 실패할 수 있으며, 이 경우 이미지 없이 텍스트 프리뷰만 표시됩니다.
- 썸네일 큐는 단일 프로세스 워커 기준으로 동작합니다(다중 인스턴스 분산 락은 미구현).
- 폰트/도형/애니메이션까지 완전 동일 렌더링이 필요하면 별도 문서 렌더러(예: LibreOffice/PDF 변환 파이프라인) 연동이 필요합니다.
- 이벤트 로그 페이지의 실시간 그래프는 클라이언트 폴링 기반이며, 다수 접속 시 폴링 주기 조정이 필요할 수 있습니다.