update new article

This commit is contained in:
2026-01-18 22:15:07 +01:00
parent 1255ce4f07
commit cc8b8b6d8b
8 changed files with 515 additions and 67 deletions

132
main.ts
View File

@@ -12,8 +12,90 @@ import { type DjAPIResult, type DjAPIResultMap } from "@/api.ts";
const utf8Decoder = new TextDecoder("utf-8");
const HOST = 'https://djledda.net';
const parser = new DOMParser();
async function getBlogEntries() {
const paths: string[] = [];
const contentDir = './public/blog/content/';
for await (const dirEnt of Deno.readDir(contentDir)) {
if (dirEnt.isFile && dirEnt.name.endsWith('.html')) {
paths.push(`${contentDir}${dirEnt.name}`);
}
}
const result: DjAPIResultMap['/blog-entries'] = [];
for (const filePath of paths) {
const content = await Deno.readTextFile(filePath);
const dom = parser.parseFromString(content, 'text/html');
const metadata = {
slug: '',
tags: [] as string[],
guid: '',
title: '',
createdAt: '',
updatedAt: '',
};
const metaTags = dom.querySelectorAll('meta') as unknown as NodeListOf<HTMLMetaElement>;
for (const metaTag of metaTags) {
const name = metaTag.attributes.getNamedItem('name')?.value ?? '';
const content = metaTag.attributes.getNamedItem('content')?.value ?? '';
if (name === 'title') {
metadata.title = content;
} else if (name === 'tags') {
metadata.tags = content ? content.split(",") : [];
} else if (name === 'guid') {
metadata.guid = content;
} else if (name === 'slug') {
metadata.slug = content;
} else if (name === 'updatedAt') {
metadata.createdAt = content;
} else if (name === 'createdAt') {
metadata.updatedAt = content;
}
}
result.push(metadata);
}
result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
return result;
}
async function rss() {
const articles = await getBlogEntries();
return `<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>djledda's blog</title>
<description>djledda's personal blog</description>
<link>${ HOST }/blog</link>
<managingEditor>dan@djledda.net (Daniel Ledda)</managingEditor>
<image>
<title>djledda's blog</title>
<url>${ HOST }/favicon.png</url>
<link>${ HOST }/blog</link>
<description>djledda's personal blog</description>
</image>
<language>en-au</language>
<copyright>${ new Date().getFullYear() } djledda.net All rights reserved</copyright>
<lastBuildDate>${ new Date(articles.at(-1)!.updatedAt).toUTCString() }</lastBuildDate>
<pubDate>${ new Date(articles.at(-1)!.updatedAt).toUTCString() }</pubDate>
<ttl>1440</ttl>
${ articles.map(article => `<item>
<title>${ article.title }</title>
<link>${ HOST }/blog/${ article.slug }</link>
<pubDate>${ new Date(article.createdAt).toUTCString() }</pubDate>
<author>dan@djledda.net (Daniel Ledda)</author>
<guid>${ article.guid }</guid>
</item>
`).join('')}
<atom:link href="${ HOST }/blog/djblog.rss" rel="self" type="application/rss+xml" />
</channel>
</rss>`;
}
function appHeaderScript(params: { ssrContext: DjSSRContext, entryPath: string }) {
return `
<title>${ toValue(params.ssrContext.head.title) }</title>
@@ -32,7 +114,7 @@ function appHeaderScript(params: { ssrContext: DjSSRContext, entryPath: string }
<style>
${ Object.values(params.ssrContext.styles).join('\n') }
</style>
<script type="module">
<script type="module">
window.appstate = ${JSON.stringify(params.ssrContext.registry)};
import('${params.entryPath}');
</script>`;
@@ -53,8 +135,6 @@ for await (const entry of siteEntries("app")) {
sites.push(entry);
}
console.log(sites);
async function getAPIResponse(apiReq: Request): Promise<Response> {
let jsonResponse: DjAPIResult | { error: string } | null = null;
let status = 200;
@@ -102,44 +182,7 @@ async function getAPIResponse(apiReq: Request): Promise<Response> {
result.sort((a, b) => a.titleDe.localeCompare(b.titleDe));
jsonResponse = result;
} else if (apiPath === "/blog-entries") {
const paths: string[] = [];
const contentDir = './public/blog/content/';
for await (const dirEnt of Deno.readDir(contentDir)) {
if (dirEnt.isFile && dirEnt.name.endsWith('.html')) {
paths.push(`${contentDir}${dirEnt.name}`);
}
}
const result: DjAPIResultMap['/blog-entries'] = [];
for (const filePath of paths) {
const content = await Deno.readTextFile(filePath);
const dom = parser.parseFromString(content, 'text/html');
const metadata = {
slug: '',
tags: [] as string[],
title: '',
createdAt: '',
updatedAt: '',
};
const metaTags = dom.querySelectorAll('meta') as unknown as NodeListOf<HTMLMetaElement>;
for (const metaTag of metaTags) {
const name = metaTag.attributes.getNamedItem('name')?.value ?? '';
const content = metaTag.attributes.getNamedItem('content')?.value ?? '';
if (name === 'title') {
metadata.title = content;
} else if (name === 'tags') {
metadata.tags = content ? content.split(",") : [];
} else if (name === 'slug') {
metadata.slug = content;
} else if (name === 'updatedAt') {
metadata.createdAt = content;
} else if (name === 'createdAt') {
metadata.updatedAt = content;
}
}
result.push(metadata);
}
result.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
jsonResponse = result;
jsonResponse = await getBlogEntries();
}
if (!jsonResponse) {
@@ -195,6 +238,13 @@ Deno.serve({
response = await getAPIResponse(req);
}
// RSS
if (response === null) {
if (pathname === '/blog/djblog.rss') {
response = new Response(await rss(), { status: 200 });
}
}
// Public/static files
if (response === null) {
let filepath = join(".", "public", pathname);