Skip to content

Commit 18e6992

Browse files
update rss rendering
1 parent a8a2436 commit 18e6992

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

src/pages/rss.xml.js

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,61 @@ import { site, i18n } from 'astro:config/client';
66

77
const blog = (await getCollection('blog')).sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
88
const parser = new MarkdownIt();
9+
const wikiImagePattern = /!\[\[([^\]]+)\]\]/g;
10+
const iframePattern = /<iframe[^>]*src=["']([^"']+)["'][^>]*>.*?<\/iframe>/gi;
11+
12+
function isFullyQualifiedUrl(value) {
13+
try {
14+
const parsed = new URL(value);
15+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
16+
}
17+
catch {
18+
return false;
19+
}
20+
}
21+
22+
function normalizeRssContent(markdown) {
23+
const withWikiEmbedsHandled = markdown.replaceAll(wikiImagePattern, (_, rawTarget) => {
24+
const [target] = rawTarget.split('|');
25+
const cleanedTarget = target.trim();
26+
27+
if (!isFullyQualifiedUrl(cleanedTarget)) {
28+
return '[Embedded Image]';
29+
}
30+
31+
return `![Embedded Image](${cleanedTarget})`;
32+
});
33+
34+
return withWikiEmbedsHandled.replaceAll(iframePattern, '[Note: Embedded content from $1]');
35+
}
36+
37+
function sanitizeRssHtml(html) {
38+
return sanitizeHtml(html, {
39+
allowedTags: sanitizeHtml.defaults.allowedTags.concat('img'),
40+
allowedAttributes: {
41+
...sanitizeHtml.defaults.allowedAttributes,
42+
img: ['src', 'alt', 'title'],
43+
},
44+
transformTags: {
45+
img: (_, attribs) => {
46+
const src = attribs.src?.trim();
47+
48+
if (!src || !isFullyQualifiedUrl(src)) {
49+
return { tagName: 'span', text: '[Embedded Image]' };
50+
}
51+
52+
return {
53+
tagName: 'img',
54+
attribs: {
55+
src,
56+
alt: attribs.alt || 'Embedded Image',
57+
...(attribs.title ? { title: attribs.title } : {}),
58+
},
59+
};
60+
},
61+
},
62+
});
63+
}
964

1065
export async function GET(context) {
1166
return rss({
@@ -26,7 +81,7 @@ export async function GET(context) {
2681
description: post.data.description,
2782
link: `/blog/${post.slug}/`,
2883
pubDate: post.data.pubDate,
29-
content: sanitizeHtml(parser.render(post.body.replaceAll(/!\[\[([^\]]+)\]\]/g, '[Embedded Image]').replaceAll(/<iframe[^>]*src=["']([^"']+)["'][^>]*>.*?<\/iframe>/gi, '[Note: Embedded content from $1]'))),
84+
content: sanitizeRssHtml(parser.render(normalizeRssContent(post.body))),
3085
})),
3186
});
32-
}
87+
}

0 commit comments

Comments
 (0)