MediaWiki:CommonsGame.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
// Experimental work to help categorizing Commons images
$(function () {
	'use strict';
	
	if (mw.config.get('wgCanonicalSpecialPageName') !== "Blankpage") {
		location.href = mw.util.getUrl('Special:BlankPage/commonsgame', { withJS: "MediaWiki:CommonsGame.js" });
		return;
	}
	
	function randomMediaInUncategorizedCategory() {
		var categories = [
			'All media needing categories as of 2015',
			'All media needing categories as of 2016',
			'All media needing categories as of 2017'
		];
		var category = categories[Math.floor(Math.random() * categories.length)];
		return $.get('/wiki/Special:RandomInCategory/' + category).then(function (page) { 
			var interestingElements = $('#firstHeading, #file img', page);
			return {
				title: interestingElements[0].innerText,
				thumbnail: interestingElements[1].src.replace(/\/\d+px-/, '\/300px-'),
				imageName: decodeURI(interestingElements[1].src.split('/').slice(-1)[0]).split('px-').slice(-1)[0]
			};
		});
	}
	
	function getImageSuggestedCategories(media) {
		return $.getJSON('https://deep-learning-services.wmflabs.org/category/' + media.imageName);
	}

	function loadPages(titles) {
		return new mw.Api().get({
			action: 'query',
			prop: 'revisions',
			titles: titles,
			rvprop: 'content'
		}).then(function (data) {
			return Object.keys(data.query.pages).reduce(function (result, pageid) {
				result[data.query.pages[pageid].title] = data.query.pages[pageid].revisions[0]['*'];
				return result;
			}, {});
		});
	}

	function savePage(title, text, summary) {
		return new mw.Api().post({
			action: 'edit',
			title: title,
			text: text,
			summary: summary || '',
			bot: '',
			token: mw.user.tokens.get('csrfToken')
		}).then(function (response) {
			return response.error ? new $.Deferred().reject(response.error) : response;
		});
	}
	
	function addCategoryAndRemoveMediaNeedingCategory(page, categoryToAdd) {
		return loadPages([page]).then(function (pages) {
			var text = pages[Object.keys(pages)[0]]
				.replace(/\[\[Category:All media needing categories.*\]\]|\{\{Uncategorized.*/, '')
				.replace('[[' + categoryToAdd + ']]\n', '') // remove if currently available
				.trim() + '\n[[' + categoryToAdd + ']]';
			return savePage(page, text, '+[[' + categoryToAdd + ']] added using [[Commons:CommonsGame|CommonsGame]]');
		});
	}
	
	var tries = 0; // not cool for being globally modified but I don't care for now

	function addMediaToGame() {
		var media;
		var suggestionCell = $('<div>', {
			class: 'commonsgame-single-media',
			style: 'display: inline-block; width: 300px; padding: 1em; border: 1px solid lightgrey; border-radius: 1em; margin: 0.5em; vertical-align: top;'
		}).append($('<center>').append($('<img>', {
			style: 'padding: 4em',
			width: 40,
			src: 'https://upload.wikimedia.org/wikipedia/commons/3/30/Chromiumthrobber.svg'
		}))).appendTo('#commonsgame-container');
		
		return randomMediaInUncategorizedCategory().then(function (result) {
			media = result;
			return getImageSuggestedCategories(media);
		}).then(function (result) {
			if (result.categories.length === 0) return new $.Deferred().reject('nothing matched');
			suggestionCell.empty().append(
				$('<a>', { href: mw.util.getUrl(media.title) }).append(
					$('<img>', { width: 300, src: media.thumbnail }),
					'<br>',
					$('<center>', { text: media.title.replace('File:', '') })
				),
				'<br>',
				$('<small style="font-size: 50%">').text(result.tags.map(function (tagRow) {
					return tagRow[0] + ': ' + Math.round(tagRow[1] * 100) + '%';
				}).join(', ')),
				'<br>',
				'<br>',
				'<small>Suggested categories:</small>',
				$('<div>').append(result.categories.slice(0, 5).map(function (category) {
					return $('<div class="commonsgame-category">').append(
						$('<button>', { text: 'Add' }).click(function () {
							var that = $(this).closest('.commonsgame-category');
							that.css({ background: 'grey', opacity: 0.5 }).find('button').hide();
							addCategoryAndRemoveMediaNeedingCategory(media.title, category).then(function () {
								that.css('background', 'green');
							});
						}),
						' ',
						$('<small>').append($('<a>', { href: mw.util.getUrl(category), text: category.replace('Category:', '') }))
					);
				})),
				'<br>',
				$('<center>').append($('<button>', { text: 'Done', class: 'mw-ui-button mw-ui-progressive' }).click(function () {
					$(this).closest('.commonsgame-single-media').hide(400);
					addMediaToGame();
				}))
			);
			tries = 0;
		}).then(undefined, function () { // retry
			suggestionCell.remove();
			if (++tries < 3) return addMediaToGame();
		});
	}
	
	(function() {
		document.title = 'CommonsGame';
		$('#content').empty().append($('<div>', { id: 'commonsgame-container' }));
		Array(10).join('.').split('').map(function () {
			return function () {
				var promise = new $.Deferred();
				setTimeout(function () {
					promise.resolve();
					addMediaToGame();
				}, 1000);
				return promise;
			};
		}).reduce(function (promise, next) {
			return promise.then(next);
		}, new $.Deferred().resolve());
	}());
});