import { exec } from 'child_process'; import { promisify } from 'util'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; const execAsync = promisify(exec); export type ToolStatus = { name: string; exists: boolean; path?: string; }; export type ToolCheckResult = { allExists: boolean; tools: ToolStatus[]; mkbrrPresetExists?: boolean; }; const REQUIRED_TOOLS = ['sox', 'mkbrr', 'salmon']; async function checkMkbrrPreset(): Promise { const tempDir = os.tmpdir(); const dummyFile = path.join(tempDir, `mkbrr_check_${Date.now()}`); const outputFile = `${dummyFile}.torrent`; const presetName = 'red'; try { // Create a dummy file await fs.writeFile(dummyFile, 'test'); // Try to create a torrent with the red preset // We expect this to fail if the preset doesn't exist // If it succeeds (or fails for other reasons but finds the preset), we're good try { // Explicitly set output file to ensure we know where it is for cleanup await execAsync(`mkbrr create "${dummyFile}" -P ${presetName} -o "${outputFile}"`); return true; } catch (error: any) { // Check for the specific error message indicating the preset is missing // We use the presetName variable so this logic holds if we change the preset for testing if (error.stderr && error.stderr.includes(`preset "${presetName}" not found`)) { return false; } // If it failed for another reason (e.g. file issue), but didn't complain about the preset, // we assume the preset exists. return true; } } catch (error) { console.error('Error checking mkbrr preset:', error); return false; // Fail safe } finally { // Cleanup try { await fs.unlink(dummyFile); await fs.unlink(outputFile).catch(() => { }); // Ignore if torrent wasn't created } catch (e) { // Ignore cleanup errors } } } export async function checkTools(): Promise { const results: ToolStatus[] = await Promise.all( REQUIRED_TOOLS.map(async (tool) => { try { const { stdout } = await execAsync(`which ${tool}`); return { name: tool, exists: true, path: stdout.trim(), }; } catch (error) { return { name: tool, exists: false, }; } }) ); const allExists = results.every((result) => result.exists); let mkbrrPresetExists = true; const mkbrrStatus = results.find(r => r.name === 'mkbrr'); if (mkbrrStatus && mkbrrStatus.exists) { mkbrrPresetExists = await checkMkbrrPreset(); } return { allExists: allExists && mkbrrPresetExists, tools: results, mkbrrPresetExists, }; }