#!/usr/bin/env node /** * check-audio.mjs — liste les enregistrements kréyòl manquants. * * Le brief §6 le demande explicitement : « prévois le contrat (audio.gcf, format .opus, * repli silencieux si le fichier manque) et un script de vérification listant les * enregistrements manquants. » * * Pas de synthèse vocale : ce script n'en fabrique aucune. Il produit une liste de courses * pour la séance d'enregistrement — une après-midi de terrain vaut dix heures de code. * * Ce script n'échoue jamais : un enregistrement manquant est un travail à faire, * pas un défaut de build. Le jeu doit se replier en silence. */ import { readFile, readdir, writeFile, access } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..'); const DATA = join(ROOT, 'src', 'lib', 'data', 'fruits'); const STATIC = join(ROOT, 'static'); async function existe(p) { try { await access(p); return true; } catch { return false; } } async function main() { const fichiers = (await readdir(DATA)).filter((f) => f.endsWith('.json')).sort(); const manquants = []; const absents = []; const presents = []; for (const f of fichiers) { const e = JSON.parse(await readFile(join(DATA, f), 'utf8')); if (!e.audio.gcf) { manquants.push(e); continue; } // Le chemin est absolu depuis la racine du site : /audio/.opus → static/audio/.opus if (await existe(join(STATIC, e.audio.gcf))) presents.push(e); else absents.push(e); } const l = [ '# Enregistrements kréyòl à réaliser', '', '> Généré par `npm run check:audio`. Aucune synthèse vocale : ces noms doivent être', '> prononcés par une voix humaine locale (brief §6).', '', "Format attendu : `.opus` — un fichier par entrée, déposé dans `static/audio/.opus`.", '', `## À enregistrer (${manquants.length})`, '' ]; for (const e of manquants) l.push(`- [ ] **${e.noms.gcf}** — \`static/audio/${e.id}.opus\` _(${e.noms.fr ?? ''})_`); l.push(''); if (absents.length) { l.push(`## Déclarés mais fichier introuvable (${absents.length})`, ''); for (const e of absents) l.push(`- ⚠ \`${e.id}\` → \`${e.audio.gcf}\` absent de \`static/\``); l.push(''); } if (presents.length) { l.push(`## En place (${presents.length})`, ''); for (const e of presents) l.push(`- ✔ \`${e.id}\` — ${e.audio.locuteur ?? 'locuteur non renseigné'}`); l.push(''); } await writeFile(join(ROOT, 'docs', 'audio-a-enregistrer.md'), l.join('\n')); console.log(`À enregistrer : ${manquants.length}`); console.log(`Introuvables : ${absents.length}`); console.log(`En place : ${presents.length}`); console.log('\n docs/audio-a-enregistrer.md'); if (absents.length) console.log("\n⚠ Des chemins audio sont déclarés sans fichier : le jeu se repliera en silence."); } main().catch((e) => { console.error('✘', e.stack ?? e.message); process.exit(1); });