// ==UserScript==
// @name IMDb List Helper
// @namespace imdb
// @description Makes creating IMDb lists more efficient and convenient
// @version 2.0
// @include http://*imdb.com/list/edit*
// ==/UserScript==
var jQuery = unsafeWindow.jQuery;
var $ = jQuery;
//
// CHANGELOG
//
// 2.0
// added: import ratings
// added: if regex doesn't match, skip entry
//
// 1.6.1.2
// added: input text suggestion as a placeholder
//
// 1.6.1.1
// fixed: some entries are skipped when adding imdb ids/urls
//
//
// milliseconds between each request
//
var REQUEST_DELAY = 1000;
var ListManager = {
regex: "^(.*)$",
processRegex: function(rx, cb) {
var filmTitle = rx[1];
cb(filmTitle);
},
handleSelection: function(imdbId, cb) {
cb();
}
};
var RatingManager = {
rating: 0,
regex: "^([1-9]{1}|10),(.*)$",
processRegex: function(rx, cb) {
RatingManager.rating = rx[1];
var filmTitle = rx[2];
cb(filmTitle);
},
handleSelection: function(imdbId, cb) {
console.log("RatingManager::handleSelection: Rating " + imdbId);
$.get("http://www.imdb.com/title/" + imdbId, function(data) {
var authHash = $(data).find("div[id^='" + imdbId + "']").data("auth");
var params = {tconst: imdbId, rating: RatingManager.rating,
auth: authHash, tracking_tag: "list"};
$.post("http://www.imdb.com/ratings/_ajax/title", params, function(data) {
if(data.status !== 200) {
alert("Rating failed. Status code " + data.status);
}
else {
cb();
}
}, "json");
});
}
};
var App = {
manager: ListManager,
films: [],
regexObj: null,
isEmpty: function() {
return App.films.length === 0;
},
next: function() {
return App.films.shift();
},
run: function() {
var textEdit = '<div id="imdbListTextEdit" style="'
+ 'padding: 10px; border: 1px solid #e8e8e8">'
+ '<p><b>Import mode:</b><input type="radio" name="importmode" value="list" checked="checked">List</input>'
+ '<input type="radio" name="importmode" value="ratings">Ratings</input></p>'
+ '<textarea id="filmList" rows="7" cols="60" placeholder="Input titles, IMDb URLs, and IDs here and click Start"></textarea><br />'
+ '<input type="button" id="doList" value="Start" /> '
+ '<input type="button" id="skipFilm" value="Skip" /> '
+ '<input type="button" id="retryPost" value="Retry" /> '
+ '<span style="font-weight: bold">Remaining: <span id="filmsRemaining">0</span></span><br /><br />'
+ '<span style="font-weight: bold;">Current: <input type="text" id="filmCurrent" size="65" style="font-family: monospace" /></span><br />'
+ '<span style="font-weight: bold;">Regexp: <input type="text" value="" id="filmRegexp" size="65" style="font-family: monospace; margin-top: 4px; margin-left: 1px" /></span><br />'
+ '</div>';
$("div#main > div.list_edit > div.add").after(textEdit);
$("#filmRegexp").val(App.manager.regex);
$("#imdbListTextEdit").on("change", "input[name=importmode]", function() {
var value = $(this).val();
if(value === "list") {
App.manager = ListManager;
}
else {
App.manager = RatingManager;
}
$("#filmRegexp").val(App.manager.regex);
});
// When start button is clicked
$("#imdbListTextEdit").on("click", "#doList", function(e) {
$regexBox = $("#filmRegexp");
if($regexBox.val()) {
App.regexObj = RegExp($regexBox.val());
}
else {
App.regexObj = RegExp(App.manager.regex);
}
// Disable the text area and the button and the regexp box
// as well as the import mode
$filmList = $("#filmList");
$filmList.attr("disabled", "disabled");
$regexBox.attr("disabled", "disabled");
$("#doList").attr("disabled", "disabled");
$("input[name=importmode]").attr("disabled", "disabled");
App.films = $filmList.val().split("\n");
App.handleNext();
});
// when skip button is clicked
$("#imdbListTextEdit").on("click", "#skipFilm", function(e) {
App.handleNext();
});
// Sometimes the request fails forcing the user to skip an entry to continue
$("#imdbListTextEdit").on("click", "#retryPost", function(e) {
$("button.search").trigger("click");
});
},
reset: function() {
App.films = [];
App.regexObj = null;
$("#filmList").removeAttr("disabled");
$("#filmRegexp").removeAttr("disabled"); // leave regex
$("#doList").removeAttr("disabled");
$("input[name=importmode]").removeAttr("disabled");
$("#filmCurrent").val("");
$("input[name=add]", "div.add").val("");
$("div.results", "div.add").html("");
},
search: function(filmTitle) {
// remove unnecessary whitespace
filmTitle = $.trim(filmTitle);
// set current text to what we're searching
$("#filmCurrent").val(filmTitle);
// remove the first title from the text box and set the remaining number
$filmList = $("#filmList");
var newList = $filmList.val().split("\n");
$("#filmsRemaining").text(newList.length-1);
$filmList.val(newList.slice(1).join("\n"));
// Run regex if it matches and let the manager process the result
var result = App.regexObj.exec(filmTitle);
if(result !== null) {
App.manager.processRegex(result, function(filmTitle) {
// Set imdb search input field to film title
$("input[name=add]", "div.add").val(filmTitle);
// Trigger search button click
$("button.search").trigger("click");
});
}
else {
App.handleNext();
}
},
handleNext: function() {
if(!App.isEmpty()) {
// if there's more items, search next...
App.search(App.next());
}
else {
// if last film
App.reset();
}
}
};
$(document).ready(App.run);
// When a search result item is clicked by user or script
$("div.results").on("click", "li", function(e) {
App.manager.handleSelection($(this).attr("id"), function() {
App.handleNext();
});
});
// Monitors for changes to the search result box
// If it recognizes an IMDBb URL/ID, it's clicked automatically
// since there's only one result
$("div.results").bind("DOMNodeInserted", function(e) {
if($("#filmCurrent").val().match(/(tt[0-9]{7})/) !== null
&& $("div.results").find("li").length) {
setTimeout(function() {
$("li", "div.results").first()[0].click();
}, REQUEST_DELAY);
}
});