perf: ノート毎にミュートワードを渡すのをやめる
This commit is contained in:
parent
9a71514b4c
commit
cc1fdece65
|
@ -24,6 +24,7 @@ import { emojiPicker } from '@/scripts/emoji-picker.js';
|
|||
import { mainRouter } from '@/router/main.js';
|
||||
import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
|
||||
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
||||
import { initMuteInfo } from '@/scripts/check-word-mute.js';
|
||||
|
||||
export async function mainBoot() {
|
||||
const { isClientUpdated } = await common(() => {
|
||||
|
@ -343,11 +344,14 @@ export async function mainBoot() {
|
|||
}
|
||||
}
|
||||
|
||||
initMuteInfo();
|
||||
|
||||
const main = markRaw(stream.useChannel('main', null, 'System'));
|
||||
|
||||
// 自分の情報が更新されたとき
|
||||
main.on('meUpdated', i => {
|
||||
updateAccountPartial(i);
|
||||
initMuteInfo();
|
||||
});
|
||||
|
||||
main.on('readAllNotifications', () => {
|
||||
|
|
|
@ -280,8 +280,8 @@ const urls = computed(() => parsed.value ? extractUrlFromMfm(parsed.value).filte
|
|||
const isLong = shouldCollapsed(appearNote.value, urls.value ?? []);
|
||||
const collapsed = ref(appearNote.value.cw == null && isLong);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
|
||||
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords, true));
|
||||
const muted = ref(checkMute(appearNote.value, 'soft'));
|
||||
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, 'hard', true));
|
||||
const showSoftWordMutedWord = computed(() => defaultStore.state.showSoftWordMutedWord);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
|
@ -300,20 +300,18 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
|||
}));
|
||||
|
||||
/* Overload FunctionにLintが対応していないのでコメントアウト
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: false): Array<string | string[]> | false | 'sensitiveMute';
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, type: 'soft' | 'hard', checkOnly: true): boolean;
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, type: 'soft' | 'hard', checkOnly: false): Array<string | string[]> | false | 'sensitiveMute';
|
||||
*/
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly = false): Array<string | string[]> | false | 'sensitiveMute' {
|
||||
if (mutedWords != null) {
|
||||
const result = checkWordMute(noteToCheck, $i, mutedWords);
|
||||
if (Array.isArray(result)) return result;
|
||||
function checkMute(noteToCheck: Misskey.entities.Note, type: 'soft' | 'hard', checkOnly = false): Array<string | string[]> | false | 'sensitiveMute' {
|
||||
const result = checkWordMute(noteToCheck, $i, type);
|
||||
if (Array.isArray(result)) return result;
|
||||
|
||||
const replyResult = noteToCheck.reply && checkWordMute(noteToCheck.reply, $i, mutedWords);
|
||||
if (Array.isArray(replyResult)) return replyResult;
|
||||
const replyResult = noteToCheck.reply && checkWordMute(noteToCheck.reply, $i, type);
|
||||
if (Array.isArray(replyResult)) return replyResult;
|
||||
|
||||
const renoteResult = noteToCheck.renote && checkWordMute(noteToCheck.renote, $i, mutedWords);
|
||||
if (Array.isArray(renoteResult)) return renoteResult;
|
||||
}
|
||||
const renoteResult = noteToCheck.renote && checkWordMute(noteToCheck.renote, $i, type);
|
||||
if (Array.isArray(renoteResult)) return renoteResult;
|
||||
|
||||
if (checkOnly) return false;
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
|
|||
const isMyRenote = $i && ($i.id === note.value.userId);
|
||||
const showContent = ref(false);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false);
|
||||
const muted = ref($i ? checkWordMute(appearNote.value, $i, 'soft') : false);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
||||
|
|
|
@ -62,7 +62,7 @@ const props = withDefaults(defineProps<{
|
|||
depth: 1,
|
||||
});
|
||||
|
||||
const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false);
|
||||
const muted = ref($i ? checkWordMute(props.note, $i, 'soft') : false);
|
||||
|
||||
const showContent = ref(false);
|
||||
const replies = ref<Misskey.entities.Note[]>([]);
|
||||
|
|
|
@ -3,22 +3,27 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import * as AhoCorasick from 'modern-ahocorasick';
|
||||
import { c } from 'node_modules/vite/dist/node/types.d-aGj9QkWt';
|
||||
import type * as Misskey from 'misskey-js';
|
||||
export function checkWordMute(
|
||||
note: Misskey.entities.Note,
|
||||
me: Misskey.entities.UserLite | null | undefined,
|
||||
mutedWords: Array<string | string[]>,
|
||||
): Array<string | string[]> | false {
|
||||
// 自分自身の投稿は対象外
|
||||
if (me && (note.userId === me.id)) return false;
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
type WordMuteInfo = false | {
|
||||
normals: string[];
|
||||
and: string[][];
|
||||
regex: Array<{ original: string; regex: RegExp }>;
|
||||
ahoCorasick: AhoCorasick.default;
|
||||
}
|
||||
|
||||
type GlobalMisskeyWordMute = {
|
||||
soft: WordMuteInfo;
|
||||
hard: WordMuteInfo;
|
||||
};
|
||||
|
||||
function createWordMuteInfo(mutedWords: Array<string | string[]>) : WordMuteInfo {
|
||||
if (mutedWords.length <= 0) return false;
|
||||
|
||||
const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
|
||||
if (text === '') return false;
|
||||
|
||||
const normalTexts: string[] = [];
|
||||
const andTexts: string[][] = [];
|
||||
const regexTexts: Array<{ originaL: string; regex: RegExp }> = [];
|
||||
const regexTexts: Array<{ original: string; regex: RegExp }> = [];
|
||||
|
||||
for (const filter of mutedWords) {
|
||||
if (Array.isArray(filter)) {
|
||||
|
@ -31,7 +36,7 @@ export function checkWordMute(
|
|||
const regExp = filter.match(/^\/(.+)\/(.*)$/);
|
||||
if (!regExp) continue;
|
||||
try {
|
||||
regexTexts.push({ originaL: filter, regex: new RegExp(filter.slice(1, -1)) });
|
||||
regexTexts.push({ original: filter, regex: new RegExp(filter.slice(1, -1)) });
|
||||
} catch {
|
||||
// 無効な正規表現はスキップ
|
||||
}
|
||||
|
@ -39,17 +44,60 @@ export function checkWordMute(
|
|||
normalTexts.push(filter);
|
||||
}
|
||||
}
|
||||
// normal wordmute with AhoCorasick
|
||||
|
||||
const ac = new AhoCorasick.default(normalTexts);
|
||||
const normalMatches = ac.search(text);
|
||||
|
||||
return {
|
||||
normals: normalTexts,
|
||||
and: andTexts,
|
||||
regex: regexTexts,
|
||||
ahoCorasick: ac,
|
||||
};
|
||||
}
|
||||
|
||||
function setWordMuteInfo(mutedWords: Array<string | string[]>, hardMutedWords: Array<string | string[]>): void {
|
||||
const soft = createWordMuteInfo(mutedWords);
|
||||
const hard = createWordMuteInfo(hardMutedWords);
|
||||
|
||||
globalThis._misskeyWordMute = { soft, hard };
|
||||
}
|
||||
|
||||
function getWordMuteInfo(): GlobalMisskeyWordMute | undefined {
|
||||
if (!globalThis._misskeyWordMute) return undefined;
|
||||
return globalThis._misskeyWordMute as unknown as GlobalMisskeyWordMute;
|
||||
}
|
||||
|
||||
export function initMuteInfo(): void {
|
||||
const mutedWords = $i?.mutedWords ?? [];
|
||||
const hardMutedWords = $i?.hardMutedWords ?? [];
|
||||
|
||||
setWordMuteInfo(mutedWords, hardMutedWords);
|
||||
}
|
||||
|
||||
export function checkWordMute(
|
||||
note: Misskey.entities.Note,
|
||||
me: Misskey.entities.UserLite | null | undefined,
|
||||
type: 'soft' | 'hard',
|
||||
): Array<string | string[]> | false {
|
||||
// 自分自身の投稿は対象外
|
||||
if (me && (note.userId === me.id)) return false;
|
||||
|
||||
const wordMuteInfo = getWordMuteInfo()?.[type];
|
||||
|
||||
if (wordMuteInfo == null || wordMuteInfo === false) return false;
|
||||
|
||||
const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
|
||||
if (text === '') return false;
|
||||
|
||||
const normalMatches = wordMuteInfo.ahoCorasick.search(text);
|
||||
|
||||
// andTexts
|
||||
const andMatches = andTexts.filter(texts => texts.filter(keyword => keyword !== '').every(keyword => text.includes(keyword)));
|
||||
const andMatches = wordMuteInfo.and.filter(texts => texts.filter(keyword => keyword !== '').every(keyword => text.includes(keyword)));
|
||||
|
||||
// RegExp
|
||||
const regexMatches = regexTexts.filter(({ regex }) => regex.test(text));
|
||||
const regexMatches = wordMuteInfo.regex.filter(({ regex }) => regex.test(text));
|
||||
|
||||
const matched: Array<string | string[]> = normalMatches.map(match => match[1]).concat(andMatches, regexMatches.map(({ originaL }) => originaL));
|
||||
const matched: Array<string | string[]> = normalMatches.map(match => match[1]).concat(andMatches, regexMatches.map(({ original }) => original));
|
||||
|
||||
return matched.length > 0 ? matched : false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue