Script to switch recommended works on pixiv to show only R-18 works

allows you to display only R-18 works in the recommended works at the bottom of the artwork page.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

/*jshint esversion: 6 */

// ==UserScript==
// @name        Script to switch recommended works on pixiv to show only R-18 works
// @name:ja           pixivの関連作品をR-18オンリーと切り替えるスクリプト
// @name:zh-CN     将pixiv上的推荐作品切换为只显示R-18的Script
// @name:ko        pixiv의 관련 작품을 R-18온리와 바꾸는 스크립트
// @description allows you to display only R-18 works in the recommended works at the bottom of the artwork page.
// @description:ja pixivの作品画面の下部に表示される関連作品を、R-18作品に絞って表示することができます。
// @description:zh-cn 它可以让您在作品页面底部的推荐作品中只显示R-18作品。
// @description:ko pixiv의 작품 화면의 하부에 표시되는 관련 작품을, R-18작품으로 좁혀 표시할 수 있습니다.
// @version        0.5.7
// @author         Qappendix
// @license        GPL v3; https://www.gnu.org/copyleft/gpl.html
// @match          *://www.pixiv.net/*
// @grant          GM.setValue
// @grant          GM.getValue
// @namespace https://greasyfork.org/users/724570
// ==/UserScript==

(function() {
    //変数初期化
    let recommendSection = null;
    let href;
    let artworkUrl = /^(http|https):\/\/(www)?\.pixiv\.net\/artworks\/.*/;

    let isEnabled = GM.getValue('isEnabled', true);
    let isArtworkURL = false;

    let allIllustsSet = new Set();
    let sensitiveIllustsSet = new Set();
    let notSensitiveIllustsSet = new Set();

    ///ボタン要素追加
    let switchButton = document.createElement('button');
    let switchButtonStyle = 'position: fixed; bottom: 10px; right: 10px; padding: 6px 40px; z-index: 101;';
    let ONText = 'R-18 only: ON';
    let OFFText = 'R-18 only: OFF';

    isEnabled ? switchButton.innerHTML = ONText : switchButton.innerHTML = OFFText;

    switchButton.id = 'switch_button';
    switchButton.setAttribute('Style', switchButtonStyle)

    document.body.appendChild(switchButton);

    //非R-18作品閲覧時メッセージ追加
    let messageText = "Viewing work is not R-18 work. R-18 only mode is off.";
    let messageElement = document.createElement('div');
    let messageStyle = 'display: none; width: calc(100vw - (100vw - 100%)); height: 2vh; position: -webkit-sticky; position: sticky; top: 98vh; background-color: gray; z-index: 100;';

    messageElement.id = 'non_R18_Message';
    messageElement.setAttribute('Style', messageStyle)
    messageElement.innerHTML = messageText;
    document.body.prepend(messageElement);

    //ボタンクリック時イベント定義
    switchButton.addEventListener('click', function(){
        isEnabled =! isEnabled;

        if(isEnabled){
            switchButton.innerHTML = ONText;
            recommendObserver.observe(recommendSection, {attributes: true, subtree: true});
            toggleDisplayIllusts();
            toggleNonR18Message();
        }else{
            switchButton.innerHTML = OFFText;
            toggleDisplayIllusts();
            toggleNonR18Message();
        }
        GM.setValue('isEnabled',isEnabled);
    });

    ///MutationObserver定義

    //ページ遷移検出、初期化
    let documentObserver = new MutationObserver( function(){
        if(href !== location.href){
            href = location.href;
            recommendSection = null;
            recommendObserver.disconnect();
            allIllustsSet.clear();
            sensitiveIllustsSet.clear();
            artworkUrl.test(href) ? isArtworkURL = true : isArtworkURL = false;
        }
        if(isArtworkURL){
            updateRecommendSection();
            if(recommendSection){
                recommendObserver.observe(recommendSection, {attributes: true, subtree: true});
                updateIllustsSet(recommendSection);
                toggleDisplayIllusts();
            }
        }
        toggleNonR18Message();
    })

    let recommendObserver = new MutationObserver( function(){
        updateIllustsSet(recommendSection);
        toggleDisplayIllusts();
    })

    //文書全体の変更を監視
    documentObserver.observe(document, {attributes: true, subtree: true});

    ///関数定義

    function updateRecommendSection(){
        for(let section of document.body.getElementsByTagName("section")){
            for(let div of section.getElementsByTagName("div")){
                if(div.textContent == "関連作品" || div.textContent == "おすすめ作品"){
                    recommendSection = section;
                }
            }
        }
    }

    function updateIllustsSet(recom){
        Array.prototype.forEach.call(recom.getElementsByTagName("li"), function(li){
            allIllustsSet.add(li);
            if(li.textContent.indexOf("R-18")!=-1){
                sensitiveIllustsSet.add(li);
            }
        })
        for(let work of allIllustsSet){
            if(!sensitiveIllustsSet.has(work)){
                notSensitiveIllustsSet.add(work);
            }
        }
    }

    function toggleDisplayIllusts(){
        if(sensitiveIllustsSet.size!=0){
            if(isEnabled){
                for(let work of notSensitiveIllustsSet){
                    work.style.display="none";
                }
            }else{
                for(let work of notSensitiveIllustsSet){
                    work.style.display="block";
                }
            }
        }
    }

    function toggleNonR18Message(){
        var non_R18_Message = document.getElementById("non_R18_Message");
        if(allIllustsSet.size!=0){
            if(sensitiveIllustsSet.size==0 && isArtworkURL && isEnabled){
                non_R18_Message.style.display="block";
            }else{
                non_R18_Message.style.display="none";
            }
        }
    }

})()