User:Habst/oly.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | Documentation for this user script can be added at User:Habst/oly. |
window.games ??= {};
window.olympaths ??= {};
window.oidsearch ??= {};
window.batchEntities ??= {};
window.entitles ??= {};
window.categories ??= {};
window.olympcountries ??= new DOMParser().parseFromString(await (await fetch('/countries')).text(), 'text/html');
(async () => {
const years = ['1896', '1900', '1904', '1908', '1912', '1920', '1924', '1928', '1932', '1936', '1948', '1952', '1956', '1960', '1964', '1968', '1972', '1976', '1980', '1984', '1988', '1992', '1996', '2000', '2004', '2008', '2012', '2016', '2020'];
const gamesAths = {};
const ents = {};
const redAths = {};
const Q_REDIRECT = 'Q70893996'; const Q_INTREDIRECT = 'Q70894304';
const getOlympath = async id => new DOMParser().parseFromString(await (await fetch(`/athletes/${id}`)).text(), 'text/html');
const ioc = Object.assign(Object.fromEntries([...olympcountries.querySelector('tbody').querySelectorAll('tr')].map(tr => {
const tds = tr.querySelectorAll('td');
return [tds[0].textContent, tds[1].textContent];
})), { CGO: 'Republic of the Congo' });
for (const year of years) {
games[year] ??= [];
gamesAths[year] = {};
redAths[year] ??= {};
let maxPage = 1;
for (let page = 1; page <= maxPage; page++) {
games[year][page - 1] ??= new DOMParser().parseFromString(await (await fetch(`/athletes/search_athlete?${new URLSearchParams({
year, page,
'role[]': 'olympic', // competitors
sport: 'ATH',
})}`)).text(), 'text/html');
const doc = games[year][page - 1];
maxPage = +new URLSearchParams([...doc.querySelectorAll('ul.pagination a')].at(-1)?.href.split('?').at(-1)).get('page') ?? 1;
}
for (const pg of games[year]) {
const trs = pg.querySelectorAll('tbody tr');
for (const tr of trs) {
const tds = tr.querySelectorAll('td');
const id = tds[0].textContent;
const name = tds[1].textContent;
const roles = tds[3].textContent;
if (!roles.split('/').includes('Olympics')) continue;
if (roles !== 'Olympics') {
// determine if year participation wasn't non-medal or non-starter
// can't merely check for era hyphen in case of https://www.olympedia.org/athletes/2791
olympaths[id] ??= await getOlympath(id);
let activeRow = [...olympaths[id].querySelectorAll('tr.active')].find(tr => tr.textContent.trim().startsWith(`${year} Summer Olympics`));
while (activeRow && activeRow.querySelectorAll('td')[1].textContent !== 'Athletics') {
activeRow = activeRow.nextElementSibling;
}
const evtRows = [];
let row = activeRow.nextElementSibling;
do {
evtRows.push(row);
row = row.nextElementSibling;
} while (row && !row.classList.contains('active'));
if (!evtRows.some(tr => tr.querySelector('small')?.textContent === '(Olympic)')) continue;
}
const countries = [...tds[2].querySelectorAll('a')].map(a => a.href.split('/').at(-1));
let country = countries[0];
if (countries.length > 1) {
olympaths[id] ??= await getOlympath(id);
country = [...olympaths[id].querySelectorAll('tr.active')].find(tr => tr.textContent.trim().split(' ')[0] === year).querySelectorAll('td')[2].textContent;
}
oidsearch[id] ??= await (await fetch('//www.wikidata.org/w/api.php?' + new URLSearchParams({
origin: '*', action: 'query', format: 'json', formatversion: '2', list: 'search', srsearch: `haswbstatement:P8286=${id}`,
}))).json();
const qid = oidsearch[id].query.search[0]?.title;
if (!qid) console.log('no qid:', name, `https://www.olympedia.org/athletes/${id}`);
gamesAths[year][country] ??= [];
gamesAths[year][country].push({ id, name, country, qid });
}
}
const qids = Object.values(gamesAths[year]).flat().map(a => a.qid);
const chunks = [];
for (let i = 0; i < qids.length; i += 50) chunks.push(qids.slice(i, i + 50));
for (const chunk of chunks) {
const ids = chunk.join('|');
batchEntities[ids] ??= await (await fetch(`//www.wikidata.org/w/api.php?${new URLSearchParams({
origin: '*', action: 'wbgetentities', ids, format: 'json', formatversion: '2',
})}`)).json();
Object.assign(ents, batchEntities[ids].entities);
}
}
let out = '';
for (const year of years) {
const getLink = async ath => {
const name = ath.name;
const lname = name.split(' ').at(-1);
const enlink = ents[ath.qid].sitelinks.enwiki;
if (enlink?.badges.includes(Q_REDIRECT) || enlink?.badges.includes(Q_INTREDIRECT)) {
categories[enlink.title] ??= await (await fetch(`//en.wikipedia.org/w/api.php?${new URLSearchParams({
origin: '*', action: 'query', format: 'json', formatversion: '2', titles: enlink.title, prop: 'categories',
})}`)).json();
const cats = categories[enlink.title].query.pages[0]?.categories?.map(c => c.title);
if (!cats) console.log('no cats', enlink.title);
if (cats?.includes('Category:Redirects from Olympians')) {
// green for Olympic redirects with bios
return `''[[${enlink.title}|<span style="color: green;">${lname}</span>]]''`;
}
redAths[year][ath.country].push(ath);
return `''[[${enlink.title}|<span style="color: red;">${lname}</span>]]''`;
}
if (enlink?.title) return `[[${enlink.title}|${lname}]]`;
redAths[year][ath.country].push(ath);
entitles[name] ??= await (await fetch(`//en.wikipedia.org/w/api.php?${new URLSearchParams({ origin: '*', action: 'query', titles: name, format: 'json', formatversion: '2' })}`)).json();
if (entitles[name].query.pages.some(p => !p.missing)) {
// add disambiguator?
// olympaths[ath.id] ??= await getOlympath(ath.id);
return `[https://www.olympedia.org/athletes/${ath.id} <span style="color: red;">${lname}</span>]`;
}
return `{{ill|${ath.name}|qid=${ath.qid}|s=1|lt=${lname}}}`;
}
const athLinks = {};
for (const ctry of Object.keys(gamesAths[year]).sort()) {
athLinks[ctry] ??= [];
redAths[year][ctry] ??= [];
for (const ath of gamesAths[year][ctry]) {
athLinks[ctry].push(await getLink(ath));
}
}
out += `==${year} (${Object.values(redAths[year]).flat().length} redlinks)==\n`;
for (const ctry of Object.keys(gamesAths[year]).sort()) {
out += `'''[[${ioc[ctry]} at the ${year} Summer Olympics|${ctry}]]''' (${gamesAths[year][ctry].length}): ${athLinks[ctry].join(', ')}. `;
}
out += '\n';
}
out = `Total: ${Object.values(redAths).flatMap(cObj => Object.values(cObj)).flat().length} redlinks, ${Object.values(redAths).flatMap(cObj => Object.values(cObj)).filter(x => x.length).length} country articles to edit.\n\n` + out;
console.log(out);
})()