// ==UserScript== // @name IAI - skrypty - RS (w oknie modalnym) // @namespace http://tampermonkey.net/ // @version 18.5 // @description Skrypty IAI z mechanizmem omijania cache, uruchamiane z nowoczesnego okna modalnego. // @author Radosław Świder & Gemini // @match *://*/panel/* // @exclude *://*/panel/tickets.php* // @connect test.creativetotal.pl // @connect www.iai-system.com // @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-body // ==/UserScript== (function() { 'use strict'; // ============================================================= // ZABEZPIECZENIE PRZED PODWÓJNYM URUCHOMIENIEM // ============================================================= if (window.self !== window.top || window.rsRocketScriptLoaded) { return; } window.rsRocketScriptLoaded = true; // --- KONFIGURACJA GŁÓWNA --- const URL_KONFIGURACJI = 'https://test.creativetotal.pl/skrypty_IAI/skrypty_konfiguracja.json'; const CZAS_RESETOWANIA_PRZYCISKU = 3000; // ============================================================= // CZĘŚĆ 1: KOD OKNA LOGÓW // ============================================================= let oknoLogow = null, trescLogow = null; let czyLogiMajaBycWidoczne = false; function logujNaEkranie(wiadomosc, typ = 'log') { const PALETA_KOLOROW = { tlo: '#2E3440', tloNaglowka: '#434C5E', tekstDomyslny: '#ECEFF4', tekstTimestamp: '#81A1C1', tekstLog: '#D8DEE9', tekstSuccess: '#A3BE8C', tekstWarn: '#EBCB8B', tekstError: '#BF616A', scrollTrack: '#3B4252', scrollThumb: '#4C566A' }; if (!document.getElementById('ladowacz-okno-logow-final-final')) { const scrollbarStyles = ` #ladowacz-okno-logow-final-final div::-webkit-scrollbar { width: 8px; } #ladowacz-okno-logow-final-final div::-webkit-scrollbar-track { background: ${PALETA_KOLOROW.scrollTrack}; border-radius: 4px; } #ladowacz-okno-logow-final-final div::-webkit-scrollbar-thumb { background: ${PALETA_KOLOROW.scrollThumb}; border-radius: 4px; } #ladowacz-okno-logow-final-final div::-webkit-scrollbar-thumb:hover { background: #5E81AC; } `; const styleSheet = document.createElement("style"); styleSheet.innerText = scrollbarStyles; document.head.appendChild(styleSheet); oknoLogow = document.createElement('div'); oknoLogow.id = 'ladowacz-okno-logow-final-final'; oknoLogow.style.cssText = `position: fixed; bottom: 20px; left: 20px; width: 600px; max-width: 90vw; max-height: 400px; background-color: ${PALETA_KOLOROW.tlo}; color: ${PALETA_KOLOROW.tekstDomyslny}; border-radius: 8px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); z-index: 10001; display: none; flex-direction: column; font-family: 'Consolas', 'Menlo', monospace; font-size: 13px; border: 1px solid ${PALETA_KOLOROW.tloNaglowka};`; const naglowek = document.createElement('div'); naglowek.style.cssText = `background-color: ${PALETA_KOLOROW.tloNaglowka}; color: ${PALETA_KOLOROW.tekstDomyslny}; padding: 8px 12px; font-weight: bold; border-top-left-radius: 8px; border-top-right-radius: 8px; display: flex; justify-content: space-between; align-items: center;`; naglowek.innerHTML = 'Logi skryptu'; const przyciskZamknij = document.createElement('button'); przyciskZamknij.innerHTML = '×'; przyciskZamknij.style.cssText = 'background:none; border:none; color:white; font-size:20px; cursor:pointer;'; przyciskZamknij.onclick = () => { oknoLogow.style.display = 'none'; }; naglowek.appendChild(przyciskZamknij); trescLogow = document.createElement('div'); trescLogow.style.cssText = `padding: 10px; overflow-y: auto; flex-grow: 1;`; oknoLogow.appendChild(naglowek); oknoLogow.appendChild(trescLogow); document.body.appendChild(oknoLogow); } else { if (!oknoLogow) oknoLogow = document.getElementById('ladowacz-okno-logow-final-final'); if (!trescLogow) trescLogow = oknoLogow.querySelector('div:last-child'); } if (czyLogiMajaBycWidoczne && oknoLogow.style.display === 'none') { oknoLogow.style.display = 'flex'; } const wpis = document.createElement('div'); const timestamp = new Date().toLocaleTimeString(); let kolorWiadomosci = PALETA_KOLOROW.tekstLog, symbol = '»'; switch (typ) { case 'success': kolorWiadomosci = PALETA_KOLOROW.tekstSuccess; symbol = '✓'; break; case 'warn': kolorWiadomosci = PALETA_KOLOROW.tekstWarn; symbol = '!'; break; case 'error': kolorWiadomosci = PALETA_KOLOROW.tekstError; symbol = '✖'; break; } wpis.innerHTML = `[${timestamp}] ${symbol} ${wiadomosc}`; trescLogow.appendChild(wpis); trescLogow.scrollTop = trescLogow.scrollHeight; } unsafeWindow.TM_logBridge = logujNaEkranie; // ============================================================= // CZĘŚĆ 2: ŁADOWACZ SKRYPTÓW // ============================================================= function ladowacz(url, przycisk) { czyLogiMajaBycWidoczne = true; logujNaEkranie(`Pobieranie: ${url.split('/').pop()}`, 'log'); GM_xmlhttpRequest({ method: "GET", url: url + '?v=' + new Date().getTime(), onload: function(response) { if (response.status >= 200 && response.status < 400) { const originalName = przycisk.getAttribute('data-name'); przycisk.innerHTML = `⚙️ ${originalName} (Uruchomiono)`; przycisk.style.backgroundColor = '#a3e635'; przycisk.style.color = '#3f6212'; przycisk.disabled = true; setTimeout(() => { przycisk.innerHTML = originalName; przycisk.style.backgroundColor = ''; przycisk.style.color = ''; przycisk.disabled = false; logujNaEkranie(`Przycisk "${originalName}" jest ponownie aktywny.`, 'log'); }, CZAS_RESETOWANIA_PRZYCISKU); // --- POCZĄTEK ZMIANY --- // Zmieniamy sposób budowania finalCode, aby uniknąć problemu z zagnieżdżonymi template literals. const finalCode = '(function(oryginalnaKonsola) {\n' + ' const console = {\n' + " log: (...args) => { oryginalnaKonsola.log(...args); unsafeWindow.TM_logBridge(args.join(' '), 'log'); },\n" + " warn: (...args) => { oryginalnaKonsola.warn(...args); unsafeWindow.TM_logBridge(args.join(' '), 'warn'); },\n" + " error: (...args) => { oryginalnaKonsola.error(...args); unsafeWindow.TM_logBridge(args.join(' '), 'error'); }\n" + ' };\n' + ' try {\n' + response.responseText + '\n' + // Wstrzykujemy kod jako czysty tekst ' } catch (e) { console.error("BŁĄD KRYTYCZNY W SKRYPCIE: ", e.message, e.stack); }\n' + '})(window.console);'; // --- KONIEC ZMIANY --- try { eval(finalCode); logujNaEkranie(`Pomyślnie wstrzyknięto i uruchomiono: ${url.split('/').pop()}`, 'success'); } catch (e) { logujNaEkranie(`Błąd wykonania wstrzykniętego skryptu: ${e.message}`, 'error'); console.error(e); } } else { logujNaEkranie(`Błąd pobierania skryptu. Status: ${response.status}`, 'error'); } }, onerror: function() { logujNaEkranie(`Błąd sieciowy podczas pobierania skryptu.`, 'error'); } }); } // ============================================================= // CZĘŚĆ 3: INTERFEJS UŻYTKOWNIKA (OKNO MODALNE) // ============================================================= function stworzInterfejsUzytkownika(listaSkryptow) { const styles = ` /* === NOWA ANIMACJA PULSOWANIA === */ /* Usunięto animację pulsowania, ponieważ nie jest już potrzebna */ #rs-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); z-index: 10000; display: none; justify-content: center; align-items: center; backdrop-filter: blur(4px); } #rs-modal-container { background-color: #f8f9fa; color: #212529; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); width: 90%; max-width: 500px; display: flex; flex-direction: column; max-height: 90vh; transition: transform 0.3s ease, opacity 0.3s ease; transform: scale(0.95); opacity: 0; } #rs-modal-overlay.visible #rs-modal-container { transform: scale(1); opacity: 1; } #rs-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; border-bottom: 1px solid #dee2e6; } #rs-modal-header h2 { margin: 0; font-size: 1.25rem; font-weight: 600; color: #343a40; } #rs-modal-close { background: none; border: none; font-size: 2rem; color: #6c757d; cursor: pointer; line-height: 1; padding: 0; } #rs-modal-close:hover { color: #212529; } #rs-modal-content { padding: 24px; overflow-y: auto; flex-grow: 1; } .rs-script-button { flex-grow: 1; padding: 12px 18px; background-color: #ffffff; color: #333; border: 1px solid #ced4da; cursor: pointer; text-align: left; font-size: 16px; border-radius: 8px; transition: all 0.2s ease; border-top-right-radius: 0; border-bottom-right-radius: 0; } .rs-script-button:not(:disabled):hover { background-color: #e9ecef; border-color: #b1bdc6; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.05); } .rs-script-button:disabled { cursor: not-allowed; } .rs-script-item { display: flex; margin-bottom: 10px; align-items: stretch; } .rs-info-icon { display: flex; align-items: center; justify-content: center; padding: 0 15px; background-color: #6c757d; color: white; border: 1px solid #6c757d; border-left: none; border-top-right-radius: 8px; border-bottom-right-radius: 8px; cursor: pointer; font-family: 'Georgia', serif; font-weight: bold; font-style: italic; font-size: 18px; } #rs-modal-footer { padding: 16px 24px; border-top: 1px solid #dee2e6; background-color: #f1f3f5; text-align: center; font-size: 0.85rem; color: #495057; border-bottom-left-radius: 12px; border-bottom-right-radius: 12px; flex-shrink: 0; } /* === NOWY, DYSKRETNY STYL DLA PRZYCISKU W STOPCE === */ .rs-footer-button { display: inline-block; text-decoration: none; background: linear-gradient(to bottom, #d1d1d1, #e0e0e0); color: #495057; padding: 6px 12px; border-radius: 5px; margin-top: 8px; transition: all 0.2s ease; font-size: 13px; font-weight: 400; border: 1px solid #dee2e6; } .rs-footer-button:hover { background: linear-gradient(to bottom, #e9ecef, #dee2e6); border-color: #ced4da; transform: translateY(-1px); color: #212529; } #rs-global-tooltip { position: fixed; visibility: hidden; opacity: 0; width: 280px; background-color: #343a40; color: #fff; text-align: left; border-radius: 6px; padding: 10px; z-index: 10002; transition: opacity 0.2s; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 13px; white-space: pre-wrap; pointer-events: none; box-shadow: 0 4px 12px rgba(0,0,0,0.3); } #rs-global-tooltip::after { content: ""; position: absolute; left: 50%; top: 100%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #343a40 transparent transparent transparent; } /* Usunięto style dla rs-ticket-badge */ `; const styleSheet = document.createElement("style"); styleSheet.innerText = styles; document.head.appendChild(styleSheet); const launcher = document.createElement('div'); launcher.id = 'rs-modal-launcher'; launcher.innerHTML = '🚀'; launcher.style.cssText = `position: fixed; top: 50%; right: 20px; transform: translateY(-50%); z-index: 9999; width: 50px; height: 50px; background-color: #007bff; color: white; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; border-radius: 50%; box-shadow: 0 4px 12px rgba(0,0,0,0.2); transition: transform 0.2s ease, background-color 0.2s ease;`; launcher.onmouseover = () => { launcher.style.transform = 'translateY(-50%) scale(1.1)'; }; launcher.onmouseout = () => { launcher.style.transform = 'translateY(-50%) scale(1)'; }; // Usunięto tworzenie elementu ticketBadge // const ticketBadge = document.createElement('div'); // ticketBadge.id = 'rs-ticket-badge'; // launcher.appendChild(ticketBadge); const overlay = document.createElement('div'); overlay.id = 'rs-modal-overlay'; const modal = document.createElement('div'); modal.id = 'rs-modal-container'; const header = document.createElement('div'); header.id = 'rs-modal-header'; header.innerHTML = `
👇 Link do aktualnej bazy skryptów oraz aktualnej wersji rakietki 👇
Otwórz katalog z plikami🚀 OTS RAKIETA v3 🚀
`; const globalTooltip = document.createElement('div'); globalTooltip.id = 'rs-global-tooltip'; document.body.appendChild(globalTooltip); listaSkryptow.forEach(skrypt => { const scriptItemContainer = document.createElement('div'); scriptItemContainer.className = 'rs-script-item'; const przyciskSkryptu = document.createElement('button'); przyciskSkryptu.innerHTML = skrypt.name; przyciskSkryptu.className = 'rs-script-button'; przyciskSkryptu.setAttribute('data-name', skrypt.name); przyciskSkryptu.onclick = () => ladowacz(skrypt.url, przyciskSkryptu); scriptItemContainer.appendChild(przyciskSkryptu); if (skrypt.description) { const infoIcon = document.createElement('div'); infoIcon.className = 'rs-info-icon'; infoIcon.textContent = 'i'; infoIcon.setAttribute('data-description', skrypt.description); infoIcon.addEventListener('mouseenter', (e) => { const icon = e.currentTarget, desc = icon.getAttribute('data-description'), iconRect = icon.getBoundingClientRect(); globalTooltip.textContent = desc; globalTooltip.style.visibility = 'visible'; globalTooltip.style.opacity = '1'; const topPos = iconRect.top - globalTooltip.offsetHeight - 10; let leftPos = iconRect.left + (iconRect.width / 2) - (globalTooltip.offsetWidth / 2); if (leftPos < 10) leftPos = 10; if (leftPos + globalTooltip.offsetWidth > window.innerWidth - 10) leftPos = window.innerWidth - globalTooltip.offsetWidth - 10; globalTooltip.style.top = `${topPos}px`; globalTooltip.style.left = `${leftPos}px`; }); infoIcon.addEventListener('mouseleave', () => { globalTooltip.style.visibility = 'hidden'; globalTooltip.style.opacity = '0'; }); scriptItemContainer.appendChild(infoIcon); } content.appendChild(scriptItemContainer); }); modal.appendChild(header); modal.appendChild(content); modal.appendChild(footer); overlay.appendChild(modal); document.body.appendChild(launcher); document.body.appendChild(overlay); const openModal = () => { overlay.style.display = 'flex'; setTimeout(() => overlay.classList.add('visible'), 10); }; const closeModal = () => { overlay.classList.remove('visible'); setTimeout(() => { overlay.style.display = 'none'; globalTooltip.style.visibility = 'hidden'; globalTooltip.style.opacity = '0'; }, 300); }; launcher.addEventListener('click', openModal); closeButton.addEventListener('click', closeModal); overlay.addEventListener('click', (e) => { if (e.target === overlay) closeModal(); }); window.addEventListener('keydown', (e) => { if (e.key === 'Escape' && overlay.style.display === 'flex') closeModal(); }); } // ============================================================= // CZĘŚĆ 4: Usunięto MODUŁ POWIADOMIEŃ O TICKETACH // ============================================================= // ============================================================= // CZĘŚĆ 5: POBIERANIE KONFIGURACJI I START // ============================================================= GM_xmlhttpRequest({ method: "GET", url: URL_KONFIGURACJI + '?v=' + new Date().getTime(), onload: (response) => { if (response.status >= 200 && response.status < 400) { try { logujNaEkranie("Pobrano świeżą konfigurację, tworzenie interfejsu...", 'success'); stworzInterfejsUzytkownika(JSON.parse(response.responseText)); // Usunięto uruchomienie modułu sprawdzania ticketów } catch (e) { logujNaEkranie("Błąd parsowania pliku konfiguracyjnego JSON.", "error"); console.error("Błąd pliku konfiguracyjnego JSON. Proszę sprawdzić jego poprawność.", e); } } else { logujNaEkranie(`Błąd pobierania konfiguracji. Status: ${response.status}`, 'error'); } }, onerror: (response) => { logujNaEkranie(`Krytyczny błąd sieciowy podczas pobierania konfiguracji.`, 'error'); } }); })();