SoulfateOriginal

Mammouth.AI UserScript

Aug 1st, 2025
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 12.20 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name                Mammouth.ai Ultimate Lazy Loader + Network Optimizer
  3. // @namespace           chartreus_ultimate_loader
  4. // @version             3.0
  5. // @description         Lazy load + interception réseau pour ne charger QUE les 120 derniers messages
  6. // @author              Chartreus (Claude Sonnet 4)
  7. // @match               https://mammouth.ai/app/a/*
  8. // @grant               none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12.     'use strict';
  13.  
  14.     // 🎯 Config optimisée
  15.     const LAZY_CONFIG = {
  16.         DISPLAY_LIMIT: 120,
  17.         BATCH_SIZE: 15,
  18.         SCROLL_THRESHOLD: 150,
  19.         CACHE_KEY: 'mammouth_messages',
  20.         DEBOUNCE_DELAY: 250,
  21.         MAX_NETWORK_MESSAGES: 120
  22.     };
  23.  
  24.     let currentConversationId = null;
  25.     let lazyLoaderInstance = null;
  26.     let originalFetch = null;
  27.     let networkInterceptionActive = false;
  28.  
  29.     // 🌐 Intercepteur réseau ultime
  30.     function setupNetworkInterception() {
  31.         if (networkInterceptionActive) return;
  32.         networkInterceptionActive = true;
  33.  
  34.         // Sauvegarde de la fonction fetch originale
  35.         originalFetch = window.fetch;
  36.  
  37.         // Interception de fetch
  38.         window.fetch = async function(...args) {
  39.             const [url, options] = args;
  40.  
  41.             // Détection des requêtes de messages
  42.             if (typeof url === 'string' && (
  43.                 url.includes('/messages') ||
  44.                 url.includes('/conversation') ||
  45.                 url.includes('/history') ||
  46.                 url.includes('/chat')
  47.             )) {
  48.                 console.log('🕵️ Intercepting message request:', url);
  49.  
  50.                 // Modification de la requête pour limiter les résultats
  51.                 let modifiedUrl = url;
  52.                 let modifiedOptions = {...options};
  53.  
  54.                 // Si c'est une requête GET, ajouter des paramètres de limite
  55.                 if (!options?.method || options.method === 'GET') {
  56.                     const urlObj = new URL(url, window.location.origin);
  57.                     urlObj.searchParams.set('limit', LAZY_CONFIG.MAX_NETWORK_MESSAGES);
  58.                     urlObj.searchParams.set('recent', 'true');
  59.                     modifiedUrl = urlObj.toString();
  60.                 }
  61.  
  62.                 // Si c'est une requête POST avec un body JSON
  63.                 if (options?.body && options?.method === 'POST') {
  64.                     try {
  65.                         const bodyData = JSON.parse(options.body);
  66.                         if (bodyData) {
  67.                             bodyData.limit = LAZY_CONFIG.MAX_NETWORK_MESSAGES;
  68.                             bodyData.recent = true;
  69.                             bodyData.maxMessages = LAZY_CONFIG.MAX_NETWORK_MESSAGES;
  70.                             modifiedOptions.body = JSON.stringify(bodyData);
  71.                         }
  72.                     } catch (e) {
  73.                         console.log('📝 Could not modify POST body, proceeding with original');
  74.                     }
  75.                 }
  76.  
  77.                 console.log('🚀 Modified request URL:', modifiedUrl);
  78.                 return originalFetch(modifiedUrl, modifiedOptions);
  79.             }
  80.  
  81.             // Pour toutes les autres requêtes, utiliser fetch original
  82.             return originalFetch(...args);
  83.         };
  84.  
  85.         // Interception de XMLHttpRequest aussi
  86.         const originalXHROpen = XMLHttpRequest.prototype.open;
  87.         XMLHttpRequest.prototype.open = function(method, url, ...args) {
  88.             if (typeof url === 'string' && (
  89.                 url.includes('/messages') ||
  90.                 url.includes('/conversation') ||
  91.                 url.includes('/history') ||
  92.                 url.includes('/chat')
  93.             )) {
  94.                 console.log('🕵️ Intercepting XHR request:', url);
  95.  
  96.                 const urlObj = new URL(url, window.location.origin);
  97.                 urlObj.searchParams.set('limit', LAZY_CONFIG.MAX_NETWORK_MESSAGES);
  98.                 urlObj.searchParams.set('recent', 'true');
  99.                 url = urlObj.toString();
  100.  
  101.                 console.log('🚀 Modified XHR URL:', url);
  102.             }
  103.  
  104.             return originalXHROpen.call(this, method, url, ...args);
  105.         };
  106.  
  107.         console.log('🌐 Network interception setup complete!');
  108.     }
  109.  
  110.     // 🛡️ Observateur DOM pour limiter les messages affichés
  111.     function setupDOMMessageLimiter() {
  112.         const messageObserver = new MutationObserver((mutations) => {
  113.             mutations.forEach((mutation) => {
  114.                 if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  115.                     setTimeout(() => limitDisplayedMessages(), 100);
  116.                 }
  117.             });
  118.         });
  119.  
  120.         messageObserver.observe(document.body, {
  121.             childList: true,
  122.             subtree: true
  123.         });
  124.  
  125.         console.log('👁️ DOM message limiter active!');
  126.     }
  127.  
  128.     function limitDisplayedMessages() {
  129.         const allMessages = document.querySelectorAll('[data-index]');
  130.  
  131.         if (allMessages.length > LAZY_CONFIG.DISPLAY_LIMIT) {
  132.             console.log(`✂️ Limiting messages: ${allMessages.length} -> ${LAZY_CONFIG.DISPLAY_LIMIT}`);
  133.  
  134.             const messagesToHide = Array.from(allMessages).slice(0, allMessages.length - LAZY_CONFIG.DISPLAY_LIMIT);
  135.  
  136.             messagesToHide.forEach((msg, index) => {
  137.                 if (!msg.hasAttribute('data-hidden-by-optimizer')) {
  138.                     replaceWithOptimizedPlaceholder(msg, index);
  139.                 }
  140.             });
  141.  
  142.             // Créer un méga-placeholder pour les messages cachés
  143.             if (messagesToHide.length > 0) {
  144.                 createNetworkOptimizedPlaceholder(messagesToHide.length);
  145.             }
  146.         }
  147.     }
  148.  
  149.     function replaceWithOptimizedPlaceholder(msg, index) {
  150.         const placeholder = document.createElement('div');
  151.         placeholder.setAttribute('data-hidden-by-optimizer', 'true');
  152.         placeholder.setAttribute('data-network-placeholder', index);
  153.  
  154.         placeholder.style.cssText = `
  155.             height: 15px;
  156.             width: 100%;
  157.             max-width: 100%;
  158.             opacity: 0;
  159.             pointer-events: none;
  160.             position: relative;
  161.             display: block;
  162.             box-sizing: border-box;
  163.             overflow: hidden;
  164.             margin: 0;
  165.             padding: 0;
  166.         `;
  167.  
  168.         msg.parentNode.insertBefore(placeholder, msg);
  169.         msg.remove();
  170.     }
  171.  
  172.     function createNetworkOptimizedPlaceholder(hiddenCount) {
  173.         // Supprimer l'ancien placeholder s'il existe
  174.         const existingPlaceholder = document.querySelector('.network-optimized-placeholder');
  175.         if (existingPlaceholder) {
  176.             existingPlaceholder.remove();
  177.         }
  178.  
  179.         const megaPlaceholder = document.createElement('div');
  180.         megaPlaceholder.className = 'network-optimized-placeholder';
  181.         megaPlaceholder.style.cssText = `
  182.             background: linear-gradient(135deg, #0f172a, #1e293b, #334155);
  183.             border: 2px dashed #22d3ee;
  184.             border-radius: 16px;
  185.             padding: 32px;
  186.             margin: 20px 0;
  187.             text-align: center;
  188.             color: #e2e8f0;
  189.             font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  190.             position: relative;
  191.             overflow: hidden;
  192.             cursor: pointer;
  193.             transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  194.             max-width: 100%;
  195.             box-sizing: border-box;
  196.             width: 100%;
  197.             display: block;
  198.             box-shadow: 0 10px 40px rgba(34, 211, 238, 0.1);
  199.         `;
  200.  
  201.         megaPlaceholder.innerHTML = `
  202.             <div style="font-size: 2.5rem; margin-bottom: 16px; animation: pulse 2s infinite;">🚀💨</div>
  203.             <div style="font-size: 1.4rem; font-weight: 700; margin-bottom: 12px; color: #22d3ee;">
  204.                 ${hiddenCount} messages optimisés (non chargés)
  205.             </div>
  206.             <div style="font-size: 1rem; opacity: 0.9; margin-bottom: 20px; line-height: 1.5;">
  207.                 <div>⚡ Requêtes réseau limitées à ${LAZY_CONFIG.MAX_NETWORK_MESSAGES} messages</div>
  208.                 <div style="margin-top: 8px;">💾 Mémoire économisée • Performance maximale</div>
  209.             </div>
  210.             <div style="font-size: 0.9rem; padding: 12px 20px; background: rgba(34, 211, 238, 0.15); border: 1px solid rgba(34, 211, 238, 0.3); border-radius: 8px; display: inline-block;">
  211.                 💡 Messages anciens non chargés pour optimiser les performances
  212.             </div>
  213.             <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, transparent 30%, rgba(34, 211, 238, 0.05) 50%, transparent 70%); animation: shimmer 3s infinite;"></div>
  214.         `;
  215.  
  216.         // Ajouter les animations CSS
  217.         const style = document.createElement('style');
  218.         style.textContent = `
  219.             @keyframes pulse {
  220.                 0%, 100% { transform: scale(1); opacity: 1; }
  221.                 50% { transform: scale(1.1); opacity: 0.8; }
  222.             }
  223.             @keyframes shimmer {
  224.                 0% { transform: translateX(-100%); }
  225.                 100% { transform: translateX(100%); }
  226.             }
  227.         `;
  228.         document.head.appendChild(style);
  229.  
  230.         megaPlaceholder.addEventListener('mouseenter', () => {
  231.             megaPlaceholder.style.transform = 'scale(1.02) translateY(-2px)';
  232.             megaPlaceholder.style.borderColor = '#06b6d4';
  233.             megaPlaceholder.style.boxShadow = '0 20px 60px rgba(34, 211, 238, 0.2)';
  234.         });
  235.  
  236.         megaPlaceholder.addEventListener('mouseleave', () => {
  237.             megaPlaceholder.style.transform = 'scale(1) translateY(0)';
  238.             megaPlaceholder.style.borderColor = '#22d3ee';
  239.             megaPlaceholder.style.boxShadow = '0 10px 40px rgba(34, 211, 238, 0.1)';
  240.         });
  241.  
  242.         const firstVisibleMessage = document.querySelector('[data-index]:not([data-hidden-by-optimizer])');
  243.         if (firstVisibleMessage) {
  244.             firstVisibleMessage.parentNode.insertBefore(megaPlaceholder, firstVisibleMessage);
  245.         }
  246.     }
  247.  
  248.     // [Garde la classe UltimateMammouthLoader originale mais simplifiée]
  249.     class UltimateMammouthLoader {
  250.         constructor() {
  251.             this.messagesContainer = null;
  252.             this.isInitialized = false;
  253.             this.initWhenReady();
  254.         }
  255.  
  256.         initWhenReady() {
  257.             const checkReady = () => {
  258.                 const messages = document.querySelectorAll('[data-index]');
  259.                 if (messages.length > 0 && !this.isInitialized) {
  260.                     console.log(`📊 Found ${messages.length} messages, checking if limitation needed...`);
  261.                     setTimeout(() => limitDisplayedMessages(), 500);
  262.                     this.isInitialized = true;
  263.                 } else if (messages.length === 0) {
  264.                     setTimeout(checkReady, 1000);
  265.                 }
  266.             };
  267.             checkReady();
  268.         }
  269.     }
  270.  
  271.     // [Garde les fonctions d'enhancement identiques...]
  272.     function enhanceMammothAI() {
  273.         const textarea = document.querySelector('textarea[placeholder="Posez votre question"]');
  274.         if (textarea && !textarea.hasAttribute('data-enhanced')) {
  275.             textarea.maxLength = 199900;
  276.             textarea.setAttribute('data-enhanced', 'true');
  277.  
  278.             ['input', 'focus', 'click', 'keydown'].forEach(eventType => {
  279.                 textarea.addEventListener(eventType, function() {
  280.                     if (this.value && !this.value.startsWith('[')) {
  281.                         const now = new Date();
  282.                         const timestamp = `[${now.toLocaleString('fr-FR')}] `;
  283.                         this.value = timestamp + this.value;
  284.                         this.setSelectionRange(this.value.length, this.value.length);
  285.                     }
  286.                 });
  287.             });
  288.         }
  289.  
  290.         // [Garde le reste de la fonction identique...]
  291.         const messageContents = document.querySelectorAll('[data-index] div[class*="message_content"]:not([data-timestamped])');
  292.         messageContents.forEach(content => {
  293.             if (content.closest('[data-index]') && content.querySelector('p strong')) {
  294.                 const timestamp = document.createElement('div');
  295.                 timestamp.className = 'text-xs text-gray-500 mb-2 font-mono';
  296.                 timestamp.style.cssText = 'opacity: 0.7; border-left: 2px solid #10b981; padding-left: 8px;';
  297.                 timestamp.textContent = `📅 ${new Date().toLocaleString('fr-FR')}`;
  298.                 content.insertBefore(timestamp, content.firstChild);
  299.                 content.setAttribute('data-timestamped', 'true');
  300.             }
  301.         });
  302.  
  303.         const copyButtons = document.querySelectorAll('.copy-button-2le1:not([data-enhanced])');
  304.         copyButtons.forEach(btn => {
  305.             btn.setAttribute('data-enhanced', 'true');
  306.             btn.addEventListener('click', () => {
  307.                 btn.style.backgroundColor = '#10b981';
  308.                 btn.style.transform = 'scale(0.95)';
  309.                 setTimeout(() => {
  310.                     btn.style.backgroundColor = '';
  311.                     btn.style.transform = '';
  312.                 }, 200);
  313.             });
  314.         });
  315.     }
  316.  
  317.     function initialize() {
  318.         console.log('🚀 Ultimate Network-Optimized Mammouth Loader starting...');
  319.  
  320.         // 🆕 Démarrer l'interception réseau AVANT tout le reste
  321.         setupNetworkInterception();
  322.         setupDOMMessageLimiter();
  323.  
  324.         setTimeout(() => {
  325.             lazyLoaderInstance = new UltimateMammouthLoader();
  326.         }, 1000);
  327.  
  328.         // Setup watchers
  329.         let lastUrl = window.location.href;
  330.         const observer = new MutationObserver(() => {
  331.             const currentUrl = window.location.href;
  332.             if (currentUrl !== lastUrl) {
  333.                 lastUrl = currentUrl;
  334.                 console.log(`🌐 Conversation changed: ${currentUrl}`);
  335.                 setTimeout(() => {
  336.                     lazyLoaderInstance = new UltimateMammouthLoader();
  337.                 }, 1000);
  338.             }
  339.         });
  340.  
  341.         observer.observe(document.body, { childList: true, subtree: true });
  342.  
  343.         const enhanceObserver = new MutationObserver(() => {
  344.             enhanceMammothAI();
  345.         });
  346.  
  347.         enhanceObserver.observe(document.body, { childList: true, subtree: true });
  348.  
  349.         // Lancer les améliorations
  350.         setTimeout(enhanceMammothAI, 750);
  351.         setTimeout(enhanceMammothAI, 2250);
  352.         setTimeout(enhanceMammothAI, 4500);
  353.     }
  354.  
  355.     // Démarrage ultra-précoce pour intercepter les requêtes
  356.     if (document.readyState === 'loading') {
  357.         setupNetworkInterception();
  358.         document.addEventListener('DOMContentLoaded', initialize);
  359.     } else {
  360.         initialize();
  361.     }
  362.  
  363.     console.log('🌐⚡ Network-Optimized Mammouth Loader ready!');
  364. })();
  365.  
Advertisement
Add Comment
Please, Sign In to add comment