145 lines
4.0 KiB
TypeScript

import type { XMLBuilder } from 'xmlbuilder2/lib/interfaces';
import { create as create_xml } from 'xmlbuilder2';
import { BuildState } from './state';
import { write_text } from '../fs';
import { AuthorConfig, app_version } from '../conf';
import { map_output_file_to_url } from './helpers';
import { DateTime } from 'luxon';
import { FileMetadata } from '../metadata';
export interface RSSEntry {
url: string;
in_file: string;
title?: string;
description?: string;
authors?: AuthorConfig[];
html_content?: string;
tags?: string[];
}
export async function write_rss_if_needed(state: BuildState) {
if (! state.conf.rss) {
return;
}
for (let index = 0; index < state.conf.rss.length; index++) {
const rss_conf = state.conf.rss[index];
const doc = create_xml({ version: '1.0', encoding: 'UTF-8' });
const { abs_url: self_url } = map_output_file_to_url(state, rss_conf.out_file);
if (rss_conf.xsl) {
for (const url of rss_conf.xsl) {
doc.ins('xml-stylesheet', `href="${url}" type="text/xsl"`);
}
}
const rss = doc.ele('rss', {
version: '2.0',
'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
'xmlns:content': 'http://purl.org/rss/1.0/modules/content/',
'xmlns:atom': 'http://www.w3.org/2005/Atom',
// 'xmlns:docs2website': 'urn:uuid:7fc4e5d4-f68e-11ed-b0d0-00155ddef564',
});
const channel = rss.ele('channel');
channel.ele('generator').txt(`docs2website ${app_version}`);
if (rss_conf.title) {
channel.ele('title').txt(rss_conf.title);
}
if (rss_conf.link) {
channel.ele('link').txt(rss_conf.link);
}
link(channel, 'application/rss+xml', 'self', self_url);
if (rss_conf.alternates?.length) {
for (const alt of rss_conf.alternates) {
link(channel, alt.type, 'alternate', alt.href);
}
}
if (rss_conf.description) {
channel.ele('description').txt(rss_conf.description);
}
if (rss_conf.language) {
channel.ele('language').txt(rss_conf.language);
}
if (rss_conf.copyright) {
channel.ele('copyright').txt(rss_conf.copyright);
}
channel.ele('lastBuildDate').txt(state.build_time.rfc2822);
// channel.ele('rating').txt(''); // see: https://www.w3.org/PICS/
// channel.ele('pubDate').txt(publish_date.toUTCString());
// channel.ele('categories').txt('');
// channel.ele('docs').txt('');
// channel.ele('managingEditor').txt('james@jbrumond.me');
// channel.ele('webMaster').txt('james@jbrumond.me');
// channel.ele('ttl').txt('');
// channel.ele('image').txt('');
// channel.ele('skipHours').txt('');
// channel.ele('skipDays').txt('');
let entries: (RSSEntry & { metadata: FileMetadata, first_seen: number })[] = [ ];
for (const entry of state.rss[index] || [ ]) {
const in_file = entry.in_file.slice(state.conf.input.root.length);
const metadata = state.new_metadata.files[in_file];
entries.push({ ...entry, metadata, first_seen: DateTime.fromISO(metadata.first_seen_time).toUnixInteger() });
}
entries = entries.sort((a, b) => {
return b.first_seen - a.first_seen;
});
for (const entry of entries) {
const item = channel.ele('item');
item.ele('link').txt(entry.url);
if (entry.title) {
item.ele('title').txt(entry.title);
}
if (entry.description) {
item.ele('description').txt(entry.description);
}
if (entry.authors) {
for (const author of entry.authors) {
item.ele('dc:creator').ele({ $: author.name || author.url || author.email });
}
}
if (entry.tags) {
entry.tags.forEach((tag) => item.ele('category').txt(tag));
}
item.ele('guid').txt(entry.url);
item.ele('pubDate').txt(DateTime.fromISO(entry.metadata.first_seen_time).toRFC2822());
if (entry.html_content) {
item.ele('content:encoded').ele({ $: entry.html_content });
}
}
const xml = doc.toString({
indent: ' ',
prettyPrint: true,
});
await write_text(rss_conf.out_file, xml);
}
}
function link(channel: XMLBuilder, type: string, rel: string, href: string) {
// channel.ele('link', { href, rel, type, });
channel.ele('atom:link', { type, rel, href, });
}