#!/usr/bin/node //Copyright Chris Xiong 2024 //License: Expat (MIT) const content_dir='../content'; const image_dir='../content/img'; const process = require('node:process'); const path = require('node:path'); const util = require('node:util'); const fs = require('node:fs'); const jsdom = require('jsdom'); const spawn = require('child_process').spawn; const image_size = require('image-size'); function promote_header(doc) { for (let i = 2; i <= 6; ++i) { const list = doc.querySelectorAll(`h${i}`); for (let j = list.length - 1; j >= 0; --j) { const e = list[j]; const newe = doc.createElement(`h${i-1}`); newe.innerHTML = e.innerHTML; e.parentNode.replaceChild(newe, e); } } } function image_unsquash(doc, wd) { for (let im of doc.querySelectorAll('img')) { const d = image_size(path.join(wd, im.src)); if (d.width > d.height) im.removeAttribute('width'); else if (d.width < d.height) im.removeAttribute('height'); } } function image_relocate(doc, wd, imd) { for (let im of doc.querySelectorAll('img')) { fs.copyFileSync(path.join(wd, im.src), path.join(imd, im.src)); im.src = `//filestorage.chrisoft.org/blog/img/${im.src}`; } } function css_embed(doc, cssc) { const style = doc.createElement('style'); style.textContent = cssc.replaceAll('font-family', 'not-font-family'); const body = doc.querySelector('body'); body.insertBefore(style, body.childNodes[0]); } async function main() { process.stdin.setEncoding('utf8'); const input = await new Promise((resolv, rej) => { let d = ''; process.stdin.on('readable', () => { const r = process.stdin.read(); if (r) d += r; }); process.stdin.on('end',() => { resolv(d.trim()); }); }); const wd = path.resolve(path.join(content_dir, path.dirname(input))); const fn = path.basename(input); const fnb = path.basename(input, '.tex'); const make4htp = spawn('make4ht', ['-f', 'html5', fn, '"fn-in"'], { cwd: wd, shell: true, stdio: ['ignore', 'pipe', 'pipe'] }); make4htp.stdout.setEncoding('utf8'); make4htp.stderr.setEncoding('utf8'); make4htp.stdout.on('data', (d) => { console.error(d); }); make4htp.stderr.on('data', (d) => { console.error(d); }); try { await new Promise((resolv, rej) => { make4htp.on('close', (r) => r ? rej(r) : resolv()) }); } catch (e) { console.error(`make4ht failed with exitcode ${e}`); return; } const htmlc = fs.readFileSync(path.join(wd, `${fnb}.html`), 'utf8'); const cssc = fs.readFileSync(path.join(wd, `${fnb}.css`), 'utf8'); const domrt = new jsdom.JSDOM(htmlc); promote_header(domrt.window.document); image_unsquash(domrt.window.document, wd); image_relocate(domrt.window.document, wd, path.resolve(image_dir)); css_embed(domrt.window.document, cssc); process.stdout.setEncoding('utf8'); process.stdout.write(domrt.window.document.querySelector('body').innerHTML); } main()