JanitorAI Token Filter

Filters character cards on JanitorAI by token count

目前为 2025-04-09 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name JanitorAI Token Filter
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.20
  5. // @description Filters character cards on JanitorAI by token count
  6. // @author Fefnik
  7. // @match https://janitorai.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. let MIN_TOKENS = 500;
  15. let sliderElement = null;
  16.  
  17. function parseTokens(tokenText) {
  18. try {
  19. let cleanText = tokenText.replace(/<!--[\s\S]*?-->/g, '').replace('tokens', '').trim();
  20. if (cleanText.includes('k')) {
  21. return parseFloat(cleanText.replace('k', '')) * 1000;
  22. }
  23. return parseInt(cleanText, 10) || 0;
  24. } catch (error) {
  25. return 0;
  26. }
  27. }
  28.  
  29. function filterCards() {
  30. const cards = document.querySelectorAll('.chakra-stack.css-1s5evre');
  31. cards.forEach(card => {
  32. const tokenElement = card.querySelector('.chakra-text.css-jccmq6');
  33. if (!tokenElement) return;
  34.  
  35. const tokenCount = parseTokens(tokenElement.textContent);
  36. const parentContainer = card.closest('.css-1sxhvxh');
  37. if (parentContainer) {
  38. parentContainer.style.display = tokenCount < MIN_TOKENS ? 'none' : '';
  39. }
  40. });
  41. }
  42.  
  43. function createOrUpdateSlider() {
  44. if (!sliderElement) {
  45. // Создаем контейнер для слайдера и метки
  46. const sliderContainer = document.createElement('div');
  47. sliderContainer.id = 'token-filter-container';
  48. sliderContainer.style.position = 'fixed';
  49. sliderContainer.style.top = '50px';
  50. sliderContainer.style.left = '0px';
  51. sliderContainer.style.zIndex = '99999';
  52. sliderContainer.style.display = 'flex';
  53. sliderContainer.style.flexDirection = 'column';
  54. sliderContainer.style.alignItems = 'center';
  55. sliderContainer.style.height = '150px'; // Высота контейнера
  56. sliderContainer.style.width = '50px'; // Ограничиваем ширину
  57.  
  58. // Создаем дополнительный контейнер для слайдера с правильной ориентацией
  59. const sliderWrapper = document.createElement('div');
  60. sliderWrapper.style.width = '100px'; // Реальная длина слайдера
  61. sliderWrapper.style.height = '10px'; // Толщина слайдера
  62. sliderWrapper.style.transform = 'rotate(-90deg)';
  63. sliderWrapper.style.transformOrigin = 'center center';
  64. sliderWrapper.style.marginTop = '10px'; // Отступ сверху для слайдера
  65.  
  66. // Создаем слайдер
  67. sliderElement = document.createElement('input');
  68. sliderElement.type = 'range';
  69. sliderElement.id = 'token-filter-slider';
  70. sliderElement.min = '0';
  71. sliderElement.max = '6000';
  72. sliderElement.step = '100';
  73. sliderElement.value = MIN_TOKENS;
  74. sliderElement.style.width = '100%'; // Занимает всю длину контейнера
  75. sliderElement.style.height = '20px';
  76. sliderElement.style.backgroundColor = '#4a4a4a';
  77. sliderElement.style.cursor = 'pointer';
  78. sliderElement.style.appearance = 'none'; // Убираем стандартные стили
  79. sliderElement.style.outline = 'none';
  80. sliderElement.style.borderRadius = '5px';
  81.  
  82. // Добавляем кастомные стили для ползунка
  83. const style = document.createElement('style');
  84. style.textContent = `
  85. #token-filter-slider::-webkit-slider-thumb {
  86. -webkit-appearance: none;
  87. appearance: none;
  88. width: 20px;
  89. height: 20px;
  90. background: #ffffff;
  91. cursor: pointer;
  92. border-radius: 50%;
  93. border: 2px solid #000;
  94. }
  95. #token-filter-slider::-moz-range-thumb {
  96. width: 20px;
  97. height: 20px;
  98. background: #ffffff;
  99. cursor: pointer;
  100. border-radius: 50%;
  101. border: 2px solid #000;
  102. }
  103. `;
  104. document.head.appendChild(style);
  105.  
  106. // Создаем метку
  107. const label = document.createElement('span');
  108. label.id = 'token-filter-label';
  109. label.style.color = '#fff';
  110. label.style.fontSize = '12px';
  111. label.style.textAlign = 'center';
  112. label.style.marginTop = '50px'; // Увеличиваем отступ, чтобы опустить текст ниже на ~10px
  113. label.textContent = `${MIN_TOKENS} tokens`;
  114.  
  115. // Добавляем обработчик событий
  116. sliderElement.addEventListener('input', (e) => {
  117. MIN_TOKENS = parseInt(e.target.value);
  118. label.textContent = `${MIN_TOKENS} tokens`;
  119. filterCards();
  120. });
  121.  
  122. // Собираем все вместе: сначала слайдер, потом метка
  123. sliderWrapper.appendChild(sliderElement);
  124. sliderContainer.appendChild(sliderWrapper);
  125. sliderContainer.appendChild(label);
  126.  
  127. const appendSlider = () => {
  128. if (document.body) {
  129. document.body.appendChild(sliderContainer);
  130. } else {
  131. setTimeout(appendSlider, 500);
  132. }
  133. };
  134. appendSlider();
  135. }
  136.  
  137. const container = document.getElementById('token-filter-container');
  138. if (container) {
  139. container.style.display = window.location.pathname === '/' ? 'flex' : 'none';
  140. }
  141. }
  142.  
  143. function initialize() {
  144. createOrUpdateSlider();
  145. if (window.location.pathname === '/') {
  146. filterCards();
  147. }
  148. }
  149.  
  150. const tryInitialize = () => {
  151. if (document.body) {
  152. initialize();
  153.  
  154. let lastPath = window.location.pathname;
  155. const checkPath = () => {
  156. if (lastPath !== window.location.pathname) {
  157. lastPath = window.location.pathname;
  158. createOrUpdateSlider();
  159. if (lastPath === '/') {
  160. filterCards();
  161. }
  162. }
  163. };
  164.  
  165. setInterval(checkPath, 500);
  166.  
  167. const observer = new MutationObserver(() => {
  168. if (window.location.pathname === '/') {
  169. setTimeout(filterCards, 500);
  170. }
  171. });
  172. observer.observe(document.body, { childList: true, subtree: true });
  173. } else {
  174. setTimeout(tryInitialize, 1000);
  175. }
  176. };
  177.  
  178. tryInitialize();
  179. })();