관리자 폴더 화면에서도 영상 카드를 좌클릭하면 공개 폴더와 동일한
내부 팝업 플레이어로 재생되도록 함. 우클릭 컨텍스트 메뉴 (수정/이름
변경/삭제) 는 그대로 유지.
- 카드에 data-video-id 추가해 기존 player.js 가 인식하게 함
- 페이지에 playerOverlay HTML 과 player.js 스크립트 포함
- window.__SITE__.folder 도 함께 노출해 player.js 의 가정 충족
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
비디오의 src 가 HTML 인라인이라 loadedmetadata 가 스크립트 실행보다
먼저 끝나는 경우, 늦게 붙은 리스너가 영원히 못 받아 duration=0 으로
멈춰있던 문제 수정. readyState 즉시 검사 + durationchange 도 같이
구독하도록 변경.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
영상편집기에 lossless-cut 류 트림 타임라인 추가. 숫자 입력만 있던 기존 UI 를
시각적 재생바 + 좌/우 드래그 핸들 + 플레이헤드로 교체.
- 좌/우 파란 핸들을 끌어 in/out 점 설정 (pointer events 기반, 터치 지원)
- 흰색 플레이헤드가 영상 재생 위치 따라감
- 타임라인 빈 공간 클릭 → 그 지점으로 시킹
- "[ 시작점" / "끝점 ]" 버튼으로 현재 시점 마크
- "선택 재생" 으로 선택구간만 미리보기, "초기화" 로 전체 선택 복원
- 기존 숫자 입력은 보조 입력으로 유지하고 상태와 양방향 동기화
저장 페이로드는 그대로 (startSec/endSec). 서버측 ffmpeg 트림 로직 변경 없음.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
리뷰어 지적사항 반영:
- "abc" 같은 오타도 Infinity 로 풀리던 문제 수정. 잘못된 값은 기본 1 GiB 로
fallback 하고 경고 로그를 남김. 무제한은 "0" 또는 "Infinity" 만 명시적으로 인정.
- .env.example / README 의 "비우면 무제한" 표현을 코드 동작과 일치시켜
"비우면 기본 1 GiB" 로 정정.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
기본 업로드 한도를 1 GiB (1073741824 바이트) 로 설정. .env 의 UPLOAD_MAX_BYTES 로
바꿀 수 있고, 0 이나 Infinity 로 두면 무제한.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
도커는 사용자가 따로 만들어 쓸 예정이라 레포에서 제거합니다. README/.env.example
의 Docker 관련 안내도 같이 정리. .env 기반 PORT/HOST 설정은 직접 실행용으로 유지.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
직접 실행과 Docker compose 가 같은 .env 한 파일로 PORT/HOST/SESSION_SECRET 등을
공유합니다. 컨테이너는 node:22-bookworm-slim 기반에 ffmpeg + 번들된 yt-dlp 포함,
data 볼륨 마운트로 영속화합니다.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
scripts/setup.mjs runs `npm install`, downloads the platform-specific
yt-dlp binary from GitHub releases to ./bin/yt-dlp (which src/youtube.ts
already prefers), checks for ffmpeg and prints install hints, then runs
`tsc`. One command replaces three for fresh checkouts.
While verifying setup, hit `MulterError: File too large` (LIMIT_FILE_SIZE)
on a 10 GB mkv upload, and ETXTBSY on freshly downloaded yt-dlp.
- ETXTBSY: the redirect path in downloadFile opened a writestream to the
destination before following the redirect, so the (unused) outer stream
still held the file open when the post-download spawnSync ran. Split
redirect-following from file writing so only the final 200 response
opens the destination file.
- LIMIT_FILE_SIZE: removed the hard-coded 4 GB cap. Upload limit now
defaults to Infinity and is configurable via UPLOAD_MAX_BYTES.
Wrapped multer's middleware so its errors (LIMIT_FILE_SIZE etc.) come
back as a clean 413 JSON instead of a stack trace from the global
error handler.
- Also disabled Node's default 5 minute requestTimeout so 10 GB uploads
over slow links don't get cut mid-stream. Configurable via
HTTP_REQUEST_TIMEOUT_MS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
.modalOverlay { display: flex } and .playerOverlay { display: flex }
were overriding the browser default [hidden] { display: none }, so the
"폴더 추가" modal stayed visible on /op/dashboard load and blocked all
other UI. Added a single [hidden] { display: none !important } rule so
the hidden attribute always wins regardless of later display rules.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1: views were emitting <%- JSON.stringify(...) %> directly inside <script>
tags. A video title like "</script><script>alert(1)</script>" would break
out of the script and inject HTML. Added res.locals.jsonForScript() that
escapes <, >, &, U+2028, U+2029 before output and switched all three
templates (op/editor.ejs, op/folder.ejs, folder.ejs) to use it.
P2: The internal popup player in /folder/:name always hit
/api/video/:id/file which returned the original. Made the file endpoint
default to the edited variant when present and only fall back to original
when ?edited=0 is given. Editor page passes ?edited=0 explicitly so the
operator always re-trims from the original. Standalone /player/:id no
longer needs the ?edited=1 hint.
Verified: rendered editor HTML escapes </script> payloads to \u003c/script,
default file endpoint serves edited.mp4 while ?edited=0 serves original.mp4.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>