//Copyright Chris Xiong 2018 //License: Expat (MIT) module.exports={ render:function(inf,outf,np,pp){return _render(inf,outf,np,pp);}, set_template:function(tmplf){return _set_template(tmplf);} }; const fs=require('fs'); const jsdom=require('jsdom'); const path=require('path'); const aes=require('aes-js'); const scrypt=require('scrypt-js'); const btoa=require('btoa'); const sha256=require('./sha256').sha256; const spawn=require('child_process').spawn; const util=require('./util'); const THUMB_IMAGE_URL='//filestorage.chrisoft.org/blog/img/'; const THUMB_LOCAL_DIR='../content/img/'; let template_file=''; let tmplcont=''; let tocid; let headerlist; function texts(n) { if (typeof n.wholeText == 'string') return n.wholeText; let ret = ''; for (let c of n.childNodes) ret += texts(c); return ret; } function _dfs(doc,el,le,p) { var e=doc.createElement('li'); e.innerHTML=`${texts(el)}`; le.appendChild(e); el.id='tocanch'+(tocid++); el.classList.add('tvis'); var che=null,i; for(i=p+1;i[${(starting+i+1)}]: ${s}
`; doc.getElementById('notediv').appendChild(span); } starting+=footnotes.length; while(footnotes.length)footnotes[0].remove(); } function gen_thumb(doc,el) { const a=doc.createElement('a'); const im=doc.createElement('img'); const srcfn=el.innerHTML; let w=el.hasAttribute('width')?Number(el.getAttribute('width')):-1; let h=el.hasAttribute('height')?Number(el.getAttribute('height')):-1; let p=el.hasAttribute('scale')?Number(el.getAttribute('scale')):-1; if(el.hasAttribute('iw')) im.style.width=el.getAttribute('iw'); if(el.hasAttribute('ih')) im.style.height=el.getAttribute('ih'); if(p>0)w=h=-1; if(w>0||h>0) { if(w<=0)w=h; else if(h<=0)h=w; } const dstfn=(p>0||w>0||h>0)?`ssbsthumb_${p>0?'s'+p.toFixed(2):w+'x'+h}_${srcfn}`:srcfn; const srcf=path.join(THUMB_LOCAL_DIR,srcfn); const dstf=path.join(THUMB_LOCAL_DIR,dstfn); if(dstfn!=srcfn&&!util.mtime_cmp(srcf,dstf)) { const m=spawn('magick',[srcf,'-resize',p>0?(p*100).toFixed()+'%':w+'x'+h,dstf]); m.stdout.on('data',(d)=>{console.log(`IMout:${d}`);}); m.stderr.on('data',(d)=>{console.log(`IMerr:${d}`);}); } a.setAttribute('href',THUMB_IMAGE_URL+srcfn); im.src=THUMB_IMAGE_URL+dstfn; a.appendChild(im); el.parentNode.replaceChild(a,el); } async function encrypt(doc) { let enid=0; for(let i of doc.querySelectorAll('encrypted')) { const key=i.getAttribute('key'); i.removeAttribute('key'); const contu8=aes.utils.utf8.toBytes(i.innerHTML); const conths=sha256.hash(aes.utils.hex.fromBytes(contu8),{msgFormat:'hex-bytes'}); const keyu8=aes.utils.utf8.toBytes(key); const saltu8=aes.utils.utf8.toBytes('mmmdeliciousthermalpasteletmeconsumeallofit'); const enckey=scrypt.syncScrypt(keyu8, saltu8, 1024, 16, 2, 32); const ctr=new aes.ModeOfOperation.ctr(enckey); const enccont=ctr.encrypt(contu8); let encconts='';for(let i=0;ihere to decrypt. `; ++enid; } } function _set_template(tmplf) { template_file=tmplf; tmplcont=fs.readFileSync(template_file,'utf8'); } function _style_to_header(doc) { const head = doc.querySelector('head'); const body = doc.querySelector('body'); const styles = body.querySelectorAll('style'); for (let s of styles) head.appendChild(s); } async function _render(inf,outf,np,pp) { const postcont=fs.readFileSync(inf,'utf8'); const tr=new jsdom.JSDOM(tmplcont); const trd=tr.window.document; const cont=fs.readFileSync(inf,'utf8'); const contsplit=cont.split('\n'); const meta=contsplit.splice(0,4); const preproc=meta[3].trim(); let unlisted = false; if (meta[1].indexOf('UNLISTED') != -1) { unlisted = true; meta[1] = meta[1].substr(0, meta[1].indexOf('UNLISTED')); } trd.getElementById('title').innerHTML= trd.getElementById('titleh').innerHTML=meta[0].trim(); trd.getElementById('datetags').innerHTML=`${meta[1].trim()}
#${meta[2].split(',').join(' #')}`; if(preproc.length) { const ppargs=preproc.split(' '); const ppcmd=ppargs.splice(0,1); const pp=spawn(ppcmd[0],ppargs,{maxBuffer:1048576, stdio:['pipe', 'pipe', 'inherit']}); let out=''; pp.stdout.setEncoding('utf8'); pp.stdout.on('data',(d)=>{out+=d;}); pp.stdin.write(contsplit.join('\n'),'utf8'); const ppp = new Promise( (resolv, rej)=> { pp.on('error', (e) => rej(e)); pp.on('close',(r) => { if(r) rej(r); resolv(out); }); } ); pp.stdin.end(); try { trd.getElementById('article').innerHTML = await ppp; } catch (e) { console.log(`failed to render ${inf} : ${e}`); } } else trd.getElementById('article').innerHTML=contsplit.join('\n'); //async images trd.getElementById('article').querySelectorAll('img').forEach( (i)=>{if(!i.getAttribute('decoding'))i.setAttribute('decoding','async');} ); //thumbnails generation trd.getElementById('article').querySelectorAll('thumb').forEach((el)=>{gen_thumb(trd,el);}); //Encryption await encrypt(trd); //TOC tocid=0; headerlist=[]; trd.getElementById('article').querySelectorAll('h2,h3,h4,h5,h6').forEach( (i)=>{if(!i.classList.contains('notoc'))headerlist.push(i);} ); const tocroot=trd.getElementById('tocroot'); for(let i=0;i${tgs[i]}`; trd.getElementById('tagslist').appendChild(l); } _style_to_header(trd); //neighboring posts if (unlisted) { trd.getElementById('prevp').parentNode.remove(); trd.getElementById('nextp').parentNode.remove(); } else { if(pp)trd.getElementById('prevp').href=`${pp}.html`; if(np)trd.getElementById('nextp').href=`${np}.html`; } fs.writeFileSync(outf,""+trd.documentElement.outerHTML,'utf8'); return outf; }