Greasy Fork

Greasy Fork is available in English.

4PDA Logo

Замена логотипа в посте

当前为 2025-11-15 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         4PDA Logo 
// @namespace    http://4pda.to/forum/index.php
// @version      4.1
// @description  Замена логотипа в посте 
// @author       BrantX
// @match        http*://4pda.to/forum/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    console.log('Logo Replacer v4.1 LOADED');

    // База логотипов
    const LOGOS = [
        { url: 'https://4pda.to/s/HL5V5qDA1xLMwNxwm561PwRaFF6TOoR9wwZ.png', description: 'AICP' },
         { url: 'https://4pda.to/s/HL5V1GHLxxp1z1TgHPZRKOvz0Rlz2z1H61bgCj7.png', description: 'AICP_2' },
        { url: 'https://4pda.to/s/HL5V6p1Ko5MmbdZ6sAUz0z25RaFFcDmsHOneE.png', description: 'AlphaDroid_2' },
        { url: 'https://4pda.to/s/HL5V7m7RgvmFbd3skM8Q33KypfPDmsnefKe.png', description: 'AlphaDroid' },
        { url: 'https://4pda.to/s/HL5VEdX4wHqbaab9ksu2VLJGz0IJyBy0ppDt.png', description: 'Ancient' },
        { url: 'https://4pda.to/s/HL5VFadBYjIQaa5vsgkbZJS81qiyByW3hnH.png', description: 'Android Beta' },
        { url: 'https://4pda.to/s/HL5V0xNpkJnip0z2Gn6Wz1PwxKtZ86YRSbq19.png', description: 'Android' },
        { url: 'https://4pda.to/s/HL5V1uHyslNJp0VWfQsPbyqCB5t6YRyLiz0l.png', description: 'ApolloOS' },
        { url: 'https://4pda.to/s/HL5V2z2TY5HKrim7SlLkb33qCB5NMAVs4dl2.png', description: 'AwakenOS' },
        { url: 'https://4pda.to/s/HL5V3yRjTjoAimdit9u2z25xKtZeMAVMqz2Ja.png', description: 'AxionOS' },
        { url: 'https://4pda.to/s/HL5V4p3HxIogyO3sEcmsj8cX6O2N9PvSRfj.png', description: 'BaikalOS' },
        { url: 'https://4pda.to/s/HL5V5m5UZkKLyOZ6MwcHHEfvwz1z0N9PPi3LB.png', description: 'BananaDroid' },
        { url: 'https://4pda.to/s/HL5V6t90GGNpZexwGrz1jtnfvwz1T7XTJz087c.png', description: 'Bliss ROM' },
        { url: 'https://4pda.to/s/HL5V7qFF8inCZeRA8feABtcX6OY7XTpDGx0.png', description: 'Bootleggers' },
        { url: 'https://4pda.to/s/HL5VEhvuSkq5qinhxtRKu95tXa4uXz0Z54PL.png', description: 'CalyxOS_1' },
        { url: 'https://4pda.to/s/HL5VFez2t4IIwqiHRZhDp4FAlT2xuXz03rSbp.png', description: 'CalyxOS_2' },
        { url: 'https://4pda.to/s/HL5V0tFF8inCZ8hoa73ez1cjphLV28Qz2J3Lh.png', description: 'Cherish OS' },
        { url: 'https://4pda.to/s/HL5V1q90GGNpZ8B2yRLF2WYhNpW28QVZRfD.png', description: 'CipherOS' },
        { url: 'https://4pda.to/s/HL5V2p5UZkKLyuJz1wKDpaVYhNp0IWULoGxW.png', description: 'ColtOS' },
        { url: 'https://4pda.to/s/HL5V3m3HxIogyupEY8RKOPjphLz2IWUr2876.png', description: 'crDroid' },
        { url: 'https://4pda.to/s/HL5V4z2RjTjoAiGNKRdJWAKm6QkLJZOQgiz0F.png', description: 'DerpFest' },
        { url: 'https://4pda.to/s/HL5V5yTY5HKriGta3x57sIz2Uc8gJZOwQq1f.png', description: 'DivestOS' },
        { url: 'https://4pda.to/s/HL5V6xHyslNJpWlO5qTxGjz2Uc8A3BSmBz2J4.png', description: 'Evolution X' },
        { url: 'https://4pda.to/s/HL5V7uNpkJnipWFeTeBSihm6Qkr3BSGxdlY.png', description: 'GrapheneOS' },
        { url: 'https://4pda.to/s/HL5VElniz1xr6oZfNT8x4mz0tgKLz2omMXWz0sz0.png', description: 'HentaiOS' },
        { url: 'https://4pda.to/s/HL5VFitZc7JvoZ9d5KjZCxuoep0omM1GbAR.png', description: 'HorizonDroid' },
        { url: 'https://4pda.to/s/HL5V0p7RgvmFb7pE2uZusIVkUaa8Pnz0sww3.png', description: 'Infinity' },
        { url: 'https://4pda.to/s/HL5V1m1Ko5Mmb7Jz1QarVAKGsY2R8PnT6Y6b.png', description: 'iode' },
        { url: 'https://4pda.to/s/HL5V2tDA1xLMwtB2ShjZihGsY2xOnrNNfK8.png', description: 'Kirisakura' },
        { url: 'https://4pda.to/s/HL5V3qB5P7pfwtho4tx4GjVkUa4Onrtdnek.png', description: 'LineageOS' },
        { url: 'https://4pda.to/s/HL5V4xJvz2up9gVFez0Opm2W2RlVkPopOFLId.png', description: 'LMODroid' },
        { url: 'https://4pda.to/s/HL5V5uLsd4LsgVlOb4bNz1cD3JvHPopuz2Dk1.png', description: 'Martixx' },
        { url: 'https://4pda.to/s/HL5V6z2PeKwMGrltaZBz0hOPD3Jvn9Qtok6yi.png', description: 'MistOS' },
        { url: 'https://4pda.to/s/HL5V7yVdC6mlrlNKxNhCaV2RlVE9QtIUU0A.png', description: 'Paranoid' },
        { url: 'https://4pda.to/s/HL5VEBfuSkq5qinhxtRKu95tXa4uXz0Z54PL.png', description: 'PhoenixAOSP' },
        { url: 'https://4pda.to/s/HL5VF8lt4IIwqiHRZhDp4FAlT2xuXz03rSbp.png', description: 'PixelDust' },
        { url: 'https://4pda.to/s/HL5V0NVF8inCZ8hoa73ez1cjphLV28Qz2J3Lh.png', description: 'PixelExperience' },
        { url: 'https://4pda.to/s/HL5V1KP0GGNpZ8B2yRLF2WYhNpW28QVZRfD.png', description: 'Pixelos' },
        { url: 'https://4pda.to/s/HL5V2JLUZkKLyuJz1wKDpaVYhNp0IWULoGxW.png', description: 'PixelPlus UI' },
        { url: 'https://4pda.to/s/HL5V3GJHxIogyupEY8RKOPjphLz2IWUr2876.png', description: 'Project Blaze' },
        { url: 'https://4pda.to/s/HL5V4VBjTjoAiGNKRdJWAKm6QkLJZOQgiz0F.png', description: 'Project elixir-new' },
        { url: 'https://4pda.to/s/HL5V5SDY5HKriGta3x57sIz2Uc8gJZOwQq1f.png', description: 'Project Elixir' },
        { url: 'https://4pda.to/s/HL5V6R1yslNJpWlO5qTxGjz2Uc8A3BSmBz2J4.png', description: 'Project Zephyrus' },
        { url: 'https://4pda.to/s/HL5V7O7pkJnipWFeTeBSihm6Qkr3BSGxdlY.png', description: 'ProjectEverest' },
        { url: 'https://4pda.to/s/HL5VEFXiz1xr6oZfNT8x4mz0tgKLz2omMXWz0sz0.png', description: 'Radioactive Kernel' },
        { url: 'https://4pda.to/s/HL5VFCdZc7JvoZ9d5KjZCxuoep0omM1GbAR.png', description: 'RisingOS' },
        { url: 'https://4pda.to/s/HL5V0JNRgvmFb7pE2uZusIVkUaa8Pnz0sww3.png', description: 'Sigmadroid_2' },
        { url: 'https://4pda.to/s/HL5V1GHKo5Mmb7Jz1QarVAKGsY2R8PnT6Y6b.png', description: 'Sigmadroid' },
        { url: 'https://4pda.to/s/HL5V2NTA1xLMwtB2ShjZihGsY2xOnrNNfK8.png', description: 'SparkOS' },
        { url: 'https://4pda.to/s/HL5V3KR5P7pfwtho4tx4GjVkUa4Onrtdnek.png', description: 'StagOS' },
        { url: 'https://4pda.to/s/HL5V4R3vz2up9gVFez0Opm2W2RlVkPopOFLId.png', description: 'StatixOS' },
        { url: 'https://4pda.to/s/HL5V5O5sd4LsgVlOb4bNz1cD3JvHPopuz2Dk1.png', description: 'Superior_2' },
        { url: 'https://4pda.to/s/HL5V6V9eKwMGrltaZBz0hOPD3Jvn9Qtok6yi.png', description: 'Superior' },
        { url: 'https://4pda.to/s/HL5V7SFdC6mlrlNKxNhCaV2RlVE9QtIUU0A.png', description: 'SyberiaOS' }
    ];

    let buttonAdded = false;
    let logoPanel = null;

    function addLogoButton() {
        if (buttonAdded) return;

        console.log('Logo Replacer: searching for editor...');

        const selectors = [
            'img[src*="folder_editor_buttons"]',
            'td.formbuttons img',
            '.buttons img',
            'input[value*="B"]',
            'input[value*="I"]',
            'input[value*="U"]',
            'textarea[name="Post"]'
        ];

        for (let selector of selectors) {
            const elements = document.querySelectorAll(selector);
            if (elements.length > 0) {
                const element = elements[0];
                addButtonAsFirst(element);
                return;
            }
        }
    }

    function addButtonAsFirst(element) {
        if (!element || buttonAdded) return;

        console.log('Logo Replacer: adding button as first element');

        const logoBtn = document.createElement('span');
        logoBtn.className = 'g-btn blue logo-replacer-btn';
        logoBtn.textContent = 'Лого';
        logoBtn.title = `Выбрать логотип из ${LOGOS.length} вариантов`;
        logoBtn.style.cssText = 'margin-left:4px;cursor:pointer;font-weight:bold;';

        logoBtn.addEventListener('click', showLogoSelector);

        const container = element.parentNode;
        container.insertBefore(logoBtn, container.firstChild);
        buttonAdded = true;

        console.log('Logo Replacer: button added as first successfully!');
    }

    function showLogoSelector() {
        console.log('Logo Replacer: showing logo selector');

        if (logoPanel) {
            logoPanel.remove();
            logoPanel = null;
            return;
        }

        logoPanel = document.createElement('div');
        logoPanel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            border: 3px solid #4a6782;
            border-radius: 10px;
            padding: 15px;
            z-index: 10000;
            box-shadow: 0 8px 25px rgba(0,0,0,0.3);
            max-width: 95vw;
            max-height: 85vh;
            overflow-y: auto;
            font-family: Arial, sans-serif;
            font-size: 12px;
        `;

        const title = document.createElement('div');
        title.textContent = `Выберите логотип (${LOGOS.length} вариантов):`;
        title.style.cssText = 'font-weight: bold; margin-bottom: 12px; color: #333; font-size: 14px; text-align: center;';
        logoPanel.appendChild(title);

        const grid = document.createElement('div');
        grid.style.cssText = 'display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px;';
        logoPanel.appendChild(grid);

        LOGOS.forEach((logo, index) => {
            const logoContainer = document.createElement('div');
            logoContainer.style.cssText = 'border: 1px solid #ddd; border-radius: 6px; padding: 8px; text-align: center; background: #f9f9f9; cursor: pointer;';

            const name = document.createElement('div');
            name.textContent = logo.description;
            name.style.cssText = 'font-weight: bold; font-size: 10px; color: #4a6782; margin-bottom: 5px; height: 30px; display: flex; align-items: center; justify-content: center;';
            logoContainer.appendChild(name);

            const preview = document.createElement('img');
            preview.src = logo.url;
            preview.style.cssText = 'max-width: 100px; max-height: 50px; display: block; margin: 0 auto 8px; border: 1px solid #ccc;';
            preview.alt = logo.description;
            logoContainer.appendChild(preview);

            const logoBtn = document.createElement('button');
            logoBtn.textContent = 'Вставить';
            logoBtn.style.cssText = `
                width: 100%;
                padding: 4px 8px;
                background: #4a6782;
                color: white;
                border: none;
                border-radius: 3px;
                cursor: pointer;
                font-size: 10px;
                font-weight: bold;
            `;

            logoBtn.addEventListener('mouseenter', function() {
                this.style.background = '#5a7792';
                logoContainer.style.background = '#f0f5fa';
            });

            logoBtn.addEventListener('mouseleave', function() {
                this.style.background = '#4a6782';
                logoContainer.style.background = '#f9f9f9';
            });

            logoBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                insertLogo(logo.url, logo.description);
                logoPanel.remove();
                logoPanel = null;
            });

            logoContainer.appendChild(logoBtn);

            logoContainer.addEventListener('click', (e) => {
                if (e.target !== logoBtn) {
                    insertLogo(logo.url, logo.description);
                    logoPanel.remove();
                    logoPanel = null;
                }
            });

            grid.appendChild(logoContainer);
        });

        const closeBtn = document.createElement('button');
        closeBtn.textContent = 'Закрыть';
        closeBtn.style.cssText = `
            display: block;
            margin: 15px auto 0;
            padding: 8px 16px;
            background: #ff4444;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: bold;
        `;

        closeBtn.addEventListener('click', () => {
            logoPanel.remove();
            logoPanel = null;
        });

        logoPanel.appendChild(closeBtn);
        document.body.appendChild(logoPanel);

        setTimeout(() => {
            const closeHandler = (e) => {
                if (logoPanel && !logoPanel.contains(e.target)) {
                    logoPanel.remove();
                    logoPanel = null;
                    document.removeEventListener('click', closeHandler);
                }
            };
            document.addEventListener('click', closeHandler);
        }, 100);
    }

    function insertLogo(logoUrl, logoName) {
        const bbcode = `[center][img]${logoUrl}[/img][/center]`;
        console.log('Logo Replacer: inserting logo BBCode:', bbcode);

        let textarea = document.querySelector('textarea[name="Post"]');

        if (!textarea) {
            textarea = document.querySelector('#Post, textarea[id*="post"], textarea[class*="editor"]');
        }

        if (!textarea) {
            const allTextareas = document.querySelectorAll('textarea');
            for (let ta of allTextareas) {
                if (ta.offsetWidth > 300 && ta.offsetHeight > 100) {
                    textarea = ta;
                    break;
                }
            }
        }

        if (!textarea) {
            alert('Не найдено поле для ввода текста! Откройте редактор поста.');
            return;
        }

        let currentText = textarea.value;

        // ОЧИСТКА РЕДАКТОРА: Удаляем все старые логотипы из текста
        currentText = removeAllLogoReferences(currentText);

        // Вставляем новый логотип в начало
        const newText = bbcode + '\n\n' + currentText;
        textarea.value = newText;
        textarea.scrollTop = 0;
        textarea.focus();

        console.log('Logo Replacer: logo inserted successfully, editor cleaned');
        showNotification(`✅ Логотип "${logoName}" добавлен! Не забудьте удалить старое вложение вручную.`);
    }

    function removeAllLogoReferences(text) {
        if (!text) return text;

        console.log('Logo Replacer: cleaning editor from old logos');

        const patterns = [
            // Спойлеры с логотипами
            /\[spoiler=Лого\][\s\S]*?\[\/spoiler\]/gi,
            /\[spoiler=.*[Лл]ого.*\][\s\S]*?\[\/spoiler\]/gi,

            // Логотипы в центре
            /\[center\]\s*\[img\][^\]]*\[\/img\]\s*\[\/center\]/gi,
            /\[center\]\s*\[attachment[^\]]*\]\s*\[\/center\]/gi,

            // Отдельные изображения логотипов
            /\[img\][^\]]*logo[^\]]*\[\/img\]/gi,
            /\[img\][^\]]*\[\/img\]/gi,

            // Вложения логотипов
            /\[attachment[^\]]*logo[^\]]*\]/gi,
            /\[attachment[^\]]*\]/gi
        ];

        let cleanedText = text;
        let totalRemoved = 0;

        patterns.forEach((pattern, index) => {
            const matches = cleanedText.match(pattern);
            if (matches) {
                console.log(`Logo Replacer: pattern ${index} removed:`, matches);
                totalRemoved += matches.length;
                cleanedText = cleanedText.replace(pattern, '');
            }
        });

        // Убираем лишние пустые строки
        if (totalRemoved > 0) {
            cleanedText = cleanedText.replace(/\n\s*\n\s*\n/g, '\n\n');
            cleanedText = cleanedText.replace(/(\r?\n){3,}/g, '\n\n');
            cleanedText = cleanedText.trim();
        }

        console.log(`Logo Replacer: total logo references removed from editor: ${totalRemoved}`);
        return cleanedText;
    }

    function showNotification(message) {
        const oldNotifications = document.querySelectorAll('.logo-replacer-notification');
        oldNotifications.forEach(notification => notification.remove());

        const notification = document.createElement('div');
        notification.className = 'logo-replacer-notification';
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: #4a6782;
            color: white;
            padding: 12px 24px;
            border-radius: 6px;
            z-index: 10000;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            text-align: center;
            max-width: 400px;
            line-height: 1.4;
        `;
        notification.textContent = message;
        document.body.appendChild(notification);

        setTimeout(() => {
            if (notification.parentNode) {
                notification.parentNode.removeChild(notification);
            }
        }, 5000); // Увеличил время показа до 5 секунд
    }

    function init() {
        console.log(`Logo Replacer v4.1 initialized with ${LOGOS.length} logos`);

        setTimeout(addLogoButton, 1000);
        setTimeout(addLogoButton, 3000);
        setTimeout(addLogoButton, 5000);

        const observer = new MutationObserver(function(mutations) {
            for (let mutation of mutations) {
                if (mutation.addedNodes.length > 0) {
                    setTimeout(addLogoButton, 500);
                    break;
                }
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        setInterval(addLogoButton, 5000);
    }

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