Chrome Extension Button Enabler

Enables the "Add to Chrome" button for extensions marked as not following best practices

// ==UserScript==
// @name         Chrome Extension Button Enabler
// @name:zh-CN   Chrome扩展按钮启用器
// @name:en      Chrome Extension Button Enabler
// @namespace    http://tampermonkey.net/
// @version      1.0
// @license      MIT
// @description  Enables the "Add to Chrome" button for extensions marked as not following best practices
// @description:zh-CN  启用被标记为"未遵循最佳实践"的Chrome扩展的"添加至Chrome"按钮
// @description:en  Enables the "Add to Chrome" button for extensions marked as not following best practices
// @author       h7ml <[email protected]>
// @match        https://chrome.google.com/webstore/detail/*
// @match        https://chromewebstore.google.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    
    // 国际化支持: 支持多种语言的"添加到Chrome"按钮文本
    // Internationalization support: "Add to Chrome" button text in multiple languages
    const buttonTexts = {
        'en': 'Add to Chrome',
        'zh-CN': '添加至 Chrome',
        'zh-TW': '新增至 Chrome',
        'ja': 'Chromeに追加',
        'ko': 'Chrome에 추가',
        'de': 'Zu Chrome hinzufügen',
        'fr': 'Ajouter à Chrome',
        'es': 'Añadir a Chrome',
        'pt': 'Adicionar ao Chrome',
        'ru': 'Добавить в Chrome',
        'it': 'Aggiungi a Chrome',
        'ar': 'إضافة إلى Chrome',
        'hi': 'Chrome में जोड़ें',
        'tr': 'Chrome\'a ekle',
        'nl': 'Toevoegen aan Chrome',
        'pl': 'Dodaj do Chrome',
        'vi': 'Thêm vào Chrome',
        'th': 'เพิ่มใน Chrome'
    };
    
    // 启用按钮函数: 查找并启用被禁用的"添加到Chrome"按钮
    // Function to enable the button: Find and enable the disabled "Add to Chrome" button
    function enableButton() {
        // 通过多种方法定位目标按钮
        // Target the specific button using various methods
        let addButton = null;
        
        // 方法1: 使用提供的选择器
        // Method 1: Using the provided selector
        addButton = document.querySelector('button.UywwFc-LgbsSe.UywwFc-LgbsSe-OWXEXe-dgl2Hf.UywwFc-StrnGf-YYd4I-VtOx3e[jsname="wQO0od"]');
        
        if (!addButton) {
            // 方法2: 尝试通过可能常见的类名模式查找
            // Method 2: Try to find by class name patterns that might be common
            addButton = document.querySelector('button[disabled][jsname="wQO0od"]');
        }
        
        if (!addButton) {
            // 方法3: 尝试通过不同语言的按钮文本内容查找
            // Method 3: Try to find by content in different languages
            for (const lang in buttonTexts) {
                const buttonByText = Array.from(document.querySelectorAll('button')).find(
                    button => button.textContent.includes(buttonTexts[lang])
                );
                
                if (buttonByText) {
                    addButton = buttonByText;
                    break;
                }
            }
        }
        
        if (!addButton) {
            // 方法4: 查找任何可能是安装按钮的禁用按钮
            // Method 4: Find any disabled button that might be the install button
            const disabledButtons = document.querySelectorAll('button[disabled]');
            for (const button of disabledButtons) {
                // 检查是否可能是安装按钮(通常具有一些独特的类或属性)
                // Check if it's likely the install button (usually has some distinctive classes or attributes)
                if (button.classList.contains('UywwFc-LgbsSe') || 
                    button.hasAttribute('jscontroller') ||
                    button.querySelector('.UywwFc-vQzf8d')) {
                    addButton = button;
                    break;
                }
            }
        }
        
        if (addButton) {
            // 移除禁用属性
            // Remove the disabled attribute
            addButton.removeAttribute('disabled');
            
            // 使按钮在视觉上显示为启用状态
            // Make the button visually appear enabled
            addButton.style.opacity = '1';
            addButton.style.cursor = 'pointer';
            addButton.style.pointerEvents = 'auto';
            
            // 移除可能阻止点击的类
            // Remove classes that might prevent clicking
            const classesToRemove = ['UywwFc-LgbsSe-OWXEXe-QVCGsb', 'UywwFc-LgbsSe-OWXEXe-QVCGsb-Rt6MAe'];
            classesToRemove.forEach(className => {
                if (addButton.classList.contains(className)) {
                    addButton.classList.remove(className);
                }
            });
            
            // 如果可能,设置aria-disabled为false
            // Set aria-disabled to false if possible
            if (addButton.hasAttribute('aria-disabled')) {
                addButton.setAttribute('aria-disabled', 'false');
            }
            
            // 添加点击事件监听器,处理可能的覆盖层问题
            // Add click event listener to handle potential overlay issues
            addButton.addEventListener('click', function(e) {
                // 有时可能有不可见的覆盖层阻止点击
                // 这段代码帮助确保点击能够通过
                // Sometimes there might be invisible overlays preventing clicks
                // This code helps ensure the click gets through
                if (!e.isTrusted) {
                    return; // 只处理真实的用户点击 / Only process real user clicks
                }
                
                // 如果Chrome有额外的JS检查,尝试模拟一个干净的点击
                // In case Chrome has additional JS checks, try to simulate a clean click
                setTimeout(() => {
                    const clickEvent = new MouseEvent('click', {
                        bubbles: true,
                        cancelable: true,
                        view: window
                    });
                    addButton.dispatchEvent(clickEvent);
                }, 100);
            });
            
            return true; // 表示成功找到并启用按钮 / Indicate successful button finding and enabling
        } else {
            setTimeout(enableButton, 1000);
            return false; // 表示未找到按钮 / Indicate button not found
        }
    }
    
    // 初始化函数
    // Initialization function
    function initialize() {
        // 初次尝试启用按钮
        // Initial try to enable button
        enableButton();
        
        // 设置定期检查,以防按钮动态加载
        // Set up a periodic check in case the button loads dynamically
        const checkInterval = setInterval(function() {
            const possibleButtons = document.querySelectorAll('button[disabled]');
            let needToEnable = false;
            
            possibleButtons.forEach(button => {
                // 检查是否与已知的按钮文本匹配
                // Check for any text match with our known button texts
                for (const lang in buttonTexts) {
                    if (button.textContent.includes(buttonTexts[lang])) {
                        needToEnable = true;
                        break;
                    }
                }
                
                // 同时检查我们已知的特定类
                // Also check for the specific class we know about
                if (button.classList.contains('UywwFc-LgbsSe')) {
                    needToEnable = true;
                }
            });
            
            if (needToEnable) {
                enableButton();
            }
        }, 2000);
        
        // 30秒后停止检查,避免不必要的处理
        // Stop checking after 30 seconds to avoid unnecessary processing
        setTimeout(() => {
            clearInterval(checkInterval);
        }, 30000);
        
        // 设置变异观察器,检测按钮可能被动态添加的情况
        // Set up a mutation observer to detect when the button might be added dynamically
        const observer = new MutationObserver(function(mutations) {
            let shouldEnableButton = false;
            
            mutations.forEach(function(mutation) {
                if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                    // 检查是否添加了禁用的按钮
                    // Check if any disabled buttons were added
                    for (let i = 0; i < mutation.addedNodes.length; i++) {
                        const node = mutation.addedNodes[i];
                        if (node.nodeType === 1) { // 元素节点 / Element node
                            if (node.tagName === 'BUTTON' && node.hasAttribute('disabled')) {
                                shouldEnableButton = true;
                                break;
                            } else if (node.querySelector && node.querySelector('button[disabled]')) {
                                shouldEnableButton = true;
                                break;
                            }
                        }
                    }
                } else if (mutation.type === 'attributes' && 
                          mutation.attributeName === 'disabled' && 
                          mutation.target.tagName === 'BUTTON') {
                    // 如果按钮的disabled属性发生变化
                    // If a button's disabled attribute changes
                    shouldEnableButton = true;
                }
            });
            
            if (shouldEnableButton) {
                enableButton();
            }
        });
        
        // 开始观察文档主体的变化
        // Begin observing the document body for changes
        observer.observe(document.body, { 
            childList: true,      // 监听子节点添加或删除 / Monitor child node additions or removals
            subtree: true,        // 监听所有后代节点 / Monitor all descendant nodes
            attributes: true,     // 监听属性变化 / Monitor attribute changes
            attributeFilter: ['disabled'] // 只监听disabled属性 / Only monitor the disabled attribute
        });
    }
    
    // 判断文档是否已经加载完成
    // Check if document is already loaded
    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
    
    // 确保在页面完全加载后也尝试启用按钮
    // Ensure we also try to enable the button after the page is fully loaded
    window.addEventListener('load', function() {
        enableButton();
    });
    
    // 导出启用函数到全局,方便在控制台手动调用
    // Export enable function to global scope for manual calls from console
    window.__chromeButtonEnabler = {
        enableButton: enableButton
    };
})();