您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allow you to hide or highlight posts by user id on Posts / Popular Posts page.
当前为
// ==UserScript== // @name Kemono QoL Improvements // @namespace Kemono_QoL_Improvements // @license WTFPL // @match https://kemono.cr/* // @match https://coomer.st/* // @grant none // @version 2.1 // @author Kaban // @description Allow you to hide or highlight posts by user id on Posts / Popular Posts page. // @description Allow you to hide posts with no preview images on Posts / Popular Posts page. // @description Auto-sorts posts by Post time on Posts / Popular Posts page (within current page). // @description Makes post thumbnails taller, allow in-post images to be tiled horizontally. // ==/UserScript== (() => { // ==<User Settings>== const hide_group = [ ["fanbox", "00000000"], // [UserName] I recommend you to take note here as comments, so that ["patreon", "000000000"] // [UserName] you don't forget why you added them to the blacklist. ]; const highlight_group_1 = [ // Red Background ["patreon", "00000000"], // [UserName] If you clear this list: const highlight_group_1 = []; ["patreon", "000000000"] // [UserName] Then this group will be skipped. ] const highlight_group_2 = [ // Green Background ["patreon", "00000000"], // [UserName] You may also add more groups as you like, just modify the code under ["patreon", "000000000"] // [UserName] section <CSS Generation> as well, I tried to make it easy to read. ]; const option_hide_posts_with_no_preview_images = true; // ==</User Settings>== // ==<CSS Generation>== let styles = []; let selectors = []; hide_group.forEach(user => { selectors.push(`article[data-service="${user[0]}"][data-user="${user[1]}"]`); }); const selector_blacklisted_users = selectors.join(",\n"); // used later for counting how many posts hidden const css_posts_page_blacklisted_users = `${selector_blacklisted_users} { display: none; }`; styles.push(`${selector_blacklisted_users} { opacity: 0.5; }`); // make the hidden posts remain semi-transparent when click on the message to show them selectors = []; highlight_group_1.forEach(user => { selectors.push(`article[data-service="${user[0]}"][data-user="${user[1]}"]`); }); styles.push(`${selectors.join(",\n")} { opacity: rgb(153 0 0 / 50%); }`); selectors = []; highlight_group_2.forEach(user => { selectors.push(`article[data-service="${user[0]}"][data-user="${user[1]}"]`); }); styles.push(`${selectors.join(",\n")} { opacity: rgb(24 153 0 / 50%) }`); styles.push(`article.post-card { height: calc(var(--card-size) / 2 * 3); } img.post-card__image { object-fit: contain; }`); // make posts taller on Posts / Popular Posts page const selector_no_preview_images = "article.post-card--preview.post-card:not(:has(div.post-card__image-container))"; // used later for counting how many posts hidden const css_posts_page_hide_no_preview_images = `${selector_no_preview_images} { display: none; }`; styles.push(`${selector_no_preview_images} { height: fit-content; }`); // make posts with no preview images shorter, so the take less space when shown const css_posts_page = styles.join("\n"); const css_user_page = `article.post-card { height: calc(var(--card-size) / 2 * 3); } img.post-card__image { object-fit: contain; }`; // just make the posts taller, don't hide any posts on User page const css_user_page_in_post = `div.post__files { flex-flow: wrap; }`; // allow images to tile horizontally on single Post page // ==</CSS Generation>== let old_url = ""; function addStyles() { if (window.location.href === old_url) return; // run only once per url change old_url = window.location.href; let styleElement = document.getElementById("__usr__page_style"); if (styleElement) styleElement.remove(); styleElement = document.createElement("style"); styleElement.id = "__usr__page_style"; if (window.location.pathname === "/posts" || window.location.pathname === "/posts/popular") { styleElement.textContent = css_posts_page; document.head.append(styleElement); styleElement = document.getElementById("__usr__page_style_hide_blacklisted_users"); if (styleElement) styleElement.remove(); styleElement = document.createElement("style"); styleElement.id = "__usr__page_style_hide_blacklisted_users"; styleElement.textContent = css_posts_page_blacklisted_users; document.head.append(styleElement); if (!option_hide_posts_with_no_preview_images) return; styleElement = document.getElementById("__usr__page_style_hide_no_preview_images"); if (styleElement) styleElement.remove(); styleElement = document.createElement("style"); styleElement.id = "__usr__page_style_hide_no_preview_images"; styleElement.textContent = css_posts_page_hide_no_preview_images; document.head.append(styleElement); } else if (window.location.pathname.includes("/user/")) { if (window.location.pathname.includes("/post/")) { styleElement.textContent = css_user_page_in_post; } else { styleElement.textContent = css_user_page; } document.head.append(styleElement); } } function sortPosts() { let sortMessageElement = document.getElementById("__usr__sort_message"); if (sortMessageElement) sortMessageElement.remove(); let hidPostsMessageElement = document.getElementById("__usr__hid_posts_message"); if (hidPostsMessageElement) hidPostsMessageElement.remove(); sortMessageElement = document.createElement("small"); sortMessageElement.id = "__usr__sort_message"; hidPostsMessageElement = document.createElement("div"); hidPostsMessageElement.id = "__usr__hid_posts_message"; let postsHolder = document.getElementsByClassName("card-list__items")[0]; let posts = postsHolder.getElementsByTagName("article"); if (posts.length === 0) return; if (posts.length > 1) { // ==<Sort Posts>== let sortedPosts = Array.from(posts).sort( (a, b) => new Date(b.getElementsByTagName("time")[0].dateTime) - new Date(a.getElementsByTagName("time")[0].dateTime) ); postsHolder.replaceChildren(); sortedPosts.forEach(post => { postsHolder.appendChild(post); }); // ==</Sort Posts>== } let insertPosition = document.getElementById("paginator-top").getElementsByTagName("small")[0]; if (insertPosition) { sortMessageElement.textContent = " posts (sorted by Post time)."; insertPosition.after(sortMessageElement); } else { sortMessageElement.textContent = `Found ${posts.length} ${posts.length > 1 ? "posts (sorted by Post time)." : "post."}`; document.getElementById("paginator-top").appendChild(sortMessageElement); } sortMessageElement.after(hidPostsMessageElement); // ==<Count Hidden Posts>== let hidPostsMessages = []; let hid_posts = document.querySelectorAll(selector_blacklisted_users); if (hid_posts.length > 0) { let blacklistedUsersMessageElement = document.createElement("small"); blacklistedUsersMessageElement.id = "__usr__hid_posts_message_blacklisted_users"; blacklistedUsersMessageElement.addEventListener('click', function() { showPostsFromBlacklistedUsers(); }); blacklistedUsersMessageElement.textContent = `${hid_posts.length} ${hid_posts.length > 1 ? "posts from blacklisted users" : "post from a blacklisted user"}`; hidPostsMessages.push(blacklistedUsersMessageElement); } if (option_hide_posts_with_no_preview_images) { hid_posts = document.querySelectorAll(selector_no_preview_images); if (hid_posts.length > 0) { let noPreviewImagesMessageElement = document.createElement("small"); noPreviewImagesMessageElement.id = "__usr__hid_posts_message_no_preview_images"; noPreviewImagesMessageElement.addEventListener('click', function() { showPostsWithNoPreviewImages(); }); noPreviewImagesMessageElement.textContent = `${hid_posts.length} ${hid_posts.length > 1 ? "posts with no preview images" : "post with no preview image"}`; hidPostsMessages.push(noPreviewImagesMessageElement); } } if (hidPostsMessages.length > 0) { let prefix = document.createElement("small"); prefix.textContent = "Hid "; hidPostsMessageElement.appendChild(prefix) hidPostsMessageElement.appendChild(hidPostsMessages[0]); if (hidPostsMessages.length > 1) { let separator = document.createElement("small"); separator.id = "__usr__hid_posts_message_separator"; separator.textContent = ", "; hidPostsMessageElement.appendChild(separator); hidPostsMessageElement.appendChild(hidPostsMessages[1]); } let suffix = document.createElement("small"); suffix.textContent = "."; hidPostsMessageElement.appendChild(suffix) } // ==</Count Hidden Posts>== } // Kemono is a SPA (Single Page Application) // It is necessary to use MutationObserver in order to run scripts when switching between pages let observer = new MutationObserver(mutations => { addStyles(); // this will fire multiple times as the page loads, but I want the styles to be added as early as possible so keep it here if (window.location.pathname === "/posts" || window.location.pathname === "/posts/popular") { let pageLoaded = false; mutations.forEach(mutation => { if (mutation.target.classList.contains("ad-container")) pageLoaded = true; // div.ad-container is the last mutations observerd on page update }); if (pageLoaded) { observer.disconnect(); sortPosts(); observer.observe(document.body, { childList: true, subtree: true }); } } }); observer.observe(document.body, { childList: true, subtree: true }); function showPostsFromBlacklistedUsers() { document.getElementById("__usr__page_style_hide_blacklisted_users").remove(); if (document.getElementById("__usr__hid_posts_message_separator")) { document.getElementById("__usr__hid_posts_message_separator").remove(); document.getElementById("__usr__hid_posts_message_blacklisted_users").remove() } else { document.getElementById("__usr__hid_posts_message").remove(); } } function showPostsWithNoPreviewImages() { document.getElementById("__usr__page_style_hide_no_preview_images").remove(); if (document.getElementById("__usr__hid_posts_message_separator")) { document.getElementById("__usr__hid_posts_message_separator").remove(); document.getElementById("__usr__hid_posts_message_no_preview_images").remove() } else { document.getElementById("__usr__hid_posts_message").remove(); } } })();