User:Polygnotus/Scripts/FilterInactiveOrBlocked.js

This is an old revision of this page, as edited by Polygnotus (talk | contribs) at 16:53, 21 June 2025 (Created page with '// Wikipedia User Block Checker for common.js // Checks if users are blocked and categorizes them async function checkUserBlocks() { // Get input from user const input = prompt("Enter usernames (one per line):\nSupported formats:\nUser:Username\nUser talk:Username\nUser:Username\nUser talk:Username"); if (!input) { console.log("No input provided"); return; } const users = parseUsers(input); if (use...'). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// Wikipedia User Block Checker for common.js
// Checks if users are blocked and categorizes them

async function checkUserBlocks() {
    // Get input from user
    const input = prompt("Enter usernames (one per line):\nSupported formats:\n[[User:Username]]\n[[User talk:Username]]\nUser:Username\nUser talk:Username");
    
    if (!input) {
        console.log("No input provided");
        return;
    }

    const users = parseUsers(input);
    
    if (users.length === 0) {
        console.log("No valid usernames found");
        return;
    }

    console.log(`Checking ${users.length} users for blocks...`);
    
    const activeUsers = [];
    const blockedUsers = [];
    
    for (const userInfo of users) {
        console.log(`Checking user: ${userInfo.username} ...`);
        
        try {
            const isBlocked = await isUserBlocked(userInfo.username);
            
            if (isBlocked) {
                blockedUsers.push(userInfo.original);
                console.log(`✗ ${userInfo.username} is blocked`);
            } else {
                activeUsers.push(userInfo.original);
                console.log(`✓ ${userInfo.username} is active`);
            }
            
        } catch (error) {
            console.error(`Failed to check ${userInfo.username} after all retries:`, error);
            // Assume active if we can't check after all retries
            activeUsers.push(userInfo.original);
            console.log(`? ${userInfo.username} - check failed, assuming active`);
        }
        
        // Add base delay between requests to avoid hammering the API
        await sleep(1000); // 1 second between requests
    }
    
    // Display results
    console.log("\n=== RESULTS ===");
    console.log(`\nActive/Non-blocked users (${activeUsers.length}):`);
    activeUsers.forEach(user => console.log(user));
    
    console.log(`\nBlocked/Inactive users (${blockedUsers.length}):`);
    blockedUsers.forEach(user => console.log(user));
    
    // Also display in a more user-friendly format
    displayResults(activeUsers, blockedUsers);
}

function parseUsers(input) {
    const lines = input.split('\n');
    const users = [];
    
    // Regex patterns for different input formats
    const patterns = [
        /\[\[User:([^\]]+)\]\]/i,           // [[User:Username]]
        /\[\[User talk:([^\]]+)\]\]/i,      // [[User talk:Username]]
        /User:([^\s\]]+)/i,                 // User:Username
        /User talk:([^\s\]]+)/i             // User talk:Username
    ];
    
    for (const line of lines) {
        const trimmedLine = line.trim();
        if (!trimmedLine) continue;
        
        for (const pattern of patterns) {
            const match = trimmedLine.match(pattern);
            if (match) {
                users.push({
                    username: match[1].trim(),
                    original: trimmedLine
                });
                break;
            }
        }
    }
    
    return users;
}

async function isUserBlocked(username) {
    const maxRetries = 3;
    const retryDelays = [60000, 180000, 300000]; // 1min, 3min, 5min in milliseconds
    
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
        try {
            const api = new mw.Api();
            
            const response = await api.get({
                action: 'query',
                format: 'json',
                list: 'blocks',
                bkusers: username,
                bklimit: 1,
                maxlag: 5 // Wait if server lag is more than 5 seconds
            });
            
            // If blocks array exists and has entries, user is blocked
            return response.query.blocks && response.query.blocks.length > 0;
            
        } catch (error) {
            console.warn(`Attempt ${attempt + 1} failed for ${username}:`, error);
            
            // Check if this is a maxlag error
            if (error.code === 'maxlag') {
                const lagTime = error.lag || 5;
                console.log(`Server lag detected (${lagTime}s). Waiting before retry...`);
                await sleep((lagTime + 1) * 1000); // Wait lag time + 1 second
                continue;
            }
            
            // Check for HTTP error codes that warrant retry
            if (isRetryableError(error)) {
                if (attempt < maxRetries) {
                    const delay = retryDelays[attempt];
                    console.log(`Retryable error for ${username}. Waiting ${delay / 1000}s before retry ${attempt + 2}...`);
                    await sleep(delay);
                    continue;
                } else {
                    console.error(`Max retries exceeded for ${username}. Final error:`, error);
                    throw new Error(`Failed after ${maxRetries + 1} attempts: ${error.message}`);
                }
            } else {
                // Non-retryable error, fail immediately
                console.error(`Non-retryable error for ${username}:`, error);
                throw error;
            }
        }
    }
}

function isRetryableError(error) {
    // Check for HTTP status codes that warrant retry
    if (error.xhr && error.xhr.status) {
        const status = error.xhr.status;
        // Retry on server errors (5xx) and some client errors
        return status >= 500 || status === 429 || status === 408 || status === 502 || status === 503 || status === 504;
    }
    
    // Check for specific MediaWiki API error codes that warrant retry
    if (error.code) {
        const retryableCodes = [
            'maxlag',           // Server lag
            'readonly',         // Database in read-only mode
            'internal_api_error_DBConnectionError',
            'internal_api_error_DBQueryError',
            'ratelimited'       // Rate limiting
        ];
        return retryableCodes.includes(error.code);
    }
    
    // Check for network-related errors
    if (error.textStatus) {
        const retryableStatus = ['timeout', 'error', 'abort'];
        return retryableStatus.includes(error.textStatus);
    }
    
    return false;
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function displayResults(activeUsers, blockedUsers) {
    // Create a results dialog
    const resultsHtml = `
        <div style="max-height: 400px; overflow-y: auto;">
            <h3>Active/Non-blocked Users (${activeUsers.length})</h3>
            <textarea readonly style="width: 100%; height: 150px; font-family: monospace;">
${activeUsers.join('\n')}
            </textarea>
            
            <h3>Blocked/Inactive Users (${blockedUsers.length})</h3>
            <textarea readonly style="width: 100%; height: 150px; font-family: monospace;">
${blockedUsers.join('\n')}
            </textarea>
        </div>
    `;
    
    // Create and show dialog
    const dialog = $('<div>').html(resultsHtml).dialog({
        title: 'User Block Check Results',
        width: 600,
        height: 500,
        modal: true,
        buttons: {
            'Close': function() {
                $(this).dialog('close');
            }
        }
    });
}

// Add a button to the page for easy access
function addBlockCheckerButton() {
    if (mw.config.get('wgNamespaceNumber') === -1) return; // Don't add on special pages
    
    const portletId = mw.config.get('skin') === 'vector' ? 'p-cactions' : 'p-tb';
    mw.util.addPortletLink(
        portletId,
        '#',
        'Check User Blocks',
        't-check-blocks',
        'Check if users are blocked'
    );
    
    $('#t-check-blocks').on('click', function(e) {
        e.preventDefault();
        checkUserBlocks();
    });
}

// Initialize when page loads
$(document).ready(function() {
    addBlockCheckerButton();
});

// Also make the function available globally
window.checkUserBlocks = checkUserBlocks;