- // ==UserScript==
- // @name JanitorAI Enhanced UI
- // @namespace http://tampermonkey.net/
- // @version 3.4
- // @description Adds UI controls for JanitorAI, hides buttons on chat pages
- // @author Fefnik
- // @match https://janitorai.com/*
- // @grant none
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- let MIN_TOKENS = parseInt(localStorage.getItem('janitorAITokenFilter')) || 500;
- let isSidebarHidden = localStorage.getItem('janitorAISidebarHidden') === 'true';
- let isAutoScrollEnabled = localStorage.getItem('janitorAIAutoScroll') !== 'false';
- let isMenuVisible = localStorage.getItem('janitorAIMenuVisible') === 'true';
-
- let sliderElement = null;
- let sliderContainer = null;
- let controlPanel = null;
- let controlsContainer = null;
- let emblaSlide = null;
- let movedButton = null;
-
- const isAllowedPage = () => {
- const path = window.location.pathname;
- return path === '/' || path.startsWith('/search') || path === '/my_characters' || path.startsWith('/profiles/');
- };
-
- const isChatsPage = () => window.location.pathname.startsWith('/chats');
-
- const parseTokens = (text) => {
- try {
- text = text.replace(/<!--[\s\S]*?-->/g, '').replace('tokens', '').trim();
- return text.includes('k') ? parseFloat(text.replace('k', '')) * 1000 : parseInt(text, 10) || 0;
- } catch {
- return 0;
- }
- };
-
- const filterCards = () => {
- document.querySelectorAll('.chakra-stack.css-1s5evre, .css-1s5evre').forEach(card => {
- const tokenElement = card.querySelector('.chakra-text.css-jccmq6, .css-jccmq6');
- if (!tokenElement) return;
-
- const tokenCount = parseTokens(tokenElement.textContent);
- const parent = card.closest('.css-1sxhvxh, .css-1dbw1r8');
- if (parent) parent.style.display = tokenCount < MIN_TOKENS ? 'none' : '';
- });
- };
-
- const setupPaginationScroll = () => {
- document.querySelectorAll('.css-kzd6o0').forEach(button => {
- button.removeEventListener('click', handlePaginationClick);
- button.addEventListener('click', handlePaginationClick);
- });
- };
-
- const handlePaginationClick = () => {
- if (isAutoScrollEnabled) {
- setTimeout(() => window.scrollTo({ top: 0, behavior: 'smooth' }), 300);
- }
- };
-
- const toggleSidebar = () => {
- const sidebar = document.querySelector('.css-h988mi');
- const css70qvj9 = document.querySelector('.css-70qvj9');
-
- if (sidebar) {
- isSidebarHidden = !isSidebarHidden;
- sidebar.style.display = isSidebarHidden ? 'none' : '';
-
- if (!emblaSlide) {
- emblaSlide = document.querySelector('.is-in-view.is-snapped.embla__slide');
- }
- if (emblaSlide) {
- emblaSlide.style.display = isSidebarHidden ? 'none' : '';
- }
-
- if (css70qvj9) {
- css70qvj9.style.display = isSidebarHidden ? 'none' : '';
- }
-
- localStorage.setItem('janitorAISidebarHidden', isSidebarHidden);
- updateControlText();
- }
- };
-
- const toggleAutoScroll = () => {
- isAutoScrollEnabled = !isAutoScrollEnabled;
- localStorage.setItem('janitorAIAutoScroll', isAutoScrollEnabled);
- updateControlText();
- };
-
- const toggleMenu = () => {
- isMenuVisible = !isMenuVisible;
- localStorage.setItem('janitorAIMenuVisible', isMenuVisible);
- updateElementsVisibility();
- updateControlText();
- };
-
- const updateControlText = () => {
- const sidebarText = document.getElementById('sidebar-toggle-text');
- const scrollText = document.getElementById('auto-scroll-text');
- if (sidebarText) {
- sidebarText.textContent = isSidebarHidden ? 'Show Topbar' : 'Hide Topbar';
- sidebarText.style.color = isSidebarHidden ? '#fff' : '#ccc';
- }
- if (scrollText) {
- scrollText.textContent = `Auto-Scroll: ${isAutoScrollEnabled ? 'ON' : 'OFF'}`;
- scrollText.style.color = isAutoScrollEnabled ? '#fff' : '#ccc';
- }
- };
-
- const createControlPanel = () => {
- if (controlPanel) return;
-
- controlPanel = document.createElement('div');
- controlPanel.id = 'janitor-control-panel';
- Object.assign(controlPanel.style, {
- position: 'fixed',
- top: '75px',
- left: '10px',
- zIndex: '100000',
- display: 'flex',
- flexDirection: 'column',
- gap: '5px',
- alignItems: 'flex-start'
- });
-
- const settingsButton = document.createElement('button');
- settingsButton.id = 'token-filter-toggle';
- settingsButton.textContent = '⚙️';
- Object.assign(settingsButton.style, {
- width: '30px',
- height: '30px',
- padding: '0',
- backgroundColor: 'rgba(74, 74, 74, 0.7)',
- color: '#fff',
- border: 'none',
- borderRadius: '5px',
- cursor: 'pointer',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- fontSize: '16px',
- transition: 'background-color 0.2s'
- });
- settingsButton.addEventListener('click', toggleMenu);
-
- controlsContainer = document.createElement('div');
- controlsContainer.id = 'controls-container';
- Object.assign(controlsContainer.style, {
- display: 'none',
- flexDirection: 'column',
- gap: '5px',
- backgroundColor: 'rgba(74, 74, 74, 0.7)',
- padding: '5px',
- borderRadius: '5px',
- zIndex: '100001'
- });
-
- const sidebarText = document.createElement('span');
- sidebarText.id = 'sidebar-toggle-text';
- sidebarText.style.cursor = 'pointer';
- sidebarText.style.fontSize = '12px';
- sidebarText.addEventListener('click', toggleSidebar);
-
- const scrollText = document.createElement('span');
- scrollText.id = 'auto-scroll-text';
- scrollText.style.cursor = 'pointer';
- scrollText.style.fontSize = '12px';
- scrollText.addEventListener('click', toggleAutoScroll);
-
- controlsContainer.appendChild(sidebarText);
- controlsContainer.appendChild(scrollText);
- controlPanel.appendChild(settingsButton);
- controlPanel.appendChild(controlsContainer);
- document.body.appendChild(controlPanel);
- updateControlText();
- };
-
- const createOrUpdateSlider = () => {
- if (sliderElement) return;
-
- sliderContainer = document.createElement('div');
- sliderContainer.id = 'token-filter-container';
- Object.assign(sliderContainer.style, {
- position: 'fixed',
- top: '75px',
- left: '50px',
- zIndex: '100002',
- display: 'none',
- flexDirection: 'row',
- alignItems: 'center',
- gap: '10px',
- padding: '5px',
- backgroundColor: 'rgba(74, 74, 74, 0.7)',
- borderRadius: '5px'
- });
-
- sliderElement = document.createElement('input');
- sliderElement.type = 'range';
- sliderElement.id = 'token-filter-slider';
- Object.assign(sliderElement, {
- min: '0',
- max: '6000',
- step: '100',
- value: MIN_TOKENS
- });
- Object.assign(sliderElement.style, {
- width: '150px',
- height: '20px',
- backgroundColor: '#4a4a4a',
- cursor: 'pointer',
- appearance: 'none',
- outline: 'none',
- borderRadius: '5px',
- padding: '0',
- zIndex: '100003'
- });
-
- const style = document.createElement('style');
- style.textContent = `
- #token-filter-slider {
- -webkit-appearance: none;
- appearance: none;
- background: #4a4a4a;
- border-radius: 5px;
- z-index: 100003;
- }
- #token-filter-slider::-webkit-slider-thumb {
- -webkit-appearance: none;
- appearance: none;
- width: 20px;
- height: 20px;
- background: #ffffff;
- cursor: pointer;
- border-radius: 50%;
- border: 2px solid #000;
- box-shadow: 0 0 2px rgba(0,0,0,0.5);
- transform: translateY(-5px);
- z-index: 100004;
- }
- #token-filter-slider::-moz-range-thumb {
- width: 20px;
- height: 20px;
- background: #ffffff;
- cursor: pointer;
- border-radius: 50%;
- border: 2px solid #000;
- box-shadow: 0 0 2px rgba(0,0,0,0.5);
- transform: translateY(-5px);
- z-index: 100004;
- }
- #token-filter-slider::-webkit-slider-runnable-track {
- height: 10px;
- background: #4a4a4a;
- border-radius: 5px;
- }
- #token-filter-slider::-moz-range-track {
- height: 10px;
- background: #4a4a4a;
- border-radius: 5px;
- }
- `;
- document.head.appendChild(style);
-
- const label = document.createElement('span');
- label.id = 'token-filter-label';
- label.style.color = '#fff';
- label.style.fontSize = '12px';
- label.style.minWidth = '60px';
- label.textContent = `${MIN_TOKENS} tokens`;
-
- sliderElement.addEventListener('input', (e) => {
- MIN_TOKENS = parseInt(e.target.value);
- label.textContent = `${MIN_TOKENS} tokens`;
- localStorage.setItem('janitorAITokenFilter', MIN_TOKENS);
- filterCards();
- });
-
- sliderContainer.appendChild(sliderElement);
- sliderContainer.appendChild(label);
- document.body.appendChild(sliderContainer);
- };
-
- const moveChatMenuButton = () => {
- if (movedButton) return;
-
- const panel = document.querySelector('.css-4nh2z0');
- if (!panel || !isChatsPage()) return;
-
- const button = panel.querySelector('.chakra-button.chakra-menu__menu-button.css-48kqv5');
- if (!button) return;
-
- movedButton = button;
- const buttonClone = button.cloneNode(true);
-
- Object.assign(buttonClone.style, {
- position: 'fixed',
- bottom: '20px',
- right: '20px',
- zIndex: '100005',
- backgroundColor: 'rgba(74, 74, 74, 0.7)',
- borderRadius: '5px',
- padding: '5px'
- });
-
- button.remove();
- document.body.appendChild(buttonClone);
-
- const menuId = buttonClone.getAttribute('aria-controls');
- const menu = document.getElementById(menuId);
- if (menu) {
- menu.style.zIndex = '100006';
- }
-
- buttonClone.addEventListener('click', () => {
- const isExpanded = buttonClone.getAttribute('aria-expanded') === 'true';
- buttonClone.setAttribute('aria-expanded', !isExpanded);
- if (menu) {
- menu.style.display = isExpanded ? 'none' : 'block';
- }
- });
- };
-
- const updateElementsVisibility = () => {
- const shouldShow = isAllowedPage() && !isChatsPage();
- if (controlPanel) controlPanel.style.display = shouldShow ? 'flex' : 'none';
- if (sliderContainer) sliderContainer.style.display = shouldShow && isMenuVisible ? 'flex' : 'none';
- if (controlsContainer) controlsContainer.style.display = shouldShow && isMenuVisible ? 'flex' : 'none';
- };
-
- const initialize = () => {
- createControlPanel();
- createOrUpdateSlider();
- moveChatMenuButton();
- updateElementsVisibility();
-
- if (isAllowedPage() && !isChatsPage()) {
- filterCards();
- setupPaginationScroll();
-
- const sidebar = document.querySelector('.css-h988mi');
- if (sidebar && isSidebarHidden) {
- sidebar.style.display = 'none';
- emblaSlide = document.querySelector('.is-in-view.is-snapped.embla__slide');
- if (emblaSlide) emblaSlide.style.display = 'none';
- const css70qvj9 = document.querySelector('.css-70qvj9');
- if (css70qvj9) css70qvj9.style.display = 'none';
- }
-
- new MutationObserver(() => {
- filterCards();
- setupPaginationScroll();
- }).observe(document.body, { childList: true, subtree: true });
- }
- };
-
- const tryInitialize = () => {
- if (document.body) {
- initialize();
- let lastPath = window.location.pathname;
- setInterval(() => {
- if (lastPath !== window.location.pathname) {
- lastPath = window.location.pathname;
- movedButton = null;
- moveChatMenuButton();
- updateElementsVisibility();
- if (isAllowedPage() && !isChatsPage()) {
- filterCards();
- setupPaginationScroll();
- }
- }
- }, 500);
- } else {
- setTimeout(tryInitialize, 1000);
- }
- };
-
- tryInitialize();
- })();