From 0672e120a0c999a40067fcb0496ab2fc95460b0e Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 11 Apr 2011 15:37:41 +0200 Subject: [PATCH] ClientScript register --- couchpotato/api/__init__.py | 4 +- couchpotato/core/loader.py | 2 +- couchpotato/core/plugins/base.py | 20 ++ couchpotato/core/plugins/clientscript/__init__.py | 6 + couchpotato/core/plugins/clientscript/main.py | 56 +++ couchpotato/core/plugins/extension/__init__.py | 6 + couchpotato/core/plugins/extension/main.py | 7 + .../plugins/extension/static/couchpotato.user.js | 389 +++++++++++++++++++++ couchpotato/core/plugins/file/main.py | 5 +- couchpotato/core/plugins/file/static/file.js | 79 +++++ couchpotato/core/plugins/movie/main.py | 4 + couchpotato/core/plugins/movie/static/search.css | 148 ++++++++ couchpotato/core/plugins/movie/static/search.js | 321 +++++++++++++++++ couchpotato/core/plugins/quality/main.py | 11 +- .../core/plugins/quality/static/quality.css | 21 ++ couchpotato/core/plugins/quality/static/quality.js | 373 ++++++++++++++++++++ couchpotato/core/plugins/status/main.py | 9 +- couchpotato/core/plugins/status/static/status.js | 11 + couchpotato/static/scripts/block/search.js | 321 ----------------- couchpotato/static/scripts/file.js | 79 ----- couchpotato/static/scripts/quality.js | 373 -------------------- couchpotato/static/scripts/status.js | 11 - couchpotato/static/style/plugin/movie_add.css | 148 -------- couchpotato/static/style/plugin/quality.css | 21 -- couchpotato/templates/_desktop.html | 10 +- 25 files changed, 1467 insertions(+), 968 deletions(-) create mode 100644 couchpotato/core/plugins/clientscript/__init__.py create mode 100644 couchpotato/core/plugins/clientscript/main.py create mode 100644 couchpotato/core/plugins/extension/__init__.py create mode 100644 couchpotato/core/plugins/extension/main.py create mode 100644 couchpotato/core/plugins/extension/static/couchpotato.user.js create mode 100644 couchpotato/core/plugins/file/static/file.js create mode 100644 couchpotato/core/plugins/movie/static/search.css create mode 100644 couchpotato/core/plugins/movie/static/search.js create mode 100644 couchpotato/core/plugins/quality/static/quality.css create mode 100644 couchpotato/core/plugins/quality/static/quality.js create mode 100644 couchpotato/core/plugins/status/static/status.js delete mode 100644 couchpotato/static/scripts/block/search.js delete mode 100644 couchpotato/static/scripts/file.js delete mode 100644 couchpotato/static/scripts/quality.js delete mode 100644 couchpotato/static/scripts/status.js delete mode 100644 couchpotato/static/style/plugin/movie_add.css delete mode 100644 couchpotato/static/style/plugin/quality.css diff --git a/couchpotato/api/__init__.py b/couchpotato/api/__init__.py index 33546af..d028119 100644 --- a/couchpotato/api/__init__.py +++ b/couchpotato/api/__init__.py @@ -3,8 +3,8 @@ from flask import Module api = Module(__name__) -def addApiView(route, func): - api.add_url_rule(route + '/', endpoint = route if route else 'index', view_func = func) +def addApiView(route, func, static = False): + api.add_url_rule(route + ('' if static else '/'), endpoint = route if route else 'index', view_func = func) """ Api view """ def index(): diff --git a/couchpotato/core/loader.py b/couchpotato/core/loader.py index aea0508..4fa31e2 100644 --- a/couchpotato/core/loader.py +++ b/couchpotato/core/loader.py @@ -60,7 +60,7 @@ class Loader: options = {} for group in section['groups']: for option in group['options']: - options[option['name']] = option['default'] + options[option['name']] = option.get('default', '') fireEvent('settings.register', section_name = section['name'], options = options, save = save) return True except Exception, e: diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 0a6ea92..8b4484a 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,7 +1,27 @@ +from couchpotato.api import addApiView from couchpotato.environment import Env +from flask.helpers import send_from_directory +import os.path class Plugin(): def conf(self, attr): return Env.setting(attr, self.__class__.__name__.lower()) + + def registerStatic(self, file_path): + + class_name = self.__class__.__name__.lower() + self.plugin_file = file_path + path = class_name + '.static/' + + addApiView(path + '', self.showStatic, static = True) + + return path + + def showStatic(self, file = ''): + + plugin_dir = os.path.dirname(self.plugin_file) + dir = os.path.join(plugin_dir, 'static') + + return send_from_directory(dir, file) diff --git a/couchpotato/core/plugins/clientscript/__init__.py b/couchpotato/core/plugins/clientscript/__init__.py new file mode 100644 index 0000000..8490eae --- /dev/null +++ b/couchpotato/core/plugins/clientscript/__init__.py @@ -0,0 +1,6 @@ +from .main import ClientScript + +def start(): + return ClientScript() + +config = [] diff --git a/couchpotato/core/plugins/clientscript/main.py b/couchpotato/core/plugins/clientscript/main.py new file mode 100644 index 0000000..8d9f28d --- /dev/null +++ b/couchpotato/core/plugins/clientscript/main.py @@ -0,0 +1,56 @@ +from couchpotato.core.event import addEvent +from couchpotato.core.logger import CPLog +from couchpotato.core.plugins.base import Plugin + +log = CPLog(__name__) + + +class ClientScript(Plugin): + + urls = { + 'style': {}, + 'script': {}, + } + + html = { + 'style': '', + 'script': '', + } + + def __init__(self): + addEvent('register_style', self.registerStyle) + addEvent('register_script', self.registerScript) + + addEvent('clientscript.get_styles', self.getStyles) + addEvent('clientscript.get_scripts', self.getScripts) + + def getStyles(self, *args, **kwargs): + return self.get('style', *args, **kwargs) + + def getScripts(self, *args, **kwargs): + return self.get('script', *args, **kwargs) + + def get(self, type, as_html = False, location = 'head'): + + data = '' if as_html else [] + + try: + return self.urls[type][location] + except Exception, e: + log.error(e) + + return data + + def registerStyle(self, path, position = 'head'): + self.register(path, 'style', position) + + def registerScript(self, path, position = 'head'): + self.register(path, 'script', position) + + def register(self, file, type, location): + + if not self.urls[type].get(location): + self.urls[type][location] = [] + + filePath = file + self.urls[type][location].append(filePath) diff --git a/couchpotato/core/plugins/extension/__init__.py b/couchpotato/core/plugins/extension/__init__.py new file mode 100644 index 0000000..962254e --- /dev/null +++ b/couchpotato/core/plugins/extension/__init__.py @@ -0,0 +1,6 @@ +from .main import Extension + +def start(): + return Extension() + +config = [] diff --git a/couchpotato/core/plugins/extension/main.py b/couchpotato/core/plugins/extension/main.py new file mode 100644 index 0000000..f961ee8 --- /dev/null +++ b/couchpotato/core/plugins/extension/main.py @@ -0,0 +1,7 @@ +from couchpotato.core.plugins.base import Plugin + + +class Extension(Plugin): + + def __init__(self): + self.registerStatic(__file__) diff --git a/couchpotato/core/plugins/extension/static/couchpotato.user.js b/couchpotato/core/plugins/extension/static/couchpotato.user.js new file mode 100644 index 0000000..305d1f5 --- /dev/null +++ b/couchpotato/core/plugins/extension/static/couchpotato.user.js @@ -0,0 +1,389 @@ +// ==UserScript== +// @name CouchPotato UserScript +// @description Add movies to your CouchPotato via external sites like IMDB +// @include http*://*.imdb.com/title/tt* +// @include http*://imdb.com/title/tt* +// @include ${host}* +// @include http://*.sharethe.tv/movies/* +// @include http://sharethe.tv/movies/* +// @include http://*.moviemeter.nl/film/* +// @include http://moviemeter.nl/film/* +// @include http://whiwa.net/stats/movie/* +// @include http://trailers.apple.com/trailers/* +// @include http://www.themoviedb.org/movie/* +// @include http://www.allocine.fr/film/* +// @include http://trakt.tv/movie/* +// @include http://*.trak.tv/movie/* +// @exclude http://trak.tv/movie/*/* +// @exclude http://*.trak.tv/movie/*/* +// ==/UserScript== + +var version = 7; + +function create() { + switch (arguments.length) { + case 1: + var A = document.createTextNode(arguments[0]); + break; + default: + var A = document.createElement(arguments[0]), B = arguments[1]; + for ( var b in B) { + if (b.indexOf("on") == 0){ + A.addEventListener(b.substring(2), B[b], false); + } + else if (",style,accesskey,id,name,src,href,which".indexOf("," + + b.toLowerCase()) != -1){ + A.setAttribute(b, B[b]); + } + else{ + A[b] = B[b]; + } + } + for ( var i = 2, len = arguments.length; i < len; ++i){ + A.appendChild(arguments[i]); + } + } + return A; +} + +if (typeof GM_addStyle == 'undefined'){ + GM_addStyle = function(css) { + var head = document.getElementsByTagName('head')[0], style = document + .createElement('style'); + if (!head) { + return + } + style.type = 'text/css'; + style.textContent = css; + head.appendChild(style); + } +} + +// Styles +GM_addStyle('\ + #mmPopup { opacity: 0.5; width:200px; font-family: "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; -moz-border-radius-topleft: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-left-radius: 6px; -webkit-border-top-right-radius: 6px; -moz-box-shadow: 0 0 20px rgba(0,0,0,0.5); -webkit-box-shadow: 0 0 20px rgba(0,0,0,0.5); position:fixed; z-index:9999; bottom:0; right:0; font-size:15px; margin: 0 20px; display: block; background:#f5f5f5; } \ + #mmPopup:hover { opacity: 1; } \ + #mmPopup a#addTo { cursor:pointer; text-align:center; text-decoration:none; color: #000; display:block; padding:15px 0 10px; } \ + #mmPopup a#closeBtn { cursor:pointer; float: right; padding:10px; } \ + #mmPopup a img { vertical-align: middle; } \ + #mmPopup a:hover { color:#000; } \ + #mmPopup iframe{ background:#f5f5f5; margin:6px; height:70px; width:188px; overflow:hidden; border:none; } \ +'); + +var cpLocation = '${host}'; +var movieImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAZCAYAAABQDyyRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA+9JREFUeNrMVklIXFkUPVWWY5cDccIpMQ444YCi7UJ3KrpUxAkURRAFW6GdMCI0ooKuxIWCIkrc6FYMcYogrgxoEHFeRFRE42w5D/X73dv1i4pUOiGmkly4/u9779c979x7z3sKSZLwK02JX2y/BYCXwmeESybyGV0Mo6YQNTBzf38f09/fj7GxMRwcHPyQnTk5OSEpKQm5ublQqVTvxdCfXwIg9fT0YGBgAO7u7qipqUFAQACurq7Q29uLoaEhXhgdHY3q6mqo1WocHx+jpaUF8/PzPJeamor8/HwKhKWlJbS2tmJ/f5/nsrKyUFhYSK8vhG8+BmD2j7Dm5mZotVqcnp5ibW0N4eHhcHFxQUREBM7OznhsZ2cHu7u7iI2Nhb29PQOi8b29PaysrECpVCIqKgpubm4IDAzE7OwsLi8vsbW1hYyMDIrVK/yTUQDd3d2oqKjgjygFc3NzCAsLg7OzMyIjI3F+fo7V1VVsbm5ie3sbMTExsLW15acMYmFhAbe3twza1dUVwcHB0Gg0WF9fR15eHsXqNAZA3wUJCQkoKipiGilIQ0MDf2xmZsYUJicn87rp6Wmm+OLigpmglIWEhPDc4OAg+vr6cH19zSwUFBR8tVa4BhITE03aauPj4/QIE75gFMBPanmjAFT05ycxYNRU8svo6CiGh4fR2dkJoQvw8PBAXV0dfHx8cHNzw+MjIyO8Ni4uDpWVlbCxseGibWpqwuLiIs9lZ2cjJycHlpaW3DlTU1N6afhfABMTE+jq6uLgnp6eqK+v5+BU2aQTcvD4+HhUVVXB2toaJycnrAdy8MzMTNYDasnl5WUeIzA6eyWc0GiNdkFbWxvvlIKKzvxs57IYGQYnMWpsbNSLEQWibqHgBIiA2dnZIS0tDbW1taxlwm0o3YYp1zNwd3fHSlheXs4MUO+TElJaZCUsKyuDubk5q9xjJaTd02/ISkgAqR1JCw4PD+XNSiZvQysrKygUClhYWDCrpAX+/v7o6OjQiOkA4RpdGi4/Y+Cp5uDggJKSEj5HiAkCQSmU2T06OlILuadikURqbgXAt+K9khlIT0/nc+ApRqceSe63/FZQUBDa29vp9W9mICUlhU/DJ10slP/Vs6+vLx9gZNRRGxsb3JJeXl76td7e3vrPiIEPYmEEtdrk5CRR9V0AHB0dUVpaitDQUD0gOmGJEV0NUAEeGVxU3gn/CwLAS7qUSCYwUf2SOOSk4uJi+vdYuJtwtfA/6AQgpxR81N1WnIU//4EKbP7w8PBGPJ9REersTHTchaE8G3bBvs6fZHJLiwBW4vakJfr9/Py4JIx+IFNhAqf6em2QkT7hysfr/hVgAIhbr+v/xmSzAAAAAElFTkSuQmCC' +var closeImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAA5ElEQVR42tRTQYoEIQwsl/2Bl3gQoY9eBKEf5kvyG8G7h4Z+S38gIu5lp5lZ2R7YPm1BDhZJSFWiGmPgDj5wE7cbfD4/mBkAHprUj9yTTyn9OsGIMSLG+Fxwxc8SiAi9d4QQHskjhIDeO4jorQcq5wwiQmsN3nt479FaAxEh5zxJmyZIKalSClprL1FKQUpJXZr4DBH52xqZeRhjICKw1sJaCxGBMQbMPN41GFpriAicc6i1otYK5xxEBFrraQuThGVZAADbtp2amXms6woAOI7j0gO17/t5MN+HNfEvBf//M30NAKe7aRqUOIlfAAAAAElFTkSuQmCC' + +lib = (function(){ + var _public = {} + _public.osd = function(id, year){ + var navbar, newElement; + + var iFrame = create('iframe', { + src : cpLocation + "movie/imdbAdd/?id=" + id + '&year=' + year, + frameborder : 0, + scrolling : 'no' + }) + + var addToText = '' + var popupId = 'mmPopup' + + var popup = create('div', { + id : popupId, + innerHTML : addToText + }); + var addButton = create('a', { + innerHTML: 'Add to CouchPotato', + id: 'addTo', + onclick: function(){ + popup.innerHTML = ''; + popup.appendChild(create('a', { + innerHTML: '', + id: 'closeBtn', + onclick: function(){ + popup.innerHTML = ''; + popup.appendChild(addButton); + } + })); + popup.appendChild(iFrame); + } + }) + popup.appendChild(addButton); + + document.body.parentNode.insertBefore(popup, document.body); + } + + _public.search = function(name, year){ + + var imdb_id = 'tt1234567'; + + lib.osd(imdb_id, year); + + return imdb_id; + } + + return _public +})(); + +var CouchPotato = {} + +CouchPotato['imdb.com'] = (function(){ + + function isMovie(){ + var series = document.getElementsByTagName('h5') + for (var i = 0; i < series.length; i++) { + if (series[i].innerHTML == 'Seasons:') { + return false; + } + } + return true; + } + + function getId(){ + return 'tt' + location.href.replace(/[^\d+]+/g, ''); + } + + function getYear(){ + try { + return document.getElementsByTagName('h1')[0].getElementsByTagName('a')[0].text; + } catch (e) { + var spans = document.getElementsByTagName('h1')[0].getElementsByTagName('span'); + var pattern = /^\((TV|Video) ([0-9]+)\)$/; + for (var i = 0; i < spans.length; i++) { + if (spans[i].innerHTML.search(pattern)) { + return spans[i].innerHTML.match(pattern)[1]; + } + } + } + } + + var constructor = function(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +CouchPotato['sharethe.tv'] = (function(){ + + function isMovie(){ + var pattern = /movies\/[^/]+\/?$/; + matched = location.href.match(pattern); + return null != matched; + } + + function getId(){ + var pattern = /imdb\.com\/title\/tt(\d+)/; + var html = document.getElementsByTagName('html')[0].innerHTML; + var imdb_id = html.match(pattern)[1]; + return imdb_id; + + } + + function getYear(){ + var pattern = /(\d+)[^\d]*$/; + var html = document.getElementsByTagName('html')[0].innerHTML; + var year = html.match(pattern)[1]; + return year; + + } + + function constructor(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +CouchPotato['moviemeter.nl'] = (function(){ + + function isMovie(){ + var pattern = /[^/]+\/?$/; + var html = document.getElementsByTagName('h1')[0].innerHTML + matched = location.href.match(pattern); + return null != matched; + } + + function getId(){ + var pattern = /imdb\.com\/title\/tt(\d+)/; + var html = document.getElementsByTagName('html')[0].innerHTML; + var imdb_id = html.match(pattern)[1]; + return imdb_id; + + } + + function getYear(){ + var pattern = /(\d+)[^\d]*$/; + var html = document.getElementsByTagName('h1')[0].innerHTML; + var year = html.match(pattern)[1]; + return year; + + } + + function constructor(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +CouchPotato['whiwa.net'] = (function(){ + + function isMovie(){ + var pattern = /[^/]+\/?$/; + var html = document.getElementsByTagName('h3')[0].innerHTML + var matched = location.href.match(pattern); + return null != matched; + } + + function getId(){ + var pattern = /imdb\.com\/title\/tt(\d+)/; + var html = document.getElementsByTagName('html')[0].innerHTML; + var imdb_id = html.match(pattern)[1]; + return imdb_id; + + } + + function getYear(){ + var pattern = /(\d+)[^\d]*$/; + var html = document.getElementsByTagName('h3')[0].innerHTML; + var year = html.match(pattern)[1]; + return year; + + } + + function constructor(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +CouchPotato['trakt.tv'] = (function(){ + + var imdb_input = null; + var year_input = null; + + function isMovie(){ + imdb_input = document.getElementById("meta-imdb-id"); + year_input = document.getElementById("meta-year"); + return (null != imdb_input) && (null != year_input); + } + + function getId(){ + return imdb_input.value.substr(2); + } + + function getYear(){ + return year_input.value; + + } + + function constructor(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +CouchPotato['trailers.apple.com'] = (function(){ + + function getId() { + var name = document.title.substr(0, document.title.indexOf(" -")).replace(/ /g, "+"); + return lib.search(name, getYear()) + + } + + function getYear(){ + var release_date = document.getElementById("view-showtimes").parentNode.innerHTML; + var year = new RegExp("\\d{4}", release_date) + + return year; + } + + function constructor(){ + getId(); + } + + return constructor; + +})(); + +CouchPotato['themoviedb.org'] = (function(){ + + var obj = this; + + function getId() { + + name = document.title.substr(0, document.title.indexOf("TMDb")-3).replace(/ /g, "+"); + lib.search(name, getYear()) + + } + + function getYear(){ + var year = document.getElementById("year").innerHTML; + year = year.substr(1, year.length-2); + return year; + } + + function constructor(){ + getId(); + } + + return constructor; + +})(); + +CouchPotato['allocine.fr'] = (function(){ + + function isMovie(){ + var pattern = /fichefilm_gen_cfilm=\d+?\.html$/; + matched = location.href.match(pattern); + return null != matched; + } + + function getId() { + var name = document.title.substr(0, document.title.indexOf(" -")).replace(/ /g, "+"); + lib.search(name, getYear()) + } + + function getYear(){ + var year = new RegExp("\\d{4}", document.title) + return year; + } + + function constructor(){ + if(isMovie()){ + lib.osd(getId(), getYear()); + } + } + + return constructor; + +})(); + +// Start +(function(){ + for (var i in CouchPotato){ + GM_log(i); + if(location.href.indexOf(i) != -1){ + new CouchPotato[i](); + break; + } + } +})(); diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index ccf89d5..4f5c3a1 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -1,6 +1,6 @@ from couchpotato import get_session from couchpotato.api import addApiView -from couchpotato.core.event import addEvent +from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin @@ -22,6 +22,9 @@ class FileManager(Plugin): addApiView('file.cache/', self.showImage) + path = self.registerStatic(__file__) + fireEvent('register_script', path + 'file.js') + def showImage(self, file = ''): cache_dir = Env.get('cache_dir') diff --git a/couchpotato/core/plugins/file/static/file.js b/couchpotato/core/plugins/file/static/file.js new file mode 100644 index 0000000..76ef62e --- /dev/null +++ b/couchpotato/core/plugins/file/static/file.js @@ -0,0 +1,79 @@ +var File = new Class({ + + initialize: function(file){ + var self = this; + + self.data = file; + self.type = File.Type.get(file.type_id); + + self['create'+(self.type.type).capitalize()]() + + }, + + createImage: function(){ + var self = this; + + self.el = new Element('div', { + 'class': 'type_image ' + self.type.identifier + }).adopt( + new Element('img', { + 'src': Api.createUrl('file.cache') + self.data.path.substring(1) + '/' + }) + ) + }, + + toElement: function(){ + return this.el; + } + +}); + +var FileSelect = new Class({ + + multiple: function(type, files, single){ + + var results = files.filter(function(file){ + return file.type_id == File.Type.get(type).id; + }); + + if(single){ + results = new File(results.pop()); + } + else { + + } + + return results; + + }, + + single: function(type, files){ + return this.multiple(type, files, true); + } + +}); +window.File.Select = new FileSelect(); + +var FileTypeBase = new Class({ + + setup: function(types){ + var self = this; + + self.typesById = {}; + self.typesByKey = {}; + Object.each(types, function(type){ + self.typesByKey[type.identifier] = type; + self.typesById[type.id] = type; + }); + + }, + + get: function(identifier){ + if(typeOf(identifier) == 'number') + return this.typesById[identifier] + else + return this.typesByKey[identifier] + } + +}); +window.File.Type = new FileTypeBase(); diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index 59716f9..20ccf16 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -19,6 +19,10 @@ class MoviePlugin(Plugin): addApiView('movie.edit', self.edit) addApiView('movie.delete', self.delete) + path = self.registerStatic(__file__) + fireEvent('register_script', path + 'search.js') + fireEvent('register_style', path + 'search.css') + def list(self): params = getParams() diff --git a/couchpotato/core/plugins/movie/static/search.css b/couchpotato/core/plugins/movie/static/search.css new file mode 100644 index 0000000..0d9551e --- /dev/null +++ b/couchpotato/core/plugins/movie/static/search.css @@ -0,0 +1,148 @@ +/* @override http://localhost:5000/static/style/plugin/movie_add.css */ + +.search_form { + display: inline-block; + width: 25%; +} + + .search_form input { + padding-right: 25px; + border: 1px solid #aaa; + padding: 4px; + margin: 0; + font-size: 14px; + width: 90%; + + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + } + .search_form .input a { + width: 12px; + height: 20px; + display: inline-block; + margin: 0 0 -5px -20px; + top: 4px; + right: 5px; + background: url('../../images/close_button.png') 0 center no-repeat; + cursor: pointer; + } + .search_form .input a:hover { background-position: -12px center; } + + .search_form .results_container { + padding: 10px 0; + position: absolute; + background: #fff; + margin: 11px 0 0 -243px; + width: 470px; + min-height: 140px; + + box-shadow: 0 0 30px rgba(0,0,0,0.2); + -moz-box-shadow: 0 0 30px rgba(0,0,0,0.2); + -webkit-box-shadow: 0 0 30px rgba(0,0,0,0.2); + + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + } + .search_form .spinner { + background: #fff url('../../images/spinner.gif') no-repeat center 70px; + } + + .search_form .pointer { + border-right: 10px solid transparent; + border-left: 10px solid transparent; + border-bottom: 10px solid #fff; + display: block; + position: absolute; + width: 0px; + left: 50%; + margin: -19px 0 0 110px; + } + + .search_form .results .movie { + overflow: hidden; + background: #666; + min-height: 140px; + } + + .search_form .results .movie .options { + height: 140px; + } + + .search_form .results .movie .options > div { + padding: 0 15px; + } + + .search_form .results .movie .options .thumbnail { + vertical-align: middle; + } + + .search_form .results .movie .options select { + vertical-align: middle; + display: inline-block; + margin-right: 10px; + } + .search_form .results .movie .options select[name=title] { width: 180px; } + .search_form .results .movie .options select[name=quality] { width: 90px; } + + .search_form .results .movie .options .button { + vertical-align: middle; + display: inline-block; + } + + .search_form .results .movie .options .message { + height: 100%; + line-height: 140px; + font-size: 20px; + text-align: center; + color: #fff; + } + + .search_form .results .movie .data { + padding: 0 15px; + width: 440px; + position: relative; + min-height: 100px; + top: 0; + margin: -140px 0 0 0; + background: #fff; + min-height: 140px; + } + + .search_form .results .movie .thumbnail { + width: 17%; + display: inline-block; + margin: 15px 3% 15px 0; + vertical-align: top; + + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 3px rgba(0,0,0,0.35); + -moz-box-shadow: 0 0 3px rgba(0,0,0,0.35); + -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.35); + } + + .search_form .results .movie .info { + width: 74%; + display: inline-block; + vertical-align: top; + padding: 15px 0; + background: #fff; + } + .search_form .results .movie .add +.info { + margin-left: 20%; + } + + .search_form .results .movie .info h2 { + margin: 0; + } + + .search_form .results .movie .info h2 span { + padding: 0 5px; + content: ")"; + } + + .search_form .results .movie .info h2 span:before { content: "("; } + .search_form .results .movie .info h2 span:after { content: ")"; } diff --git a/couchpotato/core/plugins/movie/static/search.js b/couchpotato/core/plugins/movie/static/search.js new file mode 100644 index 0000000..ce3a29f --- /dev/null +++ b/couchpotato/core/plugins/movie/static/search.js @@ -0,0 +1,321 @@ +Block.Search = new Class({ + + Extends: BlockBase, + + cache: {}, + + create: function(){ + var self = this; + + self.el = new Element('div.search_form').adopt( + new Element('div.input').adopt( + self.input = new Element('input', { + 'events': { + 'keyup': self.keyup.bind(self), + 'focus': self.hideResults.bind(self, false) + } + }), + new Element('a', { + 'events': { + 'click': self.clear.bind(self) + } + }) + ), + self.result_container = new Element('div.results_container', { + 'tween': { + 'duration': 200 + } + }).adopt( + new Element('div.pointer'), + self.results = new Element('div.results') + ).fade('hide') + ); + + self.spinner = new Spinner(self.result_container); + + }, + + clear: function(e){ + var self = this; + (e).stop(); + + self.input.set('value', ''); + self.input.focus() + + self.movies = [] + self.results.empty() + }, + + hideResults: function(bool){ + var self = this; + + if(self.hidden == bool) return; + + self.result_container.fade(bool ? 0 : 1) + + 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(e){ + var self = this; + + if(['up', 'down'].indexOf(e.key) > -1){ + p('select item') + } + else if(self.q() != self.last_q) { + self.autocomplete() + } + + }, + + autocomplete: function(delay){ + var self = this; + + if(!self.q()){ + self.hideResults(true) + return + } + + self.spinner.show() + + if(self.autocomplete_timer) clearTimeout(self.autocomplete_timer) + self.autocomplete_timer = self.list.delay((delay || 300), self) + }, + + list: function(){ + var self = this; + + if(self.api_request) self.api_request.cancel(); + + var q = self.q(); + var cache = self.cache[q]; + + self.hideResults(false) + + if(!cache){ + self.api_request = Api.request('movie.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.spinner.hide(); + self.cache[q] = json + + self.movies = {} + self.results.empty() + + Object.each(json.movies, function(movie){ + + var m = new Block.Search.Item(movie); + $(m).inject(self.results) + self.movies[movie.imdb || 'r-'+Math.floor(Math.random()*10000)] = m + + }); + + }, + + loading: function(bool){ + this.el[bool ? 'addClass' : 'removeClass']('loading') + }, + + q: function(){ + return this.input.get('value').trim(); + } + +}); + +Block.Search.Item = new Class({ + + initialize: function(info){ + var self = this; + + self.info = info; + self.alternative_titles = []; + + self.create(); + }, + + create: function(){ + var self = this; + + var info = self.info; + + self.el = new Element('div.movie', { + 'id': info.imdb + }).adopt( + self.options = new Element('div.options'), + self.data_container = new Element('div.data', { + 'tween': { + duration: 400, + transition: 'quint:in:out' + }, + 'events': { + 'click': self.showOptions.bind(self) + } + }).adopt( + self.thumbnail = info.images.posters.length > 0 ? new Element('img.thumbnail', { + 'src': info.images.posters[0] + }) : null, + new Element('div.info').adopt( + self.title = new Element('h2', { + 'text': info.titles[0] + }).adopt( + self.year = info.year ? new Element('span', { + 'text': info.year + }) : null + ), + self.tagline = new Element('span', { + 'text': info.tagline + }), + self.director = self.info.director ? new Element('span', { + 'text': 'Director:' + info.director + }) : null, + self.starring = info.actors ? new Element('span', { + 'text': 'Starring:' + }) : null + ) + ) + ) + + if(info.actors){ + Object.each(info.actors, function(actor){ + new Element('span', { + 'text': actor.name + }).inject(self.starring) + }) + } + + info.titles.each(function(title){ + self.alternativeTitle({ + 'title': title + }); + }) + }, + + alternativeTitle: function(alternative){ + var self = this; + + self.alternative_titles.include(alternative); + }, + + showOptions: function(){ + var self = this; + + self.createOptions(); + + if(!self.width) + self.width = self.data_container.getCoordinates().width + + self.data_container.tween('left', 0, self.width); + + self.el.addEvent('outerClick', self.closeOptions.bind(self)) + + }, + + closeOptions: function(){ + var self = this; + + self.data_container.tween('left', self.width, 0); + self.el.removeEvents('outerClick') + }, + + add: function(e){ + var self = this; + (e).stop(); + + Api.request('movie.add', { + 'data': { + 'identifier': self.info.imdb, + 'title': self.title_select.get('value'), + 'profile_id': self.profile_select.get('value') + }, + 'useSpinner': true, + 'spinnerTarget': self.options, + 'onComplete': function(){ + self.options.empty(); + self.options.adopt( + new Element('div.message', { + 'text': 'Movie succesfully added.' + }) + ); + }, + 'onFailure': function(){ + self.options.empty(); + self.options.adopt( + new Element('div.message', { + 'text': 'Something went wrong, check the logs for more info.' + }) + ); + } + }); + }, + + createOptions: function(){ + var self = this; + + if(!self.options.hasClass('set')){ + + self.options.adopt( + new Element('div').adopt( + self.info.images.posters.length > 0 ? new Element('img.thumbnail', { + 'src': self.info.images.posters[0] + }) : null, + self.title_select = new Element('select', { + 'name': 'title' + }), + self.profile_select = new Element('select', { + 'name': 'profile' + }), + 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) + }) + + Object.each(Quality.profiles, function(profile){ + new Element('option', { + 'value': profile.id ? profile.id : profile.data.id, + 'text': profile.label ? profile.label : profile.data.label + }).inject(self.profile_select) + }); + + self.options.addClass('set'); + } + + }, + + toElement: function(){ + return this.el + } + +}); diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 493353e..df5a2ff 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -1,13 +1,14 @@ from couchpotato import get_session -from couchpotato.core.event import addEvent +from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.logger import CPLog +from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Quality, Profile, ProfileType - log = CPLog(__name__) -class QualityPlugin: + +class QualityPlugin(Plugin): qualities = [ {'identifier': 'bd50', 'size': (15000, 60000), 'label': 'BR-Disk', 'alternative': ['1080p', 'bd25'], 'allow': [], 'ext':[], 'tags': ['x264', 'h264', 'blu ray']}, @@ -28,6 +29,10 @@ class QualityPlugin: addEvent('quality.all', self.all) addEvent('app.load', self.fill) + path = self.registerStatic(__file__) + fireEvent('register_script', path + 'quality.js') + fireEvent('register_style', path + 'quality.css') + def all(self): db = get_session() diff --git a/couchpotato/core/plugins/quality/static/quality.css b/couchpotato/core/plugins/quality/static/quality.css new file mode 100644 index 0000000..c4abc1d --- /dev/null +++ b/couchpotato/core/plugins/quality/static/quality.css @@ -0,0 +1,21 @@ +/* @override http://localhost:5000/static/style/plugin/quality.css */ + + +.profile > .delete { + background-position: center; + height: 20px; + width: 20px; +} + +.profile .types .type .handle { + background: url('../../images/handle.png') center; + display: inline-block; + height: 20px; + width: 20px; +} + +.profile .types .type .delete { + background-position: center; + height: 20px; + width: 20px; +} \ No newline at end of file diff --git a/couchpotato/core/plugins/quality/static/quality.js b/couchpotato/core/plugins/quality/static/quality.js new file mode 100644 index 0000000..9dd82d4 --- /dev/null +++ b/couchpotato/core/plugins/quality/static/quality.js @@ -0,0 +1,373 @@ +var QualityBase = new Class({ + + tab: '', + content: '', + + setup: function(data){ + var self = this; + + self.qualities = data.qualities; + + self.profiles = {} + Object.each(data.profiles, self.createProfilesClass.bind(self)); + + App.addEvent('load', self.addSettings.bind(self)) + + }, + + getProfile: function(id){ + return this.profiles[id] + }, + + addSettings: function(){ + var self = this; + + self.settings = App.getPage('Settings') + self.settings.addEvent('create', function(){ + var tab = self.settings.createTab('profile', { + 'label': 'Profile', + 'name': 'profile' + }); + + self.tab = tab.tab; + self.content = tab.content; + + self.createProfiles(); + self.createOrdering(); + self.createSizes(); + + }) + + }, + + /** + * Profiles + */ + createProfiles: function(){ + var self = this; + + self.settings.createGroup({ + 'label': 'Custom', + 'description': 'Discriptions' + }).inject(self.content).adopt( + new Element('a.add_new', { + 'text': 'Create a new quality profile', + 'events': { + 'click': function(){ + var profile = self.createProfilesClass(); + $(profile).inject(self.profile_container, 'top') + } + } + }), + self.profile_container = new Element('div.container') + ) + + Object.each(self.profiles, function(profile){ + if(!profile.isCore()) + $(profile).inject(self.profile_container, 'top') + }) + + }, + + createProfilesClass: function(data){ + var self = this; + + if(data){ + return self.profiles[data.id] = new Profile(data); + } + else { + var data = { + 'id': randomString() + } + return self.profiles[data.id] = new Profile(data); + } + }, + + /** + * Ordering + */ + createOrdering: function(){ + var self = this; + + self.settings.createGroup({ + 'label': 'Order', + 'description': 'Discriptions' + }).inject(self.content) + + }, + + /** + * Sizes + */ + createSizes: function(){ + var self = this; + + self.settings.createGroup({ + 'label': 'Sizes', + 'description': 'Discriptions', + 'advanced': true + }).inject(self.content) + } + +}); +window.Quality = new QualityBase(); + +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.header = new Element('h4', {'text': data.label}), + new Element('span.delete.icon', { + 'events': { + 'click': self.del.bind(self) + } + }), + new Element('div', { + 'class': 'ctrlHolder' + }).adopt( + new Element('label', {'text':'Name'}), + new Element('input.label.textInput.large', { + 'type':'text', + 'value': data.label, + 'events': { + 'keyup': function(){ + self.header.set('text', this.get('value')) + } + } + }) + ), + new Element('div.ctrlHolder').adopt( + new Element('label', {'text':'Wait'}), + new Element('input.wait_for.textInput.xsmall', { + 'type':'text', + 'value': data.types && data.types.length > 0 ? data.types[0].wait_for : 0 + }), + new Element('span', {'text':' day(s) for better quality.'}) + ), + new Element('div.ctrlHolder').adopt( + new Element('label', {'text': 'Qualities'}), + new Element('div.head').adopt( + new Element('span.quality_type', {'text': 'Search for'}), + new Element('span.finish', {'html': 'Finish'}) + ), + self.type_container = new Element('ol.types'), + new Element('a.addType', { + 'text': 'Add another quality to search for.', + 'href': '#', + 'events': { + 'click': self.addType.bind(self) + } + }) + ) + ); + + self.makeSortable() + + if(data.types) + Object.each(data.types, self.addType.bind(self)) + }, + + save: function(delay){ + var self = this; + + if(self.save_timer) clearTimeout(self.save_timer); + self.save_timer = (function(){ + + var data = self.getData(); + if(data.types.length < 2) return; + + Api.request('profile.save', { + 'data': self.getData(), + 'useSpinner': true, + 'spinnerOptions': { + 'target': self.el + }, + 'onComplete': function(json){ + if(json.success){ + self.data = json.profile + } + } + }); + }).delay(delay, self) + + }, + + getData: function(){ + var self = this; + + var data = { + 'id' : self.data.id, + 'label' : self.el.getElement('.label').get('value'), + 'wait_for' : self.el.getElement('.wait_for').get('value'), + 'types': [] + } + + Array.each(self.type_container.getElements('.type'), function(type){ + if(!type.hasClass('deleted')) + data.types.include({ + 'quality_id': type.getElement('select').get('value'), + 'finish': +type.getElement('input[type=checkbox]').checked + }); + }) + + return data + }, + + addType: function(data){ + var self = this; + + var t = new Profile.Type(data); + $(t).inject(self.type_container); + self.sortable.addItems($(t)); + + self.types.include(t); + + }, + + del: function(){ + var self = this; + + if(!confirm('Are you sure you want to delete this profile?')) return + + Api.request('profile.delete', { + 'data': { + 'id': self.data.id + }, + 'useSpinner': true, + 'spinnerOptions': { + 'target': self.el + }, + 'onComplete': function(json){ + if(json.success) + self.el.destroy(); + else + alert(json.message) + } + }); + }, + + makeSortable: function(){ + var self = this; + + self.sortable = new Sortables(self.type_container, { + 'revert': true, + //'clone': true, + 'handle': '.handle', + 'opacity': 0.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 = Class({ + + deleted: false, + + initialize: function(data){ + var self = this; + + self.data = data; + self.create(); + + }, + + create: function(){ + var self = this; + var data = self.data; + + self.el = new Element('li.type').adopt( + new Element('span.quality_type').adopt( + self.fillQualities() + ), + new Element('span.finish').adopt( + self.finish = new Element('input', { + 'type':'checkbox', + 'class':'finish', + 'checked': data.finish + }) + ), + new Element('span.delete.icon', { + 'events': { + 'click': self.del.bind(self) + } + }), + new Element('span.handle') + ) + + }, + + fillQualities: function(){ + var self = this; + + self.qualities = new Element('select'); + + Object.each(Quality.qualities, function(q){ + new Element('option', { + 'text': q.label, + 'value': q.id + }).inject(self.qualities) + }); + + self.qualities.set('value', self.data.quality_id); + + return self.qualities; + + }, + + getData: function(){ + var self = this; + + return { + 'quality_id': self.qualities.get('value'), + 'finish': +self.finish.checked + } + }, + + del: function(){ + var self = this; + + self.el.addClass('deleted'); + self.el.hide(); + self.deleted = true; + }, + + toElement: function(){ + return this.el; + } + +}) diff --git a/couchpotato/core/plugins/status/main.py b/couchpotato/core/plugins/status/main.py index 747cecf..c221a1b 100644 --- a/couchpotato/core/plugins/status/main.py +++ b/couchpotato/core/plugins/status/main.py @@ -1,12 +1,14 @@ from couchpotato import get_session -from couchpotato.core.event import addEvent +from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.logger import CPLog +from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Status log = CPLog(__name__) -class StatusPlugin: + +class StatusPlugin(Plugin): statuses = { 'active': 'Active', @@ -21,6 +23,9 @@ class StatusPlugin: addEvent('status.all', self.all) addEvent('app.load', self.fill) + path = self.registerStatic(__file__) + fireEvent('register_script', path + 'status.js') + def all(self): db = get_session() diff --git a/couchpotato/core/plugins/status/static/status.js b/couchpotato/core/plugins/status/static/status.js new file mode 100644 index 0000000..7967ac5 --- /dev/null +++ b/couchpotato/core/plugins/status/static/status.js @@ -0,0 +1,11 @@ +var StatusBase = new Class({ + + setup: function(statuses){ + var self = this; + + self.statuses = statuses; + + } + +}); +window.Status = new StatusBase(); diff --git a/couchpotato/static/scripts/block/search.js b/couchpotato/static/scripts/block/search.js deleted file mode 100644 index ce3a29f..0000000 --- a/couchpotato/static/scripts/block/search.js +++ /dev/null @@ -1,321 +0,0 @@ -Block.Search = new Class({ - - Extends: BlockBase, - - cache: {}, - - create: function(){ - var self = this; - - self.el = new Element('div.search_form').adopt( - new Element('div.input').adopt( - self.input = new Element('input', { - 'events': { - 'keyup': self.keyup.bind(self), - 'focus': self.hideResults.bind(self, false) - } - }), - new Element('a', { - 'events': { - 'click': self.clear.bind(self) - } - }) - ), - self.result_container = new Element('div.results_container', { - 'tween': { - 'duration': 200 - } - }).adopt( - new Element('div.pointer'), - self.results = new Element('div.results') - ).fade('hide') - ); - - self.spinner = new Spinner(self.result_container); - - }, - - clear: function(e){ - var self = this; - (e).stop(); - - self.input.set('value', ''); - self.input.focus() - - self.movies = [] - self.results.empty() - }, - - hideResults: function(bool){ - var self = this; - - if(self.hidden == bool) return; - - self.result_container.fade(bool ? 0 : 1) - - 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(e){ - var self = this; - - if(['up', 'down'].indexOf(e.key) > -1){ - p('select item') - } - else if(self.q() != self.last_q) { - self.autocomplete() - } - - }, - - autocomplete: function(delay){ - var self = this; - - if(!self.q()){ - self.hideResults(true) - return - } - - self.spinner.show() - - if(self.autocomplete_timer) clearTimeout(self.autocomplete_timer) - self.autocomplete_timer = self.list.delay((delay || 300), self) - }, - - list: function(){ - var self = this; - - if(self.api_request) self.api_request.cancel(); - - var q = self.q(); - var cache = self.cache[q]; - - self.hideResults(false) - - if(!cache){ - self.api_request = Api.request('movie.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.spinner.hide(); - self.cache[q] = json - - self.movies = {} - self.results.empty() - - Object.each(json.movies, function(movie){ - - var m = new Block.Search.Item(movie); - $(m).inject(self.results) - self.movies[movie.imdb || 'r-'+Math.floor(Math.random()*10000)] = m - - }); - - }, - - loading: function(bool){ - this.el[bool ? 'addClass' : 'removeClass']('loading') - }, - - q: function(){ - return this.input.get('value').trim(); - } - -}); - -Block.Search.Item = new Class({ - - initialize: function(info){ - var self = this; - - self.info = info; - self.alternative_titles = []; - - self.create(); - }, - - create: function(){ - var self = this; - - var info = self.info; - - self.el = new Element('div.movie', { - 'id': info.imdb - }).adopt( - self.options = new Element('div.options'), - self.data_container = new Element('div.data', { - 'tween': { - duration: 400, - transition: 'quint:in:out' - }, - 'events': { - 'click': self.showOptions.bind(self) - } - }).adopt( - self.thumbnail = info.images.posters.length > 0 ? new Element('img.thumbnail', { - 'src': info.images.posters[0] - }) : null, - new Element('div.info').adopt( - self.title = new Element('h2', { - 'text': info.titles[0] - }).adopt( - self.year = info.year ? new Element('span', { - 'text': info.year - }) : null - ), - self.tagline = new Element('span', { - 'text': info.tagline - }), - self.director = self.info.director ? new Element('span', { - 'text': 'Director:' + info.director - }) : null, - self.starring = info.actors ? new Element('span', { - 'text': 'Starring:' - }) : null - ) - ) - ) - - if(info.actors){ - Object.each(info.actors, function(actor){ - new Element('span', { - 'text': actor.name - }).inject(self.starring) - }) - } - - info.titles.each(function(title){ - self.alternativeTitle({ - 'title': title - }); - }) - }, - - alternativeTitle: function(alternative){ - var self = this; - - self.alternative_titles.include(alternative); - }, - - showOptions: function(){ - var self = this; - - self.createOptions(); - - if(!self.width) - self.width = self.data_container.getCoordinates().width - - self.data_container.tween('left', 0, self.width); - - self.el.addEvent('outerClick', self.closeOptions.bind(self)) - - }, - - closeOptions: function(){ - var self = this; - - self.data_container.tween('left', self.width, 0); - self.el.removeEvents('outerClick') - }, - - add: function(e){ - var self = this; - (e).stop(); - - Api.request('movie.add', { - 'data': { - 'identifier': self.info.imdb, - 'title': self.title_select.get('value'), - 'profile_id': self.profile_select.get('value') - }, - 'useSpinner': true, - 'spinnerTarget': self.options, - 'onComplete': function(){ - self.options.empty(); - self.options.adopt( - new Element('div.message', { - 'text': 'Movie succesfully added.' - }) - ); - }, - 'onFailure': function(){ - self.options.empty(); - self.options.adopt( - new Element('div.message', { - 'text': 'Something went wrong, check the logs for more info.' - }) - ); - } - }); - }, - - createOptions: function(){ - var self = this; - - if(!self.options.hasClass('set')){ - - self.options.adopt( - new Element('div').adopt( - self.info.images.posters.length > 0 ? new Element('img.thumbnail', { - 'src': self.info.images.posters[0] - }) : null, - self.title_select = new Element('select', { - 'name': 'title' - }), - self.profile_select = new Element('select', { - 'name': 'profile' - }), - 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) - }) - - Object.each(Quality.profiles, function(profile){ - new Element('option', { - 'value': profile.id ? profile.id : profile.data.id, - 'text': profile.label ? profile.label : profile.data.label - }).inject(self.profile_select) - }); - - self.options.addClass('set'); - } - - }, - - toElement: function(){ - return this.el - } - -}); diff --git a/couchpotato/static/scripts/file.js b/couchpotato/static/scripts/file.js deleted file mode 100644 index 76ef62e..0000000 --- a/couchpotato/static/scripts/file.js +++ /dev/null @@ -1,79 +0,0 @@ -var File = new Class({ - - initialize: function(file){ - var self = this; - - self.data = file; - self.type = File.Type.get(file.type_id); - - self['create'+(self.type.type).capitalize()]() - - }, - - createImage: function(){ - var self = this; - - self.el = new Element('div', { - 'class': 'type_image ' + self.type.identifier - }).adopt( - new Element('img', { - 'src': Api.createUrl('file.cache') + self.data.path.substring(1) + '/' - }) - ) - }, - - toElement: function(){ - return this.el; - } - -}); - -var FileSelect = new Class({ - - multiple: function(type, files, single){ - - var results = files.filter(function(file){ - return file.type_id == File.Type.get(type).id; - }); - - if(single){ - results = new File(results.pop()); - } - else { - - } - - return results; - - }, - - single: function(type, files){ - return this.multiple(type, files, true); - } - -}); -window.File.Select = new FileSelect(); - -var FileTypeBase = new Class({ - - setup: function(types){ - var self = this; - - self.typesById = {}; - self.typesByKey = {}; - Object.each(types, function(type){ - self.typesByKey[type.identifier] = type; - self.typesById[type.id] = type; - }); - - }, - - get: function(identifier){ - if(typeOf(identifier) == 'number') - return this.typesById[identifier] - else - return this.typesByKey[identifier] - } - -}); -window.File.Type = new FileTypeBase(); diff --git a/couchpotato/static/scripts/quality.js b/couchpotato/static/scripts/quality.js deleted file mode 100644 index 9dd82d4..0000000 --- a/couchpotato/static/scripts/quality.js +++ /dev/null @@ -1,373 +0,0 @@ -var QualityBase = new Class({ - - tab: '', - content: '', - - setup: function(data){ - var self = this; - - self.qualities = data.qualities; - - self.profiles = {} - Object.each(data.profiles, self.createProfilesClass.bind(self)); - - App.addEvent('load', self.addSettings.bind(self)) - - }, - - getProfile: function(id){ - return this.profiles[id] - }, - - addSettings: function(){ - var self = this; - - self.settings = App.getPage('Settings') - self.settings.addEvent('create', function(){ - var tab = self.settings.createTab('profile', { - 'label': 'Profile', - 'name': 'profile' - }); - - self.tab = tab.tab; - self.content = tab.content; - - self.createProfiles(); - self.createOrdering(); - self.createSizes(); - - }) - - }, - - /** - * Profiles - */ - createProfiles: function(){ - var self = this; - - self.settings.createGroup({ - 'label': 'Custom', - 'description': 'Discriptions' - }).inject(self.content).adopt( - new Element('a.add_new', { - 'text': 'Create a new quality profile', - 'events': { - 'click': function(){ - var profile = self.createProfilesClass(); - $(profile).inject(self.profile_container, 'top') - } - } - }), - self.profile_container = new Element('div.container') - ) - - Object.each(self.profiles, function(profile){ - if(!profile.isCore()) - $(profile).inject(self.profile_container, 'top') - }) - - }, - - createProfilesClass: function(data){ - var self = this; - - if(data){ - return self.profiles[data.id] = new Profile(data); - } - else { - var data = { - 'id': randomString() - } - return self.profiles[data.id] = new Profile(data); - } - }, - - /** - * Ordering - */ - createOrdering: function(){ - var self = this; - - self.settings.createGroup({ - 'label': 'Order', - 'description': 'Discriptions' - }).inject(self.content) - - }, - - /** - * Sizes - */ - createSizes: function(){ - var self = this; - - self.settings.createGroup({ - 'label': 'Sizes', - 'description': 'Discriptions', - 'advanced': true - }).inject(self.content) - } - -}); -window.Quality = new QualityBase(); - -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.header = new Element('h4', {'text': data.label}), - new Element('span.delete.icon', { - 'events': { - 'click': self.del.bind(self) - } - }), - new Element('div', { - 'class': 'ctrlHolder' - }).adopt( - new Element('label', {'text':'Name'}), - new Element('input.label.textInput.large', { - 'type':'text', - 'value': data.label, - 'events': { - 'keyup': function(){ - self.header.set('text', this.get('value')) - } - } - }) - ), - new Element('div.ctrlHolder').adopt( - new Element('label', {'text':'Wait'}), - new Element('input.wait_for.textInput.xsmall', { - 'type':'text', - 'value': data.types && data.types.length > 0 ? data.types[0].wait_for : 0 - }), - new Element('span', {'text':' day(s) for better quality.'}) - ), - new Element('div.ctrlHolder').adopt( - new Element('label', {'text': 'Qualities'}), - new Element('div.head').adopt( - new Element('span.quality_type', {'text': 'Search for'}), - new Element('span.finish', {'html': 'Finish'}) - ), - self.type_container = new Element('ol.types'), - new Element('a.addType', { - 'text': 'Add another quality to search for.', - 'href': '#', - 'events': { - 'click': self.addType.bind(self) - } - }) - ) - ); - - self.makeSortable() - - if(data.types) - Object.each(data.types, self.addType.bind(self)) - }, - - save: function(delay){ - var self = this; - - if(self.save_timer) clearTimeout(self.save_timer); - self.save_timer = (function(){ - - var data = self.getData(); - if(data.types.length < 2) return; - - Api.request('profile.save', { - 'data': self.getData(), - 'useSpinner': true, - 'spinnerOptions': { - 'target': self.el - }, - 'onComplete': function(json){ - if(json.success){ - self.data = json.profile - } - } - }); - }).delay(delay, self) - - }, - - getData: function(){ - var self = this; - - var data = { - 'id' : self.data.id, - 'label' : self.el.getElement('.label').get('value'), - 'wait_for' : self.el.getElement('.wait_for').get('value'), - 'types': [] - } - - Array.each(self.type_container.getElements('.type'), function(type){ - if(!type.hasClass('deleted')) - data.types.include({ - 'quality_id': type.getElement('select').get('value'), - 'finish': +type.getElement('input[type=checkbox]').checked - }); - }) - - return data - }, - - addType: function(data){ - var self = this; - - var t = new Profile.Type(data); - $(t).inject(self.type_container); - self.sortable.addItems($(t)); - - self.types.include(t); - - }, - - del: function(){ - var self = this; - - if(!confirm('Are you sure you want to delete this profile?')) return - - Api.request('profile.delete', { - 'data': { - 'id': self.data.id - }, - 'useSpinner': true, - 'spinnerOptions': { - 'target': self.el - }, - 'onComplete': function(json){ - if(json.success) - self.el.destroy(); - else - alert(json.message) - } - }); - }, - - makeSortable: function(){ - var self = this; - - self.sortable = new Sortables(self.type_container, { - 'revert': true, - //'clone': true, - 'handle': '.handle', - 'opacity': 0.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 = Class({ - - deleted: false, - - initialize: function(data){ - var self = this; - - self.data = data; - self.create(); - - }, - - create: function(){ - var self = this; - var data = self.data; - - self.el = new Element('li.type').adopt( - new Element('span.quality_type').adopt( - self.fillQualities() - ), - new Element('span.finish').adopt( - self.finish = new Element('input', { - 'type':'checkbox', - 'class':'finish', - 'checked': data.finish - }) - ), - new Element('span.delete.icon', { - 'events': { - 'click': self.del.bind(self) - } - }), - new Element('span.handle') - ) - - }, - - fillQualities: function(){ - var self = this; - - self.qualities = new Element('select'); - - Object.each(Quality.qualities, function(q){ - new Element('option', { - 'text': q.label, - 'value': q.id - }).inject(self.qualities) - }); - - self.qualities.set('value', self.data.quality_id); - - return self.qualities; - - }, - - getData: function(){ - var self = this; - - return { - 'quality_id': self.qualities.get('value'), - 'finish': +self.finish.checked - } - }, - - del: function(){ - var self = this; - - self.el.addClass('deleted'); - self.el.hide(); - self.deleted = true; - }, - - toElement: function(){ - return this.el; - } - -}) diff --git a/couchpotato/static/scripts/status.js b/couchpotato/static/scripts/status.js deleted file mode 100644 index 7967ac5..0000000 --- a/couchpotato/static/scripts/status.js +++ /dev/null @@ -1,11 +0,0 @@ -var StatusBase = new Class({ - - setup: function(statuses){ - var self = this; - - self.statuses = statuses; - - } - -}); -window.Status = new StatusBase(); diff --git a/couchpotato/static/style/plugin/movie_add.css b/couchpotato/static/style/plugin/movie_add.css deleted file mode 100644 index 0d9551e..0000000 --- a/couchpotato/static/style/plugin/movie_add.css +++ /dev/null @@ -1,148 +0,0 @@ -/* @override http://localhost:5000/static/style/plugin/movie_add.css */ - -.search_form { - display: inline-block; - width: 25%; -} - - .search_form input { - padding-right: 25px; - border: 1px solid #aaa; - padding: 4px; - margin: 0; - font-size: 14px; - width: 90%; - - border-radius: 3px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - } - .search_form .input a { - width: 12px; - height: 20px; - display: inline-block; - margin: 0 0 -5px -20px; - top: 4px; - right: 5px; - background: url('../../images/close_button.png') 0 center no-repeat; - cursor: pointer; - } - .search_form .input a:hover { background-position: -12px center; } - - .search_form .results_container { - padding: 10px 0; - position: absolute; - background: #fff; - margin: 11px 0 0 -243px; - width: 470px; - min-height: 140px; - - box-shadow: 0 0 30px rgba(0,0,0,0.2); - -moz-box-shadow: 0 0 30px rgba(0,0,0,0.2); - -webkit-box-shadow: 0 0 30px rgba(0,0,0,0.2); - - border-radius: 3px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - } - .search_form .spinner { - background: #fff url('../../images/spinner.gif') no-repeat center 70px; - } - - .search_form .pointer { - border-right: 10px solid transparent; - border-left: 10px solid transparent; - border-bottom: 10px solid #fff; - display: block; - position: absolute; - width: 0px; - left: 50%; - margin: -19px 0 0 110px; - } - - .search_form .results .movie { - overflow: hidden; - background: #666; - min-height: 140px; - } - - .search_form .results .movie .options { - height: 140px; - } - - .search_form .results .movie .options > div { - padding: 0 15px; - } - - .search_form .results .movie .options .thumbnail { - vertical-align: middle; - } - - .search_form .results .movie .options select { - vertical-align: middle; - display: inline-block; - margin-right: 10px; - } - .search_form .results .movie .options select[name=title] { width: 180px; } - .search_form .results .movie .options select[name=quality] { width: 90px; } - - .search_form .results .movie .options .button { - vertical-align: middle; - display: inline-block; - } - - .search_form .results .movie .options .message { - height: 100%; - line-height: 140px; - font-size: 20px; - text-align: center; - color: #fff; - } - - .search_form .results .movie .data { - padding: 0 15px; - width: 440px; - position: relative; - min-height: 100px; - top: 0; - margin: -140px 0 0 0; - background: #fff; - min-height: 140px; - } - - .search_form .results .movie .thumbnail { - width: 17%; - display: inline-block; - margin: 15px 3% 15px 0; - vertical-align: top; - - border-radius: 3px; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - box-shadow: 0 0 3px rgba(0,0,0,0.35); - -moz-box-shadow: 0 0 3px rgba(0,0,0,0.35); - -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.35); - } - - .search_form .results .movie .info { - width: 74%; - display: inline-block; - vertical-align: top; - padding: 15px 0; - background: #fff; - } - .search_form .results .movie .add +.info { - margin-left: 20%; - } - - .search_form .results .movie .info h2 { - margin: 0; - } - - .search_form .results .movie .info h2 span { - padding: 0 5px; - content: ")"; - } - - .search_form .results .movie .info h2 span:before { content: "("; } - .search_form .results .movie .info h2 span:after { content: ")"; } diff --git a/couchpotato/static/style/plugin/quality.css b/couchpotato/static/style/plugin/quality.css deleted file mode 100644 index c4abc1d..0000000 --- a/couchpotato/static/style/plugin/quality.css +++ /dev/null @@ -1,21 +0,0 @@ -/* @override http://localhost:5000/static/style/plugin/quality.css */ - - -.profile > .delete { - background-position: center; - height: 20px; - width: 20px; -} - -.profile .types .type .handle { - background: url('../../images/handle.png') center; - display: inline-block; - height: 20px; - width: 20px; -} - -.profile .types .type .delete { - background-position: center; - height: 20px; - width: 20px; -} \ No newline at end of file diff --git a/couchpotato/templates/_desktop.html b/couchpotato/templates/_desktop.html index c9ee8b3..1f9e802 100644 --- a/couchpotato/templates/_desktop.html +++ b/couchpotato/templates/_desktop.html @@ -7,8 +7,6 @@ - - @@ -20,7 +18,6 @@ - @@ -29,9 +26,10 @@ - - - + {% for url in fireEvent('clientscript.get_scripts', as_html = True, single = True) %} + {% endfor %} + {% for url in fireEvent('clientscript.get_styles', as_html = True, single = True) %} + {% endfor %}