// ==UserScript== // @name Fandom批量删除与保护工具 // @author PandaFiredoge // @version 2.0.1 // @description 一个用于Fandom站点的批量删除页面并可选保护的工具,支持正则匹配页面标题和删除用户创建的页面 // @match *://*.fandom.com/*/wiki/Special:* // @match *://*.wikia.com/*/wiki/Special:* // @grant none // @license GPL-3.0-or-later // @namespace https://greasyfork.org/users/1413764 // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 确保mw API可用 if (typeof mw === 'undefined' || typeof mw.Api === 'undefined') { console.error('MediaWiki API不可用,工具无法加载'); return; } // 只在特殊页面运行 if (!mw.config.get('wgCanonicalSpecialPageName')) return; // 确保用户有管理员权限 if (!mw.config.get('wgUserGroups') || !mw.config.get('wgUserGroups').includes('sysop')) { console.log('用户没有管理员权限,批量删除工具不会加载'); return; } // 创建工具界面 function createInterface() { const container = document.createElement('div'); container.id = 'bulk-delete-tool'; container.style.cssText = 'padding: 15px; margin: 15px 0; border: 1px solid #ccc; border-radius: 4px; background-color: #f9f9f9;'; container.innerHTML = `

批量删除与保护页面工具

输入要删除的页面标题(每行一个):

