parent
ec45db7870
commit
30efd932a5
@ -30,7 +30,8 @@
|
|||||||
- Enhance: ストリーミングAPIのパフォーマンスを向上
|
- Enhance: ストリーミングAPIのパフォーマンスを向上
|
||||||
- Fix: users/notesでDBから参照した際にチャンネル投稿のみ取得される問題を修正
|
- Fix: users/notesでDBから参照した際にチャンネル投稿のみ取得される問題を修正
|
||||||
- Fix: コントロールパネルの設定項目が正しく保存できない問題を修正
|
- Fix: コントロールパネルの設定項目が正しく保存できない問題を修正
|
||||||
- Change: nyaizeはAPIレスポンス時ではなく投稿時に一度だけ非可逆的に行われるようになりました
|
- Change: ユーザーのisCatがtrueでも、サーバーではnyaizeが行われなくなりました
|
||||||
|
- isCatな場合、クライアントでnyaize処理を行うことを推奨します
|
||||||
|
|
||||||
## 2023.10.1
|
## 2023.10.1
|
||||||
### General
|
### General
|
||||||
|
@ -227,8 +227,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
isBot: MiUser['isBot'];
|
isBot: MiUser['isBot'];
|
||||||
isCat: MiUser['isCat'];
|
isCat: MiUser['isCat'];
|
||||||
}, data: Option, silent = false): Promise<MiNote> {
|
}, data: Option, silent = false): Promise<MiNote> {
|
||||||
let patsedText: mfm.MfmNode[] | null = null;
|
|
||||||
|
|
||||||
// チャンネル外にリプライしたら対象のスコープに合わせる
|
// チャンネル外にリプライしたら対象のスコープに合わせる
|
||||||
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
|
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
|
||||||
if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
|
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.slice(0, DB_MAX_NOTE_TEXT_LENGTH);
|
||||||
}
|
}
|
||||||
data.text = data.text.trim();
|
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 {
|
} else {
|
||||||
data.text = null;
|
data.text = null;
|
||||||
}
|
}
|
||||||
@ -344,7 +323,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
|
|
||||||
// Parse MFM if needed
|
// Parse MFM if needed
|
||||||
if (!tags || !emojis || !mentionedUsers) {
|
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 cwTokens = data.cw ? mfm.parse(data.cw)! : [];
|
||||||
const choiceTokens = data.poll && data.poll.choices
|
const choiceTokens = data.poll && data.poll.choices
|
||||||
? concat(data.poll.choices.map(choice => mfm.parse(choice)!))
|
? concat(data.poll.choices.map(choice => mfm.parse(choice)!))
|
||||||
|
@ -17,6 +17,7 @@ import MkSparkle from '@/components/MkSparkle.vue';
|
|||||||
import MkA from '@/components/global/MkA.vue';
|
import MkA from '@/components/global/MkA.vue';
|
||||||
import { host } from '@/config.js';
|
import { host } from '@/config.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
import { nyaize } from '@/scripts/nyaize.js';
|
||||||
|
|
||||||
const QUOTE_STYLE = `
|
const QUOTE_STYLE = `
|
||||||
display: block;
|
display: block;
|
||||||
@ -55,10 +56,13 @@ export default function(props: {
|
|||||||
* @param ast MFM AST
|
* @param ast MFM AST
|
||||||
* @param scale How times large the text is
|
* @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) {
|
switch (token.type) {
|
||||||
case 'text': {
|
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) {
|
if (!props.plain) {
|
||||||
const res: (VNode | string)[] = [];
|
const res: (VNode | string)[] = [];
|
||||||
@ -260,7 +264,7 @@ export default function(props: {
|
|||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
url: token.props.url,
|
url: token.props.url,
|
||||||
rel: 'nofollow noopener',
|
rel: 'nofollow noopener',
|
||||||
}, genEl(token.children, scale))];
|
}, genEl(token.children, scale, true))];
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'mention': {
|
case 'mention': {
|
||||||
@ -299,11 +303,11 @@ export default function(props: {
|
|||||||
if (!props.nowrap) {
|
if (!props.nowrap) {
|
||||||
return [h('div', {
|
return [h('div', {
|
||||||
style: QUOTE_STYLE,
|
style: QUOTE_STYLE,
|
||||||
}, genEl(token.children, scale))];
|
}, genEl(token.children, scale, true))];
|
||||||
} else {
|
} else {
|
||||||
return [h('span', {
|
return [h('span', {
|
||||||
style: QUOTE_STYLE,
|
style: QUOTE_STYLE,
|
||||||
}, genEl(token.children, scale))];
|
}, genEl(token.children, scale, true))];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +362,7 @@ export default function(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'plain': {
|
case 'plain': {
|
||||||
return [h('span', genEl(token.children, scale))];
|
return [h('span', genEl(token.children, scale, true))];
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
20
packages/frontend/src/scripts/nyaize.ts
Normal file
20
packages/frontend/src/scripts/nyaize.ts
Normal file
@ -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, '냥');
|
||||||
|
}
|
@ -2977,6 +2977,8 @@ type UserLite = {
|
|||||||
faviconUrl: Instance['faviconUrl'];
|
faviconUrl: Instance['faviconUrl'];
|
||||||
themeColor: Instance['themeColor'];
|
themeColor: Instance['themeColor'];
|
||||||
};
|
};
|
||||||
|
isCat?: boolean;
|
||||||
|
isBot?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @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: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: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/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:109: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: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
|
// 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)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
@ -28,6 +28,8 @@ export type UserLite = {
|
|||||||
faviconUrl: Instance['faviconUrl'];
|
faviconUrl: Instance['faviconUrl'];
|
||||||
themeColor: Instance['themeColor'];
|
themeColor: Instance['themeColor'];
|
||||||
};
|
};
|
||||||
|
isCat?: boolean;
|
||||||
|
isBot?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserDetailed = UserLite & {
|
export type UserDetailed = UserLite & {
|
||||||
|
Loading…
Reference in New Issue
Block a user