// ==UserScript== // @name IMDB List Importer // @namespace Neinei0k_imdb // @include http://www.imdb.com/list/edit* // @version 5.1 // @grant none // @description Import list of titles, people or characters in the imdb list // @downloadURL none // ==/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"; } else if (document.getElementsByClassName('list_people').length !== 0) { this.log("i", "List type: people"); re = "nm"; } else if (document.getElementsByClassName('list_titles').length !== 0) { this.log("i", "List type: titles"); re = "tt"; } else { this.log("e","Could not determine type of the list"); return []; } re += "[0-9]{7}"; if (this.csv.checked) { return this.read_csv(re); } else { re = new RegExp(re); 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) { re = new RegExp("^" + re + "$"); var list = []; text = this.text.split('\n'); // Find const and description field numbers. try { var fl = JSON.parse('[' + text[0] + ']'); var fll = fl.length var const_field = fl.indexOf('const'); if (const_field === -1) throw "Field 'const' not found."; var desc_field = fl.indexOf('description'); if (desc_field === -1) throw "Field 'description' not found."; } catch (err) { this.log("e","Input line 1: " + err); return []; } this.log("i","Found csv file fields const(" + const_field + ") and description(" + desc_field + ")"); text.shift(); // Add elements to the list for (var i = 0; i < text.length; i++) { if (text[i].trim().length === 0) continue; try { fl = JSON.parse('[' + text[i] + ']'); if (fll !== fl.length) throw "Invalid number of fields."; if (re.exec(fl[const_field]) === null) throw "Invalid 'const' field."; } catch (err) { this.log("e","Input line " + (i+2) + ": " + err); 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 = '
'; if (c) { s += '
'; s += '
'; } else { s += ''; s += 'Looks like your browser does not support File API for reading local files.'; s += '
'; } s += '
'; s += '
'; s += '
Set-up parameters. Insert text or choose file. Press \'Import List\' button.
'; s += ''; 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);