Greasy Fork is available in English.
Замена логотипа в посте
当前为
// ==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();
}
})();