From f5c7b6f55ff50eaf33bfa25f97e89528b63e7bf1 Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 11:50:34 -0700 Subject: [PATCH 01/37] feat: :zap: cache server --- .config/example.yml | 14 ++++++++++++++ README.md | 9 ++++++++- packages/backend/src/config/types.ts | 10 ++++++++++ packages/backend/src/db/redis.ts | 20 ++++++++++++-------- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/.config/example.yml b/.config/example.yml index 51d380e7e..ba74df8a5 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -67,6 +67,20 @@ redis: #db: 1 #user: default +# ┌─────────────────────────────┐ +#───┘ Cache server configuration └───────────────────────────────────── + +# A Redis-compatible server (DragonflyDB, Keydb, Redis) for caching +# If left blank, it will use the Redis server from above + +#cacheServer: + #host: localhost + #port: 6379 + #family: 0 # 0=Both, 4=IPv4, 6=IPv6 + #pass: example-pass + #prefix: example-prefix + #db: 1 + # Please configure either MeiliSearch *or* Sonic. # If both MeiliSearch and Sonic configurations are present, MeiliSearch will take precedence. diff --git a/README.md b/README.md index f66d14a32..0ad935667 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,10 @@ If you have access to a server that supports one of the sources below, I recomme - 🦔 [Sonic](https://crates.io/crates/sonic-server) - [MeiliSearch](https://www.meilisearch.com/) - [ElasticSearch](https://www.elastic.co/elasticsearch/) - +- Caching server + - 🐲 At least [Dragonfly](https://www.dragonflydb.io/) v1.4.0 (recommended) + - 👻 [KeyDB](https://keydb.dev/) (untested) + - 🍱 Another [Redis](https://redis.io/) server, at least v6 ### 🏗️ Build dependencies - 🦀 At least [Rust](https://www.rust-lang.org/) v1.68.0 @@ -161,6 +164,10 @@ psql postgres -c "create database calckey with encoding = 'UTF8';" In Calckey's directory, fill out the `db` section of `.config/default.yml` with the correct information, where the `db` key is `calckey`. +## 💰 Caching server + +If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll falll back to the mandatory Redis server. + ## 🔎 Set up search ### 🦔 Sonic diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index 84808413c..43168662c 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -26,6 +26,16 @@ export type Source = { user?: string; tls?: { [y: string]: string }; }; + cacheServer: { + host: string; + port: number; + family?: number; + pass?: string; + db?: number; + prefix?: string; + user?: string; + tls?: { [z: string]: string }; + }; elasticsearch: { host: string; port: number; diff --git a/packages/backend/src/db/redis.ts b/packages/backend/src/db/redis.ts index a1f3279f3..215effd8e 100644 --- a/packages/backend/src/db/redis.ts +++ b/packages/backend/src/db/redis.ts @@ -2,15 +2,19 @@ import Redis from "ioredis"; import config from "@/config/index.js"; export function createConnection() { + let source = config.redis; + if (config.cacheServer) { + source = config.cacheServer; + } return new Redis({ - port: config.redis.port, - host: config.redis.host, - family: config.redis.family ?? 0, - password: config.redis.pass, - username: config.redis.user ?? "default", - keyPrefix: `${config.redis.prefix}:`, - db: config.redis.db || 0, - tls: config.redis.tls, + port: source.port, + host: source.host, + family: source.family ?? 0, + password: source.pass, + username: source.user ?? "default", + keyPrefix: `${source.prefix}:`, + db: source.db || 0, + tls: source.tls, }); } From 4d7a85b1a66e3ad253360c216be55225d1ec548a Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 11:52:48 -0700 Subject: [PATCH 02/37] docs: :memo: dragonfly flag --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0ad935667..d66560d0e 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,8 @@ If you have access to a server that supports one of the sources below, I recomme - [ElasticSearch](https://www.elastic.co/elasticsearch/) - Caching server - 🐲 At least [Dragonfly](https://www.dragonflydb.io/) v1.4.0 (recommended) - - 👻 [KeyDB](https://keydb.dev/) (untested) - 🍱 Another [Redis](https://redis.io/) server, at least v6 + - 👻 [KeyDB](https://keydb.dev/) (untested) ### 🏗️ Build dependencies - 🦀 At least [Rust](https://www.rust-lang.org/) v1.68.0 @@ -166,7 +166,9 @@ In Calckey's directory, fill out the `db` section of `.config/default.yml` with ## 💰 Caching server -If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll falll back to the mandatory Redis server. +If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll fall back to the mandatory Redis server. + +For DragonflyDB, launch with the flag `--default_lua_flags='allow-undeclared-keys'`. ## 🔎 Set up search From b2af795b6d72bc65d3a8d25b88b49bf97341337b Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 11:55:02 -0700 Subject: [PATCH 03/37] docs: :pencil2: dragonflydb typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d66560d0e..9701bc86e 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ If you have access to a server that supports one of the sources below, I recomme - [MeiliSearch](https://www.meilisearch.com/) - [ElasticSearch](https://www.elastic.co/elasticsearch/) - Caching server - - 🐲 At least [Dragonfly](https://www.dragonflydb.io/) v1.4.0 (recommended) + - 🐲 At least [DragonflyDB](https://www.dragonflydb.io/) v1.4.0 (recommended) - 🍱 Another [Redis](https://redis.io/) server, at least v6 - 👻 [KeyDB](https://keydb.dev/) (untested) ### 🏗️ Build dependencies From 264641ff7ddf07e21dd0b956b9abb465dce5c4c3 Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 12:25:54 -0700 Subject: [PATCH 04/37] fix: use unique key for my page query --- packages/client/src/pages/pages.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/src/pages/pages.vue b/packages/client/src/pages/pages.vue index 75a32ff29..a3a08be7c 100644 --- a/packages/client/src/pages/pages.vue +++ b/packages/client/src/pages/pages.vue @@ -66,10 +66,10 @@ :pagination="myPagesPagination" > From 46c7b3648f17a6588e83220b7ccd43c6f098423c Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 12:26:37 -0700 Subject: [PATCH 05/37] fix: use unique key for my galleries --- packages/client/src/pages/gallery/index.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/src/pages/gallery/index.vue b/packages/client/src/pages/gallery/index.vue index 66dc28d17..a4a09325c 100644 --- a/packages/client/src/pages/gallery/index.vue +++ b/packages/client/src/pages/gallery/index.vue @@ -92,9 +92,9 @@ >
From f0acadea1157129e73b5e7dca3e87c741b9755ee Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Thu, 6 Jul 2023 21:04:39 +0000 Subject: [PATCH 06/37] revert 6355bb604290a09a4a3b7c68b791234a0c1771ea revert build: :zap: build megalodon with swc --- packages/README.md | 1 - packages/megalodon/.swcrc | 19 ------------------- packages/megalodon/package.json | 9 ++------- pnpm-lock.yaml | 16 +++------------- 4 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 packages/megalodon/.swcrc diff --git a/packages/README.md b/packages/README.md index eeb5803f1..7d7c03e0b 100644 --- a/packages/README.md +++ b/packages/README.md @@ -7,4 +7,3 @@ This directory contains all of the packages Calckey uses. - `client`: Web interface written in Vue3 and TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use -- `megalodon`: TypeScript library used for Mastodon compatibility diff --git a/packages/megalodon/.swcrc b/packages/megalodon/.swcrc deleted file mode 100644 index c590064ec..000000000 --- a/packages/megalodon/.swcrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/swcrc", - "jsc": { - "parser": { - "syntax": "typescript", - "dynamicImport": true, - "decorators": true - }, - "transform": { - "decoratorMetadata": true - }, - "target": "es2022" - }, - "minify": false, - "module": { - "type": "commonjs", - "strict": true - } -} diff --git a/packages/megalodon/package.json b/packages/megalodon/package.json index 6de3076aa..43479b2e7 100644 --- a/packages/megalodon/package.json +++ b/packages/megalodon/package.json @@ -4,7 +4,7 @@ "main": "./lib/src/index.js", "typings": "./lib/src/index.d.ts", "scripts": { - "build": "pnpm swc src -d built -D", + "build": "tsc -p ./", "lint": "eslint --ext .js,.ts src", "doc": "typedoc --out ../docs ./src", "test": "NODE_ENV=test jest -u --maxWorkers=3" @@ -49,8 +49,6 @@ "async-lock": "1.4.0" }, "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.62", "@types/core-js": "^2.5.0", "@types/form-data": "^2.5.0", "@types/jest": "^29.4.0", @@ -79,8 +77,5 @@ "directories": { "lib": "lib", "test": "test" - }, - "optionalDependencies": { - "@swc/core-android-arm64": "1.3.11" - } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fc168cf1..c5e7f1fad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -789,7 +789,7 @@ importers: version: 2.30.0 emojilib: specifier: github:thatonecalculator/emojilib - version: github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b + version: github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e escape-regexp: specifier: 0.0.1 version: 0.0.1 @@ -970,17 +970,7 @@ importers: ws: specifier: 8.12.0 version: 8.12.0 - optionalDependencies: - '@swc/core-android-arm64': - specifier: 1.3.11 - version: 1.3.11 devDependencies: - '@swc/cli': - specifier: ^0.1.62 - version: 0.1.62(@swc/core@1.3.62)(chokidar@3.3.1) - '@swc/core': - specifier: ^1.3.62 - version: 1.3.62 '@types/async-lock': specifier: 1.4.0 version: 1.4.0 @@ -17444,8 +17434,8 @@ packages: url-polyfill: 1.1.12 dev: true - github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b: - resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/15fd9504f943763a057ff803ee2009ec0524c96b} + github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e: + resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/9d16541664dc8fef3201ae9b647477070676a52e} name: emojilib version: 3.0.10 dev: true From e505b0f20701c31ccad9c273b0009595a2dd7763 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Thu, 6 Jul 2023 17:06:31 -0400 Subject: [PATCH 07/37] fix: use host as prefix of cacheServer if undefined --- packages/backend/src/config/load.ts | 2 ++ packages/backend/src/config/types.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts index 9b8ee5edb..fa9878955 100644 --- a/packages/backend/src/config/load.ts +++ b/packages/backend/src/config/load.ts @@ -55,6 +55,8 @@ export default function load() { mixin.clientEntry = clientManifest["src/init.ts"]; if (!config.redis.prefix) config.redis.prefix = mixin.host; + if (config.cacheServer && !config.cacheServer.prefix) + config.cacheServer.prefix = mixin.host; return Object.assign(config, mixin); } diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index 43168662c..7789c26e0 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -26,7 +26,7 @@ export type Source = { user?: string; tls?: { [y: string]: string }; }; - cacheServer: { + cacheServer?: { host: string; port: number; family?: number; From 1ea8f8b4feb6b730ead113e5db86010678304b22 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Thu, 6 Jul 2023 17:22:15 -0400 Subject: [PATCH 08/37] perf: use msgpackr to encode and decode --- packages/backend/package.json | 4 ++-- packages/backend/src/misc/cache.ts | 2 +- pnpm-lock.yaml | 11 +++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 060064489..ec6451f61 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -28,13 +28,11 @@ "@bull-board/api": "5.2.0", "@bull-board/koa": "5.2.0", "@bull-board/ui": "5.2.0", - "megalodon": "workspace:*", "@discordapp/twemoji": "14.1.2", "@elastic/elasticsearch": "7.17.0", "@koa/cors": "3.4.3", "@koa/multer": "3.0.2", "@koa/router": "9.0.1", - "@msgpack/msgpack": "3.0.0-beta2", "@peertube/http-signature": "1.7.0", "@redocly/openapi-core": "1.0.0-beta.120", "@sinonjs/fake-timers": "9.1.2", @@ -87,9 +85,11 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", + "megalodon": "workspace:*", "meilisearch": "0.33.0", "mfm-js": "0.23.3", "mime-types": "2.1.35", + "msgpackr": "1.9.5", "multer": "1.4.4-lts.1", "native-utils": "link:native-utils", "nested-property": "4.0.0", diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index fe68908e5..913258f05 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -1,5 +1,5 @@ import { redisClient } from "@/db/redis.js"; -import { encode, decode } from "@msgpack/msgpack"; +import { encode, decode } from "msgpackr"; import { ChainableCommander } from "ioredis"; export class Cache { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fc168cf1..b9522c434 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,9 +105,6 @@ importers: '@koa/router': specifier: 9.0.1 version: 9.0.1 - '@msgpack/msgpack': - specifier: 3.0.0-beta2 - version: 3.0.0-beta2 '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 @@ -276,6 +273,9 @@ importers: mime-types: specifier: 2.1.35 version: 2.1.35 + msgpackr: + specifier: 1.9.5 + version: 1.9.5 multer: specifier: 1.4.4-lts.1 version: 1.4.4-lts.1 @@ -2607,11 +2607,6 @@ packages: os-filter-obj: 2.0.0 dev: true - /@msgpack/msgpack@3.0.0-beta2: - resolution: {integrity: sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==} - engines: {node: '>= 14'} - dev: false - /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2: resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} cpu: [arm64] From f835cccccfe0d8e43f4f7d45f4cacc92d3f4b0fb Mon Sep 17 00:00:00 2001 From: Namekuji Date: Thu, 6 Jul 2023 17:49:41 -0400 Subject: [PATCH 09/37] refactor: cache relays for a longer time --- packages/backend/src/services/relay.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/services/relay.ts b/packages/backend/src/services/relay.ts index 6f7829c21..e969d783a 100644 --- a/packages/backend/src/services/relay.ts +++ b/packages/backend/src/services/relay.ts @@ -15,7 +15,7 @@ import { createSystemUser } from "./create-system-user.js"; const ACTOR_USERNAME = "relay.actor" as const; -const relaysCache = new Cache("relay", 60 * 10); +const relaysCache = new Cache("relay", 60 * 60); export async function getRelayActor(): Promise { const user = await Users.findOneBy({ From bdca7d2f8e248ddf41df7e25706f1f9cad4a044a Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Thu, 6 Jul 2023 21:53:44 +0000 Subject: [PATCH 10/37] revert 49fd4034744f7642210bb66a3558d544d67e13b8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit revert fix: 🐛 fix quotes with CW-only quotes --- .../backend/src/server/activitypub/outbox.ts | 2 +- packages/backend/src/services/note/create.ts | 28 ++++++++++++++----- packages/client/src/components/MkNote.vue | 1 - 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index 469bd62ec..e0a380ffb 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -138,7 +138,7 @@ export async function packActivity(note: Note): Promise { ) { const renote = await Notes.findOneByOrFail({ id: note.renoteId }); return renderAnnounce( - renote.uri ?? `${config.url}/notes/${renote.id}`, + renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note, ); } diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 12c501533..095c75f42 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -67,7 +67,6 @@ import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; import meilisearch from "../../db/meilisearch.js"; import { redisClient } from "@/db/redis.js"; import { Mutex } from "redis-semaphore"; -import { packActivity } from "@/server/activitypub/outbox.js"; const mutedWordsCache = new Cache< { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] @@ -597,13 +596,9 @@ export default async ( }); //#region AP deliver - if ( - Users.isLocalUser(user) && - !data.localOnly && - !dontFederateInitially - ) { + if (Users.isLocalUser(user) && !dontFederateInitially) { (async () => { - const noteActivity = renderActivity(await packActivity(note)); + const noteActivity = await renderNoteOrRenoteActivity(data, note); const dm = new DeliverManager(user, noteActivity); // メンションされたリモートユーザーに配送 @@ -660,6 +655,25 @@ export default async ( await index(note, false); }); +async function renderNoteOrRenoteActivity(data: Option, note: Note) { + if (data.localOnly) return null; + + const content = + data.renote && + data.text == null && + data.poll == null && + (data.files == null || data.files.length === 0) + ? renderAnnounce( + data.renote.uri + ? data.renote.uri + : `${config.url}/notes/${data.renote.id}`, + note, + ) + : renderCreate(await renderNote(note, false), note); + + return renderActivity(content); +} + function incRenoteCount(renote: Note) { Notes.createQueryBuilder() .update() diff --git a/packages/client/src/components/MkNote.vue b/packages/client/src/components/MkNote.vue index a7ed28480..a1a519f79 100644 --- a/packages/client/src/components/MkNote.vue +++ b/packages/client/src/components/MkNote.vue @@ -328,7 +328,6 @@ if (noteViewInterruptors.length > 0) { const isRenote = note.renote != null && note.text == null && - note.cw == null && note.fileIds.length === 0 && note.poll == null; From 3258f5f9667bbf363a46ab4e228c10a292fc6936 Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Thu, 6 Jul 2023 22:04:11 +0000 Subject: [PATCH 11/37] =?UTF-8?q?docs:=20=F0=9F=93=9D=20KeyDB=20minimum=20?= =?UTF-8?q?version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 6decfe88e720ee594a4f1b3ad1c1b270e4e60124 Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 17:29:29 -0700 Subject: [PATCH 12/37] =?UTF-8?q?docs:=20=F0=9F=93=9D=20KeyDB,=20megalodon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++---- packages/README.md | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9701bc86e..4a58a2709 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,8 @@ If you have access to a server that supports one of the sources below, I recomme - [ElasticSearch](https://www.elastic.co/elasticsearch/) - Caching server - 🐲 At least [DragonflyDB](https://www.dragonflydb.io/) v1.4.0 (recommended) + - 👻 At least [KeyDB](https://keydb.dev/) v6.3.3 - 🍱 Another [Redis](https://redis.io/) server, at least v6 - - 👻 [KeyDB](https://keydb.dev/) (untested) ### 🏗️ Build dependencies - 🦀 At least [Rust](https://www.rust-lang.org/) v1.68.0 @@ -166,9 +166,7 @@ In Calckey's directory, fill out the `db` section of `.config/default.yml` with ## 💰 Caching server -If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll fall back to the mandatory Redis server. - -For DragonflyDB, launch with the flag `--default_lua_flags='allow-undeclared-keys'`. +If you experience a lot of traffic, it's a good idea to set up another Redis-compatible caching server. If you don't set one one up, it'll fall back to the mandatory Redis server. DragonflyDB is the recommended option due to its unrivaled performance and ease of use. ## 🔎 Set up search diff --git a/packages/README.md b/packages/README.md index 7d7c03e0b..0ed7c6403 100644 --- a/packages/README.md +++ b/packages/README.md @@ -7,3 +7,4 @@ This directory contains all of the packages Calckey uses. - `client`: Web interface written in Vue3 and TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use +- `megalodon`: TypeScript library used for partial Mastodon API compatibility From 9c96419e3d9a318d2e3f9df29308d5f4945e0c42 Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Thu, 6 Jul 2023 17:44:32 -0700 Subject: [PATCH 13/37] fix: :children_crossing: switch account when adding existing account --- packages/client/src/account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index 6d858292a..ea17387fa 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -162,7 +162,7 @@ export async function openAccountMenu( { done: (res) => { addAccount(res.id, res.i); - success(); + switchAccountWithToken(res.i); }, }, "closed", From 74ca26049831be1894d88fecc4124bf5d4193181 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Thu, 6 Jul 2023 22:54:53 -0400 Subject: [PATCH 14/37] fix: add megalodon to docker image --- .dockerignore | 14 ++++---------- Dockerfile | 7 +++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.dockerignore b/.dockerignore index 90d15ddd9..ad6ad169a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,12 +1,8 @@ # Visual Studio Code -/.vscode -!/.vscode/extensions.json +.vscode # Intelij-IDEA -/.idea -packages/backend/.idea/backend.iml -packages/backend/.idea/modules.xml -packages/backend/.idea/vcs.xml +.idea # Node.js node_modules @@ -14,7 +10,7 @@ node_modules report.*.json # Rust -packages/backend/native-utils/target/* +packages/backend/native-utils/target # Cypress cypress/screenshots @@ -24,9 +20,7 @@ cypress/videos coverage # config -/.config/* -!/.config/example.yml -!/.config/docker_example.env +/.config # misskey built diff --git a/Dockerfile b/Dockerfile index e11cb2bf4..823f78caa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,7 @@ COPY packages/backend/package.json packages/backend/package.json COPY packages/client/package.json packages/client/package.json COPY packages/sw/package.json packages/sw/package.json COPY packages/calckey-js/package.json packages/calckey-js/package.json +COPY packages/megalodon/package.json packages/megalodon/package.json COPY packages/backend/native-utils/package.json packages/backend/native-utils/package.json COPY packages/backend/native-utils/npm/linux-x64-musl/package.json packages/backend/native-utils/npm/linux-x64-musl/package.json COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/backend/native-utils/npm/linux-arm64-musl/package.json @@ -29,10 +30,7 @@ COPY packages/backend/native-utils/npm/linux-arm64-musl/package.json packages/ba RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --frozen-lockfile # Copy in the rest of the native-utils rust files -COPY packages/backend/native-utils/.cargo packages/backend/native-utils/.cargo -COPY packages/backend/native-utils/build.rs packages/backend/native-utils/ -COPY packages/backend/native-utils/src packages/backend/native-utils/src/ -COPY packages/backend/native-utils/migration/src packages/backend/native-utils/migration/src/ +COPY packages/backend/native-utils packages/backend/native-utils/ # Compile native-utils RUN pnpm run --filter native-utils build @@ -59,6 +57,7 @@ COPY --from=build /calckey/packages/backend/node_modules /calckey/packages/backe COPY --from=build /calckey/packages/sw/node_modules /calckey/packages/sw/node_modules COPY --from=build /calckey/packages/client/node_modules /calckey/packages/client/node_modules COPY --from=build /calckey/packages/calckey-js/node_modules /calckey/packages/calckey-js/node_modules +COPY --from=build /calckey/packages/megalodon/node_modules /calckey/packages/megalodon/node_modules # Copy the finished compiled files COPY --from=build /calckey/built /calckey/built From 71e97fce01e22099f140e4dd073a6a9f52070bcf Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Fri, 7 Jul 2023 05:44:22 +0000 Subject: [PATCH 15/37] =?UTF-8?q?docs:=20=F0=9F=93=9D=20simplify=20depende?= =?UTF-8?q?ncies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4a58a2709..2e6907e30 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ If you have access to a server that supports one of the sources below, I recomme ## 🧑‍💻 Dependencies - 🐢 At least [NodeJS](https://nodejs.org/en/) v18.16.0 (v20 recommended) - - Install with [nvm](https://github.com/nvm-sh/nvm) - 🐘 At least [PostgreSQL](https://www.postgresql.org/) v12 (v14 recommended) - 🍱 At least [Redis](https://redis.io/) v6 (v7 recommended) - Web Proxy (one of the following) @@ -104,10 +103,11 @@ If you have access to a server that supports one of the sources below, I recomme - 🦔 [Sonic](https://crates.io/crates/sonic-server) - [MeiliSearch](https://www.meilisearch.com/) - [ElasticSearch](https://www.elastic.co/elasticsearch/) -- Caching server - - 🐲 At least [DragonflyDB](https://www.dragonflydb.io/) v1.4.0 (recommended) - - 👻 At least [KeyDB](https://keydb.dev/) v6.3.3 - - 🍱 Another [Redis](https://redis.io/) server, at least v6 +- Caching server (one of the following) + - 🐲 [DragonflyDB](https://www.dragonflydb.io/) (recommended) + - 👻 [KeyDB](https://keydb.dev/) + - 🍱 Another [Redis](https://redis.io/) server + ### 🏗️ Build dependencies - 🦀 At least [Rust](https://www.rust-lang.org/) v1.68.0 From c9983dc08a8dda1a8ec8f903b3ad613905c5474e Mon Sep 17 00:00:00 2001 From: Namekuji Date: Fri, 7 Jul 2023 02:46:50 -0400 Subject: [PATCH 16/37] fix: copy megalodon before node_modules, fix #10424 --- Dockerfile | 3 ++- scripts/clean-all.js | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 823f78caa..744dba211 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,13 +51,14 @@ RUN apk add --no-cache --no-progress tini ffmpeg vips-dev zip unzip nodejs-curre COPY . ./ +COPY --from=build /calckey/packages/megalodon /calckey/packages/megalodon + # Copy node modules COPY --from=build /calckey/node_modules /calckey/node_modules COPY --from=build /calckey/packages/backend/node_modules /calckey/packages/backend/node_modules COPY --from=build /calckey/packages/sw/node_modules /calckey/packages/sw/node_modules COPY --from=build /calckey/packages/client/node_modules /calckey/packages/client/node_modules COPY --from=build /calckey/packages/calckey-js/node_modules /calckey/packages/calckey-js/node_modules -COPY --from=build /calckey/packages/megalodon/node_modules /calckey/packages/megalodon/node_modules # Copy the finished compiled files COPY --from=build /calckey/built /calckey/built diff --git a/scripts/clean-all.js b/scripts/clean-all.js index c5fc65849..47aaec25c 100644 --- a/scripts/clean-all.js +++ b/scripts/clean-all.js @@ -46,6 +46,14 @@ const { join } = require("node:path"); recursive: true, force: true, }); + fs.rmSync(join(__dirname, "/../packages/megalodon/built"), { + recursive: true, + force: true, + }); + fs.rmSync(join(__dirname, "/../packages/megalodon/node_modules"), { + recursive: true, + force: true, + }); fs.rmSync(join(__dirname, "/../built"), { recursive: true, force: true }); fs.rmSync(join(__dirname, "/../node_modules"), { From ea1597c6e82a262ae8e3346e09d78e58bccf4451 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Fri, 7 Jul 2023 02:53:10 -0400 Subject: [PATCH 17/37] chore: add megalodon to cleaning scripts --- scripts/clean-all.js | 2 +- scripts/clean.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/clean-all.js b/scripts/clean-all.js index 47aaec25c..4320aae2d 100644 --- a/scripts/clean-all.js +++ b/scripts/clean-all.js @@ -46,7 +46,7 @@ const { join } = require("node:path"); recursive: true, force: true, }); - fs.rmSync(join(__dirname, "/../packages/megalodon/built"), { + fs.rmSync(join(__dirname, "/../packages/megalodon/lib"), { recursive: true, force: true, }); diff --git a/scripts/clean.js b/scripts/clean.js index 39cbc77b9..727ddb66f 100644 --- a/scripts/clean.js +++ b/scripts/clean.js @@ -23,5 +23,9 @@ const { join } = require("node:path"); recursive: true, force: true, }); + fs.rmSync(join(__dirname, "/../packages/megalodon/lib"), { + recursive: true, + force: true, + }); fs.rmSync(join(__dirname, "/../built"), { recursive: true, force: true }); })(); From a4c812a92c511048f24c3000b6624a49e5a8bb8a Mon Sep 17 00:00:00 2001 From: naskya Date: Thu, 6 Jul 2023 15:39:55 +0000 Subject: [PATCH 18/37] chore: Translated using Weblate (Japanese) Currently translated at 100.0% (1816 of 1816 strings) Translation: Calckey/locales Translate-URL: https://hosted.weblate.org/projects/calckey/locales/ja/ --- locales/ja-JP.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9f2f825e5..05c4f3ab3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1064,6 +1064,7 @@ _aboutMisskey: donate: "Calckeyに寄付" morePatrons: "他にも多くの方が支援してくれています。ありがとうございます! 🥰" patrons: "支援者" + patronsList: 寄付額ではなく時系列順に並んでいます。上記のリンクから寄付を行ってここにあなたのIDを載せましょう! _nsfw: respect: "閲覧注意のメディアは隠す" ignore: "閲覧注意のメディアを隠さない" @@ -1375,11 +1376,12 @@ _permissions: _auth: shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?" shareAccessAsk: "アカウントへのアクセスを許可しますか?" - permissionAsk: "このアプリケーションは次の権限を要求しています" + permissionAsk: "このアプリケーションは次の権限を要求しています:" pleaseGoBack: "アプリケーションに戻り続行してください" callback: "アプリケーションに戻っています" denied: "アクセスを拒否しました" - copyAsk: "以下の認証コードをアプリケーションにコピーしてください" + copyAsk: "以下の認証コードをアプリケーションにコピーしてください:" + allPermissions: 全てのアクセス権 _antennaSources: all: "全ての投稿" homeTimeline: "フォローしているユーザーの投稿" @@ -1453,11 +1455,11 @@ _poll: remainingSeconds: "終了まであと{s}秒" _visibility: public: "公開" - publicDescription: "全てのユーザーに公開" + publicDescription: "全ての公開タイムラインに配信されます" home: "未収載" homeDescription: "ホームタイムラインのみに公開" followers: "フォロワー" - followersDescription: "自分のフォロワーのみに公開" + followersDescription: "フォロワーと会話相手のみに公開" specified: "ダイレクト" specifiedDescription: "指定したユーザーのみに公開" localOnly: "ローカルのみ" @@ -1890,14 +1892,14 @@ hiddenTags: 非表示にするハッシュタグ apps: "アプリ" _experiments: title: 試験的な機能 - postImportsCaption: + postImportsCaption: ユーザーが過去の投稿をCalckey・Misskey・Mastodon・Akkoma・Pleromaからインポートすることを許可します。キューが溜まっているときにインポートするとサーバーに負荷がかかる可能性があります。 enablePostImports: 投稿のインポートを有効にする sendModMail: モデレーション通知を送る deleted: 削除済み editNote: 投稿を編集 edited: '編集済み: {date} {time}' -signupsDisabled: +signupsDisabled: 現在、このサーバーでは新規登録が一般開放されていません。招待コードをお持ちの場合には、以下の欄に入力してください。招待コードをお持ちでない場合にも、新規登録を開放している他のサーバーには入れますよ! findOtherInstance: 他のサーバーを探す newer: 新しい投稿 @@ -1932,3 +1934,14 @@ isBot: このアカウントはBotです isLocked: このアカウントのフォローは承認制です isAdmin: 管理者 isPatron: Calckey 後援者 +_skinTones: + light: ペールオレンジ + mediumLight: ミディアムライト + medium: ミディアム + mediumDark: ミディアムダーク + yellow: 黄色 + dark: 茶色 +removeReaction: リアクションを取り消す +alt: 代替テキスト +swipeOnMobile: ページ間のスワイプを有効にする +reactionPickerSkinTone: 優先する絵文字のスキン色 From 16df0dd9dbbd9dafecfc854810f68495d9657a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AA=A0=E8=AA=A0-ChengCheng?= Date: Thu, 6 Jul 2023 17:24:43 +0000 Subject: [PATCH 19/37] chore: Translated using Weblate (Chinese (Traditional)) Currently translated at 94.3% (1714 of 1816 strings) Translation: Calckey/locales Translate-URL: https://hosted.weblate.org/projects/calckey/locales/zh_Hant/ --- locales/zh-TW.yml | 139 ++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index b576c6b60..3e5b6690a 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1,6 +1,6 @@ _lang_: "繁體中文" headlineMisskey: "貼文連繫網路" -introMisskey: "歡迎! Calckey是一個免費,開放原碼,去中心化的社群網路🚀" +introMisskey: "歡迎! Calckey是一個開源、去中心化且永遠免費的社群網路平台!🚀" monthAndDay: "{month}月 {day}日" search: "搜尋" notifications: "通知" @@ -21,7 +21,7 @@ basicSettings: "基本設定" otherSettings: "其他設定" openInWindow: "在新視窗開啟" profile: "個人檔案" -timeline: "時間軸" +timeline: "時間線" noAccountDescription: "此用戶還沒有自我介紹。" login: "登入" loggingIn: "登入中" @@ -31,7 +31,7 @@ uploading: "上傳中..." save: "儲存" users: "使用者" addUser: "新增使用者" -favorite: "我的最愛" +favorite: "添加至我的最愛" favorites: "我的最愛" unfavorite: "從我的最愛中移除" favorited: "已添加至我的最愛。" @@ -43,7 +43,7 @@ copyContent: "複製內容" copyLink: "複製連結" delete: "刪除" deleteAndEdit: "刪除並編輯" -deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有情感、轉發和回覆也將會消失。" +deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應、轉發和回覆也會消失。" addToList: "加入至清單" sendMessage: "發送訊息" copyUsername: "複製使用者名稱" @@ -64,7 +64,7 @@ export: "匯出" files: "檔案" download: "下載" driveFileDeleteConfirm: "確定要刪除檔案「{name}」嗎?使用此附件的貼文也會跟著消失。" -unfollowConfirm: "確定要取消追隨{name}嗎?" +unfollowConfirm: "確定要取消追隨 「{name}」 嗎?" exportRequested: "已請求匯出。這可能會花一點時間。結束後檔案將會被放到雲端裡。" importRequested: "已請求匯入。這可能會花一點時間。" lists: "清單" @@ -95,9 +95,9 @@ followRequestPending: "追隨許可批准中" enterEmoji: "輸入表情符號" renote: "轉發" unrenote: "取消轉發" -renoted: "已轉傳。" +renoted: "已轉發。" cantRenote: "無法轉發此貼文。" -cantReRenote: "無法轉傳之前已經轉傳過的內容。" +cantReRenote: "無法轉發之前已經轉發過的內容。" quote: "引用" pinnedNote: "已置頂的貼文" pinned: "置頂" @@ -105,7 +105,7 @@ you: "您" clickToShow: "按一下以顯示" sensitive: "敏感內容" add: "新增" -reaction: "情感" +reaction: "反應" enableEmojiReaction: "啟用表情符號反應" showEmojisInReactionNotifications: "在反應通知中顯示表情符號" reactionSetting: "在選擇器中顯示反應" @@ -140,14 +140,14 @@ emojiUrl: "表情符號URL" addEmoji: "加入表情符號" settingGuide: "推薦設定" cacheRemoteFiles: "快取遠端檔案" -cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外連接數據。" -flagAsBot: "此使用者是機器人" +cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間,但資料會因直接連線從而產生額外數據花費。" +flagAsBot: "標記此帳號是機器人" flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整Calckey內部系統將本帳戶識別為機器人。" -flagAsCat: "此使用者是貓" +flagAsCat: "你是喵咪嗎?w😺" flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示!" -flagShowTimelineReplies: "在時間軸上顯示貼文的回覆" +flagShowTimelineReplies: "在時間線上顯示貼文的回覆" flagShowTimelineRepliesDescription: "啟用時,時間線除了顯示用戶的貼文以外,還會顯示用戶對其他貼文的回覆。" -autoAcceptFollowed: "自動追隨中使用者的追隨請求" +autoAcceptFollowed: "自動准予追隨中使用者的追隨請求" addAccount: "添加帳戶" loginFailed: "登入失敗" showOnRemote: "轉到所在伺服器顯示" @@ -157,7 +157,7 @@ setWallpaper: "設定桌布" removeWallpaper: "移除桌布" searchWith: "搜尋: {q}" youHaveNoLists: "你沒有任何清單" -followConfirm: "你真的要追隨{name}嗎?" +followConfirm: "你真的要追隨 「{name}」 嗎?" proxyAccount: "代理帳戶" proxyAccountDescription: "代理帳戶是在某些情況下充當其他伺服器用戶的帳戶。例如,當使用者將一個來自其他伺服器的帳戶放在列表中時,由於沒有其他使用者追蹤該帳戶,該指令不會傳送到該伺服器上,因此會由代理帳戶追蹤。" host: "主機" @@ -166,7 +166,7 @@ recipient: "收件人" annotation: "註解" federation: "站台聯邦" instances: "伺服器" -registeredAt: "初次觀測" +registeredAt: "初次註冊" latestRequestSentAt: "上次發送的請求" latestRequestReceivedAt: "上次收到的請求" latestStatus: "最後狀態" @@ -234,19 +234,19 @@ lookup: "查詢" announcements: "公告" imageUrl: "圖片URL" remove: "刪除" -removed: "已刪除" +removed: "已成功刪除" removeAreYouSure: "確定要刪掉「{x}」嗎?" deleteAreYouSure: "確定要刪掉「{x}」嗎?" resetAreYouSure: "確定要重設嗎?" saved: "已儲存" -messaging: "傳送訊息" +messaging: "訊息" upload: "上傳" keepOriginalUploading: "保留原圖" -keepOriginalUploadingDescription: "上傳圖片時保留原始圖片。關閉時,瀏覽器會在上傳時生成一張用於web發布的圖片。" +keepOriginalUploadingDescription: "上傳圖片時保留原始圖片。關閉時,瀏覽器會在上傳時自動產生用於貼文發布的圖片。" fromDrive: "從雲端空間" -fromUrl: "從URL" +fromUrl: "從網址" uploadFromUrl: "從網址上傳" -uploadFromUrlDescription: "您要上傳的文件的URL" +uploadFromUrlDescription: "您要上傳的文件的網址" uploadFromUrlRequested: "已請求上傳" uploadFromUrlMayTakeTime: "還需要一些時間才能完成上傳。" explore: "探索" @@ -258,7 +258,7 @@ agreeTo: "我同意{0}" tos: "使用條款" start: "開始" home: "首頁" -remoteUserCaution: "由於該使用者來自遠端實例,因此資訊可能非即時的。" +remoteUserCaution: "由於該使用者來自遠端實例,因此資料可能是非即時的。" activity: "動態" images: "圖片" birthday: "生日" @@ -267,12 +267,12 @@ registeredDate: "註冊日期" location: "位置" theme: "外觀主題" themeForLightMode: "在淺色模式下使用的主題" -themeForDarkMode: "在黑暗模式下使用的主題" +themeForDarkMode: "在闇黑模式下使用的主題" light: "淺色" -dark: "黑暗" +dark: "闇黑" lightThemes: "明亮主題" -darkThemes: "黑暗主題" -syncDeviceDarkMode: "將黑暗模式與設備設置同步" +darkThemes: "闇黑主題" +syncDeviceDarkMode: "闇黑模式使用裝置設定" drive: "雲端硬碟" fileName: "檔案名稱" selectFile: "選擇檔案" @@ -281,19 +281,19 @@ selectFolder: "選擇資料夾" selectFolders: "選擇資料夾" renameFile: "重新命名檔案" folderName: "資料夾名稱" -createFolder: "新增資料夾" +createFolder: "創建資料夾" renameFolder: "重新命名資料夾" deleteFolder: "刪除資料夾" addFile: "加入附件" -emptyDrive: "雲端硬碟為空" -emptyFolder: "資料夾為空" +emptyDrive: "你的雲端硬碟沒有任何東西( ̄▽ ̄)\"" +emptyFolder: "資料夾裡面沒有東西(⊙_⊙;)" unableToDelete: "無法刪除" inputNewFileName: "輸入檔案名稱" inputNewDescription: "請輸入新標題" inputNewFolderName: "輸入新資料夾的名稱" circularReferenceFolder: "目標文件夾是您要移動的文件夾的子文件夾。" hasChildFilesOrFolders: "此文件夾不是空的,無法刪除。" -copyUrl: "複製URL" +copyUrl: "複製網址" rename: "重新命名" avatar: "大頭貼" banner: "橫幅" @@ -304,7 +304,7 @@ reload: "重新整理" doNothing: "無視" reloadConfirm: "確定要重新整理嗎?" watch: "關注" -unwatch: "取消追隨" +unwatch: "取消關注" accept: "接受" reject: "拒絕" normal: "正常" @@ -312,7 +312,7 @@ instanceName: "伺服器名稱" instanceDescription: "伺服器說明" maintainerName: "管理員名稱" maintainerEmail: "管理員郵箱" -tosUrl: "服務條款URL" +tosUrl: "服務條款網址" thisYear: "本年" thisMonth: "本月" today: "本日" @@ -323,23 +323,23 @@ pages: "頁面" integration: "整合" connectService: "己連結" disconnectService: "己斷開" -enableLocalTimeline: "開啟本地時間軸" -enableGlobalTimeline: "啟用公開時間軸" -disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。" +enableLocalTimeline: "開啟本地時間線" +enableGlobalTimeline: "啟用公開時間線" +disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和版主始終可以訪問所有的時間線。" registration: "註冊" enableRegistration: "開啟新使用者註冊" invite: "邀請" driveCapacityPerLocalAccount: "每個本地用戶的雲端空間大小" driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量" -inMb: "以Mbps為單位" -iconUrl: "圖像URL" -bannerUrl: "橫幅圖像URL" +inMb: "以MB為單位" +iconUrl: "圖標網址" +bannerUrl: "橫幅圖像網址" backgroundImageUrl: "背景圖片的來源網址" basicInfo: "基本資訊" pinnedUsers: "置頂用戶" -pinnedUsersDescription: "在「發現」頁面中使用換行標記想要置頂的使用者。" -pinnedPages: "釘選頁面" -pinnedPagesDescription: "輸入要固定至伺服器首頁的頁面路徑,以換行符分隔。" +pinnedUsersDescription: "在「探索」頁面中使用換行標記想要置頂的使用者。" +pinnedPages: "已釘選的頁面" +pinnedPagesDescription: "輸入要固定至伺服器首頁的頁面路徑,一行一個。" pinnedClipId: "置頂的摘錄ID" pinnedNotes: "已置頂的貼文" hcaptcha: "hCaptcha" @@ -482,7 +482,7 @@ promotion: "推廣" promote: "推廣" numberOfDays: "有效天數" hideThisNote: "隱藏此貼文" -showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦" +showFeaturedNotesInTimeline: "在時間線上顯示熱門推薦" objectStorage: "Object Storage (物件儲存)" useObjectStorage: "使用Object Storage" objectStorageBaseUrl: "根URL" @@ -502,7 +502,7 @@ objectStorageUseProxyDesc: "如果不使用代理進行API連接,請關閉" objectStorageSetPublicRead: "上傳時設定為\"public-read\"" serverLogs: "伺服器日誌" deleteAll: "刪除所有記錄" -showFixedPostForm: "於時間軸頁頂顯示「發送貼文」方框" +showFixedPostForm: "於時間線頁頂顯示「發送貼文」方框" newNoteRecived: "發現新的貼文" sounds: "音效" listen: "聆聽" @@ -661,8 +661,8 @@ repliedCount: "回覆數量" renotedCount: "轉發次數" followingCount: "正在跟隨的用戶數量" followersCount: "跟隨者數量" -sentReactionsCount: "情感發送次數" -receivedReactionsCount: "情感收到次數" +sentReactionsCount: "反應發送次數" +receivedReactionsCount: "反應收到次數" pollVotesCount: "已統計的投票數" pollVotedCount: "已投票數" yes: "確定" @@ -688,7 +688,7 @@ experimentalFeatures: "實驗中的功能" developer: "開發者" makeExplorable: "使自己的帳戶能夠在“探索”頁面中顯示" makeExplorableDescription: "如果關閉,帳戶將不會被顯示在\"探索\"頁面中。" -showGapBetweenNotesInTimeline: "分開顯示時間軸上的貼文" +showGapBetweenNotesInTimeline: "分開顯示時間線上的貼文" duplicate: "複製" left: "左" center: "置中" @@ -1089,8 +1089,8 @@ _wordMute: muteWords: "加入靜音文字" muteWordsDescription: "用空格分隔指定AND,用換行分隔指定OR。" muteWordsDescription2: "將關鍵字用斜線括起來表示正規表達式。" - softDescription: "隱藏時間軸中指定條件的貼文。" - hardDescription: "具有指定條件的貼文將不添加到時間軸。 即使您更改條件,未被添加的貼文也會被排除在外。" + softDescription: "隱藏時間線中指定條件的貼文。" + hardDescription: "具有指定條件的貼文將不添加到時間線。 即使您更改條件,未被添加的貼文也會被排除在外。" soft: "軟性靜音" hard: "硬性靜音" mutedNotes: "已靜音的貼文" @@ -1203,16 +1203,16 @@ _tutorial: step2_1: "首先,請完成你的個人資料。" step2_2: "通過提供一些關於你自己的資料,其他人會更容易了解他們是否想看到你的帖子或關注你。" step3_1: "現在是時候追隨一些人了!" - step3_2: "你的主頁和社交時間軸是基於你所追蹤的人,所以試著先追蹤幾個賬戶。\n點擊個人資料右上角的加號圈就可以關注它。" + step3_2: "你的主頁和社交時間線是基於你所追蹤的人,所以試著先追蹤幾個帳戶。\n點擊個人資料右上角的加號圈就可以關注它。" step4_1: "讓我們出去找你。" step4_2: "對於他們的第一條信息,有些人喜歡做 {introduction} 或一個簡單的 \"hello world!\"" - step5_1: "時間軸,到處都是時間軸!" - step5_2: "您的伺服器已啟用了{timelines}個時間軸。" - step5_3: "主 {icon} 時間軸是顯示你追蹤的帳號的帖子。" - step5_4: "本地 {icon} 時間軸是你可以看到伺服器中所有其他用戶的信息的時間軸。" - step5_5: "社交 {icon} 時間軸是顯示你的主時間軸 + 本地時間軸。" - step5_6: "推薦 {icon} 時間軸是顯示你的伺服器管理員推薦的帖文。" - step5_7: "全球 {icon} 時間軸是顯示來自所有其他連接的伺服器的帖文。" + step5_1: "時間線,到處都是時間線!" + step5_2: "您的伺服器已啟用了{timelines}個時間線。" + step5_3: "首頁 {icon} 時間線是顯示你追蹤的帳號的帖子。" + step5_4: "本地 {icon} 時間線是你可以看到伺服器中所有其他用戶的貼文的時間線。" + step5_5: "社交 {icon} 時間線是你的 首頁時間線 和 本地時間線 的結合體。" + step5_6: "推薦 {icon} 時間線是顯示你的伺服器管理員推薦的貼文。" + step5_7: "全球 {icon} 時間線是顯示來自所有其他連接的伺服器的貼文。" step6_1: "那麼,這裡是什麼地方?" step6_2: "你不只是加入Calckey。你已經加入了Fediverse的一個門戶,這是一個由成千上萬台服務器組成的互聯網絡。" step6_3: "每個服務器也有不同,而並不是所有的服務器都運行Calckey。但這個服務器確實是運行Calckey的! 你可能會覺得有點複雜,但你很快就會明白的。" @@ -1245,8 +1245,8 @@ _permissions: "write:notes": "撰寫或刪除貼文" "read:notifications": "查看通知" "write:notifications": "編輯通知" - "read:reactions": "查看情感" - "write:reactions": "編輯情感" + "read:reactions": "查看反應" + "write:reactions": "編輯反應" "write:votes": "投票" "read:pages": "顯示頁面" "write:pages": "編輯頁面" @@ -1284,7 +1284,7 @@ _weekday: _widgets: memo: "備忘錄" notifications: "通知" - timeline: "時間軸" + timeline: "時間線" calendar: "行事曆" trends: "發燒貼文" clock: "時鐘" @@ -1335,7 +1335,7 @@ _visibility: public: "公開" publicDescription: "發布給所有用戶" home: "不在主頁顯示" - homeDescription: "僅發送至首頁的時間軸" + homeDescription: "僅發送至首頁的時間線" followers: "追隨者" followersDescription: "僅發送至關注者" specified: "指定使用者" @@ -1403,7 +1403,7 @@ _instanceCharts: _timelines: home: "首頁" local: "本地" - social: "社群" + social: "社交" global: "公開" recommended: 推薦 _pages: @@ -1726,7 +1726,7 @@ _notification: pollEnded: "問卷調查結束" receiveFollowRequest: "已收到追隨請求" followRequestAccepted: "追隨請求已接受" - groupInvited: "加入社群邀請" + groupInvited: "群組加入邀請" app: "應用程式通知" _actions: followBack: "回關" @@ -1755,7 +1755,7 @@ _deck: main: "主列" widgets: "小工具" notifications: "通知" - tl: "時間軸" + tl: "時間線" antenna: "天線" list: "清單" mentions: "提及" @@ -1782,11 +1782,11 @@ enterSendsMessage: 在 Messaging 中按 Return 發送消息 (如關閉則是 Ctr migrationConfirm: "您確定要將你的帳戶遷移到 {account} 嗎? 一旦這樣做,你將無法復原,而你將無法再次正常使用您的帳戶。\n另外,請確保你已將此當前帳戶設置為您要遷移的帳戶。" customSplashIconsDescription: 每次用戶加載/重新加載頁面時,以換行符號分隔的自定啟動畫面圖標的網址將隨機顯示。請確保圖片位於靜態網址上,最好所有圖片解析度調整為 192x192。 -accountMoved: '該使用者已移至新帳戶:' +accountMoved: '該使用者已遷移至新帳戶:' showAds: 顯示廣告 noThankYou: 不用了,謝謝 selectInstance: 選擇伺服器 -enableRecommendedTimeline: 啟用推薦時間軸 +enableRecommendedTimeline: 啟用推薦時間線 antennaInstancesDescription: 分行列出一個伺服器 moveTo: 遷移此帳戶到新帳戶 moveToLabel: '請輸入你將會遷移到的帳戶:' @@ -1838,8 +1838,8 @@ pushNotification: 推送通知 subscribePushNotification: 啟用推送通知 unsubscribePushNotification: 禁用推送通知 pushNotificationAlreadySubscribed: 推送通知已經啟用 -recommendedInstancesDescription: 以每行分隔的推薦服務器出現在推薦的時間軸中。 不要添加 `https://`,只添加域名。 -searchPlaceholder: 搜尋 Calckey +recommendedInstancesDescription: 以每行分隔的推薦伺服器出現在推薦的時間線中。 不要添加 `https://`,只添加域名。 +searchPlaceholder: 在聯邦網路上搜尋 cw: 內容警告 selectChannel: 選擇一個頻道 newer: 較新 @@ -1848,3 +1848,10 @@ jumpToPrevious: 跳到上一個 removeReaction: 移除你的反應 listsDesc: 清單可以創建一個只有您指定用戶的時間線。 可以從時間線頁面訪問它們。 flagSpeakAsCatDescription: 在喵咪模式下你的貼文會被喵化ヾ(•ω•`)o +antennasDesc: "天線會顯示符合您設置條件的新貼文!\n 可以從時間線訪問它們。" +expandOnNoteClick: 點擊以打開貼文 +expandOnNoteClickDesc: 如果禁用,您仍然可以通過右鍵單擊菜單或單擊時間戳來打開貼文。 +hiddenTagsDescription: '列出您希望隱藏趨勢和探索的主題標籤(不帶 #)。 隱藏的主題標籤仍然可以通過其他方式發現。' +userSaysSomethingReasonQuote: '{name} 引用了一篇包含 {reason} 的貼文' +silencedInstancesDescription: 列出您想要靜音的伺服器的網址。 您列出的伺服器內的帳戶將被視為“沉默”,只能發出追隨請求,如果不追隨則不能提及本地帳戶。 + 這不會影響被阻止的伺服器。 From acff402e216ffcd4f84554aecf5401cb52e5195a Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 18:58:24 +0200 Subject: [PATCH 20/37] [mastodon-client] Fail gracefully if user resolve fails --- packages/megalodon/src/misskey.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 5275c70f6..61464522a 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1257,31 +1257,31 @@ export default class Misskey implements MegalodonInterface { } public async getMentions(text: string, cache: AccountCache): Promise { - console.log(`getting mentions for message: '${text}'`); const mentions :Entity.Mention[] = []; if (text == undefined) return mentions; - console.log('text is not undefined, continuing'); - const mentionMatch = text.matchAll(/(?<=^|\s)@(?.*?)(?:@(?.*?)|)(?=\s|$)/g); for (const m of mentionMatch) { - if (m.groups == null) - continue; + try { + if (m.groups == null) + continue; - const account = await this.getAccountByNameCached(m.groups.user, m.groups.host, cache); + const account = await this.getAccountByNameCached(m.groups.user, m.groups.host, cache); - if (account == null) - continue; + if (account == null) + continue; - mentions.push({ - id: account.id, - url: account.url, - username: account.username, - acct: account.acct - }); + mentions.push({ + id: account.id, + url: account.url, + username: account.username, + acct: account.acct + }); + } + catch {} } return mentions; From 197977c3a82cac669c3f99a6204a8097f31ae4c8 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 19:23:47 +0200 Subject: [PATCH 21/37] [mastodon-client] Fix global timeline --- .../src/server/api/mastodon/endpoints/timeline.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts index a155cc93e..efadfe786 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts @@ -45,13 +45,14 @@ export function apiTimelineMastodon(router: Router): void { const client = getClient(BASE_URL, accessTokens); try { const query: any = ctx.query; - const data = query.local - ? await client.getLocalTimeline( - convertTimelinesArgsId(argsToBools(limitToInt(query))), - ) - : await client.getPublicTimeline( - convertTimelinesArgsId(argsToBools(limitToInt(query))), - ); + const data = + query.local === "true" + ? await client.getLocalTimeline( + convertTimelinesArgsId(argsToBools(limitToInt(query))), + ) + : await client.getPublicTimeline( + convertTimelinesArgsId(argsToBools(limitToInt(query))), + ); ctx.body = data.data.map((status) => convertStatus(status)); } catch (e: any) { console.error(e); From 3d5da39d836c724e0ce54d4ab2815d402024fcc1 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 19:41:32 +0200 Subject: [PATCH 22/37] [mastodon-client] Don't display unsupported notification types --- packages/megalodon/src/misskey.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 61464522a..42268806f 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -10,6 +10,7 @@ import Entity from './entity' import { MegalodonInterface, WebSocketInterface, NoImplementedError, ArgumentError, UnexpectedError } from './megalodon' import MegalodonEntity from "@/entity"; import fs from "node:fs"; +import MisskeyNotificationType from "./misskey/notification"; type AccountCache = { locks: AsyncLock, @@ -2238,7 +2239,11 @@ export default class Misskey implements MegalodonInterface { } return this.client .post>('/api/i/notifications', params) - .then(res => ({ ...res, data: res.data.map(n => this.converter.notification(n, this.baseUrlToHost(this.baseUrl))) })) + .then(res => ({ + ...res, + data: res.data + .filter(p => p.type != MisskeyNotificationType.FollowRequestAccepted) // these aren't supported on mastodon + .map(n => this.converter.notification(n, this.baseUrlToHost(this.baseUrl))) })) } public async getNotification(_id: string): Promise> { From afc9cf325981d64f622d5fd468ca22adfdab69a0 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 20:15:24 +0200 Subject: [PATCH 23/37] [mastodon-client] populate user details for all notes --- .../src/server/api/mastodon/converters.ts | 6 +- packages/megalodon/src/misskey.ts | 79 +++++++++++++------ 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/converters.ts b/packages/backend/src/server/api/mastodon/converters.ts index 37c6283a1..cbaf5287f 100644 --- a/packages/backend/src/server/api/mastodon/converters.ts +++ b/packages/backend/src/server/api/mastodon/converters.ts @@ -2,8 +2,10 @@ import { Entity } from "megalodon"; import { convertId, IdType } from "../index.js"; function simpleConvert(data: any) { - data.id = convertId(data.id, IdType.MastodonId); - return data; + // copy the object to bypass weird pass by reference bugs + const result = Object.assign({}, data); + result.id = convertId(data.id, IdType.MastodonId); + return result; } export function convertAccount(account: Entity.Account) { diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 42268806f..4753eb480 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -333,7 +333,7 @@ export default class Misskey implements MegalodonInterface { if (res.data.pinnedNotes) { return { ...res, - data: await Promise.all(res.data.pinnedNotes.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.pinnedNotes.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) } } return {...res, data: []} @@ -385,7 +385,7 @@ export default class Misskey implements MegalodonInterface { }) } return this.client.post>('/api/users/notes', params).then(async res => { - const statuses: Array = await Promise.all(res.data.map(note => this.noteWithMentions(note, this.baseUrlToHost(this.baseUrl), accountCache))) + const statuses: Array = await Promise.all(res.data.map(note => this.noteWithDetails(note, this.baseUrlToHost(this.baseUrl), accountCache))) return Object.assign(res, { data: statuses }) @@ -424,7 +424,7 @@ export default class Misskey implements MegalodonInterface { } return this.client.post>('/api/users/reactions', params).then(async res => { return Object.assign(res, { - data: await Promise.all(res.data.map(fav => this.noteWithMentions(fav.note, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(fav => this.noteWithDetails(fav.note, this.baseUrlToHost(this.baseUrl), accountCache))) }) }) } @@ -764,7 +764,7 @@ export default class Misskey implements MegalodonInterface { } return this.client.post>('/api/i/favorites', params).then(async res => { return Object.assign(res, { - data: await Promise.all(res.data.map(s => this.noteWithMentions(s.note, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(s => this.noteWithDetails(s.note, this.baseUrlToHost(this.baseUrl), accountCache))) }) }) } @@ -1222,7 +1222,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/create', params) .then(async res => ({ ...res, - data: await this.noteWithMentions(res.data.createdNote, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) + data: await this.noteWithDetails(res.data.createdNote, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) })) } @@ -1234,7 +1234,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({ ...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})); + .then(async res => ({ ...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})); } private getFreshAccountCache() :AccountCache { @@ -1244,12 +1244,22 @@ export default class Misskey implements MegalodonInterface { } } - public async noteWithMentions(n: MisskeyAPI.Entity.Note, host: string, cache: AccountCache): Promise { - const status = await this.converter.note(n, host); - return status.mentions.length === 0 ? this.addMentionsToStatus(status, cache) : status; + public async noteWithDetails(n: MisskeyAPI.Entity.Note, host: string, cache: AccountCache): Promise { + const status = await this.addUserDetailsToStatus(this.converter.note(n, host), cache); + return this.addMentionsToStatus(status, cache); } + public async addUserDetailsToStatus(status: Entity.Status, cache: AccountCache) : Promise { + if (status.account.followers_count === 0 && status.account.followers_count === 0 && status.account.statuses_count === 0) + status.account = await this.getAccountCached(status.account.id, status.account.acct, cache) ?? status.account; + + return status; + } + public async addMentionsToStatus(status: Entity.Status, cache: AccountCache) : Promise { + if (status.mentions.length > 0) + return status; + status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null); for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) { status.content = status.content.replace(`@${m.acct}`, `@${m.acct}`); @@ -1307,6 +1317,23 @@ export default class Misskey implements MegalodonInterface { }) } + public async getAccountCached(id: string, acct: string, cache: AccountCache): Promise { + return await cache.locks.acquire(acct, async () => { + const cacheHit = cache.accounts.find(p => p.id === id); + const account = cacheHit ?? (await this.getAccount(id)).data; + + if (!account) { + return null; + } + + if (cacheHit == null) { + cache.accounts.push(account); + } + + return account; + }) + } + public async editStatus( _id: string, _options: { @@ -1375,11 +1402,11 @@ export default class Misskey implements MegalodonInterface { return this.client.post>('/api/notes/children', params).then(async res => { const accountCache = this.getFreshAccountCache(); const conversation = await this.client.post>('/api/notes/conversation', params); - const parents = await Promise.all(conversation.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))); + const parents = await Promise.all(conversation.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))); const context: Entity.Context = { ancestors: parents.reverse(), - descendants: this.dfs(await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache)))) + descendants: this.dfs(await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache)))) } return { ...res, @@ -1492,7 +1519,7 @@ export default class Misskey implements MegalodonInterface { }) .then(async res => ({ ...res, - data: await this.noteWithMentions(res.data.createdNote, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) + data: await this.noteWithDetails(res.data.createdNote, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) })) } @@ -1507,7 +1534,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } /** @@ -1521,7 +1548,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } /** @@ -1535,7 +1562,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } public async muteStatus(_id: string): Promise> { @@ -1563,7 +1590,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } /** @@ -1577,7 +1604,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } // ====================================== @@ -1663,7 +1690,7 @@ export default class Misskey implements MegalodonInterface { noteId: status_id }) .then(async res => { - const note = await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) + const note = await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) return {...res, data: note.poll} }) if (!res.data) { @@ -1768,7 +1795,7 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/global-timeline', params) .then(async res => ({ ...res, - data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) } @@ -1826,7 +1853,7 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/local-timeline', params) .then(async res => ({ ...res, - data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) } @@ -1890,7 +1917,7 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/search-by-tag', params) .then(async res => ({ ...res, - data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) } @@ -1945,7 +1972,7 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/timeline', params) .then(async res => ({ ...res, - data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) + data: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) } @@ -2001,7 +2028,7 @@ export default class Misskey implements MegalodonInterface { } return this.client .post>('/api/notes/user-list-timeline', params) - .then(async res => ({ ...res, data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) + .then(async res => ({ ...res, data: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))) })) } // ====================================== @@ -2444,7 +2471,7 @@ export default class Misskey implements MegalodonInterface { ...res, data: { accounts: [], - statuses: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl), accountCache))), + statuses: await Promise.all(res.data.map(n => this.noteWithDetails(n, this.baseUrlToHost(this.baseUrl), accountCache))), hashtags: [] } })) @@ -2582,7 +2609,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } /** @@ -2596,7 +2623,7 @@ export default class Misskey implements MegalodonInterface { .post('/api/notes/show', { noteId: id }) - .then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) + .then(async res => ({...res, data: await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())})) } public async getEmojiReactions(id: string): Promise>> { From c02fec7f36e541f6eb0bfc0bc9e8105444e1a96c Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 22:06:26 +0200 Subject: [PATCH 24/37] [mastodon-client] populate note details for notifications --- packages/megalodon/src/misskey.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 4753eb480..85489f8be 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1244,6 +1244,13 @@ export default class Misskey implements MegalodonInterface { } } + public async notificationWithDetails(n: MisskeyAPI.Entity.Notification, host: string, cache: AccountCache): Promise { + const notification = this.converter.notification(n, host); + if (n.note) + notification.status = await this.noteWithDetails(n.note, host, cache); + return notification; + } + public async noteWithDetails(n: MisskeyAPI.Entity.Note, host: string, cache: AccountCache): Promise { const status = await this.addUserDetailsToStatus(this.converter.note(n, host), cache); return this.addMentionsToStatus(status, cache); @@ -2264,13 +2271,15 @@ export default class Misskey implements MegalodonInterface { limit: 20 }) } + const cache = this.getFreshAccountCache(); return this.client .post>('/api/i/notifications', params) - .then(res => ({ + .then(async res => ({ ...res, - data: res.data + data: await Promise.all(res.data .filter(p => p.type != MisskeyNotificationType.FollowRequestAccepted) // these aren't supported on mastodon - .map(n => this.converter.notification(n, this.baseUrlToHost(this.baseUrl))) })) + .map(n => this.notificationWithDetails(n, this.baseUrlToHost(this.baseUrl), cache))) + })) } public async getNotification(_id: string): Promise> { From a94bf84f0473f9b584e50badf26761deada8e475 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 22:40:29 +0200 Subject: [PATCH 25/37] [mastodon-client] implement favorited_by --- .../src/server/api/mastodon/endpoints/status.ts | 14 +++++++++++++- packages/megalodon/src/misskey.ts | 14 +++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index ec978bc84..3c58cf3a4 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -197,7 +197,19 @@ export function apiStatusMastodon(router: Router): void { router.get<{ Params: { id: string } }>( "/v1/statuses/:id/favourited_by", async (ctx) => { - ctx.body = []; + const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; + const accessTokens = ctx.headers.authorization; + const client = getClient(BASE_URL, accessTokens); + try { + const data = await client.getStatusFavouritedBy( + convertId(ctx.params.id, IdType.CalckeyId), + ); + ctx.body = data.data.map((account) => convertAccount(account)); + } catch (e: any) { + console.error(e); + ctx.status = 401; + ctx.body = e.response.data; + } }, ); router.post<{ Params: { id: string } }>( diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 85489f8be..dda108deb 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1487,11 +1487,15 @@ export default class Misskey implements MegalodonInterface { })) } - public async getStatusFavouritedBy(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) + public async getStatusFavouritedBy(id: string): Promise>> { + return this.client + .post>('/api/notes/reactions', { + noteId: id + }) + .then(res => ({ + ...res, + data: res.data.map(n => this.converter.user(n.user)) + })) } public async favouriteStatus(id: string): Promise> { From 90e1eaa62dd64623c392a2dac6219e9f6f661c9c Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 22:51:07 +0200 Subject: [PATCH 26/37] [mastodon-client] populate user data for favorited_by and reblogged_by --- packages/megalodon/src/misskey.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index dda108deb..cc589197d 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1481,9 +1481,9 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/renotes', { noteId: id }) - .then(res => ({ + .then(async res => ({ ...res, - data: res.data.map(n => this.converter.user(n.user)) + data: (await Promise.all(res.data.map(n => this.getAccount(n.user.id)))).map(p => p.data) })) } @@ -1492,9 +1492,9 @@ export default class Misskey implements MegalodonInterface { .post>('/api/notes/reactions', { noteId: id }) - .then(res => ({ + .then(async res => ({ ...res, - data: res.data.map(n => this.converter.user(n.user)) + data: (await Promise.all(res.data.map(n => this.getAccount(n.user.id)))).map(p => p.data) })) } From 4cf8c70bf5092e94b7645786aa8914f5a61b72b8 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 23:18:43 +0200 Subject: [PATCH 27/37] [mastodon-client] populate details for quote and reblog fields --- packages/megalodon/src/misskey.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index cc589197d..48950f943 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1260,6 +1260,12 @@ export default class Misskey implements MegalodonInterface { if (status.account.followers_count === 0 && status.account.followers_count === 0 && status.account.statuses_count === 0) status.account = await this.getAccountCached(status.account.id, status.account.acct, cache) ?? status.account; + if (status.reblog != null) + status.reblog = await this.addUserDetailsToStatus(status.reblog, cache); + + if (status.quote != null) + status.quote = await this.addUserDetailsToStatus(status.quote, cache); + return status; } @@ -1267,6 +1273,12 @@ export default class Misskey implements MegalodonInterface { if (status.mentions.length > 0) return status; + if (status.reblog != null) + status.reblog = await this.addMentionsToStatus(status.reblog, cache); + + if (status.quote != null) + status.quote = await this.addMentionsToStatus(status.quote, cache); + status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null); for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) { status.content = status.content.replace(`@${m.acct}`, `@${m.acct}`); From 22825ae76a844d3fbb73f8dfa8760d15e1ba97ce Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 7 Jul 2023 23:42:19 +0200 Subject: [PATCH 28/37] [mastodon-client] fix search type param --- .../server/api/mastodon/endpoints/search.ts | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index df35b9116..c2f828ad7 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -30,21 +30,25 @@ export function apiSearchMastodon(router: Router): void { try { const query: any = convertTimelinesArgsId(limitToInt(ctx.query)); const type = query.type; - if (type) { - const data = await client.search(query.q, type, query); - ctx.body = data.data.accounts.map((account) => convertAccount(account)); - } else { - const acct = await client.search(query.q, "accounts", query); - const stat = await client.search(query.q, "statuses", query); - const tags = await client.search(query.q, "hashtags", query); - ctx.body = { - accounts: acct.data.accounts.map((account) => - convertAccount(account), - ), - statuses: stat.data.statuses.map((status) => convertStatus(status)), - hashtags: tags.data.hashtags, - }; - } + const acct = + !type || type === "accounts" + ? await client.search(query.q, "accounts", query) + : null; + const stat = + !type || type === "statuses" + ? await client.search(query.q, "statuses", query) + : null; + const tags = + !type || type === "hashtags" + ? await client.search(query.q, "hashtags", query) + : null; + ctx.body = { + accounts: + acct?.data?.accounts.map((account) => convertAccount(account)) ?? [], + statuses: + stat?.data?.statuses.map((status) => convertStatus(status)) ?? [], + hashtags: tags?.data?.hashtags ?? [], + }; } catch (e: any) { console.error(e); ctx.status = 401; From a14659f19faab3c3c8708784f531c2a99620facb Mon Sep 17 00:00:00 2001 From: freeplay Date: Fri, 7 Jul 2023 21:50:45 -0400 Subject: [PATCH 29/37] style: make background banner blur static --- packages/client/src/pages/user/home.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue index adfebd4a2..24b150bc4 100644 --- a/packages/client/src/pages/user/home.vue +++ b/packages/client/src/pages/user/home.vue @@ -26,6 +26,7 @@ class="banner" :style="{ backgroundImage: `url('${user.bannerUrl}')`, + '--backgroundImageStatic': getStaticImageUrl(user.bannerUrl) }" >
@@ -384,6 +385,7 @@ import MkRemoteCaution from "@/components/MkRemoteCaution.vue"; import MkInfo from "@/components/MkInfo.vue"; import MkMoved from "@/components/MkMoved.vue"; import { getScrollPosition } from "@/scripts/scroll"; +import { getStaticImageUrl } from "@/scripts/get-static-image-url"; import number from "@/filters/number"; import { userPage } from "@/filters/user"; import * as os from "@/os"; @@ -513,7 +515,7 @@ onUnmounted(() => { content: ""; position: fixed; inset: 0; - background: var(--blur, inherit); + background: var(--blur, --backgroundImageStatic); background-size: cover; background-position: center; pointer-events: none; From 524c8f07ecb2b526c002f24a803521bb7b7fce4d Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 02:01:02 +0200 Subject: [PATCH 30/37] [mastodon-client] fix local instance mentions --- packages/megalodon/src/misskey.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 48950f943..c7db1aad4 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1281,6 +1281,8 @@ export default class Misskey implements MegalodonInterface { status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null); for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) { + if (m.acct == m.username) + status.content = status.content.replace(`@${m.acct}@${this.baseUrlToHost(this.baseUrl)}`, `@${m.acct}`); status.content = status.content.replace(`@${m.acct}`, `@${m.acct}`); } return status; From 9d37f011132c19de91561486a27ec0973603ab72 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 01:42:51 +0200 Subject: [PATCH 31/37] [mastodon-client] fix polls --- packages/megalodon/src/entities/poll.ts | 1 + packages/megalodon/src/megalodon.ts | 2 +- packages/megalodon/src/misskey.ts | 32 +++++++++++--------- packages/megalodon/src/misskey/api_client.ts | 9 +++--- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/megalodon/src/entities/poll.ts b/packages/megalodon/src/entities/poll.ts index 69706e8ae..c4f8f4f6d 100644 --- a/packages/megalodon/src/entities/poll.ts +++ b/packages/megalodon/src/entities/poll.ts @@ -9,5 +9,6 @@ namespace Entity { votes_count: number options: Array voted: boolean + own_votes: Array } } diff --git a/packages/megalodon/src/megalodon.ts b/packages/megalodon/src/megalodon.ts index 74966ccf4..1cd0a7db3 100644 --- a/packages/megalodon/src/megalodon.ts +++ b/packages/megalodon/src/megalodon.ts @@ -841,7 +841,7 @@ export interface MegalodonInterface { * @param choices Array of own votes containing index for each option (starting from 0). * @return Poll */ - votePoll(id: string, choices: Array, status_id?: string | null): Promise> + votePoll(id: string, choices: Array): Promise> // ====================================== // statuses/scheduled_statuses // ====================================== diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index c7db1aad4..07826f316 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -1688,31 +1688,35 @@ export default class Misskey implements MegalodonInterface { // ====================================== // statuses/polls // ====================================== - public async getPoll(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) + public async getPoll(id: string): Promise> { + const res = await this.getStatus(id); + if (res.data.poll == null) + throw new Error('poll not found'); + return { ...res, data: res.data.poll } } /** * POST /api/notes/polls/vote */ - public async votePoll(_id: string, choices: Array, status_id?: string | null): Promise> { - if (!status_id) { + public async votePoll(id: string, choices: Array): Promise> { + if (!id) { return new Promise((_, reject) => { - const err = new ArgumentError('status_id is required') + const err = new ArgumentError('id is required') reject(err) }) } - const params = { - noteId: status_id, - choice: choices[0] - } - await this.client.post<{}>('/api/notes/polls/vote', params) + + for (const c of choices) { + const params = { + noteId: id, + choice: +c + } + await this.client.post<{}>('/api/notes/polls/vote', params) + } + const res = await this.client .post('/api/notes/show', { - noteId: status_id + noteId: id }) .then(async res => { const note = await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache()) diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index 1833f9956..180ec6fdb 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -275,18 +275,19 @@ namespace MisskeyAPI { } } - poll = (p: Entity.Poll): MegalodonEntity.Poll => { + poll = (p: Entity.Poll, id: string): MegalodonEntity.Poll => { const now = dayjs() const expire = dayjs(p.expiresAt) const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0) return { - id: '', + id: id, expires_at: p.expiresAt, expired: now.isAfter(expire), multiple: p.multiple, votes_count: count, options: p.choices.map(c => this.choice(c)), - voted: p.choices.some(c => c.isVoted) + voted: p.choices.some(c => c.isVoted), + own_votes: p.choices.filter(c => c.isVoted).map(c => p.choices.indexOf(c)) } } @@ -318,7 +319,7 @@ namespace MisskeyAPI { mentions: [], tags: [], card: null, - poll: n.poll ? this.poll(n.poll) : null, + poll: n.poll ? this.poll(n.poll, n.id) : null, application: null, language: null, pinned: null, From 7f7eb301a050901394d1ba19c75304c4dbe1045a Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 02:37:11 +0200 Subject: [PATCH 32/37] [mastodon-client] render bio newlines correctly --- packages/megalodon/src/misskey/api_client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/megalodon/src/misskey/api_client.ts b/packages/megalodon/src/misskey/api_client.ts index 180ec6fdb..7f1409c70 100644 --- a/packages/megalodon/src/misskey/api_client.ts +++ b/packages/megalodon/src/misskey/api_client.ts @@ -161,7 +161,7 @@ namespace MisskeyAPI { followers_count: u.followersCount, following_count: u.followingCount, statuses_count: u.notesCount, - note: u.description, + note: u.description?.replace(/\n|\\n/g, '
') ?? '', url: acctUrl, avatar: u.avatarUrl, avatar_static: u.avatarUrl, From a5be7c3ac8f61a90bd40b485d2866cce033fea89 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 03:24:11 +0200 Subject: [PATCH 33/37] [mastodon-client] handle user & note URLs in search --- .../server/api/mastodon/endpoints/search.ts | 1 + packages/megalodon/src/misskey.ts | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts index c2f828ad7..8a4817557 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/search.ts @@ -42,6 +42,7 @@ export function apiSearchMastodon(router: Router): void { !type || type === "hashtags" ? await client.search(query.q, "hashtags", query) : null; + ctx.body = { accounts: acct?.data?.accounts.map((account) => convertAccount(account)) ?? [], diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 07826f316..f2befd31e 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -2395,6 +2395,32 @@ export default class Misskey implements MegalodonInterface { switch (type) { case 'accounts': { + if (q.startsWith("http://") || q.startsWith("https://")) { + return this.client.post('/api/ap/show', {uri: q}).then(async res => { + if (res.status != 200 || res.data.type != 'User') { + res.status = 200; + res.statusText = "OK"; + res.data = { + accounts: [], + statuses: [], + hashtags: [] + }; + + return res; + } + + const account = await this.converter.userDetail(res.data.object as MisskeyAPI.Entity.UserDetail, this.baseUrlToHost(this.baseUrl)); + + return { + ...res, + data: { + accounts: options?.max_id && options?.max_id >= account.id ? [] : [account], + statuses: [], + hashtags: [] + } + }; + }) + } let params = { query: q } @@ -2468,6 +2494,32 @@ export default class Misskey implements MegalodonInterface { })) } case 'statuses': { + if (q.startsWith("http://") || q.startsWith("https://")) { + return this.client.post('/api/ap/show', {uri: q}).then(async res => { + if (res.status != 200 || res.data.type != 'Note') { + res.status = 200; + res.statusText = "OK"; + res.data = { + accounts: [], + statuses: [], + hashtags: [] + }; + + return res; + } + + const post = await this.noteWithDetails(res.data.object as MisskeyAPI.Entity.Note, this.baseUrlToHost(this.baseUrl), accountCache); + + return { + ...res, + data: { + accounts: [], + statuses: options?.max_id && options.max_id >= post.id ? [] : [post], + hashtags: [] + } + } + }) + } let params = { query: q } From 1d42fe37eebb8c61049a0580c29eccde2911a2e4 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sat, 8 Jul 2023 03:59:52 +0200 Subject: [PATCH 34/37] increase ap/show rate limit --- packages/backend/src/server/api/endpoints/ap/show.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 3dd168d71..c25f0a801 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -10,7 +10,7 @@ import type { Note } from "@/models/entities/note.js"; import type { CacheableLocalUser, User } from "@/models/entities/user.js"; import { isActor, isPost, getApId } from "@/remote/activitypub/type.js"; import type { SchemaType } from "@/misc/schema.js"; -import { HOUR } from "@/const.js"; +import { MINUTE } from "@/const.js"; import { shouldBlockInstance } from "@/misc/should-block-instance.js"; import { updateQuestion } from "@/remote/activitypub/models/question.js"; import { populatePoll } from "@/models/repositories/note.js"; @@ -22,8 +22,8 @@ export const meta = { requireCredential: true, limit: { - duration: HOUR, - max: 30, + duration: MINUTE, + max: 10, }, errors: { From a4d4bb40f22742a2f1db17b09efd4d51aa2b433a Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Fri, 7 Jul 2023 20:44:41 -0700 Subject: [PATCH 35/37] build: :zap: build megalodon with swc Do it right this time --- packages/README.md | 2 +- packages/megalodon/.swcrc | 19 +++++++++++++++++++ packages/megalodon/package.json | 9 +++++++-- pnpm-lock.yaml | 16 +++++++++++++--- 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 packages/megalodon/.swcrc diff --git a/packages/README.md b/packages/README.md index 0ed7c6403..ed4b8f6c4 100644 --- a/packages/README.md +++ b/packages/README.md @@ -7,4 +7,4 @@ This directory contains all of the packages Calckey uses. - `client`: Web interface written in Vue3 and TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use -- `megalodon`: TypeScript library used for partial Mastodon API compatibility +- `megalodon`: TypeScript library used for Mastodon API compatibility diff --git a/packages/megalodon/.swcrc b/packages/megalodon/.swcrc new file mode 100644 index 000000000..c590064ec --- /dev/null +++ b/packages/megalodon/.swcrc @@ -0,0 +1,19 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "dynamicImport": true, + "decorators": true + }, + "transform": { + "decoratorMetadata": true + }, + "target": "es2022" + }, + "minify": false, + "module": { + "type": "commonjs", + "strict": true + } +} diff --git a/packages/megalodon/package.json b/packages/megalodon/package.json index 43479b2e7..646b3040b 100644 --- a/packages/megalodon/package.json +++ b/packages/megalodon/package.json @@ -4,7 +4,7 @@ "main": "./lib/src/index.js", "typings": "./lib/src/index.d.ts", "scripts": { - "build": "tsc -p ./", + "build": "pnpm swc src -d lib/src -D", "lint": "eslint --ext .js,.ts src", "doc": "typedoc --out ../docs ./src", "test": "NODE_ENV=test jest -u --maxWorkers=3" @@ -49,6 +49,8 @@ "async-lock": "1.4.0" }, "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.62", "@types/core-js": "^2.5.0", "@types/form-data": "^2.5.0", "@types/jest": "^29.4.0", @@ -77,5 +79,8 @@ "directories": { "lib": "lib", "test": "test" - } + }, + "optionalDependencies": { + "@swc/core-android-arm64": "1.3.11" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b18c93854..b9522c434 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -789,7 +789,7 @@ importers: version: 2.30.0 emojilib: specifier: github:thatonecalculator/emojilib - version: github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e + version: github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b escape-regexp: specifier: 0.0.1 version: 0.0.1 @@ -970,7 +970,17 @@ importers: ws: specifier: 8.12.0 version: 8.12.0 + optionalDependencies: + '@swc/core-android-arm64': + specifier: 1.3.11 + version: 1.3.11 devDependencies: + '@swc/cli': + specifier: ^0.1.62 + version: 0.1.62(@swc/core@1.3.62)(chokidar@3.3.1) + '@swc/core': + specifier: ^1.3.62 + version: 1.3.62 '@types/async-lock': specifier: 1.4.0 version: 1.4.0 @@ -17429,8 +17439,8 @@ packages: url-polyfill: 1.1.12 dev: true - github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e: - resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/9d16541664dc8fef3201ae9b647477070676a52e} + github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b: + resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/15fd9504f943763a057ff803ee2009ec0524c96b} name: emojilib version: 3.0.10 dev: true From df11946d522de4cc3f5a9b364a438f7f077574fd Mon Sep 17 00:00:00 2001 From: Kainoa Kanter Date: Sat, 8 Jul 2023 16:56:54 +0000 Subject: [PATCH 36/37] revert 679d89fa59bf4628e6e27ca73af8630080d7a063 revert build: :zap: build megalodon with swc Do it right this time --- packages/README.md | 2 +- packages/megalodon/.swcrc | 19 ------------------- packages/megalodon/package.json | 9 ++------- pnpm-lock.yaml | 16 +++------------- 4 files changed, 6 insertions(+), 40 deletions(-) delete mode 100644 packages/megalodon/.swcrc diff --git a/packages/README.md b/packages/README.md index ed4b8f6c4..0ed7c6403 100644 --- a/packages/README.md +++ b/packages/README.md @@ -7,4 +7,4 @@ This directory contains all of the packages Calckey uses. - `client`: Web interface written in Vue3 and TypeScript - `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript - `calckey-js`: TypeScript SDK for both backend and client, also published on [NPM](https://www.npmjs.com/package/calckey-js) for public use -- `megalodon`: TypeScript library used for Mastodon API compatibility +- `megalodon`: TypeScript library used for partial Mastodon API compatibility diff --git a/packages/megalodon/.swcrc b/packages/megalodon/.swcrc deleted file mode 100644 index c590064ec..000000000 --- a/packages/megalodon/.swcrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/swcrc", - "jsc": { - "parser": { - "syntax": "typescript", - "dynamicImport": true, - "decorators": true - }, - "transform": { - "decoratorMetadata": true - }, - "target": "es2022" - }, - "minify": false, - "module": { - "type": "commonjs", - "strict": true - } -} diff --git a/packages/megalodon/package.json b/packages/megalodon/package.json index 646b3040b..43479b2e7 100644 --- a/packages/megalodon/package.json +++ b/packages/megalodon/package.json @@ -4,7 +4,7 @@ "main": "./lib/src/index.js", "typings": "./lib/src/index.d.ts", "scripts": { - "build": "pnpm swc src -d lib/src -D", + "build": "tsc -p ./", "lint": "eslint --ext .js,.ts src", "doc": "typedoc --out ../docs ./src", "test": "NODE_ENV=test jest -u --maxWorkers=3" @@ -49,8 +49,6 @@ "async-lock": "1.4.0" }, "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.62", "@types/core-js": "^2.5.0", "@types/form-data": "^2.5.0", "@types/jest": "^29.4.0", @@ -79,8 +77,5 @@ "directories": { "lib": "lib", "test": "test" - }, - "optionalDependencies": { - "@swc/core-android-arm64": "1.3.11" - } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9522c434..b18c93854 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -789,7 +789,7 @@ importers: version: 2.30.0 emojilib: specifier: github:thatonecalculator/emojilib - version: github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b + version: github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e escape-regexp: specifier: 0.0.1 version: 0.0.1 @@ -970,17 +970,7 @@ importers: ws: specifier: 8.12.0 version: 8.12.0 - optionalDependencies: - '@swc/core-android-arm64': - specifier: 1.3.11 - version: 1.3.11 devDependencies: - '@swc/cli': - specifier: ^0.1.62 - version: 0.1.62(@swc/core@1.3.62)(chokidar@3.3.1) - '@swc/core': - specifier: ^1.3.62 - version: 1.3.62 '@types/async-lock': specifier: 1.4.0 version: 1.4.0 @@ -17439,8 +17429,8 @@ packages: url-polyfill: 1.1.12 dev: true - github.com/thatonecalculator/emojilib/15fd9504f943763a057ff803ee2009ec0524c96b: - resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/15fd9504f943763a057ff803ee2009ec0524c96b} + github.com/thatonecalculator/emojilib/9d16541664dc8fef3201ae9b647477070676a52e: + resolution: {tarball: https://codeload.github.com/thatonecalculator/emojilib/tar.gz/9d16541664dc8fef3201ae9b647477070676a52e} name: emojilib version: 3.0.10 dev: true From 5bd5a8cc65f69a5ed1e8b826e67cd20ba0bec810 Mon Sep 17 00:00:00 2001 From: freeplay Date: Sat, 8 Jul 2023 13:06:16 -0400 Subject: [PATCH 37/37] fix: banner blur --- packages/client/src/pages/user/home.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue index 24b150bc4..54e4ab10c 100644 --- a/packages/client/src/pages/user/home.vue +++ b/packages/client/src/pages/user/home.vue @@ -26,7 +26,7 @@ class="banner" :style="{ backgroundImage: `url('${user.bannerUrl}')`, - '--backgroundImageStatic': getStaticImageUrl(user.bannerUrl) + '--backgroundImageStatic': defaultStore.state.useBlurEffect ? `url('${getStaticImageUrl(user.bannerUrl)}')` : null }" >
@@ -388,6 +388,7 @@ import { getScrollPosition } from "@/scripts/scroll"; import { getStaticImageUrl } from "@/scripts/get-static-image-url"; import number from "@/filters/number"; import { userPage } from "@/filters/user"; +import { defaultStore } from "@/store"; import * as os from "@/os"; import { i18n } from "@/i18n"; import { $i } from "@/account"; @@ -515,7 +516,7 @@ onUnmounted(() => { content: ""; position: fixed; inset: 0; - background: var(--blur, --backgroundImageStatic); + background: var(--backgroundImageStatic); background-size: cover; background-position: center; pointer-events: none;