Content deleted Content added
fetch user talk pages without using usercontribs API |
improve user talk page fetching and error handling |
||
Line 33:
version: this.version
});
}
enumerate() {
if (this.version != 4) {
throw new Error('can only enumerate IPv4 addresses');
const count = 1n << BigInt(32 - this.mask);
let current = this.masked(this.mask).ip;
return Array.from({ length: Number(count) }, () =>
IPAddress.#bigIntToIPv4(current++)
);
}
Line 241 ⟶ 252:
const heading = document.querySelector('#firstHeading');
if (heading) {
heading.
}
const contentContainer = document.querySelector('#mw-content-text');
Line 285 ⟶ 296:
async function displayRangeTalk(ip) {
async function getUserTalkPages(ip) {
const url = `/wiki/Special:Contributions/${ip}?limit=250`;
const userTalk = new Set();
const abortController = new AbortController();
Line 292 ⟶ 303:
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const talkLinks = doc.querySelectorAll('.mw-contributions-list a.mw-usertoollinks-talk:not(.new)');
for (const link of talkLinks) {
const title = link.title;
Line 300 ⟶ 311:
console.error('Error fetching usertalk pages:', error);
}
return Array.from(userTalk);
}
function timeAgo(timestamp) {
Line 356 ⟶ 367:
blockUser.href = `/wiki/Special:Block/${ip}`;
}
let userTalkMethod;
if (!userTalk.size) {▼
if (ip.version === 4 && ip.mask >= 24) {
const noContributionsMessage = document.createElement('p');▼
userTalk = ip.enumerate().map(ipString => `User talk:${ipString}`);
noContributionsMessage.innerHTML = '<span style="color:red;">No user talk pages found for recent contributions from this IP range.</span>';▼
userTalkMethod = "enumerate";
contentContainer.appendChild(noContributionsMessage);▼
} else {
return;▼
userTalk = await getUserTalkPages(ip);
userTalkMethod = "contributions";
resultMessage.style.color = 'var(--color-notice, gray)';
▲
▲ return;
}
}
const
batch(userTalk, 50).map(titles => api.get({
action: 'query',
format: 'json',
formatversion: 2
▲ });
}))
);
.filter(page => !page.missing)▼
const pages = infoResponses
.flatMap(response => response.query.pages)
▲ .filter(page => !page.missing && page.revisions && page.revisions.length > 0)
.map(page => ({
title: page.title,
redirect: !!page.redirect
}))
.sort((a, b) => b.
if (!pages.length) {
const
if (userTalkMethod === "enumerate") {
noTalkPagesMessage.innerHTML = '<span style="color:red;">An error occurred while retrieving timestamps for user talk pages in this IP range.</span>';▼
resultMessage.style.color = 'var(--color-notice, gray)';
▲ contentContainer.appendChild(noTalkPagesMessage);
resultMessage.textContent = 'No user talk pages found.';
} else {
resultMessage.style.color = 'var(--color-error, red)';
▲
}
return;
}
Line 386 ⟶ 416:
for (const page of pages) {
const ip = page.title.replace(/^User talk:/, '');
const relativeTime = `${timeAgo(page.
const headerText = `== ${relativeTime}: [[Special:Contributions/${ip}|${ip}]] ([[${page.title}|talk]]) ==`;
const inclusionText = `{{${page.title}}}`;
Line 428 ⟶ 458:
const heading = document.querySelector('#firstHeading');
if (heading) {
heading.
}
const contentContainer = document.querySelector('#mw-content-text');
Line 640 ⟶ 670:
}
return wikitext;
}
function batch(items, maxSize) {
const minBins = Math.ceil(items.length / maxSize);
const bins = Array.from({length: minBins}, () => []);
items.forEach((item, i) => {
bins[i % minBins].push(item);
});
return bins;
}
|