Handle unlinked high-res proxy blocks with fallback lookup

When proxyLinks is empty (no explicit .gves→hires linkage), now also process unlinked high-res proxy blocks that have:
- IsProxy: true
- FilePath: null
- Title metadata (e.g. 'File 1', 'File 2')

Uses fallback lookup to find matching files in hiresMediaFolder by Title, then injects FilePath into the XML Media block. This handles the case where FramelightX creates proxies but doesn't establish explicit linkages.
This commit is contained in:
Claude 2026-03-31 19:53:22 -04:00
parent 033e4bb020
commit c29245758c

View file

@ -323,6 +323,12 @@ function performSwaps(xml, mediaBlocks, proxyLinks, options = {}) {
// Collect all unique .gves UIDs that have a mapped high-res block // Collect all unique .gves UIDs that have a mapped high-res block
const gvesUids = Object.keys(proxyLinks); const gvesUids = Object.keys(proxyLinks);
// Also collect any .gves blocks that aren't in proxyLinks (for unlinked proxies)
const allGvesBlocks = Object.entries(mediaBlocks)
.filter(([uid, block]) => block.isGves)
.map(([uid, block]) => ({ uid, block }));
// Process linked proxy pairs first
for (const gvesUid of gvesUids) { for (const gvesUid of gvesUids) {
const hiresUid = proxyLinks[gvesUid]; const hiresUid = proxyLinks[gvesUid];
const gvesBlock = mediaBlocks[gvesUid]; const gvesBlock = mediaBlocks[gvesUid];
@ -400,6 +406,59 @@ 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;
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;
// Try to find a high-res file for this unlinked proxy using its Title
let hiresPath = findHighResFileForGves(
gvesRef.filePath, // Use first gves path for reference
hiresBlock.title,
options.hiresMediaFolder,
fs
);
if (!hiresPath) continue;
const hiresTitle = hiresBlock.title || pathToTitle(hiresPath);
// 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);
remappedXml = remappedXml.replace(
new RegExp(`<Title>${titleEscaped}</Title>`, 'g'),
`<Title>${hiresTitle}</Title>`
);
}
// Add a FilePath to the high-res block's Media section
// Look for the Media block with this Title and add FilePath if missing
const mediaBlockRegex = new RegExp(
`<Media[^>]*>([^<]*<Title>${escapeRegex(hiresBlock.title)}</Title>[^<]*)</Media>`,
'g'
);
remappedXml = remappedXml.replace(mediaBlockRegex, (match) => {
if (match.includes('<FilePath>')) return match; // Already has path
return match.replace(`</Media>`, `<FilePath>${hiresPath}</FilePath></Media>`);
});
swaps.push({
gvesUid: 'unlinked',
hiresUid: uid,
oldPath: 'null',
newPath: hiresPath,
newTitle: hiresTitle
});
}
}
// Remove IsProxy and OfflineReason from high-res blocks so they're treated as online // Remove IsProxy and OfflineReason from high-res blocks so they're treated as online
remappedXml = remappedXml.replace(/\s*<IsProxy>true<\/IsProxy>/g, ''); remappedXml = remappedXml.replace(/\s*<IsProxy>true<\/IsProxy>/g, '');
remappedXml = remappedXml.replace(/\s*<OfflineReason>\d+<\/OfflineReason>/g, ''); remappedXml = remappedXml.replace(/\s*<OfflineReason>\d+<\/OfflineReason>/g, '');