const fs = require("fs"); const jsdom = require("jsdom"); const fetch = require("node-fetch"); const { JSDOM } = jsdom; const { window } = new JSDOM(""); global.window = window; var showdown = require("showdown"); const converter = new showdown.Converter(); const libxmljs = require("libxmljs"); const MIRROR_URL = "http://mirror.csclub.uwaterloo.ca/csclub/"; try { fs.mkdirSync("./markdown-talks/"); } catch (e) { if (e.code !== "EEXIST") { throw e; } } const file = fs .readFileSync("../../media/index.xml", "utf8") .replace(//, ""); const xml = libxmljs.parseHtml(file); const talks = xml.find("//mediaitem"); (async () => { const all = await Promise.all( talks.map(async (talk, idx) => { const { filename, markdown } = await xml2md(talk, idx); await fs.promises.writeFile(`./markdown-talks/${filename}.md`, markdown); }), ); console.log(all.length); process.exit(0); })(); /** * * @param {libxmljs.Element} talk */ async function xml2md(talk, index) { const title = talk.attr("title").value(); const abstract = talk .get("abstract") ?.childNodes() .reduce((str, node) => str + node.toString(), "") .trim(); const presentors = talk .get("presentor") .childNodes() .toString() .split(",") .map((s) => s.trim()); const thumbSmall = MIRROR_URL + talk.get("thumbnail").attr("file").value(); /** @type{string | undefined} */ let thumbLarge = thumbSmall.replace("-thumb-small", "-thumb-large"); if (!(await resourceExists(thumbLarge))) { thumbLarge = undefined; } const links = talk .find("mediafile") .map((mf) => ({ /** @type{string} */ file: MIRROR_URL + mf.attr("file").value(), /** @type{string} */ type: mf.attr("type").value(), /** @type{string | undefined} */ size: mf.attr("size")?.value() ?? undefined, })) .map( ({ file, type, size }) => " " + ` - file: '${file.replaceAll("'", "''")}' type: '${type.replaceAll("'", "''")}' ${size == null ? "" : `size: '${size.replaceAll("'", "''")}'`} `.trim(), ); const markdown = ` --- index: ${index} title: '${title.replaceAll("'", "''")}' presentors: - ${presentors.join("\n - ").replaceAll("'", "''")} thumbnails: small: '${thumbSmall}'${thumbLarge ? `\n large: '${thumbLarge}'` : ""} links: ${links.join("\n")} --- ${converter.makeMarkdown(abstract ?? "")} `.trim() + "\n"; return { filename: title .toLowerCase() .replaceAll(" ", "-") .replaceAll(":", "") .replaceAll("=", "") .replaceAll(",", "-") .replaceAll("'", "-") .replaceAll("+", "-plus-") .replaceAll(/-+/g, "-"), markdown, }; } /** * * @param {string} url */ async function resourceExists(url) { const time = Math.trunc(Math.random() * 10000); await sleep(time); const timer = setTimeout(() => console.log("not done", time, url), time + 3000); const response = await fetch(url); clearTimeout(timer) return ( response.status.toString().startsWith("2") || response.status.toString().startsWith("3") ); } function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); }