cglogo

Play Wiki Fight in your browser NOW!

10 June 2023

Inspired by Wiki Arena and other games like it, here’s a game created in plain old HTML, Javascript and CSS which uses Wikipedia’s API and some JQuery magic to put 2 randomly chosen articles to battle! Does it work? How does it work? Let’s find out, but first…. Play it in your browser now or watch the video (opens in a new tab).

What makes it work?

Every time the page loads, the page makes a few requests into Wikipedia’s API – It’s 3 per article to get the articles name, excerpt, view count, length, most recent edit time and the time the article was originally created. If it could be less it would be, but unfortunately it looks like the APIs are separated out (and you can’t simultaneously get the first and last revision without pulling the entire history).

Following the rules of the road is crucial, which is why every time a request is made to the API service, we include a header which identifies what’s polling it and where it’s coming from – For us that’s contained in the CGWF_USER_AGENT method you can see throughout the code examples below.

So what starts it off? We don’t call the API unless we have to, but when we do we call the GetRandomWikis function below:

async function GetRandomWikis () {
    let info;
    let pages = [];
    
    for ( let i=0; i<2; i++ ) {
        info = await $.ajax( {
            url: 'https://en.wikipedia.org/w/api.php?action=query&prop=extracts|info|revisions&rvprop=timestamp&rvdir=older&generator=random&exchars=300&exlimit=1&explaintext=1&grnnamespace=0&grnlimit=1&format=json',
            headers: {
                'Api-User-Agent': CGWF_USER_AGENT(),
            },
            dataType: 'jsonp',
            cors: true,
        } );
        info = info.query.pages;

        for ( let page in info ) {
            let article = info[page];
            article['pageViews'] = await getPageViews( article.title );
			      article['created'] = await getCreationDate( article.title, article.pageid );
			      article['edited'] = new Date( article['revisions'][0]['timestamp'] ).getTime() / 1000,
            article['extract'] = article['extract'].replaceAll( "\n\n", "\n" );
            article['extract'] = article['extract'].replaceAll( "\n", "<br />" );
            pages.push( article );
        }
    }

    return pages;
}

This hits the API and gets the title, extract and most recent edit all in one hit, but you’ll notice it has to make seperate calls to get the creation date and the number of page views. Let’s take a look at the getting the creation date.

async function getCreationDate ( title, articleid) {
	info = await $.ajax( {
			url: "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=revisions&rvlimit=1&rvprop=timestamp&rvdir=newer&titles=" + title,
            headers: {
                'Api-User-Agent': CGWF_USER_AGENT(),
            },
            dataType: 'jsonp',
            cors: true,
	} );
	
	return new Date( info.query.pages[""+articleid]['revisions'][0]['timestamp'] ).getTime() / 1000;
}

As you can see, the query to get the creation date of an article is basically the same as getting the last edit, but instead of getting it for a random article we include the title and sort in the opposite order – And to make it easier we also include the Article ID since we have it already as part of the last call.

Getting the view count is a different API altogether, it uses the Wikimedia API (which covers all of the Wikipedias) instead of the Wikipedia one. We grab the info and add all the pageviews together before getting it back into the hands of the parent function.

async function getPageViews ( title ) {
    let start = new Date(new Date().setDate(new Date().getDate() - 31)).yyyymmdd();
    let end = new Date().yyyymmdd();

    let url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia.org/all-access/user/' + wikitizeTitle( title ) + '/daily/' + start + '/' + end;
    let info = await $.ajax({
        url,
        headers: {
            'Api-User-Agent': CGWF_USER_AGENT(),
        },
        dataType: 'json',
        cors: true,
    });

    let views = 0;

    info.items.forEach( item => {
        views += item.views;
    } );

    return views;
}

Why not have a go at making something like it yourself… and of course I’ll carry on iterating, as it is it’s really a MVP…

Share to socials