matrix-art

An image gallery for Matrix
git clone git://archive.git.mtrnord.blog/MTRNord/matrix-art.git
Log | Files | Refs | README | LICENSE

commit 33d644c63fbe199711c692badcc7753737b2be45
parent 238dbfec1df6e137de1326423c598210f653e5e5
Author: MTRNord <mtrnord1@gmail.com>
Date:   Fri, 14 Jan 2022 19:55:44 +0100

Add very basic rss feed support

Diffstat:
Mnext.config.js | 9+++++++++
Mpackage-lock.json | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mpackage.json | 1+
Mpages/api/directory.tsx | 1-
Apages/api/posts/feed.rss.ts | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 183 insertions(+), 1 deletion(-)

diff --git a/next.config.js b/next.config.js @@ -36,4 +36,13 @@ module.exports = { eslint: { dirs: ['pages', 'components', "helpers", "e2e"], }, + async redirects() { + return [ + { + source: '/posts.rss', + destination: '/api/posts/feed.rss', + permanent: false, + }, + ] + }, } diff --git a/package-lock.json b/package-lock.json @@ -7,6 +7,7 @@ "name": "matrix-art", "dependencies": { "cors": "^2.8.5", + "feed": "^4.2.2", "lightgallery": "^2.3.0", "meilisearch": "^0.23.0", "next": "12.0.7", @@ -4465,6 +4466,17 @@ "pend": "~1.2.0" } }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/fetch-cookie": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.10.1.tgz", @@ -7490,6 +7502,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -8520,6 +8537,17 @@ } } }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -11959,6 +11987,14 @@ "pend": "~1.2.0" } }, + "feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "requires": { + "xml-js": "^1.6.11" + } + }, "fetch-cookie": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.10.1.tgz", @@ -14170,6 +14206,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -14976,6 +15017,14 @@ "dev": true, "requires": {} }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "cors": "^2.8.5", + "feed": "^4.2.2", "lightgallery": "^2.3.0", "meilisearch": "^0.23.0", "next": "12.0.7", diff --git a/pages/api/directory.tsx b/pages/api/directory.tsx @@ -8,7 +8,6 @@ const db = new PouchDB(path.join(process.cwd(), "matrix-art-db")); // Initialize the cors middleware const cors = initMiddleware( - // You can read more about the available options here: https://github.com/expressjs/cors#configuration-options Cors({ // Only allow requests with GET, POST, DELETE and OPTIONS methods: ['GET', 'POST', 'DELETE', 'OPTIONS'], diff --git a/pages/api/posts/feed.rss.ts b/pages/api/posts/feed.rss.ts @@ -0,0 +1,123 @@ +import initMiddleware from "../../../helpers/init-middleware"; +import Cors from 'cors'; +import { NextApiRequest, NextApiResponse } from "next"; +import { Feed } from "feed"; +import { get_data } from "../directory"; +import { client } from "../../../components/ClientContext"; +import { constMatrixArtServer } from "../../../helpers/matrix_client"; +import { MatrixImageEvents } from "../../../helpers/event_types"; +import { isImageGalleryEvent } from "../../../components/FrontPageImage"; + +// Initialize the cors middleware +const cors = initMiddleware( + Cors({ + // Only allow requests with GET and OPTIONS + methods: ['GET', 'OPTIONS'], + }) +); + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + // Run cors + await cors(req, res); + + if (req.method !== "GET") { + res.status(504); + } + + res.setHeader("content-type", "application/rss+xml"); + const feed = new Feed({ + title: "Matrix-Art", + description: "Matrix-Art is a Devianart style application for posting media based on Matrix.", + id: "https://" + (req.headers.host || "art.midnightthoughts.space"), + link: "https://" + (req.headers.host || "art.midnightthoughts.space"), + language: "en", + copyright: "", + feed: "https://" + (req.headers.host || "art.midnightthoughts.space") + "/posts.rss" + }); + + try { + const directory = await get_data(); + + if (!client?.accessToken) { + try { + let serverUrl = constMatrixArtServer + "/_matrix/client"; + await client?.registerAsGuest(serverUrl); + } catch (error) { + console.error("Failed to register as guest:", error); + return { + props: { + image_events: [] + } + }; + } + } + let image_events: MatrixImageEvents[] = []; + // TODO fix this somehow. It is super inefficent. + for (let user of directory) { + // We dont need many events + const roomId = await client?.followUser(user.user_room); + const events = await client?.getTimeline(roomId, 100); + // Filter events by type + let images = events.filter((event) => event.type == "m.image_gallery" || event.type == "m.image") as MatrixImageEvents[]; + images = await Promise.all(images.map(async (image) => { + try { + const profile = await client.getProfile(image.sender); + image.content.displayname = profile.displayname; + } catch { + image.content.displayname = image.sender; + } + return image; + })); + image_events = [...image_events, ...images]; + console.log("Adding", image_events.length, "items"); + } + + for (let imageEvent of image_events) { + feed.addContributor({ + name: imageEvent.content.displayname + }); + if (isImageGalleryEvent(imageEvent)) { + for (let image of imageEvent.content["m.image_gallery"]) { + feed.addItem({ + title: image["m.text"], + id: "https://" + (req.headers.host || "art.midnightthoughts.space") + "/post/" + imageEvent.event_id + "_" + image["m.file"].url, + link: "https://" + (req.headers.host || "art.midnightthoughts.space") + "/post/" + imageEvent.event_id, + description: "", + content: "", + author: [ + { + name: imageEvent.content.displayname, + } + ], + // TODO extract real time + date: new Date(), + image: client?.downloadLink(image["m.file"].url) + }); + } + } else { + feed.addItem({ + title: imageEvent.content["m.text"], + id: "https://" + (req.headers.host || "art.midnightthoughts.space") + "/post/" + imageEvent.event_id, + link: "https://" + (req.headers.host || "art.midnightthoughts.space") + "/post/" + imageEvent.event_id, + description: "", + content: "", + author: [ + { + name: imageEvent.content.displayname, + } + ], + date: new Date(), + image: client?.downloadLink(imageEvent.content["m.file"].url) + }); + } + + } + + } catch { } + + feed.addCategory("Photography"); + feed.addCategory("Media"); + feed.addCategory("Images"); + feed.addCategory("SocialMedia"); + res.status(200).send(feed.atom1()); +} +\ No newline at end of file