Multi Newznab provider support

This commit is contained in:
Ruud
2011-08-20 16:29:51 +02:00
parent 96822fb5a0
commit dcf8ac7ada
5 changed files with 200 additions and 40 deletions
+25 -24
View File
@@ -2,10 +2,12 @@ from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
from urllib2 import URLError
from urlparse import urlparse
import math
import re
import socket
import time
import urllib
import urllib2
log = CPLog(__name__)
@@ -16,9 +18,9 @@ class Provider(Plugin):
type = None # movie, nzb, torrent, subtitle, trailer
time_between_searches = 10 # Default timeout for url requests
last_use = 0
last_available_check = 0
is_available = 0
last_use = {}
last_available_check = {}
is_available = {}
def getCache(self, cache_key):
cache = Env.get('cache').get(cache_key)
@@ -35,49 +37,48 @@ class Provider(Plugin):
if Env.get('debug'): return True
now = time.time()
host = urlparse(test_url).hostname
if self.last_available_check < now - 900:
self.last_available_check = now
if self.last_available_check.get(host) < now - 900:
self.last_available_check[host] = now
try:
self.urlopen(test_url, 30)
self.is_available = True
self.is_available[host] = True
except (IOError, URLError):
log.error('%s unavailable, trying again in an 15 minutes.' % self.name)
self.is_available = False
self.is_available[host] = False
return self.is_available
return self.is_available[host]
def urlopen(self, url, timeout = 10, username = None, password = None):
def urlopen(self, url, timeout = 10, params = {}):
socket.setdefaulttimeout(timeout)
self.wait()
host = urlparse(url).hostname
self.wait(host)
try:
log.info('Opening url: %s' % url)
if username and password:
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, url, username, password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
data = opener.open(url).read()
else:
data = urllib2.urlopen(url).read()
log.info('Opening url: %s, params: %s' % (url, params))
request = urllib2.Request(url, urllib.urlencode(params))
data = urllib2.urlopen(request).read()
except IOError, e:
log.error('Failed opening url, %s: %s' % (url, e))
data = ''
self.last_use = time.time()
self.last_use[host] = time.time()
return data
def wait(self):
def wait(self, host = ''):
now = time.time()
wait = math.ceil(self.last_use - now + self.time_between_searches)
last_use = self.last_use.get(host, 0)
wait = math.ceil(last_use - now + self.time_between_searches)
if wait > 0:
log.debug('Waiting for %s, %d seconds' % (self.getName(), wait))
time.sleep(self.last_use - now + self.time_between_searches)
time.sleep(last_use - now + self.time_between_searches)
class MovieProvider(Provider):
@@ -9,11 +9,16 @@ config = [{
{
'tab': 'providers',
'name': 'newznab',
'description': 'Enable multiple NewzNab providers',
'options': [
{
'name': 'enabled',
'type': 'enabler',
},
{
'name': 'use',
'default': '0'
},
{
'name': 'host',
'default': 'http://nzb.su',
@@ -23,7 +28,7 @@ config = [{
'name': 'api_key',
'default': '',
'label': 'Api Key',
'description': 'Can be found after login on the "API" page, bottom left. The string after "&amp;apikey=".',
'description': 'Can be found on your profile page',
},
],
},
+29 -14
View File
@@ -35,26 +35,41 @@ class Newznab(NZBProvider, RSS):
addEvent('provider.nzb.search', self.search)
addEvent('provider.yarr.search', self.search)
def getUrl(self, type):
return cleanHost(self.conf('host')) + 'api?t=' + type
self.registerStatic(__file__)
def getUrl(self, host, type):
return cleanHost(host) + 'api?t=' + type
def search(self, movie, quality):
uses = str(self.conf('use')).split(',')
hosts = self.conf('host').split(',')
api_keys = self.conf('api_key').split(',')
for nr in range(len(hosts)):
self.singleSearch({
'use': uses[nr],
'host': hosts[nr],
'api_key': api_keys[nr]
}, movie, quality)
def singleSearch(self, host, movie, quality):
results = []
if self.isDisabled() or not self.isAvailable(self.getUrl(self.urls['search'])):
if self.isDisabled(host) or not self.isAvailable(self.getUrl(host['host'], self.urls['search'])):
return results
cat_id = self.getCatId(quality['identifier'])
arguments = urlencode({
'imdbid': movie['library']['identifier'].replace('tt', ''),
'cat': cat_id[0],
'apikey': self.conf('api_key'),
'apikey': host['api_key'],
't': self.urls['search'],
'extended': 1
})
url = "%s&%s" % (self.getUrl(self.urls['search']), arguments)
url = "%s&%s" % (self.getUrl(host['host'], self.urls['search']), arguments)
cache_key = 'newznab.%s.%s' % (movie['library']['identifier'], cat_id[0])
cache_key = 'newznab.%s.%s.%s' % (host['host'], movie['library']['identifier'], cat_id[0])
single_cat = (len(cat_id) == 1 and cat_id[0] != self.cat_backup_id)
try:
@@ -91,8 +106,8 @@ class Newznab(NZBProvider, RSS):
'name': self.getTextElement(nzb, "title"),
'age': self.calculateAge(int(time.mktime(parse(date).timetuple()))),
'size': int(size) / 1024 / 1024,
'url': (self.getUrl(self.urls['download']) % id) + self.getApiExt(),
'detail_url': (self.getUrl(self.urls['detail']) % id) + self.getApiExt(),
'url': (self.getUrl(host['host'], self.urls['download']) % id) + self.getApiExt(host),
'detail_url': (self.getUrl(host['host'], self.urls['detail']) % id) + self.getApiExt(host),
'content': self.getTextElement(nzb, "description"),
}
new['score'] = fireEvent('score.calculate', new, movie, single = True)
@@ -112,11 +127,11 @@ class Newznab(NZBProvider, RSS):
return results
def isEnabled(self):
return NZBProvider.isEnabled(self) and self.conf('host') and self.conf('api_key')
def isDisabled(self, host):
return not self.isEnabled(host)
def getApiExt(self):
return '&apikey=%s' % self.conf('api_key')
def isEnabled(self, host):
return NZBProvider.isEnabled(self) and host['host'] and host['api_key'] and int(host['use'])
def detailLink(self, id):
return self.getUrl(self.detailUrl) % id
def getApiExt(self, host):
return '&apikey=%s' % host['api_key']
@@ -0,0 +1,137 @@
var MultipleNewznab = new Class({
input_types: ['use', 'host', 'api_key'],
initialize: function(){
var self = this;
self.items = [];
self.values = [];
self.inputs = {};
App.addEvent('load', self.addSettings.bind(self))
},
addSettings: function(){
var self = this;
self.settings = App.getPage('Settings')
self.settings.addEvent('create', function(){
self.fieldset = self.settings.tabs.providers.content.getElement('.section_newznab');
self.input_types.each(function(name){
self.inputs[name] = self.fieldset.getElement('input[name=newznab['+name+']]');
var values = self.inputs[name].get('value').split(',');
values.each(function(value, nr){
if (!self.values[nr]) self.values[nr] = {};
self.values[nr][name] = value.trim();
});
self.inputs[name].getParent().hide()
});
self.values.each(function(item, nr){
self.createItem(item.use, item.host, item.api_key);
});
new Element('a.nice_button', {
'text': 'Add new NewzNab provider',
'events': {
'click': function(e){
(e).stop();
self.createItem(1, '', '');
}
}
}).inject(self.fieldset.getElement('h2'), 'after');
})
},
createItem: function(use, host, api){
var self = this;
var checkbox = new Element('input[type=checkbox].use.inlay', {
'checked': +use,
'events': {
'click': self.save.bind(self),
'change': self.save.bind(self)
}
})
var item = new Element('div.ctrlHolder').adopt(
checkbox,
new Element('input[type=text].host.inlay', {
'value': host,
'placeholder': 'Host',
'events': {
'keyup': self.save.bind(self),
'change': self.save.bind(self)
}
}),
new Element('input[type=text].api_key.inlay', {
'value': api,
'placeholder': 'Api hash key',
'events': {
'keyup': self.save.bind(self),
'change': self.save.bind(self)
}
}),
new Element('a.icon.delete', {
'text': 'delete',
'events': {
'click': self.deleteItem.bind(self)
}
})
).inject(self.fieldset);
new Form.Check(checkbox, {
'onChange': checkbox.fireEvent.bind(checkbox, 'change')
});
self.items.include(item)
},
save: function(){
var self = this;
var temp = {}
self.items.each(function(item, nr){
self.input_types.each(function(type){
var input = item.getElement('input.'+type);
if(!temp[type]) temp[type] = [];
temp[type][nr] = input.get('type') == 'checkbox' ? +input.get('checked') : input.get('value').trim();
})
});
self.input_types.each(function(name){
self.inputs[name].set('value', temp[name].join(','));
self.inputs[name].fireEvent('change');
});
},
deleteItem: function(e){
var self = this;
(e).stop();
var item = e.target.getParent();
self.items.erase(item);
item.destroy();
self.save();
}
});
window.MNewznab = new MultipleNewznab();
+3 -1
View File
@@ -121,7 +121,9 @@ Page.Settings = new Class({
// Create the group
if(!self.tabs[group.tab].groups[group.name]){
var group_el = self.createGroup(group).inject(self.tabs[group.tab].content);
var group_el = self.createGroup(group)
.inject(self.tabs[group.tab].content)
.addClass('section_'+section_name);
self.tabs[group.tab].groups[group.name] = group_el
}