aboutsummaryrefslogtreecommitdiff
path: root/generator/make4htwrapper.js
diff options
context:
space:
mode:
Diffstat (limited to 'generator/make4htwrapper.js')
-rwxr-xr-xgenerator/make4htwrapper.js105
1 files changed, 105 insertions, 0 deletions
diff --git a/generator/make4htwrapper.js b/generator/make4htwrapper.js
new file mode 100755
index 0000000..b8e0c3a
--- /dev/null
+++ b/generator/make4htwrapper.js
@@ -0,0 +1,105 @@
+#!/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()