MediaWiki:SpamRemoval.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
//Part 1: Raw/Original Bookmarklet code
const fetchHtml = async (url, options = undefined) => {
const response = await fetch(url, options);
return await response.text();
};
const getPageEditToken = async (name) => {
const url =
'https://wiki.project1999.com/index.php?title=' + name + '&action=delete';
const html = await await fetchHtml(url);
const index = html.indexOf('wpEditToken');
return html.slice(index - 42, index - 8);
};
const getUserEditToken = async (name) => {
const url =
'https://wiki.project1999.com/Special:Block/' + encodeURIComponent(name);
const html = await fetchHtml(url);
const junk = ' id="wpEditToken" type="hidden" value="';
const index = html.indexOf(junk);
const token = html.slice(index + junk.length).split('"')[0];
return token;
};
const getCreatorUsername = async (pageName) => {
const url =
'https://wiki.project1999.com/index.php?title=' +
pageName +
'&action=history';
let html = await fetchHtml(url);
html = html.split(' | prev)')[1];
const junkStart1 = "<span class='history-user'><a href=\"/User:";
const junkEnd1 = '" title="';
let startIndex;
if (html.includes(junkStart1)) {
console.log(html)
startIndex = html.lastIndexOf(junkStart1) + junkStart1.length;
return html.substring(startIndex, html.indexOf(junkEnd1, startIndex));
}
const junkStart2 =
"<span class='history-user'><a href=\"/index.php?title=User:";
const junkEnd2 = '&action';
if (html.includes(junkStart2)) {
startIndex = html.indexOf(junkStart2) + junkStart2.length;
return html.substring(startIndex, html.indexOf(junkEnd2, startIndex));
}
return alert('Unexpected history page HTML for :' + pageName + '"');
};
const blockUserName = async (username) => {
const userHtml = await fetchHtml(
'https://wiki.project1999.com/Special:Block/' + username
);
const alreadyBanned = userHtml.includes(
username + ' is already blocked. Do you want to change the settings?'
);
if (alreadyBanned) {
alert('The user "' + username + '" was already banned.');
return true;
}
const editToken = await getUserEditToken(username);
const encodedName = encodeURIComponent(username);
const url = 'https://wiki.project1999.com/Special:Block/' + encodedName;
const options = {
body:
'wpTarget=' +
username +
'&wpExpiry=infinite&wpExpiry-other=' +
'&wpReason=Spamming+links+to+external+sites' +
'&wpReason-other=' +
'&wpCreateAccount=1' +
'&wpAutoBlock=1' +
'&wpEditToken=' +
encodeURIComponent(editToken) +
'&title=Special%3ABlock%2F' +
username +
'&redirectparams=' +
'&wpPreviousTarget=' +
username +
'&wpConfirm=',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
};
const responseHtml = await fetchHtml(url, options);
return responseHtml.includes('Block succeeded');
};
const deletePage = async (pageName) => {
const creator = await getCreatorUsername(pageName);
if (!creator || creator.length > 50) {
return alert(
'Unable to find creator of "' + pageName + '" (found ' + creator + ')'
);
}
const banSucceess = await blockUserName(creator);
if (!banSucceess) {
return alert('Something went wrong when blocking "' + creator + '"');
}
const url =
'https://wiki.project1999.com/index.php?title=' +
pageName +
'&action=delete';
const editToken = await getPageEditToken(pageName);
const options = {
body:
'wpDeleteReasonList=Vandalism' +
'&wpReason=Content+was+inappropriate' +
'&wpConfirmB=Delete+page' +
'&wpEditToken=' +
encodeURIComponent(editToken),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
};
const responseHtml = await fetchHtml(url, options);
const deleteSuccess = responseHtml.includes('Action complete');
alert(
deleteSuccess
? '"' + pageName + '" was deleted and "' + creator + '" was banned.'
: 'Deleting "' + pageName + '" failed: see Network tab for details.'
);
};
$('body').one('click', (e) => {
if (e.target.tagName !== 'A') return;
deletePage(e.target.innerHTML);
return false;
});
/**
* Use the following URL to "build" this bookmarklet
* https://caiorss.github.io/bookmarklet-maker/
*/
// Part 2: Escaped bookmarklet, as a string
const escapedOneUseBookmarklet = `javascript:(function()%7Bconst%20fetchHtml%20%3D%20async%20(url%2C%20options%20%3D%20undefined)%20%3D%3E%20%7B%0A%20%20const%20response%20%3D%20await%20fetch(url%2C%20options)%3B%0A%20%20return%20await%20response.text()%3B%0A%7D%3B%0A%0Aconst%20getPageEditToken%20%3D%20async%20(name)%20%3D%3E%20%7B%0A%20%20const%20url%20%3D%0A%20%20%20%20'https%3A%2F%2Fwiki.project1999.com%2Findex.php%3Ftitle%3D'%20%2B%20name%20%2B%20'%26action%3Ddelete'%3B%0A%20%20const%20html%20%3D%20await%20await%20fetchHtml(url)%3B%0A%20%20const%20index%20%3D%20html.indexOf('wpEditToken')%3B%0A%20%20return%20html.slice(index%20-%2042%2C%20index%20-%208)%3B%0A%7D%3B%0A%0Aconst%20getUserEditToken%20%3D%20async%20(name)%20%3D%3E%20%7B%0A%20%20const%20url%20%3D%0A%20%20%20%20'https%3A%2F%2Fwiki.project1999.com%2FSpecial%3ABlock%2F'%20%2B%20encodeURIComponent(name)%3B%0A%20%20const%20html%20%3D%20await%20fetchHtml(url)%3B%0A%20%20const%20junk%20%3D%20'%20id%3D%22wpEditToken%22%20type%3D%22hidden%22%20value%3D%22'%3B%0A%20%20const%20index%20%3D%20html.indexOf(junk)%3B%0A%20%20const%20token%20%3D%20html.slice(index%20%2B%20junk.length).split('%22')%5B0%5D%3B%0A%20%20return%20token%3B%0A%7D%3B%0A%0Aconst%20getCreatorUsername%20%3D%20async%20(pageName)%20%3D%3E%20%7B%0A%20%20const%20url%20%3D%0A%20%20%20%20'https%3A%2F%2Fwiki.project1999.com%2Findex.php%3Ftitle%3D'%20%2B%0A%20%20%20%20pageName%20%2B%0A%20%20%20%20'%26action%3Dhistory'%3B%0A%20%20let%20html%20%3D%20await%20fetchHtml(url)%3B%0A%20%20html%20%3D%20html.split('%20%7C%20prev)')%5B1%5D%3B%0A%20%20const%20junkStart1%20%3D%20%22%3Cspan%20class%3D'history-user'%3E%3Ca%20href%3D%5C%22%2FUser%3A%22%3B%0A%20%20const%20junkEnd1%20%3D%20'%22%20title%3D%22'%3B%0A%20%20let%20startIndex%3B%0A%20%20if%20(html.includes(junkStart1))%20%7B%0A%20%20%20%20console.log(html)%0A%20%20%20%20startIndex%20%3D%20html.lastIndexOf(junkStart1)%20%2B%20junkStart1.length%3B%0A%20%20%20%20return%20html.substring(startIndex%2C%20html.indexOf(junkEnd1%2C%20startIndex))%3B%0A%20%20%7D%0A%0A%20%20const%20junkStart2%20%3D%0A%20%20%20%20%22%3Cspan%20class%3D'history-user'%3E%3Ca%20href%3D%5C%22%2Findex.php%3Ftitle%3DUser%3A%22%3B%0A%20%20const%20junkEnd2%20%3D%20'%26amp%3Baction'%3B%0A%20%20if%20(html.includes(junkStart2))%20%7B%0A%20%20%20%20startIndex%20%3D%20html.indexOf(junkStart2)%20%2B%20junkStart2.length%3B%0A%20%20%20%20return%20html.substring(startIndex%2C%20html.indexOf(junkEnd2%2C%20startIndex))%3B%0A%20%20%7D%0A%0A%20%20return%20alert('Unexpected%20history%20page%20HTML%20for%20%3A'%20%2B%20pageName%20%2B%20'%22')%3B%0A%7D%3B%0A%0Aconst%20blockUserName%20%3D%20async%20(username)%20%3D%3E%20%7B%0A%20%20const%20userHtml%20%3D%20await%20fetchHtml(%0A%20%20%20%20'https%3A%2F%2Fwiki.project1999.com%2FSpecial%3ABlock%2F'%20%2B%20username%0A%20%20)%3B%0A%20%20const%20alreadyBanned%20%3D%20userHtml.includes(%0A%20%20%20%20username%20%2B%20'%20is%20already%20blocked.%20Do%20you%20want%20to%20change%20the%20settings%3F'%0A%20%20)%3B%0A%20%20if%20(alreadyBanned)%20%7B%0A%20%20%20%20alert('The%20user%20%22'%20%2B%20username%20%2B%20'%22%20was%20already%20banned.')%3B%0A%20%20%20%20return%20true%3B%0A%20%20%7D%0A%0A%20%20const%20editToken%20%3D%20await%20getUserEditToken(username)%3B%0A%20%20const%20encodedName%20%3D%20encodeURIComponent(username)%3B%0A%20%20const%20url%20%3D%20'https%3A%2F%2Fwiki.project1999.com%2FSpecial%3ABlock%2F'%20%2B%20encodedName%3B%0A%20%20const%20options%20%3D%20%7B%0A%20%20%20%20body%3A%0A%20%20%20%20%20%20'wpTarget%3D'%20%2B%0A%20%20%20%20%20%20username%20%2B%0A%20%20%20%20%20%20'%26wpExpiry%3Dinfinite%26wpExpiry-other%3D'%20%2B%0A%20%20%20%20%20%20'%26wpReason%3DSpamming%2Blinks%2Bto%2Bexternal%2Bsites'%20%2B%0A%20%20%20%20%20%20'%26wpReason-other%3D'%20%2B%0A%20%20%20%20%20%20'%26wpCreateAccount%3D1'%20%2B%0A%20%20%20%20%20%20'%26wpAutoBlock%3D1'%20%2B%0A%20%20%20%20%20%20'%26wpEditToken%3D'%20%2B%0A%20%20%20%20%20%20encodeURIComponent(editToken)%20%2B%0A%20%20%20%20%20%20'%26title%3DSpecial%253ABlock%252F'%20%2B%0A%20%20%20%20%20%20username%20%2B%0A%20%20%20%20%20%20'%26redirectparams%3D'%20%2B%0A%20%20%20%20%20%20'%26wpPreviousTarget%3D'%20%2B%0A%20%20%20%20%20%20username%20%2B%0A%20%20%20%20%20%20'%26wpConfirm%3D'%2C%0A%20%20%20%20headers%3A%20%7B%20'Content-Type'%3A%20'application%2Fx-www-form-urlencoded'%20%7D%2C%0A%20%20%20%20method%3A%20'POST'%2C%0A%20%20%7D%3B%0A%20%20const%20responseHtml%20%3D%20await%20fetchHtml(url%2C%20options)%3B%0A%20%20return%20responseHtml.includes('Block%20succeeded')%3B%0A%7D%3B%0A%0Aconst%20deletePage%20%3D%20async%20(pageName)%20%3D%3E%20%7B%0A%20%20const%20creator%20%3D%20await%20getCreatorUsername(pageName)%3B%0A%20%20if%20(!creator%20%7C%7C%20creator.length%20%3E%2050)%20%7B%0A%20%20%20%20return%20alert(%0A%20%20%20%20%20%20'Unable%20to%20find%20creator%20of%20%22'%20%2B%20pageName%20%2B%20'%22%20(found%20'%20%2B%20creator%20%2B%20')'%0A%20%20%20%20)%3B%0A%20%20%7D%0A%0A%20%20const%20banSucceess%20%3D%20await%20blockUserName(creator)%3B%0A%20%20if%20(!banSucceess)%20%7B%0A%20%20%20%20return%20alert('Something%20went%20wrong%20when%20blocking%20%22'%20%2B%20creator%20%2B%20'%22')%3B%0A%20%20%7D%0A%0A%20%20const%20url%20%3D%0A%20%20%20%20'https%3A%2F%2Fwiki.project1999.com%2Findex.php%3Ftitle%3D'%20%2B%0A%20%20%20%20pageName%20%2B%0A%20%20%20%20'%26action%3Ddelete'%3B%0A%20%20const%20editToken%20%3D%20await%20getPageEditToken(pageName)%3B%0A%20%20const%20options%20%3D%20%7B%0A%20%20%20%20body%3A%0A%20%20%20%20%20%20'wpDeleteReasonList%3DVandalism'%20%2B%0A%20%20%20%20%20%20'%26wpReason%3DContent%2Bwas%2Binappropriate'%20%2B%0A%20%20%20%20%20%20'%26wpConfirmB%3DDelete%2Bpage'%20%2B%0A%20%20%20%20%20%20'%26wpEditToken%3D'%20%2B%0A%20%20%20%20%20%20encodeURIComponent(editToken)%2C%0A%20%20%20%20headers%3A%20%7B%20'Content-Type'%3A%20'application%2Fx-www-form-urlencoded'%20%7D%2C%0A%20%20%20%20method%3A%20'POST'%2C%0A%20%20%7D%3B%0A%0A%20%20const%20responseHtml%20%3D%20await%20fetchHtml(url%2C%20options)%3B%0A%20%20const%20deleteSuccess%20%3D%20responseHtml.includes('Action%20complete')%3B%0A%20%20alert(%0A%20%20%20%20deleteSuccess%0A%20%20%20%20%20%20%3F%20'%22'%20%2B%20pageName%20%2B%20'%22%20was%20deleted%20and%20%22'%20%2B%20creator%20%2B%20'%22%20was%20banned.'%0A%20%20%20%20%20%20%3A%20'Deleting%20%22'%20%2B%20pageName%20%2B%20'%22%20failed%3A%20see%20Network%20tab%20for%20details.'%0A%20%20)%3B%0A%7D%3B%0A%0A%24('body').one('click'%2C%20(e)%20%3D%3E%20%7B%0A%20%20if%20(e.target.tagName%20!%3D%3D%20'A')%20return%3B%0A%0A%20%20deletePage(e.target.innerHTML)%3B%0A%20%20return%20false%3B%0A%7D)%3B%7D)()%3B`;
// Part 3: Code to show the bookmarklet (and its multi-use variant) in the wiki (since wiki's can't have "javascript:" links)
$('#oneUsePlaceholder').html(`<a>One-Use Spam Deletion</a>`);
// Don't use jQuery because it will escape the code (incorrectly)
$('#oneUsePlaceholder a').get(0).setAttribute('href', escapedOneUseBookmarklet);
const multiUseBookmarklet = escapedOneUseBookmarklet.replace(`.one('click'%2C%20(e)`, `.click((e)`);
$('#multiplePlaceholder').html(`<a>Multi-Use Spam Deletion</a>`);
$('#multiplePlaceholder a').attr('href', multiUseBookmarklet);