User:Rillke/fastTransfer.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.
/** Please always jshint validate.
 * Script allows transferring of files from other wikis without having them to save somewhere on your hard drive
 * Only works in Mozilla Firefox (because it makes use of sendAsBinary) and possibly Chrome (using FormData)
 **/

var targetFileName = 'File:TestRillkeXwd2.jpg',
	sourceFileURL = '',
	sourceFile = 'File:Calypte Anna DSC 0038.jpg',
	text = "",
	comment = '',
	lastUploader;

var APIURL = mw.util.wikiScript('api'),
	MPB = '----------rillkesuploadscript' + Math.random();

function firstItem(o) {
	for (var i in o) {
		if (o.hasOwnProperty(i)) {
			return o[i];
		}
	}
}

function firstItemName(o) {
	for (var i in o) {
		if (o.hasOwnProperty(i)) {
			return i;
		}
	}
}

function encode_utf8(s) {
	return unescape(encodeURIComponent(s));
}

// Firefox does not allow setting file titles for "blob" data. That's why we have to send it as binary.
var clnt = $.client.profile();

if ("firefox" === clnt.name && clnt.versionNumber < 22) {
	var MultipartMessage = function() {
		this.msg = '';
	};

	MultipartMessage.fn = MultipartMessage.prototype;

	$.extend(MultipartMessage.fn, {
		createPart: function(param, data, ContentType, ContentTransferEncoding, ContentDisposition) {
			var p = '--' + MPB + '\n';
			if (!ContentDisposition) {
				p += 'Content-Disposition: form-data; name=\"' + param + '\"\n';
			} else {
				p += 'Content-Disposition: ' + ContentDisposition + '\n';
			}
			p += 'Content-Type: ' + ContentType + '\n';
			p += 'Content-Transfer-Encoding: ' + ContentTransferEncoding + '\n';
			return [p, '\n', data, '\n'].join('');
		},
		appendPart: function(param, data, ContentType, ContentTransferEncoding, ContentDisposition) {
			if (!ContentType) data = encode_utf8(data);
			this.msg += this.createPart(param, data, (ContentType || "text/plain; charset=UTF-8"), (ContentTransferEncoding || "8bit"), ContentDisposition);
		},
		send: function() {
			var msg = [this.msg, '--', MPB, '--', '\n'].join('');
			
			var req = new XMLHttpRequest();
			req.onreadystatechange = function(r) {
				if (4 !== req.readyState) return;
				console.log(req.responseText);
			};
			req.open('POST', APIURL);
			req.setRequestHeader('Content-Type', 'multipart/form-data; charset=UTF-8; boundary=' + MPB);
			req.sendAsBinary(msg);
		}
	});
} else {
	// We can use FormData in Chrome and Safari
	var MultipartMessage = function() {
		this.fd = new FormData();
	};

	MultipartMessage.fn = MultipartMessage.prototype;

	$.extend(MultipartMessage.fn, {
		appendPart: function(param, data, ContentType, ContentTransferEncoding, ContentDisposition) {
			if (ContentDisposition) {
				var bl = new Blob([data], { type: ContentType });
				this.fd.append(param, bl, ContentDisposition.match(/filename\=\"([^"]+)\"/)[1]);
			} else {
				this.fd.append(param, data);
			}
		},
		send: function() {
			var req = new XMLHttpRequest();
			req.open('POST', APIURL);
			req.send(this.fd);
			req.onreadystatechange = function(r) {
				if (4 !== req.readyState) return;
				console.log(req.responseText);
			};
		}
	});
}

var _gotToken = function(t, f) {
		targetFileName = targetFileName.replace(/^(?:File|Image):/, '');
		if (!t) console.log('Error. Unable to get token.');
		var mpm = new MultipartMessage();
		mpm.appendPart('format', 'json');
		mpm.appendPart('action', 'upload');
		mpm.appendPart('filename', targetFileName);
		mpm.appendPart('comment', comment);
		mpm.appendPart('text', text);
		mpm.appendPart('file', f, 'application/octet-stream', 'binary', 'attachment; name=\"file\"; filename=\"' + targetFileName + '\"');
		//mpm.appendPart('url', u );
		mpm.appendPart('ignorewarnings', 1);
		mpm.appendPart('token', t);
		mpm.send();
	};


var _gotURL = function() {
		comment = comment || ('Copying from ' + (sourceFile ? '[[' + sourceFile + ']]' : sourceFileURL) + (lastUploader ? ' (uploaded by [[User:' + lastUploader + ']])' : '') + ' using [[User:Rillke/Down\'NUp|Down\'NUp]].');
		var _gotFile = function(f) {
				if (!f) return console.log('Error. Unable to get file.');
				$.get(APIURL, {
					format: 'json',
					action: 'tokens'
				}, function(r) {
					_gotToken(r.tokens.edittoken, f);
				});
			};

			
		$.ajax({
			url: sourceFileURL,
			beforeSend: function (xhr) {
				xhr.overrideMimeType("text/plain; charset=x-user-defined");
			}
		}).done(function (d) {
			// Some more sophisticated stuff avoiding killing performance with memory allocations and thousands of function invocations
			var f = '',
				len = d.length,
				buff = 1018, // You can't apply huge arrays to functions!
				arrCC = Array(Math.min(buff, len)),
				arrF = Array(Math.ceil(len/buff));
				
			// Remove junk-high-order-bytes
			for (var i = 0, j = 0, z = 0; i < len; i++) {
				arrCC[j] = (d.charCodeAt(i) & 0xff);
				j++;
				if (0 === (j % buff)) {
					// Convert char codes to chars
					arrF[z] = String.fromCharCode.apply(null, arrCC);
					// Empty the char code array
					arrCC = Array(Math.min(buff, len - i - 1));
					z++;
					j = 0;
				}
			}
			if (j !== 0) arrF[z + 1] = String.fromCharCode.apply(null, arrCC);
			f = arrF.join('');
			_gotFile(f);
		});
	};

if (sourceFile) {
	sourceFile = 'File:' + sourceFile.replace(/^(?:File|Image):/, '');
	mw.loader.using('ext.gadget.libAPI', function() {
		mw.libs.commons.api.query({
			action: 'query',
			titles: sourceFile,
			prop: 'revisions|imageinfo',
			iiprop: 'url|user',
			rvprop: 'content'
		}, {
			url: APIURL,
			method: 'POST',
			cb: function(r) {
				var pg = firstItem(r.query.pages);
				text = text || pg.revisions[0]['*'];
				sourceFileURL = sourceFileURL || pg.imageinfo[0].url;
				lastUploader = pg.imageinfo[0].user;
				_gotURL();
			},
			// r-result, query, text
			errCb: function(t, r, q) {

			}
		});
	});
} else if (sourceFileURL) {
	_gotURL();
}