Incognito-Wiki/scripts/publish-recovered-courses.mjs
msa46 c590f77d96
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
feat: publish legacy course archive
2026-08-03 15:12:11 +02:00

81 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { dirname } from 'node:path';
import { convertCourseSource } from './lib/previous-wiki.mjs';
const recoveryLines = (await readFile('docs/live-course-recovery.tsv', 'utf8')).trim().split(/\r?\n/);
const recoveryHeader = recoveryLines.shift();
const records = recoveryLines.map((line) => {
const [id, sourceUrl, status, destination, capturedSource, reason] = line.split('\t');
return { id, sourceUrl, status, destination, capturedSource, reason };
});
const pdfs = (await readFile('docs/pdf-inventory.tsv', 'utf8')).trim().split(/\r?\n/).slice(1)
.map((line) => {
const [mediaId, publicUrl] = line.split('\t');
return { mediaId, publicUrl };
});
const toPublish = records.filter(({ status }) => status === 'migrate');
if (toPublish.length !== 54) throw new Error(`expected 54 course pages to publish, found ${toPublish.length}`);
for (const record of toPublish) {
const source = await readFile(record.capturedSource, 'utf8');
const markdown = convertCourseSource({
pageId: record.id,
sourceUrl: record.sourceUrl,
source,
pdfs,
});
await mkdir(dirname(record.destination), { recursive: true });
await writeFile(record.destination, markdown);
}
const supplemental = JSON.parse(await readFile('docs/supplemental-content.json', 'utf8'))
.filter(({ category }) => category !== 'live-course-recovery');
for (const record of toPublish) {
supplemental.push({
destination: record.destination,
source: record.sourceUrl,
category: 'live-course-recovery',
});
}
supplemental.sort((a, b) => a.destination.localeCompare(b.destination));
await writeFile('docs/supplemental-content.json', `${JSON.stringify(supplemental, null, 2)}\n`);
const groups = new Map();
for (const record of toPublish) {
const slug = record.destination.replace(/^src\/content\/docs\//, '').replace(/\.md$/, '');
const [programme, year, block] = slug.split('/');
const key = `${programme}/${year}`;
if (!groups.has(key)) groups.set(key, new Map());
if (!groups.get(key).has(block)) groups.get(key).set(block, []);
groups.get(key).get(block).push(slug);
}
const sidebarLines = ['export const recoveredCourseSidebar = {'];
for (const [key, blocks] of [...groups].sort(([a], [b]) => a.localeCompare(b))) {
sidebarLines.push(` '${key}': [`);
for (const [block, slugs] of [...blocks].sort(([a], [b]) => a.localeCompare(b))) {
const blockNumber = block.replace('block-', '');
sidebarLines.push(` { label: 'Block ${blockNumber}', items: [`);
for (const slug of slugs.sort()) sidebarLines.push(` { slug: '${slug}' },`);
sidebarLines.push(' ] },');
}
sidebarLines.push(' ],');
}
sidebarLines.push('};', '');
await writeFile('src/config/recovered-course-sidebar.mjs', sidebarLines.join('\n'));
for (const record of toPublish) record.status = 'migrated';
const updatedTsv = [recoveryHeader, ...records.map((record) => [
record.id,
record.sourceUrl,
record.status,
record.destination,
record.capturedSource,
record.status === 'migrated' ? 'Substantive public course page migrated from the live DokuWiki.' : record.reason,
].join('\t'))].join('\n');
await writeFile('docs/live-course-recovery.tsv', `${updatedTsv}\n`);
console.log(`Published ${toPublish.length} recovered course pages.`);