Files
kleinpanicWeb/routes/blog.js
2024-10-20 17:49:24 -04:00

107 lines
3.8 KiB
JavaScript

const express = require('express');
const router = express.Router();
const path = require('path');
const fs = require('fs');
const { marked } = require('marked');
const fm = require('front-matter'); // For parsing front matter
const RSS = require('rss'); // Import RSS package
// Directory containing Markdown blog posts
const blogDirectory = path.join(__dirname, '../blog');
// Function to get all Markdown files in the blog directory
function getBlogPosts() {
const files = fs.readdirSync(blogDirectory);
return files.filter(file => file.endsWith('.md')).map(file => {
const content = fs.readFileSync(path.join(blogDirectory, file), 'utf-8');
// Parse front matter
const parsed = fm(content);
const { title, date, preview } = parsed.attributes; // Get title, date, and preview from front matter
// Remove Markdown formatting by converting to HTML and stripping the tags
const htmlContent = marked(parsed.body);
const plainText = htmlContent.replace(/<\/?[^>]+(>|$)/g, ""); // Strip HTML tags from Markdown-converted content
// Truncate the plain text to create the preview
const generatedPreview = plainText.split(' ').slice(0, 30).join(' ').substring(0, 150); // First 150 characters
// Use the preview from front matter if available, otherwise use the generated plain-text preview
const finalPreview = preview || generatedPreview;
const slug = file.replace('.md', ''); // Remove file extension for slug
console.log(`Preview for ${title}: ${finalPreview}`); // Log the preview to verify
return {
title,
date,
preview: finalPreview, // Ensure the correct preview is sent
slug
};
});
}
// New Route to generate RSS feed - put this before the dynamic slug route
router.get('/rss.xml', (req, res) => {
const feed = new RSS({
title: 'The Klein Blog',
description: 'Latest updates from The Klein Blog',
feed_url: `${req.protocol}://${req.get('host')}/rss.xml`,
site_url: `${req.protocol}://${req.get('host')}`,
language: 'en',
pubDate: new Date().toUTCString(),
});
// Add each blog post to the RSS feed
const posts = getBlogPosts();
posts.forEach(post => {
feed.item({
title: post.title,
description: post.preview, // Short preview for the RSS feed
url: `${req.protocol}://${req.get('host')}/blog/${post.slug}`, // Link to the blog post
date: post.date, // Published date
});
});
// Set the content type to XML and send the RSS feed
res.set('Content-Type', 'application/rss+xml');
res.send(feed.xml());
});
// Route to serve the blog posts as JSON
router.get('/blog-posts', (req, res) => {
const posts = getBlogPosts(); // Get all blog posts
res.json(posts); // Return posts as JSON to be fetched by the client-side JS
});
// Route to serve the main blog page (serve blog.html)
router.get('/', (req, res) => {
// Render the blog.html file from the views directory
res.sendFile(path.join(__dirname, '../views/blog.html'));
});
marked.setOptions({
gfm: true, // GitHub-flavored Markdown
breaks: true, // Enable line breaks
smartypants: true, // Use smart quotes, dashes, etc.
sanitize: false, // This is the important option to allow HTML tags
});
// Route to serve individual blog posts dynamically
router.get('/:slug', (req, res) => {
const { slug } = req.params;
const filePath = path.join(blogDirectory, `${slug}.md`);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
const parsed = fm(content); // Parse front matter
const htmlContent = marked(parsed.body); // Convert markdown body to HTML
res.render('post', { content: htmlContent, title: parsed.attributes.title, date: parsed.attributes.date }); // Render post view
} else {
res.status(404).send('Blog post not found');
}
});
module.exports = router;