├── image
├── after1.png
├── after2.png
└── before.png
├── README.md
├── README_en.md
├── LICENSE
└── script.user.js
/image/after1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hi2ma-bu4/X_impression_hide/HEAD/image/after1.png
--------------------------------------------------------------------------------
/image/after2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hi2ma-bu4/X_impression_hide/HEAD/image/after2.png
--------------------------------------------------------------------------------
/image/before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hi2ma-bu4/X_impression_hide/HEAD/image/before.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Twitter(旧:𝕏)のインプレッション小遣い稼ぎ野郎どもをdisplay:none;するやつ
2 |
3 | [](https://github.com/hi2ma-bu4/X_impression_hide/blob/main/LICENSE)
4 | [](https://greasyfork.org/ja/scripts/484303/stats)
5 |
6 | [](https://github.com/hi2ma-bu4/X_impression_hide/releases)
7 | [](https://greasyfork.org/ja/scripts/484303)
8 |
9 |
10 | 略して「#インプレゾンビをnoneするやつ」
11 |
12 | [English README is here](README_en.md)
13 |
14 | 現在更新停止。
15 | 動かなくなった場合はIssuesに報告して下さると修正します。
16 |
17 | ### 前提条件
18 | > [!WARNING]
19 | > PC専用です
20 | >
21 | > v1.11.11からkiwiブラウザ対応!
22 | >
23 | > v2.1.3からOldTweetDeck部分対応!
24 | >
25 | >
26 | > [Tampermonkey](https://chromewebstore.google.com/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo)が必要です。
27 |
28 | README更新Ver: 2.1.3
29 |
30 | ### 参考画像
31 | |||
32 | |:---:|:---:|
33 | |||
34 |
35 | 画像は開発段階のものです。
36 |
37 | ### 使い方
38 | Tampermonkeyに追加するだけで使用できます。
39 |
40 | 追加は[こちら](https://github.com/hi2ma-bu4/X_impression_hide/raw/main/script.user.js)から出来ます。
41 |
42 | また、Gresy Forkのページは[こちら](https://greasyfork.org/ja/scripts/484303-twitter-%E6%97%A7-%F0%9D%95%8F-%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%97%E3%83%AC%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E5%B0%8F%E9%81%A3%E3%81%84%E7%A8%BC%E3%81%8E%E9%87%8E%E9%83%8E%E3%81%A9%E3%82%82%E3%82%92display-none-%E3%81%99%E3%82%8B%E3%82%84%E3%81%A4)からどうぞ。
43 |
44 | 設定は
45 | > 右クリック > Tampermonkey > Twitter(旧:𝕏)の(略) > Settings
46 |
47 | か、
48 | > 右上拡張機能一覧 > Tampermonkey > Twitter(旧:𝕏)の(略) > Settings(s)
49 |
50 | で、開く事ができます。
51 |
52 | ### 設定の内容
53 | |名前|説明|初期値|型・範囲|
54 | |:---|:---|:---:|:---:|
55 | |非表示ログを表示|非表示にしたログを画面から消します。 画面が平和になりますが、投稿を非表示にされた理由・元投稿が確認出来なくなります。|true|boolean|
56 | |非表示ログに認証マーク表示|非表示にしたログの名前の後ろに認証マークを追加します。 企業バッジでも青バッジで表示されます。|true|boolean|
57 | |禁止する表現|非表示にするテキストを指定します[^1][^2]。 記述方法は正規表現[^3]で記述します。|長い為省略|string|
58 | |許可する表現|許可するテキストを指定します。 一致する投稿は非表示の対象になりません。 指定方法などは[禁止する表現]と同じです。|長い為省略|string|
59 | |禁止する名前|非表示にするユーザー名を指定します。 指定方法などは[禁止する表現]と同じです。|長い為省略|string|
60 | |除外ユーザー|指定されたユーザーidは検知の対象になりません。 指定方法はユーザーidを改行で区切って記述するだけです。 idは完全一致のみ有効です。|長い為省略|string|
61 | |許可する言語|許可する言語を指定します。 記述方法は正規表現[^3]で記述します。|長い為省略|string|
62 | |自身の引用禁止|自身を引用ツイートする投稿を非表示にします。|true|boolean|
63 | |絵文字投稿禁止|絵文字のみで構成された投稿を非表示にします。|true|boolean|
64 | |絵文字ユーザー名禁止|絵文字のみで構成されたユーザー名を非表示にします。|true|boolean|
65 | |認証アカウント禁止|認証済アカウントを無差別に非表示にします。|false|boolean|
66 | |認証RT禁止|認証済アカウント投稿に対する引用RTを非表示にします。|false|boolean|
67 | |認証アカウントのみ判定|認証済アカウントのみを検知の対象にします。 通常アカウントや認証マークの無いアカウントはブロックされなくなります。|false|boolean|
68 | |認証公式アカウントを保護|公式アカウント[^7]を検知の対象から除外します。|true|boolean|
69 | |クイックブロック表示|1クリックでブロックできるボタンを表示します。 検出された投稿にしか表示されません。|true|boolean|
70 | |クイック通報表示|1クリックで通報できるボタンを表示します。 検出された投稿にしか表示されません。 (初期値はスパム報告です)|true|boolean|
71 | |ハッシュタグの上限数|1つの投稿内でのハッシュタグの使用上限数を指定します。|6|int (1~)|
72 | |シンボルタグの上限数|1つの投稿内でのシンボルタグの使用上限数を指定します[^9]。|1|int(1~)|
73 | |ツリー返信上限数|1つの投稿ツリーでの返信上限数を指定します。 値は許可のラインです。(例: 1で2投稿以上は非表示) 0を指定するとこの設定は無効化されます。|1|int (0~)|
74 | |1人によるRT上限数|1つの投稿ツリーでの1ユーザーの引用RT返信上限数を指定します。 値は[ツリー返信上限数]と同じ指定方法です。|1|int(0~)|
75 | |同一RT上限数|1つの投稿ツリーでの複数人からの同じユーザーに対する引用RT返信上限数を指定します。 値は[ツリー返信上限数]と同じ指定方法です。|1|int(0~)|
76 | |文章類似度許可ライン|コピペ文章かを判別する為の基準値を指定します。|0.85|float (0~1)|
77 | |比較される最大テキストサイズ|コピペ投稿の文章比較の最大文字数を指定します[^4]。 値を大きくするほど誤検知率は減り、検知率も減ります。|80|int (0~)|
78 | |一時保存・比較される最小テキストサイズ|比較用文章の最小文字数を指定します[^5]。 値が大きくするほど誤検知率は減り、検知率も減ります。|8|int (0~)|
79 | |一時保存される投稿の最大数|比較用文章の保持数を指定します。 値が小さいほど処理は軽くなりますが、検知率が減ります。|100|int (1~)|
80 | |言語|表示言語を設定します。|ja|str (ja\|en)|
81 | |ページ適用css設定|ページへ適用するcssを指定します。|長い為省略|string|
82 | |ページ更新検知用処理待機時間(ms)|ページ更新を検知する際の検知の更新間隔を指定します。 値が大きいほど処理が軽くなりますが、非表示にする初速が落ちる可能性あります。|3000|int (100~)|
83 | |検知対象の記憶|検出された対象を記憶します。 ページを更新などしても過去に検知した対象を素早く非表示に出来ます[^8]。|false|boolean|
84 | |【非推奨】自動ブロック|検出された対象を自動でブロックします[^6]。|false|boolean|
85 | |設定のリセット|設定項目をリセットします|||
86 | |検知済idのリセット|検知済idをリセットします。|||
87 | |OldTweetDeck対応|負荷軽減の為に分離[^6]|false|boolean|
88 | |jQuery自動読み込み|OldTweetDeckではなぜかjQueryが使用されているのにjQueryが読み込まれていない為、 jQueryが読み込まれていない場合にjQueryを読み込む機能です。|true|boolean|
89 | |起動時設定自動表示|設定画面を自動で開く|false|boolean|
90 |
91 | [^1]: 半角カタカナ、カタカナはひらがなに自動変換され、 全角英数字は半角英数字に、改行文字は半角スペースに自動変換されます。
92 | [^2]: "!#"を行頭に記述するとコメントアウト扱いになります。
93 | [^3]: ここでの正規表現とは"/"の間部分の事を指します。
94 | [^4]: 投稿の文字数が最大値以下の場合、この値は使用されません。
95 | [^5]: [比較される最大テキストサイズ]より大きい場合、比較処理は実行されません。
96 | [^6]: この機能はbeta版です!! 誤検知でも戸惑いなくブロックされます。
97 | [^7]: 公式とは青いバッジ以外を指します。
98 | [^8]: この機能はbeta版です!! 誤検知されたアカウントが非表示のままになります。 [除外ユーザー]と併用して使用して下さい。
99 | [^9]: シンボルタグとは「$TWTR」のような#を$に置き換えた株を表す表現
100 |
101 | ### ログの種類
102 | |名前|検出値|項目|
103 | |:---|:---:|:---:|
104 | |フィルター検出|comment_フィルター「/<正規表現>/uim」|禁止する表現|
105 | |フィルター検出|name_フィルター「/<正規表現>/uim」|禁止する名前|
106 | |非許可言語|<言語コード>|許可する言語|
107 | |自身の引用||自身の引用禁止|
108 | |絵文字のみ|comment|絵文字投稿禁止|
109 | |絵文字のみ|name|絵文字ユーザー名禁止|
110 | |認証垢||認証アカウント禁止|
111 | |認証RT垢||認証RT禁止|
112 | |#多量使用|使用回数: <使用数>|ハッシュタグの上限数|
113 | |$多量使用|使用回数: <使用数>|シンボルタグの上限数|
114 | |連投||ツリー返信上限数|
115 | |RT連投||1人によるRT上限数|
116 | |RT共有連投||同一RT上限数|
117 | |文章の複製|類似度:<数値>%|文章類似度許可ライン|
118 | |再帰的検出|||
119 | |他で検出済|||
120 |
121 | ### 設定ミス、バージョンアップによる設定更新ずれが発生した場合
122 | まず、以下のページまで移動します。
123 | > 右上拡張機能一覧 > ダッシュボード > インストール済UserScript > Twitter(旧:𝕏)の(略) > ストレージ
124 |
125 | > [!TIP]
126 | > ストレージの欄の例
127 | > ```json
128 | > {
129 | > "X_impression_hide_json": "{\"visibleLog\":true, ..."
130 | > }
131 | > ```
132 |
133 | ストレージの欄に含まれている以下の記述を削除してください
134 | > [!CAUTION]
135 | > 設定されているCSSデータが全てリセットされます!
136 | ```
137 | ,\"customCss\":\" ---ユーザーによって異なる為省略--- \"
138 | ```
139 |
140 | わからない・問題が解決しなかった場合は以下の記述に変更してください。
141 | > [!CAUTION]
142 | > 設定されているデータが全てリセットされます!
143 |
144 | ```json
145 | {
146 | }
147 | ```
148 |
--------------------------------------------------------------------------------
/README_en.md:
--------------------------------------------------------------------------------
1 | ## Hide the Twitter (formerly: 𝕏) impression-earning scammers with "display:none;"
2 |
3 | [](https://github.com/hi2ma-bu4/X_impression_hide/blob/main/LICENSE)
4 | [](https://greasyfork.org/ja/scripts/484303/stats)
5 |
6 | [](https://github.com/hi2ma-bu4/X_impression_hide/releases)
7 | [](https://greasyfork.org/ja/scripts/484303)
8 |
9 | The Twitter hashtag is "#インプレゾンビをnoneするやつ"
10 |
11 | [日本語版のREADMEはこちら](README.md)
12 |
13 | Currently not updating.
14 | If it stops working, please report it to Issues and we will fix it.
15 |
16 | The latest and most correct content is in the [Japanese version](README.md).
17 |
18 | ### Prerequisite
19 | > [!WARNING]
20 | > This is for PC use only.
21 | >
22 | > Kiwi browser compatible from v1.11.11!
23 | >
24 | > OldTweetDeck is now supported from v2.1.3!
25 | >
26 | >
27 | > [Tampermonkey](https://chromewebstore.google.com/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) is required.
28 |
29 | README Update Version: 1.13.9
30 |
31 | ### Reference image
32 | |||
33 | |:---:|:---:|
34 | |||
35 |
36 | Images are from the development stage.
37 |
38 | ### Usage
39 | Simply add it to Tampermonkey to use.
40 |
41 | You can add it [here](https://github.com/hi2ma-bu4/X_impression_hide/raw/main/script.user.js).
42 |
43 | Also, you can find the Greasy Fork page [here](https://greasyfork.org/ja/scripts/484303-twitter-%E6%97%A7-%F0%9D%95%8F-%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%97%E3%83%AC%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E5%B0%8F%E9%81%A3%E3%81%84%E7%A8%BC%E3%81%8E%E9%87%8E%E9%83%8E%E3%81%A9%E3%82%82%E3%82%92display-none-%E3%81%99%E3%82%8B%E3%82%84%E3%81%A4).
44 |
45 | The setting is
46 | > right-click > Tampermonkey > Hide the Twitter... > Settings
47 |
48 | or
49 | > Extensions Menu in the Upper Right Corner > Tampermonkey > Hide the Twitter... > Settings(s)
50 |
51 | and you can open it.
52 |
53 | ### Setting details
54 | |name|explanation|initial value|type,extent|
55 | |:---|:---|:---:|:---:|
56 | |Show hidden logs|It will remove the hidden logs from the screen. The screen will be peaceful, but the reasons for hiding the posts and the original posts will no longer be visible.|true|boolean|
57 | |Prohibited expressions|Specify the text to hide[^1][^2]. The description should be written using regular expressions[^3].|Omitted due to length|string|
58 | |Expressions allowed|Specify the text to allow. Matching posts will not be hidden. The specification method is the same as [Prohibited expressions].|Omitted due to length|string|
59 | |Prohibited name|Specify the username to hide. The specification method is the same as [Prohibited expressions].|true|boolean|
60 | |Allowed languages|Specify the allowed languages. The description should be written using regular expressions[^3].|Omitted due to length|string|
61 | |Prohibition of self-quotation|It hides posts that quote oneself.|true|boolean|
62 | |No emoji posting|Hide posts composed only of emojis.|true|boolean|
63 | |Prohibit emoji usernames|Hide usernames composed only of emojis.|true|boolean|
64 | |Prohibition of authenticated accounts|It indiscriminately hides authenticated accounts.|false|boolean|
65 | |Authenticate accounts only|It detects only authenticated accounts. Regular accounts and accounts without verification badges will no longer be blocked.|false|boolean|
66 | |Protect your authenticated official account|Exclude official accounts[^7] from detection.|true|boolean|
67 | |Quick block button display|Displays a button that allows you to block with one click. It will only appear on detected posts.|true|boolean|
68 | |Quick report button display|Displays a button that allows you to block with one click. It will only appear on detected posts. (Initial value is spam report)|true|boolean|
69 | |Maximum number of hashtags|It specifies the maximum number of hashtags allowed in a single post.|6|int (1~)|
70 | |Maximum number of tree replies|Specify the maximum number of replies in one post tree. The value is the line of permission. (Example: 1 hides 2 or more posts) Specifying 0 disables this setting.|1|int (0~)|
71 | |Text similarity threshold|It specifies the threshold value for determining whether a text is a copied and pasted text.|0.85|float (0~1)|
72 | |Maximum text size for comparison|It specifies the maximum number of characters for text comparison in copied and pasted posts.[^4]. Increasing the value reduces the false positive rate but also reduces the detection rate.|80|int (0~)|
73 | |The minimum text size that is temporarily saved and compared|This specifies the minimum number of characters for the comparison text[^5]. Increasing the value reduces the false detection rate as well as the detection rate.|8|int (0~)|
74 | |The maximum number of posts that are temporarily saved|This specifies the number of comparison texts to be retained. A smaller value reduces the processing load but also decreases the detection rate.|100|int (1~)|
75 | |Language|Set the display language.|ja|string (ja\|en)|
76 | |Processing wait time (in milliseconds) for page update detection|This specifies the interval for detecting page updates. A larger value reduces the processing load but may potentially delay the initial speed of hiding.|3000|int (100~)|
77 | |Page-specific CSS settings|Specify the CSS to apply to the page.|Omitted due to length|string|
78 | |[Not recommended] Automatic block|Automatically block detected targets[^6].|false|boolean|
79 | |Reset settings|Reset the settings.|No value because it is a button||
80 |
81 | [^1]: Half-width katakana and katakana are automatically converted to hiragana, full-width alphanumeric characters are automatically converted to half-width alphanumeric characters, and line feed characters are automatically converted to half-width spaces.
82 | [^2]: If you write "!#" at the beginning of a line, it will be treated as a comment.
83 | [^3]: The regular expression here refers to the part between "/".
84 | [^4]: If your post's character count is less than or equal to the maximum value, this value will not be used.
85 | [^5]: If it is larger than [Maximum text size for comparison], the comparison process will not be performed.
86 | [^6]: This feature is in beta version! ! Even false positives are blocked without hesitation.
87 | [^7]: Official means anything other than the blue badge.
88 |
89 |
90 | ### If there is a configuration mistake or a configuration update misalignment due to a version upgrade.
91 | First, go to the page below.
92 | > Extensions Menu in the Upper Right Corner > Dashboard > Installed UserScript > Hide the Twitter... > Storage
93 |
94 | > [!TIP]
95 | > Example of storage column
96 | > ```json
97 | > {
98 | > "X_impression_hide_json": "{\"visibleLog\":true, ..."
99 | > }
100 | > ```
101 |
102 | Please delete the following description in the storage field.
103 | > [!CAUTION]
104 | > All set CSS data will be reset!
105 | ```
106 | ,\"customCss\":\" ---Omitted as it varies depending on the user--- \"
107 | ```
108 |
109 | If you do not understand or the problem is not resolved, please change the description below.
110 | > [!CAUTION]
111 | > All set data will be reset!
112 |
113 | ```json
114 | {
115 | }
116 | ```
117 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 2.1, February 1999
3 |
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | [This is the first released version of the Lesser GPL. It also counts
10 | as the successor of the GNU Library Public License, version 2, hence
11 | the version number 2.1.]
12 |
13 | Preamble
14 |
15 | The licenses for most software are designed to take away your
16 | freedom to share and change it. By contrast, the GNU General Public
17 | Licenses are intended to guarantee your freedom to share and change
18 | free software--to make sure the software is free for all its users.
19 |
20 | This license, the Lesser General Public License, applies to some
21 | specially designated software packages--typically libraries--of the
22 | Free Software Foundation and other authors who decide to use it. You
23 | can use it too, but we suggest you first think carefully about whether
24 | this license or the ordinary General Public License is the better
25 | strategy to use in any particular case, based on the explanations below.
26 |
27 | When we speak of free software, we are referring to freedom of use,
28 | not price. Our General Public Licenses are designed to make sure that
29 | you have the freedom to distribute copies of free software (and charge
30 | for this service if you wish); that you receive source code or can get
31 | it if you want it; that you can change the software and use pieces of
32 | it in new free programs; and that you are informed that you can do
33 | these things.
34 |
35 | To protect your rights, we need to make restrictions that forbid
36 | distributors to deny you these rights or to ask you to surrender these
37 | rights. These restrictions translate to certain responsibilities for
38 | you if you distribute copies of the library or if you modify it.
39 |
40 | For example, if you distribute copies of the library, whether gratis
41 | or for a fee, you must give the recipients all the rights that we gave
42 | you. You must make sure that they, too, receive or can get the source
43 | code. If you link other code with the library, you must provide
44 | complete object files to the recipients, so that they can relink them
45 | with the library after making changes to the library and recompiling
46 | it. And you must show them these terms so they know their rights.
47 |
48 | We protect your rights with a two-step method: (1) we copyright the
49 | library, and (2) we offer you this license, which gives you legal
50 | permission to copy, distribute and/or modify the library.
51 |
52 | To protect each distributor, we want to make it very clear that
53 | there is no warranty for the free library. Also, if the library is
54 | modified by someone else and passed on, the recipients should know
55 | that what they have is not the original version, so that the original
56 | author's reputation will not be affected by problems that might be
57 | introduced by others.
58 |
59 | Finally, software patents pose a constant threat to the existence of
60 | any free program. We wish to make sure that a company cannot
61 | effectively restrict the users of a free program by obtaining a
62 | restrictive license from a patent holder. Therefore, we insist that
63 | any patent license obtained for a version of the library must be
64 | consistent with the full freedom of use specified in this license.
65 |
66 | Most GNU software, including some libraries, is covered by the
67 | ordinary GNU General Public License. This license, the GNU Lesser
68 | General Public License, applies to certain designated libraries, and
69 | is quite different from the ordinary General Public License. We use
70 | this license for certain libraries in order to permit linking those
71 | libraries into non-free programs.
72 |
73 | When a program is linked with a library, whether statically or using
74 | a shared library, the combination of the two is legally speaking a
75 | combined work, a derivative of the original library. The ordinary
76 | General Public License therefore permits such linking only if the
77 | entire combination fits its criteria of freedom. The Lesser General
78 | Public License permits more lax criteria for linking other code with
79 | the library.
80 |
81 | We call this license the "Lesser" General Public License because it
82 | does Less to protect the user's freedom than the ordinary General
83 | Public License. It also provides other free software developers Less
84 | of an advantage over competing non-free programs. These disadvantages
85 | are the reason we use the ordinary General Public License for many
86 | libraries. However, the Lesser license provides advantages in certain
87 | special circumstances.
88 |
89 | For example, on rare occasions, there may be a special need to
90 | encourage the widest possible use of a certain library, so that it becomes
91 | a de-facto standard. To achieve this, non-free programs must be
92 | allowed to use the library. A more frequent case is that a free
93 | library does the same job as widely used non-free libraries. In this
94 | case, there is little to gain by limiting the free library to free
95 | software only, so we use the Lesser General Public License.
96 |
97 | In other cases, permission to use a particular library in non-free
98 | programs enables a greater number of people to use a large body of
99 | free software. For example, permission to use the GNU C Library in
100 | non-free programs enables many more people to use the whole GNU
101 | operating system, as well as its variant, the GNU/Linux operating
102 | system.
103 |
104 | Although the Lesser General Public License is Less protective of the
105 | users' freedom, it does ensure that the user of a program that is
106 | linked with the Library has the freedom and the wherewithal to run
107 | that program using a modified version of the Library.
108 |
109 | The precise terms and conditions for copying, distribution and
110 | modification follow. Pay close attention to the difference between a
111 | "work based on the library" and a "work that uses the library". The
112 | former contains code derived from the library, whereas the latter must
113 | be combined with the library in order to run.
114 |
115 | GNU LESSER GENERAL PUBLIC LICENSE
116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117 |
118 | 0. This License Agreement applies to any software library or other
119 | program which contains a notice placed by the copyright holder or
120 | other authorized party saying it may be distributed under the terms of
121 | this Lesser General Public License (also called "this License").
122 | Each licensee is addressed as "you".
123 |
124 | A "library" means a collection of software functions and/or data
125 | prepared so as to be conveniently linked with application programs
126 | (which use some of those functions and data) to form executables.
127 |
128 | The "Library", below, refers to any such software library or work
129 | which has been distributed under these terms. A "work based on the
130 | Library" means either the Library or any derivative work under
131 | copyright law: that is to say, a work containing the Library or a
132 | portion of it, either verbatim or with modifications and/or translated
133 | straightforwardly into another language. (Hereinafter, translation is
134 | included without limitation in the term "modification".)
135 |
136 | "Source code" for a work means the preferred form of the work for
137 | making modifications to it. For a library, complete source code means
138 | all the source code for all modules it contains, plus any associated
139 | interface definition files, plus the scripts used to control compilation
140 | and installation of the library.
141 |
142 | Activities other than copying, distribution and modification are not
143 | covered by this License; they are outside its scope. The act of
144 | running a program using the Library is not restricted, and output from
145 | such a program is covered only if its contents constitute a work based
146 | on the Library (independent of the use of the Library in a tool for
147 | writing it). Whether that is true depends on what the Library does
148 | and what the program that uses the Library does.
149 |
150 | 1. You may copy and distribute verbatim copies of the Library's
151 | complete source code as you receive it, in any medium, provided that
152 | you conspicuously and appropriately publish on each copy an
153 | appropriate copyright notice and disclaimer of warranty; keep intact
154 | all the notices that refer to this License and to the absence of any
155 | warranty; and distribute a copy of this License along with the
156 | Library.
157 |
158 | You may charge a fee for the physical act of transferring a copy,
159 | and you may at your option offer warranty protection in exchange for a
160 | fee.
161 |
162 | 2. You may modify your copy or copies of the Library or any portion
163 | of it, thus forming a work based on the Library, and copy and
164 | distribute such modifications or work under the terms of Section 1
165 | above, provided that you also meet all of these conditions:
166 |
167 | a) The modified work must itself be a software library.
168 |
169 | b) You must cause the files modified to carry prominent notices
170 | stating that you changed the files and the date of any change.
171 |
172 | c) You must cause the whole of the work to be licensed at no
173 | charge to all third parties under the terms of this License.
174 |
175 | d) If a facility in the modified Library refers to a function or a
176 | table of data to be supplied by an application program that uses
177 | the facility, other than as an argument passed when the facility
178 | is invoked, then you must make a good faith effort to ensure that,
179 | in the event an application does not supply such function or
180 | table, the facility still operates, and performs whatever part of
181 | its purpose remains meaningful.
182 |
183 | (For example, a function in a library to compute square roots has
184 | a purpose that is entirely well-defined independent of the
185 | application. Therefore, Subsection 2d requires that any
186 | application-supplied function or table used by this function must
187 | be optional: if the application does not supply it, the square
188 | root function must still compute square roots.)
189 |
190 | These requirements apply to the modified work as a whole. If
191 | identifiable sections of that work are not derived from the Library,
192 | and can be reasonably considered independent and separate works in
193 | themselves, then this License, and its terms, do not apply to those
194 | sections when you distribute them as separate works. But when you
195 | distribute the same sections as part of a whole which is a work based
196 | on the Library, the distribution of the whole must be on the terms of
197 | this License, whose permissions for other licensees extend to the
198 | entire whole, and thus to each and every part regardless of who wrote
199 | it.
200 |
201 | Thus, it is not the intent of this section to claim rights or contest
202 | your rights to work written entirely by you; rather, the intent is to
203 | exercise the right to control the distribution of derivative or
204 | collective works based on the Library.
205 |
206 | In addition, mere aggregation of another work not based on the Library
207 | with the Library (or with a work based on the Library) on a volume of
208 | a storage or distribution medium does not bring the other work under
209 | the scope of this License.
210 |
211 | 3. You may opt to apply the terms of the ordinary GNU General Public
212 | License instead of this License to a given copy of the Library. To do
213 | this, you must alter all the notices that refer to this License, so
214 | that they refer to the ordinary GNU General Public License, version 2,
215 | instead of to this License. (If a newer version than version 2 of the
216 | ordinary GNU General Public License has appeared, then you can specify
217 | that version instead if you wish.) Do not make any other change in
218 | these notices.
219 |
220 | Once this change is made in a given copy, it is irreversible for
221 | that copy, so the ordinary GNU General Public License applies to all
222 | subsequent copies and derivative works made from that copy.
223 |
224 | This option is useful when you wish to copy part of the code of
225 | the Library into a program that is not a library.
226 |
227 | 4. You may copy and distribute the Library (or a portion or
228 | derivative of it, under Section 2) in object code or executable form
229 | under the terms of Sections 1 and 2 above provided that you accompany
230 | it with the complete corresponding machine-readable source code, which
231 | must be distributed under the terms of Sections 1 and 2 above on a
232 | medium customarily used for software interchange.
233 |
234 | If distribution of object code is made by offering access to copy
235 | from a designated place, then offering equivalent access to copy the
236 | source code from the same place satisfies the requirement to
237 | distribute the source code, even though third parties are not
238 | compelled to copy the source along with the object code.
239 |
240 | 5. A program that contains no derivative of any portion of the
241 | Library, but is designed to work with the Library by being compiled or
242 | linked with it, is called a "work that uses the Library". Such a
243 | work, in isolation, is not a derivative work of the Library, and
244 | therefore falls outside the scope of this License.
245 |
246 | However, linking a "work that uses the Library" with the Library
247 | creates an executable that is a derivative of the Library (because it
248 | contains portions of the Library), rather than a "work that uses the
249 | library". The executable is therefore covered by this License.
250 | Section 6 states terms for distribution of such executables.
251 |
252 | When a "work that uses the Library" uses material from a header file
253 | that is part of the Library, the object code for the work may be a
254 | derivative work of the Library even though the source code is not.
255 | Whether this is true is especially significant if the work can be
256 | linked without the Library, or if the work is itself a library. The
257 | threshold for this to be true is not precisely defined by law.
258 |
259 | If such an object file uses only numerical parameters, data
260 | structure layouts and accessors, and small macros and small inline
261 | functions (ten lines or less in length), then the use of the object
262 | file is unrestricted, regardless of whether it is legally a derivative
263 | work. (Executables containing this object code plus portions of the
264 | Library will still fall under Section 6.)
265 |
266 | Otherwise, if the work is a derivative of the Library, you may
267 | distribute the object code for the work under the terms of Section 6.
268 | Any executables containing that work also fall under Section 6,
269 | whether or not they are linked directly with the Library itself.
270 |
271 | 6. As an exception to the Sections above, you may also combine or
272 | link a "work that uses the Library" with the Library to produce a
273 | work containing portions of the Library, and distribute that work
274 | under terms of your choice, provided that the terms permit
275 | modification of the work for the customer's own use and reverse
276 | engineering for debugging such modifications.
277 |
278 | You must give prominent notice with each copy of the work that the
279 | Library is used in it and that the Library and its use are covered by
280 | this License. You must supply a copy of this License. If the work
281 | during execution displays copyright notices, you must include the
282 | copyright notice for the Library among them, as well as a reference
283 | directing the user to the copy of this License. Also, you must do one
284 | of these things:
285 |
286 | a) Accompany the work with the complete corresponding
287 | machine-readable source code for the Library including whatever
288 | changes were used in the work (which must be distributed under
289 | Sections 1 and 2 above); and, if the work is an executable linked
290 | with the Library, with the complete machine-readable "work that
291 | uses the Library", as object code and/or source code, so that the
292 | user can modify the Library and then relink to produce a modified
293 | executable containing the modified Library. (It is understood
294 | that the user who changes the contents of definitions files in the
295 | Library will not necessarily be able to recompile the application
296 | to use the modified definitions.)
297 |
298 | b) Use a suitable shared library mechanism for linking with the
299 | Library. A suitable mechanism is one that (1) uses at run time a
300 | copy of the library already present on the user's computer system,
301 | rather than copying library functions into the executable, and (2)
302 | will operate properly with a modified version of the library, if
303 | the user installs one, as long as the modified version is
304 | interface-compatible with the version that the work was made with.
305 |
306 | c) Accompany the work with a written offer, valid for at
307 | least three years, to give the same user the materials
308 | specified in Subsection 6a, above, for a charge no more
309 | than the cost of performing this distribution.
310 |
311 | d) If distribution of the work is made by offering access to copy
312 | from a designated place, offer equivalent access to copy the above
313 | specified materials from the same place.
314 |
315 | e) Verify that the user has already received a copy of these
316 | materials or that you have already sent this user a copy.
317 |
318 | For an executable, the required form of the "work that uses the
319 | Library" must include any data and utility programs needed for
320 | reproducing the executable from it. However, as a special exception,
321 | the materials to be distributed need not include anything that is
322 | normally distributed (in either source or binary form) with the major
323 | components (compiler, kernel, and so on) of the operating system on
324 | which the executable runs, unless that component itself accompanies
325 | the executable.
326 |
327 | It may happen that this requirement contradicts the license
328 | restrictions of other proprietary libraries that do not normally
329 | accompany the operating system. Such a contradiction means you cannot
330 | use both them and the Library together in an executable that you
331 | distribute.
332 |
333 | 7. You may place library facilities that are a work based on the
334 | Library side-by-side in a single library together with other library
335 | facilities not covered by this License, and distribute such a combined
336 | library, provided that the separate distribution of the work based on
337 | the Library and of the other library facilities is otherwise
338 | permitted, and provided that you do these two things:
339 |
340 | a) Accompany the combined library with a copy of the same work
341 | based on the Library, uncombined with any other library
342 | facilities. This must be distributed under the terms of the
343 | Sections above.
344 |
345 | b) Give prominent notice with the combined library of the fact
346 | that part of it is a work based on the Library, and explaining
347 | where to find the accompanying uncombined form of the same work.
348 |
349 | 8. You may not copy, modify, sublicense, link with, or distribute
350 | the Library except as expressly provided under this License. Any
351 | attempt otherwise to copy, modify, sublicense, link with, or
352 | distribute the Library is void, and will automatically terminate your
353 | rights under this License. However, parties who have received copies,
354 | or rights, from you under this License will not have their licenses
355 | terminated so long as such parties remain in full compliance.
356 |
357 | 9. You are not required to accept this License, since you have not
358 | signed it. However, nothing else grants you permission to modify or
359 | distribute the Library or its derivative works. These actions are
360 | prohibited by law if you do not accept this License. Therefore, by
361 | modifying or distributing the Library (or any work based on the
362 | Library), you indicate your acceptance of this License to do so, and
363 | all its terms and conditions for copying, distributing or modifying
364 | the Library or works based on it.
365 |
366 | 10. Each time you redistribute the Library (or any work based on the
367 | Library), the recipient automatically receives a license from the
368 | original licensor to copy, distribute, link with or modify the Library
369 | subject to these terms and conditions. You may not impose any further
370 | restrictions on the recipients' exercise of the rights granted herein.
371 | You are not responsible for enforcing compliance by third parties with
372 | this License.
373 |
374 | 11. If, as a consequence of a court judgment or allegation of patent
375 | infringement or for any other reason (not limited to patent issues),
376 | conditions are imposed on you (whether by court order, agreement or
377 | otherwise) that contradict the conditions of this License, they do not
378 | excuse you from the conditions of this License. If you cannot
379 | distribute so as to satisfy simultaneously your obligations under this
380 | License and any other pertinent obligations, then as a consequence you
381 | may not distribute the Library at all. For example, if a patent
382 | license would not permit royalty-free redistribution of the Library by
383 | all those who receive copies directly or indirectly through you, then
384 | the only way you could satisfy both it and this License would be to
385 | refrain entirely from distribution of the Library.
386 |
387 | If any portion of this section is held invalid or unenforceable under any
388 | particular circumstance, the balance of the section is intended to apply,
389 | and the section as a whole is intended to apply in other circumstances.
390 |
391 | It is not the purpose of this section to induce you to infringe any
392 | patents or other property right claims or to contest validity of any
393 | such claims; this section has the sole purpose of protecting the
394 | integrity of the free software distribution system which is
395 | implemented by public license practices. Many people have made
396 | generous contributions to the wide range of software distributed
397 | through that system in reliance on consistent application of that
398 | system; it is up to the author/donor to decide if he or she is willing
399 | to distribute software through any other system and a licensee cannot
400 | impose that choice.
401 |
402 | This section is intended to make thoroughly clear what is believed to
403 | be a consequence of the rest of this License.
404 |
405 | 12. If the distribution and/or use of the Library is restricted in
406 | certain countries either by patents or by copyrighted interfaces, the
407 | original copyright holder who places the Library under this License may add
408 | an explicit geographical distribution limitation excluding those countries,
409 | so that distribution is permitted only in or among countries not thus
410 | excluded. In such case, this License incorporates the limitation as if
411 | written in the body of this License.
412 |
413 | 13. The Free Software Foundation may publish revised and/or new
414 | versions of the Lesser General Public License from time to time.
415 | Such new versions will be similar in spirit to the present version,
416 | but may differ in detail to address new problems or concerns.
417 |
418 | Each version is given a distinguishing version number. If the Library
419 | specifies a version number of this License which applies to it and
420 | "any later version", you have the option of following the terms and
421 | conditions either of that version or of any later version published by
422 | the Free Software Foundation. If the Library does not specify a
423 | license version number, you may choose any version ever published by
424 | the Free Software Foundation.
425 |
426 | 14. If you wish to incorporate parts of the Library into other free
427 | programs whose distribution conditions are incompatible with these,
428 | write to the author to ask for permission. For software which is
429 | copyrighted by the Free Software Foundation, write to the Free
430 | Software Foundation; we sometimes make exceptions for this. Our
431 | decision will be guided by the two goals of preserving the free status
432 | of all derivatives of our free software and of promoting the sharing
433 | and reuse of software generally.
434 |
435 | NO WARRANTY
436 |
437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446 |
447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456 | DAMAGES.
457 |
458 | END OF TERMS AND CONDITIONS
459 |
460 | How to Apply These Terms to Your New Libraries
461 |
462 | If you develop a new library, and you want it to be of the greatest
463 | possible use to the public, we recommend making it free software that
464 | everyone can redistribute and change. You can do so by permitting
465 | redistribution under these terms (or, alternatively, under the terms of the
466 | ordinary General Public License).
467 |
468 | To apply these terms, attach the following notices to the library. It is
469 | safest to attach them to the start of each source file to most effectively
470 | convey the exclusion of warranty; and each file should have at least the
471 | "copyright" line and a pointer to where the full notice is found.
472 |
473 |
474 | Copyright (C)
475 |
476 | This library is free software; you can redistribute it and/or
477 | modify it under the terms of the GNU Lesser General Public
478 | License as published by the Free Software Foundation; either
479 | version 2.1 of the License, or (at your option) any later version.
480 |
481 | This library is distributed in the hope that it will be useful,
482 | but WITHOUT ANY WARRANTY; without even the implied warranty of
483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 | Lesser General Public License for more details.
485 |
486 | You should have received a copy of the GNU Lesser General Public
487 | License along with this library; if not, write to the Free Software
488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
489 | USA
490 |
491 | Also add information on how to contact you by electronic and paper mail.
492 |
493 | You should also get your employer (if you work as a programmer) or your
494 | school, if any, to sign a "copyright disclaimer" for the library, if
495 | necessary. Here is a sample; alter the names:
496 |
497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the
498 | library `Frob' (a library for tweaking knobs) written by James Random
499 | Hacker.
500 |
501 | , 1 April 1990
502 | Ty Coon, President of Vice
503 |
504 | That's all there is to it!
505 |
--------------------------------------------------------------------------------
/script.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Twitter(旧:𝕏)のインプレッション小遣い稼ぎ野郎どもをdisplay:none;するやつ
3 | // @name:ja Twitter(旧:𝕏)のインプレッション小遣い稼ぎ野郎どもをdisplay:none;するやつ
4 | // @name:en Hide the Twitter (formerly: 𝕏) impression-earning scammers with "display:none;"
5 | // @name:zh-CN 使用 "display:none;" 隐藏 Twitter(曾用名: 𝕏)的印象收益骗子。
6 | // @name:zh-TW 使用 "display:none;" 隱藏 Twitter(曾用名: 𝕏)的印象詐騙者。
7 | // @namespace https://github.com/hi2ma-bu4
8 | // @version 2.1.5
9 | // @description Twitterのインプレゾンビを非表示にしたりブロック・通報するツールです。
10 | // @description:ja Twitterのインプレゾンビを非表示にしたりブロック・通報するツールです。
11 | // @description:en A tool to hide, block, and report spam on Twitter.
12 | // @description:zh-CN 用于隐藏、阻止和报告 Twitter 上的垃圾邮件的工具。
13 | // @description:zh-TW 用於隱藏、封鎖和報告 Twitter 上的垃圾郵件的工具。
14 | // @author tromtub(snows)
15 | // @license LGPL-2.1
16 | // @match *://twitter.com/*
17 | // @match *://x.com/*
18 | // @match *://tweetdeck.twitter.com/*
19 | // @icon data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB7ElEQVR4Ae1XMZLCMAwUdw0ldJQ8ATpKnkBJByUd8ALyA/gBdJTQUtHS8QT4AaRM5ctmThmfogQ75CYNmhGTbGJr45Vk0yAiQzXaF9VsHwIZAofDgYwxqo9GI/K16/X6cqyxvdVqmdvtZh6PhwmCIHXcw7vdrpFj8ny9XhsYxhe8lwWHw2EycLFYpNh0Ok2w8/nsFHy1WrkE1wnAN5tNMkGv10ux3W6XIab5fD5P3ovldCGrP2Ap4LiW8uRJAcIwe1wpArYU0FJimhQgxaQ9cqX4BZYCgSVmS8HBfRP1JQEsY1xKGSmAcTC+l0QrIWDraicVMBBA4O1265ScpQnAMbkMwphjub1HAI7EkxoDK7n0/gQQGATsCmDMo+z++Hf8E5CjPZ9PiqKIZrMZhWFIl8slxcbjMTWbTTqdTuRrXoz5i2WXRIL+WxWw2+Uml13rnJUT4K9E9nMFaF3SxiojoO1u2rJzl4z3/+oIcHBMLiUp2rDe3ozg+BIYtNee87KjGzLGndPx7JD/0K7xog2Gl30ymaSY1jm9CPhsrXnnBK1zOhHgCWWtF7l2TtA6p3S1E+73exoMBrRcLul4PJKL3e93arfbSUeMA1O/36eYPHU6nWQu7pyaqRlfZnezV05anhSN34va7PPXrHYCP+VaTG3LBV1KAAAAAElFTkSuQmCC
20 | // @updateURL https://github.com/hi2ma-bu4/X_impression_hide/raw/main/script.user.js
21 | // @downloadURL https://github.com/hi2ma-bu4/X_impression_hide/raw/main/script.user.js
22 | // @supportURL https://github.com/hi2ma-bu4/X_impression_hide
23 | // @supportURL https://greasyfork.org/ja/scripts/484303
24 | // @compatible chrome
25 | // @compatible edge
26 | // @compatible opera chromium製なので動くと仮定(It's made with chromium so I assume it works)
27 | // @compatible firefox
28 | // @compatible kiwi
29 | // @compatible safari 確実に動く事は保証しません(I can't guarantee that it will work)
30 | // @grant GM.addStyle
31 | // @grant GM.setValue
32 | // @grant GM.getValue
33 | // @grant GM.deleteValue
34 | // @grant GM.registerMenuCommand
35 | // @run-at document-idle
36 | // @noframes
37 | // ==/UserScript==
38 |
39 | /*
40 | Twitter(旧:𝕏)のインプレッション小遣い稼ぎ野郎どもをdisplay:none;するやつ
41 |
42 | 略して、
43 |
44 | インプレゾンビをnoneするやつ
45 |
46 | */
47 | /*
48 | コピー・改変してもいいけど、
49 | 「tromtub(snows)」は変えないでね。
50 |
51 | */
52 | /* todo
53 | ・URLフィルター作成
54 | ・プロフィールメッセージフィルター作成
55 | ・画像リンク取得などを高速に
56 | ・gifをブロック
57 |
58 | ・検知率を上げる
59 | ・あやしい日本語の検知(多分自分の実力じゃ無理)
60 | ・フィルターをもっと有能に
61 | ・誤検知を減らす(今はまだいい?)
62 | ・クイックミュートボタンを作成
63 | ・whitelist_filterの実装
64 | ・名前
65 | ・他人の引用ツイートテキストフィルターを作成
66 | ・menuのresize:both;を左下に
67 | ・menuをもっと見やすく(たすけて)
68 | ・正規表現などの最適化
69 | ・軽量化
70 | */
71 |
72 | (function () {
73 | ("use strict");
74 |
75 | const PRO_NAME = "X_impression_hide";
76 | const VERSION = "v2.1.5";
77 |
78 | // スマホ判定
79 | const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
80 |
81 | // ここから設定
82 | const DEBUG = true;
83 |
84 | // ==========================================================================================
85 | // 設定初期値(定数)
86 | // ==========================================================================================
87 | const BLACK_TEXT_REG = `!# 行頭が"!#"だとコメント
88 |
89 | !# プロフィールメッセージを異常に推してる人
90 | ((初|はじ)めまして|こんにち[はわ]|こんばん[はわ]|やっほ|[き気]になった|良かったら).*?ぷろふ
91 | ぷろふ.*?の(確認|チェック|check)
92 | (follow|フォロー).*?の(確認|チェック|check)
93 | (^(連絡|絡み)|[→⇒➡]).*(よろ|おねがいします|返事)
94 |
95 | !# chatGPTのエラーメッセージを取り敢えず対処
96 | ^申し訳ありません.*?(過激な表現や性的な内容|不適切なコンテンツや言葉).*?他の(質問や話題|トピックで質問)があれば.*?。$
97 |
98 | !# 謎投資話
99 | 観察.*?毎日.*?銘柄.*?[万萬]円
100 | (偶然|指摘|ブロガー|トレーダー?|毎日|金融).*?(株|投資|銘柄|アドバイス).*?[万萬][円元]
101 | 毎日.*?相場.*?予測.*?株式
102 | 相場.*?85%
103 |
104 | !# chatGPT構文
105 | ですね!.+(です|ね)[!。]$
106 | されましたね!.+(です|ね)[!。]$
107 | でしょう.+かもしれません.+(です|ね)[!。]$
108 |
109 | !# 翻訳ってこと?!
110 | ^ハハハ、.+ます。?
111 | ^ああ、.+です。?
112 | それは.+ますね。.+ですか\\?
113 |
114 | !# 文章名指し
115 | この情報を共有していただきありがとうございます
116 | これはどういう意味ですか
117 |
118 | !# 陰謀的単語
119 | 人口地震
120 |
121 | !# 炎上商法
122 | 炎上覚悟で
123 | !# 大切なことを?言います|断言します|何度も言いますが|勘違いしてい?る人が多いですが
124 |
125 | !# タイ語のハッシュタグを含む場合
126 | #[\\u0E00-\\u0F7F]+
127 |
128 | !# アラビア語の単語を含む場合
129 | [\\u0600-\\u07FF]{4,}
130 |
131 | !# 中国語のなんかよく見るやつ
132 | ^想上课的私信主人
133 | ^太阳射不进来的地方
134 | ^挂空就是舒服,接点地气
135 | ^总说我下面水太多
136 | ^在这个炮火连天的夜晚
137 | ^只进入身体不进入生活
138 | ^生活太多伪装,只能在推上面卸下伪装
139 | ^生活枯燥无味,一个人的夜晚总想找个
140 | ^我每天都有好好的穿衣服.*俘获
141 | ^人不可能每一步都正确,我不想回头看,也不想批判当时的自己
142 | ^如果你连试着的胆量也没有,你也就配不上拥有性福
143 | ^我希望以后可以不用再送我回家,而是我们一起回我们的家
144 | ^勇敢一点我们在.*就有故事
145 | ^只要你主动一点点我们就会有机会.*线下
146 | `;
147 | // --------------------------------------------------
148 | const BLACK_FULL_TEXT_REG = `!# 行頭が"!#"だとコメント
149 |
150 | !# 謎投資話
151 | @[a-z0-9_]{3,30}.*?(先生|観察|発見).*?(助け|共有)
152 | (金融|借金|最近興味).*?@[a-z0-9_]{3,30}.*?(金融|投資|アドバイス|株|[万萬][円元])
153 | `;
154 | // --------------------------------------------------
155 | const WHITE_TEXT_REG = `!# 同上
156 |
157 | !# 例としてMisskey構文に対応してみる
158 | ^:[a-z0-9\-_]:$
159 |
160 | !# 緊急性の高い単語を除外
161 | !# ゾンビも使ってくるので除外ユーザー(Excluded users)を併用推奨
162 | !# (災害・防災アカウントidをフィルターに追記した為コメントアウト)
163 | !#
164 | !# 地震|余震|マグニチュード|火災|災害|津波|波浪|台風|震度
165 | !# jQuake
166 |
167 | `;
168 | // --------------------------------------------------
169 | /*
170 | const BLACK_RT_TEXT_REG = `!# 同上
171 |
172 | !# 英語の動画宣伝RTの構文
173 | (vid|video).*free
174 | free.*(vid|video)
175 | `;
176 | */
177 | // --------------------------------------------------
178 | const BLACK_NAME_REG = `!# 同上
179 |
180 | !# アラビア語のみで構成
181 | ^([\\u0600-\\u07FF ]|\\p{P}|\\p{S})+$
182 |
183 | !# ヒンディー語のみで構成
184 | ^([\\u0900-\\u097F ]|\\p{P}|\\p{S})+$
185 |
186 | !# エロ垢抹消
187 | ぷろふ.*(確認|ちぇっく|check)
188 | おふぱこ
189 |
190 | !# 謎投資話
191 | NFT|投資
192 |
193 | !# 中国語のなんかよく見るやつ
194 | 反差
195 | 私信领福利
196 | 同城
197 | 可约
198 | `;
199 | // --------------------------------------------------
200 | const EXCLUDED_USERS = `!# 同上
201 |
202 | !# 例として製作者のidを指定
203 | @hi2ma_bu4
204 |
205 | !# 災害(緊急)情報発信者を除外
206 | !# 表記抜けや、誤字はGithubのIssuesにご報告下さい。
207 | @UN_NERV
208 | @EN_NERV
209 | @EqAlarm
210 | @saigai_sokuho
211 | @MLIT_JAPAN
212 | @CAO_BOUSAI
213 | @JMA_bousai
214 | @JMA_kishou
215 | @JCG_koho
216 | @meti_NIPPON
217 | @ModJapan_saigai
218 | @Kanboukansen
219 | @NPA_saigaiKOHO
220 | @MPD_bousai
221 | @JapanSafeTravel
222 | @JSCE_Saigai
223 | @nhk_seikatsu
224 | @TBC_saigai
225 | @ats_saigai
226 | @tokyo_bousai
227 | @yokohama_saigai
228 | @yamaguchiSaigai
229 | @y_minami_saigai
230 | @w_city_saigai
231 | @sakai_saigai
232 | @Saigai_ishikawa
233 | @saigai01
234 | @HiroshimaBousai
235 | @etajima_bousai
236 | @chibaken_saigai
237 | @aichi_bousai
238 | @kawasaki_bousai
239 | @EhimeBousai
240 | @Gunma_bousai
241 | @nodasi_saigai
242 | @IshiSaigai
243 | @kfb_saigai
244 | @KagoshimaSaigai
245 | @kouchi_bousai
246 | @NTTWestOfficial
247 | @rikudennw
248 | @denjiren
249 | @denjiren_saigai
250 | @mlit_chokoku
251 | @JREast_official
252 |
253 | !# サイバーセキュリティ
254 | @cas_nisc
255 | @nisc_forecast
256 |
257 | !# TV
258 | @news24ntv
259 |
260 | !# 交通情報
261 | @shutoko_traffic
262 | @nexco_kanto
263 | @e_nexco_touhoku
264 | @JAL_flight_info
265 | @JRE_Super_Exp
266 | @odakyuline_info
267 | `;
268 | // TODO: プロフィールメッセージフィルター機能を作る
269 | // Bimbo
270 | // --------------------------------------------------
271 | const ALLOW_LANG = "ja|en|es|zh|ko|pt|qme|qam|und";
272 | // --------------------------------------------------
273 | const SUB_DEFINITION_SUB = `!# 同上
274 |
275 | !# それっぽいのをまとめとく
276 | ((season|シーズン).{0,2}(\\d{1,2}|[IVX]{1,5})|サブ|ファースト|セカンド|サード|新・?|ファイナル|(\\d{1,4}|[一二三四五六七八九十百千万壱弐参肆伍陸漆捌玖拾陌阡萬廿丗卅世]+)代目|sub|first|1st|second|2nd|third|3rd|fourth|4th|new|final)
277 | `;
278 | // --------------------------------------------------
279 | const PLAT_FORM_BLACK_REG = `!# 同上
280 |
281 | !# 例:
282 | !# Twitter for Android
283 | !# Twitter for iPhone
284 | !# Twitter Web App
285 |
286 | !# 広告などの投稿元
287 | Twitter for Advertisers
288 | `;
289 |
290 | // ==========================================================================================
291 | // 要素命名用 定数
292 | // ==========================================================================================
293 | const EX_MENU_ID = PRO_NAME + "_menu";
294 | /**
295 | * 独自利用id,class名定義
296 | * @readonly
297 | * @enum {string}
298 | */
299 | const ELEM_NAME_DICT = {
300 | PARENT_CLASS: PRO_NAME + "_parent",
301 | CHECK_CLASS: PRO_NAME + "_check",
302 | HIDE_CLASS: PRO_NAME + "_none",
303 | LOG_CLASS: PRO_NAME + "_log",
304 | HIDE_TITLE_CLASS: PRO_NAME + "_title",
305 | HIDE_TITLE_SHOW_CLASS: PRO_NAME + "_title_show",
306 | HIDE_TITLE_BUBBLE_CLASS: PRO_NAME + "_title_bubble",
307 | MORE_TWEET_CLASS: PRO_NAME + "_moreTweet",
308 | VERIFY_CLASS: PRO_NAME + "_verify",
309 | PC_FLAG_CLASS: PRO_NAME + "_pc",
310 | MOBILE_FLAG_CLASS: PRO_NAME + "_mobile",
311 | EX_MENU_ID: EX_MENU_ID,
312 | EX_MENU_OPEN_CLASS: EX_MENU_ID + "_open",
313 | EX_MENU_ITEM_BASE_ID: EX_MENU_ID + "_item_",
314 | EX_MENU_ITEM_ERROR_CLASS: EX_MENU_ID + "_err",
315 | // Userscripts対応(ゴリ押し)
316 | EX_MENU_OPEN_BUTTON: EX_MENU_ID + "_openBtn",
317 | // OldTweetDeck対応(ゴリ押し)
318 | USE_TWEET_DECK_CLASS: PRO_NAME + "_tweetDeck",
319 | };
320 |
321 | // ==========================================================================================
322 | // css初期値(定数)
323 | // ==========================================================================================
324 | const BASE_CSS = /* css */ `
325 | #${EX_MENU_ID} {
326 | display: none;
327 | position: fixed;
328 | color: #111;
329 | top: 0;
330 | right: 0;
331 | z-index: 2000;
332 | }
333 | /* 積み防止 */
334 | #${EX_MENU_ID}.${ELEM_NAME_DICT.EX_MENU_OPEN_CLASS} {
335 | display: block !important;
336 | visibility: visible !important;
337 | }
338 |
339 | #${EX_MENU_ID} > div {
340 | position: relative;
341 | overflow-y: scroll;
342 | overscroll-behavior: contain;
343 | width: 50vh;
344 | min-width: 200px;
345 | max-width: 90vw;
346 | height: 50vh;
347 | min-height: 200px;
348 | max-height: 90vh;
349 | resize: both;
350 | border: solid #000 2px;
351 | background: #fafafaee;
352 | }
353 |
354 | #${ELEM_NAME_DICT.EX_MENU_ITEM_BASE_ID}__btns {
355 | position: sticky;
356 | right: 0;
357 | bottom: 0;
358 | text-align: right;
359 | }
360 |
361 | /* ツイート非表示 */
362 | .${ELEM_NAME_DICT.HIDE_CLASS}:has(.${ELEM_NAME_DICT.LOG_CLASS} input[type=checkbox]:not(:checked)) > div:not(.${ELEM_NAME_DICT.LOG_CLASS}),
363 | .${ELEM_NAME_DICT.HIDE_CLASS}:not(:has(.${ELEM_NAME_DICT.LOG_CLASS})) > div:not(.${ELEM_NAME_DICT.LOG_CLASS}) {
364 | display: none;
365 | }
366 |
367 | body:not(.${ELEM_NAME_DICT.USE_TWEET_DECK_CLASS}) .${ELEM_NAME_DICT.HIDE_CLASS}:has(.${ELEM_NAME_DICT.LOG_CLASS}):not(:has(article)) {
368 | display: none;
369 | }
370 |
371 | /* 検出内容の表示設定 */
372 | .${ELEM_NAME_DICT.PARENT_CLASS} .${ELEM_NAME_DICT.HIDE_CLASS} {
373 | background: #aaaa;
374 | }
375 |
376 | /* 以下非表示後の表示内容設定 */
377 | .${ELEM_NAME_DICT.LOG_CLASS} {
378 | display: flex;
379 | justify-content: space-between;
380 | }
381 |
382 | .${ELEM_NAME_DICT.HIDE_TITLE_CLASS} {
383 | position: relative;
384 | display: inline-block;
385 | cursor: help;
386 | }
387 |
388 | .${ELEM_NAME_DICT.HIDE_TITLE_BUBBLE_CLASS} {
389 | position: absolute;
390 | background-color: rgba(0, 0, 0, 0.85);
391 | color: #fff;
392 | padding: 0.3em 0.5em;
393 | border-radius: 6px;
394 | font-size: 0.8em;
395 | white-space: nowrap;
396 | word-break: keep-all;
397 | overflow-wrap: break-word;
398 | z-index: 100;
399 | bottom: 125%;
400 | left: 50%;
401 | transform: translateX(-50%);
402 | opacity: 0;
403 | pointer-events: none;
404 | transition: opacity 0.2s;
405 | max-width: 90vw;
406 | }
407 |
408 | .${ELEM_NAME_DICT.HIDE_TITLE_CLASS}.${ELEM_NAME_DICT.HIDE_TITLE_SHOW_CLASS} .${ELEM_NAME_DICT.HIDE_TITLE_BUBBLE_CLASS} {
409 | opacity: 1;
410 | pointer-events: auto;
411 | }
412 |
413 | .${ELEM_NAME_DICT.LOG_CLASS} > span > a {
414 | color: rgb(29, 155, 240);
415 | margin-left: 0.25em;
416 | text-decoration: underline;
417 | }
418 |
419 | .${ELEM_NAME_DICT.LOG_CLASS} input[type=checkbox] {
420 | display: none;
421 | }
422 | .${ELEM_NAME_DICT.LOG_CLASS} label {
423 | cursor: pointer;
424 | }
425 | .${ELEM_NAME_DICT.LOG_CLASS} label:hover {
426 | text-decoration: underline;
427 | }
428 |
429 | .${ELEM_NAME_DICT.LOG_CLASS} input[type=button] {
430 | cursor: pointer;
431 | background-color: rgba(0,0,0,0);
432 | border: white 2px outset;
433 | }
434 | .${ELEM_NAME_DICT.LOG_CLASS} input[type=button]:hover {
435 | background-color: rgba(29, 155, 240, .5);
436 | }
437 |
438 | .${ELEM_NAME_DICT.VERIFY_CLASS} {
439 | max-width: 20px;
440 | max-height: 20px;
441 | color: rgb(29, 155, 240);
442 | fill: currentcolor;
443 | user-select: none;
444 | height: 1.25em;
445 | display: inline-block;
446 | vertical-align: middle;
447 | }
448 |
449 | /* メニュー表示設定 */
450 | #${EX_MENU_ID}.${ELEM_NAME_DICT.MOBILE_FLAG_CLASS} {
451 | font-size: 0.8em;
452 | }
453 | #${EX_MENU_ID} textarea {
454 | width: 95%;
455 | resize: vertical;
456 | height: 8em;
457 | max-height: 25em;
458 | tab-size: 4;
459 | white-space: pre;
460 | font-size: 0.89em;
461 | }
462 | #${EX_MENU_ID} input[type=text] {
463 | width: 95%;
464 | }
465 |
466 | #${EX_MENU_ID} input[type=text],
467 | #${EX_MENU_ID} input[type=number],
468 | #${EX_MENU_ID} textarea,
469 | #${EX_MENU_ID} select {
470 | border: 1px solid #ccc;
471 | }
472 |
473 | #${EX_MENU_ID} input[type=button] {
474 | background-color: #ffffffaa;
475 | border: 1px solid #ccc;
476 | border-radius: 4px;
477 | color: #111133;
478 | cursor: pointer;
479 | margin: 0;
480 | padding: 0.08em 0.2em;
481 | transition: background 0.2s;
482 | }
483 | #${EX_MENU_ID} input[type=button]:hover {
484 | background-color: rgba(29, 155, 240, .5);
485 | }
486 |
487 | #${EX_MENU_ID} input[type=checkbox] + label::after {
488 | content: "Invalid";
489 | }
490 | #${EX_MENU_ID} input[type=checkbox]:checked + label::after {
491 | content: "Validity";
492 | }
493 | #${EX_MENU_ID}[lang=ja] input[type=checkbox] + label::after {
494 | content: "無効";
495 | }
496 | #${EX_MENU_ID}[lang=ja] input[type=checkbox]:checked + label::after {
497 | content: "有効";
498 | }
499 |
500 | #${EX_MENU_ID} summary {
501 | cursor: pointer;
502 | }
503 |
504 | #${EX_MENU_ID} details {
505 | margin-top: 1em;
506 | }
507 |
508 | .${ELEM_NAME_DICT.EX_MENU_ITEM_BASE_ID}_name {
509 | font-size: 1.3em;
510 | margin-bottom: 3px;
511 | margin-left: 2px;
512 | }
513 | .${ELEM_NAME_DICT.EX_MENU_ITEM_BASE_ID}_name + p {
514 | font-size: .8em;
515 | margin: 0 4px;
516 | }
517 |
518 | .${ELEM_NAME_DICT.EX_MENU_ITEM_ERROR_CLASS} {
519 | color: red;
520 | margin: 0;
521 | }
522 |
523 | #${ELEM_NAME_DICT.EX_MENU_OPEN_BUTTON} {
524 | background: transparent;
525 | font-weight: bold;
526 | position: fixed;
527 | width: 10em;
528 | height: 2em;
529 | top: 0;
530 | right: 0;
531 | }
532 |
533 | /* iPad 第1~3世代(画面横)*/
534 | @media (max-device-width: 1024px) and (orientation: landscape) {
535 | #${ELEM_NAME_DICT.EX_MENU_OPEN_BUTTON} {
536 | width: 20em;
537 | height: 4em;
538 | }
539 | }
540 | /* iPad 第4世代*/
541 | @media screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) {
542 | #${ELEM_NAME_DICT.EX_MENU_OPEN_BUTTON} {
543 | width: 20em;
544 | height: 4em;
545 | }
546 | }
547 |
548 | `;
549 | // --------------------------------------------------
550 | const CUSTOM_CSS = /* css */ ``;
551 |
552 | // ==========================================================================================
553 | // 内部使用他(定数)
554 | // ==========================================================================================
555 | /**
556 | * メニューform分類
557 | * @readonly
558 | * @enum {string}
559 | */
560 | const MENU_INPUT_TYPE = {
561 | text: "text",
562 | num: "number",
563 | check: "checkbox",
564 | textarea: "textarea",
565 | select: "select",
566 | btn: "button",
567 | };
568 | /**
569 | * メニュー分類グループ分類
570 | * @readonly
571 | * @enum {string}
572 | */
573 | const MENU_GROUP_TYPE = {
574 | basic: "basic",
575 | internalRef : "internalRef",
576 | advanced: "advanced",
577 | tweetDeck: "tweetDeck",
578 | debug: "debug",
579 | };
580 | // --------------------------------------------------
581 | // 非表示id
582 |
583 | /**
584 | * メッセージフィルターの非表示id
585 | * @readonly
586 | * @enum {number}
587 | */
588 | const FILTED_HIDDEN_ID = {
589 | processed: -2,
590 | evaluated: -1,
591 | newEntry: 0,
592 | commentFilterDetection: 1,
593 | commentEmojiOnly: 2,
594 | textDuplication: 3,
595 | highUsage: 4,
596 | selfCitation: 5,
597 | nameFilterDetection: 6,
598 | nameEmojiOnly: 7,
599 | verifyRtBlock: 8,
600 | symbolUsage: 9,
601 | detectedElsewhere: 10,
602 | authenticatedAccount: 11,
603 | unauthorizedLanguage: 12,
604 | selfCitationSub: 13,
605 | contributtonCount: 14,
606 | rtContributtonCount: 15,
607 | rtSharingSeries: 16,
608 | fullCommentFilterDetection: 17,
609 | platformFilterDetection: 18,
610 | };
611 |
612 | // --------------------------------------------------
613 | // データ保存用 定数
614 | const SETTING_SAVE_KEY = PRO_NAME + "_json";
615 | const BLACK_MEMORY_KEY = PRO_NAME + "_blackMemory";
616 |
617 | // --------------------------------------------------
618 | // 許可URL (ページ)
619 | const ALLOW_PAGE_SET = new Set(["home", "search"]);
620 | // 許可URL (ステータス)
621 | const ALLOW_STATUS_SET = new Set(["status", "tweetdeck"]);
622 |
623 | // --------------------------------------------------
624 | // 翻訳key
625 | const MENU_LANG_KEY = "menu_";
626 | const MENU_LANG_KEY_NAME = "_name";
627 | const MENU_LANG_KEY_EXPLANATION = "_explanation";
628 |
629 | // --------------------------------------------------
630 | /**
631 | * 翻訳データ
632 | * @readonly
633 | * @constant {Object.>} LANGUAGE_DICT
634 | */
635 | const LANGUAGE_DICT = {
636 | ja: {
637 | // 日本語
638 | menu_warn: /* html */ `
639 | 現在のバージョン: ${VERSION}
640 | 変更の保存をした場合、ページを更新してください。
641 | 使い方の説明はこちらから`,
642 | menu_internalRef: "追加参照機能",
643 | menu_advanced: "高度な設定",
644 | menu_tweetDeck: "OldTweetDeck",
645 | menu_debug: "デバッグ",
646 | menu_error: "上記の設定内容の実行に失敗しました",
647 | save: "保存",
648 | close: "閉じる",
649 | filter: "フィルター",
650 | similarity: "類似度",
651 | usageCount: "使用回数",
652 | viewOriginalTweet: "元Tweetを見る",
653 | sureReset: "本当にリセットを実行しますか?",
654 |
655 | // setting menu
656 | menu_visibleLog_name: "非表示ログを表示",
657 | menu_visibleLog_explanation: `非表示にしたログを画面から消します。
658 | 画面が平和になりますが、投稿を非表示にされた理由・元投稿が確認出来なくなります。`,
659 | menu_visibleVerifyLog_name: "非表示ログに認証マーク表示",
660 | menu_visibleVerifyLog_explanation: `非表示にしたログの名前の後ろに認証マークを追加します。
661 | 企業バッジでも青バッジで表示されます。`,
662 | menu_blackTextReg_name: "禁止する表現",
663 | menu_blackTextReg_explanation: `非表示にするテキストを指定します。
664 | メンション・ハッシュタグ・シンボルタグ・URLなどのリンク、絵文字は判定に含まれません。
665 | 記述方法は正規表現(/の間部分)で記述します。
666 | (半角カタカナ、カタカナはひらがなに自動変換されます)
667 | (全角英数字は半角英数字に、改行文字は半角スペースに自動変換されます)`,
668 | menu_blackFullTextReg_name: "禁止する表現[拡張]",
669 | menu_blackFullTextReg_explanation: `非表示にするテキストを指定します。
670 | メンション・ハッシュタグ・シンボルタグ・URLなどのリンク、絵文字を判定に含みます。
671 | 指定方法などは[禁止する表現]と同じです。`,
672 | menu_whiteTextReg_name: "許可する表現",
673 | menu_whiteTextReg_explanation: `許可するテキストを指定します。
674 | 一致する投稿は非表示の対象になりません。
675 | 指定方法などは[禁止する表現]と同じです。`,
676 | menu_blackRtTextReg_name: "禁止するRT表現",
677 | menu_blackRtTextReg_explanation: `非表示にするRT元テキストを指定します。
678 | 指定方法などは[禁止する表現]と同じです。`,
679 | menu_blackNameReg_name: "禁止する名前",
680 | menu_blackNameReg_explanation: `非表示にするユーザー名を指定します。
681 | 指定方法などは[禁止する表現]と同じです。`,
682 | menu_excludedUsers_name: "除外ユーザー",
683 | menu_excludedUsers_explanation: `指定されたユーザーidは検知の対象になりません。
684 | 指定方法はユーザーidを改行で区切って記述するだけです。
685 | idは完全一致のみ有効です。`,
686 | menu_allowLang_name: "許可する言語",
687 | menu_allowLang_explanation: `許可する言語を指定します。
688 | 記述方法は正規表現(/の間部分)で記述します。`,
689 | menu_oneselfRetweetBlock_name: "自身の引用禁止",
690 | menu_oneselfRetweetBlock_explanation: `自身を引用ツイートする投稿を非表示にします。`,
691 | menu_oneselfSubRetweetBlock_name: "サブ垢での自身の引用禁止",
692 | menu_oneselfSubRetweetBlock_explanation: `サブ垢での自身を引用ツイートする投稿を非表示にします。
693 | ユーザー名から[サブ,2nd]などを除外しての一致検索です。`,
694 | menu_subDefinitionReg_name: "サブ垢定義用表現",
695 | menu_subDefinitionReg_explanation: `[サブ垢での自身の引用禁止]での除外文字を指定します。
696 | 1行ずつ評価していく為同時評価が必要な場合は「(aaa|bbb)」を使用して下さい。
697 | 指定方法などは[禁止する表現]と同じです。`,
698 | menu_emojiOnryBlock_name: "絵文字投稿禁止",
699 | menu_emojiOnryBlock_explanation: `絵文字のみで構成された投稿を非表示にします。`,
700 | menu_emojiOnryNameBlock_name: "絵文字ユーザー名禁止",
701 | menu_emojiOnryNameBlock_explanation: `絵文字のみで構成されたユーザー名を非表示にします。`,
702 | menu_verifyBlock_name: "認証アカウント禁止",
703 | menu_verifyBlock_explanation: `認証済アカウントを無差別に非表示にします。`,
704 | menu_verifyRtBlock_name: "認証RT禁止",
705 | menu_verifyRtBlock_explanation: `認証済アカウント投稿に対する引用RTを非表示にします。`,
706 | menu_verifyOnryFilter_name: "認証アカウントのみ判定",
707 | menu_verifyOnryFilter_explanation: `認証済アカウントのみを検知の対象にします。
708 | 通常アカウントや認証マークの無いアカウントはブロックされなくなります。`,
709 | menu_formalityCare_name: "認証公式アカウントを保護",
710 | menu_formalityCare_explanation: `公式アカウントを検知の対象から除外します。
711 | (公式とは青いバッジ以外を指します)`,
712 | menu_visibleBlockButton_name: "クイックブロック表示",
713 | menu_visibleBlockButton_explanation: `1クリックでブロックできるボタンを表示します。
714 | 検出された投稿にしか表示されません。`,
715 | menu_visibleReportButton_name: "クイック通報表示",
716 | menu_visibleReportButton_explanation: `1クリックで通報できるボタンを表示します。
717 | 検出された投稿にしか表示されません。
718 | (初期値はスパム報告です)`,
719 | menu_maxHashtagCount_name: "ハッシュタグの上限数",
720 | menu_maxHashtagCount_explanation: `1つの投稿内でのハッシュタグの使用上限数を指定します。`,
721 | menu_maxSymboltagCount_name: "シンボルタグの上限数",
722 | menu_maxSymboltagCount_explanation: `1つの投稿内でのシンボルタグの使用上限数を指定します。
723 | ※シンボルタグとは「$TWTR」のような#を$に置き換えた株を表す表現`,
724 | menu_maxContributtonCount_name: "ツリー返信上限数",
725 | menu_maxContributtonCount_explanation: `1つの投稿ツリーでの返信上限数を指定します。
726 | 値は許可のラインです。(例: 1で2投稿以上は非表示)
727 | 0を指定するとこの設定は無効化されます。`,
728 | menu_maxRtCount_name: "1人によるRT上限数",
729 | menu_maxRtCount_explanation: `1つの投稿ツリーでの1ユーザーの引用RT返信上限数を指定します。
730 | 値は[ツリー返信上限数]と同じ指定方法です。`,
731 | menu_maxSameRtCount_name: "同一RT上限数",
732 | menu_maxSameRtCount_explanation: `1つの投稿ツリーでの複数人からの同じユーザーに対する引用RT返信上限数を指定します。
733 | 値は[ツリー返信上限数]と同じ指定方法です。`,
734 | menu_msgResemblance_name: "文章類似度許可ライン",
735 | menu_msgResemblance_explanation: `コピペ文章かを判別する為の基準値を指定します。`,
736 | menu_maxSaveTextSize_name: "比較される最大テキストサイズ",
737 | menu_maxSaveTextSize_explanation: `コピペ投稿の文章比較の最大文字数を指定します。
738 | 値を大きくするほど誤検知率は減り、検知率も減ります。
739 | (投稿の文字数が最大値以下の場合、この値は使用されません)`,
740 | menu_minSaveTextSize_name: "一時保存・比較される最小テキストサイズ",
741 | menu_minSaveTextSize_explanation: `比較用文章の最小文字数を指定します。
742 | 値が大きくするほど誤検知率は減り、検知率も減ります。
743 | ([比較される最大テキストサイズ]より大きい場合、比較処理は実行されません)`,
744 | menu_maxSaveLogSize_name: "一時保存される投稿の最大数",
745 | menu_maxSaveLogSize_explanation: `比較用文章の保持数を指定します。
746 | 値が小さいほど処理は軽くなりますが、検知率が減ります。`,
747 | menu_language_name: "言語",
748 | menu_language_explanation: `表示言語を設定します。`,
749 | menu_useTwitterInternalData_name: "Twitter内部データ使用",
750 | menu_useTwitterInternalData_explanation: `ユーザーと同じ画面(DOM)からのデータ取得ではなく、
751 | 内部で使用されているオブジェクトを処理に流用します。
752 | Twitterのアップデートで動作しなくなる可能性があります。
753 | 取得に失敗した場合既存の取得方法が代替で使用されます。
754 | OldTweetDeckでは無効です。`,
755 | menu_platformBlackReg_name: "禁止するプラットフォーム",
756 | menu_platformBlackReg_explanation: `「Twitter Web App」などの投稿環境で判定します。
757 | 指定方法などは[禁止する表現]と同じです。
758 | [Twitter内部データ使用]が無効の場合、動作しません。`,
759 | menu_customCss_name: "ページ適用css設定",
760 | menu_customCss_explanation: `ページへ適用するcssを指定します。`,
761 | menu_bodyObsTimeout_name: "ページ更新検知用処理待機時間(ms)",
762 | menu_bodyObsTimeout_explanation: `ページ更新を検知する際の検知の更新間隔を指定します。
763 | 値が大きいほど処理が軽くなりますが、非表示にする初速が落ちる可能性あります。`,
764 | menu_blackMemory_name: "検知対象の記憶",
765 | menu_blackMemory_explanation: `検出された対象を記憶します。
766 | ページを更新などしても過去に検知した対象を素早く非表示に出来ます。
767 | ※この機能はbeta版です!!
768 | 誤検知されたアカウントが非表示のままになります。
769 | [除外ユーザー]と併用して使用して下さい。`,
770 | menu_autoBlock_name: "【非推奨】自動ブロック",
771 | menu_autoBlock_explanation: `検出された対象を自動でブロックします。
772 | ※この機能はbeta版です!!
773 | 誤検知でも戸惑いなくブロックされます。`,
774 | menu_useRegModeDotAll_name: "dotAllモードの利用",
775 | menu_useRegModeDotAll_explanation: `内部で使用する正規表現でdotAllモードを使用可能にします。
776 | この機能を無効にした場合、正規表現を記述するフィルターで改行を明示的に指定する必要があります。
777 | 変更を行う前に、その影響について理解して変更して下さい。(ES9)`,
778 | menu_resetSetting_name: "設定のリセット",
779 | menu_resetSetting_explanation: `設定項目をリセットします。
780 | (ページがリロードされます)
781 | 実行すると設定は復元出来ません!!!`,
782 | menu_resetBlackMemory_name: "検知済idのリセット",
783 | menu_resetBlackMemory_explanation: `検知済idをリセットします。
784 | (ページがリロードされます)
785 | 実行するとこれまで検知・非表示にされたユーザーが再度表示される可能性が高くなります!
786 | [検知対象の記憶]を使用している状況で以前より処理が重いと感じた場合、リセットすると処理が軽くなる可能性があります。`,
787 | menu_enableOldTweetDeckMode_name: "OldTweetDeck対応",
788 | menu_enableOldTweetDeckMode_explanation: `負荷軽減の為に分離
789 | ※この機能はbeta版です!!
790 | 動作の安定性を保証出来ません。`,
791 | menu_autoLoadJQuery_name: "jQuery自動読み込み",
792 | menu_autoLoadJQuery_explanation: `OldTweetDeckではなぜかjQueryが使用されているのにjQueryが読み込まれていない為、
793 | jQueryが読み込まれていない場合にjQueryを読み込む機能です。`,
794 | menu_debug_viewSettingMenu_name: "起動時設定自動表示",
795 | menu_debug_viewSettingMenu_explanation: `設定画面を自動で開く`,
796 | menu_debug_visibleCardDebugButton_name: "クイックデバッグ表示",
797 | menu_debug_visibleCardDebugButton_explanation: `1クリックでコンソールに該当MsgDataを出力できるボタンを表示します。
798 | 検出された投稿にしか表示されません。
799 | 検出された投稿は軽量化のためMsgDataを破棄するのでこの参照が最後の記録`,
800 | menu_debug_viewBlacklist_name: "blacklist表示",
801 | menu_debug_viewBlacklist_explanation: `現在のblacklist_idをconsoleに出力する。`,
802 | menu_debug_viewMsgDB_name: "MsgDB表示",
803 | menu_debug_viewMsgDB_explanation: `現在のMsgDBをconsoleに出力する。`,
804 | menu_debug_reInit_name: "init再実行",
805 | menu_debug_reInit_explanation: `強制的にDOM設定を再設定する。
806 | [ページ更新検知用処理待機時間(ms)]が仕事を放棄した際に使用。`,
807 |
808 | //hideComment
809 | detectedElsewhere: "他で検出済",
810 | authenticatedAccount: "認証垢",
811 | verifyRtBlock: "認証RT垢",
812 | unauthorizedLanguage: "非許可言語",
813 | contributtonCount: "連投",
814 | rtContributtonCount: "RT連投",
815 | rtSharingSeries: "RT共有連投",
816 | filterDetection: "フィルター検出",
817 | emojiOnly: "絵文字のみ",
818 | textDuplication: "文章の複製",
819 | highUsage: "#多量使用",
820 | symbolUsage: "$多量使用",
821 | selfCitation: "自身の引用",
822 | selfCitationSub: "自身を引用?",
823 | platformFilterDetection: "投稿元規制",
824 | recursiveDetection: "再帰的検出",
825 | },
826 | en: {
827 | // 英語
828 | menu_warn: /* html */ `
829 | Current version: ${VERSION}
830 | If you have saved the changes, please refresh the page.
831 | You can find the usage instructions here`,
832 | menu_internalRef: "Additional Reference",
833 | menu_advanced: "Advanced settings",
834 | menu_tweetDeck: "OldTweetDeck",
835 | menu_debug: "Debug",
836 | menu_error: "Failed to execute the above settings",
837 | save: "Save",
838 | close: "Close",
839 | filter: "Filter",
840 | similarity: "Similarity",
841 | usageCount: "UsageCount",
842 | viewOriginalTweet: "View original Tweet",
843 | sureReset: "Are you sure you want to execute the reset?",
844 |
845 | // setting menu
846 | menu_visibleLog_name: "Show hidden logs",
847 | menu_visibleLog_explanation: `It will remove the hidden logs from the screen.
848 | The screen will be peaceful, but the reasons for hiding the posts and the original posts will no longer be visible.`,
849 | menu_visibleVerifyLog_name: "Certification mark displayed on hidden log",
850 | menu_visibleVerifyLog_explanation: `Adds a certification mark after the name of the hidden log.
851 | Corporate badges are also displayed as blue badges.`,
852 | menu_blackTextReg_name: "Prohibited expressions",
853 | menu_blackTextReg_explanation: `Specify the text to hide.
854 | Mentions, hashtags, symbol tags, URLs, and emojis are excluded from the evaluation.
855 | The description should be written using regular expressions (between the / characters).
856 | Half-width katakana and katakana will be automatically converted to hiragana.
857 | Full-width alphanumeric characters will be converted to half-width,
858 | and line breaks will be converted to spaces automatically.`,
859 | menu_blackFullTextReg_name: "Prohibited expressions[Plus]",
860 | menu_blackFullTextReg_explanation: `Specify the text to hide.
861 | Mentions, hashtags, symbol tags, URLs, and emojis are included in the evaluation.
862 | The specification method is the same as [Prohibited expressions].`,
863 | menu_whiteTextReg_name: "Expressions allowed",
864 | menu_whiteTextReg_explanation: `Specify the text to allow.
865 | Matching posts will not be hidden.
866 | The specification method is the same as [Prohibited expressions].`,
867 | menu_blackRtTextReg_name: "Prohibited RT expressions",
868 | menu_blackRtTextReg_explanation: `Specify the RT source text to hide.
869 | The specification method is the same as [Prohibited expressions].`,
870 | menu_blackNameReg_name: "Prohibited name",
871 | menu_blackNameReg_explanation: `Specify the username to hide.
872 | The specification method is the same as [Prohibited expressions].`,
873 | menu_excludedUsers_name: "Excluded users",
874 | menu_excludedUsers_explanation: `The specified user ID will not be detected.
875 | To specify, simply write the user IDs separated by line breaks.
876 | Only exact matches are valid for id.`,
877 | menu_allowLang_name: "Allowed languages",
878 | menu_allowLang_explanation: `Specify the allowed languages.
879 | The description should be written using regular expressions (between the / characters).`,
880 | menu_oneselfRetweetBlock_name: "Prohibition of self-quotation",
881 | menu_oneselfRetweetBlock_explanation: `It hides posts that quote oneself.`,
882 | menu_oneselfSubRetweetBlock_name: "Prohibition of quoting yourself in sub-text",
883 | menu_oneselfSubRetweetBlock_explanation: `It hides posts that quote oneself.`,
884 | menu_subDefinitionReg_name: "Expression for sub-scale definition",
885 | menu_subDefinitionReg_explanation: `Specify the excluded characters for [Prohibit quoting yourself in sub-text].
886 | If you need simultaneous evaluation, use "(aaa|bbb)" as each line is evaluated one by one.
887 | The specification method is the same as [Prohibited expressions].`,
888 | menu_emojiOnryBlock_name: "No emoji posting",
889 | menu_emojiOnryBlock_explanation: `Hide posts composed only of emojis.`,
890 | menu_emojiOnryNameBlock_name: "Prohibit emoji usernames",
891 | menu_emojiOnryNameBlock_explanation: `Hide usernames composed only of emojis.`,
892 | menu_verifyBlock_name: "Prohibition of authenticated accounts",
893 | menu_verifyBlock_explanation: `It indiscriminately hides authenticated accounts.`,
894 | menu_verifyRtBlock_name: "Authentication RT prohibited",
895 | menu_verifyRtBlock_explanation: `Hide quoted RTs for authenticated account posts.`,
896 | menu_verifyOnryFilter_name: "Authenticate accounts only",
897 | menu_verifyOnryFilter_explanation: `It detects only authenticated accounts.
898 | Regular accounts and accounts without verification badges will no longer be blocked.`,
899 | menu_formalityCare_name: "Protect your authenticated official account",
900 | menu_formalityCare_explanation: `Exclude official accounts from detection.
901 | (Official means anything other than the blue badge)`,
902 | menu_visibleBlockButton_name: "Quick block button display",
903 | menu_visibleBlockButton_explanation: `Displays a button that allows you to block with one click.
904 | It will only appear on detected posts.`,
905 | menu_visibleReportButton_name: "Quick report button display",
906 | menu_visibleReportButton_explanation: `Displays a button that allows you to report with one click.
907 | It will only appear on detected posts.
908 | (Initial value is spam report)`,
909 | menu_maxHashtagCount_name: "Maximum number of hashtags",
910 | menu_maxHashtagCount_explanation: `It specifies the maximum number of hashtags allowed in a single post.`,
911 | menu_maxSymboltagCount_name: "Maximum number of symboltags",
912 | menu_maxSymboltagCount_explanation: `It specifies the maximum number of symboltags allowed in a single post.
913 | *Symbol tag is an expression that represents a stock by replacing # with $, such as "$TWTR"`,
914 | menu_maxContributtonCount_name: "Maximum number of tree replies",
915 | menu_maxContributtonCount_explanation: `Specify the maximum number of replies in one post tree.
916 | The value is the line of permission. (Example: 1 hides 2 or more posts)
917 | Specifying 0 disables this setting.`,
918 | menu_maxRtCount_name: "Maximum number of RTs by one person",
919 | menu_maxRtCount_explanation: `Specify the maximum number of quote RT replies for one user in one post tree.
920 | The value is specified in the same way as [Maximum number of tree replies].`,
921 | menu_maxSameRtCount_name: "Maximum number of same RTs",
922 | menu_maxSameRtCount_explanation: `Specify the maximum number of quote RT replies to the same user from multiple people in one post tree.
923 | The value is specified in the same way as [Maximum number of tree replies].`,
924 | menu_msgResemblance_name: "Text similarity threshold",
925 | menu_msgResemblance_explanation: `It specifies the threshold value for determining whether a text is a copied and pasted text.`,
926 | menu_maxSaveTextSize_name: "Maximum text size for comparison",
927 | menu_maxSaveTextSize_explanation: `It specifies the maximum number of characters for text comparison in copied and pasted posts.
928 | Increasing the value reduces the false positive rate but also reduces the detection rate.
929 | (This value is not used if the post's character count is below the maximum value.)`,
930 | menu_minSaveTextSize_name: "The minimum text size that is temporarily saved and compared",
931 | menu_minSaveTextSize_explanation: `This specifies the minimum number of characters for the comparison text.
932 | Increasing the value reduces the false detection rate as well as the detection rate.
933 | If it is larger than the [Maximum text size for comparison], the comparison process will not be executed.`,
934 | menu_maxSaveLogSize_name: "The maximum number of posts that are temporarily saved",
935 | menu_maxSaveLogSize_explanation: `This specifies the number of comparison texts to be retained.
936 | A smaller value reduces the processing load but also decreases the detection rate.`,
937 | menu_language_name: "Language",
938 | menu_language_explanation: `Set the display language.`,
939 | menu_useTwitterInternalData_name: "Use of Twitter internal data",
940 | menu_useTwitterInternalData_explanation: `Instead of retrieving data from the same screen (DOM) as the user, this feature reuses internal objects used by Twitter.
941 | This may stop working if Twitter updates their platform.
942 | If data retrieval fails, the existing method will be used as a fallback.
943 | This is not supported on OldTweetDeck.`,
944 | menu_platformBlackReg_name: "Disallowed platforms",
945 | menu_platformBlackReg_explanation: `Posts are identified based on the source client, like "Twitter Web App".
946 | The specification method is the same as [Prohibited expressions].
947 | Does not work if [Use of Twitter internal data] is disabled.`,
948 | menu_customCss_name: "Page-specific CSS settings",
949 | menu_customCss_explanation: `Specify the CSS to apply to the page.`,
950 | menu_bodyObsTimeout_name: "Processing wait time (in milliseconds) for page update detection",
951 | menu_bodyObsTimeout_explanation: `This specifies the interval for detecting page updates.
952 | A larger value reduces the processing load but may potentially delay the initial speed of hiding.`,
953 | menu_blackMemory_name: "Memory of detection target",
954 | menu_blackMemory_explanation: `Remembers detected objects.
955 | Even if you refresh the page, you can quickly hide objects detected in the past.
956 | *This feature is in beta version! !
957 | Falsely detected accounts remain hidden.
958 | Please use it in conjunction with [Excluded User]. `,
959 | menu_autoBlock_name: "[Not recommended] Automatic block",
960 | menu_autoBlock_explanation: `Automatically block detected targets.
961 | *This feature is in beta version! !
962 | Even false positives are blocked without hesitation.`,
963 | menu_useRegModeDotAll_name: "Using dotAll mode",
964 | menu_useRegModeDotAll_explanation: `Enables the use of dotAll mode in regular expressions used internally.
965 | If this feature is disabled, you will need to explicitly specify line breaks in filters that use regular expressions.
966 | Please make sure you understand the implications before making changes. (ES9)`,
967 | menu_resetSetting_name: "Reset settings",
968 | menu_resetSetting_explanation: `Reset the settings.
969 | (The page will be reloaded.)
970 | Once executed, the settings cannot be restored!!!`,
971 | menu_resetBlackMemory_name: "Reset detected ID",
972 | menu_resetBlackMemory_explanation: `Reset detected ID.
973 | (The page will be reloaded.)
974 | If you run it, there is a high possibility that users who have been detected/hidden will be displayed again!
975 | If you feel that the processing is slower than before when using [Remember detection targets], resetting it may make the processing faster. `,
976 | menu_enableOldTweetDeckMode_name: "OldTweetDeck compatible",
977 | menu_enableOldTweetDeckMode_explanation: `Separated to reduce load
978 | *This feature is in beta version! !
979 | We cannot guarantee the stability of operation.`,
980 | menu_autoLoadJQuery_name: "jQuery Autoload",
981 | menu_autoLoadJQuery_explanation: `For some reason, jQuery is used in OldTweetDeck but is not loaded, so this function loads jQuery when jQuery is not loaded.`,
982 | menu_debug_viewSettingMenu_name: "Automatic display of settings at startup",
983 | menu_debug_viewSettingMenu_explanation: `Automatically open the settings screen`,
984 | menu_debug_viewBlacklist_name: "Blacklist display",
985 | menu_debug_viewBlacklist_explanation: `Output current blacklist_id to console.`,
986 | menu_debug_viewMsgDB_name: "MsgDB display",
987 | menu_debug_viewMsgDB_explanation: `Output current MsgDB to console.`,
988 | menu_debug_reInit_name: "init rerun",
989 | menu_debug_reInit_explanation: `Force DOM settings to be reset.
990 | Used when [Processing wait time (in milliseconds) for page update detection] is abandoned.`,
991 |
992 | //hideComment
993 | detectedElsewhere: "DetectedElsewhere",
994 | authenticatedAccount: "AuthenticatedAccount",
995 | verifyRtBlock: "AuthenticationRtPlaque",
996 | unauthorizedLanguage: "UnauthorizedLanguage: ",
997 | contributtonCount: "doubleTexting",
998 | rtContributtonCount: "rtDoubleTexting",
999 | rtSharingSeries: "rtSharingSeries",
1000 | filterDetection: "FilterDetection",
1001 | emojiOnly: "EmojiOnly",
1002 | textDuplication: "TextDuplication",
1003 | highUsage: "#HighUsage",
1004 | symbolUsage: "$HighUsage",
1005 | selfCitation: "SelfCitation",
1006 | selfCitationSub: "selfCitationSub",
1007 | platformFilterDetection: "PlatformRestriction",
1008 | recursiveDetection: "RecursiveDetection",
1009 | },
1010 | };
1011 |
1012 | /**
1013 | * メニューのセレクトボックス内容
1014 | * @readonly
1015 | * @constant {Object.} SETTING_LANG_SELECT
1016 | */
1017 | const SETTING_LANG_SELECT = {
1018 | ja: "日本語(ja)",
1019 | en: "English(en)",
1020 | };
1021 |
1022 | // --------------------------------------------------
1023 |
1024 | /**
1025 | * 標準参照Query一覧
1026 | * @enum {string}
1027 | */
1028 | const _BASIC_QUERY_DICT = {
1029 | OBS_QUERY: "section > div > div:has(article)",
1030 | RE_QUERY: `div:has(div > div > article):not(.${ELEM_NAME_DICT.CHECK_CLASS})`,
1031 | NAME_SPACE_QUERY: `[data-testid="User-Name"]`,
1032 | NAME_QUERY: `:not(span) > span > span`,
1033 | ID_QUERY: "div > span:not(:has(span))",
1034 | VERIFY_QUERY: `svg:not(:has([fill^="#"]))`,
1035 | VERIFY_FORMALITY_QUERY: `svg:has([fill^="#"])`,
1036 | TEXT_DIV_QUERY: "div[lang]",
1037 | IMAGE_QUERY: `a img, [data-testid="videoComponent"] video`,
1038 | MENU_BUTTON_QUERY: "[aria-haspopup=menu][role=button]:has(svg)",
1039 | MENU_DISP_QUERY: "[role=group] [role=menu]",
1040 | };
1041 | if (isMobile) {
1042 | _BASIC_QUERY_DICT.MENU_DISP_QUERY = "#layers [role=menu] [role=group]";
1043 | }
1044 |
1045 | /**
1046 | * OldTweetDeck参照Query一覧
1047 | * @enum {string}
1048 | */
1049 | const _OLD_TWEET_DECK_QUERY_DICT = {
1050 | OBS_QUERY: "body .js-app-columns:has(section)",
1051 | RE_QUERY: `article:has(div > div > header):not(.${ELEM_NAME_DICT.CHECK_CLASS})`,
1052 | NAME_SPACE_QUERY: "header",
1053 | NAME_QUERY: ".fullname",
1054 | ID_QUERY: ".username",
1055 | TEXT_DIV_QUERY: ".tweet-text",
1056 | };
1057 |
1058 | /**
1059 | * 参照Query一覧
1060 | * @enum {string}
1061 | */
1062 | const EX_QUERY_DICT = new Proxy(_BASIC_QUERY_DICT, {
1063 | get(target, prop, receiver) {
1064 | if (useOldTweetDeck) {
1065 | let ret = _OLD_TWEET_DECK_QUERY_DICT[prop];
1066 | if (ret) return ret;
1067 | }
1068 | return target[prop];
1069 | },
1070 | set(target, prop, value, receiver) {
1071 | console.warn(`Cannot assign to read-only property: ${prop}`);
1072 | return false;
1073 | },
1074 | });
1075 |
1076 | /**
1077 | * 標準参照Queryリスト一覧
1078 | * @enum {Array}
1079 | */
1080 | const _BASIC_QUERY_LIST_DICT = {
1081 | BLOCK_QUERY_LIST: [`${_BASIC_QUERY_DICT.MENU_DISP_QUERY} div[role=menuitem]:has(path[d^="M12 3.75c"])`, "[role=alertdialog] [role=group] [role=button] div"],
1082 | // 3行目は場合によっては消す
1083 | REPORT_QUERY_LIST: [`${_BASIC_QUERY_DICT.MENU_DISP_QUERY} div[role=menuitem]:has(path[d^="M3 2h18"])`, ["[role=radiogroup] label", 5], "[role=group]:has([role=radiogroup]) [role=button]:not(:has(svg))", ["[role=group] [role=button]:not(:has(svg))", 1], ["__wait__", 1000], ["[role=group] [role=button]:not(:has(svg))", 1]],
1084 | };
1085 |
1086 | /**
1087 | * OldTweetDeck参照Queryリスト一覧
1088 | * @enum {Array}
1089 | */
1090 | const _OLD_TWEET_DECK_QUERY_LIST_DICT = {};
1091 |
1092 | /**
1093 | * 参照Queryリスト一覧
1094 | * @enum {Array}
1095 | */
1096 | const EX_QUERY_LIST_DICT = new Proxy(_BASIC_QUERY_LIST_DICT, {
1097 | get(target, prop, receiver) {
1098 | if (useOldTweetDeck) {
1099 | let ret = _OLD_TWEET_DECK_QUERY_LIST_DICT[prop];
1100 | if (ret) return ret;
1101 | }
1102 | return target[prop];
1103 | },
1104 | set(target, prop, value, receiver) {
1105 | console.warn(`Cannot assign to read-only property: ${prop}`);
1106 | return false;
1107 | },
1108 | });
1109 |
1110 | const VERIFY_SVG = `
1111 |
1117 | `;
1118 |
1119 | // --------------------------------------------------
1120 | /**
1121 | * 設定リスト内容定義
1122 | * @typedef {Object} SettingItem
1123 | * @property {boolean|string|number} [initData] - 設定項目の初期データ
1124 | * @property {boolean|string|number} [data] - 設定項目データ
1125 | * @property {MENU_INPUT_TYPE} input - 設定項目の入力タイプ
1126 | * @property {MENU_GROUP_TYPE} group - 所属グループ
1127 | * @property {string} [value] - `MENU_INPUT_TYPE`が`btn`の場合のvalue
1128 | * @property {number} [min] - `MENU_INPUT_TYPE`が`num`の場合の最小値
1129 | * @property {number} [max] - `MENU_INPUT_TYPE`が`num`の場合の最小値
1130 | * @property {number} [step] - `MENU_INPUT_TYPE`が`num`の場合の増分値
1131 | * @property {string} [select] - `MENU_INPUT_TYPE`が`select`の場合のoptions
1132 | * @property {boolean} [isError] - 【自動設定】エラーが設定項目に含まれる場合true
1133 | * @property {RegExp[]} [regexp_list] - 【自動設定】regRestorationで使用
1134 | * @property {RegExp} [regexp] - 【自動設定】1項目regで使用
1135 | */
1136 |
1137 | /**
1138 | * 設定リスト
1139 | * @type {Object.}
1140 | */
1141 | const SETTING_LIST = {
1142 | visibleLog: {
1143 | initData: true,
1144 | input: MENU_INPUT_TYPE.check,
1145 | group: MENU_GROUP_TYPE.basic,
1146 | },
1147 | visibleVerifyLog: {
1148 | initData: true,
1149 | input: MENU_INPUT_TYPE.check,
1150 | group: MENU_GROUP_TYPE.basic,
1151 | },
1152 | blackTextReg: {
1153 | initData: BLACK_TEXT_REG,
1154 | input: MENU_INPUT_TYPE.textarea,
1155 | group: MENU_GROUP_TYPE.basic,
1156 | },
1157 | blackFullTextReg: {
1158 | initData: BLACK_FULL_TEXT_REG,
1159 | input: MENU_INPUT_TYPE.textarea,
1160 | group: MENU_GROUP_TYPE.basic,
1161 | },
1162 | whiteTextReg: {
1163 | initData: WHITE_TEXT_REG,
1164 | input: MENU_INPUT_TYPE.textarea,
1165 | group: MENU_GROUP_TYPE.basic,
1166 | },
1167 | // blackRtTextReg: {
1168 | // initData: BLACK_RT_TEXT_REG,
1169 | // input: MENU_INPUT_TYPE.textarea,
1170 | // group: MENU_GROUP_TYPE.basic,
1171 | // },
1172 | blackNameReg: {
1173 | initData: BLACK_NAME_REG,
1174 | input: MENU_INPUT_TYPE.textarea,
1175 | group: MENU_GROUP_TYPE.basic,
1176 | },
1177 | excludedUsers: {
1178 | initData: EXCLUDED_USERS,
1179 | input: MENU_INPUT_TYPE.textarea,
1180 | group: MENU_GROUP_TYPE.basic,
1181 | },
1182 | allowLang: {
1183 | initData: ALLOW_LANG,
1184 | input: MENU_INPUT_TYPE.text,
1185 | group: MENU_GROUP_TYPE.basic,
1186 | regexp: /.*/,
1187 | },
1188 | oneselfRetweetBlock: {
1189 | initData: true,
1190 | input: MENU_INPUT_TYPE.check,
1191 | group: MENU_GROUP_TYPE.basic,
1192 | },
1193 | oneselfSubRetweetBlock: {
1194 | initData: true,
1195 | input: MENU_INPUT_TYPE.check,
1196 | group: MENU_GROUP_TYPE.basic,
1197 | },
1198 | subDefinitionReg: {
1199 | initData: SUB_DEFINITION_SUB,
1200 | input: MENU_INPUT_TYPE.textarea,
1201 | group: MENU_GROUP_TYPE.basic,
1202 | },
1203 | emojiOnryBlock: {
1204 | initData: true,
1205 | input: MENU_INPUT_TYPE.check,
1206 | group: MENU_GROUP_TYPE.basic,
1207 | },
1208 | emojiOnryNameBlock: {
1209 | initData: true,
1210 | input: MENU_INPUT_TYPE.check,
1211 | group: MENU_GROUP_TYPE.basic,
1212 | },
1213 | verifyBlock: {
1214 | initData: false,
1215 | input: MENU_INPUT_TYPE.check,
1216 | group: MENU_GROUP_TYPE.basic,
1217 | },
1218 | verifyRtBlock: {
1219 | initData: false,
1220 | input: MENU_INPUT_TYPE.check,
1221 | group: MENU_GROUP_TYPE.basic,
1222 | },
1223 | verifyOnryFilter: {
1224 | initData: false,
1225 | input: MENU_INPUT_TYPE.check,
1226 | group: MENU_GROUP_TYPE.basic,
1227 | },
1228 | formalityCare: {
1229 | initData: true,
1230 | input: MENU_INPUT_TYPE.check,
1231 | group: MENU_GROUP_TYPE.basic,
1232 | },
1233 | visibleBlockButton: {
1234 | initData: true,
1235 | input: MENU_INPUT_TYPE.check,
1236 | group: MENU_GROUP_TYPE.basic,
1237 | },
1238 | visibleReportButton: {
1239 | initData: true,
1240 | input: MENU_INPUT_TYPE.check,
1241 | group: MENU_GROUP_TYPE.basic,
1242 | },
1243 | maxHashtagCount: {
1244 | initData: 6,
1245 | input: MENU_INPUT_TYPE.num,
1246 | group: MENU_GROUP_TYPE.basic,
1247 | min: 1,
1248 | step: 1,
1249 | },
1250 | maxSymboltagCount: {
1251 | initData: 1,
1252 | input: MENU_INPUT_TYPE.num,
1253 | group: MENU_GROUP_TYPE.basic,
1254 | min: 1,
1255 | step: 1,
1256 | },
1257 | maxContributtonCount: {
1258 | initData: 2,
1259 | input: MENU_INPUT_TYPE.num,
1260 | group: MENU_GROUP_TYPE.basic,
1261 | min: 0,
1262 | step: 1,
1263 | },
1264 | maxRtCount: {
1265 | initData: 1,
1266 | input: MENU_INPUT_TYPE.num,
1267 | group: MENU_GROUP_TYPE.basic,
1268 | min: 0,
1269 | step: 1,
1270 | },
1271 | maxSameRtCount: {
1272 | initData: 1,
1273 | input: MENU_INPUT_TYPE.num,
1274 | group: MENU_GROUP_TYPE.basic,
1275 | min: 0,
1276 | step: 1,
1277 | },
1278 | msgResemblance: {
1279 | initData: 0.85,
1280 | input: MENU_INPUT_TYPE.num,
1281 | group: MENU_GROUP_TYPE.basic,
1282 | min: 0,
1283 | max: 1,
1284 | step: 0.01,
1285 | },
1286 | maxSaveTextSize: {
1287 | initData: 100,
1288 | input: MENU_INPUT_TYPE.num,
1289 | group: MENU_GROUP_TYPE.basic,
1290 | min: 0,
1291 | step: 1,
1292 | },
1293 | minSaveTextSize: {
1294 | initData: 8,
1295 | input: MENU_INPUT_TYPE.num,
1296 | group: MENU_GROUP_TYPE.basic,
1297 | min: 0,
1298 | step: 1,
1299 | },
1300 | maxSaveLogSize: {
1301 | initData: 200,
1302 | input: MENU_INPUT_TYPE.num,
1303 | group: MENU_GROUP_TYPE.basic,
1304 | min: 1,
1305 | step: 1,
1306 | },
1307 | language: {
1308 | initData: "ja",
1309 | input: MENU_INPUT_TYPE.select,
1310 | group: MENU_GROUP_TYPE.basic,
1311 | select: SETTING_LANG_SELECT,
1312 | },
1313 | // -------------------------
1314 | useTwitterInternalData: {
1315 | initData: true,
1316 | input: MENU_INPUT_TYPE.check,
1317 | group: MENU_GROUP_TYPE.internalRef,
1318 | },
1319 | platformBlackReg: {
1320 | initData: PLAT_FORM_BLACK_REG,
1321 | input: MENU_INPUT_TYPE.textarea,
1322 | group: MENU_GROUP_TYPE.internalRef,
1323 | },
1324 | // -------------------------
1325 | customCss: {
1326 | initData: CUSTOM_CSS,
1327 | input: MENU_INPUT_TYPE.textarea,
1328 | group: MENU_GROUP_TYPE.advanced,
1329 | },
1330 | bodyObsTimeout: {
1331 | initData: 3000,
1332 | input: MENU_INPUT_TYPE.num,
1333 | group: MENU_GROUP_TYPE.advanced,
1334 | min: 100,
1335 | step: 1,
1336 | },
1337 | blackMemory: {
1338 | initData: false,
1339 | input: MENU_INPUT_TYPE.check,
1340 | group: MENU_GROUP_TYPE.advanced,
1341 | },
1342 | autoBlock: {
1343 | initData: false, // trueにしてはいけない(戒め)
1344 | input: MENU_INPUT_TYPE.check,
1345 | group: MENU_GROUP_TYPE.advanced,
1346 | },
1347 | useRegModeDotAll: {
1348 | initData: true,
1349 | input: MENU_INPUT_TYPE.check,
1350 | group: MENU_GROUP_TYPE.advanced,
1351 | },
1352 | resetSetting: {
1353 | input: MENU_INPUT_TYPE.btn,
1354 | group: MENU_GROUP_TYPE.advanced,
1355 | value: "Reset",
1356 | },
1357 | resetBlackMemory: {
1358 | input: MENU_INPUT_TYPE.btn,
1359 | group: MENU_GROUP_TYPE.advanced,
1360 | value: "Reset",
1361 | },
1362 | // -------------------------
1363 | enableOldTweetDeckMode: {
1364 | initData: false,
1365 | input: MENU_INPUT_TYPE.check,
1366 | group: MENU_GROUP_TYPE.tweetDeck,
1367 | },
1368 | autoLoadJQuery: {
1369 | initData: true,
1370 | input: MENU_INPUT_TYPE.check,
1371 | group: MENU_GROUP_TYPE.tweetDeck,
1372 | },
1373 | // -------------------------
1374 | debug_viewSettingMenu: {
1375 | initData: false,
1376 | input: MENU_INPUT_TYPE.check,
1377 | group: MENU_GROUP_TYPE.debug,
1378 | },
1379 | debug_visibleCardDebugButton: {
1380 | initData: false,
1381 | input: MENU_INPUT_TYPE.check,
1382 | group: MENU_GROUP_TYPE.debug,
1383 | },
1384 | debug_viewBlacklist: {
1385 | input: MENU_INPUT_TYPE.btn,
1386 | group: MENU_GROUP_TYPE.debug,
1387 | value: "Output",
1388 | },
1389 | debug_viewMsgDB: {
1390 | input: MENU_INPUT_TYPE.btn,
1391 | group: MENU_GROUP_TYPE.debug,
1392 | value: "Output",
1393 | },
1394 | debug_reInit: {
1395 | input: MENU_INPUT_TYPE.btn,
1396 | group: MENU_GROUP_TYPE.debug,
1397 | value: "Retry",
1398 | },
1399 | };
1400 |
1401 | // 元データ保存
1402 | for (let key in SETTING_LIST) {
1403 | if (SETTING_LIST[key].initData !== undefined) {
1404 | SETTING_LIST[key].data = SETTING_LIST[key].initData;
1405 | }
1406 | }
1407 |
1408 | // --------------------------------------------------
1409 |
1410 | /** @type {Object. | null} */
1411 | let lang_dict = null;
1412 |
1413 | /** @type {HTMLElement} */
1414 | let parentDOM = null;
1415 | /** @type {MutationObserver} */
1416 | let parent_observer = null;
1417 | /** @type {string} */
1418 | let oldUrl = location.href;
1419 | /** @type {string} */
1420 | let parent_id = null;
1421 | /** @type {HTMLElement} */
1422 | let exMenuDOM = null;
1423 |
1424 | /** @type {MessageData[]} */
1425 | const msgDB = [];
1426 | /** @type {Set} */
1427 | const msgDB_id = new Set();
1428 | /** @type {Set} */
1429 | const blacklist_id = new Set();
1430 | /** @type {Set} */
1431 | const excludedUsersSet = new Set();
1432 |
1433 | // 類似文字列検索使用フラグ
1434 | let levenshteinDistanceUseFlag = true;
1435 | let internalDataRefFlag = true;
1436 | // ページ読み込み停止フラグ
1437 | let stopFlag = false;
1438 |
1439 | /**
1440 | * 正規表現で以下を使用するか
1441 | * @enum {boolean}
1442 | */
1443 | const useRegModeList = {
1444 | i: true, // ES1 : 大文字・小文字を区別しない
1445 | m: true, // ES3 : 複数行モード (^ や $ が各行の先頭/末尾にマッチ)
1446 | u: true, // ES6 : Unicodeモード (サロゲートペアを正しく処理)
1447 | s: true, // ES9 : dotAllモード (. が改行 \n にもマッチするようになる)
1448 | };
1449 | let useRegMode = "";
1450 |
1451 | // OldTweetDeck関連
1452 | let isPageOldTweetDeck = false;
1453 | let useOldTweetDeck = false;
1454 |
1455 | // ページ変更確認に使用
1456 | let body_isReservation = false;
1457 | let body_isWait = false;
1458 | // もっと見るを軽量で観測する為に使用
1459 | let existMoreTweet = false;
1460 |
1461 | // --------------------------------------------------
1462 | const spaceRegList = [
1463 | /[ \t]/gu,
1464 | /[\u00A0\u00AD\u034F\u061C]/gu,
1465 | /[\u115F\u1160\u17B4\u17B5\u180E]/gu,
1466 | // \u200Dが合成時に消失したため部分対処
1467 | /[\u2000-\u200C\u200E-\u200F\u202F\u205F\u2060-\u2064\u206A-\u206F\u2800]/gu,
1468 | /[\u3000\u3164]/gu,
1469 | /[\uFEFF\uFFA0]/gu,
1470 | /[\u{1D159}\u{1D173}-\u{1D17A}]/gu,
1471 | ];
1472 | const normalizeRegList = [
1473 | [/[ア-ヺ]/g, (ch) => String.fromCharCode(ch.charCodeAt(0) - 0x60)],
1474 | [/[”“″‶〝‟]/gu, '"'],
1475 | [/[’‘′´‛‵']/gu, "'"],
1476 | ];
1477 | const reRegExpReg = /\\x([0-9a-fA-F]{2})|\\u([0-9a-fA-F]{4})|\\u\{([0-9a-fA-F]{1,6})\}/g;
1478 | const CrLfReg = /[\r\n]/gu;
1479 | const spaceReg = / /g;
1480 |
1481 | const tweetUrlImgReg = /^https?:\/\/pbs\.twimg\.com\/media\//;
1482 | const tweetUrlVideoReg = /^https?:\/\/video\.twimg\.com\/tweet_video\//;
1483 |
1484 | // ==========================================================================================
1485 | // メッセージデータ保存 クラス
1486 | // ==========================================================================================
1487 |
1488 | /**
1489 | * リンクデータ
1490 | */
1491 | class LinkData {
1492 | /**
1493 | * リンクデータ保存
1494 | * @param {string} href
1495 | * @param {string} value
1496 | */
1497 | constructor(href, value) {
1498 | this.href = href;
1499 | this.value = value;
1500 | }
1501 | }
1502 |
1503 | /**
1504 | * メッセージデータ
1505 | */
1506 | class MessageData {
1507 | /**
1508 | * メッセージデータ保存
1509 | * @param {string} url
1510 | * @param {HTMLElement} card
1511 | */
1512 | constructor(url, card) {
1513 | this.base_url = url;
1514 | /** @type {HTMLElement} */
1515 | this.card = card;
1516 | this.verify = false;
1517 | this.formality = false;
1518 | /**
1519 | * LinkDataを入れるオブジェクト
1520 | * @type {{mention: LinkData[], hashtag: LinkData[], symboltag: LinkData[], url: LinkData[]}}
1521 | */
1522 | this.has_link_dict = {
1523 | mention:[],
1524 | hashtag:[],
1525 | symboltag: [],
1526 | url:[],
1527 | }
1528 | this.attach_img = false;
1529 | this.attach_file_list = [];
1530 | /** @type {MessageData | null} */
1531 | this.reTweet = null;
1532 | /** @type {MessageData | null} */
1533 | this.parentTweet = null;
1534 | /** @type {HTMLElement | null} */
1535 | this.menuDOM = null;
1536 |
1537 | this._nsOneLoadFlag = false;
1538 | this._notTextDiv = false;
1539 | }
1540 |
1541 | /**
1542 | * カードデータ取得
1543 | * @returns {Promise | false}
1544 | */
1545 | cardDataGet() {
1546 | const article = this._getArticle();
1547 | if (!article) {
1548 | return false;
1549 | }
1550 |
1551 | let nameSpace_div = article.querySelectorAll(EX_QUERY_DICT.NAME_SPACE_QUERY);
1552 | nameSpace_div.forEach((div) => {
1553 | // 2回目以降はリツイート
1554 | if (this._nsOneLoadFlag) {
1555 | this._addReTweet();
1556 | }
1557 |
1558 | if (internalDataRefFlag) {
1559 | try {
1560 | const toolbar = this.card.querySelector(`div[id][aria-label][role="group"]`);
1561 | const pr_list = Object.getOwnPropertyNames(toolbar);
1562 | const pr_name = pr_list.find((input)=>input.includes('__reactProps$'));
1563 | const data = toolbar[pr_name];
1564 | this.internalData = data?.children[1]?.props?.retweetWithCommentLink?.state?.quotedStatus;
1565 | } catch (e){
1566 | console.warn(`内部データ取得失敗`);
1567 | }
1568 | }
1569 |
1570 | // ユーザー名(id)取得
1571 | let name_span = div.querySelector(EX_QUERY_DICT.NAME_QUERY);
1572 | if (this._nsOneLoadFlag) {
1573 | this.reTweet._setName(name_span?.innerText);
1574 | } else {
1575 | this._setName(name_span?.innerText);
1576 | // フルネーム取得
1577 | if (this.internalData){
1578 | this.fullName = this.internalData.user.name;
1579 | }
1580 | }
1581 |
1582 | // id取得(ついでに認証マーク判定)
1583 | let id_span = div.querySelectorAll(EX_QUERY_DICT.ID_QUERY);
1584 | id_span.forEach((span) => {
1585 | let fc = span.querySelector(EX_QUERY_DICT.VERIFY_FORMALITY_QUERY);
1586 | if (fc != null) {
1587 | if (this._nsOneLoadFlag) {
1588 | this.reTweet.formality = true;
1589 | } else {
1590 | this.formality = true;
1591 | }
1592 | }
1593 | fc = span.querySelector(EX_QUERY_DICT.VERIFY_QUERY);
1594 | if (fc != null) {
1595 | if (this._nsOneLoadFlag) {
1596 | this.reTweet.verify = true;
1597 | } else {
1598 | this.verify = true;
1599 | }
1600 | } else {
1601 | let tmp = span.innerText.trim();
1602 | if (tmp.startsWith("@")) {
1603 | if (this._nsOneLoadFlag) {
1604 | this.reTweet.id = tmp;
1605 | } else {
1606 | this.id = tmp;
1607 | }
1608 | }
1609 | }
1610 | });
1611 |
1612 | this._nsOneLoadFlag = true;
1613 | });
1614 |
1615 | // 投稿時間取得
1616 | let time_elem = article.querySelector("time");
1617 | if (!time_elem) {
1618 | return false;
1619 | }
1620 | if (!this._setDate(time_elem.dateTime)) return false;
1621 |
1622 | const pro = [
1623 | // 画像添付確認
1624 | this._imgCheck(article),
1625 | // メニュー取得(...のこと)
1626 | this._getMenu(article),
1627 | ];
1628 |
1629 | this._text_divs = article.querySelectorAll(EX_QUERY_DICT.TEXT_DIV_QUERY);
1630 | let text_div = this._text_divs?.[0];
1631 |
1632 | let fullStr = "";
1633 | let str = "";
1634 | let emojiLst = [];
1635 | if (text_div) {
1636 | let tmp;
1637 | text_div.childNodes.forEach((elem) => {
1638 | if (useOldTweetDeck) {
1639 | if (elem.nodeType === Node.TEXT_NODE) {
1640 | tmp = elem.nodeValue;
1641 | str += tmp;
1642 | fullStr += tmp;
1643 | } else if (elem.tagName === "IMG") {
1644 | tmp = elem.alt;
1645 | emojiLst.push(tmp);
1646 | fullStr += tmp;
1647 | }
1648 | } else {
1649 | switch (elem.tagName) {
1650 | case "SPAN":
1651 | tmp = elem.innerText;
1652 | str += tmp;
1653 | fullStr += tmp;
1654 | break;
1655 | case "DIV":
1656 | let a = elem.querySelector(`a[href]`);
1657 | tmp = a?.innerText;
1658 | if (!tmp || !tmp.length || !a.href.startsWith("http")){
1659 | break;
1660 | }
1661 | const hld = this.has_link_dict;
1662 | const ld = new LinkData(a.href, tmp);
1663 | switch (tmp.slice(0, 1)) {
1664 | case "@": // メンション
1665 | hld.mention.push(ld);
1666 | break;
1667 | case "#": // ハッシュタグ
1668 | hld.hashtag.push(ld);
1669 | break;
1670 | case "$": // シンボルタグ
1671 | hld.symboltag.push(ld);
1672 | break;
1673 | default:
1674 | hld.url.push(ld);
1675 | }
1676 | fullStr += ld.value;
1677 | break;
1678 | case "IMG":
1679 | tmp = elem.alt;
1680 | emojiLst.push(tmp);
1681 | fullStr += tmp;
1682 | break;
1683 | }
1684 | }
1685 | });
1686 | } else {
1687 | this._notTextDiv = true;
1688 | }
1689 |
1690 | this._setFullMessage(fullStr);
1691 | this._setMessage(str);
1692 | this.emoji = emojiLst;
1693 |
1694 | return Promise.all(pro);
1695 | }
1696 |
1697 | /**
1698 | * 処理対象か判定/取得
1699 | * @returns {HTMLElement}
1700 | */
1701 | _getArticle() {
1702 | let article;
1703 | if (useOldTweetDeck) {
1704 | article = this.card;
1705 | } else {
1706 | article = this.card.firstChild?.firstChild?.firstChild;
1707 | }
1708 | if (article?.tagName != "ARTICLE") {
1709 | return null;
1710 | }
1711 | return article;
1712 | }
1713 |
1714 | /**
1715 | * ReTweetである場合
1716 | * @returns {MessageData}
1717 | */
1718 | _addReTweet() {
1719 | const md = new MessageData(this.base_url, null);
1720 | this.reTweet = md;
1721 | md.parentTweet = this;
1722 | return md;
1723 | }
1724 |
1725 | /**
1726 | * 名前設定
1727 | * @param {string} name
1728 | * @returns {undefined}
1729 | */
1730 | _setName(name = "") {
1731 | this.name = name;
1732 | this.cleanName = normalize(name).replace(CrLfReg, " ");
1733 | }
1734 |
1735 | /**
1736 | * メッセージ設定
1737 | * @param {string} message
1738 | * @returns {undefined}
1739 | */
1740 | _setMessage(message = "") {
1741 | this.message = message;
1742 | this.cleanMessage = normalize(message);
1743 | this.message_len = this.cleanMessage.length;
1744 | }
1745 |
1746 | /**
1747 | * メッセージ設定
1748 | * @param {string} full_message
1749 | * @returns {undefined}
1750 | */
1751 | _setFullMessage(full_message = "") {
1752 | this.fullMessage = full_message;
1753 | this.cleanFullMessage = normalize(full_message);
1754 | this.full_message_len = this.cleanFullMessage.length;
1755 | }
1756 |
1757 | /**
1758 | * 日時データ設定
1759 | * @param {string} date
1760 | * @returns {boolean}
1761 | */
1762 | _setDate(date) {
1763 | try {
1764 | this.dateTime = new Date(date);
1765 | } catch (e) {
1766 | console.error(e);
1767 | return false;
1768 | }
1769 | if (this.dateTime.toString() == "Invalid Date") {
1770 | log("日付変換失敗");
1771 | return false;
1772 | }
1773 | this.time_value = this.dateTime.getTime();
1774 | return true;
1775 | }
1776 |
1777 | /**
1778 | * 画像添付確認
1779 | * @param {HTMLElement} article
1780 | * @returns {Promise}
1781 | */
1782 | _imgCheck(article) {
1783 | const this_ = this;
1784 | return new Promise((resolve) => {
1785 | setTimeout(() => {
1786 | let attach_img = article.querySelectorAll(EX_QUERY_DICT.IMAGE_QUERY);
1787 | //console.log(attach_img)
1788 | if (attach_img) {
1789 | for (let img of attach_img) {
1790 | const src = img.src;
1791 | if (tweetUrlImgReg.test(src)) {
1792 | // 画像
1793 | this_.attach_img = true;
1794 | this_.attach_file_list.push(src);
1795 | } else if (tweetUrlVideoReg.test(src)) {
1796 | // 動画(Gif含む)
1797 | this_.attach_img = true;
1798 | this_.attach_file_list.push(src);
1799 | }
1800 | }
1801 | }
1802 | resolve();
1803 | }, 1000);
1804 | });
1805 | }
1806 |
1807 | /**
1808 | * メニュー取得
1809 | * @param {HTMLElement} article
1810 | * @returns {Promise}
1811 | */
1812 | _getMenu(article) {
1813 | const this_ = this;
1814 | return new Promise((resolve) => {
1815 | setTimeout(() => {
1816 | let menuDOMs = article.querySelectorAll(EX_QUERY_DICT.MENU_BUTTON_QUERY);
1817 | if (menuDOMs.length >= 3) {
1818 | this_.menuDOM = menuDOMs[0];
1819 | }
1820 | resolve();
1821 | }, 1000);
1822 | });
1823 | }
1824 | }
1825 |
1826 | // ==========================================================================================
1827 | // 汎用 便利関数
1828 | // ==========================================================================================
1829 | /**
1830 | * ログを判別しやすく
1831 | * @param {string} str
1832 | * @returns {undefined}
1833 | */
1834 | function log(str) {
1835 | if (DEBUG) {
1836 | console.log(`[${PRO_NAME}]`, str);
1837 | }
1838 | }
1839 |
1840 | /**
1841 | * DOMが設置されるまで待機
1842 | * @param {string} selectorTxt
1843 | * @param {Function} actionFunction
1844 | * @param {boolean} [bWaitOnce=true]
1845 | * @param {string} [actionFunction]
1846 | * @returns {undefined}
1847 | */
1848 | function waitForKeyElements(
1849 | selectorTxt, //クエリセレクター
1850 | actionFunction, //実行関数
1851 | bWaitOnce = true, //要素が見つかっても検索を続ける
1852 | iframeName = null //iframeの中の要素の場合はiframeのidを書く
1853 | ) {
1854 | var targetNodes, btargetsFound;
1855 | var iframeDocument = document;
1856 | if (iframeName !== null) {
1857 | let iframeElem = document.getElementById(iframeName);
1858 |
1859 | if (!iframeElem) {
1860 | doRetry();
1861 | return;
1862 | }
1863 | iframeDocument = iframeElem.contentDocument || iframeElem.contentWindow.document;
1864 | }
1865 | targetNodes = iframeDocument.querySelectorAll(selectorTxt);
1866 |
1867 | if (targetNodes && targetNodes.length > 0) {
1868 | btargetsFound = true;
1869 | targetNodes.forEach(function (element) {
1870 | var alreadyFound = element.dataset.found == "alreadyFound" ? "alreadyFound" : false;
1871 |
1872 | if (!alreadyFound) {
1873 | var cancelFound;
1874 | if (iframeName !== null) {
1875 | cancelFound = actionFunction(element, iframeDocument);
1876 | } else {
1877 | cancelFound = actionFunction(element);
1878 | }
1879 | if (cancelFound) {
1880 | btargetsFound = false;
1881 | } else {
1882 | element.dataset.found = "alreadyFound";
1883 | }
1884 | }
1885 | });
1886 | } else {
1887 | btargetsFound = false;
1888 | }
1889 |
1890 | if (btargetsFound && bWaitOnce) {
1891 | //終了
1892 | } else {
1893 | doRetry();
1894 | }
1895 |
1896 | function doRetry() {
1897 | setTimeout(function () {
1898 | waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeName);
1899 | }, 300);
1900 | }
1901 | }
1902 |
1903 | /**
1904 | * 不明な空白を半角スペースに
1905 | * @param {string} str
1906 | * @returns {string}
1907 | */
1908 | function unifiedSpace(str) {
1909 | str = str.toString();
1910 | spaceRegList.forEach((reg) => {
1911 | str = str.replace(reg, " ");
1912 | });
1913 | return str;
1914 | }
1915 |
1916 | /**
1917 | * 全ての文字を共通化
1918 | * @param {string} str
1919 | * @param {boolean} [useLowerCase=true] - 小文字に統一するか
1920 | * @returns {string}
1921 | */
1922 | function normalize(str, useLowerCase = true) {
1923 | str = unifiedSpace(str).normalize("NFKC");
1924 | normalizeRegList.forEach((regs) => {
1925 | str = str.replace(...regs);
1926 | });
1927 | if (useLowerCase) {
1928 | str = str.toLowerCase();
1929 | }
1930 | return str;
1931 | }
1932 |
1933 | /**
1934 | * 困った時のレーベンシュタイン距離
1935 | * @param {string} str1
1936 | * @param {string} str2
1937 | * @returns {number}
1938 | */
1939 | function levenshteinDistance(str1, str2) {
1940 | let r,
1941 | c,
1942 | cost,
1943 | lr = str1.length,
1944 | lc = str2.length,
1945 | d = [];
1946 |
1947 | for (r = 0; r <= lr; r++) {
1948 | d[r] = [r];
1949 | }
1950 | for (c = 0; c <= lc; c++) {
1951 | d[0][c] = c;
1952 | }
1953 | for (r = 1; r <= lr; r++) {
1954 | for (c = 1; c <= lc; c++) {
1955 | cost = str1.charCodeAt(r - 1) == str2.charCodeAt(c - 1) ? 0 : 1;
1956 | d[r][c] = Math.min(d[r - 1][c] + 1, d[r][c - 1] + 1, d[r - 1][c - 1] + cost);
1957 | }
1958 | }
1959 | return 1 - d[lr][lc] / Math.max(lr, lc);
1960 | }
1961 |
1962 | /**
1963 | * unicodeを復元
1964 | * @param {string} str
1965 | * @returns {string}
1966 | */
1967 | function reRegExpStr(str) {
1968 | return unifiedSpace(str).replace(reRegExpReg, function (f, a, b, c) {
1969 | let str = a ?? b ?? c ?? null;
1970 | if (str == null) {
1971 | return f;
1972 | }
1973 | return String.fromCodePoint(parseInt(str, 16));
1974 | });
1975 | }
1976 |
1977 | // ==========================================================================================
1978 | // 便利関数 GM
1979 | // ==========================================================================================
1980 |
1981 | /**
1982 | * GMからjsonを取得
1983 | * @param {string} key
1984 | * @returns {Promise