JanitorAI Token Filter

Filters character cards on JanitorAI by token count

2025-04-09 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

// ==UserScript==
// @name         JanitorAI Token Filter
// @namespace    http://tampermonkey.net/
// @version      0.25
// @description  Filters character cards on JanitorAI by token count
// @author       Fefnik
// @match        https://janitorai.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let MIN_TOKENS = localStorage.getItem('janitorAITokenFilter') ? parseInt(localStorage.getItem('janitorAITokenFilter')) : 500;
    let sliderElement = null;
    let sliderContainer = null;
    let isSliderVisible = localStorage.getItem('janitorAISliderVisible') === 'true' ? true : false;

    function parseTokens(tokenText) {
        try {
            let cleanText = tokenText.replace(/<!--[\s\S]*?-->/g, '').replace('tokens', '').trim();
            if (cleanText.includes('k')) {
                return parseFloat(cleanText.replace('k', '')) * 1000;
            }
            return parseInt(cleanText, 10) || 0;
        } catch (error) {
            return 0;
        }
    }

    function filterCards() {
        const mainPageCards = document.querySelectorAll('.chakra-stack.css-1s5evre');
        mainPageCards.forEach(card => {
            const tokenElement = card.querySelector('.chakra-text.css-jccmq6');
            if (!tokenElement) return;

            const tokenCount = parseTokens(tokenElement.textContent);
            const parentContainer = card.closest('.css-1sxhvxh');
            if (parentContainer) {
                parentContainer.style.display = tokenCount < MIN_TOKENS ? 'none' : '';
            }
        });

        const searchPageCards = document.querySelectorAll('.chakra-stack.css-1s5evre, .css-1s5evre');
        searchPageCards.forEach(card => {
            const tokenElement = card.querySelector('.chakra-text.css-jccmq6, .css-jccmq6');
            if (!tokenElement) return;

            const tokenCount = parseTokens(tokenElement.textContent);
            const parentContainer = card.closest('.css-1sxhvxh, .css-1dbw1r8');
            if (parentContainer) {
                parentContainer.style.display = tokenCount < MIN_TOKENS ? 'none' : '';
            }
        });
    }

    function createOrUpdateSlider() {
        if (!sliderElement) {
            sliderContainer = document.createElement('div');
            sliderContainer.id = 'token-filter-container';
            sliderContainer.style.position = 'fixed';
            sliderContainer.style.top = '75px'; // Lowered by 25px (from 50px to 75px)
            sliderContainer.style.left = '0px';
            sliderContainer.style.zIndex = '99999';
            sliderContainer.style.display = 'flex';
            sliderContainer.style.flexDirection = 'column';
            sliderContainer.style.alignItems = 'center';
            sliderContainer.style.height = '150px';
            sliderContainer.style.width = '50px';

            const sliderWrapper = document.createElement('div');
            sliderWrapper.style.width = '100px';
            sliderWrapper.style.height = '10px';
            sliderWrapper.style.transform = 'rotate(-90deg)';
            sliderWrapper.style.transformOrigin = 'center center';
            sliderWrapper.style.marginTop = '10px';

            sliderElement = document.createElement('input');
            sliderElement.type = 'range';
            sliderElement.id = 'token-filter-slider';
            sliderElement.min = '0';
            sliderElement.max = '6000';
            sliderElement.step = '100';
            sliderElement.value = MIN_TOKENS;
            sliderElement.style.width = '100%';
            sliderElement.style.height = '20px';
            sliderElement.style.backgroundColor = '#4a4a4a';
            sliderElement.style.cursor = 'pointer';
            sliderElement.style.appearance = 'none';
            sliderElement.style.outline = 'none';
            sliderElement.style.borderRadius = '5px';

            const style = document.createElement('style');
            style.textContent = `
                #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;
                }
                #token-filter-slider::-moz-range-thumb {
                    width: 20px;
                    height: 20px;
                    background: #ffffff;
                    cursor: pointer;
                    border-radius: 50%;
                    border: 2px solid #000;
                }
            `;
            document.head.appendChild(style);

            const label = document.createElement('span');
            label.id = 'token-filter-label';
            label.style.color = '#fff';
            label.style.fontSize = '12px';
            label.style.textAlign = 'center';
            label.style.marginTop = '50px';
            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();
            });

            sliderWrapper.appendChild(sliderElement);
            sliderContainer.appendChild(sliderWrapper);
            sliderContainer.appendChild(label);

            const toggleButton = document.createElement('button');
            toggleButton.id = 'token-filter-toggle';
            toggleButton.textContent = '⚙️';
            toggleButton.style.position = 'fixed';
            toggleButton.style.top = '10px';
            toggleButton.style.left = '10px';
            toggleButton.style.zIndex = '100000';
            toggleButton.style.width = '20px';
            toggleButton.style.height = '20px';
            toggleButton.style.padding = '0';
            toggleButton.style.backgroundColor = '#4a4a4a';
            toggleButton.style.color = '#fff';
            toggleButton.style.border = 'none';
            toggleButton.style.borderRadius = '5px';
            toggleButton.style.cursor = 'pointer';
            toggleButton.style.display = 'flex';
            toggleButton.style.alignItems = 'center';
            toggleButton.style.justifyContent = 'center';
            toggleButton.style.fontSize = '14px';

            toggleButton.addEventListener('click', () => {
                isSliderVisible = !isSliderVisible;
                sliderContainer.style.display = isSliderVisible ? 'flex' : 'none';
                localStorage.setItem('janitorAISliderVisible', isSliderVisible);
            });

            const appendElements = () => {
                if (document.body) {
                    document.body.appendChild(toggleButton);
                    document.body.appendChild(sliderContainer);
                } else {
                    setTimeout(appendElements, 500);
                }
            };
            appendElements();
        }

        if (sliderContainer) {
            const isPageVisible = window.location.pathname === '/' || window.location.pathname === '/search';
            sliderContainer.style.display = isPageVisible && isSliderVisible ? 'flex' : 'none';
        }
    }

    function initialize() {
        createOrUpdateSlider();
        if (window.location.pathname === '/' || window.location.pathname === '/search') {
            filterCards();
        }
    }

    const tryInitialize = () => {
        if (document.body) {
            initialize();

            let lastPath = window.location.pathname;
            const checkPath = () => {
                if (lastPath !== window.location.pathname) {
                    lastPath = window.location.pathname;
                    createOrUpdateSlider();
                    if (lastPath === '/' || lastPath === '/search') {
                        filterCards();
                    }
                }
            };

            setInterval(checkPath, 500);

            const observer = new MutationObserver(() => {
                if (window.location.pathname === '/' || window.location.pathname === '/search') {
                    setTimeout(filterCards, 500);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
        } else {
            setTimeout(tryInitialize, 1000);
        }
    };

    tryInitialize();
})();