The previous flow required the operator to manually install yt-dlp on the
server. Now the server downloads the correct binary for the current OS/arch
from GitHub Releases (latest) the first time a playlist fetch is requested,
caches it under %appdata%/.mc_custom (resolved per-OS), chmod +x's it on
POSIX, and skips the download on every subsequent call.
- shared/paths.ts: add getAppDataDir() + getMcCustomDir() that map %appdata%
to ~/.config (Linux), ~/Library/Application Support (macOS), or
process.env.APPDATA (Windows) so the path is OS-agnostic.
- server/youtube.ts: replace the old "probe PATH and bail" probeYtDlp with
ensureYtDlp(): picks the right GitHub asset name per platform.arch
(yt-dlp.exe / yt-dlp_macos / yt-dlp_linux / yt-dlp_linux_aarch64 /
yt-dlp_linux_armv7l), downloads it with redirect-following https.get to
the install path, chmods +x, then verifies with `--version` before
reporting success. Uses an installPromise singleton so concurrent
requests don't race the download. On any failure it cleans up the
partial file and throws YtDlpUnavailableError with a real reason.
- docs/yt-dlp-setup.md: note that auto-install is now the default; manual
install is only for environments where the auto-download fails.
Smoke-tested on this Linux x64 box: first call downloads to
~/.config/.mc_custom/yt-dlp_linux and reports `2026.03.17`; second call
takes ~700ms (just the version probe) and reuses the cached file.
- /op/dashboard: remove underline from <a class="secondaryButton"> by adding
text-decoration:none + inline-flex centering on .primaryButton/.secondaryButton/
.dangerButton, plus margin-left:auto on .dashboardActions so the buttons stick
to the right side of the row even when the header is laid out as flex+wrap.
- /op/list/<pack>: fix the duplicate "save/clear + playlist URL" UI showing in
the active tab. .tabPanel had a baseline `display: block;` that overrode the
browser default `[hidden] { display: none }`. Add an explicit
`.tabPanel[hidden] { display: none !important }` rule so the inactive panel
actually hides.
- /op/list, /op/list/<pack>, /op/datapack: bump the gap between the "돌아가기"
ghost link and the page title from 8px to 20px.
- docs/yt-dlp-setup.md: install guide (single-binary curl + pipx + apt) since
the server doesn't have pip/pipx/yt-dlp installed. Server keeps the graceful
"수동 입력으로 진행" fallback when yt-dlp is missing.
docs/add.md
- 사진 PNG 규격을 1024×1024 (4×4 블록 슬롯 × ×16 배율) 로 못박음
- 짧은 변 기준 가운데 정사각 크롭 + 1024 초과 시만 축소, 미만은 native 유지
신규 라우트 (모두 requireAuth):
- GET /op/list → manifest 카드 목록
- GET /op/list/:pack → 음악목록·사진목록 탭 편집기
- POST /op/list/:pack → file/list/<pack>.json 저장 (JSON)
- POST /op/list/:pack/playlist → yt-dlp 로 플레이리스트 펼치기
- GET /op/datapack → 음악퀴즈 선택 + 출력
- GET /op/datapack/:pack/generate → 임시 포맷 mcfunction 텍스트
shared/types.ts: PackList / MusicListEntry / ImageListEntry
shared/store.ts: loadPackList, savePackList, normalizePackList
shared/paths.ts: fileListDirPath = file/list/
server/youtube.ts: yt-dlp 플레이리스트 펼치기 (--flat-playlist --dump-json),
설치 안 됐을 때 NO_YTDLP 코드로 503.
UI:
- views/op/list.ejs: 가로 카드 목록 + 돌아가기 버튼
- views/op/listEditor.ejs + public/listEditor.js: 탭 전환, 드래그 정렬,
우클릭 컨텍스트 메뉴(수정/삭제), 사진 수정 모달의 [유튜브 / 이미지] 토글,
목록 저장·초기화·플레이리스트 불러오기 확인 팝업
- views/op/datapack.ejs: 음악퀴즈 카드 선택 팝업 → 데이터팩 출력 + 복사
- views/op/dashboard.ejs: 상단에 [음악목록 수정] [데이터팩 수정] 버튼
- public/styles.css: 탭, 트랙 로우, 이미지 그리드, 컨텍스트 메뉴, 모달, 코드블록
.gitignore: conversations/ 추가.
스모크: login → /op/list 렌더, POST 저장 라운드트립 OK,
/op/datapack/.../generate 텍스트 출력 OK, 플레이리스트 fetch는 yt-dlp 미설치
환경에서 503 NO_YTDLP 메시지 정상.
Section 1 (리소스팩 설치기 EXE: yt-dlp 음악 다운로드, painting variant
텍스처 패키징, 리소스팩 zip 배치) 은 후속 커밋에서 작업.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
add.txt를 md로 옮기면서 비어 있던 칸을 채움:
- 이미지 다운로드 방식 (yt 썸네일 + 일반 URL)
- 리소스팩 패키징 흐름 (painting-variant.md 슬롯 규격에 맞춰 변환)
- 사진목록 UI: 반응형 그리드 카드 + 번호 배지 + 토글 입력
- /op/datapack mcfunction 출력 placeholder
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>