您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
MediaWiki巡查工具 | A patrol tool for MediaWiki
当前为
// ==UserScript== // @name QuickPatrol_v2 // @namespace qp_tool_v2 // @version 1.95 // @description MediaWiki巡查工具 | A patrol tool for MediaWiki // @author teaSummer // @match *://*/wiki/* // @match *://*/w/* // @match *://*/index.php?* // @license MIT // @grant none // ==/UserScript== (function () { 'use strict'; // 配置 | Configuration const config = { rollbackMode: 'summary', // 回退模式,值为'summary'、'confirm'、'd+s'、'c+s'或'default' | Rollback Mode, values are 'summary', 'confirm', 'd+s', 'c+s' or 'default' usingOOUI: true, // 使用OOUI,值为布尔值或'force' | Using OOUI, values are booleans or 'force' maxRetries: 5 // 获取mwApi最大重试次数 | Maximum Retries of Getting mwApi } // 本地化 | Localization const w = { 'en': { un: 'This edit has not yet been patrolled', ing: 'Quick patrolling...', done: 'Quick patrolled', t_un: 'Unpatrolled', g_un: 'Unpatrolled', hl: 'Highlighted: ', g_cr_1: 'Sure to rollback this edit?', g_er_1: 'Additional rollback summary:', g_er_2: 'Revert edits by [[Special:Contribs/$1|$1]] ([[User talk:$1|talk]])', g_er_3: 'Edit rollback summary', c: ': ' }, 'zh-hans': { un: '该编辑尚未巡查', ing: '快速巡查中…', done: '已快速巡查', t_un: '未巡查', g_un: '尚未巡查', hl: '已高亮:', g_cr_1: '确定要回退此编辑吗?', g_er_1: '附加回退摘要:', g_er_2: '回退[[Special:Contribs/$1|$1]]([[User talk:$1|留言]])所做的编辑', g_er_3: '编辑回退摘要', c: ':' }, 'zh-hant': { un: '該編輯尚未巡查', ing: '快速巡查中…', done: '已快速巡查', t_un: '未巡查', g_un: '尚未巡查', hl: '已明顯標示:', g_cr_1: '確定要回退此編輯嗎?', g_er_1: '附加回退摘要:', g_er_2: '回退[[Special:Contribs/$1|$1]]([[User talk:$1|留言]])所做的編輯', g_er_3: '編輯回退摘要', c: ':' }, } let mwApi, mwLang, rights, l, fail = 0, load = false; const need_patrol = '.mw-changeslist-reviewstatus-unpatrolled:not(.mw-rcfilters-ui-highlights-enhanced-toplevel):not(.quickpatrol), .revisionpatrol-unpatrolled'; function g_cr() { $('.mw-rollback-link a:not(.quickpatrol-rollback)').each(function () { const href = $(this).attr('href'); $(this).click((e) => { e.preventDefault(); if (config.usingOOUI) { OO.ui.confirm(l.g_cr_1).then((confirmed) => { if (confirmed) location.href = href; }); } else { if (confirm(l.g_cr_1)) location.href = href; } }); }).addClass('quickpatrol-rollback').addClass(mwLang.startsWith('zh-') ? 'consolas' : ''); } function g_er(p) { let el = '.mw-rollback-link a'; if (p) { if (p == 2) g_cr(); $(el).each(function () { $(this).after($(`<span class="edit-rollback" href="${$(this).attr('href')}" title="${l.g_er_3}"></span>`)); }).addClass('quickpatrol-rollback').addClass(mwLang.startsWith('zh-') ? 'consolas' : ''); el = '.edit-rollback'; } el = el + ':not(.quickpatrol-rollback)'; $(el).each(function () { const href = $(this).attr('href'); $(this).click((e) => { e.preventDefault(); const rb = (result) => { const r = result.trim(); location.href = href + '&summary=' + encodeURIComponent(r ? summary + l.c + r : summary); } const name = decodeURIComponent(href.match(/&from=(.+)&token/)[1].replace(/\+/g, ' ')); const summary = mw.format(l.g_er_2, name); if (config.usingOOUI) { OO.ui.prompt(l.g_er_1).then((result) => { rb(result); }); } else { const result = prompt(l.g_er_1); if (result != null) rb(result); } }); }).addClass('quickpatrol-rollback').addClass(mwLang.startsWith('zh-') ? 'consolas' : ''); } async function rollback_gadget() { if (config.rollbackMode == 'default' || !load) return; if (!(OO && OO.ui && OO.ui.confirm)) { if (config.usingOOUI == 'force') { await mw.loader.load('https://fastly.jsdelivr.net/npm/oojs-ui/dist/oojs-ui-windows-wikimediaui.min.css', 'text/css'); await mw.loader.load('https://fastly.jsdelivr.net/npm/oojs-ui/dist/oojs-ui-windows.min.js'); } else { // 不强制使用:在不兼容时自动禁用 config.usingOOUI = false; } } load[0](load[1]); } async function init() { if (fail >= config.maxRetries) return; try { mwApi = await new mw.Api(); mwLang = Object.keys(await mw.language.data)[0]; if (['zh-cn', 'zh-hans', 'zh-hans-cn', 'zh', 'cn'].indexOf(mwLang) != -1) mwLang = 'zh-hans'; else if (mwLang.startsWith('zh-')) mwLang = 'zh-hant'; if (Object.keys(w).indexOf(mwLang) == -1) mwLang = 'en'; l = w[mwLang]; if (!load) { load = true; const rc = $('.mw-changeslist'); const ob_IPE = new MutationObserver(with_IPE); const ob = new MutationObserver((ml) => { ml.forEach((m) => { if ($(m.target).hasClass('mw-changeslist')) main(); if (m.addedNodes.length) { const e = $(m.addedNodes); if (e.hasClass('quick-diff')) ob_IPE.observe(e.find('.ipe-progress')[0], { attributes: true }); } }); }); ob.observe(document.body, { childList: true }); if (rc.length) ob.observe(rc[0], { childList: true }); await mw.loader.load(`https://cdn.jsdelivr.net/gh/teaSummer/QuickPatrol_v2@main/styles.css`, 'text/css'); await mw.loader.load(`https://fastly.jsdelivr.net/gh/teaSummer/QuickPatrol_v2@minecraft-wiki/patrol/${mwLang}/Gadget-revisionPatrol.css`, 'text/css'); await mw.loader.load(`https://fastly.jsdelivr.net/gh/teaSummer/QuickPatrol_v2@minecraft-wiki/patrol/${mwLang}/Gadget-revisionPatrol.js`); if (config.rollbackMode == 'summary') load = [g_er]; if (config.rollbackMode == 'confirm') load = [g_cr]; if (config.rollbackMode == 'd+s') load = [g_er, 1]; if (config.rollbackMode == 'c+s') load = [g_er, 2]; if (load.length == 2) await mw.loader.load(`https://fastly.jsdelivr.net/gh/teaSummer/QuickPatrol_v2@minecraft-wiki/rollback/${mwLang}/Gadget-editableRollback.css`, 'text/css'); } } catch (e) { fail = fail + 1; if (fail < config.maxRetries) console.warn(`[QuickPatrol] Failed to call MediaWiki. Retrying... (${fail}/${config.maxRetries})`); else console.error(`[QuickPatrol] Failed to call MediaWiki. (${fail}/${config.maxRetries})`); new Promise(() => setTimeout(init, 2000)); return; } console.log('[QuickPatrol] Checking rights...'); rights = ( await mwApi.get({ action: 'query', meta: 'userinfo', uiprop: 'rights' }) ).query.userinfo.rights; main(); return; } function with_IPE() { $('.diff-version:not(.diff-hidden-history)').click(function () { const me = $(this); if (me.attr('title')) return; const value = me.text().replace(/[^0-9]/g, ''); me.addClass('patrolling').attr('title', l.ing); patrol(me, value); return value; }); } async function main() { if (!rights) { if (fail >= config.maxRetries || !fail) init(); return; } if (rights.includes('rollback')) rollback_gadget(); if (rights.includes('patrol')) { $(need_patrol).attr('data-mw-revid', function (_i, value) { const that = $(this); that.find('.revisionpatrol-icon-unpatrolled').after(`<span class="unpatrolled quickpatrol-icon-unpatrolled" title="${l.g_un}">!</span>`); that.find('.revisionpatrol-icon-unpatrolled').remove(); that.find('.unpatrolled').addClass('quickpatrol').click(async function () { const me = $(this); me.addClass('patrolling').removeClass('unpatrolled'); if (me.text() == '!') { $(this).text('#').attr('title', l.ing); if (!value && that.attr('data-mw-logid')) { try { value = new RegExp(`"logid":${that.attr('data-mw-logid')},.+?,"revid":([0-9]+)`).exec(JSON.stringify((await mwApi .get({ action: 'query', list: 'logevents', leprop: 'ids', letitle: that.find('td.mw-enhanced-rc-nested').attr('data-target-page'), letype: that.attr('data-mw-logaction').split('/')[0], lelimit: 'max', format: 'json' }) )))[1]; } catch (e) { $(this).text('!').removeClass('patrolling').attr('title', l.un); return; } } patrol(me, value, () => { that.removeClass('mw-rcfilters-highlight-color-c5').removeClass('mw-changeslist-reviewstatus-unpatrolled'); that.attr('title', that.attr('title').replace(new RegExp(`(, |、\u200B)?${l.t_un}(、\u200B|, )?`, 'g'), '')); if (that.attr('title') == l.hl) that.removeAttr('title'); }); } }); return value; }); } } function patrol(me, revid, successFallback = () => { }, exFailFallback = () => { }) { const failFallback = () => { console.warn(`[QuickPatrol] FAILED (revid: ${value})`); me.text('!').removeClass('patrolling').removeClass('unpatrolled').attr('title', l.un); if (me.hasClass('quickpatrol-icon-unpatrolled')) me.attr('title', l.g_un); exFailFallback(); } console.debug(`[QuickPatrol] TRYING (revid: ${revid})`); mwApi.get({ action: 'query', meta: 'tokens', type: 'patrol', format: 'json' }).done((data) => { mwApi.post({ action: 'patrol', revid: revid, token: data.query.tokens.patroltoken, format: 'json' }).done(() => { console.debug(`[QuickPatrol] SUCCEEDED (revid: ${revid})`); me.text('✔').removeClass('patrolling').removeClass('unpatrolled').attr('title', l.done); successFallback(); }).fail(failFallback); }).fail(failFallback); } window.onload = init; })();