您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Adds a blacklist to Fur Affinity. Also adds the ability to replace typed terms with other terms. If installed correctly you should see a link titled "Edit Blacklist" below the search box on FA's search page.
当前为
// ==UserScript== // @name FA Blacklist // @namespace http://greasyfork.icu/en/scripts/453103-fa-blacklist // @version 1.0.3 // @description Adds a blacklist to Fur Affinity. Also adds the ability to replace typed terms with other terms. If installed correctly you should see a link titled "Edit Blacklist" below the search box on FA's search page. // @author Nin // @license GNU GPLv3 // @match https://www.furaffinity.net/* // @icon https://www.google.com/s2/favicons?domain=furaffinity.net // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== // How many tabs to add between the blacklist and search var tabBuffer = "\t".repeat(30); // Save a script setting function saveUserData(key, value) { 'use strict'; GM_setValue(key, JSON.stringify(value)); }; // Load a script setting async function loadUserData(key, defaultValue) { 'use strict'; let data = await GM_getValue(key); if (data === undefined) { return defaultValue; } return JSON.parse(data); }; // Add extra search settings for using this script to FA's Search Settings section function generateSearchSettings(blacklist, replace) { 'use strict'; if (!window.location.pathname.startsWith("/controls/site-settings/")){ return; } let replaceList = []; for (const property in replace) { replaceList.push(property + "=" + replace[property]); } const replaceString = replaceList.join(", "); prependSearchSetting( "Find and Replace", "A comma separated list of search terms to replace. In the format: <br><i><span style='color:darkgray'>term1=replacement1, term2=replacement2, tf=transformation</span></i><br> Replacements can contain advanced FA queries: <br><i><span style='color:darkgray'>noodles=(dragons|snakes), ramen=(snakes&soup)</span></i>", replaceString, "replace", "Comma separated list...") const blacklistString = blacklist.join(", "); prependSearchSetting( "Blacklist", "A comma separated list of words to blacklist. In the format: <br><i><span style='color:darkgray'>these, are, search, terms, I, dislike</span></i>", blacklistString, "blacklist", "Comma separated list...") const saveButton = document.getElementsByName("save_settings")[0]; console.log(saveButton); saveButton.addEventListener("click", function(){ let blacklist = document.getElementById("blacklist").value.replaceAll(/\s/g, "").split(","); let replaceList = document.getElementById("replace").value.replaceAll(/\s/g, "").split(","); let replace = {}; for (const replaceText of replaceList) { const split = replaceText.split("="); replace[split[0]] = split[1]; } saveUserData("blacklist", blacklist); saveUserData("replace", replace); }); } // Add a search setting option to the start of the list of search settings on the Global Site Settings page function prependSearchSetting(title, description, data, id, placeholder) { 'use strict'; let html = ` <div class="control-panel-item-container"> <div class="control-panel-item-name"> <h4>${title}</h4> </div> <div class="control-panel-item-description">${description}</div> <div class="control-panel-item-options"> <div class="select-dropdown"> <input type="text" id="${id}" value="${data}" placeholder="${placeholder}" class="textbox" autocomplete="off"> </div> </div> </div>` const element = document.getElementsByClassName("section-body")[2]; element.innerHTML = html + element.innerHTML; } // Add a link to edit the blacklist to search pages function addSearchSettingsLink(){ 'use strict'; if (!window.location.pathname.startsWith("/search/")){ return; } const searchBox = document.getElementsByClassName("browser-sidebar-search-box")[0]; searchBox.outerHTML += "<a href='https://www.furaffinity.net/controls/site-settings/#blacklist' style='color:darkgray;float:right'>Edit Blacklist</a>" } // Remove the added query text from the query inputs on page load function cleanInput() { 'use strict'; document.getElementsByName("q").forEach(function(input){ if (input.value !== "") { console.log("Actual Search: " + input.value); } if (input.value.includes("\t")) { input.value = input.value.substring(0, input.value.indexOf("\t")) } // Remove any sent zero width spaces input.value = input.value.replaceAll("\u200B", ""); }); }; // Remove the blacklist text from FA's list of tags you searched function cleanQueryStats(blacklist) { 'use strict'; if (document.getElementById("query-stats") !== null) { var queryStats = document.getElementById("query-stats").children; while (blacklist.includes(queryStats[queryStats.length - 1].children[0].children[0].innerHTML)) { queryStats[queryStats.length - 1].remove(); } } }; // Replace keywords in the query string according to the specified replacements function replaceKeywords(replace) { 'use strict'; document.getElementsByName("q").forEach(function(input){ let append = ""; for (const property in replace) { const regex = new RegExp('(?<![(|&])\\b' + property + '\\b(?![)|&])', "gi"); let found = input.value.match(regex); if (found !== null) { for (const result of found) { append += " " + replace[property]; } } // Insert a zero width space between each replaced character so FA ignores it input.value = input.value.replaceAll(regex, [...property].join("\u200B")); } input.value += append; }); }; // Adds the blacklist text to the end of all query forms function addBlacklist(blacklist) { 'use strict'; document.getElementsByName("q").forEach(function(input){ if (blacklist.length && input.value.match(/\b-bl\b/) === null){ console.log(blacklist); input.value += " -" + blacklist.join(" -"); if (input.value.endsWith("-")) { input.value = input.value.substring(0, input.value.length - 1) } } }); }; // Adds a buffer of tabs to hide the added query text function addBuffer() { 'use strict'; document.getElementsByName("q").forEach(function(input){ input.value += tabBuffer; }); }; // Adds an onsubmit trigger for the element with the given ID to add the blacklist function attachHandlers(elementID, blacklist, replace) { 'use strict'; var element = document.getElementById(elementID); if (element !== null) { element.addEventListener("submit", function(){ addBuffer(); replaceKeywords(replace); addBlacklist(blacklist); }); } }; // Return some URI text that can be appended to a URI to add the blacklist function blacklistURI(blacklist) { 'use strict'; let result = tabBuffer + "-" + blacklist.join(" -"); if (result.endsWith("-")) { result = result.substring(0, result.length - 1); } return encodeURIComponent(result); } // If we somehow end up searching without the blacklist, redirect to add the blacklist function redirect(blacklist) { 'use strict'; if ((!window.location.pathname.startsWith("/search/")) || (window.location.pathname === "/search/" && window.location.search === "") || window.location.pathname.includes("09%") || window.location.search.includes("09%")){ return; } console.log("Redirecting to add blacklist..."); window.location.href = window.location.href + blacklistURI(blacklist); } // Update the links on the tags of images to add the blacklist function updateTags(blacklist) { 'use strict'; if (!window.location.pathname.startsWith("/view/")){ return; } [...document.getElementsByClassName("tags")].forEach(function(tag){ tag.firstChild.href += blacklistURI(blacklist); console.log(tag.firstChild.href); }); } async function main() { 'use strict'; const blacklist = loadUserData("blacklist", []); const replace = loadUserData("replace", {}); addSearchSettingsLink(); cleanInput(); cleanQueryStats(await blacklist); attachHandlers("search-form", await blacklist, await replace); attachHandlers("searchbox", await blacklist, await replace); generateSearchSettings(await blacklist, await replace); redirect(await blacklist); updateTags(await blacklist); }; main();