fix rss images

This commit is contained in:
Juan Carlos Manzanero Domínguez 2024-06-25 11:46:34 -06:00
parent ecca2bf614
commit fbd1b61458
5 changed files with 206 additions and 51 deletions

View File

@ -28,6 +28,7 @@
"fast-glob": "^3.3.2",
"lucide-react": "^0.396.0",
"markdown-it": "^14.1.0",
"node-html-parser": "^6.1.13",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
@ -41,6 +42,8 @@
"typescript": "^5.5.2"
},
"devDependencies": {
"@types/markdown-it": "^14.1.1",
"@types/sanitize-html": "^2.11.0",
"pocketbase": "^0.21.3"
}
}

77
pnpm-lock.yaml generated
View File

@ -62,6 +62,9 @@ importers:
markdown-it:
specifier: ^14.1.0
version: 14.1.0
node-html-parser:
specifier: ^6.1.13
version: 6.1.13
react:
specifier: ^18.3.1
version: 18.3.1
@ -96,6 +99,12 @@ importers:
specifier: ^5.5.2
version: 5.5.2
devDependencies:
'@types/markdown-it':
specifier: ^14.1.1
version: 14.1.1
'@types/sanitize-html':
specifier: ^2.11.0
version: 2.11.0
pocketbase:
specifier: ^0.21.3
version: 0.21.3
@ -932,9 +941,18 @@ packages:
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/markdown-it@14.1.1':
resolution: {integrity: sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==}
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/mdx@2.0.13':
resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
@ -956,6 +974,9 @@ packages:
'@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
'@types/sanitize-html@2.11.0':
resolution: {integrity: sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==}
'@types/unist@2.0.10':
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
@ -1139,6 +1160,9 @@ packages:
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
boxen@7.1.1:
resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==}
engines: {node: '>=14.16'}
@ -1285,6 +1309,13 @@ packages:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
css-select@5.1.0:
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
css-what@6.1.0:
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
engines: {node: '>= 6'}
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@ -1610,6 +1641,10 @@ packages:
hastscript@8.0.0:
resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==}
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
html-escaper@3.0.3:
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
@ -2106,6 +2141,9 @@ packages:
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
hasBin: true
node-html-parser@6.1.13:
resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
@ -2130,6 +2168,9 @@ packages:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
deprecated: This package is no longer supported.
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@ -3870,10 +3911,19 @@ snapshots:
dependencies:
'@types/unist': 3.0.2
'@types/linkify-it@5.0.0': {}
'@types/markdown-it@14.1.1':
dependencies:
'@types/linkify-it': 5.0.0
'@types/mdurl': 2.0.0
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 3.0.2
'@types/mdurl@2.0.0': {}
'@types/mdx@2.0.13': {}
'@types/ms@0.7.34': {}
@ -3897,6 +3947,10 @@ snapshots:
'@types/prop-types': 15.7.12
csstype: 3.1.3
'@types/sanitize-html@2.11.0':
dependencies:
htmlparser2: 8.0.2
'@types/unist@2.0.10': {}
'@types/unist@3.0.2': {}
@ -4176,6 +4230,8 @@ snapshots:
dependencies:
file-uri-to-path: 1.0.0
boolbase@1.0.0: {}
boxen@7.1.1:
dependencies:
ansi-align: 3.0.1
@ -4315,6 +4371,16 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
css-select@5.1.0:
dependencies:
boolbase: 1.0.0
css-what: 6.1.0
domhandler: 5.0.3
domutils: 3.1.0
nth-check: 2.1.1
css-what@6.1.0: {}
cssesc@3.0.0: {}
csstype@3.1.3: {}
@ -4741,6 +4807,8 @@ snapshots:
property-information: 6.5.0
space-separated-tokens: 2.0.2
he@1.2.0: {}
html-escaper@3.0.3: {}
html-url-attributes@3.0.0: {}
@ -5448,6 +5516,11 @@ snapshots:
node-gyp-build@4.8.1: {}
node-html-parser@6.1.13:
dependencies:
css-select: 5.1.0
he: 1.2.0
node-releases@2.0.14: {}
nopt@5.0.0:
@ -5469,6 +5542,10 @@ snapshots:
gauge: 3.0.2
set-blocking: 2.0.0
nth-check@2.1.1:
dependencies:
boolbase: 1.0.0
object-assign@4.1.1: {}
object-hash@3.0.0: {}

View File

@ -106,4 +106,4 @@ overwhelming myself, I'll keep my **ambitions simple**, but **constant**.
### Happy holidays!
![2023 complete image!](/blog/rewind-2023-and-future-plans/2023-complete!.png)
![2023 complete image!](@/assets/blog/rewind-2023-and-future-plans/2023-complete!.png)

