Merge branch 'refs/heads/develop'
This commit is contained in:
@@ -9,7 +9,7 @@ import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import time
|
||||
|
||||
# Root path
|
||||
base_path = dirname(os.path.abspath(__file__))
|
||||
@@ -96,6 +96,10 @@ class Loader(object):
|
||||
except:
|
||||
self.log.critical(traceback.format_exc())
|
||||
|
||||
# Release log files and shutdown logger
|
||||
logging.shutdown()
|
||||
time.sleep(3)
|
||||
|
||||
args = [sys.executable] + [os.path.join(base_path, __file__)] + sys.argv[1:]
|
||||
subprocess.Popen(args)
|
||||
except:
|
||||
|
||||
@@ -7,11 +7,12 @@ Once a movie is found, it will send it to SABnzbd or download the torrent to a s
|
||||
|
||||
## Running from Source
|
||||
|
||||
CouchPotatoServer can be run from source. This will use *git* as updater, so make sure that is installed also.
|
||||
CouchPotatoServer can be run from source. This will use *git* as updater, so make sure that is installed also.
|
||||
|
||||
Windows:
|
||||
Windows, see [the CP forum](http://couchpota.to/forum/showthread.php?tid=14) for more details:
|
||||
|
||||
* Install [PyWin32 2.7](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/) and [GIT](http://git-scm.com/)
|
||||
* Install [Python 2.7](http://www.python.org/download/releases/2.7.3/)
|
||||
* Then install [PyWin32 2.7](http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/) and [GIT](http://git-scm.com/)
|
||||
* If you come and ask on the forums 'why directory selection no work?', I will kill a kitten, also this is because you need PyWin32
|
||||
* Open up `Git Bash` (or CMD) and go to the folder you want to install CP. Something like Program Files.
|
||||
* Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git`.
|
||||
|
||||
@@ -4,22 +4,28 @@ from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.plugins.base import Plugin
|
||||
from couchpotato.environment import Env
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
|
||||
class Downloader(Plugin):
|
||||
|
||||
type = []
|
||||
|
||||
def __init__(self):
|
||||
addEvent('download', self.download)
|
||||
addEvent('download.status', self.getDownloadStatus)
|
||||
|
||||
def download(self, data = {}):
|
||||
def download(self, data = {}, movie = {}, manual = False, filedata = None):
|
||||
pass
|
||||
|
||||
def getDownloadStatus(self, data = {}, movie = {}):
|
||||
pass
|
||||
|
||||
def createNzbName(self, data, movie):
|
||||
return '%s%s' % (toSafeString(data.get('name')), self.cpTag(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))
|
||||
@@ -41,6 +47,18 @@ class Downloader(Plugin):
|
||||
|
||||
return is_correct
|
||||
|
||||
def magnetToTorrent(self, magnet_link):
|
||||
torrent_hash = re.findall('urn:btih:([\w]{40})', magnet_link)[0]
|
||||
url = 'http://torrage.com/torrent/%s.torrent' % torrent_hash
|
||||
|
||||
try:
|
||||
filedata = self.urlopen(url)
|
||||
return filedata
|
||||
except:
|
||||
log.error('Failed converting magnet url to torrent: %s, %s', (url, traceback.format_exc()))
|
||||
|
||||
return False
|
||||
|
||||
def isDisabled(self, manual):
|
||||
return not self.isEnabled(manual)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ log = CPLog(__name__)
|
||||
|
||||
class Blackhole(Downloader):
|
||||
|
||||
type = ['nzb', 'torrent']
|
||||
type = ['nzb', 'torrent', 'torrent_magnet']
|
||||
|
||||
def download(self, data = {}, movie = {}, manual = False, filedata = None):
|
||||
if self.isDisabled(manual) or (not self.isCorrectType(data.get('type')) or (not self.conf('use_for') in ['both', data.get('type')])):
|
||||
@@ -20,8 +20,16 @@ class Blackhole(Downloader):
|
||||
else:
|
||||
try:
|
||||
if not filedata or len(filedata) < 50:
|
||||
log.error('No nzb/torrent available!')
|
||||
return False
|
||||
try:
|
||||
if data.get('type') == 'torrent_magnet':
|
||||
filedata = self.magnetToTorrent(data.get('url'))
|
||||
data['type'] = 'torrent'
|
||||
except:
|
||||
log.error('Failed download torrent via magnet url: %s', traceback.format_exc())
|
||||
|
||||
if not filedata or len(filedata) < 50:
|
||||
log.error('No nzb/torrent available: %s', data.get('url'))
|
||||
return False
|
||||
|
||||
fullPath = os.path.join(directory, self.createFileName(data, filedata, movie))
|
||||
|
||||
|
||||
@@ -35,11 +35,17 @@ config = [{
|
||||
},
|
||||
{
|
||||
'name': 'manual',
|
||||
'default': 0,
|
||||
'default': False,
|
||||
'type': 'bool',
|
||||
'advanced': True,
|
||||
'description': 'Disable this downloader for automated searches, but use it when I manually send a release.',
|
||||
},
|
||||
{
|
||||
'name': 'delete_failed',
|
||||
'default': True,
|
||||
'type': 'bool',
|
||||
'description': 'Delete a release after the download has failed.',
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
|
||||
@@ -3,6 +3,7 @@ from couchpotato.core.helpers.encoding import tryUrlencode
|
||||
from couchpotato.core.helpers.variable import cleanHost
|
||||
from couchpotato.core.logger import CPLog
|
||||
import traceback
|
||||
import json
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
@@ -39,14 +40,14 @@ class Sabnzbd(Downloader):
|
||||
|
||||
try:
|
||||
if params.get('mode') is 'addfile':
|
||||
data = self.urlopen(url, timeout = 60, params = {"nzbfile": (nzb_filename, filedata)}, multipart = True, show_error = False)
|
||||
sab = self.urlopen(url, timeout = 60, params = {"nzbfile": (nzb_filename, filedata)}, multipart = True, show_error = False)
|
||||
else:
|
||||
data = self.urlopen(url, timeout = 60, show_error = False)
|
||||
sab = self.urlopen(url, timeout = 60, show_error = False)
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
log.error('Failed sending release: %s', traceback.format_exc())
|
||||
return False
|
||||
|
||||
result = data.strip()
|
||||
result = sab.strip()
|
||||
if not result:
|
||||
log.error("SABnzbd didn't return anything.")
|
||||
return False
|
||||
@@ -61,3 +62,101 @@ class Sabnzbd(Downloader):
|
||||
else:
|
||||
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
|
||||
|
||||
nzbname = self.createNzbName(data, movie)
|
||||
log.info('Checking download status of "%s" at SABnzbd.', nzbname)
|
||||
|
||||
# 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)
|
||||
except:
|
||||
log.error('Failed checking status: %s', traceback.format_exc())
|
||||
return False
|
||||
|
||||
try:
|
||||
history = json.loads(sab)
|
||||
except:
|
||||
log.debug("Result text from SAB: " + sab[:40])
|
||||
log.error('Failed parsing json status: %s', traceback.format_exc())
|
||||
return False
|
||||
|
||||
for slot in history['queue']['slots']:
|
||||
if slot['cat'] == self.conf('category'):
|
||||
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()
|
||||
|
||||
# Go through history items
|
||||
params = {
|
||||
'apikey': self.conf('api_key'),
|
||||
'mode': 'history',
|
||||
'output': 'json'
|
||||
}
|
||||
url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params)
|
||||
|
||||
try:
|
||||
sab = self.urlopen(url, timeout = 60, show_error = False)
|
||||
except:
|
||||
log.error('Failed getting history: %s', traceback.format_exc())
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
for slot in history['history']['slots']:
|
||||
if slot['category'] == self.conf('category'):
|
||||
log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status']))
|
||||
if slot['name'] == nzbname:
|
||||
if slot['status'] == 'Failed' or 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()
|
||||
|
||||
return 'not_found'
|
||||
|
||||
@@ -216,7 +216,7 @@ var NotificationBase = new Class({
|
||||
},
|
||||
|
||||
testButtonName: function(fieldset){
|
||||
var name = fieldset.getElement('h2').get('text');
|
||||
var name = String(fieldset.getElement('h2').innerHTML).substring(0,String(fieldset.getElement('h2').innerHTML).indexOf("<span")); //.get('text');
|
||||
return 'Test '+name;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class NMJ(Notification):
|
||||
|
||||
def __init__(self):
|
||||
addEvent('renamer.after', self.addToLibrary)
|
||||
|
||||
addApiView(self.testNotifyName(), self.test)
|
||||
addApiView('notify.nmj.auto_config', self.autoConfig)
|
||||
|
||||
def autoConfig(self):
|
||||
@@ -76,7 +76,7 @@ class NMJ(Notification):
|
||||
mount = self.conf('mount')
|
||||
database = self.conf('database')
|
||||
|
||||
if self.mount:
|
||||
if mount:
|
||||
log.debug('Try to mount network drive via url: %s', (mount))
|
||||
try:
|
||||
data = self.urlopen(mount)
|
||||
@@ -114,3 +114,8 @@ class NMJ(Notification):
|
||||
|
||||
def failed(self):
|
||||
return jsonified({'success': False})
|
||||
|
||||
def test(self):
|
||||
return jsonified({'success': self.addToLibrary()})
|
||||
|
||||
|
||||
|
||||
@@ -15,14 +15,22 @@ class NotifyMyAndroid(Notification):
|
||||
nma.addkey(keys)
|
||||
nma.developerkey(self.conf('dev_key'))
|
||||
|
||||
# hacky fix for the event type
|
||||
# hacky fix for the event type
|
||||
# as it seems to be part of the message now
|
||||
self.event = message.split(' ')[0]
|
||||
response = nma.push(
|
||||
application = self.default_title,
|
||||
event = self.event,
|
||||
description = message,
|
||||
priority = self.conf('priority'),
|
||||
batch_mode = len(keys) > 1
|
||||
)
|
||||
|
||||
response = nma.push(self.default_title, self.event , message, self.conf('priority'), batch_mode = len(keys) > 1)
|
||||
|
||||
successful = 0
|
||||
for key in keys:
|
||||
if not response[str(key)]['code'] == u'200':
|
||||
log.error('Could not send notification to NotifyMyAndroid (%s). %s', (key, response[key]['message']))
|
||||
else:
|
||||
successful += 1
|
||||
|
||||
return response
|
||||
return successful == len(keys)
|
||||
|
||||
@@ -13,11 +13,15 @@ class XBMC(Notification):
|
||||
def notify(self, message = '', data = {}, listener = None):
|
||||
if self.isDisabled(): return
|
||||
|
||||
for host in [x.strip() for x in self.conf('host').split(",")]:
|
||||
self.send({'command': 'ExecBuiltIn', 'parameter': 'Notification(CouchPotato, %s)' % message}, host)
|
||||
self.send({'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'}, host)
|
||||
hosts = [x.strip() for x in self.conf('host').split(",")]
|
||||
successful = 0
|
||||
for host in hosts:
|
||||
if self.send({'command': 'ExecBuiltIn', 'parameter': 'Notification(CouchPotato, %s)' % message}, host):
|
||||
successful += 1
|
||||
if self.send({'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'}, host):
|
||||
successful += 1
|
||||
|
||||
return True
|
||||
return successful == len(hosts)*2
|
||||
|
||||
def send(self, command, host):
|
||||
|
||||
|
||||
@@ -340,6 +340,32 @@
|
||||
.movies .movie .hide_trailer.hide {
|
||||
top: -30px;
|
||||
}
|
||||
|
||||
.movies .movie .try_container {
|
||||
padding: 5px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.movies .movie .try_container a {
|
||||
margin: 0 5px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
.movies .movie .releases .next_release {
|
||||
border-left: 6px solid #2aa300;
|
||||
}
|
||||
|
||||
.movies .movie .releases .next_release > :first-child {
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.movies .movie .releases .last_release {
|
||||
border-left: 6px solid #ffa200;
|
||||
}
|
||||
|
||||
.movies .movie .releases .last_release > :first-child {
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.movies .load_more {
|
||||
display: block;
|
||||
|
||||
@@ -140,28 +140,33 @@ var Movie = new Class({
|
||||
self.profile.getTypes().each(function(type){
|
||||
|
||||
var q = self.addQuality(type.quality_id || type.get('quality_id'));
|
||||
if(type.finish == true || type.get('finish'))
|
||||
if((type.finish == true || type.get('finish')) && !q.hasClass('finish')){
|
||||
q.addClass('finish');
|
||||
q.set('title', q.get('title') + ' Will finish searching for this movie if this quality is found.')
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Add done releases
|
||||
Array.each(self.data.releases, function(release){
|
||||
self.data.releases.each(function(release){
|
||||
|
||||
var q = self.quality.getElement('.q_id'+ release.quality_id),
|
||||
status = Status.get(release.status_id);
|
||||
|
||||
if(!q && (status.identifier == 'snatched' || status.identifier == 'done'))
|
||||
var q = self.addQuality(release.quality_id)
|
||||
if (status && q)
|
||||
|
||||
if (status && q && !q.hasClass(status.identifier)){
|
||||
q.addClass(status.identifier);
|
||||
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status.label)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Object.each(self.options.actions, function(action, key){
|
||||
self.actions.adopt(
|
||||
self.action[key.toLowerCase()] = new self.options.actions[key](self)
|
||||
)
|
||||
self.action[key.toLowerCase()] = action = new self.options.actions[key](self)
|
||||
if(action.el)
|
||||
self.actions.adopt(action)
|
||||
});
|
||||
|
||||
if(!self.data.library.rating)
|
||||
@@ -175,7 +180,8 @@ var Movie = new Class({
|
||||
var q = Quality.getQuality(quality_id);
|
||||
return new Element('span', {
|
||||
'text': q.label,
|
||||
'class': 'q_'+q.identifier + ' q_id' + q.id
|
||||
'class': 'q_'+q.identifier + ' q_id' + q.id,
|
||||
'title': ''
|
||||
}).inject(self.quality);
|
||||
|
||||
},
|
||||
@@ -280,6 +286,31 @@ var MovieAction = new Class({
|
||||
this.el.removeClass('disable')
|
||||
},
|
||||
|
||||
createMask: function(){
|
||||
var self = this;
|
||||
self.mask = new Element('div.mask', {
|
||||
'styles': {
|
||||
'z-index': '1'
|
||||
}
|
||||
}).inject(self.movie, 'top').fade('hide');
|
||||
self.positionMask();
|
||||
},
|
||||
|
||||
positionMask: function(){
|
||||
var self = this,
|
||||
movie = $(self.movie),
|
||||
s = movie.getSize()
|
||||
|
||||
return;
|
||||
|
||||
return self.mask.setStyles({
|
||||
'width': s.x,
|
||||
'height': s.y
|
||||
}).position({
|
||||
'relativeTo': movie
|
||||
})
|
||||
},
|
||||
|
||||
toElement: function(){
|
||||
return this.el || null
|
||||
}
|
||||
@@ -298,19 +329,10 @@ var IMDBAction = new Class({
|
||||
|
||||
self.el = new Element('a.imdb', {
|
||||
'title': 'Go to the IMDB page of ' + self.movie.getTitle(),
|
||||
'events': {
|
||||
'click': self.gotoIMDB.bind(self)
|
||||
}
|
||||
'href': 'http://www.imdb.com/title/'+self.id+'/'
|
||||
});
|
||||
|
||||
if(!self.id) self.disable();
|
||||
},
|
||||
|
||||
gotoIMDB: function(e){
|
||||
var self = this;
|
||||
(e).preventDefault();
|
||||
|
||||
window.open('http://www.imdb.com/title/'+self.id+'/');
|
||||
}
|
||||
|
||||
});
|
||||
@@ -318,13 +340,10 @@ var IMDBAction = new Class({
|
||||
var ReleaseAction = new Class({
|
||||
|
||||
Extends: MovieAction,
|
||||
id: null,
|
||||
|
||||
create: function(){
|
||||
var self = this;
|
||||
|
||||
self.id = self.movie.get('identifier');
|
||||
|
||||
self.el = new Element('a.releases.icon.download', {
|
||||
'title': 'Show the releases that are available for ' + self.movie.getTitle(),
|
||||
'events': {
|
||||
@@ -332,15 +351,33 @@ var ReleaseAction = new Class({
|
||||
}
|
||||
});
|
||||
|
||||
var buttons_done = false;
|
||||
|
||||
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
||||
if(buttons_done) return;
|
||||
|
||||
var status = Status.get(release.status_id);
|
||||
|
||||
if((status.identifier == 'ignored' || status.identifier == 'failed') || (!self.next_release && status.identifier == 'available')){
|
||||
self.hide_on_click = false;
|
||||
self.show();
|
||||
buttons_done = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
show: function(e){
|
||||
var self = this;
|
||||
(e).preventDefault();
|
||||
if(e)
|
||||
(e).preventDefault();
|
||||
|
||||
if(!self.options_container){
|
||||
self.options_container = new Element('div.options').adopt(
|
||||
self.release_container = new Element('div.releases.table')
|
||||
self.release_container = new Element('div.releases.table').adopt(
|
||||
self.trynext_container = new Element('div.buttons.try_container')
|
||||
)
|
||||
).inject(self.movie, 'top');
|
||||
|
||||
// Header
|
||||
@@ -354,29 +391,35 @@ var ReleaseAction = new Class({
|
||||
new Element('span.provider', {'text': 'Provider'})
|
||||
).inject(self.release_container)
|
||||
|
||||
Array.each(self.movie.data.releases, function(release){
|
||||
self.movie.data.releases.sortBy('-info.score').each(function(release){
|
||||
|
||||
var status = Status.get(release.status_id),
|
||||
quality = Quality.getProfile(release.quality_id) || {},
|
||||
info = release.info;
|
||||
|
||||
try {
|
||||
var details_url = info.filter(function(item){ return item.identifier == 'detail_url' }).pick().value;
|
||||
} catch(e){}
|
||||
if( status.identifier == 'ignored' || status.identifier == 'failed'){
|
||||
self.last_release = release;
|
||||
}
|
||||
else if(!self.next_release && status.identifier == 'available'){
|
||||
self.next_release = release;
|
||||
}
|
||||
|
||||
// Create release
|
||||
new Element('div', {
|
||||
'class': 'item '+status.identifier,
|
||||
'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' : ''),
|
||||
'id': 'release_'+release.id
|
||||
}).adopt(
|
||||
new Element('span.name', {'text': self.get(release, 'name'), 'title': self.get(release, 'name')}),
|
||||
new Element('span.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}),
|
||||
new Element('span.quality', {'text': quality.label || 'n/a'}),
|
||||
new Element('span.size', {'text': (self.get(release, 'size'))}),
|
||||
new Element('span.quality', {'text': quality.get('label') || 'n/a'}),
|
||||
new Element('span.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}),
|
||||
new Element('span.age', {'text': self.get(release, 'age')}),
|
||||
new Element('span.score', {'text': self.get(release, 'score')}),
|
||||
new Element('span.provider', {'text': self.get(release, 'provider')}),
|
||||
details_url ? new Element('a.info.icon', {
|
||||
'href': details_url,
|
||||
release.info['detail_url'] ? new Element('a.info.icon', {
|
||||
'href': release.info['detail_url'],
|
||||
'target': '_blank'
|
||||
}) : null,
|
||||
new Element('a.download.icon', {
|
||||
@@ -400,17 +443,37 @@ var ReleaseAction = new Class({
|
||||
).inject(self.release_container)
|
||||
});
|
||||
|
||||
self.trynext_container.adopt(
|
||||
new Element('span.or', {
|
||||
'text': 'Download'
|
||||
}),
|
||||
self.last_release ? new Element('a.button.orange', {
|
||||
'text': 'the same release again',
|
||||
'events': {
|
||||
'click': self.trySameRelease.bind(self)
|
||||
}
|
||||
}) : null,
|
||||
self.next_release && self.last_release ? new Element('span.or', {
|
||||
'text': 'or'
|
||||
}) : null,
|
||||
self.next_release ? [new Element('a.button.green', {
|
||||
'text': self.last_release ? 'another release' : 'the best release',
|
||||
'events': {
|
||||
'click': self.tryNextRelease.bind(self)
|
||||
}
|
||||
}),
|
||||
new Element('span.or', {
|
||||
'text': 'or pick one below'
|
||||
})] : null
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
self.movie.slide('in', self.options_container);
|
||||
},
|
||||
|
||||
get: function(release, type){
|
||||
var self = this;
|
||||
|
||||
return (release.info.filter(function(info){
|
||||
return type == info.identifier
|
||||
}).pick() || {}).value || 'n/a'
|
||||
return release.info[type] || 'n/a'
|
||||
},
|
||||
|
||||
download: function(release){
|
||||
@@ -444,6 +507,25 @@ var ReleaseAction = new Class({
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
tryNextRelease: function(movie_id){
|
||||
var self = this;
|
||||
|
||||
if(self.last_release)
|
||||
self.ignore(self.last_release);
|
||||
|
||||
if(self.next_release)
|
||||
self.download(self.next_release);
|
||||
|
||||
},
|
||||
|
||||
trySameRelease: function(movie_id){
|
||||
var self = this;
|
||||
|
||||
if(self.last_release)
|
||||
self.download(self.last_release);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -186,7 +186,6 @@
|
||||
|
||||
.movie_result .info h2 span {
|
||||
padding: 0 5px;
|
||||
content: ")";
|
||||
}
|
||||
|
||||
.movie_result .info h2 span:before { content: "("; }
|
||||
|
||||
@@ -170,7 +170,9 @@ class Release(Plugin):
|
||||
|
||||
# Get matching provider
|
||||
provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True)
|
||||
item['download'] = provider.download
|
||||
|
||||
if item['type'] != 'torrent_magnet':
|
||||
item['download'] = provider.download
|
||||
|
||||
success = fireEvent('searcher.download', data = item, movie = rel.movie.to_dict({
|
||||
'profile': {'types': {'quality': {}}},
|
||||
|
||||
@@ -86,15 +86,6 @@ config = [{
|
||||
'label': 'Separator',
|
||||
'description': 'Replace all the spaces with a character. Example: ".", "-" (without quotes). Leave empty to use spaces.',
|
||||
},
|
||||
{
|
||||
'advanced': True,
|
||||
'name': 'run_every',
|
||||
'label': 'Run every',
|
||||
'default': 1,
|
||||
'type': 'int',
|
||||
'unit': 'min(s)',
|
||||
'description': 'Search for new movies inside the folder every X minutes.',
|
||||
},
|
||||
],
|
||||
}, {
|
||||
'tab': 'renamer',
|
||||
|
||||
@@ -30,7 +30,7 @@ class Renamer(Plugin):
|
||||
addEvent('renamer.scan', self.scan)
|
||||
addEvent('app.load', self.scan)
|
||||
|
||||
fireEvent('schedule.interval', 'renamer.scan', self.scan, minutes = self.conf('run_every'))
|
||||
#fireEvent('schedule.interval', 'renamer.scan', self.scan, minutes = self.conf('run_every'))
|
||||
|
||||
def scanView(self):
|
||||
|
||||
@@ -327,6 +327,11 @@ class Renamer(Plugin):
|
||||
try:
|
||||
if os.path.isfile(src):
|
||||
os.remove(src)
|
||||
|
||||
parent_dir = os.path.normpath(os.path.dirname(src))
|
||||
if os.path.isdir(parent_dir) and destination != parent_dir:
|
||||
self.deleteEmptyFolder(parent_dir, show_error = False)
|
||||
|
||||
except:
|
||||
log.error('Failed removing %s: %s', (src, traceback.format_exc()))
|
||||
self.tagDir(group, 'failed_remove')
|
||||
@@ -464,8 +469,9 @@ class Renamer(Plugin):
|
||||
def replaceDoubles(self, string):
|
||||
return string.replace(' ', ' ').replace(' .', '.')
|
||||
|
||||
def deleteEmptyFolder(self, folder):
|
||||
def deleteEmptyFolder(self, folder, show_error = True):
|
||||
|
||||
loge = log.error if show_error else log.debug
|
||||
for root, dirs, files in os.walk(folder):
|
||||
|
||||
for dir_name in dirs:
|
||||
@@ -474,9 +480,9 @@ class Renamer(Plugin):
|
||||
try:
|
||||
os.rmdir(full_path)
|
||||
except:
|
||||
log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc()))
|
||||
loge('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc()))
|
||||
|
||||
try:
|
||||
os.rmdir(folder)
|
||||
except:
|
||||
log.error('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
|
||||
loge('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
|
||||
|
||||
@@ -303,7 +303,15 @@ class Scanner(Plugin):
|
||||
break
|
||||
|
||||
if file_too_new:
|
||||
log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time.ctime(file_time[0]), identifier))
|
||||
try:
|
||||
time_string = time.ctime(file_time[0])
|
||||
except:
|
||||
try:
|
||||
time_string = time.ctime(file_time[1])
|
||||
except:
|
||||
time_string = 'unknown'
|
||||
|
||||
log.info('Files seem to be still unpacking or just unpacked (created on %s), ignoring for now: %s', (time_string, identifier))
|
||||
|
||||
# Delete the unsorted list
|
||||
del group['unsorted_files']
|
||||
|
||||
@@ -39,6 +39,21 @@ config = [{
|
||||
'type': 'dropdown',
|
||||
'values': [('usenet & torrents', 'both'), ('usenet', 'nzb'), ('torrents', 'torrent')],
|
||||
},
|
||||
{
|
||||
'advanced': True,
|
||||
'name': 'run_every',
|
||||
'label': 'Run every',
|
||||
'default': 1,
|
||||
'type': 'int',
|
||||
'unit': 'min(s)',
|
||||
'description': 'Detect movie status every X minutes. Will start the renamer if movie is <strong>completed</strong> or handle <strong>failed</strong> download if these options are enabled',
|
||||
},
|
||||
{
|
||||
'name': 'next_on_failed',
|
||||
'default': True,
|
||||
'type': 'bool',
|
||||
'description': 'Try the next best release for a movie after a download failed.',
|
||||
},
|
||||
],
|
||||
}, {
|
||||
'tab': 'searcher',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from couchpotato import get_session
|
||||
from couchpotato.api import addApiView
|
||||
from couchpotato.core.event import addEvent, fireEvent
|
||||
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
|
||||
from couchpotato.core.helpers.request import jsonified, getParam
|
||||
from couchpotato.core.helpers.variable import md5, getImdb, getTitle
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.plugins.base import Plugin
|
||||
@@ -25,9 +27,19 @@ class Searcher(Plugin):
|
||||
addEvent('searcher.single', self.single)
|
||||
addEvent('searcher.correct_movie', self.correctMovie)
|
||||
addEvent('searcher.download', self.download)
|
||||
addEvent('searcher.check_snatched', self.checkSnatched)
|
||||
|
||||
addApiView('searcher.try_next', self.tryNextReleaseView, docs = {
|
||||
'desc': 'Marks the snatched results as ignored and try the next best release',
|
||||
'params': {
|
||||
'id': {'desc': 'The id of the movie'},
|
||||
},
|
||||
})
|
||||
|
||||
# Schedule cronjob
|
||||
fireEvent('schedule.cron', 'searcher.all', self.all_movies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
|
||||
fireEvent('schedule.interval', 'searcher.check_snatched', self.checkSnatched, minutes = self.conf('run_every'))
|
||||
|
||||
|
||||
def all_movies(self):
|
||||
|
||||
@@ -138,7 +150,7 @@ class Searcher(Plugin):
|
||||
|
||||
for info in nzb:
|
||||
try:
|
||||
if not isinstance(nzb[info], (str, unicode, int, long)):
|
||||
if not isinstance(nzb[info], (str, unicode, int, long, float)):
|
||||
continue
|
||||
|
||||
rls_info = ReleaseInfo(
|
||||
@@ -239,7 +251,6 @@ class Searcher(Plugin):
|
||||
def correctMovie(self, nzb = {}, movie = {}, quality = {}, **kwargs):
|
||||
|
||||
imdb_results = kwargs.get('imdb_results', False)
|
||||
single_category = kwargs.get('single_category', False)
|
||||
retention = Env.setting('retention', section = 'nzb')
|
||||
|
||||
if nzb.get('seeds') is None and retention < nzb.get('age', 0):
|
||||
@@ -272,7 +283,7 @@ class Searcher(Plugin):
|
||||
preferred_quality = fireEvent('quality.single', identifier = quality['identifier'], single = True)
|
||||
|
||||
# Contains lower quality string
|
||||
if self.containsOtherQuality(nzb, movie_year = movie['library']['year'], preferred_quality = preferred_quality, single_category = single_category):
|
||||
if self.containsOtherQuality(nzb, movie_year = movie['library']['year'], preferred_quality = preferred_quality):
|
||||
log.info('Wrong: %s, looking for %s', (nzb['name'], quality['label']))
|
||||
return False
|
||||
|
||||
@@ -324,7 +335,7 @@ class Searcher(Plugin):
|
||||
log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'" % (nzb['name'], movie_name, movie['library']['year']))
|
||||
return False
|
||||
|
||||
def containsOtherQuality(self, nzb, movie_year = None, preferred_quality = {}, single_category = False):
|
||||
def containsOtherQuality(self, nzb, movie_year = None, preferred_quality = {}):
|
||||
|
||||
name = nzb['name']
|
||||
size = nzb.get('size', 0)
|
||||
@@ -355,9 +366,6 @@ class Searcher(Plugin):
|
||||
if found.get(allowed):
|
||||
del found[allowed]
|
||||
|
||||
if (len(found) == 0 and single_category):
|
||||
return False
|
||||
|
||||
return not (found.get(preferred_quality['identifier']) and len(found) == 1)
|
||||
|
||||
def checkIMDB(self, haystack, imdbId):
|
||||
@@ -439,3 +447,96 @@ class Searcher(Plugin):
|
||||
|
||||
|
||||
return False
|
||||
|
||||
def checkSnatched(self):
|
||||
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
||||
ignored_status = fireEvent('status.get', 'ignored', single = True)
|
||||
failed_status = fireEvent('status.get', 'failed', single = True)
|
||||
|
||||
db = get_session()
|
||||
rels = db.query(Release).filter_by(status_id = snatched_status.get('id'))
|
||||
|
||||
if rels:
|
||||
log.debug('Checking status snatched releases...')
|
||||
|
||||
scanrequired = 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
|
||||
|
||||
log.debug('Checking snatched movie: %s' , default_title)
|
||||
|
||||
item = {}
|
||||
for info in rel.info:
|
||||
item[info.identifier] = info.value
|
||||
|
||||
movie_dict = fireEvent('movie.get', rel.movie_id, single = True)
|
||||
|
||||
# check status
|
||||
downloadstatus = fireEvent('download.status', data = item, movie = movie_dict, single = True)
|
||||
if not downloadstatus:
|
||||
log.debug('Download status functionality is not implemented for active downloaders.')
|
||||
scanrequired = True
|
||||
else:
|
||||
log.debug('Download status: %s' , downloadstatus)
|
||||
|
||||
if downloadstatus == 'failed':
|
||||
if self.conf('next_on_failed'):
|
||||
self.tryNextRelease(rel.movie_id)
|
||||
else:
|
||||
rel.status_id = failed_status.get('id')
|
||||
db.commit()
|
||||
|
||||
log.info('Download of %s failed.', item['name'])
|
||||
|
||||
elif downloadstatus == 'completed':
|
||||
log.info('Download of %s completed!', item['name'])
|
||||
scanrequired = True
|
||||
|
||||
elif downloadstatus == 'not_found':
|
||||
log.info('%s not found in downloaders', item['name'])
|
||||
rel.status_id = ignored_status.get('id')
|
||||
db.commit()
|
||||
|
||||
# Note that Queued, Downloading, Paused, Repair and Unpackimg are also available as status for SabNZBd
|
||||
if scanrequired:
|
||||
fireEvent('renamer.scan')
|
||||
|
||||
def tryNextReleaseView(self):
|
||||
|
||||
trynext = self.tryNextRelease(getParam('id'))
|
||||
|
||||
return jsonified({
|
||||
'success': trynext
|
||||
})
|
||||
|
||||
def tryNextRelease(self, movie_id, manual = False):
|
||||
|
||||
snatched_status = fireEvent('status.get', 'snatched', single = True)
|
||||
ignored_status = fireEvent('status.get', 'ignored', single = True)
|
||||
|
||||
try:
|
||||
movie_dict = fireEvent('movie.get', movie_id, single = True)
|
||||
|
||||
db = get_session()
|
||||
rels = db.query(Release).filter_by(
|
||||
status_id = snatched_status.get('id'),
|
||||
movie_id = movie_id
|
||||
).all()
|
||||
|
||||
for rel in rels:
|
||||
rel.status_id = ignored_status.get('id')
|
||||
db.commit()
|
||||
|
||||
log.info('Trying next release for: %s', getTitle(movie_dict['library']))
|
||||
fireEvent('searcher.single', movie_dict)
|
||||
|
||||
return True
|
||||
|
||||
except:
|
||||
log.error('Failed searching for next release: %s', traceback.format_exc())
|
||||
return False
|
||||
|
||||
@@ -19,6 +19,7 @@ class StatusPlugin(Plugin):
|
||||
'downloaded': 'Downloaded',
|
||||
'wanted': 'Wanted',
|
||||
'snatched': 'Snatched',
|
||||
'failed': 'Failed',
|
||||
'deleted': 'Deleted',
|
||||
'ignored': 'Ignored',
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'Mysterbin',
|
||||
'description': '',
|
||||
'description': 'Free provider, less accurate. See <a href="http://www.mysterbin.com/">Mysterbin</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -88,7 +88,7 @@ class Mysterbin(NZBProvider):
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
self.found(new)
|
||||
|
||||
@@ -10,6 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'newzbin',
|
||||
'description': 'See <a href="https://www.newzbin2.es/">Newzbin</a>',
|
||||
'wizard': True,
|
||||
'options': [
|
||||
{
|
||||
|
||||
@@ -96,13 +96,12 @@ class Newznab(NZBProvider, RSS):
|
||||
url = "%s&%s" % (self.getUrl(host['host'], self.urls['search']), arguments)
|
||||
|
||||
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)
|
||||
|
||||
results = self.createItems(url, cache_key, host, single_cat = single_cat, movie = movie, quality = quality)
|
||||
results = self.createItems(url, cache_key, host, movie = movie, quality = quality)
|
||||
|
||||
return results
|
||||
|
||||
def createItems(self, url, cache_key, host, single_cat = False, movie = None, quality = None, for_feed = False):
|
||||
def createItems(self, url, cache_key, host, movie = None, quality = None, for_feed = False):
|
||||
results = []
|
||||
|
||||
data = self.getCache(cache_key, url, cache_timeout = 1800, headers = {'User-Agent': Env.getIdentifier()})
|
||||
@@ -146,7 +145,7 @@ class Newznab(NZBProvider, RSS):
|
||||
if not for_feed:
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = True, single_category = single_cat, single = True)
|
||||
imdb_results = True, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
|
||||
@@ -10,7 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'NZBClub',
|
||||
'description': '',
|
||||
'description': 'Free provider, less accurate. See <a href="https://www.nzbclub.com/">NZBClub</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -86,7 +86,7 @@ class NZBClub(NZBProvider, RSS):
|
||||
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
|
||||
@@ -10,7 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'nzbindex',
|
||||
'description': 'Free provider, but less accurate.',
|
||||
'description': 'Free provider, less accurate. See <a href="http://www.nzbindex.nl/">NZBIndex</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -93,7 +93,7 @@ class NzbIndex(NZBProvider, RSS):
|
||||
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
|
||||
@@ -11,6 +11,7 @@ config = [{
|
||||
'subtab': 'providers',
|
||||
'name': 'nzbmatrix',
|
||||
'label': 'NZBMatrix',
|
||||
'description': 'See <a href="https://nzbmatrix.com/">NZBMatrix</a>',
|
||||
'wizard': True,
|
||||
'options': [
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ class NZBMatrix(NZBProvider, RSS):
|
||||
cat_ids = [
|
||||
([50], ['bd50']),
|
||||
([42, 53], ['720p', '1080p']),
|
||||
([2], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
|
||||
([2, 9], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
|
||||
([54], ['brrip']),
|
||||
([1], ['dvdr']),
|
||||
]
|
||||
@@ -49,7 +49,6 @@ class NZBMatrix(NZBProvider, RSS):
|
||||
url = "%s?%s" % (self.urls['search'], arguments)
|
||||
|
||||
cache_key = 'nzbmatrix.%s.%s' % (movie['library'].get('identifier'), cat_ids)
|
||||
single_cat = True
|
||||
|
||||
data = self.getCache(cache_key, url, cache_timeout = 1800, headers = {'User-Agent': Env.getIdentifier()})
|
||||
if data:
|
||||
@@ -86,7 +85,7 @@ class NZBMatrix(NZBProvider, RSS):
|
||||
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = True, single_category = single_cat, single = True)
|
||||
imdb_results = True, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
|
||||
40
couchpotato/core/providers/nzb/nzbsrus/__init__.py
Normal file
40
couchpotato/core/providers/nzb/nzbsrus/__init__.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from .main import Nzbsrus
|
||||
|
||||
def start():
|
||||
return Nzbsrus()
|
||||
|
||||
config = [{
|
||||
'name': 'nzbsrus',
|
||||
'groups': [
|
||||
{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'nzbsrus',
|
||||
'label': 'Nzbsrus',
|
||||
'description': 'See <a href="https://www.nzbsrus.com/">NZBsRus</a>',
|
||||
'wizard': True,
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
'type': 'enabler',
|
||||
},
|
||||
{
|
||||
'name': 'userid',
|
||||
'label': 'User ID',
|
||||
},
|
||||
{
|
||||
'name': 'api_key',
|
||||
'default': '',
|
||||
'label': 'Api Key',
|
||||
},
|
||||
{
|
||||
'name': 'english_only',
|
||||
'default': 1,
|
||||
'type': 'bool',
|
||||
'label': 'English only',
|
||||
'description': 'Only search for English spoken movies on Nzbsrus',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
104
couchpotato/core/providers/nzb/nzbsrus/main.py
Normal file
104
couchpotato/core/providers/nzb/nzbsrus/main.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from couchpotato.core.event import fireEvent
|
||||
from couchpotato.core.helpers.encoding import tryUrlencode
|
||||
from couchpotato.core.helpers.rss import RSS
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.nzb.base import NZBProvider
|
||||
from couchpotato.environment import Env
|
||||
import time
|
||||
import xml.etree.ElementTree as XMLTree
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
class Nzbsrus(NZBProvider, RSS):
|
||||
|
||||
urls = {
|
||||
'download': 'https://www.nzbsrus.com/nzbdownload_rss.php/%s',
|
||||
'detail': 'https://www.nzbsrus.com/nzbdetails.php?id=%s',
|
||||
'search': 'https://www.nzbsrus.com/api.php?extended=1&xml=1&listname={date,grabs}',
|
||||
}
|
||||
|
||||
cat_ids = [
|
||||
([90, 45, 51], ['720p', '1080p', 'brrip', 'bd50', 'dvdr']),
|
||||
([48, 51], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
|
||||
]
|
||||
cat_backup_id = 240
|
||||
|
||||
def search(self, movie, quality):
|
||||
|
||||
results = []
|
||||
|
||||
if self.isDisabled():
|
||||
return results
|
||||
|
||||
cat_id_string = '&'.join(['c%s=1' % x for x in self.getCatId(quality.get('identifier'))])
|
||||
|
||||
arguments = tryUrlencode({
|
||||
'searchtext': 'imdb:' + movie['library']['identifier'][2:],
|
||||
'uid': self.conf('userid'),
|
||||
'key': self.conf('api_key'),
|
||||
'age': Env.setting('retention', section = 'nzb'),
|
||||
|
||||
})
|
||||
|
||||
# check for english_only
|
||||
if self.conf('english_only'):
|
||||
arguments += "&lang0=1&lang3=1&lang1=1"
|
||||
|
||||
url = "%s&%s&%s" % (self.urls['search'], arguments , cat_id_string)
|
||||
|
||||
cache_key = 'nzbsrus_1.%s.%s' % (movie['library'].get('identifier'), cat_id_string)
|
||||
single_cat = True
|
||||
|
||||
data = self.getCache(cache_key, url, cache_timeout = 1800, headers = {'User-Agent': Env.getIdentifier()})
|
||||
if data:
|
||||
try:
|
||||
try:
|
||||
data = XMLTree.fromstring(data)
|
||||
nzbs = self.getElements(data, 'results/result')
|
||||
except Exception, e:
|
||||
log.debug('%s, %s', (self.getName(), e))
|
||||
return results
|
||||
|
||||
for nzb in nzbs:
|
||||
|
||||
title = self.getTextElement(nzb, "name")
|
||||
if 'error' in title.lower(): continue
|
||||
|
||||
id = self.getTextElement(nzb, "id")
|
||||
size = int(round(int(self.getTextElement(nzb, "size")) / 1048576))
|
||||
age = int(round((time.time() - int(self.getTextElement(nzb, "postdate"))) / 86400))
|
||||
|
||||
new = {
|
||||
'id': id,
|
||||
'type': 'nzb',
|
||||
'provider': self.getName(),
|
||||
'name': title,
|
||||
'age': age,
|
||||
'size': size,
|
||||
'url': self.urls['download'] % id + self.getApiExt() + self.getTextElement(nzb, "key"),
|
||||
'download': self.download,
|
||||
'detail_url': self.urls['detail'] % id,
|
||||
'description': self.getTextElement(nzb, "addtext"),
|
||||
'check_nzb': True,
|
||||
}
|
||||
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = True, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
results.append(new)
|
||||
self.found(new)
|
||||
|
||||
return results
|
||||
except SyntaxError:
|
||||
log.error('Failed to parse XML response from Nzbsrus.com')
|
||||
|
||||
return results
|
||||
|
||||
def download(self, url = '', nzb_id = ''):
|
||||
return self.urlopen(url, headers = {'User-Agent': Env.getIdentifier()})
|
||||
|
||||
def getApiExt(self):
|
||||
return '/%s/' % (self.conf('userid'))
|
||||
@@ -10,6 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'KickAssTorrents',
|
||||
'description': 'See <a href="https://kat.ph/">KickAssTorrents</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -3,8 +3,6 @@ from couchpotato.core.event import fireEvent
|
||||
from couchpotato.core.helpers.variable import tryInt
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.providers.torrent.base import TorrentProvider
|
||||
import StringIO
|
||||
import gzip
|
||||
import re
|
||||
import traceback
|
||||
|
||||
@@ -14,10 +12,9 @@ log = CPLog(__name__)
|
||||
class KickAssTorrents(TorrentProvider):
|
||||
|
||||
urls = {
|
||||
'test': 'http://www.kat.ph/',
|
||||
'detail': 'http://www.kat.ph/%s-t%s.html',
|
||||
'search': 'http://www.kat.ph/i%s/',
|
||||
'download': 'http://torcache.net/',
|
||||
'test': 'http://kat.ph/',
|
||||
'detail': 'http://kat.ph/%s',
|
||||
'search': 'http://kat.ph/i%s/',
|
||||
}
|
||||
|
||||
cat_ids = [
|
||||
@@ -60,11 +57,10 @@ class KickAssTorrents(TorrentProvider):
|
||||
continue
|
||||
|
||||
new = {
|
||||
'type': 'torrent',
|
||||
'type': 'torrent_magnet',
|
||||
'check_nzb': False,
|
||||
'description': '',
|
||||
'provider': self.getName(),
|
||||
'download': self.download,
|
||||
'score': 0,
|
||||
}
|
||||
|
||||
@@ -77,9 +73,8 @@ class KickAssTorrents(TorrentProvider):
|
||||
link = td.find('div', {'class': 'torrentname'}).find_all('a')[1]
|
||||
new['id'] = temp.get('id')[-8:]
|
||||
new['name'] = link.text
|
||||
new['url'] = td.find_all('a', 'idownload')[1]['href']
|
||||
if new['url'][:2] == '//':
|
||||
new['url'] = 'http:%s' % new['url']
|
||||
new['url'] = td.find('a', 'imagnet')['href']
|
||||
new['detail_url'] = self.urls['detail'] % link['href'][1:]
|
||||
new['score'] = 20 if td.find('a', 'iverif') else 0
|
||||
elif column_name is 'size':
|
||||
new['size'] = self.parseSize(td.text)
|
||||
@@ -95,7 +90,7 @@ class KickAssTorrents(TorrentProvider):
|
||||
new['score'] += fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie',
|
||||
nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = True, single_category = False, single = True)
|
||||
imdb_results = True, single = True)
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
self.found(new)
|
||||
@@ -129,13 +124,3 @@ class KickAssTorrents(TorrentProvider):
|
||||
age += tryInt(nr) * mult
|
||||
|
||||
return tryInt(age)
|
||||
|
||||
def download(self, url = '', nzb_id = ''):
|
||||
compressed_data = self.urlopen(url = url, headers = {'Referer': 'http://kat.ph/'})
|
||||
|
||||
compressedstream = StringIO.StringIO(compressed_data)
|
||||
gzipper = gzip.GzipFile(fileobj = compressedstream)
|
||||
data = gzipper.read()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'PublicHD',
|
||||
'description': 'Public Torrent site with only HD content.',
|
||||
'description': 'Public Torrent site with only HD content. See <a href="http://publichd.eu/">PublicHD</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
@@ -20,4 +20,4 @@ config = [{
|
||||
],
|
||||
},
|
||||
],
|
||||
}]
|
||||
}]
|
||||
|
||||
@@ -15,19 +15,9 @@ class PublicHD(TorrentProvider):
|
||||
|
||||
urls = {
|
||||
'test': 'http://publichd.eu',
|
||||
'download': 'http://publichd.eu/%s',
|
||||
'detail': 'http://publichd.eu/index.php?page=torrent-details&id=%s',
|
||||
'search': 'http://publichd.eu/index.php',
|
||||
}
|
||||
|
||||
cat_ids = [
|
||||
([9], ['bd50']),
|
||||
([5], ['1080p']),
|
||||
([2], ['720p']),
|
||||
([15, 16], ['brrip']),
|
||||
]
|
||||
|
||||
cat_backup_id = 0
|
||||
http_time_between_calls = 0
|
||||
|
||||
def search(self, movie, quality):
|
||||
@@ -39,9 +29,8 @@ class PublicHD(TorrentProvider):
|
||||
|
||||
params = tryUrlencode({
|
||||
'page':'torrents',
|
||||
'search': getTitle(movie['library']) + ' ' + quality['identifier'],
|
||||
'search': '%s %s' % (getTitle(movie['library']), movie['library']['year']),
|
||||
'active': 1,
|
||||
'category': self.getCatId(quality['identifier'])[0]
|
||||
})
|
||||
url = '%s?%s' % (self.urls['search'], params)
|
||||
|
||||
@@ -58,7 +47,7 @@ class PublicHD(TorrentProvider):
|
||||
|
||||
for result in entries[2:len(entries) - 1]:
|
||||
info_url = result.find(href = re.compile('torrent-details'))
|
||||
download = result.find(href = re.compile('\.torrent'))
|
||||
download = result.find(href = re.compile('magnet:'))
|
||||
|
||||
if info_url and download:
|
||||
|
||||
@@ -67,12 +56,11 @@ class PublicHD(TorrentProvider):
|
||||
new = {
|
||||
'id': url['id'][0],
|
||||
'name': info_url.string,
|
||||
'type': 'torrent',
|
||||
'type': 'torrent_magnet',
|
||||
'check_nzb': False,
|
||||
'description': '',
|
||||
'provider': self.getName(),
|
||||
'download': self.download,
|
||||
'url': self.urls['download'] % download['href'],
|
||||
'url': download['href'],
|
||||
'detail_url': self.urls['detail'] % url['id'][0],
|
||||
'size': self.parseSize(result.find_all('td')[7].string),
|
||||
'seeders': tryInt(result.find_all('td')[4].string),
|
||||
@@ -82,7 +70,7 @@ class PublicHD(TorrentProvider):
|
||||
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie', nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
|
||||
@@ -10,6 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'SceneAccess',
|
||||
'description': 'See <a href="https://sceneaccess.eu/">SceneAccess</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -86,7 +86,7 @@ class SceneAccess(TorrentProvider):
|
||||
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie', nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
|
||||
@@ -10,6 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'SceneHD',
|
||||
'description': 'See <a href="http://scenehd.org">SceneHD</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -79,7 +79,7 @@ class SceneHD(TorrentProvider):
|
||||
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie', nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = imdb_results, single_category = False, single = True)
|
||||
imdb_results = imdb_results, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
|
||||
@@ -9,7 +9,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'ThePirateBay',
|
||||
'description': 'The world\'s largest bittorrent tracker.',
|
||||
'description': 'The world\'s largest bittorrent tracker. See <a href="http://fucktimkuik.org/">ThePirateBay</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -120,7 +120,7 @@ class ThePirateBay(TorrentProvider):
|
||||
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie', nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = False, single_category = False, single = True)
|
||||
imdb_results = False, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
|
||||
@@ -10,6 +10,7 @@ config = [{
|
||||
'tab': 'searcher',
|
||||
'subtab': 'providers',
|
||||
'name': 'TorrentLeech',
|
||||
'description': 'See <a href="http://torrentleech.org">TorrentLeech</a>',
|
||||
'options': [
|
||||
{
|
||||
'name': 'enabled',
|
||||
|
||||
@@ -80,7 +80,7 @@ class TorrentLeech(TorrentProvider):
|
||||
|
||||
new['score'] = fireEvent('score.calculate', new, movie, single = True)
|
||||
is_correct_movie = fireEvent('searcher.correct_movie', nzb = new, movie = movie, quality = quality,
|
||||
imdb_results = imdb_results, single_category = False, single = True)
|
||||
imdb_results = imdb_results, single = True)
|
||||
|
||||
if is_correct_movie:
|
||||
results.append(new)
|
||||
|
||||
@@ -103,6 +103,22 @@ class Release(Entity):
|
||||
files = ManyToMany('File', cascade = 'all, delete-orphan', single_parent = True)
|
||||
info = OneToMany('ReleaseInfo', cascade = 'all, delete-orphan')
|
||||
|
||||
def to_dict(self, deep = {}, exclude = []):
|
||||
orig_dict = super(Release, self).to_dict(deep = deep, exclude = exclude)
|
||||
|
||||
new_info = {}
|
||||
for info in orig_dict.get('info', []):
|
||||
|
||||
value = info['value']
|
||||
try: value = int(info['value'])
|
||||
except: pass
|
||||
|
||||
new_info[info['identifier']] = value
|
||||
|
||||
orig_dict['info'] = new_info
|
||||
|
||||
return orig_dict
|
||||
|
||||
|
||||
class ReleaseInfo(Entity):
|
||||
"""Properties that can be bound to a file for off-line usage"""
|
||||
|
||||
@@ -29,6 +29,7 @@ var CouchPotato = new Class({
|
||||
|
||||
History.addEvent('change', self.openPage.bind(self));
|
||||
self.c.addEvent('click:relay(a[href^=/]:not([target]))', self.pushState.bind(self));
|
||||
self.c.addEvent('click:relay(a[href^=http])', self.openDerefered.bind(self));
|
||||
},
|
||||
|
||||
getOption: function(name){
|
||||
@@ -187,7 +188,7 @@ var CouchPotato = new Class({
|
||||
restart: function(message, title){
|
||||
var self = this;
|
||||
|
||||
self.blockPage(message || 'Restarting... please wait. If this takes to long, something must have gone wrong.', title);
|
||||
self.blockPage(message || 'Restarting... please wait. If this takes too long, something must have gone wrong.', title);
|
||||
Api.request('app.restart');
|
||||
self.checkAvailable(1000);
|
||||
},
|
||||
@@ -216,7 +217,7 @@ var CouchPotato = new Class({
|
||||
|
||||
Updater.check(onComplete)
|
||||
|
||||
self.blockPage('Please wait. If this takes to long, something must have gone wrong.', 'Checking for updates');
|
||||
self.blockPage('Please wait. If this takes too long, something must have gone wrong.', 'Checking for updates');
|
||||
self.checkAvailable(3000);
|
||||
},
|
||||
|
||||
@@ -269,6 +270,17 @@ var CouchPotato = new Class({
|
||||
|
||||
createUrl: function(action, params){
|
||||
return this.options.base_url + (action ? action+'/' : '') + (params ? '?'+Object.toQueryString(params) : '')
|
||||
},
|
||||
|
||||
openDerefered: function(e, el){
|
||||
(e).stop();
|
||||
|
||||
var url = 'http://www.dereferer.org/?' + el.get('href');
|
||||
|
||||
if(el.get('target') == '_blank' || (e.meta && Browser.Platform.mac) || (e.control && !Browser.Platform.mac))
|
||||
window.open(url);
|
||||
else
|
||||
window.location = url;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -419,15 +431,18 @@ function randomString(length, extra) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
Array.implement('sortBy', function(){
|
||||
keyPaths.empty();
|
||||
Array.each(arguments, function(argument) {
|
||||
switch (typeOf(argument)) {
|
||||
case "array": saveKeyPath(argument); break;
|
||||
case "string": saveKeyPath(argument.match(/[+-]|[^.]+/g)); break;
|
||||
}
|
||||
});
|
||||
return this.sort(comparer);
|
||||
Array.implement({
|
||||
sortBy: function(){
|
||||
keyPaths.empty();
|
||||
|
||||
Array.each(arguments, function(argument) {
|
||||
switch (typeOf(argument)) {
|
||||
case "array": saveKeyPath(argument); break;
|
||||
case "string": saveKeyPath(argument.match(/[+-]|[^.]+/g)); break;
|
||||
}
|
||||
});
|
||||
return this.sort(comparer);
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
@@ -58,6 +58,8 @@ var AboutSettingTab = new Class({
|
||||
}
|
||||
}
|
||||
}),
|
||||
new Element('dt[text=Updater]'),
|
||||
self.updater_type = new Element('dd.updater'),
|
||||
new Element('dt[text=ID]'),
|
||||
new Element('dd', {'text': App.getOption('pid')}),
|
||||
new Element('dt[text=Directories]'),
|
||||
@@ -103,12 +105,8 @@ var AboutSettingTab = new Class({
|
||||
),
|
||||
new Element('div.donate', {
|
||||
'html':
|
||||
'Or, buy me a (24 pack) Pepsi, for while I\'m coding ;)' +
|
||||
'<form action="https://www.paypal.com/cgi-bin/webscr" method="post">' +
|
||||
'<input type="hidden" name="cmd" value="_s-xclick">' +
|
||||
'<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----">' +
|
||||
'<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">' +
|
||||
'</form>'
|
||||
'Or support me via:' +
|
||||
'<iframe src="http://couchpota.to/donate.html" style="border:none; height: 200px;" scrolling="no"></iframe>'
|
||||
})
|
||||
);
|
||||
|
||||
@@ -119,6 +117,7 @@ var AboutSettingTab = new Class({
|
||||
var self = this;
|
||||
var date = new Date(json.version.date * 1000);
|
||||
self.version_text.set('text', json.version.hash + ' ('+date.toUTCString()+')');
|
||||
self.updater_type.set('text', json.version.type);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -31,7 +31,6 @@ window.addEvent('domready', function(){
|
||||
'IMDB': IMDBAction
|
||||
,'Trailer': TrailerAction
|
||||
,'Releases': ReleaseAction
|
||||
|
||||
,'Edit': new Class({
|
||||
|
||||
Extends: MovieAction,
|
||||
@@ -74,20 +73,23 @@ window.addEvent('domready', function(){
|
||||
new Element('option', {
|
||||
'text': alt.title
|
||||
}).inject(self.title_select);
|
||||
|
||||
|
||||
if(alt['default'])
|
||||
self.title_select.set('value', alt.title);
|
||||
});
|
||||
|
||||
|
||||
Quality.getActiveProfiles().each(function(profile){
|
||||
|
||||
var profile_id = profile.id ? profile.id : profile.data.id;
|
||||
|
||||
new Element('option', {
|
||||
'value': profile.id ? profile.id : profile.data.id,
|
||||
'value': profile_id,
|
||||
'text': profile.label ? profile.label : profile.data.label
|
||||
}).inject(self.profile_select);
|
||||
|
||||
if(self.movie.profile)
|
||||
self.profile_select.set('value', profile.id ? profile.id : profile.data.id);
|
||||
if(self.movie.profile && self.movie.profile.data.id == profile_id)
|
||||
self.profile_select.set('value', profile_id);
|
||||
});
|
||||
|
||||
}
|
||||
@@ -170,7 +172,7 @@ window.addEvent('domready', function(){
|
||||
(e).preventDefault();
|
||||
|
||||
if(!self.delete_container){
|
||||
self.delete_container = new Element('div.delete_container').adopt(
|
||||
self.delete_container = new Element('div.buttons.delete_container').adopt(
|
||||
new Element('a.cancel', {
|
||||
'text': 'Cancel',
|
||||
'events': {
|
||||
|
||||
Reference in New Issue
Block a user