Add content to RSS feed items
This commit is contained in:
parent
37db38b613
commit
e859109ade
4 changed files with 172 additions and 18 deletions
128
package-lock.json
generated
128
package-lock.json
generated
|
@ -1,21 +1,23 @@
|
|||
{
|
||||
"name": "gallery-badmanners-xyz",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gallery-badmanners-xyz",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.5.9",
|
||||
"@astrojs/rss": "^4.0.5",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astropub/md": "^0.4.0",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/sanitize-html": "^2.11.0",
|
||||
"astro": "^4.5.4",
|
||||
"github-slugger": "^2.0.0",
|
||||
"marked": "^12.0.1",
|
||||
"sanitize-html": "^2.13.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tiny-decode": "^0.1.3",
|
||||
"typescript": "^5.4.2"
|
||||
|
@ -1370,6 +1372,14 @@
|
|||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/sanitize-html": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
|
||||
"integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==",
|
||||
"dependencies": {
|
||||
"htmlparser2": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
|
||||
|
@ -2402,6 +2412,14 @@
|
|||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
|
@ -2465,6 +2483,57 @@
|
|||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dset": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz",
|
||||
|
@ -3147,6 +3216,24 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1",
|
||||
"entities": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
|
@ -3345,6 +3432,14 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
|
@ -4791,6 +4886,11 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-srcset": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
|
||||
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||
|
@ -6076,6 +6176,30 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/sanitize-html": {
|
||||
"version": "2.13.0",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.13.0.tgz",
|
||||
"integrity": "sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==",
|
||||
"dependencies": {
|
||||
"deepmerge": "^4.2.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"htmlparser2": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"parse-srcset": "^1.0.2",
|
||||
"postcss": "^8.3.11"
|
||||
}
|
||||
},
|
||||
"node_modules/sanitize-html/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/sass-formatter": {
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "gallery-badmanners-xyz",
|
||||
"type": "module",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
|
@ -17,9 +17,11 @@
|
|||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astropub/md": "^0.4.0",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/sanitize-html": "^2.11.0",
|
||||
"astro": "^4.5.4",
|
||||
"github-slugger": "^2.0.0",
|
||||
"marked": "^12.0.1",
|
||||
"sanitize-html": "^2.13.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tiny-decode": "^0.1.3",
|
||||
"typescript": "^5.4.2"
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import rss, { type RSSFeedItem } from "@astrojs/rss";
|
||||
import type { APIRoute } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { getCollection, type CollectionEntry } from "astro:content";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
import { marked } from "marked";
|
||||
import { decode as tinyDecode } from "tiny-decode";
|
||||
import { t } from "../i18n";
|
||||
import type { Lang } from "../content/config";
|
||||
|
||||
type FeedItem = RSSFeedItem & {
|
||||
pubDate: Date;
|
||||
};
|
||||
|
||||
const MAX_ITEMS = 10;
|
||||
const MAX_ITEMS = 8;
|
||||
|
||||
function toNoonUTCDate(date: Date) {
|
||||
const adjustedDate = new Date(date);
|
||||
|
@ -14,6 +19,15 @@ function toNoonUTCDate(date: Date) {
|
|||
return adjustedDate;
|
||||
}
|
||||
|
||||
const getLinkForUser = (user: CollectionEntry<"users">, lang: Lang) => {
|
||||
const userName = user.data.nameLang[lang] || user.data.name;
|
||||
if (user.data.preferredLink) {
|
||||
const link = user.data.links[user.data.preferredLink]!;
|
||||
return `<a href="${typeof link === "string" ? link : link[0]}">${userName}</a>`
|
||||
}
|
||||
return userName;
|
||||
}
|
||||
|
||||
export const GET: APIRoute = async ({ site }) => {
|
||||
const stories = (await getCollection("stories", (story) => !story.data.isDraft))
|
||||
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
|
||||
|
@ -21,30 +35,44 @@ export const GET: APIRoute = async ({ site }) => {
|
|||
const games = (await getCollection("games", (game) => !game.data.isDraft))
|
||||
.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime())
|
||||
.slice(0, MAX_ITEMS);
|
||||
const users = await getCollection("users");
|
||||
|
||||
return rss({
|
||||
title: "Gallery | Bad Manners",
|
||||
description: "Stories, games, and (possibly) more by Bad Manners",
|
||||
site: site as URL,
|
||||
items: [
|
||||
stories.map<FeedItem>((story) => ({
|
||||
title: `New story! "${story.data.title}"`,
|
||||
pubDate: toNoonUTCDate(story.data.pubDate),
|
||||
link: `/stories/${story.slug}`,
|
||||
await Promise.all(stories.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
|
||||
title: `New story! "${data.title}"`,
|
||||
pubDate: toNoonUTCDate(data.pubDate),
|
||||
link: `/stories/${slug}`,
|
||||
description:
|
||||
`Word count: ${story.data.wordCount}. ${story.data.contentWarning} ${story.data.descriptionPlaintext || story.data.description}`
|
||||
`Word count: ${data.wordCount}. ${data.contentWarning} ${data.descriptionPlaintext || data.description}`
|
||||
.replaceAll(/[\n ]+/g, " ")
|
||||
.trim(),
|
||||
categories: ["story"],
|
||||
})),
|
||||
games.map<FeedItem>((game) => ({
|
||||
title: `New game! "${game.data.title}"`,
|
||||
pubDate: toNoonUTCDate(game.data.pubDate),
|
||||
link: `/games/${game.slug}`,
|
||||
description: `${game.data.contentWarning} ${game.data.descriptionPlaintext || game.data.description}`
|
||||
content: sanitizeHtml(`<h1>${data.title}</h1><p>${t(data.lang, "story/authors", [data.authors].flatMap((authorArray => {
|
||||
if (!Array.isArray(authorArray)) {
|
||||
authorArray = [authorArray]
|
||||
}
|
||||
return authorArray.map(author => getLinkForUser(users.find(user => user.id === author.id)!, data.lang));
|
||||
})))}</p>${data.requester ? `<p>${t(data.lang, "export_story/request_for", getLinkForUser(users.find(user => user.id === data.requester!.id)!, data.lang))}</p>` : ""}${data.commissioner ? `<p>${t(data.lang, "export_story/commissioned_by", getLinkForUser(users.find(user => user.id === data.commissioner!.id)!, data.lang))}</p>` : ""}<hr>${tinyDecode(await marked(body))}`),
|
||||
}))),
|
||||
await Promise.all(games.map<Promise<FeedItem>>(async ({ data, slug, body }) => ({
|
||||
title: `New game! "${data.title}"`,
|
||||
pubDate: toNoonUTCDate(data.pubDate),
|
||||
link: `/games/${slug}`,
|
||||
description: `${data.contentWarning} ${data.descriptionPlaintext || data.description}`
|
||||
.replaceAll(/[\n ]+/g, " ")
|
||||
.trim(),
|
||||
categories: ["game"],
|
||||
})),
|
||||
content: sanitizeHtml(`<h1>${data.title}</h1><p>${t(data.lang, "story/authors", [data.authors].flatMap((authorArray => {
|
||||
if (!Array.isArray(authorArray)) {
|
||||
authorArray = [authorArray]
|
||||
}
|
||||
return authorArray.map(author => getLinkForUser(users.find(user => user.id === author.id)!, data.lang));
|
||||
})))}</p><hr>${tinyDecode(await marked(body))}`),
|
||||
}))),
|
||||
]
|
||||
.flat()
|
||||
.sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime())
|
||||
|
|
|
@ -3,7 +3,7 @@ import { type CollectionEntry, getCollection } from "astro:content";
|
|||
import { Image } from "astro:assets";
|
||||
import GalleryLayout from "../layouts/GalleryLayout.astro";
|
||||
|
||||
const MAX_ITEMS = 5;
|
||||
const MAX_ITEMS = 8;
|
||||
|
||||
interface LatestItemsEntry {
|
||||
type: string;
|
||||
|
|
Loading…
Add table
Reference in a new issue