feat: add blog_options and rss feed generation
This commit is contained in:
13
app/server/rss/index.js
Normal file
13
app/server/rss/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { RssGenerator } from "./rssGenerator.js";
|
||||
|
||||
let generator = null;
|
||||
|
||||
export default (() => {
|
||||
if (!generator) {
|
||||
generator = Object.freeze(new RssGenerator({
|
||||
filePath: '/home/node/rss/rss.xml',
|
||||
}));
|
||||
}
|
||||
|
||||
return generator;
|
||||
})();
|
||||
123
app/server/rss/rssGenerator.js
Normal file
123
app/server/rss/rssGenerator.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import fs from 'node:fs';
|
||||
|
||||
export class RssGenerator {
|
||||
maxItem = 10;
|
||||
items = [];
|
||||
channel = {};
|
||||
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
// TODO: move to pass an option parameter and iterate over the key/values
|
||||
setChannel (title, description, link, pubDate) {
|
||||
this.channel.title = title;
|
||||
this.channel.description = description;
|
||||
this.channel.link = link;
|
||||
this.channel.pubDate = pubDate;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addItem (item) {
|
||||
if (!this.isItemValid(item)) {
|
||||
console.error('[RssGenerator] addItem: item invalid.', item);
|
||||
return this;
|
||||
}
|
||||
|
||||
this.items.push(item);
|
||||
|
||||
if (this.items.lenght > this.maxItem) {
|
||||
this.items.shift();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
isItemValid(item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
generateFile() {
|
||||
let data = '';
|
||||
|
||||
data += '<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\"><channel>';
|
||||
data += this.#generateChannelInfos();
|
||||
data += this.#generateItems();
|
||||
data += '</channel></rss>';
|
||||
|
||||
this.#saveFile(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
#generateChannelInfos() {
|
||||
let infos = '';
|
||||
|
||||
infos += `<title>${this.channel.title}</title>\n`;
|
||||
infos += `<description>${this.channel.description}</description>\n`;
|
||||
infos += `<link>${this.channel.link}</link>\n`;
|
||||
infos += `<pubDate>${RssGenerator.formatDate(this.channel.pubDate)}</pubDate>\n`;
|
||||
infos += `<atom:link href="${this.channel.link}/rss.xml" rel="self" type="application/rss+xml" />\n`;
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
#generateItems() {
|
||||
let data = '';
|
||||
|
||||
for (const item of this.items) {
|
||||
data += '<item>\n';
|
||||
data += `<title>${item.title}</title>\n`;
|
||||
data += `<link>${item.link}</link>\n`;
|
||||
data += `<guid>${item.link}</guid>\n`;
|
||||
data += `<description>${item.description}</description>\n`;
|
||||
data += '</item>\n';
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static formatDate(date) {
|
||||
return new Intl.DateTimeFormat("en-GB", {
|
||||
hour12: false,
|
||||
weekday: "short",
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
timeZone: "Europe/London",
|
||||
}).formatToParts(date)
|
||||
.filter(el => el.type !== "literal")
|
||||
.reduce((acc, cur) => {
|
||||
switch (cur.type) {
|
||||
case "weekday":
|
||||
acc += `${cur.value}, `;
|
||||
break;
|
||||
case "hour":
|
||||
case "minute":
|
||||
acc += `${cur.value}:`;
|
||||
break;
|
||||
case "timeZoneName":
|
||||
acc += cur.value;
|
||||
break;
|
||||
default:
|
||||
acc += `${cur.value} `;
|
||||
break;
|
||||
}
|
||||
return acc;
|
||||
}, '')
|
||||
.concat(" GMT");
|
||||
}
|
||||
|
||||
#saveFile(data) {
|
||||
try {
|
||||
fs.writeFileSync(this.options.filePath, data, { encoding: 'utf8' });
|
||||
} catch (err) {
|
||||
console.error('[RssGenerator] saveFile - ERROR');
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
app/server/rss/template.xml
Normal file
8
app/server/rss/template.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>$TITLE</title>
|
||||
<description>$DESCRIPTION</description>
|
||||
<link>$LINK</link>
|
||||
<channel>
|
||||
</rss>
|
||||
Reference in New Issue
Block a user