Jump to content

User:Habst/oly.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
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);
})()