← back to Allnewsdaily

scripts/short/verify-variation.cjs

49 lines

"use strict";
const fs = require('fs');
const path = require('path');
const { execFileSync, spawnSync } = require('child_process');
const assert = require('node:assert/strict');
const { buildScript } = require('./build-script');
const root = path.resolve(__dirname, '../..');
const evidence = process.argv[2];
assert.ok(evidence, 'Pass a fresh evidence directory');
const data = path.join(root, 'data/short');
fs.mkdirSync(evidence, {recursive:true}); fs.mkdirSync(data, {recursive:true});
const headlines = [
 'Fixture: The museum opened a new exhibition on Monday.',
 'Fixture: The library added evening hours for visitors.',
 'Fixture: The city published its annual transport report.',
 'Fixture: The university announced three public science lectures.',
 'Fixture: The park reopened its walking path on Tuesday.',
];
const results = [];
for (const date of ['2026-09-10','2026-09-11','2026-09-12']) {
 const stories = {date, stories: (date === '2026-09-10' ? headlines : headlines.slice(0,1)).map((headline,i) => ({n:i+1,headline,outlet:'Fixture Civic Record '+(i+1)}))};
 fs.writeFileSync(path.join(data,'stories.json'),JSON.stringify(stories,null,2));
 const buildLog = execFileSync(process.execPath,[path.join(__dirname,'build-script.js')],{encoding:'utf8'});
 const script = JSON.parse(fs.readFileSync(path.join(data,'script.json')));
 const dir = path.join(evidence,script.format); fs.mkdirSync(dir,{recursive:true});
 const reuse = process.argv.includes('--resume') && fs.existsSync(path.join(dir,'out.mp4'));
 if (reuse) assert.deepEqual(JSON.parse(fs.readFileSync(path.join(dir,'script.json'))),script, 'Refuse stale media from a different script');
 fs.copyFileSync(path.join(data,'stories.json'),path.join(dir,'stories.json'));
 fs.copyFileSync(path.join(data,'script.json'),path.join(dir,'script.json'));
 const log = reuse ? fs.readFileSync(path.join(dir,'render.log'),'utf8') : execFileSync(process.execPath,[path.join(__dirname,'render-short.js')],{encoding:'utf8',maxBuffer:20*1024*1024});
 fs.writeFileSync(path.join(dir,'render.log'),buildLog+'\n'+log);
 if (!reuse) for (const file of ['out.mp4','thumb.jpg']) fs.copyFileSync(path.join(data,file),path.join(dir,file));
 const probe=JSON.parse(execFileSync('ffprobe',['-v','error','-show_streams','-show_format','-of','json',path.join(dir,'out.mp4')],{encoding:'utf8'}));
 fs.writeFileSync(path.join(dir,'ffprobe.json'),JSON.stringify(probe,null,2));
 const v=probe.streams.find(s=>s.codec_type==='video'),a=probe.streams.find(s=>s.codec_type==='audio');
 assert.equal(v.width,1080); assert.equal(v.height,1920); assert.equal(v.codec_name,'h264'); assert.equal(v.pix_fmt,'yuv420p'); assert.equal(v.avg_frame_rate,'30/1'); assert.equal(a.codec_name,'aac');
 assert.ok(+probe.format.duration < 60 && Math.abs(+probe.format.duration - script.totalSec) < 0.5);
 const scratch = log.match(/retained scratch=(.+)/)[1];
 fs.copyFileSync(path.join(scratch,'card1.png'),path.join(dir,'lead-card.png'));
 results.push({format:script.format,duration:+probe.format.duration,dir,scratch,verdict:'PASS'});
 console.log(JSON.stringify(results.at(-1)));
}
const script=buildScript({date:'2026-09-10',stories:[{headline:'Fixture fact.',outlet:'Fixture Record'}]});
script.totalSec=61;fs.writeFileSync(path.join(data,'script.json'),JSON.stringify(script));
const bad=spawnSync(process.execPath,[path.join(__dirname,'render-short.js')],{encoding:'utf8'});
assert.notEqual(bad.status,0); assert.match(bad.stderr,/58 seconds/);
fs.writeFileSync(path.join(evidence,'negative-render.log'),bad.stdout+bad.stderr);
fs.writeFileSync(path.join(evidence,'results.json'),JSON.stringify(results,null,2));