diff --git a/src/main/java/com/dostalgia/UploadResource.java b/src/main/java/com/dostalgia/UploadResource.java index af22e34..340396e 100644 --- a/src/main/java/com/dostalgia/UploadResource.java +++ b/src/main/java/com/dostalgia/UploadResource.java @@ -564,6 +564,46 @@ public class UploadResource { return json.getBytes(java.nio.charset.StandardCharsets.UTF_8); } + /** Resolve one CD image per parent directory with best-format priority. + * Priority: .cue > .iso > .ccd > .img > .bin + * js-dos DOSBox (Emscripten) supports .cue natively, but .ccd often fails. */ + private static List resolveCdImages(List cdImages) { + // Group by parent directory + java.util.Map> byDir = new java.util.LinkedHashMap<>(); + for (String img : cdImages) { + int slashIdx = img.lastIndexOf('/'); + String parentDir = slashIdx >= 0 ? img.substring(0, slashIdx) : ""; + byDir.computeIfAbsent(parentDir, k -> new java.util.ArrayList<>()).add(img); + } + List result = new java.util.ArrayList<>(); + for (var entry : byDir.entrySet()) { + String best = pickBestCdImage(entry.getValue()); + if (best != null) result.add(best); + } + result.sort(String::compareTo); + return result; + } + + private static String pickBestCdImage(java.util.List images) { + // Priority: .cue [5] > .iso [4] > .ccd [3] > .img [2] > .bin [1] + String best = null; + int bestScore = -1; + for (String s : images) { + String lo = s.toLowerCase(); + int score = lo.endsWith(".cue") ? 5 + : lo.endsWith(".iso") ? 4 + : lo.endsWith(".ccd") ? 3 + : lo.endsWith(".img") ? 2 + : lo.endsWith(".bin") ? 1 + : 0; + if (score > bestScore) { + bestScore = score; + best = s; + } + } + return best; + } + /** Build config for a CD-only game (no executables on the filesystem). */ private String buildCdOnlyDosboxConf(List cdImages) { StringBuilder sb = new StringBuilder(); @@ -574,27 +614,10 @@ public class UploadResource { sb.append("[dos]\nxms=true\nems=true\numb=true\n\n"); sb.append("[autoexec]\n@echo off\nmount c .\n"); // Mount CD images as D:, E:, … - // Prefer descriptor formats (.cue, .ccd) over raw data (.img, .bin) - // DOSBox needs descriptors for proper track layout and filesystem access. - Set seenDirs = new java.util.HashSet<>(); + // Resolve one image per directory with format priority (.cue > .iso > .ccd > .img > .bin) char driveLetter = 'D'; - for (String img : cdImages) { - int slashIdx = img.lastIndexOf('/'); - String parentDir = slashIdx >= 0 ? img.substring(0, slashIdx) : ""; - if (seenDirs.contains(parentDir)) continue; + for (String img : resolveCdImages(cdImages)) { String imgLower = img.toLowerCase(); - // Skip raw data files when a descriptor exists in the same directory - if (imgLower.endsWith(".img") || imgLower.endsWith(".bin")) { - boolean hasDescriptor = cdImages.stream().anyMatch(i -> { - int is = i.lastIndexOf('/'); - String ip = is >= 0 ? i.substring(0, is) : ""; - String il = i.toLowerCase(); - return ip.equals(parentDir) - && (il.endsWith(".cue") || il.endsWith(".ccd")); - }); - if (hasDescriptor) continue; - } - seenDirs.add(parentDir); String flags = (imgLower.endsWith(".bin") && !imgLower.endsWith(".cue")) ? " -t cdrom -fs iso" : " -t cdrom"; sb.append("imgmount ").append(driveLetter).append(" \"").append(img).append("\"").append(flags).append("\n"); @@ -654,28 +677,10 @@ public class UploadResource { sb.append("@echo off\n"); sb.append("mount c .\n"); // Mount CD images as D:, E:, … so games can find their CD. - // Deduplicate by parent directory — prefer descriptor formats (.cue, .ccd) - // over raw data formats (.img, .bin). DOSBox needs descriptors for proper - // track layout (audio tracks, subchannel data, copy protection). - Set seenDirs = new java.util.HashSet<>(); + // Resolve one image per directory with format priority (.cue > .iso > .ccd > .img > .bin) char driveLetter = 'D'; - for (String img : cdImages) { - int slashIdx = img.lastIndexOf('/'); - String parentDir = slashIdx >= 0 ? img.substring(0, slashIdx) : ""; - if (seenDirs.contains(parentDir)) continue; + for (String img : resolveCdImages(cdImages)) { String imgLower = img.toLowerCase(); - // Skip raw data files when a descriptor exists in the same directory - if (imgLower.endsWith(".img") || imgLower.endsWith(".bin")) { - boolean hasDescriptor = cdImages.stream().anyMatch(i -> { - int is = i.lastIndexOf('/'); - String ip = is >= 0 ? i.substring(0, is) : ""; - String il = i.toLowerCase(); - return ip.equals(parentDir) - && (il.endsWith(".cue") || il.endsWith(".ccd")); - }); - if (hasDescriptor) continue; - } - seenDirs.add(parentDir); String flags = (imgLower.endsWith(".bin") && !imgLower.endsWith(".cue")) ? " -t cdrom -fs iso" : " -t cdrom"; sb.append("imgmount ").append(driveLetter).append(" \"").append(img).append("\"").append(flags).append("\n");