View File

@ -1,50 +0,0 @@
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";
import sanitizeHtml from "sanitize-html";
import MarkdownIt from "markdown-it";
const parser = new MarkdownIt();
export async function GET(context) {
const blog = await getCollection(
"blog",
({ data }) => data.draft !== true && data.rss === true,
);
const portfolio = await getCollection(
"portfolio",
({ data }) => data.draft !== true && data.rss === true,
);
const blogItems = blog.map((post) => ({
title: post.data.title,
pubDate: post.data.date,
description: post.data.description,
tags: post.data.tags,
author: post.data.author,
link: `/blog/${post.slug}/`,
content: sanitizeHtml(parser.render(post.body), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}),
}));
const portfolioItems = portfolio.map((project) => ({
title: project.data.title,
pubDate: project.data.date,
description: project.data.description,
tags: project.data.tags,
author: project.data.author,
link: `/portfolio/${project.slug}/`,
content: sanitizeHtml(parser.render(project.body), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}),
}));
const items = [...blogItems, ...portfolioItems];
return rss({
title: "juancmandev",
description: "Welcome to my domain, stranger.",
customData: `<language>en-us</language><lastBuildDate>${new Date()}</lastBuildDate>`,
site: context.site,
items,
});
}

125
src/pages/rss.xml.ts Normal file
View File

@ -0,0 +1,125 @@
import rss from "@astrojs/rss";
import type { RSSFeedItem } from "@astrojs/rss";
import { getCollection } from "astro:content";
import sanitizeHtml from "sanitize-html";
import MarkdownIt from "markdown-it";
import { parse as htmlParser } from "node-html-parser";
import { getImage } from "astro:assets";
import type { ImageMetadata } from "astro";
const markdownParser = new MarkdownIt();
const imagesBlog = import.meta.glob<{ default: ImageMetadata }>(
"/src/assets/blog/**/**/*.{jpeg,jpg,png,gif,webp}",
);
const imagesPortfolio = import.meta.glob<{ default: ImageMetadata }>(
"/src/assets/portfolio/**/**/*.{jpeg,jpg,png,gif,webp}",
);
export async function GET(context: any) {
const items: RSSFeedItem[] = [];
const blog = await getCollection(
"blog",
({ data }) => data.draft !== true && data.rss === true,
);
const portfolio = await getCollection(
"portfolio",
({ data }) => data.draft !== true && data.rss === true,
);
for await (const post of blog) {
const body = markdownParser.render(post.body);
const html = htmlParser.parse(body);
const images = html.querySelectorAll("img");
for await (const img of images) {
const src = img.getAttribute("src")!;
console.log(src);
if (src.startsWith("@/")) {
const prefixRemoved = src.replace("@/", "");
const imagePathPrefix = `/src/${prefixRemoved}`;
const imagePath = await imagesBlog[imagePathPrefix]?.()?.then(
(res: any) => res.default,
);
if (imagePath) {
const optimizedImg = await getImage({ src: imagePath });
img.setAttribute(
"src",
context.site + optimizedImg.src.replace("/", ""),
);
}
} else if (src.startsWith("/images")) {
img.setAttribute("src", context.site + src.replace("/", ""));
} else {
throw Error("src unknown");
}
}
items.push({
title: post.data.title,
pubDate: post.data.date,
description: post.data.description,
author: post.data.author,
link: `/blog/${post.slug}/`,
content: sanitizeHtml(html.toString(), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}),
});
}
for await (const project of portfolio) {
const body = markdownParser.render(project.body);
const html = htmlParser.parse(body);
const images = html.querySelectorAll("img");
for await (const img of images) {
const src = img.getAttribute("src")!;
if (src.startsWith("@/")) {
const prefixRemoved = src.replace("@/", "");
const imagePathPrefix = `/src/${prefixRemoved}`;
const imagePath = await imagesPortfolio[imagePathPrefix]?.()?.then(
(res: any) => res.default,
);
if (imagePath) {
const optimizedImg = await getImage({ src: imagePath });
img.setAttribute(
"src",
context.site + optimizedImg.src.replace("/", ""),
);
}
} else if (src.startsWith("/images")) {
// images starting with `/images/` is the public dir
img.setAttribute("src", context.site + src.replace("/", ""));
} else {
throw Error("src unknown");
}
}
items.push({
title: project.data.title,
pubDate: project.data.date,
description: project.data.description,
author: project.data.author,
link: `/portfolio/${project.slug}/`,
content: sanitizeHtml(html.toString(), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}),
});
}
console.log(items);
return rss({
title: "juancmandev",
description: "Welcome to my domain, stranger.",
customData: `<language>en-us</language>`,
site: context.site,
items,
trailingSlash: false,
});
}