From d4600635e1efad5e619d4f7fadd57981bc07c524 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 17:35:13 +0200 Subject: [PATCH 01/41] Use sudo in readme. Thanks jbillo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0e4222..91223f1 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Linux (ubuntu / debian): * 'cd' to the folder of your choosing. * Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git` * Then do `python CouchPotatoServer/CouchPotato.py` to start -* To run on boot copy the init script. `cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` -* Change the paths inside the init script. `nano /etc/init.d/couchpotato` -* Make it executable. `chmod +x /etc/init.d/couchpotato` +* To run on boot copy the init script. `sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` +* Change the paths inside the init script. `sudo nano /etc/init.d/couchpotato` +* Make it executable. `sudo chmod +x /etc/init.d/couchpotato` * Add it to defaults. `sudo update-rc.d couchpotato defaults` From 3d26a53fbdef0996d11c99850b9b1f56d6e05871 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 21:59:36 +0200 Subject: [PATCH 02/41] Don't capitalize labels in settings --- couchpotato/static/scripts/page/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 576ad44..4352fb2 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -211,7 +211,7 @@ Page.Settings = new Class({ if(self.tabs[tab_name] && self.tabs[tab_name].tab) return self.tabs[tab_name].tab - var label = (tab.label || tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+tab_name), @@ -244,7 +244,7 @@ Page.Settings = new Class({ if(!parent_tab.subtabs_el) parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab); - var label = (tab.label || tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name), @@ -274,7 +274,7 @@ Page.Settings = new Class({ 'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '') }).adopt( new Element('h2', { - 'text': (group.label || group.name).capitalize() + 'text': group.label || (group.name).capitalize() }).adopt( new Element('span.hint', { 'html': group.description || '' From 8eee2af49b7d25b0a668a0a6d1cca1c379aab426 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 24 Sep 2012 22:23:15 +0200 Subject: [PATCH 03/41] Renamer fileinput. fix #861 --- couchpotato/static/style/page/settings.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 686c3b2..475e61e 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -324,7 +324,7 @@ cursor: text; width: 30%; margin: 0 !important; - height: 27px; + min-height: 27px; line-height: 0; display: inline-block; } From 0f1e8eeff901d4d87d90435d4c20d26c48a4c565 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 10:43:46 +0200 Subject: [PATCH 04/41] Make sure to always search for old movies --- couchpotato/core/plugins/searcher/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 567b84e..670841f 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -410,6 +410,11 @@ class Searcher(Plugin): if not dates or (dates.get('theater', 0) == 0 and dates.get('dvd', 0) == 0): return True else: + + # For movies before 1972 + if dates.get('theater', 0) < 0 or dates.get('dvd', 0) < 0: + return True + if wanted_quality in pre_releases: # Prerelease 1 week before theaters if dates.get('theater') - 604800 < now: From 0132012276e41ba7c7b67b687171aa8136bfeb3e Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 11:10:49 +0200 Subject: [PATCH 05/41] Hide ip change --- couchpotato/core/_base/_core/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/_base/_core/__init__.py b/couchpotato/core/_base/_core/__init__.py index 2aca8e2..8d702f1 100644 --- a/couchpotato/core/_base/_core/__init__.py +++ b/couchpotato/core/_base/_core/__init__.py @@ -27,6 +27,7 @@ config = [{ 'name': 'host', 'advanced': True, 'default': '0.0.0.0', + 'hidden': True, 'label': 'IP', 'description': 'Host that I should listen to. "0.0.0.0" listens to all ips.', }, From d40ad1ddf2e7160da28b55cfbfc592f985b5d920 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 12:43:22 +0200 Subject: [PATCH 06/41] Improved wizard --- couchpotato/core/downloaders/nzbget/__init__.py | 1 - couchpotato/core/downloaders/pneumatic/__init__.py | 1 - couchpotato/core/plugins/wizard/static/wizard.css | 21 +- couchpotato/core/plugins/wizard/static/wizard.js | 484 ++++++++++++--------- .../providers/torrent/kickasstorrents/__init__.py | 1 + .../providers/torrent/thepiratebay/__init__.py | 1 + 6 files changed, 289 insertions(+), 220 deletions(-) diff --git a/couchpotato/core/downloaders/nzbget/__init__.py b/couchpotato/core/downloaders/nzbget/__init__.py index 5015437..8b68c95 100644 --- a/couchpotato/core/downloaders/nzbget/__init__.py +++ b/couchpotato/core/downloaders/nzbget/__init__.py @@ -11,7 +11,6 @@ config = [{ 'name': 'nzbget', 'label': 'NZBGet', 'description': 'Send NZBs to your NZBGet installation.', - 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/downloaders/pneumatic/__init__.py b/couchpotato/core/downloaders/pneumatic/__init__.py index dedcde1..004821c 100644 --- a/couchpotato/core/downloaders/pneumatic/__init__.py +++ b/couchpotato/core/downloaders/pneumatic/__init__.py @@ -12,7 +12,6 @@ config = [{ 'name': 'pneumatic', 'label': 'Pneumatic', 'description': 'Download the .strm file to a specific folder.', - 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/plugins/wizard/static/wizard.css b/couchpotato/core/plugins/wizard/static/wizard.css index d1aa99c..dd73a65 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.css +++ b/couchpotato/core/plugins/wizard/static/wizard.css @@ -14,12 +14,13 @@ .page.wizard .tab_wrapper { background: #5c697b; - padding: 18px 0; - font-size: 23px; + padding: 10px 0; + font-size: 18px; position: fixed; top: 0; margin: 0; width: 100%; + min-width: 960px; left: 0; z-index: 2; box-shadow: 0 0 50px rgba(0,0,0,0.55); @@ -36,7 +37,7 @@ display: inline-block; } .page.wizard .tabs li a { - padding: 20px 30px; + padding: 20px 10px; } .page.wizard .tab_wrapper .pointer { @@ -45,7 +46,7 @@ border-top: 10px solid #5c697b; display: block; position: absolute; - top: 60px; + top: 44px; } .page.wizard .tab_content { @@ -58,11 +59,21 @@ .page.wizard .wgroup_finish { height: 300px; } + .page.wizard .wgroup_finish h1 { + text-align: center; + } + .page.wizard .wgroup_finish .wizard_support, + .page.wizard .wgroup_finish .description { + font-size: 25px; + line-height: 120%; + margin: 20px 0; + text-align: center; + } .page.wizard .button.green { padding: 20px; font-size: 25px; - margin: 10px 30px; + margin: 10px 30px 80px; display: block; text-align: center; } \ No newline at end of file diff --git a/couchpotato/core/plugins/wizard/static/wizard.js b/couchpotato/core/plugins/wizard/static/wizard.js index a4438cb..a3fe938 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.js +++ b/couchpotato/core/plugins/wizard/static/wizard.js @@ -1,214 +1,272 @@ -Page.Wizard = new Class({ - - Extends: Page.Settings, - - name: 'wizard', - 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 your can.
Maybe first start with importing your movies from the previous CouchPotato', - 'content': new Element('div', { - 'styles': { - 'margin': '0 0 0 30px' - } - }).adopt( - new Element('div', { - 'html': 'Select the data.db. It should be in your CouchPotato root directory.' - }), - self.import_iframe = new Element('iframe', { - 'styles': { - 'height': 40, - 'width': 300, - 'border': 0, - 'overflow': 'hidden' - } - }) - ), - 'event': function(){ - self.import_iframe.set('src', Api.createUrl('v1.import')) - } - }, - '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': 'If you don\'t have any of these listed, you have to use Blackhole. Or drop me a line, maybe I\'ll support your download app.' - }, - '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 a few more.' - }, - 'renamer': { - 'title': 'Move & rename the movies after downloading?', - 'description': '' - }, - 'finish': { - 'title': 'Finish Up', - 'description': 'Are you done? Did you fill in everything as much as possible? Yes, ok gogogo!', - 'content': new Element('div').adopt( - new Element('a.button.green', { - 'text': 'I\'m ready to start the awesomeness, wow this button is big and green!', - '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(); - } - }); - } - } - }) - ) - } - }, - groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', 'renamer', 'finish'], - - open: function(action, params){ - var self = this; - - if(!self.initialized){ - App.fireEvent('unload'); - App.getBlock('header').hide(); - - self.parent(action, params); - - self.addEvent('create', function(){ - self.order(); - }); - - self.initialized = true; - - self.scroll = new Fx.Scroll(document.body, { - 'transition': 'quint:in:out' - }); - } - else - (function(){ - var sc = self.el.getElement('.wgroup_'+action); - self.scroll.start(0, sc.getCoordinates().top-80); - }).delay(1) - }, - - order: function(){ - var self = this; - - var form = self.el.getElement('.uniForm'); - var tabs = self.el.getElement('.tabs'); - - self.groups.each(function(group){ - if(self.headers[group]){ - group_container = new Element('.wgroup_'+group, { - 'styles': { - 'opacity': 0.2 - }, - 'tween': { - 'duration': 350 - } - }); - 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, - self.headers[group].content ? self.headers[group].content : null - ).inject(form); - } - - var tab_navigation = tabs.getElement('.t_'+group); - if(tab_navigation && group_container){ - tab_navigation.inject(tabs); // Tab navigation - self.el.getElement('.tab_'+group).inject(group_container); // Tab content - if(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).adopt( - 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() - }); - - // Remove toggle - self.el.getElement('.advanced_toggle').destroy(); - - // Hide retention - self.el.getElement('.tab_searcher').hide(); - self.el.getElement('.t_searcher').hide(); - - // Add pointer - new Element('.tab_wrapper').wraps(tabs).adopt( - self.pointer = new Element('.pointer', { - 'tween': { - 'transition': 'quint:in:out' - } - }) - ); - - // Add nav - var minimum = self.el.getSize().y-window.getSize().y; - self.groups.each(function(group, nr){ - - var g = self.el.getElement('.wgroup_'+group); - if(!g || !g.isVisible()) return; - var t = self.el.getElement('.t_'+group); - if(!t) return; - - var func = function(){ - var ct = t.getCoordinates(); - self.pointer.tween('left', ct.left+(ct.width/2)-(self.pointer.getWidth()/2)); - g.tween('opacity', 1); - } - - if(nr == 0) - func(); - - - var ss = new ScrollSpy( { - min: function(){ - var c = g.getCoordinates(); - var top = c.top-(window.getSize().y/2); - return top > minimum ? minimum : top - }, - max: function(){ - var c = g.getCoordinates(); - return c.top+(c.height/2) - }, - onEnter: func, - onLeave: function(){ - g.tween('opacity', 0.2) - } - }); - }); - - } - +Page.Wizard = new Class({ + + Extends: Page.Settings, + + name: 'wizard', + 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 your can.
Maybe first start with importing your movies from the previous CouchPotato', + 'content': new Element('div', { + 'styles': { + 'margin': '0 0 0 30px' + } + }).adopt( + new Element('div', { + 'html': 'Select the data.db. It should be in your CouchPotato root directory.' + }), + self.import_iframe = new Element('iframe', { + 'styles': { + 'height': 40, + 'width': 300, + 'border': 0, + 'overflow': 'hidden' + } + }) + ), + 'event': function(){ + self.import_iframe.set('src', Api.createUrl('v1.import')) + } + }, + '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 Blackhole.' + }, + '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 a few more. Check settings for the full list of available providers.' + }, + '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 userscript or drag the bookmarklet to your browsers bookmarks.' + + '
Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)', + 'content': function(){ + + // See if userscript can be installed + var userscript = false; + try { + if(Components.interfaces.gmIGreasemonkeyService) + userscript = true + } + catch(e){ + userscript = Browser.chrome === true; + } + + var host_url = window.location.protocol + '//' + window.location.host; + + var el = new Element('div.group_userscript').adopt( + + (userscript ? [new Element('a.userscript.button', { + 'text': 'Install userscript', + 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', + 'target': '_self' + }), new Element('span.or[text=or]')] : null), + new Element('span.bookmarklet').adopt( + new Element('a.button.orange', { + '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' + }) + ) + ).setStyles({ + 'background-image': "url('"+Api.createUrl('static/userscript/userscript.png')+"')" + }); + + return el + } + }, + 'finish': { + 'title': 'Finishing Up', + 'description': 'Are you done? Did you fill in everything as much as possible?' + + '
Be sure to check the settings to see what more CP can do!

' + + '
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.
Or by getting a subscription at Usenet Server or Newshosting.
', + 'content': new Element('div').adopt( + new Element('a.button.green', { + 'styles': { + 'margin-top': 20 + }, + 'text': 'I\'m ready to start the awesomeness, wow this button is big and green!', + '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(); + } + }); + } + } + }) + ) + } + }, + groups: ['welcome', 'general', 'downloaders', 'searcher', 'providers', '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.addEvent('create', function(){ + self.order(); + }); + + self.initialized = true; + + self.scroll = new Fx.Scroll(document.body, { + 'transition': 'quint:in:out' + }); + } + else + (function(){ + var sc = self.el.getElement('.wgroup_'+action); + self.scroll.start(0, sc.getCoordinates().top-80); + }).delay(1) + }, + + order: function(){ + var self = this; + + var form = self.el.getElement('.uniForm'); + var tabs = self.el.getElement('.tabs'); + + self.groups.each(function(group, nr){ + if(self.headers[group]){ + group_container = new Element('.wgroup_'+group, { + 'styles': { + 'opacity': 0.2 + }, + 'tween': { + 'duration': 350 + } + }); + + 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 && group_container){ + tab_navigation.inject(tabs); // Tab navigation + self.el.getElement('.tab_'+group).inject(group_container); // Tab content + if(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).adopt( + 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() + }); + + // Remove toggle + self.el.getElement('.advanced_toggle').destroy(); + + // Hide retention + self.el.getElement('.tab_searcher').hide(); + self.el.getElement('.t_searcher').hide(); + + // Add pointer + new Element('.tab_wrapper').wraps(tabs).adopt( + self.pointer = new Element('.pointer', { + 'tween': { + 'transition': 'quint:in:out' + } + }) + ); + + // Add nav + var minimum = self.el.getSize().y-window.getSize().y; + self.groups.each(function(group, nr){ + + var g = self.el.getElement('.wgroup_'+group); + if(!g || !g.isVisible()) return; + var t = self.el.getElement('.t_'+group); + if(!t) return; + + var func = function(){ + var ct = t.getCoordinates(); + self.pointer.tween('left', ct.left+(ct.width/2)-(self.pointer.getWidth()/2)); + g.tween('opacity', 1); + } + + if(nr == 0) + func(); + + + var ss = new ScrollSpy( { + min: function(){ + var c = g.getCoordinates(); + var top = c.top-(window.getSize().y/2); + return top > minimum ? minimum : top + }, + max: function(){ + var c = g.getCoordinates(); + return c.top+(c.height/2) + }, + onEnter: func, + onLeave: function(){ + g.tween('opacity', 0.2) + } + }); + }); + + } + }); \ No newline at end of file diff --git a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py index 2401f95..9f0ab12 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py @@ -11,6 +11,7 @@ config = [{ 'subtab': 'providers', 'name': 'KickAssTorrents', 'description': 'See KickAssTorrents', + 'wizard': True, 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/torrent/thepiratebay/__init__.py b/couchpotato/core/providers/torrent/thepiratebay/__init__.py index 2f8872e..9a7beef 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/__init__.py +++ b/couchpotato/core/providers/torrent/thepiratebay/__init__.py @@ -10,6 +10,7 @@ config = [{ 'subtab': 'providers', 'name': 'ThePirateBay', 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', + 'wizard': True, 'options': [ { 'name': 'enabled', From 08ae51dbe615e7d847adbfd9f770d4b6db87a749 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 14:22:48 +0200 Subject: [PATCH 07/41] Improved folder select --- couchpotato/core/plugins/browser/main.py | 25 +++++++++++++++- couchpotato/static/scripts/page/settings.js | 46 +++++++++++++++++++---------- couchpotato/static/style/page/settings.css | 13 ++++++++ 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/couchpotato/core/plugins/browser/main.py b/couchpotato/core/plugins/browser/main.py index aa11b22..b84284b 100644 --- a/couchpotato/core/plugins/browser/main.py +++ b/couchpotato/core/plugins/browser/main.py @@ -27,6 +27,8 @@ class FileBrowser(Plugin): }, 'return': {'type': 'object', 'example': """{ 'is_root': bool, //is top most folder + 'parent': string, //parent folder of requested path + 'home': string, //user home folder 'empty': bool, //directory is empty 'dirs': array, //directory names }"""} @@ -64,14 +66,35 @@ class FileBrowser(Plugin): path = getParam('path', '/') + # Set proper home dir for some systems + try: + import pwd + os.environ['HOME'] = pwd.getpwuid(os.geteuid()).pw_dir + except: + pass + + home = os.path.expanduser('~') + + if not path: + path = home + try: dirs = self.getDirectories(path = path, show_hidden = getParam('show_hidden', True)) except: dirs = [] + parent = os.path.dirname(path.rstrip(os.path.sep)) + if parent == path.rstrip(os.path.sep): + parent = '/' + elif parent != '/' and parent[-2:] != ':\\': + parent += os.path.sep + return jsonified({ - 'is_root': path == '/' or not path, + 'is_root': path == '/', 'empty': len(dirs) == 0, + 'parent': parent, + 'home': home + os.path.sep, + 'platform': os.name, 'dirs': dirs, }) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 4352fb2..161da68 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -635,7 +635,7 @@ Option.Directory = new Class({ ), self.dir_list = new Element('ul', { 'events': { - 'click:relay(li)': function(e, el){ + 'click:relay(li:not(.empty))': function(e, el){ (e).preventDefault(); self.selectDirectory(el.get('data-value')) }, @@ -701,12 +701,24 @@ Option.Directory = new Class({ fillBrowser: function(json){ var self = this; - var v = self.input.get('text'); + self.data = json; + + var v = self.getValue(); var previous_dir = self.getParentDir(); + if(v == '') + self.input.set('text', json.home); + if(previous_dir != v && previous_dir.length >= 1 && !json.is_root){ + + var prev_dirname = self.getCurrentDirname(previous_dir); + if(previous_dir == json.home) + prev_dirname = 'Home'; + else if (previous_dir == '/' && json.platform == 'nt') + prev_dirname = 'Computer'; + self.back_button.set('data-value', previous_dir) - self.back_button.set('html', '« '+self.getCurrentDirname(previous_dir)) + self.back_button.set('html', '« '+prev_dirname) self.back_button.show() } else { @@ -719,23 +731,24 @@ Option.Directory = new Class({ else self.cached[v] = json; - setTimeout(function(){ - self.dir_list.empty(); + self.dir_list.empty(); + if(json.dirs.length > 0) json.dirs.each(function(dir){ - if(dir.indexOf(v) != -1){ - new Element('li', { - 'data-value': dir, - 'text': self.getCurrentDirname(dir) - }).inject(self.dir_list) - } + new Element('li', { + 'data-value': dir, + 'text': self.getCurrentDirname(dir) + }).inject(self.dir_list) }); - }, 50); + else + new Element('li.empty', { + 'text': 'Selected folder is empty' + }).inject(self.dir_list) }, getDirs: function(){ var self = this; - var c = self.input.get('text'); + var c = self.getValue(); if(self.cached[c] && self.use_cache){ self.fillBrowser() @@ -754,7 +767,10 @@ Option.Directory = new Class({ getParentDir: function(dir){ var self = this; - var v = dir || self.input.get('text'); + if(!dir && self.data && self.data.parent) + return self.data.parent; + + var v = dir || self.getValue(); var sep = Api.getOption('path_sep'); var dirs = v.split(sep); if(dirs.pop() == '') @@ -941,7 +957,7 @@ Option.Choice = new Class({ mtches.append([value == matchsplit ? match : matchsplit]); }); }); - + if(mtches.length == 0 && value != '') mtches.include(value); diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 475e61e..89f81e7 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -235,6 +235,19 @@ .page .directory_list li:hover { background-color: #515c68; } + + .page .directory_list li.empty { + background: none; + height: 100px; + text-align: center; + font-style: italic; + border: none; + line-height: 100px; + cursor: default; + color: #BBB; + text-shadow: none; + font-size: 12px; + } .page .directory_list .actions { clear: both; From 952f29918e3292570536a3a7a5161c0b37eeed7c Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 14:30:35 +0200 Subject: [PATCH 08/41] Hide git command when not using git Re-order automation --- couchpotato/core/_base/updater/__init__.py | 3 +++ couchpotato/core/plugins/automation/__init__.py | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/_base/updater/__init__.py b/couchpotato/core/_base/updater/__init__.py index 7aae0b2..a304f9e 100644 --- a/couchpotato/core/_base/updater/__init__.py +++ b/couchpotato/core/_base/updater/__init__.py @@ -1,4 +1,6 @@ from .main import Updater +from couchpotato.environment import Env +import os def start(): return Updater() @@ -33,6 +35,7 @@ config = [{ { 'name': 'git_command', 'default': 'git', + 'hidden': not os.path.isdir(os.path.join(Env.get('app_dir'), '.git')), 'advanced': True }, ], diff --git a/couchpotato/core/plugins/automation/__init__.py b/couchpotato/core/plugins/automation/__init__.py index 75e0d28..b7b1ab2 100644 --- a/couchpotato/core/plugins/automation/__init__.py +++ b/couchpotato/core/plugins/automation/__init__.py @@ -5,13 +5,12 @@ def start(): config = [{ 'name': 'automation', - 'order': 30, + 'order': 101, 'groups': [ { 'tab': 'automation', 'name': 'automation', - 'label': 'Automation', - 'description': 'Minimal movie requirements', + 'label': 'Minimal movie requirements', 'options': [ { 'name': 'year', From 24ad9759175f3e797cd630227c799e5fc646f6e5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 15:09:35 +0200 Subject: [PATCH 09/41] Movie providers in their own subgroup --- couchpotato/core/plugins/subtitle/__init__.py | 4 +- couchpotato/core/plugins/trailer/__init__.py | 4 +- .../core/providers/nzb/mysterbin/__init__.py | 2 +- couchpotato/core/providers/nzb/newzbin/__init__.py | 2 +- couchpotato/core/providers/nzb/newznab/__init__.py | 3 +- couchpotato/core/providers/nzb/nzbclub/__init__.py | 2 +- .../core/providers/nzb/nzbindex/__init__.py | 2 +- .../core/providers/nzb/nzbmatrix/__init__.py | 2 +- couchpotato/core/providers/nzb/nzbsrus/__init__.py | 2 +- .../providers/torrent/kickasstorrents/__init__.py | 2 +- .../providers/torrent/passthepopcorn/__init__.py | 58 +++++++++++----------- .../core/providers/torrent/publichd/__init__.py | 2 +- .../core/providers/torrent/sceneaccess/__init__.py | 2 +- .../core/providers/torrent/scenehd/__init__.py | 2 +- .../providers/torrent/thepiratebay/__init__.py | 42 ++++++++-------- .../providers/torrent/torrentleech/__init__.py | 2 +- couchpotato/static/scripts/page/settings.js | 2 +- 17 files changed, 70 insertions(+), 65 deletions(-) diff --git a/couchpotato/core/plugins/subtitle/__init__.py b/couchpotato/core/plugins/subtitle/__init__.py index 858ce9d..686d385 100644 --- a/couchpotato/core/plugins/subtitle/__init__.py +++ b/couchpotato/core/plugins/subtitle/__init__.py @@ -8,9 +8,9 @@ config = [{ 'groups': [ { 'tab': 'renamer', - 'subtab': 'subtitles', 'name': 'subtitle', - 'label': 'Download subtitles after rename', + 'label': 'Download subtitles', + 'description': 'after rename', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/plugins/trailer/__init__.py b/couchpotato/core/plugins/trailer/__init__.py index 033df08..3ae454d 100644 --- a/couchpotato/core/plugins/trailer/__init__.py +++ b/couchpotato/core/plugins/trailer/__init__.py @@ -8,9 +8,9 @@ config = [{ 'groups': [ { 'tab': 'renamer', - 'subtab': 'trailer', 'name': 'trailer', - 'label': 'Download trailer after rename', + 'label': 'Download trailer', + 'description': 'after rename', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/providers/nzb/mysterbin/__init__.py b/couchpotato/core/providers/nzb/mysterbin/__init__.py index 3f0d1d3..b34f72f 100644 --- a/couchpotato/core/providers/nzb/mysterbin/__init__.py +++ b/couchpotato/core/providers/nzb/mysterbin/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'Mysterbin', 'description': 'Free provider, less accurate. See Mysterbin', 'options': [ diff --git a/couchpotato/core/providers/nzb/newzbin/__init__.py b/couchpotato/core/providers/nzb/newzbin/__init__.py index 06b2548..1129233 100644 --- a/couchpotato/core/providers/nzb/newzbin/__init__.py +++ b/couchpotato/core/providers/nzb/newzbin/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'newzbin', 'description': 'See Newzbin', 'wizard': True, diff --git a/couchpotato/core/providers/nzb/newznab/__init__.py b/couchpotato/core/providers/nzb/newznab/__init__.py index e54db34..712f03e 100644 --- a/couchpotato/core/providers/nzb/newznab/__init__.py +++ b/couchpotato/core/providers/nzb/newznab/__init__.py @@ -8,8 +8,9 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'newznab', + 'order': 10, 'description': 'Enable multiple NewzNab providers such as NZB.su and nzbs.org', 'wizard': True, 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbclub/__init__.py b/couchpotato/core/providers/nzb/nzbclub/__init__.py index e3387a3..fc7b7ef 100644 --- a/couchpotato/core/providers/nzb/nzbclub/__init__.py +++ b/couchpotato/core/providers/nzb/nzbclub/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'NZBClub', 'description': 'Free provider, less accurate. See NZBClub', 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbindex/__init__.py b/couchpotato/core/providers/nzb/nzbindex/__init__.py index 59b2730..5bf5cd4 100644 --- a/couchpotato/core/providers/nzb/nzbindex/__init__.py +++ b/couchpotato/core/providers/nzb/nzbindex/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbindex', 'description': 'Free provider, less accurate. See NZBIndex', 'options': [ diff --git a/couchpotato/core/providers/nzb/nzbmatrix/__init__.py b/couchpotato/core/providers/nzb/nzbmatrix/__init__.py index 8fc6b40..c3a5bfa 100644 --- a/couchpotato/core/providers/nzb/nzbmatrix/__init__.py +++ b/couchpotato/core/providers/nzb/nzbmatrix/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbmatrix', 'label': 'NZBMatrix', 'description': 'See NZBMatrix', diff --git a/couchpotato/core/providers/nzb/nzbsrus/__init__.py b/couchpotato/core/providers/nzb/nzbsrus/__init__.py index 70f3e3f..cd4d669 100644 --- a/couchpotato/core/providers/nzb/nzbsrus/__init__.py +++ b/couchpotato/core/providers/nzb/nzbsrus/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'nzb_providers', 'name': 'nzbsrus', 'label': 'Nzbsrus', 'description': 'See NZBsRus', diff --git a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py index 9f0ab12..ffa3934 100644 --- a/couchpotato/core/providers/torrent/kickasstorrents/__init__.py +++ b/couchpotato/core/providers/torrent/kickasstorrents/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'KickAssTorrents', 'description': 'See KickAssTorrents', 'wizard': True, diff --git a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py index 67bf666..44d98cb 100644 --- a/couchpotato/core/providers/torrent/passthepopcorn/__init__.py +++ b/couchpotato/core/providers/torrent/passthepopcorn/__init__.py @@ -5,32 +5,34 @@ def start(): config = [{ 'name': 'passthepopcorn', - 'groups': [{ - 'tab': 'searcher', - 'subtab': 'providers', - 'name': 'PassThePopcorn', - 'description': 'See PassThePopcorn.me', - 'options': [ - { - 'name': 'enabled', - 'type': 'enabler', - 'default': False - }, - { - 'name': 'domain', - 'advanced': True, - 'label': 'Proxy server', - 'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).', - }, - { - 'name': 'username', - 'default': '', - }, - { - 'name': 'password', - 'default': '', - 'type': 'password', - } - ], - }] + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'torrent_providers', + 'name': 'PassThePopcorn', + 'description': 'See PassThePopcorn.me', + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + 'default': False + }, + { + 'name': 'domain', + 'advanced': True, + 'label': 'Proxy server', + 'description': 'Domain for requests (HTTPS only!), keep empty to use default (tls.passthepopcorn.me).', + }, + { + 'name': 'username', + 'default': '', + }, + { + 'name': 'password', + 'default': '', + 'type': 'password', + } + ], +} + ] }] diff --git a/couchpotato/core/providers/torrent/publichd/__init__.py b/couchpotato/core/providers/torrent/publichd/__init__.py index 94d0825..edffeba 100644 --- a/couchpotato/core/providers/torrent/publichd/__init__.py +++ b/couchpotato/core/providers/torrent/publichd/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'PublicHD', 'description': 'Public Torrent site with only HD content. See PublicHD', 'options': [ diff --git a/couchpotato/core/providers/torrent/sceneaccess/__init__.py b/couchpotato/core/providers/torrent/sceneaccess/__init__.py index 28b7ca3..e59f89b 100644 --- a/couchpotato/core/providers/torrent/sceneaccess/__init__.py +++ b/couchpotato/core/providers/torrent/sceneaccess/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'SceneAccess', 'description': 'See SceneAccess', 'options': [ diff --git a/couchpotato/core/providers/torrent/scenehd/__init__.py b/couchpotato/core/providers/torrent/scenehd/__init__.py index c9f18be..a3d0313 100644 --- a/couchpotato/core/providers/torrent/scenehd/__init__.py +++ b/couchpotato/core/providers/torrent/scenehd/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'SceneHD', 'description': 'See SceneHD', 'options': [ diff --git a/couchpotato/core/providers/torrent/thepiratebay/__init__.py b/couchpotato/core/providers/torrent/thepiratebay/__init__.py index 9a7beef..9c56eb8 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/__init__.py +++ b/couchpotato/core/providers/torrent/thepiratebay/__init__.py @@ -5,24 +5,26 @@ def start(): config = [{ 'name': 'thepiratebay', - 'groups': [{ - 'tab': 'searcher', - 'subtab': 'providers', - 'name': 'ThePirateBay', - 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', - 'wizard': True, - 'options': [ - { - 'name': 'enabled', - 'type': 'enabler', - 'default': False - }, - { - 'name': 'domain', - 'advanced': True, - 'label': 'Proxy server', - 'description': 'Domain for requests, keep empty to let CouchPotato pick.', - } - ], - }] + 'groups': [ + { + 'tab': 'searcher', + 'subtab': 'torrent_providers', + 'name': 'ThePirateBay', + 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', + 'wizard': True, + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + 'default': False + }, + { + 'name': 'domain', + 'advanced': True, + 'label': 'Proxy server', + 'description': 'Domain for requests, keep empty to let CouchPotato pick.', + } + ], + } + ] }] diff --git a/couchpotato/core/providers/torrent/torrentleech/__init__.py b/couchpotato/core/providers/torrent/torrentleech/__init__.py index 482dfda..b808a00 100644 --- a/couchpotato/core/providers/torrent/torrentleech/__init__.py +++ b/couchpotato/core/providers/torrent/torrentleech/__init__.py @@ -8,7 +8,7 @@ config = [{ 'groups': [ { 'tab': 'searcher', - 'subtab': 'providers', + 'subtab': 'torrent_providers', 'name': 'TorrentLeech', 'description': 'See TorrentLeech', 'options': [ diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 161da68..f4afc84 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -244,7 +244,7 @@ Page.Settings = new Class({ if(!parent_tab.subtabs_el) parent_tab.subtabs_el = new Element('ul.subtabs').inject(parent_tab.tab); - var label = tab.label || (tab.name || tab_name).capitalize() + var label = tab.label || (tab.name || tab_name.replace('_', ' ')).capitalize() var tab_el = new Element('li.t_'+tab_name).adopt( new Element('a', { 'href': App.createUrl(self.name+'/'+parent_tab_name+'/'+tab_name), From 7e3a6eeb83a699e0acbb9aed04f80b93e4074794 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 15:47:50 +0200 Subject: [PATCH 10/41] Make sure top quality is always checked. --- couchpotato/core/plugins/profile/static/profile.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 470fda8..947da1d 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -86,7 +86,10 @@ var Profile = new Class({ }, 'onComplete': function(json){ if(json.success){ - self.data = json.profile + self.data = json.profile; + self.type_container.getElement('li:first-child input[type=checkbox]') + .set('checked', true) + .getParent().addClass('checked'); } } }); @@ -241,7 +244,15 @@ Profile.Type = new Class({ self.finish = new Element('input.inlay.finish[type=checkbox]', { 'checked': data.finish, 'events': { - 'change': self.fireEvent.bind(self, 'change') + 'change': function(e){ + if(self.el == self.el.getParent().getElement(':first-child')){ + self.finish_class.check(); + alert('Top quality always finishes the search') + return; + } + + self.fireEvent('change'); + } } }) ), @@ -255,7 +266,7 @@ Profile.Type = new Class({ self.el[self.data.quality_id > 0 ? 'removeClass' : 'addClass']('is_empty'); - new Form.Check(self.finish); + self.finish_class = new Form.Check(self.finish); }, From 08ef153bbf4ad69a9fc497486c74a20e5c815cc4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 16:03:31 +0200 Subject: [PATCH 11/41] remove dropdown arrow --- couchpotato/static/style/main.css | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/couchpotato/static/style/main.css b/couchpotato/static/style/main.css index 183374b..e187593 100644 --- a/couchpotato/static/style/main.css +++ b/couchpotato/static/style/main.css @@ -376,22 +376,12 @@ body > .spinner, .mask{ font-weight: bold; } - .select .list:before { - content: ' '; - height: 0; - position: absolute; - width: 0; - border: 6px solid transparent; - border-bottom-color: #282d34; - margin: -11px 0 0 70px; - } - .select .list { display: none; background: #282d34; border: 1px solid #1f242b; position: absolute; - margin: 30px 0 0 0; + margin: 28px 0 0 0; box-shadow: 0 20px 20px -10px rgba(0,0,0,0.4); border-radius:3px; z-index: 3; From 3fa352e7c8abb46e2faa6eee7786e9fa4ce489b5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 19:02:28 +0200 Subject: [PATCH 12/41] Firefox fix for directory input --- couchpotato/static/style/page/settings.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css index 89f81e7..f17e618 100644 --- a/couchpotato/static/style/page/settings.css +++ b/couchpotato/static/style/page/settings.css @@ -332,7 +332,6 @@ .page .tag_input > ul { list-style: none; - padding: 3px 0; border-radius: 3px; cursor: text; width: 30%; @@ -352,7 +351,7 @@ min-width: 2px; font-size: 12px; padding: 0; - margin: 0 !important; + margin: 4px 0 0 !important; border-width: 0; background: 0; line-height: 20px; @@ -413,7 +412,7 @@ margin: -9px 0 0 -16px; border-radius: 30px 30px 0 0; cursor: pointer; - background: url('../../images/icon.delete.png') no-repeat center 2px, -webkit-linear-gradient( + background: url('../../images/icon.delete.png') no-repeat center 2px, linear-gradient( 270deg, #5b9bd1 0%, #5b9bd1 100% From 3a3a4fb1f3973ac275a4080ad8ca5c80656db822 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 25 Sep 2012 23:11:27 +0200 Subject: [PATCH 13/41] Cleanup javascript events on movie delete --- couchpotato/core/plugins/movie/static/list.js | 12 +++++++----- couchpotato/core/plugins/movie/static/movie.js | 23 +++++++++++++++++++++-- couchpotato/core/plugins/movie/static/search.js | 2 +- couchpotato/static/scripts/page/wanted.js | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 38fc710..0aff0bd 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -86,18 +86,18 @@ var MovieList = new Class({ Object.each(movies, function(movie){ self.createMovie(movie); }); - + self.setCounter(total); }, - + setCounter: function(count){ var self = this; - + if(!self.navigation_counter) return; - + self.navigation_counter.set('text', (count || 0)); - + }, createMovie: function(movie, inject_at){ @@ -309,6 +309,8 @@ var MovieList = new Class({ erase_movies.each(function(movie){ self.movies.erase(movie); + + movie.destroy() }); self.calculateSelected(); diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index abaea65..f5cd41e 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -16,16 +16,35 @@ var Movie = new Class({ self.profile = Quality.getProfile(data.profile_id) || {}; self.parent(self, options); - App.addEvent('movie.update.'+data.id, self.update.bind(self)); + self.addEvents(); + }, + + addEvents: function(){ + var self = this; + + App.addEvent('movie.update.'+self.data.id, self.update.bind(self)); ['movie.busy', 'searcher.started'].each(function(listener){ - App.addEvent(listener+'.'+data.id, function(notification){ + App.addEvent(listener+'.'+self.data.id, function(notification){ if(notification.data) self.busy(true) }); }) }, + destroy: function(){ + var self = this; + + self.el.destroy(); + delete self.list.movies_added[self.get('id')]; + + // Remove events + App.removeEvents('movie.update.'+self.data.id); + ['movie.busy', 'searcher.started'].each(function(listener){ + App.removeEvents(listener+'.'+self.data.id); + }) + }, + busy: function(set_busy){ var self = this; diff --git a/couchpotato/core/plugins/movie/static/search.js b/couchpotato/core/plugins/movie/static/search.js index 6c6c94e..63cab34 100644 --- a/couchpotato/core/plugins/movie/static/search.js +++ b/couchpotato/core/plugins/movie/static/search.js @@ -324,7 +324,7 @@ Block.Search.Item = new Class({ var self = this; if(!self.options.hasClass('set')){ - + if(self.info.in_library){ var in_library = []; self.info.in_library.releases.each(function(release){ diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 3ef10d7..a50b1bd 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -222,7 +222,7 @@ window.addEvent('domready', function(){ movie.set('tween', { 'duration': 300, 'onComplete': function(){ - movie.destroy(); + self.movie.destroy() } }); movie.tween('height', 0); From ba36c738c7d6c345e728f957ab997f1c32f89a86 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:46:10 +0930 Subject: [PATCH 14/41] Added def remove Allows renamer to request deletion of failed downloads --- couchpotato/core/downloaders/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 6fa6a91..6ca29f6 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -24,6 +24,7 @@ class Downloader(Plugin): def __init__(self): addEvent('download', self.download) addEvent('download.status', self.getDownloadStatus) + addEvent('download.remove', self.remove) def download(self, data = {}, movie = {}, manual = False, filedata = None): pass @@ -31,6 +32,9 @@ class Downloader(Plugin): def getDownloadStatus(self, data = {}, movie = {}): return False + def remove(self, name = {}, nzo_id = {}): + return False + def createNzbName(self, data, movie): tag = self.cpTag(movie) return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) From ef945597d2036217bb78a4fc166dbb55dec80e88 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:51:51 +0930 Subject: [PATCH 15/41] Removed checking of status results from here getDownloadStatus is only called once from renamer and all results are passed back. Def remove is added so that renamer can request a failed downlaod to be deleted from SABnzbd if enabled. --- couchpotato/core/downloaders/sabnzbd/main.py | 94 +++++++++++----------------- 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 0151cc4..f05f0d5 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -67,8 +67,7 @@ class Sabnzbd(Downloader): if self.isDisabled(manual = True) or not self.isCorrectType(data.get('type')): return - nzbname = self.createNzbName(data, movie) - log.info('Checking download status of "%s" at SABnzbd.', nzbname) + log.info('Checking SABnzbd download status.') # Go through Queue params = { @@ -85,20 +84,12 @@ class Sabnzbd(Downloader): return False try: - history = json.loads(sab) + queue = json.loads(sab) except: log.debug("Result text from SAB: " + sab[:40]) log.error('Failed parsing json status: %s', traceback.format_exc()) return False - try: - for slot in history['queue']['slots']: - log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) - if slot['filename'] == nzbname: - return slot['status'].lower() - except: - log.debug('No items in queue: %s', (traceback.format_exc())) - # Go through history items params = { 'apikey': self.conf('api_key'), @@ -112,57 +103,46 @@ class Sabnzbd(Downloader): sab = self.urlopen(url, timeout = 60, show_error = False) except: log.error('Failed getting history: %s', traceback.format_exc()) - return + return False try: history = json.loads(sab) except: log.debug("Result text from SAB: " + sab[:40]) log.error('Failed parsing history json: %s', traceback.format_exc()) - return + return False - try: - for slot in history['history']['slots']: - log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) - if slot['name'] == nzbname: - # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message - if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): - - # Delete failed download - if self.conf('delete_failed', default = True): - - log.info('%s failed downloading, deleting...', slot['name']) - params = { - 'apikey': self.conf('api_key'), - 'mode': 'history', - 'name': 'delete', - 'del_files': '1', - 'value': slot['nzo_id'] - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed deleting: %s', traceback.format_exc()) - return False - - result = sab.strip() - if not result: - log.error("SABnzbd didn't return anything.") - - log.debug("Result text from SAB: " + result[:40]) - if result == "ok": - log.info('SabNZBd deleted failed release %s successfully.', slot['name']) - elif result == "Missing authentication": - log.error("Incorrect username/password or API?.") - else: - log.error("Unknown error: " + result[:40]) - - return 'failed' - else: - return slot['status'].lower() - except: - log.debug('No items in history: %s', (traceback.format_exc())) + return queue, history + + def remove(self, name = {}, nzo_id = {}): + # Delete failed download + if self.conf('delete_failed', default = True): + + log.info('%s failed downloading, deleting...', name) + params = { + 'apikey': self.conf('api_key'), + 'mode': 'history', + 'name': 'delete', + 'del_files': '1', + 'value': nzo_id + } + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - return 'not_found' + try: + sab = self.urlopen(url, timeout = 60, show_error = False) + except: + log.error('Failed deleting: %s', traceback.format_exc()) + return False + + result = sab.strip() + if not result: + log.error("SABnzbd didn't return anything.") + + log.debug("Result text from SAB: " + result[:40]) + if result == "ok": + log.info('SabNZBd deleted failed release %s successfully.', name) + elif result == "Missing authentication": + log.error("Incorrect username/password or API?.") + else: + log.error("Unknown error: " + result[:40]) + return From c6cba2f6e55f5f594738e9ac4b227dc99ef34979 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 16:59:36 +0930 Subject: [PATCH 16/41] Only request SABnzbd status once Performs the checking of queue and history here. Requests delete of failed downlaods via download.remove event. --- couchpotato/core/plugins/renamer/main.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index a696265..aedc40c 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -506,9 +506,11 @@ class Renamer(Plugin): if rels: log.debug('Checking status snatched releases...') + # get queue and history (once) from SABnzbd + queue, history = fireEvent('download.status', data = {}, movie = {}, single = True) scan_required = False - + for rel in rels: # Get current selected title @@ -530,7 +532,28 @@ class Renamer(Plugin): movie_dict = fireEvent('movie.get', rel.movie_id, single = True) # check status - downloadstatus = fireEvent('download.status', data = item, movie = movie_dict, single = True) + try: + for slot in queue['queue']['slots']: + log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) + if slot['filename'] == nzbname: + downloadstatus =['status'].lower() + except: + log.debug('No items in queue: %s', (traceback.format_exc())) + try: + for slot in history['history']['slots']: + log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) + if slot['name'] == nzbname: + # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message + if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): + + # Delete failed download + rel_remove = fireEvent('download.remove', name = slot['name'], nzo_id = slot['nzo_id'], single = True) + downloadstatus = 'failed' + else: + downloadstatus = slot['status'].lower() + except: + log.debug('No items in history: %s', (traceback.format_exc())) + if not downloadstatus: log.debug('Download status functionality is not implemented for active downloaders.') scan_required = True From dc63796e4864454204bb7f88ee6383022004e2e6 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Wed, 26 Sep 2012 17:12:19 +0930 Subject: [PATCH 17/41] Added nzbname previously defined in Downloader. I forgot to bring this across. --- couchpotato/core/plugins/renamer/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index aedc40c..2f57911 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -532,6 +532,7 @@ class Renamer(Plugin): movie_dict = fireEvent('movie.get', rel.movie_id, single = True) # check status + nzbname = self.createNzbName(item, movie_dict) try: for slot in queue['queue']['slots']: log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) From 08b450fc0aae80da7af2af1fd07729fdf76d02cb Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 17:10:34 +0200 Subject: [PATCH 18/41] Remove trailer feature not implemented yet. --- couchpotato/core/plugins/trailer/__init__.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/couchpotato/core/plugins/trailer/__init__.py b/couchpotato/core/plugins/trailer/__init__.py index 3ae454d..f3aa59d 100644 --- a/couchpotato/core/plugins/trailer/__init__.py +++ b/couchpotato/core/plugins/trailer/__init__.py @@ -24,12 +24,6 @@ config = [{ 'type': 'dropdown', 'values': [('1080P', '1080p'), ('720P', '720p'), ('480P', '480p')], }, - { - 'name': 'automatic', - 'default': False, - 'type': 'bool', - 'description': 'Automaticly search & download for movies in library', - }, ], }, ], From 95c5d16991b2eb63c748af07791e30506541dcf8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 19:35:59 +0200 Subject: [PATCH 19/41] Don't check retention when it's 0 --- couchpotato/core/plugins/searcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 670841f..5bf7aeb 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -254,7 +254,7 @@ class Searcher(Plugin): imdb_results = kwargs.get('imdb_results', False) retention = Env.setting('retention', section = 'nzb') - if nzb.get('seeds') is None and retention < nzb.get('age', 0): + if nzb.get('seeds') is None and 0 < retention < nzb.get('age', 0): log.info('Wrong: Outside retention, age is %s, needs %s or lower: %s', (nzb['age'], retention, nzb['name'])) return False From 39c2567d5abb6cc01c70a7d0bfebf57ebe464d20 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:11:19 +0200 Subject: [PATCH 20/41] Also listen to search ended per movie. --- couchpotato/core/plugins/movie/static/movie.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index f5cd41e..78b9dc9 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -30,6 +30,11 @@ var Movie = new Class({ self.busy(true) }); }) + + App.addEvent('searcher.ended.'+self.data.id, function(notification){ + if(notification.data) + self.busy(false) + }); }, destroy: function(){ From 3da0b1a80410ebe166e9089d54c48c0e94dc9620 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:12:03 +0200 Subject: [PATCH 21/41] Let user know to report weird errors --- couchpotato/core/plugins/searcher/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 5bf7aeb..41ae0d9 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -65,6 +65,7 @@ class Searcher(Plugin): try: self.single(movie_dict) except IndexError: + log.error('Forcing library update for %s, if you see this often, please report: %s', (movie_dict['library']['identifier'], traceback.format_exc())) fireEvent('library.update', movie_dict['library']['identifier'], force = True) except: log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) From ed0e54d64dbecda13ae704f9841e282c8f1da7fd Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 20:59:03 +0200 Subject: [PATCH 22/41] Add force full search options to wanted list --- couchpotato/core/plugins/movie/static/movie.css | 2 +- couchpotato/core/plugins/searcher/main.py | 36 +++++++++++++++++- couchpotato/static/scripts/page/wanted.js | 49 ++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/movie.css b/couchpotato/core/plugins/movie/static/movie.css index f809c57..0979ccf 100644 --- a/couchpotato/core/plugins/movie/static/movie.css +++ b/couchpotato/core/plugins/movie/static/movie.css @@ -534,5 +534,5 @@ } .movies .alph_nav .more_menu > a { - background-position: center -157px; + background-position: center -158px; } diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 41ae0d9..76ee24d 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -1,6 +1,6 @@ from couchpotato import get_session from couchpotato.api import addApiView -from couchpotato.core.event import addEvent, fireEvent +from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import simplifyString, toUnicode from couchpotato.core.helpers.request import jsonified, getParam from couchpotato.core.helpers.variable import md5, getTitle @@ -36,9 +36,35 @@ class Searcher(Plugin): }, }) + addApiView('searcher.full_search', self.allMoviesView, docs = { + 'desc': 'Starts a full search for all wanted movies', + }) + + addApiView('searcher.progress', self.getProgress, docs = { + 'desc': 'Get the progress of current full search', + }) + # Schedule cronjob fireEvent('schedule.cron', 'searcher.all', self.allMovies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) + def allMoviesView(self): + + in_progress = self.in_progress + if not in_progress: + fireEventAsync('searcher.all') + fireEvent('notify.frontend', type = 'searcher.started', data = True, message = 'Full search started') + else: + fireEvent('notify.frontend', type = 'searcher.already_started', data = True, message = 'Full search already in progress') + + return jsonified({ + 'success': not in_progress + }) + + def getProgress(self): + + return jsonified({ + 'progress': self.in_progress + }) def allMovies(self): @@ -54,6 +80,11 @@ class Searcher(Plugin): Movie.status.has(identifier = 'active') ).all() + self.in_progress = { + 'total': len(movies), + 'to_go': len(movies), + } + for movie in movies: movie_dict = movie.to_dict({ 'profile': {'types': {'quality': {}}}, @@ -70,6 +101,9 @@ class Searcher(Plugin): except: log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) + self.in_progress['to_go'] -= 1 + time.sleep(10) + # Break if CP wants to shut down if self.shuttingDown(): break diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index a50b1bd..6974324 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -10,16 +10,63 @@ Page.Wanted = new Class({ if(!self.wanted){ + 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) + } + }); + // Wanted movies self.wanted = new MovieList({ 'identifier': 'wanted', 'status': 'active', 'actions': MovieActions, - 'add_new': true + 'add_new': true, + 'menu': [self.manual_search] }); $(self.wanted).inject(self.el); + + // Check if search is in progress + self.startProgressInterval(); + } + + }, + + doFullSearch: function(full){ + var self = this; + + if(!self.search_in_progress){ + + Api.request('searcher.full_search'); + self.startProgressInterval(); + } + }, + + startProgressInterval: function(){ + var self = this; + + var start_text = self.manual_search.get('text'); + self.progress_interval = setInterval(function(){ + Api.request('searcher.progress', { + 'onComplete': function(json){ + self.search_in_progress = true; + if(!json.progress){ + clearInterval(self.progress_interval); + self.search_in_progress = false; + self.manual_search.set('text', start_text); + } + else { + var progress = json.progress; + self.manual_search.set('text', 'Searching.. (' + (((progress.total-progress.to_go)/progress.total)*100).round() + '%)'); + } + } + }) + }, 1000); + } }); From 86bf08cbd4ffa3234c87de95e613f028e8fbcddf Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 21:01:48 +0200 Subject: [PATCH 23/41] Add documentation to progress api --- couchpotato/core/plugins/searcher/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 76ee24d..f165f6a 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -42,6 +42,9 @@ class Searcher(Plugin): addApiView('searcher.progress', self.getProgress, docs = { 'desc': 'Get the progress of current full search', + 'return': {'type': 'object', 'example': """{ + 'progress': False || object, total & to_go, +}"""}, }) # Schedule cronjob From 2ac2b0ff0603df2300f5b9c6a5656c6b1add63fa Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Sep 2012 21:12:14 +0200 Subject: [PATCH 24/41] Remove debug sleep --- couchpotato/core/plugins/searcher/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index f165f6a..03dfd70 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -105,7 +105,6 @@ class Searcher(Plugin): log.error('Search failed for %s: %s', (movie_dict['library']['identifier'], traceback.format_exc())) self.in_progress['to_go'] -= 1 - time.sleep(10) # Break if CP wants to shut down if self.shuttingDown(): From 0e23413069074bc018ef4c1fc2e2e4bb2a0719ef Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 27 Sep 2012 08:39:07 +0200 Subject: [PATCH 25/41] Mark movie snatched on manual download --- couchpotato/core/plugins/movie/static/movie.js | 32 ++++++++++++++++---------- couchpotato/core/plugins/release/main.py | 5 ++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index 78b9dc9..bb081cd 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -421,19 +421,11 @@ var ReleaseAction = new Class({ var status = Status.get(release.status_id), quality = Quality.getProfile(release.quality_id) || {}, info = release.info; - - if( status.identifier == 'ignored' || status.identifier == 'failed'){ - self.last_release = release; - } - else if(!self.next_release && status.identifier == 'available'){ - self.next_release = release; - } + release.status = status; // Create release new Element('div', { - 'class': 'item '+status.identifier + - (self.next_release && self.next_release.id == release.id ? ' next_release' : '') + - (self.last_release && self.last_release.id == release.id ? ' last_release' : ''), + 'class': 'item '+status.identifier, 'id': 'release_'+release.id }).adopt( new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}), @@ -466,11 +458,27 @@ var ReleaseAction = new Class({ } }) ).inject(self.release_container) + + if(status.identifier == 'ignored' || status.identifier == 'failed' || status.identifier == 'snatched'){ + if(!self.last_release || (self.last_release && self.last_release.status.identifier != 'snatched' && status.identifier == 'snatched')) + self.last_release = release; + } + else if(!self.next_release && status.identifier == 'available'){ + self.next_release = release; + } }); + + if(self.last_release){ + self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release'); + } + + if(self.next_release){ + self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release'); + } self.trynext_container.adopt( new Element('span.or', { - 'text': 'Download' + 'text': 'This movie is snatched, if anything went wrong, download' }), self.last_release ? new Element('a.button.orange', { 'text': 'the same release again', @@ -479,7 +487,7 @@ var ReleaseAction = new Class({ } }) : null, self.next_release && self.last_release ? new Element('span.or', { - 'text': 'or' + 'text': ',' }) : null, self.next_release ? [new Element('a.button.green', { 'text': self.last_release ? 'another release' : 'the best release', diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 9046034..9e945a8 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -161,6 +161,7 @@ class Release(Plugin): db = get_session() id = getParam('id') + status_snatched = fireEvent('status.add', 'snatched', single = True) rel = db.query(Relea).filter_by(id = id).first() if rel: @@ -181,6 +182,10 @@ class Release(Plugin): 'files': {} }), manual = True, single = True) + if success: + rel.status_id = status_snatched.get('id') + db.commit() + #db.close() return jsonified({ 'success': success From ce0bf7b51ac851387430546c53e4eac037355a41 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 28 Sep 2012 13:10:58 +0200 Subject: [PATCH 26/41] Standardized checking snatched --- couchpotato/core/downloaders/base.py | 27 +----- couchpotato/core/downloaders/sabnzbd/main.py | 130 ++++++++++++++------------- couchpotato/core/helpers/variable.py | 12 ++- couchpotato/core/plugins/base.py | 19 +++- couchpotato/core/plugins/renamer/main.py | 127 +++++++++++++------------- 5 files changed, 164 insertions(+), 151 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 6ca29f6..776976d 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -1,10 +1,7 @@ from base64 import b32decode, b16encode from couchpotato.core.event import addEvent -from couchpotato.core.helpers.encoding import toSafeString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin -from couchpotato.environment import Env -import os import random import re @@ -23,34 +20,18 @@ class Downloader(Plugin): def __init__(self): addEvent('download', self.download) - addEvent('download.status', self.getDownloadStatus) - addEvent('download.remove', self.remove) + addEvent('download.status', self.getAllDownloadStatus) + addEvent('download.remove_failed', self.removeFailed) def download(self, data = {}, movie = {}, manual = False, filedata = None): pass - def getDownloadStatus(self, data = {}, movie = {}): + def getAllDownloadStatus(self): return False - def remove(self, name = {}, nzo_id = {}): + def removeFailed(self, name = {}, nzo_id = {}): return False - def createNzbName(self, data, movie): - tag = self.cpTag(movie) - return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) - - def createFileName(self, data, filedata, movie): - name = os.path.join(self.createNzbName(data, movie)) - if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: - return '%s.%s' % (name, 'rar') - return '%s.%s' % (name, data.get('type')) - - def cpTag(self, movie): - if Env.setting('enabled', 'renamer'): - return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else '' - - return '' - def isCorrectType(self, item_type): is_correct = item_type in self.type diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index f05f0d5..eaf91b5 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -1,6 +1,6 @@ from couchpotato.core.downloaders.base import Downloader from couchpotato.core.helpers.encoding import tryUrlencode -from couchpotato.core.helpers.variable import cleanHost +from couchpotato.core.helpers.variable import cleanHost, mergeDicts from couchpotato.core.logger import CPLog import json import traceback @@ -63,86 +63,92 @@ class Sabnzbd(Downloader): log.error("Unknown error: " + result[:40]) return False - def getDownloadStatus(self, data = {}, movie = {}): - if self.isDisabled(manual = True) or not self.isCorrectType(data.get('type')): - return + def getAllDownloadStatus(self): + if self.isDisabled(manual = False): + return False - log.info('Checking SABnzbd download status.') + log.debug('Checking SABnzbd download status.') # Go through Queue - params = { - 'apikey': self.conf('api_key'), - 'mode': 'queue', - 'output': 'json' - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) - try: - sab = self.urlopen(url, timeout = 60, show_error = False) + queue = self.call({ + 'mode': 'queue', + }) except: - log.error('Failed checking status: %s', traceback.format_exc()) + log.error('Failed getting queue: %s', traceback.format_exc()) return False + # Go through history items try: - queue = json.loads(sab) + history = self.call({ + 'mode': 'history', + 'limit': 15, + }) except: - log.debug("Result text from SAB: " + sab[:40]) - log.error('Failed parsing json status: %s', traceback.format_exc()) + log.error('Failed getting history json: %s', traceback.format_exc()) return False - # Go through history items - params = { - 'apikey': self.conf('api_key'), - 'mode': 'history', - 'limit': 15, - 'output': 'json' - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + statuses = [] - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed getting history: %s', traceback.format_exc()) - return False + # Get busy releases + for item in queue.get('slots', []): + statuses.append({ + 'id': item['nzo_id'], + 'name': item['filename'], + 'status': 'busy', + 'original_status': item['status'], + 'timeleft': item['timeleft'] if not queue['paused'] else -1, + }) - try: - history = json.loads(sab) - except: - log.debug("Result text from SAB: " + sab[:40]) - log.error('Failed parsing history json: %s', traceback.format_exc()) - return False + # Get old releases + for item in history.get('slots', []): + + status = 'busy' + if item['status'] == 'Failed' or (item['status'] == 'Completed' and item['fail_message'].strip()): + status = 'failed' + elif item['status'] == 'Completed': + status = 'completed' - return queue, history + statuses.append({ + 'id': item['nzo_id'], + 'name': item['name'], + 'status': status, + 'original_status': item['status'], + 'timeleft': 0, + }) - def remove(self, name = {}, nzo_id = {}): - # Delete failed download - if self.conf('delete_failed', default = True): + return statuses - log.info('%s failed downloading, deleting...', name) - params = { - 'apikey': self.conf('api_key'), + def removeFailed(self, item): + + if not self.conf('delete_failed', default = True): + return False + + log.info('%s failed downloading, deleting...', item['name']) + + try: + self.call({ 'mode': 'history', 'name': 'delete', 'del_files': '1', - 'value': nzo_id - } - url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + 'value': item['id'] + }, use_json = False) + except: + log.error('Failed deleting: %s', traceback.format_exc()) + return False - try: - sab = self.urlopen(url, timeout = 60, show_error = False) - except: - log.error('Failed deleting: %s', traceback.format_exc()) - return False + return True - result = sab.strip() - if not result: - log.error("SABnzbd didn't return anything.") + def call(self, params, use_json = True): + + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(mergeDicts(params, { + 'apikey': self.conf('api_key'), + 'output': 'json' + })) + + data = self.urlopen(url, timeout = 60, show_error = False) + if use_json: + return json.loads(data)[params['mode']] + else: + return data - log.debug("Result text from SAB: " + result[:40]) - if result == "ok": - log.info('SabNZBd deleted failed release %s successfully.', name) - elif result == "Missing authentication": - log.error("Incorrect username/password or API?.") - else: - log.error("Unknown error: " + result[:40]) - return diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 5312177..2578d2c 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -118,8 +118,16 @@ def getTitle(library_dict): try: return library_dict['titles'][0]['title'] except: - log.error('Could not get title for %s', library_dict['identifier']) - return None + try: + for title in library_dict.titles: + if title.default: + return title.title + except: + log.error('Could not get title for %s', library_dict.identifier) + return None + + log.error('Could not get title for %s', library_dict['identifier']) + return None except: log.error('Could not get title for library item: %s', library_dict) return None diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 40189ef..8a1e076 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -1,7 +1,8 @@ from StringIO import StringIO from couchpotato import addView from couchpotato.core.event import fireEvent, addEvent -from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss +from couchpotato.core.helpers.encoding import tryUrlencode, simplifyString, ss, \ + toSafeString from couchpotato.core.helpers.variable import getExt from couchpotato.core.logger import CPLog from couchpotato.environment import Env @@ -245,6 +246,22 @@ class Plugin(object): Env.get('cache').set(cache_key, value, timeout) return value + def createNzbName(self, data, movie): + tag = self.cpTag(movie) + return '%s%s' % (toSafeString(data.get('name')[:127 - len(tag)]), tag) + + def createFileName(self, data, filedata, movie): + name = os.path.join(self.createNzbName(data, movie)) + if data.get('type') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: + return '%s.%s' % (name, 'rar') + return '%s.%s' % (name, data.get('type')) + + def cpTag(self, movie): + if Env.setting('enabled', 'renamer'): + return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else '' + + return '' + def isDisabled(self): return not self.isEnabled() diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 2f57911..1b72229 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -20,6 +20,7 @@ log = CPLog(__name__) class Renamer(Plugin): renaming_started = False + checking_snatched = False def __init__(self): @@ -33,6 +34,7 @@ class Renamer(Plugin): addEvent('app.load', self.scan) fireEvent('schedule.interval', 'renamer.check_snatched', self.checkSnatched, minutes = self.conf('run_every')) + fireEvent('schedule.interval', 'renamer.check_snatched_forced', self.scan, hours = 2) def scanView(self): @@ -495,6 +497,11 @@ class Renamer(Plugin): loge('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc())) def checkSnatched(self): + if self.checking_snatched: + log.debug('Already checking snatched') + + self.checking_snatched = True + snatched_status = fireEvent('status.get', 'snatched', single = True) ignored_status = fireEvent('status.get', 'ignored', single = True) failed_status = fireEvent('status.get', 'failed', single = True) @@ -504,81 +511,75 @@ class Renamer(Plugin): db = get_session() rels = db.query(Release).filter_by(status_id = snatched_status.get('id')).all() + scan_required = False + if rels: + self.checking_snatched = True log.debug('Checking status snatched releases...') # get queue and history (once) from SABnzbd - queue, history = fireEvent('download.status', data = {}, movie = {}, single = True) + statuses = fireEvent('download.status', merge = True) + if not statuses: + log.debug('Download status functionality is not implemented for active downloaders.') + scan_required = True - scan_required = False - - for rel in rels: - - # Get current selected title - default_title = '' - for title in rel.movie.library.titles: - if title.default: default_title = title.title - - # Check if movie has already completed and is manage tab (legacy db correction) - if rel.movie.status_id == done_status.get('id'): - log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) - rel.status_id = ignored_status.get('id') - db.commit() - continue + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) - item = {} - for info in rel.info: - item[info.identifier] = info.value + # Get current selected title + default_title = getTitle(rel.movie.library) - movie_dict = fireEvent('movie.get', rel.movie_id, single = True) + # Check if movie has already completed and is manage tab (legacy db correction) + if rel.movie.status_id == done_status.get('id'): + log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) + rel.status_id = ignored_status.get('id') + db.commit() + continue - # check status - nzbname = self.createNzbName(item, movie_dict) - try: - for slot in queue['queue']['slots']: - log.debug('Found %s in SabNZBd queue, which is %s, with %s left', (slot['filename'], slot['status'], slot['timeleft'])) - if slot['filename'] == nzbname: - downloadstatus =['status'].lower() - except: - log.debug('No items in queue: %s', (traceback.format_exc())) - try: - for slot in history['history']['slots']: - log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) - if slot['name'] == nzbname: - # Note: if post process even if failed is on in SabNZBd, it will complete with a fail message - if slot['status'] == 'Failed' or (slot['status'] == 'Completed' and slot['fail_message'].strip()): - - # Delete failed download - rel_remove = fireEvent('download.remove', name = slot['name'], nzo_id = slot['nzo_id'], single = True) - downloadstatus = 'failed' - else: - downloadstatus = slot['status'].lower() - except: - log.debug('No items in history: %s', (traceback.format_exc())) + movie_dict = fireEvent('movie.get', rel.movie_id, single = True) - if not downloadstatus: - log.debug('Download status functionality is not implemented for active downloaders.') - scan_required = True - else: - log.debug('Download status: %s' , downloadstatus) + # check status + nzbname = self.createNzbName(rel_dict['info'], movie_dict) - if downloadstatus == 'failed': - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - else: - rel.status_id = failed_status.get('id') - db.commit() + found = False + for item in statuses: + if item['name'] == nzbname: + + timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] + log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) - log.info('Download of %s failed.', item['name']) + if item['status'] == 'busy': + pass + elif item['status'] == 'failed': + if item['delete']: + fireEvent('download.remove_failed', item, single = True) - elif downloadstatus == 'completed': - log.info('Download of %s completed!', item['name']) - scan_required = True + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + else: + rel.status_id = failed_status.get('id') + db.commit() + elif item['status'] == 'completed': + log.info('Download of %s completed!', item['name']) + scan_required = True - elif downloadstatus == 'not_found': - log.info('%s not found in downloaders', item['name']) - rel.status_id = ignored_status.get('id') - db.commit() + found = True + break + + if not found: + log.info('%s not found in downloaders', nzbname) + rel.status_id = ignored_status.get('id') + db.commit() + + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + + except: + log.error('Failed checking for release in downloader: %s', traceback.format_exc()) - # Note that Queued, Downloading, Paused, Repair and Unpackimg are also available as status for SabNZBd if scan_required: fireEvent('renamer.scan') + + self.checking_snatched = False + + return True From 9184a97fcdf22a0bd50dfe83c01c9094a12f5da8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 15:56:51 +0200 Subject: [PATCH 27/41] Don't loop over releases when download doesn't support check snatched. fix #887 --- couchpotato/core/plugins/renamer/main.py | 104 +++++++++++++++---------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 1b72229..87bcad6 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -521,61 +521,61 @@ class Renamer(Plugin): if not statuses: log.debug('Download status functionality is not implemented for active downloaders.') scan_required = True + else: + try: + for rel in rels: + rel_dict = rel.to_dict({'info': {}}) + + # Get current selected title + default_title = getTitle(rel.movie.library) + + # Check if movie has already completed and is manage tab (legacy db correction) + if rel.movie.status_id == done_status.get('id'): + log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) + rel.status_id = ignored_status.get('id') + db.commit() + continue + + movie_dict = fireEvent('movie.get', rel.movie_id, single = True) + + # check status + nzbname = self.createNzbName(rel_dict['info'], movie_dict) + + found = False + for item in statuses: + if item['name'] == nzbname: + + timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] + log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) + + if item['status'] == 'busy': + pass + elif item['status'] == 'failed': + if item['delete']: + fireEvent('download.remove_failed', item, single = True) + + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + else: + rel.status_id = failed_status.get('id') + db.commit() + elif item['status'] == 'completed': + log.info('Download of %s completed!', item['name']) + scan_required = True + + found = True + break - try: - for rel in rels: - rel_dict = rel.to_dict({'info': {}}) - - # Get current selected title - default_title = getTitle(rel.movie.library) - - # Check if movie has already completed and is manage tab (legacy db correction) - if rel.movie.status_id == done_status.get('id'): - log.debug('Found a completed movie with a snatched release : %s. Setting release status to ignored...' , default_title) - rel.status_id = ignored_status.get('id') - db.commit() - continue - - movie_dict = fireEvent('movie.get', rel.movie_id, single = True) - - # check status - nzbname = self.createNzbName(rel_dict['info'], movie_dict) - - found = False - for item in statuses: - if item['name'] == nzbname: - - timeleft = 'N/A' if item['timeleft'] == -1 else item['timeleft'] - log.debug('Found %s: %s, time to go: %s', (item['name'], item['status'].upper(), timeleft)) - - if item['status'] == 'busy': - pass - elif item['status'] == 'failed': - if item['delete']: - fireEvent('download.remove_failed', item, single = True) - - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - else: - rel.status_id = failed_status.get('id') - db.commit() - elif item['status'] == 'completed': - log.info('Download of %s completed!', item['name']) - scan_required = True - - found = True - break - - if not found: - log.info('%s not found in downloaders', nzbname) - rel.status_id = ignored_status.get('id') - db.commit() + if not found: + log.info('%s not found in downloaders', nzbname) + rel.status_id = ignored_status.get('id') + db.commit() - if self.conf('next_on_failed'): - fireEvent('searcher.try_next_release', movie_id = rel.movie_id) + if self.conf('next_on_failed'): + fireEvent('searcher.try_next_release', movie_id = rel.movie_id) - except: - log.error('Failed checking for release in downloader: %s', traceback.format_exc()) + except: + log.error('Failed checking for release in downloader: %s', traceback.format_exc()) if scan_required: fireEvent('renamer.scan') From d38bd03422cabbf6518eaa5833c8ce2187e9bcad Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:15:47 +0200 Subject: [PATCH 28/41] Use finish by default when adding new type --- couchpotato/core/plugins/profile/static/profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 947da1d..3bb4498 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -242,7 +242,7 @@ Profile.Type = new Class({ ), new Element('span.finish').adopt( self.finish = new Element('input.inlay.finish[type=checkbox]', { - 'checked': data.finish, + 'checked': data.finish !== undefined ? data.finish : 1, 'events': { 'change': function(e){ if(self.el == self.el.getParent().getElement(':first-child')){ From a3b3b9c2189336a77c2f523f6b1479c2ab1a4c47 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:33:51 +0200 Subject: [PATCH 29/41] Don't use cached in_wanted when re-adding movie --- couchpotato/core/plugins/movie/static/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/movie/static/search.js b/couchpotato/core/plugins/movie/static/search.js index 63cab34..2115ef4 100644 --- a/couchpotato/core/plugins/movie/static/search.js +++ b/couchpotato/core/plugins/movie/static/search.js @@ -339,7 +339,7 @@ Block.Search.Item = new Class({ 'height': null, 'width': null }) : null, - self.info.in_wanted ? new Element('span.in_wanted', { + self.info.in_wanted && self.info.in_wanted.profile ? new Element('span.in_wanted', { 'text': 'Already in wanted list: ' + self.info.in_wanted.profile.label }) : (in_library ? new Element('span.in_library', { 'text': 'Already in library: ' + in_library.join(', ') From 50a2bca4593d88d3fef05cb41b328e408a92f551 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 30 Sep 2012 17:34:09 +0200 Subject: [PATCH 30/41] Don't open releases when all are ignored --- couchpotato/core/plugins/movie/static/movie.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index bb081cd..b406e4e 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -383,7 +383,7 @@ var ReleaseAction = new Class({ var status = Status.get(release.status_id); - if((status.identifier == 'ignored' || status.identifier == 'failed') || (!self.next_release && status.identifier == 'available')){ + if((self.next_release && (status.identifier == 'ignored' || status.identifier == 'failed')) || (!self.next_release && status.identifier == 'available')){ self.hide_on_click = false; self.show(); buttons_done = true; From 7f90135947082c99507562e338cf9f463d10ba6a Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 2 Oct 2012 22:16:21 +0200 Subject: [PATCH 31/41] checksnatched debug code leftover. fix #892 --- couchpotato/core/plugins/renamer/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 87bcad6..9e37236 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -551,8 +551,7 @@ class Renamer(Plugin): if item['status'] == 'busy': pass elif item['status'] == 'failed': - if item['delete']: - fireEvent('download.remove_failed', item, single = True) + fireEvent('download.remove_failed', item, single = True) if self.conf('next_on_failed'): fireEvent('searcher.try_next_release', movie_id = rel.movie_id) From 799b665f15d93072fea2f9860ec640fe0fc5a4e8 Mon Sep 17 00:00:00 2001 From: Tristan Fischer Date: Tue, 9 Oct 2012 00:18:31 +0300 Subject: [PATCH 32/41] fix audio scoring The elements of name_scores are compared to a lower-cased version of the release name so they need to be also lower cased. --- couchpotato/core/plugins/score/scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/score/scores.py b/couchpotato/core/plugins/score/scores.py index 385e3a9..8afa129 100644 --- a/couchpotato/core/plugins/score/scores.py +++ b/couchpotato/core/plugins/score/scores.py @@ -10,7 +10,7 @@ name_scores = [ # Video 'x264:1', 'h264:1', # Audio - 'DTS:4', 'AC3:2', + 'dts:4', 'ac3:2', # Quality '720p:10', '1080p:10', 'bluray:10', 'dvd:1', 'dvdrip:1', 'brrip:1', 'bdrip:1', 'bd50:1', 'bd25:1', # Language / Subs From 8874bd4e2b901a34d7fddd40effdf7086024df4e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 13:15:40 +0200 Subject: [PATCH 33/41] Wrongly assuming quality when no quality in the name. fix #901 --- couchpotato/core/plugins/searcher/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 03dfd70..80f2470 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -391,9 +391,11 @@ class Searcher(Plugin): year_name = fireEvent('scanner.name_year', name, single = True) if movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None): if size > 3000: # Assume dvdr - return 'dvdr' == preferred_quality['identifier'] + log.info('Quality was missing in name, assuming it\'s a DVD-R based on the size: %s', (size)) + found['dvdr'] = True else: # Assume dvdrip - return 'dvdrip' == preferred_quality['identifier'] + log.info('Quality was missing in name, assuming it\'s a DVD-Rip based on the size: %s', (size)) + found['dvdrip'] = True # Allow other qualities for allowed in preferred_quality.get('allow'): From 27635caa1db6a8e977cf07befb310cfaed466cc2 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 18:50:57 +0200 Subject: [PATCH 34/41] Simpler options for events --- couchpotato/core/event.py | 64 ++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index 8319150..4842aad 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -46,49 +46,29 @@ def fireEvent(name, *args, **kwargs): #log.debug('Firing event %s', name) try: - # Fire after event - is_after_event = False - try: - del kwargs['is_after_event'] - is_after_event = True - except: pass - - # onComplete event - on_complete = False - try: - on_complete = kwargs['on_complete'] - del kwargs['on_complete'] - except: pass - - # Return single handler - single = False - try: - del kwargs['single'] - single = True - except: pass - - # Merge items - merge = False - try: - del kwargs['merge'] - merge = True - except: pass - - # Merge items - in_order = False - try: - del kwargs['in_order'] - in_order = True - except: pass + options = { + 'is_after_event': False, # Fire after event + 'on_complete': False, # onComplete event + 'single': False, # Return single handler + 'merge': False, # Merge items + 'in_order': False, # Fire them in specific order, waits for the other to finish + } + + # Do options + for x in options: + try: + del kwargs[x] + options[x] = True + except: pass e = events[name] - if not in_order: e.lock.acquire() + if not options['in_order']: e.lock.acquire() e.asynchronous = False - e.in_order = in_order + e.in_order = options['in_order'] result = e(*args, **kwargs) - if not in_order: e.lock.release() + if not options['in_order']: e.lock.release() - if single and not merge: + if options['single'] and not options['merge']: results = None # Loop over results, stop when first not None result is found. @@ -112,7 +92,7 @@ def fireEvent(name, *args, **kwargs): errorHandler(r[1]) # Merge - if merge and len(results) > 0: + if options['merge'] and len(results) > 0: # Dict if type(results[0]) == dict: merged = {} @@ -133,11 +113,11 @@ def fireEvent(name, *args, **kwargs): log.debug('Return modified results for %s', name) results = modified_results - if not is_after_event: + if not options['is_after_event']: fireEvent('%s.after' % name, is_after_event = True) - if on_complete: - on_complete() + if options['on_complete']: + options['on_complete']() return results except KeyError, e: From f3e3632dd3327ac96e5837a99bbb83d150f5e904 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 18:52:44 +0200 Subject: [PATCH 35/41] Use less db.commits when adding quality and profiles. --- couchpotato/core/plugins/profile/main.py | 4 ++-- couchpotato/core/plugins/quality/main.py | 41 +++++++++++++++++--------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py index 76fb37c..64ee231 100644 --- a/couchpotato/core/plugins/profile/main.py +++ b/couchpotato/core/plugins/profile/main.py @@ -181,10 +181,10 @@ class ProfilePlugin(Plugin): ) p.types.append(profile_type) - db.commit() quality_order += 1 order += 1 - #db.close() + db.commit() + return True diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 84ac80a..eaeb600 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -9,6 +9,7 @@ from couchpotato.core.plugins.base import Plugin from couchpotato.core.settings.model import Quality, Profile, ProfileType import os.path import re +import time log = CPLog(__name__) @@ -113,46 +114,48 @@ class QualityPlugin(Plugin): for q in self.qualities: # Create quality - quality = db.query(Quality).filter_by(identifier = q.get('identifier')).first() + qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first() - if not quality: + if not qual: log.info('Creating quality: %s', q.get('label')) - quality = Quality() - db.add(quality) + qual = Quality() + qual.order = order + qual.identifier = q.get('identifier') + qual.label = toUnicode(q.get('label')) + qual.size_min, qual.size_max = q.get('size') - quality.order = order - quality.identifier = q.get('identifier') - quality.label = toUnicode(q.get('label')) - quality.size_min, quality.size_max = q.get('size') + db.add(qual) # Create single quality profile - profile = db.query(Profile).filter( + prof = db.query(Profile).filter( Profile.core == True ).filter( - Profile.types.any(quality = quality) + Profile.types.any(quality = qual) ).all() - if not profile: + if not prof: log.info('Creating profile: %s', q.get('label')) - profile = Profile( + prof = Profile( core = True, - label = toUnicode(quality.label), + label = toUnicode(qual.label), order = order ) - db.add(profile) + db.add(prof) profile_type = ProfileType( - quality = quality, - profile = profile, + quality = qual, + profile = prof, finish = True, order = 0 ) - profile.types.append(profile_type) + prof.types.append(profile_type) order += 1 - db.commit() - #db.close() + db.commit() + + time.sleep(0.3) # Wait a moment + return True def guess(self, files, extra = {}): From 378d1ccd1cbddde693daf2e578892edeeaf9755e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 19:03:44 +0200 Subject: [PATCH 36/41] Check if db exists before loading plugins --- couchpotato/runner.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 31a8ce3..569ff57 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -170,18 +170,17 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En log.warning('%s %s %s line:%s', (category, message, filename, lineno)) warnings.showwarning = customwarn + # Check if database exists + db = Env.get('db_path') + db_exists = os.path.isfile(db_path) # Load configs & plugins loader = Env.get('loader') loader.preload(root = base_path) loader.run() - # Load migrations - initialize = True - db = Env.get('db_path') - if os.path.isfile(db_path): - initialize = False + if db_exists: from migrate.versioning.api import version_control, db_version, version, upgrade repo = os.path.join(base_path, 'couchpotato', 'core', 'migration') @@ -201,7 +200,8 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En from couchpotato.core.settings.model import setup setup() - if initialize: + # Fill database with needed stuff + if not db_exists: fireEvent('app.initialize', in_order = True) # Create app From 269e98b0491e00b53beaf7c0ac1d092323f2fe49 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 19:09:57 +0200 Subject: [PATCH 37/41] Removed all commented out db.close --- couchpotato/core/notifications/core/main.py | 3 --- couchpotato/core/plugins/file/main.py | 2 -- couchpotato/core/plugins/library/main.py | 1 - couchpotato/core/plugins/profile/main.py | 6 ------ couchpotato/core/plugins/quality/main.py | 3 --- couchpotato/core/plugins/release/main.py | 6 ------ couchpotato/core/plugins/renamer/main.py | 1 - couchpotato/core/plugins/scanner/main.py | 1 - couchpotato/core/plugins/searcher/main.py | 3 --- couchpotato/core/plugins/subtitle/main.py | 2 -- couchpotato/core/providers/movie/_modifier/main.py | 1 - couchpotato/core/providers/movie/couchpotatoapi/main.py | 1 - couchpotato/core/settings/__init__.py | 2 -- 13 files changed, 32 deletions(-) diff --git a/couchpotato/core/notifications/core/main.py b/couchpotato/core/notifications/core/main.py index e0af50d..33f90d5 100644 --- a/couchpotato/core/notifications/core/main.py +++ b/couchpotato/core/notifications/core/main.py @@ -79,7 +79,6 @@ class CoreNotifier(Notification): q.update({Notif.read: True}) db.commit() - #db.close() return jsonified({ 'success': True @@ -107,7 +106,6 @@ class CoreNotifier(Notification): ndict['type'] = 'notification' notifications.append(ndict) - #db.close() return jsonified({ 'success': True, 'empty': len(notifications) == 0, @@ -133,7 +131,6 @@ class CoreNotifier(Notification): self.frontend(type = listener, data = data) - #db.close() return True def frontend(self, type = 'notification', data = {}, message = None): diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index 40427e4..0658911 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -109,7 +109,6 @@ class FileManager(Plugin): db.commit() type_dict = ft.to_dict() - #db.close() return type_dict def getTypes(self): @@ -122,5 +121,4 @@ class FileManager(Plugin): for type_object in results: types.append(type_object.to_dict()) - #db.close() return types diff --git a/couchpotato/core/plugins/library/main.py b/couchpotato/core/plugins/library/main.py index 95dda2f..aa1611d 100644 --- a/couchpotato/core/plugins/library/main.py +++ b/couchpotato/core/plugins/library/main.py @@ -53,7 +53,6 @@ class LibraryPlugin(Plugin): library_dict = l.to_dict(self.default_dict) - #db.close() return library_dict def update(self, identifier, default_title = '', force = False): diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py index 64ee231..4caa54f 100644 --- a/couchpotato/core/plugins/profile/main.py +++ b/couchpotato/core/plugins/profile/main.py @@ -47,7 +47,6 @@ class ProfilePlugin(Plugin): for profile in profiles: temp.append(profile.to_dict(self.to_dict)) - #db.close() return temp def save(self): @@ -84,7 +83,6 @@ class ProfilePlugin(Plugin): profile_dict = p.to_dict(self.to_dict) - #db.close() return jsonified({ 'success': True, 'profile': profile_dict @@ -95,7 +93,6 @@ class ProfilePlugin(Plugin): db = get_session() default = db.query(Profile).first() default_dict = default.to_dict(self.to_dict) - #db.close() return default_dict @@ -113,7 +110,6 @@ class ProfilePlugin(Plugin): order += 1 db.commit() - #db.close() return jsonified({ 'success': True @@ -137,8 +133,6 @@ class ProfilePlugin(Plugin): except Exception, e: message = log.error('Failed deleting Profile: %s', e) - #db.close() - return jsonified({ 'success': success, 'message': message diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index eaeb600..7964fb1 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -69,7 +69,6 @@ class QualityPlugin(Plugin): q = mergeDicts(self.getQuality(quality.identifier), quality.to_dict()) temp.append(q) - #db.close() return temp def single(self, identifier = ''): @@ -81,7 +80,6 @@ class QualityPlugin(Plugin): if quality: quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict()) - #db.close() return quality_dict def getQuality(self, identifier): @@ -101,7 +99,6 @@ class QualityPlugin(Plugin): setattr(quality, params.get('value_type'), params.get('value')) db.commit() - #db.close() return jsonified({ 'success': True }) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 9e945a8..8f40854 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -88,8 +88,6 @@ class Release(Plugin): fireEvent('movie.restatus', movie.id) - #db.close() - return True @@ -108,7 +106,6 @@ class Release(Plugin): release_id = getParam('id') - #db.close() return jsonified({ 'success': self.delete(release_id) }) @@ -152,7 +149,6 @@ class Release(Plugin): rel.status_id = available_status.get('id') if rel.status_id is ignored_status.get('id') else ignored_status.get('id') db.commit() - #db.close() return jsonified({ 'success': True }) @@ -186,14 +182,12 @@ class Release(Plugin): rel.status_id = status_snatched.get('id') db.commit() - #db.close() return jsonified({ 'success': success }) else: log.error('Couldn\'t find release with id: %s', id) - #db.close() return jsonified({ 'success': False }) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 9e37236..993575c 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -388,7 +388,6 @@ class Renamer(Plugin): if self.shuttingDown(): break - #db.close() self.renaming_started = False def getRenameExtras(self, extra_type = '', replacements = {}, folder_name = '', file_name = '', destination = '', group = {}, current_file = ''): diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index b22b626..4c639e2 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -542,7 +542,6 @@ class Scanner(Plugin): break except: pass - #db.close() # Search based on OpenSubtitleHash if not imdb_id and not group['is_dvd']: diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 80f2470..66a2e87 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -110,7 +110,6 @@ class Searcher(Plugin): if self.shuttingDown(): break - #db.close() self.in_progress = False def single(self, movie): @@ -229,7 +228,6 @@ class Searcher(Plugin): fireEvent('notify.frontend', type = 'searcher.ended.%s' % movie['id'], data = True) - #db.close() return ret def download(self, data, movie, manual = False): @@ -280,7 +278,6 @@ class Searcher(Plugin): except Exception, e: log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc())) - #db.close() return True log.info('Tried to download, but none of the downloaders are enabled') diff --git a/couchpotato/core/plugins/subtitle/main.py b/couchpotato/core/plugins/subtitle/main.py index 9ff39f4..3a66a8b 100644 --- a/couchpotato/core/plugins/subtitle/main.py +++ b/couchpotato/core/plugins/subtitle/main.py @@ -40,8 +40,6 @@ class Subtitle(Plugin): # get subtitles for those files subliminal.list_subtitles(files, cache_dir = Env.get('cache_dir'), multi = True, languages = self.getLanguages(), services = self.services) - #db.close() - def searchSingle(self, group): if self.isDisabled(): return diff --git a/couchpotato/core/providers/movie/_modifier/main.py b/couchpotato/core/providers/movie/_modifier/main.py index 5af1659..7346480 100644 --- a/couchpotato/core/providers/movie/_modifier/main.py +++ b/couchpotato/core/providers/movie/_modifier/main.py @@ -70,7 +70,6 @@ class MovieResultModifier(Plugin): except: log.error('Tried getting more info on searched movies: %s', traceback.format_exc()) - #db.close() return temp def checkLibrary(self, result): diff --git a/couchpotato/core/providers/movie/couchpotatoapi/main.py b/couchpotato/core/providers/movie/couchpotatoapi/main.py index 8e89048..5d6a35b 100644 --- a/couchpotato/core/providers/movie/couchpotatoapi/main.py +++ b/couchpotato/core/providers/movie/couchpotatoapi/main.py @@ -94,7 +94,6 @@ class CouchPotatoApi(MovieProvider): db = get_session() active_movies = db.query(Movie).filter(Movie.status.has(identifier = 'active')).all() movies = [x.library.identifier for x in active_movies] - #db.close() suggestions = self.suggest(movies, ignore) diff --git a/couchpotato/core/settings/__init__.py b/couchpotato/core/settings/__init__.py index c530a27..366a101 100644 --- a/couchpotato/core/settings/__init__.py +++ b/couchpotato/core/settings/__init__.py @@ -204,7 +204,6 @@ class Settings(object): except: pass - #db.close() return prop def setProperty(self, identifier, value = ''): @@ -221,4 +220,3 @@ class Settings(object): p.value = toUnicode(value) db.commit() - #db.close() From ef6d0e04c0b977d18d8a60b7dc60d067b42af35d Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 21:04:49 +0200 Subject: [PATCH 38/41] Use event value --- couchpotato/core/event.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/event.py b/couchpotato/core/event.py index 4842aad..3a5b900 100644 --- a/couchpotato/core/event.py +++ b/couchpotato/core/event.py @@ -57,8 +57,9 @@ def fireEvent(name, *args, **kwargs): # Do options for x in options: try: + val = kwargs[x] del kwargs[x] - options[x] = True + options[x] = val except: pass e = events[name] From fef3eb1b84403dfb9662078c567e3b43c59ccc18 Mon Sep 17 00:00:00 2001 From: clinton-hall Date: Fri, 12 Oct 2012 13:29:41 -0700 Subject: [PATCH 39/41] Added replacement of uid and key for nzbsrus Prevent people posting log files with their account information --- couchpotato/core/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/logger.py b/couchpotato/core/logger.py index 8d8c9f5..7a357b3 100644 --- a/couchpotato/core/logger.py +++ b/couchpotato/core/logger.py @@ -5,7 +5,7 @@ import traceback class CPLog(object): context = '' - replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h'] + replace_private = ['api', 'apikey', 'api_key', 'password', 'username', 'h', 'uid', 'key'] def __init__(self, context = ''): if context.endswith('.main'): From 84f5dcc134115162b4ccdb5c9e28c53863de7f45 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 23:34:13 +0200 Subject: [PATCH 40/41] Wizard fix --- couchpotato/core/plugins/wizard/static/wizard.css | 6 +- couchpotato/core/plugins/wizard/static/wizard.js | 92 +++++++++++------------ couchpotato/static/scripts/couchpotato.js | 41 ++++++++++ 3 files changed, 89 insertions(+), 50 deletions(-) diff --git a/couchpotato/core/plugins/wizard/static/wizard.css b/couchpotato/core/plugins/wizard/static/wizard.css index dd73a65..a24f2b9 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.css +++ b/couchpotato/core/plugins/wizard/static/wizard.css @@ -76,4 +76,8 @@ margin: 10px 30px 80px; display: block; text-align: center; - } \ No newline at end of file + } + +.page.wizard .tab_nzb_providers { + margin: 20px 0 0 0; +} diff --git a/couchpotato/core/plugins/wizard/static/wizard.js b/couchpotato/core/plugins/wizard/static/wizard.js index a3fe938..5d087ad 100644 --- a/couchpotato/core/plugins/wizard/static/wizard.js +++ b/couchpotato/core/plugins/wizard/static/wizard.js @@ -41,7 +41,8 @@ Page.Wizard = new Class({ }, '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 a few more. Check settings for the full list of available providers.' + 'description': 'CP uses these sites to search for movies. A few free are enabled by default, but it\'s always better to have a few more. Check settings for the full list of available providers.', + 'include': ['nzb_providers', 'torrent_providers'] }, 'renamer': { 'title': 'Move & rename the movies after downloading?', @@ -49,59 +50,18 @@ Page.Wizard = new Class({ }, '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 userscript or drag the bookmarklet to your browsers bookmarks.' + + 'description': 'You can easily add movies from your favorite movie site, like IMDB, Rotten Tomatoes, Apple Trailers and more. Just install the userscript or drag the bookmarklet to your browsers bookmarks.' + '
Once installed, just click the bookmarklet on a movie page and watch the magic happen ;)', 'content': function(){ - - // See if userscript can be installed - var userscript = false; - try { - if(Components.interfaces.gmIGreasemonkeyService) - userscript = true - } - catch(e){ - userscript = Browser.chrome === true; - } - - var host_url = window.location.protocol + '//' + window.location.host; - - var el = new Element('div.group_userscript').adopt( - - (userscript ? [new Element('a.userscript.button', { - 'text': 'Install userscript', - 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', - 'target': '_self' - }), new Element('span.or[text=or]')] : null), - new Element('span.bookmarklet').adopt( - new Element('a.button.orange', { - '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' - }) - ) - ).setStyles({ + return App.createUserscriptButtons().setStyles({ 'background-image': "url('"+Api.createUrl('static/userscript/userscript.png')+"')" - }); - - return el + }) } }, 'finish': { 'title': 'Finishing Up', 'description': 'Are you done? Did you fill in everything as much as possible?' + - '
Be sure to check the settings to see what more CP can do!

' + + '
Be sure to check the settings to see what more CP can do!

' + '
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.
Or by getting a subscription at Usenet Server or Newshosting.
', 'content': new Element('div').adopt( new Element('a.button.green', { @@ -167,6 +127,7 @@ Page.Wizard = new Class({ var tabs = self.el.getElement('.tabs'); self.groups.each(function(group, nr){ + if(self.headers[group]){ group_container = new Element('.wgroup_'+group, { 'styles': { @@ -177,6 +138,12 @@ Page.Wizard = new Class({ } }); + 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', { @@ -190,10 +157,35 @@ Page.Wizard = new Class({ } 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){ - tab_navigation.inject(tabs); // Tab navigation - self.el.getElement('.tab_'+group).inject(group_container); // Tab content - if(self.headers[group]){ + tabs.adopt(tab_navigation); // 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).adopt( + 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); // Tab content + + 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('/'); @@ -221,6 +213,8 @@ Page.Wizard = new Class({ // Hide retention self.el.getElement('.tab_searcher').hide(); self.el.getElement('.t_searcher').hide(); + self.el.getElement('.t_nzb_providers').hide(); + self.el.getElement('.t_torrent_providers').hide(); // Add pointer new Element('.tab_wrapper').wraps(tabs).adopt( diff --git a/couchpotato/static/scripts/couchpotato.js b/couchpotato/static/scripts/couchpotato.js index 61ee45b..a94f5d4 100644 --- a/couchpotato/static/scripts/couchpotato.js +++ b/couchpotato/static/scripts/couchpotato.js @@ -281,6 +281,47 @@ var CouchPotato = new Class({ window.open(url); else window.location = url; + }, + + createUserscriptButtons: function(){ + + var userscript = false; + try { + if(Components.interfaces.gmIGreasemonkeyService) + userscript = true + } + catch(e){ + userscript = Browser.chrome === true; + } + + var host_url = window.location.protocol + '//' + window.location.host; + + return new Element('div.group_userscript').adopt( + (userscript ? [new Element('a.userscript.button', { + 'text': 'Install userscript', + 'href': Api.createUrl('userscript.get')+randomString()+'/couchpotato.user.js', + 'target': '_self' + }), new Element('span.or[text=or]')] : null), + new Element('span.bookmarklet').adopt( + new Element('a.button.orange', { + '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' + }) + ) + ); } }); From 1011e2e9b82ff8e2838174a21496977c8586802a Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 12 Oct 2012 23:34:39 +0200 Subject: [PATCH 41/41] Show "how to" when wanted list is empty --- couchpotato/core/plugins/movie/main.py | 6 ++++ couchpotato/core/plugins/movie/static/list.js | 37 +++++++++++++++++++++++++ couchpotato/core/plugins/movie/static/movie.js | 7 +++-- couchpotato/static/images/emptylist.png | Bin 0 -> 146717 bytes couchpotato/static/scripts/page/wanted.js | 12 +++++++- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 couchpotato/static/images/emptylist.png diff --git a/couchpotato/core/plugins/movie/main.py b/couchpotato/core/plugins/movie/main.py index a101606..d86b97c 100644 --- a/couchpotato/core/plugins/movie/main.py +++ b/couchpotato/core/plugins/movie/main.py @@ -431,9 +431,11 @@ class MoviePlugin(Plugin): movie = db.query(Movie).filter_by(id = movie_id).first() if movie: + deleted = False if delete_from == 'all': db.delete(movie) db.commit() + deleted = True else: done_status = fireEvent('status.get', 'done', single = True) @@ -456,6 +458,7 @@ class MoviePlugin(Plugin): if total_releases == total_deleted: db.delete(movie) db.commit() + deleted = True elif new_movie_status: new_status = fireEvent('status.get', new_movie_status, single = True) movie.profile_id = None @@ -464,6 +467,9 @@ class MoviePlugin(Plugin): else: fireEvent('movie.restatus', movie.id, single = True) + if deleted: + fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict()) + #db.close() return True diff --git a/couchpotato/core/plugins/movie/static/list.js b/couchpotato/core/plugins/movie/static/list.js index 0aff0bd..51b0f4c 100644 --- a/couchpotato/core/plugins/movie/static/list.js +++ b/couchpotato/core/plugins/movie/static/list.js @@ -35,6 +35,17 @@ var MovieList = new Class({ if(options.add_new) App.addEvent('movie.added', self.movieAdded.bind(self)) + + App.addEvent('movie.deleted', self.movieDeleted.bind(self)) + }, + + movieDeleted: function(notification){ + var self = this; + + if(!self.movies_added[notification.data.id]) + self.movies_added[notification.data.id].destroy(); + + self.checkIfEmpty(); }, movieAdded: function(notification){ @@ -43,6 +54,8 @@ var MovieList = new Class({ if(!self.movies_added[notification.data.id]) self.createMovie(notification.data, 'top'); + + self.checkIfEmpty(); }, create: function(){ @@ -460,6 +473,8 @@ var MovieList = new Class({ self.addMovies(json.movies, json.total); self.load_more.set('text', 'load more movies'); if(self.scrollspy) self.scrollspy.start(); + + self.checkIfEmpty() } }); }, @@ -477,6 +492,28 @@ var MovieList = new Class({ }, + checkIfEmpty: function(){ + var self = this; + + var is_empty = self.movies.length == 0; + + if(is_empty && self.options.on_empty_element){ + self.el.grab(self.options.on_empty_element); + + 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; } diff --git a/couchpotato/core/plugins/movie/static/movie.js b/couchpotato/core/plugins/movie/static/movie.js index b406e4e..b10b5b1 100644 --- a/couchpotato/core/plugins/movie/static/movie.js +++ b/couchpotato/core/plugins/movie/static/movie.js @@ -42,6 +42,9 @@ var Movie = new Class({ self.el.destroy(); delete self.list.movies_added[self.get('id')]; + self.list.movies.erase(self) + + self.list.checkIfEmpty(); // Remove events App.removeEvents('movie.update.'+self.data.id); @@ -467,11 +470,11 @@ var ReleaseAction = new Class({ self.next_release = release; } }); - + if(self.last_release){ self.release_container.getElement('#release_'+self.last_release.id).addClass('last_release'); } - + if(self.next_release){ self.release_container.getElement('#release_'+self.next_release.id).addClass('next_release'); } diff --git a/couchpotato/static/images/emptylist.png b/couchpotato/static/images/emptylist.png new file mode 100644 index 0000000000000000000000000000000000000000..08db6537361c9c3db791bd153dd7c2339162f697 GIT binary patch literal 146717 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π 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%0ADi9& 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