Commit Graph

69 Commits

Author SHA1 Message Date
d4e4378602 revert(installer): config zip 경로를 /file/configs (복수)로 되돌림 (v0.4.30)
사용자가 서버 폴더를 configs(복수)로 정리하기로 해, 단수 config 로 바꿨던
것을 원복. resolveManifestRelative subDir 'configs', 타입 주석/로케일 힌트/
리포지토리 폴더(file/configs)/버전(0.4.30) 모두 복수로 통일.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-11 17:47:43 +09:00
9e9eae0920 fix(installer): config zip 경로 단수화 소스 반영 (v0.4.29)
이전 커밋(082dae5)은 file/configs→config 폴더 rename 만 담기고 실제 소스
변경이 누락됐다. resolveManifestRelative subDir 를 'config' 로, 관련
타입 주석/로케일 힌트/버전(0.4.29)까지 반영.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-11 00:23:48 +09:00
bed47e88a0 docs: Fabric 로더 힌트를 meta 프로필 JSON 방식으로 정정
관리자 편집기 platformLoaderHint 가 아직 "fabric-installer CLI 설치"라고
설명하고 있었으나, 실제 설치기는 자바 없이 Fabric Meta profile JSON 을 받아
.minecraft/versions 에 직접 저장한다. UI 설명을 실제 동작에 맞춤.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-10 23:47:48 +09:00
ab928b13e0 feat: config 파일(.zip) 입력/다운로드 지원 (v0.4.27)
관리자 편집기에서 맵 파일과 서버 파일 사이에 "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>
2026-08-10 23:43:54 +09:00
57e85e0352 fix(installer): fabric 설치를 자바 없이 meta 프로필 JSON 직접 저장으로
근본 해결: 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>
2026-08-10 23:25:17 +09:00
a8698ef394 fix(installer): 자바 못 찾을 때(ENOENT) "바닐라 먼저 실행" 안내 + JDK 추가 탐색
원인: 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>
2026-08-10 23:08:13 +09:00
80059d6696 fix(installer): 최종 리소스팩 자동 적용 실패를 UI 에 경고
options.txt 자동 적용이 실패하면(권한/잠금/손상 등) 예전엔 성공처럼 "자동 적용됩니다"
로 보였다. 이제 finalResourcepack:install 이 applied=false 를 반환하고, 렌더러가
"받았지만 자동 적용 실패 — 직접 켜주세요" 경고를 표시한다(다운로드 자체는 성공). 0.4.23→0.4.24.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-28 22:36:57 +09:00
68e2312ce7 feat(installer): 최종 리소스팩 다운로드 후 자동 적용(options.txt)
최종 리소스팩을 받은 뒤 gameDir 의 options.txt resourcePacks 목록에 file/<이름>
을 추가해, 마인크래프트를 켜면 수동 선택 없이 자동 적용되게 한다(목록 마지막=최상위).
options.txt 없으면 해당 한 줄만 생성, incompatibleResourcePacks 에 있으면 제거.
안내 문구도 "자동 적용" 으로 갱신. 0.4.22→0.4.23.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-28 22:21:29 +09:00
13e4e0eb13 fix(installer): fabric 를 .minecraft 에 설치 — 바닐라 라이브러리/버전 누락 해결
근본 원인(실측): 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>
2026-07-27 22:42:40 +09:00
e80933d21e fix(installer): 런타임 폴더 원본 없을 때 빈 폴더 생성 (assets 준비 실패 완화)
.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>
2026-07-27 22:20:39 +09:00
3c404ecd8c feat(installer): 최종 리소스팩 등록 시 베이스 리소스팩 다운로드 생략
최종 리소스팩(finalResourcepackPath !== ".")이 등록돼 있으면 완성본을 설치 마지막에
따로 받으므로, 클라이언트 설치 단계에서 베이스 리소스팩 다운로드를 건너뛴다
("등록한 최종 리소스팩만 다운로드"). 최종 리소스팩이 "."(없음)이면 기존대로 베이스를
받는다. 0.4.18→0.4.19.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-27 00:25:10 +09:00
e5dcc47548 feat: 최종 리소스팩(선택 설치) + 약관 표시대상 추가
- 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>
2026-07-23 00:33:07 +09:00
f53e54493d feat(installer): 완료 화면에 리소스팩 안내 경고 추가
음악퀴즈 간편설치기 마지막(완료) 단계, 마인크래프트 실행 직전에
"리소스팩은 리소스팩 설치기로 설치해서 마인크래프트 내에서 직접 적용해야 합니다"
경고 문구를 눈에 띄게 표시. 0.4.14→0.4.15.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-22 01:02:47 +09:00
9abf6da5f1 fix(rp): 노래 403 개선 — 플레이어 클라이언트 다변화 + 곡별 지연 재시도
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>
2026-07-22 00:45:33 +09:00
48d5223671 fix(installer): 다운로드 일시 오류 시 자동 재시도(백오프)
메인 간편설치기의 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>
2026-07-20 18:30:27 +09:00
fefa2dcdd2 feat(server): 권장 JDK 목록을 Adoptium 에서 동적으로 + 자세히 보기(스냅샷)
- 하드코딩 [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>
2026-07-17 14:43:55 +09:00
9d9b5183b8 feat(server): 권장 JDK 탐색을 PF/환경변수 중심으로 + 불일치 경고 + .mc_custom/jdk 설치
- 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>
2026-07-17 12:13:33 +09:00
a1d8435b71 feat(server): 사이트에서 권장 JDK 선택 + 설치기 권장 JDK 우선 탐색
- 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>
2026-07-17 08:59:41 +09:00
a6118039a3 fix(server): 직접 선택한 JDK 도 Java 25+ 검증 후 진행
자동 탐색은 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>
2026-07-17 00:45:06 +09:00
48e0421135 fix(rp): 사진 다운로드 HTTP 429(속도제한) 내성 강화
증상: 리소스팩 설치기 사진 다운로드에서 "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>
2026-07-17 00:29:23 +09:00
cf29270102 fix(server): Java 25 번들 + run.bat 이 설치기 JDK 를 쓰도록 수정
증상: 서버 실행 시 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>
2026-07-17 00:11:50 +09:00
3f553f958d feat(installer): 약관을 한 건씩 페이지로 — 개별 동의 + 상단 스크롤 + 끝까지 읽기 강제
- "위 모든 약관에 동의합니다" 통합 체크(탭 방식)를 약관별 페이지 흐름으로 변경.
  각 약관마다 "해당 약관에 동의합니다" 체크박스, [다음] 이면 다음 약관 페이지로.
- 다음 약관을 보여줄 때 화면(pageHost)을 맨 위로 스크롤해 처음부터 읽게 함.
- 본문을 끝까지 내려 읽어야 동의 체크가 활성화(짧아서 스크롤 불필요하면 즉시 허용).
  뒤로/앞으로 이동 시 이전 동의 상태 유지.
- installer / installer-rp 양쪽 적용, 로케일 키(agreeThis/readToBottom/stepLabel) 추가.
- 버전 0.4.0 → 0.4.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-15 23:54:10 +09:00
996a7cc03e feat(installer): v0.4.0 — 파일제거기, 커스텀 폴더명, 포트포워딩 개편, 이름/개발자용 표기
- 음악퀴즈 파일제거 도구 신규 추가: 동의 → 휴지통/완전삭제 선택 → 커스텀 폴더
  (현재값 + 기본 .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>
2026-07-15 23:21:46 +09:00
f392842d7f security: login rate-limit, gitignored account store, secure cookie opt, upgrade-fail log
리뷰 지적 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>
2026-07-11 12:31:34 +09:00
704d58d3ac optimize: crash guard, yt-dlp url validation, dead-key cleanup
전체 코드 재검토 기반의 안전한 개선 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>
2026-07-11 12:10:55 +09:00
2212195b3c installer: add big 'close Minecraft & launcher' notice after pack select
퀴즈팩 선택(step1) 직후, 약관 동의 진입 전에 "마인크래프트와 마인크래프트 런처를
종료한 뒤 진행해주세요"를 큰 글씨의 강조 카드(빨강 테두리 + 매우 중요 배지)로
표시하는 페이지 추가(renderCloseNotice). 이전/다음 버튼 제공. v0.3.22.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-07-11 11:23:33 +09:00
f0e07e06d6 installer: port page = check-only (no auto-open), big open/notOpen message
요청 반영: 간편설치기 포트포워딩 페이지가 포트를 직접 열지 않고 "열려 있는지"만
확인한다.
- 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>
2026-07-11 00:12:55 +09:00
281dbb644b installer-pf: prevent app from dying on nat-upnp async errors
라우터가 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>
2026-07-05 22:32:20 +09:00
005c7bf44c installer-pf: accurate CGNAT detection via router WAN vs public IP
리뷰 지적 반영. 기존엔 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>
2026-07-05 21:26:13 +09:00
05a5dcedc0 installer-pf: guide manual forwarding + detect CGNAT on failure
포트포워딩 도구가 실패/확인불가일 때 다음 조치를 바로 안내하도록 보강.
- 이 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>
2026-07-05 21:13:19 +09:00
86883f56e4 add standalone port-forwarding tool (마인크래프트 간편 포트포워딩)
포트포워딩만 단독으로 수행하는 세 번째 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>
2026-06-24 21:43:06 +09:00
674b9e7c87 installers: add intro notice (main) and finish notice (rp)
- 메인 설치기: 첫 페이지로 "마인크래프트 런처를 끄고 시작해주세요" 안내(renderIntro)
  추가 후 다음 버튼으로 step1 진입.
- 리소스팩 설치기: 완료(step3) 페이지 문구를 "사용자 동의하에 리소스팩이
  설치되었습니다." + "리소스팩은 직접 적용해주세요." 로 변경.
v0.3.12.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-06-23 23:02:38 +09:00
fe0d2f75e3 installer-rp: add resume-on-retry and discard-on-quit for failed installs
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>
2026-06-05 16:23:34 +09:00
399f4af808 installer-rp: defer yt-dlp/ffmpeg reinstall until all music workers finish
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>
2026-06-05 16:18:12 +09:00
d5f88e0e76 yt-dlp/ffmpeg: reinstall latest on failure, retry once
오래된 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회 재시도.
2026-06-05 16:08:26 +09:00
d9ba2b0f35 installer-rp: decode data: URL images instead of crashing
사진 URL 에 data: URI 가 들어오면 http/https 만 처리하는 다운로더가
'Protocol "data:" not supported' 로 설치 전체를 중단시키던 문제 수정.
data: URL 은 이미지 바이트를 직접 품고 있으므로 base64/percent-encoding
을 디코드해 Buffer 로 바로 반환한다. 잘못된 형식은 명확한 메시지로 거절.
2026-06-05 15:58:22 +09:00
b4160aefc1 list-editor: add per-track description button + modal
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>
2026-05-27 20:44:24 +09:00
b769f453a3 server-youtube: diagnostic detail + PATH fallback when bundled yt-dlp won't run
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>
2026-05-25 16:24:54 +09:00
5c13648f63 rp-pack: fail-fast on base track/painting collision (was: silent skip)
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.
2026-05-23 17:26:41 +09:00
9efd4a696a rp-pack: never overwrite base resourcepack sounds/paintings (v0.3.5)
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.
2026-05-23 17:18:46 +09:00
38df72e4f6 terms: phrase agreement-list failure as install failure (per request)
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>
2026-05-20 10:22:02 +09:00
6447b1cb78 terms: block install on terms list fetch failure (retry UI)
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>
2026-05-20 10:20:49 +09:00
9ba5dc6b7b terms: per-term installer visibility toggles + universal delete (v0.3.4)
- _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>
2026-05-20 10:14:42 +09:00
25977d894b terms: per-pack storage + import from another pack (v0.3.2)
- 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>
2026-05-20 01:29:04 +09:00
c14b0507c7 terms: dark editor BG, vertical row layout, add/delete custom kinds
- 약관 편집기 배경/슬래시 메뉴를 사이트 다크 팔레트로 통일 (흰 배경 + 흰 글씨 가시성 문제 해결)
- 약관 목록을 가로 풀폭 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>
2026-05-20 01:12:10 +09:00
ffb2048627 terms: agreement pages + site Notion-style editor + rp cancel fix
- 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>
2026-05-20 00:55:36 +09:00
40986bee11 installer-rp: delete base resourcepack zip after composing final pack
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>
2026-05-18 21:28:36 +09:00
794ad9b778 installer-rp: rename fallback pack name musicquiz → resourcepack
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>
2026-05-18 18:54:31 +09:00
f810719d92 installer-rp: site-configured outputPackName for built zip
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>
2026-05-18 18:34:46 +09:00
tkrmagid-desktop
6472b12d58 한국어 변경 2026-05-18 01:02:23 +09:00