`; // 将工具添加到页面 const mainContent = document.querySelector('#WikiaMainContent, .WikiaMainContent, #mw-content-text, .mw-body-content'); if (mainContent) { mainContent.prepend(container); } else { document.body.prepend(container); } // 添加事件监听器 document.getElementById('preview-button').addEventListener('click', previewPages); document.getElementById('delete-button').addEventListener('click', startDeletion); document.getElementById('load-category-button').addEventListener('click', showCategoryModal); document.getElementById('load-prefix-button').addEventListener('click', showPrefixModal); document.getElementById('load-regex-button').addEventListener('click', showRegexModal); document.getElementById('load-user-pages-button').addEventListener('click', showUserPagesModal); // 新增用户页面按钮事件 document.getElementById('modal-close').addEventListener('click', closeModal); // 添加保护选项切换功能 document.getElementById('protect-after-delete').addEventListener('change', function() { document.getElementById('protection-options').style.display = this.checked ? 'block' : 'none'; }); // 添加CSS样式 addStyles(); } // 添加CSS样式 function addStyles() { const style = document.createElement('style'); style.textContent = ` .collapsible-section { border: 1px solid #ddd; border-radius: 4px; margin-bottom: 15px; } .collapsible-header { padding: 10px; background-color: #f5f5f5; cursor: pointer; display: flex; justify-content: space-between; align-items: center; font-weight: bold; } .collapsible-header:hover { background-color: #e9e9e9; } .collapsible-content { padding: 10px; border-top: 1px solid #ddd; max-height: 300px; overflow-y: auto; } .collapsed .collapsible-content { display: none; } .page-list-container { max-height: 300px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; margin: 10px 0; } .action-buttons { position: sticky; bottom: 0; background-color: white; padding: 10px 0; border-top: 1px solid #ddd; margin-top: 10px; } #modal-content { display: flex; flex-direction: column; } #modal-body { overflow-y: auto; } `; document.head.appendChild(style); } // 显示消息 function showMessage(message, type) { const messageElement = document.getElementById('tool-message'); messageElement.textContent = message; messageElement.style.display = 'block'; if (type === 'error') { messageElement.style.backgroundColor = '#f2dede'; messageElement.style.borderColor = '#ebccd1'; messageElement.style.color = '#a94442'; } else if (type === 'success') { messageElement.style.backgroundColor = '#dff0d8'; messageElement.style.borderColor = '#d6e9c6'; messageElement.style.color = '#3c763d'; } else { messageElement.style.backgroundColor = '#d9edf7'; messageElement.style.borderColor = '#bce8f1'; messageElement.style.color = '#31708f'; } // 5秒后自动隐藏 setTimeout(() => { messageElement.style.display = 'none'; }, 5000); } // 显示模态框 function showModal(title, content) { document.getElementById('modal-container').style.display = 'block'; document.getElementById('modal-body').innerHTML = `

${title}

${content} `; // 添加折叠区域的事件监听器 setTimeout(() => { document.querySelectorAll('.collapsible-header').forEach(header => { header.addEventListener('click', function() { const section = this.parentElement; section.classList.toggle('collapsed'); const chevron = this.querySelector('.chevron'); if (chevron) { chevron.textContent = section.classList.contains('collapsed') ? '▼' : '▲'; } }); }); }, 100); } // 关闭模态框 function closeModal() { document.getElementById('modal-container').style.display = 'none'; } // 创建可折叠区域 function createCollapsibleSection(title, contentHtml, initiallyCollapsed = false) { return `
${title} ${initiallyCollapsed ? '▼' : '▲'}
${contentHtml}
`; } // 显示用户页面模态框 - 修改后的函数 function showUserPagesModal() { const content = `
只加载此日期之后创建的页面。留空表示加载所有页面。
${createCollapsibleSection('命名空间选项', `
`, true)}
`; showModal('加载用户创建的页面', content); document.getElementById('load-user-pages-button-modal').addEventListener('click', function() { const username = document.getElementById('username').value.trim(); if (!username) { showMessage('请输入有效的用户名', 'error'); return; } const dateLimit = document.getElementById('date-limit').value; // 获取选中的命名空间 const namespaces = []; if (document.getElementById('namespace-main').checked) namespaces.push(0); if (document.getElementById('namespace-user').checked) namespaces.push(2, 3); if (document.getElementById('namespace-template').checked) namespaces.push(10, 11); if (document.getElementById('namespace-category').checked) namespaces.push(14, 15); if (document.getElementById('namespace-file').checked) namespaces.push(6, 7); if (document.getElementById('namespace-other').checked) namespaces.push(4, 5, 8, 9, 12, 13); document.getElementById('user-pages-results').innerHTML = '

正在加载用户创建的页面,请稍候...

'; loadUserCreatedPages(username, dateLimit, namespaces); }); } // 加载用户创建的页面 - 未修改 function loadUserCreatedPages(username, dateLimit, namespaces) { const api = new mw.Api(); const resultContainer = document.getElementById('user-pages-results'); // 构建参数 let params = { action: 'query', list: 'usercontribs', ucuser: username, uclimit: 500, ucprop: 'title|timestamp', ucshow: 'new', // 只显示创建新页面的贡献 format: 'json' }; // 添加日期限制 if (dateLimit) { params.ucend = dateLimit + 'T00:00:00Z'; // 转换为ISO格式 } // 添加命名空间限制 if (namespaces && namespaces.length > 0) { params.ucnamespace = namespaces.join('|'); } // 显示加载状态 resultContainer.innerHTML = '

正在查询用户创建的页面,这可能需要一些时间...

'; // 保存找到的页面 const userPages = []; // 递归函数获取所有页面 function getUserContributions(continueParam) { if (continueParam) { // 添加continue参数 for (let prop in continueParam) { params[prop] = continueParam[prop]; } } api.get(params).done(function(data) { if (data.query && data.query.usercontribs) { data.query.usercontribs.forEach(function(contrib) { userPages.push({ title: contrib.title, timestamp: contrib.timestamp }); }); // 更新状态信息 resultContainer.innerHTML = `

已找到 ${userPages.length} 个由 ${username} 创建的页面,正在继续搜索...

`; // 如果有更多结果,继续查询 if (data.continue) { getUserContributions(data.continue); } else { // 完成所有查询 displayUserPagesResults(username, userPages); } } else { // 没有找到贡献或出现错误 if (userPages.length === 0) { resultContainer.innerHTML = `

未找到用户 "${username}" 创建的页面。

`; } else { displayUserPagesResults(username, userPages); } } }).fail(function(code, result) { resultContainer.innerHTML = `

查询用户贡献失败: ${result.error ? result.error.info : code}

`; }); } // 开始查询 getUserContributions(); } // 显示用户创建的页面结果 - 修改后的函数 function displayUserPagesResults(username, pages) { const resultContainer = document.getElementById('user-pages-results'); if (pages.length === 0) { resultContainer.innerHTML = `

未找到用户 "${username}" 创建的页面。

`; return; } // 按时间倒序排序(最新的在前) pages.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); // 创建折叠区域的内容 let pagesContent = `
`; pages.forEach((page, index) => { // 格式化时间戳为可读格式 const date = new Date(page.timestamp); const formattedDate = date.toLocaleString(); pagesContent += `
(创建于 ${formattedDate})
`; }); pagesContent += `
`; // 创建固定底部的操作按钮 const actionButtons = `
`; // 组合内容 const html = `

找到 ${pages.length} 个由 "${username}" 创建的页面:

${createCollapsibleSection('页面列表', pagesContent)} ${actionButtons} `; resultContainer.innerHTML = html; // 添加全选/取消全选功能 document.getElementById('select-all-user-pages').addEventListener('change', function() { const checkboxes = document.querySelectorAll('#user-pages-results .page-checkbox'); checkboxes.forEach(cb => { cb.checked = this.checked; }); }); // 添加添加到列表功能 document.getElementById('add-user-pages-button').addEventListener('click', function() { const selectedPages = []; document.querySelectorAll('#user-pages-results .page-checkbox:checked').forEach(cb => { selectedPages.push(cb.value); }); if (selectedPages.length === 0) { showMessage('请至少选择一个页面', 'error'); return; } const textarea = document.getElementById('pages-to-delete'); const existingText = textarea.value.trim(); const newText = selectedPages.join('\n'); textarea.value = existingText ? existingText + '\n' + newText : newText; // 更新删除原因以包含用户名 const reasonInput = document.getElementById('delete-reason'); if (reasonInput.value === '批量清理') { reasonInput.value = `清理用户 ${username} 创建的页面`; } closeModal(); showMessage(`已添加 ${selectedPages.length} 个页面到删除列表`, 'success'); }); } // 显示正则匹配模态框 - 修改后的函数 function showRegexModal() { // 获取命名空间列表 const namespaces = [ {id: '0', name: '(主命名空间)'}, {id: '1', name: 'Talk'}, {id: '2', name: 'User'}, {id: '3', name: 'User talk'}, {id: '4', name: 'Project'}, {id: '6', name: 'File'}, {id: '10', name: 'Template'}, {id: '14', name: 'Category'}, {id: '110', name: 'Forum'}, {id: '828', name: 'Module'} ]; let namespaceOptions = ''; namespaces.forEach(ns => { namespaceOptions += ``; }); const content = `
提示:使用JavaScript正则表达式语法,例如 ^Template:Test.* 将匹配所有以"Template:Test"开头的页面。
${createCollapsibleSection('高级选项', `
i = 忽略大小写, g = 全局匹配, m = 多行匹配
`, true)}
`; showModal('使用正则表达式匹配页面', content); // 更新flags值的处理 document.getElementById('regex-case-sensitive').addEventListener('change', function() { const flagsInput = document.getElementById('regex-flags'); if (this.checked) { // 移除i标志 flagsInput.value = flagsInput.value.replace(/i/g, ''); } else if (!flagsInput.value.includes('i')) { // 添加i标志 flagsInput.value += 'i'; } }); document.getElementById('load-regex-pages-button').addEventListener('click', function() { const pattern = document.getElementById('regex-pattern').value.trim(); const namespace = document.getElementById('regex-namespace').value; const flags = document.getElementById('regex-flags').value.trim(); if (!pattern) { showMessage('请输入有效的正则表达式', 'error'); return; } document.getElementById('regex-results').innerHTML = '

正在搜索匹配页面,请稍候...

'; searchPagesByRegex(pattern, namespace, flags); }); } // 使用正则表达式搜索页面 - 未修改 function searchPagesByRegex(pattern, namespace, flags) { const api = new mw.Api(); const resultContainer = document.getElementById('regex-results'); try { // 测试正则表达式是否有效 new RegExp(pattern, flags); } catch (e) { resultContainer.innerHTML = `

正则表达式无效: ${e.message}

`; return; } // 构建查询参数 let params = { action: 'query', list: 'allpages', aplimit: 500, format: 'json' }; // 只有在选择了特定命名空间时才添加命名空间参数 if (namespace !== 'all') { params.apnamespace = namespace; } // 创建正则表达式对象 const regex = new RegExp(pattern, flags); // 显示加载状态 resultContainer.innerHTML = '

正在加载页面,这可能需要一些时间...

'; // 保存匹配的页面 let matchedPages = []; // 执行递归API调用来获取所有页面 function getAllPages(continueParam) { if (continueParam) { // 添加continue参数 for (let prop in continueParam) { params[prop] = continueParam[prop]; } } api.get(params).done(function(data) { if (data.query && data.query.allpages) { // 过滤匹配正则表达式的页面 const pages = data.query.allpages; pages.forEach(function(page) { if (regex.test(page.title)) { matchedPages.push(page.title); } }); // 更新状态 resultContainer.innerHTML = `

已找到 ${matchedPages.length} 个匹配页面,正在继续搜索...

`; // 如果有更多页面,继续获取 if (data.continue) { getAllPages(data.continue); } else { // 最终完成 displayRegexResults(matchedPages, pattern, flags); } } else { displayRegexResults(matchedPages, pattern, flags); } }).fail(function() { resultContainer.innerHTML = '

获取页面列表失败,请重试。

'; }); } // 开始获取页面 getAllPages(); } // 显示正则匹配结果 - 修改后的函数 function displayRegexResults(pages, pattern, flags) { const resultContainer = document.getElementById('regex-results'); if (pages.length === 0) { resultContainer.innerHTML = `

没有找到匹配正则表达式 "${pattern}" 的页面。

`; return; } // 创建折叠区域的内容 let pagesContent = `
`; pages.forEach((page, index) => { pagesContent += `
`; }); pagesContent += `
`; // 创建固定底部的操作按钮 const actionButtons = `
`; // 组合内容 const html = `

找到 ${pages.length} 个匹配正则表达式 /${pattern}/${flags} 的页面:

${createCollapsibleSection('页面列表', pagesContent)} ${actionButtons} `; resultContainer.innerHTML = html; // 添加全选/取消全选功能 document.getElementById('select-all-regex').addEventListener('change', function() { const checkboxes = document.querySelectorAll('#regex-results .page-checkbox'); checkboxes.forEach(cb => { cb.checked = this.checked; }); }); // 添加添加到列表功能 document.getElementById('add-regex-pages-button').addEventListener('click', function() { const selectedPages = []; document.querySelectorAll('#regex-results .page-checkbox:checked').forEach(cb => { selectedPages.push(cb.value); }); if (selectedPages.length === 0) { showMessage('请至少选择一个页面', 'error'); return; } const textarea = document.getElementById('pages-to-delete'); const existingText = textarea.value.trim(); const newText = selectedPages.join('\n'); textarea.value = existingText ? existingText + '\n' + newText : newText; closeModal(); showMessage(`已添加 ${selectedPages.length} 个页面到删除列表`, 'success'); }); } // 显示分类模态框 - 修改后的函数 function showCategoryModal() { const content = `
`; showModal('从分类加载页面', content); document.getElementById('load-category-pages-button').addEventListener('click', function() { const categoryName = document.getElementById('category-name').value.trim(); const depth = parseInt(document.getElementById('category-depth').value); if (!categoryName) { showMessage('请输入有效的分类名称', 'error'); return; } document.getElementById('category-results').innerHTML = '

正在加载分类页面,请稍候...

'; loadPagesFromCategory(categoryName, depth); }); } // 显示前缀模态框 - 修改后的函数 function showPrefixModal() { // 获取命名空间列表 const namespaces = [ {id: '0', name: '(主命名空间)'}, {id: '1', name: 'Talk'}, {id: '2', name: 'User'}, {id: '3', name: 'User talk'}, {id: '4', name: 'Project'}, {id: '6', name: 'File'}, {id: '10', name: 'Template'}, {id: '14', name: 'Category'}, {id: '110', name: 'Forum'}, {id: '828', name: 'Module'} ]; let namespaceOptions = ''; namespaces.forEach(ns => { namespaceOptions += ``; }); const content = `
`; showModal('从前缀加载页面', content); document.getElementById('load-prefix-pages-button').addEventListener('click', function() { const prefix = document.getElementById('prefix-name').value.trim(); const namespace = document.getElementById('namespace-select').value; if (!prefix) { showMessage('请输入有效的页面前缀', 'error'); return; } document.getElementById('prefix-results').innerHTML = '

正在加载前缀页面,请稍候...

'; loadPagesFromPrefix(prefix, namespace); }); } // 从分类加载页面 - 未修改 function loadPagesFromCategory(categoryName, depth) { const api = new mw.Api(); api.get({ action: 'query', list: 'categorymembers', cmtitle: 'Category:' + categoryName, cmlimit: 500, cmnamespace: '*', cmtype: 'page|subcat', format: 'json' }).done(function(data) { const pages = []; const subcats = []; if (data.query && data.query.categorymembers) { data.query.categorymembers.forEach(function(member) { if (member.ns === 14) { // 这是子分类 subcats.push(member.title.replace('Category:', '')); } else { // 这是页面 pages.push(member.title); } }); // 显示结果 displayCategoryResults(categoryName, pages); // 如果需要处理子分类并且深度大于0 if (depth > 0 && subcats.length > 0) { loadSubcategories(subcats, pages, depth - 1); } } else { document.getElementById('category-results').innerHTML = '

在分类 "' + categoryName + '" 中未找到页面。

'; } }).fail(function() { document.getElementById('category-results').innerHTML = '

无法加载分类页面。请检查分类名称后重试。

'; }); } // 递归加载子分类 - 未修改 function loadSubcategories(subcats, allPages, remainingDepth) { if (subcats.length === 0 || remainingDepth < 0) return; const currentCat = subcats.shift(); const api = new mw.Api(); api.get({ action: 'query', list: 'categorymembers', cmtitle: 'Category:' + currentCat, cmlimit: 500, cmnamespace: '*', cmtype: 'page|subcat', format: 'json' }).done(function(data) { const newSubcats = []; if (data.query && data.query.categorymembers) { data.query.categorymembers.forEach(function(member) { if (member.ns === 14) { // 这是子分类 newSubcats.push(member.title.replace('Category:', '')); } else { // 这是页面 allPages.push(member.title); } }); // 更新显示 displayCategoryResults('所有分类', allPages); // 处理任何新发现的子分类 if (remainingDepth > 0) { subcats.push(...newSubcats); } // 继续处理队列中的下一个子分类 if (subcats.length > 0) { loadSubcategories(subcats, allPages, remainingDepth); } } }); } // 显示分类结果 - 修改后的函数 function displayCategoryResults(categoryName, pages) { const resultContainer = document.getElementById('category-results'); if (pages.length === 0) { resultContainer.innerHTML = '

在分类 "' + categoryName + '" 中未找到页面。

'; return; } // 创建折叠区域的内容 let pagesContent = `
`; pages.forEach((page, index) => { pagesContent += `
`; }); pagesContent += `
`; // 创建固定底部的操作按钮 const actionButtons = `
`; // 组合内容 const html = `

在分类 "${categoryName}" 中找到 ${pages.length} 个页面:

${createCollapsibleSection('页面列表', pagesContent)} ${actionButtons} `; resultContainer.innerHTML = html; // 添加全选/取消全选功能 document.getElementById('select-all-category').addEventListener('change', function() { const checkboxes = document.querySelectorAll('#category-results .page-checkbox'); checkboxes.forEach(cb => { cb.checked = this.checked; }); }); // 添加添加到列表功能 document.getElementById('add-category-pages-button').addEventListener('click', function() { const selectedPages = []; document.querySelectorAll('#category-results .page-checkbox:checked').forEach(cb => { selectedPages.push(cb.value); }); if (selectedPages.length === 0) { showMessage('请至少选择一个页面', 'error'); return; } const textarea = document.getElementById('pages-to-delete'); const existingText = textarea.value.trim(); const newText = selectedPages.join('\n'); textarea.value = existingText ? existingText + '\n' + newText : newText; closeModal(); showMessage(`已添加 ${selectedPages.length} 个页面到删除列表`, 'success'); }); } // 从前缀加载页面 - 未修改 function loadPagesFromPrefix(prefix, namespace) { const api = new mw.Api(); api.get({ action: 'query', list: 'allpages', apprefix: prefix, apnamespace: namespace, aplimit: 500, format: 'json' }).done(function(data) { const pages = []; if (data.query && data.query.allpages) { data.query.allpages.forEach(function(page) { pages.push(page.title); }); // 显示结果 displayPrefixResults(prefix, namespace, pages); } else { document.getElementById('prefix-results').innerHTML = '

使用前缀 "' + prefix + '" 未找到页面。

'; } }).fail(function() { document.getElementById('prefix-results').innerHTML = '

无法加载前缀页面。请检查前缀后重试。

'; }); } // 显示前缀结果 - 修改后的函数 function displayPrefixResults(prefix, namespace, pages) { const resultContainer = document.getElementById('prefix-results'); if (pages.length === 0) { resultContainer.innerHTML = '

使用前缀 "' + prefix + '" 未找到页面。

'; return; } const namespaceText = document.querySelector('#namespace-select option[value="' + namespace + '"]')?.textContent || namespace; // 创建折叠区域的内容 let pagesContent = `
`; pages.forEach((page, index) => { pagesContent += `
`; }); pagesContent += `
`; // 创建固定底部的操作按钮 const actionButtons = `
`; // 组合内容 const html = `

在命名空间 "${namespaceText}" 中找到 ${pages.length} 个以 "${prefix}" 开头的页面:

${createCollapsibleSection('页面列表', pagesContent)} ${actionButtons} `; resultContainer.innerHTML = html; // 添加全选/取消全选功能 document.getElementById('select-all-prefix').addEventListener('change', function() { const checkboxes = document.querySelectorAll('#prefix-results .page-checkbox'); checkboxes.forEach(cb => { cb.checked = this.checked; }); }); // 添加添加到列表功能 document.getElementById('add-prefix-pages-button').addEventListener('click', function() { const selectedPages = []; document.querySelectorAll('#prefix-results .page-checkbox:checked').forEach(cb => { selectedPages.push(cb.value); }); if (selectedPages.length === 0) { showMessage('请至少选择一个页面', 'error'); return; } const textarea = document.getElementById('pages-to-delete'); const existingText = textarea.value.trim(); const newText = selectedPages.join('\n'); textarea.value = existingText ? existingText + '\n' + newText : newText; closeModal(); showMessage(`已添加 ${selectedPages.length} 个页面到删除列表`, 'success'); }); } // 预览页面 - 未修改 function previewPages() { const pagesText = document.getElementById('pages-to-delete').value.trim(); if (!pagesText) { showMessage('请先添加要删除的页面', 'error'); return; } // 将文本分割成页面数组 const pagesToDelete = pagesText.split('\n') .map(page => page.trim()) .filter(page => page.length > 0); if (pagesToDelete.length === 0) { showMessage('没有找到有效的页面标题', 'error'); return; } const protectEnabled = document.getElementById('protect-after-delete').checked; let protectionInfo = ''; if (protectEnabled) { const protectionLevel = document.getElementById('protection-level').value; const protectionExpiry = document.getElementById('protection-expiry').value; const protectionReason = document.getElementById('protection-reason').value; // 转换保护期限为人类可读形式 let readableExpiry = protectionExpiry; if (protectionExpiry === 'infinite') { readableExpiry = '永久'; } protectionInfo = `
删除后将保护这些页面:
保护级别: ${protectionLevel === 'sysop' ? '仅管理员' : '仅自动确认用户'}
保护期限: ${readableExpiry}
保护原因: ${protectionReason}
`; } // 显示预览 const content = `
总页面数: ${pagesToDelete.length}
删除原因: ${document.getElementById('delete-reason').value}
${protectionInfo} ${createCollapsibleSection('页面列表', `
    ${pagesToDelete.map(page => `
  1. ${page}
  2. `).join('')}
`)}
警告: 请确认以上列表。点击"开始删除"后,这些页面将被永久删除。此操作无法撤销,请确保您有删除权限。
`; showModal('预览删除列表', content); } // 开始删除 - 未修改 function startDeletion() { const pagesText = document.getElementById('pages-to-delete').value.trim(); if (!pagesText) { showMessage('请先添加要删除的页面', 'error'); return; } // 将文本分割成页面数组 const pagesToDelete = pagesText.split('\n') .map(page => page.trim()) .filter(page => page.length > 0); if (pagesToDelete.length === 0) { showMessage('没有找到有效的页面标题', 'error'); return; } // 删除确认 if (!confirm('您即将删除 ' + pagesToDelete.length + ' 个页面。此操作无法撤销。是否继续?')) { return; } // 准备删除 const reason = document.getElementById('delete-reason').value; // 获取保护设置 const protectEnabled = document.getElementById('protect-after-delete').checked; let protectionParams = null; if (protectEnabled) { // 保护参数 protectionParams = { level: document.getElementById('protection-level').value, expiry: convertExpiryToTimestamp(document.getElementById('protection-expiry').value), reason: document.getElementById('protection-reason').value }; } const statusContainer = document.getElementById('deletion-status'); statusContainer.style.display = 'block'; const resultsElement = document.getElementById('deletion-results'); resultsElement.innerHTML = ''; // 开始删除过程 processPageDeletion(pagesToDelete, 0, reason, protectionParams); } // 转换保护期限为MediaWiki API接受的格式 - 未修改 function convertExpiryToTimestamp(expiryOption) { // 如果是infinite(永久),直接返回 if (expiryOption === 'infinite') { return 'infinite'; } // 获取当前日期 const now = new Date(); // 根据选择的选项计算到期日期 switch (expiryOption) { case '1 week': now.setDate(now.getDate() + 7); break; case '1 month': now.setMonth(now.getMonth() + 1); break; case '3 months': now.setMonth(now.getMonth() + 3); break; case '6 months': now.setMonth(now.getMonth() + 6); break; case '1 year': now.setFullYear(now.getFullYear() + 1); break; default: // 如果无法识别选项,默认为一周 now.setDate(now.getDate() + 7); } // 将日期格式化为MediaWiki API接受的格式:YYYY-MM-DDThh:mm:ssZ return now.toISOString().replace(/\.\d+Z$/, 'Z'); } // 处理页面删除(递归) - 未修改 function processPageDeletion(pages, index, reason, protectionParams) { if (index >= pages.length) { // 所有页面处理完毕 document.getElementById('progress-text').textContent = '完成! 删除操作已结束。'; return; } const page = pages[index]; const progressElement = document.getElementById('progress'); const progressTextElement = document.getElementById('progress-text'); const resultsElement = document.getElementById('deletion-results'); // 更新进度 const progressPercentage = Math.round((index / pages.length) * 100); progressElement.style.width = progressPercentage + '%'; progressTextElement.textContent = '正在处理: ' + page + ' (' + (index + 1) + '/' + pages.length + ', ' + progressPercentage + '%)'; // 执行删除API调用 const api = new mw.Api(); api.postWithToken('csrf', { action: 'delete', title: page, reason: reason, format: 'json' }).done(function() { // 删除成功 const resultItem = document.createElement('div'); resultItem.style.color = '#3c763d'; resultItem.textContent = '✓ 成功删除: ' + page; resultsElement.appendChild(resultItem); // 如果需要保护页面 if (protectionParams) { protectDeletedPage(page, protectionParams, resultsElement); } // 继续下一个 setTimeout(function() { processPageDeletion(pages, index + 1, reason, protectionParams); }, 500); // 添加短暂延迟以避免过快发送请求 }).fail(function(code, result) { // 删除失败 const resultItem = document.createElement('div'); resultItem.style.color = '#a94442'; resultItem.textContent = '✗ 删除失败: ' + page + ' - ' + (result.error ? result.error.info : code); resultsElement.appendChild(resultItem); // 继续下一个 setTimeout(function() { processPageDeletion(pages, index + 1, reason, protectionParams); }, 500); // 添加短暂延迟以避免过快发送请求 }); } // 保护已删除的页面 - 未修改 function protectDeletedPage(page, protectionParams, resultsElement) { const api = new mw.Api(); api.postWithToken('csrf', { action: 'protect', title: page, protections: 'create=' + protectionParams.level, expiry: protectionParams.expiry, reason: protectionParams.reason, format: 'json' }).done(function() { // 保护成功 const resultItem = document.createElement('div'); resultItem.style.color = '#3a87ad'; resultItem.textContent = '🔒 成功保护: ' + page; resultsElement.appendChild(resultItem); }).fail(function(code, result) { // 保护失败 const resultItem = document.createElement('div'); resultItem.style.color = '#8a6d3b'; resultItem.textContent = '⚠ 保护失败: ' + page + ' - ' + (result.error ? result.error.info : code); resultsElement.appendChild(resultItem); }); } // 检查页面是否存在 - 未修改 function checkPageExists(pageName, callback) { const api = new mw.Api(); api.get({ action: 'query', titles: pageName, format: 'json' }).done(function(data) { if (data.query && data.query.pages) { // 页面ID为负数表示不存在 const pageId = Object.keys(data.query.pages)[0]; callback(parseInt(pageId) > 0); } else { callback(false); } }).fail(function() { callback(false); }); } // 工具初始化 function initTool() { console.log('正在初始化Fandom批量删除与保护工具...'); createInterface(); console.log('Fandom批量删除与保护工具已加载。'); } // 在DOM加载完成后初始化工具 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initTool); } else { initTool(); } })();