diff --git a/content/blog/2020/06/2020-06-05--missing-entropy.md b/content/blog/2020/06/2020-06-05--missing-entropy.md index 8fd0452..c7e4fba 100644 --- a/content/blog/2020/06/2020-06-05--missing-entropy.md +++ b/content/blog/2020/06/2020-06-05--missing-entropy.md @@ -70,7 +70,7 @@ In other words, VPSs are severely lacking in sources of entropy. That is why the There is a way to remedy the situation: [haveged](https://wiki.archlinux.org/index.php/Haveged). Having only discovered it last night, I do not fully understand it yet but from what I have read, it is a pseudorandom number generator (PRNG) that fills the `entropy pool` with "pseudorandomness". Installing `haveged` immediately solved my issue, all docker commands were running instantly again. -![Available entropy suddenly increases after installing haveged](/content/img/entropy_haveged.png) +![Available entropy suddenly increases after installing haveged](/static/entropy_haveged.png) *Can you tell when I installed haveged?* ## Caveat: pseudorandomness diff --git a/content/blog/2020/06/2020-06-05--website-load-performance.md b/content/blog/2020/06/2020-06-05--website-load-performance.md index ba40c98..a6cde5c 100644 --- a/content/blog/2020/06/2020-06-05--website-load-performance.md +++ b/content/blog/2020/06/2020-06-05--website-load-performance.md @@ -28,13 +28,13 @@ I decided to use [WebPageTest.org](https://www.webpagetest.org) to measure load First, a baseline measurement of my existing Cloudways solution. -![Cloudways - overview](/content/img/wpt_1_1a.png) +![Cloudways - overview](/static/wpt_1_1a.png) *Cloudways - overview* -![Cloudways - rating](/content/img/wpt_1_1b.png) +![Cloudways - rating](/static/wpt_1_1b.png) *Cloudways - rating* -![Cloudways - waterfall](/content/img/wpt_1_1c.png) +![Cloudways - waterfall](/static/wpt_1_1c.png) *Cloudways - waterfall* So the server returns the first byte of information after 480 milliseconds. Now, I should tell you that my website is based on [Phug](https://phug-lang.com), the PHP port of [pug.js templating](https://pugjs.org). The page is rendered in real-time and apparently, that takes a little over 300 ms. @@ -53,13 +53,13 @@ Anyway, can Caddy do better? ### Caddy -![Caddy - overview](/content/img/wpt_1_2a.png) +![Caddy - overview](/static/wpt_1_2a.png) *Caddy - overview* -![Caddy - rating](/content/img/wpt_1_2b.png) +![Caddy - rating](/static/wpt_1_2b.png) *Caddy - rating* -![Caddy - waterfall](/content/img/wpt_1_2c.png) +![Caddy - waterfall](/static/wpt_1_2c.png) *Caddy - waterfall* Well, as it turns out, it's largely the same performance. First byte arrived after 459 ms, but I've ran it a few times and there's really little difference between Cloudways and Caddy. @@ -76,13 +76,13 @@ I've tried a lot of things, I'll just narrow it down to the two most important f As it turned out, I had a few small SVG icons and some CSS files. I tried rendering them into the HTML page, so the data would be sent on the first data transmission and no separate requests were needed. For good measure, I also minified the CSS files which, for one file, reduced the size by 30%! -![Caddy+inline - overview](/content/img/wpt_1_6a.png) +![Caddy+inline - overview](/static/wpt_1_6a.png) *Caddy+inline - overview* -![Caddy+inline - rating](/content/img/wpt_1_6b.png) +![Caddy+inline - rating](/static/wpt_1_6b.png) *Caddy+inline - rating* -![Caddy+inline - waterfall](/content/img/wpt_1_6c.png) +![Caddy+inline - waterfall](/static/wpt_1_6c.png) *Caddy+inline - waterfall* On the waterfall above, you can clearly see the `dank-mono.css` was not inlined but I tried multiple configurations, there was no real gain as the image also needed to load and took longer anyway. So, all in all, inlining the SVG and CSS content did little in this case. @@ -97,13 +97,13 @@ As described on [their website](https://phug-lang.com/#usage), PHUG has support ### Caddy - PHUG optimization -![Caddy+PHUG - overview](/content/img/wpt_1_7a.png) +![Caddy+PHUG - overview](/static/wpt_1_7a.png) *Caddy+PHUG - overview* -![Caddy+PHUG - rating](/content/img/wpt_1_7b.png) +![Caddy+PHUG - rating](/static/wpt_1_7b.png) *Caddy+PHUG - rating* -![Caddy+PHUG - waterfall](/content/img/wpt_1_7c.png) +![Caddy+PHUG - waterfall](/static/wpt_1_7c.png) *Caddy+PHUG - waterfall* Well, there it is!!! First byte of data arrived after a mere 173 ms, website is useable in less than half a second and all scores are `A`! diff --git a/content/blog/2020/07/2020-07-03--keybase-website.md b/content/blog/2020/07/2020-07-03--keybase-website.md index dc071c5..a01561c 100644 --- a/content/blog/2020/07/2020-07-03--keybase-website.md +++ b/content/blog/2020/07/2020-07-03--keybase-website.md @@ -26,19 +26,19 @@ When you load that specific page, make sure to load it in a private session or w It is slow. Really slow. I noticed so too and decided to run a [Webpagetest (link to result)](https://www.webpagetest.org/result/200627_0Q_044080ef3ab8a678721658c90d2f4706/). Out of three runs, we analyze only the median run (so not the best one, not the worst one). -![Keybase encrypt Webpagetest overview](/content/img/keybase_encrypt__wpt_overview.png) +![Keybase encrypt Webpagetest overview](/static/keybase_encrypt__wpt_overview.png) *keybase.io/encrypt* ## The content loaded It takes **6.25 seconds** to fully load the **2.9 megabytes** that are used on this page. That is hefty for a page that is essentially a single form. I mean, look at it: -![Keybase encrypt page](/content/img/keybase_encrypt.png) +![Keybase encrypt page](/static/keybase_encrypt.png) *Why 2.9 megabytes?* That's a regular web form. What could possibly be **2.9 megabytes**? The javascript? -![Webpagetest run 1 overview](/content/img/keybase_encrypt__wpt_1.png) +![Webpagetest run 1 overview](/static/keybase_encrypt__wpt_1.png) *How many requests? How many bytes?* Most requests are fonts. That makes sense. Earlier, we saw the page only makes **12 requests**, so I could imagine a few of those being several fonts files. Fortunately, fonts are only **6.5%** of the bytes loaded, so we'll forgive them. @@ -49,7 +49,7 @@ Most requests are fonts. That makes sense. Earlier, we saw the page only makes * Let's grab the [waterfall](https://www.webpagetest.org/result/200627_0Q_044080ef3ab8a678721658c90d2f4706/1/details/#waterfall_view_step1) and see what is going on: -![Webpagetest run 1 waterfall](/content/img/keybase_encrypt__wpt_1_waterfall.png) +![Webpagetest run 1 waterfall](/static/keybase_encrypt__wpt_1_waterfall.png) *Run 1 waterfall* At two points in time, the loading of the website stalls. The first stall is **2.6 seconds** for the file `sitewide-js.js`. The second stall is **2.5 seconds** for the file `footprints_transp.png`. Let's go. @@ -58,7 +58,7 @@ At two points in time, the loading of the website stalls. The first stall is **2 This file is **4.7 megabytes** raw and **1.2 megabytes** gzipped. Let us look at a random excerpt: -![Javascript excerpt](/content/img/keybase_encrypt__js_excerpt.png) +![Javascript excerpt](/static/keybase_encrypt__js_excerpt.png) *Javascript excerpt* This is not really optimized for performance: one could choose to minimize the javascript. Allow me to use `@node-minify/cli`. @@ -78,7 +78,7 @@ Well, I need to specify one thing: the website loads a gzipped version of the or Have you found the image yet? It's the little image at the bottom of the dog (?) following footprints. Cute :) -![Footprints image](/content/img/keybase_encrypt__img.png) +![Footprints image](/static/keybase_encrypt__img.png) *Footprints image* Dimensions on page: **330 x 90 pixels** @@ -122,7 +122,7 @@ Anything else? Given that this is all cryptography related, maybe some security ## Security -![Webpagetest security score](/content/img/keybase_encrypt__security.png) +![Webpagetest security score](/static/keybase_encrypt__security.png) *Webpagetest security score* I've ran quite a few webpagetests on different website, but a **0** security score is new to me. What does that even mean? diff --git a/content/blog/2020/07/2020-07-31--flipper-zero-limited.md b/content/blog/2020/07/2020-07-31--flipper-zero-limited.md index 8a41468..bc0953c 100644 --- a/content/blog/2020/07/2020-07-31--flipper-zero-limited.md +++ b/content/blog/2020/07/2020-07-31--flipper-zero-limited.md @@ -14,39 +14,39 @@ I'm not going to lie, Flipper Zero sounds like a cool project for hackers. Here' Something extremely scummy is going on right now! Have a look: -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__1a.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__1a.png) Looking good, lot's of stuff to read, let's take our time. -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__1b.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__1b.png) My word, they're almost out of Early Birds! Please, for the love of god, if you want to save some money, pledge now, only 9 left and it clearly says "Limited"! ### One minute later -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__2.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__2.png) A person has just pledged! Where's my credit card? ### Another minute later -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__3.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__3.png) Wait, 9 left? Someone bailed? Doesn't matter, I need this! ### Yet another minute later -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__4.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__4.png) Wait, what? ### And it goes on -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__5.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__5.png) ### And on -![Flipper Zero Kickstarter](/content/img/kickstarted_counter__6.png) +![Flipper Zero Kickstarter](/static/kickstarted_counter__6.png) ## This needs to stop diff --git a/content/music/aotw.yaml b/content/music/aotw.yaml deleted file mode 100644 index aaf4954..0000000 --- a/content/music/aotw.yaml +++ /dev/null @@ -1,12 +0,0 @@ -- week: 2020-26 - year: 2017 - artist: Peter Silberman - title: Impermanence -- week: 2020-25 - year: 1984 - artist: Jean-Michel Jarre - title: Zoolook -- week: 2020-24 - year: 1962 - artist: Booker T. & the M.G.'s - title: Green Onions diff --git a/content/notes/2020/06/2020-06-08--nuc-fan-cleaning.md b/content/notes/2020/06/2020-06-08--nuc-fan-cleaning.md index bf7b075..f370977 100644 --- a/content/notes/2020/06/2020-06-08--nuc-fan-cleaning.md +++ b/content/notes/2020/06/2020-06-08--nuc-fan-cleaning.md @@ -14,5 +14,5 @@ If you haven't cleaned the fan in a while, your best bet is to open the NUC up a To prevent having to open a NUC up too often, I bought a few cans of compressed air and regularly blow air through the device. I'm also looking into placing air filters near the air intake. -![NUC cools down when fan is cleaned](/content/img/nuc_temp_fan_cleaning.png) +![NUC cools down when fan is cleaned](/static/nuc_temp_fan_cleaning.png) *Can you tell when compressed air was applied to the NUC?* diff --git a/content/notes/2020/06/2020-06-29--github-sinking.md b/content/notes/2020/06/2020-06-29--github-sinking.md index b022552..84525ca 100644 --- a/content/notes/2020/06/2020-06-29--github-sinking.md +++ b/content/notes/2020/06/2020-06-29--github-sinking.md @@ -10,7 +10,7 @@ published: true I rarely interact with [Github](https://github.com) anymore. All my projects are either on my selfhosted [Gitea](https://gitea.io) instance or on [Codeberg.org](https://codeberg.org/). That's why I missed the following on [Github Status](https://www.githubstatus.com/): -![Github status shows a lot of downtimes](/content/img/github_status.png) +![Github status shows a lot of downtimes](/static/github_status.png) *Yikes* Yikes, indeed. How everyone handles this is up to them. Large projects will find it hard to move, no doubt. diff --git a/index.js b/index.js index f08f756..038255c 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const express = require('express') -const fs = require('fs') const app = express() +const fs = require('fs') require('dotenv').config() app.set('env', process.env.NODE_ENV || "production") @@ -9,12 +9,7 @@ app.set('port', process.env.PORT || 3000) app.use('/', require('./routes/main')) app.use('/', require('./routes/static')) -// app.use('/server', require('./routes/server')) -// app.use('/encrypt', require('./routes/encrypt')) -// app.use('/verify', require('./routes/verify')) -// app.use('/proofs', require('./routes/proofs')) -// app.use('/util', require('./routes/util')) -// app.use('/', require('./routes/profile')) +app.use('/rss', require('./routes/rss')) app.listen(app.get('port'), () => { console.log(`Node server listening at http://localhost:${app.get('port')}`) diff --git a/package-lock.json b/package-lock.json index a014b8a..546e5f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -562,6 +562,14 @@ "validator": "^13.1.1" } }, + "feed": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.1.tgz", + "integrity": "sha512-l28KKcK1J/u3iq5dRDmmoB2p7dtBfACC2NqJh4dI2kFptxH0asfjmOfcxqh5Sv8suAlVa73gZJ4REY5RrafVvg==", + "requires": { + "xml-js": "^1.6.11" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1402,6 +1410,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -1739,6 +1752,19 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, + "yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" + }, "yaml-front-matter": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-4.1.0.tgz", diff --git a/package.json b/package.json index 4dcfd18..8731977 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,15 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "express-validator": "^6.6.1", + "feed": "^4.2.1", "jstransformer-markdown-it": "^2.1.0", + "lodash": "^4.17.20", "luxon": "^1.25.0", "markdown-it-anchor": "^5.3.0", "markdown-it-table-of-contents": "^0.4.4", "markdown-it-title": "^3.0.0", "pug": "^3.0.0", + "yaml": "^1.10.0", "yaml-front-matter": "^4.1.0" }, "devDependencies": { diff --git a/routes/main.js b/routes/main.js index 3ce2972..4eef129 100644 --- a/routes/main.js +++ b/routes/main.js @@ -1,40 +1,66 @@ const router = require('express').Router() const fs = require('fs') +const _ = require('lodash') const mw = require('../server/middlewares') +const util = require('../server/util') + +router.param('slug', async (req, res, next, slug) => { + let posts = await util.getBlogPosts() + posts = _.filter(posts, (p) => { return slug == p.slug }) + if (posts.length > 0) { + res.locals.post = posts[0] + next() + return + } + posts = await util.getNotes() + posts = _.filter(posts, (p) => { return slug == p.slug }) + if (posts.length > 0) { + res.locals.post = posts[0] + next() + return + } + res.locals.post = null + next() +}) router.get('/', mw.getBlogPosts, (req, res) => { - res.render('index', { title: 'yarmo.eu' }) + res.render('blog', { title: 'yarmo.eu' }) }) - -router.get('/getting-started', (req, res) => { - let rawContent = fs.readFileSync(`./content/getting-started.md`, "utf8") - const content = md.render(rawContent) - res.render(`basic`, { title: `Getting started - Keyoxide`, content: content }) +router.get('/blog', mw.getBlogPosts, (req, res) => { + res.render('blog', { title: 'yarmo.eu' }) }) - -router.get('/faq', (req, res) => { - const mdAlt = require('markdown-it')({typographer: true}) - mdAlt.use(require("markdown-it-anchor"), { "level": 2, "permalink": true, "permalinkClass": 'header-anchor', "permalinkSymbol": 'ΒΆ', "permalinkBefore": false }) - mdAlt.use(require("markdown-it-table-of-contents"), { "includeLevel": [2], "listType": "ul" }) - - let rawContent = fs.readFileSync(`./content/faq.md`, "utf8") - rawContent = rawContent.replace('${domain}', req.app.get('domain')) - const content = mdAlt.render(rawContent) - res.render(`basic`, { title: `Frequently Asked Questions - Keyoxide`, content: content }) +router.get('/notes', mw.getNotes, (req, res) => { + res.render('notes', { title: 'yarmo.eu' }) }) - -router.get('/guides', (req, res) => { - res.render('guides', { title: `Guides - Keyoxide` }) +router.get('/post/:slug', (req, res) => { + res.render('post', { title: 'yarmo.eu' }) }) - -router.get('/guides/:guideId', (req, res) => { - let env = {} - let rawContent = fs.readFileSync(`./content/guides/${req.params.guideId}.md`, "utf8", (err, data) => { - if (err) throw err - return data - }) - const content = md.render(rawContent, env) - res.render(`basic`, { title: `${env.title} - Keyoxide`, content: content }) +router.get('/blogroll', (req, res) => { + res.render('blogroll', { title: 'yarmo.eu' }) +}) +router.get('/feeds', (req, res) => { + res.render('feeds', { title: 'yarmo.eu' }) +}) +router.get('/about', (req, res) => { + res.render('about', { title: 'yarmo.eu' }) +}) +router.get('/contact', (req, res) => { + res.render('contact', { title: 'yarmo.eu' }) +}) +router.get('/now', (req, res) => { + res.render('now', { title: 'yarmo.eu' }) +}) +router.get('/uses', (req, res) => { + res.render('uses', { title: 'yarmo.eu' }) +}) +router.get('/music', (req, res) => { + res.render('music', { title: 'yarmo.eu' }) +}) +router.get('/vinyl', mw.getVinyl, (req, res) => { + res.render('vinyl', { title: 'yarmo.eu' }) +}) +router.get('/pgp', (req, res) => { + res.render('pgp', { title: 'yarmo.eu' }) }) module.exports = router diff --git a/routes/rss.js b/routes/rss.js new file mode 100644 index 0000000..ffc9ee5 --- /dev/null +++ b/routes/rss.js @@ -0,0 +1,19 @@ +const router = require('express').Router() +const fs = require('fs') +const _ = require('lodash') +const util = require('../server/util') + +router.get('/all', async (req, res) => { + res.setHeader('Content-Type', 'application/xml') + res.end(await util.getRSS()) +}) +router.get('/blog', async (req, res) => { + res.setHeader('Content-Type', 'application/xml') + res.end(await util.getRSS({ include: ['blog'] })) +}) +router.get('/notes', async (req, res) => { + res.setHeader('Content-Type', 'application/xml') + res.end(await util.getRSS({ include: ['notes'] })) +}) + +module.exports = router diff --git a/routes/static.js b/routes/static.js index f373067..252bb0a 100644 --- a/routes/static.js +++ b/routes/static.js @@ -4,5 +4,6 @@ const path = require('path') router.use('/favicon.png', express.static(path.join(__dirname, '../', 'public', 'favicon.png'))) router.use('/static', express.static(path.join(__dirname, '../', 'public'))) +router.use('/static', express.static(path.join(__dirname, '../', 'content', 'img'))) module.exports = router diff --git a/server/middlewares.js b/server/middlewares.js index e807341..d43ed78 100644 --- a/server/middlewares.js +++ b/server/middlewares.js @@ -1,30 +1,20 @@ -const path = require('path') const fs = require('fs') +const path = require('path') +const YAML = require('yaml') const util = require('./util') -const md = require('markdown-it')({ typographer: true }) -const yamlFront = require('yaml-front-matter') -const { DateTime } = require('luxon') module.exports.getBlogPosts = async (req, res, next) => { - let data = [] - for await (const f of util.getFiles(path.join(__dirname, '../', 'content', 'blog'))) { - const rawContent = fs.readFileSync(f, 'utf8') - const fm = yamlFront.loadFront(rawContent) - data.push({ - type: 'blog', - title: fm['title'], - author: fm['author'], - urlrel: `/post/${fm['slug']}`, - url: `https://yarmo.eu/post/${fm['slug']}`, - slug: fm['slug'], - date: fm['date'], - // date_formatted: DateTime.fromFormat(fm['date'], 'yyyy-LL-dd hh:mm:ss').toFormat('yyyy-LL-dd'), - date_formatted: DateTime.fromFormat(fm['date'], 'yyyy-LL-dd hh:mm:ss').setLocale("en").toLocaleString(DateTime.DATE_MED), - published: fm['published'], - discussion: fm['discussion'], - content: md.render(fm.__content) - }) - } - res.locals.blogPosts = data.reverse() + res.locals.blogPosts = await util.getBlogPosts({ publishedOnly: true }) + next() +} + +module.exports.getNotes = async (req, res, next) => { + res.locals.notes = await util.getNotes({ publishedOnly: true }) + next() +} + +module.exports.getVinyl = async (req, res, next) => { + const file = fs.readFileSync(path.join(__dirname, '../', 'content', 'music', 'vinyl.yaml'), 'utf8') + res.locals.vinyl = YAML.parse(file) next() } diff --git a/server/util.js b/server/util.js index fedf988..989d666 100644 --- a/server/util.js +++ b/server/util.js @@ -1,6 +1,12 @@ -const { resolve } = require('path') -const { readdir } = require('fs').promises const fs = require('fs') +const { readdir } = require('fs').promises +const path = require('path') +const { resolve } = require('path') +const _ = require('lodash') +const md = require('markdown-it')({ typographer: true }) +const yamlFront = require('yaml-front-matter') +const { DateTime } = require('luxon') +const Feed = require('feed').Feed async function* getFiles(dir) { const dirents = await readdir(dir, { withFileTypes: true }) @@ -14,4 +20,126 @@ async function* getFiles(dir) { } } -module.exports.getFiles = getFiles +const getBlogPosts = async (opts) => { + if (!opts) { opts = {} } + opts.publishedOnly = 'publishedOnly' in opts ? opts.publishedOnly : true + + let data = [] + for await (const f of getFiles(path.join(__dirname, '../', 'content', 'blog'))) { + const rawContent = fs.readFileSync(f, 'utf8') + const fm = yamlFront.loadFront(rawContent) + + if (opts.publishedOnly && !fm.published) { continue } + + data.push({ + type: 'blog', + title: fm.title, + author: fm.author, + urlrel: `/post/${fm.slug}`, + url: `https://yarmo.eu/post/${fm.slug}`, + slug: fm.slug, + date: fm.date, + date_formatted: DateTime.fromFormat(fm.date, 'yyyy-LL-dd hh:mm:ss').setLocale("en").toLocaleString(DateTime.DATE_MED), + published: fm.published, + discussion: fm.discussion, + content: md.render(fm.__content) + }) + } + return data.reverse() +} + +const getNotes = async (opts) => { + if (!opts) { opts = {} } + opts.publishedOnly = 'publishedOnly' in opts ? opts.publishedOnly : true + + let data = [] + for await (const f of getFiles(path.join(__dirname, '../', 'content', 'notes'))) { + const rawContent = fs.readFileSync(f, 'utf8') + const fm = yamlFront.loadFront(rawContent) + + if (opts.publishedOnly && !fm.published) { continue } + + data.push({ + type: 'note', + title: fm.title, + author: fm.author, + urlrel: `/post/${fm.slug}`, + url: `https://yarmo.eu/post/${fm.slug}`, + slug: fm.slug, + date: fm.date, + date_formatted: DateTime.fromFormat(fm.date, 'yyyy-LL-dd hh:mm:ss').setLocale("en").toLocaleString(DateTime.DATE_MED), + published: fm.published, + discussion: fm.discussion, + content: md.render(fm.__content) + }) + } + return data.reverse() +} + +const getRSS = async (opts) => { + if (!opts) { opts = {} } + opts.include = 'include' in opts ? opts.include : ['blog', 'notes'] + // opts.excludeBlogPosts = 'excludeBlogPosts' in opts ? opts.excludeBlogPosts : false + // opts.excludeNotes = 'excludeNotes' in opts ? opts.excludeNotes : false + + const feed = new Feed({ + title: "Yarmo's blog and notes", + description: "Blog posts and notes feed for yarmo.eu discussing open source, privacy and selfhosted stuff", + id: "https://yarmo.eu", + link: "https://yarmo.eu", + language: "en", + favicon: "https://yarmo.eu/favicon.png", + copyright: "All rights reserved 2020 Yarmo Mackenbach", + updated: new Date(Date.now()), + author: { + name: "Yarmo Mackenbach", + email: "yarmo@yarmo.eu", + link: "https://yarmo.eu" + } + }) + + feed.addCategory("Technology") + feed.addCategory("FOSS") + feed.addCategory("Decentralization") + feed.addCategory("Privacy") + feed.addCategory("Identity") + feed.addCategory("Cryptography") + feed.addCategory("Selfhosted") + + let posts = [] + if (opts.include.includes('blog')) { + posts = posts.concat(await getBlogPosts()) + } + if (opts.include.includes('notes')) { + posts = posts.concat(await getNotes()) + } + + posts = _.sortBy(posts, ['date']).reverse() + + posts.forEach((item, i) => { + feed.addItem({ + title: item.title, + id: item.url, + link: item.url, + description: item.content, + content: item.content, + author: [ + { + name: "Yarmo Mackenbach", + email: "yarmo@yarmo.eu", + link: "https://yarmo.eu" + } + ], + date: new Date(item.date) + }) + }) + + return feed.rss2() +} + +module.exports = { + getFiles: getFiles, + getBlogPosts: getBlogPosts, + getNotes: getNotes, + getRSS: getRSS +} diff --git a/views/404.pug b/views/404.pug index 8fd6645..d33bf36 100644 --- a/views/404.pug +++ b/views/404.pug @@ -1,4 +1,4 @@ -extends layout +extends templates/main block content h2 HTTP 404 diff --git a/views/about.pug b/views/about.pug index cebefe3..fc990da 100644 --- a/views/about.pug +++ b/views/about.pug @@ -1,28 +1,25 @@ -extends layout +extends templates/main block content header - nav - | about me h1 | About Me + nav + | >> + a(href="/about") about me nav | Go to: - a(href="/now") now - | | a(href="/") blog | | a(href="/notes") notes | | a(href="/feeds") feeds | | - a(href="/blogroll") blogroll + a(href="/now") now | | a(href="/uses") uses | | - a(href="/foss") FOSS - | | - a(href="/projects") projects + a(href="/work") work | | a(href="/music") music | | diff --git a/views/aotw.pug b/views/aotw.pug deleted file mode 100644 index e12d466..0000000 --- a/views/aotw.pug +++ /dev/null @@ -1,19 +0,0 @@ -extends layout - -mixin entry($item) - .list__item - p !{$item['week']} >> !{$item['artist']} - !{$item['title']} (!{$item['year']}) - -block content - header - nav - a(href="/about") about me - | > - a(href="/music") music - | > album of the week - h1 Yarmo's Album Of The Week - - main - .list - each $item in $albums - +entry($item) diff --git a/views/index.pug b/views/blog.pug similarity index 79% rename from views/index.pug rename to views/blog.pug index 968b807..a51dcd6 100644 --- a/views/index.pug +++ b/views/blog.pug @@ -3,19 +3,22 @@ extends templates/main mixin entry(item) article.longform_list__item.h-entry p - a(href="{item['urlrel']}").p-name.u-url !{item['title']} + a(href=item['urlrel']).p-name.u-url !{item['title']} br | Posted on - time(datetime="{item['date']}").dt-published !{item['date_formatted']} + time(datetime=item['date']).dt-published !{item['date_formatted']} block content .h-card header - nav + //nav a(href="/about") about me | > blog h1 | Yarmo's blog + nav + | >> + a(href="/") blog nav | Go to: a(href="/about") about me diff --git a/views/blogroll.pug b/views/blogroll.pug index f01d3ce..c4fa75a 100644 --- a/views/blogroll.pug +++ b/views/blogroll.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > blogroll h1 | Blogroll + nav + | >> + a(href="/about") about me + | > + a(href="/blogroll") blogroll main a(href="https://ar.al/") Aral Balkan diff --git a/views/contact.pug b/views/contact.pug index 215d603..375aa46 100644 --- a/views/contact.pug +++ b/views/contact.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > contact h1 | Contact me + nav + | >> + a(href="/about") about me + | > + a(href="/contact") contact main h2 >> Online presence @@ -106,7 +108,7 @@ block content a(href="mailto:yarmo@yarmo.eu") yarmo@yarmo.eu | . - h3#pgp-advanced#kleopatra Using the Kleopatra software (advanced) + h3#pgp-advanced Using the Kleopatra software (advanced) ol li diff --git a/views/feeds.pug b/views/feeds.pug index f338f89..e397a14 100644 --- a/views/feeds.pug +++ b/views/feeds.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > feeds h1 | Feeds + nav + | >> + a(href="/about") about me + | > + a(href="/feeds") feeds main ul diff --git a/views/foss.pug b/views/foss.pug index 4dd38ea..3adaca4 100644 --- a/views/foss.pug +++ b/views/foss.pug @@ -1,4 +1,4 @@ -extends layout +extends templates/main mixin foss_contribution($item) p diff --git a/views/music.pug b/views/music.pug index a9245a5..a23da9b 100644 --- a/views/music.pug +++ b/views/music.pug @@ -1,16 +1,16 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > music h1 Yarmo's music - p + nav + | >> + a(href="/about") about me + | > + a(href="/music") music + nav | Go to: a(href="/vinyl") vinyl - | | - a(href="/aotw") Album Of The Week main h3 Instruments diff --git a/views/notes.pug b/views/notes.pug index 8d96450..a8c5d98 100644 --- a/views/notes.pug +++ b/views/notes.pug @@ -1,21 +1,33 @@ -extends layout +extends templates/main -mixin entry($item) +mixin entry(item) article.longform_list__item.h-entry p - a(href="{$item['urlrel']}").p-nameu-url !{$item['title']} + a(href=item['urlrel']).p-nameu-url !{item['title']} br | Posted on - time(datetime="{$item['date']}").dt-published !{$item['date_formatted']} + time(datetime=item['date']).dt-published !{item['date_formatted']} block content header - nav + //nav a(href="/about") about me | > notes h1 Yarmo's notes + nav + | >> + a(href="/notes") notes + nav + | Go to: + a(href="/about") about me + | | + a(href="/") blog + | | + a(href="/feeds") feeds + | | + a(href="/contact") contact main .longform_list - each $item in $posts - +entry($item) + each item in notes + +entry(item) diff --git a/views/now.pug b/views/now.pug index 2b30320..4694626 100644 --- a/views/now.pug +++ b/views/now.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > now h1 | Now + nav + | >> + a(href="/about") about me + | > + a(href="/now") now main h3 Working on diff --git a/views/pgp.pug b/views/pgp.pug index 81df1dc..647f762 100644 --- a/views/pgp.pug +++ b/views/pgp.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > pgp h1 | PGP public key + nav + | >> + a(href="/about") about me + | > + a(href="/pgp") pgp main h3#pgp-fingerprint Fingerprint diff --git a/views/post.pug b/views/post.pug index 1a6426a..ab8b45f 100644 --- a/views/post.pug +++ b/views/post.pug @@ -1,72 +1,72 @@ -extends layout +extends templates/main -mixin webmention($item) - if (!array_key_exists('type', $item)) +mixin webmention(item) + if (!array_key_exists('type', item)) p - if (array_key_exists('title', $item)) - a(href="{$item['source']}") !{$item['title']} + if (array_key_exists('title', item)) + a(href="{item['source']}") !{item['title']} else - a(href="{$item['source']}") !{$item['source']} - if (array_key_exists('author_name', $item)) - | by !{$item['author_name']} - if (array_key_exists('date', $item)) - | on !{$item['date']} - if (array_key_exists('time', $item)) - | at !{$item['time']} UTC - else if ($item['type'] == "comment") + a(href="{item['source']}") !{item['source']} + if (array_key_exists('author_name', item)) + | by !{item['author_name']} + if (array_key_exists('date', item)) + | on !{item['date']} + if (array_key_exists('time', item)) + | at !{item['time']} UTC + else if (item['type'] == "comment") .comment p.quote - if (array_key_exists('title', $item)) - strong !{$item['title']} + if (array_key_exists('title', item)) + strong !{item['title']} br - if (array_key_exists('content', $item)) - | !{$item['content']} + if (array_key_exists('content', item)) + | !{item['content']} p.sub - a(href="{$item['source']}") Commented - if (array_key_exists('author_name', $item)) - | by !{$item['author_name']} - if (array_key_exists('date', $item)) - | on !{$item['date']} - if (array_key_exists('time', $item)) - | at !{$item['time']} UTC + a(href="{item['source']}") Commented + if (array_key_exists('author_name', item)) + | by !{item['author_name']} + if (array_key_exists('date', item)) + | on !{item['date']} + if (array_key_exists('time', item)) + | at !{item['time']} UTC -mixin discussionLink($item) +mixin discussionLink(item) p - a(href="{$item}") !{$item} + a(href="{item}") !{item} block content header nav - a(href="/about") about me - | > - if ($post["type"] == "blog") + | >> + if post.type == 'blog' a(href="/") blog - if ($post["type"] == "note") + if post.type == 'note' a(href="/notes") notes - | > !{$post['slug']} + | > + a(href=post.url)= post.slug main article.longform.h-entry - h1.p-name !{$post['title']} + h1.p-name !{post.title} p.longform__header | Posted on - a(href="{$post['url']}" datetime="{$post['date']}").u-url.dt-published !{$post['date_formatted']} + a(href=post.url datetime="{post.date}").u-url.dt-published !{post.date_formatted} | by - a(href="/" rel="author").p-author.h-card !{$post['author']} + a(href="/" rel="author").p-author.h-card !{post.author} .longform__content.e-content - | !{$post['content']} + | !{post.content} - if (array_key_exists('discussion', $post) && isset($post['discussion'])) + if ('discussion' in post && post.discussion) .discussion.subsection h2 Join the discussion - each $item in $post["discussion"] - +discussionLink($item) + each item in post["discussion"] + +discussionLink(item) .webmentions.subsection h2 Webmentions - if ($post['hasWebmentions']) - each $item in $post["webmentions"] - +webmention($item) + if (post.hasWebmentions) + each item in post["webmentions"] + +webmention(item) else p This post has not been mentioned yet. diff --git a/views/projects.pug b/views/projects.pug index a7d200c..7d07df8 100644 --- a/views/projects.pug +++ b/views/projects.pug @@ -1,4 +1,4 @@ -extends layout +extends templates/main mixin entry($item) article.longform_list__item diff --git a/views/projects_details.pug b/views/projects_details.pug index 7360efe..e97daa8 100644 --- a/views/projects_details.pug +++ b/views/projects_details.pug @@ -1,4 +1,4 @@ -extends layout +extends templates/main mixin webmention($item) p diff --git a/views/reply.pug b/views/reply.pug index 1cbfa92..ab80420 100644 --- a/views/reply.pug +++ b/views/reply.pug @@ -1,4 +1,4 @@ -extends layout +extends templates/main mixin webmention($item) if (!array_key_exists('type', $item)) diff --git a/views/uses.pug b/views/uses.pug index a554058..8597b2d 100644 --- a/views/uses.pug +++ b/views/uses.pug @@ -1,12 +1,14 @@ -extends layout +extends templates/main block content header - nav - a(href="/about") about me - | > uses h1 | Uses + nav + | >> + a(href="/about") about me + | > + a(href="/uses") uses main h2 Hardware diff --git a/views/vinyl.pug b/views/vinyl.pug index c5904bb..28ad33d 100644 --- a/views/vinyl.pug +++ b/views/vinyl.pug @@ -1,19 +1,21 @@ -extends layout +extends templates/main -mixin entry($item) +mixin entry(item) .list__item - p !{$item['artist']} - !{$item['title']} (!{$item['year']}) + p !{item['artist']} - !{item['title']} (!{item['year']}) block content header + h1 Yarmo's vinyl collection nav + | >> a(href="/about") about me | > a(href="/music") music - | > vinyl - h1 Yarmo's vinyl collection + | > + a(href="/vinyl") vinyl main .list - each $item in $albums - +entry($item) + each item in vinyl.albums + +entry(item)