diff --git a/couchpotato/core/downloaders/sabnzbd/__init__.py b/couchpotato/core/downloaders/sabnzbd/__init__.py
index 470a2f4..4d49c4d 100644
--- a/couchpotato/core/downloaders/sabnzbd/__init__.py
+++ b/couchpotato/core/downloaders/sabnzbd/__init__.py
@@ -26,6 +26,12 @@ config = [{
'label': 'Api Key',
'description': 'Used for all calls to Sabnzbd.',
},
+ {
+ 'advanced': True,
+ 'name': 'pp_directory',
+ 'type': 'directory',
+ 'description': 'Your Post-Processing Script directory, set in Sabnzbd > Config > Directories.',
+ },
],
}
],
diff --git a/couchpotato/core/notifications/base.py b/couchpotato/core/notifications/base.py
index d45c085..ea577ab 100644
--- a/couchpotato/core/notifications/base.py
+++ b/couchpotato/core/notifications/base.py
@@ -14,12 +14,6 @@ class Notification(Plugin):
def notify(self, message = '', data = {}):
pass
- def isDisabled(self):
- return not self.isEnabled()
-
- def isEnabled(self):
- return self.conf('enabled', True)
-
def test(self):
success = self.notify(message = self.test_message)
diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py
index 8b4484a..3c2bfe6 100644
--- a/couchpotato/core/plugins/base.py
+++ b/couchpotato/core/plugins/base.py
@@ -7,7 +7,10 @@ import os.path
class Plugin():
def conf(self, attr):
- return Env.setting(attr, self.__class__.__name__.lower())
+ return Env.setting(attr, self.getName().lower())
+
+ def getName(self):
+ return self.__class__.__name__
def registerStatic(self, file_path):
@@ -25,3 +28,9 @@ class Plugin():
dir = os.path.join(plugin_dir, 'static')
return send_from_directory(dir, file)
+
+ def isDisabled(self):
+ return not self.isEnabled()
+
+ def isEnabled(self):
+ return self.conf('enabled', True)
diff --git a/couchpotato/core/plugins/renamer/__init__.py b/couchpotato/core/plugins/renamer/__init__.py
index 49296d4..5d8aa22 100644
--- a/couchpotato/core/plugins/renamer/__init__.py
+++ b/couchpotato/core/plugins/renamer/__init__.py
@@ -1,33 +1,42 @@
+from couchpotato.core.plugins.renamer.main import Renamer
+
def start():
- pass
+ return Renamer()
-#config = [{
-# 'name': 'Renamer',
-# 'tab': 'renaming',
-# 'options': {
-# 'enabled': {
-# 'default': False,
-# 'type': 'bool',
-# 'description': 'Enable renaming',
-# },
-# 'from': {
-# 'default': '',
-# 'type': 'directory',
-# 'label': 'From',
-# 'description': 'Folder where the movies are downloaded to.',
-# },
-# 'to': {
-# 'default': '',
-# 'type': 'directory',
-# 'label': 'To',
-# 'description': 'Folder where the movies will be moved to.',
-# },
-# 'run_every': {
-# 'default': 1,
-# 'type': 'int',
-# 'unit': 'min(s)',
-# 'description': 'Search for new movies inside the folder every X minutes.',
-# }
-# }
-#}]
-config = []
+config = [{
+ 'name': 'renamer',
+ 'groups': [
+ {
+ 'tab': 'renamer',
+ 'name': 'tmdb',
+ 'label': 'TheMovieDB',
+ 'advanced': True,
+ 'description': 'Move and rename your downloaded movies to your movie directory.',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'default': False,
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'from',
+ 'type': 'directory',
+ 'description': 'Folder where the movies are downloaded to.',
+ },
+ {
+ 'name': 'to',
+ 'type': 'directory',
+ 'description': 'Folder where the movies will be moved to.',
+ },
+ {
+ 'name': 'run_every',
+ 'label': 'Run every',
+ 'default': 1,
+ 'type': 'int',
+ 'unit': 'min(s)',
+ 'description': 'Search for new movies inside the folder every X minutes.',
+ }
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py
new file mode 100644
index 0000000..5576178
--- /dev/null
+++ b/couchpotato/core/plugins/renamer/main.py
@@ -0,0 +1,10 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.plugins.base import Plugin
+
+log = CPLog(__name__)
+
+
+class Renamer(Plugin):
+
+ def __init__(self):
+ pass
diff --git a/couchpotato/core/providers/base.py b/couchpotato/core/providers/base.py
index 23e15eb..7367bf2 100644
--- a/couchpotato/core/providers/base.py
+++ b/couchpotato/core/providers/base.py
@@ -8,3 +8,25 @@ class Provider(Plugin):
type = None # movie, nzb, torrent, subtitle, trailer
timeout = 10 # Default timeout for url requests
+
+
+class MovieProvider(Provider):
+ type = 'movie'
+
+
+class NZBProvider(Provider):
+ type = 'nzb'
+
+ time_between_searches = 10 # Seconds
+
+
+class TorrentProvider(Provider):
+ type = 'torrent'
+
+
+class SubtitleProvider(Provider):
+ type = 'subtitle'
+
+
+class TrailerProvider(Provider):
+ type = 'trailer'
diff --git a/couchpotato/core/providers/imdb/main.py b/couchpotato/core/providers/imdb/main.py
index 2d330c0..3eb7cac 100644
--- a/couchpotato/core/providers/imdb/main.py
+++ b/couchpotato/core/providers/imdb/main.py
@@ -1,14 +1,12 @@
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
-from couchpotato.core.providers.base import Provider
+from couchpotato.core.providers.base import MovieProvider
from imdb import IMDb
log = CPLog(__name__)
-class IMDB(Provider):
-
- type = 'movie'
+class IMDB(MovieProvider):
def __init__(self):
diff --git a/couchpotato/core/providers/newzbin/__init__.py b/couchpotato/core/providers/newzbin/__init__.py
new file mode 100644
index 0000000..0b411bf
--- /dev/null
+++ b/couchpotato/core/providers/newzbin/__init__.py
@@ -0,0 +1,29 @@
+from .main import Newzbin
+
+def start():
+ return Newzbin()
+
+config = [{
+ 'name': 'newzbin',
+ 'groups': [
+ {
+ 'tab': 'providers',
+ 'name': 'newzbin',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'username',
+ 'default': '',
+ },
+ {
+ 'name': 'password',
+ 'default': '',
+ 'type': 'password',
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/providers/newzbin/main.py b/couchpotato/core/providers/newzbin/main.py
new file mode 100644
index 0000000..3fe3a29
--- /dev/null
+++ b/couchpotato/core/providers/newzbin/main.py
@@ -0,0 +1,8 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.providers.base import NZBProvider
+
+log = CPLog(__name__)
+
+
+class Newzbin(NZBProvider):
+ pass
diff --git a/couchpotato/core/providers/newznab/__init__.py b/couchpotato/core/providers/newznab/__init__.py
new file mode 100644
index 0000000..6587764
--- /dev/null
+++ b/couchpotato/core/providers/newznab/__init__.py
@@ -0,0 +1,30 @@
+from .main import Newznab
+
+def start():
+ return Newznab()
+
+config = [{
+ 'name': 'newznab',
+ 'groups': [
+ {
+ 'tab': 'providers',
+ 'name': 'newznab',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'host',
+ 'default': 'http://nzb.su',
+ },
+ {
+ 'name': 'api_key',
+ 'default': '',
+ 'label': 'Api Key',
+ 'description': 'Can be found after login on the "API" page, bottom left. The string after "&apikey=".',
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/providers/newznab/main.py b/couchpotato/core/providers/newznab/main.py
new file mode 100644
index 0000000..0e2f30d
--- /dev/null
+++ b/couchpotato/core/providers/newznab/main.py
@@ -0,0 +1,8 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.providers.base import NZBProvider
+
+log = CPLog(__name__)
+
+
+class Newznab(NZBProvider):
+ pass
diff --git a/couchpotato/core/providers/nzbmatrix/__init__.py b/couchpotato/core/providers/nzbmatrix/__init__.py
new file mode 100644
index 0000000..201cfcc
--- /dev/null
+++ b/couchpotato/core/providers/nzbmatrix/__init__.py
@@ -0,0 +1,29 @@
+from .main import NZBMatrix
+
+def start():
+ return NZBMatrix()
+
+config = [{
+ 'name': 'nzbmatrix',
+ 'groups': [
+ {
+ 'tab': 'providers',
+ 'name': 'nzbmatrix',
+ 'label': 'NZBMatrix',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'username',
+ },
+ {
+ 'name': 'api_key',
+ 'default': '9b939aee0aaafc12a65bf448e4af9543',
+ 'label': 'Api Key',
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/providers/nzbmatrix/main.py b/couchpotato/core/providers/nzbmatrix/main.py
new file mode 100644
index 0000000..fe7d80a
--- /dev/null
+++ b/couchpotato/core/providers/nzbmatrix/main.py
@@ -0,0 +1,116 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.providers.base import NZBProvider
+
+log = CPLog(__name__)
+
+
+class NZBMatrix(NZBProvider):
+
+ urls = {
+ 'download': 'https://api.nzbmatrix.com/v1.1/download.php?id=%s%s',
+ 'detail': 'https://nzbmatrix.com/nzb-details.php?id=%s&hit=1',
+ 'search': 'http://rss.nzbmatrix.com/rss.php',
+ }
+
+ cat_ids = [
+ ([42], ['720p', '1080p']),
+ ([2], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
+ ([54], ['brrip']),
+ ([1], ['dvdr']),
+ ]
+ cat_backup_id = 2
+
+ def __init__(self, config):
+ log.info('Using NZBMatrix provider')
+
+ self.config = config
+
+ def find(self, movie, quality, type, retry = False):
+
+ self.cleanCache();
+
+ results = []
+ if not self.enabled() or not self.isAvailable(self.searchUrl):
+ return results
+
+ catId = self.getCatId(type)
+ arguments = urlencode({
+ 'term': movie.imdb,
+ 'subcat': catId,
+ 'username': self.conf('username'),
+ 'apikey': self.conf('apikey'),
+ 'searchin': 'weblink',
+ 'english': 1 if self.conf('english') else 0,
+ })
+ url = "%s?%s" % (self.searchUrl, arguments)
+ cacheId = str(movie.imdb) + '-' + str(catId)
+ singleCat = (len(self.catIds.get(catId)) == 1 and catId != self.catBackupId)
+
+ try:
+ cached = False
+ if(self.cache.get(cacheId)):
+ data = True
+ cached = True
+ log.info('Getting RSS from cache: %s.' % cacheId)
+ else:
+ log.info('Searching: %s' % url)
+ data = self.urlopen(url)
+ self.cache[cacheId] = {
+ 'time': time.time()
+ }
+
+ except (IOError, URLError):
+ log.error('Failed to open %s.' % url)
+ return results
+
+ if data:
+ try:
+ try:
+ if cached:
+ xml = self.cache[cacheId]['xml']
+ else:
+ xml = self.getItems(data)
+ self.cache[cacheId]['xml'] = xml
+ except:
+ log.debug('No valid xml or to many requests.. You never know with %s.' % self.name)
+ return results
+
+ for nzb in xml:
+
+ title = self.gettextelement(nzb, "title")
+ if 'error' in title.lower(): continue
+
+ id = int(self.gettextelement(nzb, "link").split('&')[0].partition('id=')[2])
+ size = self.gettextelement(nzb, "description").split('
')[2].split('> ')[1]
+ date = str(self.gettextelement(nzb, "description").split('
')[3].partition('Added: ')[2])
+
+ new = self.feedItem()
+ new.id = id
+ new.type = 'nzb'
+ new.name = title
+ new.date = int(time.mktime(parse(date).timetuple()))
+ new.size = self.parseSize(size)
+ new.url = self.downloadLink(id)
+ new.detailUrl = self.detailLink(id)
+ new.content = self.gettextelement(nzb, "description")
+ new.score = self.calcScore(new, movie)
+ new.checkNZB = True
+
+ if new.date > time.time() - (int(self.config.get('NZB', 'retention')) * 24 * 60 * 60):
+ if self.isCorrectMovie(new, movie, type, imdbResults = True, singleCategory = singleCat):
+ results.append(new)
+ log.info('Found: %s' % new.name)
+ else:
+ log.info('Found outside retention: %s' % new.name)
+
+ return results
+ except SyntaxError:
+ log.error('Failed to parse XML response from NZBMatrix.com')
+
+ return results
+
+ def getApiExt(self):
+ return '&username=%s&apikey=%s' % (self.conf('username'), self.conf('apikey'))
+
+ def isEnabled(self):
+ return self.conf('enabled') and self.conf('username') and self.conf('apikey')
diff --git a/couchpotato/core/providers/nzbs/__init__.py b/couchpotato/core/providers/nzbs/__init__.py
new file mode 100644
index 0000000..1fe5a64
--- /dev/null
+++ b/couchpotato/core/providers/nzbs/__init__.py
@@ -0,0 +1,30 @@
+from .main import Nzbs
+
+def start():
+ return Nzbs()
+
+config = [{
+ 'name': 'nzbs',
+ 'groups': [
+ {
+ 'tab': 'providers',
+ 'name': 'nzbs',
+ 'options': [
+ {
+ 'name': 'enabled',
+ 'type': 'enabler',
+ },
+ {
+ 'name': 'id',
+ 'label': 'Id',
+ 'description': 'Can be found here, the number after "&i="',
+ },
+ {
+ 'name': 'api_key',
+ 'label': 'Api Key',
+ 'description': 'Can be found here, the string after "&h="'
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/providers/nzbs/main.py b/couchpotato/core/providers/nzbs/main.py
new file mode 100644
index 0000000..fb4742c
--- /dev/null
+++ b/couchpotato/core/providers/nzbs/main.py
@@ -0,0 +1,8 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.providers.base import NZBProvider
+
+log = CPLog(__name__)
+
+
+class Nzbs(NZBProvider):
+ pass
diff --git a/couchpotato/core/providers/themoviedb/main.py b/couchpotato/core/providers/themoviedb/main.py
index bc077cf..bd9e0ad 100644
--- a/couchpotato/core/providers/themoviedb/main.py
+++ b/couchpotato/core/providers/themoviedb/main.py
@@ -2,16 +2,15 @@ from __future__ import with_statement
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato.core.logger import CPLog
-from couchpotato.core.providers.base import Provider
+from couchpotato.core.providers.base import MovieProvider
from libs.themoviedb import tmdb
log = CPLog(__name__)
-class TheMovieDb(Provider):
+class TheMovieDb(MovieProvider):
"""Api for theMovieDb"""
- type = 'movie'
apiUrl = 'http://api.themoviedb.org/2.1'
imageUrl = 'http://hwcdn.themoviedb.org'
diff --git a/couchpotato/core/providers/thepiratebay/__init__.py b/couchpotato/core/providers/thepiratebay/__init__.py
new file mode 100644
index 0000000..1e154ce
--- /dev/null
+++ b/couchpotato/core/providers/thepiratebay/__init__.py
@@ -0,0 +1,24 @@
+from .main import ThePirateBay
+
+def start():
+ return ThePirateBay()
+
+config = [{
+ 'name': 'themoviedb',
+ 'groups': [
+ {
+ 'tab': 'providers',
+ 'name': 'tmdb',
+ 'label': 'TheMovieDB',
+ 'advanced': True,
+ 'description': 'Used for all calls to TheMovieDB.',
+ 'options': [
+ {
+ 'name': 'api_key',
+ 'default': '9b939aee0aaafc12a65bf448e4af9543',
+ 'label': 'Api Key',
+ },
+ ],
+ },
+ ],
+}]
diff --git a/couchpotato/core/providers/thepiratebay/main.py b/couchpotato/core/providers/thepiratebay/main.py
new file mode 100644
index 0000000..2c2ce6f
--- /dev/null
+++ b/couchpotato/core/providers/thepiratebay/main.py
@@ -0,0 +1,8 @@
+from couchpotato.core.logger import CPLog
+from couchpotato.core.providers.base import TorrentProvider
+
+log = CPLog(__name__)
+
+
+class ThePirateBay(TorrentProvider):
+ pass
diff --git a/couchpotato/static/scripts/couchpotato.js b/couchpotato/static/scripts/couchpotato.js
index b335b12..d299f77 100644
--- a/couchpotato/static/scripts/couchpotato.js
+++ b/couchpotato/static/scripts/couchpotato.js
@@ -92,6 +92,7 @@ var CouchPotato = new Class({
getPage: function(name){
return this.pages[name]
}
+
});
window.App = new CouchPotato();
diff --git a/couchpotato/static/scripts/page.js b/couchpotato/static/scripts/page.js
index dd4d4b0..f178da0 100644
--- a/couchpotato/static/scripts/page.js
+++ b/couchpotato/static/scripts/page.js
@@ -8,18 +8,17 @@ var PageBase = new Class({
has_tab: true,
- initialize: function(parent, options) {
+ initialize: function(options) {
var self = this;
self.setOptions(options)
- self.setParent(parent)
// Create main page container
self.el = new Element('div.page.'+self.name);
// Create tab for page
if(self.has_tab){
- var nav = self.getParent().getBlock('navigation');
+ var nav = App.getBlock('navigation');
self.tab = nav.addTab({
'href': '/'+self.name,
'title': self.title,
@@ -49,14 +48,6 @@ var PageBase = new Class({
getName: function(){
return this.name
},
-
- setParent: function(parent){
- this.app = parent
- },
-
- getParent: function(){
- return this.app
- },
show: function(){
this.el.addClass('active');
diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js
index b5c619f..0759133 100644
--- a/couchpotato/static/scripts/page/settings.js
+++ b/couchpotato/static/scripts/page/settings.js
@@ -6,18 +6,10 @@ Page.Settings = new Class({
title: 'Change settings.',
tabs: {
- 'general': {
- 'label': 'General'
- },
- 'providers': {
- 'label': 'Providers'
- },
- 'downloaders': {
- 'label': 'Downloaders'
- },
- 'notifications': {
- 'label': 'Notifications'
- }
+ 'general': {},
+ 'providers': {},
+ 'downloaders': {},
+ 'notifications': {}
},
open: function(action, params){
@@ -150,16 +142,17 @@ 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).capitalize()
var tab_el = new Element('li').adopt(
new Element('a', {
'href': '/'+self.name+'/'+tab_name+'/',
- 'text': (tab.label || tab.name).capitalize()
+ 'text': label
})
).inject(self.tabs_container);
if(!self.tabs[tab_name])
self.tabs[tab_name] = {
- 'label': tab.label || tab.name
+ 'label': label
}
self.tabs[tab_name] = Object.merge(self.tabs[tab_name], {
@@ -179,7 +172,7 @@ Page.Settings = new Class({
'class': group.advanced ? 'inlineLabels advanced' : 'inlineLabels'
}).adopt(
new Element('h2', {
- 'text': group.label || group.name.capitalize()
+ 'text': (group.label || group.name).capitalize()
}).adopt(
new Element('span.hint', {
'text': group.description
@@ -236,7 +229,7 @@ var OptionBase = new Class({
createLabel: function(){
var self = this;
return new Element('label', {
- 'text': self.options.label || self.options.name.capitalize()
+ 'text': (self.options.label || self.options.name).capitalize()
})
},