Sleazy Fork is available in English.

maskNGwordsOnFANZA (experimental)

検索文字列からFANZA独自のNGワードを伏せ字化

/* jshint esversion: 6 */
// ==UserScript==
// @name         maskNGwordsOnFANZA (experimental)
// @namespace    https://greasyfork.org/ja/users/289387-unagionunagi
// @version      0.3.1
// @description  検索文字列からFANZA独自のNGワードを伏せ字化
// @author       unagiOnUnagi
// @match        *://*.dmm.co.jp/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GPL-2.0-or-later
// @run-at       document-start
// ==/UserScript==

function _mask(phrase) {
    const _NGwords = [
        ['犯され', '犯 れ'],
        [/犯す([\s\d])/g, '犯 $1'],
        ['犯す', ' す'],
        [/強[制姦]/g, '強 '],
        ['レイプ', 'レ プ'],
        [/([陵凌])辱/g, '$1 '],
        ['夜這い', '夜 い'],
        ['酔っ払', ' っ払'],
        ['酔っぱら', ' っぱら'],
        ['痴漢', '痴 '],
        ['輪姦', '輪 '],
        ['催眠', '催 '],
        ['泥酔', '泥 '],
        ['奴隷', '奴 '],
        ['ショタ', 'シ タ'],
        ['無修正', '無 正'],
        ['昏睡', '昏 '],
        ['折檻', '折 '],
        [/(?<=[薬酒]を)飲ませ/g, ' ませ'],
    ];

    for (let [ng, mask] of _NGwords) {
        phrase = phrase.replaceAll(ng, mask);
    }

    // console.log(phrase);
    return phrase;
}

function maskFromSearchStr(matched) {
    // console.log(matched);
    let searchstr = matched[1];
    let decoded = decodeURIComponent(searchstr);
    let masked = _mask(decoded);

    if (decoded == masked) return;

    let encoded = encodeURIComponent(masked);
    let maskedURL = matched[0].replace(searchstr, encoded);
    window.location.href = maskedURL;
}

function control2Mask() {
    let searchBox = document.querySelector('#naviapi-search-text,#searchstr');
    if (!searchBox) return;

    searchBox.addEventListener('paste', (ev) => {
        if (GM_getValue('checked', true)) {
            let phrase = (ev.clipboardData || window.clipboardData).getData('text');
            phrase = _mask(phrase);
            let target = ev.target;
            target.setRangeText(phrase, target.selectionStart, target.selectionEnd, 'end');
            ev.preventDefault();
        }
    });
    searchBox.addEventListener('compositionend', (ev) => {
        if (GM_getValue('checked', true)) {
            searchBox.value = _mask(searchBox.value);
        }
    });

    let mu = document.querySelector('#mu,.top-maincolumn,.l-areaMainColumn,#l-contents,#main-bmk,#l_page_bookmark');
    if (!mu) return;

    let maskSpan = document.createElement('span');
    maskSpan.title = '検索文字列にFANZA検閲ワードがあればFANZA形式で伏せ字化します';
    maskSpan.style.cssText = 'margin-left: 10px;';
    mu.appendChild(maskSpan);

    let maskCb = document.createElement('input');
    maskCb.type = 'checkbox';
    maskCb.id = 'mask-ngwords-cb';
    maskCb.name = 'mask-ngwords-cb';
    maskCb.style.cssText = 'vertical-align: middle; transform: scale(0.8);';
    maskSpan.appendChild(maskCb);

    let maskLabel = document.createElement('label');
    maskLabel.htmlFor = 'mask-ngwords-cb';
    maskLabel.style.cssText = 'font-size: 10px;';
    maskLabel.innerText = '検索文字列からNGワードを伏せ字化';
    maskSpan.appendChild(maskLabel);

    maskCb.checked = GM_getValue('checked', true);
    maskCb.addEventListener('change', (ev) => {
        GM_setValue('checked', ev.target.checked);
    });
}

(function() {
    'use strict';

    if (window.frameElement) return;

    if (GM_getValue('checked', true)) {
        let matched = document.referrer.indexOf('://www.dmm.co.jp/') < 0 && document.URL.match(/.+\/searchstr=(.+?)\//);
        if (matched) {
            maskFromSearchStr(matched);
        }
    }

    window.addEventListener('load', control2Mask);

})();