matrix-art

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

commit e11757fd021a22f0e1796cd4624fc09c8fceeb90
parent e97078a1c13588cc2878dc2c6d84662fd2273805
Author: MTRNord <mtrnord1@gmail.com>
Date:   Fri, 31 Dec 2021 11:40:35 +0100

Prerender posts

Diffstat:
M.gitignore | 2+-
Mhelpers/storage.ts | 14++++++++++++++
Mpackage-lock.json | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpackage.json | 2++
Mpages/Home.tsx | 9++++-----
Mpages/post/[id].tsx | 64+++++++++++++++++++++++++++++++++++++++++++++++++++-------------
6 files changed, 157 insertions(+), 22 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -38,7 +38,7 @@ yarn-error.log* #pouchdb /matrix-art-db - +/localstorage #nextjs .env.*.local .env.local \ No newline at end of file diff --git a/helpers/storage.ts b/helpers/storage.ts @@ -1,19 +1,33 @@ export default class Storage { + private nodeLocalStorage?; + constructor() { + if (typeof window === "undefined") { + var LocalStorage = require('node-localstorage').LocalStorage; + var path = require('path'); + this.nodeLocalStorage = new LocalStorage(path.join(process.cwd(), "localstorage")); + } + } getItem(key: string): any { if (typeof window !== "undefined") { return window.localStorage.getItem(key); + } else { + return this.nodeLocalStorage?.getItem(key); } } setItem(key: string, value: any): any { if (typeof window !== "undefined") { return window.localStorage.setItem(key, value); + } else { + return this.nodeLocalStorage?.setItem(key, value); } } removeItem(key: string): any { if (typeof window !== "undefined") { return window.localStorage.removeItem(key); + } else { + return this.nodeLocalStorage?.removeItem(key); } } diff --git a/package-lock.json b/package-lock.json @@ -8,6 +8,7 @@ "dependencies": { "cors": "^2.8.5", "next": "12.0.7", + "node-localstorage": "^2.2.1", "pouchdb": "^7.2.2", "react": "17.0.2", "react-dom": "17.0.2", @@ -18,6 +19,7 @@ "@emotion/babel-plugin": "^11.7.2", "@types/cors": "^2.8.12", "@types/node": "17.0.5", + "@types/node-localstorage": "^1.3.0", "@types/pouchdb": "^6.4.0", "@types/react": "17.0.38", "autoprefixer": "^10.4.0", @@ -1413,6 +1415,12 @@ "@types/ms": "*" } }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1430,6 +1438,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz", "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==" }, + "node_modules/@types/node-localstorage": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/node-localstorage/-/node-localstorage-1.3.0.tgz", + "integrity": "sha512-9+s5CWGhkYitklhLgnbf4s5ncCEx0An2jhBuhvw/sh9WNQ+/WvNFkPLyLjXGy+Oeo8CjPl69oz6M2FzZH+KwWA==", + "dev": true, + "dependencies": { + "@types/events": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -4249,7 +4266,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, "engines": { "node": ">=0.8.19" } @@ -5172,6 +5188,17 @@ "he": "1.2.0" } }, + "node_modules/node-localstorage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.2.1.tgz", + "integrity": "sha512-vv8fJuOUCCvSPjDjBLlMqYMHob4aGjkmrkaE42/mZr0VT+ZAU10jRF8oTnX9+pgU9/vYJ8P7YT3Vd6ajkmzSCw==", + "dependencies": { + "write-file-atomic": "^1.1.4" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/node-releases": { "version": "1.1.77", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", @@ -6153,6 +6180,14 @@ "node": ">=8" } }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "engines": { + "node": "*" + } + }, "node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -6897,6 +6932,16 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "node_modules/write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, "node_modules/write-stream": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz", @@ -7965,6 +8010,12 @@ "@types/ms": "*" } }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -7982,6 +8033,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz", "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==" }, + "@types/node-localstorage": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/node-localstorage/-/node-localstorage-1.3.0.tgz", + "integrity": "sha512-9+s5CWGhkYitklhLgnbf4s5ncCEx0An2jhBuhvw/sh9WNQ+/WvNFkPLyLjXGy+Oeo8CjPl69oz6M2FzZH+KwWA==", + "dev": true, + "requires": { + "@types/events": "*" + } + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -10183,8 +10243,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "inflight": { "version": "1.0.6", @@ -10862,6 +10921,14 @@ "he": "1.2.0" } }, + "node-localstorage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.2.1.tgz", + "integrity": "sha512-vv8fJuOUCCvSPjDjBLlMqYMHob4aGjkmrkaE42/mZr0VT+ZAU10jRF8oTnX9+pgU9/vYJ8P7YT3Vd6ajkmzSCw==", + "requires": { + "write-file-atomic": "^1.1.4" + } + }, "node-releases": { "version": "1.1.77", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", @@ -11572,6 +11639,11 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + }, "source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -12147,6 +12219,16 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, "write-stream": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz", diff --git a/package.json b/package.json @@ -11,6 +11,7 @@ "dependencies": { "cors": "^2.8.5", "next": "12.0.7", + "node-localstorage": "^2.2.1", "pouchdb": "^7.2.2", "react": "17.0.2", "react-dom": "17.0.2", @@ -21,6 +22,7 @@ "@emotion/babel-plugin": "^11.7.2", "@types/cors": "^2.8.12", "@types/node": "17.0.5", + "@types/node-localstorage": "^1.3.0", "@types/pouchdb": "^6.4.0", "@types/react": "17.0.38", "autoprefixer": "^10.4.0", diff --git a/pages/Home.tsx b/pages/Home.tsx @@ -50,10 +50,7 @@ export default class Home extends Component<Props, State>{ async componentDidMount() { // auto-register as a guest if not logged in if (!this.context.client?.accessToken) { - // Client-side-only code - if (typeof window !== "undefined") { - this.registerAsGuest(); - } + this.registerAsGuest(); } else { console.log("Already logged in"); try { @@ -72,7 +69,9 @@ export default class Home extends Component<Props, State>{ try { let serverUrl = constMatrixArtServer + "/_matrix/client"; await this.context.client?.registerAsGuest(serverUrl); - window.location.reload(); + if (typeof window !== "undefined") { + window.location.reload(); + } } catch (err) { console.error("Failed to register as guest:", err); this.setState({ diff --git a/pages/post/[id].tsx b/pages/post/[id].tsx @@ -6,6 +6,7 @@ import { ClientContext } from "../../components/ClientContext"; import Header from "../../components/Header"; import { ImageEvent, ImageGalleryEvent, MatrixEventBase, MatrixImageEvents } from "../../helpers/event_types"; import { constMatrixArtServer } from "../../helpers/matrix_client"; +import { get_data } from "../api/directory"; import { isImageEvent, isImageGalleryEvent } from "../Home"; const centerSpinner = ` @@ -48,8 +49,30 @@ class Post extends Component<Props, State> { } } - // TODO make getStaticPaths and get this properly prerendered. (Needs to make the client not use localstorage. Aka figure out pouchdb) - async handleRouteChangeComplete(url: string, { shallow }: any) { + async getStaticPaths() { + const directory_data = await get_data(); + let paths: { params: { id: string; }; }[] = []; + for (let user of directory_data) { + // We dont need many events + const roomId = await this.context.client?.followUser(user.user_room); + await this.context.client?.getTimeline(roomId, 100, (events) => { + // Filter events by type + const image_events = events.filter((event) => event.type == "m.image_gallery" || event.type == "m.image"); + for (let event of image_events) { + const path_non_encoded = { params: { id: event.event_id } }; + const path = { params: { id: encodeURIComponent(event.event_id) } }; + paths.push(path); + } + }); + } + return { + paths: paths, + fallback: 'blocking' + }; + } + + + async componentDidMount() { const { id } = this.props.router.query; console.log(`id: ${id}`); console.log(`is ready: ${this.props.router.isReady}`); @@ -58,10 +81,7 @@ class Post extends Component<Props, State> { if (event_id && event_id.startsWith("$")) { // auto-register as a guest if not logged in if (!this.context.client?.accessToken) { - // Client-side-only code - if (typeof window !== "undefined") { - this.registerAsGuest(); - } + this.registerAsGuest(); } else { console.log("Already logged in"); try { @@ -77,20 +97,38 @@ class Post extends Component<Props, State> { } } - componentDidMount() { - // Hack due to SSR - this.props.router.events.on("routeChangeComplete", this.handleRouteChangeComplete.bind(this)); - } + async componentWillUnmount() { + const { id } = this.props.router.query; + console.log(`id: ${id}`); + console.log(`is ready: ${this.props.router.isReady}`); + const event_id = decodeURIComponent(id as string); - componentWillUnmount() { - this.props.router.events.off("routeChangeComplete", this.handleRouteChangeComplete.bind(this)); + if (event_id && event_id.startsWith("$")) { + // auto-register as a guest if not logged in + if (!this.context.client?.accessToken) { + this.registerAsGuest(); + } else { + console.log("Already logged in"); + try { + const data = await (await fetch('/api/directory')).json(); + this.setState({ event_id: event_id, directory_data: data.data, directoryIsLoaded: true }); + } catch (error) { + this.setState({ + hasFullyLoaded: true, + error + }); + } + } + } } async registerAsGuest() { try { let serverUrl = constMatrixArtServer + "/_matrix/client"; await this.context.client?.registerAsGuest(serverUrl); - window.location.reload(); + if (typeof window !== "undefined") { + window.location.reload(); + } } catch (err) { console.error("Failed to register as guest:", err); this.setState({