diff options
| author | ache <ache@ache.one> | 2025-01-22 09:17:52 +0100 |
|---|---|---|
| committer | ache <ache@ache.one> | 2025-01-22 09:17:52 +0100 |
| commit | 591e05350749c59170969cb13408bf10d143c3f0 (patch) | |
| tree | 24ac2b82a3cf318f8e936037bbde1054575a7155 /src | |
| parent | Fix english: business => visiting (diff) | |
Add a anti-website
Diffstat (limited to 'src')
| -rw-r--r-- | src/build/anti-index.mjs | 309 | ||||
| -rw-r--r-- | src/build/index.mjs | 2 | ||||
| -rw-r--r-- | src/build/loadMD.mjs | 15 |
3 files changed, 318 insertions, 8 deletions
diff --git a/src/build/anti-index.mjs b/src/build/anti-index.mjs new file mode 100644 index 0000000..fb750a2 --- /dev/null +++ b/src/build/anti-index.mjs @@ -0,0 +1,309 @@ +import process from "node:process"; +import fs from "node:fs"; +import mustache from "mustache"; +import loadSVG from "./load-svg.mjs"; +import getRSS from "./rss.mjs"; +import loadMD from "./loadMD.mjs"; +import { cmpArticles } from "./article.mjs"; +import i18n from "./i18n.mjs"; +import { addDescription } from "./i18n.mjs"; +import { minifyHTML } from "./utils.mjs"; + +import { SitemapStream, streamToPromise } from "sitemap"; +import { Readable } from "stream"; + +const leftPanelTmpl = fs.readFileSync("src/templates/left.tmpl", "utf8"); +const likesTmpl = fs.readFileSync("src/templates/likes.tmpl", "utf8"); +const headerTmpl = fs.readFileSync("src/templates/header.tmpl", "utf8"); +const articleTmpl = fs.readFileSync("src/templates/article.tmpl", "utf8"); +const indexTmpl = fs.readFileSync("src/templates/index.tmpl", "utf8"); +const notesTmpl = fs.readFileSync("src/templates/notes.tmpl", "utf8"); +const legalTmpl = fs.readFileSync("src/templates/legal.tmpl", "utf8"); +const tagTmpl = fs.readFileSync("src/templates/tag.tmpl", "utf8"); +const hidTmpl = fs.readFileSync("src/templates/hid.tmpl", "utf8"); +const style_xslTmpl = fs.readFileSync("src/templates/style_xsl.tmpl", "utf8"); +const baseUrl = "https://ache.one/"; + +const partials = { + header: headerTmpl, + leftPanel: leftPanelTmpl, + likesButton: likesTmpl, + hid: hidTmpl, +}; + +// Load global variables +const svg = loadSVG(); +const antiDir = ".anti"; + +let links = []; + +const listNotes = fs + .readdirSync("anti-notes") + .filter((name) => name.endsWith(".md")); +const notesAll = loadMD(listNotes, "notes"); // lang is determined from the note +const legalPages = loadMD(["legal.md", "legal-en.md"], "src/pages"); + +for (const lang in i18n) { + const tagsArticle = new Map(); + const filter = process.argv.slice(2); + const listArticles = + filter.length > 0 + ? i18n[lang].articles.filter((article) => filter.includes(article.name)) + : i18n[lang].articles; + const articles = loadMD(listArticles, "anti-articles", "articles", lang); + + // Same for notes + const notes = notesAll.filter((note) => note.metaData.lang == lang); + const material = [...articles, ...notes]; + + // Make notes directory + try { + fs.mkdirSync(`${antiDir}/${lang}/notes`, { recursive: true }); + } catch { + fs.rmSync(`${antiDir}/${lang}/notes`, { force: true, recursive: true }); + fs.mkdirSync(`${antiDir}/${lang}/notes`, { recursive: true }); + } + + for (const post of material) { + const context = { + svg, + page_title: `${post.title} - ache`, + title: i18n[lang].title, + intro: i18n[lang].intro, + lang, + canonical: `${baseUrl}${post.url.slice(1)}`, + content: post.content, + metaData: post.metaData, + alt_lang: addDescription(post.metaData.alt_lang), + description: post.intro, + + like_title: i18n[lang].like_title, + like_text: i18n[lang].like_text, + }; + const output = mustache.render(articleTmpl, context, partials); + + console.log(`Create : ${post.title}`); + const type = post.metaData?.type || "article"; + fs.writeFileSync( + `${antiDir}/${type}s/${post.name}.html`, + minifyHTML(output), + ); + links.push({ + url: context.canonical, + changefreq: "yearly", + priority: 0.6, + img: [{ url: post?.imageUrl }], + }); + + for (const tag of post.metaData.tags) { + // Insert the tag, if it already exists add it, otherwise create a object for it. + if (tagsArticle.has(tag)) { + tagsArticle.get(tag).push(post); + } else { + tagsArticle.set(tag, [post]); + } + } + } + + // Set of pages language dependant + try { + fs.mkdirSync(`${antiDir}/${lang}/tag`, { recursive: true }); + } catch { + fs.rmSync(`${antiDir}/${lang}/tag`, { force: true, recursive: true }); + fs.mkdirSync(`${antiDir}/${lang}/tag`, { recursive: true }); + } + + for (const [tag, material] of tagsArticle.entries()) { + console.log(`Create tag page : ${lang}/${tag}.html`); + material.sort(cmpArticles); + + const articles = material.filter((item) => item.metaData.type != "note"); + const notes = material.filter((item) => item.metaData.type == "note"); + + const context = { + svg, + page_title: `ache - Tag: ${tag}`, + title: i18n[lang].title, + intro: i18n[lang].intro, + lang, + tag, + articles, + notes, + description: `${i18n[lang]["tag_desc"]} ${tag}.`, + }; + + const output = mustache.render(tagTmpl, context, partials); + fs.writeFileSync(`${antiDir}/${lang}/tag/${tag}.html`, minifyHTML(output)); + links.push({ + url: `${baseUrl}${lang}/tag/${tag}`, + changefreq: "monthly", + priority: 0.3, + }); + } + + { + material.sort(cmpArticles); + console.log(`Create RSS Flux: ${lang}/rss.xml`); + const xmlFeed = getRSS(material, baseUrl, lang); + fs.writeFileSync(`${antiDir}/${lang}/rss.xml`, xmlFeed); + links.push({ + url: `${baseUrl}${lang}/rss.xml`, + changefreq: "monthly", + priority: 0.3, + }); + } + + { + console.log(`Create RSS Flux: ${lang}/rss-main.xml`); + const xmlFeed = getRSS(articles, baseUrl, lang, "rss"); + fs.writeFileSync(`${antiDir}/${lang}/rss-main.xml`, xmlFeed); + links.push({ + url: `${baseUrl}${lang}/rss-main.xml`, + changefreq: "monthly", + priority: 0.3, + }); + } + + // Notes page: A note with a list of every note in that language + { + // Pages to redirect to when switching languages. + const alt_lang = { + fr: { + lang: "en", + url: "/en/notes", + }, + en: { + lang: "fr", + url: "/fr/notes", + }, + }; + const context = { + page_title: i18n[lang].title.notes, + title: i18n[lang].title, + intro: i18n[lang].intro, + lang, + canonical: `${baseUrl}${lang}`, + svg, + notes, + alt_lang: [alt_lang[lang]], + description: i18n[lang].index_desc, + }; + + console.log(`Create : Notes page ${lang}`); + const output = mustache.render(notesTmpl, context, partials); + fs.writeFileSync(`${antiDir}/${lang}/notes/index.html`, minifyHTML(output)); + links.push({ + url: `${baseUrl}${lang}/notes`, + changefreq: "monthly", + priority: 0.7, + img: [{ url: "https://ache.one/res/ache.svg" }], + }); + } + + // Legal page + { + const legal_page = legalPages.filter( + (page) => page.metaData.lang == lang, + )[0]; + // Pages to redirect to when switching languages. + const alt_lang = { + fr: { + lang: "en", + url: "/en/legal", + }, + en: { + lang: "fr", + url: "/fr/legal", + }, + }; + const context = { + page_title: i18n[lang].title.legal, + title: i18n[lang].title, + intro: i18n[lang].intro, + lang, + canonical: `${baseUrl}${lang}/legal`, + svg, + content: legal_page.content, + alt_lang: [alt_lang[lang]], + description: i18n[lang].index_desc, + }; + + console.log(`Create : Legal page ${lang}`); + const output = mustache.render(legalTmpl, context, partials); + + fs.writeFileSync(`${antiDir}/${lang}/legal.html`, minifyHTML(output)); + links.push({ + url: `${lang}/legal.html`, + changefreq: "yearly", + priority: 0.1, + }); + } + + // Home page + { + // Pages to redirect to when switching languages. + const alt_lang = { + fr: { + lang: "en", + url: "/en/", + }, + en: { + lang: "fr", + url: "/fr/", + }, + }; + const context = { + page_title: i18n[lang].title.main, + title: i18n[lang].title, + intro: i18n[lang].intro, + lang, + canonical: `${baseUrl}${lang}`, + svg, + articles, + alt_lang: [alt_lang[lang]], + description: i18n[lang].index_desc, + }; + + console.log(`Create : Home page ${lang}`); + const output = mustache.render(indexTmpl, context, partials); + fs.writeFileSync(`${antiDir}/${lang}/index.html`, minifyHTML(output)); + links.push({ + url: `${baseUrl}${lang}`, + changefreq: "monthly", + priority: 0.7, + img: [{ url: "https://ache.one/res/ache.svg" }], + }); + } + + // style.xsl + { + /* Because firefox doesn't support disable-output-escaping="yes" (it doesn't do anything) + * The description must be in the xsl file non escaped. 🤷 + * So the xsl file is made from a template to insert the description. + * Even if the goal of xsl is to grab that information from the initial page + */ + let context = { + lang, + svg, + description: i18n[lang].rss_full.description, + }; + + console.log(`Create : Style.xsl (${lang})`); + let output = mustache.render(style_xslTmpl, context, partials); + fs.writeFileSync(`${antiDir}/${lang}/style.xsl`, output); + + context.description = i18n[lang].rss.description; + console.log(`Create : Style.xsl (${lang})`); + output = mustache.render(style_xslTmpl, context, partials); + fs.writeFileSync(`${antiDir}/${lang}/style_main.xsl`, output); + } +} + +console.log(`Create: sitemap.xml`); +// Create a stream to write to +const stream = new SitemapStream({ hostname: "https://ache.one" }); + +// Return a promise that resolves with your XML string +streamToPromise(Readable.from(links).pipe(stream)) + .then((data) => data.toString()) + .then((sitemapXML) => fs.writeFileSync(`${antiDir}/sitemap.xml`, sitemapXML)); diff --git a/src/build/index.mjs b/src/build/index.mjs index 8baeeef..fda873f 100644 --- a/src/build/index.mjs +++ b/src/build/index.mjs @@ -49,7 +49,7 @@ for (const lang in i18n) { filter.length > 0 ? i18n[lang].articles.filter((article) => filter.includes(article.name)) : i18n[lang].articles; - const articles = loadMD(listArticles, "articles", lang); + const articles = loadMD(listArticles, "articles", "articles", lang); // Same for notes const notes = notesAll.filter((note) => note.metaData.lang == lang); diff --git a/src/build/loadMD.mjs b/src/build/loadMD.mjs index 8153d37..ed31196 100644 --- a/src/build/loadMD.mjs +++ b/src/build/loadMD.mjs @@ -10,17 +10,18 @@ import { toString, toMdRaw, mdToHtmlRaw } from "./to-html.mjs"; import { getArticleYear } from "./article.mjs"; import i18n from "./i18n.mjs"; -const loadMD = (listFile, suffix, lang) => { +const loadMD = (listFile, dirSuffix, pathLinkSuffix, lang) => { const listContent = []; for (const file of listFile) { console.log(`Working on ${file}`); - const content = fs.readFileSync(`${suffix}/${file}`, "utf8"); + const content = fs.readFileSync(`${dirSuffix}/${file}`, "utf8"); const mdRaw = toMdRaw(content); const tomlStringValue = mdRaw.children[0].value; const metaData = toml.parse(tomlStringValue); const newHTML = mdToHtmlRaw(mdRaw); const langR = lang || metaData.lang; + const linkSuffix = pathLinkSuffix || dirSuffix; const htmlContent = newHTML; const htmlRender = toString(htmlContent); @@ -32,7 +33,7 @@ const loadMD = (listFile, suffix, lang) => { const logo = select("img", intro); if (logo && logo?.properties) { if (logo.properties.src[0] != "/") { - logo.properties.src = `/${suffix}/${logo.properties.src}`; + logo.properties.src = `/${linkSuffix}/${logo.properties.src}`; } logo.properties.height = "150"; logo.properties.width = "150"; @@ -40,10 +41,10 @@ const loadMD = (listFile, suffix, lang) => { const logoP = select("source", intro); if (logoP !== null) { - logoP.properties.srcSet = `/${suffix}/${logoP.properties.srcSet}`; + logoP.properties.srcSet = `/${linkSuffix}/${logoP.properties.srcSet}`; } - titleHtml.children[0].properties.href = `/${suffix}/${file.slice(0, -3)}`; + titleHtml.children[0].properties.href = `/${linkSuffix}/${file.slice(0, -3)}`; const title = hastToString(titleHtml); const domTitle = cssesc( @@ -56,7 +57,7 @@ const loadMD = (listFile, suffix, lang) => { console.log(langR); const readMore = h("a", i18n[langR]["read_more"]); - readMore.properties.href = `/${suffix}/${file.slice(0, -3)}`; + readMore.properties.href = `/${linkSuffix}/${file.slice(0, -3)}`; const pubYear = getArticleYear({ metaData }); if (metaData.pubDate) { @@ -79,7 +80,7 @@ const loadMD = (listFile, suffix, lang) => { pubYear, title, domTitle, - url: `/${suffix}/${file.slice(0, -3)}`, + url: `/${linkSuffix}/${file.slice(0, -3)}`, }); } |