diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index adc42b96d..44e69d4fd 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -935,6 +935,10 @@ common/views/components/mute-and-block.vue:
block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません"
no-blocked-users: "ブロックしているユーザーはいません"
+ word-mute: "ワードミュート"
+ muted-words: "ミュートされたキーワード"
+ muted-words-description: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
+ save: "保存"
common/views/components/password-settings.vue:
reset: "パスワードを変更する"
diff --git a/src/client/app/common/scripts/note-mixin.ts b/src/client/app/common/scripts/note-mixin.ts
index dd5098f4c..9f1a4c6ee 100644
--- a/src/client/app/common/scripts/note-mixin.ts
+++ b/src/client/app/common/scripts/note-mixin.ts
@@ -1,5 +1,6 @@
import parse from '../../../../mfm/parse';
import { sum } from '../../../../prelude/array';
+import shouldMuteNote from './should-mute-note';
import MkNoteMenu from '../views/components/note-menu.vue';
import MkReactionPicker from '../views/components/reaction-picker.vue';
import Ok from '../views/components/ok.vue';
@@ -22,7 +23,8 @@ type Opts = {
export default (opts: Opts = {}) => ({
data() {
return {
- showContent: false
+ showContent: false,
+ hideThisNote: false
};
},
@@ -86,6 +88,10 @@ export default (opts: Opts = {}) => ({
}
},
+ created() {
+ this.hideThisNote = shouldMuteNote(this.$store.state.i, this.$store.state.settings, this.appearNote);
+ },
+
methods: {
reply(viaKeyboard = false) {
this.$root.$post({
diff --git a/src/client/app/common/scripts/should-mute-note.ts b/src/client/app/common/scripts/should-mute-note.ts
new file mode 100644
index 000000000..a84913576
--- /dev/null
+++ b/src/client/app/common/scripts/should-mute-note.ts
@@ -0,0 +1,28 @@
+export default function(me, settings, note) {
+ const isMyNote = note.userId == me.id;
+ const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
+
+ if (settings.showMyRenotes === false) {
+ if (isMyNote && isPureRenote) {
+ return true;
+ }
+ }
+
+ if (settings.showRenotedMyNotes === false) {
+ if (isPureRenote && (note.renote.userId == me.id)) {
+ return true;
+ }
+ }
+
+ if (settings.showLocalRenotes === false) {
+ if (isPureRenote && (note.renote.user.host == null)) {
+ return true;
+ }
+ }
+
+ if (!isMyNote && note.text && settings.mutedWords.some(q => !q.some(word => !note.text.includes(word)))) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/client/app/common/views/components/mute-and-block.vue b/src/client/app/common/views/components/mute-and-block.vue
index 3ed02e644..fdeaa97eb 100644
--- a/src/client/app/common/views/components/mute-and-block.vue
+++ b/src/client/app/common/views/components/mute-and-block.vue
@@ -21,6 +21,14 @@
+
+
+
+
+ {{ $t('muted-words') }}{{ $t('muted-words-description') }}
+
+ {{ $t('save') }}
+
@@ -30,16 +38,27 @@ import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('common/views/components/mute-and-block.vue'),
+
data() {
return {
muteFetching: true,
blockFetching: true,
mute: [],
- block: []
+ block: [],
+ mutedWords: ''
};
},
+ computed: {
+ _mutedWords: {
+ get() { return this.$store.state.settings.mutedWords; },
+ set(value) { this.$store.dispatch('settings/set', { key: 'mutedWords', value }); }
+ },
+ },
+
mounted() {
+ this.mutedWords = this._mutedWords.map(words => words.join(' ')).join('\n');
+
this.$root.api('mute/list').then(mute => {
this.mute = mute.map(x => x.mutee);
this.muteFetching = false;
@@ -49,6 +68,12 @@ export default Vue.extend({
this.block = blocking.map(x => x.blockee);
this.blockFetching = false;
});
+ },
+
+ methods: {
+ save() {
+ this._mutedWords = this.mutedWords.split('\n').map(line => line.split(' '));
+ }
}
});
diff --git a/src/client/app/desktop/views/components/note.vue b/src/client/app/desktop/views/components/note.vue
index 2b164687e..e2b67c150 100644
--- a/src/client/app/desktop/views/components/note.vue
+++ b/src/client/app/desktop/views/components/note.vue
@@ -2,7 +2,7 @@
import Vue from 'vue';
import i18n from '../../../../i18n';
+import shouldMuteNote from '../../../../common/scripts/should-mute-note';
import XNote from '../../components/note.vue';
@@ -135,28 +136,8 @@ export default Vue.extend({
},
prepend(note, silent = false) {
- //#region 弾く
- const isMyNote = note.userId == this.$store.state.i.id;
- const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
-
- if (this.$store.state.settings.showMyRenotes === false) {
- if (isMyNote && isPureRenote) {
- return;
- }
- }
-
- if (this.$store.state.settings.showRenotedMyNotes === false) {
- if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
- return;
- }
- }
-
- if (this.$store.state.settings.showLocalRenotes === false) {
- if (isPureRenote && (note.renote.user.host == null)) {
- return;
- }
- }
- //#endregion
+ // 弾く
+ if (shouldMuteNote(this.$store.state.i, this.$store.state.settings, note)) return;
// タブが非表示ならタイトルで通知
if (document.hidden) {
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index f6b7d39b8..d42efbf34 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -1,7 +1,7 @@
import Vue from 'vue';
import i18n from '../../../i18n';
+import shouldMuteNote from '../../../common/scripts/should-mute-note';
const displayLimit = 30;
@@ -118,28 +119,8 @@ export default Vue.extend({
},
prepend(note, silent = false) {
- //#region 弾く
- const isMyNote = note.userId == this.$store.state.i.id;
- const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
-
- if (this.$store.state.settings.showMyRenotes === false) {
- if (isMyNote && isPureRenote) {
- return;
- }
- }
-
- if (this.$store.state.settings.showRenotedMyNotes === false) {
- if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
- return;
- }
- }
-
- if (this.$store.state.settings.showLocalRenotes === false) {
- if (isPureRenote && (note.renote.user.host == null)) {
- return;
- }
- }
- //#endregion
+ // 弾く
+ if (shouldMuteNote(this.$store.state.i, this.$store.state.settings, note)) return;
// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知
if (document.hidden || !this.isScrollTop()) {
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
index 08d5c9b12..065015b3d 100644
--- a/src/client/app/store.ts
+++ b/src/client/app/store.ts
@@ -34,6 +34,7 @@ const defaultSettings = {
iLikeSushi: false,
rememberNoteVisibility: false,
defaultNoteVisibility: 'public',
+ mutedWords: [],
games: {
reversi: {
showBoardLabels: false,