124 lines
2.9 KiB
JavaScript
124 lines
2.9 KiB
JavaScript
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|