관리자 편집기 platformLoaderHint 가 아직 "fabric-installer CLI 설치"라고
설명하고 있었으나, 실제 설치기는 자바 없이 Fabric Meta profile JSON 을 받아
.minecraft/versions 에 직접 저장한다. UI 설명을 실제 동작에 맞춤.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
관리자 편집기에서 맵 파일과 서버 파일 사이에 "config 파일 (.zip)" 필드를
추가하고, 간편설치기가 /file/configs/<name> zip 을 받아 게임 폴더(.mc_custom)
루트에 그대로 풀도록 했다(zip 안의 config/ 가 .mc_custom/config/ 로 배치).
- PackDefinition.configPath 추가 + store 정규화/기본값
- 설치기 downloadConfigZip 헬퍼 + client:install 흐름 반영
- 편집기 필드, op 저장 파싱, 로케일 키(server/installer)
- docs/installer.md 다운로드 단계 갱신, file/configs/ 폴더 생성
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
근본 해결: fabric-installer(jar) 를 java 로 실행하던 것을 없애고, fabric meta
(/v2/versions/loader/<mc>/<loader>/profile/json)에서 버전 프로필 JSON 을 그대로
받아 .minecraft/versions/<id>/<id>.json 에 저장한다. 라이브러리는 프로필의 maven url
로 런처가 실행 시 자동 다운로드. 자바가 없어도 되어 "spawn java.exe ENOENT" 가
원천 제거되고, 바닐라 선행 실행/자바 설치 없이도 fabric 설치가 된다.
findJavaExecutable/runJavaProcess/FabricInstallerMeta(자바 실행 경로) 제거. 0.4.25→0.4.26.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
원인: findJavaExecutable 이 JAVA_HOME → .minecraft/runtime(런처 번들 JRE, 바닐라를
한 번 실행해야 생김) → 폴백 "java.exe" 순이라, 바닐라 미실행 + 시스템 java 없음이면
fabric-installer 실행에서 spawn java.exe ENOENT 로 실패.
- findJavaExecutable 에 설치기 자동설치 JDK(.mc_custom/jdk) 와 C:\Program Files\Java
탐색을 추가해 불필요한 실패를 줄인다(fabric 실행엔 아무 자바나 됨).
- 그래도 자바가 전혀 없어 ENOENT 면, "먼저 [버전] 바닐라를 한 번 실행해 자바 런타임을
받은 뒤 다시 시도" 안내 메시지로 바꿔 던진다. 0.4.24→0.4.25.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
options.txt 자동 적용이 실패하면(권한/잠금/손상 등) 예전엔 성공처럼 "자동 적용됩니다"
로 보였다. 이제 finalResourcepack:install 이 applied=false 를 반환하고, 렌더러가
"받았지만 자동 적용 실패 — 직접 켜주세요" 경고를 표시한다(다운로드 자체는 성공). 0.4.23→0.4.24.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
최종 리소스팩을 받은 뒤 gameDir 의 options.txt resourcePacks 목록에 file/<이름>
을 추가해, 마인크래프트를 켜면 수동 선택 없이 자동 적용되게 한다(목록 마지막=최상위).
options.txt 없으면 해당 한 줄만 생성, incompatibleResourcePacks 에 있으면 제거.
안내 문구도 "자동 적용" 으로 갱신. 0.4.22→0.4.23.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
근본 원인(실측): fabric-installer 를 -dir .mc_custom 으로 돌리면 .mc_custom 에
versions/ 와 libraries/ 를 실제 폴더로 만드는데 fabric 것만 들어가고 바닐라 버전
JSON·라이브러리는 빠진다. 그러면 .minecraft 로의 링크가 "폴더 있음" 으로 건너뛰어져
런처가 바닐라 데이터를 못 찾고 "Unable to prepare assets for download" 로 실패.
(웹 조사 확인: assets/libraries/versions 는 런처 폴더 .minecraft 아래 형제 폴더.)
- fabric 을 .minecraft 에 설치(-dir .minecraft)해 바닐라와 같은 위치에 둠. 최신 fabric
버전 폴더에 .jar 이 없어 설치 완료 판정을 .json 존재로 변경.
- linkMinecraftRuntimeDirs: 예전 설치가 gameDir 에 만든 불완전한 versions/libraries
실제 폴더를 .minecraft 링크로 교체(관리 데이터라 안전). assets 는 보존.
- 문서 갱신. 0.4.21→0.4.22.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
.minecraft/{assets,libraries,versions} 가 없으면(바닐라 미실행/다른 런처 환경)
링크를 건너뛰어 .mc_custom/<dir> 이 아예 없어졌고, 그러면 마인크래프트가
"Unable to prepare assets for download" 로 실패했다(코드 주석에도 명시된 원인).
원본이 없으면 .mc_custom/<dir> 을 빈 폴더로 만들어 런처가 그 gameDir 에 직접
받아가도록 수정. 0.4.20→0.4.21.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
최종 리소스팩(finalResourcepackPath !== ".")이 등록돼 있으면 완성본을 설치 마지막에
따로 받으므로, 클라이언트 설치 단계에서 베이스 리소스팩 다운로드를 건너뛴다
("등록한 최종 리소스팩만 다운로드"). 최종 리소스팩이 "."(없음)이면 기존대로 베이스를
받는다. 0.4.18→0.4.19.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- pack.finalResourcepackPath 추가(/file/resourcepacks/outputs/, "."=없음, 기본 ".").
편집기에 "최종 리소스팩 (.zip)" 입력 필드 추가.
- 약관 표시대상에 showInFinalResourcepack("최종 리소스팩에 표시") 3번째 토글 추가
(스키마/시드/마이그레이션/편집기 체크박스·배지·저장 라우트, index.json 노출).
- 간편설치기 완료 단계: 기존 "직접 적용" 경고 제거 → 최종 리소스팩이 "."이 아니면
"리소스팩을 설치하시겠습니까?" 예/아니요. 아니요→완료, 예→최종 리소스팩 약관
(showInFinalResourcepack) 동의→/file/resourcepacks/outputs/ 에서 다운로드→완료.
"." 이면 이 페이지 자체를 건너뜀.
- 0.4.15→0.4.16.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
음악퀴즈 간편설치기 마지막(완료) 단계, 마인크래프트 실행 직전에
"리소스팩은 리소스팩 설치기로 설치해서 마인크래프트 내에서 직접 적용해야 합니다"
경고 문구를 눈에 띄게 표시. 0.4.14→0.4.15.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v0.4.12 의 yt-dlp 내부 재시도(--retries)로도 남는 403(특정 클라이언트/스트림 URL
차단, 예: android_vr)에 대응:
- yt-dlp 에 --extractor-args youtube:player_client=default,web_safari,tv,ios 추가.
한 클라이언트의 URL 이 403 이어도 다른 클라이언트 포맷으로 받는다(클라이언트명
유효성은 실제 yt-dlp 로 검증).
- 실패한 곡의 순차 재시도를 1회 → 최대 3회로, 시도마다 점점 더(최대 20s) 쉬어
유튜브 rate-limit 이 풀릴 시간을 준다. 0.4.13→0.4.14.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
메인 간편설치기의 fetchBuffer/downloadFile 은 재시도가 없어, 너무 빠르게/자주
요청해 생기는 일시적 오류(429·5xx·네트워크 끊김·타임아웃, 일부 403)에 곧바로
실패했다. RP 설치기처럼 일시 오류를 지수 백오프(Retry-After 우선)로 최대 3회
재시도하도록 보강(모드 다중 다운로드/서버·맵·리소스팩·매니페스트 모두 적용).
404 등 영구 오류는 그대로 실패. 0.4.12→0.4.13.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 하드코딩 [8,11,17,21,25] 대신 Adoptium(Temurin) API 에서 실제 배포 버전을 가져와
편집기 드롭다운을 채운다. 브라우저 CORS 차단이라 서버가 프록시:
GET /op/jdk-versions (메이저 목록), GET /op/jdk-versions/:major (GA/EA 릴리스명).
6h 캐시 + 네트워크 실패 시 정적 폴백.
- 편집기: 기본은 LTS(25/21/17/11/8)만 표시, "자세히 보기" 체크 시 비-LTS 메이저까지
펼치고 선택 메이저의 GA/EA 스냅샷 릴리스명을 함께 보여준다.
- normalizeRecommendedJdk 를 고정 목록 대신 8~99 범위로 완화(동적 메이저 허용).
- 버전 0.4.7→0.4.8.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- JDK 탐색을 C:\Program Files\Java → 환경변수(JAVA_HOME/JDK_HOME) → 설치기
자동설치 위치 순으로 훑어 권장 버전을 우선 선택. 권장이 없으면 가장 높은 버전을
대신 고르되 match=false 로 표시.
- 권장과 다른 버전을 찾거나 직접 선택하면 "권장과 달라 정상 실행이 안 될 수 있음"
경고를 띄우고, 동의(확인) 시에만 진행(무조건 차단 대신 경고+동의).
- 자동 설치 경로를 %APPDATA%/jdk → .mc_custom/jdk 로 변경(파일제거기가 함께 정리).
Adoptium zip 의 중첩 jdk-* 폴더까지 탐색하도록 resolveJdkHome 보강.
- 버전 0.4.6→0.4.7.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- pack 에 recommendedJdk 추가(shared/types, store 정규화, 기본 25, 허용목록
[8,11,17,21,25]). 사이트 편집기에 JDK 버전 드롭다운 추가(직접 입력 X).
- 설치기 JDK 탐색 순서 변경: ① 권장 JDK 자동설치 위치(temurin-<권장>) 우선 →
② 없으면 컴퓨터 JDK(JAVA_HOME/Program Files, 권장 버전 이상만 인정).
- 자동 설치/버전 검증도 pack 의 권장 버전을 사용(하드코딩 25 제거).
- 렌더러에 권장 JDK 표시, 관련 안내/문서 갱신. 버전 0.4.5→0.4.6.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
자동 탐색은 Java 25 미만을 걸렀지만, 사용자가 직접 입력/폴더선택한 JDK 는
버전 검증 없이 다음 단계로 넘어가 run.bat 이 낡은 자바로 패치될 수 있었다.
그러면 서버가 여전히 UnsupportedClassVersionError 로 뜨지 않는다.
- jdk:verify IPC 추가(java -version 으로 메이저 버전 확인) + preload 노출.
- JDK 단계 "다음" 에서 선택 경로를 검증해 Java 25 미만이거나 버전을 못 읽으면
진행을 막고 안내. 자동 설치/자동 탐색 경로도 이 게이트를 통과.
- 버전 0.4.4→0.4.5.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
증상: 리소스팩 설치기 사진 다운로드에서 "N번 사진 다운로드 실패: HTTP 429" 로
설치가 중단됨. 원인: 음악(yt-dlp) 단계가 유튜브를 많이 두드려 IP 가 일시
throttle 되고, 사진 단계는 순차이긴 하나 요청 간 간격이 없어 i.ytimg.com 429 를
유발/회복하지 못하고 첫 장부터 실패.
- 음악 단계 직후 사진 단계 시작 전 쿨다운(4s).
- 사진 요청 사이 간격(0.8s+jitter)으로 429 유발 억제.
- 재시도 5→6회, 재시도마다 로그/진행률로 대기 상태 표시(멈춘 것처럼 보이지 않게).
- 최종 실패가 429면 "잠시 뒤 다시 시도하면 이어받는다"는 안내 추가.
- 버전 0.4.3→0.4.4.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
증상: 서버 실행 시 UnsupportedClassVersionError (class 69.0=Java 25 서버를
Java 17 로 실행). 원인: (1) 자동 설치 JDK 가 21 로 최신 MC(Java 25)에 부족,
(2) server:install 이 jdkPath 를 무시해 run.bat 이 시스템 PATH 의 낡은 java 사용.
- 번들 JDK 21→25(Adoptium Temurin 25). BUNDLED_JDK_MAJOR 상수로 일원화.
- jdk:detect 가 `java -version` 으로 메이저 버전을 확인해 25 미만은 "없음" 처리
→ 낡은 JAVA_HOME/시스템 자바에 걸리지 않고 자동 설치(25)로 유도.
- server:install 이 run.bat 의 `java` 실행 토큰을 설치기 JDK 의 java 로 치환.
자동설치 JDK 는 %APPDATA% 전개형 경로라 한글 사용자명에도 안전, latin1
라운드트립으로 기존 주석 바이트 보존.
- 안내 문구/문서(Java 25), 버전 0.4.2→0.4.3.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- "위 모든 약관에 동의합니다" 통합 체크(탭 방식)를 약관별 페이지 흐름으로 변경.
각 약관마다 "해당 약관에 동의합니다" 체크박스, [다음] 이면 다음 약관 페이지로.
- 다음 약관을 보여줄 때 화면(pageHost)을 맨 위로 스크롤해 처음부터 읽게 함.
- 본문을 끝까지 내려 읽어야 동의 체크가 활성화(짧아서 스크롤 불필요하면 즉시 허용).
뒤로/앞으로 이동 시 이전 동의 상태 유지.
- installer / installer-rp 양쪽 적용, 로케일 키(agreeThis/readToBottom/stepLabel) 추가.
- 버전 0.4.0 → 0.4.1.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 음악퀴즈 파일제거 도구 신규 추가: 동의 → 휴지통/완전삭제 선택 → 커스텀 폴더
(현재값 + 기본 .mc_custom) 전체, 데스크톱 바로가기, gameDir 가 해당 폴더인
마인크래프트 런처 프로필 정리.
- MC_CUSTOM_DIR .env 로 커스텀 게임 폴더 이름 유동화(.mc_custom 기본). 렌더러
사전에도 실제 폴더명 반영.
- 간편포트포워딩: 실행 중 UPnP 매핑 유지, 창 닫힘/종료 시 자동 제거(activePort 추적).
- 개발자용 빌드는 창/헤더 제목 앞에 (개발자용) 표기, exe 이름에도 반영.
- exe 이름 변경: 음악퀴즈 간편설치기 / 음악퀴즈 리소스팩설치기 / 간편포트포워딩.
- README 및 .env 템플릿 갱신, 버전 0.3.23 → 0.4.0.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
리뷰 지적 4건 반영(서버 전용, exe 영향 없음).
- 로그인 IP 기준 실패 제한(15분 창 10회 → 15분 차단). 브루트포스 + scrypt CPU
남용 방지. 인메모리, 무한 성장 가드 포함.
- 운영 계정을 gitignore 된 account.local.json 으로 이전. readAccounts 는 local
우선, 없으면 추적되는 account.json 을 시드로 읽음. writeAccounts 는 local 에만
기록 → 첫 로그인 자동 해시 업그레이드부터는 추적 평문 파일을 더 쓰지 않음.
(account.json 을 git rm --cached 하면 서버 pull 시 삭제되는 위험이 있어 추적 자체는
건드리지 않고, 실질 사용 파일만 분리.)
- 세션 쿠키 secure 를 SESSION_COOKIE_SECURE=true 로 켤 수 있게(HTTPS 배포용).
- 평문→해시 자동 업그레이드 저장 실패를 조용히 무시하지 않고 console.error 로 기록.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
전체 코드 재검토 기반의 안전한 개선 1차 배치.
- 메인 설치기에 전역 uncaughtException/unhandledRejection 가드 추가. nat-upnp
(detectExternalIpUpnp)의 비동기 소켓 오류로 앱이 조용히 종료되던 잠재 크래시
방지(포트포워딩 도구 v0.3.18 과 동일 대비).
- 서버: fetchVideoMeta/fetchPlaylistEntries 에 http(s) URL 검증 추가(운영자 입력이
yt-dlp 플래그로 오인되는 인자 주입 차단). /file/mods/:folder/index.json 의 async
throw → next(error) 로 위임(unhandledRejection 방지). index 라우트 pack 정의
병렬 로드.
- 죽은 i18n 키 정리: installer 로케일의 UPnP/run.bat 관련 19개 + pf 로케일 2개
제거(코드에서 미참조 확인). 크래시 가드용 log.internalError, youtube.invalidUrl 추가.
v0.3.23.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
퀴즈팩 선택(step1) 직후, 약관 동의 진입 전에 "마인크래프트와 마인크래프트 런처를
종료한 뒤 진행해주세요"를 큰 글씨의 강조 카드(빨강 테두리 + 매우 중요 배지)로
표시하는 페이지 추가(renderCloseNotice). 이전/다음 버튼 제공. v0.3.22.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
요청 반영: 간편설치기 포트포워딩 페이지가 포트를 직접 열지 않고 "열려 있는지"만
확인한다.
- server:portForward 를 UPnP 자동 개방/재점검 없이 외부 도달 점검만 하도록 변경,
결과를 open/notOpen 으로 반환(PortForwardResult status 타입도 변경).
- 열려 있으면 외부 접속 주소를 크게, 안 열려 있으면 "직접 포트포워딩 해주세요"
를 크게 표시.
- 페이지 체크에서만 쓰이던 openPortViaUpnp/removeUpnpMapping 제거(고아 코드).
- 참고: 서버 기동 시 run.bat 의 UPnP 자동 개방 주입(injectUpnpToRunBat)은 이번엔
유지. v0.3.19.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
라우터가 UPnP 를 거부(ECONNREFUSED)하는 환경에서 nat-upnp 가 콜백 밖에서
비동기 소켓 오류를 내면 Electron 메인이 종료돼 창이 갑자기 닫히는("오류나면서
끝남") 현상이 생길 수 있다. v0.3.17 에서 CGNAT 판별용으로 externalIp() 를 항상
호출하게 되면서 이 경로가 새로 노출됨. process 전역 uncaughtException/
unhandledRejection 가드로 잡아 로그만 남기고 앱은 계속 살려 둔다(각 UPnP 호출은
타임아웃으로 진행되므로 멈추지 않음). v0.3.18.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
리뷰 지적 반영. 기존엔 HTTP 공인 egress IP 만 100.64/10 검사라, 전형적 CGNAT
(egress 는 ISP 공인, 라우터 WAN 만 100.64)을 놓치고 "CGNAT 아님"처럼 오진 가능.
- 라우터 WAN(IGD 외부) IP 를 UPnP 로 조회해 HTTP 공인 IP 와 비교.
- cgnat 를 3-state(yes/no/unknown)로: WAN 이 사설/CGNAT 이거나 공인 IP 와 다르면
yes, 같으면 no, WAN 못 읽으면 unknown.
- unknown 이면 "외부 IP만으론 CGNAT 확정/배제 불가, 라우터 WAN 확인" 안내.
- WAN 조회 타임아웃 8s→6s. v0.3.17.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
포트포워딩 도구가 실패/확인불가일 때 다음 조치를 바로 안내하도록 보강.
- 이 PC LAN IPv4 자동 감지 → "외부 TCP {port} → {localIp}:{port} 수동 포워딩 +
Windows 방화벽 인바운드 허용" 안내.
- 외부 IP 가 CGNAT(100.64/10) 대역이면 경고(공유기 포워딩만으론 불가).
- UPnP 가 ECONNREFUSED/타임아웃이면 "라우터 UPnP 거부/미지원" 로그 힌트.
실제 사용자 로그(라우터 UPnP ECONNREFUSED, 공인 IP, ifconfig false)에 기반한
개선. v0.3.16.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
포트포워딩만 단독으로 수행하는 세 번째 Electron 앱 추가.
- 포트 입력(기본 25565) → UPnP 개방 시도 → 외부에서 닿는지 점검(ifconfig.co
+ 임시 리스너) → 외부 접속 주소/성공·실패·확인불가 안내. '포트 닫기'로 매핑 제거.
- 점검 로직은 메인 설치기의 v0.3.14 오탐 수정(ifconfig 실패→확인불가)을 반영해
자체 포함. sharp 미사용이라 빌드에서 제외(exe 약 73MB).
- 신규: src/installer-pf/{main,preload}.ts, installer-pf/{index.html,renderer.js},
locales/installer-pf/ko-kr.json, tsconfig.installer-pf.json, electron-builder-pf.yml.
- package.json 에 installer:pf / dist:win:pf 스크립트, i18n 컴포넌트 유니온에
'installer-pf' 추가. v0.3.15.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
- 메인 설치기: 첫 페이지로 "마인크래프트 런처를 끄고 시작해주세요" 안내(renderIntro)
추가 후 다음 버튼으로 step1 진입.
- 리소스팩 설치기: 완료(step3) 페이지 문구를 "사용자 동의하에 리소스팩이
설치되었습니다." + "리소스팩은 직접 적용해주세요." 로 변경.
v0.3.12.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
On install failure the temp folder is now preserved instead of wiped, so
already-downloaded songs/images are skipped on the next attempt. The
error screen offers 재시도 (resume from the failed item) and 처음으로
(discard the partial download and restart). Closing the program without
retrying still wipes the partial download via window-all-closed, and an
explicit cancel also clears it.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Avoid the Windows file-lock race where one worker deletes/overwrites
yt-dlp.exe/ffmpeg.exe while sibling workers still run those processes.
Now pass 1 downloads all tracks and collects failures without any
mid-flight refresh; after Promise.all (no live child processes), the
binaries are force-reinstalled once and only the failed tracks retry.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
오래된 yt-dlp/ffmpeg 가 유튜브 변경을 못 따라가 다운로드가 실패할 때
최신 버전으로 강제 재설치 후 한 번 더 시도한다.
- server youtube.ts: ensureYtDlp(force) 추가(캐시·zipapp 삭제 후 최신 재다운로드).
fetchVideoMeta/fetchPlaylistEntries 를 runYtDlp 로 묶어 1차 실패 시
강제 재설치 후 재시도.
- installer ytdlp.ts/ffmpeg.ts: ensure*Exe(log, force) 추가.
- installer main.ts: 음악 워커가 곡 다운로드 실패 시 전역 1회 강제 재설치
(refreshBinariesOnce) 후 해당 곡을 1회 재시도.
사진 URL 에 data: URI 가 들어오면 http/https 만 처리하는 다운로더가
'Protocol "data:" not supported' 로 설치 전체를 중단시키던 문제 수정.
data: URL 은 이미지 바이트를 직접 품고 있으므로 base64/percent-encoding
을 디코드해 Buffer 로 바로 반환한다. 잘못된 형식은 명확한 메시지로 거절.
Each music list row now shows a 설명 button immediately to the left of
the 별칭 button. Click opens a modal with a multi-line textarea; on
close the value is persisted into MusicListEntry.description and saved
to the same pack list JSON. The button gets a hasDesc visual indicator
when filled. Description is stored but intentionally not consumed by
datapack export or alias matching — purely informational metadata.
- types.ts: add description: string to MusicListEntry
- store.ts: normalize entry.description via sanitizeStr (defaults to '')
- listEditor.ejs: new #descModal alongside aliasModal
- listEditor.js: render descBtn left of aliasBtn, attach handlers,
also set description: '' on playlist-fetched entries
- styles.css: extend trackRow grid to 6 cols, reuse aliasBtn styling
for descBtn, add descTextarea sizing
- locale (ko-kr): descBtn / descModalTitle / descBack / descPlaceholder
/ descHint
Backwards-compatible: existing list JSON files without description
field normalize to ''.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
probeVersion() now captures stderr/exit-code/signal/spawn-error instead of
returning a bare boolean, and ensureYtDlp() tries the bundled binary first,
falls back to `yt-dlp(.exe)` on PATH if the bundled one won't execute (AV
block, missing libc symbol, broken download), and only then re-downloads.
The final user-facing error includes the per-attempt diagnostics so we can
actually see WHY verification failed instead of the opaque
"yt-dlp 다운로드는 됐지만 실행 검증에 실패했습니다." message.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reviewer correctly flagged that the previous skip-on-collision
behavior silently drops new quiz tracks when the base resourcepack
already has the same track_NN key. That makes the install LOOK
successful but breaks the quiz at runtime (datapack references the
missing track).
The new behavior throws a clear error explaining which key collided
and what the user must do (remove the conflicting base entry, or
use a different base). The base assets are still preserved (we
never overwrite); we just refuse to build a broken pack.
Removed the now-unused skip-summary log keys.
If the base resourcepack already has audio files under
assets/musicquiz/sounds/ or entries in assets/musicquiz/sounds.json,
the build now PRESERVES them and skips any new track that would
collide. Same policy for painting textures: existing cover_*.png
in the base are not overwritten by new ones.
Per-track collision is logged so the user can see exactly what was
preserved and what was skipped. Summary counts (added / skipped)
are also logged.
Requested by 사금향: "기존에 있는걸 삭제하거나 이상하게 엎어쓰지
말것" — preserve base assets unconditionally.
User asked for "약관 표시 실패시 설치 실패로 처리". The block-on-failure path
is already in place; this just sharpens the message so users see "설치를
진행할 수 없습니다" rather than a soft retry prompt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reviewer caught that v0.3.4 was bypassing the agreement step entirely on
network/server errors, letting users install without ever seeing terms.
Now only the explicit empty-list response (terms:[]) skips the step.
Network errors, 404s, and IPC failures render an error page with Back/Retry
buttons; no next button is exposed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- _meta.json: customLabels -> terms.{label,showInInstaller,showInInstallerRp}
- Drop builtin protection; any term kind can be deleted/added/toggled
- New public route /manifest/terms/<pack>/index.json for installer term lists
- Installers fetch terms:list dynamically; skip agreement step if list empty
- Term editor: 2 visibility checkboxes (설치기 / 리소스팩 설치기), multi-select
- Migration from old schema preserves custom labels (default: visible in both)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- store.ts: 약관을 manifest/terms/<packKey>/ 폴더별로 저장. 첫 접근 시
legacy 전역 .md 파일을 시드로 자동 복사한다.
- importTerms() 추가: 다른 음악퀴즈의 .md + _meta.json 을 현재 pack 으로
복사한다. 동일 kind 는 source 값으로 덮어쓴다.
- /op/agreement 라우트를 세 단계로 분리:
· /op/agreement → 음악퀴즈 카드 선택 페이지
· /op/agreement/:packName → 해당 pack 의 약관 목록 + 추가 + 불러오기
· /op/agreement/:packName/:kind → 에디터
- 공개 라우트도 /manifest/terms/:packKey/:fileName 으로 변경.
- 설치기 main.ts: state.selectedKey 를 약관 URL 에 포함하도록 수정 (메인 +
rp 양쪽). pack 미선택 상태에서는 에러 반환.
- termsEditor.js: PACK_KEY 를 받아 저장 URL 에 포함.
- 다른 음악퀴즈 후보 select + 확인 모달 + locale 추가.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 약관 편집기 배경/슬래시 메뉴를 사이트 다크 팔레트로 통일 (흰 배경 + 흰 글씨 가시성 문제 해결)
- 약관 목록을 가로 풀폭 1줄씩 세로로 쌓이는 레이아웃으로 변경
- 사용자 정의 약관 추가/삭제 지원
- manifest/terms/_meta.json 에 라벨 저장
- builtin 5종(map/resourcepack/mod/installer/installer-rp)은 삭제 불가, "기본" 배지 표시
- kind 식별자 규칙: 소문자/숫자/하이픈 32자 이내
- 공개 라우트 /manifest/terms/<file>.md 는 isPublicTermsFile() 로 _meta.json 차단
- 0.3.0 → 0.3.1
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 5종 약관(map/resourcepack/mod/installer/installer-rp) markdown 시드 + manifest/terms/ 노출
- 사이트 /op/agreement 목록 + Notion 스타일 markdown 에디터 (슬래시 명령어, 미리보기)
- 메인 installer: 음악퀴즈 선택 직후 약관 동의 페이지(맵·모드·설치기) 추가
- rp installer: 음악퀴즈 선택 직후 약관 동의 페이지(리소스팩·설치기) 추가
- rp installer 취소 버그 수정: buildResourcepackZip 단계간 + archive.abort() 폴링
- rp installer 취소 UX: 즉시 "취소 중…" 표시, 취소 시 installFailed 알림 생략
- 0.2.6 → 0.3.0 (큰 기능)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The RP installer downloads a fresh copy of the base zip into its temp
dir and composes the final pack on top of it. The base zip the main
installer placed in .mc_custom/resourcepacks/ has nothing to do after
that — but it stays in the Minecraft resource-pack list as a second
entry. Delete it after the final zip is written.
Guard against the case where the user set outputPackName equal to the
base filename, which would make base path == final path; in that case
we leave it alone so we don't wipe the file we just wrote.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per user request: when outputPackName is empty, fall back to
`<packKey>_resourcepack` instead of `<packKey>_musicquiz`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a new "생성되는 리소스팩 이름" admin field saved to the pack
manifest and consumed by the rp installer when naming the final zip.
Empty value falls back to <packKey>_musicquiz; Windows-invalid chars
are sanitized to '_'. Bumps version 0.1.1 → 0.2.0 (new feature).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reviewer follow-ups:
1) Preserve mods/ for vanilla packs. `downloadModsFolder` now checks
`!pack.modsFolder` BEFORE wiping — vanilla packs (no modsFolder) no
longer clobber a user's hand-curated mods directory. Wipe still runs
for modded packs to keep different MC versions from colliding.
2) Always rename the extracted map to `saves/<퀴즈이름>/`, regardless of
the zip's top-level layout. The zip is now extracted into a temp
directory under saves/, and:
- if the temp has a single subdirectory, that subdirectory's content
becomes the world;
- otherwise the temp dir itself (e.g. level.dat + region/ at root) is
the world.
In either case, it is renamed atomically to `saves/<sanitized name>`
(or `<name>_2` etc. if a user world collides). Marker tracks the
final folder name for participant cleanup.
User request: replace both .exe icons.
- Added build/icon.ico (multi-size 16/32/48/64/128/256) and build/icon.png
generated from the new music-note artwork.
- electron-builder.yml: set win.icon, nsis installer/uninstaller icons,
buildResources=build, include build/icon.* in files for runtime use.
- New electron-builder-rp.yml + dist:win:rp script so the resourcepack
installer also packages with the same icon.
- BrowserWindow({ icon }) wired in both installer and installer-rp main
processes so the running window's titlebar/taskbar icon matches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two follow-ups requested by the user (and the first flagged by the
reviewer for omission):
1) Different Minecraft versions or different packs leave behind mod jars
that crash Fabric on load. `downloadModsFolder` now removes the entire
`.mc_custom/mods/` directory before every install — including when the
pack is vanilla (no modsFolder) so leftovers from a previous modded
pack get cleared too.
2) `downloadMapZip` renames the single extracted top-level folder to the
pack name (sanitized for Windows: forbidden chars `<>:"/\|?*` and
control chars → `_`, trailing space/dot trimmed, reserved names like
CON/NUL prefixed, empty fallback to `map`). Collisions with user
worlds get `_2`, `_3` … suffixes so we never overwrite the user's
own worlds. The marker file tracks the post-rename folder so future
participant cleanup still removes only what the installer created.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>