code icon Code

Prep Story for Audio

Strip frontmatter and footer from story file, output clean text for TTS

Source Code

import fs from "fs";
import path from "path";

const [storyFilePath, outputDir] = process.argv.slice(2);

if (!storyFilePath) {
  console.error("Error: storyFilePath is required");
  process.exit(1);
}

if (!outputDir) {
  console.error("Error: outputDir is required");
  process.exit(1);
}

if (!fs.existsSync(storyFilePath)) {
  console.error(`Error: file not found: ${storyFilePath}`);
  process.exit(1);
}

const raw = fs.readFileSync(storyFilePath, "utf-8");

// Strip YAML frontmatter (between --- markers at start)
let text = raw.replace(/^---[\s\S]*?---\s*/m, "");

// Strip metadata footer (--- followed by *For Name, age X* pattern)
text = text.replace(/\n---\s*\n\*For .+\*\s*$/m, "");

// Clean up extra whitespace
text = text.trim();

if (!text) {
  console.error("Error: no story content after stripping frontmatter/footer");
  process.exit(1);
}

// Write clean text to output directory
const basename = path.basename(storyFilePath, path.extname(storyFilePath));
const outputPath = path.join(outputDir, `${basename}-clean.txt`);

fs.mkdirSync(outputDir, { recursive: true });
fs.writeFileSync(outputPath, text);

console.log(`✓ Prepped story for TTS`);
console.log(`Input: ${storyFilePath}`);
console.log(`Output: ${outputPath}`);
console.log(`Characters: ${text.length}`);
console.log(
  JSON.stringify(
    {
      success: true,
      inputPath: storyFilePath,
      outputPath: outputPath,
      characterCount: text.length,
    },
    null,
    2
  )
);