diff --git a/Dockerfile b/Dockerfile index c050c39..52a4203 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,7 @@ COPY tsconfig.json \ webpack.config.js \ .babelrc \ generate_translations.mjs \ + generate_rss_feed.mjs \ tailwind.config.js \ ./ diff --git a/generate_rss_feed.mjs b/generate_rss_feed.mjs new file mode 100644 index 0000000..934168c --- /dev/null +++ b/generate_rss_feed.mjs @@ -0,0 +1,63 @@ +import fs from "fs-extra"; +import MarkdownIt from "markdown-it"; +import { Builder } from "xml2js"; + +async function generateRSSFeed() { + const md = new MarkdownIt(); + const posts = []; + const files = await fs.readdir("./src/assets/news"); // a folder with markdown files + const newestFirstFiles = Array.from(files).reverse(); + + for (const file of newestFirstFiles) { + if (file.endsWith(".md")) { + const content = await fs.readFile(`./src/assets/news/${file}`, "utf8"); + const lines = content.split("\n"); + const title = lines[0].replace(/^# /, ""); + const dateFromFileName = file.slice(0, 10); + const date = new Date(dateFromFileName).toUTCString(); + const htmlContent = md.render(content); + const link = `https://join-lemmy.org/news/${file + .replace(".md", "") + .replaceAll(" ", "_")}`; + + posts.push({ title, date, content: htmlContent, link }); + } + } + + const rss = { + rss: { + $: { + version: "2.0", + "xmlns:atom": "http://www.w3.org/2005/Atom", + }, + channel: [ + { + "atom:link": { + $: { + href: "https://join-lemmy.org/feed.xml", + rel: "self", + type: "application/rss+xml", + }, + }, + title: "join-lemmy.org News", + link: "https://join-lemmy.org/", + description: "News about Lemmy, a link aggregator for the fediverse.", + item: posts.map(post => ({ + title: post.title, + link: post.link, + description: post.content, + pubDate: post.date, + guid: post.link, + })), + }, + ], + }, + }; + + const builder = new Builder(); + const xml = builder.buildObject(rss); + + await fs.writeFile("./dist/feed.xml", xml); +} + +generateRSSFeed().then(() => console.log("RSS feed generated successfully.")); diff --git a/package.json b/package.json index f3bb616..0cfebe9 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,9 @@ "crawl": "node crawl.mjs", "update-donations": "node update_donations.mjs", "lint": "node generate_translations.mjs && tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check \"src/**/*.{ts,tsx,js,css,scss}\"", - "prebuild:dev": "yarn clean && node generate_translations.mjs && yarn tailwind", - "prebuild:prod": "yarn clean && node generate_translations.mjs && yarn tailwind", + "prebuild:dev": "yarn clean && node generate_translations.mjs && yarn tailwind && yarn generate_rss_feed", + "prebuild:prod": "yarn clean && node generate_translations.mjs && yarn tailwind && yarn generate_rss_feed", + "generate_rss_feed": "node generate_rss_feed.mjs", "tailwind": "tailwindcss -i ./src/style.css -o ./dist/styles/styles.css --minify", "prepare": "husky install", "start": "yarn build:dev --watch & yarn tailwind --watch" @@ -35,6 +36,7 @@ "countries-list": "^3.0.6", "daisyui": "^3.9.4", "express": "~4.18.2", + "fs-extra": "^11.2.0", "i18next": "^23.6.0", "inferno": "^8.2.2", "inferno-create-element": "^8.2.2", @@ -50,7 +52,8 @@ "tailwindcss": "^3.3.5", "webpack": "5.89.0", "webpack-cli": "^5.1.4", - "webpack-node-externals": "^3.0.0" + "webpack-node-externals": "^3.0.0", + "xml2js": "^0.6.2" }, "devDependencies": { "@types/express": "^4.17.20", diff --git a/src/assets/images/rss.svg b/src/assets/images/rss.svg new file mode 100644 index 0000000..659268c --- /dev/null +++ b/src/assets/images/rss.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/server/index.tsx b/src/server/index.tsx index 83929ad..98c1bc3 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -17,6 +17,7 @@ server.use(express.urlencoded({ extended: false }) as RequestHandler); server.use("/static", express.static(path.resolve("./dist"))); server.use("/docs", express.static(path.resolve("./dist/assets/docs"))); server.use("/api", express.static(path.resolve("./dist/assets/api"))); +server.use("/feed.xml", express.static(path.resolve("./dist/feed.xml"))); function erudaInit(): string { if (process.env["NODE_ENV"] == "development") { diff --git a/src/shared/components/main.tsx b/src/shared/components/main.tsx index 52af6dd..6d36a61 100644 --- a/src/shared/components/main.tsx +++ b/src/shared/components/main.tsx @@ -490,6 +490,12 @@ export class Main extends Component { + ( -
{title}
+
+ {title} + + + +
); const NewsCards = () => buildNewsInfoArray().map(n => ); @@ -99,6 +104,12 @@ export class News extends Component {
+ diff --git a/yarn.lock b/yarn.lock index dec6b03..cb86fd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3949,6 +3949,15 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-extra@^11.2.0: + version "11.2.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" + integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-minipass@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" @@ -4236,6 +4245,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== +graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@~4.1.11: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -5121,6 +5135,15 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -7400,6 +7423,11 @@ sass@^1.69.5: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" +sax@>=0.6.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" @@ -8393,6 +8421,11 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -8799,6 +8832,19 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xml2js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" + integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"