MilkyWay Idle - Infinite Chat History

Almost Infinite Chat History

// ==UserScript==
// @name         MilkyWay Idle - Infinite Chat History
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Almost Infinite Chat History
// @author       SilkyPanda
// @license      CC-BY-NC-SA-4.0
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==

(function() {
    'use-strict';

    const CHAT_HISTORY_SELECTOR = '[class^="ChatHistory_chatHistory"]';
    const LOCAL_STORAGE_KEY = 'mwi-persistent-chat-log-v1';
    const MAX_LOG_SIZE = 2000;
    const MAX_MESSAGES_IN_DOM = 1000;
    const patchedChatContainers = new Set();
    let messageLogs = {};

    function loadMessagesFromStorage() {
        const savedData = localStorage.getItem(LOCAL_STORAGE_KEY);
        try {
            return savedData ? JSON.parse(savedData) : {};
        } catch (e) {
            console.error('[MWI Infinite Chat] Could not parse saved log, starting fresh.', e);
            return {};
        }
    }

    function saveMessagesToStorage() {
        try {
            localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(messageLogs));
        } catch (e) {
            console.error('[MWI Infinite Chat] An error occurred while saving the log:', e);
        }
    }

    const originalRemoveChild = Node.prototype.removeChild;
    const originalAppendChild = Node.prototype.appendChild;

    Node.prototype.removeChild = function(child) {
        if (patchedChatContainers.has(this)) {
            return child;
        }
        return originalRemoveChild.apply(this, arguments);
    };

    Node.prototype.appendChild = function(child) {
        const result = originalAppendChild.apply(this, arguments);
        if (patchedChatContainers.has(this) && child.nodeType === 1) {
            const containerIndex = this.dataset.mwiChatIndex;
            if (messageLogs[containerIndex]) {
                const html = child.outerHTML;
                const lastMessage = messageLogs[containerIndex][messageLogs[containerIndex].length - 1];
                if (html !== lastMessage) {
                    messageLogs[containerIndex].push(html);
                    if (messageLogs[containerIndex].length > MAX_LOG_SIZE) {
                        messageLogs[containerIndex] = messageLogs[containerIndex].slice(-MAX_LOG_SIZE);
                    }
                    saveMessagesToStorage();
                }
            }
        }
        return result;
    };


    const cappingObserver = new MutationObserver(mutations => {
        for (const mutation of mutations) {
            if (mutation.addedNodes.length > 0) {
                const container = mutation.target;
                while (container.children.length > MAX_MESSAGES_IN_DOM) {
                    originalRemoveChild.call(container, container.firstChild);
                }
            }
        }
    });


    function initialize() {
        messageLogs = loadMessagesFromStorage();

        const appObserver = new MutationObserver(() => {
            const chatContainers = document.querySelectorAll(CHAT_HISTORY_SELECTOR);
            if (chatContainers.length > 0) {
                chatContainers.forEach((container, index) => {
                    if (container.dataset.mwiInitialized) return;
                    container.dataset.mwiInitialized = 'true';
                    container.dataset.mwiChatIndex = index;

                    console.log(`[MWI Infinite Chat] Initializing container for channel ${index}`);

                    if (!messageLogs[index]) {
                        messageLogs[index] = [];
                    }

                    const savedLogHTML = messageLogs[index].join('');
                    if (savedLogHTML) {
                        container.insertAdjacentHTML('afterbegin', savedLogHTML);
                    }

                    patchedChatContainers.add(container);
                    cappingObserver.observe(container, { childList: true });
                });
            }
        });

        appObserver.observe(document.body, { childList: true, subtree: true });
        console.log('[MWI Infinite Chat] Persistent logger active. Waiting for chat containers...');
    }

    GM_registerMenuCommand('Clear Saved Chat History', () => {
        if (confirm('Are you sure you want to permanently delete all saved chat history for MilkyWay Idle?')) {
            localStorage.removeItem(LOCAL_STORAGE_KEY);
            alert('Saved chat history has been cleared. Please reload the page to start fresh.');
        }
    });

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }

})();