Mastodon 連合 or ローカルタイムライン用正規表現フィルタ
by
pacochi
2017-06-01 [2017/06/01 20:54:17]
名前にも適用されます。画像とか動画とか不適切系も判別できます。
@@ -1,79 +1,118 @@
/*
* @title Mastodon 連合 or ローカルタイムライン用正規表現フィルタ
- * @description 名前にも適用されます。
+ * @description 名前にも適用されます。画像とか動画とか不適切系も判別できます。
* @include *
* @license MIT License
* @javascript_url
*/
/*
-TODO:
--$('.column:last') に直付けしなくなったから $('.column:last') が消えた時に察知して対象を変える必要がある
- (もっかい $('.columns-area') に MutationObserver つけることにして XPath のあたりでホームの status をスルーさせる)
--入力欄に見たくない文字列が常時表示されてるの精神衛生上よくない
--省略された URL、media の有無、拡張子、sensitive の有無、必要そうならつける
+ブックマークレットを実行すると入力欄とボタンが出ます。
+入力欄に正規表現を入れてエンターを押してください。ボタンはフィルタのオンオフです。
+諸事情あって、ブックマークレットは自動更新されません。
+新しいバージョンに変更したい場合は、一旦古いブックマークレットを削除して、新しく追加し直してください。
+
+入力例:
+
+たけのこに関するトゥートを NG
+たけのこ|タケノコ|竹の子|筍
+たけのこに関するトゥートのみ表示
+^(?![\s\S]*(たけのこ|タケノコ|竹の子|筍))
+不適切なコンテンツを NG
+sensitive
+不適切なコンテンツのみ表示
+^(?![\s\S]*sensitive)
+画像、動画のみ表示
+^(?![\s\S]*media)
+画像、動画のみ表示 (誤爆なし)
+^(?![\s\S]* media)
+PNG のみ表示 (イラスト多めになる)
+^(?![\s\S]*media\.png)
+動画 (GIFアニメ含む) のみ表示
+^(?![\s\S]*media\.mp4)
+
+更新履歴:
+
+4/24
+-正規表現入力欄が入力後に隠れるようになりました。クリックするとまた出てきます。
+-フィルタが効かなくなる現象の出現頻度が低くなりました。
+-画像や動画がある場合、検索される文字列に「\tmedia」という文字列が追加されます。拡張子が判別できたら「\tmedia.png」のような文字列になります。
+-不適切なコンテンツがある場合、検索される文字列に「\tsensitive」という文字列が追加されます。「\t」はタブ文字です。
+
+4/22
+-https://mstdn.jp/users/soraki_yoshiko2/updates/1277707 こういう経緯で作りました。
+-名前も検索される文字列に含まれます。
*/
-((d = document, o, x, i, c, b, r, n) => {
+((d = document, l = { childList: 1 }, p = $('.columns-area'), t, r, o, c, b, m, a) => {
- r = new RegExp(decodeURIComponent((d.cookie.split('let_filter_regexp=')[1] || '').split(';')[0]) || 'きのこ|たけのこ|すぎのこ', 'i');
-
- o = new MutationObserver(s => s.forEach(t => {
+ r = new RegExp(
+ decodeURIComponent((d.cookie.split('let_filter_regexp=')[1] || '').split(';')[0])
+ || 'きのこ|たけのこ|すぎのこ', 'i'
+ );
- x = d.evaluate('.//div[@class="status" and not(@style)]', t.target, null, 6, x);
+ // この辺なるたけ速い方がいいかなって思って jQuery 使ってない
+ o = new MutationObserver(s => s.forEach(e => {
- // この辺速い方がいいかなって思って jQuery 使ってない
- for (i = 0; i < x.snapshotLength; i++) {
-
- n = x.snapshotItem(i);
+ [...e.target.querySelectorAll('.status:not(.viewed)')].forEach(n => {
- [...n.querySelectorAll('img[alt]')].forEach(f => {
+ [...n.querySelectorAll('img[alt]')].forEach(i => {
- f.parentNode.insertBefore(Object.assign(
+ i.parentNode.insertBefore(Object.assign(
d.createElement('span'), {
style: 'display: none;',
- textContent: f.alt
+ textContent: i.alt
}
- ), f);
+ ), i);
});
- if (
- r.test(n.querySelector('.display-name').textContent)
- || r.test(n.querySelector('.status__content').textContent)
- ) n.style.display = 'none';
+ m = n.querySelector('.media-spoiler') ? '\tsensitive\tmedia' : '';
+ [...n.querySelectorAll('a[href*=media_attachments], video')].forEach(a => {
+
+ m += '\tmedia' + ((a.href || a.src).match(/(\.\w+)(?:\?|$)/) || [''])[0];
+
+ });
- }
+ if (r.test(
+ n.querySelector('.display-name').textContent
+ + '\t' + n.querySelector('.status__content').textContent + m
+ )) n.style.display = 'none';
+
+ n.className += ' viewed';
+
+ });
}));
- c = $('#mute-buttons');
- if (!c[0]) c = $('<div />')
- .css({ position: 'fixed', height: '1em', bottom: '2em', right: 0, zIndex: 99 })
- .attr('id', 'mute-buttons').appendTo($('.columns-area'));
- b = $('<button />').text('?')
- .click(function (e) {
+ a = s => {
- if (b.text() == '?') {
+ if (s == '?') {
b.text('?');
- o.observe($('.column:last')[0], {
- childList: 1,
- subtree: 1
- });
+ o.observe(t[0], l);
} else {
b.text('?');
o.disconnect();
- $('.status').filter(":hidden").show();
+ $('.status').removeClass('viewed').filter(':hidden').show();
}
- });
- c.append(b.click()).append(
- $('<input />').val(r.source).css('width', '10em')
- .change(function (e, s) {
+ };
+
+ c = $('#mute-buttons');
+ if (!c[0]) c = $('<div />')
+ .css({ position: 'fixed', height: '1em', bottom: '2em', right: 0, zIndex: 99 })
+ .attr('id', 'mute-buttons').appendTo(p);
+
+ b = $('<button />').text('?')
+ .click(function() { a(b.text()); });
+
+ c.append(b).append(
+ $('<input />').val(r.source).css('width', '12em')
+ .change(function(s) {
s = this.value;
@@ -83,18 +122,45 @@
if (typeof s == 'object') {
- b.text('?');
o.disconnect();
r = s;
d.cookie = `let_filter_regexp=${encodeURIComponent(r.source)}; path=\x2F; expires=Tue, 19 Jan 2038 03:14:07 GMT`;
+ a('?');
+ a('?');
+
+ } else a('?');
+
+ } else a('?');
+
+ })
+ .focus(function() {
- } else b.text('?');
+ this.style.paddingLeft = '0';
+ this.style.width = '12em';
- } else b.text('?');
+ }).blur(function() {
- b.click();
+ this.style.paddingLeft = '2em';
+ this.style.width = '0';
})
);
+ f = n => {
+
+ n = $('.column:last>.scrollable>div:last');
+
+ if (!t || t[0] != n[0]) {
+
+ t = n;
+ a('?');
+ a('?');
+
+ }
+
+ };
+
+ new MutationObserver(s => f).observe(p[0], l);
+ f();
+
})();
/*
* @title Mastodon 連合 or ローカルタイムライン用正規表現フィルタ
* @description 名前にも適用されます。画像とか動画とか不適切系も判別できます。
* @include *
* @license MIT License
* @javascript_url
*/
/*
ブックマークレットを実行すると入力欄とボタンが出ます。
入力欄に正規表現を入れてエンターを押してください。ボタンはフィルタのオンオフです。
諸事情あって、ブックマークレットは自動更新されません。
新しいバージョンに変更したい場合は、一旦古いブックマークレットを削除して、新しく追加し直してください。
入力例:
たけのこに関するトゥートを NG
たけのこ|タケノコ|竹の子|筍
たけのこに関するトゥートのみ表示
^(?![\s\S]*(たけのこ|タケノコ|竹の子|筍))
不適切なコンテンツを NG
sensitive
不適切なコンテンツのみ表示
^(?![\s\S]*sensitive)
画像、動画のみ表示
^(?![\s\S]*media)
画像、動画のみ表示 (誤爆なし)
^(?![\s\S]* media)
PNG のみ表示 (イラスト多めになる)
^(?![\s\S]*media\.png)
動画 (GIFアニメ含む) のみ表示
^(?![\s\S]*media\.mp4)
更新履歴:
4/24
-正規表現入力欄が入力後に隠れるようになりました。クリックするとまた出てきます。
-フィルタが効かなくなる現象の出現頻度が低くなりました。
-画像や動画がある場合、検索される文字列に「\tmedia」という文字列が追加されます。拡張子が判別できたら「\tmedia.png」のような文字列になります。
-不適切なコンテンツがある場合、検索される文字列に「\tsensitive」という文字列が追加されます。「\t」はタブ文字です。
4/22
-https://mstdn.jp/users/soraki_yoshiko2/updates/1277707 こういう経緯で作りました。
-名前も検索される文字列に含まれます。
*/
((d = document, l = { childList: 1 }, p = $('.columns-area'), t, r, o, c, b, m, a) => {
r = new RegExp(
decodeURIComponent((d.cookie.split('let_filter_regexp=')[1] || '').split(';')[0])
|| 'きのこ|たけのこ|すぎのこ', 'i'
);
// この辺なるたけ速い方がいいかなって思って jQuery 使ってない
o = new MutationObserver(s => s.forEach(e => {
[...e.target.querySelectorAll('.status:not(.viewed)')].forEach(n => {
[...n.querySelectorAll('img[alt]')].forEach(i => {
i.parentNode.insertBefore(Object.assign(
d.createElement('span'), {
style: 'display: none;',
textContent: i.alt
}
), i);
});
m = n.querySelector('.media-spoiler') ? '\tsensitive\tmedia' : '';
[...n.querySelectorAll('a[href*=media_attachments], video')].forEach(a => {
m += '\tmedia' + ((a.href || a.src).match(/(\.\w+)(?:\?|$)/) || [''])[0];
});
if (r.test(
n.querySelector('.display-name').textContent
+ '\t' + n.querySelector('.status__content').textContent + m
)) n.style.display = 'none';
n.className += ' viewed';
});
}));
a = s => {
if (s == '?') {
b.text('?');
o.observe(t[0], l);
} else {
b.text('?');
o.disconnect();
$('.status').removeClass('viewed').filter(':hidden').show();
}
};
c = $('#mute-buttons');
if (!c[0]) c = $('<div />')
.css({ position: 'fixed', height: '1em', bottom: '2em', right: 0, zIndex: 99 })
.attr('id', 'mute-buttons').appendTo(p);
b = $('<button />').text('?')
.click(function() { a(b.text()); });
c.append(b).append(
$('<input />').val(r.source).css('width', '12em')
.change(function(s) {
s = this.value;
if (s.length) {
try { s = new RegExp(s); } catch(e) {}
if (typeof s == 'object') {
o.disconnect();
r = s;
d.cookie = `let_filter_regexp=${encodeURIComponent(r.source)}; path=\x2F; expires=Tue, 19 Jan 2038 03:14:07 GMT`;
a('?');
a('?');
} else a('?');
} else a('?');
})
.focus(function() {
this.style.paddingLeft = '0';
this.style.width = '12em';
}).blur(function() {
this.style.paddingLeft = '2em';
this.style.width = '0';
})
);
f = n => {
n = $('.column:last>.scrollable>div:last');
if (!t || t[0] != n[0]) {
t = n;
a('?');
a('?');
}
};
new MutationObserver(s => f).observe(p[0], l);
f();
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。