Skip to content

Instantly share code, notes, and snippets.

@Tarrgon
Last active November 10, 2024 20:55
Show Gist options
  • Select an option

  • Save Tarrgon/e8357b5f8139e494acb6a587c6b9e9c8 to your computer and use it in GitHub Desktop.

Select an option

Save Tarrgon/e8357b5f8139e494acb6a587c6b9e9c8 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Blacklist Categories
// @namespace http://tampermonkey.net/
// @version 1.1
// @description E621 blacklist categories and switching
// @author Tarrgon
// @match https://e621.net/*
// @match https://e926.net/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=e621.net
// @grant GM_addElement
// @grant GM.setValue
// @grant GM.getValue
// @grant GM.deleteValue
// @grant GM_addStyle
// @require https://unpkg.com/hotkeys-js/dist/hotkeys.min.js
// @run-at document-end
// ==/UserScript==
let blacklistTextInput = null
GM_addStyle(`
.bc-category-button {
background-color: #142642;
margin-right: 0.3rem;
margin-top: 0.3rem;
}
.bc-category-button.bc-category-enabled {
outline: 2px solid lime;
}
`)
let categoryCache = null
async function loadHotkeys() {
let keys = (await GM.getValue("hotkeys")) || []
for (let hotkey of keys) {
console.log("Loading hotkey", hotkey)
hotkeys(hotkey.sequence, async (event) => {
event.preventDefault()
await toggleCategory(hotkey.name)
reloadBlacklist()
})
}
}
async function toggleCategory(name) {
let curContent = JSON.parse($("meta[name=blacklisted-tags]").attr("content") || "[]")
let category = await getCategoryByName(name)
if (!category) return
let text = curContent.join("\n")
let isActive = await determineIfCategoryIsActive(name, text)
if (!isActive) {
text += `\n# [[${category.name}]]\n${category.blacklist}\n# [[end ${category.name}]]\n`
text = text.trimStart()
} else {
let startIndex = text.indexOf(`# [[${category.name}]]`)
let endIndex = text.indexOf(`# [[end ${category.name}]]`)
if (startIndex == -1 || endIndex == -1) return
endIndex += `# [[end ${category.name}]]`.length
text = text.slice(0, startIndex) + text.slice(endIndex + 2)
text = text.trimStart()
}
$("meta[name=blacklisted-tags]").attr("content", JSON.stringify(text.split(/\n\r?/)))
if (blacklistTextInput) blacklistTextInput.value = text
}
async function getExistingCategories() {
if (categoryCache) return categoryCache
categoryCache = (await GM.getValue("categories")) || []
return categoryCache
}
async function saveCategory(name, category) {
let categories = await getExistingCategories()
let categoryIndex = categories.findIndex(c => c.name == name)
if (categoryIndex != -1) categories[categoryIndex] = category
else categories.push(category)
await GM.setValue("categories", categories)
}
async function removeCategory(name) {
let categories = await getExistingCategories()
let categoryIndex = categories.findIndex(c => c.name == name)
if (categoryIndex == -1) return
categories.splice(categoryIndex, 1)
await GM.setValue("categories", categories)
}
async function getCategoryByName(name) {
let categories = await getExistingCategories()
return categories.find(c => c.name == name)
}
async function fixActiveAndSave(text) {
let categories = await getExistingCategories()
for (let button of document.querySelectorAll(".bc-category-button")) {
let category = categories.find(c => c.name == button.getAttribute("data-category"))
if (!category) continue
if (determineIfCategoryIsActive(category.name)) {
category.isActive = true
button.classList.add("bc-category-enabled")
} else {
category.isActive = false
button.classList.remove("bc-category-enabled")
}
}
let split = text.split("\n")
let blacklistText = ""
let curCategory = null
for (let item of split) {
let match
if ((match = /# \[\[(.*)\]\]/.exec(item))) {
if (match[1].startsWith("end")) {
curCategory.blacklist = blacklistText.trim()
curCategory = null
blacklistText = ""
} else {
curCategory = categories.find(c => c.name == match[1])
}
} else if (curCategory) {
blacklistText += item + "\n"
}
}
await GM.setValue("categories", categories)
}
function reloadBlacklist() {
// $.ajax("/users/" + Danbooru.Utility.meta("current-user-id") + ".json", {
// method: "PUT",
// data: {
// "user[blacklisted_tags]": $("meta[name=blacklisted-tags]").attr("content") || "[]",
// },
// }).done(function () {
// Danbooru.Utility.notice("Blacklist updated")
// }).fail(function () {
// Danbooru.Utility.error("Failed to update blacklist")
// })
Danbooru.Blacklist.regenerate_filters()
Danbooru.Blacklist.add_posts($(".post-preview"))
Danbooru.Blacklist.update_visibility()
}
function determineIfCategoryIsActive(name, overrideText = null) {
return (overrideText ?? blacklistTextInput.value).indexOf(`# [[${name}]]`) != -1
}
function showHotkeyDialogue() {
}
function categoryButtonFromCategory(category) {
let button = document.createElement("button")
button.classList.add("button", "bc-category-button")
category.isActive = determineIfCategoryIsActive(category.name, JSON.parse($("meta[name=blacklisted-tags]").attr("content")).join("\n"))
if (category.isActive) button.classList.add("bc-category-enabled")
button.innerText = category.name
button.setAttribute("data-category", category.name)
button.addEventListener("click", (e) => {
console.log(e)
e.preventDefault()
category.isActive = !category.isActive
button.classList.toggle("bc-category-enabled")
if (category.isActive) {
blacklistTextInput.value += `\n# [[${category.name}]]\n${category.blacklist}\n# [[end ${category.name}]]\n`
blacklistTextInput.value = blacklistTextInput.value.trimStart()
} else {
let startIndex = blacklistTextInput.value.indexOf(`# [[${category.name}]]`)
let endIndex = blacklistTextInput.value.indexOf(`# [[end ${category.name}]]`)
if (startIndex == -1 || endIndex == -1) return
endIndex += `# [[end ${category.name}]]`.length
blacklistTextInput.value = blacklistTextInput.value.slice(0, startIndex) + blacklistTextInput.value.slice(endIndex + 2)
blacklistTextInput.value = blacklistTextInput.value.trimStart()
}
})
button.addEventListener("mousedown", (e) => {
if (e.button != 1) return
e.preventDefault()
e.stopImmediatePropagation()
showHotkeyDialogue()
})
button.addEventListener("contextmenu", async (e) => {
e.preventDefault()
e.stopImmediatePropagation()
if (!confirm(`Delete ${category.name}?`)) return
removeCategory(category.name)
button.remove()
})
saveCategory(category.name, category)
return button
}
function newCategoryButton() {
let button = document.createElement("button")
button.classList.add("button", "bc-category-button")
button.innerText = "Add Category"
button.addEventListener("click", (e) => {
e.preventDefault()
e.stopImmediatePropagation()
let name = prompt("Category name?").toLowerCase()
let category = {
name,
blacklist: "",
isActive: true
}
blacklistTextInput.value += `\n# [[${category.name}]]\n\n# [[end ${category.name}]]\n`
blacklistTextInput.value = blacklistTextInput.value.trimStart()
saveCategory(name, category)
button.before(categoryButtonFromCategory(category))
})
return button
}
async function addPrimaryCategorySwitcher() {
let blacklistedTagsDiv = document.querySelector(".user_blacklisted_tags")
blacklistTextInput = blacklistedTagsDiv.querySelector("#user_blacklisted_tags")
blacklistTextInput.addEventListener("input", () => {
fixActiveAndSave(blacklistTextInput.value.trim())
})
let hint = blacklistedTagsDiv.querySelector(".hint")
let container = document.createElement("div")
container.style.paddingTop = "0.25rem"
for (let category of await getExistingCategories()) {
container.append(categoryButtonFromCategory(category))
}
container.append(newCategoryButton())
hint.before(container)
}
async function addSecondaryCategorySwitcher() {
let box = document.getElementById("blacklist-edit-dialog")
if (!box) return
blacklistTextInput = box.querySelector("#blacklist-edit")
blacklistTextInput.addEventListener("input", () => {
fixActiveAndSave(blacklistTextInput.value.trim())
})
let saveButton = box.querySelector("#blacklist-save")
let container = document.createElement("div")
container.style.paddingTop = "0.25rem"
container.style.gridColumnStart = "1"
container.style.gridColumnEnd = "3"
for (let category of await getExistingCategories()) {
let button = categoryButtonFromCategory(category)
container.append(button)
}
container.append(newCategoryButton())
saveButton.before(container)
saveButton.style.gridColumnStart = "1"
container.after(document.createElement("br"))
}
(async function () {
let url = window.location.href
if (url.match(/users\/.*\/edit/)) {
addPrimaryCategorySwitcher()
} else {
addSecondaryCategorySwitcher()
}
loadHotkeys()
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment