Blacklists posts by Creator ID
// ==UserScript==
// @name Kemono Party Blacklist
// @namespace https://MeusArtis.ca
// @version 2.1.0
// @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*
// @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);
})();