Копирует текст и медиа. Умное восстановление времени для групп сообщений.
// ==UserScript==
// @name Lolz Chat Message Copier
// @namespace http://tampermonkey.net/
// @version 1.7
// @description Копирует текст и медиа. Умное восстановление времени для групп сообщений.
// @author GodlikeGL
// @match *://lolz.live/*
// @match *://zelenka.guru/*
// @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: #99ff99 !important;
}
/* Делаем восстановленное время чуть прозрачным, чтобы не перегружать интерфейс */
.injected-date {
margin-left: 6px;
opacity: 0.3;
}
.chat2-message:hover .injected-date {
opacity: 1; /* При наведении на сообщение время становится ярким */
}
`);
// --- БЛОК 1: Восстановление пропавшего времени ---
function restoreMissingDates() {
const messageBlocks = document.querySelectorAll('.chat2-message:not(.date-checked)');
messageBlocks.forEach(block => {
block.classList.add('date-checked');
const textContainer = block.querySelector('.chat2-message-text');
if (!textContainer) return;
// Если оригинального времени внутри нет
if (!textContainer.querySelector('.chat2-message-date')) {
let timeText = null;
let titleText = 'Скопировать (восстановлено)';
// Попытка 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: Ищем оригинальное время у соседей по группе
if (!timeText) {
const group = block.closest('.chat2-message-group');
if (group) {
// Ищем дату, которую сгенерировал сам сайт (без класса injected-date)
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;
textContainer.appendChild(dateEl);
}
}
});
}
const observer = new MutationObserver(() => {
restoreMissingDates();
});
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, '&').replace(/</g, '<').replace(/>/g, '>');
plain += text;
} else if (child.nodeType === Node.ELEMENT_NODE) {
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 };
}
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() + ' ';
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);
}
}
}
});
})();