diff --git a/CHANGELOG.md b/CHANGELOG.md index ee2d39cde..8f895f800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,8 @@ - Enhance: ストリーミングAPIのパフォーマンスを向上 - Fix: users/notesでDBから参照した際にチャンネル投稿のみ取得される問題を修正 - Fix: コントロールパネルの設定項目が正しく保存できない問題を修正 -- Change: nyaizeはAPIレスポンス時ではなく投稿時に一度だけ非可逆的に行われるようになりました +- Change: ユーザーのisCatがtrueでも、サーバーではnyaizeが行われなくなりました + - isCatな場合、クライアントでnyaize処理を行うことを推奨します ## 2023.10.1 ### General diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 2c00418c4..f5cfe0312 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -227,8 +227,6 @@ export class NoteCreateService implements OnApplicationShutdown { isBot: MiUser['isBot']; isCat: MiUser['isCat']; }, data: Option, silent = false): Promise { - let patsedText: mfm.MfmNode[] | null = null; - // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { @@ -315,25 +313,6 @@ export class NoteCreateService implements OnApplicationShutdown { data.text = data.text.slice(0, DB_MAX_NOTE_TEXT_LENGTH); } data.text = data.text.trim(); - - if (user.isCat) { - patsedText = mfm.parse(data.text); - function nyaizeNode(node: mfm.MfmNode) { - if (node.type === 'quote') return; - if (node.type === 'text') { - node.props.text = nyaize(node.props.text); - } - if (node.children) { - for (const child of node.children) { - nyaizeNode(child); - } - } - } - for (const node of patsedText) { - nyaizeNode(node); - } - data.text = mfm.toString(patsedText); - } } else { data.text = null; } @@ -344,7 +323,7 @@ export class NoteCreateService implements OnApplicationShutdown { // Parse MFM if needed if (!tags || !emojis || !mentionedUsers) { - const tokens = patsedText ?? (data.text ? mfm.parse(data.text)! : []); + const tokens = (data.text ? mfm.parse(data.text)! : []); const cwTokens = data.cw ? mfm.parse(data.cw)! : []; const choiceTokens = data.poll && data.poll.choices ? concat(data.poll.choices.map(choice => mfm.parse(choice)!)) diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index 2ae3fc89c..ea3655f6b 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -17,6 +17,7 @@ import MkSparkle from '@/components/MkSparkle.vue'; import MkA from '@/components/global/MkA.vue'; import { host } from '@/config.js'; import { defaultStore } from '@/store.js'; +import { nyaize } from '@/scripts/nyaize.js'; const QUOTE_STYLE = ` display: block; @@ -55,10 +56,13 @@ export default function(props: { * @param ast MFM AST * @param scale How times large the text is */ - const genEl = (ast: mfm.MfmNode[], scale: number) => ast.map((token): VNode | string | (VNode | string)[] => { + const genEl = (ast: mfm.MfmNode[], scale: number, disableNyaize = false) => ast.map((token): VNode | string | (VNode | string)[] => { switch (token.type) { case 'text': { - const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); + let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); + if (!disableNyaize && props.author.isCat) { + text = nyaize(text); + } if (!props.plain) { const res: (VNode | string)[] = []; @@ -260,7 +264,7 @@ export default function(props: { key: Math.random(), url: token.props.url, rel: 'nofollow noopener', - }, genEl(token.children, scale))]; + }, genEl(token.children, scale, true))]; } case 'mention': { @@ -299,11 +303,11 @@ export default function(props: { if (!props.nowrap) { return [h('div', { style: QUOTE_STYLE, - }, genEl(token.children, scale))]; + }, genEl(token.children, scale, true))]; } else { return [h('span', { style: QUOTE_STYLE, - }, genEl(token.children, scale))]; + }, genEl(token.children, scale, true))]; } } @@ -358,7 +362,7 @@ export default function(props: { } case 'plain': { - return [h('span', genEl(token.children, scale))]; + return [h('span', genEl(token.children, scale, true))]; } default: { diff --git a/packages/frontend/src/scripts/nyaize.ts b/packages/frontend/src/scripts/nyaize.ts new file mode 100644 index 000000000..0ac77e100 --- /dev/null +++ b/packages/frontend/src/scripts/nyaize.ts @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +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') + // ko-KR + .replace(/[나-낳]/g, match => String.fromCharCode( + match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0), + )) + .replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, '다냥') + .replace(/(야(?=\?))|(야$)|(야(?= ))/gm, '냥'); +} diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 895f34689..54bbfae14 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2977,6 +2977,8 @@ type UserLite = { faviconUrl: Instance['faviconUrl']; themeColor: Instance['themeColor']; }; + isCat?: boolean; + isBot?: boolean; }; // @public (undocumented) @@ -2987,8 +2989,8 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:633:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts -// src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts -// src/entities.ts:603:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:109:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts +// src/entities.ts:605:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index e05412abb..659045bd6 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -28,6 +28,8 @@ export type UserLite = { faviconUrl: Instance['faviconUrl']; themeColor: Instance['themeColor']; }; + isCat?: boolean; + isBot?: boolean; }; export type UserDetailed = UserLite & {