From fbd1b61458d12ac016679f6d09eea219bba29ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Carlos=20Manzanero=20Dom=C3=ADnguez?= Date: Tue, 25 Jun 2024 11:46:34 -0600 Subject: [PATCH] fix rss images --- package.json | 3 + pnpm-lock.yaml | 77 +++++++++++ .../blog/rewind-2023-and-future-plans.mdx | 2 +- src/pages/rss.xml.js | 50 ------- src/pages/rss.xml.ts | 125 ++++++++++++++++++ 5 files changed, 206 insertions(+), 51 deletions(-) delete mode 100644 src/pages/rss.xml.js create mode 100644 src/pages/rss.xml.ts diff --git a/package.json b/package.json index de79fcb..783936e 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30a7b95..57f8466 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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: {} diff --git a/src/content/blog/rewind-2023-and-future-plans.mdx b/src/content/blog/rewind-2023-and-future-plans.mdx index 380e2b4..d1069ad 100644 --- a/src/content/blog/rewind-2023-and-future-plans.mdx +++ b/src/content/blog/rewind-2023-and-future-plans.mdx @@ -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) diff --git a/src/pages/rss.xml.js b/src/pages/rss.xml.js deleted file mode 100644 index 0a0cefb..0000000 --- a/src/pages/rss.xml.js +++ /dev/null @@ -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: `en-us${new Date()}`, - site: context.site, - items, - }); -} diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts new file mode 100644 index 0000000..df99679 --- /dev/null +++ b/src/pages/rss.xml.ts @@ -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: `en-us`, + site: context.site, + items, + trailingSlash: false, + }); +}