IMDB List Importer

Import list of titles, people or characters in the imdb list

目前为 2017-07-14 提交的版本。查看 最新版本

// ==UserScript==
// @name         IMDB List Importer
// @namespace    Neinei0k_imdb
// @include      http://www.imdb.com/list/edit*
// @version	     5.0
// @grant        none
// @description  Import list of titles, people or characters in the imdb list
// ==/UserScript==

var o = {

init: function(e) {
	this.etext = e.querySelector('textarea');
	this.efile = e.querySelector('input[type="file"]');
	this.eready = e.children[10];
	var checkboxes = e.querySelectorAll('input[type="checkbox"]');
	this.source = checkboxes[0]; 
	this.csv = checkboxes[1];
	this.unique = checkboxes[2];
},

run: function(event) {
	this.text = this.etext.value;
	if (this.source.checked) { // read data from file
		var file = this.efile.files[0];
		if (file !== undefined) {
			this.log("i","Reading file " + file.name);
			var r = new FileReader();
			r.onload = this.file_onload.bind(this);
			r.readAsText(file);
		} else {
			this.log("e","File is undefined");
		}
	} else { // read data from input element
		this.add_list(this.create_list());
	}
},

file_onload: function(e) {
	if (e.target.error === null) {
		this.text = e.target.result;
		this.add_list(this.create_list());
	} else {
		this.log("e","File reading error: " + e.target.error);
	}
},

log: function(level,msg) {
	var l = "";
	if (level === "i") l = "Info: ";
	else if (level === "e") l = "Error: ";
	if (l.length !== 0)
		console.log("IMDB List Importer: " + l + msg);
	if (level == "n" || level == "e")
		this.eready.innerText = msg;
},

create_list: function() {
	var re;
	// Find type of the list
	if (document.getElementsByClassName('list_characters').length !== 0) {
		this.log("i", "List type: characters");
		re = /ch[0-9]{7}/;
	} else if (document.getElementsByClassName('list_people').length !== 0) {
		this.log("i", "List type: people");
		re = /nm[0-9]{7}/;
	} else if (document.getElementsByClassName('list_titles').length !== 0) {
		this.log("i", "List type: titles");
		re = /tt[0-9]{7}/;
	} else {
		this.log("e","Could not determine type of the list");
		return [];
	}

	if (this.csv.checked) {
		return this.read_csv(re);
	} else {
		var list = [];
		var e;
		var text = this.text;
		while ((e = re.exec(text)) !== null) {
			var flag = '';
			if (this.unique.checked) flag = 'g';
			text = text.replace(new RegExp(e[0], flag), '');
			list.push({const: e[0], description: ""});
		}
		return list;
	}
},

read_csv: function(re) {
	var list = [];
	text = this.text.split('\n');

	// Remove empty strings from the end
	var i = text.length-1;
	for (;i >= 0 && text[i].trim().length === 0; i--);
	i++;
	text.splice(i,text.length - i);

	// Find const and description field numbers.
	var fl = JSON.parse('[' + text[0] + ']');
	var fll = fl.length
	var const_field = fl.indexOf('const')
	var desc_field = fl.indexOf('description');
	if (const_field === -1 || desc_field === -1) {
		this.log("e","File line 1: fields 'const' or/and 'description'" +
		             "are not found.");
		return [];
	}
	this.log("i","Found csv file fields const(" + const_field +
	             ") and description(" + desc_field + ")");
	text.shift();

	// Add elements to the list
	for (i = 0; i < text.length; i++) {
		fl = JSON.parse('[' + text[i] + ']');
		if (fll !== fl.length || re.exec(text) === null) {
			this.log("e","File line " + (i+2) +
		                 ": invalid data structure");
			return [];
		}
		if (this.unique.checked) {
			var exists = list.findIndex(function(v){
				return v.const === fl[const_field];
			});
			if (exists !== -1) continue;
		}
		list.push({const: fl[const_field],description: fl[desc_field]});
	}
	return list;
},
	
add_list: function(list) {
	if (list.length === 0)
		return;

	var msg = "Elements to add: ";
	for (var i in list)
		msg += list[i].const + ",";
	this.log("i",msg);

	var l = {};
	l.list = list;
	l.ready = 0;
	l.list_id = /ls[0-9]{1,}/.exec(location.href)[0];
	this.sendNext(l);
},

sendNext: function(l) {
	this.log("i",'Add element ' + l.ready + ': ' + l.list[l.ready].const);
	this.send_request(this.check_item, l, 'const=' + l.list[l.ready].const +
	                                     '&list_id=' + l.list_id);
},

send_request: function(f,l,d) {
	var x = new XMLHttpRequest();
	x.onreadystatechange = f.bind(this,l);
	x.open('POST', '/list/_ajax/edit', true);
	x.setRequestHeader('Content-Type',
	  'application/x-www-form-urlencoded; charset=UTF-8');
	x.send(d);
},

check_item: function(l, e) {
	this.log("i","Add element(" + l.list[l.ready].const +
	             ") request: readyState(" + e.target.readyState +
	             "), status(" + e.target.status + ")");
	if (e.target.readyState == 4 && e.target.status == 200) {
		if (l.list[l.ready].description.length !== 0) {
			this.send_request(this.check_item_desc, l,
			                  'description=' + l.list[l.ready].description +
			                  '&list_id=' + l.list_id + '&list_item_id=' +
			                  JSON.parse(e.target.responseText).list_item_id);
		} else {
			this.showReady(l);
		}
	}
},

check_item_desc: function(l,e) {
	this.log("i","Add element(" + l.list[l.ready].const +
	             ") description request: readyState(" + e.target.readyState +
	             "), status(" + e.target.status + ")");
	if (e.target.readyState == 4 && e.target.status == 200) {
		this.showReady(l);
	}
},

showReady: function(l) {
	l.ready += 1;
	this.log("n",'Ready ' + l.ready + ' of ' + l.list.length + '.');
	if (l.ready == l.list.length) {
		location.reload();
	} else {
		this.sendNext(l);
	}
},

change: function(e) {
	var s = e.target.checked;
	this.etext.disabled = s;
	this.efile.disabled = !s;
},

};

var c = window.File && window.FileReader && window.FileList && window.Blob;
var div = document.createElement('div');
div.setAttribute('class', 'add');
var s = '<textarea style="background-color: white"></textarea><br>';
if (c) {
	s += '<input type="file" disabled><br>';
	s += '<label>';
	s += '<input type="checkbox" style="width: initial;">';
	s += '<span style="font-weight: normal;">';
	s += 'Import from file (otherwise import from text)';
	s += '</span>';
	s += '</label><br>';
}
s += '<label>';
s += '<input type="checkbox" checked style="width: initial;">';
s += '<span style="font-weight: normal;">Data from .csv file</span>';
s += '</label><br>';
s += '<label>';
s += '<input type="checkbox" style="width: initial;">';
s += '<span style="font-weight: normal;">Add only unique elements</span>';
s += '</label><br>';
s += '<div>Insert text with id\'s in the field above and press button "Import list"</div>';
s += '<button class="btn">Import List</button>';
div.innerHTML = s;

o.init(div);
div.querySelector('button').addEventListener('click',o.run.bind(o),false);
if (c) {
	o.source.addEventListener('change',o.change.bind(o),false);
}

var list_edit = document.querySelector('.list_edit');
var footer = document.querySelector('.footer');
list_edit.insertBefore(div, footer);