User:Habst/WorldAthletics2Medalists.js

window.data ??= {} for (const day of [1,2]) window.data[day]??=await (await fetch("https://wpgiegzkbrhj5mlsdxnipboepm.appsync-api.eu-west-1.amazonaws.com/graphql", { "headers": { "x-api-key": "da2-juounigq4vhkvg5ac47mezxqge" // note API key is intentionally public }, "body": JSON.stringify({  "operationName": "getCalendarCompetitionResults",  "variables": {    "competitionId": 7176907,    "day": day,    "eventId": null  },  "query": `query getCalendarCompetitionResults($competitionId: Int, $day: Int, $eventId: Int) {  getCalendarCompetitionResults(competitionId: $competitionId, day: $day, eventId: $eventId) {    competition {      dateRange      endDate      name      rankingCategory      startDate      venue      __typename    }    eventTitles {      rankingCategory      eventTitle      events {        event        eventId        gender        isRelay        perResultWind        withWind        summary {          competitor {            teamMembers {              id              name              iaafId              urlSlug              __typename            }            id            name            iaafId            urlSlug            birthDate __typename }         mark nationality placeInRace placeInRound points raceNumber records wind __typename }       races { date day race raceId raceNumber results { competitor { teamMembers { id               name iaafId urlSlug __typename }             id              name iaafId urlSlug birthDate hasProfile __typename }           mark nationality place points qualified records wind remark details { event eventId raceNumber mark wind placeInRound placeInRace points overallPoints placeInRoundByPoints overallPlaceByPoints __typename }           __typename }         startList { competitor { birthDate country id             name urlSlug __typename }           order pb           sb            bib __typename }         wind __typename }       __typename }     __typename }   options { days { date day __typename }     events { gender id       name combined __typename }     __typename }   parameters { competitionId day eventId __typename }   __typename } }` }), "method": "POST", })).json; window.cache??={}; if (typeof nameFixer === 'undefined') {  const script = Object.assign(document.createElement('script'), { src: 'https://unpkg.com/name-fixer@1.0.0' });  document.body.appendChild(script);  await new Promise(res => script.addEventListener('load', res)); } titleExists=async (name)=>{  const enLabelTitleMatch = await fetch(pre+'https://en.wikipedia.org/wiki/' + name.replace('|', ));  return enLabelTitleMatch.status === 200; } getTitle=async (id,name,evt=,year)=>{  const words = name.split(' ');  const lnameStart = words.findIndex(w => w.toUpperCase === w);  const fname = words.slice(0, lnameStart).join(' ');  const lname = words.slice(lnameStart).join(' ');  name = fname + ' ' + nameFixer.nameFixer(lname);  name = name.replace('LI', 'Li').replace('XI', 'Xi');  if (cache[id]) return cache[id];  const pages = await (await fetch('https://www.wikidata.org/w/api.php?' + new URLSearchParams({ action: 'query', format: 'json', list: 'search', srsearch: `haswbstatement:P1146=${id}`, }))).json; const qid = pages.query.search[0]?.title;  if (qid) {    const entity = await (await fetch('https://www.wikidata.org/w/api.php?' + new URLSearchParams({ action: 'wbgetentities', format: 'json', ids: qid, }))).json;   const sitelinks = entity.entities[qid].sitelinks;    const enTitle = sitelinks.enwiki?.title;    if (enTitle) {      cache[id] = `' : ''}`; return cache[id]; }   let enLabel = entity.entities[qid].labels.en?.value ?? name; const enLabelNoParens = enLabel; if (await titleExists(enLabel)) enLabel += ' (athlete)'; // todo awb job? const otherWikis = Object.keys(sitelinks).filter(key => !key.startsWith('commons') && key.endsWith('wiki')); if (otherWikis.length) { const positionals = otherWikis.map(ow => `|${ow.replace('wiki', )}|${sitelinks[ow].title}`).join(); cache[id] = `${enLabel}${positionals}${enLabel.includes('(') ? ``;     return cache[id];    }    cache[id] = `${enLabel}`;    return cache[id];  }  if (await titleExists(name)) {    name += ' (athlete)|';    if (await titleExists(name)) {      const el = evt.toLowerCase;      const parens = el.includes('mH') ? 'hurdler' : el.includes('high jump') ? 'high jumper' : el.includes('long jump') ? 'long jumper' : el.includes('triple jump') ? 'triple jumper' : el.includes('shot put') ? 'shot putter' : el.includes('discus') ? 'discus thrower' : el.includes('hammer') ? 'hammer thrower' : el.includes('javelin') ? 'javelin thrower' : el.includes('steeplchase') ? 'steeplechase runner' : 'runner';      name = name.replace('(athlete)', `(${parens})`);      if (await titleExists(name)) name = name.replace(`(${parens})`, `(${parens}, born ${year})`);    }  }  cache[id] = `${name}`;  return cache[id]; } mark2secs=(mark, isField = false)=>{ const parts = mark.split(':'); let ret; if (parts.length === 1) ret = +mark; else if (parts.length === 2) ret = +parts[0] * 60 + +parts[1]; else ret = +parts[0] * 60 * 60 + +parts[1] * 60 + +parts[2]; if (Number.isNaN(ret)) return isField ? -Infinity : Infinity; return ret; } const medalRows = []; for (const dayData of Object.values(data)) for (const eventTitle of dayData.data.getCalendarCompetitionResults?.eventTitles ?? []) { if (![null].includes(eventTitle.eventTitle)) continue; for (const evt of eventTitle.events) { const isLastEvt = eventTitle.events.indexOf(evt) === eventTitle.events.length - 1; const isField = ['jump', 'throw', 'vault', 'discus', 'put'].some(s => evt.event?.toLowerCase.includes(s)); const stages = Object.values(evt.races.reduce((acc, r) => { acc[r.race] ??= []; acc[r.race].push(r); return acc; }, {})); for (const stage of stages) { const isLastStage = stages.indexOf(stage) === stages.length - 1; const isFinal = stage[0].race === 'Final'; if (!isFinal) continue; const isMulti = stage.length > 1; let medalRow = `|-\n| ${evt.event.replace(' indoor', '')}\n`; const results = stage.flatMap(race => race.results.map(res => ({...res, raceNumber: race.raceNumber}))).sort((a, b) => isField ? mark2secs(b.mark, true) - mark2secs(a.mark, true) : mark2secs(a.mark) - mark2secs(b.mark)).filter((r, i, arr) => r.competitor.teamMembers?.length || arr.findIndex(r2 => r.competitor.urlSlug === r2.competitor.urlSlug) === i); for (const result of results.slice(0, 3)) { const pl = ['DNS', 'DNF', 'DQ', 'NM'].includes(result.mark) ? '' : results.indexOf(result) + 1; const name = result.competitor.name; const dob = new Date(result.competitor.birthDate); const id = result.competitor.urlSlug?.split('-').at(-1).replace(/^0/, ''); medalRow += `| ${id ? `` : ` ${(await Promise.all(result.competitor.teamMembers.map(async tm => await getTitle(tm.id, tm.name)))).join(' ')}`} || ${result.mark + (isField && pl ? ' m' : '')}\n`; }   medalRows.push(medalRow); } } } let out = ''; for (const gen of [`Men's `, `Women's `]) { out += `===${gen.replace(`'s `, '')}===\n{| \n`; out += medalRows.filter(row => row.includes(gen)).map(row => row.replace(gen, )).sort((a, b) => {   const evtOrder = ['100m', '200m', '400m', '800m', '1500m', '5000m', '10,000m', 'Marathon', '110mH', '100mH', '400mH', '3000mSC'].reverse;    const bScore = evtOrder.findIndex(evt => b.includes(evt) && !b.includes('x' + evt));    const aScore = evtOrder.findIndex(evt => a.includes(evt) && !a.includes('x' + evt));    if (bScore === -1 && aScore === -1) return a.localeCompare(b);    return bScore - aScore;  }).join(); out += '|}\n'; }