feat(IconExporter): ZIP에 metadata.json 추가 및 압축 후 폴더 자동 삭제
- metadata.json에 mod_id, icon_size, exported_at, total_count, skipped_count 포함 - ZIP 압축 완료 후 원본 폴더 자동 삭제 - 특정 모드/전체 모드 압축 시 경로 구조 개선
This commit is contained in:
parent
6a3d698d9a
commit
4949a7071e
1 changed files with 92 additions and 12 deletions
|
|
@ -271,24 +271,72 @@ object IconExportManager {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val modName = currentModFilter ?: "all"
|
||||||
|
|
||||||
// ZIP 파일명 생성
|
// ZIP 파일명 생성
|
||||||
val timestamp =
|
val timestamp =
|
||||||
java.time.LocalDateTime.now()
|
java.time.LocalDateTime.now()
|
||||||
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
|
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
|
||||||
val modName = currentModFilter ?: "all"
|
|
||||||
val zipFileName = "${modName}_$timestamp.zip"
|
val zipFileName = "${modName}_$timestamp.zip"
|
||||||
// icons 폴더 안에 ZIP 생성
|
// icons 폴더 안에 ZIP 생성
|
||||||
val zipPath = iconsDir.resolve(zipFileName)
|
val zipPath = iconsDir.resolve(zipFileName)
|
||||||
|
|
||||||
IconExporter.LOGGER.info("ZIP 압축 생성 중: {}", zipPath)
|
IconExporter.LOGGER.info("ZIP 압축 생성 중: {}", zipPath)
|
||||||
|
|
||||||
|
// 압축할 모드 폴더 경로 (특정 모드 또는 전체)
|
||||||
|
val targetDir =
|
||||||
|
if (currentModFilter != null) {
|
||||||
|
iconsDir.resolve(currentModFilter!!)
|
||||||
|
} else {
|
||||||
|
iconsDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetDir.exists()) {
|
||||||
|
IconExporter.LOGGER.error("대상 폴더가 없습니다: {}", targetDir)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
ZipOutputStream(FileOutputStream(zipPath.toFile())).use { zos ->
|
ZipOutputStream(FileOutputStream(zipPath.toFile())).use { zos ->
|
||||||
Files.walk(iconsDir).use { paths ->
|
// metadata.json 추가
|
||||||
paths.filter { Files.isRegularFile(it) && it.name.endsWith(".png") }.forEach { file
|
val metadata = buildString {
|
||||||
->
|
append("{\n")
|
||||||
|
append(" \"mod_id\": \"$modName\",\n")
|
||||||
|
append(" \"icon_size\": $iconSize,\n")
|
||||||
|
append(" \"exported_at\": \"${java.time.LocalDateTime.now()}\",\n")
|
||||||
|
append(" \"total_count\": $successCount,\n")
|
||||||
|
append(" \"skipped_count\": $skipCount\n")
|
||||||
|
append("}")
|
||||||
|
}
|
||||||
|
zos.putNextEntry(ZipEntry("metadata.json"))
|
||||||
|
zos.write(metadata.toByteArray(Charsets.UTF_8))
|
||||||
|
zos.closeEntry()
|
||||||
|
|
||||||
|
// PNG 파일 추가
|
||||||
|
if (currentModFilter != null) {
|
||||||
|
// 특정 모드만 압축
|
||||||
|
Files.walk(targetDir).use { paths ->
|
||||||
|
paths.filter { Files.isRegularFile(it) && it.name.endsWith(".png") }.forEach {
|
||||||
|
file ->
|
||||||
try {
|
try {
|
||||||
// ZIP 내 상대 경로: <namespace>/<type>/<item>.png
|
// ZIP 내 상대 경로: blocks/<item>.png 또는 items/<item>.png
|
||||||
val relativePath = iconsDir.relativize(file).pathString.replace("\\", "/")
|
val relativePath =
|
||||||
|
targetDir.relativize(file).pathString.replace("\\", "/")
|
||||||
|
zos.putNextEntry(ZipEntry(relativePath))
|
||||||
|
Files.copy(file, zos)
|
||||||
|
zos.closeEntry()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
IconExporter.LOGGER.error("ZIP에 파일 추가 실패: {} - {}", file, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 전체 압축
|
||||||
|
Files.walk(iconsDir).use { paths ->
|
||||||
|
paths.filter { Files.isRegularFile(it) && it.name.endsWith(".png") }.forEach {
|
||||||
|
file ->
|
||||||
|
try {
|
||||||
|
val relativePath =
|
||||||
|
iconsDir.relativize(file).pathString.replace("\\", "/")
|
||||||
zos.putNextEntry(ZipEntry(relativePath))
|
zos.putNextEntry(ZipEntry(relativePath))
|
||||||
Files.copy(file, zos)
|
Files.copy(file, zos)
|
||||||
zos.closeEntry()
|
zos.closeEntry()
|
||||||
|
|
@ -298,11 +346,43 @@ object IconExportManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IconExporter.LOGGER.info("ZIP 압축 완료: {}", zipPath)
|
IconExporter.LOGGER.info("ZIP 압축 완료: {}", zipPath)
|
||||||
|
|
||||||
|
// 압축 완료 후 원본 폴더 삭제
|
||||||
|
try {
|
||||||
|
if (currentModFilter != null) {
|
||||||
|
// 특정 모드 폴더만 삭제
|
||||||
|
deleteDirectory(targetDir)
|
||||||
|
IconExporter.LOGGER.info("원본 폴더 삭제됨: {}", targetDir)
|
||||||
|
} else {
|
||||||
|
// 전체 모드인 경우 각 모드 폴더 삭제 (ZIP 파일 제외)
|
||||||
|
Files.list(iconsDir).use { dirs ->
|
||||||
|
dirs.filter { Files.isDirectory(it) }.forEach { dir -> deleteDirectory(dir) }
|
||||||
|
}
|
||||||
|
IconExporter.LOGGER.info("모든 원본 폴더 삭제됨")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
IconExporter.LOGGER.error("원본 폴더 삭제 실패: {}", e.message)
|
||||||
|
}
|
||||||
|
|
||||||
return zipPath
|
return zipPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 디렉토리 재귀 삭제 */
|
||||||
|
private fun deleteDirectory(dir: Path) {
|
||||||
|
if (!dir.exists()) return
|
||||||
|
|
||||||
|
Files.walk(dir).sorted(Comparator.reverseOrder()).forEach { path ->
|
||||||
|
try {
|
||||||
|
Files.delete(path)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
IconExporter.LOGGER.error("파일 삭제 실패: {} - {}", path, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 작업 취소 */
|
/** 작업 취소 */
|
||||||
fun cancel() {
|
fun cancel() {
|
||||||
if (!isRunning) return
|
if (!isRunning) return
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue