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.
// <nowiki>
function getAllOfCategory(category, array, cmcontinue) {
	return new mw.Api().get({
		action: 'query',
		list: 'categorymembers',
		cmtitle: category,
		format: 'json',
		cmlimit: 500,
		cmtype: 'file',
		cmcontinue: cmcontinue
	}).then(function (data) {
		//array = (array || []).concat(data.query.categorymembers.map(value => value.title));
		if (!data['continue']) {
			return array;
		}
		return getAllOfCategory(category, array, data['continue'].cmcontinue);
	});
}

function loadPage(title) {
  return new mw.Api().get({
    action: 'query',
    prop: 'revisions',
    titles: title,
    rvprop: 'content',
    format: 'json'
  }).then(function (data) {
    if (data.query.pages['-1'] !== undefined) { return null; }
    return $.map(data.query.pages, function (value) { return value; })[0].revisions[0]['*'];
  });
}

mw.loader.load('mediawiki.api.edit');
function savePage(title, text, summary) {
  return new mw.Api().postWithEditToken({
    action: 'edit',
    title: title,
    text: text,
    summary: summary,
    nocreate: '',
    minor: '',
    token: mw.user.tokens.get('csrfToken')
  }).then(function (data) {
    if (data.error && data.error.info) {
      mw.notify(data.error.info);
    }
  }, function (data) {
    mw.notify(data);
  });
}

var list = $('td a.image').get();
var batches = [];
for (var i = 0; i < list.length; i += 2) { batches.push({ from: 'File:' + list[i].firstChild.alt, to: 'File:' + list[i + 1].firstChild.alt }); }
batches.map(function (batch) {
  return function () { 
    return loadPage(batch.from).then(function (x) {
      var cats = x.match(/Category:[^\]]*/g).filter(function (x) { return ['Category:Noto Color Emoji', 'Category:Uploaded with VicuñaUploader'].indexOf(x) === -1; });
      return loadPage(batch.to).then(function (content) {
        cats = cats.filter(function (x) { return content.indexOf(x) === -1; });
        if (cats.length === 0) { console.log('No change on ' + batch.to + ' needed!'); return; }
        return savePage(batch.to, content + '\n[[' + cats.join(']]\n[[') + ']]', 'Adding categories per Noto Emoji counterpart')
          .then(function (x) { console.log(batch.to + ' done!'); });
      });
    });
  };
}).reduce(function (defer, job) { return defer.then(job); }, $.Deferred().resolve());



$(".gallerytext a").get().map(function (x) { return x.title; }).map(function (file) {
  return function () {
    console.log('Starting ' + file);
    return loadPage(file).then(function (content) {
      return savePage(file, content.replace("license]}\n", "license]}}\n"), '');
    });
  }
}).reduce(function (defer, job) { // https://gist.github.com/ebraminio/515856764c30d12a9f6f
  return defer.then(job);
}, $.Deferred().resolve()).then(function () { console.log('Async Job Queue done'); });


