☰

JanitorAI → DataCat FINAL

On JanitorAI: grabs the bot name and opens DataCat. On DataCat: automatically pastes the name into the search bar.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         JanitorAI → DataCat FINAL
// @namespace    janitorai-datacat
// @version      1.2
// @description  On JanitorAI: grabs the bot name and opens DataCat. On DataCat: automatically pastes the name into the search bar.
// @author       You
// @match        *://janitorai.com/*
// @match        *://www.janitorai.com/*
// @match        *://*.janitorai.com/*
// @match        *://datacat.run/*
// @match        *://www.datacat.run/*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const host = location.hostname.toLowerCase();
    const isJanitor = host === 'janitorai.com' || host === 'www.janitorai.com' || host.endsWith('.janitorai.com');
    const isDataCat = host === 'datacat.run' || host === 'www.datacat.run' || host.endsWith('.datacat.run');

    console.log('[JanitorAI → DataCat] Host:', host, '| Janitor:', isJanitor, '| DataCat:', isDataCat);

    /* =========================
       PART 1 — JANITOR AI
    ========================= */
    if (isJanitor) {
        const BUTTON_ID = 'jcc-datacat-button';
        let currentBotName = null;

        function cleanBotName(name) {
            if (!name) return null;
            return name
                .replace(/\s+/g, ' ')
                .replace(/\s*\|\s*JanitorAI.*$/i, '')
                .replace(/\s*-\s*JanitorAI.*$/i, '')
                .trim();
        }

        function findBotName() {
            const title = cleanBotName(document.title);
            if (
                title &&
                title.length > 1 &&
                !/^(janitorai|chat|home|similar characters)$/i.test(title)
            ) {
                return title;
            }

            const headings = document.querySelectorAll('h1, h2, [role="heading"]');
            for (const el of headings) {
                const text = cleanBotName(el.textContent);
                if (!text) continue;
                if (/^(chat|chats|characters|home|settings|search|similar characters|discover characters)$/i.test(text)) continue;
                if (text.length >= 3) return text;
            }
            return null;
        }

        function detectBotName() {
            const name = findBotName();
            if (name && name !== currentBotName) {
                currentBotName = name;
                console.log('[JanitorAI → DataCat] Bot found:', currentBotName);
                updateButton();
            }
            return currentBotName;
        }

        function updateButton() {
            const button = document.getElementById(BUTTON_ID);
            if (!button) return;

            if (currentBotName) {
                button.textContent = 'DataCat';
                button.style.background = '#16a34a';
                button.title = 'Open DataCat with: ' + currentBotName;
            } else {
                button.textContent = 'DataCat: searching...';
                button.style.background = '#6b7280';
                button.title = 'Waiting for bot name...';
            }
        }

        function createButton() {
            if (document.getElementById(BUTTON_ID)) return;
            if (!document.body) return;

            const button = document.createElement('button');
            button.id = BUTTON_ID;
            button.type = 'button';
            button.textContent = 'DataCat: searching...';
            button.style.cssText = `
                position: fixed;
                bottom: 20px;
                right: 20px;
                z-index: 2147483647;
                padding: 10px 16px;
                border: 0;
                border-radius: 8px;
                background: #6b7280;
                color: white;
                font-family: system-ui, -apple-system, sans-serif;
                font-size: 13px;
                font-weight: 700;
                cursor: pointer;
                box-shadow: 0 3px 12px rgba(0,0,0,.35);
            `;

            button.addEventListener('click', function () {
                const botName = detectBotName();
                if (!botName) {
                    alert('Could not find the bot name yet.\nWait for the chat to load and try again.');
                    return;
                }
                const url = 'https://datacat.run/characters/recent#q=' + encodeURIComponent(botName);
                window.open(url, '_blank');
            });

            document.body.appendChild(button);
            console.log('[JanitorAI → DataCat] Button created');
            updateButton();
        }

        // SPA navigation
        let lastUrl = location.href;
        function checkUrlChange() {
            if (location.href === lastUrl) return;
            lastUrl = location.href;
            currentBotName = null;
            updateButton();
            setTimeout(detectBotName, 300);
            setTimeout(detectBotName, 1000);
            setTimeout(detectBotName, 2500);
        }

        const originalPushState = history.pushState;
        history.pushState = function () {
            const result = originalPushState.apply(this, arguments);
            checkUrlChange();
            return result;
        };

        const originalReplaceState = history.replaceState;
        history.replaceState = function () {
            const result = originalReplaceState.apply(this, arguments);
            checkUrlChange();
            return result;
        };

        window.addEventListener('popstate', checkUrlChange);

        const observer = new MutationObserver(function () {
            detectBotName();
            createButton();
        });

        function startJanitor() {
            if (!document.body) {
                setTimeout(startJanitor, 50);
                return;
            }
            createButton();
            observer.observe(document.documentElement, { childList: true, subtree: true });
            setTimeout(detectBotName, 100);
            setTimeout(detectBotName, 500);
            setTimeout(detectBotName, 1000);
            setTimeout(detectBotName, 2000);
            setTimeout(detectBotName, 4000);
        }

        startJanitor();
    }

    /* =========================
       PART 2 — DATACAT
    ========================= */
    if (isDataCat) {
        function getQueryFromHash() {
            const hash = location.hash || '';
            const match = hash.match(/[#&]q=([^&]+)/);
            if (!match) return null;
            try {
                return decodeURIComponent(match[1].replace(/\+/g, ' '));
            } catch (e) {
                return match[1];
            }
        }

        function findSearchInput() {
            const inputs = Array.from(document.querySelectorAll('input'));
            const candidates = inputs.filter(function (el) {
                const ph = (el.placeholder || '').toLowerCase();
                const type = (el.type || '').toLowerCase();
                return type === 'search' || type === 'text' ||
                    ph.indexOf('search') !== -1 ||
                    ph.indexOf('filter') !== -1 ||
                    ph.indexOf('character') !== -1;
            });

            return candidates.find(function (el) {
                const ph = (el.placeholder || '').toLowerCase();
                return ph.indexOf('search') !== -1 || ph.indexOf('character') !== -1;
            }) || candidates[0] || null;
        }

        function setReactValue(input, value) {
            const descriptor = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value');
            if (descriptor && descriptor.set) {
                descriptor.set.call(input, value);
            } else {
                input.value = value;
            }
            input.dispatchEvent(new Event('input', { bubbles: true }));
            input.dispatchEvent(new Event('change', { bubbles: true }));
        }

        function tryPaste() {
            const query = getQueryFromHash();
            if (!query) return true;

            const input = findSearchInput();
            if (!input) return false;

            input.focus();
            setReactValue(input, query);

            ['keydown', 'keypress', 'keyup'].forEach(function (type) {
                input.dispatchEvent(new KeyboardEvent(type, {
                    key: 'Enter',
                    code: 'Enter',
                    keyCode: 13,
                    which: 13,
                    bubbles: true
                }));
            });

            history.replaceState(null, '', location.pathname + location.search);
            console.log('[JanitorAI → DataCat] Pasted into DataCat:', query);
            return true;
        }

        let attempts = 0;
        const interval = setInterval(function () {
            attempts++;
            if (tryPaste() || attempts > 30) {
                clearInterval(interval);
            }
        }, 400);
    }
})();