JanitorAI Custom Profile CSS Toggle

Adds a button to toggle custom CSS on JanitorAI creator profiles.

  1. // ==UserScript==
  2. // @name JanitorAI Custom Profile CSS Toggle
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-10-19
  5. // @description Adds a button to toggle custom CSS on JanitorAI creator profiles.
  6. // @author Cyrus Firheir
  7. // @match https://janitorai.com/*
  8. // @icon https://ella.janitorai.com/hotlink-ok/logo.png
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. const main = () => {
  14. const lsKey = 'jai-custom-css-disabled-urls';
  15. const url = location.pathname;
  16. if (!url.startsWith("/profiles/")) {
  17. [ ...document.querySelectorAll('.css-toggle-button, .css-toggle-button-styles') ].forEach(e => e.remove());
  18. return;
  19. };
  20.  
  21. const styleElements = [];
  22. const inlineStyledElements = [];
  23.  
  24. let stylesDisabled = false;
  25.  
  26. const updateUrls = (add) => {
  27. let disabledUrls = JSON.parse(localStorage.getItem(lsKey));
  28. if (add) disabledUrls.push(url);
  29. else disabledUrls = disabledUrls.filter(e => e !== url);
  30. localStorage.setItem(lsKey, JSON.stringify(disabledUrls));
  31. };
  32.  
  33. const getUrlDisabledState = () => {
  34. if (localStorage.getItem(lsKey)) {
  35. const disabledUrls = JSON.parse(localStorage.getItem(lsKey));
  36. return disabledUrls.includes(url);
  37. } else {
  38. localStorage.setItem(lsKey, '[]');
  39. return false;
  40. }
  41. };
  42.  
  43. const disableStyles = () => {
  44. styleElements.forEach(e => {
  45. e.disabled = true;
  46. });
  47. inlineStyledElements.forEach(e => {
  48. e.setAttribute('style', '');
  49. });
  50. updateUrls(true);
  51. stylesDisabled = true;
  52. };
  53.  
  54. const enableStyles = () => {
  55. styleElements.forEach(e => {
  56. e.disabled = false;
  57. });
  58. inlineStyledElements.forEach(e => {
  59. e.setAttribute('style', e.archivedStyle);
  60. });
  61. updateUrls();
  62. stylesDisabled = false;
  63. };
  64.  
  65. const setDisabled = (disabled) => disabled ? disableStyles() : enableStyles();
  66. const toggleDisabled = () => stylesDisabled ? enableStyles() : disableStyles();
  67.  
  68. const toggleButtonText = () => `${ stylesDisabled ? '🌫️' : '✨' } Custom CSS: ${ stylesDisabled ? 'OFF' : 'ON' }`;
  69.  
  70. const randomHash = Math.random().toString(16).slice(2);
  71. const stylesheet = `
  72. .css-toggle-button.css-${randomHash} {
  73. position: fixed;
  74. z-index: 100000;
  75. text-align: left;
  76. background: #150421; color: #d7cfef;
  77. bottom: 0px; left: 0px; width: 12rem;
  78. border: 2px solid; border-radius: 8px;
  79. margin: 3rem; padding: 0.5rem 1rem;
  80. transition: all 0.1s ease;
  81. }
  82. .css-toggle-button.css-${randomHash}:hover {
  83. background: #1c0947;
  84. }
  85. @media screen and (max-width: 768px) {
  86. .css-toggle-button.css-${randomHash} {
  87. margin: 4rem 1rem;
  88. }
  89. }
  90. `;
  91.  
  92. const observer = new MutationObserver((mutationList, observer) => {
  93. for (const mutation of mutationList) {
  94. if (mutation.type === "childList") {
  95. const bio = Array.from(mutation.addedNodes).find(e => e.classList.contains("css-njzqh0"));
  96. if (bio) {
  97. styleElements.push(...bio.querySelectorAll('style'));
  98. inlineStyledElements.push(...bio.querySelectorAll('[style]'));
  99. inlineStyledElements.forEach(e => {
  100. e.archivedStyle = e.getAttribute('style');
  101. });
  102. stylesDisabled = getUrlDisabledState();
  103. setDisabled(stylesDisabled);
  104. document.addEventListener("keyup", ({ key, altKey }) => {
  105. if (altKey && key === "c") toggleDisabled();
  106. });
  107. const toggleButton = document.createElement("button");
  108. toggleButton.classList.add(`css-${randomHash}`, 'css-toggle-button');
  109. toggleButton.innerHTML = toggleButtonText();
  110. toggleButton.addEventListener("click", () => {
  111. toggleDisabled();
  112. toggleButton.innerHTML = toggleButtonText();
  113. });
  114. const toggleButtonStyles = document.createElement("style");
  115. toggleButtonStyles.classList.add("css-toggle-button-styles");
  116. toggleButtonStyles.innerHTML = stylesheet;
  117. document.body.appendChild(toggleButton);
  118. document.body.appendChild(toggleButtonStyles);
  119. observer.disconnect();
  120. }
  121. }
  122. }
  123. });
  124. observer.observe(document.body, { childList: true, subtree: true });
  125. };
  126.  
  127. let oldHref = location.href;
  128.  
  129. window.onload = function() {
  130. const bodyList = document.querySelector("body")
  131. const observer = new MutationObserver(function(mutations) {
  132. mutations.forEach(function(mutation) {
  133. if (oldHref != location.href) {
  134. oldHref = location.href;
  135. main();
  136. }
  137. });
  138. });
  139. observer.observe(document.body, { childList: true, subtree: true });
  140. };
  141.  
  142. main();