function ucfirst(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
$($0).val().split('\n').map(function (raw, i) {
  var row = raw.split('\t');
  return function () {
    var file = ('File:Emoji ' + row[0].toLowerCase() + '.svg').replace(/ /g, '_');
    console.log(i, 'Starting ' + file);
    var defer = $.Deferred();
    setTimeout(function () {
      loadPage(file).then(function (content) {
        if (content === null) { console.log(file + ' is not existed'); return; }
        var newContent = content.replace('}}\n|', "\n\n'''Unicode name:''' " + ucfirst(row[1]) + "\n\n'''Annotations:''' " + row[2].split(', ').map(function (x) { return ucfirst(x); }).join(', ') + '\n}}\n|');
        if (newContent === content) { console.log('content is not changed!', file); return; }
        return savePage(file, newContent, 'from http://www.unicode.org/reports/tr51/full-emoji-list.html');
      }).then(defer.resolve, defer.resolve);
    }, 10000);
    return defer.promise();
  };
}).reduce(function (defer, job) { // https://gist.github.com/ebraminio/515856764c30d12a9f6f
  return defer.then(job);
}, $.Deferred().resolve());



////////////
var async = require('async');

var bot = require('nodemw');
var client = new bot('config.js');

var fs = require('fs');

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/upload');
var UploadedFile = mongoose.model('UploadedFile', { name: String });

client.logIn(function() {

  async.mapSeries(
    fs.readdirSync('.').filter(function (x) { return x.match(/\.svg$/); }),
    function (x, callback) {
      UploadedFile.find({ name: x }, function (err, files) {
        if (files.length !== 0) {
          console.log(x + ' is already uploaded! (mongoose)');
          callback();
          return;
        }


        client.getArticle('File:Twemoji_' + x, function (content, err) {
          if (content) {
            console.log(x + ' already exists!');
            var uploaded = new UploadedFile({ name: x });
            uploaded.save();
            callback();
            return;
          }
          client.upload(
            'Twemoji ' + x,
            fs.readFileSync(x),
            { text: '=={{int:filedesc}}==\n{{Information\n' +
              '|description = {{en|A colored [[:en:Emoji|Emoji]] from ' +
              '[https://github.com/twitter/twemoji Twitter Emoji project]}}\n' +
              '|source = https://github.com/twitter/twemoji\n' +
              '|author = Twitter\n}}\n\n' +
              '=={{int:license-header}}==\n' +
              '{{Cc-by-4.0|Twitter}}\n\n' +
              '[' + '[Category:Twitter Emoji]]'
            },
            function () {
              console.log(x + ' uploaded successfully!');
              var uploaded = new UploadedFile({ name: x }); 
              uploaded.save();
              callback();
            }
          );
        });
      });
    },
    function () {
      console.log('done');
    }
  );

});


// How many distinct pages on Wikimedia are using colored emoji? Currently 27741
// sql commons, SELECT COUNT(DISTINCT gil_page) FROM globalimagelinks WHERE gil_to LIKE "Emoji_%.svg";


///////////////////////////

var fs = require('fs'),
  cheerio = require('cheerio'),
  $ = cheerio.load(fs.readFileSync('full-emoji-list.html'));

var phantom = {};
// https://github.com/break24/PhantomOpenEmoji/blob/master/app/assets/javascripts/poe/index.json
JSON.parse(fs.readFileSync('phantom.json')).forEach(function (x) {
  if (x.unicode !== undefined) phantom[x.unicode] = x.name;
});

var result = [];
$('tr').get().forEach(function (row) {
  row = $('td', row).get().map(function (x) { return $(x).text(); });
  if (row.length === 0) { return; }
  result.push('|-');
  result.push('| ' + row[0]);
  result.push('| ' + row[1]);
  result.push('|style="font-size: 64px; line-height: 0.5;"| ' + row[2]);
  result.push('| [[File:Emoji u' + row[1].toLowerCase().replace(/[+u]/g, '') + '.svg|64px]]');
  result.push('| [[File:Twemoji ' + row[1].toLowerCase().replace(/[+u]/g, '').replace(/^0+/, '').replace(' ', '-') + '.svg|64px]]');
  result.push('| [[File:Emojione ' + row[1].toUpperCase().replace(/[+uU]/g, '').replace(' ', '-') + '.svg|64px]]');
  var p = phantom[row[1].toLowerCase().replace(/[+u]/g, '').replace(/^0+/, '')];
  if (p !== undefined) {
    result.push('| [[File:PEO-' + p.replace(/_/g, ' ') + '.svg|64px]]');
  } else {
    result.push('| ');
  }
  result.push('| ' + row[12]);
  result.push('| ' + row[13]);
  result.push('| ' + row[14]);
  result.push('| ' + row[15]);
});

fs.writeFileSync('result.txt', result.join('\n'));

// before save
//$('#wpTextbox1').val($('#wpTextbox1').val().replace(new RegExp('\\[\\[(' + $('.new').get().map(function (x) { return x.title; }).join('|') + ')\\|64px\\]\\]', 'g'), ''))