You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

3805 lines
147 KiB

var DownloadersBase = new Class({
Implements: [ Events ],
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addTestButtons.bind(self));
},
addTestButtons: function() {
var self = this;
var setting_page = App.getPage("Settings");
setting_page.addEvent("create", function() {
Object.each(setting_page.tabs.downloaders.groups, self.addTestButton.bind(self));
});
},
addTestButton: function(fieldset, plugin_name) {
var self = this, button_name = self.testButtonName(fieldset);
if (button_name.contains("Downloaders")) return;
new Element(".ctrlHolder.test_button").grab(new Element("a.button", {
text: button_name,
events: {
click: function() {
var button = fieldset.getElement(".test_button .button");
button.set("text", "Connecting...");
Api.request("download." + plugin_name + ".test", {
onComplete: function(json) {
button.set("text", button_name);
var message;
if (json.success) {
message = new Element("span.success", {
text: "Connection successful"
}).inject(button, "after");
} else {
var msg_text = "Connection failed. Check logs for details.";
if (json.hasOwnProperty("msg")) msg_text = json.msg;
message = new Element("span.failed", {
text: msg_text
}).inject(button, "after");
}
requestTimeout(function() {
message.destroy();
}, 3e3);
}
});
}
}
})).inject(fieldset);
},
testButtonName: function(fieldset) {
var name = fieldset.getElement("h2 .group_label").get("text");
return "Test " + name;
}
});
var Downloaders = new DownloadersBase();
var UpdaterBase = new Class({
Implements: [ Events ],
initialize: function() {
var self = this;
App.addEvent("load", self.info.bind(self, 2e3));
App.addEvent("unload", function() {
if (self.timer) clearRequestTimeout(self.timer);
});
},
check: function(onComplete) {
var self = this;
Api.request("updater.check", {
onComplete: function(json) {
if (onComplete) onComplete(json);
if (json.update_available) self.doUpdate(); else {
App.unBlockPage();
App.trigger("message", [ "No updates available" ]);
}
}
});
},
info: function(timeout) {
var self = this;
if (self.timer) clearRequestTimeout(self.timer);
self.timer = requestTimeout(function() {
Api.request("updater.info", {
onComplete: function(json) {
self.json = json;
self.fireEvent("loaded", [ json ]);
if (json.update_version) {
self.createMessage(json);
} else {
if (self.message) self.message.destroy();
}
}
});
}, timeout || 0);
},
getInfo: function() {
return this.json;
},
createMessage: function(data) {
var self = this;
if (self.message) return;
var changelog = "https://github.com/" + data.repo_name + "/compare/" + data.version.hash + "..." + data.branch;
if (data.update_version.changelog) changelog = data.update_version.changelog + "#" + data.version.hash + "..." + data.update_version.hash;
self.message = new Element("div.message.update").adopt(new Element("span", {
text: "A new version is available"
}), new Element("a", {
href: changelog,
text: "see what has changed",
target: "_blank"
}), new Element("span[text=or]"), new Element("a", {
text: "just update, gogogo!",
events: {
click: self.doUpdate.bind(self)
}
})).inject(App.getBlock("footer"));
},
doUpdate: function() {
var self = this;
App.blockPage("Please wait while CouchPotato is being updated with more awesome stuff.", "Updating");
Api.request("updater.update", {
onComplete: function(json) {
if (json.success) self.updating(); else App.unBlockPage();
}
});
},
updating: function() {
requestTimeout(function() {
App.checkAvailable(1e3, function() {
window.location.reload();
});
}, 500);
if (self.message) self.message.destroy();
}
});
var Updater = new UpdaterBase();
var PutIODownloader = new Class({
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addRegisterButton.bind(self));
},
addRegisterButton: function() {
var self = this;
var setting_page = App.getPage("Settings");
setting_page.addEvent("create", function() {
var fieldset = setting_page.tabs.downloaders.groups.putio, l = window.location;
var putio_set = 0;
fieldset.getElements("input[type=text]").each(function(el) {
putio_set += +(el.get("value") !== "");
});
new Element(".ctrlHolder").adopt(putio_set > 0 ? [ self.unregister = new Element("a.button.red", {
text: 'Unregister "' + fieldset.getElement("input[name*=oauth_token]").get("value") + '"',
events: {
click: function() {
fieldset.getElements("input[name*=oauth_token]").set("value", "").fireEvent("change");
self.unregister.destroy();
self.unregister_or.destroy();
}
}
}), self.unregister_or = new Element("span[text=or]") ] : null, new Element("a.button", {
text: putio_set > 0 ? "Register a different account" : "Register your put.io account",
events: {
click: function() {
Api.request("downloader.putio.auth_url", {
data: {
host: l.protocol + "//" + l.hostname + (l.port ? ":" + l.port : "")
},
onComplete: function(json) {
window.location = json.url;
}
});
}
}
})).inject(fieldset.getElement(".test_button"), "before");
});
}
});
window.addEvent("domready", function() {
new PutIODownloader();
});
var BlockSearch = new Class({
Extends: BlockBase,
options: {
animate: true
},
cache: {},
create: function() {
var self = this;
var focus_timer = 0;
self.el = new Element("div.search_form").adopt(new Element("a.icon-search", {
events: {
click: self.clear.bind(self)
}
}), self.wrapper = new Element("div.wrapper").adopt(self.result_container = new Element("div.results_container", {
events: {
mousewheel: function(e) {
e.stopPropagation();
}
}
}).grab(self.results = new Element("div.results")), new Element("div.input").grab(self.input = new Element("input", {
placeholder: "Search & add a new media",
events: {
input: self.keyup.bind(self),
paste: self.keyup.bind(self),
change: self.keyup.bind(self),
keyup: self.keyup.bind(self),
focus: function() {
if (focus_timer) clearRequestTimeout(focus_timer);
if (this.get("value")) self.hideResults(false);
},
blur: function() {
focus_timer = requestTimeout(function() {
self.el.removeClass("focused");
self.last_q = null;
}, 100);
}
}
}))));
self.mask = new Element("div.mask").inject(self.result_container);
},
clear: function(e) {
var self = this;
e.preventDefault();
if (self.last_q === "") {
self.input.blur();
self.last_q = null;
} else {
self.last_q = "";
self.input.set("value", "");
self.el.addClass("focused");
self.input.focus();
self.media = {};
self.results.empty();
self.el.removeClass("filled");
if (self.options.animate) {
dynamics.css(self.wrapper, {
opacity: 0,
scale: .1
});
dynamics.animate(self.wrapper, {
opacity: 1,
scale: 1
}, {
type: dynamics.spring,
frequency: 200,
friction: 270,
duration: 800
});
}
}
},
hideResults: function(bool) {
var self = this;
if (self.hidden == bool) return;
self.el[bool ? "removeClass" : "addClass"]("shown");
if (bool) {
History.removeEvent("change", self.hideResults.bind(self, !bool));
self.el.removeEvent("outerClick", self.hideResults.bind(self, !bool));
} else {
History.addEvent("change", self.hideResults.bind(self, !bool));
self.el.addEvent("outerClick", self.hideResults.bind(self, !bool));
}
self.hidden = bool;
},
keyup: function() {
var self = this;
self.el[self.q() ? "addClass" : "removeClass"]("filled");
if (self.q() != self.last_q) {
if (self.api_request && self.api_request.isRunning()) self.api_request.cancel();
if (self.autocomplete_timer) clearRequestTimeout(self.autocomplete_timer);
self.autocomplete_timer = requestTimeout(self.autocomplete.bind(self), 300);
}
},
autocomplete: function() {
var self = this;
if (!self.q()) {
self.hideResults(true);
return;
}
self.list();
},
list: function() {
var self = this, q = self.q(), cache = self.cache[q];
self.hideResults(false);
if (!cache) {
requestTimeout(function() {
self.mask.addClass("show");
}, 10);
if (!self.spinner) self.spinner = createSpinner(self.mask);
self.api_request = Api.request("search", {
data: {
q: q
},
onComplete: self.fill.bind(self, q)
});
} else self.fill(q, cache);
self.last_q = q;
},
fill: function(q, json) {
var self = this;
self.cache[q] = json;
self.media = {};
self.results.empty();
Object.each(json, function(media) {
if (typeOf(media) == "array") {
Object.each(media, function(me) {
var m = new (window["BlockSearch" + me.type.capitalize() + "Item"])(me);
$(m).inject(self.results);
self.media[m.imdb || "r-" + Math.floor(Math.random() * 1e4)] = m;
if (q == m.imdb) m.showOptions();
});
}
});
self.mask.removeClass("show");
},
loading: function(bool) {
this.el[bool ? "addClass" : "removeClass"]("loading");
},
q: function() {
return this.input.get("value").trim();
}
});
var MovieDetails = new Class({
Extends: BlockBase,
sections: null,
buttons: null,
initialize: function(parent, options) {
var self = this;
self.sections = {};
var category = parent.get("category");
self.el = new Element("div", {
class: "page active movie_details level_" + (options.level || 0)
}).adopt(self.overlay = new Element("div.overlay", {
events: {
click: self.close.bind(self)
}
}).grab(new Element("a.close.icon-left-arrow")), self.content = new Element("div.scroll_content").grab(new Element("div.head").adopt(new Element("h1").grab(self.title_dropdown = new BlockMenu(self, {
class: "title",
button_text: parent.getTitle() + (parent.get("year") ? " (" + parent.get("year") + ")" : ""),
button_class: "icon-dropdown"
})), self.buttons = new Element("div.buttons"))));
var eta_date = parent.getETA("%b %Y");
self.addSection("description", new Element("div").adopt(new Element("div", {
text: parent.get("plot")
}), new Element("div.meta", {
html: (eta_date ? "<span>ETA:" + eta_date + "</span>" : "") + "<span>" + (parent.get("genres") || []).join(", ") + "</span>"
})));
var titles = parent.get("info").titles;
$(self.title_dropdown).addEvents({
"click:relay(li a)": function(e, el) {
e.stopPropagation();
Api.request("movie.edit", {
data: {
id: parent.get("_id"),
default_title: el.get("text")
}
});
$(self.title_dropdown).getElements(".icon-ok").removeClass("icon-ok");
el.addClass("icon-ok");
self.title_dropdown.button.set("text", el.get("text") + (parent.get("year") ? " (" + parent.get("year") + ")" : ""));
}
});
titles.each(function(t) {
self.title_dropdown.addLink(new Element("a", {
text: t,
class: parent.get("title") == t ? "icon-ok" : ""
}));
});
},
addSection: function(name, section_el) {
var self = this;
name = name.toLowerCase();
self.content.grab(self.sections[name] = new Element("div", {
class: "section section_" + name
}).grab(section_el));
},
addButton: function(button) {
var self = this;
self.buttons.grab(button);
},
open: function() {
var self = this;
self.el.addClass("show");
self.outer_click = function() {
self.close();
};
App.addEvent("history.push", self.outer_click);
},
close: function() {
var self = this;
var ended = function() {
self.el.dispose();
self.overlay.removeEventListener("transitionend", ended);
};
self.overlay.addEventListener("transitionend", ended, false);
self.el.removeClass("show");
App.removeEvent("history.push", self.outer_click);
}
});
var MovieList = new Class({
Implements: [ Events, Options ],
options: {
api_call: "media.list",
navigation: true,
limit: 50,
load_more: true,
loader: true,
menu: [],
add_new: false,
force_view: false
},
available_views: [ "thumb", "list" ],
movies: [],
movies_added: {},
total_movies: 0,
letters: {},
filter: null,
initialize: function(options) {
var self = this;
self.setOptions(options);
self.offset = 0;
self.filter = self.options.filter || {
starts_with: null,
search: null
};
self.el = new Element("div.movies").adopt(self.title = self.options.title ? new Element("h2", {
text: self.options.title,
styles: {
display: "none"
}
}) : null, self.description = self.options.description ? new Element("div.description", {
html: self.options.description,
styles: {
display: "none"
}
}) : null, self.movie_list = new Element("div", {
events: {
"click:relay(.movie)": function(e, el) {
el.retrieve("klass").onClick(e);
},
"mouseenter:relay(.movie)": function(e, el) {
e.stopPropagation();
el.retrieve("klass").onMouseenter(e);
},
"change:relay(.movie input)": function(e, el) {
e.stopPropagation();
el = el.getParent(".movie");
var klass = el.retrieve("klass");
klass.fireEvent("select");
klass.select(klass.select_checkbox.get("checked"));
}
}
}), self.load_more = self.options.load_more ? new Element("a.load_more", {
events: {
click: self.loadMore.bind(self)
}
}) : null);
self.changeView(self.getSavedView() || self.options.view || "thumb");
if (self.options.navigation) self.createNavigation();
if (self.options.api_call) self.getMovies();
App.on("movie.added", self.movieAdded.bind(self));
App.on("movie.deleted", self.movieDeleted.bind(self));
},
movieDeleted: function(notification) {
var self = this;
if (self.movies_added[notification.data._id]) {
self.movies.each(function(movie) {
if (movie.get("_id") == notification.data._id) {
movie.destroy();
delete self.movies_added[notification.data._id];
self.setCounter(self.counter_count - 1);
self.total_movies--;
}
});
}
self.checkIfEmpty();
},
movieAdded: function(notification) {
var self = this;
self.fireEvent("movieAdded", notification);
if (self.options.add_new && !self.movies_added[notification.data._id] && notification.data.status == self.options.status) {
window.scroll(0, 0);
self.createMovie(notification.data, "top");
self.setCounter(self.counter_count + 1);
self.checkIfEmpty();
}
},
create: function() {
var self = this;
if (self.options.load_more) {
self.scrollspy = new ScrollSpy({
container: self.el.getParent(),
min: function() {
return self.load_more.getCoordinates().top;
},
onEnter: self.loadMore.bind(self)
});
}
self.created = true;
},
addMovies: function(movies, total) {
var self = this;
if (!self.created) self.create();
if (movies.length < self.options.limit && self.scrollspy) {
self.load_more.hide();
self.scrollspy.stop();
}
self.createMovie(movies, "bottom");
self.total_movies += total;
self.setCounter(total);
self.calculateSelected();
},
setCounter: function(count) {
var self = this;
if (!self.navigation_counter) return;
self.counter_count = count;
self.navigation_counter.set("text", count === 1 ? "1 movie" : (count || 0) + " movies");
if (self.empty_message) {
self.empty_message.destroy();
self.empty_message = null;
}
if (self.total_movies && count === 0 && !self.empty_message) {
var message = (self.filter.search ? 'for "' + self.filter.search + '"' : "") + (self.filter.starts_with ? " in <strong>" + self.filter.starts_with + "</strong>" : "");
self.empty_message = new Element(".message", {
html: "No movies found " + message + ".<br/>"
}).grab(new Element("a", {
text: "Reset filter",
events: {
click: function() {
self.filter = {
starts_with: null,
search: null
};
self.navigation_search_input.set("value", "");
self.reset();
self.activateLetter();
self.getMovies(true);
self.last_search_value = "";
}
}
})).inject(self.movie_list);
}
},
createMovie: function(movie, inject_at, nr) {
var self = this, movies = Array.isArray(movie) ? movie : [ movie ], movie_els = [];
inject_at = inject_at || "bottom";
movies.each(function(movie, nr) {
var m = new Movie(self, {
actions: self.options.actions,
view: self.current_view,
onSelect: self.calculateSelected.bind(self)
}, movie);
var el = $(m);
if (inject_at === "bottom") {
movie_els.push(el);
} else {
el.inject(self.movie_list, inject_at);
}
self.movies.include(m);
self.movies_added[movie._id] = true;
});
if (movie_els.length > 0) {
$(self.movie_list).adopt(movie_els);
}
},
createNavigation: function() {
var self = this;
var chars = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
self.el.addClass("with_navigation");
self.navigation = new Element("div.alph_nav").adopt(self.mass_edit_form = new Element("div.mass_edit_form").adopt(new Element("span.select").adopt(self.mass_edit_select = new Element("input[type=checkbox]", {
events: {
change: self.massEditToggleAll.bind(self)
}
}), self.mass_edit_selected = new Element("span.count", {
text: 0
}), self.mass_edit_selected_label = new Element("span", {
text: "selected"
})), new Element("div.quality").adopt(self.mass_edit_quality = new Element("select"), new Element("a.button.orange", {
text: "Change quality",
events: {
click: self.changeQualitySelected.bind(self)
}
})), new Element("div.delete").adopt(new Element("span[text=or]"), new Element("a.button.red", {
text: "Delete",
events: {
click: self.deleteSelected.bind(self)
}
})), new Element("div.refresh").adopt(new Element("span[text=or]"), new Element("a.button.green", {
text: "Refresh",
events: {
click: self.refreshSelected.bind(self)
}
}))), new Element("div.menus").adopt(self.navigation_counter = new Element("span.counter[title=Total]"), self.filter_menu = new BlockMenu(self, {
class: "filter",
button_class: "icon-filter"
}), self.navigation_actions = new Element("div.actions", {
events: {
click: function(e, el) {
e.preventDefault();
var new_view = self.current_view == "list" ? "thumb" : "list";
var a = "active";
self.navigation_actions.getElements("." + a).removeClass(a);
self.changeView(new_view);
self.navigation_actions.getElement("[data-view=" + new_view + "]").addClass(a);
}
}
}), self.navigation_menu = new BlockMenu(self, {
class: "extra",
button_class: "icon-dots"
})));
Quality.getActiveProfiles().each(function(profile) {
new Element("option", {
value: profile.get("_id"),
text: profile.get("label")
}).inject(self.mass_edit_quality);
});
self.filter_menu.addLink(self.navigation_search_input = new Element("input", {
title: "Search through " + self.options.identifier,
placeholder: "Search through " + self.options.identifier,
events: {
keyup: self.search.bind(self),
change: self.search.bind(self)
}
})).addClass("search icon-search");
var available_chars;
self.filter_menu.addEvent("open", function() {
self.navigation_search_input.focus();
if (!available_chars && (self.navigation.isDisplayed() || self.navigation.isVisible())) Api.request("media.available_chars", {
data: Object.merge({
status: self.options.status
}, self.filter),
onSuccess: function(json) {
available_chars = json.chars;
available_chars.each(function(c) {
self.letters[c.capitalize()].addClass("available");
});
}
});
});
self.filter_menu.addLink(self.navigation_alpha = new Element("ul.numbers", {
events: {
"click:relay(li.available)": function(e, el) {
self.activateLetter(el.get("data-letter"));
self.getMovies(true);
}
}
}));
[ "thumb", "list" ].each(function(view) {
var current = self.current_view == view;
new Element("a", {
class: "icon-" + view + (current ? " active " : ""),
"data-view": view
}).inject(self.navigation_actions, current ? "top" : "bottom");
});
self.letters.all = new Element("li.letter_all.available.active", {
text: "ALL"
}).inject(self.navigation_alpha);
chars.split("").each(function(c) {
self.letters[c] = new Element("li", {
text: c,
class: "letter_" + c,
"data-letter": c
}).inject(self.navigation_alpha);
});
if (self.options.menu.length > 0) self.options.menu.each(function(menu_item) {
self.navigation_menu.addLink(menu_item);
}); else self.navigation_menu.hide();
},
calculateSelected: function() {
var self = this;
var selected = 0, movies = self.movies.length;
self.movies.each(function(movie) {
selected += movie.isSelected() ? 1 : 0;
});
var indeterminate = selected > 0 && selected < movies, checked = selected == movies && selected > 0;
document.body[selected > 0 ? "addClass" : "removeClass"]("mass_editing");
if (self.mass_edit_select) {
self.mass_edit_select.set("checked", checked);
self.mass_edit_select.indeterminate = indeterminate;
self.mass_edit_selected.set("text", selected);
}
},
deleteSelected: function() {
var self = this, ids = self.getSelectedMovies(), help_msg = self.identifier == "wanted" ? "If you do, you won't be able to watch them, as they won't get downloaded!" : "Your files will be safe, this will only delete the references in CouchPotato";
var qObj = new Question("Are you sure you want to delete " + ids.length + " movie" + (ids.length != 1 ? "s" : "") + "?", help_msg, [ {
text: "Yes, delete " + (ids.length != 1 ? "them" : "it"),
class: "delete",
events: {
click: function(e) {
e.preventDefault();
this.set("text", "Deleting..");
Api.request("media.delete", {
method: "post",
data: {
id: ids.join(","),
delete_from: self.options.identifier
},
onSuccess: function() {
qObj.close();
var erase_movies = [];
self.movies.each(function(movie) {
if (movie.isSelected()) {
$(movie).destroy();
erase_movies.include(movie);
}
});
erase_movies.each(function(movie) {
self.movies.erase(movie);
movie.destroy();
self.setCounter(self.counter_count - 1);
self.total_movies--;
});
self.calculateSelected();
}
});
}
}
}, {
text: "Cancel",
cancel: true
} ]);
},
changeQualitySelected: function() {
var self = this;
var ids = self.getSelectedMovies();
Api.request("movie.edit", {
method: "post",
data: {
id: ids.join(","),
profile_id: self.mass_edit_quality.get("value")
},
onSuccess: self.search.bind(self)
});
},
refreshSelected: function() {
var self = this;
var ids = self.getSelectedMovies();
Api.request("media.refresh", {
method: "post",
data: {
id: ids.join(",")
}
});
},
getSelectedMovies: function() {
var self = this;
var ids = [];
self.movies.each(function(movie) {
if (movie.isSelected()) ids.include(movie.get("_id"));
});
return ids;
},
massEditToggleAll: function() {
var self = this;
var select = self.mass_edit_select.get("checked");
self.movies.each(function(movie) {
movie.select(select);
});
self.calculateSelected();
},
reset: function() {
var self = this;
self.movies = [];
if (self.mass_edit_select) self.calculateSelected();
if (self.navigation_alpha) self.navigation_alpha.getElements(".active").removeClass("active");
self.offset = 0;
if (self.scrollspy) {
self.scrollspy.start();
}
},
activateLetter: function(letter) {
var self = this;
self.reset();
self.letters[letter || "all"].addClass("active");
self.filter.starts_with = letter;
},
changeView: function(new_view) {
var self = this;
if (self.available_views.indexOf(new_view) == -1) new_view = "thumb";
self.el.removeClass(self.current_view + "_list").addClass(new_view + "_list");
self.current_view = new_view;
Cookie.write(self.options.identifier + "_view", new_view, {
duration: 1e3
});
},
getSavedView: function() {
var self = this;
return self.options.force_view ? self.options.view : Cookie.read(self.options.identifier + "_view");
},
search: function() {
var self = this;
if (self.search_timer) clearRequestTimeout(self.search_timer);
self.search_timer = requestTimeout(function() {
var search_value = self.navigation_search_input.get("value");
if (search_value == self.last_search_value) return;
self.reset();
self.activateLetter();
self.filter.search = search_value;
self.getMovies(true);
self.last_search_value = search_value;
}, 250);
},
update: function() {
var self = this;
self.reset();
self.getMovies(true);
},
getMovies: function(reset) {
var self = this;
if (self.scrollspy) {
self.scrollspy.stop();
self.load_more.set("text", "loading...");
}
var loader_timeout;
if (self.movies.length === 0 && self.options.loader) {
self.loader_first = new Element("div.mask.loading.with_message").grab(new Element("div.message", {
text: self.options.title ? "Loading '" + self.options.title + "'" : "Loading..."
})).inject(self.el, "top");
createSpinner(self.loader_first);
var lfc = self.loader_first;
loader_timeout = requestTimeout(function() {
lfc.addClass("show");
}, 10);
self.el.setStyle("min-height", 220);
}
Api.request(self.options.api_call, {
data: Object.merge({
type: self.options.type || "movie",
status: self.options.status,
limit_offset: self.options.limit ? self.options.limit + "," + self.offset : null
}, self.filter),
onSuccess: function(json) {
if (reset) self.movie_list.empty();
if (loader_timeout) clearRequestTimeout(loader_timeout);
if (self.loader_first) {
var lf = self.loader_first;
self.loader_first = null;
lf.removeClass("show");
requestTimeout(function() {
lf.destroy();
}, 1e3);
self.el.setStyle("min-height", null);
}
self.store(json.movies);
self.addMovies(json.movies, json.total || json.movies.length);
if (self.scrollspy) {
self.load_more.set("text", "load more movies");
self.scrollspy.start();
}
self.checkIfEmpty();
self.fireEvent("loaded");
}
});
},
loadMore: function() {
var self = this;
if (self.offset >= self.options.limit) self.getMovies();
},
store: function(movies) {
var self = this;
self.offset += movies.length;
},
checkIfEmpty: function() {
var self = this;
var is_empty = self.movies.length === 0 && (self.total_movies === 0 || self.total_movies === undefined);
if (self.title) self.title[is_empty ? "hide" : "show"]();
if (self.description) self.description.setStyle("display", [ is_empty ? "none" : "" ]);
if (is_empty && self.options.on_empty_element) {
self.options.on_empty_element.inject(self.loader_first || self.title || self.movie_list, "after");
if (self.navigation) self.navigation.hide();
self.empty_element = self.options.on_empty_element;
} else if (self.empty_element) {
self.empty_element.destroy();
if (self.navigation) self.navigation.show();
}
},
toElement: function() {
return this.el;
}
});
var MoviesManage = new Class({
Extends: PageBase,
order: 20,
name: "manage",
title: "Do stuff to your existing movies!",
indexAction: function() {
var self = this;
if (!self.list) {
self.refresh_button = new Element("a", {
title: "Rescan your library for new movies",
text: "Full library refresh",
events: {
click: self.refresh.bind(self, true)
}
});
self.refresh_quick = new Element("a", {
title: "Just scan for recently changed",
text: "Quick library scan",
events: {
click: self.refresh.bind(self, false)
}
});
self.list = new MovieList({
identifier: "manage",
filter: {
status: "done",
release_status: "done",
status_or: 1
},
actions: [ MA.IMDB, MA.Files, MA.Trailer, MA.Readd, MA.Delete ],
menu: [ self.refresh_button, self.refresh_quick ],
on_empty_element: new Element("div.empty_manage").adopt(new Element("div", {
text: "Seems like you don't have anything in your library yet. Add your existing movie folders in "
}).grab(new Element("a", {
text: "Settings > Manage",
href: App.createUrl("settings/manage")
})), new Element("div.after_manage", {
text: "When you've done that, hit this button → "
}).grab(new Element("a.button.green", {
text: "Hit me, but not too hard",
events: {
click: self.refresh.bind(self, true)
}
})))
});
$(self.list).inject(self.content);
self.startProgressInterval();
}
},
refresh: function(full) {
var self = this;
if (!self.update_in_progress) {
Api.request("manage.update", {
data: {
full: +full
}
});
self.startProgressInterval();
}
},
startProgressInterval: function() {
var self = this;
self.progress_interval = requestInterval(function() {
if (self.progress_request && self.progress_request.running) return;
self.update_in_progress = true;
self.progress_request = Api.request("manage.progress", {
onComplete: function(json) {
if (!json || !json.progress) {
clearRequestInterval(self.progress_interval);
self.update_in_progress = false;
if (self.progress_container) {
self.progress_container.destroy();
self.list.update();
}
} else {
var progress = json.progress;
if (!self.list.navigation) return;
if (!self.progress_container) self.progress_container = new Element("div.progress").inject(self.list, "top");
self.progress_container.empty();
var sorted_table = self.parseProgress(json.progress);
sorted_table.each(function(folder) {
var folder_progress = progress[folder];
new Element("div").adopt(new Element("span.folder", {
text: folder + (folder_progress.eta > 0 ? ", " + new Date().increment("second", folder_progress.eta).timeDiffInWords().replace("from now", "to go") : "")
}), new Element("span.percentage", {
text: folder_progress.total ? Math.round((folder_progress.total - folder_progress.to_go) / folder_progress.total * 100) + "%" : "0%"
})).inject(self.progress_container);
});
}
}
});
}, 1e3);
},
parseProgress: function(progress_object) {
var folder, temp_array = [];
for (folder in progress_object) {
if (progress_object.hasOwnProperty(folder)) {
temp_array.push(folder);
}
}
return temp_array.stableSort();
}
});
var MovieAction = new Class({
Implements: [ Options ],
class_name: "action",
label: "UNKNOWN",
icon: null,
button: null,
details: null,
detail_button: null,
initialize: function(movie, options) {
var self = this;
self.setOptions(options);
self.movie = movie;
self.create();
if (self.button) {
var wrapper = new Element("div", {
class: self.class_name
});
self.button.inject(wrapper);
self.button = wrapper;
}
},
create: function() {},
getButton: function() {
return this.button || null;
},
getDetails: function() {
return this.details || null;
},
getDetailButton: function() {
return this.detail_button || null;
},
getLabel: function() {
return this.label;
},
disable: function() {
if (this.el) this.el.addClass("disable");
},
enable: function() {
if (this.el) this.el.removeClass("disable");
},
getTitle: function() {
var self = this;
try {
return self.movie.getTitle(true);
} catch (e) {
try {
return self.movie.original_title ? self.movie.original_title : self.movie.titles[0];
} catch (e2) {
return "Unknown";
}
}
},
get: function(key) {
var self = this;
try {
return self.movie.get(key);
} catch (e) {
return self.movie[key];
}
},
createMask: function() {
var self = this;
self.mask = new Element("div.mask", {
styles: {
"z-index": "1"
}
}).inject(self.movie, "top").fade("hide");
},
toElement: function() {
return this.el || null;
}
});
var MA = {};
MA.IMDB = new Class({
Extends: MovieAction,
id: null,
create: function() {
var self = this;
self.id = self.movie.getIdentifier ? self.movie.getIdentifier() : self.get("imdb");
self.button = self.createButton();
self.detail_button = self.createButton();
if (!self.id) self.disable();
},
createButton: function() {
var self = this;
return new Element("a.imdb", {
text: "IMDB",
title: "Go to the IMDB page of " + self.getTitle(),
href: "http://www.imdb.com/title/" + self.id + "/",
target: "_blank"
});
}
});
MA.Release = new Class({
Extends: MovieAction,
label: "Releases",
create: function() {
var self = this;
App.on("movie.searcher.ended", function(notification) {
if (self.movie.data._id != notification.data._id) return;
self.releases = null;
if (self.options_container) {
if (self.options_container.isDisplayed()) {
self.options_container.destroy();
self.getDetails();
} else {
self.options_container.destroy();
self.options_container = null;
}
}
});
},
getDetails: function(refresh) {
var self = this;
if (!self.movie.data.releases || self.movie.data.releases.length === 0) return;
if (!self.options_container || refresh) {
self.options_container = new Element("div.options").grab(self.release_container = new Element("div.releases.table"));
new Element("div.item.head").adopt(new Element("span.name", {
text: "Release name"
}), new Element("span.status", {
text: "Status"
}), new Element("span.quality", {
text: "Quality"
}), new Element("span.size", {
text: "Size"
}), new Element("span.age", {
text: "Age"
}), new Element("span.score", {
text: "Score"
}), new Element("span.provider", {
text: "Provider"
}), new Element("span.actions")).inject(self.release_container);
if (self.movie.data.releases) self.movie.data.releases.each(function(release) {
var quality = Quality.getQuality(release.quality) || {}, info = release.info || {}, provider = self.get(release, "provider") + (info.provider_extra ? self.get(release, "provider_extra") : "");
var release_name = self.get(release, "name");
if (release.files && release.files.length > 0) {
try {
var movie_file = release.files.filter(function(file) {
var type = File.Type.get(file.type_id);
return type && type.identifier == "movie";
}).pick();
release_name = movie_file.path.split(Api.getOption("path_sep")).getLast();
} catch (e) {}
}
var size = info.size ? Math.floor(self.get(release, "size")) : 0;
size = size ? size < 1e3 ? size + "MB" : Math.round(size * 10 / 1024) / 10 + "GB" : "n/a";
release.el = new Element("div", {
class: "item " + release.status,
id: "release_" + release._id
}).adopt(new Element("span.name", {
text: release_name,
title: release_name
}), new Element("span.status", {
text: release.status,
class: "status " + release.status
}), new Element("span.quality", {
text: quality.label + (release.is_3d ? " 3D" : "") || "n/a"
}), new Element("span.size", {
text: size
}), new Element("span.age", {
text: self.get(release, "age")
}), new Element("span.score", {
text: self.get(release, "score")
}), new Element("span.provider", {
text: provider,
title: provider
}), new Element("span.actions").adopt(info.detail_url ? new Element("a.icon-info", {
href: info.detail_url,
target: "_blank"
}) : new Element("a"), new Element("a.icon-download", {
events: {
click: function(e) {
e.stopPropagation();
if (!this.hasClass("completed")) self.download(release);
}
}
}), new Element("a", {
class: release.status == "ignored" ? "icon-redo" : "icon-cancel",
events: {
click: function(e) {
e.stopPropagation();
self.ignore(release);
this.toggleClass("icon-redo");
this.toggleClass("icon-cancel");
}
}
}))).inject(self.release_container);
if (release.status == "ignored" || release.status == "failed" || release.status == "snatched") {
if (!self.last_release || self.last_release && self.last_release.status != "snatched" && release.status == "snatched") self.last_release = release;
} else if (!self.next_release && release.status == "available") {
self.next_release = release;
}
var update_handle = function(notification) {
if (notification.data._id != release._id) return;
var q = self.movie.quality.getElement(".q_" + release.quality), new_status = notification.data.status;
release.el.set("class", "item " + new_status);
var status_el = release.el.getElement(".status");
status_el.set("class", "status " + new_status);
status_el.set("text", new_status);
if (!q && (new_status == "snatched" || new_status == "seeding" || new_status == "done")) q = self.addQuality(release.quality_id);
if (q && !q.hasClass(new_status)) {
q.removeClass(release.status).addClass(new_status);
q.set("title", q.get("title").replace(release.status, new_status));
}
};
App.on("release.update_status", update_handle);
});
if (self.last_release) self.release_container.getElements("#release_" + self.last_release._id).addClass("last_release");
if (self.next_release) self.release_container.getElements("#release_" + self.next_release._id).addClass("next_release");
if (self.next_release || self.last_release && [ "ignored", "failed" ].indexOf(self.last_release.status) === false) {
self.trynext_container = new Element("div.buttons.try_container").inject(self.release_container, "top");
var nr = self.next_release, lr = self.last_release;
self.trynext_container.adopt(new Element("span.or", {
text: "If anything went wrong, download "
}), lr ? new Element("a.orange", {
text: "the same release again",
events: {
click: function() {
self.download(lr);
}
}
}) : null, nr && lr ? new Element("span.or", {
text: ", "
}) : null, nr ? [ new Element("a.green", {
text: lr ? "another release" : "the best release",
events: {
click: function() {
self.download(nr);
}
}
}), new Element("span.or", {
text: " or pick one below"
}) ] : null);
}
self.last_release = null;
self.next_release = null;
}
return self.options_container;
},
get: function(release, type) {
return release.info && release.info[type] !== undefined ? release.info[type] : "n/a";
},
download: function(release) {
var self = this;
var release_el = self.release_container.getElement("#release_" + release._id), icon = release_el.getElement(".icon-download");
if (icon) icon.addClass("icon spinner").removeClass("download");
Api.request("release.manual_download", {
data: {
id: release._id
},
onComplete: function(json) {
if (icon) icon.removeClass("icon spinner");
if (json.success) {
if (icon) icon.addClass("completed");
release_el.getElement(".status").set("text", "snatched");
} else if (icon) icon.addClass("attention").set("title", "Something went wrong when downloading, please check logs.");
}
});
},
ignore: function(release) {
Api.request("release.ignore", {
data: {
id: release._id
}
});
}
});
MA.Trailer = new Class({
Extends: MovieAction,
id: null,
label: "Trailer",
getDetails: function() {
var self = this, data_url = 'https://www.googleapis.com/youtube/v3/search?q="{title}" {year} trailer&maxResults=1&type=video&videoDefinition=high&videoEmbeddable=true&part=snippet&key=AIzaSyAT3li1KjfLidaL6Vt8T92MRU7n4VOrjYk';
if (!self.player_container) {
self.id = "trailer-" + randomString();
self.container = new Element("div.trailer_container").adopt(self.player_container = new Element("div.icon-play[id=" + self.id + "]", {
events: {
click: self.watch.bind(self)
}
}).adopt(new Element('span[text="watch"]'), new Element('span[text="trailer"]')), self.background = new Element("div.background"));
requestTimeout(function() {
var url = data_url.substitute({
title: encodeURI(self.getTitle()),
year: self.get("year")
});
new Request.JSONP({
url: url,
onComplete: function(json) {
if (json.items.length > 0) {
self.video_id = json.items[0].id.videoId;
self.background.setStyle("background-image", "url(" + json.items[0].snippet.thumbnails.high.url + ")");
self.background.addClass("visible");
} else {
self.container.getParent(".section").addClass("no_trailer");
}
}
}).send();
}, 1e3);
}
return self.container;
},
watch: function() {
var self = this;
new Element("iframe", {
src: "https://www.youtube-nocookie.com/embed/" + self.video_id + "?rel=0&showinfo=0&autoplay=1&showsearch=0&iv_load_policy=3&vq=hd720"
}).inject(self.container);
}
});
MA.Category = new Class({
Extends: MovieAction,
create: function() {
var self = this;
var category = self.movie.get("category");
self.detail_button = new BlockMenu(self, {
class: "category",
button_text: category ? category.label : "No category",
button_class: "icon-dropdown"
});
var categories = CategoryList.getAll();
if (categories.length > 0) {
$(self.detail_button).addEvents({
"click:relay(li a)": function(e, el) {
e.stopPropagation();
Api.request("movie.edit", {
data: {
id: self.movie.get("_id"),
category_id: el.get("data-id")
}
});
$(self.detail_button).getElements(".icon-ok").removeClass("icon-ok");
el.addClass("icon-ok");
self.detail_button.button.set("text", el.get("text"));
}
});
self.detail_button.addLink(new Element("a[text=No category]", {
class: !category ? "icon-ok" : "",
"data-id": ""
}));
categories.each(function(c) {
self.detail_button.addLink(new Element("a", {
text: c.get("label"),
class: category && category._id == c.get("_id") ? "icon-ok" : "",
"data-id": c.get("_id")
}));
});
} else {
$(self.detail_button).hide();
}
}
});
MA.Profile = new Class({
Extends: MovieAction,
create: function() {
var self = this;
var profile = self.movie.profile;
self.detail_button = new BlockMenu(self, {
class: "profile",
button_text: profile ? profile.get("label") : "No profile",
button_class: "icon-dropdown"
});
var profiles = Quality.getActiveProfiles();
if (profiles.length > 0) {
$(self.detail_button).addEvents({
"click:relay(li a)": function(e, el) {
e.stopPropagation();
Api.request("movie.edit", {
data: {
id: self.movie.get("_id"),
profile_id: el.get("data-id")
}
});
$(self.detail_button).getElements(".icon-ok").removeClass("icon-ok");
el.addClass("icon-ok");
self.detail_button.button.set("text", el.get("text"));
}
});
profiles.each(function(pr) {
self.detail_button.addLink(new Element("a", {
text: pr.get("label"),
class: profile && profile.get("_id") == pr.get("_id") ? "icon-ok" : "",
"data-id": pr.get("_id")
}));
});
} else {
$(self.detail_button).hide();
}
}
});
MA.Refresh = new Class({
Extends: MovieAction,
icon: "refresh",
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.refresh", {
text: "Refresh",
title: "Refresh the movie info and do a forced search",
events: {
click: self.doRefresh.bind(self)
}
});
},
doRefresh: function(e) {
var self = this;
e.stop();
Api.request("media.refresh", {
data: {
id: self.movie.get("_id")
}
});
}
});
var SuggestBase = new Class({
Extends: MovieAction,
getIMDB: function() {
return this.movie.data.info.imdb;
},
refresh: function(json) {
var self = this;
if (json && json.movie) {
self.movie.list.addMovies([ json.movie ], 1);
var last_added = self.movie.list.movies[self.movie.list.movies.length - 1];
$(last_added).inject(self.movie, "before");
}
self.movie.destroy();
}
});
MA.Add = new Class({
Extends: SuggestBase,
label: "Add",
icon: "plus",
create: function() {
var self = this;
self.button = new Element("a.add", {
text: "Add",
title: "Re-add the movie and mark all previous snatched/downloaded as ignored",
events: {
click: function() {
self.movie.openDetails();
}
}
});
},
getDetails: function() {
var self = this;
var m = new BlockSearchMovieItem(self.movie.data.info, {
onAdded: self.movie.data.status == "suggested" ? function() {
Api.request("suggestion.ignore", {
data: {
imdb: self.movie.data.info.imdb,
remove_only: true
},
onComplete: self.refresh.bind(self)
});
} : function() {
self.movie.destroy();
}
});
m.showOptions();
return m;
}
});
MA.SuggestSeen = new Class({
Extends: SuggestBase,
icon: "eye",
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.seen", {
text: "Already seen",
title: "Already seen it!",
events: {
click: self.markAsSeen.bind(self)
}
});
},
markAsSeen: function(e) {
var self = this;
e.stopPropagation();
Api.request("suggestion.ignore", {
data: {
imdb: self.getIMDB(),
mark_seen: 1
},
onComplete: function(json) {
self.refresh(json);
if (self.movie.details) {
self.movie.details.close();
}
}
});
}
});
MA.SuggestIgnore = new Class({
Extends: SuggestBase,
icon: "error",
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.ignore", {
text: "Ignore",
title: "Don't suggest this movie anymore",
events: {
click: self.markAsIgnored.bind(self)
}
});
},
markAsIgnored: function(e) {
var self = this;
e.stopPropagation();
Api.request("suggestion.ignore", {
data: {
imdb: self.getIMDB()
},
onComplete: function(json) {
self.refresh(json);
if (self.movie.details) {
self.movie.details.close();
}
}
});
}
});
MA.ChartIgnore = new Class({
Extends: SuggestBase,
icon: "error",
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.ignore", {
text: "Hide",
title: "Don't show this movie in charts",
events: {
click: self.markAsHidden.bind(self)
}
});
},
markAsHidden: function(e) {
var self = this;
e.stopPropagation();
Api.request("charts.ignore", {
data: {
imdb: self.getIMDB()
},
onComplete: function(json) {
if (self.movie.details) {
self.movie.details.close();
}
self.movie.destroy();
}
});
}
});
MA.Readd = new Class({
Extends: MovieAction,
create: function() {
var self = this, movie_done = self.movie.data.status == "done", snatched;
if (self.movie.data.releases && !movie_done) snatched = self.movie.data.releases.filter(function(release) {
return release.status && (release.status == "snatched" || release.status == "seeding" || release.status == "downloaded" || release.status == "done");
}).length;
if (movie_done || snatched && snatched > 0) self.el = new Element("a.readd", {
title: "Re-add the movie and mark all previous snatched/downloaded as ignored",
events: {
click: self.doReadd.bind(self)
}
});
},
doReadd: function(e) {
var self = this;
e.stopPropagation();
Api.request("movie.add", {
data: {
identifier: self.movie.getIdentifier(),
ignore_previous: 1
}
});
}
});
MA.Delete = new Class({
Extends: MovieAction,
Implements: [ Chain ],
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.delete", {
text: "Delete",
title: "Remove the movie from this CP list",
events: {
click: self.showConfirm.bind(self)
}
});
},
showConfirm: function(e) {
var self = this;
e.stopPropagation();
self.question = new Question("Are you sure you want to delete <strong>" + self.getTitle() + "</strong>?", "", [ {
text: "Yes, delete " + self.getTitle(),
class: "delete",
events: {
click: function(e) {
e.target.set("text", "Deleting...");
self.del();
}
}
}, {
text: "Cancel",
cancel: true
} ]);
},
del: function() {
var self = this;
var movie = $(self.movie);
Api.request("media.delete", {
data: {
id: self.movie.get("_id"),
delete_from: self.movie.list.options.identifier
},
onComplete: function() {
if (self.question) self.question.close();
dynamics.animate(movie, {
opacity: 0,
scale: 0
}, {
type: dynamics.bezier,
points: [ {
x: 0,
y: 0,
cp: [ {
x: .876,
y: 0
} ]
}, {
x: 1,
y: 1,
cp: [ {
x: .145,
y: 1
} ]
} ],
duration: 400,
complete: function() {
self.movie.destroy();
}
});
}
});
}
});
MA.Files = new Class({
Extends: MovieAction,
label: "Files",
getDetails: function() {
var self = this;
if (!self.movie.data.releases || self.movie.data.releases.length === 0) return;
if (!self.files_container) {
self.files_container = new Element("div.files.table");
new Element("div.item.head").adopt(new Element("span.name", {
text: "File"
}), new Element("span.type", {
text: "Type"
})).inject(self.files_container);
if (self.movie.data.releases) Array.each(self.movie.data.releases, function(release) {
var rel = new Element("div.release").inject(self.files_container);
Object.each(release.files, function(files, type) {
Array.each(files, function(file) {
new Element("div.file.item").adopt(new Element("span.name", {
text: file
}), new Element("span.type", {
text: type
})).inject(rel);
});
});
});
}
return self.files_container;
}
});
MA.MarkAsDone = new Class({
Extends: MovieAction,
create: function() {
var self = this;
self.button = self.createButton();
self.detail_button = self.createButton();
},
createButton: function() {
var self = this;
return new Element("a.mark_as_done", {
text: "Mark as done",
title: "Remove from available list and move to managed movies",
events: {
click: self.markMovieDone.bind(self)
}
});
},
markMovieDone: function() {
var self = this;
Api.request("media.delete", {
data: {
id: self.movie.get("_id"),
delete_from: "wanted"
},
onComplete: function() {
self.movie.destroy();
}
});
}
});
var Movie = new Class({
Extends: BlockBase,
Implements: [ Options, Events ],
actions: null,
details: null,
initialize: function(list, options, data) {
var self = this;
self.actions = [];
self.data = data;
self.list = list;
self.buttons = [];
self.el = new Element("a.movie").grab(self.inner = new Element("div.inner"));
self.el.store("klass", self);
self.profile = Quality.getProfile(data.profile_id) || {};
self.category = CategoryList.getCategory(data.category_id) || {};
self.parent(self, options);
self.addEvents();
},
openDetails: function() {
var self = this;
if (!self.details) {
self.details = new MovieDetails(self, {
level: 3
});
self.actions.each(function(action, nr) {
var details = action.getDetails();
if (details) {
self.details.addSection(action.getLabel(), details);
} else {
var button = action.getDetailButton();
if (button) {
self.details.addButton(button);
}
}
});
}
App.getPageContainer().grab(self.details);
requestTimeout(self.details.open.bind(self.details), 20);
},
addEvents: function() {
var self = this;
self.global_events = {};
self.global_events["movie.update"] = function(notification) {
if (self.data._id != notification.data._id) return;
self.busy(false);
requestTimeout(function() {
self.update(notification);
}, 2e3);
};
App.on("movie.update", self.global_events["movie.update"]);
[ "media.busy", "movie.searcher.started" ].each(function(listener) {
self.global_events[listener] = function(notification) {
if (notification.data && (self.data._id == notification.data._id || typeOf(notification.data._id) == "array" && notification.data._id.indexOf(self.data._id) > -1)) self.busy(true);
};
App.on(listener, self.global_events[listener]);
});
self.global_events["movie.searcher.ended"] = function(notification) {
if (notification.data && self.data._id == notification.data._id) self.busy(false);
};
App.on("movie.searcher.ended", self.global_events["movie.searcher.ended"]);
self.global_events["release.update_status"] = function(notification) {
var data = notification.data;
if (data && self.data._id == data.media_id) {
if (!self.data.releases) self.data.releases = [];
var updated = false;
self.data.releases.each(function(release) {
if (release._id == data._id) {
release.status = data.status;
updated = true;
}
});
if (updated) self.updateReleases();
}
};
App.on("release.update_status", self.global_events["release.update_status"]);
},
destroy: function() {
var self = this;
self.el.destroy();
delete self.list.movies_added[self.get("id")];
self.list.movies.erase(self);
self.list.checkIfEmpty();
if (self.details) self.details.close();
Object.each(self.global_events, function(handle, listener) {
App.off(listener, handle);
});
},
busy: function(set_busy, timeout) {
var self = this;
if (!set_busy) {
requestTimeout(function() {
if (self.spinner) {
self.mask.fade("out");
requestTimeout(function() {
if (self.mask) self.mask.destroy();
if (self.spinner) self.spinner.destroy();
self.spinner = null;
self.mask = null;
}, timeout || 400);
}
}, timeout || 1e3);
} else if (!self.spinner) {
self.createMask();
self.spinner = createSpinner(self.mask);
self.mask.fade("in");
}
},
createMask: function() {
var self = this;
self.mask = new Element("div.mask", {
styles: {
"z-index": 4
}
}).inject(self.el, "top").fade("hide");
},
update: function(notification) {
var self = this;
self.actions = [];
self.data = notification.data;
self.inner.empty();
self.profile = Quality.getProfile(self.data.profile_id) || {};
self.category = CategoryList.getCategory(self.data.category_id) || {};
self.create();
self.select(self.select_checkbox.get("checked"));
self.busy(false);
},
create: function() {
var self = this;
self.el.addClass("status_" + self.get("status"));
var eta_date = self.getETA();
var rating, stars;
if ([ "suggested", "chart" ].indexOf(self.data.status) > -1 && self.data.info && self.data.info.rating && self.data.info.rating.imdb) {
rating = self.data.info.rating.imdb;
stars = [];
var half_rating = rating[0] / 2;
for (var i = 1; i <= 5; i++) {
if (half_rating >= 1) stars.push(new Element("span.icon-star")); else if (half_rating > 0) stars.push(new Element("span.icon-star-half")); else stars.push(new Element("span.icon-star-empty"));
half_rating -= 1;
}
}
var thumbnail = new Element("div.poster");
if (self.data.files && self.data.files.image_poster && self.data.files.image_poster.length > 0) {
thumbnail = new Element("div", {
class: "type_image poster",
styles: {
"background-image": "url(" + Api.createUrl("file.cache") + self.data.files.image_poster[0].split(Api.getOption("path_sep")).pop() + ")"
}
});
} else if (self.data.info && self.data.info.images && self.data.info.images.poster && self.data.info.images.poster.length > 0) {
thumbnail = new Element("div", {
class: "type_image poster",
styles: {
"background-image": "url(" + self.data.info.images.poster[0] + ")"
}
});
}
self.inner.adopt(self.select_checkbox = new Element("input[type=checkbox]"), new Element("div.poster_container").adopt(thumbnail, self.actions_el = new Element("div.actions")), new Element("div.info").adopt(new Element("div.title").adopt(new Element("span", {
text: self.getTitle() || "n/a"
}), new Element("div.year", {
text: self.data.info.year || "n/a"
})), eta_date ? new Element("div.eta", {
text: eta_date,
title: "ETA"
}) : null, self.quality = new Element("div.quality"), rating ? new Element("div.rating[title=" + rating[0] + "]").adopt(stars, new Element("span.votes[text=(" + rating.join(" / ") + ")][title=Votes]")) : null));
if (!thumbnail) self.el.addClass("no_thumbnail");
if (self.profile.data) self.profile.getTypes().each(function(type) {
var q = self.addQuality(type.get("quality"), type.get("3d"));
if ((type.finish === true || type.get("finish")) && !q.hasClass("finish")) {
q.addClass("finish");
q.set("title", q.get("title") + " Will finish searching for this movie if this quality is found.");
}
});
self.updateReleases();
},
onClick: function(e) {
var self = this;
if (e.target.getParents(".actions").length === 0 && e.target != self.select_checkbox) {
e.stopPropagation();
self.addActions();
self.openDetails();
}
},
addActions: function() {
var self = this;
if (self.actions.length <= 0) {
self.options.actions.each(function(a) {
var action = new a(self), button = action.getButton();
if (button) {
self.actions_el.grab(button);
self.buttons.push(button);
}
self.actions.push(action);
});
}
},
onMouseenter: function() {
var self = this;
if (App.mobile_screen) return;
self.addActions();
if (self.list.current_view == "thumb") {
self.el.addClass("hover_start");
requestTimeout(function() {
self.el.removeClass("hover_start");
}, 300);
dynamics.css(self.inner, {
scale: 1
});
dynamics.animate(self.inner, {
scale: .9
}, {
type: dynamics.bounce
});
self.buttons.each(function(el, nr) {
dynamics.css(el, {
opacity: 0,
translateY: 50
});
dynamics.animate(el, {
opacity: 1,
translateY: 0
}, {
type: dynamics.spring,
frequency: 200,
friction: 300,
duration: 800,
delay: 100 + nr * 40
});
});
}
},
updateReleases: function() {
var self = this;
if (!self.data.releases || self.data.releases.length === 0) return;
self.data.releases.each(function(release) {
var q = self.quality.getElement(".q_" + release.quality + (release.is_3d ? ".is_3d" : ":not(.is_3d)")), status = release.status;
if (!q && (status == "snatched" || status == "seeding" || status == "done")) q = self.addQuality(release.quality, release.is_3d || false);
if (q && !q.hasClass(status)) {
q.addClass(status);
q.set("title", (q.get("title") ? q.get("title") : "") + " status: " + status);
}
});
},
addQuality: function(quality, is_3d) {
var self = this;
var q = Quality.getQuality(quality);
return new Element("span", {
text: q.label + (is_3d ? " 3D" : ""),
class: "q_" + q.identifier + (is_3d ? " is_3d" : ""),
title: ""
}).inject(self.quality);
},
getTitle: function(prefixed) {
var self = this;
if (self.data.title) return prefixed ? self.data.title : self.getUnprefixedTitle(self.data.title); else if (self.data.info && self.data.info.titles && self.data.info.titles.length > 0) return prefixed ? self.data.info.titles[0] : self.getUnprefixedTitle(self.data.info.titles[0]);
return "Unknown movie";
},
getUnprefixedTitle: function(t) {
if (t.substr(0, 4).toLowerCase() == "the ") t = t.substr(4) + ", The"; else if (t.substr(0, 3).toLowerCase() == "an ") t = t.substr(3) + ", An"; else if (t.substr(0, 2).toLowerCase() == "a ") t = t.substr(2) + ", A";
return t;
},
getIdentifier: function() {
var self = this;
try {
return self.get("identifiers").imdb;
} catch (e) {}
return self.get("imdb");
},
getETA: function(format) {
var self = this, d = new Date(), now = Math.round(+d / 1e3), eta = null, eta_date = "";
if (self.data.info.release_date) [ self.data.info.release_date.dvd, self.data.info.release_date.theater ].each(function(timestamp) {
if (timestamp > 0 && (eta === null || Math.abs(timestamp - now) < Math.abs(eta - now))) eta = timestamp;
});
if (eta) {
eta_date = new Date(eta * 1e3);
if (+eta_date / 1e3 < now) {
eta_date = null;
} else {
eta_date = format ? eta_date.format(format) : eta_date.format("%b") + (d.getFullYear() != eta_date.getFullYear() ? " " + eta_date.getFullYear() : "");
}
}
return now + 8035200 > eta ? eta_date : "";
},
get: function(attr) {
return this.data[attr] || this.data.info[attr];
},
select: function(select) {
var self = this;
self.select_checkbox.set("checked", select);
self.el[self.select_checkbox.get("checked") ? "addClass" : "removeClass"]("checked");
},
isSelected: function() {
return this.select_checkbox.get("checked");
},
toElement: function() {
return this.el;
}
});
Page.Movies = new Class({
Extends: PageBase,
name: "movies",
icon: "movie",
sub_pages: [ "Wanted", "Manage" ],
default_page: "Wanted",
current_page: null,
initialize: function(parent, options) {
var self = this;
self.parent(parent, options);
self.navigation = new BlockNavigation();
$(self.navigation).inject(self.el);
},
defaultAction: function(action, params) {
var self = this;
if (self.current_page) {
self.current_page.hide();
if (self.current_page.list && self.current_page.list.navigation) self.current_page.list.navigation.dispose();
}
var route = new Route();
route.parse(action);
var page_name = route.getPage() != "index" ? route.getPage().capitalize() : self.default_page;
var page = self.sub_pages.filter(function(page) {
return page.name == page_name;
}).pick()["class"];
page.open(route.getAction() || "index", params);
page.show();
if (page.list && page.list.navigation) page.list.navigation.inject(self.navigation);
self.current_page = page;
self.navigation.activate(page_name.toLowerCase());
}
});
var BlockSearchMovieItem = new Class({
Implements: [ Options, Events ],
initialize: function(info, options) {
var self = this;
self.setOptions(options);
self.info = info;
self.alternative_titles = [];
self.create();
},
create: function() {
var self = this, info = self.info;
var in_library;
if (info.in_library) {
in_library = [];
(info.in_library.releases || []).each(function(release) {
in_library.include(release.quality);
});
}
self.el = new Element("div.media_result", {
id: info.imdb,
events: {
click: self.showOptions.bind(self)
}
}).adopt(self.thumbnail = info.images && info.images.poster.length > 0 ? new Element("img.thumbnail", {
src: info.images.poster[0],
height: null,
width: null
}) : null, self.options_el = new Element("div.options"), self.data_container = new Element("div.data").grab(self.info_container = new Element("div.info").grab(new Element("h2", {
class: info.in_wanted && info.in_wanted.profile_id || in_library ? "in_library_wanted" : "",
title: self.getTitle()
}).adopt(self.title = new Element("span.title", {
text: self.getTitle()
}), self.year = info.year ? new Element("span.year", {
text: info.year
}) : null, info.in_wanted && info.in_wanted.profile_id ? new Element("span.in_wanted", {
text: "Already in wanted list: " + Quality.getProfile(info.in_wanted.profile_id).get("label")
}) : in_library ? new Element("span.in_library", {
text: "Already in library: " + in_library.join(", ")
}) : null))));
if (info.titles) info.titles.each(function(title) {
self.alternativeTitle({
title: title
});
});
},
alternativeTitle: function(alternative) {
var self = this;
self.alternative_titles.include(alternative);
},
getTitle: function() {
var self = this;
try {
return self.info.original_title ? self.info.original_title : self.info.titles[0];
} catch (e) {
return "Unknown";
}
},
get: function(key) {
return this.info[key];
},
showOptions: function() {
var self = this;
self.createOptions();
self.data_container.addClass("open");
self.el.addEvent("outerClick", self.closeOptions.bind(self));
},
closeOptions: function() {
var self = this;
self.data_container.removeClass("open");
self.el.removeEvents("outerClick");
},
add: function(e) {
var self = this;
if (e) e.preventDefault();
self.loadingMask();
Api.request("movie.add", {
data: {
identifier: self.info.imdb,
title: self.title_select.get("value"),
profile_id: self.profile_select.get("value"),
category_id: self.category_select.get("value")
},
onComplete: function(json) {
self.options_el.empty();
self.options_el.grab(new Element("div.message", {
text: json.success ? "Movie successfully added." : "Movie didn't add properly. Check logs"
}));
self.mask.fade("out");
self.fireEvent("added");
},
onFailure: function() {
self.options_el.empty();
self.options_el.grab(new Element("div.message", {
text: "Something went wrong, check the logs for more info."
}));
self.mask.fade("out");
}
});
},
createOptions: function() {
var self = this, info = self.info;
if (!self.options_el.hasClass("set")) {
self.options_el.grab(new Element("div").adopt(new Element("div.title").grab(self.title_select = new Element("select", {
name: "title"
})), new Element("div.profile").grab(self.profile_select = new Element("select", {
name: "profile"
})), self.category_select_container = new Element("div.category").grab(self.category_select = new Element("select", {
name: "category"
}).grab(new Element("option", {
value: -1,
text: "None"
}))), new Element("div.add").grab(self.add_button = new Element("a.button", {
text: "Add",
events: {
click: self.add.bind(self)
}
}))));
Array.each(self.alternative_titles, function(alt) {
new Element("option", {
text: alt.title
}).inject(self.title_select);
});
var categories = CategoryList.getAll();
if (categories.length === 0) self.category_select_container.hide(); else {
self.category_select_container.show();
categories.each(function(category) {
new Element("option", {
value: category.data._id,
text: category.data.label
}).inject(self.category_select);
});
}
var profiles = Quality.getActiveProfiles();
if (profiles.length == 1) self.profile_select.hide();
profiles.each(function(profile) {
new Element("option", {
value: profile.get("_id"),
text: profile.get("label")
}).inject(self.profile_select);
});
self.options_el.addClass("set");
if (categories.length === 0 && self.title_select.getElements("option").length == 1 && profiles.length == 1 && !(self.info.in_wanted && self.info.in_wanted.profile_id || in_library)) self.add();
}
},
loadingMask: function() {
var self = this;
self.mask = new Element("div.mask").inject(self.el).fade("hide");
createSpinner(self.mask);
self.mask.fade("in");
},
toElement: function() {
return this.el;
}
});
var MoviesWanted = new Class({
Extends: PageBase,
order: 10,
name: "wanted",
title: "Gimmy gimmy gimmy!",
folder_browser: null,
indexAction: function() {
var self = this;
if (!self.list) {
self.manual_search = new Element("a", {
title: "Force a search for the full wanted list",
text: "Search all wanted",
events: {
click: self.doFullSearch.bind(self, true)
}
});
self.scan_folder = new Element("a", {
title: "Scan a folder and rename all movies in it",
text: "Manual folder scan",
events: {
click: self.scanFolder.bind(self)
}
});
self.list = new MovieList({
identifier: "wanted",
status: "active",
actions: [ MA.IMDB, MA.Release, MA.Trailer, MA.Refresh, MA.Readd, MA.Delete, MA.Category, MA.Profile ],
add_new: true,
menu: [ self.manual_search, self.scan_folder ],
on_empty_element: new Element("div.empty_wanted").adopt(new Element("div.no_movies", {
text: "Seems like you don't have any movies yet.. Maybe add some via search or the extension."
}), App.createUserscriptButtons())
});
$(self.list).inject(self.content);
requestTimeout(self.startProgressInterval.bind(self), 4e3);
}
},
doFullSearch: function() {
var self = this;
if (!self.search_in_progress) {
Api.request("movie.searcher.full_search");
self.startProgressInterval();
}
},
startProgressInterval: function() {
var self = this;
var start_text = self.manual_search.get("text");
self.progress_interval = requestInterval(function() {
if (self.search_progress && self.search_progress.running) return;
self.search_progress = Api.request("movie.searcher.progress", {
onComplete: function(json) {
self.search_in_progress = true;
if (!json.movie) {
clearRequestInterval(self.progress_interval);
self.search_in_progress = false;
self.manual_search.set("text", start_text);
} else {
var progress = json.movie;
self.manual_search.set("text", "Searching.. (" + Math.round((progress.total - progress.to_go) / progress.total * 100) + "%)");
}
}
});
}, 1e3);
},
scanFolder: function(e) {
e.stop();
var self = this;
var options = {
name: "Scan_folder"
};
if (!self.folder_browser) {
self.folder_browser = new Option.Directory("Scan", "folder", "", options);
self.folder_browser.save = function() {
var folder = self.folder_browser.getValue();
Api.request("renamer.scan", {
data: {
base_folder: folder
}
});
};
self.folder_browser.inject(self.content, "top");
self.folder_browser.fireEvent("injected");
self.folder_browser.directory_inlay.hide();
self.folder_browser.el.removeChild(self.folder_browser.el.firstChild);
self.folder_browser.showBrowser();
self.folder_browser.browser.getElements(".clear.button").hide();
self.folder_browser.save_button.text = "Select";
self.folder_browser.browser.setStyles({
"z-index": 1e3,
right: 20,
top: 0,
margin: 0
});
self.folder_browser.pointer.setStyles({
right: 20
});
} else {
self.folder_browser.showBrowser();
}
self.list.navigation_menu.hide();
}
});
var Charts = new Class({
Implements: [ Options, Events ],
shown_once: false,
initialize: function(options) {
var self = this;
self.setOptions(options);
self.create();
},
create: function() {
var self = this;
self.el = new Element("div.charts").grab(self.el_refresh_container = new Element("div.refresh").grab(self.el_refreshing_text = new Element("span.refreshing", {
text: "Refreshing charts..."
})));
self.show();
requestTimeout(function() {
self.fireEvent("created");
}, 0);
},
fill: function(json) {
var self = this;
self.el_refreshing_text.hide();
if (json && json.count > 0) {
json.charts.sort(function(a, b) {
return a.order - b.order;
});
Object.each(json.charts, function(chart) {
var chart_list = new MovieList({
navigation: false,
identifier: chart.name.toLowerCase().replace(/[^a-z0-9]+/g, "_"),
title: chart.name,
description: '<a href="' + chart.url + '">See source</a>',
actions: [ MA.Add, MA.ChartIgnore, MA.IMDB, MA.Trailer ],
load_more: false,
view: "thumb",
force_view: true,
api_call: null
});
chart_list.store(chart.list);
chart_list.addMovies(chart.list, chart.list.length);
chart_list.checkIfEmpty();
chart_list.fireEvent("loaded");
$(chart_list).inject(self.el);
});
}
self.fireEvent("loaded");
},
show: function() {
var self = this;
self.el.show();
if (!self.shown_once) {
requestTimeout(function() {
self.api_request = Api.request("charts.view", {
onComplete: self.fill.bind(self)
});
}, 100);
self.shown_once = true;
}
},
toElement: function() {
return this.el;
}
});
var TraktAutomation = new Class({
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addRegisterButton.bind(self));
},
addRegisterButton: function() {
var self = this, setting_page = App.getPage("Settings");
setting_page.addEvent("create", function() {
var fieldset = setting_page.tabs.automation.groups.trakt_automation, l = window.location;
var trakt_set = 0;
fieldset.getElements("input[type=text]").each(function(el) {
trakt_set += +(el.get("value") !== "");
});
new Element(".ctrlHolder").adopt(trakt_set > 0 ? [ self.unregister = new Element("a.button.red", {
text: "Unregister",
events: {
click: function() {
fieldset.getElements("input[name*=oauth_token]").set("value", "").fireEvent("change");
self.unregister.destroy();
self.unregister_or.destroy();
}
}
}), self.unregister_or = new Element("span[text=or]") ] : null, new Element("a.button", {
text: trakt_set > 0 ? "Register a different account" : "Register your trakt.tv account",
events: {
click: function() {
Api.request("automation.trakt.auth_url", {
data: {
host: l.protocol + "//" + l.hostname + (l.port ? ":" + l.port : "")
},
onComplete: function(json) {
window.location = json.url;
}
});
}
}
})).inject(fieldset);
});
}
});
new TraktAutomation();
var NotificationBase = new Class({
Extends: BlockBase,
Implements: [ Options, Events ],
initialize: function(options) {
var self = this;
self.setOptions(options);
App.addEvent("unload", self.stopPoll.bind(self));
App.addEvent("reload", self.startInterval.bind(self, [ true ]));
App.on("notification", self.notify.bind(self));
App.on("message", self.showMessage.bind(self));
App.addEvent("loadSettings", self.addTestButtons.bind(self));
self.notifications = [];
App.addEvent("load", function() {
App.block.notification = new BlockMenu(self, {
button_class: "icon-notifications",
class: "notification_menu",
onOpen: self.markAsRead.bind(self)
});
$(App.block.notification).inject(App.getBlock("search"), "after");
self.badge = new Element("div.badge").inject(App.block.notification, "top").hide();
});
window.addEvent("load", function() {
requestTimeout(function() {
self.startInterval($(window).getSize().x <= 480 ? 2e3 : 100);
}, 0);
});
},
notify: function(result) {
var self = this;
var added = new Date();
added.setTime(result.added * 1e3);
result.el = App.getBlock("notification").addLink(new Element("span." + (result.read ? "read" : "")).adopt(new Element("span.message", {
html: result.message
}), new Element("span.added", {
text: added.timeDiffInWords(),
title: added
})), "top");
self.notifications.include(result);
if ((result.important !== undefined || result.sticky !== undefined) && !result.read) {
var sticky = true;
App.trigger("message", [ result.message, sticky, result ]);
} else if (!result.read) {
self.setBadge(self.notifications.filter(function(n) {
return !n.read;
}).length);
}
},
setBadge: function(value) {
var self = this;
self.badge.set("text", value);
self.badge[value ? "show" : "hide"]();
},
markAsRead: function(force_ids) {
var self = this, ids = force_ids;
if (!force_ids) {
var rn = self.notifications.filter(function(n) {
return !n.read && n.important === undefined;
});
ids = [];
rn.each(function(n) {
ids.include(n._id);
});
}
if (ids.length > 0) Api.request("notification.markread", {
data: {
ids: ids.join(",")
},
onSuccess: function() {
self.setBadge("");
}
});
},
startInterval: function(force) {
var self = this;
if (self.stopped && !force) {
self.stopped = false;
return;
}
self.request = Api.request("notification.listener", {
data: {
init: true
},
onSuccess: function(json) {
self.processData(json, true);
}
}).send();
requestInterval(function() {
if (self.request && self.request.isRunning()) {
self.request.cancel();
self.startPoll();
}
}, 12e4);
},
startPoll: function() {
var self = this;
if (self.stopped) return;
if (self.request && self.request.isRunning()) self.request.cancel();
self.request = Api.request("nonblock/notification.listener", {
onSuccess: function(json) {
self.processData(json, false);
},
data: {
last_id: self.last_id
},
onFailure: function() {
requestTimeout(self.startPoll.bind(self), 2e3);
}
}).send();
},
stopPoll: function() {
if (this.request) this.request.cancel();
this.stopped = true;
},
processData: function(json, init) {
var self = this;
if (json && json.result) {
Array.each(json.result, function(result) {
App.trigger(result._t || result.type, [ result ]);
if (result.message && result.read === undefined && !init) self.showMessage(result.message);
});
if (json.result.length > 0) self.last_id = json.result.getLast().message_id;
}
requestTimeout(self.startPoll.bind(self), 1500);
},
showMessage: function(message, sticky, data) {
var self = this;
if (!self.message_container) self.message_container = new Element("div.messages").inject(document.body);
var new_message = new Element("div", {
class: "message" + (sticky ? " sticky" : ""),
html: '<div class="inner">' + message + "</div>"
}).inject(self.message_container, "top");
requestTimeout(function() {
new_message.addClass("show");
}, 10);
var hide_message = function() {
new_message.addClass("hide");
requestTimeout(function() {
new_message.destroy();
}, 1e3);
};
if (sticky) new_message.grab(new Element("a.close.icon2", {
events: {
click: function() {
self.markAsRead([ data._id ]);
hide_message();
}
}
})); else requestTimeout(hide_message, 4e3);
},
addTestButtons: function() {
var self = this;
var setting_page = App.getPage("Settings");
setting_page.addEvent("create", function() {
Object.each(setting_page.tabs.notifications.groups, self.addTestButton.bind(self));
});
},
addTestButton: function(fieldset, plugin_name) {
var self = this, button_name = self.testButtonName(fieldset);
if (button_name.contains("Notifications")) return;
new Element(".ctrlHolder.test_button").grab(new Element("a.button", {
text: button_name,
events: {
click: function() {
var button = fieldset.getElement(".test_button .button");
button.set("text", "Sending notification");
Api.request("notify." + plugin_name + ".test", {
onComplete: function(json) {
button.set("text", button_name);
var message;
if (json.success) {
message = new Element("span.success", {
text: "Notification successful"
}).inject(button, "after");
} else {
message = new Element("span.failed", {
text: "Notification failed. Check logs for details."
}).inject(button, "after");
}
requestTimeout(function() {
message.destroy();
}, 3e3);
}
});
}
}
})).inject(fieldset);
},
testButtonName: function(fieldset) {
var name = fieldset.getElement("h2 .group_label").get("text");
return "Test " + name;
}
});
window.Notification = new NotificationBase();
var TwitterNotification = new Class({
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addRegisterButton.bind(self));
},
addRegisterButton: function() {
var self = this;
var setting_page = App.getPage("Settings");
setting_page.addEvent("create", function() {
var fieldset = setting_page.tabs.notifications.groups.twitter, l = window.location;
var twitter_set = 0;
fieldset.getElements("input[type=text]").each(function(el) {
twitter_set += +(el.get("value") !== "");
});
new Element(".ctrlHolder").adopt(twitter_set > 0 ? [ self.unregister = new Element("a.button.red", {
text: 'Unregister "' + fieldset.getElement("input[name*=screen_name]").get("value") + '"',
events: {
click: function() {
fieldset.getElements("input[type=text]").set("value", "").fireEvent("change");
self.unregister.destroy();
self.unregister_or.destroy();
}
}
}), self.unregister_or = new Element("span[text=or]") ] : null, new Element("a.button", {
text: twitter_set > 0 ? "Register a different account" : "Register your Twitter account",
events: {
click: function() {
Api.request("notify.twitter.auth_url", {
data: {
host: l.protocol + "//" + l.hostname + (l.port ? ":" + l.port : "")
},
onComplete: function(json) {
window.location = json.url;
}
});
}
}
})).inject(fieldset.getElement(".test_button"), "before");
});
}
});
window.addEvent("domready", function() {
new TwitterNotification();
});
var CategoryListBase = new Class({
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addSettings.bind(self));
},
setup: function(categories) {
var self = this;
self.categories = [];
Array.each(categories, self.createCategory.bind(self));
},
addSettings: function() {
var self = this;
self.settings = App.getPage("Settings");
self.settings.addEvent("create", function() {
var tab = self.settings.createSubTab("category", {
label: "Categories",
name: "category",
subtab_label: "Category & filtering"
}, self.settings.tabs.searcher, "searcher");
self.tab = tab.tab;
self.content = tab.content;
self.createList();
self.createOrdering();
});
self.settings.addEvent("create", function() {
var renamer_group = self.settings.tabs.renamer.groups.renamer;
self.categories.each(function(category) {
var input = new Option.Directory("section_name", "option.name", category.get("destination"), {
name: category.get("label")
});
input.inject(renamer_group.getElement(".renamer_to"));
input.fireEvent("injected");
input.save = function() {
category.data.destination = input.getValue();
category.save();
};
});
});
},
createList: function() {
var self = this;
var count = self.categories.length;
self.settings.createGroup({
label: "Categories",
description: "Create categories, each one extending global filters. (Needs refresh '" + (App.isMac() ? "CMD+R" : "F5") + "' after editing)"
}).inject(self.content).adopt(self.category_container = new Element("div.container"), new Element("a.add_new_category", {
text: count > 0 ? "Create another category" : "Click here to create a category.",
events: {
click: function() {
var category = self.createCategory();
$(category).inject(self.category_container);
}
}
}));
Array.each(self.categories, function(category) {
$(category).inject(self.category_container);
});
},
getCategory: function(id) {
return this.categories.filter(function(category) {
return category.data._id == id;
}).pick();
},
getAll: function() {
return this.categories;
},
createCategory: function(data) {
var self = this;
data = data || {
id: randomString()
};
var category = new Category(data);
self.categories.include(category);
return category;
},
createOrdering: function() {
var self = this;
var category_list;
self.settings.createGroup({
label: "Category ordering"
}).adopt(new Element(".ctrlHolder#category_ordering").adopt(new Element("label[text=Order]"), category_list = new Element("ul"), new Element("p.formHint", {
html: "Change the order the categories are in the dropdown list."
}))).inject(self.content);
Array.each(self.categories, function(category) {
new Element("li", {
"data-id": category.data._id
}).adopt(new Element("span.category_label", {
text: category.data.label
}), new Element("span.handle.icon-handle")).inject(category_list);
});
self.category_sortable = new Sortables(category_list, {
revert: true,
handle: "",
opacity: .5,
onComplete: self.saveOrdering.bind(self)
});
},
saveOrdering: function() {
var self = this;
var ids = [];
self.category_sortable.list.getElements("li").each(function(el) {
ids.include(el.get("data-id"));
});
Api.request("category.save_order", {
data: {
ids: ids
}
});
}
});
window.CategoryList = new CategoryListBase();
var Category = new Class({
data: {},
initialize: function(data) {
var self = this;
self.data = data;
self.create();
self.el.addEvents({
"change:relay(select)": self.save.bind(self, 0),
"keyup:relay(input[type=text])": self.save.bind(self, [ 300 ])
});
},
create: function() {
var self = this;
var data = self.data;
self.el = new Element("div.category").adopt(self.delete_button = new Element("span.delete.icon-delete", {
events: {
click: self.del.bind(self)
}
}), new Element(".category_label.ctrlHolder").adopt(new Element("label", {
text: "Name"
}), new Element("input", {
type: "text",
value: data.label,
placeholder: "Example: Kids, Horror or His"
}), new Element("p.formHint", {
text: "See global filters for explanation."
})), new Element(".category_preferred.ctrlHolder").adopt(new Element("label", {
text: "Preferred"
}), new Element("input", {
type: "text",
value: data.preferred,
placeholder: "Blu-ray, DTS"
})), new Element(".category_required.ctrlHolder").adopt(new Element("label", {
text: "Required"
}), new Element("input", {
type: "text",
value: data.required,
placeholder: "Example: DTS, AC3 & English"
})), new Element(".category_ignored.ctrlHolder").adopt(new Element("label", {
text: "Ignored"
}), new Element("input", {
type: "text",
value: data.ignored,
placeholder: "Example: dubbed, swesub, french"
})));
self.makeSortable();
},
save: function(delay) {
var self = this;
if (self.save_timer) clearRequestTimeout(self.save_timer);
self.save_timer = requestTimeout(function() {
Api.request("category.save", {
data: self.getData(),
useSpinner: true,
spinnerOptions: {
target: self.el
},
onComplete: function(json) {
if (json.success) {
self.data = json.category;
}
}
});
}, delay || 0);
},
getData: function() {
var self = this;
return {
id: self.data._id,
label: self.el.getElement(".category_label input").get("value"),
required: self.el.getElement(".category_required input").get("value"),
preferred: self.el.getElement(".category_preferred input").get("value"),
ignored: self.el.getElement(".category_ignored input").get("value"),
destination: self.data.destination
};
},
del: function() {
var self = this;
if (self.data.label === undefined) {
self.el.destroy();
return;
}
var label = self.el.getElement(".category_label input").get("value");
var qObj = new Question('Are you sure you want to delete <strong>"' + label + '"</strong>?', "", [ {
text: 'Delete "' + label + '"',
class: "delete",
events: {
click: function(e) {
e.preventDefault();
Api.request("category.delete", {
data: {
id: self.data._id
},
useSpinner: true,
spinnerOptions: {
target: self.el
},
onComplete: function(json) {
if (json.success) {
qObj.close();
self.el.destroy();
} else {
alert(json.message);
}
}
});
}
}
}, {
text: "Cancel",
cancel: true
} ]);
},
makeSortable: function() {
var self = this;
self.sortable = new Sortables(self.category_container, {
revert: true,
handle: ".handle",
opacity: .5,
onComplete: self.save.bind(self, 300)
});
},
get: function(attr) {
return this.data[attr];
},
toElement: function() {
return this.el;
}
});
Page.Log = new Class({
Extends: PageBase,
order: 60,
name: "log",
title: "Show recent logs.",
has_tab: false,
navigation: null,
log_items: [],
report_text: "### Steps to reproduce:\n" + "1. ..\n" + "2. ..\n" + "\n" + "### Information:\n" + "Movie(s) I have this with: ...\n" + "Quality of the movie being searched: ...\n" + "Providers I use: ...\n" + "Version of CouchPotato: {version}\n" + "Running on: ...\n" + "\n" + "### Logs:\n" + "```\n{issue}```",
indexAction: function() {
var self = this;
self.getLogs(0);
},
getLogs: function(nr) {
var self = this;
if (self.log) self.log.destroy();
self.log = new Element("div.container.loading", {
text: "loading...",
events: {
"mouseup:relay(.time)": function(e) {
requestTimeout(function() {
self.showSelectionButton(e);
}, 100);
}
}
}).inject(self.content);
if (self.navigation) {
var nav = self.navigation.getElement(".nav");
nav.getElements(".active").removeClass("active");
self.navigation.getElements("li")[nr + 1].addClass("active");
}
if (self.request && self.request.running) self.request.cancel();
self.request = Api.request("logging.get", {
data: {
nr: nr
},
onComplete: function(json) {
self.log.set("text", "");
self.log_items = self.createLogElements(json.log);
self.log.adopt(self.log_items);
self.log.removeClass("loading");
self.scrollToBottom();
if (!self.navigation) {
self.navigation = new Element("div.navigation").adopt(new Element("h2[text=Logs]"), new Element("div.hint", {
text: "Select multiple lines & report an issue"
}));
var nav = new Element("ul.nav", {
events: {
"click:relay(li.select)": function(e, el) {
self.getLogs(parseInt(el.get("text")) - 1);
}
}
}).inject(self.navigation);
new Element("li.filter").grab(new Element("select", {
events: {
change: function() {
var type_filter = this.getSelected()[0].get("value");
self.content.set("data-filter", type_filter);
self.scrollToBottom();
}
}
}).adopt(new Element("option", {
value: "ALL",
text: "Show all logs"
}), new Element("option", {
value: "INFO",
text: "Show only INFO"
}), new Element("option", {
value: "DEBUG",
text: "Show only DEBUG"
}), new Element("option", {
value: "ERROR",
text: "Show only ERROR"
}))).inject(nav);
for (var i = 0; i <= json.total; i++) {
new Element("li", {
text: i + 1,
class: "select " + (nr == i ? "active" : "")
}).inject(nav);
}
new Element("li.clear", {
text: "clear",
events: {
click: function() {
Api.request("logging.clear", {
onComplete: function() {
self.getLogs(0);
}
});
}
}
}).inject(nav);
self.navigation.inject(self.content, "top");
}
}
});
},
createLogElements: function(logs) {
var elements = [];
logs.each(function(log) {
elements.include(new Element("div", {
class: "time " + log.type.toLowerCase()
}).adopt(new Element("span", {
text: log.time
}), new Element("span.type", {
text: log.type
}), new Element("span.message", {
text: log.message
})));
});
return elements;
},
scrollToBottom: function() {
new Fx.Scroll(this.content, {
duration: 0
}).toBottom();
},
showSelectionButton: function(e) {
var self = this, selection = self.getSelected(), start_node = selection.anchorNode, parent_start = start_node.parentNode.getParent(".time"), end_node = selection.focusNode.parentNode.getParent(".time"), text = "";
var remove_button = function() {
self.log.getElements(".highlight").removeClass("highlight");
if (self.do_report) self.do_report.destroy();
document.body.removeEvent("click", remove_button);
};
remove_button();
if (parent_start) start_node = parent_start;
var index = {
start: self.log_items.indexOf(start_node),
end: self.log_items.indexOf(end_node)
};
if (index.start > index.end) {
index = {
start: index.end,
end: index.start
};
}
var nodes = self.log_items.slice(index.start, index.end + 1);
nodes.each(function(node, nr) {
node.addClass("highlight");
node.getElements("span").each(function(span) {
text += self.spaceFill(span.get("text") + " ", 6);
});
text += "\n";
});
self.do_report = new Element("a.do_report.button", {
text: "Report issue",
styles: {
top: e.page.y,
left: e.page.x
},
events: {
click: function(e) {
e.stop();
self.showReport(text);
}
}
}).inject(document.body);
requestTimeout(function() {
document.body.addEvent("click", remove_button);
}, 0);
},
showReport: function(text) {
var self = this, version = Updater.getInfo(), body = self.report_text.replace("{issue}", text).replace("{version}", version ? version.version.repr : "..."), textarea;
var overlay = new Element("div.mask.report_popup", {
method: "post",
events: {
click: function(e) {
overlay.destroy();
}
}
}).grab(new Element("div.bug", {
events: {
click: function(e) {
e.stopPropagation();
}
}
}).adopt(new Element("h1", {
text: "Report a bug"
}), new Element("span").adopt(new Element("span", {
text: "Read "
}), new Element("a.button", {
target: "_blank",
text: "the contributing guide",
href: "https://github.com/RuudBurger/CouchPotatoServer/blob/develop/contributing.md"
}), new Element("span", {
html: " before posting, then copy the text below and <strong>FILL IN</strong> the dots."
})), textarea = new Element("textarea", {
text: body
}), new Element("a.button", {
target: "_blank",
text: "Create a new issue on GitHub with the text above",
href: "https://github.com/RuudBurger/CouchPotatoServer/issues/new",
events: {
click: function(e) {
e.stop();
var body = textarea.get("value"), bdy = "?body=" + (body.length < 2e3 ? encodeURIComponent(body) : "Paste the text here"), win = window.open(e.target.get("href") + bdy, "_blank");
win.focus();
}
}
})));
overlay.inject(document.body);
},
getSelected: function() {
if (window.getSelection) return window.getSelection(); else if (document.getSelection) return document.getSelection(); else {
var selection = document.selection && document.selection.createRange();
if (selection.text) return selection.text;
}
return false;
},
spaceFill: function(number, width) {
if (number.toString().length >= width) return number;
return (new Array(width).join(" ") + number.toString()).substr(-width);
}
});
var Profile = new Class({
data: {},
types: [],
initialize: function(data) {
var self = this;
self.data = data;
self.types = [];
self.create();
self.el.addEvents({
"change:relay(select, input[type=checkbox])": self.save.bind(self, 0),
"keyup:relay(input[type=text])": self.save.bind(self, [ 300 ])
});
},
create: function() {
var self = this;
var data = self.data;
self.el = new Element("div.profile").adopt(self.delete_button = new Element("span.delete.icon-delete", {
events: {
click: self.del.bind(self)
}
}), new Element(".quality_label.ctrlHolder").adopt(new Element("label", {
text: "Name"
}), new Element("input", {
type: "text",
value: data.label,
placeholder: "Profile name"
})), new Element("div.qualities.ctrlHolder").adopt(new Element("label", {
text: "Search for"
}), self.type_container = new Element("ol.types"), new Element("div.formHint", {
html: "Search these qualities (2 minimum), from top to bottom. Use the checkbox, to stop searching after it found this quality."
})), new Element("div.wait_for.ctrlHolder").adopt(new Element("span", {
text: "Wait"
}), new Element("input.wait_for_input.xsmall", {
type: "text",
value: data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0
}), new Element("span", {
text: "day(s) for a better quality "
}), new Element("span.advanced", {
text: "and keep searching"
}), new Element("input.xsmall.stop_after_input.advanced", {
type: "text",
value: data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0
}), new Element("span.advanced", {
text: "day(s) for a better (checked) quality."
}), new Element("span.advanced", {
html: "<br/>Releases need a minimum score of"
}), new Element("input.advanced.xsmall.minimum_score_input", {
size: 4,
type: "text",
value: data.minimum_score || 1
})));
self.makeSortable();
if (data.qualities) {
data.types = [];
data.qualities.each(function(quality, nr) {
data.types.include({
quality: quality,
finish: data.finish[nr] || false,
"3d": data["3d"] ? data["3d"][nr] || false : false
});
});
}
if (data.types) data.types.each(self.addType.bind(self)); else self.delete_button.hide();
self.addType();
},
save: function(delay) {
var self = this;
if (self.save_timer) clearRequestTimeout(self.save_timer);
self.save_timer = requestTimeout(function() {
self.addType();
var data = self.getData();
if (data.types.length < 2) return; else self.delete_button.show();
Api.request("profile.save", {
data: self.getData(),
useSpinner: true,
spinnerOptions: {
target: self.el
},
onComplete: function(json) {
if (json.success) {
self.data = json.profile;
self.type_container.getElement("li:first-child input.finish[type=checkbox]").set("checked", true).getParent().addClass("checked");
}
}
});
}, delay);
},
getData: function() {
var self = this;
var data = {
id: self.data._id,
label: self.el.getElement(".quality_label input").get("value"),
wait_for: self.el.getElement(".wait_for_input").get("value"),
stop_after: self.el.getElement(".stop_after_input").get("value"),
minimum_score: self.el.getElement(".minimum_score_input").get("value"),
types: []
};
Array.each(self.type_container.getElements(".type"), function(type) {
if (!type.hasClass("deleted") && type.getElement("select").get("value") != -1) data.types.include({
quality: type.getElement("select").get("value"),
finish: +type.getElement("input.finish[type=checkbox]").checked,
"3d": +type.getElement("input.3d[type=checkbox]").checked
});
});
return data;
},
addType: function(data) {
var self = this;
var has_empty = false;
self.types.each(function(type) {
if ($(type).hasClass("is_empty")) has_empty = true;
});
if (has_empty) return;
var t = new Profile.Type(data, {
onChange: self.save.bind(self, 0)
});
$(t).inject(self.type_container);
self.sortable.addItems($(t));
self.types.include(t);
},
getTypes: function() {
var self = this;
return self.types.filter(function(type) {
return type.get("quality");
});
},
del: function() {
var self = this;
var label = self.el.getElement(".quality_label input").get("value");
var qObj = new Question('Are you sure you want to delete <strong>"' + label + '"</strong>?', "Items using this profile, will be set to the default quality.", [ {
text: 'Delete "' + label + '"',
class: "delete",
events: {
click: function(e) {
e.preventDefault();
Api.request("profile.delete", {
data: {
id: self.data._id
},
useSpinner: true,
spinnerOptions: {
target: self.el
},
onComplete: function(json) {
if (json.success) {
qObj.close();
self.el.destroy();
} else {
alert(json.message);
}
}
});
}
}
}, {
text: "Cancel",
cancel: true
} ]);
},
makeSortable: function() {
var self = this;
self.sortable = new Sortables(self.type_container, {
revert: true,
handle: ".handle",
opacity: .5,
onComplete: self.save.bind(self, 300)
});
},
get: function(attr) {
return this.data[attr];
},
isCore: function() {
return this.data.core;
},
toElement: function() {
return this.el;
}
});
Profile.Type = new Class({
Implements: [ Events, Options ],
deleted: false,
initialize: function(data, options) {
var self = this;
self.setOptions(options);
self.data = data || {};
self.create();
self.addEvent("change", function() {
self.el[self.qualities.get("value") == "-1" ? "addClass" : "removeClass"]("is_empty");
self.el[Quality.getQuality(self.qualities.get("value")).allow_3d ? "addClass" : "removeClass"]("allow_3d");
self.deleted = self.qualities.get("value") == "-1";
});
},
create: function() {
var self = this;
var data = self.data;
self.el = new Element("li.type").adopt(new Element("span.quality_type.select_wrapper.icon-dropdown").grab(self.fillQualities()), self.finish_container = new Element("label.finish").adopt(self.finish = new Element("input.finish[type=checkbox]", {
checked: data.finish !== undefined ? data.finish : 1,
events: {
change: function() {
if (self.el == self.el.getParent().getElement(":first-child")) {
alert("Top quality always finishes the search");
return;
}
self.fireEvent("change");
}
}
}), new Element("span.check_label[text=finish]")), self["3d_container"] = new Element("label.threed").adopt(self["3d"] = new Element("input.3d[type=checkbox]", {
checked: data["3d"] !== undefined ? data["3d"] : 0,
events: {
change: function() {
self.fireEvent("change");
}
}
}), new Element("span.check_label[text=3D]")), new Element("span.delete.icon-cancel", {
events: {
click: self.del.bind(self)
}
}), new Element("span.handle.icon-handle"));
self.el[self.data.quality ? "removeClass" : "addClass"]("is_empty");
if (self.data.quality && Quality.getQuality(self.data.quality).allow_3d) self.el.addClass("allow_3d");
},
fillQualities: function() {
var self = this;
self.qualities = new Element("select", {
events: {
change: self.fireEvent.bind(self, "change")
}
}).grab(new Element("option", {
text: "+ Add another quality",
value: -1
}));
Object.each(Quality.qualities, function(q) {
new Element("option", {
text: q.label,
value: q.identifier,
"data-allow_3d": q.allow_3d
}).inject(self.qualities);
});
self.qualities.set("value", self.data.quality);
return self.qualities;
},
getData: function() {
var self = this;
return {
quality: self.qualities.get("value"),
finish: +self.finish.checked,
"3d": +self["3d"].checked
};
},
get: function(key) {
return this.data[key];
},
del: function() {
var self = this;
self.el.addClass("deleted");
self.el.hide();
self.deleted = true;
self.fireEvent("change");
},
toElement: function() {
return this.el;
}
});
var QualityBase = new Class({
tab: "",
content: "",
setup: function(data) {
var self = this;
self.qualities = data.qualities;
self.profiles_list = null;
self.profiles = [];
Array.each(data.profiles, self.createProfilesClass.bind(self));
App.addEvent("loadSettings", self.addSettings.bind(self));
},
getProfile: function(id) {
return this.profiles.filter(function(profile) {
return profile.data._id == id;
}).pick();
},
getActiveProfiles: function() {
return Array.filter(this.profiles, function(profile) {
return !profile.data.hide;
});
},
getQuality: function(identifier) {
try {
return this.qualities.filter(function(q) {
return q.identifier == identifier;
}).pick();
} catch (e) {}
return {};
},
addSettings: function() {
var self = this;
self.settings = App.getPage("Settings");
self.settings.addEvent("create", function() {
var tab = self.settings.createSubTab("profile", {
label: "Quality",
name: "profile",
subtab_label: "Qualities"
}, self.settings.tabs.searcher, "searcher");
self.tab = tab.tab;
self.content = tab.content;
self.createProfiles();
self.createProfileOrdering();
self.createSizes();
});
},
createProfiles: function() {
var self = this;
var non_core_profiles = Array.filter(self.profiles, function(profile) {
return !profile.isCore();
});
var count = non_core_profiles.length;
self.settings.createGroup({
label: "Quality Profiles",
description: "Create your own profiles with multiple qualities."
}).inject(self.content).adopt(self.profile_container = new Element("div.container"), new Element("a.add_new_profile", {
text: count > 0 ? "Create another quality profile" : "Click here to create a quality profile.",
events: {
click: function() {
var profile = self.createProfilesClass();
$(profile).inject(self.profile_container);
}
}
}));
Array.each(non_core_profiles, function(profile) {
$(profile).inject(self.profile_container);
});
},
createProfilesClass: function(data) {
var self = this;
data = data || {
id: randomString()
};
var profile = new Profile(data);
self.profiles.include(profile);
return profile;
},
createProfileOrdering: function() {
var self = this;
self.settings.createGroup({
label: "Profile Defaults",
description: "(Needs refresh '" + (App.isMac() ? "CMD+R" : "F5") + "' after editing)"
}).grab(new Element(".ctrlHolder#profile_ordering").adopt(new Element("label[text=Order]"), self.profiles_list = new Element("ul"), new Element("p.formHint", {
html: "Change the order the profiles are in the dropdown list. Uncheck to hide it completely.<br />First one will be default."
}))).inject(self.content);
Array.each(self.profiles, function(profile) {
var check;
new Element("li", {
"data-id": profile.data._id
}).adopt(check = new Element("input[type=checkbox]", {
checked: !profile.data.hide,
events: {
change: self.saveProfileOrdering.bind(self)
}
}), new Element("span.profile_label", {
text: profile.data.label
}), new Element("span.handle.icon-handle")).inject(self.profiles_list);
});
var sorted_changed = false;
self.profile_sortable = new Sortables(self.profiles_list, {
revert: true,
handle: ".handle",
opacity: .5,
onSort: function() {
sorted_changed = true;
},
onComplete: function() {
if (sorted_changed) {
self.saveProfileOrdering();
sorted_changed = false;
}
}
});
},
saveProfileOrdering: function() {
var self = this, ids = [], hidden = [];
self.profiles_list.getElements("li").each(function(el, nr) {
ids.include(el.get("data-id"));
hidden[nr] = +!el.getElement("input[type=checkbox]").get("checked");
});
Api.request("profile.save_order", {
data: {
ids: ids,
hidden: hidden
}
});
},
createSizes: function() {
var self = this;
var group = self.settings.createGroup({
label: "Sizes",
description: "Edit the minimal and maximum sizes (in MB) for each quality.",
advanced: true,
name: "sizes"
}).inject(self.content);
new Element("div.item.head.ctrlHolder").adopt(new Element("span.label", {
text: "Quality"
}), new Element("span.min", {
text: "Min"
}), new Element("span.max", {
text: "Max"
})).inject(group);
Array.each(self.qualities, function(quality) {
new Element("div.ctrlHolder.item").adopt(new Element("span.label", {
text: quality.label
}), new Element("input.min[type=text]", {
value: quality.size_min,
events: {
keyup: function(e) {
self.changeSize(quality.identifier, "size_min", e.target.get("value"));
}
}
}), new Element("input.max[type=text]", {
value: quality.size_max,
events: {
keyup: function(e) {
self.changeSize(quality.identifier, "size_max", e.target.get("value"));
}
}
})).inject(group);
});
},
size_timer: {},
changeSize: function(identifier, type, value) {
var self = this;
if (self.size_timer[identifier + type]) clearRequestTimeout(self.size_timer[identifier + type]);
self.size_timer[identifier + type] = requestTimeout(function() {
Api.request("quality.size.save", {
data: {
identifier: identifier,
value_type: type,
value: value
}
});
}, 300);
}
});
window.Quality = new QualityBase();
Page.Userscript = new Class({
Extends: PageBase,
order: 80,
name: "userscript",
has_tab: false,
options: {
onOpened: function() {
App.fireEvent("unload");
App.getBlock("header").hide();
}
},
indexAction: function() {
var self = this;
self.content.grab(self.frame = new Element("div.frame.loading", {
text: "Loading..."
}));
var url = window.location.href.split("url=")[1];
Api.request("userscript.add_via_url", {
data: {
url: url
},
onComplete: function(json) {
self.frame.empty();
self.frame.removeClass("loading");
if (json.error) self.frame.set("html", json.error); else {
var item = new BlockSearchMovieItem(json.movie);
self.frame.adopt(item);
item.showOptions();
}
}
});
}
});
var UserscriptSettingTab = new Class({
tab: "",
content: "",
initialize: function() {
var self = this;
App.addEvent("loadSettings", self.addSettings.bind(self));
},
addSettings: function() {
var self = this;
self.settings = App.getPage("Settings");
self.settings.addEvent("create", function() {
var host_url = window.location.protocol + "//" + window.location.host;
self.settings.createGroup({
name: "userscript",
label: "Install the browser extension or bookmarklet",
description: "Easily add movies via imdb.com, appletrailers and more"
}).inject(self.settings.tabs.automation.content, "top").adopt(new Element("div").adopt(new Element("a.userscript.button", {
text: "Install extension",
href: "https://couchpota.to/extension/",
target: "_blank"
}), new Element("span.or[text=or]"), new Element("span.bookmarklet").adopt(new Element("a.button.green", {
text: "+CouchPotato",
href: "javascript:void((function(){var e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','" + host_url + Api.createUrl("userscript.bookmark") + "?host=" + encodeURI(host_url + Api.createUrl("userscript.get") + randomString() + "/") + "&r='+Math.random()*99999999);document.body.appendChild(e)})());",
target: "",
events: {
click: function(e) {
e.stop();
alert("Drag it to your bookmark ;)");
}
}
}), new Element("span", {
text: "⇽ Drag this to your bookmarks"
}))), new Element("img", {
src: "https://couchpota.to/media/images/userscript.gif"
}));
});
}
});
window.addEvent("domready", function() {
new UserscriptSettingTab();
});
window.addEvent("load", function() {
var your_version = $(document.body).get("data-userscript_version"), latest_version = App.getOption("userscript_version") || "", key = "cp_version_check", checked_already = Cookie.read(key);
if (your_version && your_version < latest_version && checked_already < latest_version) {
if (confirm("Update to the latest Userscript?\nYour version: " + your_version + ", new version: " + latest_version)) {
document.location = Api.createUrl("userscript.get") + randomString() + "/couchpotato.user.js";
}
Cookie.write(key, latest_version, {
duration: 100
});
}
});
Page.Wizard = new Class({
Extends: Page.Settings,
order: 70,
name: "wizard",
current: "welcome",
has_tab: false,
wizard_only: true,
headers: {
welcome: {
title: "Welcome to the new CouchPotato",
description: "To get started, fill in each of the following settings as much as you can.",
content: new Element("div", {
styles: {
margin: "0 0 0 30px"
}
})
},
general: {
title: "General",
description: "If you want to access CP from outside your local network, you better secure it a bit with a username & password."
},
downloaders: {
title: "What download apps are you using?",
description: "CP needs an external download app to work with. Choose one below. For more downloaders check settings after you have filled in the wizard. If your download app isn't in the list, use the default Blackhole."
},
searcher: {
label: "Providers",
title: "Are you registered at any of these sites?",
description: "CP uses these sites to search for movies. A few free are enabled by default, but it's always better to have more."
},
renamer: {
title: "Move & rename the movies after downloading?",
description: "The coolest part of CP is that it can move and organize your downloaded movies automagically. Check settings and you can even download trailers, subtitles and other data when it has finished downloading. It's awesome!"
},
automation: {
title: "Easily add movies to your wanted list!",
description: "You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the extension or drag the bookmarklet to your bookmarks." + "<br />Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)",
content: function() {
return App.createUserscriptButtons();
}
},
finish: {
title: "Finishing Up",
description: "Are you done? Did you fill in everything as much as possible?" + "<br />Be sure to check the settings to see what more CP can do!<br /><br />" + '<div class="wizard_support">After you\'ve used CP for a while, and you like it (which of course you will), consider supporting CP. Maybe even by writing some code. <br />Or by getting a subscription at <a href="https://usenetserver.com/partners/?a_aid=couchpotato&a_bid=3f357c6f">Usenet Server</a> or <a href="http://www.newshosting.com/partners/?a_aid=couchpotato&a_bid=a0b022df">Newshosting</a>.</div>',
content: new Element("div").grab(new Element("a.button.green", {
styles: {
"margin-top": 20
},
text: "I'm ready to start the awesomeness!",
events: {
click: function(e) {
e.preventDefault();
Api.request("settings.save", {
data: {
section: "core",
name: "show_wizard",
value: 0
},
useSpinner: true,
spinnerOptions: {
target: self.el
},
onComplete: function() {
window.location = App.createUrl("wanted");
}
});
}
}
}))
}
},
groups: [ "welcome", "general", "downloaders", "searcher", "renamer", "automation", "finish" ],
open: function(action, params) {
var self = this;
if (!self.initialized) {
App.fireEvent("unload");
App.getBlock("header").hide();
self.parent(action, params);
self.el.addClass("settings");
self.addEvent("create", function() {
self.orderGroups();
});
self.initialized = true;
self.scroll = new Fx.Scroll(document.body, {
transition: "quint:in:out"
});
} else requestTimeout(function() {
var sc = self.el.getElement(".wgroup_" + action);
self.scroll.start(0, sc.getCoordinates().top - 80);
}, 1);
},
orderGroups: function() {
var self = this;
var form = self.el.getElement(".uniForm");
var tabs = self.el.getElement(".tabs").hide();
self.groups.each(function(group) {
var group_container;
if (self.headers[group]) {
group_container = new Element(".wgroup_" + group);
if (self.headers[group].include) {
self.headers[group].include.each(function(inc) {
group_container.addClass("wgroup_" + inc);
});
}
var content = self.headers[group].content;
group_container.adopt(new Element("h1", {
text: self.headers[group].title
}), self.headers[group].description ? new Element("span.description", {
html: self.headers[group].description
}) : null, content ? typeOf(content) == "function" ? content() : content : null).inject(form);
}
var tab_navigation = tabs.getElement(".t_" + group);
if (!tab_navigation && self.headers[group] && self.headers[group].include) {
tab_navigation = [];
self.headers[group].include.each(function(inc) {
tab_navigation.include(tabs.getElement(".t_" + inc));
});
}
if (tab_navigation && group_container) {
tabs.adopt(tab_navigation);
if (self.headers[group] && self.headers[group].include) {
self.headers[group].include.each(function(inc) {
self.el.getElement(".tab_" + inc).inject(group_container);
});
new Element("li.t_" + group).grab(new Element("a", {
href: App.createUrl("wizard/" + group),
text: (self.headers[group].label || group).capitalize()
})).inject(tabs);
} else self.el.getElement(".tab_" + group).inject(group_container);
if (tab_navigation.getElement && self.headers[group]) {
var a = tab_navigation.getElement("a");
a.set("text", (self.headers[group].label || group).capitalize());
var url_split = a.get("href").split("wizard")[1].split("/");
if (url_split.length > 3) a.set("href", a.get("href").replace(url_split[url_split.length - 3] + "/", ""));
}
} else {
new Element("li.t_" + group).grab(new Element("a", {
href: App.createUrl("wizard/" + group),
text: (self.headers[group].label || group).capitalize()
})).inject(tabs);
}
if (self.headers[group] && self.headers[group].event) self.headers[group].event.call();
});
self.el.getElement(".advanced_toggle").destroy();
self.el.getElement(".section_nzb").hide();
}
});