Create and link RSS feed
This commit is contained in:
55
src/routes/blog/_content.js
Normal file
55
src/routes/blog/_content.js
Normal file
@ -0,0 +1,55 @@
|
||||
import { readdir, readFile } from 'fs'
|
||||
import { promisify } from 'util'
|
||||
import { basename } from 'path'
|
||||
import { pipe, partial, prop, sortBy, reverse, filter } from 'ramda'
|
||||
import fm from 'front-matter'
|
||||
import marked from 'marked'
|
||||
|
||||
const { NODE_ENV } = process.env
|
||||
|
||||
export async function getBlogListing(tag) {
|
||||
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
|
||||
const filteredFiles = filterDevelopmentFiles(files)
|
||||
|
||||
const contents = await Promise.all(
|
||||
filteredFiles.map(async file => {
|
||||
const fileContent = await promisify(readFile)(
|
||||
`_posts/blog/${file}`,
|
||||
'utf-8'
|
||||
)
|
||||
const parsedAttributes = fm(fileContent)
|
||||
|
||||
const lineOfTextRegExp = /^(?:\w|\[).+/gm
|
||||
const lines = parsedAttributes.body
|
||||
.match(lineOfTextRegExp)
|
||||
.slice(0, 2)
|
||||
.join('\n')
|
||||
|
||||
const preview = marked(lines)
|
||||
return {
|
||||
...parsedAttributes.attributes,
|
||||
preview,
|
||||
slug: basename(file, '.md'),
|
||||
}
|
||||
})
|
||||
)
|
||||
const filteredContents = pipe(
|
||||
sortBy(prop('date')),
|
||||
reverse,
|
||||
filter(article => article.published),
|
||||
partial(filterByTag, [tag])
|
||||
)(contents)
|
||||
|
||||
return filteredContents
|
||||
}
|
||||
|
||||
function filterDevelopmentFiles(files) {
|
||||
return NODE_ENV !== 'production'
|
||||
? files
|
||||
: files.filter(file => !file.startsWith('dev-'))
|
||||
}
|
||||
|
||||
function filterByTag(tag, contents) {
|
||||
return tag ? contents.filter(content => content.tags.includes(tag)) : contents
|
||||
}
|
||||
|
@ -1,63 +1,10 @@
|
||||
import { readdir, readFile } from 'fs'
|
||||
import { promisify } from 'util'
|
||||
import { basename } from 'path'
|
||||
import { pipe, partial, prop, sortBy, reverse, filter } from 'ramda'
|
||||
import fm from 'front-matter'
|
||||
import marked from 'marked'
|
||||
|
||||
const { NODE_ENV } = process.env
|
||||
import { getBlogListing } from './_content'
|
||||
|
||||
export async function get(req, res) {
|
||||
const { tag } = req.query
|
||||
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
|
||||
const filteredFiles = filterDevelopmentFiles(files)
|
||||
|
||||
const contents = await Promise.all(
|
||||
filteredFiles.map(async file => {
|
||||
const fileContent = await promisify(readFile)(
|
||||
`_posts/blog/${file}`,
|
||||
'utf-8'
|
||||
)
|
||||
const parsedAttributes = fm(fileContent)
|
||||
|
||||
const lineOfTextRegExp = /^(?:\w|\[).+/gm
|
||||
const sentenceRegExp = /(?:\w|\[).[.?!]/
|
||||
const lines = parsedAttributes.body
|
||||
.match(lineOfTextRegExp)
|
||||
.slice(0, 2)
|
||||
.join('\n')
|
||||
|
||||
const preview = marked(lines)
|
||||
return {
|
||||
...parsedAttributes.attributes,
|
||||
preview,
|
||||
slug: basename(file, '.md'),
|
||||
}
|
||||
})
|
||||
)
|
||||
const filteredContents = pipe(
|
||||
sortBy(prop('date')),
|
||||
reverse,
|
||||
filter(article => article.published),
|
||||
partial(filterByTag, [tag])
|
||||
)(contents)
|
||||
|
||||
const filteredContents = await getBlogListing(tag)
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
res.end(JSON.stringify(filteredContents))
|
||||
}
|
||||
|
||||
function filterDevelopmentFiles(files) {
|
||||
return NODE_ENV !== 'production'
|
||||
? files
|
||||
: files.filter(file => !file.startsWith('dev-'))
|
||||
}
|
||||
|
||||
function filterByTag(tag, contents) {
|
||||
return tag ? contents.filter(content => content.tags.includes(tag)) : contents
|
||||
}
|
||||
|
||||
function filterPublished(article) {
|
||||
return article.published
|
||||
}
|
||||
|
39
src/routes/feed/_feed.js
Normal file
39
src/routes/feed/_feed.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { Feed } from 'feed'
|
||||
import { getBlogListing } from '../blog/_content'
|
||||
|
||||
export async function getFeed() {
|
||||
const feed = new Feed({
|
||||
title: 'michalvanko.dev latest posts',
|
||||
id: 'https://michalvanko.dev',
|
||||
link: 'https://michalvanko.dev',
|
||||
description: 'Latest posts published on michalvanko.dev',
|
||||
copyright: 'All rights reserved 2020, Michal Vanko',
|
||||
generator: 'sapper with Feed for node.js',
|
||||
updated: new Date(),
|
||||
image: 'https://michalvanko.dev/eye.png',
|
||||
favicon: 'https://michalvanko.dev/m-favicon-192x192.png',
|
||||
language: 'en',
|
||||
author: {
|
||||
name: 'Michal Vanko',
|
||||
email: 'michalvankosk@gmail.com',
|
||||
link: 'https://michalvanko.dev',
|
||||
},
|
||||
feedLinks: {
|
||||
json: 'https://michalvanko.dev/feed.json',
|
||||
rss: 'https://michalvanko.dev/feed.xml',
|
||||
},
|
||||
})
|
||||
|
||||
const blogListing = await getBlogListing()
|
||||
blogListing.forEach(post => {
|
||||
feed.addItem({
|
||||
title: post.title,
|
||||
id: `https://michalvanko.dev/blog/${post.slug}`,
|
||||
link: `https://michalvanko.dev/blog/${post.slug}`,
|
||||
description: post.preview,
|
||||
date: post.date,
|
||||
image: post.thumbnail ? `https://michalvanko.dev/${post.thumbnail}` : undefined,
|
||||
})
|
||||
})
|
||||
return feed
|
||||
}
|
11
src/routes/feed/index.json.js
Normal file
11
src/routes/feed/index.json.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { getFeed } from './_feed'
|
||||
|
||||
export async function get(req, res) {
|
||||
const feed = await getFeed()
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
res.end(feed.json1())
|
||||
}
|
||||
|
11
src/routes/feed/index.xml.js
Normal file
11
src/routes/feed/index.xml.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { getFeed } from './_feed'
|
||||
|
||||
export async function get(req, res) {
|
||||
const feed = await getFeed()
|
||||
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/xml',
|
||||
})
|
||||
res.end(feed.rss2())
|
||||
}
|
||||
|
@ -33,7 +33,11 @@
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>michalvanko.dev index page</title>
|
||||
<title>Introduction @michalvankodev</title>
|
||||
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS feed for latest posts" href="https://michalvanko.dev/feed.xml" />
|
||||
<link rel="alternate" title="JSON feed for latest posts" type="application/json" href="https://michalvanko.dev/feed.json" />
|
||||
</svelte:head>
|
||||
|
||||
<header class="index-header">
|
||||
|
Reference in New Issue
Block a user