// ==UserScript==
// @name JanitorAI Enhanced UI with CSS Toggle and Auto Pagination
// @namespace http://tampermonkey.net/
// @version 3.7
// @description Adds UI controls, hides buttons, toggles custom CSS, and auto-paginates on JanitorAI
// @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 = false;
let isCustomCssDisabled = localStorage.getItem('janitorAICustomCssDisabled') === 'true';
let isAutoPaginationEnabled = localStorage.getItem('janitorAIAutoPagination') !== 'false'; // Новая настройка
let sliderElement = null;
let sliderContainer = null;
let controlPanel = null;
let controlsContainer = null;
let emblaSlide = 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 getNextPageElement = () => {
const currentPage = document.querySelector('.css-1xdrgup');
if (!currentPage) return null;
let nextElement = currentPage.nextElementSibling;
while (nextElement) {
if (nextElement.classList.contains('css-kzd6o0') || nextElement.classList.contains('css-15aspjy')) {
return nextElement;
}
nextElement = nextElement.nextElementSibling;
}
return null;
};
// Проверка полного достижения конца страницы
const isAtVeryBottom = () => {
const scrollPosition = window.scrollY + window.innerHeight;
const pageHeight = document.documentElement.scrollHeight;
return pageHeight - scrollPosition <= 1;
};
// Логика автоперехода
const setupAutoPagination = () => {
let isNavigating = false;
let scrollCount = 0;
const requiredScrolls = 3;
window.addEventListener('wheel', function(event) {
if (isAutoPaginationEnabled && event.deltaY > 0 && isAtVeryBottom() && !isNavigating) {
scrollCount++;
if (scrollCount >= requiredScrolls) {
const nextPage = getNextPageElement();
if (nextPage) {
isNavigating = true;
nextPage.click();
setTimeout(() => {
isNavigating = false;
scrollCount = 0;
}, 2000);
}
}
} else if (!isAtVeryBottom()) {
scrollCount = 0;
}
}, { passive: true });
};
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 toggleAutoPagination = () => {
isAutoPaginationEnabled = !isAutoPaginationEnabled;
localStorage.setItem('janitorAIAutoPagination', isAutoPaginationEnabled);
updateControlText();
};
const toggleMenu = () => {
isMenuVisible = !isMenuVisible;
updateElementsVisibility();
updateControlText();
};
const toggleCustomCss = () => {
isCustomCssDisabled = !isCustomCssDisabled;
localStorage.setItem('janitorAICustomCssDisabled', isCustomCssDisabled);
applyCustomCssToggle();
updateControlText();
};
const applyCustomCssToggle = () => {
if (isCustomCssDisabled) {
removeCustomStyles();
blockCustomElements();
}
};
const removeCustomStyles = () => {
const styles = document.querySelectorAll('body style');
styles.forEach(style => style.remove());
};
const blockCustomElements = () => {
document.querySelectorAll('.css-1bn1yyx').forEach(element => {
element.style.display = 'none';
});
document.querySelectorAll('*').forEach(element => {
const style = window.getComputedStyle(element);
const bgImage = style.backgroundImage;
if (bgImage && bgImage.includes('ella.janitorai.com/background-image/')) {
element.style.backgroundImage = 'none';
}
});
};
const updateControlText = () => {
const sidebarText = document.getElementById('sidebar-toggle-text');
const scrollText = document.getElementById('auto-scroll-text');
const paginationText = document.getElementById('auto-pagination-text');
const cssToggleText = document.getElementById('css-toggle-text');
if (sidebarText) {
sidebarText.textContent = isSidebarHidden ? 'Topbar: OFF' : 'Topbar: ON';
sidebarText.style.color = isSidebarHidden ? '#fff' : '#ccc';
}
if (scrollText) {
scrollText.textContent = `Auto-Scroll: ${isAutoScrollEnabled ? 'ON' : 'OFF'}`;
scrollText.style.color = isAutoScrollEnabled ? '#fff' : '#ccc';
}
if (paginationText) {
paginationText.textContent = `Auto-Page: ${isAutoPaginationEnabled ? 'ON' : 'OFF'}`;
paginationText.style.color = isAutoPaginationEnabled ? '#fff' : '#ccc';
}
if (cssToggleText) {
cssToggleText.textContent = `Custom CSS: ${isCustomCssDisabled ? 'OFF' : 'ON'}`;
cssToggleText.style.color = isCustomCssDisabled ? '#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);
const paginationText = document.createElement('span');
paginationText.id = 'auto-pagination-text';
paginationText.style.cursor = 'pointer';
paginationText.style.fontSize = '12px';
paginationText.addEventListener('click', toggleAutoPagination);
const cssToggleText = document.createElement('span');
cssToggleText.id = 'css-toggle-text';
cssToggleText.style.cursor = 'pointer';
cssToggleText.style.fontSize = '12px';
cssToggleText.addEventListener('click', toggleCustomCss);
controlsContainer.appendChild(sidebarText);
controlsContainer.appendChild(scrollText);
controlsContainer.appendChild(paginationText);
controlsContainer.appendChild(cssToggleText);
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: 10px;
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(0px);
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(-10px);
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 applySidebarState = () => {
const sidebar = document.querySelector('.css-h988mi');
const css70qvj9 = document.querySelector('.css-70qvj9');
emblaSlide = document.querySelector('.is-in-view.is-snapped.embla__slide');
if (sidebar && isSidebarHidden) {
sidebar.style.display = 'none';
if (emblaSlide) emblaSlide.style.display = 'none';
if (css70qvj9) css70qvj9.style.display = 'none';
}
};
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();
applySidebarState();
updateElementsVisibility();
setupAutoPagination(); // Инициализация автоперехода
if (isAllowedPage() && !isChatsPage()) {
filterCards();
setupPaginationScroll();
applyCustomCssToggle();
new MutationObserver(() => {
filterCards();
setupPaginationScroll();
applyCustomCssToggle();
applySidebarState();
}).observe(document.body, { childList: true, subtree: true });
const originalAppendChild = Element.prototype.appendChild;
Element.prototype.appendChild = function(node) {
if (isCustomCssDisabled && node.tagName === 'STYLE' && this.tagName === 'HEAD') {
return node;
}
return originalAppendChild.call(this, node);
};
}
};
const tryInitialize = () => {
if (document.body) {
initialize();
let lastPath = window.location.pathname;
setInterval(() => {
if (lastPath !== window.location.pathname) {
lastPath = window.location.pathname;
updateElementsVisibility();
if (isAllowedPage() && !isChatsPage()) {
filterCards();
setupPaginationScroll();
applyCustomCssToggle();
applySidebarState();
}
}
}, 500);
} else {
setTimeout(tryInitialize, 1000);
}
};
tryInitialize();
})();