NZB/Torrent provider base
This commit is contained in:
@@ -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.',
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,33 +1,42 @@
|
||||
def start():
|
||||
pass
|
||||
from couchpotato.core.plugins.renamer.main import 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 = []
|
||||
def start():
|
||||
return Renamer()
|
||||
|
||||
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.',
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
|
||||
@@ -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
|
||||
@@ -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'
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -0,0 +1,8 @@
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.base import NZBProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class Newzbin(NZBProvider):
|
||||
pass
|
||||
@@ -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=".',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -0,0 +1,8 @@
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.base import NZBProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class Newznab(NZBProvider):
|
||||
pass
|
||||
@@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -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('<br /><b>')[2].split('> ')[1]
|
||||
date = str(self.gettextelement(nzb, "description").split('<br /><b>')[3].partition('Added:</b> ')[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')
|
||||
@@ -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 <a href="http://nzbs.org/index.php?action=rss" target="_blank">here</a>, the number after "&i="',
|
||||
},
|
||||
{
|
||||
'name': 'api_key',
|
||||
'label': 'Api Key',
|
||||
'description': 'Can be found <a href="http://nzbs.org/index.php?action=rss" target="_blank">here</a>, the string after "&h="'
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -0,0 +1,8 @@
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.base import NZBProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class Nzbs(NZBProvider):
|
||||
pass
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
@@ -0,0 +1,8 @@
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.base import TorrentProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class ThePirateBay(TorrentProvider):
|
||||
pass
|
||||
@@ -92,6 +92,7 @@ var CouchPotato = new Class({
|
||||
getPage: function(name){
|
||||
return this.pages[name]
|
||||
}
|
||||
|
||||
});
|
||||
window.App = new CouchPotato();
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user