diff --git a/README.md b/README.md index aad5b4d8b3..2926f7a63b 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ pm2 start "NODE_ENV=production pnpm run start" --name Firefish - When editing the config file, please don't fill out the settings at the bottom. They're designed *only* for managed hosting, not self hosting. Those settings are much better off being set in Firefish's control panel. - Port 3000 (used in the default config) might be already used on your server for something else. To find an open port for Firefish, run `for p in {3000..4000}; do ss -tlnH | tr -s ' ' | cut -d" " -sf4 | grep -q "${p}$" || echo "${p}"; done | head -n 1`. Replace 3000 with the minimum port and 4000 with the maximum port if you need it. - I'd recommend you use a S3 Bucket/CDN for Object Storage, especially if you use Docker. +- When using object storage, setting a proper `Access-Control-Allow-Origin` response header is highly recommended. - I'd ***strongly*** recommend against using CloudFlare, but if you do, make sure to turn code minification off. - For push notifications, run `npx web-push generate-vapid-keys`, then put the public and private keys into Control Panel > General > ServiceWorker. - For translations, make a [DeepL](https://deepl.com) account and generate an API key, then put it into Control Panel > General > DeepL Translation. diff --git a/custom/assets/badges/error.avif b/custom/assets/badges/error.avif new file mode 100644 index 0000000000..f6f507a5b5 Binary files /dev/null and b/custom/assets/badges/error.avif differ diff --git a/custom/assets/badges/error.png b/custom/assets/badges/error.png deleted file mode 100644 index 046f18e149..0000000000 Binary files a/custom/assets/badges/error.png and /dev/null differ diff --git a/custom/assets/badges/info.avif b/custom/assets/badges/info.avif new file mode 100644 index 0000000000..6a66997a28 Binary files /dev/null and b/custom/assets/badges/info.avif differ diff --git a/custom/assets/badges/info.png b/custom/assets/badges/info.png deleted file mode 100644 index c6ab300a72..0000000000 Binary files a/custom/assets/badges/info.png and /dev/null differ diff --git a/custom/assets/badges/not-found.avif b/custom/assets/badges/not-found.avif new file mode 100644 index 0000000000..dd27b7470a Binary files /dev/null and b/custom/assets/badges/not-found.avif differ diff --git a/custom/assets/badges/not-found.png b/custom/assets/badges/not-found.png deleted file mode 100644 index 63356530ce..0000000000 Binary files a/custom/assets/badges/not-found.png and /dev/null differ diff --git a/docs/migrate.md b/docs/migrate.md index 6569d419e5..e687b4ee64 100644 --- a/docs/migrate.md +++ b/docs/migrate.md @@ -103,4 +103,4 @@ NODE_ENV=production pnpm run migrate ## Reverse -You ***cannot*** migrate back to Misskey from Firefish due to re-hashing passwords on signin with argon2. You can migrate from Firefish to FoundKey, although this is not recommended due to FoundKey being end-of-life, and may have some problems with alt-text. +You ***cannot*** migrate back to Misskey from Firefish due to re-hashing passwords on signin with argon2. You can migrate to [Sharkey](https://github.com/transfem-org/Sharkey), a soft fork of Misskey that uses argon2 though. You can also migrate from Firefish to FoundKey, although this is not recommended due to FoundKey being end-of-life, and may have some problems with alt-text. diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 4c9648739a..9ef01815c5 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -2200,3 +2200,4 @@ languageForTranslation: Idioma de traducció d'articles openServerInfo: Mostra la informació del servidor fent clic al símbol del servidor en un missatge vibrate: Activar vibracions +clickToShowPatterns: Fes clic per veure patrons de mòduls diff --git a/locales/en-US.yml b/locales/en-US.yml index 37de0e0acc..2eaec59af3 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1186,7 +1186,8 @@ _accountDelete: inProgress: "Deletion is currently in progress" _ad: back: "Back" - reduceFrequencyOfThisAd: "Show this ad less" + adsBy: "Community banner by {by}" + reduceFrequencyOfThisAd: "Show this banner less" _forgotPassword: enterEmail: "Enter the email address you used to register. A link with which you can reset your password will then be sent to it." diff --git a/locales/hi.yml b/locales/hi.yml new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/locales/hi.yml @@ -0,0 +1 @@ +{} diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 9ecb4ac304..c4c1ab4bf3 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -626,7 +626,7 @@ emptyToDisableSmtpAuth: "Lasciare username e password vuoti per disabilitare la smtpSecure: "Usa la porta SSL/TLS predefinita per le connessioni SMTP" smtpSecureInfo: "Disabilita quando è attivo STARTTLS" testEmail: "Test di consegna email" -wordMute: "Filtro parole" +wordMute: "Filtro parole e lingua" instanceMute: "Server silenziati" userSaysSomething: "{name} ha detto qualcosa" makeActive: "Attiva" @@ -1084,6 +1084,11 @@ _wordMute: soft: "Moderato" hard: "Severo" mutedNotes: "Post silenziati" + muteLangsDescription2: 'Usa il codice lingua, esempio: en, fr, ja, zh.' + lang: Lingua + langDescription: Nascondi dalla timeline i post in quest'insieme di lingue. + muteLangs: Lingue da non mostrare + muteLangsDescription: Separa andando a capo o con spazi per la condizione OR. _theme: explore: "Esplora temi" install: "Installa un tema" @@ -2164,3 +2169,4 @@ indexable: Indicizzabile languageForTranslation: Linguaggio di traduzione dei post openServerInfo: Mostra informazioni sul server cliccando sul riquadro del server in un post +vibrate: Abilita la vibrazione diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2b82df1f8b..d6df04e65e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1022,7 +1022,8 @@ _accountDelete: inProgress: "削除が進行中" _ad: back: "戻る" - reduceFrequencyOfThisAd: "この広告の表示頻度を下げる" + adsBy: "バナーで{by}" + reduceFrequencyOfThisAd: "このバナーの表示頻度を下げる" _forgotPassword: enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。" ifNoEmail: "メールアドレスを登録していない場合は、管理者までお問い合わせください。" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index bc59ba62a5..5e20452a76 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -12,7 +12,7 @@ ok: "好" gotIt: "知道了!" cancel: "取消" enterUsername: "输入用户名" -renotedBy: "转发自 {user}" +renotedBy: "{user} 转发了" noNotes: "没有帖子" noNotifications: "没有通知" instance: "服务器" @@ -69,7 +69,7 @@ exportRequested: "导出请求已提交,这可能需要花一些时间,导 importRequested: "导入请求已提交,这可能需要花一点时间。" lists: "列表" noLists: "列表为空" -note: "帖子" +note: "发帖" notes: "帖子" following: "关注中" followers: "关注者" @@ -243,7 +243,7 @@ saved: "已保存" messaging: "聊天" upload: "本地上传" keepOriginalUploading: "保留原图" -keepOriginalUploadingDescription: "上传图片时保留原始图片。如果关闭,会在上传时生成一张用于 web 发布的图片。" +keepOriginalUploadingDescription: "上传图片时保留原始图片。如果关闭,会在上传时生成一张用于 Web 发布的图片。" fromDrive: "从网盘中" fromUrl: "从 URL" uploadFromUrl: "从 URL 上传" @@ -690,8 +690,8 @@ useSystemFont: "使用系统默认字体" clips: "便签" experimentalFeatures: "实验性功能" developer: "开发者" -makeExplorable: "使账号在“发现”中可见" -makeExplorableDescription: "关闭时,账号不会显示在\"发现\"中。" +makeExplorable: "使账号在「发现」中可见" +makeExplorableDescription: "关闭时,账号不会显示在「发现」中。" showGapBetweenNotesInTimeline: "时间线上的帖子分开显示" duplicate: "复制" left: "左" @@ -823,8 +823,8 @@ makeReactionsPublicDescription: "将您发表过的回应设置成公开可见 classic: "居中" muteThread: "静音帖子串" unmuteThread: "取消静音帖子串" -ffVisibility: "关注/关注者 可见性" -ffVisibilityDescription: "您可以设置谁可以看到您的关注/关注者信息。" +ffVisibility: "关注 / 关注者可见性" +ffVisibilityDescription: "您可以设置谁可以看到您的关注 / 关注者信息。" continueThread: "查看更多帖子" deleteAccountConfirm: "这将不可逆转地删除账号,是否继续?" incorrectPassword: "密码错误。" @@ -922,7 +922,7 @@ _emailUnavailable: _ffVisibility: public: "公开" followers: "仅对关注者可见" - private: "私信" + private: "私密" _signup: almostThere: "即将完成" emailAddressInfo: "请输入您所使用的电子邮件地址,它不会公开显示。" @@ -1237,11 +1237,11 @@ _tutorial: step4_2: "对于第一条帖子,可以做一个 {introduction} 或一个简单的 \"hello world!\"" step5_1: "时间线,无处不在的时间线!" step5_2: "您的服务器已启用 {timelines} 种不同的时间线。" - step5_3: "主页 {icon} 时间线是您可以看到您关注账号的帖子的时间线。" + step5_3: "首页{icon}时间线是您可以看到您关注账号的帖子的时间线。" step5_4: "本地{icon}时间线是您可以看到此服务器上其它用户的帖子的时间线。" step5_5: "社交{icon}时间线是主页和本地时间线的结合。" step5_6: "推荐{icon}时间线是您可以看到管理员推荐服务器的帖子的时间线。" - step5_7: "全球{icon}时间线是您可以看到来自其它所有互联服务器的帖子的时间线。" + step5_7: "全局{icon}时间线是您可以看到来自其它所有互联服务器的帖子的时间线。" step6_1: "那么,这里是什么地方?" step6_2: "好吧,您不只是加入 Firefish。您已经加入了 Fediverse 的一个门户,这是一个由成千上万台服务器组成的互联网络。" step6_3: "每个服务器的工作方式不同,并不是所有的服务器都运行 Firefish。但这个服务器是的! 这有点复杂,但您很快就会明白的。" diff --git a/package.json b/package.json index 71aa1b2df8..1e1f6a463f 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "packageManager": "pnpm@8.7.6", "private": true, "scripts": { - "rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp", - "build": "./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp", + "rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm --filter !sw -r --parallel run build && pnpm --filter sw run build && pnpm run gulp", + "build": "./scripts/build-greet.sh && pnpm --filter !sw -r --parallel run build && pnpm --filter sw run build && pnpm run gulp", "start": "pnpm --filter backend run start", "start:test": "pnpm --filter backend run start:test", "init": "pnpm run migrate", diff --git a/packages/backend/assets/badges/error.avif b/packages/backend/assets/badges/error.avif new file mode 100644 index 0000000000..f6f507a5b5 Binary files /dev/null and b/packages/backend/assets/badges/error.avif differ diff --git a/packages/backend/assets/badges/error.png b/packages/backend/assets/badges/error.png deleted file mode 100644 index 046f18e149..0000000000 Binary files a/packages/backend/assets/badges/error.png and /dev/null differ diff --git a/packages/backend/assets/badges/info.avif b/packages/backend/assets/badges/info.avif new file mode 100644 index 0000000000..6a66997a28 Binary files /dev/null and b/packages/backend/assets/badges/info.avif differ diff --git a/packages/backend/assets/badges/info.png b/packages/backend/assets/badges/info.png deleted file mode 100644 index c6ab300a72..0000000000 Binary files a/packages/backend/assets/badges/info.png and /dev/null differ diff --git a/packages/backend/assets/badges/not-found.avif b/packages/backend/assets/badges/not-found.avif new file mode 100644 index 0000000000..dd27b7470a Binary files /dev/null and b/packages/backend/assets/badges/not-found.avif differ diff --git a/packages/backend/assets/badges/not-found.png b/packages/backend/assets/badges/not-found.png deleted file mode 100644 index 63356530ce..0000000000 Binary files a/packages/backend/assets/badges/not-found.png and /dev/null differ diff --git a/packages/backend/migration/1000000000000-Init.js b/packages/backend/migration/1000000000000-Init.js index bab5fae7a0..d736f6b8ee 100644 --- a/packages/backend/migration/1000000000000-Init.js +++ b/packages/backend/migration/1000000000000-Init.js @@ -220,7 +220,7 @@ export class Init1000000000000 { `CREATE INDEX "IDX_3c601b70a1066d2c8b517094cb" ON "notification" ("notifieeId") `, ); await queryRunner.query( - `CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/static-assets/badges/info.png', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT '/static-assets/badges/error.png', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT false, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`, + `CREATE TABLE "meta" ("id" character varying(32) NOT NULL, "name" character varying(128), "description" character varying(1024), "maintainerName" character varying(128), "maintainerEmail" character varying(128), "announcements" jsonb NOT NULL DEFAULT '[]', "disableRegistration" boolean NOT NULL DEFAULT false, "disableLocalTimeline" boolean NOT NULL DEFAULT false, "disableGlobalTimeline" boolean NOT NULL DEFAULT false, "enableEmojiReaction" boolean NOT NULL DEFAULT true, "useStarForReactionFallback" boolean NOT NULL DEFAULT false, "langs" character varying(64) array NOT NULL DEFAULT '{}'::varchar[], "hiddenTags" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "blockedHosts" character varying(256) array NOT NULL DEFAULT '{}'::varchar[], "mascotImageUrl" character varying(512) DEFAULT '/static-assets/badges/info.avif', "bannerUrl" character varying(512), "errorImageUrl" character varying(512) DEFAULT '/static-assets/badges/error.avif', "iconUrl" character varying(512), "cacheRemoteFiles" boolean NOT NULL DEFAULT false, "proxyAccount" character varying(128), "enableRecaptcha" boolean NOT NULL DEFAULT false, "recaptchaSiteKey" character varying(64), "recaptchaSecretKey" character varying(64), "localDriveCapacityMb" integer NOT NULL DEFAULT 1024, "remoteDriveCapacityMb" integer NOT NULL DEFAULT 32, "maxNoteTextLength" integer NOT NULL DEFAULT 500, "summalyProxy" character varying(128), "enableEmail" boolean NOT NULL DEFAULT false, "email" character varying(128), "smtpSecure" boolean NOT NULL DEFAULT false, "smtpHost" character varying(128), "smtpPort" integer, "smtpUser" character varying(128), "smtpPass" character varying(128), "enableServiceWorker" boolean NOT NULL DEFAULT false, "swPublicKey" character varying(128), "swPrivateKey" character varying(128), "enableTwitterIntegration" boolean NOT NULL DEFAULT false, "twitterConsumerKey" character varying(128), "twitterConsumerSecret" character varying(128), "enableGithubIntegration" boolean NOT NULL DEFAULT false, "githubClientId" character varying(128), "githubClientSecret" character varying(128), "enableDiscordIntegration" boolean NOT NULL DEFAULT false, "discordClientId" character varying(128), "discordClientSecret" character varying(128), CONSTRAINT "PK_c4c17a6c2bd7651338b60fc590b" PRIMARY KEY ("id"))`, ); await queryRunner.query( `CREATE TABLE "following" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "followeeId" character varying(32) NOT NULL, "followerId" character varying(32) NOT NULL, "followerHost" character varying(128), "followerInbox" character varying(512), "followerSharedInbox" character varying(512), "followeeHost" character varying(128), "followeeInbox" character varying(512), "followeeSharedInbox" character varying(512), CONSTRAINT "PK_c76c6e044bdf76ecf8bfb82a645" PRIMARY KEY ("id"))`, diff --git a/packages/backend/src/misc/detect-language.ts b/packages/backend/src/misc/detect-language.ts new file mode 100644 index 0000000000..6147247dee --- /dev/null +++ b/packages/backend/src/misc/detect-language.ts @@ -0,0 +1,11 @@ +import { detect } from "tinyld"; +import * as mfm from "mfm-js"; + +export default function detectLanguage(text: string): string { + const nodes = mfm.parse(text); + const filtered = mfm.extract(nodes, (node) => { + return node.type === "text" || node.type === "quote"; + }); + const purified = mfm.toString(filtered); + return detect(purified); +} diff --git a/packages/backend/src/misc/nyaize.ts b/packages/backend/src/misc/nyaize.ts index 13a112ce57..32c54fbd7b 100644 --- a/packages/backend/src/misc/nyaize.ts +++ b/packages/backend/src/misc/nyaize.ts @@ -1,28 +1,31 @@ -export function nyaize(text: string): string { - return ( - text - // ja-JP - .replaceAll("な", "にゃ") - .replaceAll("ナ", "ニャ") - .replaceAll("ナ", "ニャ") - // en-US - .replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya")) - .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) - .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) - .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => - x === "NON" ? "NYAN" : "nyan", - ) - // ko-KR - .replace(/[나-낳]/g, (match) => - String.fromCharCode( - match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), - ), - ) - .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") - .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") - // el-GR - .replaceAll("να", "νια") - .replaceAll("ΝΑ", "ΝΙΑ") - .replaceAll("Να", "Νια") - ); +export function nyaize(text: string, lang?: string): string { + text = text + // ja-JP + .replaceAll("な", "にゃ") + .replaceAll("ナ", "ニャ") + .replaceAll("ナ", "ニャ") + // en-US + .replace(/(?<=n)a/gi, (x) => (x === "A" ? "YA" : "ya")) + .replace(/(?<=morn)ing/gi, (x) => (x === "ING" ? "YAN" : "yan")) + .replace(/(?<=every)one/gi, (x) => (x === "ONE" ? "NYAN" : "nyan")) + .replace(/non(?=[bcdfghjklmnpqrstvwxyz])/gi, (x) => + x === "NON" ? "NYAN" : "nyan", + ) + // ko-KR + .replace(/[나-낳]/g, (match) => + String.fromCharCode( + match.charCodeAt(0)! + "냐".charCodeAt(0) - "나".charCodeAt(0), + ), + ) + .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥") + .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥") + // el-GR + .replaceAll("να", "νια") + .replaceAll("ΝΑ", "ΝΙΑ") + .replaceAll("Να", "Νια"); + + // zh-CN, zh-TW + if (lang === "zh") text = text.replace(/(妙|庙|描|渺|瞄|秒|苗|藐|廟)/g, "喵"); + + return text; } diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 9fbe30449b..ad7238da52 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -162,7 +162,7 @@ export class Meta { @Column("varchar", { length: 512, nullable: true, - default: "/static-assets/badges/info.png", + default: "/static-assets/badges/info.avif", }) public mascotImageUrl: string | null; @@ -187,7 +187,7 @@ export class Meta { @Column("varchar", { length: 512, nullable: true, - default: "/static-assets/badges/error.png", + default: "/static-assets/badges/error.avif", }) public errorImageUrl: string | null; diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index e7d9191a2c..890178109c 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -34,7 +34,7 @@ import { } from "@/db/scylla.js"; import { LocalFollowingsCache } from "@/misc/cache.js"; import { userByIdCache } from "@/services/user-cache.js"; -import { detect as detectLanguage } from "tinyld"; +// import detectLanguage from "@/misc/detect-language.js"; export async function populatePoll( note: Note | ScyllaNote, @@ -279,7 +279,7 @@ export const NoteRepository = db.getRepository(Note).extend({ let text = note.text; if (note.name && (note.url ?? note.uri)) { - text = `【${note.name}】\n${(note.text || "").trim()}\n\n${ + text = `${note.name}\n${(note.text || "").trim()}\n\n${ note.url ?? note.uri }`; } @@ -381,7 +381,8 @@ export const NoteRepository = db.getRepository(Note).extend({ const tokens = packed.text ? mfm.parse(packed.text) : []; function nyaizeNode(node: mfm.MfmNode) { if (node.type === "quote") return; - if (node.type === "text") node.props.text = nyaize(node.props.text); + if (node.type === "text") + node.props.text = nyaize(node.props.text, packed.lang); if (node.children) { for (const child of node.children) { diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts index d625308f00..61c20a898f 100644 --- a/packages/backend/src/models/schema/user.ts +++ b/packages/backend/src/models/schema/user.ts @@ -24,7 +24,7 @@ export const packedUserLiteSchema = { type: "string", nullable: true, optional: false, - example: "misskey.example.com", + example: "firefish.example.com", description: "The local host is represented with `null`.", }, avatarUrl: { diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 5be2363afe..d1e85890e6 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -306,7 +306,10 @@ export async function createPerson( tags, isBot, isCat: (person as any).isCat === true, - speakAsCat: (person as any).speakAsCat === true, + speakAsCat: + person.speakAsCat != null + ? person.speakAsCat === true + : (person as any).isCat === true, isIndexable: person.indexable, }), )) as IRemoteUser; @@ -557,7 +560,10 @@ export async function updatePerson( tags, isBot: getApType(object) !== "Person", isCat: (person as any).isCat === true, - speakAsCat: (person as any).speakAsCat === true, + speakAsCat: + person.speakAsCat != null + ? person.speakAsCat === true + : (person as any).isCat === true, isIndexable: person.indexable, isLocked: !!person.manuallyApprovesFollowers, movedToUri: person.movedTo || null, diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts index 1571e7ba58..ce93bc7768 100644 --- a/packages/backend/src/remote/activitypub/renderer/note.ts +++ b/packages/backend/src/remote/activitypub/renderer/note.ts @@ -1,12 +1,12 @@ import { In, IsNull } from "typeorm"; -import { detect as detectLanguage } from "tinyld"; import config from "@/config/index.js"; import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js"; import type { Emoji } from "@/models/entities/emoji.js"; import type { Poll } from "@/models/entities/poll.js"; -import toHtml from "../misc/get-note-html.js"; +import toHtml from "@/remote/activitypub/misc/get-note-html.js"; +import detectLanguage from "@/misc/detect-language.js"; import renderEmoji from "./emoji.js"; import renderMention from "./mention.js"; import renderHashtag from "./hashtag.js"; diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 9abb57b1b3..098271793e 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -64,7 +64,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/info.png", + default: "/static-assets/badges/info.avif", }, bannerUrl: { type: "string", @@ -75,7 +75,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/error.png", + default: "/static-assets/badges/error.avif", }, iconUrl: { type: "string", diff --git a/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts b/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts index db12ab6c23..ac0e0528ad 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-mod-mail.ts @@ -49,7 +49,7 @@ export default define(meta, paramDef, async (ps) => { createNotification(user.id, "app", { customBody: ps.comment, customHeader: "Moderation Notice", - customIcon: "/static-assets/badges/info.png", + customIcon: "/static-assets/badges/info.avif", }); setImmediate(async () => { diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index fc8235ea60..b7905e583f 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -155,7 +155,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/info.png", + default: "/static-assets/badges/info.avif", }, bannerUrl: { type: "string", @@ -166,7 +166,7 @@ export const meta = { type: "string", optional: false, nullable: false, - default: "/static-assets/badges/error.png", + default: "/static-assets/badges/error.avif", }, iconUrl: { type: "string", diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts index 2a8f8214ec..389a70940f 100644 --- a/packages/backend/src/server/api/endpoints/notes/edit.ts +++ b/packages/backend/src/server/api/endpoints/notes/edit.ts @@ -44,8 +44,10 @@ import { parseHomeTimeline, } from "@/db/scylla.js"; import type { Client } from "cassandra-driver"; -import { detect as detectLanguage } from "tinyld"; +// import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; import { langmap } from "@/misc/langmap.js"; +import detectLanguage from "@/misc/detect-language.js"; export const meta = { tags: ["notes"], diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index c3e6946e2f..bc95d77769 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -12,6 +12,7 @@ import { convertPoll, convertStatus, } from "../converters.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; function normalizeQuery(data: any) { const str = querystring.stringify(data); @@ -216,10 +217,11 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/favourite", async (ctx) => { + const meta = await fetchMeta(); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); - const react = await getFirstReaction(BASE_URL, accessTokens); + const react = meta.defaultReaction; try { const a = (await client.createEmojiReaction( convertId(ctx.params.id, IdType.FirefishId), @@ -238,10 +240,11 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/unfavourite", async (ctx) => { + const meta = await fetchMeta(); const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; const accessTokens = ctx.headers.authorization; const client = getClient(BASE_URL, accessTokens); - const react = await getFirstReaction(BASE_URL, accessTokens); + const react = meta.defaultReaction; try { const data = await client.deleteEmojiReaction( convertId(ctx.params.id, IdType.FirefishId), @@ -476,25 +479,3 @@ export function apiStatusMastodon(router: Router): void { }, ); } - -async function getFirstReaction( - BASE_URL: string, - accessTokens: string | undefined, -) { - const accessTokenArr = accessTokens?.split(" ") ?? [null]; - const accessToken = accessTokenArr[accessTokenArr.length - 1]; - let react = "⭐"; - try { - const api = await axios.post(`${BASE_URL}/api/i/registry/get-unsecure`, { - scope: ["client", "base"], - key: "reactions", - i: accessToken, - }); - const reactRaw = api.data; - react = Array.isArray(reactRaw) ? api.data[0] : "⭐"; - console.log(api.data); - return react; - } catch (e) { - return react; - } -} diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 886e7aa9be..cc5595caf3 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -36,9 +36,9 @@ html link(rel='icon' href= icon || `/favicon.ico?${ timestamp }`) link(rel='apple-touch-icon' href= icon || `/apple-touch-icon.png?${ timestamp }`) link(rel='manifest' href='/manifest.json') - link(rel='prefetch' href=`/static-assets/badges/info.png?${ timestamp }`) - link(rel='prefetch' href=`/static-assets/badges/not-found.png?${ timestamp }`) - link(rel='prefetch' href=`/static-assets/badges/error.png?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/info.avif?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/not-found.avif?${ timestamp }`) + link(rel='prefetch' href=`/static-assets/badges/error.avif?${ timestamp }`) link(rel='stylesheet' href=`/static-assets/instance.css?${ timestamp }`) link(rel='modulepreload' href=`/assets/${clientEntry.file}`) diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 3e61dcfd23..fb989f33ee 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -70,7 +70,7 @@ import type { UserProfile } from "@/models/entities/user-profile.js"; import { db } from "@/db/postgre.js"; import { getActiveWebhooks } from "@/misc/webhook-cache.js"; import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; -import meilisearch from "../../db/meilisearch.js"; +import meilisearch from "@/db/meilisearch.js"; import { redisClient } from "@/db/redis.js"; import { Mutex } from "redis-semaphore"; import { @@ -81,8 +81,8 @@ import { ScyllaPoll, } from "@/db/scylla.js"; import { userByIdCache, userDenormalizedCache } from "../user-cache.js"; -import { detect as detectLanguage } from "tinyld"; import { langmap } from "@/misc/langmap.js"; +import detectLanguage from "@/misc/detect-language.js"; export const mutedWordsCache = new Cache< { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 86e254aebf..28d5468ecf 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -15,7 +15,7 @@ import { failedApiCall, uploadFile, } from "../utils.js"; -import type * as misskey from "misskey-js"; +import type * as firefish from "firefish-js"; import type { INestApplicationContext } from "@nestjs/common"; describe("ユーザー", () => { @@ -34,16 +34,16 @@ describe("ユーザー", () => { }; // BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う - type UserLite = misskey.entities.UserLite & { + type UserLite = firefish.entities.UserLite & { badgeRoles: any[]; }; type UserDetailedNotMe = UserLite & - misskey.entities.UserDetailed & { + firefish.entities.UserDetailed & { roles: any[]; }; - type MeDetailed = UserDetailedNotMe & misskey.entities.MeDetailed; + type MeDetailed = UserDetailedNotMe & firefish.entities.MeDetailed; type User = MeDetailed & { token: string }; @@ -183,12 +183,12 @@ describe("ユーザー", () => { let root: User; let alice: User; - let aliceNote: misskey.entities.Note; - let alicePage: misskey.entities.Page; - let aliceList: misskey.entities.UserList; + let aliceNote: firefish.entities.Note; + let alicePage: firefish.entities.Page; + let aliceList: firefish.entities.UserList; let bob: User; - let bobNote: misskey.entities.Note; + let bobNote: firefish.entities.Note; let carol: User; let dave: User; diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 79d622b54b..ff2dd79de9 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -6,7 +6,7 @@ import * as childProcess from "child_process"; import * as http from "node:http"; import { SIGKILL } from "constants"; import WebSocket from "ws"; -import * as misskey from "firefish-js"; +import * as firefish from "firefish-js"; import fetch from "node-fetch"; import FormData from "form-data"; import { DataSource } from "typeorm"; @@ -113,8 +113,8 @@ export const signup = async (params?: any): Promise => { export const post = async ( user: any, - params?: misskey.Endpoints["notes/create"]["req"], -): Promise => { + params?: firefish.Endpoints["notes/create"]["req"], +): Promise => { const q = Object.assign( { text: "test", diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index 13408b525d..bb526846e1 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -1,5 +1,5 @@ import { defineAsyncComponent, reactive } from "vue"; -import type * as misskey from "firefish-js"; +import type * as firefish from "firefish-js"; import { i18n } from "./i18n"; import { del, get, set } from "@/scripts/idb-proxy"; import { apiUrl } from "@/config"; @@ -8,7 +8,7 @@ import { reloadChannel, unisonReload } from "@/scripts/unison-reload"; // TODO: 他のタブと永続化されたstateを同期 -type Account = misskey.entities.MeDetailed; +type Account = firefish.entities.MeDetailed; const accountData = localStorage.getItem("account"); @@ -150,8 +150,8 @@ export async function openAccountMenu( opts: { includeCurrentAccount?: boolean; withExtraOperation: boolean; - active?: misskey.entities.UserDetailed["id"]; - onChoose?: (account: misskey.entities.UserDetailed) => void; + active?: firefish.entities.UserDetailed["id"]; + onChoose?: (account: firefish.entities.UserDetailed) => void; }, ev: MouseEvent, ) { @@ -183,7 +183,7 @@ export async function openAccountMenu( ); } - async function switchAccount(account: misskey.entities.UserDetailed) { + async function switchAccount(account: firefish.entities.UserDetailed) { const storedAccounts = await getAccounts(); const token = storedAccounts.find((x) => x.id === account.id).token; switchAccountWithToken(token); @@ -200,7 +200,7 @@ export async function openAccountMenu( userIds: storedAccounts.map((x) => x.id), }); - function createItem(account: misskey.entities.UserDetailed) { + function createItem(account: firefish.entities.UserDetailed) { return { type: "user", user: account, diff --git a/packages/client/src/components/MkAbuseReportWindow.vue b/packages/client/src/components/MkAbuseReportWindow.vue index ed4737894a..3839789436 100644 --- a/packages/client/src/components/MkAbuseReportWindow.vue +++ b/packages/client/src/components/MkAbuseReportWindow.vue @@ -41,7 +41,7 @@ diff --git a/packages/client/src/components/MkDriveWindow.vue b/packages/client/src/components/MkDriveWindow.vue index 24daea977b..f116b6e8f5 100644 --- a/packages/client/src/components/MkDriveWindow.vue +++ b/packages/client/src/components/MkDriveWindow.vue @@ -15,13 +15,13 @@ diff --git a/packages/client/src/components/MkNoteSub.vue b/packages/client/src/components/MkNoteSub.vue index 99dc6e6521..73f45b2fa6 100644 --- a/packages/client/src/components/MkNoteSub.vue +++ b/packages/client/src/components/MkNoteSub.vue @@ -191,9 +191,8 @@