1
// ==UserScript==
// @name         Binguru Copy Post
// @namespace    binguru-copy-post
// @version      1.0.0
// @description  Заменяет кнопку "Жалоба" на "Копировать" для быстрого копирования поста в AI
// @match        https://binguru.net/forums/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    // Сразу скрываем текст "Жалоба" через CSS и показываем иконку копирования
    const style = document.createElement('style');
    style.textContent = `
        a[href*="reportPost"] {
            font-size: 0 !important;
            display: inline-block;
            width: 12px;
            height: 12px;
            padding: 4px;
            border-radius: 4px;
            vertical-align: middle;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23775454' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='13' height='13' rx='2' ry='2'/%3E%3Cpath d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/%3E%3C/svg%3E");
            background-size: 12px 12px;
            background-repeat: no-repeat;
            background-position: center;
            box-sizing: content-box;
            transition: background-color 0.2s;
        }
        a[href*="reportPost"]:hover {
            background-color: #775454;
            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='13' height='13' rx='2' ry='2'/%3E%3Cpath d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/%3E%3C/svg%3E");
        }
    `;
    (document.head || document.documentElement).appendChild(style);

    /**
     * Найти элемент с контентом поста
     */
    function getPostContent(container) {
        // Контент: вторая строка таблицы (как в obsidian скрипте)
        const rows = container.querySelectorAll('table.forums > tbody > tr');
        
        if (rows.length >= 2) {
            const cells = rows[1].querySelectorAll('td');
            let best = null;
            let maxLen = 0;
            for (const td of cells) {
                if (td.textContent.length > maxLen) {
                    maxLen = td.textContent.length;
                    best = td;
                }
            }
            if (best) return best;
        }

        // Fallback
        const cells = container.querySelectorAll('td, div.post-content, div.message-body');
        let best = null;
        let bestLen = 0;
        for (const cell of cells) {
            const text = cell.textContent.trim();
            if (/^(Автор|Дата:|#\d)/.test(text)) continue;
            if (text.length > bestLen) {
                bestLen = text.length;
                best = cell;
            }
        }
        return best;
    }

    /**
     * Подготовить контент для копирования
     */
    function prepareContentForCopy(el) {
        const clone = el.cloneNode(true);

        // Удаляем лишнее
        clone.querySelectorAll('script, style, noscript, .likes-container, .like-button-container, .reactions-display, .likes-list, .spoiler-toggle, img').forEach(n => n.remove());

        // Ссылки → markdown
        clone.querySelectorAll('a[href]').forEach(a => {
            const href = a.href;
            const text = a.textContent.trim();
            if (href && text && !href.startsWith('javascript:')) {
                a.replaceWith(`[${text}](${href})`);
            }
        });

        // HTML → текст
        return clone.innerHTML
            .replace(/<br\s*\/?>/gi, '\n')
            .replace(/<\/p>/gi, '\n\n')
            .replace(/<\/div>/gi, '\n')
            .replace(/<[^>]+>/g, '')
            .replace(/&nbsp;/gi, ' ')
            .replace(/&amp;/gi, '&')
            .replace(/&lt;/gi, '<')
            .replace(/&gt;/gi, '>')
            .replace(/&quot;/gi, '"')
            .replace(/\n{3,}/g, '\n\n')
            .trim();
    }

    /**
     * Копировать текст в буфер обмена
     */
    async function copyToClipboard(text) {
        try {
            await navigator.clipboard.writeText(text);
            return true;
        } catch {
            return false;
        }
    }

    /**
     * Показать toast уведомление
     */
    function toast(message, success = true) {
        const el = document.createElement('div');
        el.style.cssText = `
            position: fixed; top: 20px; right: 20px; z-index: 999999;
            background: #1e1e2e; color: ${success ? '#a6e3a1' : '#f38ba8'};
            padding: 12px 18px; border-radius: 8px;
            font: 14px/1.4 system-ui, sans-serif;
            box-shadow: 0 8px 30px rgba(0,0,0,.5);
            border-left: 4px solid ${success ? '#a6e3a1' : '#f38ba8'};
            transform: translateX(120%); transition: transform .3s ease;
        `;
        el.textContent = message;
        document.body.appendChild(el);
        requestAnimationFrame(() => el.style.transform = 'translateX(0)');
        setTimeout(() => {
            el.style.transform = 'translateX(120%)';
            setTimeout(() => el.remove(), 300);
        }, 500);
    }

    /**
     * Обработчик клика — копировать пост
     */
    async function handleCopyClick(e, postContainer) {
        e.preventDefault();
        e.stopPropagation();

        const contentEl = getPostContent(postContainer);
        if (!contentEl) {
            toast('❌ Не удалось найти контент', false);
            return;
        }

        const text = prepareContentForCopy(contentEl);

        const ok = await copyToClipboard(text);
        if (ok) {
            toast('✅ Скопировано');
        } else {
            toast('❌ Ошибка копирования', false);
        }
    }

    /**
     * Заменить кнопки "Жалоба" на "Копировать"
     */
    function replaceFlagButtons() {
        // Ищем ссылки с reportPost в href
        const links = document.querySelectorAll('a[href*="reportPost"]');
        
        for (const link of links) {
            if (link.dataset.bgCopyReplaced) continue;
            link.dataset.bgCopyReplaced = 'true';

            const postContainer = link.closest('.modern-post-container');
            if (!postContainer) continue;

            // Меняем внешний вид (текст уже скрыт через CSS)
            link.title = 'Копировать пост';
            link.style.cursor = 'pointer';

            // Вешаем обработчик
            link.addEventListener('click', (e) => handleCopyClick(e, postContainer), true);
        }
    }

    /**
     * Инициализация
     */
    function init() {
        replaceFlagButtons();

        // Debounced MutationObserver
        let debounceTimer = null;
        const observer = new MutationObserver(() => {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(replaceFlagButtons, 300);
        });
        observer.observe(document.body, { childList: true, subtree: true });

        console.log('[Binguru Copy] ✅ Скрипт загружен');
    }

    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', () => setTimeout(init, 100));
    } else {
        setTimeout(init, 100);
    }

})();

For immediate assistance, please email our customer support: [email protected]

Download RAW File