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:
parent
d048c1fb31
commit
bc0ae7566e
90
src/tools/stem-split.ts
Normal file
90
src/tools/stem-split.ts
Normal 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);
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user