IMDB List Importer

Import list of titles or people in the imdb list

目前為 2020-05-22 提交的版本,檢視 最新版本

// ==UserScript==
// @name         IMDB List Importer
// @namespace    Neinei0k_imdb
// @include      https://www.imdb.com/list/*
// @version	 7.2
// @license      GNU General Public License v3.0 or later
// @grant        GM.xmlHttpRequest
// @description  Import list of titles or people 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]; // DOM element with messages for the user.
	var checkboxes = e.querySelectorAll('input[type="checkbox"]');
	this.source = checkboxes[0];
	this.csv = checkboxes[1];
	this.unique = checkboxes[2];
  
  var hidden_element =  document.querySelector('#main > input'); // Unknown hidden element. Data needs to be send with all requests.
  if (hidden_element === null) {
   	this.log('e','Hidden element not found');
  } else {
  	this.hidden_data = hidden_element.id + "=" + hidden_element.value;
  }
},

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 = "";
  switch (level) {
    case 'i': l = "Info: "; break;
    case 'w': l = "Warning: "; break;
    case 'e': l = "Error: "; break;
  }
	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.querySelector('[data-type="Characters"]') !== null) {
		this.log("i", "List type: characters");
		re = "ch";
	} else*/
  if (document.querySelector('[data-type="People"]') !== null) {
		this.log("i", "List type: people");
		re = "nm";
	} else if (document.querySelector('[data-type="Titles"]') !== null) {
		this.log("i", "List type: titles");
		re = "tt";
	} else {
		this.log("e","Could not determine type of the list");
		return [];
	}
	re += "[0-9]{7,8}";

	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 = [];
  
  // Parse csv
  var text = this.text.split('\n'); // Separate by lines
  this.text = null; // Variable may have lots of data which is no longer needed
  var parsed_text = [];
  for (var i in text) { // For each line
    if (text[i].trim().length === 0) { // Ignore empty lines including lines with only white space characters
      continue;
    }
    var state = 0; // 0 - outside of double quotes (comma character is the separator), 1 - inside double quotes (comma character is part of a field)
    var parsed_line = [""];
    for (var j in text[i]) {
      if (state === 0 && text[i][j] == ',') {
        parsed_line.push("");
      } else if (text[i][j] == '"') {
        state = (state + 1) % 2;
      } else {
        parsed_line[parsed_line.length-1] += text[i][j];
      }
    }
    parsed_text.push(parsed_line);
  }
  text = parsed_text;
  
  // console.log(text); // print parsed data

  var fl = "";
  var fll = "";
  var const_field = "";
  // Find const and description field numbers.
    try {
    if (text.length < 2) { // There must be at least 2 rows in the data
    	throw "No data";
    }
		fl = text[0];
		fll = fl.length;
		const_field = fl.indexOf('const');
		if (const_field === -1) {
      const_field = fl.indexOf('Const');
      if (const_field === -1) {
      	throw "Field 'const' not found.";
      }
    }
	} catch (err) {
		this.log("e","Input line 1: " + err);
		return [];
	}
  var desc_field = fl.indexOf('description');
		if (desc_field === -1) {
      desc_field = fl.indexOf('Description');
    }
  
	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++) {
		if (text[i].length === 0)
			continue;
		try {
			fl = 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: (desc_field == -1 ? "" : fl[desc_field])});
	}
 
  // console.log(list); // Print final list
  
	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, 'https://www.imdb.com/list/' + l.list_id + '/' + l.list[l.ready].const + '/add', this.hidden_data);
},

send_request: function(f,l,u,d) {
  GM.xmlHttpRequest({
  	method: "POST",
    url: u,
    data: d,
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    },
    onreadystatechange: f.bind(this,l)
  });
	/*var x = new XMLHttpRequest();
	x.onreadystatechange = f.bind(this,l);
	x.open('POST', u, true);
	x.setRequestHeader('Content-Type',
	  'application/x-www-form-urlencoded');
	x.send(d);*/
},

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

check_item_desc: function(l,e) {
	this.log("i","Add element(" + l.list[l.ready].const +
	             ") description request: readyState(" + e.readyState +
	             "), status(" + e.status + ")");
	if (e.readyState == 4 && e.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; // Check support of File API
var div = document.createElement('div');
div.setAttribute('class', 'search-bar');
div.style.height = "initial";
var s = '<textarea style="background-color: white; width: 100%; height: 100px; overflow: initial"></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>';
} else {
	s += '<span style="font-weight: normal;">';
	s += 'Looks like your browser does not support File API for reading local files.';
	s += '</span><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>Set-up parameters. Insert text or choose file. Press \'Import List\' button.</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('.lister-search');
list_edit.appendChild(div);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址