const minisrv_service_file = true; if (!minisrv_config.services['pnm']) { throw ("ERROR: pnm service not defined in config!"); } const pnmVaults = []; // Check pnm service vault for .ra and .rm files if (minisrv_config.config.ServiceVaults) { Object.keys(minisrv_config.config.ServiceVaults).forEach(function (k) { const service_vault = wtvshared.getAbsolutePath(minisrv_config.config.ServiceVaults[k]); pnmVaults.push(service_vault + "/pnm"); }) } else { throw ("ERROR: No Service Vaults defined!"); } // Detect subdirectory structure of this catchall.js file and strip it from requests // e.g., if at /ServiceVault/wtv-music/ragen/catchall.js, extract "ragen" // if at /ServiceVault/wtv-music/ra/gen/catchall.js, extract "ra/gen" let subDirPath = ''; const currentDir = path.dirname(__filename); const serviceVaultIdx = currentDir.indexOf('ServiceVault'); console.log("DEBUG: currentDir =", currentDir, "serviceVaultIdx =", serviceVaultIdx); if (serviceVaultIdx !== -1) { const afterVault = currentDir.substring(serviceVaultIdx + 12); // 12 = length of 'ServiceVault' console.log("DEBUG: afterVault =", afterVault); const parts = afterVault.split(path.sep).filter(p => p); console.log("DEBUG: parts =", parts); if (parts.length > 1) { // parts[0] is the service name (e.g., 'wtv-music'), parts[1+] are the subdirs const subdirs = parts.slice(1); subDirPath = '/' + subdirs.join('/'); } } console.log("DEBUG: Detected subDirPath =", subDirPath); const url_path = request_headers.request_url.split('?')[0]; const pathParts = url_path.split('/').filter(p => p); const serviceName = pathParts.length > 0 ? pathParts[0] : ''; let remainingPath = '/' + pathParts.slice(1).join('/'); const hadTrailingSlash = request_headers.request_url.endsWith('/'); console.log("DEBUG: Before stripping - subDirPath =", subDirPath, "remainingPath =", remainingPath); let strippedSubDir = ''; // Store what was stripped for link rebuilding // Strip the subdirectory structure from the request path if (subDirPath) { if (remainingPath.startsWith(subDirPath + '/')) { // Has something after the subdirectory, e.g., /ragen/classicrom strippedSubDir = subDirPath; remainingPath = remainingPath.substring(subDirPath.length); } else if (remainingPath === subDirPath || remainingPath === subDirPath + '/') { // Just the subdirectory itself, e.g., /ragen or /ragen/ strippedSubDir = subDirPath; remainingPath = '/'; } } console.log("DEBUG: After stripping - remainingPath =", remainingPath, "strippedSubDir =", strippedSubDir); // Restore trailing slash if original URL had one if (hadTrailingSlash && !remainingPath.endsWith('/')) { remainingPath += '/'; } const filename = remainingPath.endsWith('/') ? '' : remainingPath.split('/').pop().replace('.ram', ''); const directory = remainingPath.endsWith('/') ? remainingPath.replace(/\/$/, '') : remainingPath.substring(0, remainingPath.lastIndexOf('/')); console.log("DEBUG: Request for service", serviceName, "with filename", filename, "and directory", directory, "remainingPath", remainingPath); let fileFound = false; const extensions = ['.ra', '.rm']; let resolvedPath = null; // Check if request is for a directory listing (no filename or ends with /) if (!filename || (request_headers.request_url.endsWith('/') && minisrv_config.services['pnm'].allow_indexing !== false)) { const listingDir = filename ? directory : directory || '/'; const allFiles = []; for (const pnmVault of pnmVaults) { const targetDir = path.join(pnmVault, listingDir); console.log("DEBUG: Listing files in", targetDir); if (fs.existsSync(targetDir) && fs.statSync(targetDir).isDirectory()) { const files = fs.readdirSync(targetDir); files.forEach(file => { const fullPath = path.join(targetDir, file); if (fs.statSync(fullPath).isFile() && (file.endsWith('.ra') || file.endsWith('.rm'))) { const baseFileName = file.substring(0, file.lastIndexOf('.')); allFiles.push(baseFileName + '.ram'); } else if (fs.statSync(fullPath).isDirectory()) { allFiles.push(file + '/'); } }); } } if (allFiles.length > 0) { headers = `200 OK Content-type: text/html`; data = `