docs: add /mnt/work documentation + fix storage paths

- stem-split models dir: /mnt/work/models/audio-separator/
- stem-split output: /mnt/work/tmp/stem-splits/
- full docs at /mnt/work/docs/discord-feed-bots.md
This commit is contained in:
Nicholai Vogel 2026-01-24 02:02:07 -07:00
parent d048c1fb31
commit bc0ae7566e

90
src/tools/stem-split.ts Normal file
View File

@ -0,0 +1,90 @@
/**
* Stem splitting tool using audio-separator (UVR5 models).
* Usage: bun run src/tools/stem-split.ts "artist - song name"
*
* Pipeline:
* 1. Search + download audio via yt-dlp
* 2. Separate stems using audio-separator (MDX-Net/Roformer)
* 3. Output file paths for each stem
*/
import { $ } from 'bun';
const OUTPUT_DIR = '/mnt/work/tmp/stem-splits';
const MODEL_DIR = '/mnt/work/models/audio-separator';
const MODEL = 'UVR-MDX-NET-Inst_HQ_3'; // High quality instrumental/vocal split
async function searchAndDownload(query: string): Promise<string> {
console.error(`Searching: "${query}"...`);
const outPath = `${OUTPUT_DIR}/input.wav`;
await $`mkdir -p ${OUTPUT_DIR}`.quiet();
// Search youtube and download best audio
const result = await $`yt-dlp \
--extract-audio \
--audio-format wav \
--audio-quality 0 \
--output ${outPath} \
--no-playlist \
--default-search "ytsearch1" \
"${query}" 2>&1`.text();
console.error(result);
// yt-dlp might append .wav to the path
const { existsSync } = await import('fs');
if (existsSync(outPath)) return outPath;
if (existsSync(`${outPath}.wav`)) return `${outPath}.wav`;
throw new Error('Download failed - file not found');
}
async function splitStems(inputPath: string): Promise<string[]> {
console.error(`Splitting stems with ${MODEL}...`);
const result = await $`audio-separator \
--model_filename ${MODEL} \
--model_file_dir ${MODEL_DIR} \
--output_dir ${OUTPUT_DIR}/stems \
--output_format wav \
${inputPath} 2>&1`.text();
console.error(result);
// Find output files
const { readdirSync } = await import('fs');
const stemDir = `${OUTPUT_DIR}/stems`;
const files = readdirSync(stemDir)
.filter(f => f.endsWith('.wav'))
.map(f => `${stemDir}/${f}`);
return files;
}
async function main() {
const query = process.argv.slice(2).join(' ');
if (!query) {
console.error('Usage: bun run src/tools/stem-split.ts "artist - song name"');
process.exit(1);
}
// Clean previous run
await $`rm -rf ${OUTPUT_DIR}`.quiet();
const inputPath = await searchAndDownload(query);
const stems = await splitStems(inputPath);
console.log(JSON.stringify({
query,
stems: stems.map(s => ({
path: s,
name: s.split('/').pop()?.replace('.wav', '') || s,
})),
}, null, 2));
}
main().catch(e => {
console.error(e);
process.exit(1);
});