Boothの検索で除外検索できるようにしてみた

# 前置き
Boothって除外検索できないよね～っていう話をしてたのでぱぱっと作ってみました

# TL;DR
1. Chrome専用
2. [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=ja)という拡張機能を入れていることが前提です
3. [これ](https://gist.github.com/Angeart/02965594d1207fc764a5d87cae134728/raw/d8e51568c52a5eec323c473fa53458bf0171b4a3/BoothIgnoreSearch.user.js)をインストールする

おわり

# 使い方
簡単！
検索ボックスの隣にignore...と書かれたボックスが現れるので除外したい単語を入れてチェックを付けるだけです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137384/84e5cd05-4385-dc42-9718-8a89927ba279.png)
👇😎
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137384/a9a7ef94-74fa-35df-46c5-94d590f18f2a.png)

# Tampermonkeyって何？
とあるページに自分のスクリプトを介入させることのできるすげーやつ

# Scriptのお話
単純に検索結果のアイテムを総なめして除外しているだけです
`RegExp`にぶち込んでるので正規表現で除外もできるぞ
テキストフォームは隣の検索ボックスからパクってきました

```js
// ==UserScript==
// @name         Booth Ignore Search
// @namespace    http://tampermonkey.net/
// @version      0.1.6
// @description  Boothの検索結果から特定のキーワードを除外します（正規表現可能）
// @author       Angeart
// @match        https://booth.pm/*
// @icon         https://www.google.com/s2/favicons?domain=booth.pm
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const ignoreSearchBox = `
<div class="item-search-box">
    <form class="item-search">
        <input name="utf8" type="hidden" value="✓">
        <span class="twitter-typeahead" style="position: relative; display: inline-block; direction: ltr;">
            <input type="search" value="" autocomplete="off" class="ac-tags item-search-input tt-hint" readonly="" spellcheck="false" tabindex="-1" style="position: absolute; top: 0px; left: 0px; border-color: transparent; box-shadow: none; opacity: 1; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255);">
            <input type="search" name="query" id="ignore-query" value="" placeholder="ignore..." autocomplete="off" class="ac-tags item-search-input tt-input" spellcheck="false" dir="auto" style="position: relative; vertical-align: top; background-color: transparent;">
            <pre aria-hidden="true" style="position: absolute; visibility: hidden; white-space: pre; font-family: Arial; font-size: 13.3333px; font-style: normal; font-variant: normal; font-weight: 400; word-spacing: 0px; letter-spacing: 0px; text-indent: 0px; text-rendering: auto; text-transform: none;"></pre>
            <span class="tt-dropdown-menu" style="position: absolute; top: 100%; left: 0px; z-index: 100; display: none; right: auto;">
                <div class="tt-dataset-0"></div>
            </span>
        </span>
        <input id="exec-ignore" type="checkbox" class="btn search">
    </form>
</div>
    `;
    document.querySelector('.global-nav').insertAdjacentHTML('beforeend', ignoreSearchBox);
    const ignoreSearchBoxEl = document.querySelector('#ignore-query');
    ignoreSearchBoxEl.value = sessionStorage.ignoreQuery ?? "";
    const ignoreExec = document.querySelector("#exec-ignore");
    ignoreExec.checked = (sessionStorage.execIgnore === 'true') ?? false;
    const exec = function() {
        const ignoreSearchBoxEl = document.querySelector('#ignore-query');
        [...document.querySelectorAll('.item-card')].forEach(v => v.style.display = 'inline-block');
        if (ignoreExec.checked && ignoreSearchBoxEl.value !== '') {
            let matchRegex = null;
            try {
                matchRegex = new RegExp(ignoreSearchBoxEl.value, "ig");
            } catch {
                return;
            }
            const matchedEl = [...document.querySelectorAll('.item-card')].filter(v => v.querySelector('.item-card__title > a').text.match(matchRegex)) ?? [];
            matchedEl.forEach(v => v.style.display = 'none');
            window.matchedEl = matchedEl;
        } else if (window.matchedEl != null) {
            window.matchedEl.forEach(v => v.style.display = 'inline-block');
        }
    }
    ignoreSearchBoxEl.addEventListener('input', function() {
        sessionStorage.ignoreQuery = this.value;
        exec();
    });
    if (document.readyState == "complete" || document.readyState == "loaded" || document.readyState == "interactive") {
        exec();
    } else {
        document.addEventListener("DOMContentLoaded", function(event) {
            exec();
        });
    }
    ignoreExec.addEventListener("change", function () {
        exec();
        sessionStorage.execIgnore = this.checked;
    });
})();
```

## 余談
BoothはどうやらjQuery使ってるみたいだけどnativeオンリーで書きました。
5分くらいで書いたのでバグってたりしたら教えて頂けると助かります。