import { NextResponse } from 'next/server'; import { exec } from 'child_process'; import util from 'util'; import fs from 'fs-extra'; import path from 'path'; import * as mm from 'music-metadata'; import { CheckUpconvResponse } from '@/types'; const execPromise = util.promisify(exec); export async function POST(request: Request) { try { const { albumPath } = await request.json(); if (!albumPath || !(await fs.pathExists(albumPath))) { return NextResponse.json({ error: 'Invalid album path' }, { status: 400 }); } // Find all FLAC files const files = await fs.readdir(albumPath); const flacFiles = files.filter(f => f.toLowerCase().endsWith('.flac')); if (flacFiles.length === 0) { return NextResponse.json({ error: 'No FLAC files found' }, { status: 400 }); } let outputLog = ""; let failureCount = 0; let checkedCount = 0; // Check all 24-bit files for (const file of flacFiles) { const filePath = path.join(albumPath, file); try { // Check bit depth first const metadata = await mm.parseFile(filePath); const bitsPerSample = metadata.format.bitsPerSample || 16; if (bitsPerSample < 24) { continue; // Skip non-24-bit files } checkedCount++; const command = `salmon check upconv "${filePath}"`; const { stdout } = await execPromise(command); // Output example: "01...flac: does not have a high number of wasted bits (Wasted bits: 0/24)" const match = stdout.match(/Wasted bits: (\d+\/\d+)/); const wastedBits = match ? match[1] : 'Unknown'; // Determine pass/fail based on wasted bits (simplified logic: if wasted bits > 0, it might be upconv, but usually salmon says "has a high number..." if it fails) // Actually salmon output usually says "does not have a high number..." for pass. // Let's rely on the text "does not have a high number". const passed = stdout.includes('does not have a high number'); outputLog += `[${file}]: ${passed ? "OK" : "POSSIBLE UPCONV"} (${wastedBits})\n`; if (!passed) { failureCount++; } } catch (e) { const errorMessage = e instanceof Error ? e.message : String(e); outputLog += `[${file}]: Error - ${errorMessage}\n`; } } if (checkedCount === 0) { const response: CheckUpconvResponse = { success: true, output: "No 24-bit files found to check.", wastedBits: "N/A" }; return NextResponse.json(response); } const response: CheckUpconvResponse = { success: true, output: outputLog, wastedBits: failureCount > 0 ? "Issues Found" : "Clean" }; return NextResponse.json(response); } catch (error) { console.error('Error checking upconv:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }