Kemono Party Blacklist

Blacklists posts by Creator ID

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Kemono Party Blacklist
// @namespace    https://MeusArtis.ca
// @version      2.1.1
// @author       Meus Artis
// @description  Blacklists posts by Creator ID
// @icon         https://www.google.com/s2/favicons?domain=kemono.cr
// @match        https://coomer.st/*/user/*
// @match        https://coomer.st/artists*
// @match        https://coomer.st/account/favorites/*
// @match        https://coomer.st/posts*
// @match        https://kemono.cr/*/user/*
// @match        https://kemono.cr/artists*
// @match        https://kemono.cr/account/favorites/*
// @match        https://kemono.cr/dms*
// @match        https://kemono.cr/posts*
// @match        https://pawchive.st/*/user/*
// @match        https://pawchive.st/artists*
// @match        https://pawchive.st/favorites*
// @match        https://pawchive.st/dms*
// @match        https://pawchive.st/posts*
// @match        https://pawchive.pw/*/user/*
// @match        https://pawchive.pw/artists*
// @match        https://pawchive.pw/favorites*
// @match        https://pawchive.pw/dms*
// @match        https://pawchive.pw/posts*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license      CC BY-NC-SA 4.0
// @run-at       document-end
// ==/UserScript==
(function () {
    const styleSheet = document.createElement("style");
    const styles = `.creator__blacklist{color:#ddd;font-weight:700;text-shadow:#000 0 0 3px,#000 -1px -1px 0px,#000 1px 1px 0;background-color:transparent;border:transparent}.user-header__blacklist{box-sizing:border-box;font-weight:700;color:#fff;text-shadow:#000 0 0 3px,#000 -1px -1px 0px,#000 1px 1px 0;background-color:transparent;border:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}`;
    document.head.appendChild(styleSheet);
    styleSheet.innerText = styles;
    styleSheet.type = "text/css";
    if (GM_getValue("Blacklist") === undefined) {
        alert("Blacklist does not exist, creating a new one"); // Nobody still has the localstorage blacklist... right?
        GM_setValue("Blacklist", "");
    }
    function getBlacklist() {
        return GM_getValue("Blacklist", "").split(',').filter(Boolean);
    }
    function saveBlacklist(list) {
        GM_setValue("Blacklist", list.join(','));
    }
    let Blacklisted = getBlacklist();
    function applyBlacklist() {
        Blacklisted.forEach((item) => {
            $(`article[data-user='${item}']`).css({ display: "none" });
            $(`a[data-id='${item}']`).css({ display: "none" });
            $(`article.dm-card header a[href='/patreon/user/${item}']`).closest("article").css({ display: "none" });
            $(`a.user-card[href='/patreon/user/${item}']`).css({ display: "none" }); // Lazy Pawchive fix, will do properly before v3
            $(`a.user-card[href='/fanbox/user/${item}']`).css({ display: "none" });
        });
    }
    function setupBlacklistButtons() {
        const ButtonArea = document.querySelector('.post__actions') ?? document.querySelector('.user-header__actions');
        const BlacklistButton = document.createElement("BUTTON");
        BlacklistButton.classList.add("creator__blacklist");
        BlacklistButton.type = "button";
        let Page = window.location.pathname // Technically more reliable than the <meta> tags that pawchive only adds after refreshing sometimes
        let [, Platform, ID] = window.location.pathname.match(/^\/(\w+)\/user\/(\w+)(\/.+)?$/) ?? window.location.pathname.match(/^\/(discord)\/server\/(\d+)(\/.+)?$/);
        if (Page.match(/^\/\w+\/user\/\w+(\/\w+)?$/)) { // Debugging, see if the script actually fucking loads
           console.log("Creator Page");
        } else if (Page.match(/^\/\w+\/user\/\w+\/post\/(\w|-)+(\/revision\/\d+)?$/)) {
           console.log("Post Page");
        } else if (Page.match(/^\/discord\/server\/\d+(\/d+)?$/)) {
           console.log("Discord Server");
        }
        if (ButtonArea) { // Didn't bother checking where to put this on Discord servers, will check before v3
            const isBlacklisted = Blacklisted.includes(ID);
            BlacklistButton.innerHTML = isBlacklisted
                ? '<span class="creator__blacklist-icon">⛒</span><span>Blacklisted</span>'
                : '<span class="creator__blacklist-icon">⛔</span><span>Blacklist</span>';
            BlacklistButton.onclick = () => {
                Blacklisted = getBlacklist();
                if (isBlacklisted) {
                    Blacklisted = Blacklisted.filter(id => id !== ID);
                    console.log("Creator Unblacklisted");
                } else {
                    Blacklisted.push(ID);
                    console.log("Creator Blacklisted");
                }
                saveBlacklist(Blacklisted);
                history.back();
            };
            console.log(Platform + ":" + ID) // Debugging, will use to prevent ID collisions in v3 (currently only a few dozen in nearly 100K creators)
            ButtonArea.appendChild(BlacklistButton);
        }
    }
    function observeUrlChange(callback) { // Replacement for this fixes the needing-to-refresh problem reported by Naxeti, and reduces loading time by 1.3 seconds per 10K creators blacklisted (40K+ tested, still looking for edge cases)
        let lastUrl = location.href;
        new MutationObserver(() => {
            const currentUrl = location.href;
            if (currentUrl !== lastUrl) {
                lastUrl = currentUrl;
                callback();
            }
        }).observe(document.body, { childList: true, subtree: true });
    }
    function initializeScript() {
        setTimeout(() => {
            Blacklisted = getBlacklist();
            applyBlacklist();
            setupBlacklistButtons();
        }, 333);
    }
    function donate() {
        window.open("https://ko-fi.com/meusartis", '_blank')
    }
    GM_registerMenuCommand("Donate", donate);
    window.addEventListener("DOMContentLoaded", initializeScript);
    observeUrlChange(initializeScript);
})();