您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Import list of titles or people in the imdb list
当前为
- // ==UserScript==
- // @name IMDB List Importer
- // @namespace Neinei0k_imdb
- // @include https://www.imdb.com/list/*
- // @version 8.2
- // @license GNU General Public License v3.0 or later
- // @description Import list of titles or people in the imdb list
- // ==/UserScript==
- let elements = createHTMLForm();
- function log(level, message) {
- console.log("(IMDB List Importer) " + level + ": " + message);
- }
- function setStatus(message) {
- elements.status.textContent = message;
- }
- function createHTMLForm() {
- let elements = {};
- try {
- let root = createRoot();
- elements.text = createTextField(root);
- if (isFileAPISupported()) {
- elements.file = createFileInput(root);
- elements.isFromFile = createFromFileCheckbox(root);
- } else {
- createFileAPINotSupportedMessage(root);
- }
- elements.isCSV = createCSVCheckbox(root);
- elements.isUnique = createUniqueCheckbox(root);
- elements.status = createStatusBar(root);
- createImportButton(root);
- } catch (message) {
- log("Error", message);
- }
- return elements;
- }
- function isFileAPISupported() {
- return window.File && window.FileReader && window.FileList && window.Blob;
- }
- function createRoot() {
- let container = document.querySelector('.lister-search');
- if (container === null) {
- throw ".lister-search element not found";
- }
- let root = document.createElement('div');
- root.setAttribute('class', 'search-bar');
- root.style.height = 'initial';
- root.style.marginBottom = '30px';
- container.appendChild(root);
- return root;
- }
- function createTextField(root) {
- let text = document.createElement('textarea');
- text.style = "background-color: white; width: 100%; height: 100px; overflow: initial;";
- root.appendChild(text);
- root.appendChild(document.createElement('br'));
- return text;
- }
- function createFileInput(root) {
- let file = document.createElement('input');
- file.type = 'file';
- file.disabled = true;
- file.style.marginBottom = '10px';
- root.appendChild(file);
- root.appendChild(document.createElement('br'));
- return file;
- }
- function createFromFileCheckbox(root) {
- let isFromFile = createCheckbox("Import from file (otherwise import from text)");
- root.appendChild(isFromFile.label);
- root.appendChild(document.createElement('br'));
- isFromFile.checkbox.addEventListener('change', fromFileOrTextChangeHandler, false);
- return isFromFile.checkbox;
- }
- function createCheckbox(textContent) {
- let checkbox = document.createElement('input');
- checkbox.type = 'checkbox';
- checkbox.style = 'width: initial;';
- let text = document.createElement('span');
- text.style = 'font-weight: normal;';
- text.textContent = textContent;
- let label = document.createElement('label');
- label.appendChild(checkbox);
- label.appendChild(text);
- return {label: label, checkbox: checkbox};
- }
- function fromFileOrTextChangeHandler(event) {
- let isChecked = event.target.checked;
- elements.text.disabled = isChecked;
- elements.file.disabled = !isChecked;
- }
- function createFileAPINotSupportedMessage(root) {
- let notSupported = document.createElement('div');
- notSupported.style = 'font-weight: normal;';
- notSupported.style.marginTop = '10px';
- notSupported.style.marginBottom = '10px';
- notSupported.textContent = "Your browser does not support File API for reading local files.";
- root.appendChild(notSupported);
- }
- function createCSVCheckbox(root) {
- let isCSV = createCheckbox("Data from .csv file (otherwise extract ids from text)");
- isCSV.checkbox.checked = true;
- root.appendChild(isCSV.label);
- root.appendChild(document.createElement('br'));
- return isCSV.checkbox;
- }
- function createUniqueCheckbox(root) {
- let isUnique = createCheckbox("Add only unique elements");
- root.appendChild(isUnique.label);
- root.appendChild(document.createElement('br'));
- return isUnique.checkbox;
- }
- function createStatusBar(root) {
- let status = document.createElement('div');
- status.textContent = "Set-up parameters. Insert text or choose file. Press 'Import List' button.";
- status.style.marginTop = '10px';
- status.style.marginBottom = '10px';
- root.appendChild(status);
- return status;
- }
- function createImportButton(root) {
- let importList = document.createElement('button');
- importList.class = 'btn';
- importList.textContent = "Import List";
- root.appendChild(importList);
- importList.addEventListener('click', importListClickHandler, false);
- }
- function importListClickHandler(event) {
- if (elements.hasOwnProperty('isFromFile') && elements.isFromFile.checked) {
- readFile();
- } else {
- importList(extractItems(elements.text.value));
- }
- }
- function readFile() {
- let file = elements.file.files[0];
- if (file !== undefined) {
- log("Info", "Reading file " + file.name);
- setStatus("Reading file " + file.name);
- let fileReader = new FileReader();
- fileReader.onload = fileOnloadHandler;
- fileReader.readAsText(file);
- } else {
- setStatus("Error: File is not selected");
- }
- }
- function fileOnloadHandler(event) {
- if (event.target.error === null) {
- importList(extractItems(event.target.result));
- } else {
- log("Error", e.target.error);
- setStatus("Error: " + e.target.error);
- }
- }
- function extractItems(text) {
- try {
- let itemRegExp = getRegExpForItems();
- if (elements.isCSV.checked) {
- return extractItemsFromCSV(itemRegExp, text);
- } else {
- return extractItemsFromText(itemRegExp, text);
- }
- } catch (message) {
- log("Error", message);
- setStatus("Error: " + message);
- return [];
- }
- }
- function getRegExpForItems() {
- let listType;
- if (isPeopleList()) {
- log("Info", "List type: people");
- listType = "nm";
- } else if (isTitlesList()) {
- log("Info", "List type: titles");
- listType = "tt";
- } else {
- throw "Could not determine list type";
- }
- return listType + "[0-9]{7,8}";
- }
- function isPeopleList() {
- return document.querySelector('[data-type="People"]') !== null;
- }
- function isTitlesList() {
- return document.querySelector('[data-type="Titles"]') !== null;
- }
- function extractItemsFromCSV(re, text) {
- let table = parseCSV(text);
- let fields = findFieldNumbers(table);
- if (fields.description !== -1) {
- log("Info", "Found csv file fields Const(" + fields.const + ") and Description(" + fields.description + ")");
- } else {
- log("Info", "Found csv file field Const(" + fields.const + "). Description field is not found.");
- }
- re = new RegExp("^" + re + "$");
- let items = [];
- // Add elements to the list
- for (let i = 1; i < table.length; i++) {
- let row = table[i];
- if (re.exec(row[fields.const]) === null) {
- throw "Invalid 'const' field format on line " + (i+1);
- }
- if (elements.isUnique.checked) {
- let exists = items.findIndex(function(v){
- return v.const === row[fields.const];
- });
- if (exists !== -1) continue;
- }
- items.push({const: row[fields.const], description: (fields.description == -1 ? "" : row[fields.description])});
- }
- return items;
- }
- function parseCSV(text) {
- let lines = text.split(/\r|\n/);
- let table = [];
- for (let i=0; i < lines.length; i++) {
- if (isEmpty(lines[i])) {
- continue;
- }
- let isInsideString = false;
- let row = [""];
- for (let j=0; j < lines[i].length; j++) {
- if (!isInsideString && lines[i][j] === ',') {
- row.push("");
- } else if (lines[i][j] === '"') {
- isInsideString = !isInsideString;
- } else {
- row[row.length-1] += lines[i][j];
- }
- }
- table.push(row);
- if (isInsideString) {
- throw "Wrong number of \" on line " + (i+1);
- }
- if (row.length != table[0].length) {
- throw "Wrong number of fields on line " + (i+1) + ". Expected " + table[0].length + " but found " + row.length + ".";
- }
- }
- return table;
- }
- function isEmpty(str) {
- return str.trim().length === 0;
- }
- function findFieldNumbers(table) {
- let fieldNames = table[0];
- let fieldNumbers = {'const': -1, 'description': -1};
- for (let i = 0; i < fieldNames.length; i++) {
- let fieldName = fieldNames[i].toLowerCase().trim();
- if (fieldName === 'const') {
- fieldNumbers.const = i;
- } else if (fieldName === 'description') {
- fieldNumbers.description = i;
- }
- }
- if (fieldNumbers.const === -1) {
- throw "Field 'const' not found."
- }
- return fieldNumbers;
- }
- function extractItemsFromText(re, text) {
- re = new RegExp(re);
- let items = [];
- let e;
- while ((e = re.exec(text)) !== null) {
- let flag = '';
- if (elements.isUnique.checked)
- flag = 'g';
- text = text.replace(new RegExp(e[0], flag), '');
- items.push({const: e[0], description: ""});
- }
- return items;
- }
- function importList(list) {
- if (list.length === 0)
- return;
- let msg = "Elements to add: ";
- for (let i = 0; i < list.length; i++)
- msg += list[i].const + ",";
- log("Info", msg);
- let l = {};
- l.list = list;
- l.ready = 0;
- l.list_id = /ls[0-9]{1,}/.exec(location.href)[0];
- l.hiddenElementData = getHiddenElementData(); // Data needs to be send with all requests.
- sendItem(l);
- }
- function getHiddenElementData() {
- let hiddenElement = document.querySelector('#main > input');
- if (hiddenElement === null) {
- log("Error", "Hidden element not found. It is required to be sent with every request.");
- setStatus("Error: Hidden element not found. It is required to be sent with every request.");
- return "";
- }
- return hiddenElement.id + "=" + hiddenElement.value;
- }
- function sendItem(l) {
- log("Info", 'Add element ' + l.ready + ': ' + l.list[l.ready].const);
- let url = 'https://www.imdb.com/list/' + l.list_id + '/' + l.list[l.ready].const + '/add';
- sendRequest(sendItemHandler, l, url, l.hiddenElementData);
- }
- function sendRequest(handler, l, url, data) {
- var x = new XMLHttpRequest();
- x.onreadystatechange = function(event) {
- handler(l, event);
- }
- x.open('POST', url, true);
- x.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- x.send(data);
- }
- function sendItemHandler(l, event) {
- let target = event.target;
- log("Info", "Add element(" + l.list[l.ready].const + ") request: readyState(" + target.readyState + "), status(" + target.status + ")");
- if (target.readyState == 4 && target.status == 200) {
- let description = l.list[l.ready].description;
- if (description.length !== 0) {
- let listItemId = JSON.parse(target.responseText).list_item_id;
- let url = 'https://www.imdb.com/list/' + l.list_id + '/edit/itemdescription';
- let data = 'newDescription=' + description + '&listItem=' + listItemId + '&' + l.hiddenElementData
- sendRequest(sendItemDescriptionHandler, l, url, data);
- } else {
- showReady(l);
- }
- }
- }
- function sendItemDescriptionHandler(l, event) {
- let target = event.target;
- log("Info", "Add element(" + l.list[l.ready].const + ") description request: readyState(" + target.readyState + "), status(" + target.status + ")");
- if (target.readyState == 4 && target.status == 200) {
- showReady(l);
- }
- }
- function showReady(l) {
- l.ready += 1;
- setStatus('Ready ' + l.ready + ' of ' + l.list.length + '.');
- if (l.ready == l.list.length) {
- location.reload();
- } else {
- sendItem(l);
- }
- }