diff --git a/docker-compose.yml b/docker-compose.yml
index acd13f9..d0acf08 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -38,6 +38,8 @@ services:
- /mnt/smb-ame/Watch:/watch
- /mnt/smb-ame/Output:/output
- /mnt/smb-ame/Logs:/ame-logs
+ # High-res media folder for fallback lookup
+ - /mnt/Hitchcock/bmg_video/Media:/hires-media:ro
volumes:
app_data:
diff --git a/prproj-remapper.js b/prproj-remapper.js
index 2834201..a8289de 100644
--- a/prproj-remapper.js
+++ b/prproj-remapper.js
@@ -246,6 +246,8 @@ function parseProxyLinks(xml, mediaBlocks) {
function findHighResFileForGves(gvesPath, hiresTitle, hiresMediaFolder, fs) {
if (!hiresMediaFolder) return null;
+ console.log(`[HIRES LOOKUP] Searching for title="${hiresTitle}" in folder="${hiresMediaFolder}"`);
+
try {
// Normalize the folder path
const searchFolder = hiresMediaFolder.replace(/\\/g, '/').replace(/\/$/, '');
@@ -266,6 +268,7 @@ function findHighResFileForGves(gvesPath, hiresTitle, hiresMediaFolder, fs) {
// Match if filename contains the title
if (fileLower.includes(titleLower)) {
const fullPath = `${searchFolder}/${file}`;
+ console.log(`[HIRES LOOKUP] MATCH FOUND: "${file}" contains "${hiresTitle}"`);
return fullPath.replace(/\//g, '\\');
}
}
@@ -406,56 +409,93 @@ function performSwaps(xml, mediaBlocks, proxyLinks, options = {}) {
);
}
- // Handle unlinked high-res proxy blocks (have IsProxy: true, FilePath: null, no proxyLinks entry)
- // These occur when FramelightX created proxy blocks but didn't link them explicitly
- if (options.hiresMediaFolder && allGvesBlocks.length > 0) {
- // Get the first .gves block as reference (for path lookup)
- const gvesRef = allGvesBlocks[0].block;
+ // ─── Direct .gves → high-res lookup (when proxyLinks is empty) ───
+ // When FramelightX doesn't create explicit proxy linkages, we need to
+ // directly find high-res files for each .gves block in the media folder.
+ if (options.hiresMediaFolder) {
+ const processedGves = new Set(gvesUids); // Already handled above
- for (const [uid, hiresBlock] of Object.entries(mediaBlocks)) {
- // Skip if already processed, not a proxy, or already has a path
- if (gvesUids.includes(uid) || !hiresBlock.isProxy || hiresBlock.filePath) continue;
+ for (const { uid: gvesUid, block: gvesBlock } of allGvesBlocks) {
+ if (processedGves.has(gvesUid)) continue;
- // Try to find a high-res file for this unlinked proxy using its Title
+ // Extract the .gves filename to use as a lookup key
+ const gvesFilename = gvesBlock.filePath.split('\\').pop().split('/').pop();
+ const gvesBaseName = gvesFilename.replace(/\.[^.]+$/, '');
+
+ // Try to find a matching high-res file using the .gves block's title
+ // or by searching the high-res media folder
let hiresPath = findHighResFileForGves(
- gvesRef.filePath, // Use first gves path for reference
- hiresBlock.title,
+ gvesBlock.filePath,
+ gvesBlock.title,
options.hiresMediaFolder,
fs
);
+ // Also try matching against unlinked high-res proxy blocks' titles
+ if (!hiresPath) {
+ for (const [huid, hblock] of Object.entries(mediaBlocks)) {
+ if (!hblock.isProxy || hblock.filePath) continue;
+ hiresPath = findHighResFileForGves(
+ gvesBlock.filePath,
+ hblock.title,
+ options.hiresMediaFolder,
+ fs
+ );
+ if (hiresPath) break;
+ }
+ }
+
if (!hiresPath) continue;
- const hiresTitle = hiresBlock.title || pathToTitle(hiresPath);
+ const hiresTitle = pathToTitle(hiresPath);
+ const gvesPath = gvesBlock.filePath;
+ const gvesPathEscaped = escapeRegex(gvesPath);
- // Perform replacements for this unlinked proxy
- // We'll replace the Title in the XML with the found file
- if (hiresBlock.title) {
- const titleEscaped = escapeRegex(hiresBlock.title);
+ console.log(`[FALLBACK SWAP] ${gvesPath} → ${hiresPath}`);
+
+ swaps.push({
+ gvesUid,
+ hiresUid: 'direct-lookup',
+ oldPath: gvesPath,
+ newPath: hiresPath,
+ newTitle: hiresTitle
+ });
+
+ // Replace FilePath tags
+ remappedXml = remappedXml.replace(
+ new RegExp(`