fix: smarter CD image selection per directory with format priority
Build & Deploy / build-and-deploy (push) Successful in 43s

Replace the broken descriptor-preference logic with a clean two-pass
approach: group images by parent directory, then pick the best format
per directory with priority .cue > .iso > .ccd > .img > .bin.

js-dos DOSBox's imgmount does NOT support .ccd (CloneCD descriptor)
natively, but .cue is widely supported. When both exist, .cue wins.
When only .ccd exists, it falls back to mounting the .img directly.
This commit is contained in:
Hermes Agent
2026-06-03 12:40:11 +02:00
parent 8a45ceccdc
commit 57842abe0d
+44 -39
View File
@@ -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<String> resolveCdImages(List<String> cdImages) {
// Group by parent directory
java.util.Map<String, java.util.List<String>> 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<String> 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<String> 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<String> 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<String> 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<String> 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");