User:Satricious/covidstats
Appearance
NOTE: I have posted about this in Template talk:COVID-19 cases in Asia#Automated script that can update all countries stats from virusncov.com
Below is a script that I intend to run on Template:COVID-19 cases in Asia, it scrapes virusncov
Currently the code is rather unclean as I just whipped this script while I was bored in class but I intend to (hopefully) clean it up soon.
The script is really easy to run, once set up correctly it's almost as simple as clicking a button.
Ambitious list of sources to cover
|
---|
Yeah, yeah... there isn't a whole lot, I know. I'll add more later
|
How to run
[edit]- Show your bookmarks bar (Ctrl+⇧ Shift+B)
- Click on create a page, enter the name as 'run covidstats' (or whatever you like), and for the url, first enter
javascript:
, and then copy the code below and paste it after the colon - Save that bookmark, click it while on any Wikipedia page and it should work :^)
Once you click the button, give it a second or two and it will take you take you to the 'show changes' page with the changes made.
var region = "Asia";
var title = `Template:COVID-19_cases_in_${region}`;
if(!window.jQuery) {
alert("jQuery is required to run this script!");
throw Error("jQuery is missing");
}
function getDOM(url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", url, false);
xmlhttp.send();
parser = new DOMParser();
return parser.parseFromString(xmlhttp.responseText, "text/html");
}
function createWithTBody(b){
let obj = {};
Array.from(b.childNodes).filter(e => e.nodeName == "TR").forEach(e => {
let countryTarget;
let nodes = e.cells[1].childNodes;
if(nodes && (countryTarget = Array.from(nodes).find(ee => ee.className == "country-detail"))){
obj[countryTarget.textContent] = {
"totalCases": e.cells[2].innerText,
"activeCases": e.cells[6].innerText,
"totalDeaths": e.cells[4].innerText,
"totalRecoveries": e.cells[7].innerText
}
}
});
return obj;
}
var doc = getDOM("https://virusncov.com/");
var cases = createWithTBody(doc.querySelector("#table_stas tbody"));
var reg = /\|\-\n[^\n]+?\|([\w ]+)\]\]\n\|([\d, ]+)\n\|([\d, ]+)\n\|([\d, ]+)\n\|([\d, ]+)/gm; /* See https://regex101.com/r/rH3OCD/1 */
function transl(w){ /* wikitext -> virusncov name mismatch handling */
if(w == "South Korea") return "S. Korea";
if(w == "Macau") return "Macao";
if(w == "United Arab Emirates") return "UAE";
return w;
}
function parseNum(num) {
if(num == "" || !num) return 0;
return parseInt(num.replace(/,/g, "").trim());
}
function comma(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function anyChange(wiki, ncov) {
return (parseNum(wiki.totCases) != parseNum(ncov.totalCases))
|| (parseNum(wiki.actCases) != parseNum(ncov.activeCases))
|| (parseNum(wiki.totDeaths) != parseNum(ncov.totalDeaths))
|| (parseNum(wiki.totRecovs) != parseNum(ncov.totalRecoveries));
}
var updated = [];
/* c = cumulative */
var cTotalCases = 0;
var cActiveCases = 0;
var cTotalDeaths = 0;
var cTotalRecoveries = 0;
function update(tc, ac, td, tr) {
cTotalCases += parseNum(tc);
cActiveCases += parseNum(ac);
cTotalDeaths += parseNum(td);
cTotalRecoveries += parseNum(tr);
}
function pad(n){
return n.toString().padStart(2, '0');
}
function UTCtime() {
const date = new Date();
const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
return `${date.getUTCDate()} ${months[date.getUTCMonth()]} ${date.getUTCFullYear()}, ${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())} UTC`;
}
function replacer(match, country, totCases, actCases, totDeaths, totRecovs, offset, str) {
if(!match || match == "") return "";
country = transl(country);
if(!(country in cases)) throw Error(`cannot resolve country: ${country}`);
if(parseNum(cases[country].totalCases) < parseNum(totCases)) {
/* console.log(`Skpping ${country} because it is more up to date`) */
return match;
}
const cc = cases[country];
if(anyChange({totCases, actCases, totDeaths, totRecovs}, cases[country])) {
updated.push(country);
return `${match.split("\n")[0]}\n${match.split("\n")[1]}\n|${cc.totalCases || 0}\n|${cc.activeCases || 0}\n|${cc.totalDeaths || 0}\n|${cc.totalRecoveries|| 0}`;
}else{
return match;
}
}
function summer(match, country, totCases, actCases, totDeaths, totRecovs, offset, str) {
if(!match || match == "") return "";
update(totCases, actCases, totDeaths, totRecovs);
return match;
}
var cumulReg = /\|'''Total'''\n.+?'([\d,]+)'''\s*?\n.+?'([\d,]+)'''\s*?\n.+?'([\d,]+)'''\s*?\n.+?'([\d,]+)'''/gm; /* See https://regex101.com/r/Y316l5/1 */
function goToShowChangesScreen(title, wikicode, editSummary) {
let titleEncoded = encodeURIComponent(title.replace(/ /g, "_")); /* must incl namespace */
let wgServer = mw.config.get('wgServer');
let wgScriptPath = mw.config.get('wgScriptPath');
let baseURL = wgServer + wgScriptPath + '/';
$(`<form action="${baseURL}index.php?title=${titleEncoded}&action=submit" method="POST"/>`)
.append($('<input type="hidden" name="wpTextbox1">').val(wikicode))
.append($('<input type="hidden" name="wpSummary">').val(editSummary))
.append($('<input type="hidden" name="mode">').val('preview'))
.append($('<input type="hidden" name="wpDiff">').val('Show changes'))
.append($('<input type="hidden" name="wpUltimateParam">').val('1'))
.appendTo($(document.body))
.submit();
}
function getWikitext(title){
const apiEndpoint = "https://en.wikipedia.org/w/api.php";
const params = `action=query&prop=revisions&rvprop=content&format=json&titles=${title}&rvslots=main`;
return fetch(apiEndpoint + "?" + params + "&origin=*")
.then(res => res.json())
.then(res => res.query.pages[Object.keys(res.query.pages)[0]].revisions[0].slots.main['*']);
}
getWikitext(title).then(wikit => {
modified = wikit.replace(reg, replacer);
modified = modified.replace(reg, summer);
modified = modified.replace(cumulReg, (a) => {
if(!a || a == "") return a;
return `|'''Total'''\n|'''${comma(cTotalCases)}'''\n|'''${comma(cActiveCases)}'''\n|'''${comma(cTotalDeaths)}'''\n|'''${comma(cTotalRecoveries)}'''`
});
if(!updated.length) {
alert("No changes to be made. Already up to date!");
return;
}
const summary = `Updated (${updated.join(", ")}) with virusncov.com data as of ${UTCtime()} ([[User:Satricious/covidstats|covidstats]])`;
goToShowChangesScreen(title, modified, summary)
})