19 lines
2.7 KiB
JavaScript
19 lines
2.7 KiB
JavaScript
/** Publish a normal Wiki tutorial using only generic post, tag and media APIs. */
|
|
import {readFile,writeFile,mkdir} from 'node:fs/promises';
|
|
const base=(process.env.WIKI_BASE||'http://8.211.154.134:18131').replace(/\/$/,''),out=process.env.STUDIO_PUBLISH_OUTPUT||'../output/studio-tools',publicId='9ebd8f78d54b4b9db741b4e8';
|
|
await mkdir(out,{recursive:true});
|
|
async function api(path,options={}){const r=await fetch(base+path,{...options,signal:AbortSignal.timeout(60000)});if(r.status===404)return null;if(!r.ok)throw Error(path+': '+r.status+' '+(await r.text()).slice(0,300));return r.json()}
|
|
const post=(path,body,method='POST')=>api(path,{method,headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
|
|
let state;try{state=JSON.parse(await readFile(out+'/published.json','utf8'))}catch{state={base,assets:{}}}if(state.base!==base)throw Error('Wrong publish target');
|
|
for(const name of ['cover.png','ref17-master.png','ref17-notes.png','ref17-teaching.png','ref17-english.png','ref-01.png','ref-07.png','ref-26.png']){
|
|
if(state.assets[name])continue;const form=new FormData();form.set('kind','image');form.set('assetOnly','true');form.append('files',new Blob([await readFile(out+'/'+name)],{type:'image/png'}),name);
|
|
const data=await api('/api/upload',{method:'POST',body:form});state.assets[name]=data.assets[0];await writeFile(out+'/published.json',JSON.stringify(state,null,2));
|
|
}
|
|
const ids=JSON.parse(await readFile('content/layout-reference/post-ids.json','utf8'));
|
|
const gallery=Object.entries(state.assets).filter(([name])=>name!=='cover.png').map(([name,id])=>``).join('\n\n');
|
|
const text=(await readFile('content/studio-tools/tutorial.md','utf8')).replace('{{GALLERY}}',gallery).replace('{{REF26}}',`[ref-26](/explore/${ids['ref-26']})`);
|
|
const tag=await post('/api/tags',{name:'Studio工具',slug:'studio-tools'}),title='Studio 封面工具 · 同一母版与三种构图',description='从 PROMPT 进入两件 Studio 工具:ref-17 四张同母版试版,以及 ref-01/07/26 三种构图。含可访问图像、GET/POST API、HTML/React/Next.js 示例与构件验收。';
|
|
const assets=Object.values(state.assets).map(id=>({id,role:'content'})),coverAssetId=state.assets['cover.png'],old=await api('/api/notes/'+publicId);
|
|
state.post=old?await post('/api/notes/'+publicId,{title,description,markdown:text,tags:[tag.id],assets,coverAssetId,revision:old.entry.revision},'PUT'):await post('/api/posts',{publicId,slug:'studio-cover-tools',kind:'article',title,description,text,tags:[tag.id],assets,coverAssetId});
|
|
await writeFile(out+'/published.json',JSON.stringify(state,null,2));console.log(base+'/explore/'+publicId);
|