Lolz Chat Message Copier

Копирует текст, медиа и пинги (@ник). Мгновенно восстанавливает время.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Lolz Chat Message Copier
// @namespace    http://tampermonkey.net/
// @version      1.8
// @description  Копирует текст, медиа и пинги (@ник). Мгновенно восстанавливает время.
// @author       GodlikeGL
// @match        *://lolz.live/*
// @match        *://lzt.market/*
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Стили
    GM_addStyle(`
        .chat2-message-date {
            cursor: pointer !important;
            transition: color 0.2s ease, opacity 0.2s ease;
        }
        .chat2-message-date:hover {
            color: #12BDE3 !important;
        }
        .injected-date {
            margin-left: 6px;
            opacity: 0.3;
        }
        .chat2-message:hover .injected-date {
            opacity: 1;
        }
    `);

    // --- БЛОК 1: Восстановление времени (Оптимизированное) ---
    function restoreMissingDates() {
        // Ищем все контейнеры текста сообщений
        const textContainers = document.querySelectorAll('.chat2-message-text');

        textContainers.forEach(container => {
            // Если внутри контейнера нет времени (ни оригинального, ни нашего)
            if (!container.querySelector('.chat2-message-date')) {
                let timeText = null;
                let titleText = 'Скопировать (восстановлено)';

                const block = container.closest('.chat2-message');
                if (!block) return;

                // 1. Пробуем достать из data-info
                const infoStr = block.getAttribute('data-info');
                if (infoStr) {
                    try {
                        const info = JSON.parse(infoStr);
                        if (info && info.time) {
                            const date = new Date(info.time);
                            const hours = String(date.getHours()).padStart(2, '0');
                            const minutes = String(date.getMinutes()).padStart(2, '0');
                            timeText = `${hours}:${minutes}`;
                        }
                    } catch (e) {}
                }

                // 2. Если нет data-info, берем время у последнего сообщения в этой же группе
                if (!timeText) {
                    const group = block.closest('.chat2-message-group');
                    if (group) {
                        const existingDate = group.querySelector('.chat2-message-date:not(.injected-date)');
                        if (existingDate) {
                            timeText = existingDate.innerText;
                            titleText = existingDate.getAttribute('title') || titleText;
                        }
                    }
                }

                // Вставляем время
                if (timeText) {
                    const dateEl = document.createElement('span');
                    dateEl.className = 'chat2-message-date lztng-133npr8 chat2-message-date-muted injected-date';
                    dateEl.title = titleText;
                    dateEl.innerText = timeText;
                    container.appendChild(dateEl);
                }
            }
        });
    }

    // Используем таймер (debounce) для MutationObserver, чтобы не вызывать функцию 100 раз при рендере
    let dateTimeout;
    const observer = new MutationObserver(() => {
        clearTimeout(dateTimeout);
        dateTimeout = setTimeout(restoreMissingDates, 100);
    });
    observer.observe(document.body, { childList: true, subtree: true });
    restoreMissingDates();


    // --- БЛОК 2: Улучшенный парсер с поддержкой пингов ---
    function parseContent(node) {
        let html = '';
        let plain = '';

        for (let child of node.childNodes) {
            if (child.nodeType === Node.TEXT_NODE) {
                const text = child.textContent;
                html += text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                plain += text;
            } else if (child.nodeType === Node.ELEMENT_NODE) {

                // === НОВОЕ: Обработка пингов пользователя ===
                if (child.tagName === 'A' && child.classList.contains('mention')) {
                    // Вытаскиваем только текст никнейма, игнорируя картинку аватарки внутри
                    const username = child.textContent.trim();
                    // Добавляем @ перед ником (и пробел после, чтобы текст не слипался)
                    html += '@' + username + '&nbsp;';
                    plain += '@' + username + ' ';
                }
                // ============================================

                else if (child.classList.contains('mceSmilie')) {
                    const alt = child.alt || '';
                    html += alt;
                    plain += alt;
                } else if (child.classList.contains('media-embedded') || child.tagName === 'IMG') {
                    const img = child.tagName === 'IMG' ? child : child.querySelector('img');
                    if (img && img.src) {
                        html += `<img src="${img.src}">`;
                        plain += `[URL]${img.src}[/URL]`;
                    }
                } else if (child.tagName === 'BR') {
                    html += '<br>';
                    plain += '\n';
                } else if (child.tagName === 'P') {
                    const inner = parseContent(child);
                    html += '<p>' + inner.html + '</p>';
                    plain += inner.plain + '\n';
                } else {
                    const inner = parseContent(child);
                    html += inner.html;
                    plain += inner.plain;
                }
            }
        }
        return { html, plain };
    }

    // --- БЛОК 3: Обработчик клика ---
    document.addEventListener('click', function(e) {
        const timeElement = e.target.closest('.chat2-message-date');

        if (timeElement) {
            e.preventDefault();
            e.stopPropagation();

            const textContainer = timeElement.parentElement.querySelector('.chat2-message-text-inner');

            if (textContainer) {
                const content = parseContent(textContainer);
                const finalHtml = content.html.trim() + '&nbsp;';
                const finalPlain = content.plain.trim() + ' ';

                const inputField = document.querySelector('.tiptap.ProseMirror[contenteditable="true"]');

                if (inputField) {
                    inputField.focus();

                    const dataTransfer = new DataTransfer();
                    dataTransfer.setData('text/html', finalHtml);
                    dataTransfer.setData('text/plain', finalPlain);

                    const pasteEvent = new ClipboardEvent('paste', {
                        clipboardData: dataTransfer,
                        bubbles: true,
                        cancelable: true
                    });

                    inputField.dispatchEvent(pasteEvent);
                }
            }
        }
    });
})();