Add-to-blacklist-Danbooru

The script adds a button to add a tag to the blacklist on wiki pages

  1. // ==UserScript==
  2. // @name Add-to-blacklist-Danbooru
  3. // @namespace https://danbooru.donmai.us/
  4. // @version 2024-07-27
  5. // @description The script adds a button to add a tag to the blacklist on wiki pages
  6. // @author anonbl (https://danbooru.donmai.us/users/473183)
  7. // @match https://*.donmai.us/artists/*
  8. // @match https://*.donmai.us/wiki_pages/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=donmai.us
  10. // @grant none
  11. // @run-at document-start
  12. // @homepageURL https://danbooru.donmai.us/forum_topics/28131
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function () {
  17. "use strict";
  18. var csrfToken;
  19. addEventListener("DOMContentLoaded", () => {
  20. let headerElement = document.querySelector(
  21. "#wiki-page-title, #a-show > div.flex.items-center.gap-2"
  22. );
  23. if (!headerElement.querySelector('a[class^="tag-type"]')) return;
  24.  
  25. let tagInfoFetchPromise = fetch(document.location.pathname + ".json")
  26. .then((response) => {
  27. if (!response.ok) throw new Error(response.status);
  28. return response.json();
  29. })
  30. .then((json) => json?.name ?? json?.title)
  31. .catch(errorHandler);
  32.  
  33. let profileInfoFetchPromise = getProfileInfo()
  34. .then((profile) => getBlacklist(profile))
  35. .catch(errorHandler);
  36.  
  37. Promise.all([tagInfoFetchPromise, profileInfoFetchPromise])
  38. .then(([tag, blacklisted_tags]) => {
  39. var buttonsContainerElement = document.createElement("div");
  40. buttonsContainerElement.style.display = "inline-block";
  41. headerElement.append(buttonsContainerElement);
  42. if (!blacklisted_tags.includes(tag)) {
  43. buttonsContainerElement.append(createAddButton(tag));
  44. }
  45. for (const blacklistedTag of blacklisted_tags) {
  46. if (!blacklistedTag.includes(tag)) continue;
  47. buttonsContainerElement.append(createRemoveButton(blacklistedTag));
  48. }
  49. })
  50. .catch(errorHandler);
  51. });
  52.  
  53. function addToBlacklist(tag) {
  54. return getProfileInfo()
  55. .then((profile) => {
  56. let blacklistArray = getBlacklist(profile);
  57. if (!blacklistArray.includes(tag)) blacklistArray.push(tag);
  58. blacklistArray.sort();
  59. let blacklisted_tags = blacklistArray.join("\n");
  60. return updateBlacklist(blacklisted_tags, profile.id);
  61. })
  62. .then((response) => response?.ok)
  63. .catch(errorHandler);
  64. }
  65.  
  66. function removeFromBlacklist(tag) {
  67. return getProfileInfo()
  68. .then((profile) => {
  69. let blacklistArray = getBlacklist(profile);
  70. blacklistArray = blacklistArray.filter((t) => t != tag);
  71. blacklistArray.sort();
  72. let blacklisted_tags = blacklistArray.join("\n");
  73. return updateBlacklist(blacklisted_tags, profile.id);
  74. })
  75. .then((response) => response?.ok)
  76. .catch(errorHandler);
  77. }
  78.  
  79. function getBlacklist(profile) {
  80. return profile?.blacklisted_tags?.split("\n") ?? [];
  81. }
  82.  
  83. function getProfileInfo() {
  84. return fetch("/profile.json")
  85. .then((response) => {
  86. if (!response.ok) throw new Error(response.status);
  87. return response.json();
  88. })
  89. .catch(errorHandler);
  90. }
  91.  
  92. function updateBlacklist(blacklisted_tags, userId) {
  93. csrfToken ??= document.head.querySelector('[name="csrf-token"][content]').content;
  94. return fetch(`/users/${userId}.json`, {
  95. method: "PUT",
  96. headers: {
  97. "Content-Type": "application/json",
  98. "X-CSRF-Token": csrfToken,
  99. },
  100. credentials: "same-origin",
  101. body: JSON.stringify({ user: { blacklisted_tags } }),
  102. })
  103. .then((response) => {
  104. if (!response.ok) throw new Error(response.status);
  105. return response;
  106. })
  107. .catch(errorHandler);
  108. }
  109.  
  110. function createAddButton(tag, button) {
  111. button = button ?? document.createElement("button");
  112. button.innerHTML = `Add to blacklist (${tag})`;
  113. button.setAttribute("class", "button-primary button-sm");
  114. button.onclick = () => {
  115. button.disabled = true;
  116. addToBlacklist(tag)
  117. .then((ok) => {
  118. if (!ok) return;
  119. showNotice(`${tag} has been added to the blacklist`);
  120. createRemoveButton(tag, button);
  121. })
  122. .finally(() => {
  123. button.disabled = false;
  124. });
  125. };
  126. return button;
  127. }
  128.  
  129. function showNotice(msg) {
  130. let noticeElement = document.querySelector("#notice");
  131. noticeElement.querySelector("span").innerHTML = msg;
  132. noticeElement.style.display = "";
  133. }
  134.  
  135. function errorHandler(err) {
  136. console.error(err);
  137. showNotice("Error: " + err?.message);
  138. }
  139.  
  140. function createRemoveButton(tag, button) {
  141. button = button ?? document.createElement("button");
  142. button.innerHTML = `Remove from blacklist (${tag})`;
  143. button.setAttribute("class", "button-primary button-sm");
  144. button.onclick = () => {
  145. button.disabled = true;
  146. removeFromBlacklist(tag)
  147. .then((ok) => {
  148. if (!ok) return;
  149. createAddButton(tag, button);
  150. showNotice(`${tag} has been removed from the blacklist`);
  151. })
  152. .finally(() => {
  153. button.disabled = false;
  154. });
  155. };
  156. return button;
  157. }
  158. })();